d: Merge upstream dmd, druntime f1a045928e

D front-end changes:

    - Import dmd v2.106.1-rc.1.
    - Unrecognized pragmas are no longer an error by default.

D runtime changes:

    - Import druntime v2.106.1-rc.1.

gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd f1a045928e.
	* dmd/VERSION: Bump version to v2.106.1-rc.1.
	* gdc.texi (fignore-unknown-pragmas): Update documentation.
	* d-builtins.cc (covariant_with_builtin_type_p): Update for new
	front-end interface.
	* d-lang.cc (d_parse_file): Likewise.
	* typeinfo.cc (make_frontend_typeinfo): Likewise.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime f1a045928e.
	* libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add
	core/stdc/stdatomic.d.
	* libdruntime/Makefile.in: Regenerate.
This commit is contained in:
Iain Buclaw 2024-01-16 19:57:40 +01:00
parent cfc6d9ae81
commit 838e706fa5
65 changed files with 3210 additions and 1961 deletions

View file

@ -724,7 +724,7 @@ static bool
covariant_with_builtin_type_p (Type *t1, Type *t2)
{
/* Check whether the declared function matches the built-in. */
if (same_type_p (t1, t2) || t1->covariant (t2) == Covariant::yes)
if (same_type_p (t1, t2) || covariant (t1, t2) == Covariant::yes)
return true;
/* May not be covariant because of D attributes applied on t1.

View file

@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
#include "dmd/cond.h"
#include "dmd/declaration.h"
#include "dmd/doc.h"
#include "dmd/dsymbol.h"
#include "dmd/errors.h"
#include "dmd/expression.h"
#include "dmd/hdrgen.h"
@ -1226,7 +1227,7 @@ d_parse_file (void)
if (global.params.v.verbose)
message ("importall %s", m->toChars ());
m->importAll (NULL);
importAll (m, NULL);
}
if (global.errors)

View file

@ -1,4 +1,4 @@
2bbf64907cbbb483d003e0a8fcf8b502e4883799
f1a045928e03239b9477f9497f43f2cf0e61e959
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.

View file

@ -1 +1 @@
v2.106.0
v2.106.1-rc.1

View file

@ -14,16 +14,10 @@
module dmd.aliasthis;
import core.stdc.stdio;
import dmd.aggregate;
import dmd.dscope;
import dmd.dsymbol;
import dmd.expression;
import dmd.expressionsem;
import dmd.globals;
import dmd.identifier;
import dmd.location;
import dmd.mtype;
import dmd.tokens;
import dmd.visitor;
/***********************************************************
@ -71,161 +65,3 @@ extern (C++) final class AliasThis : Dsymbol
return this.isDeprecated_;
}
}
/*************************************
* Find the `alias this` symbol of e's type.
* Params:
* sc = context
* e = expression forming the `this`
* gag = do not print errors, return `null` instead
* findOnly = don't do further processing like resolving properties,
* i.e. just return plain dotExp() result.
* Returns:
* Expression that is `e.aliasthis`
*/
Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false)
{
import dmd.typesem : dotExp;
for (AggregateDeclaration ad = isAggregate(e.type); ad;)
{
if (ad.aliasthis)
{
Loc loc = e.loc;
Type tthis = (e.op == EXP.type ? e.type : null);
const flags = cast(DotExpFlag) (DotExpFlag.noAliasThis | (gag * DotExpFlag.gag));
uint olderrors = gag ? global.startGagging() : 0;
e = dotExp(ad.type, sc, e, ad.aliasthis.ident, flags);
if (!e || findOnly)
return gag && global.endGagging(olderrors) ? null : e;
if (tthis && ad.aliasthis.sym.needThis())
{
if (auto ve = e.isVarExp())
{
if (auto fd = ve.var.isFuncDeclaration())
{
// https://issues.dlang.org/show_bug.cgi?id=13009
// Support better match for the overloaded alias this.
bool hasOverloads;
if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads))
{
if (!hasOverloads)
fd = f; // use exact match
e = new VarExp(loc, fd, hasOverloads);
e.type = f.type;
e = new CallExp(loc, e);
goto L1;
}
}
}
/* non-@property function is not called inside typeof(),
* so resolve it ahead.
*/
{
int save = sc.intypeof;
sc.intypeof = 1; // bypass "need this" error check
e = resolveProperties(sc, e);
sc.intypeof = save;
}
L1:
e = new TypeExp(loc, new TypeTypeof(loc, e));
e = e.expressionSemantic(sc);
}
e = resolveProperties(sc, e);
if (!gag)
ad.aliasthis.checkDeprecatedAliasThis(loc, sc);
else if (global.endGagging(olderrors))
e = null;
}
import dmd.dclass : ClassDeclaration;
auto cd = ad.isClassDeclaration();
if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
{
ad = cd.baseClass;
continue;
}
break;
}
return e;
}
/**
* Check if an `alias this` is deprecated
*
* Usually one would use `expression.checkDeprecated(scope, aliasthis)` to
* check if `expression` uses a deprecated `aliasthis`, but this calls
* `toPrettyChars` which lead to the following message:
* "Deprecation: alias this `fullyqualified.aggregate.__anonymous` is deprecated"
*
* Params:
* at = The `AliasThis` object to check
* loc = `Loc` of the expression triggering the access to `at`
* sc = `Scope` of the expression
* (deprecations do not trigger in deprecated scopes)
*
* Returns:
* Whether the alias this was reported as deprecated.
*/
bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc)
{
import dmd.errors : deprecation, Classification;
import dmd.dsymbolsem : getMessage;
if (global.params.useDeprecated != DiagnosticReporting.off
&& at.isDeprecated() && !sc.isDeprecated())
{
const(char)* message = null;
for (Dsymbol p = at; p; p = p.parent)
{
message = p.depdecl ? p.depdecl.getMessage() : null;
if (message)
break;
}
if (message)
deprecation(loc, "`alias %s this` is deprecated - %s",
at.sym.toChars(), message);
else
deprecation(loc, "`alias %s this` is deprecated",
at.sym.toChars());
if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
ti.printInstantiationTrace(Classification.deprecation);
return true;
}
return false;
}
/**************************************
* Check and set 'att' if 't' is a recursive 'alias this' type
*
* The goal is to prevent endless loops when there is a cycle in the alias this chain.
* Since there is no multiple `alias this`, the chain either ends in a leaf,
* or it loops back on itself as some point.
*
* Example: S0 -> (S1 -> S2 -> S3 -> S1)
*
* `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried.
* `S1` is a recursive alias this type, but since `att` is initialized to `null`,
* this still returns `false`, but `att1` is set to `S1`.
* A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again,
* we notice `att == t`, so we're back at the start of the loop, and this returns `true`.
*
* Params:
* att = type reference used to detect recursion. Should be initialized to `null`.
* t = type of 'alias this' rewrite to attempt
*
* Returns:
* `false` if the rewrite is safe, `true` if it would loop back around
*/
bool isRecursiveAliasThis(ref Type att, Type t)
{
//printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars());
auto tb = t.toBasetype();
if (att && tb.equivalent(att))
return true;
else if (!att && tb.checkAliasThisRec())
att = tb;
return false;
}

View file

@ -97,6 +97,6 @@ struct ASTCodegen
alias isExpression = dmd.dtemplate.isExpression;
alias isTuple = dmd.dtemplate.isTuple;
alias IgnoreErrors = dmd.dsymbol.IgnoreErrors;
alias SearchOpt = dmd.dsymbol.SearchOpt;
alias PASS = dmd.dsymbol.PASS;
}

View file

@ -123,19 +123,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
return sc;
}
override void importAll(Scope* sc)
{
Dsymbols* d = include(sc);
//printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d);
if (d)
{
Scope* sc2 = newScope(sc);
d.foreachDsymbol( s => s.importAll(sc2) );
if (sc2 != sc)
sc2.pop();
}
}
override void addComment(const(char)* comment)
{
//printf("AttribDeclaration::addComment %s\n", comment);
@ -156,11 +143,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
return Dsymbol.oneMembers(d, ps, ident);
}
override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
{
include(null).foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
}
override final bool hasPointers()
{
return include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
@ -675,81 +657,6 @@ extern (C++) final class AnonDeclaration : AttribDeclaration
return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl));
}
override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
{
//printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this);
if (decl)
{
/* This works by treating an AnonDeclaration as an aggregate 'member',
* so in order to place that member we need to compute the member's
* size and alignment.
*/
size_t fieldstart = ad.fields.length;
/* Hackishly hijack ad's structsize and alignsize fields
* for use in our fake anon aggregate member.
*/
uint savestructsize = ad.structsize;
uint savealignsize = ad.alignsize;
ad.structsize = 0;
ad.alignsize = 0;
FieldState fs;
decl.foreachDsymbol( (s)
{
s.setFieldOffset(ad, fs, this.isunion);
if (this.isunion)
fs.offset = 0;
});
/* https://issues.dlang.org/show_bug.cgi?id=13613
* If the fields in this.members had been already
* added in ad.fields, just update *poffset for the subsequent
* field offset calculation.
*/
if (fieldstart == ad.fields.length)
{
ad.structsize = savestructsize;
ad.alignsize = savealignsize;
fieldState.offset = ad.structsize;
return;
}
anonstructsize = ad.structsize;
anonalignsize = ad.alignsize;
ad.structsize = savestructsize;
ad.alignsize = savealignsize;
// 0 sized structs are set to 1 byte
if (anonstructsize == 0)
{
anonstructsize = 1;
anonalignsize = 1;
}
assert(_scope);
auto alignment = _scope.alignment();
/* Given the anon 'member's size and alignment,
* go ahead and place it.
*/
anonoffset = placeField(
fieldState.offset,
anonstructsize, anonalignsize, alignment,
ad.structsize, ad.alignsize,
isunion);
// Add to the anon fields the base offset of this anonymous aggregate
//printf("anon fields, anonoffset = %d\n", anonoffset);
foreach (const i; fieldstart .. ad.fields.length)
{
VarDeclaration v = ad.fields[i];
//printf("\t[%d] %s %d\n", i, v.toChars(), v.offset);
v.offset += anonoffset;
}
}
}
override const(char)* kind() const
{
return (isunion ? "anonymous union" : "anonymous struct");
@ -943,11 +850,6 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
}
}
override void importAll(Scope* sc)
{
// do not evaluate condition before semantic pass
}
override const(char)* kind() const
{
return "static if";
@ -1057,11 +959,6 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration
// change this to give semantics to documentation comments on static foreach declarations
}
override void importAll(Scope* sc)
{
// do not evaluate aggregate before semantic pass
}
override const(char)* kind() const
{
return "static foreach";

View file

@ -26,11 +26,9 @@ public:
virtual Dsymbols *include(Scope *sc);
virtual Scope *newScope(Scope *sc);
void importAll(Scope *sc) override;
void addComment(const utf8_t *comment) override;
const char *kind() const override;
bool oneMember(Dsymbol **ps, Identifier *ident) override;
void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
bool hasPointers() override final;
bool hasStaticCtorOrDtor() override final;
void checkCtorConstInit() override final;
@ -132,7 +130,6 @@ public:
unsigned anonalignsize; // size of anonymous struct for alignment purposes
AnonDeclaration *syntaxCopy(Dsymbol *s) override;
void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
const char *kind() const override;
AnonDeclaration *isAnonDeclaration() override { return this; }
void accept(Visitor *v) override { v->visit(this); }
@ -171,7 +168,6 @@ public:
StaticIfDeclaration *syntaxCopy(Dsymbol *s) override;
Dsymbols *include(Scope *sc) override;
void importAll(Scope *sc) override;
StaticIfDeclaration *isStaticIfDeclaration() override { return this; }
const char *kind() const override;
void accept(Visitor *v) override { v->visit(this); }
@ -190,7 +186,6 @@ public:
bool oneMember(Dsymbol **ps, Identifier *ident) override;
Dsymbols *include(Scope *sc) override;
void addComment(const utf8_t *comment) override;
void importAll(Scope *sc) override;
const char *kind() const override;
void accept(Visitor *v) override { v->visit(this); }
};

View file

@ -247,6 +247,8 @@ final class CParser(AST) : Parser!AST
break;
case TOK.charLiteral:
case TOK.wcharLiteral:
case TOK.dcharLiteral:
case TOK.int32Literal:
case TOK.uns32Literal:
case TOK.int64Literal:
@ -725,6 +727,12 @@ final class CParser(AST) : Parser!AST
nextToken();
break;
case TOK.wcharLiteral:
e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tuns16);
nextToken();
break;
case TOK.dcharLiteral:
case TOK.uns32Literal:
e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns32);
nextToken();
@ -1899,6 +1907,7 @@ final class CParser(AST) : Parser!AST
}
bool isalias = true;
Identifier idt;
if (auto ts = dt.isTypeStruct())
{
if (ts.sym.isAnonymous())
@ -1908,6 +1917,7 @@ final class CParser(AST) : Parser!AST
ts.sym.ident = id;
isalias = false;
}
idt = ts.sym.ident;
}
else if (auto te = dt.isTypeEnum())
{
@ -1917,6 +1927,7 @@ final class CParser(AST) : Parser!AST
te.sym.ident = id;
isalias = false;
}
idt = te.sym.ident;
}
else if (auto tt = dt.isTypeTag())
{
@ -1930,11 +1941,13 @@ final class CParser(AST) : Parser!AST
Specifier spec;
declareTag(tt, spec);
}
idt = tt.id;
}
if (isalias)
{
auto ad = new AST.AliasDeclaration(token.loc, id, dt);
ad.adFlags |= ad.hidden; // do not print when generating .di files
if (id == idt)
ad.adFlags |= ad.hidden; // do not print when generating .di files
s = ad;
}
@ -4272,6 +4285,7 @@ final class CParser(AST) : Parser!AST
case TOK.rightParenthesis:
case TOK.rightBracket:
case TOK.endOfFile:
case TOK.endOfLine:
if (!any)
return false;
break;
@ -4940,6 +4954,8 @@ final class CParser(AST) : Parser!AST
{
case TOK.identifier:
case TOK.charLiteral:
case TOK.wcharLiteral:
case TOK.dcharLiteral:
case TOK.int32Literal:
case TOK.uns32Literal:
case TOK.int64Literal:
@ -5794,6 +5810,9 @@ final class CParser(AST) : Parser!AST
buf.writeByte(0);
auto slice = buf.peekChars()[0 .. length];
resetDefineLines(slice); // reset lexer
auto save = eSink;
auto eLatch = new ErrorSinkLatch();
eSink = eLatch;
const(char)* endp = &slice[length - 7];
@ -5801,40 +5820,40 @@ final class CParser(AST) : Parser!AST
// indexed by Identifier, returns index into symbols[]
// The memory for this is leaked
void addVar(AST.VarDeclaration v)
void addVar(AST.Dsymbol s)
{
//printf("addVar() %s\n", v.toChars());
v.isCmacro(true); // mark it as coming from a C #define
//printf("addVar() %s\n", s.toChars());
if (auto v = s.isVarDeclaration())
v.isCmacro(true); // mark it as coming from a C #define
/* If it's already defined, replace the earlier
* definition
*/
if (size_t* pd = cast(void*)v.ident in defineTab)
if (size_t* pd = cast(void*)s.ident in defineTab)
{
//printf("replacing %s\n", v.toChars());
(*symbols)[*pd] = v;
(*symbols)[*pd] = s;
return;
}
defineTab[cast(void*)v.ident] = symbols.length;
symbols.push(v);
defineTab[cast(void*)s.ident] = symbols.length;
symbols.push(s);
}
Token n;
while (p < endp)
{
if (p[0 .. 7] == "#define")
{
p += 7;
scan(&n);
//printf("%s\n", n.toChars());
if (n.value == TOK.identifier)
nextToken();
//printf("define %s\n", token.toChars());
if (token.value == TOK.identifier)
{
auto id = n.ident;
scan(&n);
auto id = token.ident;
const params = *p == '(';
nextToken();
AST.Type t;
switch (n.value)
switch (token.value)
{
case TOK.endOfLine: // #define identifier
nextDefineLine();
@ -5842,14 +5861,16 @@ final class CParser(AST) : Parser!AST
case TOK.int32Literal:
case TOK.charLiteral: t = AST.Type.tint32; goto Linteger;
case TOK.wcharLiteral: t = AST.Type.tuns16; goto Linteger;
case TOK.dcharLiteral:
case TOK.uns32Literal: t = AST.Type.tuns32; goto Linteger;
case TOK.int64Literal: t = AST.Type.tint64; goto Linteger;
case TOK.uns64Literal: t = AST.Type.tuns64; goto Linteger;
Linteger:
const intvalue = n.intvalue;
scan(&n);
if (n.value == TOK.endOfLine)
const intvalue = token.intvalue;
nextToken();
if (token.value == TOK.endOfLine)
{
/* Declare manifest constant:
* enum id = intvalue;
@ -5870,9 +5891,9 @@ final class CParser(AST) : Parser!AST
case TOK.imaginary80Literal: t = AST.Type.timaginary80; goto Lfloat;
Lfloat:
const floatvalue = n.floatvalue;
scan(&n);
if (n.value == TOK.endOfLine)
const floatvalue = token.floatvalue;
nextToken();
if (token.value == TOK.endOfLine)
{
/* Declare manifest constant:
* enum id = floatvalue;
@ -5886,11 +5907,11 @@ final class CParser(AST) : Parser!AST
break;
case TOK.string_:
const str = n.ustring;
const len = n.len;
const postfix = n.postfix;
scan(&n);
if (n.value == TOK.endOfLine)
const str = token.ustring;
const len = token.len;
const postfix = token.postfix;
nextToken();
if (token.value == TOK.endOfLine)
{
/* Declare manifest constant:
* enum id = "string";
@ -5903,6 +5924,39 @@ final class CParser(AST) : Parser!AST
}
break;
case TOK.leftParenthesis:
/* Look for:
* #define ID ( expression )
* and rewrite it to a template function:
* auto ID()() { return expression; }
*/
if (params)
break; // no parameters
nextToken();
eLatch.sawErrors = false;
auto exp = cparseExpression();
if (eLatch.sawErrors) // parsing errors
break; // abandon this #define
if (token.value != TOK.rightParenthesis)
break;
nextToken();
if (token.value != TOK.endOfLine)
break;
auto ret = new AST.ReturnStatement(exp.loc, exp);
auto parameterList = AST.ParameterList(new AST.Parameters(), VarArg.none, 0);
StorageClass stc = STC.auto_;
auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc);
auto fd = new AST.FuncDeclaration(exp.loc, exp.loc, id, stc, tf, 0);
fd.fbody = ret;
AST.Dsymbols* decldefs = new AST.Dsymbols();
decldefs.push(fd);
AST.TemplateParameters* tpl = new AST.TemplateParameters();
AST.Expression constraint = null;
auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, constraint, decldefs, false);
addVar(tempdecl);
nextDefineLine();
continue;
default:
break;
}
@ -5911,8 +5965,8 @@ final class CParser(AST) : Parser!AST
}
else
{
scan(&n);
if (n.value != TOK.endOfLine)
scan(&token);
if (token.value != TOK.endOfLine)
{
skipToNextLine();
}
@ -5920,6 +5974,7 @@ final class CParser(AST) : Parser!AST
nextDefineLine();
}
eSink = save;
defines = buf;
}

View file

@ -636,8 +636,11 @@ bool isSafePointerCast(Type srcPointee, Type destPointee)
// It's OK if function pointers differ only in safe/pure/nothrow
if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction)
{
import dmd.typesem : covariant;
return srcPointee.covariant(destPointee) == Covariant.yes ||
destPointee.covariant(srcPointee) == Covariant.yes;
}
// it's OK to cast to void*
if (destPointee.ty == Tvoid)
return true;

View file

@ -24,6 +24,7 @@ import dmd.dinterpret;
import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
import dmd.dsymbolsem;
import dmd.errors;
import dmd.escape;
import dmd.expression;

View file

@ -594,7 +594,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
fieldState.offset = structsize;
foreach (s; *members)
{
s.setFieldOffset(this, fieldState, false);
s.setFieldOffset(this, &fieldState, false);
}
sizeok = Sizeok.done;
@ -614,7 +614,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
final bool isFuncHidden(FuncDeclaration fd)
{
//printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars());
Dsymbol s = this.search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors);
Dsymbol s = this.search(Loc.initial, fd.ident, SearchOpt.ignoreAmbiguous | SearchOpt.ignoreErrors);
if (!s)
{
//printf("not found\n");
@ -670,6 +670,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
void searchVtbl(ref Dsymbols vtbl)
{
import dmd.typesem : covariant;
bool seenInterfaceVirtual;
foreach (s; vtbl)
{

View file

@ -1214,88 +1214,6 @@ extern (C++) class VarDeclaration : Declaration
return v;
}
override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
{
//printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
if (aliasTuple)
{
// If this variable was really a tuple, set the offsets for the tuple fields
aliasTuple.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); });
return;
}
if (!isField())
return;
assert(!(storage_class & (STC.static_ | STC.extern_ | STC.parameter)));
//printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
/* Fields that are tuples appear both as part of TupleDeclarations and
* as members. That means ignore them if they are already a field.
*/
if (offset)
{
// already a field
fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613
return;
}
for (size_t i = 0; i < ad.fields.length; i++)
{
if (ad.fields[i] == this)
{
// already a field
fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613
return;
}
}
// Check for forward referenced types which will fail the size() call
Type t = type.toBasetype();
if (storage_class & STC.ref_)
{
// References are the size of a pointer
t = Type.tvoidptr;
}
Type tv = t.baseElemOf();
if (tv.ty == Tstruct)
{
auto ts = cast(TypeStruct)tv;
assert(ts.sym != ad); // already checked in ad.determineFields()
if (!ts.sym.determineSize(loc))
{
type = Type.terror;
errors = true;
return;
}
}
// List in ad.fields. Even if the type is error, it's necessary to avoid
// pointless error diagnostic "more initializers than fields" on struct literal.
ad.fields.push(this);
if (t.ty == Terror)
return;
/* If coming after a bit field in progress,
* advance past the field
*/
fieldState.inFlight = false;
const sz = t.size(loc);
assert(sz != SIZE_INVALID && sz < uint.max);
uint memsize = cast(uint)sz; // size of member
uint memalignsize = target.fieldalign(t); // size of member for alignment purposes
offset = placeField(
fieldState.offset,
memsize, memalignsize, alignment,
ad.structsize, ad.alignsize,
isunion);
//printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
//printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
}
override const(char)* kind() const
{
return "variable";
@ -1803,211 +1721,6 @@ extern (C++) class BitFieldDeclaration : VarDeclaration
: (1L << (width - 1)) - 1);
return v;
}
override final void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
{
enum log = false;
static if (log)
{
printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars());
void print(const ref FieldState fieldState)
{
fieldState.print();
printf(" fieldWidth = %d bits\n", fieldWidth);
}
print(fieldState);
}
Type t = type.toBasetype();
const bool anon = isAnonymous();
// List in ad.fields. Even if the type is error, it's necessary to avoid
// pointless error diagnostic "more initializers than fields" on struct literal.
if (!anon)
ad.fields.push(this);
if (t.ty == Terror)
return;
const sz = t.size(loc);
assert(sz != SIZE_INVALID && sz < uint.max);
uint memsize = cast(uint)sz; // size of member
uint memalignsize = target.fieldalign(t); // size of member for alignment purposes
if (log) printf(" memsize: %u memalignsize: %u\n", memsize, memalignsize);
if (fieldWidth == 0 && !anon)
error(loc, "named bit fields cannot have 0 width");
if (fieldWidth > memsize * 8)
error(loc, "bit field width %d is larger than type", fieldWidth);
const style = target.c.bitFieldStyle;
void startNewField()
{
if (log) printf("startNewField()\n");
uint alignsize;
if (style == TargetC.BitFieldStyle.Gcc_Clang)
{
if (fieldWidth > 32)
alignsize = memalignsize;
else if (fieldWidth > 16)
alignsize = 4;
else if (fieldWidth > 8)
alignsize = 2;
else
alignsize = 1;
}
else
alignsize = memsize; // not memalignsize
uint dummy;
offset = placeField(
fieldState.offset,
memsize, alignsize, alignment,
ad.structsize,
(anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize,
isunion);
fieldState.inFlight = true;
fieldState.fieldOffset = offset;
fieldState.bitOffset = 0;
fieldState.fieldSize = memsize;
}
if (style == TargetC.BitFieldStyle.Gcc_Clang)
{
if (fieldWidth == 0)
{
if (!isunion)
{
// Use type of zero width field to align to next field
fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1);
ad.structsize = fieldState.offset;
}
fieldState.inFlight = false;
return;
}
if (ad.alignsize == 0)
ad.alignsize = 1;
if (!anon &&
ad.alignsize < memalignsize)
ad.alignsize = memalignsize;
}
else if (style == TargetC.BitFieldStyle.MS)
{
if (ad.alignsize == 0)
ad.alignsize = 1;
if (fieldWidth == 0)
{
if (fieldState.inFlight && !isunion)
{
// documentation says align to next int
//const alsz = cast(uint)Type.tint32.size();
const alsz = memsize; // but it really does this
fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
ad.structsize = fieldState.offset;
}
fieldState.inFlight = false;
return;
}
}
else if (style == TargetC.BitFieldStyle.DM)
{
if (anon && fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0))
return; // this probably should be a bug in DMC
if (ad.alignsize == 0)
ad.alignsize = 1;
if (fieldWidth == 0)
{
if (fieldState.inFlight && !isunion)
{
const alsz = memsize;
fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
ad.structsize = fieldState.offset;
}
fieldState.inFlight = false;
return;
}
}
if (!fieldState.inFlight)
{
//printf("not in flight\n");
startNewField();
}
else if (style == TargetC.BitFieldStyle.Gcc_Clang)
{
// If the bit-field spans more units of alignment than its type,
// start a new field at the next alignment boundary.
if (fieldState.bitOffset == fieldState.fieldSize * 8 &&
fieldState.bitOffset + fieldWidth > memalignsize * 8)
{
if (log) printf("more units of alignment than its type\n");
startNewField(); // the bit field is full
}
else
{
// if alignment boundary is crossed
uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset;
uint end = start + fieldWidth;
//printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
{
if (log) printf("alignment is crossed\n");
startNewField();
}
}
}
else if (style == TargetC.BitFieldStyle.DM ||
style == TargetC.BitFieldStyle.MS)
{
if (memsize != fieldState.fieldSize ||
fieldState.bitOffset + fieldWidth > fieldState.fieldSize * 8)
{
//printf("new field\n");
startNewField();
}
}
else
assert(0);
offset = fieldState.fieldOffset;
bitOffset = fieldState.bitOffset;
const pastField = bitOffset + fieldWidth;
if (style == TargetC.BitFieldStyle.Gcc_Clang)
{
auto size = (pastField + 7) / 8;
fieldState.fieldSize = size;
//printf(" offset: %d, size: %d\n", offset, size);
if (isunion)
{
const newstructsize = offset + size;
if (newstructsize > ad.structsize)
ad.structsize = newstructsize;
}
else
ad.structsize = offset + size;
}
else
fieldState.fieldSize = memsize;
//printf("at end: ad.structsize = %d\n", cast(int)ad.structsize);
//print(fieldState);
if (!isunion)
{
fieldState.offset = offset + fieldState.fieldSize;
fieldState.bitOffset = pastField;
}
//printf("\t%s: offset = %d bitOffset = %d fieldWidth = %d memsize = %d\n", toChars(), offset, bitOffset, fieldWidth, memsize);
//printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
//printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
}
}
/***********************************************************

View file

@ -281,7 +281,6 @@ public:
bool systemInferred(bool v);
static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined);
VarDeclaration *syntaxCopy(Dsymbol *) override;
void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override final;
const char *kind() const override;
AggregateDeclaration *isThis() override final;
bool needThis() override final;

View file

@ -222,48 +222,6 @@ extern (C++) final class Import : Dsymbol
return global.errors != errors;
}
override void importAll(Scope* sc)
{
if (mod) return; // Already done
/*
* https://issues.dlang.org/show_bug.cgi?id=15525
*
* Loading the import has failed,
* most likely because of parsing errors.
* Therefore we cannot trust the resulting AST.
*/
if (load(sc))
{
// https://issues.dlang.org/show_bug.cgi?id=23873
// For imports that are not at module or function level,
// e.g. aggregate level, the import symbol is added to the
// symbol table and later semantic is performed on it.
// This leads to semantic analysis on an malformed AST
// which causes all kinds of segfaults.
// The fix is to note that the module has errors and avoid
// semantic analysis on it.
if(mod)
mod.errors = true;
return;
}
if (!mod) return; // Failed
if (sc.stc & STC.static_)
isstatic = true;
mod.importAll(null);
mod.checkImportDeprecation(loc, sc);
if (sc.explicitVisibility)
visibility = sc.visibility;
if (!isstatic && !aliasId && !names.length)
sc.scopesym.importScope(mod, visibility);
// Enable access to pkgs/mod as soon as posible, because compiler
// can traverse them before the import gets semantic (Issue: 21501)
if (!aliasId && !names.length)
addPackageAccess(sc.scopesym);
}
/*******************************
* Mark the imported packages as accessible from the current
* scope. This access check is necessary when using FQN b/c

View file

@ -401,7 +401,7 @@ extern (C++) final class Module : Package
Identifier searchCacheIdent;
Dsymbol searchCacheSymbol; // cached value of search
int searchCacheFlags; // cached flags
SearchOptFlags searchCacheFlags; // cached flags
bool insearch;
/**
@ -921,70 +921,6 @@ extern (C++) final class Module : Package
return this;
}
override void importAll(Scope* prevsc)
{
//printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
if (_scope)
return; // already done
if (filetype == FileType.ddoc)
{
error(loc, "%s `%s` is a Ddoc file, cannot import it", kind, toPrettyChars);
return;
}
/* Note that modules get their own scope, from scratch.
* This is so regardless of where in the syntax a module
* gets imported, it is unaffected by context.
* Ignore prevsc.
*/
Scope* sc = Scope.createGlobal(this, global.errorSink); // create root scope
if (md && md.msg)
md.msg = semanticString(sc, md.msg, "deprecation message");
// Add import of "object", even for the "object" module.
// If it isn't there, some compiler rewrites, like
// classinst == classinst -> .object.opEquals(classinst, classinst)
// would fail inside object.d.
if (filetype != FileType.c &&
(members.length == 0 ||
(*members)[0].ident != Id.object ||
(*members)[0].isImport() is null))
{
auto im = new Import(Loc.initial, null, Id.object, null, 0);
members.shift(im);
}
if (!symtab)
{
// Add all symbols into module's symbol table
symtab = new DsymbolTable();
for (size_t i = 0; i < members.length; i++)
{
Dsymbol s = (*members)[i];
s.addMember(sc, sc.scopesym);
}
}
// anything else should be run after addMember, so version/debug symbols are defined
/* Set scope for the symbols so that if we forward reference
* a symbol, it can possibly be resolved on the spot.
* If this works out well, it can be extended to all modules
* before any semantic() on any of them.
*/
this.setScope(sc); // remember module scope for semantic
for (size_t i = 0; i < members.length; i++)
{
Dsymbol s = (*members)[i];
s.setScope(sc);
}
for (size_t i = 0; i < members.length; i++)
{
Dsymbol s = (*members)[i];
s.importAll(sc);
}
sc = sc.pop();
sc.pop(); // 2 pops because Scope.createGlobal() created 2
}
/**********************************
* Determine if we need to generate an instance of ModuleInfo
* for this Module.
@ -1021,14 +957,14 @@ extern (C++) final class Module : Package
}
}
override bool isPackageAccessible(Package p, Visibility visibility, int flags = 0)
override bool isPackageAccessible(Package p, Visibility visibility, SearchOptFlags flags = SearchOpt.all)
{
if (insearch) // don't follow import cycles
return false;
insearch = true;
scope (exit)
insearch = false;
if (flags & IgnorePrivateImports)
if (flags & SearchOpt.ignorePrivateImports)
visibility = Visibility(Visibility.Kind.public_); // only consider public imports
return super.isPackageAccessible(p, visibility);
}
@ -1384,7 +1320,53 @@ extern (C++) void getLocalClasses(Module mod, ref ClassDeclarations aclasses)
return 0;
}
ScopeDsymbol._foreach(null, mod.members, &pushAddClassDg);
_foreach(null, mod.members, &pushAddClassDg);
}
alias ForeachDg = int delegate(size_t idx, Dsymbol s);
/***************************************
* Expands attribute declarations in members in depth first
* order. Calls dg(size_t symidx, Dsymbol *sym) for each
* member.
* If dg returns !=0, stops and returns that value else returns 0.
* Use this function to avoid the O(N + N^2/2) complexity of
* calculating dim and calling N times getNth.
* Returns:
* last value returned by dg()
*/
int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null)
{
assert(dg);
if (!members)
return 0;
size_t n = pn ? *pn : 0; // take over index
int result = 0;
foreach (size_t i; 0 .. members.length)
{
import dmd.attrib : AttribDeclaration;
import dmd.dtemplate : TemplateMixin;
Dsymbol s = (*members)[i];
if (AttribDeclaration a = s.isAttribDeclaration())
result = _foreach(sc, a.include(sc), dg, &n);
else if (TemplateMixin tm = s.isTemplateMixin())
result = _foreach(sc, tm.members, dg, &n);
else if (s.isTemplateInstance())
{
}
else if (s.isUnitTestDeclaration())
{
}
else
result = dg(n++, s);
if (result)
break;
}
if (pn)
*pn = n; // update index
return result;
}
/**

View file

@ -748,7 +748,8 @@ void emitAnchor(ref OutBuffer buf, Dsymbol s, Scope* sc, bool forHeader = false)
auto a = imp.aliases[i];
auto id = a ? a : imp.names[i];
auto loc = Loc.init;
if (auto symFromId = sc.search(loc, id, null))
Dsymbol pscopesym;
if (auto symFromId = sc.search(loc, id, pscopesym))
{
emitAnchor(buf, symFromId, sc, forHeader);
}
@ -3636,11 +3637,12 @@ struct MarkdownLinkReferences
if (id)
{
auto loc = Loc();
auto symbol = _scope.search(loc, id, null, IgnoreErrors);
Dsymbol pscopesym;
auto symbol = _scope.search(loc, id, pscopesym, SearchOpt.ignoreErrors);
for (size_t i = 1; symbol && i < ids.length; ++i)
{
id = Identifier.lookup(ids[i].ptr, ids[i].length);
symbol = id !is null ? symbol.search(loc, id, IgnoreErrors) : null;
symbol = id !is null ? symbol.search(loc, id, SearchOpt.ignoreErrors) : null;
}
if (symbol)
link = MarkdownLink(createHref(symbol), null, name, symbol);
@ -4997,7 +4999,8 @@ void highlightCode(Scope* sc, Dsymbol s, ref OutBuffer buf, size_t offset)
auto a = imp.aliases[i];
auto id = a ? a : imp.names[i];
auto loc = Loc.init;
if (auto symFromId = sc.search(loc, id, null))
Dsymbol pscopesym;
if (auto symFromId = sc.search(loc, id, pscopesym))
{
highlightCode(sc, symFromId, buf, offset);
}

View file

@ -344,13 +344,13 @@ extern (C++) struct Scope
* Params:
* loc = location to use for error messages
* ident = name to look up
* pscopesym = if supplied and name is found, set to scope that ident was found in
* pscopesym = if supplied and name is found, set to scope that ident was found in, otherwise set to null
* flags = modify search based on flags
*
* Returns:
* symbol if found, null if not
*/
extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone)
extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, out Dsymbol pscopesym, SearchOptFlags flags = SearchOpt.all)
{
version (LOGSEARCH)
{
@ -371,7 +371,7 @@ extern (C++) struct Scope
}
// This function is called only for unqualified lookup
assert(!(flags & (SearchLocalsOnly | SearchImportsOnly)));
assert(!(flags & (SearchOpt.localsOnly | SearchOpt.importsOnly)));
/* If ident is "start at module scope", only look at module scope
*/
@ -386,15 +386,14 @@ extern (C++) struct Scope
if (Dsymbol s = sc.scopesym.isModule())
{
//printMsg("\tfound", s);
if (pscopesym)
*pscopesym = sc.scopesym;
pscopesym = sc.scopesym;
return s;
}
}
return null;
}
Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, int flags, Expression* exp)
Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, SearchOptFlags flags, Expression* exp)
{
import dmd.mtype;
if (!ad || !ad.aliasthis)
@ -458,7 +457,7 @@ extern (C++) struct Scope
return s;
}
Dsymbol searchScopes(int flags)
Dsymbol searchScopes(SearchOptFlags flags)
{
for (Scope* sc = &this; sc; sc = sc.enclosing)
{
@ -468,13 +467,13 @@ extern (C++) struct Scope
//printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc.scopesym.toChars(), sc.scopesym.kind(), flags);
if (sc.scopesym.isModule())
flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
flags |= SearchOpt.unqualifiedModule; // tell Module.search() that SearchOpt.localsOnly is to be obeyed
else if (sc.flags & SCOPE.Cfile && sc.scopesym.isStructDeclaration())
continue; // C doesn't have struct scope
if (Dsymbol s = sc.scopesym.search(loc, ident, flags))
{
if (flags & TagNameSpace)
if (flags & SearchOpt.tagNameSpace)
{
// ImportC: if symbol is not a tag, look for it in tag table
if (!s.isScopeDsymbol())
@ -486,8 +485,7 @@ extern (C++) struct Scope
}
}
//printMsg("\tfound local", s);
if (pscopesym)
*pscopesym = sc.scopesym;
pscopesym = sc.scopesym;
return s;
}
@ -499,8 +497,7 @@ extern (C++) struct Scope
if (aliasSym)
{
//printf("found aliassym: %s\n", aliasSym.toChars());
if (pscopesym)
*pscopesym = new ExpressionDsymbol(exp);
pscopesym = new ExpressionDsymbol(exp);
return aliasSym;
}
}
@ -513,15 +510,15 @@ extern (C++) struct Scope
}
if (this.flags & SCOPE.ignoresymbolvisibility)
flags |= IgnoreSymbolVisibility;
flags |= SearchOpt.ignoreVisibility;
// First look in local scopes
Dsymbol s = searchScopes(flags | SearchLocalsOnly);
Dsymbol s = searchScopes(flags | SearchOpt.localsOnly);
version (LOGSEARCH) if (s) printMsg("-Scope.search() found local", s);
if (!s)
{
// Second look in imported modules
s = searchScopes(flags | SearchImportsOnly);
s = searchScopes(flags | SearchOpt.importsOnly);
version (LOGSEARCH) if (s) printMsg("-Scope.search() found import", s);
}
return s;
@ -554,8 +551,8 @@ extern (C++) struct Scope
return null;
Scope* sc = &this;
Module.clearCache();
Dsymbol scopesym = null;
Dsymbol s = sc.search(Loc.initial, id, &scopesym, IgnoreErrors);
Dsymbol scopesym;
Dsymbol s = sc.search(Loc.initial, id, scopesym, SearchOpt.ignoreErrors);
if (!s)
return null;
@ -579,9 +576,9 @@ extern (C++) struct Scope
return s;
}
Dsymbol scopesym = null;
Dsymbol scopesym;
// search for exact name first
if (auto s = search(Loc.initial, ident, &scopesym, IgnoreErrors))
if (auto s = search(Loc.initial, ident, scopesym, SearchOpt.ignoreErrors))
return s;
return speller!scope_search_fp(ident.toString());
}

View file

@ -289,7 +289,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
for (size_t i = 0; i < members.length; i++)
{
Dsymbol s = (*members)[i];
s.setFieldOffset(this, fieldState, isunion);
s.setFieldOffset(this, &fieldState, isunion);
}
if (type.ty == Terror)
{

View file

@ -203,20 +203,21 @@ enum PASS : ubyte
}
// Search options
enum : int
alias SearchOptFlags = uint;
enum SearchOpt : SearchOptFlags
{
IgnoreNone = 0x00, // default
IgnorePrivateImports = 0x01, // don't search private imports
IgnoreErrors = 0x02, // don't give error messages
IgnoreAmbiguous = 0x04, // return NULL if ambiguous
SearchLocalsOnly = 0x08, // only look at locals (don't search imports)
SearchImportsOnly = 0x10, // only look in imports
SearchUnqualifiedModule = 0x20, // the module scope search is unqualified,
all = 0x00, // search for all symbols
ignorePrivateImports = 0x01, // don't search private imports
ignoreErrors = 0x02, // don't give error messages
ignoreAmbiguous = 0x04, // return NULL if ambiguous
localsOnly = 0x08, // only look at locals (don't search imports)
importsOnly = 0x10, // only look in imports
unqualifiedModule = 0x20, // the module scope search is unqualified,
// meaning don't search imports in that scope,
// because qualified module searches search
// their imports
IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols
TagNameSpace = 0x100, // search ImportC tag symbol table
tagNameSpace = 0x40, // search ImportC tag symbol table
ignoreVisibility = 0x80, // also find private and package protected symbols
}
/***********************************************************
@ -712,10 +713,6 @@ extern (C++) class Dsymbol : ASTNode
return toAlias();
}
void importAll(Scope* sc)
{
}
bool overloadInsert(Dsymbol s)
{
//printf("Dsymbol::overloadInsert('%s')\n", s.toChars());
@ -922,10 +919,6 @@ extern (C++) class Dsymbol : ASTNode
return true;
}
void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
{
}
/*****************************************
* Is Dsymbol a variable that contains pointers?
*/
@ -1263,7 +1256,7 @@ public:
(*pary)[p.tag] = true;
}
bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) nothrow
bool isPackageAccessible(Package p, Visibility visibility, SearchOptFlags flags = SearchOpt.all) nothrow
{
if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] ||
visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag])
@ -1272,7 +1265,7 @@ public:
{
// only search visible scopes && imported modules should ignore private imports
if (visibility.kind <= visibilities[i] &&
ss.isScopeDsymbol.isPackageAccessible(p, visibility, IgnorePrivateImports))
ss.isScopeDsymbol.isPackageAccessible(p, visibility, SearchOpt.ignorePrivateImports))
return true;
}
return false;
@ -1371,48 +1364,6 @@ public:
return false;
}
extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s);
/***************************************
* Expands attribute declarations in members in depth first
* order. Calls dg(size_t symidx, Dsymbol *sym) for each
* member.
* If dg returns !=0, stops and returns that value else returns 0.
* Use this function to avoid the O(N + N^2/2) complexity of
* calculating dim and calling N times getNth.
* Returns:
* last value returned by dg()
*/
extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null)
{
assert(dg);
if (!members)
return 0;
size_t n = pn ? *pn : 0; // take over index
int result = 0;
foreach (size_t i; 0 .. members.length)
{
Dsymbol s = (*members)[i];
if (AttribDeclaration a = s.isAttribDeclaration())
result = _foreach(sc, a.include(sc), dg, &n);
else if (TemplateMixin tm = s.isTemplateMixin())
result = _foreach(sc, tm.members, dg, &n);
else if (s.isTemplateInstance())
{
}
else if (s.isUnitTestDeclaration())
{
}
else
result = dg(n++, s);
if (result)
break;
}
if (pn)
*pn = n; // update index
return result;
}
override final inout(ScopeDsymbol) isScopeDsymbol() inout
{
return this;

View file

@ -147,20 +147,21 @@ enum
/* Flags for symbol search
*/
enum
typedef uint SearchOptFlags;
enum class SearchOpt : SearchOptFlags
{
IgnoreNone = 0x00, // default
IgnorePrivateImports = 0x01, // don't search private imports
IgnoreErrors = 0x02, // don't give error messages
IgnoreAmbiguous = 0x04, // return NULL if ambiguous
SearchLocalsOnly = 0x08, // only look at locals (don't search imports)
SearchImportsOnly = 0x10, // only look in imports
SearchUnqualifiedModule = 0x20, // the module scope search is unqualified,
// meaning don't search imports in that scope,
// because qualified module searches search
// their imports
IgnoreSymbolVisibility = 0x80, // also find private and package protected symbols
TagNameSpace = 0x100, // search ImportC tag symbol table
all = 0x00, // default
ignorePrivateImports = 0x01, // don't search private imports
ignoreErrors = 0x02, // don't give error messages
ignoreAmbiguous = 0x04, // return NULL if ambiguous
localsOnly = 0x08, // only look at locals (don't search imports)
importsOnly = 0x10, // only look in imports
unqualifiedModule = 0x20, // the module scope search is unqualified,
// meaning don't search imports in that scope,
// because qualified module searches search
// their imports
tagNameSpace = 0x40, // search ImportC tag symbol table
ignoreVisibility = 0x80, // also find private and package protected symbols
};
struct FieldState
@ -227,7 +228,6 @@ public:
virtual const char *kind() const;
virtual Dsymbol *toAlias(); // resolve real symbol
virtual Dsymbol *toAlias2();
virtual void importAll(Scope *sc);
virtual bool overloadInsert(Dsymbol *s);
virtual uinteger_t size(const Loc &loc);
virtual bool isforwardRef();
@ -247,7 +247,6 @@ public:
virtual Visibility visible();
virtual Dsymbol *syntaxCopy(Dsymbol *s); // copy only syntax trees
virtual bool oneMember(Dsymbol **ps, Identifier *ident);
virtual void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
virtual bool hasPointers();
virtual bool hasStaticCtorOrDtor();
virtual void addObjcSymbols(ClassDeclarations *, ClassDeclarations *) { }
@ -336,7 +335,7 @@ private:
public:
ScopeDsymbol *syntaxCopy(Dsymbol *s) override;
virtual void importScope(Dsymbol *s, Visibility visibility);
virtual bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0);
virtual bool isPackageAccessible(Package *p, Visibility visibility, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all);
bool isforwardRef() override final;
static void multiplyDefined(const Loc &loc, Dsymbol *s1, Dsymbol *s2);
const char *kind() const override;
@ -427,6 +426,8 @@ public:
};
void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds);
Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, SearchOptFlags flags = (SearchOptFlags)SearchOpt::localsOnly);
bool checkDeprecated(Dsymbol *d, const Loc &loc, Scope *sc);
void setScope(Dsymbol *d, Scope *sc);
void importAll(Dsymbol *d, Scope *sc);
void setFieldOffset(Dsymbol *d, AggregateDeclaration *ad, FieldState& fieldState, bool isunion);

View file

@ -246,6 +246,20 @@ bool checkDeprecated(Dsymbol d, const ref Loc loc, Scope* sc)
return true;
}
/*********************************
* Check type to see if it is based on a deprecated symbol.
*/
private void checkDeprecated(Type type, const ref Loc loc, Scope* sc)
{
if (Dsymbol s = type.toDsymbol(sc))
{
s.checkDeprecated(loc, sc);
}
if (auto tn = type.nextOf())
tn.checkDeprecated(loc, sc);
}
// Returns true if a contract can appear without a function body.
package bool allowsContractWithoutBody(FuncDeclaration funcdecl)
{
@ -304,6 +318,128 @@ bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, Tem
return false;
}
/*************************************
* Find the `alias this` symbol of e's type.
* Params:
* sc = context
* e = expression forming the `this`
* gag = do not print errors, return `null` instead
* findOnly = don't do further processing like resolving properties,
* i.e. just return plain dotExp() result.
* Returns:
* Expression that is `e.aliasthis`
*/
Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false)
{
import dmd.typesem : dotExp;
for (AggregateDeclaration ad = isAggregate(e.type); ad;)
{
if (ad.aliasthis)
{
Loc loc = e.loc;
Type tthis = (e.op == EXP.type ? e.type : null);
const flags = cast(DotExpFlag) (DotExpFlag.noAliasThis | (gag * DotExpFlag.gag));
uint olderrors = gag ? global.startGagging() : 0;
e = dotExp(ad.type, sc, e, ad.aliasthis.ident, flags);
if (!e || findOnly)
return gag && global.endGagging(olderrors) ? null : e;
if (tthis && ad.aliasthis.sym.needThis())
{
if (auto ve = e.isVarExp())
{
if (auto fd = ve.var.isFuncDeclaration())
{
// https://issues.dlang.org/show_bug.cgi?id=13009
// Support better match for the overloaded alias this.
bool hasOverloads;
if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads))
{
if (!hasOverloads)
fd = f; // use exact match
e = new VarExp(loc, fd, hasOverloads);
e.type = f.type;
e = new CallExp(loc, e);
goto L1;
}
}
}
/* non-@property function is not called inside typeof(),
* so resolve it ahead.
*/
{
int save = sc.intypeof;
sc.intypeof = 1; // bypass "need this" error check
e = resolveProperties(sc, e);
sc.intypeof = save;
}
L1:
e = new TypeExp(loc, new TypeTypeof(loc, e));
e = e.expressionSemantic(sc);
}
e = resolveProperties(sc, e);
if (!gag)
ad.aliasthis.checkDeprecatedAliasThis(loc, sc);
else if (global.endGagging(olderrors))
e = null;
}
import dmd.dclass : ClassDeclaration;
auto cd = ad.isClassDeclaration();
if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
{
ad = cd.baseClass;
continue;
}
break;
}
return e;
}
/**
* Check if an `alias this` is deprecated
*
* Usually one would use `expression.checkDeprecated(scope, aliasthis)` to
* check if `expression` uses a deprecated `aliasthis`, but this calls
* `toPrettyChars` which lead to the following message:
* "Deprecation: alias this `fullyqualified.aggregate.__anonymous` is deprecated"
*
* Params:
* at = The `AliasThis` object to check
* loc = `Loc` of the expression triggering the access to `at`
* sc = `Scope` of the expression
* (deprecations do not trigger in deprecated scopes)
*
* Returns:
* Whether the alias this was reported as deprecated.
*/
private bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc)
{
if (global.params.useDeprecated != DiagnosticReporting.off
&& at.isDeprecated() && !sc.isDeprecated())
{
const(char)* message = null;
for (Dsymbol p = at; p; p = p.parent)
{
message = p.depdecl ? p.depdecl.getMessage() : null;
if (message)
break;
}
if (message)
deprecation(loc, "`alias %s this` is deprecated - %s",
at.sym.toChars(), message);
else
deprecation(loc, "`alias %s this` is deprecated",
at.sym.toChars());
if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
ti.printInstantiationTrace(Classification.deprecation);
return true;
}
return false;
}
private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
alias visit = Visitor.visit;
@ -359,7 +495,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
Dsymbol s = ad.search(dsym.loc, dsym.ident);
if (!s)
{
s = sc.search(dsym.loc, dsym.ident, null);
Dsymbol pscopesym;
s = sc.search(dsym.loc, dsym.ident, pscopesym);
if (s)
error(dsym.loc, "`%s` is not a member of `%s`", s.toChars(), ad.toChars());
else
@ -449,7 +586,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
printf(" type = %s\n", dsym.type ? dsym.type.toChars() : "null");
printf(" stc = x%llx\n", dsym.storage_class);
printf(" storage_class = x%llx\n", dsym.storage_class);
printf("linkage = %d\n", dsym.linkage);
printf("linkage = %d\n", dsym._linkage);
//if (strcmp(toChars(), "mul") == 0) assert(0);
}
//if (semanticRun > PASS.initial)
@ -1494,7 +1631,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
{
AliasDeclaration ad = imp.aliasdecls[i];
//printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i].toChars(), names[i].toChars(), ad._scope);
Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], IgnorePrivateImports);
Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], SearchOpt.ignorePrivateImports);
if (sym)
{
import dmd.access : symbolIsVisible;
@ -4121,7 +4258,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
// check if `_d_cmain` is defined
bool cmainTemplateExists()
{
auto rootSymbol = sc.search(funcdecl.loc, Id.empty, null);
Dsymbol pscopesym;
auto rootSymbol = sc.search(funcdecl.loc, Id.empty, pscopesym);
if (auto moduleSymbol = rootSymbol.search(funcdecl.loc, Id.object))
if (moduleSymbol.search(funcdecl.loc, Id.CMain))
return true;
@ -7206,7 +7344,7 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
AliasDeclaration findAliasDeclaration(AliasAssign ds, Scope* sc)
{
Dsymbol scopesym;
Dsymbol as = sc.search(ds.loc, ds.ident, &scopesym);
Dsymbol as = sc.search(ds.loc, ds.ident, scopesym);
if (!as)
{
.error(ds.loc, "%s `%s` undefined identifier `%s`", ds.kind, ds.toPrettyChars, ds.ident.toChars());
@ -7833,11 +7971,11 @@ void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope*
* d = dsymbol where ident is searched for
* loc = location to print for error messages
* ident = identifier to search for
* flags = IgnoreXXXX
* flags = search options
* Returns:
* null if not found
*/
extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, int flags = IgnoreNone)
extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, SearchOptFlags flags = SearchOpt.all)
{
scope v = new SearchVisitor(loc, ident, flags);
d.accept(v);
@ -7862,13 +8000,13 @@ Dsymbol search_correct(Dsymbol d, Identifier ident)
cost = 0; // all the same cost
Dsymbol s = d;
Module.clearCache();
return s.search(Loc.initial, id, IgnoreErrors);
return s.search(Loc.initial, id, SearchOpt.ignoreErrors);
}
if (global.gag)
return null; // don't do it for speculative compiles; too time consuming
// search for exact name first
if (auto s = d.search(Loc.initial, ident, IgnoreErrors))
if (auto s = d.search(Loc.initial, ident, SearchOpt.ignoreErrors))
return s;
import dmd.root.speller : speller;
@ -7881,10 +8019,10 @@ private extern(C++) class SearchVisitor : Visitor
const Loc loc;
Identifier ident;
int flags;
SearchOptFlags flags;
Dsymbol result;
this(const ref Loc loc, Identifier ident, int flags)
this(const ref Loc loc, Identifier ident, SearchOptFlags flags)
{
this.loc = loc;
this.ident = ident;
@ -7908,7 +8046,7 @@ private extern(C++) class SearchVisitor : Visitor
//if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0;
// Look in symbols declared in this module
if (sds.symtab && !(flags & SearchImportsOnly))
if (sds.symtab && !(flags & SearchOpt.importsOnly))
{
//printf(" look in locals\n");
auto s1 = sds.symtab.lookup(ident);
@ -7931,30 +8069,30 @@ private extern(C++) class SearchVisitor : Visitor
for (size_t i = 0; i < sds.importedScopes.length; i++)
{
// If private import, don't search it
if ((flags & IgnorePrivateImports) && sds.visibilities[i] == Visibility.Kind.private_)
if ((flags & SearchOpt.ignorePrivateImports) && sds.visibilities[i] == Visibility.Kind.private_)
continue;
int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches
SearchOptFlags sflags = flags & (SearchOpt.ignoreErrors | SearchOpt.ignoreAmbiguous); // remember these in recursive searches
Dsymbol ss = (*sds.importedScopes)[i];
//printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport());
if (ss.isModule())
{
if (flags & SearchLocalsOnly)
if (flags & SearchOpt.localsOnly)
continue;
}
else // mixin template
{
if (flags & SearchImportsOnly)
if (flags & SearchOpt.importsOnly)
continue;
sflags |= SearchLocalsOnly;
sflags |= SearchOpt.localsOnly;
}
/* Don't find private members if ss is a module
*/
Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone));
Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? SearchOpt.ignorePrivateImports : SearchOpt.all));
import dmd.access : symbolIsVisible;
if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(sds, s2))
if (!s2 || !(flags & SearchOpt.ignoreVisibility) && !symbolIsVisible(sds, s2))
continue;
if (!s)
{
@ -8025,7 +8163,7 @@ private extern(C++) class SearchVisitor : Visitor
}
}
if (flags & IgnoreAmbiguous) // if return NULL on ambiguity
if (flags & SearchOpt.ignoreAmbiguous) // if return NULL on ambiguity
return setResult(null);
/* If two imports from C import files, pick first one, as C has global name space
@ -8033,7 +8171,7 @@ private extern(C++) class SearchVisitor : Visitor
if (s.isCsymbol() && s2.isCsymbol())
continue;
if (!(flags & IgnoreErrors))
if (!(flags & SearchOpt.ignoreErrors))
ScopeDsymbol.multiplyDefined(loc, s, s2);
break;
}
@ -8060,7 +8198,7 @@ private extern(C++) class SearchVisitor : Visitor
override void visit(WithScopeSymbol ws)
{
//printf("WithScopeSymbol.search(%s)\n", ident.toChars());
if (flags & SearchImportsOnly)
if (flags & SearchOpt.importsOnly)
return setResult(null);
// Acts as proxy to the with class declaration
Dsymbol s = null;
@ -8301,7 +8439,7 @@ private extern(C++) class SearchVisitor : Visitor
if (!ns.members || !ns.symtab) // opaque or semantic() is not yet called
{
if (!(flags & IgnoreErrors))
if (!(flags & SearchOpt.ignoreErrors))
.error(loc, "%s `%s` is forward referenced when looking for `%s`", ns.kind, ns.toPrettyChars, ident.toChars());
return setResult(null);
}
@ -8324,7 +8462,7 @@ private extern(C++) class SearchVisitor : Visitor
override void visit(Package pkg)
{
//printf("%s Package.search('%s', flags = x%x)\n", pkg.toChars(), ident.toChars(), flags);
flags &= ~SearchLocalsOnly; // searching an import is always transitive
flags &= ~cast(int)SearchOpt.localsOnly; // searching an import is always transitive
if (!pkg.isModule() && pkg.mod)
{
// Prefer full package name.
@ -8351,8 +8489,8 @@ private extern(C++) class SearchVisitor : Visitor
/* Qualified module searches always search their imports,
* even if SearchLocalsOnly
*/
if (!(flags & SearchUnqualifiedModule))
flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly);
if (!(flags & SearchOpt.unqualifiedModule))
flags &= ~(SearchOpt.unqualifiedModule | SearchOpt.localsOnly);
if (m.searchCacheIdent == ident && m.searchCacheFlags == flags)
{
@ -8401,7 +8539,7 @@ private extern(C++) class SearchVisitor : Visitor
if (!sd.members || !sd.symtab) // opaque or semantic() is not yet called
{
// .stringof is always defined (but may be hidden by some other symbol)
if(ident != Id.stringof && !(flags & IgnoreErrors) && sd.semanticRun < PASS.semanticdone)
if(ident != Id.stringof && !(flags & SearchOpt.ignoreErrors) && sd.semanticRun < PASS.semanticdone)
.error(loc, "%s `%s` is forward referenced when looking for `%s`", sd.kind, sd.toPrettyChars, ident.toChars());
return setResult(null);
}
@ -8427,7 +8565,7 @@ private extern(C++) class SearchVisitor : Visitor
if (!cd.members || !cd.symtab) // opaque or addMember is not yet done
{
// .stringof is always defined (but may be hidden by some other symbol)
if (ident != Id.stringof && !(flags & IgnoreErrors) && cd.semanticRun < PASS.semanticdone)
if (ident != Id.stringof && !(flags & SearchOpt.ignoreErrors) && cd.semanticRun < PASS.semanticdone)
cd.classError("%s `%s` is forward referenced when looking for `%s`", ident.toChars());
//*(char*)0=0;
return setResult(null);
@ -8437,7 +8575,7 @@ private extern(C++) class SearchVisitor : Visitor
auto s = result;
// don't search imports of base classes
if (flags & SearchImportsOnly)
if (flags & SearchOpt.importsOnly)
return setResult(s);
if (s)
@ -8462,7 +8600,7 @@ private extern(C++) class SearchVisitor : Visitor
continue;
else if (s == cd) // happens if s is nested in this and derives from this
s = null;
else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(cd, s))
else if (!(flags & SearchOpt.ignoreVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(cd, s))
s = null;
else
break;
@ -8621,3 +8759,554 @@ private extern(C++) class SetScopeVisitor : Visitor
visit(cast(AttribDeclaration)uad);
}
}
extern(C++) void importAll(Dsymbol d, Scope* sc)
{
scope iav = new ImportAllVisitor(sc);
d.accept(iav);
}
extern(C++) class ImportAllVisitor : Visitor
{
alias visit = typeof(super).visit;
Scope* sc;
this(Scope* sc)
{
this.sc = sc;
}
override void visit(Dsymbol d) {}
override void visit(Import imp)
{
if (imp.mod) return; // Already done
/*
* https://issues.dlang.org/show_bug.cgi?id=15525
*
* Loading the import has failed,
* most likely because of parsing errors.
* Therefore we cannot trust the resulting AST.
*/
if (imp.load(sc))
{
// https://issues.dlang.org/show_bug.cgi?id=23873
// For imports that are not at module or function level,
// e.g. aggregate level, the import symbol is added to the
// symbol table and later semantic is performed on it.
// This leads to semantic analysis on an malformed AST
// which causes all kinds of segfaults.
// The fix is to note that the module has errors and avoid
// semantic analysis on it.
if(imp.mod)
imp.mod.errors = true;
return;
}
if (!imp.mod) return; // Failed
if (sc.stc & STC.static_)
imp.isstatic = true;
imp.mod.importAll(null);
imp.mod.checkImportDeprecation(imp.loc, sc);
if (sc.explicitVisibility)
imp.visibility = sc.visibility;
if (!imp.isstatic && !imp.aliasId && !imp.names.length)
sc.scopesym.importScope(imp.mod, imp.visibility);
// Enable access to pkgs/mod as soon as posible, because compiler
// can traverse them before the import gets semantic (Issue: 21501)
if (!imp.aliasId && !imp.names.length)
imp.addPackageAccess(sc.scopesym);
}
override void visit(Module m)
{
//printf("+Module::importAll(this = %p, '%s'): parent = %p\n", m, m.toChars(), m.parent);
if (m._scope)
return; // already done
if (m.filetype == FileType.ddoc)
{
error(m.loc, "%s `%s` is a Ddoc file, cannot import it", m.kind, m.toPrettyChars);
return;
}
/* Note that modules get their own scope, from scratch.
* This is so regardless of where in the syntax a module
* gets imported, it is unaffected by context.
* Ignore prevsc.
*/
Scope* sc = Scope.createGlobal(m, global.errorSink); // create root scope
if (m.md && m.md.msg)
m.md.msg = semanticString(sc, m.md.msg, "deprecation message");
// Add import of "object", even for the "object" module.
// If it isn't there, some compiler rewrites, like
// classinst == classinst -> .object.opEquals(classinst, classinst)
// would fail inside object.d.
if (m.filetype != FileType.c &&
(m.members.length == 0 ||
(*m.members)[0].ident != Id.object ||
(*m.members)[0].isImport() is null))
{
auto im = new Import(Loc.initial, null, Id.object, null, 0);
m.members.shift(im);
}
if (!m.symtab)
{
// Add all symbols into module's symbol table
m.symtab = new DsymbolTable();
for (size_t i = 0; i < m.members.length; i++)
{
Dsymbol s = (*m.members)[i];
s.addMember(sc, sc.scopesym);
}
}
// anything else should be run after addMember, so version/debug symbols are defined
/* Set scope for the symbols so that if we forward reference
* a symbol, it can possibly be resolved on the spot.
* If this works out well, it can be extended to all modules
* before any semantic() on any of them.
*/
m.setScope(sc); // remember module scope for semantic
for (size_t i = 0; i < m.members.length; i++)
{
Dsymbol s = (*m.members)[i];
s.setScope(sc);
}
for (size_t i = 0; i < m.members.length; i++)
{
Dsymbol s = (*m.members)[i];
s.importAll(sc);
}
sc = sc.pop();
sc.pop(); // 2 pops because Scope.createGlobal() created 2
}
override void visit(AttribDeclaration atb)
{
Dsymbols* d = atb.include(sc);
//printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d);
if (d)
{
Scope* sc2 = atb.newScope(sc);
d.foreachDsymbol( s => s.importAll(sc2) );
if (sc2 != sc)
sc2.pop();
}
}
// do not evaluate condition before semantic pass
override void visit(StaticIfDeclaration _) {}
// do not evaluate aggregate before semantic pass
override void visit(StaticForeachDeclaration _) {}
}
extern(C++) void setFieldOffset(Dsymbol d, AggregateDeclaration ad, FieldState* fieldState, bool isunion)
{
scope v = new SetFieldOffsetVisitor(ad, fieldState, isunion);
d.accept(v);
}
private extern(C++) class SetFieldOffsetVisitor : Visitor
{
alias visit = Visitor.visit;
AggregateDeclaration ad;
FieldState* fieldState;
bool isunion;
this(AggregateDeclaration ad, FieldState* fieldState, bool isunion)
{
this.ad = ad;
this.fieldState = fieldState;
this.isunion = isunion;
}
override void visit(Dsymbol d) {}
override void visit(Nspace ns)
{
//printf("Nspace::setFieldOffset() %s\n", toChars());
if (ns._scope) // if fwd reference
dsymbolSemantic(ns, null); // try to resolve it
ns.members.foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
}
override void visit(VarDeclaration vd)
{
//printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), vd.toChars());
if (vd.aliasTuple)
{
// If this variable was really a tuple, set the offsets for the tuple fields
vd.aliasTuple.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); });
return;
}
if (!vd.isField())
return;
assert(!(vd.storage_class & (STC.static_ | STC.extern_ | STC.parameter)));
//printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
/* Fields that are tuples appear both as part of TupleDeclarations and
* as members. That means ignore them if they are already a field.
*/
if (vd.offset)
{
// already a field
fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613
return;
}
for (size_t i = 0; i < ad.fields.length; i++)
{
if (ad.fields[i] == vd)
{
// already a field
fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613
return;
}
}
// Check for forward referenced types which will fail the size() call
Type t = vd.type.toBasetype();
if (vd.storage_class & STC.ref_)
{
// References are the size of a pointer
t = Type.tvoidptr;
}
Type tv = t.baseElemOf();
if (tv.ty == Tstruct)
{
auto ts = cast(TypeStruct)tv;
assert(ts.sym != ad); // already checked in ad.determineFields()
if (!ts.sym.determineSize(vd.loc))
{
vd.type = Type.terror;
vd.errors = true;
return;
}
}
// List in ad.fields. Even if the type is error, it's necessary to avoid
// pointless error diagnostic "more initializers than fields" on struct literal.
ad.fields.push(vd);
if (t.ty == Terror)
return;
/* If coming after a bit field in progress,
* advance past the field
*/
fieldState.inFlight = false;
const sz = t.size(vd.loc);
assert(sz != SIZE_INVALID && sz < uint.max);
uint memsize = cast(uint)sz; // size of member
uint memalignsize = target.fieldalign(t); // size of member for alignment purposes
vd.offset = placeField(
fieldState.offset,
memsize, memalignsize, vd.alignment,
ad.structsize, ad.alignsize,
isunion);
//printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
//printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
}
override void visit(BitFieldDeclaration bfd)
{
enum log = false;
static if (log)
{
printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), bfd.toChars());
void print(const FieldState* fieldState)
{
fieldState.print();
printf(" fieldWidth = %d bits\n", bfd.fieldWidth);
}
print(fieldState);
}
Type t = bfd.type.toBasetype();
const bool anon = bfd.isAnonymous();
// List in ad.fields. Even if the type is error, it's necessary to avoid
// pointless error diagnostic "more initializers than fields" on struct literal.
if (!anon)
ad.fields.push(bfd);
if (t.ty == Terror)
return;
const sz = t.size(bfd.loc);
assert(sz != SIZE_INVALID && sz < uint.max);
uint memsize = cast(uint)sz; // size of member
uint memalignsize = target.fieldalign(t); // size of member for alignment purposes
if (log) printf(" memsize: %u memalignsize: %u\n", memsize, memalignsize);
if (bfd.fieldWidth == 0 && !anon)
error(bfd.loc, "named bit fields cannot have 0 width");
if (bfd.fieldWidth > memsize * 8)
error(bfd.loc, "bit field width %d is larger than type", bfd.fieldWidth);
const style = target.c.bitFieldStyle;
void startNewField()
{
if (log) printf("startNewField()\n");
uint alignsize;
if (style == TargetC.BitFieldStyle.Gcc_Clang)
{
if (bfd.fieldWidth > 32)
alignsize = memalignsize;
else if (bfd.fieldWidth > 16)
alignsize = 4;
else if (bfd.fieldWidth > 8)
alignsize = 2;
else
alignsize = 1;
}
else
alignsize = memsize; // not memalignsize
uint dummy;
bfd.offset = placeField(
fieldState.offset,
memsize, alignsize, bfd.alignment,
ad.structsize,
(anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize,
isunion);
fieldState.inFlight = true;
fieldState.fieldOffset = bfd.offset;
fieldState.bitOffset = 0;
fieldState.fieldSize = memsize;
}
if (style == TargetC.BitFieldStyle.Gcc_Clang)
{
if (bfd.fieldWidth == 0)
{
if (!isunion)
{
// Use type of zero width field to align to next field
fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1);
ad.structsize = fieldState.offset;
}
fieldState.inFlight = false;
return;
}
if (ad.alignsize == 0)
ad.alignsize = 1;
if (!anon &&
ad.alignsize < memalignsize)
ad.alignsize = memalignsize;
}
else if (style == TargetC.BitFieldStyle.MS)
{
if (ad.alignsize == 0)
ad.alignsize = 1;
if (bfd.fieldWidth == 0)
{
if (fieldState.inFlight && !isunion)
{
// documentation says align to next int
//const alsz = cast(uint)Type.tint32.size();
const alsz = memsize; // but it really does this
fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
ad.structsize = fieldState.offset;
}
fieldState.inFlight = false;
return;
}
}
else if (style == TargetC.BitFieldStyle.DM)
{
if (anon && bfd.fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0))
return; // this probably should be a bug in DMC
if (ad.alignsize == 0)
ad.alignsize = 1;
if (bfd.fieldWidth == 0)
{
if (fieldState.inFlight && !isunion)
{
const alsz = memsize;
fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
ad.structsize = fieldState.offset;
}
fieldState.inFlight = false;
return;
}
}
if (!fieldState.inFlight)
{
//printf("not in flight\n");
startNewField();
}
else if (style == TargetC.BitFieldStyle.Gcc_Clang)
{
// If the bit-field spans more units of alignment than its type,
// start a new field at the next alignment boundary.
if (fieldState.bitOffset == fieldState.fieldSize * 8 &&
fieldState.bitOffset + bfd.fieldWidth > memalignsize * 8)
{
if (log) printf("more units of alignment than its type\n");
startNewField(); // the bit field is full
}
else
{
// if alignment boundary is crossed
uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset;
uint end = start + bfd.fieldWidth;
//printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
{
if (log) printf("alignment is crossed\n");
startNewField();
}
}
}
else if (style == TargetC.BitFieldStyle.DM ||
style == TargetC.BitFieldStyle.MS)
{
if (memsize != fieldState.fieldSize ||
fieldState.bitOffset + bfd.fieldWidth > fieldState.fieldSize * 8)
{
//printf("new field\n");
startNewField();
}
}
else
assert(0);
bfd.offset = fieldState.fieldOffset;
bfd.bitOffset = fieldState.bitOffset;
const pastField = bfd.bitOffset + bfd.fieldWidth;
if (style == TargetC.BitFieldStyle.Gcc_Clang)
{
auto size = (pastField + 7) / 8;
fieldState.fieldSize = size;
//printf(" offset: %d, size: %d\n", offset, size);
if (isunion)
{
const newstructsize = bfd.offset + size;
if (newstructsize > ad.structsize)
ad.structsize = newstructsize;
}
else
ad.structsize = bfd.offset + size;
}
else
fieldState.fieldSize = memsize;
//printf("at end: ad.structsize = %d\n", cast(int)ad.structsize);
//print(fieldState);
if (!isunion)
{
fieldState.offset = bfd.offset + fieldState.fieldSize;
fieldState.bitOffset = pastField;
}
//printf("\t%s: offset = %d bitOffset = %d fieldWidth = %d memsize = %d\n", toChars(), offset, bitOffset, fieldWidth, memsize);
//printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
//printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
}
override void visit(TemplateMixin tm)
{
//printf("TemplateMixin.setFieldOffset() %s\n", tm.toChars());
if (tm._scope) // if fwd reference
dsymbolSemantic(tm, null); // try to resolve it
tm.members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } );
}
override void visit(AttribDeclaration atd)
{
atd.include(null).foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
}
override void visit(AnonDeclaration anond)
{
//printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", anond);
if (anond.decl)
{
/* This works by treating an AnonDeclaration as an aggregate 'member',
* so in order to place that member we need to compute the member's
* size and alignment.
*/
size_t fieldstart = ad.fields.length;
/* Hackishly hijack ad's structsize and alignsize fields
* for use in our fake anon aggregate member.
*/
uint savestructsize = ad.structsize;
uint savealignsize = ad.alignsize;
ad.structsize = 0;
ad.alignsize = 0;
FieldState fs;
anond.decl.foreachDsymbol( (s)
{
s.setFieldOffset(ad, &fs, anond.isunion);
if (anond.isunion)
fs.offset = 0;
});
/* https://issues.dlang.org/show_bug.cgi?id=13613
* If the fields in this.members had been already
* added in ad.fields, just update *poffset for the subsequent
* field offset calculation.
*/
if (fieldstart == ad.fields.length)
{
ad.structsize = savestructsize;
ad.alignsize = savealignsize;
fieldState.offset = ad.structsize;
return;
}
anond.anonstructsize = ad.structsize;
anond.anonalignsize = ad.alignsize;
ad.structsize = savestructsize;
ad.alignsize = savealignsize;
// 0 sized structs are set to 1 byte
if (anond.anonstructsize == 0)
{
anond.anonstructsize = 1;
anond.anonalignsize = 1;
}
assert(anond._scope);
auto alignment = anond._scope.alignment();
/* Given the anon 'member's size and alignment,
* go ahead and place it.
*/
anond.anonoffset = placeField(
fieldState.offset,
anond.anonstructsize, anond.anonalignsize, alignment,
ad.structsize, ad.alignsize,
isunion);
// Add to the anon fields the base offset of this anonymous aggregate
//printf("anon fields, anonoffset = %d\n", anonoffset);
foreach (const i; fieldstart .. ad.fields.length)
{
VarDeclaration v = ad.fields[i];
//printf("\t[%d] %s %d\n", i, v.toChars(), v.offset);
v.offset += anond.anonoffset;
}
}
}
}

View file

@ -6465,7 +6465,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
*/
Identifier id = name;
Dsymbol scopesym;
Dsymbol s = sc.search(loc, id, &scopesym);
Dsymbol s = sc.search(loc, id, scopesym);
if (!s)
{
s = sc.search_correct(id);
@ -7831,15 +7831,6 @@ extern (C++) final class TemplateMixin : TemplateInstance
return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
}
override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
{
//printf("TemplateMixin.setFieldOffset() %s\n", toChars());
if (_scope) // if fwd reference
dsymbolSemantic(this, null); // try to resolve it
members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } );
}
override const(char)* toChars() const
{
OutBuffer buf;

View file

@ -3284,7 +3284,7 @@ ASTCodegen.Dsymbol symbolFromType(ASTCodegen.Type t) @safe
*/
ASTCodegen.Dsymbol findMember(ASTCodegen.Dsymbol sym, Identifier name)
{
if (auto mem = sym.search(Loc.initial, name, ASTCodegen.IgnoreErrors))
if (auto mem = sym.search(Loc.initial, name, ASTCodegen.SearchOpt.ignoreErrors))
return mem;
// search doesn't work for declarations inside of uninstantiated

View file

@ -60,6 +60,20 @@ class ErrorSinkNull : ErrorSink
void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { }
}
/*****************************************
* Ignores the messages, but sets `sawErrors` for any calls to `error()`
*/
class ErrorSinkLatch : ErrorSinkNull
{
nothrow:
extern (C++):
override:
bool sawErrors;
void error(const ref Loc loc, const(char)* format, ...) { sawErrors = true; }
}
/*****************************************
* Simplest implementation, just sends messages to stderr.
* See also: ErrorSinkCompiler.

View file

@ -21,7 +21,6 @@ import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
import dmd.gluelayer;
import dmd.dclass;
import dmd.declaration;
import dmd.dimport;
@ -2240,7 +2239,7 @@ extern (C++) final class StructLiteralExp : Expression
// while `sym` is only used in `e2ir/s2ir/tocsym` which comes after
union
{
Symbol* sym; /// back end symbol to initialize with literal
void* sym; /// back end symbol to initialize with literal (used as a Symbol*)
/// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
StructLiteralExp inlinecopy;

View file

@ -875,7 +875,7 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
Loc loc = ue.loc;
// TODO: merge with Scope.search.searchScopes()
Dsymbol searchScopes(int flags)
Dsymbol searchScopes(SearchOptFlags flags)
{
Dsymbol s = null;
for (Scope* scx = sc; scx; scx = scx.enclosing)
@ -883,7 +883,7 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
if (!scx.scopesym)
continue;
if (scx.scopesym.isModule())
flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
flags |= SearchOpt.unqualifiedModule; // tell Module.search() that SearchOpt.localsOnly is to be obeyed
s = scx.scopesym.search(loc, ident, flags);
if (s)
{
@ -910,18 +910,18 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
return s;
}
int flags = 0;
SearchOptFlags flags = SearchOpt.all;
Dsymbol s;
if (sc.flags & SCOPE.ignoresymbolvisibility)
flags |= IgnoreSymbolVisibility;
flags |= SearchOpt.ignoreVisibility;
// First look in local scopes
s = searchScopes(flags | SearchLocalsOnly);
s = searchScopes(flags | SearchOpt.localsOnly);
if (!s)
{
// Second look in imported modules
s = searchScopes(flags | SearchImportsOnly);
s = searchScopes(flags | SearchOpt.importsOnly);
}
if (!s)
@ -3743,7 +3743,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
Dsymbol scopesym;
Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym);
Dsymbol s = sc.search(exp.loc, exp.ident, scopesym);
if (s)
{
if (s.errors)
@ -6744,7 +6744,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (!sc.insert(s))
{
auto conflict = sc.search(Loc.initial, s.ident, null);
Dsymbol pscopesym;
auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
conflict.kind(), conflict.toChars());
@ -6986,7 +6987,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
if (!tup && !sc.insert(s))
{
auto conflict = sc.search(Loc.initial, s.ident, null);
Dsymbol pscopesym;
auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
conflict.kind(), conflict.toChars());
@ -7293,7 +7295,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
s.dsymbolSemantic(sc);
if (!sc.insert(s))
{
auto conflict = sc.search(Loc.initial, s.ident, null);
Dsymbol pscopesym;
auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
conflict.kind(), conflict.toChars());
@ -14208,15 +14211,15 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
if (auto ie = eright.isScopeExp()) // also used for template alias's
{
auto flags = SearchLocalsOnly;
SearchOptFlags flags = SearchOpt.localsOnly;
/* Disable access to another module's private imports.
* The check for 'is sds our current module' is because
* the current module should have access to its own imports.
*/
if (ie.sds.isModule() && ie.sds != sc._module)
flags |= IgnorePrivateImports;
flags |= SearchOpt.ignorePrivateImports;
if (sc.flags & SCOPE.ignoresymbolvisibility)
flags |= IgnoreSymbolVisibility;
flags |= SearchOpt.ignoreVisibility;
Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags);
/* Check for visibility before resolving aliases because public
* aliases to private symbols are public.
@ -16038,7 +16041,8 @@ VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration f
*/
bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object)
{
auto rootSymbol = sc.search(loc, Id.empty, null);
Dsymbol pscopesym;
auto rootSymbol = sc.search(loc, Id.empty, pscopesym);
if (auto moduleSymbol = rootSymbol.search(loc, module_))
if (moduleSymbol.search(loc, id))
return true;

View file

@ -695,6 +695,7 @@ extern (C++) class FuncDeclaration : Declaration
int result = 0;
if (fd.ident == ident)
{
import dmd.typesem : covariant;
const cov = type.covariant(fd.type);
if (cov != Covariant.distinct)
{
@ -721,6 +722,8 @@ extern (C++) class FuncDeclaration : Declaration
final int findVtblIndex(Dsymbols* vtbl, int dim)
{
//printf("findVtblIndex() %s\n", toChars());
import dmd.typesem : covariant;
FuncDeclaration mismatch = null;
StorageClass mismatchstc = 0;
int mismatchvi = -1;
@ -947,6 +950,7 @@ extern (C++) class FuncDeclaration : Declaration
*/
if (t.ty == Tfunction)
{
import dmd.typesem : covariant;
auto tf = cast(TypeFunction)f.type;
if (tf.covariant(t) == Covariant.yes &&
tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
@ -1157,6 +1161,7 @@ extern (C++) class FuncDeclaration : Declaration
args.push(e);
}
import dmd.typesem : callMatch;
MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1);
if (m > MATCH.nomatch)
{

View file

@ -167,7 +167,7 @@ extern (C++) struct Param
bool cov; // generate code coverage data
ubyte covPercent; // 0..100 code coverage percentage required
bool ctfe_cov = false; // generate coverage data for ctfe
bool ignoreUnsupportedPragmas; // rather than error on them
bool ignoreUnsupportedPragmas = true; // rather than error on them
bool useModuleInfo = true; // generate runtime module information
bool useTypeInfo = true; // generate runtime type information
bool useExceptions = true; // support exception handling

View file

@ -41,7 +41,6 @@ public:
const char *kind() const override;
Visibility visible() override;
Import *syntaxCopy(Dsymbol *s) override; // copy only syntax trees
void importAll(Scope *sc) override;
Dsymbol *toAlias() override;
bool overloadInsert(Dsymbol *s) override;

View file

@ -12,21 +12,15 @@
module dmd.init;
import core.stdc.stdio;
import core.checkedint;
import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
import dmd.dsymbol;
import dmd.expression;
import dmd.globals;
import dmd.hdrgen;
import dmd.identifier;
import dmd.location;
import dmd.mtype;
import dmd.common.outbuffer;
import dmd.rootobject;
import dmd.tokens;
import dmd.visitor;
enum NeedInterpret : int

View file

@ -606,7 +606,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
{
import dmd.common.outbuffer;
OutBuffer buf;
HdrGenStage hgs;
HdrGenState hgs;
toCBuffer(ts.sym, buf, hgs);
printf("%s\n", buf.peekChars());
}
@ -803,9 +803,6 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
Loop1:
for (size_t index = 0; index < ci.initializerList.length; )
{
CInitializer cprev;
size_t indexprev;
L1:
DesigInit di = ci.initializerList[index];
Designators* dlist = di.designatorList;
if (dlist)
@ -833,15 +830,6 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
continue Loop1;
}
}
if (cprev)
{
/* The peeling didn't work, so unpeel it
*/
ci = cprev;
index = indexprev;
di = ci.initializerList[index];
goto L2;
}
error(ci.loc, "`.%s` is not a field of `%s`\n", id.toChars(), sd.toChars());
return err();
}
@ -849,18 +837,55 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
{
if (fieldi == nfields)
break;
if (/*index == 0 && ci.initializerList.length == 1 &&*/ di.initializer.isCInitializer())
auto ix = di.initializer;
/* If a C initializer is wrapped in a C initializer, with no designators,
* peel off the outer one
*/
if (ix.isCInitializer())
{
/* Try peeling off this set of { } and see if it works
*/
cprev = ci;
ci = di.initializer.isCInitializer();
indexprev = index;
index = 0;
goto L1;
CInitializer cix = ix.isCInitializer();
if (cix.initializerList.length == 1)
{
DesigInit dix = cix.initializerList[0];
if (!dix.designatorList)
{
Initializer inix = dix.initializer;
if (inix.isCInitializer())
ix = inix;
}
}
}
if (auto cix = ix.isCInitializer())
{
/* ImportC loses the structure from anonymous structs, but this is retained
* by the initializer syntax. if a CInitializer has a Designator, it is probably
* a nested anonymous struct
*/
if (cix.initializerList.length)
{
DesigInit dix = cix.initializerList[0];
Designators* dlistx = dix.designatorList;
if (dlistx && (*dlistx).length == 1 && (*dlistx)[0].ident)
{
auto id = (*dlistx)[0].ident;
foreach (k, f; sd.fields[]) // linear search for now
{
if (f.ident == id)
{
fieldi = k;
si.addInit(id, dix.initializer);
++fieldi;
++index;
continue Loop1;
}
}
}
}
}
L2:
VarDeclaration field;
while (1) // skip field if it overlaps with previously seen fields
{
@ -871,10 +896,11 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
if (fieldi == nfields)
break;
}
auto tn = field.type.toBasetype();
auto tnsa = tn.isTypeSArray();
auto tns = tn.isTypeStruct();
auto ix = di.initializer;
if (tnsa && ix.isExpInitializer())
{
ExpInitializer ei = ix.isExpInitializer();
@ -1013,7 +1039,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
}
else
{
error(ci.loc, "unrecognized C initializer `%s`", toChars(ci));
error(ci.loc, "unrecognized C initializer `%s` for type `%s`", toChars(ci), t.toChars());
return err();
}
}
@ -1548,6 +1574,11 @@ Expressions* resolveStructLiteralNamedArgs(StructDeclaration sd, Type t, Scope*
cast(int) nfields, nfields != 1 ? "s".ptr : "".ptr);
return null;
}
if (fieldi >= nfields)
{
error(argLoc, "trying to initialize past the last field `%s` of `%s`", sd.fields[nfields - 1].toChars(), sd.toChars());
return null;
}
VarDeclaration vd = sd.fields[fieldi];
if (elems[fieldi])

View file

@ -244,7 +244,7 @@ public:
{
// we must check what the identifier expression is.
Dsymbol scopesym;
Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym);
Dsymbol s = sc.search(exp.loc, exp.ident, scopesym);
if (s)
{
auto v = s.isVarDeclaration();

View file

@ -2008,23 +2008,17 @@ class Lexer
case 'u':
dchar d1;
size_t idx;
auto msg = utf_decodeChar(str, idx, d1);
dchar d2 = 0;
if (idx < n && !msg)
msg = utf_decodeChar(str, idx, d2);
if (msg)
error(loc, "%.*s", cast(int)msg.length, msg.ptr);
else if (idx < n)
error(loc, "max number of chars in 16 bit character literal is 2, had %d",
cast(int)((n + 1) >> 1));
else if (d1 > 0x1_0000)
error(loc, "%d does not fit in 16 bits", d1);
else if (d2 > 0x1_0000)
error(loc, "%d does not fit in 16 bits", d2);
u = d1;
if (d2)
u = (d1 << 16) | d2;
break;
while (idx < n)
{
string msg = utf_decodeChar(str, idx, d1);
if (msg)
error(loc, "%.*s", cast(int)msg.length, msg.ptr);
}
if (d1 >= 0x1_0000)
error(loc, "x%x does not fit in 16 bits", d1);
t.unsvalue = d1;
t.value = TOK.wcharLiteral; // C11 6.4.4.4-9
return;
case 'U':
dchar d;
@ -2035,8 +2029,9 @@ class Lexer
else if (idx < n)
error(loc, "max number of chars in 32 bit character literal is 1, had %d",
cast(int)((n + 3) >> 2));
u = d;
break;
t.unsvalue = d;
t.value = TOK.dcharLiteral; // C11 6.4.4.4-9
return;
default:
assert(0);
@ -3270,7 +3265,7 @@ class Lexer
while (1)
{
printf("%s ", (*tk).toChars());
if (tk.value == TOK.endOfFile)
if (tk.value == TOK.endOfFile || tk.value == TOK.endOfLine)
break;
tk = peek(tk);
}

View file

@ -88,7 +88,7 @@ public:
Identifier *searchCacheIdent;
Dsymbol *searchCacheSymbol; // cached value of search
int searchCacheFlags; // cached flags
SearchOptFlags searchCacheFlags; // cached flags
d_bool insearch;
// module from command line we're imported from,
@ -121,9 +121,8 @@ public:
const char *kind() const override;
bool read(const Loc &loc); // read file, returns 'true' if succeed, 'false' otherwise.
Module *parse(); // syntactic parse
void importAll(Scope *sc) override;
int needModuleInfo();
bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0) override;
bool isPackageAccessible(Package *p, Visibility visibility, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all) override;
Dsymbol *symtabInsert(Dsymbol *s) override;
static void runDeferredSemantic();
static void runDeferredSemantic2();

View file

@ -19,7 +19,6 @@ import core.stdc.string;
import dmd.aggregate;
import dmd.arraytypes;
import dmd.attrib;
import dmd.astenums;
import dmd.ast_node;
import dmd.gluelayer;
@ -35,7 +34,6 @@ import dmd.dsymbolsem;
import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
import dmd.globals;
import dmd.hdrgen;
@ -522,262 +520,6 @@ extern (C++) abstract class Type : ASTNode
return mcache;
}
/*******************************
* Covariant means that 'this' can substitute for 't',
* i.e. a pure function is a match for an impure type.
* Params:
* t = type 'this' is covariant with
* pstc = if not null, store STCxxxx which would make it covariant
* cppCovariant = true if extern(C++) function types should follow C++ covariant rules
* Returns:
* An enum value of either `Covariant.yes` or a reason it's not covariant.
*/
final Covariant covariant(Type t, StorageClass* pstc = null, bool cppCovariant = false)
{
version (none)
{
printf("Type::covariant(t = %s) %s\n", t.toChars(), toChars());
printf("deco = %p, %p\n", deco, t.deco);
// printf("ty = %d\n", next.ty);
printf("mod = %x, %x\n", mod, t.mod);
}
if (pstc)
*pstc = 0;
StorageClass stc = 0;
bool notcovariant = false;
if (equals(t))
return Covariant.yes;
TypeFunction t1 = this.isTypeFunction();
TypeFunction t2 = t.isTypeFunction();
if (!t1 || !t2)
goto Ldistinct;
if (t1.parameterList.varargs != t2.parameterList.varargs)
goto Ldistinct;
if (t1.parameterList.parameters && t2.parameterList.parameters)
{
if (t1.parameterList.length != t2.parameterList.length)
goto Ldistinct;
foreach (i, fparam1; t1.parameterList)
{
Parameter fparam2 = t2.parameterList[i];
Type tp1 = fparam1.type;
Type tp2 = fparam2.type;
if (!tp1.equals(tp2))
{
if (tp1.ty == tp2.ty)
{
if (auto tc1 = tp1.isTypeClass())
{
if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
goto Lcov;
}
else if (auto ts1 = tp1.isTypeStruct())
{
if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
goto Lcov;
}
else if (tp1.ty == Tpointer)
{
if (tp2.implicitConvTo(tp1))
goto Lcov;
}
else if (tp1.ty == Tarray)
{
if (tp2.implicitConvTo(tp1))
goto Lcov;
}
else if (tp1.ty == Tdelegate)
{
if (tp2.implicitConvTo(tp1))
goto Lcov;
}
}
goto Ldistinct;
}
Lcov:
notcovariant |= !fparam1.isCovariant(t1.isref, fparam2);
/* https://issues.dlang.org/show_bug.cgi?id=23135
* extern(C++) mutable parameters are not covariant with const.
*/
if (t1.linkage == LINK.cpp && cppCovariant)
{
notcovariant |= tp1.isNaked() != tp2.isNaked();
if (auto tpn1 = tp1.nextOf())
notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked();
}
}
}
else if (t1.parameterList.parameters != t2.parameterList.parameters)
{
if (t1.parameterList.length || t2.parameterList.length)
goto Ldistinct;
}
// The argument lists match
if (notcovariant)
goto Lnotcovariant;
if (t1.linkage != t2.linkage)
goto Lnotcovariant;
{
// Return types
Type t1n = t1.next;
Type t2n = t2.next;
if (!t1n || !t2n) // happens with return type inference
goto Lnotcovariant;
if (t1n.equals(t2n))
goto Lcovariant;
if (t1n.ty == Tclass && t2n.ty == Tclass)
{
/* If same class type, but t2n is const, then it's
* covariant. Do this test first because it can work on
* forward references.
*/
if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
goto Lcovariant;
// If t1n is forward referenced:
ClassDeclaration cd = (cast(TypeClass)t1n).sym;
if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
cd.dsymbolSemantic(null);
if (!cd.isBaseInfoComplete())
{
return Covariant.fwdref;
}
}
if (t1n.ty == Tstruct && t2n.ty == Tstruct)
{
if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
goto Lcovariant;
}
else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n))
{
if (t1.isref && t2.isref)
{
// Treat like pointers to t1n and t2n
if (t1n.constConv(t2n) < MATCH.constant)
goto Lnotcovariant;
}
goto Lcovariant;
}
else if (t1n.ty == Tnull)
{
// NULL is covariant with any pointer type, but not with any
// dynamic arrays, associative arrays or delegates.
// https://issues.dlang.org/show_bug.cgi?id=8589
// https://issues.dlang.org/show_bug.cgi?id=19618
Type t2bn = t2n.toBasetype();
if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass)
goto Lcovariant;
}
// bottom type is covariant to any type
else if (t1n.ty == Tnoreturn)
goto Lcovariant;
}
goto Lnotcovariant;
Lcovariant:
if (t1.isref != t2.isref)
goto Lnotcovariant;
if (!t1.isref && (t1.isScopeQual || t2.isScopeQual))
{
StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0;
StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0;
if (t1.isreturn)
{
stc1 |= STC.return_;
if (!t1.isScopeQual)
stc1 |= STC.ref_;
}
if (t2.isreturn)
{
stc2 |= STC.return_;
if (!t2.isScopeQual)
stc2 |= STC.ref_;
}
if (!Parameter.isCovariantScope(t1.isref, stc1, stc2))
goto Lnotcovariant;
}
// We can subtract 'return ref' from 'this', but cannot add it
else if (t1.isreturn && !t2.isreturn)
goto Lnotcovariant;
/* https://issues.dlang.org/show_bug.cgi?id=23135
* extern(C++) mutable member functions are not covariant with const.
*/
if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked())
goto Lnotcovariant;
/* Can convert mutable to const
*/
if (!MODimplicitConv(t2.mod, t1.mod))
{
version (none)
{
//stop attribute inference with const
// If adding 'const' will make it covariant
if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_)))
stc |= STC.const_;
else
goto Lnotcovariant;
}
else
{
goto Ldistinct;
}
}
/* Can convert pure to impure, nothrow to throw, and nogc to gc
*/
if (!t1.purity && t2.purity)
stc |= STC.pure_;
if (!t1.isnothrow && t2.isnothrow)
stc |= STC.nothrow_;
if (!t1.isnogc && t2.isnogc)
stc |= STC.nogc;
/* Can convert safe/trusted to system
*/
if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted)
{
// Should we infer trusted or safe? Go with safe.
stc |= STC.safe;
}
if (stc)
{
if (pstc)
*pstc = stc;
goto Lnotcovariant;
}
//printf("\tcovaraint: 1\n");
return Covariant.yes;
Ldistinct:
//printf("\tcovaraint: 0\n");
return Covariant.distinct;
Lnotcovariant:
//printf("\tcovaraint: 2\n");
return Covariant.no;
}
/********************************
* For pretty-printing a type.
*/
@ -1061,17 +803,6 @@ extern (C++) abstract class Type : ASTNode
return isscalar();
}
/*********************************
* Check type to see if it is based on a deprecated symbol.
*/
void checkDeprecated(const ref Loc loc, Scope* sc)
{
if (Dsymbol s = toDsymbol(sc))
{
s.checkDeprecated(loc, sc);
}
}
final bool isConst() const nothrow pure @nogc @safe
{
return (mod & MODFlags.const_) != 0;
@ -2825,13 +2556,6 @@ extern (C++) abstract class TypeNext : Type
this.next = next;
}
override final void checkDeprecated(const ref Loc loc, Scope* sc)
{
Type.checkDeprecated(loc, sc);
if (next) // next can be NULL if TypeFunction and auto return type
next.checkDeprecated(loc, sc);
}
override final int hasWild() const
{
if (ty == Tfunction)
@ -4612,27 +4336,7 @@ extern (C++) final class TypeFunction : TypeNext
return t.merge();
}
// arguments get specially formatted
private const(char)* getParamError(Expression arg, Parameter par)
{
if (global.gag && !global.params.v.showGaggedErrors)
return null;
// show qualification when toChars() is the same but types are different
// https://issues.dlang.org/show_bug.cgi?id=19948
// when comparing the type with strcmp, we need to drop the qualifier
bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) &&
strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0;
auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars();
OutBuffer buf;
// only mention rvalue if it's relevant
const rv = !arg.isLvalue() && par.isReference();
buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at,
parameterToChars(par, this, qual));
return buf.extractChars();
}
private extern(D) const(char)* getMatchError(A...)(const(char)* format, A args)
extern(D) static const(char)* getMatchError(A...)(const(char)* format, A args)
{
if (global.gag && !global.params.v.showGaggedErrors)
return null;
@ -4641,185 +4345,6 @@ extern (C++) final class TypeFunction : TypeNext
return buf.extractChars();
}
/********************************
* 'args' are being matched to function 'this'
* Determine match level.
* Params:
* tthis = type of `this` pointer, null if not member function
* argumentList = arguments to function call
* flag = 1: performing a partial ordering match
* pMessage = address to store error message, or null
* sc = context
* Returns:
* MATCHxxxx
*/
extern (D) MATCH callMatch(Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null)
{
//printf("TypeFunction::callMatch() %s\n", toChars());
MATCH match = MATCH.exact; // assume exact match
ubyte wildmatch = 0;
if (tthis)
{
Type t = tthis;
if (t.toBasetype().ty == Tpointer)
t = t.toBasetype().nextOf(); // change struct* to struct
if (t.mod != mod)
{
if (MODimplicitConv(t.mod, mod))
match = MATCH.constant;
else if ((mod & MODFlags.wild) && MODimplicitConv(t.mod, (mod & ~MODFlags.wild) | MODFlags.const_))
{
match = MATCH.constant;
}
else
return MATCH.nomatch;
}
if (isWild())
{
if (t.isWild())
wildmatch |= MODFlags.wild;
else if (t.isConst())
wildmatch |= MODFlags.const_;
else if (t.isImmutable())
wildmatch |= MODFlags.immutable_;
else
wildmatch |= MODFlags.mutable;
}
}
const nparams = parameterList.length;
if (argumentList.length > nparams)
{
if (parameterList.varargs == VarArg.none)
{
// suppress early exit if an error message is wanted,
// so we can check any matching args are valid
if (!pMessage)
return MATCH.nomatch;
}
// too many args; no match
match = MATCH.convert; // match ... with a "conversion" match level
}
// https://issues.dlang.org/show_bug.cgi?id=22997
if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs)
{
OutBuffer buf;
buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length);
if (pMessage)
*pMessage = buf.extractChars();
return MATCH.nomatch;
}
auto resolvedArgs = resolveNamedArgs(argumentList, pMessage);
Expression[] args;
if (!resolvedArgs)
{
if (!pMessage || *pMessage)
return MATCH.nomatch;
// if no message was provided, it was because of overflow which will be diagnosed below
match = MATCH.nomatch;
args = argumentList.arguments ? (*argumentList.arguments)[] : null;
}
else
{
args = (*resolvedArgs)[];
}
foreach (u, p; parameterList)
{
if (u >= args.length)
break;
Expression arg = args[u];
if (!arg)
continue; // default argument
Type tprm = p.type;
Type targ = arg.type;
if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid))
{
const isRef = p.isReference();
wildmatch |= targ.deduceWild(tprm, isRef);
}
}
if (wildmatch)
{
/* Calculate wild matching modifier
*/
if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1))
wildmatch = MODFlags.const_;
else if (wildmatch & MODFlags.immutable_)
wildmatch = MODFlags.immutable_;
else if (wildmatch & MODFlags.wild)
wildmatch = MODFlags.wild;
else
{
assert(wildmatch & MODFlags.mutable);
wildmatch = MODFlags.mutable;
}
}
foreach (u, p; parameterList)
{
MATCH m;
assert(p);
// One or more arguments remain
if (u < args.length)
{
Expression arg = args[u];
if (!arg)
continue; // default argument
m = argumentMatchParameter(this, p, arg, wildmatch, flag, sc, pMessage);
}
else if (p.defaultArg)
continue;
/* prefer matching the element type rather than the array
* type when more arguments are present with T[]...
*/
if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams)
goto L1;
//printf("\tm = %d\n", m);
if (m == MATCH.nomatch) // if no match
{
L1:
if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param
{
auto trailingArgs = args[u .. $];
if (auto vmatch = matchTypeSafeVarArgs(this, p, trailingArgs, pMessage))
return vmatch < match ? vmatch : match;
// Error message was already generated in `matchTypeSafeVarArgs`
return MATCH.nomatch;
}
if (pMessage && u >= args.length)
*pMessage = getMatchError("missing argument for parameter #%d: `%s`",
u + 1, parameterToChars(p, this, false));
// If an error happened previously, `pMessage` was already filled
else if (pMessage && !*pMessage)
*pMessage = getParamError(args[u], p);
return MATCH.nomatch;
}
if (m < match)
match = m; // pick worst match
}
if (pMessage && !parameterList.varargs && args.length > nparams)
{
// all parameters had a match, but there are surplus args
*pMessage = getMatchError("expected %d argument(s), not %d", nparams, args.length);
return MATCH.nomatch;
}
//printf("match = %d\n", match);
return match;
}
/********************************
* Convert an `argumentList`, which may contain named arguments, into
* a list of arguments in the order of the parameter list.
@ -6935,7 +6460,7 @@ extern (C++) final class Parameter : ASTNode
return isCovariantScope(returnByRef, thisSTC, otherSTC);
}
extern (D) private static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe
extern (D) static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe
{
// Workaround for failing covariance when finding a common type of delegates,
// some of which have parameters with inferred scope
@ -7234,328 +6759,6 @@ const(char)* toChars(ScopeRef sr) pure nothrow @nogc @safe
}
}
/**
* Used by `callMatch` to check if the copy constructor may be called to
* copy the argument
*
* This is done by seeing if a call to the copy constructor can be made:
* ```
* typeof(tprm) __copytmp;
* copytmp.__copyCtor(arg);
* ```
*/
private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
Expression arg, Type tprm, Scope* sc, const(char)** pMessage)
{
auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null);
tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe;
tmp.dsymbolSemantic(sc);
Expression ve = new VarExp(arg.loc, tmp);
Expression e = new DotIdExp(arg.loc, ve, Id.ctor);
e = new CallExp(arg.loc, e, arg);
//printf("e = %s\n", e.toChars());
if (.trySemantic(e, sc))
return true;
if (pMessage)
{
/* https://issues.dlang.org/show_bug.cgi?id=22202
*
* If a function was deduced by semantic on the CallExp,
* it means that resolveFuncCall completed succesfully.
* Therefore, there exists a callable copy constructor,
* however, it cannot be called because scope constraints
* such as purity, safety or nogc.
*/
OutBuffer buf;
auto callExp = e.isCallExp();
if (auto f = callExp.f)
{
char[] s;
if (!f.isPure && sc.func.setImpure())
s ~= "pure ";
if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe())
s ~= "@safe ";
if (!f.isNogc && sc.func.setGC(arg.loc, null))
s ~= "nogc ";
if (s)
{
s[$-1] = '\0';
buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr);
}
else if (f.isGenerated() && f.isDisabled())
{
/* https://issues.dlang.org/show_bug.cgi?id=23097
* Compiler generated copy constructor failed.
*/
buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable",
argStruct.toChars());
}
else
{
/* Although a copy constructor may exist, no suitable match was found.
* i.e: `inout` constructor creates `const` object, not mutable.
* Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202.
*/
goto Lnocpctor;
}
}
else
{
Lnocpctor:
buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
argStruct.toChars(), arg.type.toChars(), tprm.toChars());
}
*pMessage = buf.extractChars();
}
return false;
}
/**
* Match a single parameter to an argument.
*
* This function is called by `TypeFunction.callMatch` while iterating over
* the list of parameter. Here we check if `arg` is a match for `p`,
* which is mostly about checking if `arg.type` converts to `p`'s type
* and some check about value reference.
*
* Params:
* tf = The `TypeFunction`, only used for error reporting
* p = The parameter of `tf` being matched
* arg = Argument being passed (bound) to `p`
* wildmatch = Wild (`inout`) matching level, derived from the full argument list
* flag = A non-zero value means we're doing a partial ordering check
* (no value semantic check)
* sc = Scope we are in
* pMessage = A buffer to write the error in, or `null`
*
* Returns: Whether `trailingArgs` match `p`.
*/
private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p,
Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage)
{
//printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars());
MATCH m;
Type targ = arg.type;
Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type;
if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)
m = MATCH.convert;
else if (flag)
{
// for partial ordering, value is an irrelevant mockup, just look at the type
m = targ.implicitConvTo(tprm);
}
else
{
const isRef = p.isReference();
StructDeclaration argStruct, prmStruct;
// first look for a copy constructor
if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct)
{
// if the argument and the parameter are of the same unqualified struct type
argStruct = (cast(TypeStruct)targ).sym;
prmStruct = (cast(TypeStruct)tprm).sym;
}
// check if the copy constructor may be called to copy the argument
if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor)
{
if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage))
return MATCH.nomatch;
m = MATCH.exact;
}
else
{
import dmd.dcast : cimplicitConvTo;
m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm);
}
}
// Non-lvalues do not match ref or out parameters
if (p.isReference())
{
// https://issues.dlang.org/show_bug.cgi?id=13783
// Don't use toBasetype() to handle enum types.
Type ta = targ;
Type tp = tprm;
//printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars());
if (m && !arg.isLvalue())
{
if (p.storageClass & STC.out_)
{
if (pMessage) *pMessage = tf.getParamError(arg, p);
return MATCH.nomatch;
}
if (arg.op == EXP.string_ && tp.ty == Tsarray)
{
if (ta.ty != Tsarray)
{
Type tn = tp.nextOf().castMod(ta.nextOf().mod);
dinteger_t dim = (cast(StringExp)arg).len;
ta = tn.sarrayOf(dim);
}
}
else if (arg.op == EXP.slice && tp.ty == Tsarray)
{
// Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
if (ta.ty != Tsarray)
{
Type tn = ta.nextOf();
dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
ta = tn.sarrayOf(dim);
}
}
else if ((p.storageClass & STC.in_) && global.params.previewIn)
{
// Allow converting a literal to an `in` which is `ref`
if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray)
{
Type tn = tp.nextOf();
dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
ta = tn.sarrayOf(dim);
}
// Need to make this a rvalue through a temporary
m = MATCH.convert;
}
else if (global.params.rvalueRefParam != FeatureState.enabled ||
p.storageClass & STC.out_ ||
!arg.type.isCopyable()) // can't copy to temp for ref parameter
{
if (pMessage) *pMessage = tf.getParamError(arg, p);
return MATCH.nomatch;
}
else
{
/* in functionParameters() we'll convert this
* rvalue into a temporary
*/
m = MATCH.convert;
}
}
/* If the match is not already perfect or if the arg
is not a lvalue then try the `alias this` chain
see https://issues.dlang.org/show_bug.cgi?id=15674
and https://issues.dlang.org/show_bug.cgi?id=21905
*/
if (ta != tp || !arg.isLvalue())
{
Type firsttab = ta.toBasetype();
while (1)
{
Type tab = ta.toBasetype();
Type tat = tab.aliasthisOf();
if (!tat || !tat.implicitConvTo(tprm))
break;
if (tat == tab || tat == firsttab)
break;
ta = tat;
}
}
/* A ref variable should work like a head-const reference.
* e.g. disallows:
* ref T <- an lvalue of const(T) argument
* ref T[dim] <- an lvalue of const(T[dim]) argument
*/
if (!ta.constConv(tp))
{
if (pMessage) *pMessage = tf.getParamError(arg, p);
return MATCH.nomatch;
}
}
return m;
}
/**
* Match the remaining arguments `trailingArgs` with parameter `p`.
*
* Assume we already checked that `p` is the last parameter of `tf`,
* and we want to know whether the arguments would match `p`.
*
* Params:
* tf = The `TypeFunction`, only used for error reporting
* p = The last parameter of `tf` which is variadic
* trailingArgs = The remaining arguments that should match `p`
* pMessage = A buffer to write the error in, or `null`
*
* Returns: Whether `trailingArgs` match `p`.
*/
private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p,
Expression[] trailingArgs, const(char)** pMessage)
{
Type tb = p.type.toBasetype();
switch (tb.ty)
{
case Tsarray:
TypeSArray tsa = cast(TypeSArray)tb;
dinteger_t sz = tsa.dim.toInteger();
if (sz != trailingArgs.length)
{
if (pMessage)
*pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu",
sz, trailingArgs.length);
return MATCH.nomatch;
}
goto case Tarray;
case Tarray:
{
MATCH match = MATCH.exact;
TypeArray ta = cast(TypeArray)tb;
foreach (arg; trailingArgs)
{
MATCH m;
assert(arg);
/* If lazy array of delegates,
* convert arg(s) to delegate(s)
*/
Type tret = p.isLazyArray();
if (tret)
{
if (ta.next.equals(arg.type))
m = MATCH.exact;
else if (tret.toBasetype().ty == Tvoid)
m = MATCH.convert;
else
{
m = arg.implicitConvTo(tret);
if (m == MATCH.nomatch)
m = arg.implicitConvTo(ta.next);
}
}
else
m = arg.implicitConvTo(ta.next);
if (m == MATCH.nomatch)
{
if (pMessage) *pMessage = tf.getParamError(arg, p);
return MATCH.nomatch;
}
if (m < match)
match = m;
}
return match;
}
case Tclass:
// We leave it up to the actual constructor call to do the matching.
return MATCH.exact;
default:
// We can have things as `foo(int[int] wat...)` but they only match
// with an associative array proper.
if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p);
return MATCH.nomatch;
}
}
/**
* Creates an appropriate vector type for `tv` that will hold one boolean
* result for each element of the vector type. The result of vector comparisons
@ -7738,3 +6941,36 @@ TypeIdentifier getException()
tid.addIdent(Id.Exception);
return tid;
}
/**************************************
* Check and set 'att' if 't' is a recursive 'alias this' type
*
* The goal is to prevent endless loops when there is a cycle in the alias this chain.
* Since there is no multiple `alias this`, the chain either ends in a leaf,
* or it loops back on itself as some point.
*
* Example: S0 -> (S1 -> S2 -> S3 -> S1)
*
* `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried.
* `S1` is a recursive alias this type, but since `att` is initialized to `null`,
* this still returns `false`, but `att1` is set to `S1`.
* A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again,
* we notice `att == t`, so we're back at the start of the loop, and this returns `true`.
*
* Params:
* att = type reference used to detect recursion. Should be initialized to `null`.
* t = type of 'alias this' rewrite to attempt
*
* Returns:
* `false` if the rewrite is safe, `true` if it would loop back around
*/
bool isRecursiveAliasThis(ref Type att, Type t)
{
//printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars());
auto tb = t.toBasetype();
if (att && tb.equivalent(att))
return true;
else if (!att && tb.checkAliasThisRec())
att = tb;
return false;
}

View file

@ -225,7 +225,6 @@ public:
// kludge for template.isType()
DYNCAST dyncast() const override final { return DYNCAST_TYPE; }
size_t getUniqueID() const;
Covariant covariant(Type *, StorageClass * = NULL, bool = false);
const char *toChars() const override;
char *toPrettyChars(bool QualifyTypes = false);
static void _init();
@ -249,7 +248,6 @@ public:
virtual bool isString();
virtual bool isAssignable();
virtual bool isBoolean();
virtual void checkDeprecated(const Loc &loc, Scope *sc);
bool isConst() const { return (mod & MODconst) != 0; }
bool isImmutable() const { return (mod & MODimmutable) != 0; }
bool isMutable() const { return (mod & (MODconst | MODimmutable | MODwild)) == 0; }
@ -364,7 +362,6 @@ class TypeNext : public Type
public:
Type *next;
void checkDeprecated(const Loc &loc, Scope *sc) override final;
int hasWild() const override final;
Type *nextOf() override final;
Type *makeConst() override final;
@ -929,3 +926,4 @@ public:
// If the type is a class or struct, returns the symbol for it, else null.
AggregateDeclaration *isAggregate(Type *t);
Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false);

View file

@ -46,22 +46,14 @@
module dmd.nspace;
import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
import dmd.dscope;
import dmd.dsymbol;
import dmd.dsymbolsem;
import dmd.errors;
import dmd.expression;
import dmd.globals;
import dmd.identifier;
import dmd.location;
import dmd.visitor;
import core.stdc.stdio;
private enum LOG = false;
/// Ditto
extern (C++) final class Nspace : ScopeDsymbol
{
@ -91,14 +83,6 @@ extern (C++) final class Nspace : ScopeDsymbol
return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
}
override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
{
//printf("Nspace::setFieldOffset() %s\n", toChars());
if (_scope) // if fwd reference
dsymbolSemantic(this, null); // try to resolve it
members.foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
}
override const(char)* kind() const
{
return "namespace";

View file

@ -22,7 +22,6 @@ class Nspace final : public ScopeDsymbol
Expression *identExp;
Nspace *syntaxCopy(Dsymbol *s) override;
bool hasPointers() override;
void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
const char *kind() const override;
Nspace *isNspace() override { return this; }
void accept(Visitor *v) override { v->visit(this); }

View file

@ -130,5 +130,5 @@ struct Scope
AliasDeclaration *aliasAsg; // if set, then aliasAsg is being assigned a new value,
// do not set wasRead for it
Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol **pscopesym, int flags = IgnoreNone);
Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol **pscopesym, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all);
};

View file

@ -520,7 +520,8 @@ private extern(C++) final class Semantic3Visitor : Visitor
{
Parameter narg = Parameter.getNth(t.arguments, j);
assert(narg.ident);
VarDeclaration v = sc2.search(Loc.initial, narg.ident, null).isVarDeclaration();
Dsymbol pscopesym;
VarDeclaration v = sc2.search(Loc.initial, narg.ident, pscopesym).isVarDeclaration();
assert(v);
(*exps)[j] = new VarExp(v.loc, v);
}

View file

@ -20,19 +20,15 @@ import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
import dmd.errors;
import dmd.gluelayer;
import dmd.cond;
import dmd.declaration;
import dmd.dsymbol;
import dmd.expression;
import dmd.func;
import dmd.globals;
import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.location;
import dmd.mtype;
import dmd.common.outbuffer;
import dmd.rootobject;
import dmd.sapply;
import dmd.staticassert;
@ -333,6 +329,8 @@ extern (C++) final class ErrorStatement : Statement
extern (D) this()
{
super(Loc.initial, STMT.Error);
import dmd.globals;
assert(global.gaggedErrors || global.errors);
}
@ -1773,7 +1771,7 @@ extern (C++) class AsmStatement : Statement
*/
extern (C++) final class InlineAsmStatement : AsmStatement
{
code* asmcode;
void* asmcode;
uint asmalign; // alignment of this statement
uint regs; // mask of registers modified (must match regm_t in back end)
bool refparam; // true if function parameter is referenced

View file

@ -716,7 +716,7 @@ public:
class InlineAsmStatement final : public AsmStatement
{
public:
code *asmcode;
void *asmcode;
unsigned asmalign; // alignment of this statement
unsigned regs; // mask of registers modified (must match regm_t in back end)
d_bool refparam; // true if function parameter is referenced

View file

@ -2261,7 +2261,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
continue;
assert(scx.sw == sw);
if (!scx.search(cs.exp.loc, v.ident, null))
Dsymbol pscopesym;
if (!scx.search(cs.exp.loc, v.ident, pscopesym))
{
error(cs.loc, "`case` variable `%s` declared at %s cannot be declared in `switch` body",
v.toChars(), v.loc.toChars());
@ -2525,10 +2526,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
if (fd.fes)
fd = fd.fes.func; // fd is now function enclosing foreach
TypeFunction tf = cast(TypeFunction)fd.type;
assert(tf.ty == Tfunction);
auto tf = fd.type.isTypeFunction();
if (rs.exp && rs.exp.op == EXP.variable && (cast(VarExp)rs.exp).var == fd.vresult)
if (rs.exp && rs.exp.isVarExp() && rs.exp.isVarExp().var == fd.vresult)
{
// return vresult;
if (sc.fes)
@ -2616,7 +2616,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
rs.exp.checkSharedAccess(sc, returnSharedRef);
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
if (rs.exp.op == EXP.type)
if (rs.exp.isTypeExp())
rs.exp = resolveAliasThis(sc, rs.exp);
rs.exp = resolveProperties(sc, rs.exp);
@ -2632,14 +2632,14 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
// Extract side-effect part
rs.exp = Expression.extractLast(rs.exp, e0);
if (rs.exp.op == EXP.call)
if (rs.exp.isCallExp())
rs.exp = valueNoDtor(rs.exp);
/* Void-return function can have void / noreturn typed expression
* on return statement.
*/
auto texp = rs.exp.type;
const convToVoid = texp.ty == Tvoid || texp.ty == Tnoreturn;
const convToVoid = texp.ty == Tvoid || texp.isTypeNoreturn();
if (tbret && tbret.ty == Tvoid || convToVoid)
{
@ -2688,7 +2688,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
{
tf.next = rs.exp.type;
}
else if (tret.ty != Terror && !rs.exp.type.equals(tret))
else if (!tret.isTypeError() && !rs.exp.type.equals(tret))
{
int m1 = rs.exp.type.implicitConvTo(tret);
int m2 = tret.implicitConvTo(rs.exp.type);
@ -2789,7 +2789,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
// Found an actual return value before
else if (tf.next.ty != Tvoid && !resType.toBasetype().isTypeNoreturn())
{
if (tf.next.ty != Terror)
if (!tf.next.isTypeError())
{
error(rs.loc, "mismatched function return type inference of `void` and `%s`", tf.next.toChars());
}
@ -2807,7 +2807,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
if (tbret.ty != Tvoid && !resType.isTypeNoreturn()) // if non-void return
{
if (tbret.ty != Terror)
if (!tbret.isTypeError())
{
if (e0)
error(rs.loc, "expected return type of `%s`, not `%s`", tret.toChars(), resType.toChars());
@ -2901,7 +2901,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
}
if (e0)
{
if (e0.op == EXP.declaration || e0.op == EXP.comma)
if (e0.isDeclarationExp() || e0.isCommaExp())
{
rs.exp = Expression.combine(e0, rs.exp);
}

View file

@ -14,14 +14,11 @@
module dmd.staticassert;
import dmd.arraytypes;
import dmd.dscope;
import dmd.dsymbol;
import dmd.expression;
import dmd.globals;
import dmd.location;
import dmd.id;
import dmd.identifier;
import dmd.mtype;
import dmd.visitor;
/***********************************************************

View file

@ -311,7 +311,6 @@ public:
const char *kind() const override;
bool oneMember(Dsymbol **ps, Identifier *ident) override;
bool hasPointers() override;
void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
const char *toChars() const override;
TemplateMixin *isTemplateMixin() override { return this; }

View file

@ -1665,12 +1665,12 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
}
else if (auto ed = sm.isEnumDeclaration())
{
ScopeDsymbol._foreach(null, ed.members, &pushIdentsDg);
_foreach(null, ed.members, &pushIdentsDg);
}
return 0;
}
ScopeDsymbol._foreach(sc, sds.members, &pushIdentsDg);
_foreach(sc, sds.members, &pushIdentsDg);
auto cd = sds.isClassDeclaration();
if (cd && e.ident == Id.allMembers)
{
@ -1684,7 +1684,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
{
auto cb = (*cd.baseclasses)[i].sym;
assert(cb);
ScopeDsymbol._foreach(null, cb.members, &pushIdentsDg);
_foreach(null, cb.members, &pushIdentsDg);
if (cb.baseclasses.length)
pushBaseMembersDg(cb);
}

View file

@ -228,7 +228,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
Type t = s.getType(); // type symbol, type alias, or type tuple?
uint errorsave = global.errors;
int flags = t is null ? SearchLocalsOnly : IgnorePrivateImports;
SearchOptFlags flags = t is null ? SearchOpt.localsOnly : SearchOpt.ignorePrivateImports;
Dsymbol sm = s.searchX(loc, sc, id, flags);
if (sm)
@ -380,12 +380,12 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
* loc = location to print the error messages
* sc = the scope where the symbol is located
* id = the id of the symbol
* flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports`
* flags = the search flags which can be `SearchLocalsOnly` or `SearchOpt.ignorePrivateImports`
*
* Returns:
* symbol found, NULL if not
*/
private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, int flags)
private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, SearchOptFlags flags)
{
//printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
Dsymbol s = dsym.toAlias();
@ -486,6 +486,529 @@ Expression typeToExpression(Type t)
}
}
/********************************
* 'args' are being matched to function type 'tf'
* Determine match level.
* Params:
* tf = function type
* tthis = type of `this` pointer, null if not member function
* argumentList = arguments to function call
* flag = 1: performing a partial ordering match
* pMessage = address to store error message, or null
* sc = context
* Returns:
* MATCHxxxx
*/
extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null)
{
//printf("TypeFunction::callMatch() %s\n", tf.toChars());
MATCH match = MATCH.exact; // assume exact match
ubyte wildmatch = 0;
if (tthis)
{
Type t = tthis;
if (t.toBasetype().ty == Tpointer)
t = t.toBasetype().nextOf(); // change struct* to struct
if (t.mod != tf.mod)
{
if (MODimplicitConv(t.mod, tf.mod))
match = MATCH.constant;
else if ((tf.mod & MODFlags.wild) && MODimplicitConv(t.mod, (tf.mod & ~MODFlags.wild) | MODFlags.const_))
{
match = MATCH.constant;
}
else
return MATCH.nomatch;
}
if (tf.isWild())
{
if (t.isWild())
wildmatch |= MODFlags.wild;
else if (t.isConst())
wildmatch |= MODFlags.const_;
else if (t.isImmutable())
wildmatch |= MODFlags.immutable_;
else
wildmatch |= MODFlags.mutable;
}
}
ParameterList* parameterList = &tf.parameterList;
const nparams = parameterList.length;
if (argumentList.length > nparams)
{
if (parameterList.varargs == VarArg.none)
{
// suppress early exit if an error message is wanted,
// so we can check any matching args are valid
if (!pMessage)
return MATCH.nomatch;
}
// too many args; no match
match = MATCH.convert; // match ... with a "conversion" match level
}
// https://issues.dlang.org/show_bug.cgi?id=22997
if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs)
{
OutBuffer buf;
buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length);
if (pMessage)
*pMessage = buf.extractChars();
return MATCH.nomatch;
}
auto resolvedArgs = tf.resolveNamedArgs(argumentList, pMessage);
Expression[] args;
if (!resolvedArgs)
{
if (!pMessage || *pMessage)
return MATCH.nomatch;
// if no message was provided, it was because of overflow which will be diagnosed below
match = MATCH.nomatch;
args = argumentList.arguments ? (*argumentList.arguments)[] : null;
}
else
{
args = (*resolvedArgs)[];
}
foreach (u, p; *parameterList)
{
if (u >= args.length)
break;
Expression arg = args[u];
if (!arg)
continue; // default argument
Type tprm = p.type;
Type targ = arg.type;
if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid))
{
const isRef = p.isReference();
wildmatch |= targ.deduceWild(tprm, isRef);
}
}
if (wildmatch)
{
/* Calculate wild matching modifier
*/
if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1))
wildmatch = MODFlags.const_;
else if (wildmatch & MODFlags.immutable_)
wildmatch = MODFlags.immutable_;
else if (wildmatch & MODFlags.wild)
wildmatch = MODFlags.wild;
else
{
assert(wildmatch & MODFlags.mutable);
wildmatch = MODFlags.mutable;
}
}
foreach (u, p; *parameterList)
{
MATCH m;
assert(p);
// One or more arguments remain
if (u < args.length)
{
Expression arg = args[u];
if (!arg)
continue; // default argument
m = argumentMatchParameter(tf, p, arg, wildmatch, flag, sc, pMessage);
}
else if (p.defaultArg)
continue;
/* prefer matching the element type rather than the array
* type when more arguments are present with T[]...
*/
if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams)
goto L1;
//printf("\tm = %d\n", m);
if (m == MATCH.nomatch) // if no match
{
L1:
if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param
{
auto trailingArgs = args[u .. $];
if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage))
return vmatch < match ? vmatch : match;
// Error message was already generated in `matchTypeSafeVarArgs`
return MATCH.nomatch;
}
if (pMessage && u >= args.length)
*pMessage = tf.getMatchError("missing argument for parameter #%d: `%s`",
u + 1, parameterToChars(p, tf, false));
// If an error happened previously, `pMessage` was already filled
else if (pMessage && !*pMessage)
*pMessage = tf.getParamError(args[u], p);
return MATCH.nomatch;
}
if (m < match)
match = m; // pick worst match
}
if (pMessage && !parameterList.varargs && args.length > nparams)
{
// all parameters had a match, but there are surplus args
*pMessage = tf.getMatchError("expected %d argument(s), not %d", nparams, args.length);
return MATCH.nomatch;
}
//printf("match = %d\n", match);
return match;
}
/**
* Used by `callMatch` to check if the copy constructor may be called to
* copy the argument
*
* This is done by seeing if a call to the copy constructor can be made:
* ```
* typeof(tprm) __copytmp;
* copytmp.__copyCtor(arg);
* ```
*/
private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
Expression arg, Type tprm, Scope* sc, const(char)** pMessage)
{
auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null);
tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe;
tmp.dsymbolSemantic(sc);
Expression ve = new VarExp(arg.loc, tmp);
Expression e = new DotIdExp(arg.loc, ve, Id.ctor);
e = new CallExp(arg.loc, e, arg);
//printf("e = %s\n", e.toChars());
if (.trySemantic(e, sc))
return true;
if (pMessage)
{
/* https://issues.dlang.org/show_bug.cgi?id=22202
*
* If a function was deduced by semantic on the CallExp,
* it means that resolveFuncCall completed succesfully.
* Therefore, there exists a callable copy constructor,
* however, it cannot be called because scope constraints
* such as purity, safety or nogc.
*/
OutBuffer buf;
auto callExp = e.isCallExp();
if (auto f = callExp.f)
{
char[] s;
if (!f.isPure && sc.func.setImpure())
s ~= "pure ";
if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe())
s ~= "@safe ";
if (!f.isNogc && sc.func.setGC(arg.loc, null))
s ~= "nogc ";
if (s)
{
s[$-1] = '\0';
buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr);
}
else if (f.isGenerated() && f.isDisabled())
{
/* https://issues.dlang.org/show_bug.cgi?id=23097
* Compiler generated copy constructor failed.
*/
buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable",
argStruct.toChars());
}
else
{
/* Although a copy constructor may exist, no suitable match was found.
* i.e: `inout` constructor creates `const` object, not mutable.
* Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202.
*/
goto Lnocpctor;
}
}
else
{
Lnocpctor:
buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
argStruct.toChars(), arg.type.toChars(), tprm.toChars());
}
*pMessage = buf.extractChars();
}
return false;
}
/**
* Match a single parameter to an argument.
*
* This function is called by `TypeFunction.callMatch` while iterating over
* the list of parameter. Here we check if `arg` is a match for `p`,
* which is mostly about checking if `arg.type` converts to `p`'s type
* and some check about value reference.
*
* Params:
* tf = The `TypeFunction`, only used for error reporting
* p = The parameter of `tf` being matched
* arg = Argument being passed (bound) to `p`
* wildmatch = Wild (`inout`) matching level, derived from the full argument list
* flag = A non-zero value means we're doing a partial ordering check
* (no value semantic check)
* sc = Scope we are in
* pMessage = A buffer to write the error in, or `null`
*
* Returns: Whether `trailingArgs` match `p`.
*/
private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p,
Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage)
{
//printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars());
MATCH m;
Type targ = arg.type;
Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type;
if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)
m = MATCH.convert;
else if (flag)
{
// for partial ordering, value is an irrelevant mockup, just look at the type
m = targ.implicitConvTo(tprm);
}
else
{
const isRef = p.isReference();
StructDeclaration argStruct, prmStruct;
// first look for a copy constructor
if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct)
{
// if the argument and the parameter are of the same unqualified struct type
argStruct = (cast(TypeStruct)targ).sym;
prmStruct = (cast(TypeStruct)tprm).sym;
}
// check if the copy constructor may be called to copy the argument
if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor)
{
if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage))
return MATCH.nomatch;
m = MATCH.exact;
}
else
{
import dmd.dcast : cimplicitConvTo;
m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm);
}
}
// Non-lvalues do not match ref or out parameters
if (p.isReference())
{
// https://issues.dlang.org/show_bug.cgi?id=13783
// Don't use toBasetype() to handle enum types.
Type ta = targ;
Type tp = tprm;
//printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars());
if (m && !arg.isLvalue())
{
if (p.storageClass & STC.out_)
{
if (pMessage) *pMessage = tf.getParamError(arg, p);
return MATCH.nomatch;
}
if (arg.op == EXP.string_ && tp.ty == Tsarray)
{
if (ta.ty != Tsarray)
{
Type tn = tp.nextOf().castMod(ta.nextOf().mod);
dinteger_t dim = (cast(StringExp)arg).len;
ta = tn.sarrayOf(dim);
}
}
else if (arg.op == EXP.slice && tp.ty == Tsarray)
{
// Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
if (ta.ty != Tsarray)
{
Type tn = ta.nextOf();
dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
ta = tn.sarrayOf(dim);
}
}
else if ((p.storageClass & STC.in_) && global.params.previewIn)
{
// Allow converting a literal to an `in` which is `ref`
if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray)
{
Type tn = tp.nextOf();
dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
ta = tn.sarrayOf(dim);
}
// Need to make this a rvalue through a temporary
m = MATCH.convert;
}
else if (global.params.rvalueRefParam != FeatureState.enabled ||
p.storageClass & STC.out_ ||
!arg.type.isCopyable()) // can't copy to temp for ref parameter
{
if (pMessage) *pMessage = tf.getParamError(arg, p);
return MATCH.nomatch;
}
else
{
/* in functionParameters() we'll convert this
* rvalue into a temporary
*/
m = MATCH.convert;
}
}
/* If the match is not already perfect or if the arg
is not a lvalue then try the `alias this` chain
see https://issues.dlang.org/show_bug.cgi?id=15674
and https://issues.dlang.org/show_bug.cgi?id=21905
*/
if (ta != tp || !arg.isLvalue())
{
Type firsttab = ta.toBasetype();
while (1)
{
Type tab = ta.toBasetype();
Type tat = tab.aliasthisOf();
if (!tat || !tat.implicitConvTo(tprm))
break;
if (tat == tab || tat == firsttab)
break;
ta = tat;
}
}
/* A ref variable should work like a head-const reference.
* e.g. disallows:
* ref T <- an lvalue of const(T) argument
* ref T[dim] <- an lvalue of const(T[dim]) argument
*/
if (!ta.constConv(tp))
{
if (pMessage) *pMessage = tf.getParamError(arg, p);
return MATCH.nomatch;
}
}
return m;
}
// arguments get specially formatted
private const(char)* getParamError(TypeFunction tf, Expression arg, Parameter par)
{
if (global.gag && !global.params.v.showGaggedErrors)
return null;
// show qualification when toChars() is the same but types are different
// https://issues.dlang.org/show_bug.cgi?id=19948
// when comparing the type with strcmp, we need to drop the qualifier
bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) &&
strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0;
auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars();
OutBuffer buf;
// only mention rvalue if it's relevant
const rv = !arg.isLvalue() && par.isReference();
buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at,
parameterToChars(par, tf, qual));
return buf.extractChars();
}
/**
* Match the remaining arguments `trailingArgs` with parameter `p`.
*
* Assume we already checked that `p` is the last parameter of `tf`,
* and we want to know whether the arguments would match `p`.
*
* Params:
* tf = The `TypeFunction`, only used for error reporting
* p = The last parameter of `tf` which is variadic
* trailingArgs = The remaining arguments that should match `p`
* pMessage = A buffer to write the error in, or `null`
*
* Returns: Whether `trailingArgs` match `p`.
*/
private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p,
Expression[] trailingArgs, const(char)** pMessage)
{
Type tb = p.type.toBasetype();
switch (tb.ty)
{
case Tsarray:
TypeSArray tsa = cast(TypeSArray)tb;
dinteger_t sz = tsa.dim.toInteger();
if (sz != trailingArgs.length)
{
if (pMessage)
*pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu",
sz, trailingArgs.length);
return MATCH.nomatch;
}
goto case Tarray;
case Tarray:
{
MATCH match = MATCH.exact;
TypeArray ta = cast(TypeArray)tb;
foreach (arg; trailingArgs)
{
MATCH m;
assert(arg);
/* If lazy array of delegates,
* convert arg(s) to delegate(s)
*/
Type tret = p.isLazyArray();
if (tret)
{
if (ta.next.equals(arg.type))
m = MATCH.exact;
else if (tret.toBasetype().ty == Tvoid)
m = MATCH.convert;
else
{
m = arg.implicitConvTo(tret);
if (m == MATCH.nomatch)
m = arg.implicitConvTo(ta.next);
}
}
else
m = arg.implicitConvTo(ta.next);
if (m == MATCH.nomatch)
{
if (pMessage) *pMessage = tf.getParamError(arg, p);
return MATCH.nomatch;
}
if (m < match)
match = m;
}
return match;
}
case Tclass:
// We leave it up to the actual constructor call to do the matching.
return MATCH.exact;
default:
// We can have things as `foo(int[int] wat...)` but they only match
// with an associative array proper.
if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p);
return MATCH.nomatch;
}
}
/******************************************
* Perform semantic analysis on a type.
* Params:
@ -1878,7 +2401,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
/* look for pre-existing declaration
*/
Dsymbol scopesym;
auto s = sc2.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace);
auto s = sc2.search(mtype.loc, mtype.id, scopesym, SearchOpt.ignoreErrors | SearchOpt.tagNameSpace);
if (!s || s.isModule())
{
// no pre-existing declaration, so declare it
@ -2753,7 +3276,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
}
Dsymbol scopesym;
Dsymbol s = sc.search(loc, mt.ident, &scopesym);
Dsymbol s = sc.search(loc, mt.ident, scopesym);
/*
* https://issues.dlang.org/show_bug.cgi?id=1170
* https://issues.dlang.org/show_bug.cgi?id=10739
@ -2776,7 +3299,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
mixinTempl.dsymbolSemantic(sc);
}
sds.members.foreachDsymbol( s => semanticOnMixin(s) );
s = sc.search(loc, mt.ident, &scopesym);
s = sc.search(loc, mt.ident, scopesym);
}
}
@ -3794,8 +4317,8 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
return e;
}
immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : 0;
s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports);
L1:
if (!s)
{
@ -4074,8 +4597,8 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
return e;
}
int flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
SearchOptFlags flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : SearchOpt.all;
s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports);
L1:
if (!s)
@ -4723,7 +5246,7 @@ Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty)
return *pt;
}
Dsymbol s = mConfig.searchX(Loc.initial, sc, id, IgnorePrivateImports);
Dsymbol s = mConfig.searchX(Loc.initial, sc, id, SearchOpt.ignorePrivateImports);
if (!s)
{
error(loc, "`%s` not found in core.stdc.config", id.toChars());
@ -4748,6 +5271,263 @@ Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty)
return *pt;
}
/*******************************
* Covariant means that 'src' can substitute for 't',
* i.e. a pure function is a match for an impure type.
* Params:
* src = source type
* t = type 'src' is covariant with
* pstc = if not null, store STCxxxx which would make it covariant
* cppCovariant = true if extern(C++) function types should follow C++ covariant rules
* Returns:
* An enum value of either `Covariant.yes` or a reason it's not covariant.
*/
extern (C++) Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false)
{
version (none)
{
printf("Type::covariant(t = %s) %s\n", t.toChars(), src.toChars());
printf("deco = %p, %p\n", src.deco, t.deco);
// printf("ty = %d\n", next.ty);
printf("mod = %x, %x\n", src.mod, t.mod);
}
if (pstc)
*pstc = 0;
StorageClass stc = 0;
bool notcovariant = false;
if (src.equals(t))
return Covariant.yes;
TypeFunction t1 = src.isTypeFunction();
TypeFunction t2 = t.isTypeFunction();
if (!t1 || !t2)
goto Ldistinct;
if (t1.parameterList.varargs != t2.parameterList.varargs)
goto Ldistinct;
if (t1.parameterList.parameters && t2.parameterList.parameters)
{
if (t1.parameterList.length != t2.parameterList.length)
goto Ldistinct;
foreach (i, fparam1; t1.parameterList)
{
Parameter fparam2 = t2.parameterList[i];
Type tp1 = fparam1.type;
Type tp2 = fparam2.type;
if (!tp1.equals(tp2))
{
if (tp1.ty == tp2.ty)
{
if (auto tc1 = tp1.isTypeClass())
{
if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
goto Lcov;
}
else if (auto ts1 = tp1.isTypeStruct())
{
if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
goto Lcov;
}
else if (tp1.ty == Tpointer)
{
if (tp2.implicitConvTo(tp1))
goto Lcov;
}
else if (tp1.ty == Tarray)
{
if (tp2.implicitConvTo(tp1))
goto Lcov;
}
else if (tp1.ty == Tdelegate)
{
if (tp2.implicitConvTo(tp1))
goto Lcov;
}
}
goto Ldistinct;
}
Lcov:
notcovariant |= !fparam1.isCovariant(t1.isref, fparam2);
/* https://issues.dlang.org/show_bug.cgi?id=23135
* extern(C++) mutable parameters are not covariant with const.
*/
if (t1.linkage == LINK.cpp && cppCovariant)
{
notcovariant |= tp1.isNaked() != tp2.isNaked();
if (auto tpn1 = tp1.nextOf())
notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked();
}
}
}
else if (t1.parameterList.parameters != t2.parameterList.parameters)
{
if (t1.parameterList.length || t2.parameterList.length)
goto Ldistinct;
}
// The argument lists match
if (notcovariant)
goto Lnotcovariant;
if (t1.linkage != t2.linkage)
goto Lnotcovariant;
{
// Return types
Type t1n = t1.next;
Type t2n = t2.next;
if (!t1n || !t2n) // happens with return type inference
goto Lnotcovariant;
if (t1n.equals(t2n))
goto Lcovariant;
if (t1n.ty == Tclass && t2n.ty == Tclass)
{
/* If same class type, but t2n is const, then it's
* covariant. Do this test first because it can work on
* forward references.
*/
if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
goto Lcovariant;
// If t1n is forward referenced:
ClassDeclaration cd = (cast(TypeClass)t1n).sym;
if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
cd.dsymbolSemantic(null);
if (!cd.isBaseInfoComplete())
{
return Covariant.fwdref;
}
}
if (t1n.ty == Tstruct && t2n.ty == Tstruct)
{
if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
goto Lcovariant;
}
else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n))
{
if (t1.isref && t2.isref)
{
// Treat like pointers to t1n and t2n
if (t1n.constConv(t2n) < MATCH.constant)
goto Lnotcovariant;
}
goto Lcovariant;
}
else if (t1n.ty == Tnull)
{
// NULL is covariant with any pointer type, but not with any
// dynamic arrays, associative arrays or delegates.
// https://issues.dlang.org/show_bug.cgi?id=8589
// https://issues.dlang.org/show_bug.cgi?id=19618
Type t2bn = t2n.toBasetype();
if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass)
goto Lcovariant;
}
// bottom type is covariant to any type
else if (t1n.ty == Tnoreturn)
goto Lcovariant;
}
goto Lnotcovariant;
Lcovariant:
if (t1.isref != t2.isref)
goto Lnotcovariant;
if (!t1.isref && (t1.isScopeQual || t2.isScopeQual))
{
StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0;
StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0;
if (t1.isreturn)
{
stc1 |= STC.return_;
if (!t1.isScopeQual)
stc1 |= STC.ref_;
}
if (t2.isreturn)
{
stc2 |= STC.return_;
if (!t2.isScopeQual)
stc2 |= STC.ref_;
}
if (!Parameter.isCovariantScope(t1.isref, stc1, stc2))
goto Lnotcovariant;
}
// We can subtract 'return ref' from 'this', but cannot add it
else if (t1.isreturn && !t2.isreturn)
goto Lnotcovariant;
/* https://issues.dlang.org/show_bug.cgi?id=23135
* extern(C++) mutable member functions are not covariant with const.
*/
if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked())
goto Lnotcovariant;
/* Can convert mutable to const
*/
if (!MODimplicitConv(t2.mod, t1.mod))
{
version (none)
{
//stop attribute inference with const
// If adding 'const' will make it covariant
if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_)))
stc |= STC.const_;
else
goto Lnotcovariant;
}
else
{
goto Ldistinct;
}
}
/* Can convert pure to impure, nothrow to throw, and nogc to gc
*/
if (!t1.purity && t2.purity)
stc |= STC.pure_;
if (!t1.isnothrow && t2.isnothrow)
stc |= STC.nothrow_;
if (!t1.isnogc && t2.isnogc)
stc |= STC.nogc;
/* Can convert safe/trusted to system
*/
if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted)
{
// Should we infer trusted or safe? Go with safe.
stc |= STC.safe;
}
if (stc)
{
if (pstc)
*pstc = stc;
goto Lnotcovariant;
}
//printf("\tcovaraint: 1\n");
return Covariant.yes;
Ldistinct:
//printf("\tcovaraint: 0\n");
return Covariant.distinct;
Lnotcovariant:
//printf("\tcovaraint: 2\n");
return Covariant.no;
}
/******************************* Private *****************************************/
private:

View file

@ -740,8 +740,10 @@ arguments like @code{va_start}.
@opindex fignore-unknown-pragmas
@opindex fno-ignore-unknown-pragmas
@item -fignore-unknown-pragmas
Turns off errors for unsupported pragmas.
@item -fno-ignore-unknown-pragmas
Do not recognize unsupported pragmas. Any @code{pragma()} encountered that is
not part of the D language will result in an error. This option is now
deprecated and will be removed in a future release.
@opindex fmax-errors
@item -fmax-errors=@var{n}

View file

@ -20,6 +20,7 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "dmd/aggregate.h"
#include "dmd/dsymbol.h"
#include "dmd/enum.h"
#include "dmd/errors.h"
#include "dmd/expression.h"
@ -205,7 +206,7 @@ make_frontend_typeinfo (Identifier *ident, ClassDeclaration *base = NULL)
/* Create object module in order to complete the semantic. */
if (!object_module->_scope)
object_module->importAll (NULL);
importAll (object_module, NULL);
/* Object class doesn't exist, create a stub one that will cause an error if
used. */

View file

@ -26,3 +26,7 @@ _Static_assert(F80 == 9.0L, "9");
#define SSS "hello"
_Static_assert(SSS[0] == 'h', "10");
#define ABC 12
#define GHI (size) abbadabba
#define DEF (ABC + 5)

View file

@ -1,86 +0,0 @@
// REQUIRED_ARGS: -o-
// PERMUTE_ARGS:
template TypeTuple(T...) { alias TypeTuple = T; }
bool startsWith(string s, string m) { return s[0 .. m.length] == m; }
void main()
{
enum string castPrefix = "cast(" ~ size_t.stringof ~ ")";
// TypeSArray
static assert((int[10]).stringof == "int[10]", T.stringof);
int[] arr;
// IndexExp
{
// index == IntegerExp
static assert((arr[ 4 ]).stringof == "arr[4]");
static assert((arr[ 4U ]).stringof == "arr[4]");
static assert((arr[ 4L ]).stringof == "arr[4]");
static assert((arr[ 4LU]).stringof == "arr[4]");
// index == UAddExp
static assert((arr[+4 ]).stringof == "arr[4]");
static assert((arr[+4U ]).stringof == "arr[4]");
static assert((arr[+4L ]).stringof == "arr[4]");
static assert((arr[+4LU]).stringof == "arr[4]");
// index == NegExp
static assert((arr[-4 ]).stringof == "arr[" ~ castPrefix ~ "-4]");
static assert((arr[-4U ]).stringof == "arr[4294967292]");
static assert((arr[int.min] ).stringof == "arr[" ~ castPrefix ~ "-2147483648]");
static if (is(size_t == ulong))
{
static assert((arr[-4L ]).stringof == "arr[" ~ castPrefix ~ "-4L]");
static assert((arr[-4LU]).stringof == "arr[-4LU]");
// IntegerLiteral needs suffix if the value is greater than long.max
static assert((arr[long.max + 0]).stringof == "arr[9223372036854775807]");
static assert((arr[long.max + 1]).stringof == "arr[" ~ castPrefix ~ "(9223372036854775807L + 1L)]");
}
foreach (Int; TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong))
{
enum Int p4 = +4;
enum string result1 = (arr[p4]).stringof;
static assert(result1 == "arr[4]");
enum string result2 = (arr[cast(Int)+4]).stringof;
static assert(result2 == "arr[4]");
}
foreach (Int; TypeTuple!(byte, short, int, long))
{
// keep "cast(Type)" in the string representation
enum Int m4 = -4;
static if (is(typeof({ size_t x = m4; })))
{
enum string result1 = (arr[m4]).stringof;
static assert(result1.startsWith("arr[" ~ castPrefix));
}
else
static assert(!__traits(compiles, arr[m4]));
enum string result2 = (arr[cast(Int)-4]).stringof;
static assert(result2.startsWith("arr[" ~ castPrefix));
}
}
// SliceExp
{
// lwr,upr == IntegerExp
static assert((arr[4 .. 8 ]).stringof == "arr[4..8]");
static assert((arr[4U .. 8U ]).stringof == "arr[4..8]");
static assert((arr[4L .. 8L ]).stringof == "arr[4..8]");
static assert((arr[4LU .. 8LU]).stringof == "arr[4..8]");
// lwr,upr == UAddExp
static assert((arr[+4 .. +8 ]).stringof == "arr[4..8]");
static assert((arr[+4U .. +8U ]).stringof == "arr[4..8]");
static assert((arr[+4L .. +8L ]).stringof == "arr[4..8]");
static assert((arr[+4LU .. +8LU]).stringof == "arr[4..8]");
}
}

View file

@ -12,3 +12,6 @@ static assert(F64 == 8.0);
static assert(F80 == 9.0L);
static assert(SSS == "hello");
static assert(ABC == 12);
static assert(DEF == 17);

View file

@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail19890a.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array
fail_compilation/fail19890a.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32omf=0x1000000|0x7fffffff$ size limit for static array
---
*/

View file

@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail19890b.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array
fail_compilation/fail19890b.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32omf=0x1000000|0x7fffffff$ size limit for static array
---
*/

View file

@ -1,7 +1,7 @@
/*
TEST_OUTPUT:
---
fail_compilation/fail4611.d(15): Error: `Vec[$n$]` size 4 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array
fail_compilation/fail4611.d(15): Error: `Vec[$n$]` size 4 * $n$ exceeds $?:windows+32omf=0x1000000|0x7fffffff$ size limit for static array
---
*/

View file

@ -5,7 +5,6 @@ TEST_OUTPUT:
---
fail_compilation/pragmas.d(103): Error: one boolean expression expected for `pragma(inline)`, not 2
fail_compilation/pragmas.d(108): Error: one boolean expression expected for `pragma(inline)`, not 2
fail_compilation/pragmas.d(118): Error: unrecognized `pragma(unrecognized)`
---
*/
@ -28,5 +27,5 @@ void test3()
void test4()
{
pragma(unrecognized, "string");
pragma(unrecognized, "string"); // permitted, just ignored
}

View file

@ -1,4 +1,4 @@
2bbf64907cbbb483d003e0a8fcf8b502e4883799
f1a045928e03239b9477f9497f43f2cf0e61e959
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.

View file

@ -202,26 +202,26 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
core/stdc/ctype.d core/stdc/errno.d core/stdc/fenv.d \
core/stdc/float_.d core/stdc/inttypes.d core/stdc/limits.d \
core/stdc/locale.d core/stdc/math.d core/stdc/signal.d \
core/stdc/stdarg.d core/stdc/stddef.d core/stdc/stdint.d \
core/stdc/stdio.d core/stdc/stdlib.d core/stdc/string.d \
core/stdc/tgmath.d core/stdc/time.d core/stdc/wchar_.d \
core/stdc/wctype.d core/sync/barrier.d core/sync/condition.d \
core/sync/config.d core/sync/event.d core/sync/exception.d \
core/sync/mutex.d core/sync/package.d core/sync/rwmutex.d \
core/sync/semaphore.d core/thread/context.d core/thread/fiber.d \
core/thread/osthread.d core/thread/package.d core/thread/threadbase.d \
core/thread/threadgroup.d core/thread/types.d core/time.d \
core/vararg.d core/volatile.d etc/valgrind/valgrind.d gcc/attribute.d \
gcc/attributes.d gcc/backtrace.d gcc/builtins.d gcc/deh.d gcc/emutls.d \
gcc/gthread.d gcc/sections/common.d gcc/sections/elf.d \
gcc/sections/macho.d gcc/sections/package.d gcc/sections/pecoff.d \
gcc/simd.d gcc/unwind/arm.d gcc/unwind/arm_common.d gcc/unwind/c6x.d \
gcc/unwind/generic.d gcc/unwind/package.d gcc/unwind/pe.d object.d \
rt/aApply.d rt/aApplyR.d rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d \
rt/config.d rt/critical_.d rt/deh.d rt/dmain2.d rt/ehalloc.d \
rt/invariant.d rt/lifetime.d rt/memory.d rt/minfo.d rt/monitor_.d \
rt/profilegc.d rt/sections.d rt/tlsgc.d rt/util/typeinfo.d \
rt/util/utility.d
core/stdc/stdarg.d core/stdc/stdatomic.d core/stdc/stddef.d \
core/stdc/stdint.d core/stdc/stdio.d core/stdc/stdlib.d \
core/stdc/string.d core/stdc/tgmath.d core/stdc/time.d \
core/stdc/wchar_.d core/stdc/wctype.d core/sync/barrier.d \
core/sync/condition.d core/sync/config.d core/sync/event.d \
core/sync/exception.d core/sync/mutex.d core/sync/package.d \
core/sync/rwmutex.d core/sync/semaphore.d core/thread/context.d \
core/thread/fiber.d core/thread/osthread.d core/thread/package.d \
core/thread/threadbase.d core/thread/threadgroup.d core/thread/types.d \
core/time.d core/vararg.d core/volatile.d etc/valgrind/valgrind.d \
gcc/attribute.d gcc/attributes.d gcc/backtrace.d gcc/builtins.d \
gcc/deh.d gcc/emutls.d gcc/gthread.d gcc/sections/common.d \
gcc/sections/elf.d gcc/sections/macho.d gcc/sections/package.d \
gcc/sections/pecoff.d gcc/simd.d gcc/unwind/arm.d \
gcc/unwind/arm_common.d gcc/unwind/c6x.d gcc/unwind/generic.d \
gcc/unwind/package.d gcc/unwind/pe.d object.d rt/aApply.d rt/aApplyR.d \
rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d rt/config.d rt/critical_.d \
rt/deh.d rt/dmain2.d rt/ehalloc.d rt/invariant.d rt/lifetime.d \
rt/memory.d rt/minfo.d rt/monitor_.d rt/profilegc.d rt/sections.d \
rt/tlsgc.d rt/util/typeinfo.d rt/util/utility.d
DRUNTIME_DSOURCES_STDCXX = core/stdcpp/allocator.d core/stdcpp/array.d \
core/stdcpp/exception.d core/stdcpp/memory.d core/stdcpp/new_.d \

View file

@ -225,23 +225,24 @@ am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \
core/stdc/config.lo core/stdc/ctype.lo core/stdc/errno.lo \
core/stdc/fenv.lo core/stdc/float_.lo core/stdc/inttypes.lo \
core/stdc/limits.lo core/stdc/locale.lo core/stdc/math.lo \
core/stdc/signal.lo core/stdc/stdarg.lo core/stdc/stddef.lo \
core/stdc/stdint.lo core/stdc/stdio.lo core/stdc/stdlib.lo \
core/stdc/string.lo core/stdc/tgmath.lo core/stdc/time.lo \
core/stdc/wchar_.lo core/stdc/wctype.lo core/sync/barrier.lo \
core/sync/condition.lo core/sync/config.lo core/sync/event.lo \
core/sync/exception.lo core/sync/mutex.lo core/sync/package.lo \
core/sync/rwmutex.lo core/sync/semaphore.lo \
core/thread/context.lo core/thread/fiber.lo \
core/thread/osthread.lo core/thread/package.lo \
core/thread/threadbase.lo core/thread/threadgroup.lo \
core/thread/types.lo core/time.lo core/vararg.lo \
core/volatile.lo etc/valgrind/valgrind.lo gcc/attribute.lo \
gcc/attributes.lo gcc/backtrace.lo gcc/builtins.lo gcc/deh.lo \
gcc/emutls.lo gcc/gthread.lo gcc/sections/common.lo \
gcc/sections/elf.lo gcc/sections/macho.lo \
gcc/sections/package.lo gcc/sections/pecoff.lo gcc/simd.lo \
gcc/unwind/arm.lo gcc/unwind/arm_common.lo gcc/unwind/c6x.lo \
core/stdc/signal.lo core/stdc/stdarg.lo core/stdc/stdatomic.lo \
core/stdc/stddef.lo core/stdc/stdint.lo core/stdc/stdio.lo \
core/stdc/stdlib.lo core/stdc/string.lo core/stdc/tgmath.lo \
core/stdc/time.lo core/stdc/wchar_.lo core/stdc/wctype.lo \
core/sync/barrier.lo core/sync/condition.lo \
core/sync/config.lo core/sync/event.lo core/sync/exception.lo \
core/sync/mutex.lo core/sync/package.lo core/sync/rwmutex.lo \
core/sync/semaphore.lo core/thread/context.lo \
core/thread/fiber.lo core/thread/osthread.lo \
core/thread/package.lo core/thread/threadbase.lo \
core/thread/threadgroup.lo core/thread/types.lo core/time.lo \
core/vararg.lo core/volatile.lo etc/valgrind/valgrind.lo \
gcc/attribute.lo gcc/attributes.lo gcc/backtrace.lo \
gcc/builtins.lo gcc/deh.lo gcc/emutls.lo gcc/gthread.lo \
gcc/sections/common.lo gcc/sections/elf.lo \
gcc/sections/macho.lo gcc/sections/package.lo \
gcc/sections/pecoff.lo gcc/simd.lo gcc/unwind/arm.lo \
gcc/unwind/arm_common.lo gcc/unwind/c6x.lo \
gcc/unwind/generic.lo gcc/unwind/package.lo gcc/unwind/pe.lo \
object.lo rt/aApply.lo rt/aApplyR.lo rt/aaA.lo rt/adi.lo \
rt/arraycat.lo rt/cast_.lo rt/config.lo rt/critical_.lo \
@ -879,26 +880,26 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
core/stdc/ctype.d core/stdc/errno.d core/stdc/fenv.d \
core/stdc/float_.d core/stdc/inttypes.d core/stdc/limits.d \
core/stdc/locale.d core/stdc/math.d core/stdc/signal.d \
core/stdc/stdarg.d core/stdc/stddef.d core/stdc/stdint.d \
core/stdc/stdio.d core/stdc/stdlib.d core/stdc/string.d \
core/stdc/tgmath.d core/stdc/time.d core/stdc/wchar_.d \
core/stdc/wctype.d core/sync/barrier.d core/sync/condition.d \
core/sync/config.d core/sync/event.d core/sync/exception.d \
core/sync/mutex.d core/sync/package.d core/sync/rwmutex.d \
core/sync/semaphore.d core/thread/context.d core/thread/fiber.d \
core/thread/osthread.d core/thread/package.d core/thread/threadbase.d \
core/thread/threadgroup.d core/thread/types.d core/time.d \
core/vararg.d core/volatile.d etc/valgrind/valgrind.d gcc/attribute.d \
gcc/attributes.d gcc/backtrace.d gcc/builtins.d gcc/deh.d gcc/emutls.d \
gcc/gthread.d gcc/sections/common.d gcc/sections/elf.d \
gcc/sections/macho.d gcc/sections/package.d gcc/sections/pecoff.d \
gcc/simd.d gcc/unwind/arm.d gcc/unwind/arm_common.d gcc/unwind/c6x.d \
gcc/unwind/generic.d gcc/unwind/package.d gcc/unwind/pe.d object.d \
rt/aApply.d rt/aApplyR.d rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d \
rt/config.d rt/critical_.d rt/deh.d rt/dmain2.d rt/ehalloc.d \
rt/invariant.d rt/lifetime.d rt/memory.d rt/minfo.d rt/monitor_.d \
rt/profilegc.d rt/sections.d rt/tlsgc.d rt/util/typeinfo.d \
rt/util/utility.d
core/stdc/stdarg.d core/stdc/stdatomic.d core/stdc/stddef.d \
core/stdc/stdint.d core/stdc/stdio.d core/stdc/stdlib.d \
core/stdc/string.d core/stdc/tgmath.d core/stdc/time.d \
core/stdc/wchar_.d core/stdc/wctype.d core/sync/barrier.d \
core/sync/condition.d core/sync/config.d core/sync/event.d \
core/sync/exception.d core/sync/mutex.d core/sync/package.d \
core/sync/rwmutex.d core/sync/semaphore.d core/thread/context.d \
core/thread/fiber.d core/thread/osthread.d core/thread/package.d \
core/thread/threadbase.d core/thread/threadgroup.d core/thread/types.d \
core/time.d core/vararg.d core/volatile.d etc/valgrind/valgrind.d \
gcc/attribute.d gcc/attributes.d gcc/backtrace.d gcc/builtins.d \
gcc/deh.d gcc/emutls.d gcc/gthread.d gcc/sections/common.d \
gcc/sections/elf.d gcc/sections/macho.d gcc/sections/package.d \
gcc/sections/pecoff.d gcc/simd.d gcc/unwind/arm.d \
gcc/unwind/arm_common.d gcc/unwind/c6x.d gcc/unwind/generic.d \
gcc/unwind/package.d gcc/unwind/pe.d object.d rt/aApply.d rt/aApplyR.d \
rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d rt/config.d rt/critical_.d \
rt/deh.d rt/dmain2.d rt/ehalloc.d rt/invariant.d rt/lifetime.d \
rt/memory.d rt/minfo.d rt/monitor_.d rt/profilegc.d rt/sections.d \
rt/tlsgc.d rt/util/typeinfo.d rt/util/utility.d
DRUNTIME_DSOURCES_STDCXX = core/stdcpp/allocator.d core/stdcpp/array.d \
core/stdcpp/exception.d core/stdcpp/memory.d core/stdcpp/new_.d \
@ -1316,6 +1317,7 @@ core/stdc/locale.lo: core/stdc/$(am__dirstamp)
core/stdc/math.lo: core/stdc/$(am__dirstamp)
core/stdc/signal.lo: core/stdc/$(am__dirstamp)
core/stdc/stdarg.lo: core/stdc/$(am__dirstamp)
core/stdc/stdatomic.lo: core/stdc/$(am__dirstamp)
core/stdc/stddef.lo: core/stdc/$(am__dirstamp)
core/stdc/stdint.lo: core/stdc/$(am__dirstamp)
core/stdc/stdio.lo: core/stdc/$(am__dirstamp)

View file

@ -33,7 +33,7 @@ version (LDC) version = GNU_OR_LDC;
*
* Returns: the slice containing the result
*/
T[] arrayOp(T : T[], Args...)(T[] res, Filter!(isType, Args) args) @trusted @nogc pure nothrow
T[] arrayOp(T : T[], Args...)(T[] res, Filter!(isType, Args) args) @trusted
{
alias scalarizedExp = staticMap!(toElementType, Args);
alias check = typeCheck!(true, T, scalarizedExp); // must support all scalar ops
@ -541,7 +541,7 @@ unittest
}
// test handling of v op= exp
unittest
@nogc nothrow pure @safe unittest
{
uint[32] c;
arrayOp!(uint[], uint, "+=")(c[], 2);
@ -556,7 +556,7 @@ unittest
}
// proper error message for UDT lacking certain ops
unittest
@nogc nothrow pure @safe unittest
{
static assert(!is(typeof(&arrayOp!(int[4][], int[4], "+="))));
static assert(!is(typeof(&arrayOp!(int[4][], int[4], "u-", "="))));
@ -585,7 +585,7 @@ unittest
}
// test mixed type array op
unittest
@nogc nothrow pure @safe unittest
{
uint[32] a = 0xF;
float[32] res = 2.0f;
@ -595,7 +595,7 @@ unittest
}
// test mixed type array op
unittest
@nogc nothrow pure @safe unittest
{
static struct S
{
@ -613,7 +613,7 @@ unittest
}
// test scalar after operation argument
unittest
@nogc nothrow pure @safe unittest
{
float[32] res, a = 2, b = 3;
float c = 4;
@ -622,7 +622,7 @@ unittest
assert(v == 2 * 3 + 4);
}
unittest
@nogc nothrow pure @safe unittest
{
// https://issues.dlang.org/show_bug.cgi?id=17964
uint bug(){
@ -635,7 +635,7 @@ unittest
}
// https://issues.dlang.org/show_bug.cgi?id=19796
unittest
nothrow pure @safe unittest
{
double[] data = [0.5];
double[] result;
@ -645,7 +645,7 @@ unittest
}
// https://issues.dlang.org/show_bug.cgi?id=21110
unittest
pure unittest
{
import core.exception;
@ -668,3 +668,20 @@ unittest
void func() { dst[] = a[] + b[]; }
assertThrown!AssertError(func(), "Array operations with mismatched lengths must throw an error");
}
// https://issues.dlang.org/show_bug.cgi?id=24272
unittest
{
static struct B
{
B opOpAssign(string op)(B other)
{
static int g;
g++;
throw new Exception("");
}
}
B[] bArr;
bArr[] += B();
}

View file

@ -49,6 +49,8 @@ version (DigitalMars)
enum SizedReg(int reg, T = size_t) = registerNames[reg][RegIndex!T];
}
enum IsAtomicLockFree(T) = T.sizeof <= size_t.sizeof * 2;
inout(T) atomicLoad(MemoryOrder order = MemoryOrder.seq, T)(inout(T)* src) pure nothrow @nogc @trusted
if (CanCAS!T)
{
@ -649,6 +651,11 @@ version (DigitalMars)
}
}
void atomicSignalFence(MemoryOrder order = MemoryOrder.seq)() pure nothrow @nogc @trusted
{
// no-op, dmd doesn't reorder instructions
}
void pause() pure nothrow @nogc @trusted
{
version (D_InlineAsm_X86)
@ -681,37 +688,57 @@ else version (GNU)
import gcc.builtins;
import gcc.config;
// Targets where MemoryOrder.acq_rel is sufficiently cheaper than using
// MemoryOrder.seq, used when the MemoryOrder requested is not valid for
// a given atomic operation.
version (IA64)
private enum PreferAcquireRelease = true;
else version (PPC)
private enum PreferAcquireRelease = true;
else version (PPC64)
private enum PreferAcquireRelease = true;
else
private enum PreferAcquireRelease = false;
enum IsAtomicLockFree(T) = __atomic_is_lock_free(T.sizeof, null);
inout(T) atomicLoad(MemoryOrder order = MemoryOrder.seq, T)(inout(T)* src) pure nothrow @nogc @trusted
if (CanCAS!T)
{
// MemoryOrder.rel and MemoryOrder.acq_rel are not valid for load.
static assert(order != MemoryOrder.rel, "invalid MemoryOrder for atomicLoad()");
static if (order == MemoryOrder.acq_rel)
enum smodel = PreferAcquireRelease ? MemoryOrder.acq : MemoryOrder.seq;
else
enum smodel = order;
static if (GNU_Have_Atomics || GNU_Have_LibAtomic)
{
static if (T.sizeof == ubyte.sizeof)
{
ubyte value = __atomic_load_1(cast(shared)src, order);
ubyte value = __atomic_load_1(cast(shared)src, smodel);
return *cast(typeof(return)*)&value;
}
else static if (T.sizeof == ushort.sizeof)
{
ushort value = __atomic_load_2(cast(shared)src, order);
ushort value = __atomic_load_2(cast(shared)src, smodel);
return *cast(typeof(return)*)&value;
}
else static if (T.sizeof == uint.sizeof)
{
uint value = __atomic_load_4(cast(shared)src, order);
uint value = __atomic_load_4(cast(shared)src, smodel);
return *cast(typeof(return)*)&value;
}
else static if (T.sizeof == ulong.sizeof && GNU_Have_64Bit_Atomics)
{
ulong value = __atomic_load_8(cast(shared)src, order);
ulong value = __atomic_load_8(cast(shared)src, smodel);
return *cast(typeof(return)*)&value;
}
else static if (GNU_Have_LibAtomic)
{
T value;
__atomic_load(T.sizeof, cast(shared)src, &value, order);
__atomic_load(T.sizeof, cast(shared)src, &value, smodel);
return *cast(typeof(return)*)&value;
}
else
@ -728,20 +755,26 @@ else version (GNU)
void atomicStore(MemoryOrder order = MemoryOrder.seq, T)(T* dest, T value) pure nothrow @nogc @trusted
if (CanCAS!T)
{
// MemoryOrder.acq and MemoryOrder.acq_rel are not valid for store.
static assert(order != MemoryOrder.acq, "Invalid MemoryOrder for atomicStore()");
static if (order == MemoryOrder.acq_rel)
enum smodel = PreferAcquireRelease ? MemoryOrder.rel : MemoryOrder.seq;
else
enum smodel = order;
static if (GNU_Have_Atomics || GNU_Have_LibAtomic)
{
static if (T.sizeof == ubyte.sizeof)
__atomic_store_1(cast(shared)dest, *cast(ubyte*)&value, order);
__atomic_store_1(cast(shared)dest, *cast(ubyte*)&value, smodel);
else static if (T.sizeof == ushort.sizeof)
__atomic_store_2(cast(shared)dest, *cast(ushort*)&value, order);
__atomic_store_2(cast(shared)dest, *cast(ushort*)&value, smodel);
else static if (T.sizeof == uint.sizeof)
__atomic_store_4(cast(shared)dest, *cast(uint*)&value, order);
__atomic_store_4(cast(shared)dest, *cast(uint*)&value, smodel);
else static if (T.sizeof == ulong.sizeof && GNU_Have_64Bit_Atomics)
__atomic_store_8(cast(shared)dest, *cast(ulong*)&value, order);
__atomic_store_8(cast(shared)dest, *cast(ulong*)&value, smodel);
else static if (GNU_Have_LibAtomic)
__atomic_store(T.sizeof, cast(shared)dest, cast(void*)&value, order);
__atomic_store(T.sizeof, cast(shared)dest, cast(void*)&value, smodel);
else
static assert(0, "Invalid template type specified.");
}
@ -814,30 +847,36 @@ else version (GNU)
{
static if (GNU_Have_Atomics || GNU_Have_LibAtomic)
{
// MemoryOrder.acq is not valid for exchange.
static if (order == MemoryOrder.acq)
enum smodel = PreferAcquireRelease ? MemoryOrder.acq_rel : MemoryOrder.seq;
else
enum smodel = order;
static if (T.sizeof == byte.sizeof)
{
ubyte res = __atomic_exchange_1(cast(shared)dest, *cast(ubyte*)&value, order);
ubyte res = __atomic_exchange_1(cast(shared)dest, *cast(ubyte*)&value, smodel);
return *cast(typeof(return)*)&res;
}
else static if (T.sizeof == short.sizeof)
{
ushort res = __atomic_exchange_2(cast(shared)dest, *cast(ushort*)&value, order);
ushort res = __atomic_exchange_2(cast(shared)dest, *cast(ushort*)&value, smodel);
return *cast(typeof(return)*)&res;
}
else static if (T.sizeof == int.sizeof)
{
uint res = __atomic_exchange_4(cast(shared)dest, *cast(uint*)&value, order);
uint res = __atomic_exchange_4(cast(shared)dest, *cast(uint*)&value, smodel);
return *cast(typeof(return)*)&res;
}
else static if (T.sizeof == long.sizeof && GNU_Have_64Bit_Atomics)
{
ulong res = __atomic_exchange_8(cast(shared)dest, *cast(ulong*)&value, order);
ulong res = __atomic_exchange_8(cast(shared)dest, *cast(ulong*)&value, smodel);
return *cast(typeof(return)*)&res;
}
else static if (GNU_Have_LibAtomic)
{
T res = void;
__atomic_exchange(T.sizeof, cast(shared)dest, cast(void*)&value, &res, order);
__atomic_exchange(T.sizeof, cast(shared)dest, cast(void*)&value, &res, smodel);
return res;
}
else
@ -885,21 +924,42 @@ else version (GNU)
static if (GNU_Have_Atomics || GNU_Have_LibAtomic)
{
static if (fail == MemoryOrder.rel || fail == MemoryOrder.acq_rel)
{
// MemoryOrder.rel and MemoryOrder.acq_rel are not valid failure models.
enum smodel = (succ != MemoryOrder.seq && PreferAcquireRelease)
? MemoryOrder.acq_rel : MemoryOrder.seq;
enum fmodel = (succ != MemoryOrder.seq && PreferAcquireRelease)
? MemoryOrder.raw : MemoryOrder.seq;
}
else static if (fail > succ)
{
// Failure memory model cannot be stronger than success.
enum smodel = (fail != MemoryOrder.seq && PreferAcquireRelease)
? MemoryOrder.acq_rel : MemoryOrder.seq;
enum fmodel = fail;
}
else
{
enum smodel = succ;
enum fmodel = fail;
}
static if (T.sizeof == byte.sizeof)
res = __atomic_compare_exchange_1(cast(shared)dest, compare, *cast(ubyte*)&value,
weak, succ, fail);
weak, smodel, fmodel);
else static if (T.sizeof == short.sizeof)
res = __atomic_compare_exchange_2(cast(shared)dest, compare, *cast(ushort*)&value,
weak, succ, fail);
weak, smodel, fmodel);
else static if (T.sizeof == int.sizeof)
res = __atomic_compare_exchange_4(cast(shared)dest, compare, *cast(uint*)&value,
weak, succ, fail);
weak, smodel, fmodel);
else static if (T.sizeof == long.sizeof && GNU_Have_64Bit_Atomics)
res = __atomic_compare_exchange_8(cast(shared)dest, compare, *cast(ulong*)&value,
weak, succ, fail);
weak, smodel, fmodel);
else static if (GNU_Have_LibAtomic)
res = __atomic_compare_exchange(T.sizeof, cast(shared)dest, compare, cast(void*)&value,
succ, fail);
smodel, fmodel);
else
static assert(0, "Invalid template type specified.");
}
@ -945,6 +1005,11 @@ else version (GNU)
}
}
void atomicSignalFence(MemoryOrder order = MemoryOrder.seq)() pure nothrow @nogc @trusted
{
__atomic_signal_fence(order);
}
void pause() pure nothrow @nogc @trusted
{
version (X86)

File diff suppressed because it is too large Load diff

View file

@ -2129,6 +2129,13 @@ extern (C) void thread_init() @nogc nothrow
static extern(C) void initChildAfterFork()
{
auto thisThread = Thread.getThis();
if (!thisThread)
{
// It is possible that runtime was not properly initialized in the current process or thread -
// it may happen after `fork` call when using a dynamically loaded shared library written in D from a multithreaded non-D program.
// In such case getThis will return null.
return;
}
thisThread.m_addr = pthread_self();
assert( thisThread.m_addr != thisThread.m_addr.init );
thisThread.m_tmach = pthread_mach_thread_np( thisThread.m_addr );

View file

@ -526,6 +526,12 @@ unittest
private extern(C) void _d_setSameMutex(shared Object ownee, shared Object owner) nothrow;
/** Makes ownee use owner's mutex.
* This will initialize owner's mutex if it hasn't been set yet.
* Params:
* ownee = object to change
* owner = source object
*/
void setSameMutex(shared Object ownee, shared Object owner)
{
import core.atomic : atomicLoad;