diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2025-01-08 21:02:56 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2025-01-12 21:53:50 +0100 |
commit | 0dd21bce3afe9b0081d1d5bf4b53f9b43980c1c4 (patch) | |
tree | 4326f2031f50a7a326d79c25589ff50d00e36e77 /gcc/d/dmd | |
parent | a236f70617213343f3075ee43e8d9f5882dca400 (diff) | |
download | gcc-0dd21bce3afe9b0081d1d5bf4b53f9b43980c1c4.zip gcc-0dd21bce3afe9b0081d1d5bf4b53f9b43980c1c4.tar.gz gcc-0dd21bce3afe9b0081d1d5bf4b53f9b43980c1c4.tar.bz2 |
d: Merge upstream dmd, druntime c57da0cf59, phobos ad8ee5587
D front-end changes:
- Import latest fixes from dmd v2.110.0-beta.1.
- The `align' attribute now allows to specify `default'
explicitly.
- Add primary expression of the form `__rvalue(expression)'
which causes `expression' to be treated as an rvalue, even if
it is an lvalue.
- Shortened method syntax can now be used in constructors.
D runtime changes:
- Import latest fixes from druntime v2.110.0-beta.1.
Phobos changes:
- Import latest fixes from phobos v2.110.0-beta.1.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd c57da0cf59.
* d-codegen.cc (can_elide_copy_p): New.
(d_build_call): Use it.
* d-lang.cc (d_post_options): Update for new front-end interface.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime c57da0cf59.
* src/MERGE: Merge upstream phobos ad8ee5587.
* testsuite/libphobos.init_fini/custom_gc.d: Adjust test.
gcc/testsuite/ChangeLog:
* gdc.dg/copy1.d: New test.
Diffstat (limited to 'gcc/d/dmd')
39 files changed, 626 insertions, 509 deletions
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index bfdc9ea..e5884c6 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -82a5d2a7c4dd3d270537bcede2981e047bfd0e6a +c57da0cf5945cfb45eed06f1fd820435cda3ee3a 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/astenums.d b/gcc/d/dmd/astenums.d index 1e30b9f..551b453 100644 --- a/gcc/d/dmd/astenums.d +++ b/gcc/d/dmd/astenums.d @@ -302,7 +302,7 @@ enum ThreeState : ubyte enum TRUST : ubyte { default_ = 0, - system = 1, // @system (same as TRUST.default) + system = 1, // @system (same as TRUST.default_ unless feature "safer" is enabled) trusted = 2, // @trusted safe = 3, // @safe } diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index 0b5cd9d..5da4721 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -104,16 +104,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol return sc2; } - - override void addComment(const(char)* comment) - { - //printf("AttribDeclaration::addComment %s\n", comment); - if (comment) - { - this.include(null).foreachDsymbol( s => s.addComment(comment) ); - } - } - override const(char)* kind() const { return "attribute"; @@ -653,20 +643,6 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration } } - override final void addComment(const(char)* comment) - { - /* Because addComment is called by the parser, if we called - * include() it would define a version before it was used. - * But it's no problem to drill down to both decl and elsedecl, - * so that's the workaround. - */ - if (comment) - { - decl .foreachDsymbol( s => s.addComment(comment) ); - elsedecl.foreachDsymbol( s => s.addComment(comment) ); - } - } - override void accept(Visitor v) { v.visit(this); @@ -762,12 +738,6 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration return false; } - override void addComment(const(char)* comment) - { - // do nothing - // change this to give semantics to documentation comments on static foreach declarations - } - override const(char)* kind() const { return "static foreach"; diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h index d2d18db..ef01d0f 100644 --- a/gcc/d/dmd/attrib.h +++ b/gcc/d/dmd/attrib.h @@ -28,7 +28,6 @@ class AttribDeclaration : public Dsymbol { public: Dsymbols *decl; // array of Dsymbol's - void addComment(const utf8_t *comment) override; const char *kind() const override; bool oneMember(Dsymbol *&ps, Identifier *ident) override; bool hasPointers() override final; @@ -148,7 +147,6 @@ public: ConditionalDeclaration *syntaxCopy(Dsymbol *s) override; bool oneMember(Dsymbol *&ps, Identifier *ident) override final; - void addComment(const utf8_t *comment) override final; void accept(Visitor *v) override { v->visit(this); } }; @@ -176,7 +174,6 @@ public: StaticForeachDeclaration *syntaxCopy(Dsymbol *s) override; bool oneMember(Dsymbol *&ps, Identifier *ident) override; - void addComment(const utf8_t *comment) override; const char *kind() const override; void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index bbfb1ee..1b83860 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -1610,13 +1610,15 @@ private Statement generateCopyCtorBody(StructDeclaration sd) * Params: * sd = the `struct` for which the copy constructor is generated * hasCpCtor = set to true if a copy constructor is already present + * hasMoveCtor = set to true if a move constructor is already present * * Returns: * `true` if one needs to be generated * `false` otherwise */ -bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor) +bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor, out bool hasMoveCtor) { + //printf("needCopyCtor() %s\n", sd.toChars()); if (global.errors) return false; @@ -1648,14 +1650,17 @@ bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor) return 0; } - if (isRvalueConstructor(sd, ctorDecl)) + if (ctorDecl.isMoveCtor) rvalueCtor = ctorDecl; return 0; }); + if (rvalueCtor) + hasMoveCtor = true; + if (cpCtor) { - if (rvalueCtor) + if (0 && rvalueCtor) { .error(sd.loc, "`struct %s` may not define both a rvalue constructor and a copy constructor", sd.toChars()); errorSupplemental(rvalueCtor.loc,"rvalue constructor defined here"); @@ -1710,6 +1715,7 @@ LcheckFields: * Params: * sd = the `struct` for which the copy constructor is generated * sc = the scope where the copy constructor is generated + * hasMoveCtor = set to true when a move constructor is also detected * * Returns: * `true` if `struct` sd defines a copy constructor (explicitly or generated), @@ -1717,10 +1723,10 @@ LcheckFields: * References: * https://dlang.org/spec/struct.html#struct-copy-constructor */ -bool buildCopyCtor(StructDeclaration sd, Scope* sc) +bool buildCopyCtor(StructDeclaration sd, Scope* sc, out bool hasMoveCtor) { bool hasCpCtor; - if (!needCopyCtor(sd, hasCpCtor)) + if (!needCopyCtor(sd, hasCpCtor, hasMoveCtor)) return hasCpCtor; //printf("generating copy constructor for %s\n", sd.toChars()); diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 1578ef7..9d5aa96 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -806,6 +806,7 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2) { + //printf("Identity %s %s\n", e1.toChars(), e2.toChars()); UnionExp ue = void; int cmp; if (e1.op == EXP.null_) @@ -820,7 +821,17 @@ UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expressio { SymOffExp es1 = e1.isSymOffExp(); SymOffExp es2 = e2.isSymOffExp(); - cmp = (es1.var == es2.var && es1.offset == es2.offset); + cmp = es1.offset == es2.offset; + if (cmp) + { + cmp = es1.var == es2.var; + if (!cmp && (es1.var.isParameter() || es2.var.isParameter())) + { + // because of ref's, they may still be the same, we cannot tell + cantExp(ue); + return ue; + } + } } else { diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 9959954..e6fb1ed 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -30,6 +30,7 @@ import dmd.func; import dmd.funcsem : overloadApply, getLevelAndCheck; import dmd.globals; import dmd.gluelayer; +import dmd.hdrgen; import dmd.id; import dmd.identifier; import dmd.init; @@ -95,6 +96,7 @@ extern (C++) abstract class Declaration : Dsymbol enum ignoreRead = 2; // ignore any reads of AliasDeclaration enum nounderscore = 4; // don't prepend _ to mangled name enum hidden = 8; // don't print this in .di files + enum nrvo = 0x10; /// forward to fd.nrvo_var when generating code // overridden symbol with pragma(mangle, "...") const(char)[] mangleOverride; @@ -441,8 +443,7 @@ extern (C++) final class AliasDeclaration : Declaration extern (D) this(const ref Loc loc, Identifier ident, Type type) @safe { super(loc, ident); - //printf("AliasDeclaration(id = '%s', type = %p)\n", ident.toChars(), type); - //printf("type = '%s'\n", type.toChars()); + //debug printf("AliasDeclaration(id = '%s', type = `%s`, %p)\n", ident.toChars(), dmd.hdrgen.toChars(type), type.isTypeIdentifier()); this.type = type; assert(type); } @@ -450,7 +451,7 @@ extern (C++) final class AliasDeclaration : Declaration extern (D) this(const ref Loc loc, Identifier ident, Dsymbol s) @safe { super(loc, ident); - //printf("AliasDeclaration(id = '%s', s = %p)\n", ident.toChars(), s); + //debug printf("AliasDeclaration(id = '%s', s = `%s`)\n", ident.toChars(), s.toChars()); assert(s != this); this.aliassym = s; assert(s); @@ -611,8 +612,9 @@ extern (C++) final class AliasDeclaration : Declaration override Dsymbol toAlias() { - //printf("[%s] AliasDeclaration::toAlias('%s', this = %p, aliassym = %p, kind = '%s', inuse = %d)\n", - // loc.toChars(), toChars(), this, aliassym, aliassym ? aliassym.kind() : "", inuse); + static if (0) + printf("[%s] AliasDeclaration::toAlias('%s', this = %p, aliassym: %s, kind: '%s', inuse = %d)\n", + loc.toChars(), toChars(), this, aliassym ? aliassym.toChars() : "", aliassym ? aliassym.kind() : "", inuse); assert(this != aliassym); //static int count; if (++count == 10) *(char*)0=0; diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index bdefd2d..a98213d 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -782,6 +782,7 @@ class CtorDeclaration final : public FuncDeclaration { public: d_bool isCpCtor; + d_bool isMoveCtor; CtorDeclaration *syntaxCopy(Dsymbol *) override; const char *kind() const override; const char *toChars() const override; diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index aa48d57..76627be 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -24,6 +24,7 @@ import dmd.dclass; import dmd.declaration; import dmd.dmodule; import dmd.doc; +import dmd.dstruct; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; @@ -146,6 +147,7 @@ extern (C++) struct Scope AliasDeclaration aliasAsg; /// if set, then aliasAsg is being assigned a new value, /// do not set wasRead for it + StructDeclaration argStruct; /// elimiate recursion when looking for rvalue construction extern (D) __gshared Scope* freelist; diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index d7b1ace..abeffcb 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -101,6 +101,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration bool hasIdentityEquals; // true if has identity opEquals bool hasNoFields; // has no fields bool hasCopyCtor; // copy constructor + bool hasMoveCtor; // move constructor bool hasPointerField; // members with indirections bool hasVoidInitPointers; // void-initialized unsafe fields bool hasUnsafeBitpatterns; // @system members, pointers, bool @@ -171,11 +172,12 @@ extern (C++) class StructDeclaration : AggregateDeclaration { Dsymbol s = (*members)[i]; s.setFieldOffset(this, &fieldState, isunion); - } - if (type.ty == Terror) - { - errors = true; - return; + if (type.ty == Terror) + { + errorSupplemental(s.loc, "error on member `%s`", s.toPrettyChars); + errors = true; + return; + } } if (structsize == 0) @@ -320,11 +322,16 @@ extern (C++) class StructDeclaration : AggregateDeclaration import dmd.clone; bool hasCpCtorLocal; - needCopyCtor(this, hasCpCtorLocal); + bool hasMoveCtorLocal; + needCopyCtor(this, hasCpCtorLocal, hasMoveCtorLocal); if (enclosing || // is nested search(this, loc, Id.postblit) || // has postblit search(this, loc, Id.dtor) || // has destructor + /* This is commented out because otherwise buildkite vibe.d: + `canCAS!Task` fails to compile + */ + //hasMoveCtorLocal || // has move constructor hasCpCtorLocal) // has copy constructor { ispod = ThreeState.no; diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index af32f7a..3aed16a 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -925,22 +925,8 @@ extern (C++) class Dsymbol : ASTNode */ void addComment(const(char)* comment) { - if (!comment || !*comment) - return; - - //printf("addComment '%s' to Dsymbol %p '%s'\n", comment, this, toChars()); - void* h = cast(void*)this; // just the pointer is the key - auto p = h in commentHashTable; - if (!p) - { - commentHashTable[h] = comment; - return; - } - if (strcmp(*p, comment) != 0) - { - // Concatenate the two - *p = Lexer.combineComments((*p).toDString(), comment.toDString(), true); - } + import dmd.dsymbolsem; + dmd.dsymbolsem.addComment(this, comment); } /// get documentation comment for this Dsymbol @@ -958,7 +944,7 @@ extern (C++) class Dsymbol : ASTNode /* Shell around addComment() to avoid disruption for the moment */ final void comment(const(char)* comment) { addComment(comment); } - private extern (D) __gshared const(char)*[void*] commentHashTable; + extern (D) __gshared const(char)*[void*] commentHashTable; /********************************** diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index 7b33ed2..3936c3e 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -433,4 +433,5 @@ namespace dmd Dsymbols *include(Dsymbol *d, Scope *sc); void setScope(Dsymbol *d, Scope *sc); void importAll(Dsymbol *d, Scope *sc); + void addComment(Dsymbol *d, const char *comment); } diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 173532a..7e98436 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -53,6 +53,7 @@ import dmd.init; import dmd.initsem; import dmd.intrange; import dmd.hdrgen; +import dmd.lexer; import dmd.location; import dmd.mtype; import dmd.mustuse; @@ -64,6 +65,7 @@ import dmd.parse; debug import dmd.printast; import dmd.root.array; import dmd.root.filename; +import dmd.root.string; import dmd.common.outbuffer; import dmd.root.rmem; import dmd.rootobject; @@ -256,6 +258,10 @@ Return: */ bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, TemplateInstance ti) { + //printf("checkHasBothRvalueAndCpCtor() sd: %s ctor: %s ti: %s\n", sd.toChars(), ctor.toChars(), ti.toChars()); + /* cannot use ctor.isMoveCtor because semantic pass may not have been run yet, + * so use isRvalueConstructor() + */ if (sd && sd.hasCopyCtor && isRvalueConstructor(sd, ctor)) { .error(ctor.loc, "cannot define both an rvalue constructor and a copy constructor for `struct %s`", sd.toChars()); @@ -280,6 +286,7 @@ bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, Tem */ bool isRvalueConstructor(StructDeclaration sd, CtorDeclaration ctor) { + // note commonality with setting isMoveCtor in the semantic code for CtorDeclaration auto tf = ctor.type.isTypeFunction(); const dim = tf.parameterList.length; if (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg)) @@ -306,6 +313,7 @@ bool isRvalueConstructor(StructDeclaration sd, CtorDeclaration ctor) */ Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false) { + //printf("resolveAliasThis() %s\n", toChars(e)); import dmd.typesem : dotExp; for (AggregateDeclaration ad = isAggregate(e.type); ad;) { @@ -2399,7 +2407,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(CtorDeclaration ctd) { - //printf("CtorDeclaration::semantic() %s\n", toChars()); + //printf("CtorDeclaration::semantic() %p %s\n", ctd, ctd.toChars()); if (ctd.semanticRun >= PASS.semanticdone) return; if (ctd._scope) @@ -2432,6 +2440,24 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc.stc &= ~STC.static_; // not a static constructor funcDeclarationSemantic(sc, ctd); + // Check short constructor: this() => expr; + if (ctd.fbody) + { + if (auto s = ctd.fbody.isExpStatement()) + { + if (s.exp) + { + auto ce = s.exp.isCallExp(); + // check this/super before semantic + if (!ce || (!ce.e1.isThisExp() && !ce.e1.isSuperExp())) + { + s.exp = s.exp.expressionSemantic(sc); + if (s.exp.type.ty != Tvoid) + error(s.loc, "can only return void expression, `this` call or `super` call from constructor"); + } + } + } + } sc.pop(); @@ -2482,12 +2508,15 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } else if ((dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))) { - //printf("tf: %s\n", tf.toChars()); + //printf("tf: %s\n", toChars(tf)); auto param = tf.parameterList[0]; - if (param.storageClass & STC.ref_ && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf()) + if (param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf()) { - //printf("copy constructor\n"); - ctd.isCpCtor = true; + //printf("copy constructor %p\n", ctd); + if (param.storageClass & STC.ref_) + ctd.isCpCtor = true; // copy constructor + else + ctd.isMoveCtor = true; // move constructor } } } @@ -2978,7 +3007,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor buildDtors(sd, sc2); - sd.hasCopyCtor = buildCopyCtor(sd, sc2); + bool hasMoveCtor; + sd.hasCopyCtor = buildCopyCtor(sd, sc2, hasMoveCtor); + sd.hasMoveCtor = hasMoveCtor; + sd.postblit = buildPostBlit(sd, sc2); buildOpAssign(sd, sc2); @@ -5211,7 +5243,7 @@ void aliasInstanceSemantic(TemplateInstance tempinst, Scope* sc, TemplateDeclara // function used to perform semantic on AliasDeclaration void aliasSemantic(AliasDeclaration ds, Scope* sc) { - //printf("AliasDeclaration::semantic() %s\n", ds.toChars()); + //printf("AliasDeclaration::semantic() %s %p\n", ds.toChars(), ds.aliassym); // as DsymbolSemanticVisitor::visit(AliasDeclaration), in case we're called first. // see https://issues.dlang.org/show_bug.cgi?id=21001 @@ -7782,7 +7814,6 @@ private Expression callScopeDtor(VarDeclaration vd, Scope* sc) Expression ec; ec = new VarExp(vd.loc, vd); e = new DeleteExp(vd.loc, ec, true); - e.type = Type.tvoid; break; } return e; @@ -7845,3 +7876,57 @@ Lfail: } return false; } + +extern (C++) void addComment(Dsymbol d, const(char)* comment) +{ + scope v = new AddCommentVisitor(comment); + d.accept(v); +} + +extern (C++) class AddCommentVisitor: Visitor +{ + alias visit = Visitor.visit; + + const(char)* comment; + + this(const(char)* comment) + { + this.comment = comment; + } + + override void visit(Dsymbol d) + { + if (!comment || !*comment) + return; + + //printf("addComment '%s' to Dsymbol %p '%s'\n", comment, this, toChars()); + void* h = cast(void*)d; // just the pointer is the key + auto p = h in d.commentHashTable; + if (!p) + { + d.commentHashTable[h] = comment; + return; + } + if (strcmp(*p, comment) != 0) + { + // Concatenate the two + *p = Lexer.combineComments((*p).toDString(), comment.toDString(), true); + } + } + override void visit(AttribDeclaration atd) + { + if (comment) + { + atd.include(null).foreachDsymbol( s => s.addComment(comment) ); + } + } + override void visit(ConditionalDeclaration cd) + { + if (comment) + { + cd.decl .foreachDsymbol( s => s.addComment(comment) ); + cd.elsedecl.foreachDsymbol( s => s.addComment(comment) ); + } + } + override void visit(StaticForeachDeclaration sfd) {} +} diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index dc72b3a..355bdc4 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -293,10 +293,16 @@ enum WANTexpand = 1; // expand const/immutable variables if possible */ extern (C++) abstract class Expression : ASTNode { - Type type; // !=null means that semantic() has been run + /// Usually, this starts out as `null` and gets set to the final expression type by + /// `expressionSemantic`. However, for some expressions (such as `TypeExp`,`RealExp`, + /// `VarExp`), the field can get set to an assigned type before running semantic. + /// See `expressionSemanticDone` + Type type; + 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 extern (D) this(const ref Loc loc, EXP op) scope @safe { @@ -724,7 +730,7 @@ extern (C++) abstract class Expression : ASTNode inout(TypeidExp) isTypeidExp() { return op == EXP.typeid_ ? cast(typeof(return))this : null; } inout(TraitsExp) isTraitsExp() { return op == EXP.traits ? cast(typeof(return))this : null; } inout(HaltExp) isHaltExp() { return op == EXP.halt ? cast(typeof(return))this : null; } - inout(IsExp) isExp() { return op == EXP.is_ ? cast(typeof(return))this : null; } + inout(IsExp) isIsExp() { return op == EXP.is_ ? cast(typeof(return))this : null; } inout(MixinExp) isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; } inout(ImportExp) isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; } inout(AssertExp) isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; } @@ -1307,7 +1313,7 @@ extern (C++) class IdentifierExp : Expression override final bool isLvalue() { - return true; + return !this.rvalue; } override void accept(Visitor v) @@ -1351,7 +1357,7 @@ extern (C++) final class DsymbolExp : Expression override bool isLvalue() { - return true; + return !rvalue; } override void accept(Visitor v) @@ -1397,7 +1403,7 @@ extern (C++) class ThisExp : Expression override final bool isLvalue() { // Class `this` should be an rvalue; struct `this` should be an lvalue. - return type.toBasetype().ty != Tclass; + return !rvalue && type.toBasetype().ty != Tclass; } override void accept(Visitor v) @@ -1782,7 +1788,7 @@ extern (C++) final class StringExp : Expression /* string literal is rvalue in default, but * conversion to reference of static array is only allowed. */ - return (type && type.toBasetype().ty == Tsarray); + return !rvalue && (type && type.toBasetype().ty == Tsarray); } /******************************** @@ -2719,7 +2725,7 @@ extern (C++) final class VarExp : SymbolExp override bool isLvalue() { - if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest)) + if (rvalue || var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest)) return false; return true; } @@ -3098,7 +3104,7 @@ extern (C++) class BinAssignExp : BinExp override final bool isLvalue() { - return true; + return !rvalue; } override void accept(Visitor v) @@ -3212,7 +3218,6 @@ extern (C++) final class ThrowExp : UnaExp extern (D) this(const ref Loc loc, Expression e) { super(loc, EXP.throw_, e); - this.type = Type.tnoreturn; } override ThrowExp syntaxCopy() @@ -3303,6 +3308,8 @@ extern (C++) final class DotVarExp : UnaExp override bool isLvalue() { + if (rvalue) + return false; if (e1.op != EXP.structLiteral) return true; auto vd = var.isVarDeclaration(); @@ -3530,6 +3537,8 @@ extern (C++) final class CallExp : UnaExp override bool isLvalue() { + if (rvalue) + return false; Type tb = e1.type.toBasetype(); if (tb.ty == Tdelegate || tb.ty == Tpointer) tb = tb.nextOf(); @@ -3648,7 +3657,7 @@ extern (C++) final class PtrExp : UnaExp override bool isLvalue() { - return true; + return !rvalue; } override void accept(Visitor v) @@ -3777,7 +3786,7 @@ extern (C++) final class CastExp : UnaExp override bool isLvalue() { //printf("e1.type = %s, to.type = %s\n", e1.type.toChars(), to.toChars()); - if (!e1.isLvalue()) + if (rvalue || !e1.isLvalue()) return false; return (to.ty == Tsarray && (e1.type.ty == Tvector || e1.type.ty == Tsarray)) || e1.type.mutableOf.unSharedOf().equals(to.mutableOf().unSharedOf()); @@ -3834,7 +3843,7 @@ extern (C++) final class VectorArrayExp : UnaExp override bool isLvalue() { - return e1.isLvalue(); + return !rvalue && e1.isLvalue(); } override void accept(Visitor v) @@ -3891,7 +3900,7 @@ extern (C++) final class SliceExp : UnaExp /* slice expression is rvalue in default, but * conversion to reference of static array is only allowed. */ - return (type && type.toBasetype().ty == Tsarray); + return !rvalue && (type && type.toBasetype().ty == Tsarray); } override Optional!bool toBool() @@ -3956,6 +3965,8 @@ extern (C++) final class ArrayExp : UnaExp override bool isLvalue() { + if (rvalue) + return false; if (type && type.toBasetype().ty == Tvoid) return false; return true; @@ -4005,7 +4016,7 @@ extern (C++) final class CommaExp : BinExp override bool isLvalue() { - return e2.isLvalue(); + return !rvalue && e2.isLvalue(); } override Optional!bool toBool() @@ -4080,7 +4091,7 @@ extern (C++) final class DelegatePtrExp : UnaExp override bool isLvalue() { - return e1.isLvalue(); + return !rvalue && e1.isLvalue(); } override void accept(Visitor v) @@ -4103,7 +4114,7 @@ extern (C++) final class DelegateFuncptrExp : UnaExp override bool isLvalue() { - return e1.isLvalue(); + return !rvalue && e1.isLvalue(); } override void accept(Visitor v) @@ -4143,6 +4154,8 @@ extern (C++) final class IndexExp : BinExp override bool isLvalue() { + if (rvalue) + return false; auto t1b = e1.type.toBasetype(); if (t1b.isTypeAArray() || t1b.isTypeSArray() || (e1.isIndexExp() && t1b != t1b.isTypeDArray())) @@ -4251,7 +4264,7 @@ extern (C++) class AssignExp : BinExp { return false; } - return true; + return !rvalue; } override void accept(Visitor v) @@ -4982,7 +4995,7 @@ extern (C++) final class CondExp : BinExp override bool isLvalue() { - return e1.isLvalue() && e2.isLvalue(); + return !rvalue && e1.isLvalue() && e2.isLvalue(); } override void accept(Visitor v) diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index c353a19..d62aea8 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -78,6 +78,7 @@ public: 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 size_t size() const; static void _init(); @@ -138,7 +139,7 @@ public: TypeidExp* isTypeidExp(); TraitsExp* isTraitsExp(); HaltExp* isHaltExp(); - IsExp* isExp(); + IsExp* isIsExp(); MixinExp* isMixinExp(); ImportExp* isImportExp(); AssertExp* isAssertExp(); diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index e1baa48..413d31a 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -816,21 +816,58 @@ extern(D) bool arrayExpressionSemantic( * Params: * sc = the scope where the expression is encountered * e = the expression the needs to be moved or copied (source) - * t = if the struct defines a copy constructor, the type of the destination - * + * t = if the struct defines a copy constructor, the type of the destination (can be NULL) + * nrvo = true if the generated copy can be treated as NRVO + * move = true to allow a move constructor to be used, false to prevent infinite recursion * Returns: * The expression that copy constructs or moves the value. */ -extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null) +extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t, bool nrvo, bool move = false) { + //printf("doCopyOrMove() %s\n", toChars(e)); + StructDeclaration sd; + if (t) + { + if (auto ts = t.isTypeStruct()) + sd = ts.sym; + } + if (auto ce = e.isCondExp()) { - ce.e1 = doCopyOrMove(sc, ce.e1); - ce.e2 = doCopyOrMove(sc, ce.e2); + ce.e1 = doCopyOrMove(sc, ce.e1, null, nrvo); + ce.e2 = doCopyOrMove(sc, ce.e2, null, nrvo); + } + else if (e.isLvalue()) + { + e = callCpCtor(sc, e, t, nrvo); + } + else if (move && sd && sd.hasMoveCtor && !e.isCallExp() && !e.isStructLiteralExp()) + { + // #move + /* Rewrite as: + * S __copyrvalue; + * __copyrvalue.moveCtor(e); + * __copyrvalue; + */ + VarDeclaration vd = new VarDeclaration(e.loc, e.type, Identifier.generateId("__copyrvalue"), null); + if (nrvo) + vd.adFlags |= Declaration.nrvo; + vd.storage_class |= STC.nodtor; + vd.dsymbolSemantic(sc); + Expression de = new DeclarationExp(e.loc, vd); + Expression ve = new VarExp(e.loc, vd); + + Expression er; + er = new DotIdExp(e.loc, ve, Id.ctor); // ve.ctor + er = new CallExp(e.loc, er, e); // ve.ctor(e) + er = new CommaExp(e.loc, er, new VarExp(e.loc, vd)); // ve.ctor(e),vd + er = Expression.combine(de, er); // de,ve.ctor(e),vd + + e = er.expressionSemantic(sc); } else { - e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e); + e = valueNoDtor(e); } return e; } @@ -839,13 +876,15 @@ extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null) * If e is an instance of a struct, and that struct has a copy constructor, * rewrite e as: * (tmp = e),tmp - * Input: + * Params: * sc = just used to specify the scope of created temporary variable * destinationType = the type of the object on which the copy constructor is called; * may be null if the struct defines a postblit + * nrvo = true if the generated copy can be treated as NRVO */ -private Expression callCpCtor(Scope* sc, Expression e, Type destinationType) +private Expression callCpCtor(Scope* sc, Expression e, Type destinationType, bool nrvo) { + //printf("callCpCtor(e: %s et: %s destinationType: %s\n", toChars(e), toChars(e.type), toChars(destinationType)); auto ts = e.type.baseElemOf().isTypeStruct(); if (!ts) @@ -860,7 +899,9 @@ private Expression callCpCtor(Scope* sc, Expression e, Type destinationType) * This is not the most efficient, ideally tmp would be constructed * directly onto the stack. */ - auto tmp = copyToTemp(STC.rvalue, "__copytmp", e); + VarDeclaration tmp = copyToTemp(STC.rvalue, "__copytmp", e); + if (nrvo) + tmp.adFlags |= Declaration.nrvo; if (sd.hasCopyCtor && destinationType) { // https://issues.dlang.org/show_bug.cgi?id=22619 @@ -888,6 +929,7 @@ private Expression callCpCtor(Scope* sc, Expression e, Type destinationType) */ Expression valueNoDtor(Expression e) { + //printf("valueNoDtor() %s\n", toChars(e)); auto ex = lastComma(e); if (auto ce = ex.isCallExp()) @@ -2706,7 +2748,7 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps) continue; } - e = doCopyOrMove(sc, e); + e = doCopyOrMove(sc, e, null, false); if (!foundType && t0 && !t0.equals(e.type)) { @@ -2952,7 +2994,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, Type* prettype, Expression* peprefix) { Expressions* arguments = argumentList.arguments; - //printf("functionParameters() %s\n", fd ? fd.toChars() : ""); + //printf("functionParameters() fd: %s tf: %s\n", fd ? fd.ident.toChars() : "", toChars(tf)); assert(arguments); assert(fd || tf.next); const size_t nparams = tf.parameterList.length; @@ -3677,7 +3719,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, */ Type tv = arg.type.baseElemOf(); if (!isRef && tv.ty == Tstruct) - arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null); + arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null, false); } (*arguments)[i] = arg; @@ -3886,11 +3928,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars()); } - if (exp.type) // This is used as the dummy expression - { - result = exp; - return; - } + + scope (exit) result.rvalue = exp.rvalue; Dsymbol scopesym; Dsymbol s = sc.search(exp.loc, exp.ident, scopesym); @@ -4109,11 +4148,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("ThisExp::semantic()\n"); } - if (e.type) - { - result = e; - return; - } FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable AggregateDeclaration ad; @@ -4174,11 +4208,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("SuperExp::semantic('%s')\n", e.toChars()); } - if (e.type) - { - result = e; - return; - } FuncDeclaration fd = hasThis(sc); ClassDeclaration cd; @@ -4255,11 +4284,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("NullExp::semantic('%s')\n", e.toChars()); } // NULL is the same as (void *)0 - if (e.type) - { - result = e; - return; - } e.type = Type.tnull; result = e; } @@ -4348,11 +4372,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("StringExp::semantic() %s\n", e.toChars()); } - if (e.type) - { - result = e; - return; - } OutBuffer buffer; size_t newlen = 0; @@ -4461,11 +4480,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("+TupleExp::semantic(%s)\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } if (exp.e0) exp.e0 = exp.e0.expressionSemantic(sc); @@ -4503,11 +4517,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("ArrayLiteralExp::semantic('%s')\n", e.toChars()); } - if (e.type) - { - result = e; - return; - } /* Perhaps an empty array literal [ ] should be rewritten as null? */ @@ -4550,11 +4559,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars()); } - if (e.type) - { - result = e; - return; - } // Run semantic() on each element bool err_keys = arrayExpressionSemantic(e.keys.peekSlice(), sc); @@ -4593,11 +4597,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("StructLiteralExp::semantic('%s')\n", e.toChars()); } - if (e.type) - { - result = e; - return; - } e.sd.size(e.loc); if (e.sd.sizeok != Sizeok.done) @@ -4702,11 +4701,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } ScopeDsymbol sds2 = exp.sds; TemplateInstance ti = sds2.isTemplateInstance(); @@ -4895,11 +4889,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("\tthisexp = %s\n", exp.thisexp.toChars()); printf("\tnewtype: %s\n", exp.newtype.toChars()); } - if (exp.type) // if semantic() already run - { - result = exp; - return; - } //for error messages if the argument in [] is not convertible to size_t const originalNewtype = exp.newtype; @@ -5677,7 +5666,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor symtab = sds.symtab; } assert(symtab); - Identifier id = Identifier.generateIdWithLoc(s, exp.loc); + Identifier id = Identifier.generateIdWithLoc(s, exp.loc, cast(string) toDString(sc.parent.toPrettyChars())); exp.fd.ident = id; if (exp.td) exp.td.ident = id; @@ -5693,11 +5682,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf(" treq = %s\n", exp.fd.treq.toChars()); } - if (exp.type) - { - result = exp; - return; - } Expression e = exp; @@ -5891,11 +5875,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("CallExp::semantic() %s\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; // semantic() already run - } Objects* tiargs = null; // initial list of template arguments Expression ethis = null; @@ -6718,7 +6697,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor errorSupplemental(exp.loc, "%s", failMessage); } - if (tf.callMatch(null, exp.argumentList, 0, &errorHelper, sc) == MATCH.nomatch) + if (callMatch(exp.f, tf, null, exp.argumentList, 0, &errorHelper, sc) == MATCH.nomatch) return setError(); // Purity and safety check should run after testing arguments matching @@ -6801,7 +6780,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.f = null; } - if (tf.callMatch(null, exp.argumentList, 0, &errorHelper2, sc) == MATCH.nomatch) + if (callMatch(exp.f, tf, null, exp.argumentList, 0, &errorHelper2, sc) == MATCH.nomatch) exp.f = null; } if (!exp.f || exp.f.errors) @@ -6954,11 +6933,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(DeclarationExp e) { - if (e.type) - { - result = e; - return; - } static if (LOGSEMANTIC) { printf("DeclarationExp::semantic() %s\n", e.toChars()); @@ -7575,11 +7549,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(BinAssignExp exp) { - if (exp.type) - { - result = exp; - return; - } Expression e = exp.op_overload(sc); if (e) @@ -8157,6 +8126,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { import dmd.statementsem; + te.type = Type.tnoreturn; if (throwSemantic(te.loc, te.e1, sc)) result = te; else @@ -8168,7 +8138,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor static if (LOGSEMANTIC) { printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars()); - //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op)); + printAST(exp); } if (sc.inCfile) @@ -8251,11 +8221,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(DotTemplateExp e) { - if (e.type) - { - result = e; - return; - } if (Expression ex = unaSemantic(e, sc)) { result = ex; @@ -8272,11 +8237,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("DotVarExp::semantic('%s')\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } exp.var = exp.var.toAlias().isDeclaration(); @@ -8444,11 +8404,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } // Indicate we need to resolve by UFCS. Expression e = exp.dotTemplateSemanticProp(sc, DotExpFlag.gag); if (!e) @@ -8464,11 +8419,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("DelegateExp::semantic('%s')\n", e.toChars()); } - if (e.type) - { - result = e; - return; - } e.e1 = e.e1.expressionSemantic(sc); @@ -8530,11 +8480,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("DotTypeExp::semantic('%s')\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } if (auto e = unaSemantic(exp, sc)) { @@ -8552,11 +8497,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("AddrExp::semantic('%s')\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } if (Expression ex = unaSemantic(exp, sc)) { @@ -8853,11 +8793,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("PtrExp::semantic('%s')\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } Expression e = exp.op_overload(sc); if (e) @@ -8916,11 +8851,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("NegExp::semantic('%s')\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } Expression e = exp.op_overload(sc); if (e) @@ -8962,7 +8892,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("UAddExp::semantic('%s')\n", exp.toChars()); } - assert(!exp.type); Expression e = exp.op_overload(sc); if (e) @@ -8989,11 +8918,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(ComExp exp) { - if (exp.type) - { - result = exp; - return; - } Expression e = exp.op_overload(sc); if (e) @@ -9031,11 +8955,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(NotExp e) { - if (e.type) - { - result = e; - return; - } e.setNoderefOperand(); @@ -9140,11 +9059,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("CastExp::semantic('%s')\n", exp.toChars()); } //static int x; assert(++x < 10); - if (exp.type) - { - result = exp; - return; - } if ((sc && sc.inCfile) && exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) && @@ -9429,11 +9343,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("VectorExp::semantic('%s')\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } exp.e1 = exp.e1.expressionSemantic(sc); exp.type = exp.to.typeSemantic(exp.loc, sc); @@ -9502,11 +9411,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("SliceExp::semantic('%s')\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } // operator overloading should be handled in ArrayExp already. if (Expression ex = unaSemantic(exp, sc)) @@ -9789,11 +9693,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("ArrayLengthExp::semantic('%s')\n", e.toChars()); } - if (e.type) - { - result = e; - return; - } if (Expression ex = unaSemantic(e, sc)) { @@ -9812,7 +9711,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("ArrayExp::semantic('%s')\n", exp.toChars()); } - assert(!exp.type); if (sc.inCfile) { @@ -9886,11 +9784,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(CommaExp e) { //printf("Semantic.CommaExp() %s\n", e.toChars()); - if (e.type) - { - result = e; - return; - } // Allow `((a,b),(x,y))` if (e.allowCommaExp) @@ -9936,11 +9829,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("IntervalExp::semantic('%s')\n", e.toChars()); } - if (e.type) - { - result = e; - return; - } Expression le = e.lwr; le = le.expressionSemantic(sc); @@ -10015,11 +9903,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("IndexExp::semantic('%s')\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } // operator overloading should be handled in ArrayExp already. if (!exp.e1.type) @@ -10242,11 +10125,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("PostExp::semantic('%s')\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } if (sc.inCfile) { @@ -10404,9 +10282,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { static if (LOGSEMANTIC) { - if (exp.op == EXP.blit) printf("BlitExp.toElem('%s')\n", exp.toChars()); - if (exp.op == EXP.assign) printf("AssignExp.toElem('%s')\n", exp.toChars()); - if (exp.op == EXP.construct) printf("ConstructExp.toElem('%s')\n", exp.toChars()); + if (exp.op == EXP.blit) printf("BlitExp.semantic('%s')\n", exp.toChars()); + if (exp.op == EXP.assign) printf("AssignExp.semantic('%s')\n", exp.toChars()); + if (exp.op == EXP.construct) printf("ConstructExp.semantic('%s')\n", exp.toChars()); } void setResult(Expression e, int line = __LINE__) @@ -10415,11 +10293,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = e; } - if (exp.type) - { - return setResult(exp); - } - Expression e1old = exp.e1; if (auto e2comma = exp.e2.isCommaExp()) @@ -10876,6 +10749,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* We have a copy constructor for this */ + //printf("exp: %s\n", toChars(exp)); + //printf("e2x: %s\n", toChars(e2x)); if (e2x.isLvalue()) { if (sd.hasCopyCtor) @@ -10922,6 +10797,38 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } } + else if (sd.hasMoveCtor && !e2x.isCallExp() && !e2x.isStructLiteralExp()) + { + // #move + /* The !e2x.isCallExp() is because it is already an rvalue + and the move constructor is unnecessary: + struct S { + alias TT this; + long TT(); + this(T)(int x) {} + this(S); + this(ref S); + ~this(); + } + S fun(ref S arg); + void test() { S st; fun(st); } + */ + /* Rewrite as: + * e1 = init, e1.moveCtor(e2); + */ + Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1)); + einit.type = e1x.type; + + Expression e; + e = new DotIdExp(exp.loc, e1x, Id.ctor); + e = new CallExp(exp.loc, e, e2x); + e = new CommaExp(exp.loc, einit, e); + + //printf("e: %s\n", e.toChars()); + + result = e.expressionSemantic(sc); + return; + } else { /* The struct value returned from the function is transferred @@ -11815,11 +11722,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(PowAssignExp exp) { - if (exp.type) - { - result = exp; - return; - } Expression e = exp.op_overload(sc); if (e) @@ -11899,11 +11801,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(CatAssignExp exp) { - if (exp.type) - { - result = exp; - return; - } //printf("CatAssignExp::semantic() %s\n", exp.toChars()); Expression e = exp.op_overload(sc); @@ -11985,7 +11882,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor ce.trusted = true; exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, ecast); - exp.e2 = doCopyOrMove(sc, exp.e2); + exp.e2 = doCopyOrMove(sc, exp.e2, null, false); } else if (tb1.ty == Tarray && (tb1next.ty == Tchar || tb1next.ty == Twchar) && @@ -12195,11 +12092,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("AddExp::semantic('%s')\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } if (Expression ex = binSemanticProp(exp, sc)) { @@ -12302,11 +12194,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("MinExp::semantic('%s')\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } if (Expression ex = binSemanticProp(exp, sc)) { @@ -12554,11 +12441,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { // https://dlang.org/spec/expression.html#cat_expressions //printf("CatExp.semantic() %s\n", toChars()); - if (exp.type) - { - result = exp; - return; - } if (Expression ex = binSemanticProp(exp, sc)) { @@ -12610,7 +12492,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { if (exp.e1.op == EXP.arrayLiteral) { - exp.e2 = doCopyOrMove(sc, exp.e2); + exp.e2 = doCopyOrMove(sc, exp.e2, null, false); // https://issues.dlang.org/show_bug.cgi?id=14686 // Postblit call appears in AST, and this is // finally translated to an ArrayLiteralExp in below optimize(). @@ -12649,7 +12531,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { if (exp.e2.op == EXP.arrayLiteral) { - exp.e1 = doCopyOrMove(sc, exp.e1); + exp.e1 = doCopyOrMove(sc, exp.e1, null, false); } else if (exp.e2.op == EXP.string_) { @@ -12741,11 +12623,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("MulExp::semantic() %s\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } if (Expression ex = binSemanticProp(exp, sc)) { @@ -12841,11 +12718,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(DivExp exp) { - if (exp.type) - { - result = exp; - return; - } if (Expression ex = binSemanticProp(exp, sc)) { @@ -12942,11 +12814,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(ModExp exp) { - if (exp.type) - { - result = exp; - return; - } if (Expression ex = binSemanticProp(exp, sc)) { @@ -13000,11 +12867,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(PowExp exp) { - if (exp.type) - { - result = exp; - return; - } //printf("PowExp::semantic() %s\n", toChars()); if (Expression ex = binSemanticProp(exp, sc)) @@ -13080,11 +12942,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor private void visitShift(BinExp exp) { - if (exp.type) - { - result = exp; - return; - } if (Expression ex = binSemanticProp(exp, sc)) { @@ -13133,11 +12990,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor private void visitBinaryBitOp(BinExp exp) { - if (exp.type) - { - result = exp; - return; - } if (Expression ex = binSemanticProp(exp, sc)) { @@ -13206,11 +13058,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("LogicalExp::semantic() %s\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } exp.setNoderefOperands(); @@ -13292,11 +13139,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("CmpExp::semantic('%s')\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } exp.setNoderefOperands(); @@ -13461,11 +13303,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(InExp exp) { - if (exp.type) - { - result = exp; - return; - } if (Expression ex = binSemanticProp(exp, sc)) { @@ -13531,11 +13368,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(EqualExp exp) { //printf("EqualExp::semantic('%s')\n", exp.toChars()); - if (exp.type) - { - result = exp; - return; - } exp.setNoderefOperands(); @@ -13754,11 +13586,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor override void visit(IdentityExp exp) { - if (exp.type) - { - result = exp; - return; - } exp.setNoderefOperands(); @@ -13822,11 +13649,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("CondExp::semantic('%s')\n", exp.toChars()); } - if (exp.type) - { - result = exp; - return; - } if (auto die = exp.econd.isDotIdExp()) die.noderef = true; @@ -14188,9 +14010,25 @@ Expression binSemanticProp(BinExp e, Scope* sc) return null; } +/// Returns: whether expressionSemantic() has been run on expression `e` +private bool expressionSemanticDone(Expression e) +{ + // Usually, Expression.type gets set by expressionSemantic and is `null` beforehand + // There are some exceptions however: + return e.type !is null && !( + e.isRealExp() // type sometimes gets set already before semantic + || e.isTypeExp() // stores its type in the Expression.type field + || e.isCompoundLiteralExp() // stores its `(type) {}` in type field, gets rewritten to struct literal + || e.isVarExp() // type sometimes gets set already before semantic + ); +} + // entrypoint for semantic ExpressionSemanticVisitor Expression expressionSemantic(Expression e, Scope* sc) { + if (e.expressionSemanticDone) + return e; + scope v = new ExpressionSemanticVisitor(sc); e.accept(v); return v.result; @@ -14198,7 +14036,7 @@ Expression expressionSemantic(Expression e, Scope* sc) private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc) { - //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars()); + //printf("dotIdSemanticPropX() %s\n", toChars(exp)); if (Expression ex = unaSemantic(exp, sc)) return ex; @@ -14326,7 +14164,7 @@ private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc) */ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag) { - //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars()); + //printf("dotIdSemanticProp('%s')\n", exp.toChars()); //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; } @@ -14664,7 +14502,7 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag) const flag = cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref | gag * DotExpFlag.gag); - Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag); + Expression e = dotExp(exp.e1.type, sc, exp.e1, exp.ident, flag); if (e) { e = e.expressionSemantic(sc); @@ -15482,6 +15320,7 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc) */ Expression addDtorHook(Expression e, Scope* sc) { + //printf("addDtorHook() %s\n", toChars(e)); Expression visit(Expression exp) { return exp; @@ -16510,7 +16349,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions if (e.op == EXP.error) return false; - (*elements)[i] = doCopyOrMove(sc, e); + (*elements)[i] = doCopyOrMove(sc, e, null, false); } return true; } diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 153befd..9c5a3d0 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -269,6 +269,10 @@ extern (C++) class FuncDeclaration : Declaration */ VarDeclarations outerVars; + // Most recent encountered `main` (`WinMain` or `DllMain`) function. + // Track it to give error messages for multiple entrypoints + __gshared FuncDeclaration lastMain; + /// Sibling nested functions which called this one FuncDeclarations siblingCallers; @@ -1366,11 +1370,13 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration */ extern (C++) final class CtorDeclaration : FuncDeclaration { - bool isCpCtor; - extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false) + bool isCpCtor; // copy constructor + bool isMoveCtor; // move constructor (aka rvalue constructor) + extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Type type, bool isCpCtor = false, bool isMoveCtor = false) { super(loc, endloc, Id.ctor, stc, type); this.isCpCtor = isCpCtor; + this.isMoveCtor = isMoveCtor; //printf("CtorDeclaration(loc = %s) %s %p\n", loc.toChars(), toChars(), this); } diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d index bfa0fac..eba9397 100644 --- a/gcc/d/dmd/funcsem.d +++ b/gcc/d/dmd/funcsem.d @@ -154,6 +154,28 @@ public: } } +/**************************************** + * Only one entry point function is allowed. Print error if more than one. + * Params: + * fd = a "main" function + * Returns: + * true if haven't seen "main" before + */ +extern (C++) bool onlyOneMain(FuncDeclaration fd) +{ + if (auto lastMain = FuncDeclaration.lastMain) + { + const format = (target.os == Target.OS.Windows) + ? "only one entry point `main`, `WinMain` or `DllMain` is allowed" + : "only one entry point `main` is allowed"; + error(fd.loc, format.ptr); + errorSupplemental(lastMain.loc, "previously found `%s` here", lastMain.toFullSignature()); + return false; + } + FuncDeclaration.lastMain = fd; + return true; +} + /********************************** * Main semantic routine for functions. */ @@ -1507,6 +1529,7 @@ enum FuncResolveFlag : ubyte FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags) { + //printf("resolveFuncCall() %s\n", s.toChars()); auto fargs = argumentList.arguments; if (!s) return null; // no match @@ -2066,7 +2089,7 @@ MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* name args.push(e); } - MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1); + MATCH m = callMatch(g, tg, null, ArgumentList(&args, names), 1); if (m > MATCH.nomatch) { /* A variadic parameter list is less specialized than a @@ -2939,6 +2962,7 @@ extern (D) void checkMain(FuncDeclaration fd) */ extern (D) bool checkNRVO(FuncDeclaration fd) { + //printf("checkNRVO*() %s\n", fd.ident.toChars()); if (!fd.isNRVO() || fd.returns is null) return false; diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index 88b27d2..901561f 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -82,6 +82,13 @@ enum CLIIdentifierTable : ubyte All = 4, /// The least restrictive set of all other tables } +/// Specifies the mode for error printing +enum ErrorPrintMode : ubyte +{ + simpleError, // Print errors without squiggles and carets + printErrorContext, // Print errors with context (source line and caret) +} + extern(C++) struct Output { bool doOutput; // Output is enabled @@ -126,10 +133,10 @@ extern(C++) struct Verbose bool complex = true; // identify complex/imaginary type usage bool vin; // identify 'in' parameters bool showGaggedErrors; // print gagged errors anyway - bool printErrorContext; // print errors with the error context (the error line in the source file) bool logo; // print compiler logo bool color; // use ANSI colors in console output bool cov; // generate code coverage data + ErrorPrintMode errorPrintMode; // enum for error printing mode MessageStyle messageStyle = MessageStyle.digitalmars; // style of file/line annotations on messages uint errorLimit = 20; uint errorSupplementLimit = 6; // Limit the number of supplemental messages for each error (0 means unlimited) diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index c5659ea..669f83e 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -94,6 +94,13 @@ enum class CLIIdentifierTable : unsigned char All = 4, /// The least restrictive set of all other tables }; +/// Specifies the mode for error printing +enum class ErrorPrintMode : unsigned char +{ + simpleError, // Print errors without squiggles and carets + printErrorContext, // Print errors with the error line and caret +}; + struct Output { /// Configuration for the compiler generator @@ -138,10 +145,10 @@ struct Verbose d_bool complex = true; // identify complex/imaginary type usage d_bool vin; // identify 'in' parameters d_bool showGaggedErrors; // print gagged errors anyway - d_bool printErrorContext; // print errors with the error context (the error line in the source file) d_bool logo; // print compiler logo d_bool color; // use ANSI colors in console output d_bool cov; // generate code coverage data + ErrorPrintMode errorPrintMode; // enum for error printing mode MessageStyle messageStyle; // style of file/line annotations on messages unsigned errorLimit; unsigned errorSupplementLimit; // Limit the number of supplemental messages for each error (0 means unlimited) @@ -192,7 +199,7 @@ struct Param // https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html // Implementation: https://github.com/dlang/dmd/pull/9817 FeatureState safer; // safer by default (more @safe checks in unattributed code) - // https://github.com/WalterBright/documents/blob/38f0a846726b571f8108f6e63e5e217b91421c86/safer.md + // https://github.com/WalterBright/documents/blob/38f0a846726b571f8108f6e63e5e217b91421c86/safer.md FeatureState noSharedAccess; // read/write access to shared memory objects d_bool previewIn; // `in` means `[ref] scope const`, accepts rvalues diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 86131f2..cfe4262 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -305,10 +305,9 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState h buf.writenl(); } - void visitWhile(WhileStatement s) + void printConditionAssignment(Parameter p, Expression condition) { - buf.writestring("while ("); - if (auto p = s.param) + if (p) { // Print condition assignment StorageClass stc = p.storageClass; @@ -322,7 +321,13 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState h buf.writestring(p.ident.toString()); buf.writestring(" = "); } - s.condition.expressionToBuffer(buf, hgs); + condition.expressionToBuffer(buf, hgs); + } + + void visitWhile(WhileStatement s) + { + buf.writestring("while ("); + printConditionAssignment(s.param, s.condition); buf.writeByte(')'); buf.writenl(); if (s._body) @@ -460,20 +465,7 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState h void visitIf(IfStatement s) { buf.writestring("if ("); - if (Parameter p = s.prm) - { - StorageClass stc = p.storageClass; - if (!p.type && !stc) - stc = STC.auto_; - if (stcToBuffer(buf, stc)) - buf.writeByte(' '); - if (p.type) - typeToBuffer(p.type, p.ident, buf, hgs); - else - buf.writestring(p.ident.toString()); - buf.writestring(" = "); - } - s.condition.expressionToBuffer(buf, hgs); + printConditionAssignment(s.prm, s.condition); buf.writeByte(')'); buf.writenl(); if (s.ifbody.isScopeStatement()) @@ -572,21 +564,7 @@ private void statementToBuffer(Statement s, ref OutBuffer buf, ref HdrGenState h void visitSwitch(SwitchStatement s) { buf.writestring(s.isFinal ? "final switch (" : "switch ("); - if (auto p = s.param) - { - // Print condition assignment - StorageClass stc = p.storageClass; - if (!p.type && !stc) - stc = STC.auto_; - if (stcToBuffer(buf, stc)) - buf.writeByte(' '); - if (p.type) - typeToBuffer(p.type, p.ident, buf, hgs); - else - buf.writestring(p.ident.toString()); - buf.writestring(" = "); - } - s.condition.expressionToBuffer(buf, hgs); + printConditionAssignment(s.param, s.condition); buf.writeByte(')'); buf.writenl(); if (s._body) @@ -1718,7 +1696,10 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) void visitFuncDeclaration(FuncDeclaration f) { //printf("FuncDeclaration::toCBuffer() '%s'\n", f.toChars()); - if (stcToBuffer(buf, f.storage_class)) + + // https://issues.dlang.org/show_bug.cgi?id=24891 + // return/scope storage classes are printed as part of function type + if (stcToBuffer(buf, f.storage_class & ~(STC.scope_ | STC.return_ | STC.returnScope))) buf.writeByte(' '); typeToBuffer(f.type, f.ident, buf, hgs); auto tf = f.type.isTypeFunction(); @@ -2888,6 +2869,13 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt buf.writestring(e.value.toChars()); } + if (e.rvalue) + buf.writestring("__rvalue("); + + scope (exit) + if (e.rvalue) + buf.writeByte(')'); + switch (e.op) { default: @@ -2929,7 +2917,7 @@ private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt case EXP.typeid_: return visitTypeid(e.isTypeidExp()); case EXP.traits: return visitTraits(e.isTraitsExp()); case EXP.halt: return visitHalt(e.isHaltExp()); - case EXP.is_: return visitIs(e.isExp()); + case EXP.is_: return visitIs(e.isIsExp()); case EXP.comma: return visitComma(e.isCommaExp()); case EXP.mixin_: return visitMixin(e.isMixinExp()); case EXP.import_: return visitImport(e.isImportExp()); diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index aae07bc..ee4214a 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -519,6 +519,7 @@ immutable Msgtable[] msgtable = { "getLocation" }, { "hasPostblit" }, { "hasCopyConstructor" }, + { "hasMoveConstructor" }, { "isCopyable" }, { "toType" }, { "parameters" }, diff --git a/gcc/d/dmd/identifier.d b/gcc/d/dmd/identifier.d index 6fd0d3a..74be1be 100644 --- a/gcc/d/dmd/identifier.d +++ b/gcc/d/dmd/identifier.d @@ -211,11 +211,14 @@ nothrow: * Params: * prefix = first part of the identifier name. * loc = source location to use in the identifier name. + * parent = (optional) extra part to be used in uniqueness check, + * if (prefix1, loc1) == (prefix2, loc2), but + * parent1 != parent2, no new name will be generated. * Returns: * Identifier (inside Identifier.idPool) with deterministic name based * on the source location. */ - extern (D) static Identifier generateIdWithLoc(string prefix, const ref Loc loc) + extern (D) static Identifier generateIdWithLoc(string prefix, const ref Loc loc, string parent = "") { // generate `<prefix>_L<line>_C<col>` OutBuffer idBuf; @@ -234,14 +237,20 @@ nothrow: * https://issues.dlang.org/show_bug.cgi?id=18880 * https://issues.dlang.org/show_bug.cgi?id=18868 * https://issues.dlang.org/show_bug.cgi?id=19058 + * + * It is a bit trickier for lambdas/dgliterals: we want them to be unique per + * module/mixin + function/template instantiation context. So we use extra parent + * argument for that when dealing with lambdas. We could have added it to prefix + * directly, but that would unnecessary lengthen symbols names. See issue: + * https://issues.dlang.org/show_bug.cgi?id=23722 */ - static struct Key { Loc loc; string prefix; } + static struct Key { Loc loc; string prefix; string parent; } __gshared uint[Key] counters; static if (__traits(compiles, counters.update(Key.init, () => 0u, (ref uint a) => 0u))) { // 2.082+ - counters.update(Key(loc, prefix), + counters.update(Key(loc, prefix, parent), () => 1u, // insertion (ref uint counter) // update { @@ -253,7 +262,7 @@ nothrow: } else { - const key = Key(loc, prefix); + const key = Key(loc, prefix, parent); if (auto pCounter = key in counters) { idBuf.writestring("_"); diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 505a3e1..0c13bc7 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -1630,7 +1630,7 @@ Expressions* resolveStructLiteralNamedArgs(StructDeclaration sd, Type t, Scope* continue; } - elems[fieldi] = doCopyOrMove(sc, ex); + elems[fieldi] = doCopyOrMove(sc, ex, null, false); ++fieldi; } if (errors) diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d index 021387d..174a2d9 100644 --- a/gcc/d/dmd/json.d +++ b/gcc/d/dmd/json.d @@ -42,7 +42,8 @@ import dmd.target; import dmd.visitor; version(Windows) { - extern (C) char* getcwd(char* buffer, size_t maxlen); + extern (C) char* _getcwd(char* buffer, size_t maxlen); + alias getcwd = _getcwd; } else { import core.sys.posix.unistd : getcwd; } diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 6d57467..4a4254f 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -1609,7 +1609,7 @@ extern (C++) abstract class TypeNext : Type /******************************* * For TypeFunction, nextOf() can return NULL if the function return - * type is meant to be inferred, and semantic() hasn't yet ben run + * type is meant to be inferred, and semantic() hasn't yet been run * on the function. After semantic(), it must no longer be NULL. */ override final Type nextOf() @safe @@ -3543,17 +3543,19 @@ extern (C++) final class TypeTuple : Type extern (D) this(Expressions* exps) { super(Ttuple); - auto arguments = new Parameters(exps ? exps.length : 0); - if (exps) + if (!exps) { - for (size_t i = 0; i < exps.length; i++) - { - Expression e = (*exps)[i]; - if (e.type.ty == Ttuple) - error(e.loc, "cannot form sequence of sequences"); - auto arg = new Parameter(e.loc, STC.undefined_, e.type, null, null, null); - (*arguments)[i] = arg; - } + this.arguments = new Parameters(0); + return; + } + auto arguments = new Parameters(exps.length); + + for (size_t i = 0; i < exps.length; i++) + { + Expression e = (*exps)[i]; + assert(e.type.ty != Ttuple); + auto arg = new Parameter(e.loc, STC.undefined_, e.type, null, null, null); + (*arguments)[i] = arg; } this.arguments = arguments; //printf("TypeTuple() %p, %s\n", this, toChars()); diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index eced43e..e69d2ba 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -469,7 +469,7 @@ enum RET enum class TRUST : unsigned char { default_ = 0, - system = 1, // @system (same as TRUSTdefault) + system = 1, // @system (same as TRUST.default_ unless feature "safer" is enabled) trusted = 2, // @trusted safe = 3 // @safe }; diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d index 5cd928c..c5ee77a 100644 --- a/gcc/d/dmd/objc.d +++ b/gcc/d/dmd/objc.d @@ -93,39 +93,66 @@ struct ObjcSelector return sel; } + static const(char)[] toPascalCase(const(char)[] id) { + OutBuffer buf; + char firstChar = id[0]; + if (firstChar >= 'a' && firstChar <= 'z') + firstChar = cast(char)(firstChar - 'a' + 'A'); + + buf.writeByte(firstChar); + buf.writestring(id[1..$]); + return cast(const(char)[])buf.extractSlice(false); + } + extern (C++) static ObjcSelector* create(FuncDeclaration fdecl) { OutBuffer buf; auto ftype = cast(TypeFunction)fdecl.type; const id = fdecl.ident.toString(); const nparams = ftype.parameterList.length; + // Special case: property setter if (ftype.isProperty && nparams == 1) { - // rewrite "identifier" as "setIdentifier" - char firstChar = id[0]; - if (firstChar >= 'a' && firstChar <= 'z') - firstChar = cast(char)(firstChar - 'a' + 'A'); - buf.writestring("set"); - buf.writeByte(firstChar); - buf.write(id[1 .. id.length - 1]); + + // Special case: "isXYZ:" + if (id.length >= 2 && id[0..2] == "is") + { + buf.writestring("set"); + buf.write(toPascalCase(id[2..$])); + } + else + { + buf.writestring("set"); + buf.write(toPascalCase(id)); + } buf.writeByte(':'); goto Lcomplete; } + // write identifier in selector buf.write(id[]); - // add mangled type and colon for each parameter - if (nparams) + + // To make it easier to match the selectors of objects nicely, + // the implementation has been replaced so that the parameter name followed by a colon + // is used instead. + // eg. void myFunction(int a, int b, int c) would be mangled to a selector as `myFunction:b:c: + if (nparams > 1) { - buf.writeByte('_'); - foreach (i, fparam; ftype.parameterList) + buf.writeByte(':'); + foreach(i; 1..nparams) { - mangleToBuffer(fparam.type, buf); + buf.write(ftype.parameterList[i].ident.toString()); buf.writeByte(':'); } } + else if (nparams == 1) + { + buf.writeByte(':'); + } Lcomplete: buf.writeByte('\0'); + // the slice is not expected to include a terminating 0 return lookup(cast(const(char)*)buf[].ptr, buf.length - 1, nparams); } @@ -565,6 +592,16 @@ extern(C++) private final class Supported : Objc return 0; }); + + // Avoid attempting to generate selectors for template instances. + if (fd.parent && fd.parent.isTemplateInstance()) + return; + + // No selector declared, generate one. + if (fd._linkage == LINK.objc && !fd.objc.selector) + { + fd.objc.selector = ObjcSelector.create(fd); + } } override void validateSelector(FuncDeclaration fd) diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 3e145be..fd42838 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -932,22 +932,14 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { const attrLoc = token.loc; - nextToken(); - - AST.Expression e = null; // default - if (token.value == TOK.leftParenthesis) - { - nextToken(); - e = parseAssignExp(); - check(TOK.rightParenthesis); - } + AST.Expression e = parseAlign(); if (pAttrs.setAlignment) { if (e) error("redundant alignment attribute `align(%s)`", e.toChars()); else - error("redundant alignment attribute `align`"); + error("redundant alignment attribute `align(default)`"); } pAttrs.setAlignment = true; @@ -4371,14 +4363,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } case TOK.align_: { - nextToken(); setAlignment = true; - if (token.value == TOK.leftParenthesis) - { - nextToken(); - ealign = parseExpression(); - check(TOK.rightParenthesis); - } + ealign = parseAlign(); continue; } default: @@ -4388,6 +4374,27 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } } + /** + * Parse `align` or `align(n)` + * Returns: + * expression `n` if it is present, or `null` otherwise. + */ + private AST.Expression parseAlign() + { + assert(token.value == TOK.align_); + AST.Expression e = null; + nextToken(); + if (token.value == TOK.leftParenthesis) + { + nextToken(); + if (token.value == TOK.default_) + nextToken(); + else + e = parseAssignExp(); + check(TOK.rightParenthesis); + } + return e; + } /********************************** * Parse Declarations. * These can be: @@ -5252,7 +5259,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer error("missing `do { ... }` after `in` or `out`"); const returnloc = token.loc; nextToken(); - f.fbody = new AST.ReturnStatement(returnloc, parseExpression()); + if (f.isCtorDeclaration) + f.fbody = new AST.ExpStatement(returnloc, parseExpression()); + else + f.fbody = new AST.ReturnStatement(returnloc, parseExpression()); f.endloc = token.loc; check(TOK.semicolon); break; @@ -5877,6 +5887,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.moduleString: case TOK.functionString: case TOK.prettyFunction: + case TOK.rvalue: Lexp: { AST.Expression exp = parseExpression(); @@ -8423,6 +8434,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer e = new AST.TypeidExp(loc, o); break; } + case TOK.rvalue: + { + nextToken(); + check(TOK.leftParenthesis, "`__rvalue`"); + e = parseAssignExp(); + e.rvalue = true; + check(TOK.rightParenthesis); + break; + } case TOK.traits: { /* __traits(identifier, args...) diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d index 02dc653..26d2770 100644 --- a/gcc/d/dmd/printast.d +++ b/gcc/d/dmd/printast.d @@ -51,6 +51,12 @@ extern (C++) final class PrintASTVisitor : Visitor printf("%.*s %s\n", cast(int)s.length, s.ptr, e.type ? e.type.toChars() : ""); } + override void visit(IdentifierExp e) + { + printIndent(indent); + printf("Identifier `%s` %s\n", e.ident.toChars(), e.type ? e.type.toChars() : ""); + } + override void visit(IntegerExp e) { printIndent(indent); diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d index a2f074d..cf00d8a 100644 --- a/gcc/d/dmd/root/filename.d +++ b/gcc/d/dmd/root/filename.d @@ -42,7 +42,8 @@ version (Windows) extern (Windows) DWORD GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR*) nothrow @nogc; extern (Windows) void SetLastError(DWORD) nothrow @nogc; - extern (C) char* getcwd(char* buffer, size_t maxlen) nothrow; + extern (C) char* _getcwd(char* buffer, size_t maxlen) nothrow; + alias getcwd = _getcwd; } version (CRuntime_Glibc) diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h index 7983a7a..ac11266 100644 --- a/gcc/d/dmd/scope.h +++ b/gcc/d/dmd/scope.h @@ -143,6 +143,7 @@ struct Scope final AliasDeclaration *aliasAsg; // if set, then aliasAsg is being assigned a new value, // do not set wasRead for it + StructDeclaration *argStruct; // elimiate recursion when looking for rvalue construction Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol *&pscopesym, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all); }; diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 4f10982..1ea1ca1 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -940,7 +940,7 @@ private extern(C++) final class Semantic3Visitor : Visitor * If NRVO is not possible, all returned lvalues should call their postblits. */ if (!funcdecl.isNRVO()) - exp = doCopyOrMove(sc2, exp, f.next); + exp = doCopyOrMove(sc2, exp, f.next, true, true); if (tret.hasPointers()) checkReturnEscape(*sc2, exp, false); diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 8138bd2..d259abf 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -2460,7 +2460,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) /* https://dlang.org/spec/statement.html#return-statement */ - //printf("ReturnStatement.dsymbolSemantic() %p, %s\n", rs, rs.toChars()); + //printf("ReturnStatement.dsymbolSemantic() %s\n", toChars(rs)); FuncDeclaration fd = sc.parent.isFuncDeclaration(); if (fd.fes) diff --git a/gcc/d/dmd/templatesem.d b/gcc/d/dmd/templatesem.d index 0e9c433..8be9730 100644 --- a/gcc/d/dmd/templatesem.d +++ b/gcc/d/dmd/templatesem.d @@ -623,7 +623,7 @@ MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td, TemplateDeclaration enum LOG_LEASTAS = 0; static if (LOG_LEASTAS) { - printf("%s.leastAsSpecialized(%s)\n", toChars(), td2.toChars()); + printf("%s.leastAsSpecialized(%s)\n", td.toChars(), td2.toChars()); } /* This works by taking the template parameters to this template @@ -1890,23 +1890,22 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, { version (none) { - printf("functionResolve() dstart = %s\n", dstart.toChars()); - printf(" tiargs:\n"); - if (tiargs) + printf("functionResolve() dstart: %s (", dstart.toChars()); + for (size_t i = 0; i < (tiargs ? (*tiargs).length : 0); i++) { - for (size_t i = 0; i < tiargs.length; i++) - { - RootObject arg = (*tiargs)[i]; - printf("\t%s\n", arg.toChars()); - } + if (i) printf(", "); + RootObject arg = (*tiargs)[i]; + printf("%s", arg.toChars()); } - printf(" fargs:\n"); - for (size_t i = 0; i < (fargs ? fargs.length : 0); i++) + printf(")("); + for (size_t i = 0; i < (argumentList.arguments ? (*argumentList.arguments).length : 0); i++) { - Expression arg = (*fargs)[i]; - printf("\t%s %s\n", arg.type.toChars(), arg.toChars()); + if (i) printf(", "); + Expression arg = (*argumentList.arguments)[i]; + printf("%s %s", arg.type.toChars(), arg.toChars()); //printf("\tty = %d\n", arg.type.ty); } + printf(")\n"); //printf("stc = %llx\n", dstart._scope.stc); //printf("match:t/f = %d/%d\n", ta_last, m.last); } @@ -1993,7 +1992,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, tf.mod = tthis_fd.mod; } const(char)* failMessage; - MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, errorHelper, sc); + MATCH mfa = callMatch(fd, tf, tthis_fd, argumentList, 0, errorHelper, sc); //printf("test1: mfa = %d\n", mfa); if (failMessage) errorHelper(failMessage); @@ -2198,7 +2197,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null; auto tf = fd.type.isTypeFunction(); - MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, null, sc); + MATCH mfa = callMatch(fd, tf, tthis_fd, argumentList, 0, null, sc); if (mfa < m.last) return 0; @@ -2300,8 +2299,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, // Disambiguate by tf.callMatch auto tf1 = fd.type.isTypeFunction(); auto tf2 = m.lastf.type.isTypeFunction(); - MATCH c1 = tf1.callMatch(tthis_fd, argumentList, 0, null, sc); - MATCH c2 = tf2.callMatch(tthis_best, argumentList, 0, null, sc); + MATCH c1 = callMatch(fd, tf1, tthis_fd, argumentList, 0, null, sc); + MATCH c2 = callMatch(m.lastf, tf2, tthis_best, argumentList, 0, null, sc); //printf("2: c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; @@ -2404,7 +2403,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, if (m.lastf.type.ty == Terror) goto Lerror; auto tf = m.lastf.type.isTypeFunction(); - if (!tf.callMatch(tthis_best, argumentList, 0, null, sc)) + if (callMatch(m.lastf, tf, tthis_best, argumentList, 0, null, sc) == MATCH.nomatch) goto Lnomatch; /* As https://issues.dlang.org/show_bug.cgi?id=3682 shows, diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index da4a3ee..b499c00 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -27,6 +27,9 @@ enum TOK : ubyte { reserved, + // if this list changes, update + // tokens.h, ../tests/cxxfrontend.cc and ../../test/unit/lexer/location_offset.d to match + // Other leftParenthesis, rightParenthesis, @@ -249,6 +252,7 @@ enum TOK : ubyte wchar_tLiteral, endOfLine, // \n, \r, \u2028, \u2029 whitespace, + rvalue, // C only keywords inline, @@ -425,6 +429,7 @@ enum EXP : ubyte interval, loweredAssignExp, + rvalue, } enum FirstCKeyword = TOK.inline; @@ -556,6 +561,7 @@ private immutable TOK[] keywords = TOK.prettyFunction, TOK.shared_, TOK.immutable_, + TOK.rvalue, // C only keywords TOK.inline, @@ -680,6 +686,7 @@ extern (C++) struct Token TOK.pragma_: "pragma", TOK.typeof_: "typeof", TOK.typeid_: "typeid", + TOK.rvalue: "__rvalue", TOK.template_: "template", TOK.void_: "void", TOK.int8: "byte", diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index 929897a..2a984b4 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -258,6 +258,7 @@ enum class TOK : unsigned char wchar_tLiteral, endOfLine, // \n, \r, \u2028, \u2029 whitespace, + rvalue, // C only keywords inline_, diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index f7f4cd2..34cdf81 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -544,7 +544,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } return True(); } - if (e.ident == Id.hasCopyConstructor || e.ident == Id.hasPostblit) + if (e.ident == Id.hasCopyConstructor || + e.ident == Id.hasMoveConstructor || + e.ident == Id.hasPostblit) { if (dim != 1) return dimError(1); @@ -562,8 +564,14 @@ Expression semanticTraits(TraitsExp e, Scope* sc) auto ts = tb.isTypeStruct(); if (auto sd = ts ? ts.sym : null) { - return (e.ident == Id.hasPostblit) ? (sd.postblit ? True() : False()) - : (sd.hasCopyCtor ? True() : False()); + bool result; + if (e.ident == Id.hasPostblit) + result = sd.postblit !is null; + else if (e.ident == Id. hasCopyConstructor) + result = sd.hasCopyCtor; + else + result = sd.hasMoveCtor; + return result ? True() : False(); } return False(); } diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index aea969a..2ec88f2 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -681,6 +681,7 @@ extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc) * 'args' are being matched to function type 'tf' * Determine match level. * Params: + * fd = function being called, if a symbol * tf = function type * tthis = type of `this` pointer, null if not member function * argumentList = arguments to function call @@ -690,9 +691,10 @@ extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc) * Returns: * MATCHxxxx */ -extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, void delegate(const(char)*) scope errorHelper = null, Scope* sc = null) +extern (D) MATCH callMatch(FuncDeclaration fd, TypeFunction tf, Type tthis, ArgumentList argumentList, + int flag = 0, void delegate(const(char)*) scope errorHelper = null, Scope* sc = null) { - //printf("TypeFunction::callMatch() %s\n", tf.toChars()); + //printf("callMatch() fd: %s, tf: %s\n", fd ? fd.ident.toChars() : "null", toChars(tf)); MATCH match = MATCH.exact; // assume exact match ubyte wildmatch = 0; @@ -820,7 +822,7 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis Expression arg = args[u]; if (!arg) continue; // default argument - m = argumentMatchParameter(tf, p, arg, wildmatch, flag, sc, pMessage); + m = argumentMatchParameter(fd, tf, p, arg, wildmatch, flag, sc, pMessage); if (failMessage) { buf.reset(); @@ -887,14 +889,15 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis * * This is done by seeing if a call to the copy constructor can be made: * ``` - * typeof(tprm) __copytmp; - * copytmp.__copyCtor(arg); + * typeof(tprm) __copytemp; + * copytemp.__copyCtor(arg); * ``` */ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, Expression arg, Type tprm, Scope* sc, const(char)** pMessage) { - auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null); + //printf("isCopyConstructorCallable() argStruct: %s arg: %s tprm: %s\n", argStruct.toChars(), toChars(arg), toChars(tprm)); + auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytemp"), null); tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe; tmp.dsymbolSemantic(sc); Expression ve = new VarExp(arg.loc, tmp); @@ -980,25 +983,28 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, * * This function is called by `TypeFunction.callMatch` while iterating over * the list of parameter. Here we check if `arg` is a match for `p`, - * which is mostly about checking if `arg.type` converts to `p`'s type + * which is mostly about checking if `arg.type` converts to type of `p` * and some check about value reference. * * Params: + * fd = the function being called if symbol, null if not * tf = The `TypeFunction`, only used for error reporting * p = The parameter of `tf` being matched * arg = Argument being passed (bound) to `p` * wildmatch = Wild (`inout`) matching level, derived from the full argument list - * flag = A non-zero value means we're doing a partial ordering check + * flag = A non-zero value means we are doing a partial ordering check * (no value semantic check) * sc = Scope we are in * pMessage = A buffer to write the error in, or `null` * * Returns: Whether `trailingArgs` match `p`. */ -private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p, +private extern(D) MATCH argumentMatchParameter (FuncDeclaration fd, TypeFunction tf, Parameter p, Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage) { - //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars()); + static if (0) + printf("argumentMatchParameter() sc: %p, fd: %s, tf: %s, p: %s, arg: %s, arg.type: %s\n", + sc, fd ? fd.ident.toChars() : "null", tf.toChars(), parameterToChars(p, tf, false), arg.toChars(), arg.type.toChars()); MATCH m; Type targ = arg.type; Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type; @@ -1013,18 +1019,47 @@ private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p, else { const isRef = p.isReference(); - StructDeclaration argStruct, prmStruct; - // first look for a copy constructor - if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct) + StructDeclaration argStruct, prmStruct; + if (targ.ty == Tstruct && tprm.ty == Tstruct) { // if the argument and the parameter are of the same unqualified struct type argStruct = (cast(TypeStruct)targ).sym; prmStruct = (cast(TypeStruct)tprm).sym; + + /* if both a copy constructor and move constructor exist, then match + * the lvalue to the copy constructor only and the rvalue to the move constructor + * only + */ + if (argStruct == prmStruct && fd) + { + if (auto cfd = fd.isCtorDeclaration()) + { + /* Get struct that constructor is making + */ + + auto t1 = cfd.type.toBasetype(); + auto t2 = t1.nextOf(); + auto t3 = t2.isTypeStruct(); + if (t3) + { + auto ctorStruct = t3.sym; +// StructDeclaration ctorStruct = cfd.type.toBasetype().nextOf().isTypeStruct().sym; + + if (prmStruct == ctorStruct && ctorStruct.hasCopyCtor && ctorStruct.hasMoveCtor) + { + if (cfd.isCpCtor && !arg.isLvalue()) + return MATCH.nomatch; // copy constructor is only for lvalues + else if (cfd.isMoveCtor && arg.isLvalue()) + return MATCH.nomatch; // move constructor is only for rvalues + } + } + } + } } // check if the copy constructor may be called to copy the argument - if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor) + if (arg.isLvalue() && !isRef && argStruct && argStruct == prmStruct && argStruct.hasCopyCtor) { if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage)) return MATCH.nomatch; @@ -4427,6 +4462,10 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type */ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag flag) { + enum LOGDOTEXP = false; + if (LOGDOTEXP) + printf("dotExp()\n"); + Expression visitType(Type mt) { VarDeclaration v = null; @@ -5047,8 +5086,41 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag return noMember(mt, sc, e, ident, flag); } // check before alias resolution; the alias itself might be deprecated! - if (s.isAliasDeclaration) + if (auto ad = s.isAliasDeclaration) + { s.checkDeprecated(e.loc, sc); + + // Fix for https://github.com/dlang/dmd/issues/20610 + if (ad.originalType) + { + if (auto tid = ad.originalType.isTypeIdentifier()) + { + if (tid.idents.length) + { + static if (0) + { + printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars()); + printf("AliasDeclaration: %s\n", ad.toChars()); + if (ad.aliassym) + printf("aliassym: %s\n", ad.aliassym.toChars()); + printf("tid type: %s\n", toChars(tid)); + } + /* Rewrite e.s as e.(tid.ident).(tid.idents) + */ + Expression die = new DotIdExp(e.loc, e, tid.ident); + foreach (id; tid.idents) // maybe use typeToExpressionHelper() + die = new DotIdExp(e.loc, die, cast(Identifier)id); + /* Ambiguous syntax, only way to disambiguate it to try it + */ + die = dmd.expressionsem.trySemantic(die, sc); + if (die && die.isDotVarExp()) // shrink wrap around DotVarExp() + { + return die; + } + } + } + } + } s = s.toAlias(); if (auto em = s.isEnumMember()) @@ -6039,7 +6111,7 @@ Dsymbol toDsymbol(Type type, Scope* sc) Dsymbol visitIdentifier(TypeIdentifier type) { - //printf("TypeIdentifier::toDsymbol('%s')\n", toChars()); + //printf("TypeIdentifier::toDsymbol('%s')\n", toChars(type)); if (!sc) return null; @@ -6051,7 +6123,6 @@ Dsymbol toDsymbol(Type type, Scope* sc) s = t.toDsymbol(sc); if (e) s = getDsymbol(e); - return s; } |