diff options
Diffstat (limited to 'gcc')
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); |