aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/attrib.d6
-rw-r--r--gcc/d/dmd/cparse.d88
-rw-r--r--gcc/d/dmd/cppmangle.d2
-rw-r--r--gcc/d/dmd/dcast.d4
-rw-r--r--gcc/d/dmd/dinterpret.d38
-rw-r--r--gcc/d/dmd/dscope.d17
-rw-r--r--gcc/d/dmd/dsymbol.d18
-rw-r--r--gcc/d/dmd/dsymbol.h2
-rw-r--r--gcc/d/dmd/dsymbolsem.d7
-rw-r--r--gcc/d/dmd/dtemplate.d8
-rw-r--r--gcc/d/dmd/expressionsem.d100
-rw-r--r--gcc/d/dmd/func.d4
-rw-r--r--gcc/d/dmd/id.d1
-rw-r--r--gcc/d/dmd/mtype.d13
-rw-r--r--gcc/d/dmd/mtype.h11
-rw-r--r--gcc/d/dmd/parse.d2
-rw-r--r--gcc/d/dmd/scope.h1
-rw-r--r--gcc/d/dmd/statement.d2
-rw-r--r--gcc/d/dmd/statementsem.d25
-rw-r--r--gcc/d/dmd/typesem.d471
-rw-r--r--gcc/d/dmd/typinf.d9
-rw-r--r--gcc/d/expr.cc10
-rw-r--r--gcc/d/runtime.def1
-rw-r--r--gcc/testsuite/gdc.test/compilable/imports/defines.c28
-rw-r--r--gcc/testsuite/gdc.test/compilable/nogc.d9
-rw-r--r--gcc/testsuite/gdc.test/compilable/test22626.d23
-rw-r--r--gcc/testsuite/gdc.test/compilable/test23076.d38
-rw-r--r--gcc/testsuite/gdc.test/compilable/test23142.d19
-rw-r--r--gcc/testsuite/gdc.test/compilable/test23174.d58
-rw-r--r--gcc/testsuite/gdc.test/compilable/testdefines.d14
-rw-r--r--gcc/testsuite/gdc.test/compilable/testdip1008.d19
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/mixin_template.d10
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/noreturn.d18
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/template_decl.d9
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test21477.d16
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/test23159.d22
-rw-r--r--gcc/testsuite/gdc.test/fail_compilation/traits.d18
38 files changed, 826 insertions, 317 deletions
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index c37da05..d39658a 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-4d07f22f29d098869ad937f0499d8895df089a71
+821ed393d428c7db5a48623e77d43f5647d5c6a2
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/attrib.d b/gcc/d/dmd/attrib.d
index 1e84b55..b569a9c 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -1274,14 +1274,14 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration
* declarations.
*/
-extern(C++) final class ForwardingAttribDeclaration: AttribDeclaration
+extern(C++) final class ForwardingAttribDeclaration : AttribDeclaration
{
ForwardingScopeDsymbol sym = null;
this(Dsymbols* decl)
{
super(decl);
- sym = new ForwardingScopeDsymbol(null);
+ sym = new ForwardingScopeDsymbol();
sym.symtab = new DsymbolTable();
}
@@ -1298,7 +1298,7 @@ extern(C++) final class ForwardingAttribDeclaration: AttribDeclaration
*/
override void addMember(Scope* sc, ScopeDsymbol sds)
{
- parent = sym.parent = sym.forward = sds;
+ sym.parent = sds;
return super.addMember(sc, sym);
}
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index 344933a..62ba889 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -5156,26 +5156,80 @@ final class CParser(AST) : Parser!AST
{
auto id = n.ident;
scan(&n);
- if (n.value == TOK.endOfLine) // #define identifier
- {
- nextDefineLine();
- continue;
- }
- if (n.value == TOK.int32Literal)
+
+ AST.Type t;
+
+ switch (n.value)
{
- const value = n.intvalue;
- scan(&n);
- if (n.value == TOK.endOfLine)
- {
- /* Declare manifest constant:
- * enum id = value;
- */
- AST.Expression e = new AST.IntegerExp(scanloc, value, AST.Type.tint32);
- auto v = new AST.VarDeclaration(scanloc, AST.Type.tint32, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
- symbols.push(v);
+ case TOK.endOfLine: // #define identifier
nextDefineLine();
continue;
- }
+
+ case TOK.int32Literal:
+ case TOK.charLiteral: t = AST.Type.tint32; goto Linteger;
+ case TOK.uns32Literal: t = AST.Type.tuns32; goto Linteger;
+ case TOK.int64Literal: t = AST.Type.tint64; goto Linteger;
+ case TOK.uns64Literal: t = AST.Type.tuns64; goto Linteger;
+
+ Linteger:
+ const intvalue = n.intvalue;
+ scan(&n);
+ if (n.value == TOK.endOfLine)
+ {
+ /* Declare manifest constant:
+ * enum id = intvalue;
+ */
+ AST.Expression e = new AST.IntegerExp(scanloc, intvalue, t);
+ auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
+ symbols.push(v);
+ nextDefineLine();
+ continue;
+ }
+ break;
+
+ case TOK.float32Literal: t = AST.Type.tfloat32; goto Lfloat;
+ case TOK.float64Literal: t = AST.Type.tfloat64; goto Lfloat;
+ case TOK.float80Literal: t = AST.Type.tfloat80; goto Lfloat;
+ case TOK.imaginary32Literal: t = AST.Type.timaginary32; goto Lfloat;
+ case TOK.imaginary64Literal: t = AST.Type.timaginary64; goto Lfloat;
+ case TOK.imaginary80Literal: t = AST.Type.timaginary80; goto Lfloat;
+
+ Lfloat:
+ const floatvalue = n.floatvalue;
+ scan(&n);
+ if (n.value == TOK.endOfLine)
+ {
+ /* Declare manifest constant:
+ * enum id = floatvalue;
+ */
+ AST.Expression e = new AST.RealExp(scanloc, floatvalue, t);
+ auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
+ symbols.push(v);
+ nextDefineLine();
+ continue;
+ }
+ break;
+
+ case TOK.string_:
+ const str = n.ustring;
+ const len = n.len;
+ const postfix = n.postfix;
+ scan(&n);
+ if (n.value == TOK.endOfLine)
+ {
+ /* Declare manifest constant:
+ * enum id = "string";
+ */
+ AST.Expression e = new AST.StringExp(scanloc, str[0 .. len], len, 1, postfix);
+ auto v = new AST.VarDeclaration(scanloc, null, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
+ symbols.push(v);
+ nextDefineLine();
+ continue;
+ }
+ break;
+
+ default:
+ break;
}
}
skipToNextLine();
diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d
index 6235342..fed83b8 100644
--- a/gcc/d/dmd/cppmangle.d
+++ b/gcc/d/dmd/cppmangle.d
@@ -1318,7 +1318,7 @@ private final class CppMangleVisitor : Visitor
Type t = fparam.type.merge2();
if (fparam.isReference())
t = t.referenceTo();
- else if (fparam.storageClass & STC.lazy_)
+ else if (fparam.isLazy())
{
// Mangle as delegate
auto tf = new TypeFunction(ParameterList(), t, LINK.d);
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index 4607d6f..12051d9 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -916,7 +916,7 @@ MATCH implicitConvTo(Expression e, Type t)
if (i - j < nparams)
{
Parameter fparam = tf.parameterList[i - j];
- if (fparam.storageClass & STC.lazy_)
+ if (fparam.isLazy())
return result; // not sure what to do with this
Type tparam = fparam.type;
if (!tparam)
@@ -1224,7 +1224,7 @@ MATCH implicitConvTo(Expression e, Type t)
if (i - j < nparams)
{
Parameter fparam = tf.parameterList[i - j];
- if (fparam.storageClass & STC.lazy_)
+ if (fparam.isLazy())
return MATCH.nomatch; // not sure what to do with this
Type tparam = fparam.type;
if (!tparam)
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index 5e7527d..bb25210 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -492,7 +492,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
if (CTFEExp.isCantExp(earg))
return earg;
}
- else if (fparam.storageClass & STC.lazy_)
+ else if (fparam.isLazy())
{
}
else
@@ -5000,6 +5000,27 @@ public:
printf("%s CommaExp::interpret() %s\n", e.loc.toChars(), e.toChars());
}
+ bool isNewThrowableHook()
+ {
+ auto de = e.e1.isDeclarationExp();
+ if (de is null)
+ return false;
+
+ auto vd = de.declaration.isVarDeclaration();
+ if (vd is null)
+ return false;
+
+ auto ei = vd._init.isExpInitializer();
+ if (ei is null)
+ return false;
+
+ auto ce = ei.exp.isConstructExp();
+ if (ce is null)
+ return false;
+
+ return isRuntimeHook(ce.e2, Id._d_newThrowable) !is null;
+ }
+
if (auto ce = isRuntimeHook(e.e1, Id._d_arrayappendcTX))
{
// In expressionsem.d `arr ~= elem` was lowered to
@@ -5018,6 +5039,21 @@ public:
result = interpret(cae, istate);
return;
}
+ else if (isNewThrowableHook())
+ {
+ // In expressionsem.d `throw new Exception(args)` was lowered to
+ // `throw (tmp = _d_newThrowable!Exception(), tmp.ctor(args), tmp)`.
+ // The following code will rewrite it back to `throw new Exception(args)`
+ // and then interpret this expression instead.
+ auto ce = e.e2.isCallExp();
+ assert(ce);
+
+ auto ne = new NewExp(e.loc, null, e.type, ce.arguments);
+ ne.type = e.e1.type;
+
+ result = interpret(ne, istate);
+ return;
+ }
// If it creates a variable, and there's no context for
// the variable to be created in, we need to create one now.
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index b546e37..9c30978 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -754,7 +754,6 @@ struct Scope
// assert(0);
}
}
-
/******************************
*/
structalign_t alignment()
@@ -771,13 +770,13 @@ struct Scope
return sa;
}
}
-
+ @safe @nogc pure nothrow const:
/**********************************
* Checks whether the current scope (or any of its parents) is deprecated.
*
* Returns: `true` if this or any parent scope is deprecated, `false` otherwise`
*/
- extern(C++) bool isDeprecated() @safe @nogc pure nothrow const
+ extern(C++) bool isDeprecated()
{
for (const(Dsymbol)* sp = &(this.parent); *sp; sp = &(sp.parent))
{
@@ -799,4 +798,16 @@ struct Scope
}
return false;
}
+ /**
+ * dmd relies on mutation of state during semantic analysis, however
+ * sometimes semantic is being performed in a speculative context that should
+ * not have any visible effect on the rest of the compilation: for example when compiling
+ * a typeof() or __traits(compiles).
+ *
+ * Returns: `true` if this `Scope` is known to be from one of these speculative contexts
+ */
+ extern(C++) bool isFromSpeculativeSemanticContext() scope
+ {
+ return this.intypeof || this.flags & SCOPE.compile;
+ }
}
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index 3b3a527..2b608f6 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -2184,20 +2184,13 @@ extern (C++) final class OverloadSet : Dsymbol
*/
extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
{
- /*************************
- * Symbol to forward insertions to.
- * Can be `null` before being lazily initialized.
- */
- ScopeDsymbol forward;
- extern (D) this(ScopeDsymbol forward) nothrow
+ extern (D) this() nothrow
{
- super(null);
- this.forward = forward;
+ super();
}
override Dsymbol symtabInsert(Dsymbol s) nothrow
{
- assert(forward);
if (auto d = s.isDeclaration())
{
if (d.storage_class & STC.local)
@@ -2212,6 +2205,8 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
return super.symtabInsert(s); // insert locally
}
}
+ auto forward = parent.isScopeDsymbol();
+ assert(forward);
if (!forward.symtab)
{
forward.symtab = new DsymbolTable();
@@ -2228,7 +2223,6 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
*/
override Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow
{
- assert(forward);
// correctly diagnose clashing foreach loop variables.
if (auto d = s.isDeclaration())
{
@@ -2243,6 +2237,8 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
}
// Declarations within `static foreach` do not clash with
// `static foreach` loop variables.
+ auto forward = parent.isScopeDsymbol();
+ assert(forward);
if (!forward.symtab)
{
forward.symtab = new DsymbolTable();
@@ -2252,6 +2248,8 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
override void importScope(Dsymbol s, Visibility visibility)
{
+ auto forward = parent.isScopeDsymbol();
+ assert(forward);
forward.importScope(s, visibility);
}
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index 23a2c77..bea4b77 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -391,8 +391,6 @@ public:
class ForwardingScopeDsymbol final : public ScopeDsymbol
{
public:
- ScopeDsymbol *forward;
-
Dsymbol *symtabInsert(Dsymbol *s) override;
Dsymbol *symtabLookup(Dsymbol *s, Identifier *id) override;
void importScope(Dsymbol *s, Visibility visibility) override;
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index e491272..6dbc129 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -3276,13 +3276,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if ((funcdecl.storage_class & STC.auto_) && !f.isref && !funcdecl.inferRetType)
funcdecl.error("storage class `auto` has no effect if return type is not inferred");
- /* Functions can only be 'scope' if they have a 'this'
- */
- if (f.isScopeQual && !funcdecl.isNested() && !ad)
- {
- funcdecl.error("functions cannot be `scope`");
- }
-
if (f.isreturn && !funcdecl.needThis() && !funcdecl.isNested())
{
/* Non-static nested functions have a hidden 'this' pointer to which
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index a450ea5..c0a8e9f 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -1632,7 +1632,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
if (farg.op == EXP.error || farg.type.ty == Terror)
return nomatch();
- if (!(fparam.storageClass & STC.lazy_) && farg.type.ty == Tvoid)
+ if (!fparam.isLazy() && farg.type.ty == Tvoid)
return nomatch();
Type tt;
@@ -1837,7 +1837,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
}
Type argtype = farg.type;
- if (!(fparam.storageClass & STC.lazy_) && argtype.ty == Tvoid && farg.op != EXP.function_)
+ if (!fparam.isLazy() && argtype.ty == Tvoid && farg.op != EXP.function_)
return nomatch();
// https://issues.dlang.org/show_bug.cgi?id=12876
@@ -1958,7 +1958,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
if (!farg.type.isMutable()) // https://issues.dlang.org/show_bug.cgi?id=11916
return nomatch();
}
- if (m == MATCH.nomatch && (fparam.storageClass & STC.lazy_) && prmtype.ty == Tvoid && farg.type.ty != Tvoid)
+ if (m == MATCH.nomatch && fparam.isLazy() && prmtype.ty == Tvoid && farg.type.ty != Tvoid)
m = MATCH.convert;
if (m != MATCH.nomatch)
{
@@ -7723,7 +7723,7 @@ extern (C++) final class TemplateMixin : TemplateInstance
}
if (!tempdecl)
{
- error("`%s` isn't a template", s.toChars());
+ error("- `%s` is a %s, not a template", s.toChars(), s.kind());
return false;
}
}
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index cb72027..dcc5b50 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -443,7 +443,7 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
}
if (!s)
- return ue.e1.type.Type.getProperty(sc, loc, ident, 0);
+ return ue.e1.type.getProperty(sc, loc, ident, 0);
FuncDeclaration f = s.isFuncDeclaration();
if (f)
@@ -1856,7 +1856,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
}
L1:
- if (!(p.storageClass & STC.lazy_ && p.type.ty == Tvoid))
+ if (!(p.isLazy() && p.type.ty == Tvoid))
{
if (ubyte wm = arg.type.deduceWild(p.type, p.isReference()))
{
@@ -1953,7 +1953,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
Type targ = arg.type; // keep original type for isCopyable() because alias this
// resolution may hide an uncopyable type
- if (!(p.storageClass & STC.lazy_ && p.type.ty == Tvoid))
+ if (!(p.isLazy() && p.type.ty == Tvoid))
{
Type tprm = p.type.hasWild()
? p.type.substWildTo(wildmatch)
@@ -2018,7 +2018,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
}
arg = arg.toLvalue(sc, arg);
}
- else if (p.storageClass & STC.lazy_)
+ else if (p.isLazy())
{
// Convert lazy argument to a delegate
auto t = (p.type.ty == Tvoid) ? p.type : arg.type;
@@ -2050,7 +2050,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
// Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference
// may be unreliable when scope violations only manifest as deprecation warnings.
// However, existing `@nogc` code may rely on it, so still do it when the parameter is explicitly marked `scope`
- const explicitScope = (p.storageClass & STC.lazy_) ||
+ const explicitScope = p.isLazy() ||
((p.storageClass & STC.scope_) && !(p.storageClass & STC.scopeinferred));
if ((pStc & (STC.scope_ | STC.lazy_)) &&
((global.params.useDIP1000 == FeatureState.enabled) || explicitScope) &&
@@ -2261,7 +2261,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
if (arg.type.needsDestruction())
{
Parameter p = (i >= nparams ? null : tf.parameterList[i]);
- if (!(p && (p.storageClass & (STC.lazy_ | STC.ref_ | STC.out_))))
+ if (!(p && (p.isLazy() || p.isReference())))
{
if (firstdtor == -1)
firstdtor = i;
@@ -2302,7 +2302,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
Parameter parameter = (i >= nparams ? null : tf.parameterList[i]);
const bool isRef = parameter && parameter.isReference();
- const bool isLazy = (parameter && (parameter.storageClass & STC.lazy_));
+ const bool isLazy = parameter && parameter.isLazy();
/* Skip lazy parameters
*/
@@ -3722,6 +3722,36 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
}
+
+ // When using `@nogc` exception handling, lower `throw new E(args)` to
+ // `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`.
+ if (global.params.ehnogc && exp.thrownew &&
+ !cd.isCOMclass() && !cd.isCPPclass())
+ {
+ assert(cd.ctor);
+
+ Expression id = new IdentifierExp(exp.loc, Id.empty);
+ id = new DotIdExp(exp.loc, id, Id.object);
+
+ auto tiargs = new Objects();
+ tiargs.push(exp.newtype);
+ id = new DotTemplateInstanceExp(exp.loc, id, Id._d_newThrowable, tiargs);
+ id = new CallExp(exp.loc, id).expressionSemantic(sc);
+
+ Expression idVal;
+ Expression tmp = extractSideEffect(sc, "__tmpThrowable", idVal, id, true);
+ // auto castTmp = new CastExp(exp.loc, tmp, exp.type);
+
+ auto ctor = new DotIdExp(exp.loc, tmp, Id.ctor).expressionSemantic(sc);
+ auto ctorCall = new CallExp(exp.loc, ctor, exp.arguments);
+
+ id = Expression.combine(idVal, exp.argprefix).expressionSemantic(sc);
+ id = Expression.combine(id, ctorCall).expressionSemantic(sc);
+ // id = Expression.combine(id, castTmp).expressionSemantic(sc);
+
+ result = id.expressionSemantic(sc);
+ return;
+ }
}
else if (auto ts = tb.isTypeStruct())
{
@@ -6582,6 +6612,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = e;
return;
}
+ else if (auto ad = exp.var.isAliasDeclaration())
+ {
+ if (auto t = ad.getType())
+ {
+ result = new TypeExp(exp.loc, t).expressionSemantic(sc);
+ return;
+ }
+ }
exp.e1 = exp.e1.addDtorHook(sc);
@@ -7006,9 +7044,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
/* Because nested functions cannot be overloaded,
* mark here that we took its address because castTo()
* may not be called with an exact match.
+ *
+ * https://issues.dlang.org/show_bug.cgi?id=19285 :
+ * We also need to make sure we aren't inside a typeof. Ideally the compiler
+ * would do typeof(...) semantic analysis speculatively then collect information
+ * about what it used rather than relying on what are effectively semantically-global
+ * variables but it doesn't.
*/
- if (!ve.hasOverloads || (f.isNested() && !f.needThis()))
+ if (!sc.isFromSpeculativeSemanticContext() && (!ve.hasOverloads || (f.isNested() && !f.needThis())))
+ {
+ // TODO: Refactor to use a proper interface that can keep track of causes.
f.tookAddressOf++;
+ }
+
if (f.isNested() && !f.needThis())
{
if (f.isFuncLiteralDeclaration())
@@ -12855,11 +12903,8 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag)
if (Declaration v = exp.ti.toAlias().isDeclaration())
{
- if (v.isFuncDeclaration() || v.isVarDeclaration())
- {
- return new DotVarExp(exp.loc, exp.e1, v)
- .expressionSemantic(sc);
- }
+ return new DotVarExp(exp.loc, exp.e1, v)
+ .expressionSemantic(sc);
}
return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
.expressionSemantic(sc);
@@ -12966,8 +13011,19 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
bool visitVar(VarExp e)
{
- if (!allowRef && e.var.type.isShared())
+ // https://issues.dlang.org/show_bug.cgi?id=22626
+ // Synchronized functions don't need to use core.atomic
+ // when accessing `this`.
+ if (sc.func && sc.func.isSynchronized())
+ {
+ if (e.var.isThisDeclaration())
+ return false;
+ else
+ return sharedError(e);
+ }
+ else if (!allowRef && e.var.type.isShared())
return sharedError(e);
+
return false;
}
@@ -12987,15 +13043,22 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
return check(e.e1, false);
}
+ bool visitThis(ThisExp e)
+ {
+ if (sc.func && sc.func.isSynchronized())
+ return false;
+
+ return sharedError(e);
+ }
+
bool visitDotVar(DotVarExp e)
{
+ //printf("dotvarexp = %s\n", e.toChars());
auto fd = e.var.isFuncDeclaration();
const sharedFunc = fd && fd.type.isShared;
-
- if (!allowRef && e.type.isShared() && !sharedFunc)
- return sharedError(e);
-
// Allow using `DotVarExp` within value types
+ if (!allowRef && e.type.isShared() && !sharedFunc && !(sc.func && sc.func.isSynchronized()))
+ return sharedError(e);
if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
return check(e.e1, allowRef);
@@ -13044,6 +13107,7 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
case EXP.star: return visitPtr(e.isPtrExp());
case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
case EXP.index: return visitIndex(e.isIndexExp());
+ case EXP.this_: return visitThis(e.isThisExp());
}
}
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index 0403948..d429259 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -1773,7 +1773,7 @@ extern (C++) class FuncDeclaration : Declaration
if (!tp)
continue;
- if (fparam.storageClass & (STC.lazy_ | STC.out_ | STC.ref_))
+ if (fparam.isLazy() || fparam.isReference())
{
if (!traverseIndirections(tp, t))
return false;
@@ -2528,7 +2528,7 @@ extern (C++) class FuncDeclaration : Declaration
foreach (n, p; parameterList)
{
p = p.syntaxCopy();
- if (!(p.storageClass & STC.lazy_))
+ if (!p.isLazy())
p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
p.defaultArg = null; // won't be the same with ref
result.push(p);
diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d
index 4993a9e..5142daa 100644
--- a/gcc/d/dmd/id.d
+++ b/gcc/d/dmd/id.d
@@ -311,6 +311,7 @@ immutable Msgtable[] msgtable =
{ "__ArrayPostblit" },
{ "__ArrayDtor" },
{ "_d_delThrowable" },
+ { "_d_newThrowable" },
{ "_d_assert_fail" },
{ "dup" },
{ "_aaApply" },
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 052c23d..6b5389d 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -529,7 +529,6 @@ extern (C++) abstract class Type : ASTNode
* Returns:
* An enum value of either `Covariant.yes` or a reason it's not covariant.
*/
- extern (D)
final Covariant covariant(Type t, StorageClass* pstc = null, bool cppCovariant = false)
{
version (none)
@@ -4361,7 +4360,7 @@ extern (C++) final class TypeFunction : TypeNext
{
foreach (i, fparam; parameterList)
{
- if (fparam.storageClass & STC.lazy_)
+ if (fparam.isLazy())
return true;
}
return false;
@@ -4675,7 +4674,7 @@ extern (C++) final class TypeFunction : TypeNext
Type tprm = p.type;
Type targ = arg.type;
- if (!(p.storageClass & STC.lazy_ && tprm.ty == Tvoid && targ.ty != Tvoid))
+ if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid))
{
const isRef = p.isReference();
wildmatch |= targ.deduceWild(tprm, isRef);
@@ -4718,7 +4717,7 @@ extern (C++) final class TypeFunction : TypeNext
Type targ = arg.type;
Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type;
- if (p.storageClass & STC.lazy_ && tprm.ty == Tvoid && targ.ty != Tvoid)
+ if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)
m = MATCH.convert;
else
{
@@ -6825,6 +6824,12 @@ extern (C++) final class Parameter : ASTNode
return null;
}
+ /// Returns: Whether the function parameter is lazy
+ bool isLazy() const @safe pure nothrow @nogc
+ {
+ return (this.storageClass & (STC.lazy_)) != 0;
+ }
+
/// Returns: Whether the function parameter is a reference (out / ref)
bool isReference() const @safe pure nothrow @nogc
{
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index 3565913..3e614d8 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -128,6 +128,14 @@ enum VarArgValues
};
typedef unsigned char VarArg;
+enum class Covariant
+{
+ distinct = 0, /// types are distinct
+ yes = 1, /// types are covariant
+ no = 2, /// arguments match as far as overloading goes, but types are not covariant
+ fwdref = 3, /// cannot determine covariance because of forward references
+};
+
class Type : public ASTNode
{
public:
@@ -218,6 +226,7 @@ public:
// kludge for template.isType()
DYNCAST dyncast() const override final { return DYNCAST_TYPE; }
size_t getUniqueID() const;
+ Covariant covariant(Type *, StorageClass * = NULL, bool = false);
const char *toChars() const override;
char *toPrettyChars(bool QualifyTypes = false);
static void _init();
@@ -560,6 +569,8 @@ public:
Expression *defaultArg, UserAttributeDeclaration *userAttribDecl);
Parameter *syntaxCopy();
Type *isLazyArray();
+ bool isLazy() const;
+ bool isReference() const;
// kludge for template.isType()
DYNCAST dyncast() const override { return DYNCAST_PARAMETER; }
void accept(Visitor *v) override { v->visit(this); }
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 15b7658..89f8ae3 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -1460,7 +1460,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (token.value != TOK.leftCurly)
{
- error("members of template declaration expected");
+ error("`{` expected after template parameter list, not `%s`", token.toChars());
goto Lerr;
}
decldefs = parseBlock(null);
diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h
index a163e75..b29c599 100644
--- a/gcc/d/dmd/scope.h
+++ b/gcc/d/dmd/scope.h
@@ -147,4 +147,5 @@ struct Scope
structalign_t alignment();
bool isDeprecated() const;
+ bool isFromSpeculativeSemanticContext() const;
};
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
index 0654625..a519f3b 100644
--- a/gcc/d/dmd/statement.d
+++ b/gcc/d/dmd/statement.d
@@ -761,7 +761,7 @@ extern (C++) final class ForwardingStatement : Statement
extern (D) this(const ref Loc loc, Statement statement)
{
- auto sym = new ForwardingScopeDsymbol(null);
+ auto sym = new ForwardingScopeDsymbol();
sym.symtab = new DsymbolTable();
this(loc, sym, statement);
}
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index ed47b91..06e28a4 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -502,10 +502,10 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
override void visit(ForwardingStatement ss)
{
assert(ss.sym);
- for (Scope* csc = sc; !ss.sym.forward; csc = csc.enclosing)
+ for (Scope* csc = sc; !ss.sym.parent; csc = csc.enclosing)
{
assert(csc);
- ss.sym.forward = csc.scopesym;
+ ss.sym.parent = csc.scopesym;
}
sc = sc.push(ss.sym);
sc.sbreak = ss;
@@ -2891,7 +2891,8 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
/* Void-return function can have void / noreturn typed expression
* on return statement.
*/
- const convToVoid = rs.exp.type.ty == Tvoid || rs.exp.type.ty == Tnoreturn;
+ auto texp = rs.exp.type;
+ const convToVoid = texp.ty == Tvoid || texp.ty == Tnoreturn;
if (tbret && tbret.ty == Tvoid || convToVoid)
{
@@ -2903,6 +2904,15 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
rs.exp = rs.exp.expressionSemantic(sc);
}
+ // https://issues.dlang.org/show_bug.cgi?id=23063
+ if (texp.isTypeNoreturn() && !rs.exp.isAssertExp() && !rs.exp.isThrowExp() && !rs.exp.isCallExp())
+ {
+ auto msg = new StringExp(rs.exp.loc, "Accessed expression of type `noreturn`");
+ msg.type = Type.tstring;
+ rs.exp = new AssertExp(rs.loc, IntegerExp.literal!0, msg);
+ rs.exp.type = texp;
+ }
+
/* Replace:
* return exp;
* with:
@@ -3698,6 +3708,13 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
if (oss.tok != TOK.onScopeExit)
{
+ // https://issues.dlang.org/show_bug.cgi?id=23159
+ if (!global.params.useExceptions)
+ {
+ oss.error("`%s` cannot be used with -betterC", Token.toChars(oss.tok));
+ return setError();
+ }
+
// scope(success) and scope(failure) are rewritten to try-catch(-finally) statement,
// so the generated catch block cannot be placed in finally block.
// See also Catch::semantic.
@@ -4312,7 +4329,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState
if (!skip && dim == 2)
{
// Declare key
- if (p.storageClass & (STC.out_ | STC.ref_ | STC.lazy_))
+ if (p.isReference() || p.isLazy())
{
fs.error("no storage class for key `%s`", p.ident.toChars());
return returnEarly();
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index 4c9ca28f..31ecbd2 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -64,48 +64,6 @@ import dmd.sideeffect;
import dmd.target;
import dmd.tokens;
-/**************************
- * This evaluates exp while setting length to be the number
- * of elements in the tuple t.
- */
-private Expression semanticLength(Scope* sc, Type t, Expression exp)
-{
- if (auto tt = t.isTypeTuple())
- {
- ScopeDsymbol sym = new ArrayScopeSymbol(sc, tt);
- sym.parent = sc.scopesym;
- sc = sc.push(sym);
- sc = sc.startCTFE();
- exp = exp.expressionSemantic(sc);
- exp = resolveProperties(sc, exp);
- sc = sc.endCTFE();
- sc.pop();
- }
- else
- {
- sc = sc.startCTFE();
- exp = exp.expressionSemantic(sc);
- exp = resolveProperties(sc, exp);
- sc = sc.endCTFE();
- }
- return exp;
-}
-
-private Expression semanticLength(Scope* sc, TupleDeclaration tup, Expression exp)
-{
- ScopeDsymbol sym = new ArrayScopeSymbol(sc, tup);
- sym.parent = sc.scopesym;
-
- sc = sc.push(sym);
- sc = sc.startCTFE();
- exp = exp.expressionSemantic(sc);
- exp = resolveProperties(sc, exp);
- sc = sc.endCTFE();
- sc.pop();
-
- return exp;
-}
-
/*************************************
* Resolve a tuple index, `s[oindex]`, by figuring out what `s[oindex]` represents.
* Setting one of pe/pt/ps.
@@ -452,101 +410,6 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
pt = t.merge();
}
-/************************************
- * Transitively search a type for all function types.
- * If any function types with parameters are found that have parameter identifiers
- * or default arguments, remove those and create a new type stripped of those.
- * This is used to determine the "canonical" version of a type which is useful for
- * comparisons.
- * Params:
- * t = type to scan
- * Returns:
- * `t` if no parameter identifiers or default arguments found, otherwise a new type that is
- * the same as t but with no parameter identifiers or default arguments.
- */
-private Type stripDefaultArgs(Type t)
-{
- static Parameters* stripParams(Parameters* parameters)
- {
- static Parameter stripParameter(Parameter p)
- {
- Type t = stripDefaultArgs(p.type);
- return (t != p.type || p.defaultArg || p.ident || p.userAttribDecl)
- ? new Parameter(p.storageClass, t, null, null, null)
- : null;
- }
-
- if (parameters)
- {
- foreach (i, p; *parameters)
- {
- Parameter ps = stripParameter(p);
- if (ps)
- {
- // Replace params with a copy we can modify
- Parameters* nparams = new Parameters(parameters.dim);
-
- foreach (j, ref np; *nparams)
- {
- Parameter pj = (*parameters)[j];
- if (j < i)
- np = pj;
- else if (j == i)
- np = ps;
- else
- {
- Parameter nps = stripParameter(pj);
- np = nps ? nps : pj;
- }
- }
- return nparams;
- }
- }
- }
- return parameters;
- }
-
- if (t is null)
- return t;
-
- if (auto tf = t.isTypeFunction())
- {
- Type tret = stripDefaultArgs(tf.next);
- Parameters* params = stripParams(tf.parameterList.parameters);
- if (tret == tf.next && params == tf.parameterList.parameters)
- return t;
- TypeFunction tr = tf.copy().isTypeFunction();
- tr.parameterList.parameters = params;
- tr.next = tret;
- //printf("strip %s\n <- %s\n", tr.toChars(), t.toChars());
- return tr;
- }
- else if (auto tt = t.isTypeTuple())
- {
- Parameters* args = stripParams(tt.arguments);
- if (args == tt.arguments)
- return t;
- TypeTuple tr = t.copy().isTypeTuple();
- tr.arguments = args;
- return tr;
- }
- else if (t.ty == Tenum)
- {
- // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
- return t;
- }
- else
- {
- Type tn = t.nextOf();
- Type n = stripDefaultArgs(tn);
- if (n == tn)
- return t;
- TypeNext tr = cast(TypeNext)t.copy();
- tr.next = n;
- return tr;
- }
-}
-
/******************************************
* We've mistakenly parsed `t` as a type.
* Redo `t` as an Expression only if there are no type modifiers.
@@ -603,53 +466,6 @@ Expression typeToExpression(Type t)
}
}
-/* Helper function for `typeToExpression`. Contains common code
- * for TypeQualified derived classes.
- */
-Expression typeToExpressionHelper(TypeQualified t, Expression e, size_t i = 0)
-{
- //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars());
- foreach (id; t.idents[i .. t.idents.dim])
- {
- //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
-
- final switch (id.dyncast())
- {
- // ... '. ident'
- case DYNCAST.identifier:
- e = new DotIdExp(e.loc, e, cast(Identifier)id);
- break;
-
- // ... '. name!(tiargs)'
- case DYNCAST.dsymbol:
- auto ti = (cast(Dsymbol)id).isTemplateInstance();
- assert(ti);
- e = new DotTemplateInstanceExp(e.loc, e, ti.name, ti.tiargs);
- break;
-
- // ... '[type]'
- case DYNCAST.type: // https://issues.dlang.org/show_bug.cgi?id=1215
- e = new ArrayExp(t.loc, e, new TypeExp(t.loc, cast(Type)id));
- break;
-
- // ... '[expr]'
- case DYNCAST.expression: // https://issues.dlang.org/show_bug.cgi?id=1215
- e = new ArrayExp(t.loc, e, cast(Expression)id);
- break;
-
- case DYNCAST.object:
- case DYNCAST.tuple:
- case DYNCAST.parameter:
- case DYNCAST.statement:
- case DYNCAST.condition:
- case DYNCAST.templateparameter:
- case DYNCAST.initializer:
- assert(0);
- }
- }
- return e;
-}
-
/******************************************
* Perform semantic analysis on a type.
* Params:
@@ -1431,7 +1247,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
errors = true;
}
}
- else if (!(fparam.storageClass & STC.lazy_) && t.ty == Tvoid)
+ else if (!fparam.isLazy() && t.ty == Tvoid)
{
.error(loc, "cannot have parameter of type `%s`", fparam.type.toChars());
errors = true;
@@ -2157,47 +1973,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
}
}
-/******************************************
- * Compile the MixinType, returning the type or expression AST.
- *
- * Doesn't run semantic() on the returned object.
- * Params:
- * tm = mixin to compile as a type or expression
- * loc = location for error messages
- * sc = context
- * Return:
- * null if error, else RootObject AST as parsed
- */
-RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc)
-{
- OutBuffer buf;
- if (expressionsToString(buf, sc, tm.exps))
- return null;
-
- const errors = global.errors;
- const len = buf.length;
- buf.writeByte(0);
- const str = buf.extractSlice()[0 .. len];
- scope p = new Parser!ASTCodegen(loc, sc._module, str, false);
- p.nextToken();
- //printf("p.loc.linnum = %d\n", p.loc.linnum);
-
- auto o = p.parseTypeOrAssignExp(TOK.endOfFile);
- if (errors != global.errors)
- {
- assert(global.errors != errors); // should have caught all these cases
- return null;
- }
- if (p.token.value != TOK.endOfFile)
- {
- .error(loc, "incomplete mixin type `%s`", str.ptr);
- return null;
- }
-
- return o;
-}
-
-
/************************************
* If an identical type to `type` is in `type.stringtable`, return
* the latter one. Otherwise, add it to `type.stringtable`.
@@ -3243,6 +3018,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
{
pt = mt.obj.isType();
ps = mt.obj.isDsymbol();
+ pe = mt.obj.isExpression();
return;
}
@@ -3310,7 +3086,10 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
case EXP.overloadSet:
mt.obj = e.isOverExp().type;
break;
+ case EXP.error:
+ break;
default:
+ mt.obj = e;
break;
}
}
@@ -3318,14 +3097,19 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
if (mt.obj)
{
if (auto t = mt.obj.isType())
- returnType(t.addMod(mt.mod));
+ {
+ t = t.addMod(mt.mod);
+ mt.obj = t;
+ returnType(t);
+ }
else if (auto s = mt.obj.isDsymbol())
returnSymbol(s);
- else
- assert(0);
+ else if (auto e = mt.obj.isExpression())
+ returnExp(e);
}
else
{
+ assert(global.errors);
mt.obj = Type.terror;
return returnError();
}
@@ -4817,6 +4601,193 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi
}
}
+/******************************* Private *****************************************/
+
+private:
+
+/* Helper function for `typeToExpression`. Contains common code
+ * for TypeQualified derived classes.
+ */
+Expression typeToExpressionHelper(TypeQualified t, Expression e, size_t i = 0)
+{
+ //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars());
+ foreach (id; t.idents[i .. t.idents.dim])
+ {
+ //printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
+
+ final switch (id.dyncast())
+ {
+ // ... '. ident'
+ case DYNCAST.identifier:
+ e = new DotIdExp(e.loc, e, cast(Identifier)id);
+ break;
+
+ // ... '. name!(tiargs)'
+ case DYNCAST.dsymbol:
+ auto ti = (cast(Dsymbol)id).isTemplateInstance();
+ assert(ti);
+ e = new DotTemplateInstanceExp(e.loc, e, ti.name, ti.tiargs);
+ break;
+
+ // ... '[type]'
+ case DYNCAST.type: // https://issues.dlang.org/show_bug.cgi?id=1215
+ e = new ArrayExp(t.loc, e, new TypeExp(t.loc, cast(Type)id));
+ break;
+
+ // ... '[expr]'
+ case DYNCAST.expression: // https://issues.dlang.org/show_bug.cgi?id=1215
+ e = new ArrayExp(t.loc, e, cast(Expression)id);
+ break;
+
+ case DYNCAST.object:
+ case DYNCAST.tuple:
+ case DYNCAST.parameter:
+ case DYNCAST.statement:
+ case DYNCAST.condition:
+ case DYNCAST.templateparameter:
+ case DYNCAST.initializer:
+ assert(0);
+ }
+ }
+ return e;
+}
+
+/**************************
+ * This evaluates exp while setting length to be the number
+ * of elements in the tuple t.
+ */
+Expression semanticLength(Scope* sc, Type t, Expression exp)
+{
+ if (auto tt = t.isTypeTuple())
+ {
+ ScopeDsymbol sym = new ArrayScopeSymbol(sc, tt);
+ sym.parent = sc.scopesym;
+ sc = sc.push(sym);
+ sc = sc.startCTFE();
+ exp = exp.expressionSemantic(sc);
+ exp = resolveProperties(sc, exp);
+ sc = sc.endCTFE();
+ sc.pop();
+ }
+ else
+ {
+ sc = sc.startCTFE();
+ exp = exp.expressionSemantic(sc);
+ exp = resolveProperties(sc, exp);
+ sc = sc.endCTFE();
+ }
+ return exp;
+}
+
+Expression semanticLength(Scope* sc, TupleDeclaration tup, Expression exp)
+{
+ ScopeDsymbol sym = new ArrayScopeSymbol(sc, tup);
+ sym.parent = sc.scopesym;
+
+ sc = sc.push(sym);
+ sc = sc.startCTFE();
+ exp = exp.expressionSemantic(sc);
+ exp = resolveProperties(sc, exp);
+ sc = sc.endCTFE();
+ sc.pop();
+
+ return exp;
+}
+
+/************************************
+ * Transitively search a type for all function types.
+ * If any function types with parameters are found that have parameter identifiers
+ * or default arguments, remove those and create a new type stripped of those.
+ * This is used to determine the "canonical" version of a type which is useful for
+ * comparisons.
+ * Params:
+ * t = type to scan
+ * Returns:
+ * `t` if no parameter identifiers or default arguments found, otherwise a new type that is
+ * the same as t but with no parameter identifiers or default arguments.
+ */
+Type stripDefaultArgs(Type t)
+{
+ static Parameters* stripParams(Parameters* parameters)
+ {
+ static Parameter stripParameter(Parameter p)
+ {
+ Type t = stripDefaultArgs(p.type);
+ return (t != p.type || p.defaultArg || p.ident || p.userAttribDecl)
+ ? new Parameter(p.storageClass, t, null, null, null)
+ : null;
+ }
+
+ if (parameters)
+ {
+ foreach (i, p; *parameters)
+ {
+ Parameter ps = stripParameter(p);
+ if (ps)
+ {
+ // Replace params with a copy we can modify
+ Parameters* nparams = new Parameters(parameters.dim);
+
+ foreach (j, ref np; *nparams)
+ {
+ Parameter pj = (*parameters)[j];
+ if (j < i)
+ np = pj;
+ else if (j == i)
+ np = ps;
+ else
+ {
+ Parameter nps = stripParameter(pj);
+ np = nps ? nps : pj;
+ }
+ }
+ return nparams;
+ }
+ }
+ }
+ return parameters;
+ }
+
+ if (t is null)
+ return t;
+
+ if (auto tf = t.isTypeFunction())
+ {
+ Type tret = stripDefaultArgs(tf.next);
+ Parameters* params = stripParams(tf.parameterList.parameters);
+ if (tret == tf.next && params == tf.parameterList.parameters)
+ return t;
+ TypeFunction tr = tf.copy().isTypeFunction();
+ tr.parameterList.parameters = params;
+ tr.next = tret;
+ //printf("strip %s\n <- %s\n", tr.toChars(), t.toChars());
+ return tr;
+ }
+ else if (auto tt = t.isTypeTuple())
+ {
+ Parameters* args = stripParams(tt.arguments);
+ if (args == tt.arguments)
+ return t;
+ TypeTuple tr = t.copy().isTypeTuple();
+ tr.arguments = args;
+ return tr;
+ }
+ else if (t.ty == Tenum)
+ {
+ // TypeEnum::nextOf() may be != NULL, but it's not necessary here.
+ return t;
+ }
+ else
+ {
+ Type tn = t.nextOf();
+ Type n = stripDefaultArgs(tn);
+ if (n == tn)
+ return t;
+ TypeNext tr = cast(TypeNext)t.copy();
+ tr.next = n;
+ return tr;
+ }
+}
/******************************
* Get the value of the .max/.min property of `ed` as an Expression.
@@ -4829,7 +4800,7 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi
* Returns:
* corresponding value of .max/.min
*/
-private Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id)
+Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id)
{
//printf("EnumDeclaration::getMaxValue()\n");
@@ -4935,3 +4906,43 @@ private Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identif
}
return ed.errors ? errorReturn() : pvalToResult(*pval, loc);
}
+
+/******************************************
+ * Compile the MixinType, returning the type or expression AST.
+ *
+ * Doesn't run semantic() on the returned object.
+ * Params:
+ * tm = mixin to compile as a type or expression
+ * loc = location for error messages
+ * sc = context
+ * Return:
+ * null if error, else RootObject AST as parsed
+ */
+RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc)
+{
+ OutBuffer buf;
+ if (expressionsToString(buf, sc, tm.exps))
+ return null;
+
+ const errors = global.errors;
+ const len = buf.length;
+ buf.writeByte(0);
+ const str = buf.extractSlice()[0 .. len];
+ scope p = new Parser!ASTCodegen(loc, sc._module, str, false);
+ p.nextToken();
+ //printf("p.loc.linnum = %d\n", p.loc.linnum);
+
+ auto o = p.parseTypeOrAssignExp(TOK.endOfFile);
+ if (errors != global.errors)
+ {
+ assert(global.errors != errors); // should have caught all these cases
+ return null;
+ }
+ if (p.token.value != TOK.endOfFile)
+ {
+ .error(loc, "incomplete mixin type `%s`", str.ptr);
+ return null;
+ }
+
+ return o;
+}
diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d
index 21447ae..b701be3 100644
--- a/gcc/d/dmd/typinf.d
+++ b/gcc/d/dmd/typinf.d
@@ -18,6 +18,7 @@ import dmd.dscope;
import dmd.dclass;
import dmd.dstruct;
import dmd.errors;
+import dmd.expression;
import dmd.globals;
import dmd.gluelayer;
import dmd.mtype;
@@ -28,11 +29,12 @@ import core.stdc.stdio;
* Generates the `TypeInfo` object associated with `torig` if it
* hasn't already been generated
* Params:
+ * e = if not null, then expression for pretty-printing errors
* loc = the location for reporting line numbers in errors
* torig = the type to generate the `TypeInfo` object for
* sc = the scope
*/
-extern (C++) void genTypeInfo(const ref Loc loc, Type torig, Scope* sc)
+extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc)
{
// printf("genTypeInfo() %s\n", torig.toChars());
@@ -43,7 +45,10 @@ extern (C++) void genTypeInfo(const ref Loc loc, Type torig, Scope* sc)
{
if (!global.params.useTypeInfo)
{
- .error(loc, "`TypeInfo` cannot be used with -betterC");
+ if (e)
+ .error(loc, "expression `%s` uses the GC and cannot be used with switch `-betterC`", e.toChars());
+ else
+ .error(loc, "`TypeInfo` cannot be used with -betterC");
fatal();
}
}
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index 7edcbc4..179f9a5 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -2238,13 +2238,17 @@ public:
new_call = build_nop (type, build_address (var));
setup_exp = modify_expr (var, aggregate_initializer_decl (cd));
}
+ else if (global.params.ehnogc && e->thrownew)
+ {
+ /* Allocating a `@nogc' Exception with `_d_newThrowable' has already
+ been handled by the front-end. */
+ gcc_unreachable ();
+ }
else
{
/* Generate: _d_newclass() */
tree arg = build_address (get_classinfo_decl (cd));
- libcall_fn libcall = (global.params.ehnogc && e->thrownew)
- ? LIBCALL_NEWTHROW : LIBCALL_NEWCLASS;
- new_call = build_libcall (libcall, tb, 1, arg);
+ new_call = build_libcall (LIBCALL_NEWCLASS, tb, 1, arg);
}
/* Set the context pointer for nested classes. */
diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def
index 1ad0369..459a283 100644
--- a/gcc/d/runtime.def
+++ b/gcc/d/runtime.def
@@ -61,7 +61,6 @@ DEF_D_RUNTIME (ARRAYBOUNDS_INDEXP, "_d_arraybounds_indexp", RT(VOID),
/* Used when calling new on a class. */
DEF_D_RUNTIME (NEWCLASS, "_d_newclass", RT(OBJECT), P1(CONST_CLASSINFO), 0)
-DEF_D_RUNTIME (NEWTHROW, "_d_newThrowable", RT(OBJECT), P1(CONST_CLASSINFO), 0)
/* Used when calling delete on a stack-allocated class or interface. */
DEF_D_RUNTIME (CALLFINALIZER, "_d_callfinalizer", RT(VOID), P1(VOIDPTR), 0)
diff --git a/gcc/testsuite/gdc.test/compilable/imports/defines.c b/gcc/testsuite/gdc.test/compilable/imports/defines.c
new file mode 100644
index 0000000..6bd0736
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/defines.c
@@ -0,0 +1,28 @@
+/* */
+
+#define CC 'c'
+_Static_assert(CC == 'c', "1");
+
+#define I32 3
+_Static_assert(I32 == 3, "3");
+
+#define U32 4U
+_Static_assert(U32 == 4U, "4");
+
+#define I64 5L
+_Static_assert(I64 == 5U, "5");
+
+#define U64 6UL
+_Static_assert(U64 == 6UL, "6");
+
+#define F32 7.0f
+_Static_assert(F32 == 7.0f, "7");
+
+#define F64 8.0f
+_Static_assert(F64 == 8.0, "8");
+
+#define F80 9.0f
+_Static_assert(F80 == 9.0L, "9");
+
+#define SSS "hello"
+_Static_assert(SSS[0] == 'h', "10");
diff --git a/gcc/testsuite/gdc.test/compilable/nogc.d b/gcc/testsuite/gdc.test/compilable/nogc.d
index 2751801..6ce5094 100644
--- a/gcc/testsuite/gdc.test/compilable/nogc.d
+++ b/gcc/testsuite/gdc.test/compilable/nogc.d
@@ -109,3 +109,12 @@ auto foo13550() @nogc
}
return &bar;
}
+
+// https://issues.dlang.org/show_bug.cgi?id=19285
+
+void f(bool cond, string s) @nogc {
+ auto inner() { return s; }
+ alias Unused1 = typeof(inner); // OK
+ alias Unused2 = typeof(&inner); // (Does not) INFERS GC (anymore)
+ enum Unused3 = __traits(compiles , &inner);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test22626.d b/gcc/testsuite/gdc.test/compilable/test22626.d
new file mode 100644
index 0000000..5f72eb6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22626.d
@@ -0,0 +1,23 @@
+// https://issues.dlang.org/show_bug.cgi?id=22626
+// REQUIRED_ARGS: -preview=nosharedaccess
+
+shared int k;
+
+class Oops
+{
+ shared int a;
+ shared int* pa;
+ synchronized void oops()
+ {
+ // this should compile since the function is synchronized
+ // and `a` is accessed through `this`.
+ a = 2;
+
+ // this shouldn't compile because synchronized guards
+ // only accesses to the first level of dereferencing
+ static assert (!__traits(compiles, *pa = 2));
+
+ // this shouldn't compile `k` is a field of class `Oops`
+ static assert (!__traits(compiles, k = 2));
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test23076.d b/gcc/testsuite/gdc.test/compilable/test23076.d
new file mode 100644
index 0000000..10a0c2f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test23076.d
@@ -0,0 +1,38 @@
+/* REQUIRED_ARGS: -O -inline
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=23076
+
+struct S
+{
+ int depthLow = 0;
+ int depthHigh = 30000;
+
+ void fun(int* pixels)
+ {
+ float b = depthLow;
+ int depthA = cast(int)(b);
+ int depthB = cast(short)(cast(float)depthHigh * cast(float)depthLow);
+ pixels[depthA] = depthB;
+ }
+}
+
+/**********************/
+
+float mul3(float a, float b, float t)
+{
+ return t * b * a;
+}
+
+class A
+{
+ ushort depthLow = 0;
+ ushort depthHigh = 30000;
+
+ void fun(short* pixels)
+ {
+ short depthA = (cast(short)(mul3(depthHigh, depthLow, 0)));
+ short depthB = (cast(short)(mul3(depthLow, depthHigh, 0)));
+ pixels[depthA] = depthB;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test23142.d b/gcc/testsuite/gdc.test/compilable/test23142.d
new file mode 100644
index 0000000..28bb691
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test23142.d
@@ -0,0 +1,19 @@
+// https://issues.dlang.org/show_bug.cgi?id=23142
+
+struct Foo
+{
+ int x;
+
+scope:
+ void func()
+ {
+ }
+
+ unittest
+ {
+ }
+
+ static void func2()
+ {
+ }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test23174.d b/gcc/testsuite/gdc.test/compilable/test23174.d
new file mode 100644
index 0000000..9047fd7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test23174.d
@@ -0,0 +1,58 @@
+// https://issues.dlang.org/show_bug.cgi?id=23174
+
+alias AliasSeq(T...) = T;
+
+template staticMap(alias fun, args...)
+{
+ alias staticMap = AliasSeq!();
+ static foreach(arg; args)
+ staticMap = AliasSeq!(staticMap, fun!arg);
+}
+
+template Filter(alias pred, args...)
+{
+ alias Filter = AliasSeq!();
+ static foreach (arg; args)
+ static if (pred!arg)
+ Filter = AliasSeq!(Filter, arg);
+}
+
+struct Fields(T)
+{
+ private static alias toField(alias e) = Field!(__traits(identifier, e));
+ alias fields = staticMap!(toField, T.tupleof);
+
+ static alias map(alias F) = staticMap!(F, fields);
+ static alias filter(alias pred) = Filter!(pred, fields);
+}
+
+struct Field(string n)
+{
+ enum name = n;
+}
+
+struct Foo
+{
+ int a;
+}
+
+void test23174()
+{
+ Foo value;
+
+ enum toName(alias e) = e.name;
+ enum pred(alias e) = true;
+
+ alias a = Fields!(Foo).filter!(pred); // works
+ static assert(is(a == AliasSeq!(Field!"a")));
+
+ alias b = Fields!(Foo).map!(toName); // works
+ static assert(b == AliasSeq!("a"));
+
+ alias c = Fields!(Foo).init.filter!(pred); // works
+ static assert(is(c == AliasSeq!(Field!"a")));
+
+ // OK <- Error: alias `d` cannot alias an expression `Fields().tuple("a")`
+ alias d = Fields!(Foo).init.map!(toName);
+ static assert(d == AliasSeq!("a"));
+}
diff --git a/gcc/testsuite/gdc.test/compilable/testdefines.d b/gcc/testsuite/gdc.test/compilable/testdefines.d
new file mode 100644
index 0000000..4507266
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/testdefines.d
@@ -0,0 +1,14 @@
+// EXTRA_FILES: imports/defines.c
+import imports.defines;
+
+static assert(CC == 'c');
+static assert(I32 == 3);
+static assert(U32 == 4);
+static assert(I64 == 5);
+static assert(U64 == 6);
+
+static assert(F32 == 7.0f);
+static assert(F64 == 8.0);
+static assert(F80 == 9.0L);
+
+static assert(SSS == "hello");
diff --git a/gcc/testsuite/gdc.test/compilable/testdip1008.d b/gcc/testsuite/gdc.test/compilable/testdip1008.d
index 5e024fe..54d404c 100644
--- a/gcc/testsuite/gdc.test/compilable/testdip1008.d
+++ b/gcc/testsuite/gdc.test/compilable/testdip1008.d
@@ -13,9 +13,28 @@ int bar()
}
}
+void throwQualifiers() @safe @nogc pure
+{
+ throw new Exception("baz");
+}
+
+bool testThrowQualifiers()
+{
+ try
+ {
+ throwQualifiers();
+ } catch (Exception e)
+ {
+ return true;
+ }
+
+ return false;
+}
void foo()
{
enum r = bar();
static assert(r == 7);
+
+ static assert(testThrowQualifiers());
}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/mixin_template.d b/gcc/testsuite/gdc.test/fail_compilation/mixin_template.d
new file mode 100644
index 0000000..b088da8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/mixin_template.d
@@ -0,0 +1,10 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/mixin_template.d(10): Error: mixin `mixin_template.f!1` - `f` is a function, not a template
+---
+*/
+string f() {
+ return "int i;";
+}
+mixin f!1;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/noreturn.d b/gcc/testsuite/gdc.test/fail_compilation/noreturn.d
index 696081a..d47d449 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/noreturn.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/noreturn.d
@@ -118,3 +118,21 @@ enum forceInClassRef = inClassRef();
*/
enum throwEnum = throw new Exception("");
+
+
+/*
+https://issues.dlang.org/show_bug.cgi?id=23063
+
+TEST_OUTPUT:
+---
+fail_compilation/noreturn.d(135): Error: `"Accessed expression of type `noreturn`"`
+fail_compilation/noreturn.d(138): called from here: `func()`
+---
+*/
+noreturn func()
+{
+ noreturn a;
+ return a;
+}
+
+enum f = func();
diff --git a/gcc/testsuite/gdc.test/fail_compilation/template_decl.d b/gcc/testsuite/gdc.test/fail_compilation/template_decl.d
new file mode 100644
index 0000000..d986dd6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/template_decl.d
@@ -0,0 +1,9 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/template_decl.d(8): Error: `{` expected after template parameter list, not `(`
+fail_compilation/template_decl.d(8): Error: declaration expected, not `(`
+---
+*/
+template b(alias d)() {
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21477.d b/gcc/testsuite/gdc.test/fail_compilation/test21477.d
new file mode 100644
index 0000000..c9c7c7f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21477.d
@@ -0,0 +1,16 @@
+/* REQUIRED_ARGS: -betterC
+TEST_OUTPUT:
+---
+fail_compilation/test21477.d(103): Error: expression `[1]` uses the GC and cannot be used with switch `-betterC`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=21477
+
+#line 100
+
+int test()
+{
+ int[] foo = [1];
+ return 0;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23159.d b/gcc/testsuite/gdc.test/fail_compilation/test23159.d
new file mode 100644
index 0000000..cdafc61
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test23159.d
@@ -0,0 +1,22 @@
+// https://issues.dlang.org/show_bug.cgi?id=23159
+
+// REQUIRED_ARGS: -betterC
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test23159.d(14): Error: `scope(failure)` cannot be used with -betterC
+fail_compilation/test23159.d(18): Error: `scope(success)` cannot be used with -betterC
+---
+*/
+
+void main()
+{
+ scope(failure)
+ {
+ int a;
+ }
+ scope(success)
+ {
+ int a;
+ }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/traits.d b/gcc/testsuite/gdc.test/fail_compilation/traits.d
index 8c16afe..21f3f57 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/traits.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/traits.d
@@ -116,3 +116,21 @@ pragma(msg, __traits(hasCopyConstructor));
pragma(msg, __traits(hasCopyConstructor, S()));
pragma(msg, __traits(hasPostblit));
pragma(msg, __traits(hasPostblit, S()));
+
+/********************************************
+https://issues.dlang.org/show_bug.cgi?id=23178
+
+TEST_OUTPUT:
+---
+fail_compilation/traits.d(701): Error: alias `traits.a` cannot alias an expression `true`
+fail_compilation/traits.d(702): Error: alias `traits.b` cannot alias an expression `false`
+fail_compilation/traits.d(703): Error: alias `traits.c` cannot alias an expression `"Object"`
+fail_compilation/traits.d(704): while evaluating `pragma(msg, a)`
+---
+*/
+#line 700
+
+alias a = __traits(compiles, 1);
+alias b = __traits(isIntegral, 1.1);
+alias c = __traits(identifier, Object);
+pragma(msg, a, b, c);