diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2025-03-12 18:16:46 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2025-03-15 17:54:15 +0100 |
commit | df1f6b98578be7a6276580e35c9302aa5622f113 (patch) | |
tree | adac24cf39366869dd233e2e5fd0a099daad1aea /gcc/d | |
parent | e8c9f4ab8f0c8ad8da5f7fb0f1a4956507fe64f5 (diff) | |
download | gcc-df1f6b98578be7a6276580e35c9302aa5622f113.zip gcc-df1f6b98578be7a6276580e35c9302aa5622f113.tar.gz gcc-df1f6b98578be7a6276580e35c9302aa5622f113.tar.bz2 |
d: Merge upstream dmd, druntime d29e3eca45
D front-end changes:
- Error messages related to operator overloading have been improved.
D runtime changes:
- Import latest fixes from druntime.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd d29e3eca45.
* d-codegen.cc (can_elide_copy_p): Update for new front-end interface.
* d-lang.cc (d_handle_option): Likewise.
* expr.cc (class ExprVisitor): Likewise.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime d29e3eca45.
Diffstat (limited to 'gcc/d')
53 files changed, 859 insertions, 845 deletions
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 50362e6f..4d8ed65 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -637,7 +637,7 @@ static bool can_elide_copy_p (Expression *exp) { /* Explicit `__rvalue(exp)'. */ - if (exp->rvalue) + if (exp->rvalue ()) return true; /* Look for variable expression. */ diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index a4cde58..585737b 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -450,7 +450,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_fdebug: - global.params.debuglevel = value ? 1 : 0; + global.params.debugEnabled = value ? true : false; break; case OPT_fdebug_: diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index a91f40b..c81fccb 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -b7e3b3b61711bf6c6cad27c7b5b73df0e570c215 +d29e3eca45edaeef63b31f78c9846fc6e2870c49 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/access.d b/gcc/d/dmd/access.d index e778ed9..b3e98f8 100644 --- a/gcc/d/dmd/access.d +++ b/gcc/d/dmd/access.d @@ -142,7 +142,7 @@ private bool hasPackageAccess(Module mod, Dsymbol s) /**************************************** * Determine if scope sc has protected level access to cd. */ -private bool hasProtectedAccess(Scope *sc, Dsymbol s) +private bool hasProtectedAccess(Scope* sc, Dsymbol s) { if (auto cd = s.isClassMember()) // also includes interfaces { @@ -273,7 +273,7 @@ bool symbolIsVisible(Dsymbol origin, Dsymbol s) * s = symbol to check for visibility * Returns: true if s is visible by origin */ -bool symbolIsVisible(Scope *sc, Dsymbol s) +bool symbolIsVisible(Scope* sc, Dsymbol s) { s = mostVisibleOverload(s); return checkSymbolAccess(sc, s); @@ -288,7 +288,7 @@ bool symbolIsVisible(Scope *sc, Dsymbol s) * s = symbol to check for visibility * Returns: true if s is visible by origin */ -bool checkSymbolAccess(Scope *sc, Dsymbol s) +bool checkSymbolAccess(Scope* sc, Dsymbol s) { final switch (s.visible().kind) { diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d index 25f54b5..20bcafe 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -447,7 +447,8 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol s.isTemplateDeclaration() || s.isOverloadSet())) { - .error(s.loc, "%s `%s` is not a constructor; identifiers starting with `__` are reserved for the implementation", s.kind(), s.toPrettyChars()); + error(s.loc, "%s name `__ctor` is not allowed", s.kind); + errorSupplemental(s.loc, "identifiers starting with `__` are reserved for internal use"); errors = true; s = null; } diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d index 5fe5273..e1aefdb 100644 --- a/gcc/d/dmd/arrayop.d +++ b/gcc/d/dmd/arrayop.d @@ -44,12 +44,12 @@ bool isArrayOpValid(Expression e) if (e.op == EXP.arrayLiteral) { Type t = e.type.toBasetype(); - while (t.ty == Tarray || t.ty == Tsarray) + while (t.isStaticOrDynamicArray()) t = t.nextOf().toBasetype(); return (t.ty != Tvoid); } Type tb = e.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) + if (tb.isStaticOrDynamicArray()) { if (isUnaArrayOp(e.op)) { @@ -80,7 +80,7 @@ bool isNonAssignmentArrayOp(Expression e) return isNonAssignmentArrayOp(e.isSliceExp().e1); Type tb = e.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) + if (tb.isStaticOrDynamicArray()) { return (isUnaArrayOp(e.op) || isBinArrayOp(e.op)); } @@ -119,7 +119,7 @@ Expression arrayOp(BinExp e, Scope* sc) { //printf("BinExp.arrayOp() %s\n", e.toChars()); Type tb = e.type.toBasetype(); - assert(tb.ty == Tarray || tb.ty == Tsarray); + assert(tb.isStaticOrDynamicArray()); Type tbn = tb.nextOf().toBasetype(); if (tbn.ty == Tvoid) { @@ -346,7 +346,7 @@ bool isArrayOpOperand(Expression e) if (e.op == EXP.arrayLiteral) { Type t = e.type.toBasetype(); - while (t.ty == Tarray || t.ty == Tsarray) + while (t.isStaticOrDynamicArray()) t = t.nextOf().toBasetype(); return (t.ty != Tvoid); } diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index 5da4721..7a60ecb 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -271,17 +271,6 @@ extern (C++) final class LinkDeclaration : AttribDeclaration return new LinkDeclaration(loc, linkage, Dsymbol.arraySyntaxCopy(decl)); } - - override const(char)* toChars() const - { - return toString().ptr; - } - - extern(D) override const(char)[] toString() const - { - return "extern ()"; - } - override void accept(Visitor v) { v.visit(this); @@ -313,16 +302,6 @@ extern (C++) final class CPPMangleDeclaration : AttribDeclaration return new CPPMangleDeclaration(loc, cppmangle, Dsymbol.arraySyntaxCopy(decl)); } - override const(char)* toChars() const - { - return toString().ptr; - } - - extern(D) override const(char)[] toString() const - { - return "extern ()"; - } - override void accept(Visitor v) { v.visit(this); @@ -383,16 +362,6 @@ extern (C++) final class CPPNamespaceDeclaration : AttribDeclaration this.loc, this.ident, this.exp, Dsymbol.arraySyntaxCopy(this.decl), this.cppnamespace); } - override const(char)* toChars() const - { - return toString().ptr; - } - - extern(D) override const(char)[] toString() const - { - return "extern (C++, `namespace`)"; - } - override void accept(Visitor v) { v.visit(this); diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h index ef01d0f..1c9bd96 100644 --- a/gcc/d/dmd/attrib.h +++ b/gcc/d/dmd/attrib.h @@ -67,7 +67,6 @@ public: static LinkDeclaration *create(const Loc &loc, LINK p, Dsymbols *decl); LinkDeclaration *syntaxCopy(Dsymbol *s) override; - const char *toChars() const override; void accept(Visitor *v) override { v->visit(this); } }; @@ -77,7 +76,6 @@ public: CPPMANGLE cppmangle; CPPMangleDeclaration *syntaxCopy(Dsymbol *s) override; - const char *toChars() const override; void accept(Visitor *v) override { v->visit(this); } }; @@ -87,7 +85,6 @@ public: Expression *exp; CPPNamespaceDeclaration *syntaxCopy(Dsymbol *s) override; - const char *toChars() const override; void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d index f66f14a..186efb0 100644 --- a/gcc/d/dmd/cond.d +++ b/gcc/d/dmd/cond.d @@ -166,7 +166,7 @@ extern (C++) final class StaticForeach : RootObject return; } - Expressions *es; + Expressions* es; if (auto ale = aggr.isArrayLiteralExp()) { // Directly use the elements of the array for the TupleExp creation @@ -493,15 +493,13 @@ extern (C++) final class StaticForeach : RootObject */ extern (C++) class DVCondition : Condition { - uint level; Identifier ident; Module mod; - extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident) @safe + extern (D) this(const ref Loc loc, Module mod, Identifier ident) @safe { super(loc); this.mod = mod; - this.level = level; this.ident = ident; } @@ -556,15 +554,13 @@ extern (C++) final class DebugCondition : DVCondition * * Params: * mod = Module this node belongs to - * level = Minimum global level this condition needs to pass. - * Only used if `ident` is `null`. * ident = Identifier required for this condition to pass. * If `null`, this conditiion will use an integer level. * loc = Location in the source file */ - extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident) @safe + extern (D) this(const ref Loc loc, Module mod, Identifier ident) @safe { - super(loc, mod, level, ident); + super(loc, mod, ident); } override int include(Scope* sc) @@ -592,8 +588,9 @@ extern (C++) final class DebugCondition : DVCondition mod.debugidsNot.push(ident); } } - else if (level <= global.params.debuglevel || level <= mod.debuglevel) + else if (global.params.debugEnabled) inc = Include.yes; + if (!definedInModule) printDepsConditional(sc, this, "depsDebug "); return (inc == Include.yes); @@ -608,11 +605,6 @@ extern (C++) final class DebugCondition : DVCondition { v.visit(this); } - - override const(char)* toChars() const - { - return ident ? ident.toChars() : "debug".ptr; - } } /** @@ -837,15 +829,13 @@ extern (C++) final class VersionCondition : DVCondition * * Params: * mod = Module this node belongs to - * level = Minimum global level this condition needs to pass. - * Only used if `ident` is `null`. * ident = Identifier required for this condition to pass. * If `null`, this conditiion will use an integer level. * loc = Location in the source file */ - extern (D) this(const ref Loc loc, Module mod, uint level, Identifier ident) @safe + extern (D) this(const ref Loc loc, Module mod, Identifier ident) @safe { - super(loc, mod, level, ident); + super(loc, mod, ident); } override int include(Scope* sc) @@ -875,8 +865,6 @@ extern (C++) final class VersionCondition : DVCondition mod.versionidsNot.push(ident); } } - else if (level <= global.params.versionlevel || level <= mod.versionlevel) - inc = Include.yes; if (!definedInModule && (!ident || (!isReserved(ident.toString()) && ident != Id._unittest && ident != Id._assert))) { @@ -894,11 +882,6 @@ extern (C++) final class VersionCondition : DVCondition { v.visit(this); } - - override const(char)* toChars() const - { - return ident ? ident.toChars() : "version".ptr; - } } /*********************************************************** @@ -968,11 +951,6 @@ extern (C++) final class StaticIfCondition : Condition { return this; } - - override const(char)* toChars() const - { - return exp ? exp.toChars() : "static if".ptr; - } } @@ -1010,7 +988,5 @@ private void printDepsConditional(Scope* sc, DVCondition condition, const(char)[ ob.writestring(") : "); if (condition.ident) ob.writestring(condition.ident.toString()); - else - ob.print(condition.level); ob.writeByte('\n'); } diff --git a/gcc/d/dmd/cond.h b/gcc/d/dmd/cond.h index fc3ebd4..ec68d19 100644 --- a/gcc/d/dmd/cond.h +++ b/gcc/d/dmd/cond.h @@ -58,7 +58,6 @@ public: class DVCondition : public Condition { public: - unsigned level; Identifier *ident; Module *mod; diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 354d83b..bef1ec9 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -2990,7 +2990,7 @@ final class CParser(AST) : Parser!AST if (isStatic || mod) error("static or type qualifier used outside of function prototype"); } - if (ts.isTypeSArray() || ts.isTypeDArray()) + if (ts.isStaticOrDynamicArray()) { /* C11 6.7.6.2-1: type qualifiers and 'static' shall only appear * in the outermost array type derivation. diff --git a/gcc/d/dmd/ctfe.h b/gcc/d/dmd/ctfe.h index 72d895c..73f1939 100644 --- a/gcc/d/dmd/ctfe.h +++ b/gcc/d/dmd/ctfe.h @@ -48,7 +48,6 @@ class ThrownExceptionExp final : public Expression { public: ClassReferenceExp *thrown; // the thing being tossed - const char *toChars() const override; void accept(Visitor *v) override { v->visit(this); } }; @@ -58,6 +57,4 @@ public: class CTFEExp final : public Expression { -public: - const char *toChars() const override; }; diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index 6d2a954..9a92781 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -688,7 +688,7 @@ Expression getAggregateFromPointer(Expression e, dinteger_t* ofs) if (auto ie = e.isIndexExp()) { // Note that each AA element is part of its own memory block - if ((ie.e1.type.ty == Tarray || ie.e1.type.ty == Tsarray || ie.e1.op == EXP.string_ || ie.e1.op == EXP.arrayLiteral) && ie.e2.op == EXP.int64) + if ((ie.e1.type.isStaticOrDynamicArray() || ie.e1.op == EXP.string_ || ie.e1.op == EXP.arrayLiteral) && ie.e2.op == EXP.int64) { *ofs = ie.e2.toInteger(); return ie.e1; @@ -697,7 +697,7 @@ Expression getAggregateFromPointer(Expression e, dinteger_t* ofs) if (auto se = e.isSliceExp()) { if (se && e.type.toBasetype().ty == Tsarray && - (se.e1.type.ty == Tarray || se.e1.type.ty == Tsarray || se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral) && se.lwr.op == EXP.int64) + (se.e1.type.isStaticOrDynamicArray() || se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral) && se.lwr.op == EXP.int64) { *ofs = se.lwr.toInteger(); return se.e1; @@ -1841,7 +1841,7 @@ bool isCtfeValueValid(Expression newval) const SliceExp se = newval.isSliceExp(); assert(se.lwr && se.lwr.op == EXP.int64); assert(se.upr && se.upr.op == EXP.int64); - return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral); + return tb.isStaticOrDynamicArray() && (se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral); } case EXP.void_: diff --git a/gcc/d/dmd/cxxfrontend.d b/gcc/d/dmd/cxxfrontend.d index b74b11b..3807c1d 100644 --- a/gcc/d/dmd/cxxfrontend.d +++ b/gcc/d/dmd/cxxfrontend.d @@ -338,13 +338,13 @@ const(char)* parametersTypeToChars(ParameterList pl) /*********************************************************** * iasm.d */ -Statement asmSemantic(AsmStatement s, Scope *sc) +Statement asmSemantic(AsmStatement s, Scope* sc) { import dmd.iasm; return dmd.iasm.asmSemantic(s, sc); } -void asmSemantic(CAsmDeclaration d, Scope *sc) +void asmSemantic(CAsmDeclaration d, Scope* sc) { import dmd.iasm; return dmd.iasm.asmSemantic(d, sc); @@ -353,13 +353,13 @@ void asmSemantic(CAsmDeclaration d, Scope *sc) /*********************************************************** * iasmgcc.d */ -Statement gccAsmSemantic(GccAsmStatement s, Scope *sc) +Statement gccAsmSemantic(GccAsmStatement s, Scope* sc) { import dmd.iasmgcc; return dmd.iasmgcc.gccAsmSemantic(s, sc); } -void gccAsmSemantic(CAsmDeclaration d, Scope *sc) +void gccAsmSemantic(CAsmDeclaration d, Scope* sc) { import dmd.iasmgcc; return dmd.iasmgcc.gccAsmSemantic(d, sc); diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 0d95ad4..bb85318 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -626,7 +626,7 @@ MATCH implicitConvTo(Expression e, Type t) if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid) return MATCH.nomatch; - if (!(e.type.ty == Tsarray || e.type.ty == Tarray || e.type.ty == Tpointer)) + if (!(e.type.isStaticOrDynamicArray() || e.type.ty == Tpointer)) return visit(e); TY tyn = e.type.nextOf().ty; @@ -758,8 +758,7 @@ MATCH implicitConvTo(Expression e, Type t) Type typeb = e.type.toBasetype(); auto result = MATCH.nomatch; - if ((tb.ty == Tarray || tb.ty == Tsarray) && - (typeb.ty == Tarray || typeb.ty == Tsarray)) + if (tb.isStaticOrDynamicArray() && typeb.isStaticOrDynamicArray()) { result = MATCH.exact; Type typen = typeb.nextOf().toBasetype(); @@ -802,7 +801,7 @@ MATCH implicitConvTo(Expression e, Type t) return result; } - else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray || typeb.ty == Tpointer)) + else if (tb.ty == Tvector && (typeb.isStaticOrDynamicArray() || typeb.ty == Tpointer)) { // Tpointer because ImportC eagerly converts Tsarray to Tpointer result = MATCH.exact; // Convert array literal to vector type @@ -2724,8 +2723,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) } Type typeb = e.type.toBasetype(); - if ((tb.ty == Tarray || tb.ty == Tsarray) && - (typeb.ty == Tarray || typeb.ty == Tsarray)) + if (tb.isStaticOrDynamicArray() && typeb.isStaticOrDynamicArray()) { if (tb.nextOf().toBasetype().ty == Tvoid && typeb.nextOf().toBasetype().ty != Tvoid) { @@ -2768,7 +2766,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) ae.type = tp; } } - else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray || typeb.ty == Tpointer)) + else if (tb.ty == Tvector && (typeb.isStaticOrDynamicArray() || typeb.ty == Tpointer)) { // Convert array literal to vector type // The Tpointer case comes from C eagerly converting Tsarray to Tpointer @@ -3140,7 +3138,7 @@ Expression inferType(Expression e, Type t, int flag = 0) Expression visitAle(ArrayLiteralExp ale) { Type tb = t.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) + if (tb.isStaticOrDynamicArray()) { Type tn = tb.nextOf(); if (ale.basis) @@ -3284,7 +3282,7 @@ private bool isVoidArrayLiteral(Expression e, Type other) { auto ale = e.isArrayLiteralExp(); e = ale[0]; - if (other.ty == Tsarray || other.ty == Tarray) + if (other.isStaticOrDynamicArray()) other = other.nextOf(); else return false; @@ -3550,7 +3548,7 @@ Lagain: return null; } - if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == EXP.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == EXP.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && t2.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1))) + if (t1.isStaticOrDynamicArray() && (e2.op == EXP.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == EXP.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && t2.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1))) { /* (T[n] op void*) => T[] * (T[] op void*) => T[] @@ -3562,7 +3560,9 @@ Lagain: return coerce(t1.nextOf().arrayOf()); } - if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == EXP.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == EXP.arrayLiteral && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && t1.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2))) + if (t2.isStaticOrDynamicArray() && + (e1.op == EXP.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == EXP.arrayLiteral + && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && t1.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2))) { /* (void* op T[n]) => T[] * (void* op T[]) => T[] @@ -3574,7 +3574,7 @@ Lagain: return coerce(t2.nextOf().arrayOf()); } - if ((t1.ty == Tsarray || t1.ty == Tarray) && (m = t1.implicitConvTo(t2)) != MATCH.nomatch) + if (t1.isStaticOrDynamicArray() && (m = t1.implicitConvTo(t2)) != MATCH.nomatch) { // https://issues.dlang.org/show_bug.cgi?id=7285 // Tsarray op [x, y, ...] should to be Tsarray @@ -3590,7 +3590,7 @@ Lagain: return convert(e1, t2); } - if ((t2.ty == Tsarray || t2.ty == Tarray) && t2.implicitConvTo(t1)) + if (t2.isStaticOrDynamicArray() && t2.implicitConvTo(t1)) { // https://issues.dlang.org/show_bug.cgi?id=7285 // https://issues.dlang.org/show_bug.cgi?id=14737 @@ -3599,7 +3599,8 @@ Lagain: return convert(e2, t1); } - if ((t1.ty == Tsarray || t1.ty == Tarray || t1.ty == Tpointer) && (t2.ty == Tsarray || t2.ty == Tarray || t2.ty == Tpointer) && t1.nextOf().mod != t2.nextOf().mod) + if ((t1.isStaticOrDynamicArray() || t1.ty == Tpointer) && (t2.isStaticOrDynamicArray() || t2.ty == Tpointer) + && t1.nextOf().mod != t2.nextOf().mod) { /* If one is mutable and the other immutable, then retry * with both of them as const @@ -3919,7 +3920,7 @@ LmodCompare: return convert(e1, t2); /// Covers array operations for user-defined types - Type checkArrayOpType(Expression e1, Expression e2, EXP op, Scope *sc) + Type checkArrayOpType(Expression e1, Expression e2, EXP op, Scope* sc) { // scalar op scalar - we shouldn't be here if (e1.type.ty != Tarray && e1.type.ty != Tsarray && e2.type.ty != Tarray && e2.type.ty != Tsarray) @@ -4138,7 +4139,7 @@ Expression typeCombine(BinExp be, Scope* sc) { Expression errorReturn() { - Expression ex = be.incompatibleTypes(); + Expression ex = be.incompatibleTypes(sc); if (ex.op == EXP.error) return ex; return ErrorExp.get(); @@ -4240,7 +4241,7 @@ extern (D) bool arrayTypeCompatibleWithoutCasting(Type t1, Type t2) t1 = t1.toBasetype(); t2 = t2.toBasetype(); - if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && t2.ty == t1.ty) + if ((t1.isStaticOrDynamicArray() || t1.ty == Tpointer) && t2.ty == t1.ty) { if (t1.nextOf().implicitConvTo(t2.nextOf()) >= MATCH.constant || t2.nextOf().implicitConvTo(t1.nextOf()) >= MATCH.constant) return true; diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index e6fb1ed..c94443d 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -1379,16 +1379,6 @@ extern (C++) class TypeInfoDeclaration : VarDeclaration assert(0); // should never be produced by syntax } - override final const(char)* toChars() const - { - //printf("TypeInfoDeclaration::toChars() tinfo = %s\n", tinfo.toChars()); - OutBuffer buf; - buf.writestring("typeid("); - buf.writestring(tinfo.toChars()); - buf.writeByte(')'); - return buf.extractChars(); - } - override final inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout @nogc nothrow pure @safe { return this; diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 7f37f89..e2ac13e 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -342,7 +342,6 @@ public: static TypeInfoDeclaration *create(Type *tinfo); TypeInfoDeclaration *syntaxCopy(Dsymbol *) override final; - const char *toChars() const override final; TypeInfoDeclaration *isTypeInfoDeclaration() override final { return this; } void accept(Visitor *v) override { v->visit(this); } @@ -787,7 +786,6 @@ public: d_bool isMoveCtor; CtorDeclaration *syntaxCopy(Dsymbol *) override; const char *kind() const override; - const char *toChars() const override; bool isVirtual() const override; bool addPreInvariant() override; bool addPostInvariant() override; @@ -814,7 +812,6 @@ class DtorDeclaration final : public FuncDeclaration public: DtorDeclaration *syntaxCopy(Dsymbol *) override; const char *kind() const override; - const char *toChars() const override; bool isVirtual() const override; bool addPreInvariant() override; bool addPostInvariant() override; diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index f219e3f..648c5b4 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -1885,7 +1885,7 @@ public: // Check for taking an address of a shared variable. // If the shared variable is an array, the offset might not be zero. Type fromType = null; - if (e.var.type.ty == Tarray || e.var.type.ty == Tsarray) + if (e.var.type.isStaticOrDynamicArray()) { fromType = (cast(TypeArray)e.var.type).next; } @@ -1900,7 +1900,7 @@ public: Expression val = getVarExp(e.loc, istate, e.var, goal); if (exceptionOrCant(val)) return; - if (val.type.ty == Tarray || val.type.ty == Tsarray) + if (val.type.isStaticOrDynamicArray()) { // Check for unsupported type painting operations Type elemtype = (cast(TypeArray)val.type).next; @@ -3354,7 +3354,7 @@ public: // a[] = e can have const e. So we compare the naked types. Type tdst = e1.type.toBasetype(); Type tsrc = e.e2.type.toBasetype(); - while (tdst.ty == Tsarray || tdst.ty == Tarray) + while (tdst.isStaticOrDynamicArray()) { tdst = (cast(TypeArray)tdst).next.toBasetype(); if (tsrc.equivalent(tdst)) @@ -4302,7 +4302,7 @@ public: Expression assignTo(ArrayLiteralExp ae, size_t lwr, size_t upr) { Expressions* w = ae.elements; - assert(ae.type.ty == Tsarray || ae.type.ty == Tarray || ae.type.ty == Tpointer); + assert(ae.type.isStaticOrDynamicArray() || ae.type.ty == Tpointer); bool directblk = (cast(TypeNext)ae.type).next.equivalent(newval.type); for (size_t k = lwr; k < upr; k++) { @@ -5804,8 +5804,7 @@ public: auto expTb = exp.type.toBasetype(); if (exp.type.implicitConvTo(tbNext) >= MATCH.convert && - (tb.ty == Tarray || tb.ty == Tsarray) && - (expTb.ty == Tarray || expTb.ty == Tsarray)) + tb.isStaticOrDynamicArray() && expTb.isStaticOrDynamicArray()) return new ArrayLiteralExp(exp.loc, e.type, exp); return exp; } @@ -5921,7 +5920,7 @@ public: bool castToSarrayPointer = false; bool castBackFromVoid = false; - if (e1.type.ty == Tarray || e1.type.ty == Tsarray || e1.type.ty == Tpointer) + if (e1.type.isStaticOrDynamicArray() || e1.type.ty == Tpointer) { // Check for unsupported type painting operations // For slices, we need the type being sliced, @@ -6101,7 +6100,7 @@ public: // Disallow array type painting, except for conversions between built-in // types of identical size. - if ((e.to.ty == Tsarray || e.to.ty == Tarray) && (e1.type.ty == Tsarray || e1.type.ty == Tarray) && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf())) + if (e.to.isStaticOrDynamicArray() && e1.type.isStaticOrDynamicArray() && !isSafePointerCast(e1.type.nextOf(), e.to.nextOf())) { auto se = e1.isStringExp(); // Allow casting a hex string literal to short[], int[] or long[] diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index f26c581..d599d9c 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -430,11 +430,9 @@ extern (C++) final class Module : Package Modules aimports; // all imported modules - uint debuglevel; // debug level Identifiers* debugids; // debug identifiers Identifiers* debugidsNot; // forward referenced debug identifiers - uint versionlevel; // version level Identifiers* versionids; // version identifiers Identifiers* versionidsNot; // forward referenced version identifiers diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index eba8ddd..0e77cdf 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -433,10 +433,7 @@ void gendocfile(Module m, const char[] ddoctext, const char* datetime, ErrorSink OutBuffer buf; if (m.filetype == FileType.ddoc) { - const ploc = m.md ? &m.md.loc : &m.loc; - Loc loc = *ploc; - if (!loc.filename) - loc.filename = srcfilename.ptr; + Loc loc = m.md ? m.md.loc : m.loc; size_t commentlen = m.comment ? strlen(cast(char*)m.comment) : 0; Dsymbols a; @@ -694,9 +691,7 @@ bool emitAnchorName(ref OutBuffer buf, Dsymbol s, Scope* sc, bool includeParent) } else { - /* We just want the identifier, not overloads like TemplateDeclaration::toChars. - * We don't want the template parameter list and constraints. */ - buf.writestring(s.Dsymbol.toChars()); + buf.writestring(s.ident ? s.ident.toString : "__anonymous"); } return true; } @@ -799,7 +794,11 @@ void emitAnchor(ref OutBuffer buf, Dsymbol s, Scope* sc, bool forHeader = false) } else { - auto symbolName = ident.toString(); + // buf.writestring("<<<"); + // buf.writestring(typeof(ident).stringof); + // buf.writestring(">>>"); + // auto symbolName = ident.toString(); + auto symbolName = ident.toChars().toDString(); buf.printf("$(%.*s %.*s", cast(int) macroName.length, macroName.ptr, cast(int) symbolName.length, symbolName.ptr); @@ -2624,7 +2623,7 @@ Parameter isFunctionParameter(Dsymbols* a, const(char)[] p) @safe /**************************************************** */ -Parameter isEponymousFunctionParameter(Dsymbols *a, const(char)[] p) @safe +Parameter isEponymousFunctionParameter(Dsymbols* a, const(char)[] p) @safe { foreach (Dsymbol dsym; *a) { @@ -3603,7 +3602,7 @@ struct MarkdownLinkReferences auto id = Identifier.lookup(ids[0].ptr, ids[0].length); if (id) { - auto loc = Loc(); + auto loc = Loc.initial; Dsymbol pscopesym; auto symbol = _scope.search(loc, id, pscopesym, SearchOpt.ignoreErrors); for (size_t i = 1; symbol && i < ids.length; ++i) @@ -4096,9 +4095,8 @@ size_t endRowAndTable(ref OutBuffer buf, size_t iStart, size_t iEnd, ref Markdow */ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t offset) { - const incrementLoc = loc.linnum == 0 ? 1 : 0; - loc.linnum = loc.linnum + incrementLoc; - loc.charnum = 0; + loc.nextLine(); + //printf("highlightText()\n"); bool leadingBlank = true; size_t iParagraphStart = offset; @@ -4202,7 +4200,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of lineQuoted = false; tableRowDetected = false; iLineStart = i + 1; - loc.linnum = loc.linnum + incrementLoc; + loc.nextLine(); // update the paragraph start if we just entered a macro if (previousMacroLevel < macroLevel && iParagraphStart < iLineStart) diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index e3feefe..2f2c017 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -55,7 +55,7 @@ import dmd.visitor; import dmd.common.outbuffer; /*************************************** - * Calls dg(Dsymbol *sym) for each Dsymbol. + * Calls dg(Dsymbol* sym) for each Dsymbol. * If dg returns !=0, stops and returns that value else returns 0. * Params: * symbols = Dsymbols @@ -84,7 +84,7 @@ int foreachDsymbol(Dsymbols* symbols, scope int delegate(Dsymbol) dg) } /*************************************** - * Calls dg(Dsymbol *sym) for each Dsymbol. + * Calls dg(Dsymbol* sym) for each Dsymbol. * Params: * symbols = Dsymbols * dg = delegate to call for each Dsymbol @@ -297,9 +297,10 @@ extern (C++) class Dsymbol : ASTNode return new Dsymbol(ident); } - override const(char)* toChars() const + final override const(char)* toChars() const { - return ident ? ident.toChars() : "__anonymous"; + import dmd.hdrgen : toChars; + return toChars(this); } // Getters / setters for fields stored in `DsymbolAttributes` diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index 3936c3e..c83b8d1 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -187,7 +187,7 @@ public: PASS semanticRun; unsigned short localNum; // perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab static Dsymbol *create(Identifier *); - const char *toChars() const override; + const char *toChars() const final override; DeprecatedDeclaration* depdecl(); CPPNamespaceDeclaration* cppnamespace(); UserAttributeDeclaration* userAttribDecl(); diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index c7fb26a..378ef9a 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -424,7 +424,7 @@ private bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc } // Save the scope and defer semantic analysis on the Dsymbol. -void deferDsymbolSemantic(Scope* sc, Dsymbol s, Scope *scx) +void deferDsymbolSemantic(Scope* sc, Dsymbol s, Scope* scx) { s._scope = scx ? scx : sc.copy(); s._scope.setNoFree(); @@ -4352,34 +4352,21 @@ private extern(C++) class AddMemberVisitor : Visitor 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) { - if (!m) - { - .error(ds.loc, "%s `%s` declaration must be at module level", ds.kind, ds.toPrettyChars); - ds.errors = true; - } - else - { - if (m.debugidsNot && 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); - } + .error(ds.loc, "%s `%s` declaration must be at module level", ds.kind, ds.toPrettyChars); + ds.errors = true; } else { - if (!m) + if (m.debugidsNot && findCondition(*m.debugidsNot, ds.ident)) { - .error(ds.loc, "%s `%s` level declaration must be at module level", ds.kind, ds.toPrettyChars); + .error(ds.loc, "%s `%s` defined after use", ds.kind, ds.toPrettyChars); ds.errors = true; } - else - m.debuglevel = ds.level; + if (!m.debugids) + m.debugids = new Identifiers(); + m.debugids.push(ds.ident); } } @@ -4389,36 +4376,24 @@ private extern(C++) class AddMemberVisitor : Visitor 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) { - 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 (m.versionidsNot && 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); - } + .error(vs.loc, "%s `%s` declaration must be at module level", vs.kind, vs.toPrettyChars); + vs.errors = true; } else { - if (!m) + if (m.versionidsNot && findCondition(*m.versionidsNot, vs.ident)) { - .error(vs.loc, "%s `%s` level declaration must be at module level", vs.kind, vs.toPrettyChars); + .error(vs.loc, "%s `%s` defined after use", vs.kind, vs.toPrettyChars); vs.errors = true; } - else - m.versionlevel = vs.level; + if (!m.versionids) + m.versionids = new Identifiers(); + m.versionids.push(vs.ident); } + } override void visit(Nspace ns) diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index dd9f3da..296c10c 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -57,7 +57,7 @@ import dmd.dsymbolsem : dsymbolSemantic, checkDeprecated, aliasSemantic, search, import dmd.errors; import dmd.errorsink; import dmd.expression; -import dmd.expressionsem : resolveLoc, expressionSemantic, resolveProperties; +import dmd.expressionsem : resolveLoc, expressionSemantic, resolveProperties, checkValue; import dmd.func; import dmd.funcsem : functionSemantic, leastAsSpecialized, overloadApply; import dmd.globals; @@ -746,14 +746,6 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol return (onemember && onemember.isAggregateDeclaration()) ? onemember.kind() : "template"; } - override const(char)* toChars() const - { - HdrGenState hgs; - OutBuffer buf; - toCharsMaybeConstraints(this, buf, hgs); - return buf.extractChars(); - } - /**************************** * Similar to `toChars`, but does not print the template constraints */ @@ -3830,13 +3822,6 @@ extern (C++) class TemplateInstance : ScopeDsymbol return true; } - override const(char)* toChars() const - { - OutBuffer buf; - toCBufferInstance(this, buf); - return buf.extractChars(); - } - override final const(char)* toPrettyCharsHelper() { OutBuffer buf; @@ -5524,13 +5509,6 @@ extern (C++) final class TemplateMixin : TemplateInstance return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0; } - override const(char)* toChars() const - { - OutBuffer buf; - toCBufferInstance(this, buf); - return buf.extractChars(); - } - extern (D) bool findTempDecl(Scope* sc) { // Follow qualifications to find the TemplateDeclaration diff --git a/gcc/d/dmd/dversion.d b/gcc/d/dmd/dversion.d index 42d7d8f..d8c8b24 100644 --- a/gcc/d/dmd/dversion.d +++ b/gcc/d/dmd/dversion.d @@ -29,21 +29,17 @@ import dmd.visitor; /*********************************************************** * DebugSymbol's happen for statements like: * debug = identifier; - * debug = integer; */ extern (C++) final class DebugSymbol : Dsymbol { - uint level; - extern (D) this(const ref Loc loc, Identifier ident) @safe { super(loc, ident); } - extern (D) this(const ref Loc loc, uint level) @safe + extern (D) this(const ref Loc loc) @safe { super(loc, null); - this.level = level; } override DebugSymbol syntaxCopy(Dsymbol s) @@ -51,19 +47,9 @@ extern (C++) final class DebugSymbol : Dsymbol assert(!s); auto ds = new DebugSymbol(loc, ident); ds.comment = comment; - ds.level = level; return ds; } - override const(char)* toChars() const nothrow - { - if (ident) - return ident.toChars(); - OutBuffer buf; - buf.print(level); - return buf.extractChars(); - } - override const(char)* kind() const nothrow { return "debug"; @@ -83,41 +69,28 @@ extern (C++) final class DebugSymbol : Dsymbol /*********************************************************** * VersionSymbol's happen for statements like: * version = identifier; - * version = integer; */ extern (C++) final class VersionSymbol : Dsymbol { - uint level; extern (D) this(const ref Loc loc, Identifier ident) @safe { super(loc, ident); } - extern (D) this(const ref Loc loc, uint level) @safe + extern (D) this(const ref Loc loc) @safe { super(loc, null); - this.level = level; } override VersionSymbol syntaxCopy(Dsymbol s) { assert(!s); - auto ds = ident ? new VersionSymbol(loc, ident) - : new VersionSymbol(loc, level); + auto ds = new VersionSymbol(loc, ident); ds.comment = comment; return ds; } - override const(char)* toChars() const nothrow - { - if (ident) - return ident.toChars(); - OutBuffer buf; - buf.print(level); - return buf.extractChars(); - } - override const(char)* kind() const nothrow { return "version"; diff --git a/gcc/d/dmd/errors.d b/gcc/d/dmd/errors.d index 7faa536d..ddab8a8 100644 --- a/gcc/d/dmd/errors.d +++ b/gcc/d/dmd/errors.d @@ -11,7 +11,8 @@ module dmd.errors; -import core.stdc.stdarg; +public import core.stdc.stdarg; +public import dmd.root.string: fTuple; import dmd.errorsink; import dmd.globals; import dmd.location; @@ -384,7 +385,7 @@ else * see verrorReport for arguments * Returns: true if error handling is done, false to continue printing to stderr */ -alias DiagnosticHandler = bool delegate(const ref Loc location, Color headerColor, const(char)* header, const(char)* messageFormat, va_list args, const(char)* prefix1, const(char)* prefix2); +alias DiagnosticHandler = bool delegate(const ref SourceLoc location, Color headerColor, const(char)* header, const(char)* messageFormat, va_list args, const(char)* prefix1, const(char)* prefix2); /** * The diagnostic handler. diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index ecf4f91..b9e89e8 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -1607,7 +1607,7 @@ void escapeExp(Expression e, ref scope EscapeByResults er, int deref) void visitArrayLiteral(ArrayLiteralExp e) { Type tb = e.type.toBasetype(); - if (tb.isTypeSArray() || tb.isTypeDArray()) + if (tb.isStaticOrDynamicArray()) { if (e.basis) escapeExp(e.basis, er, deref); @@ -2245,7 +2245,7 @@ private bool isTypesafeVariadicArray(VarDeclaration v) if (v.storage_class & STC.variadic) { Type tb = v.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) + if (tb.isStaticOrDynamicArray()) return true; } return false; diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 5b8e010..c8e7309 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -301,8 +301,14 @@ extern (C++) abstract class Expression : ASTNode Loc loc; // file location const EXP op; // to minimize use of dynamic_cast - bool parens; // if this is a parenthesized expression - bool rvalue; // true if this is considered to be an rvalue, even if it is an lvalue + + static struct BitFields + { + bool parens; // if this is a parenthesized expression + bool rvalue; // true if this is considered to be an rvalue, even if it is an lvalue + } + import dmd.common.bitfields; + mixin(generateBitFields!(BitFields, ubyte)); extern (D) this(const ref Loc loc, EXP op) scope @safe { @@ -375,8 +381,13 @@ extern (C++) abstract class Expression : ASTNode return DYNCAST.expression; } - override const(char)* toChars() const + final override const(char)* toChars() const { + // FIXME: Test suite relies on lambda's being printed as __lambdaXXX in errors and .stringof + // Printing a (truncated) lambda body is more user friendly + if (auto fe = isFuncExp()) + return fe.fd.toChars(); + return .toChars(this); } @@ -516,25 +527,6 @@ extern (C++) abstract class Expression : ASTNode return false; } - /**************************************** - * Check that the expression has a valid value. - * If not, generates an error "... has no value". - * Returns: - * true if the expression is not valid or has void type. - */ - bool checkValue() - { - if (type && type.toBasetype().ty == Tvoid) - { - error(loc, "expression `%s` is `void` and has no value", toChars()); - //print(); assert(0); - if (!global.gag) - type = Type.terror; - return true; - } - return false; - } - /****************************** * Take address of expression. */ @@ -2126,6 +2118,16 @@ extern (C++) final class AssocArrayLiteralExp : Expression */ extern (C++) final class StructLiteralExp : Expression { + struct BitFields + { + bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol + bool isOriginal = false; /// used when moving instances to indicate `this is this.origin` + OwnedBy ownedByCtfe = OwnedBy.code; + } + import dmd.common.bitfields; + mixin(generateBitFields!(BitFields, ubyte)); + StageFlags stageflags; + StructDeclaration sd; /// which aggregate this is for Expressions* elements; /// parallels sd.fields[] with null entries for fields to skip Type stype; /// final type of result (can be different from sd's type) @@ -2163,11 +2165,6 @@ extern (C++) final class StructLiteralExp : Expression inlineScan = 0x10, /// inlineScan is running toCBuffer = 0x20 /// toCBuffer is running } - StageFlags stageflags; - - bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol - bool isOriginal = false; /// used when moving instances to indicate `this is this.origin` - OwnedBy ownedByCtfe = OwnedBy.code; extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null) @safe { @@ -2349,12 +2346,6 @@ extern (C++) final class TypeExp : Expression return true; } - override bool checkValue() - { - error(loc, "type `%s` has no value", toChars()); - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -2408,12 +2399,6 @@ extern (C++) final class ScopeExp : Expression return false; } - override bool checkValue() - { - error(loc, "%s `%s` has no value", sds.kind(), sds.toChars()); - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -2447,12 +2432,6 @@ extern (C++) final class TemplateExp : Expression return true; } - override bool checkValue() - { - error(loc, "%s `%s` has no value", td.kind(), toChars()); - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -2720,11 +2699,6 @@ extern (C++) final class FuncExp : Expression return new FuncExp(loc, fd); } - override const(char)* toChars() const - { - return fd.toChars(); - } - override bool checkType() { if (td) @@ -2735,16 +2709,6 @@ extern (C++) final class FuncExp : Expression return false; } - override bool checkValue() - { - if (td) - { - error(loc, "template lambda has no value"); - return true; - } - return false; - } - override void accept(Visitor v) { v.visit(this); @@ -3168,12 +3132,6 @@ extern (C++) final class DotTemplateExp : UnaExp return true; } - override bool checkValue() - { - error(loc, "%s `%s` has no value", td.kind(), toChars()); - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -3252,18 +3210,6 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp return false; } - override bool checkValue() - { - if (ti.tempdecl && - ti.semantictiargsdone && - ti.semanticRun == PASS.initial) - - error(loc, "partial %s `%s` has no value", ti.kind(), toChars()); - else - error(loc, "%s `%s` has no value", ti.kind(), ti.toChars()); - return true; - } - override void accept(Visitor v) { v.visit(this); @@ -4180,10 +4126,6 @@ extern (C++) final class LoweredAssignExp : AssignExp this.lowering = lowering; } - override const(char)* toChars() const - { - return lowering.toChars(); - } override void accept(Visitor v) { v.visit(this); @@ -5089,27 +5031,6 @@ extern (C++) final class CTFEExp : Expression type = Type.tvoid; } - override const(char)* toChars() const - { - switch (op) - { - case EXP.cantExpression: - return "<cant>"; - case EXP.voidExpression: - return "cast(void)0"; - case EXP.showCtfeContext: - return "<error>"; - case EXP.break_: - return "<break>"; - case EXP.continue_: - return "<continue>"; - case EXP.goto_: - return "<goto>"; - default: - assert(0); - } - } - extern (D) __gshared CTFEExp cantexp; extern (D) __gshared CTFEExp voidexp; extern (D) __gshared CTFEExp breakexp; @@ -5146,11 +5067,6 @@ extern (C++) final class ThrownExceptionExp : Expression this.type = victim.type; } - override const(char)* toChars() const - { - return "CTFE ThrownException"; - } - override void accept(Visitor v) { v.visit(this); diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 07b163f1..09ed60f 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -77,8 +77,12 @@ public: Type *type; // !=NULL means that semantic() has been run Loc loc; // file location EXP op; // to minimize use of dynamic_cast - d_bool parens; // if this is a parenthesized expression - d_bool rvalue; // consider this an rvalue, even if it is an lvalue + uint8_t bitFields; + + bool parens() const; + bool parens(bool v); + bool rvalue() const; + bool rvalue(bool v); size_t size() const; static void _init(); @@ -87,7 +91,7 @@ public: // kludge for template.isExpression() DYNCAST dyncast() const override final { return DYNCAST_EXPRESSION; } - const char *toChars() const override; + const char* toChars() const final override; virtual dinteger_t toInteger(); virtual uinteger_t toUInteger(); @@ -97,7 +101,6 @@ public: virtual StringExp *toStringExp(); virtual bool isLvalue(); virtual bool checkType(); - virtual bool checkValue(); Expression *addressOf(); Expression *deref(); @@ -431,6 +434,24 @@ public: class StructLiteralExp final : public Expression { public: + uint8_t bitFields; + + // if this is true, use the StructDeclaration's init symbol + bool useStaticInit() const; + bool useStaticInit(bool v); + // used when moving instances to indicate `this is this.origin` + bool isOriginal() const; + bool isOriginal(bool v); + OwnedBy ownedByCtfe() const; + OwnedBy ownedByCtfe(OwnedBy v); + + /** anytime when recursive function is calling, 'stageflags' marks with bit flag of + * current stage and unmarks before return from this function. + * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline' + * (with infinite recursion) of this expression. + */ + uint8_t stageflags; + StructDeclaration *sd; // which aggregate this is for Expressions *elements; // parallels sd->fields[] with NULL entries for fields to skip Type *stype; // final type of result (can be different from sd's type) @@ -451,17 +472,6 @@ public: StructLiteralExp *origin; - /** anytime when recursive function is calling, 'stageflags' marks with bit flag of - * current stage and unmarks before return from this function. - * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline' - * (with infinite recursion) of this expression. - */ - uint8_t stageflags; - - d_bool useStaticInit; // if this is true, use the StructDeclaration's init symbol - d_bool isOriginal; // used when moving instances to indicate `this is this.origin` - OwnedBy ownedByCtfe; - static StructLiteralExp *create(const Loc &loc, StructDeclaration *sd, void *elements, Type *stype = nullptr); bool equals(const RootObject * const o) const override; StructLiteralExp *syntaxCopy() override; @@ -474,7 +484,6 @@ class TypeExp final : public Expression public: TypeExp *syntaxCopy() override; bool checkType() override; - bool checkValue() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -485,7 +494,6 @@ public: ScopeExp *syntaxCopy() override; bool checkType() override; - bool checkValue() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -497,7 +505,6 @@ public: bool isLvalue() override; bool checkType() override; - bool checkValue() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -595,9 +602,7 @@ public: bool equals(const RootObject * const o) const override; FuncExp *syntaxCopy() override; - const char *toChars() const override; bool checkType() override; - bool checkValue() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -741,7 +746,6 @@ public: TemplateDeclaration *td; bool checkType() override; - bool checkValue() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -762,7 +766,6 @@ public: DotTemplateInstanceExp *syntaxCopy() override; bool checkType() override; - bool checkValue() override; void accept(Visitor *v) override { v->visit(this); } }; @@ -1045,7 +1048,6 @@ class LoweredAssignExp final : public AssignExp public: Expression *lowering; - const char *toChars() const override; void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index fcb47a5..b498998 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -308,7 +308,7 @@ extern (D) bool findTempDecl(DotTemplateInstanceExp exp, Scope* sc) * Returns: * String literal, or `null` if error happens. */ -StringExp semanticString(Scope *sc, Expression exp, const char* s) +StringExp semanticString(Scope* sc, Expression exp, const char* s) { sc = sc.startCTFE(); exp = exp.expressionSemantic(sc); @@ -377,7 +377,7 @@ private Expression incompatibleTypes(UnaExp e) * Returns: * ErrorExp */ -extern (D) Expression incompatibleTypes(BinExp e) +extern (D) Expression incompatibleTypes(BinExp e, Scope* sc = null) { if (e.e1.type.toBasetype() == Type.terror) return e.e1; @@ -386,6 +386,10 @@ extern (D) Expression incompatibleTypes(BinExp e) // CondExp uses 'a ? b : c' but we're comparing 'b : c' const(char)* thisOp = (e.op == EXP.question) ? ":" : EXPtoString(e.op).ptr; + + if (sc && suggestBinaryOverloads(e, sc)) + return ErrorExp.get(); + if (e.e1.op == EXP.type || e.e2.op == EXP.type) { error(e.loc, "incompatible types for `(%s) %s (%s)`: cannot use `%s` with types", @@ -658,10 +662,9 @@ TupleDeclaration isAliasThisTuple(Expression e) * Runs semantic on ae.arguments. Declares temporary variables * if '$' was used. */ -Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0) +Expression resolveOpDollar(Scope* sc, ArrayExp ae, out Expression pe0) { assert(!ae.lengthVar); - *pe0 = null; AggregateDeclaration ad = isAggregate(ae.e1.type); Dsymbol slice = search_function(ad, Id.opSlice); //printf("slice = %s %s\n", slice.kind(), slice.toChars()); @@ -675,7 +678,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0) foreach (i, e; *ae.arguments) { if (i == 0) - *pe0 = extractOpDollarSideEffect(sc, ae); + pe0 = extractOpDollarSideEffect(sc, ae); if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration())) { @@ -698,7 +701,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0) // If $ was used, declare it now Expression de = new DeclarationExp(ae.loc, ae.lengthVar); de = de.expressionSemantic(sc); - *pe0 = Expression.combine(*pe0, de); + pe0 = Expression.combine(pe0, de); } sc = sc.pop(); @@ -721,7 +724,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0) if (!fslice) return fallback(); - e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs); + e = new DotTemplateInstanceExp(ae.loc, ae.e1, Id.opSlice, tiargs); e = new CallExp(ae.loc, e, fargs); e = e.expressionSemantic(sc); } @@ -745,7 +748,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0) * Returns: * ae, or ErrorExp if errors occurred */ -Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0) +Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, ref Expression pe0) { //assert(!ae.lengthVar); if (!ie) @@ -782,7 +785,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* p // If $ was used, declare it now Expression de = new DeclarationExp(ae.loc, ae.lengthVar); de = de.expressionSemantic(sc); - *pe0 = Expression.combine(*pe0, de); + pe0 = Expression.combine(pe0, de); } sc = sc.pop(); @@ -821,7 +824,7 @@ extern(D) bool arrayExpressionSemantic( * Returns: * The expression that copy constructs or moves the value. */ -extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t, bool nrvo, bool move = false) +extern (D) Expression doCopyOrMove(Scope* sc, Expression e, Type t, bool nrvo, bool move = false) { //printf("doCopyOrMove() %s\n", toChars(e)); StructDeclaration sd; @@ -1203,7 +1206,7 @@ private Expression resolveUFCS(Scope* sc, CallExp ce) eleft = die.e1; Type t = eleft.type.toBasetype(); - if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid)) + if (t.isStaticOrDynamicArray() || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid)) { /* Built-in types and arrays have no callable properties, so do shortcut. * It is necessary in: e.init() @@ -1561,7 +1564,7 @@ Expression resolvePropertiesOnly(Scope* sc, Expression e1) * Returns: * `s` turned into an expression, `ErrorExp` if an error occurred */ -Expression symbolToExp(Dsymbol s, const ref Loc loc, Scope *sc, bool hasOverloads) +Expression symbolToExp(Dsymbol s, const ref Loc loc, Scope* sc, bool hasOverloads) { static if (LOGSEMANTIC) { @@ -2346,7 +2349,7 @@ private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc) if (isRootTraitsCompilesScope(sc) ? !sc.func.isNogcBypassingInference() : !sc.func.setGCCall(f)) return false; - if (loc.linnum == 0) // e.g. implicitly generated dtor + if (loc == Loc.initial) // e.g. implicitly generated dtor loc = sc.func.loc; // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)), @@ -2368,8 +2371,14 @@ private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc) } /******************************************** - * Check that the postblit is callable if t is an array of structs. - * Returns true if error happens. + * Check that the postblit of `t` isn't @disabled and has the right + * function attributes for this scope. + * + * Params: + * t = struct type, or static array of struct type to check + * loc = error message location + * sc = scope in which attributes are checked + * Returns: true if there's an error */ private bool checkPostblit(Type t, ref Loc loc, Scope* sc) { @@ -2392,12 +2401,12 @@ private bool checkPostblit(Type t, ref Loc loc, Scope* sc) return true; //checkDeprecated(sc, sd.postblit); // necessary? - sd.postblit.checkPurity(loc, sc); - sd.postblit.checkSafety(loc, sc); - sd.postblit.checkNogc(loc, sc); //checkAccess(sd, loc, sc, sd.postblit); // necessary? - return false; - + bool result = false; + result |= sd.postblit.checkPurity(loc, sc); + result |= sd.postblit.checkSafety(loc, sc); + result |= sd.postblit.checkNogc(loc, sc); + return result; } /*************************************** @@ -3815,6 +3824,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // See tryAliasThisSemantic Type[2] aliasThisStop; + // (Optional) the expression this was lowered from, for better error messages + Expression parent; + this(Scope* sc) scope @safe { this.sc = sc; @@ -7550,7 +7562,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = e; return; } - if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray) + if (exp.e1.op == EXP.slice || exp.e1.type.isStaticOrDynamicArray()) { if (checkNonAssignmentArrayOp(exp.e1)) return setError(); @@ -7579,15 +7591,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true); exp.type = exp.e1.type; - if (auto ad = isAggregate(exp.e1.type)) - { - if (const s = search_function(ad, Id.opOpAssign)) - { - error(exp.loc, "none of the `opOpAssign` overloads of `%s` are callable for `%s` of type `%s`", ad.toChars(), exp.e1.toChars(), exp.e1.type.toChars()); - return setError(); - } - } - if (exp.e1.checkScalar() || + if (exp.suggestOpOpAssign(sc, parent) || + exp.e1.checkScalar() || exp.e1.checkReadModifyWrite(exp.op, exp.e2) || exp.e1.checkSharedAccess(sc)) return setError(); @@ -7644,7 +7649,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = (cast(BinExp)e).reorderSettingAAElem(sc); } - private Expression compileIt(MixinExp exp, Scope *sc) + private Expression compileIt(MixinExp exp, Scope* sc) { OutBuffer buf; if (expressionsToString(buf, sc, exp.exps, exp.loc, null, true)) @@ -8842,7 +8847,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor fix16997(sc, exp); exp.type = exp.e1.type; Type tb = exp.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) + if (tb.isStaticOrDynamicArray()) { if (!isArrayOpValid(exp.e1)) { @@ -8857,9 +8862,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = exp.incompatibleTypes(); return; } - if (exp.e1.checkNoBool()) - return setError(); - if (exp.e1.checkArithmetic(exp.op) || + if (exp.e1.checkNoBool() || + exp.e1.checkArithmetic(exp.op) || exp.e1.checkSharedAccess(sc)) return setError(); @@ -8885,11 +8889,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = exp.incompatibleTypes(); return; } - if (exp.e1.checkNoBool()) - return setError(); - if (exp.e1.checkArithmetic(exp.op)) - return setError(); - if (exp.e1.checkSharedAccess(sc)) + + if (exp.e1.checkNoBool() || + exp.e1.checkArithmetic(exp.op) || + exp.e1.checkSharedAccess(sc)) return setError(); result = exp.e1; @@ -8907,7 +8910,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor fix16997(sc, exp); exp.type = exp.e1.type; Type tb = exp.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) + if (tb.isStaticOrDynamicArray()) { if (!isArrayOpValid(exp.e1)) { @@ -8922,9 +8925,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = exp.incompatibleTypes(); return; } - if (exp.e1.checkNoBool()) - return setError(); - if (exp.e1.checkIntegral() || + if (exp.e1.checkNoBool() || + exp.e1.checkIntegral() || exp.e1.checkSharedAccess(sc)) return setError(); @@ -9189,7 +9191,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } - if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray)) + if (!t1b.equals(tob) && t1b.isStaticOrDynamicArray()) { if (checkNonAssignmentArrayOp(exp.e1)) return setError(); @@ -9509,7 +9511,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* Run semantic on lwr and upr. */ Scope* scx = sc; - if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple) + if (t1b.isStaticOrDynamicArray() || t1b.ty == Ttuple) { // Create scope for 'length' variable ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp); @@ -9616,7 +9618,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor IntRange lwrRange = getIntRange(exp.lwr); IntRange uprRange = getIntRange(exp.upr); - if (t1b.ty == Tsarray || t1b.ty == Tarray) + if (t1b.isStaticOrDynamicArray()) { Expression el = new ArrayLengthExp(exp.loc, exp.e1); el = el.expressionSemantic(sc); @@ -9702,8 +9704,39 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (auto ad = isAggregate(exp.e1.type)) { - error(exp.loc, "no `[]` operator overload for type `%s`", exp.e1.type.toChars()); - errorSupplemental(ad.loc, "`%s` declared here", ad.toPrettyChars()); + if (exp.arguments.length == 0) + { + error(exp.loc, "no `[]` operator overload for type `%s`", exp.e1.type.toChars()); + errorSupplemental(ad.loc, "perhaps define `auto opIndex() {}` for `%s`", ad.toPrettyChars()); + } + else + { + const(char)* typeString(Expression exp) + { + if (auto e = exp.trySemantic(sc)) + return e.type.toChars(); + else + return "__error__"; + } + + if (auto ie = (*exp.arguments)[0].isIntervalExp()) + { + error(exp.loc, "no `[%s]` operator overload for type `%s`", ie.toChars(), exp.e1.type.toChars()); + errorSupplemental(ad.loc, "perhaps define `auto opSlice(%s lower, %s upper) {}` for `%s`", + typeString(ie.lwr), typeString(ie.upr), ad.toPrettyChars()); + } + else + { + OutBuffer buf; + buf.printf("%s", typeString((*exp.arguments)[0])); + foreach (e; (*exp.arguments)[1 .. $]) + buf.printf(", %s", typeString(e)); + + error(exp.loc, "no `[]` operator overload for type `%s`", exp.e1.type.toChars()); + errorSupplemental(ad.loc, "perhaps define `auto opIndex(%s) {}` for `%s`", + buf.extractChars, ad.toPrettyChars()); + } + } } else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple) error(exp.loc, "static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars()); @@ -9906,7 +9939,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor t1b = t1b.castMod(tv1.mod); exp.e1 = exp.e1.castTo(sc, t1b); } - if (t1b.ty == Tsarray || t1b.ty == Tarray) + if (t1b.isStaticOrDynamicArray()) { if (!checkAddressable(exp, sc)) return setError(); @@ -9915,7 +9948,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* Run semantic on e2 */ Scope* scx = sc; - if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple) + if (t1b.isStaticOrDynamicArray() || t1b.ty == Ttuple) { // Create scope for 'length' variable ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp); @@ -10051,7 +10084,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // We might know $ now setLengthVarIfKnown(exp.lengthVar, t1b); - if (t1b.ty == Tsarray || t1b.ty == Tarray) + if (t1b.isStaticOrDynamicArray()) { Expression el = new ArrayLengthExp(exp.loc, exp.e1); el = el.expressionSemantic(sc); @@ -10198,7 +10231,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1); else e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1); - result = e.expressionSemantic(sc); + result = e.expressionSemanticWithParent(sc, exp); } /* @@ -10307,7 +10340,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (search_function(ad, Id.opIndexAssign)) { // Deal with $ - res = resolveOpDollar(sc, ae, &e0); + res = resolveOpDollar(sc, ae, e0); if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j) goto Lfallback; if (res.op == EXP.error) @@ -10337,7 +10370,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (maybeSlice && search_function(ad, Id.opSliceAssign)) { // Deal with $ - res = resolveOpDollar(sc, ae, ie, &e0); + res = resolveOpDollar(sc, ae, ie, e0); if (res.op == EXP.error) return setResult(res); @@ -11317,7 +11350,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } else if (exp.e1.op == EXP.slice && - (t2.ty == Tarray || t2.ty == Tsarray) && + t2.isStaticOrDynamicArray() && t2.nextOf().implicitConvTo(t1.nextOf())) { // Check element-wise assignment. @@ -11426,7 +11459,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (exp.e1.op == EXP.slice && - (t1.ty == Tarray || t1.ty == Tsarray) && + t1.isStaticOrDynamicArray() && t1.nextOf().toBasetype().ty == Tvoid) { if (t2.nextOf().implicitConvTo(t1.nextOf())) @@ -11461,7 +11494,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* Look for array operations */ - if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2)) + if (t2.isStaticOrDynamicArray() && isArrayOpValid(exp.e2)) { // Look for valid array operations if (exp.memset != MemorySet.blockAssign && @@ -11638,7 +11671,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return ae; const isArrayAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) && - (ae.e2.type.ty == Tsarray || ae.e2.type.ty == Tarray) && + (ae.e2.type.isStaticOrDynamicArray()) && (ae.e1.type.nextOf() && ae.e2.type.nextOf() && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf())); const isArraySetAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) && @@ -11710,11 +11743,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } - if (exp.e1.checkReadModifyWrite(exp.op, exp.e2)) + if (exp.suggestOpOpAssign(sc, parent) || + exp.e1.checkReadModifyWrite(exp.op, exp.e2)) return setError(); assert(exp.e1.type && exp.e2.type); - if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray) + if (exp.e1.op == EXP.slice || exp.e1.type.isStaticOrDynamicArray()) { if (checkNonAssignmentArrayOp(exp.e1)) return setError(); @@ -11734,7 +11768,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Check element types are arithmetic Type tb1 = exp.e1.type.nextOf().toBasetype(); Type tb2 = exp.e2.type.toBasetype(); - if (tb2.ty == Tarray || tb2.ty == Tsarray) + if (tb2.isStaticOrDynamicArray()) tb2 = tb2.nextOf().toBasetype(); if ((tb1.isIntegral() || tb1.isFloating()) && (tb2.isIntegral() || tb2.isFloating())) { @@ -11789,6 +11823,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } + if (exp.suggestOpOpAssign(sc, parent)) + return setError(); + if (SliceExp se = exp.e1.isSliceExp()) { if (se.e1.type.toBasetype().ty == Tsarray) @@ -11823,7 +11860,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor * EXP.concatenateDcharAssign: appending dchar to T[] */ if ((tb1.ty == Tarray) && - (tb2.ty == Tarray || tb2.ty == Tsarray) && + tb2.isStaticOrDynamicArray() && (exp.e2.implicitConvTo(exp.e1.type) || (tb2.nextOf().implicitConvTo(tb1next) && // Do not strip const(void)[] @@ -12081,7 +12118,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } Type tb = exp.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) + if (tb.isStaticOrDynamicArray()) { if (!isArrayOpValid(exp)) { @@ -12092,7 +12129,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } - if (exp.checkArithmeticBin()) + if (exp.suggestBinaryOverloads(sc) || exp.checkArithmeticBin()) return setError(); tb1 = exp.e1.type.toBasetype(); @@ -12234,7 +12271,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } Type tb = exp.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) + if (tb.isStaticOrDynamicArray()) { if (!isArrayOpValid(exp)) { @@ -12245,7 +12282,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } - if (exp.checkArithmeticBin()) + if (exp.suggestBinaryOverloads(sc) || exp.checkArithmeticBin()) return setError(); t1 = exp.e1.type.toBasetype(); @@ -12308,7 +12345,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return result; } - void handleCatArgument(Expressions *arguments, Expression e, Type catType, bool isRightArg) + void handleCatArgument(Expressions* arguments, Expression e, Type catType, bool isRightArg) { auto tb = e.type.toBasetype(); @@ -12416,7 +12453,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // Check for: array ~ element - if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid) + if (tb1.isStaticOrDynamicArray() && tb2.ty != Tvoid) { if (exp.e1.op == EXP.arrayLiteral) { @@ -12455,7 +12492,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } // Check for: element ~ array - if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid) + if (tb2.isStaticOrDynamicArray() && tb1.ty != Tvoid) { if (exp.e2.op == EXP.arrayLiteral) { @@ -12490,7 +12527,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } Lpeer: - if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod)) + if (tb1.isStaticOrDynamicArray() && tb2.isStaticOrDynamicArray() && + (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod)) { Type t1 = tb1next.mutableOf().constOf().arrayOf(); Type t2 = tb2next.mutableOf().constOf().arrayOf(); @@ -12529,8 +12567,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Type t1 = exp.e1.type.toBasetype(); Type t2 = exp.e2.type.toBasetype(); Expression e; - if ((t1.ty == Tarray || t1.ty == Tsarray) && - (t2.ty == Tarray || t2.ty == Tsarray)) + if (t1.isStaticOrDynamicArray() && t2.isStaticOrDynamicArray()) { // Normalize to ArrayLiteralExp or StringExp as far as possible e = exp.optimize(WANTvalue); @@ -12546,7 +12583,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor trySetCatExpLowering(result); } - bool commonBinOpSemantic(BinExp exp) + bool commonArithBinOpSemantic(BinExp exp) { if (Expression e = exp.opOverloadBinary(sc, aliasThisStop)) { @@ -12559,15 +12596,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = ex; return true; } - return false; - } - bool commonArithBinOpSemantic(BinExp exp) - { - if (commonBinOpSemantic(exp)) - return true; Type tb = exp.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) + if (tb.isStaticOrDynamicArray()) { if (!isArrayOpValid(exp)) { @@ -12578,7 +12609,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return true; } - if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) + if (exp.suggestBinaryOverloads(sc) || exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)) { setError(); return true; @@ -12792,7 +12823,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } - if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) + if (exp.suggestBinaryOverloads(sc) || exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) return setError(); if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype())) @@ -12847,7 +12878,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } Type tb = exp.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) + if (tb.isStaticOrDynamicArray()) { if (!isArrayOpValid(exp)) { @@ -12862,7 +12893,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = exp.incompatibleTypes(); return; } - if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) + + if (exp.suggestBinaryOverloads(sc) || exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)) return setError(); result = exp; @@ -13008,7 +13040,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Expression arrayLowering = null; t1 = exp.e1.type.toBasetype(); t2 = exp.e2.type.toBasetype(); - if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer)) + if ((t1.isStaticOrDynamicArray() || t1.ty == Tpointer) && (t2.isStaticOrDynamicArray() || t2.ty == Tpointer)) { Type t1next = t1.nextOf(); Type t2next = t2.nextOf(); @@ -13018,8 +13050,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - if ((t1.ty == Tarray || t1.ty == Tsarray) && - (t2.ty == Tarray || t2.ty == Tsarray)) + if (t1.isStaticOrDynamicArray() && t2.isStaticOrDynamicArray()) { if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays")) return setError(); @@ -13040,12 +13071,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor arrayLowering = al; } } - else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass)) + else if (t1.isTypeClass() && t2.isTypeClass()) { - if (t2.ty == Tstruct) - error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars()); - else - error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars()); + error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars()); return setError(); } else if (t1.isComplex() || t2.isComplex()) @@ -13119,7 +13147,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); case Tarray, Tsarray: - result = exp.incompatibleTypes(); + result = exp.incompatibleTypes(sc); errorSupplemental(exp.loc, "`in` is only allowed on associative arrays"); const(char)* slice = (t2b.ty == Tsarray) ? "[]" : ""; errorSupplemental(exp.loc, "perhaps use `std.algorithm.find(%s, %s%s)` instead", @@ -13127,7 +13155,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; default: - result = exp.incompatibleTypes(); + result = exp.incompatibleTypes(sc); return; } result = exp; @@ -13258,8 +13286,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } - const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) && - (t2.ty == Tarray || t2.ty == Tsarray); + const isArrayComparison = t1.isStaticOrDynamicArray() && t2.isStaticOrDynamicArray(); const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc); if (!needsArrayLowering) @@ -13849,6 +13876,20 @@ private Expression expressionSemantic(Expression e, Scope* sc, Type[2] aliasThis return v.result; } +// ditto, but with `parent` parameter that represents the expression before rewriting. +// This way, when lowering an expression (e.g. i++ to i+=1), error messages can still +// refer to the original expression. +private Expression expressionSemanticWithParent(Expression e, Scope* sc, Expression parent) +{ + if (e.expressionSemanticDone) + return e; + + scope v = new ExpressionSemanticVisitor(sc); + v.parent = parent; + e.accept(v); + return v.result; +} + private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc) { //printf("dotIdSemanticPropX() %s\n", toChars(exp)); @@ -14371,7 +14412,7 @@ Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool g { exp.e1 = die.e1; // take back Type t1b = exp.e1.type.toBasetype(); - if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid)) + if (t1b.isStaticOrDynamicArray() || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid)) { /* No built-in type has templatized properties, so do shortcut. * It is necessary in: 1024.max!"a < b" @@ -14741,11 +14782,16 @@ private bool checkArithmetic(Expression e, EXP op) return true; } - // FIXME: Existing code relies on adding / subtracting types in typeof() expressions: - // alias I = ulong; alias U = typeof(I + 1u); - // https://github.com/dlang/dmd/issues/20763 - if (op == EXP.add || op == EXP.min) + if ((op == EXP.add || op == EXP.min) && e.isTypeExp()) + { + // @@@DEPRECATED_2.121@@@ + // Deprecated in 2.111 + // In 2.121, remove this branch to let `checkValue` raise the error + deprecation(e.loc, "type `%s` has no value", e.toChars); + if (!e.type.isOpaqueType) + deprecationSupplemental(e.loc, "perhaps use `%s.init`", e.toChars); return false; + } return e.checkValue(); } @@ -14801,6 +14847,77 @@ private bool checkArithmeticBin(BinExp e) return (e.e1.checkArithmetic(e.op) || e.e2.checkArithmetic(e.op)); } +/**************************************** + * Check that the expression has a valid value. + * If not, generates an error "... has no value".` + * + * Params: + * e = expression to check + * + * Returns: + * `true` if the expression is not valid or has `void` type. + */ +bool checkValue(Expression e) +{ + if (auto te = e.isTypeExp()) + { + error(e.loc, "type `%s` has no value", e.toChars()); + if (!e.type.isOpaqueType) + errorSupplemental(e.loc, "perhaps use `%s.init`", e.toChars()); + return true; + } + + if (auto dtie = e.isDotTemplateInstanceExp()) + { + if (dtie.ti.tempdecl && + dtie.ti.semantictiargsdone && + dtie.ti.semanticRun == PASS.initial) + + error(e.loc, "partial %s `%s` has no value", dtie.ti.kind(), e.toChars()); + else + error(e.loc, "%s `%s` has no value", dtie.ti.kind(), dtie.ti.toChars()); + return true; + } + + if (auto se = e.isScopeExp()) + { + error(e.loc, "%s `%s` has no value", se.sds.kind(), se.sds.toChars()); + return true; + } + + if (auto te = e.isTemplateExp()) + { + error(e.loc, "%s `%s` has no value", te.td.kind(), te.toChars()); + return true; + } + + if (auto fe = e.isFuncExp()) + { + if (fe.td) + { + error(e.loc, "template lambda has no value"); + return true; + } + return false; + } + + if (auto dte = e.isDotTemplateExp()) + { + error(e.loc, "%s `%s` has no value", dte.td.kind(), e.toChars()); + return true; + } + + if (e.type && e.type.toBasetype().ty == Tvoid) + { + error(e.loc, "expression `%s` is `void` and has no value", e.toChars()); + //print(); assert(0); + if (!global.gag) + e.type = Type.terror; + return true; + } + return false; +} + /*************************************** * If expression is shared, check that we can access it. * Give error message if not. @@ -16251,7 +16368,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions Type typeb = se.type.toBasetype(); TY tynto = tb.nextOf().ty; if (!se.committed && - (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar && + typeb.isStaticOrDynamicArray() && tynto.isSomeChar && se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger()) { e = se.castTo(sc, t); @@ -16623,7 +16740,7 @@ private Modifiable checkModify(Declaration d, Loc loc, Scope* sc, Expression e1, if (scx.func == vthis.parent && scx.contract != Contract.none) { if (!(flag & ModifyFlags.noError)) - error(loc, "%s `%s` cannot modify parameter `this` in contract", d.kind, d.toPrettyChars); + error(loc, "cannot modify member variable `%s` in contract", d.toPrettyChars()); return Modifiable.initialization; // do not report type related errors } } diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 70f4c83..613dc1c 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -277,7 +277,7 @@ extern (C++) class FuncDeclaration : Declaration /// Sibling nested functions which called this one FuncDeclarations siblingCallers; - FuncDeclarations *inlinedNestedCallees; + FuncDeclarations* inlinedNestedCallees; /// In case of failed `@safe` inference, store the error that made the function `@system` for /// better diagnostics @@ -1390,11 +1390,6 @@ extern (C++) final class CtorDeclaration : FuncDeclaration return isCpCtor ? "copy constructor" : "constructor"; } - override const(char)* toChars() const - { - return "this"; - } - override bool isVirtual() const { return false; @@ -1496,11 +1491,6 @@ extern (C++) final class DtorDeclaration : FuncDeclaration return "destructor"; } - override const(char)* toChars() const - { - return "~this"; - } - override bool isVirtual() const { // D dtor's don't get put into the vtbl[] diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index 4d3c1b9..be65557 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -242,8 +242,7 @@ extern (C++) struct Param Output mixinOut; // write expanded mixins for debugging Output moduleDeps; // Generate `.deps` module dependencies - uint debuglevel; // debug level - uint versionlevel; // version level + bool debugEnabled; // Global -debug flag (no -debug=XXX) is active bool run; // run resulting executable Strings runargs; // arguments for executable diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 6dd4be4..e94b804 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -250,8 +250,7 @@ struct Param Output mixinOut; // write expanded mixins for debugging Output moduleDeps; // Generate `.deps` module dependencies - unsigned debuglevel; // debug level - unsigned versionlevel; // version level + d_bool debugEnabled; // -debug flag is passed d_bool run; // run resulting executable Strings runargs; // arguments for executable diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 961a0d2..c0fcf64 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -140,6 +140,42 @@ public const(char)* toChars(const Type t) return buf.extractChars(); } +public const(char)* toChars(const Dsymbol d) +{ + if (auto td = d.isTemplateDeclaration()) + { + HdrGenState hgs; + OutBuffer buf; + toCharsMaybeConstraints(td, buf, hgs); + return buf.extractChars(); + } + + if (auto ti = d.isTemplateInstance()) + { + OutBuffer buf; + toCBufferInstance(ti, buf); + return buf.extractChars(); + } + + if (auto tm = d.isTemplateMixin()) + { + OutBuffer buf; + toCBufferInstance(tm, buf); + return buf.extractChars(); + } + + if (auto tid = d.isTypeInfoDeclaration()) + { + OutBuffer buf; + buf.writestring("typeid("); + buf.writestring(tid.tinfo.toChars()); + buf.writeByte(')'); + return buf.extractChars(); + } + + return d.ident ? d.ident.toHChars2() : "__anonymous"; +} + public const(char)[] toString(const Initializer i) { OutBuffer buf; @@ -880,10 +916,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitDebugSymbol(DebugSymbol s) { buf.writestring("debug = "); - if (s.ident) - buf.writestring(s.ident.toString()); - else - buf.print(s.level); + buf.writestring(s.ident.toString()); buf.writeByte(';'); buf.writenl(); } @@ -891,10 +924,7 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitVersionSymbol(VersionSymbol s) { buf.writestring("version = "); - if (s.ident) - buf.writestring(s.ident.toString()); - else - buf.print(s.level); + buf.writestring(s.ident.toString()); buf.writeByte(';'); buf.writenl(); } @@ -2237,9 +2267,20 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt buf.writestring(e.ident.toString()); } - void visitDsymbol(DsymbolExp e) + void visitDsymbol(Dsymbol s) + { + // For -vcg-ast, print internal names such as __invariant, __ctor etc. + // This condition is a bit kludge, and can be cleaned up if the + // mutual dependency `AST.toChars <> hdrgen.d` gets refactored + if (hgs.vcg_ast && s.ident && !s.isTemplateInstance() && !s.isTemplateDeclaration()) + buf.writestring(s.ident.toChars()); + else + buf.writestring(s.toChars()); + } + + void visitDsymbolExp(DsymbolExp e) { - buf.writestring(e.s.toChars()); + visitDsymbol(e.s); } void visitThis(ThisExp e) @@ -2444,7 +2485,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt void visitVar(VarExp e) { - buf.writestring(e.var.toChars()); + visitDsymbol(e.var); } void visitOver(OverExp e) @@ -2678,7 +2719,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt { expToBuffer(e.e1, PREC.primary, buf, hgs); buf.writeByte('.'); - buf.writestring(e.var.toChars()); + visitDsymbol(e.var); } void visitDotTemplateInstance(DotTemplateInstanceExp e) @@ -2893,7 +2934,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt case EXP.float64: return visitReal(e.isRealExp()); case EXP.complex80: return visitComplex(e.isComplexExp()); case EXP.identifier: return visitIdentifier(e.isIdentifierExp()); - case EXP.dSymbol: return visitDsymbol(e.isDsymbolExp()); + case EXP.dSymbol: return visitDsymbolExp(e.isDsymbolExp()); case EXP.this_: return visitThis(e.isThisExp()); case EXP.super_: return visitSuper(e.isSuperExp()); case EXP.null_: return visitNull(e.isNullExp()); @@ -3112,20 +3153,14 @@ public: override void visit(DebugCondition c) { buf.writestring("debug ("); - if (c.ident) - buf.writestring(c.ident.toString()); - else - buf.print(c.level); + buf.writestring(c.ident.toString()); buf.writeByte(')'); } override void visit(VersionCondition c) { buf.writestring("version ("); - if (c.ident) - buf.writestring(c.ident.toString()); - else - buf.print(c.level); + buf.writestring(c.ident.toString()); buf.writeByte(')'); } @@ -4505,7 +4540,15 @@ string EXPtoString(EXP op) EXP.declaration : "declaration", EXP.interval : "interval", - EXP.loweredAssignExp : "=" + EXP.loweredAssignExp : "=", + + EXP.thrownException : "CTFE ThrownException", + EXP.cantExpression : "<cant>", + EXP.voidExpression : "cast(void)0", + EXP.showCtfeContext : "<error>", + EXP.break_ : "<break>", + EXP.continue_ : "<continue>", + EXP.goto_ : "<goto>", ]; const p = strings[op]; if (!p) diff --git a/gcc/d/dmd/iasm.d b/gcc/d/dmd/iasm.d index 7eb51d9..d04bef3 100644 --- a/gcc/d/dmd/iasm.d +++ b/gcc/d/dmd/iasm.d @@ -39,7 +39,7 @@ else /************************ AsmStatement ***************************************/ -Statement asmSemantic(AsmStatement s, Scope *sc) +Statement asmSemantic(AsmStatement s, Scope* sc) { //printf("AsmStatement.semantic()\n"); @@ -89,7 +89,7 @@ Statement asmSemantic(AsmStatement s, Scope *sc) /************************ CAsmDeclaration ************************************/ -void asmSemantic(CAsmDeclaration ad, Scope *sc) +void asmSemantic(CAsmDeclaration ad, Scope* sc) { version (NoBackend) { diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d index 1410e0a..0961354 100644 --- a/gcc/d/dmd/iasmgcc.d +++ b/gcc/d/dmd/iasmgcc.d @@ -37,17 +37,17 @@ import dmd.statementsem; * Returns: * the completed gcc asm statement, or null if errors occurred */ -public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc) +public Statement gccAsmSemantic(GccAsmStatement s, Scope* sc) { //printf("GccAsmStatement.semantic()\n"); const bool doUnittests = global.params.parsingUnittestsRequired(); scope p = new Parser!ASTCodegen(sc._module, ";", false, global.errorSink, &global.compileEnv, doUnittests); // Make a safe copy of the token list before parsing. - Token *toklist = null; + Token* toklist = null; Token **ptoklist = &toklist; - for (Token *token = s.tokens; token; token = token.next) + for (Token* token = s.tokens; token; token = token.next) { *ptoklist = p.allocateToken(); memcpy(*ptoklist, token, Token.sizeof); @@ -126,7 +126,7 @@ public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc) * ad = asm declaration * sc = the scope where the asm declaration is located */ -public void gccAsmSemantic(CAsmDeclaration ad, Scope *sc) +public void gccAsmSemantic(CAsmDeclaration ad, Scope* sc) { import dmd.typesem : pointerTo; ad.code = semanticString(sc, ad.code, "asm definition"); @@ -254,9 +254,9 @@ Lerror: * Returns: * array of parsed clobber expressions */ -Expressions *parseExtAsmClobbers(Parser)(Parser p) +Expressions* parseExtAsmClobbers(Parser)(Parser p) { - Expressions *clobbers; + Expressions* clobbers; while (1) { @@ -305,9 +305,9 @@ Lerror: * Returns: * array of parsed goto labels */ -Identifiers *parseExtAsmGotoLabels(Parser)(Parser p) +Identifiers* parseExtAsmGotoLabels(Parser)(Parser p) { - Identifiers *labels; + Identifiers* labels; while (1) { diff --git a/gcc/d/dmd/identifier.d b/gcc/d/dmd/identifier.d index 74be1be..c3ea0f7 100644 --- a/gcc/d/dmd/identifier.d +++ b/gcc/d/dmd/identifier.d @@ -108,7 +108,8 @@ nothrow: const(char)* p = null; if (this == Id.ctor) p = "this"; - else if (this == Id.dtor) + else if (this == Id.dtor || this == Id.__xdtor || this == Id.__fieldDtor || + this == Id.__aggrDtor || this == Id.cppdtor || this == Id.ticppdtor) p = "~this"; else if (this == Id.unitTest) p = "unittest"; @@ -120,6 +121,8 @@ nothrow: p = "result"; else if (this == Id.returnLabel) p = "return"; + else if (this == Id.postblit) + p = "this(this)"; else { p = toChars(); diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d index 0413df0..84fed8f 100644 --- a/gcc/d/dmd/importc.d +++ b/gcc/d/dmd/importc.d @@ -166,7 +166,7 @@ Expression carraySemantic(ArrayExp ae, Scope* sc) * So, rewrite as an IndexExp if we can. */ auto t1 = e1.type.toBasetype(); - if (t1.isTypeDArray() || t1.isTypeSArray()) + if (t1.isStaticOrDynamicArray()) { e2 = e2.expressionSemantic(sc).arrayFuncConv(sc); // C doesn't do array bounds checking, so `true` turns it off @@ -176,7 +176,7 @@ Expression carraySemantic(ArrayExp ae, Scope* sc) e1 = e1.arrayFuncConv(sc); // e1 might still be a function call e2 = e2.expressionSemantic(sc); auto t2 = e2.type.toBasetype(); - if (t2.isTypeDArray() || t2.isTypeSArray()) + if (t2.isStaticOrDynamicArray()) { return new IndexExp(ae.loc, e2, e1, true).expressionSemantic(sc); // swap operands } diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index c181d53..467b796 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -439,7 +439,7 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn Type typeb = se.type.toBasetype(); TY tynto = tb.nextOf().ty; if (!se.committed && - (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar && + typeb.isStaticOrDynamicArray() && tynto.isSomeChar && se.numberOfCodeUnits(tynto) < tb.isTypeSArray().dim.toInteger()) { i.exp = se.castTo(sc, t); diff --git a/gcc/d/dmd/intrange.d b/gcc/d/dmd/intrange.d index 242cac0..8395a84 100644 --- a/gcc/d/dmd/intrange.d +++ b/gcc/d/dmd/intrange.d @@ -141,7 +141,7 @@ struct SignExtendedNumber SignExtendedNumber opBinary(string op : "*")(SignExtendedNumber rhs) { - // perform *saturated* multiplication, otherwise we may get bogus ranges + // perform* saturated* multiplication, otherwise we may get bogus ranges // like 0x10 * 0x10 == 0x100 == 0. /* Special handling for zeros: diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d index 37f8cfd..25b0812 100644 --- a/gcc/d/dmd/json.d +++ b/gcc/d/dmd/json.d @@ -351,19 +351,18 @@ public: { if (loc.isValid()) { - if (auto filename = loc.filename.toDString) + SourceLoc sl = SourceLoc(loc); + if (sl.filename.length > 0 && sl.filename != this.filename) { - if (filename != this.filename) - { - this.filename = filename; - property("file", filename); - } + this.filename = sl.filename; + property("file", sl.filename); } - if (loc.linnum) + + if (sl.linnum) { - property(linename, loc.linnum); - if (loc.charnum) - property(charname, loc.charnum); + property(linename, sl.linnum); + if (sl.charnum) + property(charname, sl.charnum); } } } diff --git a/gcc/d/dmd/location.d b/gcc/d/dmd/location.d index 0787068..75cd068 100644 --- a/gcc/d/dmd/location.d +++ b/gcc/d/dmd/location.d @@ -96,6 +96,16 @@ nothrow: return _linnum = num; } + /// Advance this location to the first column of the next line + void nextLine() + { + if (this._linnum) + { + this._linnum++; + this.charnum = 0; + } + } + /*** * Returns: filename for this location, null if none */ @@ -126,9 +136,7 @@ nothrow: bool showColumns = Loc.showColumns, MessageStyle messageStyle = Loc.messageStyle) const nothrow { - OutBuffer buf; - writeSourceLoc(buf, SourceLoc(this), showColumns, messageStyle); - return buf.extractChars(); + return SourceLoc(this).toChars(showColumns, messageStyle); } /** @@ -140,9 +148,11 @@ nothrow: */ extern (C++) bool equals(ref const(Loc) loc) const { - return (!showColumns || charnum == loc.charnum) && - linnum == loc.linnum && - FileName.equals(filename, loc.filename); + SourceLoc lhs = SourceLoc(this); + SourceLoc rhs = SourceLoc(loc); + return (!showColumns || lhs.column == rhs.column) && + lhs.line == rhs.line && + FileName.equals(lhs.filename, rhs.filename); } /** @@ -198,6 +208,8 @@ void writeSourceLoc(ref OutBuffer buf, bool showColumns, MessageStyle messageStyle) nothrow { + if (loc.filename.length == 0) + return; buf.writestring(loc.filename); if (loc.line == 0) return; @@ -258,4 +270,18 @@ struct SourceLoc this.line = loc.linnum; this.column = loc.charnum; } + + extern (C++) const(char)* toChars( + bool showColumns = Loc.showColumns, + MessageStyle messageStyle = Loc.messageStyle) const nothrow + { + OutBuffer buf; + writeSourceLoc(buf, this, showColumns, messageStyle); + return buf.extractChars(); + } + + bool opEquals(SourceLoc other) const nothrow + { + return this.filename == other.filename && this.line == other.line && this.column == other.column; + } } diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index 7f02bec2..fd01e73 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -109,11 +109,9 @@ public: Modules aimports; // all imported modules - unsigned debuglevel; // debug level Identifiers *debugids; // debug identifiers Identifiers *debugidsNot; // forward referenced debug identifiers - unsigned versionlevel; // version level Identifiers *versionids; // version identifiers Identifiers *versionidsNot; // forward referenced version identifiers diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index b270943..81f8a98 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -1521,6 +1521,8 @@ extern (C++) abstract class Type : ASTNode inout(TypeTraits) isTypeTraits() { return ty == Ttraits ? cast(typeof(return))this : null; } inout(TypeNoreturn) isTypeNoreturn() { return ty == Tnoreturn ? cast(typeof(return))this : null; } inout(TypeTag) isTypeTag() { return ty == Ttag ? cast(typeof(return))this : null; } + + extern (D) bool isStaticOrDynamicArray() const { return ty == Tarray || ty == Tsarray; } } override void accept(Visitor v) @@ -3947,7 +3949,7 @@ extern (C++) final class Parameter : ASTNode Type isLazyArray() { Type tb = type.toBasetype(); - if (tb.ty == Tsarray || tb.ty == Tarray) + if (tb.isStaticOrDynamicArray()) { Type tel = (cast(TypeArray)tb).next.toBasetype(); if (auto td = tel.isTypeDelegate()) @@ -4057,7 +4059,7 @@ extern (C++) final class Parameter : ASTNode /*************************************** * Expands tuples in args in depth first order. Calls - * dg(void *ctx, size_t argidx, Parameter *arg) for each Parameter. + * dg(void* ctx, size_t argidx, Parameter* arg) for each Parameter. * If dg returns !=0, stops and returns that value else returns 0. * Use this function to avoid the O(N + N^2/2) complexity of * calculating dim and calling N times getNth. @@ -4316,10 +4318,10 @@ void attributesApply(const TypeFunction tf, void delegate(string) dg, TRUSTforma AggregateDeclaration isAggregate(Type t) { t = t.toBasetype(); - if (t.ty == Tclass) - return (cast(TypeClass)t).sym; - if (t.ty == Tstruct) - return (cast(TypeStruct)t).sym; + if (auto tc = t.isTypeClass()) + return tc.sym; + if (auto ts = t.isTypeStruct()) + return ts.sym; return null; } @@ -4334,7 +4336,7 @@ AggregateDeclaration isAggregate(Type t) bool isIndexableNonAggregate(Type t) { t = t.toBasetype(); - return (t.ty == Tpointer || t.ty == Tsarray || t.ty == Tarray || t.ty == Taarray || + return (t.ty == Tpointer || t.isStaticOrDynamicArray() || t.ty == Taarray || t.ty == Ttuple || t.ty == Tvector); } diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d index ab48019..5e773f0 100644 --- a/gcc/d/dmd/ob.d +++ b/gcc/d/dmd/ob.d @@ -1683,7 +1683,7 @@ void genKill(ref ObState obstate, ObNode* ob) override void visit(ArrayLiteralExp e) { Type tb = e.type.toBasetype(); - if (tb.ty == Tsarray || tb.ty == Tarray) + if (tb.isStaticOrDynamicArray()) { if (e.basis) e.basis.accept(this); @@ -2424,7 +2424,7 @@ void checkObErrors(ref ObState obstate) override void visit(ArrayLiteralExp e) { Type tb = e.type.toBasetype(); - if (tb.ty == Tsarray || tb.ty == Tarray) + if (tb.isStaticOrDynamicArray()) { if (e.basis) e.basis.accept(this); diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index 92f3bb2..ac9e072 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -71,58 +71,63 @@ bool isCommutative(EXP op) @safe return false; } +/// Returns: whether `op` can be overloaded with `opBinary` +private bool hasOpBinary(EXP op) pure @safe +{ + switch (op) + { + case EXP.add: return true; + case EXP.min: return true; + case EXP.mul: return true; + case EXP.div: return true; + case EXP.mod: return true; + case EXP.and: return true; + case EXP.or: return true; + case EXP.xor: return true; + case EXP.leftShift: return true; + case EXP.rightShift: return true; + case EXP.unsignedRightShift: return true; + case EXP.concatenate: return true; + case EXP.pow: return true; + case EXP.in_: return true; + default: return false; + } +} + +/** + * Remove the = from op=, e.g. += becomes + + * + * Params: + * op = tag for a binary assign operator + * Returns: the corresponding binary operator, or `op` if it wasn't an assign operator +*/ +private EXP stripAssignOp(EXP op) +{ + switch (op) + { + case EXP.addAssign: return EXP.add; + case EXP.minAssign: return EXP.min; + case EXP.mulAssign: return EXP.mul; + case EXP.divAssign: return EXP.div; + case EXP.modAssign: return EXP.mod; + case EXP.andAssign: return EXP.and; + case EXP.orAssign: return EXP.or; + case EXP.xorAssign: return EXP.xor; + case EXP.leftShiftAssign: return EXP.leftShift; + case EXP.rightShiftAssign: return EXP.rightShift; + case EXP.unsignedRightShiftAssign: return EXP.unsignedRightShift; + case EXP.concatenateAssign: return EXP.concatenate; + case EXP.powAssign: return EXP.pow; + default: return op; + } +} + /******************************************* * Helper function to turn operator into template argument list */ Objects* opToArg(Scope* sc, EXP op) { - /* Remove the = from op= - */ - switch (op) - { - case EXP.addAssign: - op = EXP.add; - break; - case EXP.minAssign: - op = EXP.min; - break; - case EXP.mulAssign: - op = EXP.mul; - break; - case EXP.divAssign: - op = EXP.div; - break; - case EXP.modAssign: - op = EXP.mod; - break; - case EXP.andAssign: - op = EXP.and; - break; - case EXP.orAssign: - op = EXP.or; - break; - case EXP.xorAssign: - op = EXP.xor; - break; - case EXP.leftShiftAssign: - op = EXP.leftShift; - break; - case EXP.rightShiftAssign: - op = EXP.rightShift; - break; - case EXP.unsignedRightShiftAssign: - op = EXP.unsignedRightShift; - break; - case EXP.concatenateAssign: - op = EXP.concatenate; - break; - case EXP.powAssign: - op = EXP.pow; - break; - default: - break; - } - Expression e = new StringExp(Loc.initial, EXPtoString(op)); + Expression e = new StringExp(Loc.initial, EXPtoString(stripAssignOp(op))); e = e.expressionSemantic(sc); auto tiargs = new Objects(); tiargs.push(e); @@ -144,7 +149,7 @@ Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinExp e, Ty BinExp be = cast(BinExp)e.copy(); // Resolve 'alias this' but in case of assigment don't resolve properties yet // because 'e1 = e2' could mean 'e1(e2)' or 'e1() = e2' - bool findOnly = (e.op == EXP.assign); + bool findOnly = e.isAssignExp() !is null; be.e1 = resolveAliasThis(sc, e.e1, true, findOnly); if (!be.e1) return null; @@ -173,13 +178,12 @@ Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinExp e, Ty Expression opOverloadUnary(UnaExp e, Scope* sc) { - Expression result; if (auto ae = e.e1.isArrayExp()) { ae.e1 = ae.e1.expressionSemantic(sc); ae.e1 = resolveProperties(sc, ae.e1); Expression ae1old = ae.e1; - const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval); + const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].isIntervalExp()); IntervalExp ie = null; if (maybeSlice && ae.arguments.length) { @@ -188,70 +192,61 @@ Expression opOverloadUnary(UnaExp e, Scope* sc) Type att = null; // first cyclic `alias this` type while (true) { - if (ae.e1.op == EXP.error) + if (ae.e1.isErrorExp()) { return ae.e1; } - Expression e0 = null; Expression ae1save = ae.e1; ae.lengthVar = null; - Type t1b = ae.e1.type.toBasetype(); - AggregateDeclaration ad = isAggregate(t1b); + + AggregateDeclaration ad = isAggregate(ae.e1.type); if (!ad) break; + if (search_function(ad, Id.opIndexUnary)) { + Expression e0; // Deal with $ - result = resolveOpDollar(sc, ae, &e0); - if (!result) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j) + Expression ae2 = resolveOpDollar(sc, ae, e0); + if (!ae2) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j) goto Lfallback; - if (result.op == EXP.error) - return result; + if (ae2.isErrorExp()) + return ae2; /* Rewrite op(a[arguments]) as: - * a.opIndexUnary!(op)(arguments) - */ - Expressions* a = ae.arguments.copy(); - Objects* tiargs = opToArg(sc, e.op); - result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opIndexUnary, tiargs); - result = new CallExp(e.loc, result, a); + * a.opIndexUnary!(op)(arguments) + */ + Expression result = dotTemplateCall(ae.e1, Id.opIndexUnary, opToArg(sc, e.op), (*ae.arguments)[]); if (maybeSlice) // op(a[]) might be: a.opSliceUnary!(op)() result = result.trySemantic(sc); else result = result.expressionSemantic(sc); + if (result) - { return Expression.combine(e0, result); - } } Lfallback: if (maybeSlice && search_function(ad, Id.opSliceUnary)) { // Deal with $ - result = resolveOpDollar(sc, ae, ie, &e0); - if (result.op == EXP.error) - return result; + Expression e0; + auto ae2 = resolveOpDollar(sc, ae, ie, e0); + if (ae2.isErrorExp()) + return ae2; /* Rewrite op(a[i..j]) as: - * a.opSliceUnary!(op)(i, j) - */ - auto a = new Expressions(); - if (ie) - { - a.push(ie.lwr); - a.push(ie.upr); - } - Objects* tiargs = opToArg(sc, e.op); - result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opSliceUnary, tiargs); - result = new CallExp(e.loc, result, a); - result = result.expressionSemantic(sc); - result = Expression.combine(e0, result); - return result; + * a.opSliceUnary!(op)(i, j) + */ + Expression result = ie ? + dotTemplateCall(ae.e1, Id.opSliceUnary, opToArg(sc, e.op), ie.lwr, ie.upr) : + dotTemplateCall(ae.e1, Id.opSliceUnary, opToArg(sc, e.op)); + + return Expression.combine(e0, result.expressionSemantic(sc)); } // Didn't find it. Forward to aliasthis if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) { /* Rewrite op(a[arguments]) as: - * op(a.aliasthis[arguments]) - */ + * op(a.aliasthis[arguments]) + */ ae.e1 = resolveAliasThis(sc, ae1save, true); if (ae.e1) continue; @@ -266,7 +261,7 @@ Expression opOverloadUnary(UnaExp e, Scope* sc) Type att = null; // first cyclic `alias this` type while (1) { - if (e.e1.op == EXP.error) + if (e.e1.isErrorExp()) { return e.e1; } @@ -275,19 +270,11 @@ Expression opOverloadUnary(UnaExp e, Scope* sc) if (!ad) break; - Dsymbol fd = null; /* Rewrite as: * e1.opUnary!(op)() */ - fd = search_function(ad, Id.opUnary); - if (fd) - { - Objects* tiargs = opToArg(sc, e.op); - result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs); - result = new CallExp(e.loc, result); - result = result.expressionSemantic(sc); - return result; - } + if (Dsymbol fd = search_function(ad, Id.opUnary)) + return dotTemplateCall(e.e1, Id.opUnary, opToArg(sc, e.op)).expressionSemantic(sc); // Didn't find it. Forward to aliasthis if (ad.aliasthis && !isRecursiveAliasThis(att, e.e1.type)) @@ -303,9 +290,19 @@ Expression opOverloadUnary(UnaExp e, Scope* sc) } break; } + + // For ++ and --, rewrites to += and -= are also tried, so don't error yet + if (!e.isPreExp()) + { + error(e.loc, "operator `%s` is not defined for `%s`", EXPtoString(e.op).ptr, ad.toChars()); + errorSupplemental(ad.loc, "perhaps overload the operator with `auto opUnary(string op : \"%s\")() {}`", + EXPtoString(e.op).ptr); + return ErrorExp.get(); + } + break; } - return result; + return null; } Expression opOverloadArray(ArrayExp ae, Scope* sc) @@ -313,17 +310,16 @@ Expression opOverloadArray(ArrayExp ae, Scope* sc) ae.e1 = ae.e1.expressionSemantic(sc); ae.e1 = resolveProperties(sc, ae.e1); Expression ae1old = ae.e1; - const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval); + const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].isIntervalExp()); IntervalExp ie = null; if (maybeSlice && ae.arguments.length) { ie = (*ae.arguments)[0].isIntervalExp(); } - Expression result; Type att = null; // first cyclic `alias this` type while (true) { - if (ae.e1.op == EXP.error) + if (ae.e1.isErrorExp()) { return ae.e1; } @@ -336,67 +332,58 @@ Expression opOverloadArray(ArrayExp ae, Scope* sc) { // If the non-aggregate expression ae.e1 is indexable or sliceable, // convert it to the corresponding concrete expression. - if (isIndexableNonAggregate(t1b) || ae.e1.op == EXP.type) + if (isIndexableNonAggregate(t1b) || ae.e1.isTypeExp()) { // Convert to SliceExp if (maybeSlice) - { - result = new SliceExp(ae.loc, ae.e1, ie); - result = result.expressionSemantic(sc); - return result; - } + return new SliceExp(ae.loc, ae.e1, ie).expressionSemantic(sc); + // Convert to IndexExp if (ae.arguments.length == 1) - { - result = new IndexExp(ae.loc, ae.e1, (*ae.arguments)[0]); - result = result.expressionSemantic(sc); - return result; - } + return new IndexExp(ae.loc, ae.e1, (*ae.arguments)[0]).expressionSemantic(sc); } break; } if (search_function(ad, Id.opIndex)) { // Deal with $ - result = resolveOpDollar(sc, ae, &e0); - if (!result) // a[i..j] might be: a.opSlice(i, j) + auto ae2 = resolveOpDollar(sc, ae, e0); + if (!ae2) // a[i..j] might be: a.opSlice(i, j) goto Lfallback; - if (result.op == EXP.error) - return result; + if (ae2.isErrorExp()) + return ae2; /* Rewrite e1[arguments] as: * e1.opIndex(arguments) */ Expressions* a = ae.arguments.copy(); - result = new DotIdExp(ae.loc, ae.e1, Id.opIndex); + Expression result = new DotIdExp(ae.loc, ae.e1, Id.opIndex); result = new CallExp(ae.loc, result, a); if (maybeSlice) // a[] might be: a.opSlice() result = result.trySemantic(sc); else result = result.expressionSemantic(sc); + if (result) - { return Expression.combine(e0, result); - } } Lfallback: - if (maybeSlice && ae.e1.op == EXP.type) + if (maybeSlice && ae.e1.isTypeExp()) { - result = new SliceExp(ae.loc, ae.e1, ie); + Expression result = new SliceExp(ae.loc, ae.e1, ie); result = result.expressionSemantic(sc); - result = Expression.combine(e0, result); - return result; + return Expression.combine(e0, result); } if (maybeSlice && search_function(ad, Id.opSlice)) { // Deal with $ - result = resolveOpDollar(sc, ae, ie, &e0); + auto ae2 = resolveOpDollar(sc, ae, ie, e0); - if (result.op == EXP.error) + if (ae2.isErrorExp()) { - if (!e0 && !search_function(ad, Id.dollar)) { - ae.loc.errorSupplemental("Aggregate declaration '%s' does not define 'opDollar'", ae.e1.toChars()); - } - return result; + if (!e0 && !search_function(ad, Id.dollar)) + ad.loc.errorSupplemental("perhaps define `opDollar` for `%s`", ad.toChars()); + + return ae2; } /* Rewrite a[i..j] as: * a.opSlice(i, j) @@ -407,11 +394,10 @@ Expression opOverloadArray(ArrayExp ae, Scope* sc) a.push(ie.lwr); a.push(ie.upr); } - result = new DotIdExp(ae.loc, ae.e1, Id.opSlice); + Expression result = new DotIdExp(ae.loc, ae.e1, Id.opSlice); result = new CallExp(ae.loc, result, a); result = result.expressionSemantic(sc); - result = Expression.combine(e0, result); - return result; + return Expression.combine(e0, result); } // Didn't find it. Forward to aliasthis if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) @@ -428,7 +414,7 @@ Expression opOverloadArray(ArrayExp ae, Scope* sc) } ae.e1 = ae1old; // recovery ae.lengthVar = null; - return result; + return null; } /*********************************************** @@ -437,48 +423,38 @@ Expression opOverloadArray(ArrayExp ae, Scope* sc) */ Expression opOverloadCast(CastExp e, Scope* sc, Type att = null) { - Expression result; - if (AggregateDeclaration ad = isAggregate(e.e1.type)) + AggregateDeclaration ad = isAggregate(e.e1.type); + if (!ad) + return null; + + // Rewrite as: e1.opCast!(T)() + if (Dsymbol fd = search_function(ad, Id.opCast)) { - Dsymbol fd = null; - /* Rewrite as: - * e1.opCast!(T)() - */ - fd = search_function(ad, Id.opCast); - if (fd) + version (all) { - version (all) + // Backwards compatibility with D1 if opCast is a function, not a template + if (fd.isFuncDeclaration()) { - // Backwards compatibility with D1 if opCast is a function, not a template - if (fd.isFuncDeclaration()) - { - // Rewrite as: e1.opCast() - return build_overload(e.loc, sc, e.e1, null, fd); - } + // Rewrite as: e1.opCast() + return build_overload(e.loc, sc, e.e1, null, fd); } - auto tiargs = new Objects(); - tiargs.push(e.to); - result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs); - result = new CallExp(e.loc, result); - result = result.expressionSemantic(sc); - return result; } - // Didn't find it. Forward to aliasthis - if (ad.aliasthis && !isRecursiveAliasThis(att, e.e1.type)) + auto tiargs = new Objects(); + tiargs.push(e.to); + return dotTemplateCall(e.e1, Id.opCast, tiargs).expressionSemantic(sc); + } + // Didn't find it. Forward to aliasthis + if (ad.aliasthis && !isRecursiveAliasThis(att, e.e1.type)) + { + // Rewrite `e1.opCast()` as `e1.aliasthis.opCast()` + if (auto e1 = resolveAliasThis(sc, e.e1, true)) { - /* Rewrite op(e1) as: - * op(e1.aliasthis) - */ - if (auto e1 = resolveAliasThis(sc, e.e1, true)) - { - result = e.copy(); - (cast(UnaExp)result).e1 = e1; - result = opOverloadCast(result.isCastExp(), sc, att); - return result; - } + CastExp result = e.copy().isCastExp(); + result.e1 = e1; + return result.opOverloadCast(sc, att); } } - return result; + return null; } // When no operator overload functions are found for `e`, recursively try with `alias this` @@ -488,7 +464,7 @@ Expression binAliasThis(BinExp e, Scope* sc, Type[2] aliasThisStop) AggregateDeclaration ad1 = isAggregate(e.e1.type); AggregateDeclaration ad2 = isAggregate(e.e2.type); Expression rewrittenLhs; - if (!(e.op == EXP.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 + if (!(e.isAssignExp && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 { if (Expression result = checkAliasThisForLhs(ad1, sc, e, aliasThisStop)) { @@ -503,14 +479,14 @@ Expression binAliasThis(BinExp e, Scope* sc, Type[2] aliasThisStop) * one of the members, hence the `ad1.fields.length == 2 && ad1.vthis` * condition. */ - if (result.op != EXP.assign) + auto ae = result.isAssignExp(); + if (!ae) return result; // i.e: Rewrote `e1 = e2` -> `e1(e2)` - auto ae = result.isAssignExp(); - if (ae.e1.op != EXP.dotVariable) + auto dve = ae.e1.isDotVarExp(); + if (!dve) return result; // i.e: Rewrote `e1 = e2` -> `e1() = e2` - auto dve = ae.e1.isDotVarExp(); if (auto ad = dve.var.isMember2()) { // i.e: Rewrote `e1 = e2` -> `e1.some.var = e2` @@ -524,7 +500,7 @@ Expression binAliasThis(BinExp e, Scope* sc, Type[2] aliasThisStop) rewrittenLhs = ae.e1; } } - if (!(e.op == EXP.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 + if (!(e.isAssignExp && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943 { if (Expression result = checkAliasThisForRhs(ad2, sc, e, aliasThisStop)) return result; @@ -591,12 +567,104 @@ Expression opOverloadBinary(BinExp e, Scope* sc, Type[2] aliasThisStop) s_r = null; bool choseReverse; - if (auto res = pickBestBinaryOverload(sc, opToArg(sc, e.op), s, s_r, e, choseReverse)) - return res; + if (auto result = pickBestBinaryOverload(sc, opToArg(sc, e.op), s, s_r, e, choseReverse)) + return result; return binAliasThis(e, sc, aliasThisStop); } +/** + * If applicable, print an error relating to implementing / fixing `opBinary` functions. + * Params: + * e = binary operation + * sc = scope to try `opBinary!""` semantic in for error messages + * Returns: `true` when an error related to `opBinary` was printed + */ +bool suggestBinaryOverloads(BinExp e, Scope* sc) +{ + if (!e.op.hasOpBinary) + return false; + + AggregateDeclaration ad1 = isAggregate(e.e1.type); + AggregateDeclaration ad2 = isAggregate(e.e2.type); + + if (ad1) + { + if (Dsymbol s = search_function(ad1, Id.opBinary)) + { + // This expressionSemantic will fail, otherwise operator overloading would have succeeded before + dotTemplateCall(e.e1, Id.opBinary, opToArg(sc, e.op), e.e2).expressionSemantic(sc); + errorSupplemental(s.loc, "`opBinary` defined here"); + return true; + } + error(e.loc, "operator `%s` is not defined for type `%s`", EXPtoString(e.op).ptr, e.e1.type.toChars); + errorSupplemental(ad1.loc, "perhaps overload the operator with `auto opBinary(string op : \"%s\")(%s rhs) {}`", EXPtoString(e.op).ptr, e.e2.type.toChars); + return true; + } + else if (ad2) + { + if (Dsymbol s_r = search_function(ad1, Id.opBinaryRight)) + { + dotTemplateCall(e.e2, Id.opBinaryRight, opToArg(sc, e.op), e.e1).expressionSemantic(sc); + errorSupplemental(s_r.loc, "`opBinaryRight` defined here"); + return true; + } + error(e.loc, "operator `%s` is not defined for type `%s`", EXPtoString(e.op).ptr, e.e2.type.toChars); + errorSupplemental(ad2.loc, "perhaps overload the operator with `auto opBinaryRight(string op : \"%s\")(%s rhs) {}`", EXPtoString(e.op).ptr, e.e1.type.toChars); + return true; + } + return false; +} + +/** + * If applicable, print an error relating to implementing / fixing `opOpAssign` or `opUnary` functions. + * Params: + * exp = binary operation + * sc = scope to try `opOpAssign!""` semantic in for error messages + * parent = if `exp` was lowered from this `PreExp` or `PostExp`, mention `opUnary` as well + * Returns: `true` when an error related to `opOpAssign` was printed + */ +bool suggestOpOpAssign(BinAssignExp exp, Scope* sc, Expression parent) +{ + auto ad = isAggregate(exp.e1.type); + if (!ad) + return false; + + if (parent && (parent.isPreExp() || parent.isPostExp())) + { + error(exp.loc, "operator `%s` not supported for `%s` of type `%s`", EXPtoString(parent.op).ptr, exp.e1.toChars(), ad.toChars()); + errorSupplemental(ad.loc, + "perhaps implement `auto opUnary(string op : \"%s\")() {}`"~ + " or `auto opOpAssign(string op : \"%s\")(int) {}`", + EXPtoString(stripAssignOp(parent.op)).ptr, + EXPtoString(stripAssignOp(exp.op)).ptr + ); + return true; + } + + if (const s = search_function(ad, Id.opOpAssign)) + { + // This expressionSemantic will fail, otherwise operator overloading would have succeeded before + dotTemplateCall(exp.e1, Id.opOpAssign, opToArg(sc, exp.op), exp.e2).expressionSemantic(sc); + } + else + { + error(exp.loc, "operator `%s` not supported for `%s` of type `%s`", EXPtoString(exp.op).ptr, exp.e1.toChars(), ad.toChars()); + errorSupplemental(ad.loc, "perhaps implement `auto opOpAssign(string op : \"%s\")(%s) {}`", + EXPtoString(stripAssignOp(exp.op)).ptr, exp.e2.type.toChars()); + } + return true; +} + +// Helper to construct e.id!tiargs(args), e.g. `lhs.opBinary!"+"(rhs)` +private Expression dotTemplateCall(Expression e, Identifier id, Objects* tiargs, Expression[] args...) +{ + auto ti = new DotTemplateInstanceExp(e.loc, e, id, tiargs); + auto expressions = new Expressions(); + expressions.pushSlice(args); + return new CallExp(e.loc, ti, expressions); +} + Expression opOverloadEqual(EqualExp e, Scope* sc, Type[2] aliasThisStop) { Type t1 = e.e1.type.toBasetype(); @@ -606,24 +674,23 @@ Expression opOverloadEqual(EqualExp e, Scope* sc, Type[2] aliasThisStop) * lowering to object.__equals(), which takes care of overloaded * operators for the element types. */ - if ((t1.ty == Tarray || t1.ty == Tsarray) && - (t2.ty == Tarray || t2.ty == Tsarray)) + if (t1.isStaticOrDynamicArray() && t2.isStaticOrDynamicArray()) { return null; } /* Check for class equality with null literal or typeof(null). */ - if (t1.ty == Tclass && e.e2.op == EXP.null_ || - t2.ty == Tclass && e.e1.op == EXP.null_) + if (t1.isTypeClass() && e.e2.isNullExp() || + t2.isTypeClass() && e.e1.isNullExp()) { error(e.loc, "use `%s` instead of `%s` when comparing with `null`", EXPtoString(e.op == EXP.equal ? EXP.identity : EXP.notIdentity).ptr, EXPtoString(e.op).ptr); return ErrorExp.get(); } - if (t1.ty == Tclass && t2.ty == Tnull || - t1.ty == Tnull && t2.ty == Tclass) + if (t1.isTypeClass() && t2.isTypeNull() || + t1.isTypeNull() && t2.isTypeClass()) { // Comparing a class with typeof(null) should not call opEquals return null; @@ -631,7 +698,7 @@ Expression opOverloadEqual(EqualExp e, Scope* sc, Type[2] aliasThisStop) /* Check for class equality. */ - if (t1.ty == Tclass && t2.ty == Tclass) + if (t1.isTypeClass() && t2.isTypeClass()) { ClassDeclaration cd1 = t1.isClassHandle(); ClassDeclaration cd2 = t2.isClassHandle(); @@ -672,7 +739,7 @@ Expression opOverloadEqual(EqualExp e, Scope* sc, Type[2] aliasThisStop) EXP cmpOp; if (Expression result = compare_overload(e, sc, Id.opEquals, cmpOp, aliasThisStop)) { - if (lastComma(result).op == EXP.call && e.op == EXP.notEqual) + if (lastComma(result).isCallExp() && e.op == EXP.notEqual) { result = new NotExp(result.loc, result); result = result.expressionSemantic(sc); @@ -682,7 +749,7 @@ Expression opOverloadEqual(EqualExp e, Scope* sc, Type[2] aliasThisStop) /* Check for pointer equality. */ - if (t1.ty == Tpointer || t2.ty == Tpointer) + if (t1.isTypePointer() || t2.isTypePointer()) { /* Rewrite: * ptr1 == ptr2 @@ -699,7 +766,7 @@ Expression opOverloadEqual(EqualExp e, Scope* sc, Type[2] aliasThisStop) /* Check for struct equality without opEquals. */ - if (t1.ty == Tstruct && t2.ty == Tstruct) + if (t1.isTypeStruct() && t2.isTypeStruct()) { auto sd = t1.isTypeStruct().sym; if (sd != t2.isTypeStruct().sym) @@ -738,10 +805,10 @@ Expression opOverloadEqual(EqualExp e, Scope* sc, Type[2] aliasThisStop) /* Check for tuple equality. */ - if (e.e1.op == EXP.tuple && e.e2.op == EXP.tuple) + auto tup1 = e.e1.isTupleExp(); + auto tup2 = e.e2.isTupleExp(); + if (tup1 && tup2) { - auto tup1 = e.e1.isTupleExp(); - auto tup2 = e.e2.isTupleExp(); size_t dim = tup1.exps.length; if (dim != tup2.exps.length) { @@ -794,12 +861,12 @@ Expression opOverloadCmp(CmpExp exp, Scope* sc, Type[2] aliasThisStop) error(e.loc, "recursive `opCmp` expansion"); return ErrorExp.get(); } - if (e.op != EXP.call) + if (!e.isCallExp()) return e; Type t1 = exp.e1.type.toBasetype(); Type t2 = exp.e2.type.toBasetype(); - if (t1.ty != Tclass || t2.ty != Tclass) + if (!t1.isTypeClass() || !t2.isTypeClass()) { return new CmpExp(cmpOp, exp.loc, e, IntegerExp.literal!0).expressionSemantic(sc); } @@ -842,7 +909,7 @@ Expression opOverloadBinaryAssign(BinAssignExp e, Scope* sc, Type[2] aliasThisSt ae.e1 = ae.e1.expressionSemantic(sc); ae.e1 = resolveProperties(sc, ae.e1); Expression ae1old = ae.e1; - const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval); + const(bool) maybeSlice = (ae.arguments.length == 0 || ae.arguments.length == 1 && (*ae.arguments)[0].isIntervalExp()); IntervalExp ie = null; if (maybeSlice && ae.arguments.length) { @@ -851,73 +918,61 @@ Expression opOverloadBinaryAssign(BinAssignExp e, Scope* sc, Type[2] aliasThisSt Type att = null; // first cyclic `alias this` type while (true) { - if (ae.e1.op == EXP.error) - { + if (ae.e1.isErrorExp()) return ae.e1; - } + Expression e0 = null; Expression ae1save = ae.e1; ae.lengthVar = null; - Type t1b = ae.e1.type.toBasetype(); - AggregateDeclaration ad = isAggregate(t1b); + AggregateDeclaration ad = isAggregate(ae.e1.type); if (!ad) break; if (search_function(ad, Id.opIndexOpAssign)) { // Deal with $ - Expression result = resolveOpDollar(sc, ae, &e0); - if (!result) // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j) + Expression ae2 = resolveOpDollar(sc, ae, e0); + if (!ae2) // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j) goto Lfallback; - if (result.op == EXP.error) - return result; - result = e.e2.expressionSemantic(sc); - if (result.op == EXP.error) - return result; - e.e2 = result; + if (ae2.isErrorExp()) + return ae2; + e.e2 = e.e2.expressionSemantic(sc); + if (e.e2.isErrorExp()) + return e.e2; + /* Rewrite a[arguments] op= e2 as: * a.opIndexOpAssign!(op)(e2, arguments) */ Expressions* a = ae.arguments.copy(); a.insert(0, e.e2); - Objects* tiargs = opToArg(sc, e.op); - result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opIndexOpAssign, tiargs); - result = new CallExp(e.loc, result, a); + Expression result = dotTemplateCall(ae.e1, Id.opIndexOpAssign, opToArg(sc, e.op), (*a)[]); if (maybeSlice) // (a[] op= e2) might be: a.opSliceOpAssign!(op)(e2) result = result.trySemantic(sc); else result = result.expressionSemantic(sc); + if (result) - { return Expression.combine(e0, result); - } } Lfallback: if (maybeSlice && search_function(ad, Id.opSliceOpAssign)) { // Deal with $ - Expression result = resolveOpDollar(sc, ae, ie, &e0); - if (result.op == EXP.error) - return result; - result = e.e2.expressionSemantic(sc); - if (result.op == EXP.error) - return result; - e.e2 = result; + Expression ae2 = resolveOpDollar(sc, ae, ie, e0); + if (ae2.isErrorExp()) + return ae2; + + e.e2 = e.e2.expressionSemantic(sc); + if (e.e2.isErrorExp()) + return e.e2; + /* Rewrite (a[i..j] op= e2) as: * a.opSliceOpAssign!(op)(e2, i, j) */ - auto a = new Expressions(); - a.push(e.e2); - if (ie) - { - a.push(ie.lwr); - a.push(ie.upr); - } - Objects* tiargs = opToArg(sc, e.op); - result = new DotTemplateInstanceExp(e.loc, ae.e1, Id.opSliceOpAssign, tiargs); - result = new CallExp(e.loc, result, a); - result = result.expressionSemantic(sc); - result = Expression.combine(e0, result); - return result; + auto result = ie ? + dotTemplateCall(ae.e1, Id.opSliceOpAssign, opToArg(sc, e.op), e.e2, ie.lwr, ie.upr) : + dotTemplateCall(ae.e1, Id.opSliceOpAssign, opToArg(sc, e.op), e.e2); + + return Expression.combine(e0, result.expressionSemantic(sc)); } // Didn't find it. Forward to aliasthis if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) @@ -934,14 +989,14 @@ Expression opOverloadBinaryAssign(BinAssignExp e, Scope* sc, Type[2] aliasThisSt ae.e1 = ae1old; // recovery ae.lengthVar = null; } - Expression result = e.binSemanticProp(sc); - if (result) + + if (Expression result = e.binSemanticProp(sc)) return result; + // Don't attempt 'alias this' if an error occurred - if (e.e1.type.ty == Terror || e.e2.type.ty == Terror) - { + if (e.e1.type.isTypeError() || e.e2.type.isTypeError()) return ErrorExp.get(); - } + AggregateDeclaration ad1 = isAggregate(e.e1.type); Dsymbol s = search_function(ad1, Id.opOpAssign); if (s && !s.isTemplateDeclaration()) @@ -954,7 +1009,7 @@ Expression opOverloadBinaryAssign(BinAssignExp e, Scope* sc, Type[2] aliasThisSt if (auto res = pickBestBinaryOverload(sc, opToArg(sc, e.op), s, null, e, choseReverse)) return res; - result = checkAliasThisForLhs(ad1, sc, e, aliasThisStop); + Expression result = checkAliasThisForLhs(ad1, sc, e, aliasThisStop); if (result || !s) // no point in trying Rhs alias-this if there's no overload of any kind in lhs return result; @@ -990,7 +1045,7 @@ private Expression pickBestBinaryOverload(Scope* sc, Objects* tiargs, Dsymbol s, if (s) { - functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2)); + functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(args2), null); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) return ErrorExp.get(); } @@ -998,7 +1053,7 @@ private Expression pickBestBinaryOverload(Scope* sc, Objects* tiargs, Dsymbol s, int count = m.count; if (s_r) { - functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1)); + functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(args1), null); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) return ErrorExp.get(); } @@ -1069,10 +1124,34 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, ref EXP * at this point, no matching opEquals was found for structs, * so we should not follow the alias this comparison code. */ - if ((e.op == EXP.equal || e.op == EXP.notEqual) && ad1 == ad2) + if (e.isEqualExp() && ad1 == ad2) return null; Expression result = checkAliasThisForLhs(ad1, sc, e, aliasThisStop); - return result ? result : checkAliasThisForRhs(isAggregate(e.e2.type), sc, e, aliasThisStop); + if (result) + return result; + + result = checkAliasThisForRhs(isAggregate(e.e2.type), sc, e, aliasThisStop); + if (result) + return result; + + if (s || s_r) + return null; + + Expression suggestOverloading(Expression other, AggregateDeclaration ad) + { + error(e.loc, "no operator `%s` for type `%s`", EXPtoString(e.op).ptr, ad.toChars); + string op = e.isEqualExp() ? "bool" : "int"; + errorSupplemental(ad.loc, "perhaps overload it with `%.*s %s(%s other) const {}`", op.fTuple.expand, id.toChars, other.type.toChars); + return ErrorExp.get(); + } + + // Classes have opCmp and opEquals defined in `Object` to fall back on already + if (ad1 && ad1.isStructDeclaration) + return suggestOverloading(e.e2, ad1); + if (ad2 && ad2.isStructDeclaration) + return suggestOverloading(e.e1, ad2); + + return null; } /*********************************** @@ -1104,7 +1183,7 @@ Dsymbol search_function(ScopeDsymbol ad, Identifier funcid) Dsymbol s2 = s.toAlias(); //printf("search_function: s2 = '%s'\n", s2.kind()); FuncDeclaration fd = s2.isFuncDeclaration(); - if (fd && fd.type.ty == Tfunction) + if (fd && fd.type.isTypeFunction()) return fd; if (TemplateDeclaration td = s2.isTemplateDeclaration()) return td; @@ -1135,7 +1214,7 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out aggr = aggr.expressionSemantic(sc); aggr = resolveProperties(sc, aggr); aggr = aggr.optimize(WANTvalue); - if (!aggr.type || aggr.op == EXP.error) + if (!aggr.type || aggr.isErrorExp()) return false; Type tab = aggr.type.toBasetype(); switch (tab.ty) @@ -1149,8 +1228,7 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out case Tclass: case Tstruct: { - AggregateDeclaration ad = (tab.ty == Tclass) ? tab.isTypeClass().sym - : tab.isTypeStruct().sym; + AggregateDeclaration ad = isAggregate(tab); if (!sliced) { sapply = search_function(ad, isForeach ? Id.apply : Id.applyReverse); @@ -1240,11 +1318,11 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply) // Determine ethis for sapply Expression ethis; Type tab = fes.aggr.type.toBasetype(); - if (tab.ty == Tclass || tab.ty == Tstruct) + if (tab.isTypeClass() || tab.isTypeStruct()) ethis = fes.aggr; else { - assert(tab.ty == Tdelegate && fes.aggr.op == EXP.delegate_); + assert(tab.isTypeDelegate() && fes.aggr.isDelegateExp()); ethis = fes.aggr.isDelegateExp().e1; } @@ -1284,7 +1362,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply) } p = (*fes.parameters)[1]; } - if (!p.type && tab.ty != Ttuple) + if (!p.type && !tab.isTypeTuple()) { p.type = tab.nextOf(); // value type p.type = p.type.addStorageClass(p.storageClass); @@ -1316,8 +1394,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply) case Tclass: case Tstruct: { - AggregateDeclaration ad = (tab.ty == Tclass) ? tab.isTypeClass().sym - : tab.isTypeStruct().sym; + AggregateDeclaration ad = isAggregate(tab); if (fes.parameters.length == 1) { if (!p.type) diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 2e29762..33472c8 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -2274,7 +2274,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer */ private AST.Condition parseDebugCondition() { - uint level = 1; Identifier id = null; Loc loc = token.loc; @@ -2290,7 +2289,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); check(TOK.rightParenthesis); } - return new AST.DebugCondition(loc, mod, level, id); + return new AST.DebugCondition(loc, mod, id); } /************************************** @@ -2319,7 +2318,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer */ private AST.Condition parseVersionCondition() { - uint level = 1; Identifier id = null; Loc loc; @@ -2345,7 +2343,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else error("(condition) expected following `version`"); - return new AST.VersionCondition(loc, mod, level, id); + return new AST.VersionCondition(loc, mod, id); } /*********************************************** @@ -5379,7 +5377,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer */ private void checkDanglingElse(Loc elseloc) { - if (token.value != TOK.else_ && token.value != TOK.catch_ && token.value != TOK.finally_ && lookingForElse.linnum != 0) + if (token.value != TOK.else_ && token.value != TOK.catch_ && token.value != TOK.finally_ && lookingForElse.isValid) { eSink.warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars()); } @@ -6255,12 +6253,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.assign) { if (auto ds = parseDebugSpecification()) - { - if (ds.ident) - eSink.error(ds.loc, "%s `%s` declaration must be at module level", ds.kind, ds.toPrettyChars); - else - eSink.error(ds.loc, "%s `%s` level declaration must be at module level", ds.kind, ds.toPrettyChars); - } + eSink.error(ds.loc, "%s `%s` declaration must be at module level", ds.kind, ds.toPrettyChars); + break; } cond = parseDebugCondition(); @@ -6271,12 +6265,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.assign) { if (auto vs = parseVersionSpecification()) - { - if (vs.ident) - eSink.error(vs.loc, "%s `%s` declaration must be at module level", vs.kind, vs.toPrettyChars); - else - eSink.error(vs.loc, "%s `%s` level declaration must be at module level", vs.kind, vs.toPrettyChars); - } + eSink.error(vs.loc, "%s `%s` declaration must be at module level", vs.kind, vs.toPrettyChars); + break; } cond = parseVersionCondition(); diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 6bbc1a9..00dc606 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -2089,7 +2089,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) // Make a copy of all the cases so that qsort doesn't scramble the actual // data we pass to codegen (the order of the cases in the switch). - CaseStatements *csCopy = (*ss.cases).copy(); + CaseStatements* csCopy = (*ss.cases).copy(); if (numcases) { diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h index e751ead..cdb1c85 100644 --- a/gcc/d/dmd/template.h +++ b/gcc/d/dmd/template.h @@ -79,7 +79,6 @@ public: bool overloadInsert(Dsymbol *s) override; bool hasStaticCtorOrDtor() override; const char *kind() const override; - const char *toChars() const override; Visibility visible() override; @@ -272,7 +271,6 @@ public: Dsymbol *toAlias() override final; // resolve real symbol const char *kind() const override; bool oneMember(Dsymbol *&ps, Identifier *ident) override; - const char *toChars() const override; const char* toPrettyCharsHelper() override final; Identifier *getIdent() override final; @@ -292,7 +290,6 @@ public: const char *kind() const override; bool oneMember(Dsymbol *&ps, Identifier *ident) override; bool hasPointers() override; - const char *toChars() const override; TemplateMixin *isTemplateMixin() override { return this; } void accept(Visitor *v) override { v->visit(this); } diff --git a/gcc/d/dmd/templatesem.d b/gcc/d/dmd/templatesem.d index a69edef..48c4297 100644 --- a/gcc/d/dmd/templatesem.d +++ b/gcc/d/dmd/templatesem.d @@ -1425,7 +1425,7 @@ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat Expression e; Type t; Dsymbol s; - Scope *sco; + Scope* sco; const errors = global.startGagging(); /* ref: https://issues.dlang.org/show_bug.cgi?id=11118 diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 65d267f..6d21d67 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -3128,7 +3128,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc) else { /* struct S { int a; }; - * struct S *s; + * struct S* s; */ } mtype.resolved = sd.type; @@ -3159,14 +3159,14 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc) mtype.tok == TOK.struct_ && s.isStructDeclaration()) { /* struct S; - * { struct S *s; } + * { struct S* s; } */ mtype.resolved = s.isStructDeclaration().type; } else { /* union S; - * { struct S *s; } + * { struct S* s; } */ .error(mtype.loc, "redeclaring `%s %s` as `%s %s`", s.kind(), s.toChars(), Token.toChars(mtype.tok), mtype.id.toChars()); @@ -7609,6 +7609,18 @@ bool checkRetType(TypeFunction tf, const ref Loc loc) return false; } +/// Returns: whether `t` is a struct/class/enum without a body +bool isOpaqueType(Type t) +{ + if (auto te = t.isTypeEnum()) + return te.sym.members is null; + if (auto ts = t.isTypeStruct()) + return ts.sym.members is null; + if (auto tc = t.isTypeClass()) + return tc.sym.members is null; + return false; +} + /******************************* Private *****************************************/ diff --git a/gcc/d/dmd/version.h b/gcc/d/dmd/version.h index dd83fd6..7913c96 100644 --- a/gcc/d/dmd/version.h +++ b/gcc/d/dmd/version.h @@ -15,11 +15,8 @@ class DebugSymbol final : public Dsymbol { public: - unsigned level; - DebugSymbol *syntaxCopy(Dsymbol *) override; - const char *toChars() const override; const char *kind() const override; DebugSymbol *isDebugSymbol() override; void accept(Visitor *v) override { v->visit(this); } @@ -28,11 +25,8 @@ public: class VersionSymbol final : public Dsymbol { public: - unsigned level; - VersionSymbol *syntaxCopy(Dsymbol *) override; - const char *toChars() const override; const char *kind() const override; VersionSymbol *isVersionSymbol() override; void accept(Visitor *v) override { v->visit(this); } diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index f04ec33..da794ea 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -1622,7 +1622,7 @@ public: if (dve->e1->op == EXP::structLiteral) { StructLiteralExp *sle = dve->e1->isStructLiteralExp (); - sle->useStaticInit = false; + sle->useStaticInit (false); } FuncDeclaration *fd = dve->var->isFuncDeclaration (); @@ -2773,7 +2773,7 @@ public: /* Building sinit trees are delayed until after frontend semantic processing has complete. Build the static initializer now. */ - if (e->useStaticInit && !this->constp_ && !e->sd->isCsymbol ()) + if (e->useStaticInit () && !this->constp_ && !e->sd->isCsymbol ()) { tree init = aggregate_initializer_decl (e->sd); @@ -2841,7 +2841,7 @@ public: tree field = get_symbol_decl (e->sd->vthis); tree value = build_vthis (e->sd); CONSTRUCTOR_APPEND_ELT (ve, field, value); - gcc_assert (e->useStaticInit == false); + gcc_assert (e->useStaticInit () == false); } /* Build a constructor in the correct shape of the aggregate type. */ |