aboutsummaryrefslogtreecommitdiff
path: root/gcc
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
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')
-rw-r--r--gcc/d/d-codegen.cc37
-rw-r--r--gcc/d/d-lang.cc3
-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
-rw-r--r--gcc/testsuite/gdc.dg/copy1.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/aligndefault.d28
-rw-r--r--gcc/testsuite/gdc.test/compilable/extra-files/header1.d5
-rw-r--r--gcc/testsuite/gdc.test/compilable/rvalue2.d22
-rw-r--r--gcc/testsuite/gdc.test/compilable/shortened_methods.d13
-rw-r--r--gcc/testsuite/gdc.test/compilable/test19227.d4
-rw-r--r--gcc/testsuite/gdc.test/compilable/traits.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19871.d20
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail19931.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/fail23036.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice14642.d5
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/ice9865.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/parseStc2.d4
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/short_fn.d15
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test19473.d3
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test20719.d7
-rw-r--r--gcc/testsuite/gdc.test/runnable/aliasassign.d32
-rw-r--r--gcc/testsuite/gdc.test/runnable/imports/test23722_2b.d13
-rw-r--r--gcc/testsuite/gdc.test/runnable/mars1.d59
-rw-r--r--gcc/testsuite/gdc.test/runnable/nrvo.d26
-rw-r--r--gcc/testsuite/gdc.test/runnable/rvalue1.d209
-rw-r--r--gcc/testsuite/gdc.test/runnable/test23036.d13
-rw-r--r--gcc/testsuite/gdc.test/runnable/test23722_2.d10
64 files changed, 1142 insertions, 584 deletions
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index e9962e6..66f06e9 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -631,6 +631,37 @@ force_target_expr (tree exp)
return build_target_expr (decl, exp);
}
+/* Determine whether expression EXP can have a copy of its value elided. */
+
+static bool
+can_elide_copy_p (Expression *exp)
+{
+ /* Explicit `__rvalue(exp)'. */
+ if (exp->rvalue)
+ return true;
+
+ /* Look for variable expression. */
+ Expression *last = exp;
+ while (CommaExp *ce = last->isCommaExp ())
+ last = ce->e2;
+
+ if (VarExp *ve = last->isVarExp ())
+ {
+ if (VarDeclaration *vd = ve->var->isVarDeclaration ())
+ {
+ /* Variable is an implicit copy of an lvalue. */
+ if (vd->storage_class & STCrvalue)
+ return true;
+
+ /* The destructor is going to run on the variable. */
+ if (vd->isArgDtorVar ())
+ return true;
+ }
+ }
+
+ return false;
+}
+
/* Returns the address of the expression EXP. */
tree
@@ -2280,8 +2311,10 @@ d_build_call (TypeFunction *tf, tree callable, tree object,
- The ABI of the function expects the callee to destroy its
arguments; when the caller is handles destruction, then `targ'
has already been made into a temporary. */
- if (arg->op == EXP::structLiteral || (!sd->postblit && !sd->dtor)
- || target.isCalleeDestroyingArgs (tf))
+ if (!can_elide_copy_p (arg)
+ && (arg->op == EXP::structLiteral
+ || (!sd->postblit && !sd->dtor)
+ || target.isCalleeDestroyingArgs (tf)))
targ = force_target_expr (targ);
targ = convert (build_reference_type (TREE_TYPE (targ)),
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 3e9067e..a4cde58 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -925,7 +925,8 @@ d_post_options (const char ** fn)
global.params.v.errorLimit = flag_max_errors;
global.params.v.showColumns = flag_show_column;
- global.params.v.printErrorContext = flag_diagnostics_show_caret;
+ global.params.v.errorPrintMode = flag_diagnostics_show_caret
+ ? ErrorPrintMode::printErrorContext : ErrorPrintMode::simpleError;
/* Keep the front-end location type in sync with params. */
Loc::set (global.params.v.showColumns, global.params.v.messageStyle);
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;
}
diff --git a/gcc/testsuite/gdc.dg/copy1.d b/gcc/testsuite/gdc.dg/copy1.d
new file mode 100644
index 0000000..7b539fa
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/copy1.d
@@ -0,0 +1,19 @@
+// { dg-do compile }
+// { dg-options "-fno-moduleinfo -fdump-tree-original" }
+struct S
+{
+ int i;
+ this(ref S);
+ void opAssign(S s)
+ {
+ i = s.i + 1;
+ }
+}
+
+void test_opAssign()
+{
+ S s;
+ S t;
+ // { dg-final { scan-tree-dump-not "&TARGET_EXPR" "original" } }
+ t = s;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/aligndefault.d b/gcc/testsuite/gdc.test/compilable/aligndefault.d
new file mode 100644
index 0000000..5c66bff
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/aligndefault.d
@@ -0,0 +1,28 @@
+
+struct S
+{
+ align(1)
+ {
+ short x1;
+ int y1;
+ long z1;
+
+ align(default)
+ {
+ short x;
+ int y;
+ long z;
+ }
+ }
+}
+
+void fun()
+{
+ static assert(S.x1.alignof == 1);
+ static assert(S.y1.alignof == 1);
+ static assert(S.z1.alignof == 1);
+
+ static assert(S.x.alignof == short.alignof);
+ static assert(S.y.alignof == int.alignof);
+ static assert(S.z.alignof == long.alignof);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/header1.d b/gcc/testsuite/gdc.test/compilable/extra-files/header1.d
index 9756264..ee698f1 100644
--- a/gcc/testsuite/gdc.test/compilable/extra-files/header1.d
+++ b/gcc/testsuite/gdc.test/compilable/extra-files/header1.d
@@ -564,6 +564,11 @@ ref int* foo(scope return ref int* a) @safe
struct SafeS
{
+ this(int[1] x) scope {}
+ this(int[2] x) return scope {}
+ this(int[3] x) scope return {}
+ this(int[4] x) return {}
+
@safe:
ref SafeS foo() return
{
diff --git a/gcc/testsuite/gdc.test/compilable/rvalue2.d b/gcc/testsuite/gdc.test/compilable/rvalue2.d
new file mode 100644
index 0000000..e1dc44e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/rvalue2.d
@@ -0,0 +1,22 @@
+/* PERMUTE_ARGS: -preview=rvaluerefparam
+ */
+
+struct S
+{
+ alias TT this;
+ long TT();
+ this(T)(int x) {} // works if `int` is `long`
+
+ this(S);
+ this(ref S);
+
+ ~this();
+}
+
+S fun(ref S arg);
+
+void test()
+{
+ S st;
+ fun(st);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/shortened_methods.d b/gcc/testsuite/gdc.test/compilable/shortened_methods.d
index 785cb8e..76a4c8a 100644
--- a/gcc/testsuite/gdc.test/compilable/shortened_methods.d
+++ b/gcc/testsuite/gdc.test/compilable/shortened_methods.d
@@ -13,6 +13,10 @@ class A {
// or normal method defintions
bool isNull() => this is null;
+
+ this() {}
+ this(int x) { _x = x; }
+ this(float y) => this(cast(int) y);
}
class B : A{
@@ -36,3 +40,12 @@ void func() {
// Issue 24088 - https://issues.dlang.org/show_bug.cgi?id=24088
S!int f() => S!int();
}
+
+struct T
+{
+ void inc() {}
+ this(this) => inc();
+
+ void free() {}
+ ~this() => free();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test19227.d b/gcc/testsuite/gdc.test/compilable/test19227.d
index 6ff5349..55fa591 100644
--- a/gcc/testsuite/gdc.test/compilable/test19227.d
+++ b/gcc/testsuite/gdc.test/compilable/test19227.d
@@ -1,9 +1,7 @@
// https://issues.dlang.org/show_bug.cgi?id=19227
/* TEST_OUTPUT:
---
-compilable/test19227.d(18): Deprecation: use of complex type `cfloat` is deprecated, use `std.complex.Complex!(float)` instead
-Deprecation: use of complex type `const(cfloat)` is deprecated, use `std.complex.Complex!(float)` instead
-Deprecation: use of complex type `const(cfloat)` is deprecated, use `std.complex.Complex!(float)` instead
+compilable/test19227.d(16): Deprecation: use of complex type `cfloat` is deprecated, use `std.complex.Complex!(float)` instead
Deprecation: use of complex type `const(cfloat)` is deprecated, use `std.complex.Complex!(float)` instead
---
*/
diff --git a/gcc/testsuite/gdc.test/compilable/traits.d b/gcc/testsuite/gdc.test/compilable/traits.d
index d5e2cb0..09538b1 100644
--- a/gcc/testsuite/gdc.test/compilable/traits.d
+++ b/gcc/testsuite/gdc.test/compilable/traits.d
@@ -137,6 +137,8 @@ struct DisabledPostblit
struct NoCpCtor { }
class C19902 { }
+struct MoveCtor { this(MoveCtor) { } }
+
static assert(__traits(hasCopyConstructor, S));
static assert(__traits(hasCopyConstructor, OuterS.S));
static assert(__traits(hasCopyConstructor, OuterS));
@@ -147,6 +149,8 @@ static assert(__traits(hasCopyConstructor, U!S));
static assert(!__traits(hasPostblit, U!S));
static assert(__traits(hasPostblit, SPostblit));
static assert(!__traits(hasCopyConstructor, SPostblit));
+static assert(__traits(hasMoveConstructor, MoveCtor));
+static assert(!__traits(hasMoveConstructor, NoCpCtor));
static assert(!__traits(hasCopyConstructor, NoCpCtor));
static assert(!__traits(hasCopyConstructor, C19902));
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19871.d b/gcc/testsuite/gdc.test/fail_compilation/fail19871.d
deleted file mode 100644
index ad458df..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19871.d
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail19871.d(10): Error: `struct Struct` may not define both a rvalue constructor and a copy constructor
-fail_compilation/fail19871.d(19): rvalue constructor defined here
-fail_compilation/fail19871.d(13): copy constructor defined here
----
-*/
-
-struct Struct
-{
- @disable this();
- this(ref Struct other)
- {
- const Struct s = void;
- this(s);
- }
-
- this(Struct) {}
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19931.d b/gcc/testsuite/gdc.test/fail_compilation/fail19931.d
deleted file mode 100644
index 940a1fa..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19931.d
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail19931.d(10): Error: `struct S` may not define both a rvalue constructor and a copy constructor
-fail_compilation/fail19931.d(12): rvalue constructor defined here
-fail_compilation/fail19931.d(13): copy constructor defined here
----
-*/
-
-struct S
-{
- this(S s) {}
- this(ref S s) {}
- this(this) {}
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23036.d b/gcc/testsuite/gdc.test/fail_compilation/fail23036.d
deleted file mode 100644
index 8920586..0000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail23036.d
+++ /dev/null
@@ -1,22 +0,0 @@
-// https://issues.dlang.org/show_bug.cgi?id=23036
-
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail23036.d(12): Error: `struct S` may not define both a rvalue constructor and a copy constructor
-fail_compilation/fail23036.d(15): rvalue constructor defined here
-fail_compilation/fail23036.d(14): copy constructor defined here
----
-*/
-
-struct S
-{
- this(ref S) {}
- this(S, int a = 2) {}
-}
-
-void main()
-{
- S a;
- S b = a;
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice14642.d b/gcc/testsuite/gdc.test/fail_compilation/ice14642.d
index 90b9867..91b1f95 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice14642.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice14642.d
@@ -1,8 +1,9 @@
/*
TEST_OUTPUT:
---
-fail_compilation/ice14642.d(47): Error: undefined identifier `errorValue`
-fail_compilation/ice14642.d(23): Error: template instance `ice14642.X.NA!()` error instantiating
+fail_compilation/ice14642.d(48): Error: undefined identifier `errorValue`
+fail_compilation/ice14642.d(52): error on member `ice14642.Z.v`
+fail_compilation/ice14642.d(24): Error: template instance `ice14642.X.NA!()` error instantiating
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9865.d b/gcc/testsuite/gdc.test/fail_compilation/ice9865.d
index 3d8e997..ec84263 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice9865.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice9865.d
@@ -2,7 +2,8 @@
EXTRA_FILES: imports/ice9865b.d
TEST_OUTPUT:
---
-fail_compilation/ice9865.d(9): Error: alias `ice9865.Baz` recursive alias declaration
+fail_compilation/ice9865.d(10): Error: alias `ice9865.Baz` recursive alias declaration
+fail_compilation/ice9865.d(11): error on member `ice9865.Foo.f`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/parseStc2.d b/gcc/testsuite/gdc.test/fail_compilation/parseStc2.d
index 936769a..dbc98f9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/parseStc2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/parseStc2.d
@@ -53,10 +53,10 @@ public private void f10() {}
/*
TEST_OUTPUT:
---
-fail_compilation/parseStc2.d(63): Error: redundant alignment attribute `align`
+fail_compilation/parseStc2.d(63): Error: redundant alignment attribute `align(default)`
fail_compilation/parseStc2.d(64): Error: redundant alignment attribute `align(1)`
fail_compilation/parseStc2.d(65): Error: redundant alignment attribute `align(1)`
-fail_compilation/parseStc2.d(66): Error: redundant alignment attribute `align`
+fail_compilation/parseStc2.d(66): Error: redundant alignment attribute `align(default)`
fail_compilation/parseStc2.d(67): Error: redundant alignment attribute `align(2)`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/short_fn.d b/gcc/testsuite/gdc.test/fail_compilation/short_fn.d
new file mode 100644
index 0000000..04f3e3f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/short_fn.d
@@ -0,0 +1,15 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/short_fn.d(13): Error: can only return void expression, `this` call or `super` call from constructor
+fail_compilation/short_fn.d(14): Error: can only return void expression, `this` call or `super` call from constructor
+---
+*/
+
+struct Number
+{
+ int x;
+
+ this(int x) => this.x = x;
+ this(byte x) => Number();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19473.d b/gcc/testsuite/gdc.test/fail_compilation/test19473.d
index ba6024b..67a66c5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test19473.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test19473.d
@@ -1,6 +1,7 @@
/* TEST_OUTPUT:
---
-fail_compilation/test19473.d(14): Error: union `test19473.P` no size because of forward reference
+fail_compilation/test19473.d(15): Error: union `test19473.P` no size because of forward reference
+fail_compilation/test19473.d(31): error on member `test19473.P.p`
---
*/
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20719.d b/gcc/testsuite/gdc.test/fail_compilation/test20719.d
index 4db59d6..56b80bb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test20719.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20719.d
@@ -1,8 +1,9 @@
/* TEST_OUTPUT:
---
-fail_compilation/test20719.d(13): Error: struct `test20719.SumType` no size because of forward reference
-fail_compilation/test20719.d(32): Error: variable `test20719.isCopyable!(SumType).__lambda_L32_C22.foo` - size of type `SumType` is invalid
-fail_compilation/test20719.d(18): Error: template instance `test20719.isCopyable!(SumType)` error instantiating
+fail_compilation/test20719.d(14): Error: struct `test20719.SumType` no size because of forward reference
+fail_compilation/test20719.d(17): error on member `test20719.SumType.storage`
+fail_compilation/test20719.d(33): Error: variable `test20719.isCopyable!(SumType).__lambda_L33_C22.foo` - size of type `SumType` is invalid
+fail_compilation/test20719.d(19): Error: template instance `test20719.isCopyable!(SumType)` error instantiating
---
*/
struct SumType
diff --git a/gcc/testsuite/gdc.test/runnable/aliasassign.d b/gcc/testsuite/gdc.test/runnable/aliasassign.d
index 986cccc..4f61e37 100644
--- a/gcc/testsuite/gdc.test/runnable/aliasassign.d
+++ b/gcc/testsuite/gdc.test/runnable/aliasassign.d
@@ -15,7 +15,7 @@ template Qual(alias T)
alias Qual = T;
}
-void test()
+void test1()
{
int x = 3;
int y = 4;
@@ -25,7 +25,33 @@ void test()
assert(XY[1] == 4);
}
-void main()
+/**********************************************/
+
+struct T
+{
+ int k,i = 2;
+}
+
+struct S
+{
+ int x;
+ T t;
+ alias ti = t.i;
+}
+
+void test2()
+{
+ T t = T(1, 2);
+ S s;
+ assert(s.ti == 2);
+}
+
+/**********************************************/
+
+int main()
{
- test();
+ test1();
+ test2();
+
+ return 0;
}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/test23722_2b.d b/gcc/testsuite/gdc.test/runnable/imports/test23722_2b.d
new file mode 100644
index 0000000..b0e54a9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/test23722_2b.d
@@ -0,0 +1,13 @@
+module imports.test23722_2b;
+
+struct T(alias fun) { }
+
+struct S(int i) {
+ auto t = T!(x => i)();
+}
+
+string g() {
+ S!0 s0;
+ S!1 s1;
+ return s1.t.init.mangleof;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/mars1.d b/gcc/testsuite/gdc.test/runnable/mars1.d
index f493eac..1c2ae55 100644
--- a/gcc/testsuite/gdc.test/runnable/mars1.d
+++ b/gcc/testsuite/gdc.test/runnable/mars1.d
@@ -2492,6 +2492,62 @@ void testDoWhileContinue()
}
////////////////////////////////////////////////////////////////////////
+// https://github.com/dlang/dmd/issues/20574
+
+int test20574x(int i, int y)
+{
+ return i ? y : y;
+}
+
+void test20574()
+{
+ assert(test20574x(1, 2) == 2);
+ assert(test20574x(0, 2) == 2);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+struct S8
+{
+ int x,y,z;
+}
+
+int test8x(S8 s)
+{
+ s = s;
+ return s.y;
+}
+
+void test8()
+{
+ S8 s;
+ s.y = 2;
+ assert(test8x(s) == 2);
+}
+
+////////////////////////////////////////////////////////////////////////
+
+struct S9
+{
+ int a,b;
+ ~this() { }
+}
+
+
+S9 test9x(ref S9 arg)
+{
+ return arg;
+}
+
+void test9()
+{
+ S9 s;
+ s.b = 3;
+ S9 t = test9x(s);
+ assert(t.b == 3);
+}
+
+////////////////////////////////////////////////////////////////////////
int main()
{
@@ -2592,6 +2648,9 @@ int main()
test21816();
test21835();
testDoWhileContinue();
+ test20574();
+ test8();
+ test9();
printf("Success\n");
return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/nrvo.d b/gcc/testsuite/gdc.test/runnable/nrvo.d
index 5c653fe..bceba10 100644
--- a/gcc/testsuite/gdc.test/runnable/nrvo.d
+++ b/gcc/testsuite/gdc.test/runnable/nrvo.d
@@ -23,8 +23,34 @@ void test1()
}
/***************************************************/
+// https://github.com/dlang/dmd/issues/20567
+
+struct S2
+{
+ int x;
+ this(ref S2 s) { x = s.x; }
+}
+
+S2 returnRval(ref S2 arg1, ref S2 arg2, int i)
+{
+ return i ? arg1 : arg2;
+}
+
+void test2()
+{
+ S2 s1, s2;
+ s1.x = 3;
+ s2.x = 4;
+ S2 s = returnRval(s1, s2, 0);
+ assert(s.x == 4);
+ s = returnRval(s1, s2, 1);
+ assert(s.x == 3);
+}
+
+/***************************************************/
void main()
{
test1();
+ test2();
}
diff --git a/gcc/testsuite/gdc.test/runnable/rvalue1.d b/gcc/testsuite/gdc.test/runnable/rvalue1.d
new file mode 100644
index 0000000..f8134f7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/rvalue1.d
@@ -0,0 +1,209 @@
+/* PERMUTE_ARGS: -preview=rvaluerefparam
+/* testing __rvalue */
+
+import core.stdc.stdio;
+
+/********************************/
+
+int foo(int) { printf("foo(int)\n"); return 1; }
+int foo(ref int) { printf("foo(ref int)\n"); return 2; }
+
+void test1()
+{
+ int s;
+ assert(foo(s) == 2);
+ assert(foo(__rvalue(s)) == 1);
+}
+
+/********************************/
+
+struct S
+{
+ nothrow:
+ ~this() { printf("~this() %p\n", &this); }
+ this(ref S) { printf("this(ref S)\n"); }
+ void opAssign(S) { printf("opAssign(S)\n"); }
+}
+
+void test2()
+{
+ S s;
+ S t;
+
+ t = __rvalue(s);
+}
+
+/********************************/
+
+struct S3
+{
+ int a, b, c;
+
+ this(S3) {}
+ this(ref S3) {}
+}
+
+void test3()
+{
+ S3 s;
+ S3 x = s; // this line causes the compiler to crash
+}
+
+/********************************/
+
+struct S4
+{
+ void* p;
+
+ this(ref S4) { }
+
+ this(S4 s)
+ {
+ assert(&s is &x); // confirm the rvalue reference
+ }
+}
+
+__gshared S4 x;
+
+void test4()
+{
+ S4 t = __rvalue(x);
+}
+
+/********************************/
+
+struct S5
+{
+ this(S5 s) { printf("this(S5 s)\n"); }
+ this(ref inout S5 s) inout { printf("this(ref inout S5 s) inout\n"); }
+}
+
+void test5()
+{
+ S5 t;
+ S5 t1 = t;
+ S5 t2 = __rvalue(t);
+}
+
+/********************************/
+
+int moveCtor, copyCtor, moveAss, copyAss;
+
+struct S6
+{
+ this(S6 s) { ++moveCtor; }
+ this(ref S6 s) { ++copyCtor; }
+ void opAssign(S6 s) { ++moveAss; }
+ void opAssign(ref S6 s) { ++copyAss; }
+}
+
+void test6()
+{
+ S6 x;
+ S6 s = x;
+// printf("S6 s = x; moveCtor %d copyCtor %d moveAss %d copyAss %d\n", moveCtor, copyCtor, moveAss, copyAss);
+ assert(copyCtor == 1);
+ S6 s2 = __rvalue(x);
+// printf("S6 s2 = __rvalue(x); moveCtor %d copyCtor %d moveAss %d copyAss %d\n", moveCtor, copyCtor, moveAss, copyAss);
+ assert(moveCtor == 1);
+ s2 = s;
+// printf("s2 = s; moveCtor %d copyCtor %d moveAss %d copyAss %d\n", moveCtor, copyCtor, moveAss, copyAss);
+ assert(copyAss == 1);
+ s2 = __rvalue(s);
+// printf("s2 = __rvalue(s); moveCtor %d copyCtor %d moveAss %d copyAss %d\n", moveCtor, copyCtor, moveAss, copyAss);
+ assert(moveAss == 1);
+ assert(copyCtor == 1 && moveCtor == 1 && copyAss == 1 && moveAss == 1);
+}
+
+/********************************/
+// https://github.com/dlang/dmd/pull/17050#issuecomment-2543370370
+
+struct MutableString(size_t E) {}
+
+struct StringTest
+{
+ alias toString this;
+ const(char)[] toString() const pure
+ => null;
+
+ this(StringTest rhs) {}
+ this(ref inout StringTest rhs) inout pure {}
+
+ this(typeof(null)) inout pure {}
+ this(size_t Embed)(MutableString!Embed str) inout {}
+
+ ~this() {}
+}
+
+
+void test7()
+{
+ StringTest s = StringTest(null);
+}
+
+/********************************/
+// https://github.com/dlang/dmd/issues/20562
+
+struct S8
+{
+ int a,b;
+ this(S8) { printf("this(S)\n"); b = 4; }
+ this(ref S8) { printf("this(ref S)\n"); assert(0); }
+}
+
+
+S8 returnRval(ref S8 arg)
+{
+static if (0)
+{
+ /* __copytmp2 = 0 ;
+ _D7rvalue51S6__ctorMFNcKSQxQrZQg call (arg param #__copytmp2);
+ * __HID1 streq 1 __copytmp2;
+ __HID1;
+ */
+ return arg;
+}
+else static if (1)
+{
+ /* * __HID1 streq 1 * arg;
+ __HID1;
+ */
+ return __rvalue(arg); // should move-construct the NRVO value
+}
+else
+{
+ /* * t = 0 ;
+ t;
+ _TMP0 = t;
+ _D7rvalue51S6__ctorMFNcSQwQqZQg call (arg param _TMP0);
+ t;
+ */
+ S8 t = __rvalue(arg);
+ return t;
+}
+}
+
+
+void test8()
+{
+ S8 s;
+ S8 t = returnRval(s);
+ printf("t.b: %d\n", t.b);
+ assert(t.b == 4);
+}
+
+/********************************/
+
+int main()
+{
+ test1();
+ test2();
+ test3();
+ test4();
+ test5();
+ test6();
+ test7();
+ test8();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test23036.d b/gcc/testsuite/gdc.test/runnable/test23036.d
new file mode 100644
index 0000000..efb6fef
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test23036.d
@@ -0,0 +1,13 @@
+// https://issues.dlang.org/show_bug.cgi?id=23036
+
+struct S
+{
+ this(ref S) {}
+ this(S, int a = 2) {}
+}
+
+void main()
+{
+ S a;
+ S b = a;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test23722_2.d b/gcc/testsuite/gdc.test/runnable/test23722_2.d
new file mode 100644
index 0000000..cce4629
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test23722_2.d
@@ -0,0 +1,10 @@
+// COMPILE_SEPARATELY:
+// EXTRA_SOURCES: imports/test23722_2b.d
+// https://issues.dlang.org/show_bug.cgi?id=23722
+// Lambdas are mangled incorrectly when using multiple compilation units, resulting in incorrect code
+import imports.test23722_2b;
+
+void main() {
+ S!1 s1;
+ assert(s1.t.init.mangleof == g);
+}