diff options
Diffstat (limited to 'gcc/d')
58 files changed, 1447 insertions, 1265 deletions
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 0cf9b5f..aa0062c 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -65a3da148c0c700a6c928f0e13799b2a7d34fcbe +ff57fec51558013b25cadb7e83da9f4675915d56 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index b272d4b..41fdc65 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.106.0-beta.1 +v2.106.0-rc.1 diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d index d42ef951..307bb01 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -663,7 +663,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol */ extern (D) final Dsymbol searchCtor() { - auto s = search(Loc.initial, Id.ctor); + auto s = this.search(Loc.initial, Id.ctor); if (s) { if (!(s.isCtorDeclaration() || diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h index 58a0126..cd8f1a1 100644 --- a/gcc/d/dmd/aggregate.h +++ b/gcc/d/dmd/aggregate.h @@ -167,7 +167,6 @@ private: public: static StructDeclaration *create(const Loc &loc, Identifier *id, bool inObject); StructDeclaration *syntaxCopy(Dsymbol *s) override; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final; const char *kind() const override; void finalizeSize() override final; bool isPOD(); @@ -285,7 +284,6 @@ public: virtual bool isBaseOf(ClassDeclaration *cd, int *poffset); bool isBaseInfoComplete(); - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final; void finalizeSize() override; bool hasMonitor(); bool isFuncHidden(FuncDeclaration *fd); diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d index 77f36f3..6a9c010 100644 --- a/gcc/d/dmd/astenums.d +++ b/gcc/d/dmd/astenums.d @@ -383,6 +383,7 @@ enum STMT : ubyte enum InitKind : ubyte { void_, + default_, error, struct_, array, diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index 49fc308..251e2e8 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -32,7 +32,7 @@ import dmd.declaration; import dmd.dmodule; import dmd.dscope; import dmd.dsymbol; -import dmd.dsymbolsem : dsymbolSemantic; +import dmd.dsymbolsem; import dmd.errors; import dmd.expression; import dmd.expressionsem; @@ -123,18 +123,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol return sc; } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - Dsymbols* d = include(sc); - if (d) - { - Scope* sc2 = newScope(sc); - d.foreachDsymbol( s => s.addMember(sc2, sds) ); - if (sc2 != sc) - sc2.pop(); - } - } - override void setScope(Scope* sc) { Dsymbols* d = include(sc); @@ -295,34 +283,6 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration return t; } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - Dsymbols* d = include(sc); - if (d) - { - Scope* sc2 = newScope(sc); - - d.foreachDsymbol( (s) - { - //printf("\taddMember %s to %s\n", s.toChars(), sds.toChars()); - // STC.local needs to be attached before the member is added to the scope (because it influences the parent symbol) - if (auto decl = s.isDeclaration()) - { - decl.storage_class |= stc & STC.local; - if (auto sdecl = s.isStorageClassDeclaration()) // TODO: why is this not enough to deal with the nested case? - { - sdecl.stc |= stc & STC.local; - } - } - s.addMember(sc2, sds); - }); - - if (sc2 != sc) - sc2.pop(); - } - - } - override inout(StorageClassDeclaration) isStorageClassDeclaration() inout { return this; @@ -640,37 +600,6 @@ extern (C++) final class VisibilityDeclaration : AttribDeclaration return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.visibility, 1, sc.aligndecl, sc.inlining); } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - if (pkg_identifiers) - { - Dsymbol tmp; - Package.resolve(pkg_identifiers, &tmp, null); - visibility.pkg = tmp ? tmp.isPackage() : null; - pkg_identifiers = null; - } - if (visibility.kind == Visibility.Kind.package_ && visibility.pkg && sc._module) - { - Module m = sc._module; - - // https://issues.dlang.org/show_bug.cgi?id=17441 - // While isAncestorPackageOf does an equality check, the fix for the issue adds a check to see if - // each package's .isModule() properites are equal. - // - // Properties generated from `package(foo)` i.e. visibility.pkg have .isModule() == null. - // This breaks package declarations of the package in question if they are declared in - // the same package.d file, which _do_ have a module associated with them, and hence a non-null - // isModule() - if (!m.isPackage() || !visibility.pkg.ident.equals(m.isPackage().ident)) - { - Package pkg = m.parent ? m.parent.isPackage() : null; - if (!pkg || !visibility.pkg.isAncestorPackageOf(pkg)) - .error(loc, "%s `%s` does not bind to one of ancestor packages of module `%s`", kind(), toPrettyChars(false), m.toPrettyChars(true)); - } - } - return AttribDeclaration.addMember(sc, sds); - } - override const(char)* kind() const { return "visibility attribute"; @@ -1054,23 +983,6 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration } } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - //printf("StaticIfDeclaration::addMember() '%s'\n", toChars()); - /* This is deferred until the condition evaluated later (by the include() call), - * so that expressions in the condition can refer to declarations - * in the same scope, such as: - * - * template Foo(int i) - * { - * const int j = i + 1; - * static if (j == 3) - * const int k; - * } - */ - this.scopesym = sds; - } - override void setScope(Scope* sc) { // do not evaluate condition before semantic pass @@ -1186,12 +1098,6 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration return d; } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - // used only for caching the enclosing symbol - this.scopesym = sds; - } - override void addComment(const(char)* comment) { // do nothing @@ -1266,15 +1172,6 @@ extern(C++) final class ForwardingAttribDeclaration : AttribDeclaration return sc.push(sym); } - /*************************************** - * Lazily initializes the scope to forward to. - */ - override void addMember(Scope* sc, ScopeDsymbol sds) - { - sym.parent = sds; - return super.addMember(sc, sym); - } - override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout { return this; @@ -1312,12 +1209,6 @@ extern (C++) final class MixinDeclaration : AttribDeclaration return new MixinDeclaration(loc, Expression.arraySyntaxCopy(exps)); } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - //printf("MixinDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum); - this.scopesym = sds; - } - override void setScope(Scope* sc) { Dsymbol.setScope(sc); diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h index f47a1f6..efea9af 100644 --- a/gcc/d/dmd/attrib.h +++ b/gcc/d/dmd/attrib.h @@ -26,7 +26,6 @@ public: virtual Dsymbols *include(Scope *sc); virtual Scope *newScope(Scope *sc); - void addMember(Scope *sc, ScopeDsymbol *sds) override; void setScope(Scope *sc) override; void importAll(Scope *sc) override; void addComment(const utf8_t *comment) override; @@ -49,7 +48,6 @@ public: StorageClassDeclaration *syntaxCopy(Dsymbol *s) override; Scope *newScope(Scope *sc) override; bool oneMember(Dsymbol **ps, Identifier *ident) override final; - void addMember(Scope *sc, ScopeDsymbol *sds) override; StorageClassDeclaration *isStorageClassDeclaration() override { return this; } void accept(Visitor *v) override { v->visit(this); } @@ -110,7 +108,6 @@ public: VisibilityDeclaration *syntaxCopy(Dsymbol *s) override; Scope *newScope(Scope *sc) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; const char *kind() const override; const char *toPrettyChars(bool unused) override; VisibilityDeclaration *isVisibilityDeclaration() override { return this; } @@ -179,7 +176,6 @@ public: StaticIfDeclaration *syntaxCopy(Dsymbol *s) override; Dsymbols *include(Scope *sc) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; void setScope(Scope *sc) override; void importAll(Scope *sc) override; StaticIfDeclaration *isStaticIfDeclaration() override { return this; } @@ -199,7 +195,6 @@ public: StaticForeachDeclaration *syntaxCopy(Dsymbol *s) override; bool oneMember(Dsymbol **ps, Identifier *ident) override; Dsymbols *include(Scope *sc) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; void addComment(const utf8_t *comment) override; void setScope(Scope *sc) override; void importAll(Scope *sc) override; @@ -213,7 +208,6 @@ public: ForwardingScopeDsymbol *sym; Scope *newScope(Scope *sc) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; ForwardingAttribDeclaration *isForwardingAttribDeclaration() override { return this; } void accept(Visitor *v) override { v->visit(this); } }; @@ -229,7 +223,6 @@ public: d_bool compiled; MixinDeclaration *syntaxCopy(Dsymbol *s) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; void setScope(Scope *sc) override; const char *kind() const override; void accept(Visitor *v) override { v->visit(this); } diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d index b8ad785..4e7a82f 100644 --- a/gcc/d/dmd/common/outbuffer.d +++ b/gcc/d/dmd/common/outbuffer.d @@ -281,7 +281,7 @@ struct OutBuffer write(&v, v.sizeof); } - /// NOT zero-terminated + /// Buffer will NOT be zero-terminated extern (C++) void writestring(const(char)* s) pure nothrow @system { if (!s) @@ -302,14 +302,14 @@ struct OutBuffer write(s); } - /// NOT zero-terminated, followed by newline + /// Buffer will NOT be zero-terminated, followed by newline void writestringln(const(char)[] s) pure nothrow @safe { writestring(s); writenl(); } - /** Write string to buffer, ensure it is zero terminated + /** Write C string AND null byte */ void writeStringz(const(char)* s) pure nothrow @system { diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index f0c8349..ed5f1f8 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -2168,6 +2168,7 @@ final class CParser(AST) : Parser!AST * C11 Initialization * initializer: * assignment-expression + * { } // C23 6.7.10 addition * { initializer-list } * { initializer-list , } * @@ -2198,6 +2199,12 @@ final class CParser(AST) : Parser!AST nextToken(); const loc = token.loc; + if (token.value == TOK.rightCurly) // { } + { + nextToken(); + return new AST.DefaultInitializer(loc); + } + /* Collect one or more `designation (opt) initializer` * into ci.initializerList, but lazily create ci */ diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index c93269f..43efc05 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -28,6 +28,7 @@ import dmd.func; import dmd.globals; import dmd.location; import dmd.mtype; +import dmd.root.bitarray; import dmd.root.complex; import dmd.root.ctfloat; import dmd.root.port; @@ -43,14 +44,14 @@ import dmd.visitor; extern (D) struct UnionExp { // yes, default constructor does nothing - extern (D) this(Expression e) + extern (D) this(Expression e) nothrow { memcpy(&this, cast(void*)e, e.size); } /* Extract pointer to Expression */ - extern (D) Expression exp() return + extern (D) Expression exp() return nothrow { return cast(Expression)&u; } @@ -109,7 +110,7 @@ void emplaceExp(T : Expression, Args...)(void* p, Args args) (cast(T)p).__ctor(args); } -void emplaceExp(T : UnionExp)(T* p, Expression e) +void emplaceExp(T : UnionExp)(T* p, Expression e) nothrow { memcpy(p, cast(void*)e, e.size); } @@ -134,7 +135,7 @@ void generateUncaughtError(ThrownExceptionExp tee) * Returns: * index of the field, or -1 if not found */ -int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pure @safe +int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pure @safe nothrow { foreach (i, field; sd.fields) { @@ -145,7 +146,7 @@ int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pur } // True if 'e' is CTFEExp::cantexp, or an exception -bool exceptionOrCantInterpret(const Expression e) @safe +bool exceptionOrCantInterpret(const Expression e) @safe nothrow { return e && (e.op == EXP.cantExpression || e.op == EXP.thrownException || e.op == EXP.showCtfeContext); } @@ -153,7 +154,7 @@ bool exceptionOrCantInterpret(const Expression e) @safe /************** Aggregate literals (AA/string/array/struct) ******************/ // Given expr, which evaluates to an array/AA/string literal, // return true if it needs to be copied -bool needToCopyLiteral(const Expression expr) +bool needToCopyLiteral(const Expression expr) nothrow { Expression e = cast()expr; for (;;) @@ -593,7 +594,7 @@ TypeAArray toBuiltinAAType(Type t) /************** TypeInfo operations ************************************/ // Return true if type is TypeInfo_Class -bool isTypeInfo_Class(const Type type) +bool isTypeInfo_Class(const Type type) nothrow { auto tc = cast()type.isTypeClass(); return tc && (Type.dtypeinfo == tc.sym || Type.dtypeinfo.isBaseOf(tc.sym, null)); @@ -741,14 +742,14 @@ Expression pointerDifference(UnionExp* pue, const ref Loc loc, Type type, Expres Expression agg2 = getAggregateFromPointer(e2, &ofs2); if (agg1 == agg2) { - Type pointee = (cast(TypePointer)agg1.type).next; + Type pointee = agg1.type.nextOf(); const sz = pointee.size(); emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type); } else if (agg1.op == EXP.string_ && agg2.op == EXP.string_ && agg1.isStringExp().peekString().ptr == agg2.isStringExp().peekString().ptr) { - Type pointee = (cast(TypePointer)agg1.type).next; + Type pointee = agg1.type.nextOf(); const sz = pointee.size(); emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type); } @@ -794,14 +795,14 @@ Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type goto Lcant; } dinteger_t ofs2 = e2.toInteger(); - Type pointee = (cast(TypeNext)agg1.type.toBasetype()).next; + Type pointee = agg1.type.toBasetype().nextOf(); dinteger_t sz = pointee.size(); sinteger_t indx; dinteger_t len; - if (agg1.op == EXP.symbolOffset) + if (auto soe = agg1.isSymOffExp()) { indx = ofs1 / sz; - len = (cast(TypeSArray)agg1.isSymOffExp().var.type).dim.toInteger(); + len = soe.var.type.isTypeSArray().dim.toInteger(); } else { @@ -836,9 +837,9 @@ Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type error(loc, "CTFE internal error: pointer arithmetic `%s`", agg1.toChars()); goto Lcant; } - if (eptr.type.toBasetype().ty == Tsarray) + if (auto tsa = eptr.type.toBasetype().isTypeSArray()) { - dinteger_t dim = (cast(TypeSArray)eptr.type.toBasetype()).dim.toInteger(); + dinteger_t dim = tsa.dim.toInteger(); // Create a CTFE pointer &agg1[indx .. indx+dim] auto se = ctfeEmplaceExp!SliceExp(loc, agg1, ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t), @@ -978,7 +979,7 @@ bool isCtfeComparable(Expression e) } /// Map EXP comparison ops -private bool numCmp(N)(EXP op, N n1, N n2) +private bool numCmp(N)(EXP op, N n1, N n2) nothrow { switch (op) { @@ -997,25 +998,25 @@ private bool numCmp(N)(EXP op, N n1, N n2) } /// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1 -bool specificCmp(EXP op, int rawCmp) @safe +bool specificCmp(EXP op, int rawCmp) @safe nothrow { return numCmp!int(op, rawCmp, 0); } /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1 -bool intUnsignedCmp(EXP op, dinteger_t n1, dinteger_t n2) @safe +bool intUnsignedCmp(EXP op, dinteger_t n1, dinteger_t n2) @safe nothrow { return numCmp!dinteger_t(op, n1, n2); } /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1 -bool intSignedCmp(EXP op, sinteger_t n1, sinteger_t n2) @safe +bool intSignedCmp(EXP op, sinteger_t n1, sinteger_t n2) @safe nothrow { return numCmp!sinteger_t(op, n1, n2); } /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1 -bool realCmp(EXP op, real_t r1, real_t r2) @safe +bool realCmp(EXP op, real_t r1, real_t r2) @safe nothrow { // Don't rely on compiler, handle NAN arguments separately if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered @@ -1105,7 +1106,7 @@ private int ctfeCmpArrays(const ref Loc loc, Expression e1, Expression e2, uinte /* Given a delegate expression e, return .funcptr. * If e is NullExp, return NULL. */ -private FuncDeclaration funcptrOf(Expression e) @safe +private FuncDeclaration funcptrOf(Expression e) @safe nothrow { assert(e.type.ty == Tdelegate); if (auto de = e.isDelegateExp()) @@ -1116,7 +1117,7 @@ private FuncDeclaration funcptrOf(Expression e) @safe return null; } -private bool isArray(const Expression e) @safe +private bool isArray(const Expression e) @safe nothrow { return e.op == EXP.arrayLiteral || e.op == EXP.string_ || e.op == EXP.slice || e.op == EXP.null_; } @@ -1270,8 +1271,8 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide size_t dim = es1.keys.length; if (es2.keys.length != dim) return 1; - bool* used = cast(bool*)mem.xmalloc(bool.sizeof * dim); - memset(used, 0, bool.sizeof * dim); + BitArray used; + used.length = dim; foreach (size_t i; 0 .. dim) { Expression k1 = (*es1.keys)[i]; @@ -1290,11 +1291,9 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide } if (!v2 || ctfeRawCmp(loc, v1, v2, identity)) { - mem.xfree(used); return 1; } } - mem.xfree(used); return 0; } else if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.null_) @@ -2000,9 +1999,8 @@ void showCtfeExpr(Expression e, int level = 0) UnionExp voidInitLiteral(Type t, VarDeclaration var) { UnionExp ue; - if (t.ty == Tsarray) + if (auto tsa = t.isTypeSArray()) { - TypeSArray tsa = cast(TypeSArray)t; Expression elem = voidInitLiteral(tsa.next, var).copy(); // For aggregate value types (structs, static arrays) we must // create an a separate copy for each element. @@ -2019,9 +2017,8 @@ UnionExp voidInitLiteral(Type t, VarDeclaration var) ArrayLiteralExp ae = ue.exp().isArrayLiteralExp(); ae.ownedByCtfe = OwnedBy.ctfe; } - else if (t.ty == Tstruct) + else if (auto ts = t.isTypeStruct()) { - TypeStruct ts = cast(TypeStruct)t; auto exps = new Expressions(ts.sym.fields.length); foreach (size_t i; 0 .. ts.sym.fields.length) { diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index eb3890b..14c67f0 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -1631,6 +1631,13 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) } else if (tob.ty == Tvector && t1b.ty != Tvector) { + if (t1b.ty == Tsarray) + { + // Casting static array to vector with same size, e.g. `cast(int4) int[4]` + if (t1b.size(e.loc) != tob.size(e.loc)) + goto Lfail; + return new VectorExp(e.loc, e, tob).expressionSemantic(sc); + } //printf("test1 e = %s, e.type = %s, tob = %s\n", e.toChars(), e.type.toChars(), tob.toChars()); TypeVector tv = tob.isTypeVector(); Expression result = new CastExp(e.loc, e, tv.elementType()); diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index bae942c..72b85cf 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -180,7 +180,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration int cppDtorVtblIndex = -1; /// to prevent recursive attempts - private bool inuse; + bool inuse; ThreeState isabstract; @@ -367,7 +367,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration baseok = Baseok.none; } - extern (D) private void classError(const(char)* fmt, const(char)* arg) + extern (D) final void classError(const(char)* fmt, const(char)* arg) { .error(loc, fmt, kind, toPrettyChars, arg); } @@ -468,67 +468,6 @@ extern (C++) class ClassDeclaration : AggregateDeclaration return baseok >= Baseok.done; } - override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", toChars(), ident.toChars(), flags); - //if (_scope) printf("%s baseok = %d\n", toChars(), baseok); - if (_scope && baseok < Baseok.semanticdone) - { - if (!inuse) - { - // must semantic on base class/interfaces - inuse = true; - dsymbolSemantic(this, null); - inuse = false; - } - } - - if (!members || !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) && semanticRun < PASS.semanticdone) - classError("%s `%s` is forward referenced when looking for `%s`", ident.toChars()); - //*(char*)0=0; - return null; - } - - auto s = ScopeDsymbol.search(loc, ident, flags); - - // don't search imports of base classes - if (flags & SearchImportsOnly) - return s; - - if (s) - return s; - - // Search bases classes in depth-first, left to right order - foreach (b; (*baseclasses)[]) - { - if (!b.sym) - continue; - - if (!b.sym.symtab) - { - classError("%s `%s` base `%s` is forward referenced", b.sym.ident.toChars()); - continue; - } - - import dmd.access : symbolIsVisible; - - s = b.sym.search(loc, ident, flags); - if (!s) - continue; - else if (s == this) // happens if s is nested in this and derives from this - s = null; - else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(this, s)) - s = null; - else - break; - } - - return s; - } - /************************************ * Search base classes in depth-first, left-to-right order for * a class or interface named 'ident'. @@ -675,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 = search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors); + Dsymbol s = this.search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors); if (!s) { //printf("not found\n"); diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 76a31f4..0e125fd 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -421,18 +421,6 @@ extern (C++) abstract class Declaration : Dsymbol return Modifiable.yes; } - override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - Dsymbol s = Dsymbol.search(loc, ident, flags); - if (!s && type) - { - s = type.toDsymbol(_scope); - if (s) - s = s.search(loc, ident, flags); - } - return s; - } - final bool isStatic() const pure nothrow @nogc @safe { return (storage_class & STC.static_) != 0; diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 8cd295f..a65fb44 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -124,7 +124,6 @@ public: const char *kind() const override; uinteger_t size(const Loc &loc) override final; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final; bool isStatic() const { return (storage_class & STCstatic) != 0; } LINK resolvedLinkage() const; // returns the linkage, resolving the target-specific `System` one diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d index f33b5fd..797f6ee 100644 --- a/gcc/d/dmd/denum.d +++ b/gcc/d/dmd/denum.d @@ -83,25 +83,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol return ed; } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - version (none) - { - printf("EnumDeclaration::addMember() %s\n", toChars()); - for (size_t i = 0; i < members.length; i++) - { - EnumMember em = (*members)[i].isEnumMember(); - printf(" member %s\n", em.toChars()); - } - } - if (!isAnonymous()) - { - ScopeDsymbol.addMember(sc, sds); - } - - addEnumMembersToSymtab(this, sc, sds); - } - override void setScope(Scope* sc) { if (semanticRun > PASS.initial) @@ -126,19 +107,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol return "enum"; } - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident.toChars()); - if (_scope) - { - // Try one last time to resolve this enum - dsymbolSemantic(this, _scope); - } - - Dsymbol s = ScopeDsymbol.search(loc, ident, flags); - return s; - } - // is Dsymbol deprecated? override bool isDeprecated() const { diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d index d74c860..0132e49 100644 --- a/gcc/d/dmd/dimport.d +++ b/gcc/d/dmd/dimport.d @@ -305,33 +305,6 @@ extern (C++) final class Import : Dsymbol return this; } - /***************************** - * Add import to sd's symbol table. - */ - override void addMember(Scope* sc, ScopeDsymbol sd) - { - //printf("Import.addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd.toChars(), sc); - if (names.length == 0) - return Dsymbol.addMember(sc, sd); - if (aliasId) - Dsymbol.addMember(sc, sd); - /* Instead of adding the import to sd's symbol table, - * add each of the alias=name pairs - */ - for (size_t i = 0; i < names.length; i++) - { - Identifier name = names[i]; - Identifier _alias = aliases[i]; - if (!_alias) - _alias = name; - auto tname = new TypeIdentifier(loc, name); - auto ad = new AliasDeclaration(loc, _alias, tname); - ad._import = this; - ad.addMember(sc, sd); - aliasdecls.push(ad); - } - } - override void setScope(Scope* sc) { Dsymbol.setScope(sc); @@ -348,19 +321,6 @@ extern (C++) final class Import : Dsymbol } } - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("%s.Import.search(ident = '%s', flags = x%x)\n", toChars(), ident.toChars(), flags); - if (!pkg) - { - load(null); - mod.importAll(null); - mod.dsymbolSemantic(null); - } - // Forward it to the package/module - return pkg.search(loc, ident, flags); - } - override bool overloadInsert(Dsymbol s) { /* Allow multiple imports with the same package base, but disallow diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index e6dde18..5f5de63 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -268,22 +268,6 @@ extern (C++) class Package : ScopeDsymbol return isAncestorPackageOf(pkg.parent.isPackage()); } - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("%s Package.search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags); - flags &= ~SearchLocalsOnly; // searching an import is always transitive - if (!isModule() && mod) - { - // Prefer full package name. - Dsymbol s = symtab ? symtab.lookup(ident) : null; - if (s) - return s; - //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars()); - return mod.search(loc, ident, flags); - } - return ScopeDsymbol.search(loc, ident, flags); - } - override void accept(Visitor v) { v.visit(this); @@ -414,10 +398,10 @@ extern (C++) final class Module : Package return rootimports == ThreeState.yes; } - private Identifier searchCacheIdent; - private Dsymbol searchCacheSymbol; // cached value of search - private int searchCacheFlags; // cached flags - private bool insearch; + Identifier searchCacheIdent; + Dsymbol searchCacheSymbol; // cached value of search + int searchCacheFlags; // cached flags + bool insearch; /** * A root module is one that will be compiled all the way to @@ -1036,47 +1020,6 @@ extern (C++) final class Module : Package } } - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - /* Since modules can be circularly referenced, - * need to stop infinite recursive searches. - * This is done with the cache. - */ - //printf("%s Module.search('%s', flags = x%x) insearch = %d\n", toChars(), ident.toChars(), flags, insearch); - if (insearch) - return null; - - /* Qualified module searches always search their imports, - * even if SearchLocalsOnly - */ - if (!(flags & SearchUnqualifiedModule)) - flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly); - - if (searchCacheIdent == ident && searchCacheFlags == flags) - { - //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n", - // toChars(), ident.toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol.toChars() : "null"); - return searchCacheSymbol; - } - - uint errors = global.errors; - - insearch = true; - Dsymbol s = ScopeDsymbol.search(loc, ident, flags); - insearch = false; - - if (errors == global.errors) - { - // https://issues.dlang.org/show_bug.cgi?id=10752 - // Can cache the result only when it does not cause - // access error so the side-effect should be reproduced in later search. - searchCacheIdent = ident; - searchCacheSymbol = s; - searchCacheFlags = flags; - } - return s; - } - override bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) { if (insearch) // don't follow import cycles diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index 3853512..d68bcda 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -66,13 +66,15 @@ enum SCOPE fullinst = 0x10000, /// fully instantiate templates ctfeBlock = 0x20000, /// inside a `if (__ctfe)` block + dip1000 = 0x40000, /// dip1000 errors enabled for this scope + dip25 = 0x80000, /// dip25 errors enabled for this scope } /// Flags that are carried along with a scope push() private enum PersistentFlags = SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint | SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility | - SCOPE.Cfile | SCOPE.ctfeBlock; + SCOPE.Cfile | SCOPE.ctfeBlock | SCOPE.dip1000 | SCOPE.dip25; extern (C++) struct Scope { @@ -176,6 +178,10 @@ extern (C++) struct Scope m = m.parent; m.addMember(null, sc.scopesym); m.parent = null; // got changed by addMember() + if (global.params.useDIP1000 == FeatureState.enabled) + sc.flags |= SCOPE.dip1000; + if (global.params.useDIP25 == FeatureState.enabled) + sc.flags |= SCOPE.dip25; if (_module.filetype == FileType.c) sc.flags |= SCOPE.Cfile; // Create the module scope underneath the global scope @@ -344,7 +350,7 @@ extern (C++) struct Scope * Returns: * symbol if found, null if not */ - extern (D) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone) + extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone) { version (LOGSEARCH) { @@ -821,4 +827,16 @@ extern (C++) struct Scope { return (flags & (SCOPE.ctfe | SCOPE.ctfeBlock | SCOPE.compile)) == 0; } + + /// Returns: whether to raise DIP1000 warnings (FeatureStabe.default) or errors (FeatureState.enabled) + extern (D) FeatureState useDIP1000() + { + return (flags & SCOPE.dip1000) ? FeatureState.enabled : FeatureState.disabled; + } + + /// Returns: whether to raise DIP25 warnings (FeatureStabe.default) or errors (FeatureState.enabled) + extern (D) FeatureState useDIP25() + { + return (flags & SCOPE.dip25) ? FeatureState.enabled : FeatureState.disabled; + } } diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index f77a263..36e847c 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -263,23 +263,6 @@ extern (C++) class StructDeclaration : AggregateDeclaration return sd; } - override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags); - if (_scope && !symtab) - dsymbolSemantic(this, _scope); - - if (!members || !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) && semanticRun < PASS.semanticdone) - .error(loc, "%s `%s` is forward referenced when looking for `%s`", kind, toPrettyChars, ident.toChars()); - return null; - } - - return ScopeDsymbol.search(loc, ident, flags); - } - override const(char)* kind() const { return "struct"; diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 914213c..a52745f 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -35,7 +35,6 @@ import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; -import dmd.expressionsem; import dmd.func; import dmd.globals; import dmd.id; @@ -750,67 +749,6 @@ extern (C++) class Dsymbol : ASTNode return toAlias(); } - void addMember(Scope* sc, ScopeDsymbol sds) - { - //printf("Dsymbol::addMember('%s')\n", toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars()); - //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab); - parent = sds; - if (isAnonymous()) // no name, so can't add it to symbol table - return; - - if (!sds.symtabInsert(this)) // if name is already defined - { - if (isAliasDeclaration() && !_scope) - setScope(sc); - Dsymbol s2 = sds.symtabLookup(this,ident); - /* https://issues.dlang.org/show_bug.cgi?id=17434 - * - * If we are trying to add an import to the symbol table - * that has already been introduced, then keep the one with - * larger visibility. This is fine for imports because if - * we have multiple imports of the same file, if a single one - * is public then the symbol is reachable. - */ - if (auto i1 = isImport()) - { - if (auto i2 = s2.isImport()) - { - if (sc.explicitVisibility && sc.visibility > i2.visibility) - sds.symtab.update(this); - } - } - - // If using C tag/prototype/forward declaration rules - if (sc.flags & SCOPE.Cfile && !this.isImport()) - { - if (handleTagSymbols(*sc, this, s2, sds)) - return; - if (handleSymbolRedeclarations(*sc, this, s2, sds)) - return; - - sds.multiplyDefined(Loc.initial, this, s2); // ImportC doesn't allow overloading - errors = true; - return; - } - - if (!s2.overloadInsert(this)) - { - sds.multiplyDefined(Loc.initial, this, s2); - errors = true; - } - } - if (sds.isAggregateDeclaration() || sds.isEnumDeclaration()) - { - if (ident == Id.__sizeof || - !(sc && sc.flags & SCOPE.Cfile) && (ident == Id.__xalignof || ident == Id._mangleof)) - { - .error(loc, "%s `%s` `.%s` property cannot be redefined", kind, toPrettyChars, ident.toChars()); - errors = true; - } - } - } - /************************************* * Set scope for future semantic analysis so we can * deal better with forward references. @@ -831,21 +769,6 @@ extern (C++) class Dsymbol : ASTNode { } - /********************************************* - * Search for ident as member of s. - * Params: - * loc = location to print for error messages - * ident = identifier to search for - * flags = IgnoreXXXX - * Returns: - * null if not found - */ - Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone) - { - //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars()); - return null; - } - extern (D) final Dsymbol search_correct(Identifier ident) { /*************************************************** @@ -870,7 +793,7 @@ extern (C++) class Dsymbol : ASTNode if (global.gag) return null; // don't do it for speculative compiles; too time consuming // search for exact name first - if (auto s = search(Loc.initial, ident, IgnoreErrors)) + if (auto s = this.search(Loc.initial, ident, IgnoreErrors)) return s; return speller!symbol_search_fp(ident.toString()); } @@ -1339,12 +1262,12 @@ extern (C++) class ScopeDsymbol : Dsymbol Dsymbols* members; // all Dsymbol's in this scope DsymbolTable symtab; // members[] sorted into table uint endlinnum; // the linnumber of the statement after the scope (0 if unknown) - -private: /// symbols whose members have been imported, i.e. imported modules and template mixins Dsymbols* importedScopes; Visibility.Kind* visibilities; // array of Visibility.Kind, one for each import +private: + import dmd.root.bitarray; BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages @@ -1373,166 +1296,7 @@ public: return sds; } - /***************************************** - * This function is #1 on the list of functions that eat cpu time. - * Be very, very careful about slowing it down. - */ - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags); - //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0; - - // Look in symbols declared in this module - if (symtab && !(flags & SearchImportsOnly)) - { - //printf(" look in locals\n"); - auto s1 = symtab.lookup(ident); - if (s1) - { - //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars()); - return s1; - } - } - //printf(" not found in locals\n"); - - // Look in imported scopes - if (!importedScopes) - return null; - - //printf(" look in imports\n"); - Dsymbol s = null; - OverloadSet a = null; - // Look in imported modules - for (size_t i = 0; i < importedScopes.length; i++) - { - // If private import, don't search it - if ((flags & IgnorePrivateImports) && visibilities[i] == Visibility.Kind.private_) - continue; - int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches - Dsymbol ss = (*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) - continue; - } - else // mixin template - { - if (flags & SearchImportsOnly) - continue; - - sflags |= SearchLocalsOnly; - } - - /* Don't find private members if ss is a module - */ - Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone)); - import dmd.access : symbolIsVisible; - if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2)) - continue; - if (!s) - { - s = s2; - if (s && s.isOverloadSet()) - a = mergeOverloadSet(ident, a, s); - } - else if (s2 && s != s2) - { - if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType()) - { - /* After following aliases, we found the same - * symbol, so it's not an ambiguity. But if one - * alias is deprecated or less accessible, prefer - * the other. - */ - if (s.isDeprecated() || s.visible() < s2.visible() && s2.visible().kind != Visibility.Kind.none) - s = s2; - } - else - { - /* Two imports of the same module should be regarded as - * the same. - */ - Import i1 = s.isImport(); - Import i2 = s2.isImport(); - if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident))))) - { - /* https://issues.dlang.org/show_bug.cgi?id=8668 - * Public selective import adds AliasDeclaration in module. - * To make an overload set, resolve aliases in here and - * get actual overload roots which accessible via s and s2. - */ - s = s.toAlias(); - s2 = s2.toAlias(); - /* If both s2 and s are overloadable (though we only - * need to check s once) - */ - - auto so2 = s2.isOverloadSet(); - if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable())) - { - if (symbolIsVisible(this, s2)) - { - a = mergeOverloadSet(ident, a, s2); - } - if (!symbolIsVisible(this, s)) - s = s2; - continue; - } - - /* Two different overflow sets can have the same members - * https://issues.dlang.org/show_bug.cgi?id=16709 - */ - auto so = s.isOverloadSet(); - if (so && so2) - { - if (so.a.length == so2.a.length) - { - foreach (j; 0 .. so.a.length) - { - if (so.a[j] !is so2.a[j]) - goto L1; - } - continue; // the same - L1: - { } // different - } - } - - if (flags & IgnoreAmbiguous) // if return NULL on ambiguity - return null; - - /* If two imports from C import files, pick first one, as C has global name space - */ - if (s.isCsymbol() && s2.isCsymbol()) - continue; - - if (!(flags & IgnoreErrors)) - ScopeDsymbol.multiplyDefined(loc, s, s2); - break; - } - } - } - } - if (s) - { - /* Build special symbol if we had multiple finds - */ - if (a) - { - if (!s.isOverloadSet()) - a = mergeOverloadSet(ident, a, s); - s = a; - } - //printf("\tfound in imports %s.%s\n", toChars(), s.toChars()); - return s; - } - //printf(" not found in imports\n"); - return null; - } - - extern (D) private OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s) + extern (D) final OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s) { if (!os) { @@ -1844,40 +1608,6 @@ extern (C++) final class WithScopeSymbol : ScopeDsymbol this.withstate = withstate; } - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("WithScopeSymbol.search(%s)\n", ident.toChars()); - if (flags & SearchImportsOnly) - return null; - // Acts as proxy to the with class declaration - Dsymbol s = null; - Expression eold = null; - for (Expression e = withstate.exp; e && e != eold; e = resolveAliasThis(_scope, e, true)) - { - if (auto se = e.isScopeExp()) - { - s = se.sds; - } - else if (e.isTypeExp()) - { - s = e.type.toDsymbol(null); - } - else - { - Type t = e.type.toBasetype(); - s = t.toDsymbol(null); - } - if (s) - { - s = s.search(loc, ident, flags); - if (s) - return s; - } - eold = e; - } - return null; - } - override inout(WithScopeSymbol) isWithScopeSymbol() inout { return this; @@ -1896,217 +1626,28 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol { // either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration. // Discriminated using DYNCAST and, for expressions, also EXP - private RootObject arrayContent; - Scope* sc; + RootObject arrayContent; extern (D) this(Scope* sc, Expression exp) nothrow @safe { super(exp.loc, null); assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array); - this.sc = sc; + this._scope = sc; this.arrayContent = exp; } extern (D) this(Scope* sc, TypeTuple type) nothrow @safe { - this.sc = sc; + this._scope = sc; this.arrayContent = type; } extern (D) this(Scope* sc, TupleDeclaration td) nothrow @safe { - this.sc = sc; + this._scope = sc; this.arrayContent = td; } - /// This override is used to solve `$` - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone) - { - //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags); - if (ident != Id.dollar) - return null; - - VarDeclaration* pvar; - Expression ce; - - static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc) - { - - /* $ gives the number of type entries in the type tuple - */ - auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null); - Expression e = new IntegerExp(Loc.initial, tt.arguments.length, Type.tsize_t); - v._init = new ExpInitializer(Loc.initial, e); - v.storage_class |= STC.temp | STC.static_ | STC.const_; - v.dsymbolSemantic(sc); - return v; - } - - const DYNCAST kind = arrayContent.dyncast(); - switch (kind) with (DYNCAST) - { - case dsymbol: - TupleDeclaration td = cast(TupleDeclaration) arrayContent; - /* $ gives the number of elements in the tuple - */ - auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null); - Expression e = new IntegerExp(Loc.initial, td.objects.length, Type.tsize_t); - v._init = new ExpInitializer(Loc.initial, e); - v.storage_class |= STC.temp | STC.static_ | STC.const_; - v.dsymbolSemantic(sc); - return v; - case type: - return dollarFromTypeTuple(loc, cast(TypeTuple) arrayContent, sc); - default: - break; - } - Expression exp = cast(Expression) arrayContent; - if (auto ie = exp.isIndexExp()) - { - /* array[index] where index is some function of $ - */ - pvar = &ie.lengthVar; - ce = ie.e1; - } - else if (auto se = exp.isSliceExp()) - { - /* array[lwr .. upr] where lwr or upr is some function of $ - */ - pvar = &se.lengthVar; - ce = se.e1; - } - else if (auto ae = exp.isArrayExp()) - { - /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $ - * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...) - */ - pvar = &ae.lengthVar; - ce = ae.e1; - } - else - { - /* Didn't find $, look in enclosing scope(s). - */ - return null; - } - ce = ce.lastComma(); - /* If we are indexing into an array that is really a type - * tuple, rewrite this as an index into a type tuple and - * try again. - */ - if (auto te = ce.isTypeExp()) - { - if (auto ttp = te.type.isTypeTuple()) - return dollarFromTypeTuple(loc, ttp, sc); - } - /* *pvar is lazily initialized, so if we refer to $ - * multiple times, it gets set only once. - */ - if (!*pvar) // if not already initialized - { - /* Create variable v and set it to the value of $ - */ - VarDeclaration v; - Type t; - if (auto tupexp = ce.isTupleExp()) - { - /* It is for an expression tuple, so the - * length will be a const. - */ - Expression e = new IntegerExp(Loc.initial, tupexp.exps.length, Type.tsize_t); - v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e)); - v.storage_class |= STC.temp | STC.static_ | STC.const_; - } - else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass)) - { - // Look for opDollar - assert(exp.op == EXP.array || exp.op == EXP.slice); - AggregateDeclaration ad = isAggregate(t); - assert(ad); - Dsymbol s = ad.search(loc, Id.opDollar); - if (!s) // no dollar exists -- search in higher scope - return null; - s = s.toAlias(); - Expression e = null; - // Check for multi-dimensional opDollar(dim) template. - if (TemplateDeclaration td = s.isTemplateDeclaration()) - { - dinteger_t dim = 0; - if (auto ae = exp.isArrayExp()) - { - dim = ae.currentDimension; - } - else if (exp.isSliceExp()) - { - dim = 0; // slices are currently always one-dimensional - } - else - { - assert(0); - } - auto tiargs = new Objects(); - Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t); - edim = edim.expressionSemantic(sc); - tiargs.push(edim); - e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs); - } - else - { - /* opDollar exists, but it's not a template. - * This is acceptable ONLY for single-dimension indexing. - * Note that it's impossible to have both template & function opDollar, - * because both take no arguments. - */ - auto ae = exp.isArrayExp(); - if (ae && ae.arguments.length != 1) - { - error(exp.loc, "`%s` only defines opDollar for one dimension", ad.toChars()); - return null; - } - Declaration d = s.isDeclaration(); - assert(d); - e = new DotVarExp(loc, ce, d); - } - e = e.expressionSemantic(sc); - if (!e.type) - error(exp.loc, "`%s` has no value", e.toChars()); - t = e.type.toBasetype(); - if (t && t.ty == Tfunction) - e = new CallExp(e.loc, e); - v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e)); - v.storage_class |= STC.temp | STC.ctfe | STC.rvalue; - } - else - { - /* For arrays, $ will either be a compile-time constant - * (in which case its value in set during constant-folding), - * or a variable (in which case an expression is created in - * toir.c). - */ - - // https://issues.dlang.org/show_bug.cgi?id=16213 - // For static arrays $ is known at compile time, - // so declare it as a manifest constant. - auto tsa = ce.type ? ce.type.isTypeSArray() : null; - if (tsa) - { - auto e = new ExpInitializer(loc, tsa.dim); - v = new VarDeclaration(loc, tsa.dim.type, Id.dollar, e, STC.manifest); - } - else - { - auto e = new VoidInitializer(Loc.initial); - e.type = Type.tsize_t; - v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e); - v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable - } - } - *pvar = v; - } - (*pvar).dsymbolSemantic(sc); - return (*pvar); - } - override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout { return this; diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index 0278975..e0c2046 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -228,10 +228,8 @@ public: virtual const char *kind() const; virtual Dsymbol *toAlias(); // resolve real symbol virtual Dsymbol *toAlias2(); - virtual void addMember(Scope *sc, ScopeDsymbol *sds); virtual void setScope(Scope *sc); virtual void importAll(Scope *sc); - virtual Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone); virtual bool overloadInsert(Dsymbol *s); virtual uinteger_t size(const Loc &loc); virtual bool isforwardRef(); @@ -331,16 +329,14 @@ public: Dsymbols *members; // all Dsymbol's in this scope DsymbolTable *symtab; // members[] sorted into table unsigned endlinnum; // the linnumber of the statement after the scope (0 if unknown) - -private: Dsymbols *importedScopes; // imported Dsymbol's Visibility::Kind *visibilities; // array of `Visibility.Kind`, one for each import +private: BitArray accessiblePackages, privateAccessiblePackages; public: ScopeDsymbol *syntaxCopy(Dsymbol *s) override; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; virtual void importScope(Dsymbol *s, Visibility visibility); virtual bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0); bool isforwardRef() override final; @@ -362,7 +358,6 @@ class WithScopeSymbol final : public ScopeDsymbol public: WithStatement *withstate; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; WithScopeSymbol *isWithScopeSymbol() override { return this; } void accept(Visitor *v) override { v->visit(this); } @@ -372,12 +367,8 @@ public: class ArrayScopeSymbol final : public ScopeDsymbol { -private: - RootObject *arrayContent; public: - Scope *sc; - - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone) override; + RootObject *arrayContent; ArrayScopeSymbol *isArrayScopeSymbol() override { return this; } void accept(Visitor *v) override { v->visit(this); } @@ -437,3 +428,6 @@ public: // Number of symbols in symbol table size_t length() const; }; + +void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds); +Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly); diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 637edd7..430377f 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -23,6 +23,7 @@ import dmd.astenums; import dmd.attrib; import dmd.blockexit; import dmd.clone; +import dmd.cond; import dmd.compiler; import dmd.dcast; import dmd.dclass; @@ -1141,7 +1142,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor else if (auto ale = ex.isArrayLiteralExp()) { // or an array literal assigned to a `scope` variable - if (global.params.useDIP1000 == FeatureState.enabled + if (sc.useDIP1000 == FeatureState.enabled && !dsym.type.nextOf().needsDestruction()) ale.onstack = true; } @@ -1170,10 +1171,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // https://issues.dlang.org/show_bug.cgi?id=14166 // Don't run CTFE for the temporary variables inside typeof dsym._init = dsym._init.initializerSemantic(sc, dsym.type, sc.intypeof == 1 ? INITnointerpret : INITinterpret); + import dmd.semantic2 : lowerStaticAAs; + lowerStaticAAs(dsym, sc); const init_err = dsym._init.isExpInitializer(); if (init_err && init_err.exp.op == EXP.showCtfeContext) { - errorSupplemental(dsym.loc, "compile time context created here"); + errorSupplemental(dsym.loc, "compile time context created here"); } } } @@ -1979,7 +1982,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (!cd.compiled) { cd.decl = compileIt(cd); - cd.AttribDeclaration.addMember(sc, cd.scopesym); + attribAddMember(cd, sc, cd.scopesym); cd.compiled = true; if (cd._scope && cd.decl) @@ -3385,7 +3388,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (!tf.isNaked() && !(funcdecl.isThis() || funcdecl.isNested())) { - import core.bitop; + import core.bitop : popcnt; auto mods = MODtoChars(tf.mod); .error(funcdecl.loc, "%s `%s` without `this` cannot be `%s`", funcdecl.kind, funcdecl.toPrettyChars, mods); if (tf.next && tf.next.ty != Tvoid && popcnt(tf.mod) == 1) @@ -5831,6 +5834,365 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } } +/* +Adds dsym as a member of scope sds. + +Params: + dsym = dsymbol to inserted + sc = scope where the dsymbol is declared + sds = ScopeDsymbol where dsym is inserted +*/ +extern(C++) void addMember(Dsymbol dsym, Scope* sc, ScopeDsymbol sds) +{ + auto addMemberVisitor = new AddMemberVisitor(sc, sds); + dsym.accept(addMemberVisitor); +} + +private void attribAddMember(AttribDeclaration atb, Scope* sc, ScopeDsymbol sds) +{ + Dsymbols* d = atb.include(sc); + if (d) + { + Scope* sc2 = atb.newScope(sc); + d.foreachDsymbol( s => s.addMember(sc2, sds) ); + if (sc2 != sc) + sc2.pop(); + } +} + +private extern(C++) class AddMemberVisitor : Visitor +{ + alias visit = Visitor.visit; + + Scope* sc; + ScopeDsymbol sds; + + this(Scope* sc, ScopeDsymbol sds) + { + this.sc = sc; + this.sds = sds; + } + + override void visit(Dsymbol dsym) + { + //printf("Dsymbol::addMember('%s')\n", toChars()); + //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars()); + //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab); + dsym.parent = sds; + if (dsym.isAnonymous()) // no name, so can't add it to symbol table + return; + + if (!sds.symtabInsert(dsym)) // if name is already defined + { + if (dsym.isAliasDeclaration() && !dsym._scope) + dsym.setScope(sc); + Dsymbol s2 = sds.symtabLookup(dsym, dsym.ident); + /* https://issues.dlang.org/show_bug.cgi?id=17434 + * + * If we are trying to add an import to the symbol table + * that has already been introduced, then keep the one with + * larger visibility. This is fine for imports because if + * we have multiple imports of the same file, if a single one + * is public then the symbol is reachable. + */ + if (auto i1 = dsym.isImport()) + { + if (auto i2 = s2.isImport()) + { + if (sc.explicitVisibility && sc.visibility > i2.visibility) + sds.symtab.update(dsym); + } + } + + // If using C tag/prototype/forward declaration rules + if (sc.flags & SCOPE.Cfile && !dsym.isImport()) + { + if (handleTagSymbols(*sc, dsym, s2, sds)) + return; + if (handleSymbolRedeclarations(*sc, dsym, s2, sds)) + return; + + sds.multiplyDefined(Loc.initial, dsym, s2); // ImportC doesn't allow overloading + dsym.errors = true; + return; + } + + if (!s2.overloadInsert(dsym)) + { + sds.multiplyDefined(Loc.initial, dsym, s2); + dsym.errors = true; + } + } + if (sds.isAggregateDeclaration() || sds.isEnumDeclaration()) + { + if (dsym.ident == Id.__sizeof || + !(sc && sc.flags & SCOPE.Cfile) && (dsym.ident == Id.__xalignof || dsym.ident == Id._mangleof)) + { + .error(dsym.loc, "%s `%s` `.%s` property cannot be redefined", dsym.kind, dsym.toPrettyChars, dsym.ident.toChars()); + dsym.errors = true; + } + } + } + + + override void visit(StaticAssert _) + { + // we didn't add anything + } + + /***************************** + * Add import to sd's symbol table. + */ + override void visit(Import imp) + { + //printf("Import.addMember(this=%s, sds=%s, sc=%p)\n", imp.toChars(), sds.toChars(), sc); + if (imp.names.length == 0) + return visit(cast(Dsymbol)imp); + if (imp.aliasId) + visit(cast(Dsymbol)imp); + + /* Instead of adding the import to sds's symbol table, + * add each of the alias=name pairs + */ + for (size_t i = 0; i < imp.names.length; i++) + { + Identifier name = imp.names[i]; + Identifier _alias = imp.aliases[i]; + if (!_alias) + _alias = name; + auto tname = new TypeIdentifier(imp.loc, name); + auto ad = new AliasDeclaration(imp.loc, _alias, tname); + ad._import = imp; + addMember(ad, sc, sds); + imp.aliasdecls.push(ad); + } + } + + override void visit(AttribDeclaration atb) + { + attribAddMember(atb, sc, sds); + } + + override void visit(StorageClassDeclaration stcd) + { + Dsymbols* d = stcd.include(sc); + if (d) + { + Scope* sc2 = stcd.newScope(sc); + + d.foreachDsymbol( (s) + { + //printf("\taddMember %s to %s\n", s.toChars(), sds.toChars()); + // STC.local needs to be attached before the member is added to the scope (because it influences the parent symbol) + if (auto decl = s.isDeclaration()) + { + decl.storage_class |= stcd.stc & STC.local; + if (auto sdecl = s.isStorageClassDeclaration()) // TODO: why is this not enough to deal with the nested case? + { + sdecl.stc |= stcd.stc & STC.local; + } + } + s.addMember(sc2, sds); + }); + + if (sc2 != sc) + sc2.pop(); + } + } + + override void visit(VisibilityDeclaration visd) + { + if (visd.pkg_identifiers) + { + Dsymbol tmp; + Package.resolve(visd.pkg_identifiers, &tmp, null); + visd.visibility.pkg = tmp ? tmp.isPackage() : null; + visd.pkg_identifiers = null; + } + if (visd.visibility.kind == Visibility.Kind.package_ && visd.visibility.pkg && sc._module) + { + Module m = sc._module; + + // https://issues.dlang.org/show_bug.cgi?id=17441 + // While isAncestorPackageOf does an equality check, the fix for the issue adds a check to see if + // each package's .isModule() properites are equal. + // + // Properties generated from `package(foo)` i.e. visibility.pkg have .isModule() == null. + // This breaks package declarations of the package in question if they are declared in + // the same package.d file, which _do_ have a module associated with them, and hence a non-null + // isModule() + if (!m.isPackage() || !visd.visibility.pkg.ident.equals(m.isPackage().ident)) + { + Package pkg = m.parent ? m.parent.isPackage() : null; + if (!pkg || !visd.visibility.pkg.isAncestorPackageOf(pkg)) + .error(visd.loc, "%s `%s` does not bind to one of ancestor packages of module `%s`", visd.kind(), visd.toPrettyChars(false), m.toPrettyChars(true)); + } + } + attribAddMember(visd, sc, sds); + } + + override void visit(StaticIfDeclaration sid) + { + //printf("StaticIfDeclaration::addMember() '%s'\n", sid.toChars()); + /* This is deferred until the condition evaluated later (by the include() call), + * so that expressions in the condition can refer to declarations + * in the same scope, such as: + * + * template Foo(int i) + * { + * const int j = i + 1; + * static if (j == 3) + * const int k; + * } + */ + sid.scopesym = sds; + } + + + override void visit(StaticForeachDeclaration sfd) + { + // used only for caching the enclosing symbol + sfd.scopesym = sds; + } + + /*************************************** + * Lazily initializes the scope to forward to. + */ + override void visit(ForwardingAttribDeclaration fad) + { + fad.sym.parent = sds; + sds = fad.sym; + attribAddMember(fad, sc, fad.sym); + } + + override void visit(MixinDeclaration md) + { + //printf("MixinDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, md.memnum); + md.scopesym = sds; + } + + override void visit(DebugSymbol ds) + { + //printf("DebugSymbol::addMember('%s') %s\n", sds.toChars(), ds.toChars()); + Module m = sds.isModule(); + // Do not add the member to the symbol table, + // just make sure subsequent debug declarations work. + if (ds.ident) + { + if (!m) + { + .error(ds.loc, "%s `%s` declaration must be at module level", ds.kind, ds.toPrettyChars); + ds.errors = true; + } + else + { + if (findCondition(m.debugidsNot, ds.ident)) + { + .error(ds.loc, "%s `%s` defined after use", ds.kind, ds.toPrettyChars); + ds.errors = true; + } + if (!m.debugids) + m.debugids = new Identifiers(); + m.debugids.push(ds.ident); + } + } + else + { + if (!m) + { + .error(ds.loc, "%s `%s` level declaration must be at module level", ds.kind, ds.toPrettyChars); + ds.errors = true; + } + else + m.debuglevel = ds.level; + } + } + + override void visit(VersionSymbol vs) + { + //printf("VersionSymbol::addMember('%s') %s\n", sds.toChars(), vs.toChars()); + Module m = sds.isModule(); + // Do not add the member to the symbol table, + // just make sure subsequent debug declarations work. + if (vs.ident) + { + VersionCondition.checkReserved(vs.loc, vs.ident.toString()); + if (!m) + { + .error(vs.loc, "%s `%s` declaration must be at module level", vs.kind, vs.toPrettyChars); + vs.errors = true; + } + else + { + if (findCondition(m.versionidsNot, vs.ident)) + { + .error(vs.loc, "%s `%s` defined after use", vs.kind, vs.toPrettyChars); + vs.errors = true; + } + if (!m.versionids) + m.versionids = new Identifiers(); + m.versionids.push(vs.ident); + } + } + else + { + if (!m) + { + .error(vs.loc, "%s `%s` level declaration must be at module level", vs.kind, vs.toPrettyChars); + vs.errors = true; + } + else + m.versionlevel = vs.level; + } + } + + override void visit(Nspace ns) + { + visit(cast(Dsymbol)ns); + + if (ns.members) + { + if (!ns.symtab) + ns.symtab = new DsymbolTable(); + // The namespace becomes 'imported' into the enclosing scope + for (Scope* sce = sc; 1; sce = sce.enclosing) + { + ScopeDsymbol sds2 = sce.scopesym; + if (sds2) + { + sds2.importScope(ns, Visibility(Visibility.Kind.public_)); + break; + } + } + assert(sc); + sc = sc.push(ns); + sc.linkage = LINK.cpp; // namespaces default to C++ linkage + sc.parent = ns; + ns.members.foreachDsymbol(s => s.addMember(sc, ns)); + sc.pop(); + } + } + + override void visit(EnumDeclaration ed) + { + version (none) + { + printf("EnumDeclaration::addMember() %s\n", ed.toChars()); + for (size_t i = 0; i < ed.members.length; i++) + { + EnumMember em = (*ed.members)[i].isEnumMember(); + printf(" member %s\n", em.toChars()); + } + } + if (!ed.isAnonymous()) + { + visit(cast(Dsymbol)ed); + } + + addEnumMembersToSymtab(ed, sc, sds); + } +} + /******************************************* * Add members of EnumDeclaration to the symbol table(s). * Params: @@ -5904,7 +6266,7 @@ private bool isDRuntimeHook(Identifier id) id == Id._d_arraysetlengthTImpl || id == Id._d_arraysetlengthT || id == Id._d_arraysetlengthTTrace || id == Id._d_arrayappendT || id == Id._d_arrayappendTTrace || - id == Id._d_arrayappendcTXImpl; + id == Id._d_arrayappendcTX; } void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList argumentList) @@ -7431,3 +7793,617 @@ void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope* p, funcdecl.toChars()); } } + +/********************************************* + * Search for ident as member of d. + * Params: + * d = dsymbol where ident is searched for + * loc = location to print for error messages + * ident = identifier to search for + * flags = IgnoreXXXX + * Returns: + * null if not found + */ +extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, int flags = IgnoreNone) +{ + scope v = new SearchVisitor(loc, ident, flags); + d.accept(v); + return v.result; +} + +private extern(C++) class SearchVisitor : Visitor +{ + alias visit = Visitor.visit; + + const Loc loc; + Identifier ident; + int flags; + Dsymbol result; + + this(const ref Loc loc, Identifier ident, int flags) + { + this.loc = loc; + this.ident = ident; + this.flags = flags; + } + + void setResult(Dsymbol d) + { + result = d; + } + + override void visit(Dsymbol d) + { + //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", d, d.toChars(), ident.toChars()); + return setResult(null); + } + + override void visit(ScopeDsymbol sds) + { + //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", sds.toChars(), ident.toChars(), flags); + //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0; + + // Look in symbols declared in this module + if (sds.symtab && !(flags & SearchImportsOnly)) + { + //printf(" look in locals\n"); + auto s1 = sds.symtab.lookup(ident); + if (s1) + { + //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars()); + return setResult(s1); + } + } + //printf(" not found in locals\n"); + + // Look in imported scopes + if (!sds.importedScopes) + return setResult(null); + + //printf(" look in imports\n"); + Dsymbol s = null; + OverloadSet a = null; + // Look in imported modules + 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_) + continue; + int sflags = flags & (IgnoreErrors | 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) + continue; + } + else // mixin template + { + if (flags & SearchImportsOnly) + continue; + + sflags |= SearchLocalsOnly; + } + + /* Don't find private members if ss is a module + */ + Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone)); + import dmd.access : symbolIsVisible; + if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(sds, s2)) + continue; + if (!s) + { + s = s2; + if (s && s.isOverloadSet()) + a = sds.mergeOverloadSet(ident, a, s); + } + else if (s2 && s != s2) + { + if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType()) + { + /* After following aliases, we found the same + * symbol, so it's not an ambiguity. But if one + * alias is deprecated or less accessible, prefer + * the other. + */ + if (s.isDeprecated() || s.visible() < s2.visible() && s2.visible().kind != Visibility.Kind.none) + s = s2; + } + else + { + /* Two imports of the same module should be regarded as + * the same. + */ + Import i1 = s.isImport(); + Import i2 = s2.isImport(); + if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident))))) + { + /* https://issues.dlang.org/show_bug.cgi?id=8668 + * Public selective import adds AliasDeclaration in module. + * To make an overload set, resolve aliases in here and + * get actual overload roots which accessible via s and s2. + */ + s = s.toAlias(); + s2 = s2.toAlias(); + /* If both s2 and s are overloadable (though we only + * need to check s once) + */ + + auto so2 = s2.isOverloadSet(); + if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable())) + { + if (symbolIsVisible(sds, s2)) + { + a = sds.mergeOverloadSet(ident, a, s2); + } + if (!symbolIsVisible(sds, s)) + s = s2; + continue; + } + + /* Two different overflow sets can have the same members + * https://issues.dlang.org/show_bug.cgi?id=16709 + */ + auto so = s.isOverloadSet(); + if (so && so2) + { + if (so.a.length == so2.a.length) + { + foreach (j; 0 .. so.a.length) + { + if (so.a[j] !is so2.a[j]) + goto L1; + } + continue; // the same + L1: + { } // different + } + } + + if (flags & 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 + */ + if (s.isCsymbol() && s2.isCsymbol()) + continue; + + if (!(flags & IgnoreErrors)) + ScopeDsymbol.multiplyDefined(loc, s, s2); + break; + } + } + } + } + if (s) + { + /* Build special symbol if we had multiple finds + */ + if (a) + { + if (!s.isOverloadSet()) + a = sds.mergeOverloadSet(ident, a, s); + s = a; + } + //printf("\tfound in imports %s.%s\n", toChars(), s.toChars()); + return setResult(s); + } + //printf(" not found in imports\n"); + return setResult(null); + } + + override void visit(WithScopeSymbol ws) + { + //printf("WithScopeSymbol.search(%s)\n", ident.toChars()); + if (flags & SearchImportsOnly) + return setResult(null); + // Acts as proxy to the with class declaration + Dsymbol s = null; + Expression eold = null; + for (Expression e = ws.withstate.exp; e && e != eold; e = resolveAliasThis(ws._scope, e, true)) + { + if (auto se = e.isScopeExp()) + { + s = se.sds; + } + else if (e.isTypeExp()) + { + s = e.type.toDsymbol(null); + } + else + { + Type t = e.type.toBasetype(); + s = t.toDsymbol(null); + } + if (s) + { + s = s.search(loc, ident, flags); + if (s) + return setResult(s); + } + eold = e; + } + return setResult(null); + } + + override void visit(ArrayScopeSymbol ass) + { + //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags); + if (ident != Id.dollar) + return setResult(null); + + VarDeclaration* pvar; + Expression ce; + + static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc) + { + + /* $ gives the number of type entries in the type tuple + */ + auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null); + Expression e = new IntegerExp(Loc.initial, tt.arguments.length, Type.tsize_t); + v._init = new ExpInitializer(Loc.initial, e); + v.storage_class |= STC.temp | STC.static_ | STC.const_; + v.dsymbolSemantic(sc); + return v; + } + + const DYNCAST kind = ass.arrayContent.dyncast(); + switch (kind) with (DYNCAST) + { + case dsymbol: + TupleDeclaration td = cast(TupleDeclaration) ass.arrayContent; + /* $ gives the number of elements in the tuple + */ + auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null); + Expression e = new IntegerExp(Loc.initial, td.objects.length, Type.tsize_t); + v._init = new ExpInitializer(Loc.initial, e); + v.storage_class |= STC.temp | STC.static_ | STC.const_; + v.dsymbolSemantic(ass._scope); + return setResult(v); + case type: + return setResult(dollarFromTypeTuple(loc, cast(TypeTuple) ass.arrayContent, ass._scope)); + default: + break; + } + Expression exp = cast(Expression) ass.arrayContent; + if (auto ie = exp.isIndexExp()) + { + /* array[index] where index is some function of $ + */ + pvar = &ie.lengthVar; + ce = ie.e1; + } + else if (auto se = exp.isSliceExp()) + { + /* array[lwr .. upr] where lwr or upr is some function of $ + */ + pvar = &se.lengthVar; + ce = se.e1; + } + else if (auto ae = exp.isArrayExp()) + { + /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $ + * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...) + */ + pvar = &ae.lengthVar; + ce = ae.e1; + } + else + { + /* Didn't find $, look in enclosing scope(s). + */ + return setResult(null); + } + ce = ce.lastComma(); + /* If we are indexing into an array that is really a type + * tuple, rewrite this as an index into a type tuple and + * try again. + */ + if (auto te = ce.isTypeExp()) + { + if (auto ttp = te.type.isTypeTuple()) + return setResult(dollarFromTypeTuple(loc, ttp, ass._scope)); + } + /* *pvar is lazily initialized, so if we refer to $ + * multiple times, it gets set only once. + */ + if (!*pvar) // if not already initialized + { + /* Create variable v and set it to the value of $ + */ + VarDeclaration v; + Type t; + if (auto tupexp = ce.isTupleExp()) + { + /* It is for an expression tuple, so the + * length will be a const. + */ + Expression e = new IntegerExp(Loc.initial, tupexp.exps.length, Type.tsize_t); + v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e)); + v.storage_class |= STC.temp | STC.static_ | STC.const_; + } + else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass)) + { + // Look for opDollar + assert(exp.op == EXP.array || exp.op == EXP.slice); + AggregateDeclaration ad = isAggregate(t); + assert(ad); + Dsymbol s = ad.search(loc, Id.opDollar); + if (!s) // no dollar exists -- search in higher scope + return setResult(null); + s = s.toAlias(); + Expression e = null; + // Check for multi-dimensional opDollar(dim) template. + if (TemplateDeclaration td = s.isTemplateDeclaration()) + { + dinteger_t dim = 0; + if (auto ae = exp.isArrayExp()) + { + dim = ae.currentDimension; + } + else if (exp.isSliceExp()) + { + dim = 0; // slices are currently always one-dimensional + } + else + { + assert(0); + } + auto tiargs = new Objects(); + Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t); + edim = edim.expressionSemantic(ass._scope); + tiargs.push(edim); + e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs); + } + else + { + /* opDollar exists, but it's not a template. + * This is acceptable ONLY for single-dimension indexing. + * Note that it's impossible to have both template & function opDollar, + * because both take no arguments. + */ + auto ae = exp.isArrayExp(); + if (ae && ae.arguments.length != 1) + { + error(exp.loc, "`%s` only defines opDollar for one dimension", ad.toChars()); + return setResult(null); + } + Declaration d = s.isDeclaration(); + assert(d); + e = new DotVarExp(loc, ce, d); + } + e = e.expressionSemantic(ass._scope); + if (!e.type) + error(exp.loc, "`%s` has no value", e.toChars()); + t = e.type.toBasetype(); + if (t && t.ty == Tfunction) + e = new CallExp(e.loc, e); + v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e)); + v.storage_class |= STC.temp | STC.ctfe | STC.rvalue; + } + else + { + /* For arrays, $ will either be a compile-time constant + * (in which case its value in set during constant-folding), + * or a variable (in which case an expression is created in + * toir.c). + */ + + // https://issues.dlang.org/show_bug.cgi?id=16213 + // For static arrays $ is known at compile time, + // so declare it as a manifest constant. + auto tsa = ce.type ? ce.type.isTypeSArray() : null; + if (tsa) + { + auto e = new ExpInitializer(loc, tsa.dim); + v = new VarDeclaration(loc, tsa.dim.type, Id.dollar, e, STC.manifest); + } + else + { + auto e = new VoidInitializer(Loc.initial); + e.type = Type.tsize_t; + v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e); + v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable + } + } + *pvar = v; + } + (*pvar).dsymbolSemantic(ass._scope); + return setResult((*pvar)); + + } + + override void visit(Import imp) + { + //printf("%s.Import.search(ident = '%s', flags = x%x)\n", imp.toChars(), ident.toChars(), flags); + if (!imp.pkg) + { + imp.load(null); + imp.mod.importAll(null); + imp.mod.dsymbolSemantic(null); + } + // Forward it to the package/module + return setResult(imp.pkg.search(loc, ident, flags)); + + } + + override void visit(Nspace ns) + { + //printf("%s.Nspace.search('%s')\n", toChars(), ident.toChars()); + if (ns._scope && !ns.symtab) + dsymbolSemantic(ns, ns._scope); + + if (!ns.members || !ns.symtab) // opaque or semantic() is not yet called + { + if (!(flags & IgnoreErrors)) + .error(loc, "%s `%s` is forward referenced when looking for `%s`", ns.kind, ns.toPrettyChars, ident.toChars()); + return setResult(null); + } + + visit(cast(ScopeDsymbol)ns); + } + + override void visit(EnumDeclaration em) + { + //printf("%s.EnumDeclaration::search('%s')\n", em.toChars(), ident.toChars()); + if (em._scope) + { + // Try one last time to resolve this enum + dsymbolSemantic(em, em._scope); + } + + visit(cast(ScopeDsymbol)em); + } + + 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 + if (!pkg.isModule() && pkg.mod) + { + // Prefer full package name. + Dsymbol s = pkg.symtab ? pkg.symtab.lookup(ident) : null; + if (s) + return setResult(s); + //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars()); + return setResult(pkg.mod.search(loc, ident, flags)); + } + + visit(cast(ScopeDsymbol)pkg); + } + + override void visit(Module m) + { + /* Since modules can be circularly referenced, + * need to stop infinite recursive searches. + * This is done with the cache. + */ + //printf("%s Module.search('%s', flags = x%x) insearch = %d\n", m.toChars(), ident.toChars(), flags, m.insearch); + if (m.insearch) + return setResult(null); + + /* Qualified module searches always search their imports, + * even if SearchLocalsOnly + */ + if (!(flags & SearchUnqualifiedModule)) + flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly); + + if (m.searchCacheIdent == ident && m.searchCacheFlags == flags) + { + //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n", + // toChars(), ident.toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol.toChars() : "null"); + return setResult(m.searchCacheSymbol); + } + + uint errors = global.errors; + + m.insearch = true; + visit(cast(ScopeDsymbol)m); + Dsymbol s = result; + m.insearch = false; + + if (errors == global.errors) + { + // https://issues.dlang.org/show_bug.cgi?id=10752 + // Can cache the result only when it does not cause + // access error so the side-effect should be reproduced in later search. + m.searchCacheIdent = ident; + m.searchCacheSymbol = s; + m.searchCacheFlags = flags; + } + return setResult(s); + } + + override void visit(Declaration decl) + { + Dsymbol s = null; + if (decl.type) + { + s = decl.type.toDsymbol(decl._scope); + if (s) + s = s.search(loc, ident, flags); + } + return setResult(s); + } + + override void visit(StructDeclaration sd) + { + //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", sd.toChars(), ident.toChars(), flags); + if (sd._scope && !sd.symtab) + dsymbolSemantic(sd, sd._scope); + + 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) + .error(loc, "%s `%s` is forward referenced when looking for `%s`", sd.kind, sd.toPrettyChars, ident.toChars()); + return setResult(null); + } + + visit(cast(ScopeDsymbol)sd); + } + + override void visit(ClassDeclaration cd) + { + //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", cd.toChars(), ident.toChars(), flags); + //if (_scope) printf("%s baseok = %d\n", toChars(), baseok); + if (cd._scope && cd.baseok < Baseok.semanticdone) + { + if (!cd.inuse) + { + // must semantic on base class/interfaces + cd.inuse = true; + dsymbolSemantic(cd, null); + cd.inuse = false; + } + } + + 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) + cd.classError("%s `%s` is forward referenced when looking for `%s`", ident.toChars()); + //*(char*)0=0; + return setResult(null); + } + + visit(cast(ScopeDsymbol)cd); + auto s = result; + + // don't search imports of base classes + if (flags & SearchImportsOnly) + return setResult(s); + + if (s) + return setResult(s); + + // Search bases classes in depth-first, left to right order + foreach (b; (*cd.baseclasses)[]) + { + if (!b.sym) + continue; + + if (!b.sym.symtab) + { + cd.classError("%s `%s` base `%s` is forward referenced", b.sym.ident.toChars()); + continue; + } + + import dmd.access : symbolIsVisible; + + s = b.sym.search(loc, ident, flags); + if (!s) + 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)) + s = null; + else + break; + } + + return setResult(s); + } +} diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 4cf1bae..037e0d0 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -746,7 +746,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol OutBuffer buf; HdrGenState hgs; - buf.writestring(ident.toString()); + buf.writestring(ident == Id.ctor ? "this" : ident.toString()); buf.writeByte('('); foreach (i, const tp; *parameters) { @@ -763,6 +763,11 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol { TypeFunction tf = cast(TypeFunction)fd.type; buf.writestring(parametersTypeToChars(tf.parameterList)); + if (tf.mod) + { + buf.writeByte(' '); + buf.MODtoBuffer(tf.mod); + } } } diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 7c76da9..9f85574 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -20,6 +20,7 @@ import dmd.astenums; import dmd.arraytypes; import dmd.attrib; import dmd.dsymbol; +import dmd.dsymbolsem; import dmd.errors; import dmd.globals; import dmd.hdrgen; diff --git a/gcc/d/dmd/dversion.d b/gcc/d/dmd/dversion.d index aa22532..31725c8 100644 --- a/gcc/d/dmd/dversion.d +++ b/gcc/d/dmd/dversion.d @@ -68,43 +68,6 @@ extern (C++) final class DebugSymbol : Dsymbol } } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - //printf("DebugSymbol::addMember('%s') %s\n", sds.toChars(), toChars()); - Module m = sds.isModule(); - // Do not add the member to the symbol table, - // just make sure subsequent debug declarations work. - if (ident) - { - if (!m) - { - .error(loc, "%s `%s` declaration must be at module level", kind, toPrettyChars); - errors = true; - } - else - { - if (findCondition(m.debugidsNot, ident)) - { - .error(loc, "%s `%s` defined after use", kind, toPrettyChars); - errors = true; - } - if (!m.debugids) - m.debugids = new Identifiers(); - m.debugids.push(ident); - } - } - else - { - if (!m) - { - .error(loc, "%s `%s` level declaration must be at module level", kind, toPrettyChars); - errors = true; - } - else - m.debuglevel = level; - } - } - override const(char)* kind() const nothrow { return "debug"; @@ -162,44 +125,6 @@ extern (C++) final class VersionSymbol : Dsymbol } } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - //printf("VersionSymbol::addMember('%s') %s\n", sds.toChars(), toChars()); - Module m = sds.isModule(); - // Do not add the member to the symbol table, - // just make sure subsequent debug declarations work. - if (ident) - { - VersionCondition.checkReserved(loc, ident.toString()); - if (!m) - { - .error(loc, "%s `%s` declaration must be at module level", kind, toPrettyChars); - errors = true; - } - else - { - if (findCondition(m.versionidsNot, ident)) - { - .error(loc, "%s `%s` defined after use", kind, toPrettyChars); - errors = true; - } - if (!m.versionids) - m.versionids = new Identifiers(); - m.versionids.push(ident); - } - } - else - { - if (!m) - { - .error(loc, "%s `%s` level declaration must be at module level", kind, toPrettyChars); - errors = true; - } - else - m.versionlevel = level; - } - } - override const(char)* kind() const nothrow { return "version"; diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h index be12c65..e17e8cf 100644 --- a/gcc/d/dmd/enum.h +++ b/gcc/d/dmd/enum.h @@ -46,12 +46,10 @@ public: bool inuse(bool v); EnumDeclaration *syntaxCopy(Dsymbol *s) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; void setScope(Scope *sc) override; bool oneMember(Dsymbol **ps, Identifier *ident) override; Type *getType() override; const char *kind() const override; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; bool isDeprecated() const override; // is Dsymbol deprecated? Visibility visible() override; bool isSpecial() const; diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 3f85ea0..e25fc84 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -25,7 +25,7 @@ import dmd.dsymbol; import dmd.errors; import dmd.expression; import dmd.func; -import dmd.globals; +import dmd.globals : FeatureState; import dmd.id; import dmd.identifier; import dmd.init; @@ -169,7 +169,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf, if (!(eb.isMutable || eb2.isMutable)) return; - if (!tf.islive && !(global.params.useDIP1000 == FeatureState.enabled && sc.func && sc.func.setUnsafe())) + if (!tf.islive && !(sc.useDIP1000 == FeatureState.enabled && sc.func && sc.func.setUnsafe())) return; if (!gag) @@ -377,7 +377,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId, sc.setUnsafeDIP1000(gag, arg.loc, msg, v, parId ? parId : fdc, fdc)) { result = true; - printScopeFailure(previewSupplementalFunc(sc.isDeprecated(), global.params.useDIP1000), vPar, 10); + printScopeFailure(previewSupplementalFunc(sc.isDeprecated(), sc.useDIP1000), vPar, 10); } } @@ -1094,7 +1094,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) { if (p == sc.func) { - result |= escapingRef(v, global.params.useDIP1000); + result |= escapingRef(v, sc.useDIP1000); continue; } } @@ -1110,7 +1110,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) { //printf("escaping reference to local ref variable %s\n", v.toChars()); //printf("storage class = x%llx\n", v.storage_class); - result |= escapingRef(v, global.params.useDIP25); + result |= escapingRef(v, sc.useDIP25); continue; } // Don't need to be concerned if v's parent does not return a ref @@ -1125,12 +1125,12 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) const(char)* msg = "storing reference to outer local variable `%s` into allocated memory causes it to escape"; if (!gag) { - previewErrorFunc(sc.isDeprecated(), global.params.useDIP25)(e.loc, msg, v.toChars()); + previewErrorFunc(sc.isDeprecated(), sc.useDIP25)(e.loc, msg, v.toChars()); } // If -preview=dip25 is used, the user wants an error // Otherwise, issue a deprecation - result |= (global.params.useDIP25 == FeatureState.enabled); + result |= (sc.useDIP25 == FeatureState.enabled); } } @@ -1264,7 +1264,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) // https://issues.dlang.org/show_bug.cgi?id=23191 if (!gag) { - previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)(e.loc, + previewErrorFunc(sc.isDeprecated(), sc.useDIP1000)(e.loc, "scope parameter `%s` may not be returned", v.toChars() ); result = true; @@ -1403,7 +1403,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) { //printf("escaping reference to local ref variable %s\n", v.toChars()); //printf("storage class = x%llx\n", v.storage_class); - escapingRef(v, global.params.useDIP25); + escapingRef(v, sc.useDIP25); continue; } // Don't need to be concerned if v's parent does not return a ref @@ -1415,7 +1415,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) { const(char)* msg = "escaping reference to outer local variable `%s`"; if (!gag) - previewErrorFunc(sc.isDeprecated(), global.params.useDIP25)(e.loc, msg, v.toChars()); + previewErrorFunc(sc.isDeprecated(), sc.useDIP25)(e.loc, msg, v.toChars()); result = true; continue; } @@ -2588,7 +2588,7 @@ public bool setUnsafeDIP1000(Scope* sc, bool gag, Loc loc, const(char)* msg, RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null) { - return setUnsafePreview(sc, global.params.useDIP1000, gag, loc, msg, arg0, arg1, arg2); + return setUnsafePreview(sc, sc.useDIP1000, gag, loc, msg, arg0, arg1, arg2); } /*************************************** diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 4790221..cd93e54 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -4617,7 +4617,9 @@ extern (C++) final class UshrAssignExp : BinAssignExp */ extern (C++) class CatAssignExp : BinAssignExp { - extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe + Expression lowering; // lowered druntime hook `_d_arrayappend{cTX,T}` + + extern (D) this(const ref Loc loc, Expression e1, Expression e2) { super(loc, EXP.concatenateAssign, e1, e2); } diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 12ca6b4..b4ace74b 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -52,7 +52,7 @@ void expandTuples(Expressions *exps, Identifiers *names = nullptr); StringExp *toUTF8(StringExp *se, Scope *sc); Expression *resolveLoc(Expression *exp, const Loc &loc, Scope *sc); MATCH implicitConvTo(Expression *e, Type *t); -Expression *toLvalue(Expression *_this, Scope *sc); +Expression *toLvalue(Expression *_this, Scope *sc, const char* action); Expression *modifiableLvalue(Expression* exp, Scope *sc); typedef unsigned char OwnedBy; @@ -1114,6 +1114,8 @@ public: class CatAssignExp : public BinAssignExp { public: + Expression *lowering; // lowered druntime hook `_d_arrayappend{cTX,T}` + void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index d55ab3b..e6b9018 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -2150,7 +2150,7 @@ private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc) * verified instead. This is to keep errors related to the original code * and not the lowering. */ - if (f.ident == Id._d_newitemT || f.ident == Id._d_newarrayT) + if (f.ident == Id._d_newitemT || f.ident == Id._d_newarrayT || f.ident == Id._d_newarraymTX) return false; if (!f.isNogc()) @@ -3129,7 +3129,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v)); arg = ev.expressionSemantic(sc); } - arg = arg.toLvalue(sc); + arg = arg.toLvalue(sc, "create `in` parameter from"); // Look for mutable misaligned pointer, etc., in @safe mode err |= checkUnsafeAccess(sc, arg, false, true); @@ -3147,7 +3147,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v)); arg = ev.expressionSemantic(sc); } - arg = arg.toLvalue(sc); + arg = arg.toLvalue(sc, "create `ref` parameter from"); // Look for mutable misaligned pointer, etc., in @safe mode err |= checkUnsafeAccess(sc, arg, false, true); @@ -3166,7 +3166,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, err |= checkUnsafeAccess(sc, arg, false, true); err |= checkDefCtor(arg.loc, t); // t must be default constructible } - arg = arg.toLvalue(sc); + arg = arg.toLvalue(sc, "create `out` parameter from"); } else if (p.isLazy()) { @@ -3209,7 +3209,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, const explicitScope = p.isLazy() || ((p.storageClass & STC.scope_) && !(p.storageClass & STC.scopeinferred)); if ((pStc & (STC.scope_ | STC.lazy_)) && - ((global.params.useDIP1000 == FeatureState.enabled) || explicitScope) && + ((sc.useDIP1000 == FeatureState.enabled) || explicitScope) && !(pStc & STC.return_)) { /* Argument value cannot escape from the called function. @@ -5115,23 +5115,23 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor tb = tb.isTypeDArray().next.toBasetype(); } - if (nargs == 1) - { - if (global.params.betterC || !sc.needsCodegen()) + if (global.params.betterC || !sc.needsCodegen()) goto LskipNewArrayLowering; - /* Class types may inherit base classes that have errors. - * This may leak errors from the base class to the derived one - * and then to the hook. Semantic analysis is performed eagerly - * to a void this. - */ - if (auto tc = exp.type.nextOf.isTypeClass()) - { - tc.sym.dsymbolSemantic(sc); - if (tc.sym.errors) - goto LskipNewArrayLowering; - } + /* Class types may inherit base classes that have errors. + * This may leak errors from the base class to the derived one + * and then to the hook. Semantic analysis is performed eagerly + * to a void this. + */ + if (auto tc = exp.type.nextOf.isTypeClass()) + { + tc.sym.dsymbolSemantic(sc); + if (tc.sym.errors) + goto LskipNewArrayLowering; + } + if (nargs == 1) + { auto hook = global.params.tracegc ? Id._d_newarrayTTrace : Id._d_newarrayT; if (!verifyHookExist(exp.loc, *sc, hook, "new array")) goto LskipNewArrayLowering; @@ -5166,6 +5166,45 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor lowering = new CallExp(exp.loc, lowering, arguments); exp.lowering = lowering.expressionSemantic(sc); } + else + { + auto hook = global.params.tracegc ? Id._d_newarraymTXTrace : Id._d_newarraymTX; + if (!verifyHookExist(exp.loc, *sc, hook, "new multi-dimensional array")) + goto LskipNewArrayLowering; + + /* Lower the memory allocation and initialization of `new T[][]...[](n1, n2, ...)` + * to `_d_newarraymTX!(T[][]...[], T)([n1, n2, ...])`. + */ + Expression lowering = new IdentifierExp(exp.loc, Id.empty); + lowering = new DotIdExp(exp.loc, lowering, Id.object); + + auto tbn = exp.type.nextOf(); + while (tbn.ty == Tarray) + tbn = tbn.nextOf(); + auto unqualTbn = tbn.unqualify(MODFlags.wild | MODFlags.const_ | + MODFlags.immutable_ | MODFlags.shared_); + + auto tiargs = new Objects(); + tiargs.push(exp.type); + tiargs.push(unqualTbn); + lowering = new DotTemplateInstanceExp(exp.loc, lowering, hook, tiargs); + + auto arguments = new Expressions(); + if (global.params.tracegc) + { + auto funcname = (sc.callsc && sc.callsc.func) ? + sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); + arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); + arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); + arguments.push(new StringExp(exp.loc, funcname.toDString())); + } + + arguments.push(new ArrayLiteralExp(exp.loc, Type.tsize_t.sarrayOf(nargs), exp.arguments)); + arguments.push(new IntegerExp(exp.loc, tbn.isShared(), Type.tbool)); + + lowering = new CallExp(exp.loc, lowering, arguments); + exp.lowering = lowering.expressionSemantic(sc); + } } else if (tb.isscalar()) { @@ -8295,7 +8334,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else { // `toLvalue` call further below is upon exp.e1, omitting & from the error message - exp.toLvalue(sc); + exp.toLvalue(sc, "take address of"); return setError(); } } @@ -8385,7 +8424,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } - exp.e1 = exp.e1.toLvalue(sc); + exp.e1 = exp.e1.toLvalue(sc, "take address of"); if (exp.e1.op == EXP.error) { result = exp.e1; @@ -9017,14 +9056,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - // Look for casting to a vector type - if (tob.ty == Tvector && t1b.ty != Tvector) - { - result = new VectorExp(exp.loc, exp.e1, exp.to); - result = result.expressionSemantic(sc); - return; - } - Expression ex = exp.e1.castTo(sc, exp.to); if (ex.op == EXP.error) { @@ -11727,8 +11758,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = res; - if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) && - sc.needsCodegen()) + if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) && sc.needsCodegen()) { // if aa ordering is triggered, `res` will be a CommaExp // and `.e2` will be the rewritten original expression. @@ -11772,7 +11802,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor arguments.push(exp.e1); arguments.push(exp.e2); Expression ce = new CallExp(exp.loc, id, arguments); - *output = ce.expressionSemantic(sc); + + exp.lowering = ce.expressionSemantic(sc); + *output = exp; } else if (exp.op == EXP.concatenateElemAssign) { @@ -11792,15 +11824,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX; - if (!verifyHookExist(exp.loc, *sc, Id._d_arrayappendcTXImpl, "appending element to arrays", Id.object)) + if (!verifyHookExist(exp.loc, *sc, hook, "appending element to arrays", Id.object)) return setError(); - // Lower to object._d_arrayappendcTXImpl!(typeof(e1))._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2 + // Lower to object._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2 Expression id = new IdentifierExp(exp.loc, Id.empty); id = new DotIdExp(exp.loc, id, Id.object); - auto tiargs = new Objects(); - tiargs.push(exp.e1.type); - id = new DotTemplateInstanceExp(exp.loc, id, Id._d_arrayappendcTXImpl, tiargs); id = new DotIdExp(exp.loc, id, hook); auto arguments = new Expressions(); @@ -11827,11 +11856,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { /* Before the template hook, this check was performed in e2ir.d * for expressions like `a ~= a[$-1]`. Here, $ will be modified - * by calling `_d_arrayappendcT`, so we need to save `a[$-1]` in + * by calling `_d_arrayappendcTX`, so we need to save `a[$-1]` in * a temporary variable. */ value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true); - exp.e2 = value2; // `__appendtmp*` will be destroyed together with the array `exp.e1`. auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration(); @@ -11847,13 +11875,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor auto e0 = Expression.combine(ce, ae).expressionSemantic(sc); e0 = Expression.combine(e0, value1); e0 = Expression.combine(eValue1, e0); - e0 = Expression.combine(eValue2, e0); - *output = e0.expressionSemantic(sc); + exp.lowering = e0.expressionSemantic(sc); + *output = exp; } } - } override void visit(AddExp exp) @@ -15210,15 +15237,21 @@ Expression addDtorHook(Expression e, Scope* sc) * Params: * _this = expression to convert * sc = scope + * action = for error messages, what the lvalue is needed for (e.g. take address of for `&x`, modify for `x++`) * Returns: converted expression, or `ErrorExp` on error */ -extern(C++) Expression toLvalue(Expression _this, Scope* sc) +extern(C++) Expression toLvalue(Expression _this, Scope* sc, const(char)* action) { - return toLvalueImpl(_this, sc, _this); + return toLvalueImpl(_this, sc, action, _this); } // e = original un-lowered expression for error messages, in case of recursive calls -private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) { +private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action, Expression e) +{ + if (!action) + action = "create lvalue of"; + + assert(e); Expression visit(Expression _this) { // BinaryAssignExp does not have an EXP associated @@ -15230,9 +15263,11 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) { _this.loc = e.loc; if (e.op == EXP.type) - error(_this.loc, "`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind()); + error(_this.loc, "cannot %s type `%s`", action, e.type.toChars()); + else if (e.op == EXP.template_) + error(_this.loc, "cannot %s template `%s`, perhaps instantiate it first", action, e.toChars()); else - error(_this.loc, "`%s` is not an lvalue and cannot be modified", e.toChars()); + error(_this.loc, "cannot %s expression `%s` because it is not an lvalue", action, e.toChars()); return ErrorExp.get(); } @@ -15241,7 +15276,7 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) { { if (!_this.loc.isValid()) _this.loc = e.loc; - error(e.loc, "cannot modify constant `%s`", e.toChars()); + error(e.loc, "cannot %s constant `%s`", action, e.toChars()); return ErrorExp.get(); } @@ -15285,22 +15320,22 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) { auto var = _this.var; if (var.storage_class & STC.manifest) { - error(_this.loc, "manifest constant `%s` cannot be modified", var.toChars()); + error(_this.loc, "cannot %s manifest constant `%s`", action, var.toChars()); return ErrorExp.get(); } if (var.storage_class & STC.lazy_ && !_this.delegateWasExtracted) { - error(_this.loc, "lazy variable `%s` cannot be modified", var.toChars()); + error(_this.loc, "cannot %s lazy variable `%s`", action, var.toChars()); return ErrorExp.get(); } if (var.ident == Id.ctfe) { - error(_this.loc, "cannot modify compiler-generated variable `__ctfe`"); + error(_this.loc, "cannot %s compiler-generated variable `__ctfe`", action); return ErrorExp.get(); } if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574 { - error(_this.loc, "cannot modify operator `$`"); + error(_this.loc, "cannot %s operator `$`", action); return ErrorExp.get(); } return _this; @@ -15370,7 +15405,7 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) { Expression visitVectorArray(VectorArrayExp _this) { - _this.e1 = _this.e1.toLvalueImpl(sc, e); + _this.e1 = _this.e1.toLvalueImpl(sc, action, e); return _this; } @@ -15389,19 +15424,19 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) { Expression visitComma(CommaExp _this) { - _this.e2 = _this.e2.toLvalue(sc); + _this.e2 = _this.e2.toLvalue(sc, action); return _this; } Expression visitDelegatePointer(DelegatePtrExp _this) { - _this.e1 = _this.e1.toLvalueImpl(sc, e); + _this.e1 = _this.e1.toLvalueImpl(sc, action, e); return _this; } Expression visitDelegateFuncptr(DelegateFuncptrExp _this) { - _this.e1 = _this.e1.toLvalueImpl(sc, e); + _this.e1 = _this.e1.toLvalueImpl(sc, action, e); return _this; } @@ -15430,8 +15465,8 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) { { // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2) CondExp e = cast(CondExp)(_this.copy()); - e.e1 = _this.e1.toLvalue(sc).addressOf(); - e.e2 = _this.e2.toLvalue(sc).addressOf(); + e.e1 = _this.e1.toLvalue(sc, action).addressOf(); + e.e2 = _this.e2.toLvalue(sc, action).addressOf(); e.type = _this.type.pointerTo(); return new PtrExp(_this.loc, e, _this.type); @@ -15634,12 +15669,13 @@ extern(C++) Expression modifiableLvalue(Expression _this, Scope* sc) // e = original / un-lowered expression to print in error messages private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression e) { + assert(e); Expression visit(Expression exp) { //printf("Expression::modifiableLvalue() %s, type = %s\n", exp.toChars(), exp.type.toChars()); // See if this expression is a modifiable lvalue (i.e. not const) if (exp.isBinAssignExp()) - return exp.toLvalue(sc); + return exp.toLvalue(sc, "modify"); auto type = exp.type; if (checkModifiable(exp, sc) == Modifiable.yes) @@ -15672,7 +15708,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression return ErrorExp.get(); } } - return exp.toLvalueImpl(sc, e); + return exp.toLvalueImpl(sc, "modify", e); } Expression visitString(StringExp exp) @@ -15762,7 +15798,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression } exp.e1 = exp.e1.modifiableLvalue(sc); exp.e2 = exp.e2.modifiableLvalue(sc); - return exp.toLvalue(sc); + return exp.toLvalue(sc, "modify"); } switch(_this.op) @@ -15803,7 +15839,7 @@ bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v) } if (sc.func && !sc.intypeof && !v.isDataseg()) { - if (global.params.useDIP1000 != FeatureState.enabled && + if (sc.useDIP1000 != FeatureState.enabled && !(v.storage_class & STC.temp) && sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func)) { diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index edf113e..351faa47 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -3241,13 +3241,6 @@ unittest assert(mismatches.isMutable); } -private const(char)* prependSpace(const(char)* str) -{ - if (!str || !*str) return ""; - - return (" " ~ str.toDString() ~ "\0").ptr; -} - /// Flag used by $(LREF resolveFuncCall). enum FuncResolveFlag : ubyte { @@ -3361,14 +3354,11 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, const(char)* lastprms = parametersTypeToChars(tf1.parameterList); const(char)* nextprms = parametersTypeToChars(tf2.parameterList); - const(char)* mod1 = prependSpace(MODtoChars(tf1.mod)); - const(char)* mod2 = prependSpace(MODtoChars(tf2.mod)); - .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`", s.parent.toPrettyChars(), s.ident.toChars(), fargsBuf.peekChars(), - m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, mod1, - m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, mod2); + m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, tf1.modToChars(), + m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, tf2.modToChars()); return null; } @@ -3422,15 +3412,25 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, if (!tf) tf = fd.originalType.toTypeFunction(); - if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch + // modifier mismatch + if (tthis && (fd.isCtorDeclaration() ? + !MODimplicitConv(tf.mod, tthis.mod) : + !MODimplicitConv(tthis.mod, tf.mod))) { OutBuffer thisBuf, funcBuf; MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod); auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod); if (hasOverloads) { - .error(loc, "none of the overloads of `%s` are callable using a %sobject", - fd.ident.toChars(), thisBuf.peekChars()); + OutBuffer buf; + buf.argExpTypesToCBuffer(fargs); + if (fd.isCtorDeclaration()) + .error(loc, "none of the overloads of `%s` can construct a %sobject with argument types `(%s)`", + fd.toChars(), thisBuf.peekChars(), buf.peekChars()); + else + .error(loc, "none of the overloads of `%s` are callable using a %sobject with argument types `(%s)`", + fd.toChars(), thisBuf.peekChars(), buf.peekChars()); + if (!global.gag || global.params.v.showGaggedErrors) printCandidates(loc, fd, sc.isDeprecated()); return null; @@ -3447,8 +3447,12 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, return null; } - .error(loc, "%smethod `%s` is not callable using a %sobject", - funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars()); + if (fd.isCtorDeclaration()) + .error(loc, "%s%s `%s` cannot construct a %sobject", + funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars()); + else + .error(loc, "%smethod `%s` is not callable using a %sobject", + funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars()); if (mismatches.isNotShared) .errorSupplemental(fd.loc, "Consider adding `shared` here"); @@ -3535,11 +3539,17 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) if (!print) return true; auto tf = cast(TypeFunction) fd.type; + OutBuffer buf; + buf.writestring(fd.toPrettyChars()); + buf.writestring(parametersTypeToChars(tf.parameterList)); + if (tf.mod) + { + buf.writeByte(' '); + buf.MODtoBuffer(tf.mod); + } .errorSupplemental(fd.loc, - printed ? " `%s%s`" : - single_candidate ? "Candidate is: `%s%s`" : "Candidates are: `%s%s`", - fd.toPrettyChars(), - parametersTypeToChars(tf.parameterList)); + printed ? " `%s`" : + single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars()); } else if (auto td = s.isTemplateDeclaration()) { @@ -4621,7 +4631,14 @@ bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char) case default_: if (!sc.func) return false; - if (!sc.func.isSafeBypassingInference() && !sc.func.safetyViolation) + if (sc.func.isSafeBypassingInference()) + { + if (!gag) + { + warning(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : ""); + } + } + else if (!sc.func.safetyViolation) { import dmd.func : AttributeViolation; sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2); diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 8325081..ac2dda3 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -1943,7 +1943,7 @@ private void visitTemplateParameters(TemplateParameters* parameters, ref OutBuff { if (i) buf.writestring(", "); - p.templateParameterToBuffer(buf, &hgs); + toCBuffer(p, buf, hgs); } } @@ -2885,10 +2885,10 @@ void floatToBuffer(Type type, const real_t value, ref OutBuffer buf, const bool } } -private void templateParameterToBuffer(TemplateParameter tp, ref OutBuffer buf, HdrGenState* hgs) +void toCBuffer(const TemplateParameter tp, ref OutBuffer buf, ref HdrGenState hgs) { - scope v = new TemplateParameterPrettyPrintVisitor(&buf, hgs); - tp.accept(v); + scope v = new TemplateParameterPrettyPrintVisitor(&buf, &hgs); + (cast() tp).accept(v); } private extern (C++) final class TemplateParameterPrettyPrintVisitor : Visitor @@ -3262,12 +3262,6 @@ void argExpTypesToCBuffer(ref OutBuffer buf, Expressions* arguments) } } -void toCBuffer(const TemplateParameter tp, ref OutBuffer buf, ref HdrGenState hgs) -{ - scope v = new TemplateParameterPrettyPrintVisitor(&buf, &hgs); - (cast() tp).accept(v); -} - void arrayObjectsToBuffer(ref OutBuffer buf, Objects* objects) { if (!objects || !objects.length) @@ -3837,7 +3831,7 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te { if (i) buf.writestring(", "); - p.templateParameterToBuffer(buf, hgs); + toCBuffer(p, buf, *hgs); } buf.writeByte(')'); } @@ -3862,6 +3856,11 @@ private void initializerToBuffer(Initializer inx, ref OutBuffer buf, HdrGenState buf.writestring("void"); } + void visitDefault(DefaultInitializer iz) + { + buf.writestring("{ }"); + } + void visitStruct(StructInitializer si) { //printf("StructInitializer::toCBuffer()\n"); diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index 5fcda91..32221d9 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -323,6 +323,8 @@ immutable Msgtable[] msgtable = { "_d_newitemTTrace" }, { "_d_newarrayT" }, { "_d_newarrayTTrace" }, + { "_d_newarraymTX" }, + { "_d_newarraymTXTrace" }, { "_d_assert_fail" }, { "dup" }, { "_aaApply" }, @@ -366,7 +368,6 @@ immutable Msgtable[] msgtable = { "_d_arraysetlengthTTrace"}, { "_d_arrayappendT" }, { "_d_arrayappendTTrace" }, - { "_d_arrayappendcTXImpl" }, { "_d_arrayappendcTX" }, { "_d_arrayappendcTXTrace" }, { "_d_arraycatnTX" }, diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h index 31ee61a..aeb3621 100644 --- a/gcc/d/dmd/import.h +++ b/gcc/d/dmd/import.h @@ -43,9 +43,7 @@ public: Import *syntaxCopy(Dsymbol *s) override; // copy only syntax trees void importAll(Scope *sc) override; Dsymbol *toAlias() override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; void setScope(Scope* sc) override; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; bool overloadInsert(Dsymbol *s) override; Import *isImport() override { return this; } diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d index 98ac903..2c7699b 100644 --- a/gcc/d/dmd/importc.d +++ b/gcc/d/dmd/importc.d @@ -20,6 +20,7 @@ import dmd.dcast; import dmd.declaration; import dmd.dscope; import dmd.dsymbol; +import dmd.dsymbolsem; import dmd.errors; import dmd.expression; import dmd.expressionsem; diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d index ebcd011..e484100 100644 --- a/gcc/d/dmd/init.d +++ b/gcc/d/dmd/init.d @@ -68,6 +68,11 @@ extern (C++) class Initializer : ASTNode return kind == InitKind.void_ ? cast(inout VoidInitializer)cast(void*)this : null; } + final inout(DefaultInitializer) isDefaultInitializer() inout @nogc nothrow pure + { + return kind == InitKind.default_ ? cast(inout DefaultInitializer)cast(void*)this : null; + } + final inout(StructInitializer) isStructInitializer() inout @nogc nothrow pure { return kind == InitKind.struct_ ? cast(inout StructInitializer)cast(void*)this : null; @@ -112,6 +117,24 @@ extern (C++) final class VoidInitializer : Initializer } /*********************************************************** + * The C23 default initializer `{ }` + */ +extern (C++) final class DefaultInitializer : Initializer +{ + Type type; // type that this will initialize to + + extern (D) this(const ref Loc loc) @safe + { + super(loc, InitKind.default_); + } + + override void accept(Visitor v) + { + v.visit(this); + } +} + +/*********************************************************** */ extern (C++) final class ErrorInitializer : Initializer { @@ -266,6 +289,11 @@ Initializer syntaxCopy(Initializer inx) return new VoidInitializer(vi.loc); } + static Initializer visitDefault(DefaultInitializer vi) + { + return new DefaultInitializer(vi.loc); + } + static Initializer visitError(ErrorInitializer vi) { return vi; @@ -352,6 +380,7 @@ mixin template VisitInitializer(Result) final switch (init.kind) { case InitKind.void_: mixin(visitCase("Void")); break; + case InitKind.default_: mixin(visitCase("Default")); break; case InitKind.error: mixin(visitCase("Error")); break; case InitKind.struct_: mixin(visitCase("Struct")); break; case InitKind.array: mixin(visitCase("Array")); break; diff --git a/gcc/d/dmd/init.h b/gcc/d/dmd/init.h index 67d0527..21bd07f 100644 --- a/gcc/d/dmd/init.h +++ b/gcc/d/dmd/init.h @@ -20,6 +20,7 @@ class Expression; class Type; class ErrorInitializer; class VoidInitializer; +class DefaultInitializer; class StructInitializer; class ArrayInitializer; class ExpInitializer; @@ -37,6 +38,7 @@ public: ErrorInitializer *isErrorInitializer(); VoidInitializer *isVoidInitializer(); + DefaultInitializer *isDefaultInitializer(); StructInitializer *isStructInitializer(); ArrayInitializer *isArrayInitializer(); ExpInitializer *isExpInitializer(); @@ -53,6 +55,14 @@ public: void accept(Visitor *v) override { v->visit(this); } }; +class DefaultInitializer final : public Initializer +{ +public: + Type *type; // type that this will initialize to + + void accept(Visitor *v) override { v->visit(this); } +}; + class ErrorInitializer final : public Initializer { public: diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 139db0f..76c2d89 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -24,6 +24,7 @@ import dmd.dinterpret; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; +import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; @@ -106,6 +107,7 @@ Expression toAssocArrayLiteral(ArrayInitializer ai) */ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedInterpret needInterpret) { + //printf("initializerSemantic() tx: %p %s\n", tx, tx.toChars()); Type t = tx; static Initializer err() @@ -119,6 +121,12 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ return i; } + Initializer visitDefault(DefaultInitializer i) + { + i.type = t; + return i; + } + Initializer visitError(ErrorInitializer i) { return i; @@ -1017,6 +1025,12 @@ Initializer inferType(Initializer init, Scope* sc) return new ErrorInitializer(); } + Initializer visitDefault(DefaultInitializer i) + { + error(i.loc, "cannot infer type from default initializer"); + return new ErrorInitializer(); + } + Initializer visitError(ErrorInitializer i) { return i; @@ -1175,6 +1189,11 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n return null; } + Expression visitDefault(DefaultInitializer di) + { + return di.type ? di.type.defaultInit(Loc.initial, isCfile) : null; + } + Expression visitError(ErrorInitializer) { return ErrorExp.get(); diff --git a/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d index ec070d8..d19d435 100644 --- a/gcc/d/dmd/lambdacomp.d +++ b/gcc/d/dmd/lambdacomp.d @@ -22,6 +22,7 @@ import dmd.astenums; import dmd.declaration; import dmd.denum; import dmd.dsymbol; +import dmd.dsymbolsem; import dmd.dtemplate; import dmd.expression; import dmd.func; diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index 6e8153d..92efc16 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -43,7 +43,6 @@ public: bool isAncestorPackageOf(const Package * const pkg) const; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; void accept(Visitor *v) override { v->visit(this); } Module *isPackageMod(); @@ -124,7 +123,6 @@ public: Module *parse(); // syntactic parse void importAll(Scope *sc) override; int needModuleInfo(); - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0) override; Dsymbol *symtabInsert(Dsymbol *s) override; static void runDeferredSemantic(); diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index 59bf1d5..e59b010 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/dmd/nogc.d @@ -108,12 +108,6 @@ public: return; f.printGCUsage(e.loc, "setting `length` may cause a GC allocation"); } - else if (fd.ident == Id._d_arrayappendT || fd.ident == Id._d_arrayappendcTX) - { - if (setGC(e, "cannot use operator `~=` in `@nogc` %s `%s`")) - return; - f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation"); - } } override void visit(ArrayLiteralExp e) @@ -187,20 +181,14 @@ public: override void visit(CatAssignExp e) { - /* CatAssignExp will exist in `__traits(compiles, ...)` and in the `.e1` branch of a `__ctfe ? :` CondExp. - * The other branch will be `_d_arrayappendcTX(e1, 1), e1[$-1]=e2` which will generate the warning about - * GC usage. See visit(CallExp). - */ if (checkOnly) { err = true; return; } - if (f.setGC(e.loc, null)) - { - err = true; + if (setGC(e, "cannot use operator `~=` in `@nogc` %s `%s`")) return; - } + f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation"); } override void visit(CatExp e) diff --git a/gcc/d/dmd/nspace.d b/gcc/d/dmd/nspace.d index 2d3367a..a49e0bf 100644 --- a/gcc/d/dmd/nspace.d +++ b/gcc/d/dmd/nspace.d @@ -85,33 +85,6 @@ extern (C++) final class Nspace : ScopeDsymbol return ns; } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - ScopeDsymbol.addMember(sc, sds); - - if (members) - { - if (!symtab) - symtab = new DsymbolTable(); - // The namespace becomes 'imported' into the enclosing scope - for (Scope* sce = sc; 1; sce = sce.enclosing) - { - ScopeDsymbol sds2 = sce.scopesym; - if (sds2) - { - sds2.importScope(this, Visibility(Visibility.Kind.public_)); - break; - } - } - assert(sc); - sc = sc.push(this); - sc.linkage = LINK.cpp; // namespaces default to C++ linkage - sc.parent = this; - members.foreachDsymbol(s => s.addMember(sc, this)); - sc.pop(); - } - } - override void setScope(Scope* sc) { ScopeDsymbol.setScope(sc); @@ -126,22 +99,6 @@ extern (C++) final class Nspace : ScopeDsymbol } } - override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly) - { - //printf("%s.Nspace.search('%s')\n", toChars(), ident.toChars()); - if (_scope && !symtab) - dsymbolSemantic(this, _scope); - - if (!members || !symtab) // opaque or semantic() is not yet called - { - if (!(flags & IgnoreErrors)) - .error(loc, "%s `%s` is forward referenced when looking for `%s`", kind, toPrettyChars, ident.toChars()); - return null; - } - - return ScopeDsymbol.search(loc, ident, flags); - } - override bool hasPointers() { //printf("Nspace::hasPointers() %s\n", toChars()); diff --git a/gcc/d/dmd/nspace.h b/gcc/d/dmd/nspace.h index e9fb7bd..7d30402 100644 --- a/gcc/d/dmd/nspace.h +++ b/gcc/d/dmd/nspace.h @@ -21,9 +21,7 @@ class Nspace final : public ScopeDsymbol public: Expression *identExp; Nspace *syntaxCopy(Dsymbol *s) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; void setScope(Scope *sc) override; - Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override; bool hasPointers() override; void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override; const char *kind() const override; diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index b445b7b..b7bc925 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -23,6 +23,7 @@ import dmd.declaration; import dmd.dscope; import dmd.dstruct; import dmd.dsymbol; +import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; import dmd.expression; diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index 69028fa..a979168 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -928,6 +928,14 @@ Expression optimize(Expression e, int result, bool keepLvalue = false) } } + void visitCatAssign(CatAssignExp e) + { + if (auto lowering = e.lowering) + optimize(lowering, result, keepLvalue); + else + visitBinAssign(e); + } + void visitBin(BinExp e) { //printf("BinExp::optimize(result = %d) %s\n", result, e.toChars()); @@ -1392,9 +1400,9 @@ Expression optimize(Expression e, int result, bool keepLvalue = false) case EXP.leftShiftAssign: case EXP.rightShiftAssign: case EXP.unsignedRightShiftAssign: + case EXP.concatenateDcharAssign: visitBinAssign(ex.isBinAssignExp()); break; case EXP.concatenateElemAssign: - case EXP.concatenateDcharAssign: - case EXP.concatenateAssign: visitBinAssign(ex.isBinAssignExp()); break; + case EXP.concatenateAssign: visitCatAssign(cast(CatAssignExp) ex); break; case EXP.minusMinus: case EXP.plusPlus: diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 51e522d..f9d174a 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -4878,30 +4878,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer AST.Declaration v; AST.Dsymbol s; - // try to parse function type: - // TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes bool attributesAppended; const StorageClass funcStc = parseTypeCtor(); - Token* tlu = &token; Token* tk; - if (token.value != TOK.function_ && - token.value != TOK.delegate_ && - isBasicType(&tlu) && tlu && - tlu.value == TOK.leftParenthesis) - { - AST.Type tret = parseBasicType(); - auto parameterList = parseParameterList(null); - - parseAttributes(); - if (udas) - error("user-defined attributes not allowed for `alias` declarations"); - - attributesAppended = true; - storage_class = appendStorageClass(storage_class, funcStc); - AST.Type tf = new AST.TypeFunction(parameterList, tret, link, storage_class); - v = new AST.AliasDeclaration(loc, ident, tf); - } - else if (token.value == TOK.function_ || + // function literal? + if (token.value == TOK.function_ || token.value == TOK.delegate_ || token.value == TOK.leftParenthesis && skipAttributes(peekPastParen(&token), &tk) && @@ -4911,10 +4892,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer token.value == TOK.ref_ && peekNext() == TOK.leftParenthesis && skipAttributes(peekPastParen(peek(&token)), &tk) && (tk.value == TOK.goesTo || tk.value == TOK.leftCurly) || - token.value == TOK.auto_ && peekNext() == TOK.ref_ && - peekNext2() == TOK.leftParenthesis && - skipAttributes(peekPastParen(peek(peek(&token))), &tk) && - (tk.value == TOK.goesTo || tk.value == TOK.leftCurly) + token.value == TOK.auto_ && + (peekNext() == TOK.leftParenthesis || // for better error + peekNext() == TOK.ref_ && + peekNext2() == TOK.leftParenthesis) ) { // function (parameters) { statements... } @@ -4955,21 +4936,46 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else { - parseAttributes(); // type + parseAttributes(); if (udas) error("user-defined attributes not allowed for `alias` declarations"); - auto t = parseType(); + auto t = parseBasicType(); + t = parseTypeSuffixes(t); + if (token.value == TOK.identifier) + { + error("unexpected identifier `%s` after `%s`", + token.ident.toChars(), t.toChars()); + nextToken(); + } + else if (token.value == TOK.leftParenthesis) + { + // function type: + // StorageClasses Type ( Parameters ) MemberFunctionAttributes + auto parameterList = parseParameterList(null); + udas = null; + parseStorageClasses(storage_class, link, setAlignment, ealign, udas, linkloc); + if (udas) + error("user-defined attributes not allowed for `alias` declarations"); + + attributesAppended = true; + // Note: method types can have a TypeCtor attribute + storage_class = appendStorageClass(storage_class, funcStc); + t = new AST.TypeFunction(parameterList, t, link, storage_class); + } // Disallow meaningless storage classes on type aliases if (storage_class) { // Don't raise errors for STC that are part of a function/delegate type, e.g. // `alias F = ref pure nothrow @nogc @safe int function();` - auto tp = t.isTypePointer; - const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate; - const remStc = isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class; + const remStc = t.isTypeFunction ? + storage_class & ~(STC.FUNCATTR | STC.TYPECTOR) : { + auto tp = t.isTypePointer; + const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate; + return isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class; + }(); if (remStc) { @@ -7217,6 +7223,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer return false; } + // pt = test token. If found, pt is set to the token after BasicType private bool isBasicType(Token** pt) { // This code parallels parseBasicType() diff --git a/gcc/d/dmd/parsetimevisitor.d b/gcc/d/dmd/parsetimevisitor.d index a4a9434..3d0a585 100644 --- a/gcc/d/dmd/parsetimevisitor.d +++ b/gcc/d/dmd/parsetimevisitor.d @@ -298,5 +298,6 @@ public: void visit(AST.StructInitializer i) { visit(cast(AST.Initializer)i); } void visit(AST.ArrayInitializer i) { visit(cast(AST.Initializer)i); } void visit(AST.VoidInitializer i) { visit(cast(AST.Initializer)i); } + void visit(AST.DefaultInitializer i) { visit(cast(AST.Initializer)i); } void visit(AST.CInitializer i) { visit(cast(AST.CInitializer)i); } } diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h index 178542e..2cac5f2 100644 --- a/gcc/d/dmd/scope.h +++ b/gcc/d/dmd/scope.h @@ -61,6 +61,9 @@ enum class SCOPE Cfile = 0x0800, // C semantics apply free = 0x8000, // is on free list fullinst = 0x10000, // fully instantiate templates + ctfeBlock = 0x20000, // inside a `if (__ctfe)` block + dip1000 = 0x40000, // dip1000 errors enabled for this scope + dip25 = 0x80000, // dip25 errors enabled for this scope }; struct Scope @@ -126,4 +129,6 @@ 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); }; diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index bf220f3..c255701 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -918,7 +918,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if (f.isref) { // Function returns a reference - exp = exp.toLvalue(sc2); + exp = exp.toLvalue(sc2, "`ref` return"); checkReturnEscapeRef(sc2, exp, false); exp = exp.optimize(WANTvalue, /*keepLvalue*/ true); } diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index f8b2c26..3873adc 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -3801,7 +3801,7 @@ private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde, { version (none) { - if (global.params.useDIP1000 == FeatureState.enabled) + if (sc2.useDIP1000 == FeatureState.enabled) { message(loc, "To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`"); } @@ -3809,7 +3809,7 @@ private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde, } else { - if (global.params.useDIP1000 == FeatureState.enabled) + if (sc2.useDIP1000 == FeatureState.enabled) ++(cast(FuncExp)flde).fd.tookAddressOf; // allocate a closure unless the opApply() uses 'scope' } assert(tab.ty == Tstruct || tab.ty == Tclass); diff --git a/gcc/d/dmd/staticassert.d b/gcc/d/dmd/staticassert.d index 15c46b3..7f22c4c 100644 --- a/gcc/d/dmd/staticassert.d +++ b/gcc/d/dmd/staticassert.d @@ -52,11 +52,6 @@ extern (C++) final class StaticAssert : Dsymbol return new StaticAssert(loc, exp.syntaxCopy(), msgs ? Expression.arraySyntaxCopy(msgs) : null); } - override void addMember(Scope* sc, ScopeDsymbol sds) - { - // we didn't add anything - } - override bool oneMember(Dsymbol* ps, Identifier ident) { //printf("StaticAssert::oneMember())\n"); diff --git a/gcc/d/dmd/staticassert.h b/gcc/d/dmd/staticassert.h index 2b7d300..c0d5363 100644 --- a/gcc/d/dmd/staticassert.h +++ b/gcc/d/dmd/staticassert.h @@ -21,7 +21,6 @@ public: Expressions *msg; StaticAssert *syntaxCopy(Dsymbol *s) override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; bool oneMember(Dsymbol **ps, Identifier *ident) override; const char *kind() const override; StaticAssert *isStaticAssert() override { return this; } diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index 79df7fd..0acadbb 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -32,6 +32,7 @@ import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; +import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.func; @@ -92,43 +93,50 @@ private Dsymbol getDsymbolWithoutExpCtx(RootObject oarg) } /** - * get an array of size_t values that indicate possible pointer words in memory - * if interpreted as the type given as argument - * Returns: the size of the type in bytes, ulong.max on error + * Fill an array of target size_t values that indicate possible pointer words in memory + * if interpreted as the type given as argument. + * One bit in the array per pointer-sized piece of memory + * Params: + * loc = location for error messages + * t = type to generate pointer bitmap from + * data = array forming the bitmap + * eSink = error message sink + * Returns: + * size of the type `t` in bytes, ulong.max on error */ -ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data) +ulong getTypePointerBitmap(Loc loc, Type t, ref Array!(ulong) data, ErrorSink eSink) { - ulong sz; - if (t.ty == Tclass && !(cast(TypeClass)t).sym.isInterfaceDeclaration()) - sz = (cast(TypeClass)t).sym.AggregateDeclaration.size(loc); - else - sz = t.size(loc); + auto tc = t.isTypeClass(); + const ulong sz = (tc && !tc.sym.isInterfaceDeclaration()) + ? tc.sym.AggregateDeclaration.size(loc) + : t.size(loc); if (sz == SIZE_INVALID) return ulong.max; - const sz_size_t = Type.tsize_t.size(loc); + const sz_size_t = Type.tsize_t.size(loc); // size of target's size_t + assert(sz_size_t <= ulong.sizeof); if (sz > sz.max - sz_size_t) { - error(loc, "size overflow for type `%s`", t.toChars()); + eSink.error(loc, "size overflow for type `%s`", t.toChars()); return ulong.max; } - ulong bitsPerWord = sz_size_t * 8; - ulong cntptr = (sz + sz_size_t - 1) / sz_size_t; - ulong cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord; + const ulong bitsPerElement = sz_size_t * 8; // bits used in each array element + const ulong cntptr = (sz + sz_size_t - 1) / sz_size_t; // pointers have same size as sz_size_t + const ulong length = (cntptr + bitsPerElement - 1) / bitsPerElement; // a bit per pointer - data.setDim(cast(size_t)cntdata); + data.setDim(cast(size_t)length); data.zero(); ulong offset; - bool error; + bool error; // sticky error indicator void visit(Type t) { void setpointer(ulong off) { ulong ptroff = off / sz_size_t; - (*data)[cast(size_t)(ptroff / (8 * sz_size_t))] |= 1L << (ptroff % (8 * sz_size_t)); + data[cast(size_t)(ptroff / bitsPerElement)] |= 1L << (ptroff % bitsPerElement); } void visitType(Type t) @@ -247,7 +255,7 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data) visit.VisitType(t); } - if (auto tc = t.isTypeClass()) + if (auto tcx = t.isTypeClass()) { // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references void visitTopLevelClass(TypeClass t) @@ -264,7 +272,7 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data) offset = classoff; } - visitTopLevelClass(tc); + visitTopLevelClass(tcx); } else visit(t); @@ -281,28 +289,28 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data) * * Returns: [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...] */ -private Expression pointerBitmap(TraitsExp e) +private Expression pointerBitmap(TraitsExp e, ErrorSink eSink) { if (!e.args || e.args.length != 1) { - error(e.loc, "a single type expected for trait pointerBitmap"); + eSink.error(e.loc, "a single type expected for trait pointerBitmap"); return ErrorExp.get(); } Type t = getType((*e.args)[0]); if (!t) { - error(e.loc, "`%s` is not a type", (*e.args)[0].toChars()); + eSink.error(e.loc, "`%s` is not a type", (*e.args)[0].toChars()); return ErrorExp.get(); } Array!(ulong) data; - ulong sz = getTypePointerBitmap(e.loc, t, &data); + const ulong sz = getTypePointerBitmap(e.loc, t, data, eSink); if (sz == ulong.max) return ErrorExp.get(); auto exps = new Expressions(data.length + 1); - (*exps)[0] = new IntegerExp(e.loc, sz, Type.tsize_t); + (*exps)[0] = new IntegerExp(e.loc, sz, Type.tsize_t); // [0] is size in bytes of t foreach (size_t i; 1 .. exps.length) (*exps)[i] = new IntegerExp(e.loc, data[cast(size_t) (i - 1)], Type.tsize_t); @@ -472,13 +480,13 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } if (e.ident == Id.isAbstractClass) { - return isTypeX(t => t.toBasetype().ty == Tclass && - (cast(TypeClass)t.toBasetype()).sym.isAbstract()); + return isTypeX(t => t.toBasetype().isTypeClass() && + t.toBasetype().isTypeClass().sym.isAbstract()); } if (e.ident == Id.isFinalClass) { - return isTypeX(t => t.toBasetype().ty == Tclass && - ((cast(TypeClass)t.toBasetype()).sym.storage_class & STC.final_) != 0); + return isTypeX(t => t.toBasetype().isTypeClass() && + (t.toBasetype().isTypeClass().sym.storage_class & STC.final_) != 0); } if (e.ident == Id.isTemplate) { @@ -508,7 +516,8 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } Type tb = t.baseElemOf(); - if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null) + auto ts = tb.isTypeStruct(); + if (auto sd = ts ? ts.sym : null) { return sd.isPOD() ? True() : False(); } @@ -529,7 +538,8 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } Type tb = t.baseElemOf(); - if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null) + auto ts = tb.isTypeStruct(); + if (auto sd = ts ? ts.sym : null) { return (e.ident == Id.hasPostblit) ? (sd.postblit ? True() : False()) : (sd.hasCopyCtor ? True() : False()); @@ -793,10 +803,10 @@ Expression semanticTraits(TraitsExp e, Scope* sc) { if (auto p = s.toParent()) // `C`'s parent is `C!2`, believe it or not { - if (p.isTemplateInstance()) // `C!2` is a template instance + if (auto ti = p.isTemplateInstance()) // `C!2` is a template instance { s = p; // `C!2`'s parent is `T1` - auto td = (cast(TemplateInstance)p).tempdecl; + auto td = ti.tempdecl; if (td) s = td; // get the declaration context just in case there's two contexts } @@ -1297,7 +1307,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) if (fd && fd.parent && fd.parent.isTemplateInstance) { fd.functionSemantic3(); - tf = cast(TypeFunction)fd.type; + tf = fd.type.isTypeFunction(); } auto mods = new Expressions(); @@ -1738,9 +1748,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc) ex = ex.expressionSemantic(sc2); ex = resolvePropertiesOnly(sc2, ex); ex = ex.optimize(WANTvalue); - if (sc2.func && sc2.func.type.ty == Tfunction) + if (sc2.func && sc2.func.type.isTypeFunction()) { - const tf = cast(TypeFunction)sc2.func.type; + const tf = sc2.func.type.isTypeFunction(); err |= tf.isnothrow && canThrow(ex, sc2.func, null); } ex = checkGC(sc2, ex); @@ -1868,7 +1878,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } if (e.ident == Id.getPointerBitmap) { - return pointerBitmap(e); + return pointerBitmap(e, global.errorSink); } if (e.ident == Id.initSymbol) { diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 4a4c5d4..8795002 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -1099,7 +1099,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) if (isRefOrOut && !isAuto && !(global.params.previewIn && (fparam.storageClass & STC.in_)) && global.params.rvalueRefParam != FeatureState.enabled) - e = e.toLvalue(sc); + e = e.toLvalue(sc, "create default argument for `ref` / `out` parameter from"); fparam.defaultArg = e; return (e.op != EXP.error); diff --git a/gcc/d/dmd/version.h b/gcc/d/dmd/version.h index 697d46e..c268bc9 100644 --- a/gcc/d/dmd/version.h +++ b/gcc/d/dmd/version.h @@ -20,7 +20,6 @@ public: DebugSymbol *syntaxCopy(Dsymbol *) override; const char *toChars() const override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; const char *kind() const override; DebugSymbol *isDebugSymbol() override; void accept(Visitor *v) override { v->visit(this); } @@ -34,7 +33,6 @@ public: VersionSymbol *syntaxCopy(Dsymbol *) override; const char *toChars() const override; - void addMember(Scope *sc, ScopeDsymbol *sds) override; const char *kind() const override; VersionSymbol *isVersionSymbol() override; void accept(Visitor *v) override { v->visit(this); } diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h index 3d8c3e6..360784a 100644 --- a/gcc/d/dmd/visitor.h +++ b/gcc/d/dmd/visitor.h @@ -176,6 +176,7 @@ class NewDeclaration; class Initializer; class VoidInitializer; +class DefaultInitializer; class ErrorInitializer; class StructInitializer; class ArrayInitializer; @@ -591,6 +592,7 @@ public: virtual void visit(StructInitializer *i) { visit((Initializer *)i); } virtual void visit(ArrayInitializer *i) { visit((Initializer *)i); } virtual void visit(VoidInitializer *i) { visit((Initializer *)i); } + virtual void visit(DefaultInitializer *i) { visit((Initializer *)i); } virtual void visit(CInitializer *i) { visit((Initializer *)i); } }; diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 17801a3..a907979 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -789,42 +789,58 @@ public: void visit (CatAssignExp *e) final override { + if (!global.params.useGC) + { + error_at (make_location_t (e->loc), + "appending to array in %qs requires the GC and cannot be " + "used with %<-fno-druntime%>", e->toChars ()); + this->result_ = error_mark_node; + return; + } + Type *tb1 = e->e1->type->toBasetype (); Type *tb2 = e->e2->type->toBasetype (); - Type *etype = tb1->nextOf ()->toBasetype (); - - /* Save the address of `e1', so it can be evaluated first. - As all D run-time library functions for concat assignments update `e1' - in-place and then return its value, the saved address can also be used as - the result of this expression as well. */ - tree lhs = build_expr (e->e1); - tree lexpr = stabilize_expr (&lhs); - tree ptr = d_save_expr (build_address (lhs)); - tree result = NULL_TREE; - if (tb1->ty == TY::Tarray && tb2->ty == TY::Tdchar - && (etype->ty == TY::Tchar || etype->ty == TY::Twchar)) + if (e->op == EXP::concatenateDcharAssign) { /* Append a dchar to a char[] or wchar[]: The assignment is handled by the D run-time library, so only need to call `_d_arrayappend[cw]d(&e1, e2)' */ + Type *etype = tb1->nextOf ()->toBasetype (); + + /* Save the address of `e1', so it can be evaluated first. + As all D run-time library functions for concat assignments update + `e1' in-place and then return its value, the saved address can also + be used as the result of this expression as well. */ + tree lhs = build_expr (e->e1); + tree lexpr = stabilize_expr (&lhs); + tree ptr = d_save_expr (build_address (lhs)); + tree result = NULL_TREE; + + gcc_assert (tb1->ty == TY::Tarray && tb2->ty == TY::Tdchar + && (etype->ty == TY::Tchar || etype->ty == TY::Twchar)); + libcall_fn libcall = (etype->ty == TY::Tchar) ? LIBCALL_ARRAYAPPENDCD : LIBCALL_ARRAYAPPENDWD; result = build_libcall (libcall, e->type, 2, ptr, build_expr (e->e2)); + + /* Construct in order: ptr = &e1, _d_arrayappend(ptr, e2), *ptr; */ + result = compound_expr (compound_expr (lexpr, ptr), result); + this->result_ = compound_expr (result, build_deref (ptr)); } else { + gcc_assert (e->op == EXP::concatenateAssign + || e->op == EXP::concatenateElemAssign); + gcc_assert (tb1->ty == TY::Tarray || tb2->ty == TY::Tsarray); /* Appending an element or array to another array has already been handled by the front-end. */ - gcc_assert (tb1->ty == TY::Tarray || tb2->ty == TY::Tsarray); - gcc_unreachable (); - } + gcc_assert (e->lowering); - /* Construct in order: ptr = &e1, _d_arrayappend(ptr, e2), *ptr; */ - result = compound_expr (compound_expr (lexpr, ptr), result); - this->result_ = compound_expr (result, build_deref (ptr)); + this->result_ = build_expr (e->lowering); + } } /* Build an assignment expression. The right operand is implicitly @@ -2359,50 +2375,9 @@ public: /* Allocating memory for a new D array. */ gcc_assert (e->arguments && e->arguments->length >= 1); - if (e->arguments->length == 1) - { - /* Single dimension array allocations has already been handled by - the front-end. */ - gcc_assert (e->lowering); - result = build_expr (e->lowering); - } - else - { - /* Multidimensional array allocations. */ - tree tarray = make_array_type (Type::tsize_t, e->arguments->length); - tree var = build_local_temp (tarray); - vec <constructor_elt, va_gc> *elms = NULL; - - /* Get the base element type for the array, generating the - initializer for the dims parameter along the way. */ - Type *telem = e->newtype->toBasetype (); - for (size_t i = 0; i < e->arguments->length; i++) - { - Expression *arg = (*e->arguments)[i]; - CONSTRUCTOR_APPEND_ELT (elms, size_int (i), build_expr (arg)); - - gcc_assert (telem->ty == TY::Tarray); - telem = telem->toBasetype ()->nextOf (); - gcc_assert (telem); - } - - /* Initialize the temporary. */ - tree init = modify_expr (var, build_constructor (tarray, elms)); - var = compound_expr (init, var); - - /* Generate: _d_newarraymTX(ti, dims) - or: _d_newarraymiTX(ti, dims) */ - libcall_fn libcall = telem->isZeroInit () - ? LIBCALL_NEWARRAYMTX : LIBCALL_NEWARRAYMITX; - - tree tinfo = build_typeinfo (e, e->type); - tree dims = d_array_value (build_ctype (Type::tsize_t->arrayOf ()), - size_int (e->arguments->length), - build_address (var)); - - result = build_libcall (libcall, e->newtype->toBasetype (), 2, - tinfo, dims); - } + /* Array allocations have already been handled by the front-end. */ + gcc_assert (e->lowering != NULL); + result = build_expr (e->lowering); if (e->argprefix) result = compound_expr (build_expr (e->argprefix), result); diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def index f7887e1..3307b3b 100644 --- a/gcc/d/runtime.def +++ b/gcc/d/runtime.def @@ -70,13 +70,6 @@ DEF_D_RUNTIME (DYNAMIC_CAST, "_d_dynamic_cast", RT(OBJECT), DEF_D_RUNTIME (INTERFACE_CAST, "_d_interface_cast", RT(OBJECT), P2(OBJECT, CLASSINFO), 0) -/* Used when calling `new' on a multi-dimensional array. - The `i' variant is for when the initializer is nonzero. */ -DEF_D_RUNTIME (NEWARRAYMTX, "_d_newarraymTX", RT(ARRAY_VOID), - P2(CONST_TYPEINFO, ARRAY_SIZE_T), 0) -DEF_D_RUNTIME (NEWARRAYMITX, "_d_newarraymiTX", RT(ARRAY_VOID), - P2(CONST_TYPEINFO, ARRAY_SIZE_T), 0) - /* Used for allocating an array literal on the GC heap. */ DEF_D_RUNTIME (ARRAYLITERALTX, "_d_arrayliteralTX", RT(VOIDPTR), P2(CONST_TYPEINFO, SIZE_T), 0) |