aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2025-01-08 21:02:56 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2025-01-12 21:53:50 +0100
commit0dd21bce3afe9b0081d1d5bf4b53f9b43980c1c4 (patch)
tree4326f2031f50a7a326d79c25589ff50d00e36e77 /gcc/d/dmd
parenta236f70617213343f3075ee43e8d9f5882dca400 (diff)
downloadgcc-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')
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/astenums.d2
-rw-r--r--gcc/d/dmd/attrib.d30
-rw-r--r--gcc/d/dmd/attrib.h3
-rw-r--r--gcc/d/dmd/clone.d16
-rw-r--r--gcc/d/dmd/constfold.d13
-rw-r--r--gcc/d/dmd/declaration.d12
-rw-r--r--gcc/d/dmd/declaration.h1
-rw-r--r--gcc/d/dmd/dscope.d2
-rw-r--r--gcc/d/dmd/dstruct.d19
-rw-r--r--gcc/d/dmd/dsymbol.d20
-rw-r--r--gcc/d/dmd/dsymbol.h1
-rw-r--r--gcc/d/dmd/dsymbolsem.d101
-rw-r--r--gcc/d/dmd/expression.d49
-rw-r--r--gcc/d/dmd/expression.h3
-rw-r--r--gcc/d/dmd/expressionsem.d405
-rw-r--r--gcc/d/dmd/func.d10
-rw-r--r--gcc/d/dmd/funcsem.d26
-rw-r--r--gcc/d/dmd/globals.d9
-rw-r--r--gcc/d/dmd/globals.h11
-rw-r--r--gcc/d/dmd/hdrgen.d58
-rw-r--r--gcc/d/dmd/id.d1
-rw-r--r--gcc/d/dmd/identifier.d17
-rw-r--r--gcc/d/dmd/initsem.d2
-rw-r--r--gcc/d/dmd/json.d3
-rw-r--r--gcc/d/dmd/mtype.d24
-rw-r--r--gcc/d/dmd/mtype.h2
-rw-r--r--gcc/d/dmd/objc.d61
-rw-r--r--gcc/d/dmd/parse.d56
-rw-r--r--gcc/d/dmd/printast.d6
-rw-r--r--gcc/d/dmd/root/filename.d3
-rw-r--r--gcc/d/dmd/scope.h1
-rw-r--r--gcc/d/dmd/semantic3.d2
-rw-r--r--gcc/d/dmd/statementsem.d2
-rw-r--r--gcc/d/dmd/templatesem.d35
-rw-r--r--gcc/d/dmd/tokens.d7
-rw-r--r--gcc/d/dmd/tokens.h1
-rw-r--r--gcc/d/dmd/traits.d14
-rw-r--r--gcc/d/dmd/typesem.d105
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;
}