diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2023-07-09 22:08:36 +0200 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2023-07-09 22:08:36 +0200 |
commit | 3b007164b3ef114c3c86c42ca2455f8f2696fb0d (patch) | |
tree | 340037c67d4a2a57774103d54fa103390611f6e5 /gcc | |
parent | d6c1d7c4009bfe759719675ce3bc03ca503b9bf4 (diff) | |
download | gcc-3b007164b3ef114c3c86c42ca2455f8f2696fb0d.zip gcc-3b007164b3ef114c3c86c42ca2455f8f2696fb0d.tar.gz gcc-3b007164b3ef114c3c86c42ca2455f8f2696fb0d.tar.bz2 |
d: Merge upstream dmd, druntime 28a3b24c2e, phobos 8ab95ded5.
D front-end changes:
- Import dmd v2.104.0-beta.1.
- Better error message when attribute inference fails down the
call stack.
- Using `;' as an empty statement has been turned into an error.
- Using `in' parameters with non- `extern(D)' or `extern(C++)'
functions is deprecated.
- `in ref' on parameters has been deprecated in favor of
`-preview=in'.
- Throwing `immutable', `const', `inout', and `shared' qualified
objects is now deprecated.
- User Defined Attributes now parse Template Arguments.
D runtime changes:
- Import druntime v2.104.0-beta.1.
Phobos changes:
- Import phobos v2.104.0-beta.1.
- Better static assert messages when instantiating
`std.algorithm.comparison.clamp' with wrong inputs.
- `std.typecons.Rebindable' now supports all types.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd 28a3b24c2e.
* dmd/VERSION: Bump version to v2.104.0-beta.1.
* d-codegen.cc (build_bounds_slice_condition): Update for new
front-end interface.
* d-lang.cc (d_init_options): Likewise.
(d_handle_option): Likewise.
(d_post_options): Initialize global.compileEnv.
* expr.cc (ExprVisitor::visit (CatExp *)): Replace code generation
with new front-end lowering.
(ExprVisitor::visit (LoweredAssignExp *)): New method.
(ExprVisitor::visit (StructLiteralExp *)): Don't generate static
initializer symbols for structs defined in C sources.
* runtime.def (ARRAYCATT): Remove.
(ARRAYCATNTX): Remove.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime 28a3b24c2e.
* src/MERGE: Merge upstream phobos 8ab95ded5.
gcc/testsuite/ChangeLog:
* gdc.dg/rtti1.d: Move array concat testcase to ...
* gdc.dg/nogc1.d: ... here. New test.
Diffstat (limited to 'gcc')
153 files changed, 4297 insertions, 2259 deletions
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 9bae060..689d1c5 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -1986,14 +1986,14 @@ build_bounds_slice_condition (SliceExp *se, tree lower, tree upper, tree length) tree condition = NULL_TREE; /* Enforces that `upper <= length`. */ - if (!se->upperIsInBounds && length != NULL_TREE) + if (!se->upperIsInBounds () && length != NULL_TREE) condition = fold_build2 (GT_EXPR, d_bool_type, upper, length); else length = integer_zero_node; /* Enforces that `lower <= upper`. No need to check `lower <= length` as we've already ensured that `upper <= length`. */ - if (!se->lowerIsLessThanUpper) + if (!se->lowerIsLessThanUpper ()) { tree lwr_cond = fold_build2 (GT_EXPR, d_bool_type, lower, upper); diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 235e22a..7cb86bf 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -293,7 +293,7 @@ d_init_options (unsigned int, cl_decoded_option *decoded_options) /* Set default values. */ global._init (); - global.vendor = lang_hooks.name; + global.compileEnv.vendor = lang_hooks.name; global.params.argv0 = xstrdup (decoded_options[0].arg); global.params.errorLimit = flag_max_errors; @@ -562,7 +562,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.useDIP1021 = value; global.params.bitfields = value; global.params.dtorFields = FeatureState::enabled; - global.params.fieldwise = value; + global.params.fieldwise = FeatureState::enabled; global.params.fixAliasThis = value; global.params.previewIn = value; global.params.fix16997 = value; @@ -594,7 +594,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_fpreview_fieldwise: - global.params.fieldwise = value; + global.params.fieldwise = FeatureState::enabled; break; case OPT_fpreview_fixaliasthis: @@ -934,6 +934,12 @@ d_post_options (const char ** fn) global.params.obj = !flag_syntax_only; + /* The front-end parser only has access to `compileEnv', synchronize its + fields with params. */ + global.compileEnv.previewIn = global.params.previewIn; + global.compileEnv.ddocOutput = global.params.ddoc.doOutput; + global.compileEnv.shortenedMethods = global.params.shortenedMethods; + /* Add in versions given on the command line. */ if (global.params.versionids) { diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 1205cd9..95ea67d 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -a45f4e9f43e9fdbf0b666175e5e66b1ce4f561f6 +28a3b24c2e45de39cd3df528142fd06b6456e8fd 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/README.md b/gcc/d/dmd/README.md index cecd008..57f56f3 100644 --- a/gcc/d/dmd/README.md +++ b/gcc/d/dmd/README.md @@ -19,7 +19,7 @@ this license for that file. | Folder | Purpose | |--------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | [dmd/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd) | The dmd driver and front-end | -| [dmd/backend/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/backend) | Code generation for x86 or x86-64. Shared by the [Digital Mars C compiler](https://github.com/DigitalMars/Compiler/), but not [LDC](https://github.com/ldc-developers/ldc) or [GDC](https://gdcproject.org/). | +| [dmd/backend/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/backend) | Code generation for x86 or x86-64. Based on [DMC](https://github.com/DigitalMars/Compiler/)'s backend, but not kept in sync anymore. Not used by [LDC](https://github.com/ldc-developers/ldc) or [GDC](https://gdcproject.org/). | | [dmd/common/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/common) | Code shared by the front-end and back-end | | [dmd/root/](https://github.com/dlang/dmd/tree/master/compiler/src/dmd/root) | Meant as a portable utility library, but ["it wasn't very good and the only project left using it is dmd"](https://github.com/dlang/dmd/pull/9844#issuecomment-498479516). | diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index 8316aaf..7cf9127 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.103.1 +v2.104.0-beta.1 diff --git a/gcc/d/dmd/aliasthis.d b/gcc/d/dmd/aliasthis.d index ef839fa..ce38459 100644 --- a/gcc/d/dmd/aliasthis.d +++ b/gcc/d/dmd/aliasthis.d @@ -78,7 +78,7 @@ extern (C++) final class AliasThis : Dsymbol * Params: * sc = context * e = expression forming the `this` - * gag = if true do not print errors, return null instead + * gag = do not print errors, return `null` instead * findOnly = don't do further processing like resolving properties, * i.e. just return plain dotExp() result. * Returns: @@ -93,7 +93,7 @@ Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool find { Loc loc = e.loc; Type tthis = (e.op == EXP.type ? e.type : null); - const flags = DotExpFlag.noAliasThis | (gag ? DotExpFlag.gag : 0); + const flags = cast(DotExpFlag) (DotExpFlag.noAliasThis | (gag * DotExpFlag.gag)); uint olderrors = gag ? global.startGagging() : 0; e = dotExp(ad.type, sc, e, ad.aliasthis.ident, flags); if (!e || findOnly) @@ -200,15 +200,29 @@ bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc) /************************************** * Check and set 'att' if 't' is a recursive 'alias this' type + * + * The goal is to prevent endless loops when there is a cycle in the alias this chain. + * Since there is no multiple `alias this`, the chain either ends in a leaf, + * or it loops back on itself as some point. + * + * Example: S0 -> (S1 -> S2 -> S3 -> S1) + * + * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried. + * `S1` is a recursive alias this type, but since `att` is initialized to `null`, + * this still returns `false`, but `att1` is set to `S1`. + * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again, + * we notice `att == t`, so we're back at the start of the loop, and this returns `true`. + * * Params: - * att = type reference used to detect recursion - * t = 'alias this' type + * att = type reference used to detect recursion. Should be initialized to `null`. + * t = type of 'alias this' rewrite to attempt * * Returns: - * Whether the 'alias this' is recursive or not + * `false` if the rewrite is safe, `true` if it would loop back around */ bool isRecursiveAliasThis(ref Type att, Type t) { + //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars()); auto tb = t.toBasetype(); if (att && tb.equivalent(att)) return true; diff --git a/gcc/d/dmd/apply.d b/gcc/d/dmd/apply.d index 59ba9f5..d18b81f 100644 --- a/gcc/d/dmd/apply.d +++ b/gcc/d/dmd/apply.d @@ -170,7 +170,7 @@ public: { if (e.stageflags & stageApply) return; - int old = e.stageflags; + const old = e.stageflags; e.stageflags |= stageApply; doCond(e.elements.peekSlice()) || applyTo(e); e.stageflags = old; diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d index 6e88208..77f36f3 100644 --- a/gcc/d/dmd/astenums.d +++ b/gcc/d/dmd/astenums.d @@ -214,8 +214,8 @@ enum TY : ubyte Tmixin, Tnoreturn, Ttag, - TMAX } +enum TMAX = TY.max + 1; alias Tarray = TY.Tarray; alias Tsarray = TY.Tsarray; @@ -265,7 +265,6 @@ alias Ttraits = TY.Ttraits; alias Tmixin = TY.Tmixin; alias Tnoreturn = TY.Tnoreturn; alias Ttag = TY.Ttag; -alias TMAX = TY.TMAX; enum TFlags { @@ -328,6 +327,7 @@ enum VarArg : ubyte variadic = 1, /// (T t, ...) can be C-style (core.stdc.stdarg) or D-style (core.vararg) typesafe = 2, /// (T t ...) typesafe https://dlang.org/spec/function.html#typesafe_variadic_functions /// or https://dlang.org/spec/function.html#typesafe_variadic_functions + KRvariadic = 3, /// K+R C style variadics (no function prototype) } /************************* @@ -339,7 +339,7 @@ enum STMT : ubyte Error, Peel, Exp, DtorExp, - Compile, + Mixin, Compound, CompoundDeclaration, CompoundAsm, UnrolledLoop, Scope, @@ -439,3 +439,22 @@ enum FileType : ubyte ddoc, /// Ddoc documentation file (.dd) c, /// C source file } + +extern (C++) struct structalign_t +{ + private: + ushort value = 0; // unknown + enum STRUCTALIGN_DEFAULT = 1234; // default = match whatever the corresponding C compiler does + bool pack; // use #pragma pack semantics + + public: + pure @safe @nogc nothrow: + bool isDefault() const { return value == STRUCTALIGN_DEFAULT; } + void setDefault() { value = STRUCTALIGN_DEFAULT; } + bool isUnknown() const { return value == 0; } // value is not set + void setUnknown() { value = 0; } + void set(uint value) { this.value = cast(ushort)value; } + uint get() const { return value; } + bool isPack() const { return pack; } + void setPack(bool pack) { this.pack = pack; } +} diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index dbe78ef..c08382c 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -62,6 +62,12 @@ extern (C++) abstract class AttribDeclaration : Dsymbol this.decl = decl; } + extern (D) this(const ref Loc loc, Dsymbols* decl) + { + super(loc, null); + this.decl = decl; + } + extern (D) this(const ref Loc loc, Identifier ident, Dsymbols* decl) { super(loc, ident); @@ -228,6 +234,12 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration this.stc = stc; } + extern (D) this(const ref Loc loc, StorageClass stc, Dsymbols* decl) + { + super(loc, decl); + this.stc = stc; + } + override StorageClassDeclaration syntaxCopy(Dsymbol s) { assert(!s); @@ -1279,7 +1291,8 @@ extern(C++) final class ForwardingAttribDeclaration : AttribDeclaration * mixin("int x"); * https://dlang.org/spec/module.html#mixin-declaration */ -extern (C++) final class CompileDeclaration : AttribDeclaration +// Note: was CompileDeclaration +extern (C++) final class MixinDeclaration : AttribDeclaration { Expressions* exps; ScopeDsymbol scopesym; @@ -1288,19 +1301,19 @@ extern (C++) final class CompileDeclaration : AttribDeclaration extern (D) this(const ref Loc loc, Expressions* exps) { super(loc, null, null); - //printf("CompileDeclaration(loc = %d)\n", loc.linnum); + //printf("MixinDeclaration(loc = %d)\n", loc.linnum); this.exps = exps; } - override CompileDeclaration syntaxCopy(Dsymbol s) + override MixinDeclaration syntaxCopy(Dsymbol s) { - //printf("CompileDeclaration::syntaxCopy('%s')\n", toChars()); - return new CompileDeclaration(loc, Expression.arraySyntaxCopy(exps)); + //printf("MixinDeclaration::syntaxCopy('%s')\n", toChars()); + return new MixinDeclaration(loc, Expression.arraySyntaxCopy(exps)); } override void addMember(Scope* sc, ScopeDsymbol sds) { - //printf("CompileDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum); + //printf("MixinDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum); this.scopesym = sds; } @@ -1314,7 +1327,7 @@ extern (C++) final class CompileDeclaration : AttribDeclaration return "mixin"; } - override inout(CompileDeclaration) isCompileDeclaration() inout + override inout(MixinDeclaration) isMixinDeclaration() inout { return this; } diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h index 113653e..1e75598 100644 --- a/gcc/d/dmd/attrib.h +++ b/gcc/d/dmd/attrib.h @@ -221,7 +221,7 @@ public: // Mixin declarations -class CompileDeclaration final : public AttribDeclaration +class MixinDeclaration final : public AttribDeclaration { public: Expressions *exps; @@ -229,7 +229,7 @@ public: ScopeDsymbol *scopesym; d_bool compiled; - CompileDeclaration *syntaxCopy(Dsymbol *s) override; + MixinDeclaration *syntaxCopy(Dsymbol *s) override; void addMember(Scope *sc, ScopeDsymbol *sds) override; void setScope(Scope *sc) override; const char *kind() const override; diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d index bd5b78e..db738b4 100644 --- a/gcc/d/dmd/blockexit.d +++ b/gcc/d/dmd/blockexit.d @@ -63,34 +63,21 @@ enum BE : int */ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) { - extern (C++) final class BlockExit : Visitor - { - alias visit = Visitor.visit; - public: - FuncDeclaration func; - bool mustNotThrow; - int result; - - extern (D) this(FuncDeclaration func, bool mustNotThrow) scope - { - this.func = func; - this.mustNotThrow = mustNotThrow; - result = BE.none; - } + int result = BE.none; - override void visit(Statement s) + void visitDefaultCase(Statement s) { printf("Statement::blockExit(%p)\n", s); printf("%s\n", s.toChars()); assert(0); } - override void visit(ErrorStatement s) + void visitError(ErrorStatement s) { result = BE.none; } - override void visit(ExpStatement s) + void visitExp(ExpStatement s) { result = BE.fallthru; if (s.exp) @@ -115,13 +102,18 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) } } - override void visit(CompileStatement s) + void visitDtorExp(DtorExpStatement s) + { + visitExp(s); + } + + void visitMixin(MixinStatement s) { assert(global.errors); result = BE.fallthru; } - override void visit(CompoundStatement cs) + void visitCompound(CompoundStatement cs) { //printf("CompoundStatement.blockExit(%p) %d result = x%X\n", cs, cs.statements.length, result); result = BE.fallthru; @@ -175,7 +167,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) } } - override void visit(UnrolledLoopStatement uls) + void visitUnrolledLoop(UnrolledLoopStatement uls) { result = BE.fallthru; foreach (s; *uls.statements) @@ -190,19 +182,19 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) } } - override void visit(ScopeStatement s) + void visitScope(ScopeStatement s) { //printf("ScopeStatement::blockExit(%p)\n", s.statement); result = blockExit(s.statement, func, mustNotThrow); } - override void visit(WhileStatement s) + void visitWhile(WhileStatement s) { assert(global.errors); result = BE.fallthru; } - override void visit(DoStatement s) + void visitDo(DoStatement s) { if (s._body) { @@ -227,7 +219,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) result &= ~(BE.break_ | BE.continue_); } - override void visit(ForStatement s) + void visitFor(ForStatement s) { result = BE.fallthru; if (s._init) @@ -259,7 +251,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) result |= canThrow(s.increment, func, mustNotThrow); } - override void visit(ForeachStatement s) + void visitForeach(ForeachStatement s) { result = BE.fallthru; result |= canThrow(s.aggr, func, mustNotThrow); @@ -268,13 +260,13 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) result |= blockExit(s._body, func, mustNotThrow) & ~(BE.break_ | BE.continue_); } - override void visit(ForeachRangeStatement s) + void visitForeachRange(ForeachRangeStatement s) { assert(global.errors); result = BE.fallthru; } - override void visit(IfStatement s) + void visitIf(IfStatement s) { //printf("IfStatement::blockExit(%p)\n", s); result = BE.none; @@ -297,24 +289,24 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) //printf("IfStatement::blockExit(%p) = x%x\n", s, result); } - override void visit(ConditionalStatement s) + void visitConditional(ConditionalStatement s) { result = blockExit(s.ifbody, func, mustNotThrow); if (s.elsebody) result |= blockExit(s.elsebody, func, mustNotThrow); } - override void visit(PragmaStatement s) + void visitPragma(PragmaStatement s) { result = BE.fallthru; } - override void visit(StaticAssertStatement s) + void visitStaticAssert(StaticAssertStatement s) { result = BE.fallthru; } - override void visit(SwitchStatement s) + void visitSwitch(SwitchStatement s) { result = BE.none; result |= canThrow(s.condition, func, mustNotThrow); @@ -332,63 +324,63 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) result |= BE.fallthru; } - override void visit(CaseStatement s) + void visitCase(CaseStatement s) { result = blockExit(s.statement, func, mustNotThrow); } - override void visit(DefaultStatement s) + void visitDefault(DefaultStatement s) { result = blockExit(s.statement, func, mustNotThrow); } - override void visit(GotoDefaultStatement s) + void visitGotoDefault(GotoDefaultStatement s) { result = BE.goto_; } - override void visit(GotoCaseStatement s) + void visitGotoCase(GotoCaseStatement s) { result = BE.goto_; } - override void visit(SwitchErrorStatement s) + void visitSwitchError(SwitchErrorStatement s) { // Switch errors are non-recoverable result = BE.halt; } - override void visit(ReturnStatement s) + void visitReturn(ReturnStatement s) { result = BE.return_; if (s.exp) result |= canThrow(s.exp, func, mustNotThrow); } - override void visit(BreakStatement s) + void visitBreak(BreakStatement s) { //printf("BreakStatement::blockExit(%p) = x%x\n", s, s.ident ? BE.goto_ : BE.break_); result = s.ident ? BE.goto_ : BE.break_; } - override void visit(ContinueStatement s) + void visitContinue(ContinueStatement s) { result = s.ident ? BE.continue_ | BE.goto_ : BE.continue_; } - override void visit(SynchronizedStatement s) + void visitSynchronized(SynchronizedStatement s) { result = blockExit(s._body, func, mustNotThrow); } - override void visit(WithStatement s) + void visitWith(WithStatement s) { result = BE.none; result |= canThrow(s.exp, func, mustNotThrow); result |= blockExit(s._body, func, mustNotThrow); } - override void visit(TryCatchStatement s) + void visitTryCatch(TryCatchStatement s) { assert(s._body); result = blockExit(s._body, func, false); @@ -428,7 +420,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) result |= catchresult; } - override void visit(TryFinallyStatement s) + void visitTryFinally(TryFinallyStatement s) { result = BE.fallthru; if (s._body) @@ -470,13 +462,13 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) result |= finalresult & ~BE.fallthru; } - override void visit(ScopeGuardStatement s) + void visitScopeGuard(ScopeGuardStatement s) { // At this point, this statement is just an empty placeholder result = BE.fallthru; } - override void visit(ThrowStatement s) + void visitThrow(ThrowStatement s) { if (s.internalThrow) { @@ -486,16 +478,16 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) return; } - result = checkThrow(s.loc, s.exp, mustNotThrow); + result = checkThrow(s.loc, s.exp, mustNotThrow, func); } - override void visit(GotoStatement s) + void visitGoto(GotoStatement s) { //printf("GotoStatement::blockExit(%p)\n", s); result = BE.goto_; } - override void visit(LabelStatement s) + void visitLabel(LabelStatement s) { //printf("LabelStatement::blockExit(%p)\n", s); result = blockExit(s.statement, func, mustNotThrow); @@ -503,30 +495,31 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) result |= BE.fallthru; } - override void visit(CompoundAsmStatement s) + void visitCompoundAsm(CompoundAsmStatement s) { // Assume the worst result = BE.fallthru | BE.return_ | BE.goto_ | BE.halt; if (!(s.stc & STC.nothrow_)) { - if (mustNotThrow && !(s.stc & STC.nothrow_)) - s.error("`asm` statement is assumed to throw - mark it with `nothrow` if it does not"); + if(func) + func.setThrow(s.loc, "`asm` statement is assumed to throw - mark it with `nothrow` if it does not"); + if (mustNotThrow) + s.error("`asm` statement is assumed to throw - mark it with `nothrow` if it does not"); // TODO else result |= BE.throw_; } } - override void visit(ImportStatement s) + void visitImport(ImportStatement s) { result = BE.fallthru; } - } if (!s) return BE.fallthru; - scope BlockExit be = new BlockExit(func, mustNotThrow); - s.accept(be); - return be.result; + mixin VisitStatement!void visit; + visit.VisitStatement(s); + return result; } /++ @@ -537,10 +530,11 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) + loc = location of the `throw` + exp = expression yielding the throwable + mustNotThrow = inside of a `nothrow` scope? + + func = function containing the `throw` + + Returns: `BE.[err]throw` depending on the type of `exp` +/ -BE checkThrow(ref const Loc loc, Expression exp, const bool mustNotThrow) +BE checkThrow(ref const Loc loc, Expression exp, const bool mustNotThrow, FuncDeclaration func) { import dmd.errors : error; @@ -554,6 +548,8 @@ BE checkThrow(ref const Loc loc, Expression exp, const bool mustNotThrow) } if (mustNotThrow) loc.error("`%s` is thrown but not caught", exp.type.toChars()); + else if (func) + func.setThrow(loc, "`%s` is thrown but not caught", exp.type); return BE.throw_; } diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d index 0c237e6..7dfec8a 100644 --- a/gcc/d/dmd/canthrow.d +++ b/gcc/d/dmd/canthrow.d @@ -53,7 +53,7 @@ enum CT : BE */ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustNotThrow) { - //printf("Expression::canThrow(%d) %s\n", mustNotThrow, toChars()); + //printf("Expression::canThrow(%d) %s\n", mustNotThrow, e.toChars()); // stop walking if we determine this expression can throw extern (C++) final class CanThrow : StoppableVisitor { @@ -76,11 +76,16 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN { if (mustNotThrow) { - e.error("%s `%s` is not `nothrow`", - f.kind(), f.toPrettyChars()); + e.error("%s `%s` is not `nothrow`", f.kind(), f.toPrettyChars()); + if (!f.isDtorDeclaration()) + errorSupplementalInferredAttr(f, 10, false, STC.nothrow_); e.checkOverridenDtor(null, f, dd => dd.type.toTypeFunction().isnothrow, "not nothrow"); } + else if (func) + { + func.setThrowCall(e.loc, f); + } result |= CT.exception; } } @@ -205,7 +210,7 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN override void visit(ThrowExp te) { - const res = checkThrow(te.loc, te.e1, mustNotThrow); + const res = checkThrow(te.loc, te.e1, mustNotThrow, func); assert((res & ~(CT.exception | CT.error)) == 0); result |= res; } diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index 19bf83e..60e373c 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -840,7 +840,7 @@ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc) " else " ~ " h = h * 33 + typeid(T).getHash(cast(const void*)&p.tupleof[i]);" ~ "return h;"; - fop.fbody = new CompileStatement(loc, new StringExp(loc, code)); + fop.fbody = new MixinStatement(loc, new StringExp(loc, code)); Scope* sc2 = sc.push(); sc2.stc = 0; sc2.linkage = LINK.d; @@ -1261,8 +1261,9 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) // if this field's postblit is not `nothrow`, add a `scope(failure)` // block to destroy any prior successfully postblitted fields should - // this field's postblit fail - if (fieldsToDestroy.length > 0 && !(cast(TypeFunction)sdv.postblit.type).isnothrow) + // this field's postblit fail. + // Don't generate it for betterC code since it cannot throw exceptions. + if (fieldsToDestroy.length > 0 && !(cast(TypeFunction)sdv.postblit.type).isnothrow && !global.params.betterC) { // create a list of destructors that need to be called Expression[] dtorCalls; diff --git a/gcc/d/dmd/common/string.d b/gcc/d/dmd/common/string.d index 1111cec..a1614fd 100644 --- a/gcc/d/dmd/common/string.d +++ b/gcc/d/dmd/common/string.d @@ -13,7 +13,7 @@ module dmd.common.string; nothrow: /** -Defines a temporary array using a fixed-length buffer as back store. If the length +Defines a temporary array of `Element`s using a fixed-length buffer as back store. If the length of the buffer suffices, it is readily used. Otherwise, `malloc` is used to allocate memory for the array and `free` is used for deallocation in the destructor. @@ -21,19 +21,26 @@ destructor. This type is meant to use exclusively as an automatic variable. It is not default constructible or copyable. */ -struct SmallBuffer(T) +struct SmallBuffer(Element) { import core.stdc.stdlib : malloc, free; - private T[] _extent; + private Element[] _extent; private bool needsFree; nothrow: + @nogc: @disable this(); // no default ctor - @disable this(ref const SmallBuffer!T); // noncopyable, nonassignable - - this(size_t len, T[] buffer) + @disable this(ref const SmallBuffer!Element); // noncopyable, nonassignable + + /*********** + * Construct a SmallBuffer + * Params: + * len = number of elements in array + * buffer = slice to use as backing-store, if len will fit in it + */ + scope this(size_t len, return scope Element[] buffer) { if (len <= buffer.length) { @@ -41,7 +48,8 @@ struct SmallBuffer(T) } else { - _extent = (cast(typeof(_extent.ptr)) malloc(len * _extent[0].sizeof))[0 .. len]; + assert(len < sizeof.max / Element.sizeof); + _extent = (cast(typeof(_extent.ptr)) malloc(len * Element.sizeof))[0 .. len]; _extent.ptr || assert(0, "Out of memory."); needsFree = true; } @@ -54,16 +62,22 @@ struct SmallBuffer(T) free(_extent.ptr); } - void create(size_t len) + /****** + * Resize existing SmallBuffer. + * Params: + * len = number of elements after resize + */ + scope void create(size_t len) { if (len <= _extent.length) { - _extent = _extent[0 .. len]; + _extent = _extent[0 .. len]; // reuse existing storage } else { __dtor(); - _extent = (cast(typeof(_extent.ptr)) malloc(len * _extent[0].sizeof))[0 .. len]; + assert(len < sizeof.max / Element.sizeof); + _extent = (cast(typeof(_extent.ptr)) malloc(len * Element.sizeof))[0 .. len]; _extent.ptr || assert(0, "Out of memory."); needsFree = true; } diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index e4be63c..415606b 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -1437,7 +1437,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz); StringExp es = ue.exp().isStringExp(); es.type = type; - es.committed = 1; + es.committed = true; } else { diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index a18f810..9b7db1f 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -14,22 +14,18 @@ module dmd.cparse; import core.stdc.stdio; -import core.stdc.string; +import core.stdc.string : memcpy; + import dmd.astenums; import dmd.errorsink; -import dmd.globals; import dmd.id; import dmd.identifier; import dmd.lexer; import dmd.location; import dmd.parse; -import dmd.errors; import dmd.root.array; -import dmd.root.filename; import dmd.common.outbuffer; import dmd.root.rmem; -import dmd.root.rootobject; -import dmd.root.string; import dmd.tokens; /*********************************************************** @@ -71,9 +67,10 @@ final class CParser(AST) : Parser!AST extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment, ErrorSink errorSink, - const ref TARGET target, OutBuffer* defines) scope + const ref TARGET target, OutBuffer* defines, const CompileEnv* compileEnv) scope { - super(_module, input, doDocComment, errorSink); + const bool doUnittests = false; + super(_module, input, doDocComment, errorSink, compileEnv, doUnittests); //printf("CParser.this()\n"); mod = _module; @@ -202,7 +199,7 @@ final class CParser(AST) : Parser!AST else if (token.value == TOK.leftCurly) s = cparseStatement(ParseStatementFlags.curly | ParseStatementFlags.scope_); else - s = cparseStatement(ParseStatementFlags.semiOk); + s = cparseStatement(0); s = new AST.LabelStatement(loc, ident, s); break; } @@ -307,6 +304,7 @@ final class CParser(AST) : Parser!AST case TOK.extern_: case TOK.static_: case TOK._Thread_local: + case TOK.__thread: case TOK.auto_: case TOK.register: @@ -376,7 +374,7 @@ final class CParser(AST) : Parser!AST auto statements = new AST.Statements(); while (token.value != TOK.rightCurly && token.value != TOK.endOfFile) { - statements.push(cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope)); + statements.push(cparseStatement(ParseStatementFlags.curlyScope)); } if (endPtr) *endPtr = token.ptr; @@ -510,6 +508,14 @@ final class CParser(AST) : Parser!AST nextToken(); auto exp = cparseAssignExp(); + AST.Expression expHigh; + if (token.value == TOK.dotDotDot) + { + /* Case Ranges https://gcc.gnu.org/onlinedocs/gcc/Case-Ranges.html + */ + nextToken(); + expHigh = cparseAssignExp(); + } check(TOK.colon); if (flags & ParseStatementFlags.curlyScope) @@ -517,7 +523,7 @@ final class CParser(AST) : Parser!AST auto statements = new AST.Statements(); while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly) { - auto cur = cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope); + auto cur = cparseStatement(ParseStatementFlags.curlyScope); statements.push(cur); // https://issues.dlang.org/show_bug.cgi?id=21739 @@ -532,10 +538,13 @@ final class CParser(AST) : Parser!AST } else { - s = cparseStatement(ParseStatementFlags.semi); + s = cparseStatement(0); } s = new AST.ScopeStatement(loc, s, token.loc); - s = new AST.CaseStatement(loc, exp, s); + if (expHigh) + s = new AST.CaseRangeStatement(loc, exp, expHigh, s); + else + s = new AST.CaseStatement(loc, exp, s); break; } @@ -549,12 +558,12 @@ final class CParser(AST) : Parser!AST auto statements = new AST.Statements(); while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly) { - statements.push(cparseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope)); + statements.push(cparseStatement(ParseStatementFlags.curlyScope)); } s = new AST.CompoundStatement(loc, statements); } else - s = cparseStatement(ParseStatementFlags.semi); + s = cparseStatement(0); s = new AST.ScopeStatement(loc, s, token.loc); s = new AST.DefaultStatement(loc, s); break; @@ -604,7 +613,20 @@ final class CParser(AST) : Parser!AST } case TOK.asm_: - s = parseAsm(); + switch (peekNext()) + { + case TOK.goto_: + case TOK.inline: + case TOK.volatile: + case TOK.leftParenthesis: + s = cparseGnuAsm(); + break; + + default: + // ImportC extensions: parse as a D asm block. + s = parseAsm(); + break; + } break; default: @@ -777,7 +799,10 @@ final class CParser(AST) : Parser!AST case TOK.leftParenthesis: nextToken(); - e = cparseExpression(); + if (token.value == TOK.leftCurly) + e = cparseStatementExpression(); // gcc extension + else + e = cparseExpression(); check(TOK.rightParenthesis); break; @@ -1600,6 +1625,41 @@ final class CParser(AST) : Parser!AST return e; } + /***************************** + * gcc extension: https://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html + * Represent as a function literal, then call the function literal. + * Parser is on opening curly brace. + */ + private AST.Expression cparseStatementExpression() + { + AST.ParameterList parameterList; + StorageClass stc = 0; + const loc = token.loc; + typedefTab.push(null); + auto fbody = cparseStatement(ParseStatementFlags.scope_); + typedefTab.pop(); // end of function scope + + // Rewrite last ExpStatement (if there is one) as a ReturnStatement + auto ss = fbody.isScopeStatement(); + auto cs = ss.statement.isCompoundStatement(); + assert(cs); + if (const len = (*cs.statements).length) + { + auto s = (*cs.statements)[len - 1]; + if (auto es = s.isExpStatement()) + (*cs.statements)[len - 1] = new AST.ReturnStatement(es.loc, es.exp); + } + + auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc); + auto fd = new AST.FuncLiteralDeclaration(loc, token.loc, tf, TOK.delegate_, null, null, 0); + fd.fbody = fbody; + + auto fe = new AST.FuncExp(loc, fd); + auto args = new AST.Expressions(); + auto e = new AST.CallExp(loc, fe, args); // call the function literal + return e; + } + //} /********************************************************************************/ /********************************* Declaration Parser ***************************/ @@ -1660,6 +1720,12 @@ final class CParser(AST) : Parser!AST auto stag = (tt.tok == TOK.struct_) ? new AST.StructDeclaration(tt.loc, tt.id, false) : (tt.tok == TOK.union_) ? new AST.UnionDeclaration(tt.loc, tt.id) : new AST.EnumDeclaration(tt.loc, tt.id, tt.base); + if (!tt.packalign.isUnknown()) + { + // saw `struct __declspec(align(N)) Tag ...` + auto st = stag.isStructDeclaration(); + st.alignment = tt.packalign; + } stag.members = tt.members; tt.members = null; if (!symbols) @@ -1759,7 +1825,7 @@ final class CParser(AST) : Parser!AST case TOK.asm_: case TOK.__attribute__: if (token.value == TOK.asm_) - asmName = cparseSimpleAsmExpr(); + asmName = cparseGnuAsmLabel(); if (token.value == TOK.__attribute__) { cparseGnuAttributes(specifier); @@ -1892,6 +1958,7 @@ final class CParser(AST) : Parser!AST if (specifier.scw & SCW.x_Thread_local) error("functions cannot be `_Thread_local`"); // C11 6.7.1-4 auto fd = new AST.FuncDeclaration(token.loc, Loc.initial, id, specifiersToSTC(level, specifier), dt, specifier.noreturn); + specifiersToFuncDeclaration(fd, specifier); s = fd; } else @@ -1901,7 +1968,9 @@ final class CParser(AST) : Parser!AST if (!hasInitializer && !(specifier.scw & (SCW.xextern | SCW.xstatic | SCW.x_Thread_local) || level == LVL.global)) initializer = new AST.VoidInitializer(token.loc); - s = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(level, specifier)); + auto vd = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(level, specifier)); + specifiersToVarDeclaration(vd, specifier); + s = vd; } if (level != LVL.global) insertIdToTypedefTab(id); // non-typedef declarations can hide typedefs in outer scopes @@ -2012,8 +2081,7 @@ final class CParser(AST) : Parser!AST auto pl = ft.parameterList; if (pl.varargs != AST.VarArg.none && pl.length) error("function identifier-list cannot end with `...`"); - ft.parameterList.varargs = AST.VarArg.variadic; // but C11 allows extra arguments - importBuiltins = true; // will need __va_list_tag + ft.parameterList.varargs = AST.VarArg.KRvariadic; // but C11 allows extra arguments auto plLength = pl.length; if (symbols.length != plLength) error(token.loc, "%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length); @@ -2038,6 +2106,10 @@ final class CParser(AST) : Parser!AST error("storage class and type are not allowed in identifier-list"); foreach (s; (*symbols)[]) // yes, quadratic { + auto ad = s.isAttribDeclaration(); + if (ad) + s = (*ad.decl)[0]; // AlignDeclaration wrapping the declaration + auto d = s.isDeclaration(); if (d && p.ident == d.ident && d.type) { @@ -2062,6 +2134,7 @@ final class CParser(AST) : Parser!AST typedefTab.pop(); // end of function scope auto fd = new AST.FuncDeclaration(locFunc, prevloc, id, specifiersToSTC(LVL.global, specifier), ft, specifier.noreturn); + specifiersToFuncDeclaration(fd, specifier); if (addFuncName) { @@ -2234,6 +2307,7 @@ final class CParser(AST) : Parser!AST case TOK.typedef_: scwx = SCW.xtypedef; break; case TOK.inline: scwx = SCW.xinline; break; case TOK._Noreturn: scwx = SCW.x_Noreturn; break; + case TOK.__thread: case TOK._Thread_local: scwx = SCW.x_Thread_local; break; // Type qualifiers @@ -2269,15 +2343,23 @@ final class CParser(AST) : Parser!AST const sloc = token.loc; nextToken(); + Specifier tagSpecifier; + /* GNU Extensions * struct-or-union-specifier: * struct-or-union gnu-attributes (opt) identifier (opt) { struct-declaration-list } gnu-attributes (opt) * struct-or-union gnu-attribute (opt) identifier */ - if (token.value == TOK.__attribute__) - cparseGnuAttributes(specifier); - - t = cparseStruct(sloc, structOrUnion, symbols); + while (1) + { + if (token.value == TOK.__attribute__) + cparseGnuAttributes(tagSpecifier); + else if (token.value == TOK.__declspec) + cparseDeclspec(tagSpecifier); + else + break; + } + t = cparseStruct(sloc, structOrUnion, tagSpecifier.packalign, symbols); tkwx = TKW.xtag; break; } @@ -2298,8 +2380,8 @@ final class CParser(AST) : Parser!AST if (isTypeName(tk) && tk.value == TOK.rightParenthesis) { nextToken(); + nextToken(); t = cparseTypeName(); - // TODO - implement the "atomic" part of t tkwx = TKW.x_Atomic; break; } @@ -2468,6 +2550,12 @@ final class CParser(AST) : Parser!AST error("`inline` and `_Noreturn` function specifiers not allowed for `_Thread_local`"); scw &= ~scwx; } + if (level == LVL.local && + scw & (SCW.x_Thread_local) && !(scw & (SCW.xstatic | SCW.xextern))) + { + error("`_Thread_local` in block scope must be accompanied with `static` or `extern`"); // C11 6.7.1-3 + scw &= ~scwx; + } if (level & (LVL.parameter | LVL.prototype) && scw & ~SCW.xregister) { @@ -2568,6 +2656,7 @@ final class CParser(AST) : Parser!AST } case TKW.xtag: + case TKW.x_Atomic: // no atomics for you break; // t is already set default: @@ -2806,7 +2895,10 @@ final class CParser(AST) : Parser!AST auto parameterList = cparseParameterList(); const lkg = specifier.mod & MOD.x__stdcall ? LINK.windows : linkage; - AST.Type tf = new AST.TypeFunction(parameterList, t, lkg, 0); + StorageClass stc = specifier._nothrow ? STC.nothrow_ : 0; + if (specifier._pure) + stc |= STC.pure_; + AST.Type tf = new AST.TypeFunction(parameterList, t, lkg, stc); // tf = tf.addSTC(storageClass); // TODO insertTx(ts, tf, t); // ts -> ... -> tf -> t @@ -2959,8 +3051,7 @@ final class CParser(AST) : Parser!AST if (token.value == TOK.rightParenthesis) // func() { nextToken(); - importBuiltins = true; // will need __va_list_tag - return AST.ParameterList(parameters, AST.VarArg.variadic, varargsStc); + return AST.ParameterList(parameters, AST.VarArg.KRvariadic, varargsStc); } /* Create function prototype scope @@ -3084,9 +3175,15 @@ final class CParser(AST) : Parser!AST * extended-decl-modifier extended-decl-modifier-seq * * extended-decl-modifier: + * align(number) + * deprecated(depMsg) * dllimport * dllexport + * naked + * noinline * noreturn + * nothrow + * thread * Params: * specifier = filled in with the attribute(s) */ @@ -3096,8 +3193,6 @@ final class CParser(AST) : Parser!AST /* Check for dllexport, dllimport * Ignore the rest */ - bool dllimport; // TODO implement - bool dllexport; // TODO implement nextToken(); // move past __declspec check(TOK.leftParenthesis); while (1) @@ -3113,12 +3208,22 @@ final class CParser(AST) : Parser!AST { if (token.ident == Id.dllimport) { - dllimport = true; + specifier.dllimport = true; nextToken(); } else if (token.ident == Id.dllexport) { - dllexport = true; + specifier.dllexport = true; + nextToken(); + } + else if (token.ident == Id.naked) + { + specifier.naked = true; + nextToken(); + } + else if (token.ident == Id.noinline) + { + specifier.scw |= SCW.xnoinline; nextToken(); } else if (token.ident == Id.noreturn) @@ -3126,6 +3231,49 @@ final class CParser(AST) : Parser!AST specifier.noreturn = true; nextToken(); } + else if (token.ident == Id._nothrow) + { + specifier._nothrow = true; + nextToken(); + } + else if (token.ident == Id.thread) + { + specifier.scw |= SCW.x_Thread_local; + nextToken(); + } + else if (token.ident == Id._align) + { + // Microsoft spec is very imprecise as to how this actually works + nextToken(); + check(TOK.leftParenthesis); + if (token.value == TOK.int32Literal) + { + const n = token.unsvalue; + if (n < 1 || n & (n - 1) || 8192 < n) + error("__decspec(align(%lld)) must be an integer positive power of 2 and be <= 8,192", cast(ulong)n); + specifier.packalign.set(cast(uint)n); + specifier.packalign.setPack(true); + nextToken(); + } + else + { + error("alignment value expected, not `%s`", token.toChars()); + nextToken(); + } + + check(TOK.rightParenthesis); + } + else if (token.ident == Id._deprecated) + { + specifier._deprecated = true; + nextToken(); + if (token.value == TOK.leftParenthesis) // optional deprecation message + { + nextToken(); + specifier.depMsg = cparseExpression(); + check(TOK.rightParenthesis); + } + } else { nextToken(); @@ -3133,6 +3281,8 @@ final class CParser(AST) : Parser!AST cparseParens(); } } + else if (token.value == TOK.restrict) // ImportC assigns no semantics to `restrict`, so just ignore the keyword. + nextToken(); else { error("extended-decl-modifier expected"); @@ -3142,7 +3292,8 @@ final class CParser(AST) : Parser!AST } /************************* - * Simple asm parser + * Parser for asm label. It appears after the declarator, and has apparently + * nothing to do with inline assembler. * https://gcc.gnu.org/onlinedocs/gcc/Asm-Labels.html * simple-asm-expr: * asm ( asm-string-literal ) @@ -3150,17 +3301,107 @@ final class CParser(AST) : Parser!AST * asm-string-literal: * string-literal */ - private AST.StringExp cparseSimpleAsmExpr() + private AST.StringExp cparseGnuAsmLabel() { nextToken(); // move past asm check(TOK.leftParenthesis); if (token.value != TOK.string_) - error("string literal expected"); + error("string literal expected for Asm Label, not `%s`", token.toChars()); auto label = cparsePrimaryExp(); check(TOK.rightParenthesis); return cast(AST.StringExp) label; } + /******************** + * Parse C inline assembler statement in Gnu format. + * https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html + * asm asm-qualifiers ( AssemblerTemplate : OutputOperands : InputOperands : Clobbers : GotoLabels ) + * Current token is on the `asm`. + * Returns: + * inline assembler expression as a Statement + */ + private AST.Statement cparseGnuAsm() + { + // Defer parsing of AsmStatements until semantic processing. + const loc = token.loc; + + nextToken(); + + // Consume all asm-qualifiers. As a future optimization, we could record + // the `inline` and `volatile` storage classes against the statement. + while (token.value == TOK.goto_ || + token.value == TOK.inline || + token.value == TOK.volatile) + nextToken(); + + check(TOK.leftParenthesis); + if (token.value != TOK.string_) + error("string literal expected for Assembler Template, not `%s`", token.toChars()); + Token* toklist = null; + Token** ptoklist = &toklist; + //Identifier label = null; + auto statements = new AST.Statements(); + + int parens; + while (1) + { + switch (token.value) + { + case TOK.leftParenthesis: + ++parens; + goto default; + + case TOK.rightParenthesis: + --parens; + if (parens >= 0) + goto default; + break; + + case TOK.semicolon: + error("matching `)` expected, not `;`"); + break; + + case TOK.endOfFile: + /* ( */ + error("matching `)` expected, not end of file"); + break; + + case TOK.colonColon: // treat as two separate : tokens for iasmgcc + *ptoklist = allocateToken(); + memcpy(*ptoklist, &token, Token.sizeof); + (*ptoklist).value = TOK.colon; + ptoklist = &(*ptoklist).next; + + *ptoklist = allocateToken(); + memcpy(*ptoklist, &token, Token.sizeof); + (*ptoklist).value = TOK.colon; + ptoklist = &(*ptoklist).next; + + *ptoklist = null; + nextToken(); + continue; + + default: + *ptoklist = allocateToken(); + memcpy(*ptoklist, &token, Token.sizeof); + ptoklist = &(*ptoklist).next; + *ptoklist = null; + nextToken(); + continue; + } + if (toklist) + { + // Create AsmStatement from list of tokens we've saved + AST.Statement s = new AST.AsmStatement(token.loc, toklist); + statements.push(s); + } + break; + } + nextToken(); + auto s = new AST.CompoundAsmStatement(loc, statements, 0); + return s; + } + /************************* * __attribute__ parser * https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html @@ -3222,25 +3463,75 @@ final class CParser(AST) : Parser!AST */ private void cparseGnuAttribute(ref Specifier specifier) { - /* Check for dllimport, dllexport, vector_size(bytes) + /* Check for dllimport, dllexport, naked, noreturn, vector_size(bytes) * Ignore the rest */ - bool dllimport; // TODO implement - bool dllexport; // TODO implement - if (!isGnuAttributeName()) return; if (token.value == TOK.identifier) { - if (token.ident == Id.dllimport) + if (token.ident == Id.aligned) { - dllimport = true; + nextToken(); + if (token.value == TOK.leftParenthesis) + { + nextToken(); + if (token.value == TOK.int32Literal) + { + const n = token.unsvalue; + if (n < 1 || n & (n - 1) || ushort.max < n) + error("__attribute__((aligned(%lld))) must be an integer positive power of 2 and be <= 32,768", cast(ulong)n); + specifier.packalign.set(cast(uint)n); + specifier.packalign.setPack(true); + nextToken(); + } + else + { + error("alignment value expected, not `%s`", token.toChars()); + nextToken(); + } + + check(TOK.rightParenthesis); + } + /* ignore __attribute__((aligned)), which sets the alignment to the largest value for any data + * type on the target machine. It's the opposite of __attribute__((packed)) + */ + } + else if (token.ident == Id.always_inline) // https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html + { + specifier.scw |= SCW.xinline; + nextToken(); + } + else if (token.ident == Id._deprecated) + { + specifier._deprecated = true; + nextToken(); + if (token.value == TOK.leftParenthesis) // optional deprecation message + { + nextToken(); + specifier.depMsg = cparseExpression(); + check(TOK.rightParenthesis); + } + } + else if (token.ident == Id.dllimport) + { + specifier.dllimport = true; nextToken(); } else if (token.ident == Id.dllexport) { - dllexport = true; + specifier.dllexport = true; + nextToken(); + } + else if (token.ident == Id.naked) + { + specifier.naked = true; + nextToken(); + } + else if (token.ident == Id.noinline) + { + specifier.scw |= SCW.xnoinline; nextToken(); } else if (token.ident == Id.noreturn) @@ -3248,6 +3539,16 @@ final class CParser(AST) : Parser!AST specifier.noreturn = true; nextToken(); } + else if (token.ident == Id._nothrow) + { + specifier._nothrow = true; + nextToken(); + } + else if (token.ident == Id._pure) + { + specifier._pure = true; + nextToken(); + } else if (token.ident == Id.vector_size) { nextToken(); @@ -3408,7 +3709,8 @@ final class CParser(AST) : Parser!AST * https://en.cppreference.com/w/cpp/language/enum * enum Identifier : Type */ - AST.Type base = AST.Type.tint32; // C11 6.7.2.2-4 implementation defined default base type + //AST.Type base = AST.Type.tint32; // C11 6.7.2.2-4 implementation defined default base type + AST.Type base = null; // C23 says base type is determined by enum member values if (token.value == TOK.colon) { nextToken(); @@ -3488,7 +3790,7 @@ final class CParser(AST) : Parser!AST * redeclaration, or reference to existing declaration. * Defer to the semantic() pass with a TypeTag. */ - return new AST.TypeTag(loc, TOK.enum_, tag, base, members); + return new AST.TypeTag(loc, TOK.enum_, tag, structalign_t.init, base, members); } /************************************* @@ -3510,11 +3812,12 @@ final class CParser(AST) : Parser!AST * Params: * loc = location of `struct` or `union` * structOrUnion = TOK.struct_ or TOK.union_ + * packalign = alignment to use for struct members * symbols = symbols to add struct-or-union declaration to * Returns: * type of the struct */ - private AST.Type cparseStruct(Loc loc, TOK structOrUnion, ref AST.Dsymbols* symbols) + private AST.Type cparseStruct(Loc loc, TOK structOrUnion, structalign_t packalign, ref AST.Dsymbols* symbols) { Identifier tag; @@ -3553,7 +3856,7 @@ final class CParser(AST) : Parser!AST * redeclaration, or reference to existing declaration. * Defer to the semantic() pass with a TypeTag. */ - return new AST.TypeTag(loc, structOrUnion, tag, null, members); + return new AST.TypeTag(loc, structOrUnion, tag, packalign, null, members); } /************************************* @@ -3996,6 +4299,13 @@ final class CParser(AST) : Parser!AST case TOK.union_: case TOK.enum_: t = peek(t); + if (t.value == TOK.__attribute__ || + t.value == TOK.__declspec) + { + t = peek(t); + if (!skipParens(t, &t)) + return false; + } if (t.value == TOK.identifier) { t = peek(t); @@ -4019,6 +4329,7 @@ final class CParser(AST) : Parser!AST case TOK.typedef_: case TOK.extern_: case TOK.static_: + case TOK.__thread: case TOK._Thread_local: case TOK.auto_: case TOK.register: @@ -4620,6 +4931,8 @@ final class CParser(AST) : Parser!AST // C11 6.7.4 Function specifiers xinline = 0x40, x_Noreturn = 0x80, + + xnoinline = 0x100, } /// C11 6.7.3 Type qualifiers @@ -4639,6 +4952,14 @@ final class CParser(AST) : Parser!AST struct Specifier { bool noreturn; /// noreturn attribute + bool naked; /// naked attribute + bool _nothrow; /// nothrow attribute + bool _pure; /// pure attribute + bool dllimport; /// dllimport attribute + bool dllexport; /// dllexport attribute + bool _deprecated; /// deprecated attribute + AST.Expression depMsg; /// deprecated message + SCW scw; /// storage-class specifiers MOD mod; /// type qualifiers AST.Expressions* alignExps; /// alignment @@ -4662,6 +4983,8 @@ final class CParser(AST) : Parser!AST { if (specifier.scw & SCW.xextern) stc = AST.STC.extern_; + else if (specifier.scw & SCW.xstatic) + stc = AST.STC.static_; } else if (level == LVL.local) { @@ -4713,10 +5036,42 @@ final class CParser(AST) : Parser!AST stc = AST.STC.gshared; } } + if (specifier._deprecated && !specifier.depMsg) + stc |= AST.STC.deprecated_; return stc; } /*********************** + * Add attributes from Specifier to function + * Params: + * fd = function to apply them to + * specifier = specifiers + */ + void specifiersToFuncDeclaration(AST.FuncDeclaration fd, const ref Specifier specifier) + { + fd.isNaked = specifier.naked; + fd.dllImport = specifier.dllimport; + fd.dllExport = specifier.dllexport; + + if (specifier.scw & SCW.xnoinline) + fd.inlining = PINLINE.never; + else if (specifier.scw & SCW.xinline) + fd.inlining = PINLINE.always; + } + + /*********************** + * Add attributes from Specifier to variable + * Params: + * vd = function to apply them to + * specifier = specifiers + */ + void specifiersToVarDeclaration(AST.VarDeclaration vd, const ref Specifier specifier) + { + vd.dllImport = specifier.dllimport; + vd.dllExport = specifier.dllexport; + } + + /*********************** * Return suitable signed integer type for the given size * Params: * size = size of type @@ -4826,7 +5181,7 @@ final class CParser(AST) : Parser!AST auto lenfn = new AST.IntegerExp(loc, fn.length + 1, AST.Type.tuns32); // +1 for terminating 0 auto tfn = new AST.TypeSArray(AST.Type.tchar, lenfn); efn.type = tfn.immutableOf(); - efn.committed = 1; + efn.committed = true; auto sfn = new AST.VarDeclaration(loc, tfn, Id.__func__, ifn, STC.gshared | STC.immutable_); auto e = new AST.DeclarationExp(loc, sfn); return new AST.ExpStatement(loc, e); @@ -4879,6 +5234,17 @@ final class CParser(AST) : Parser!AST private AST.Dsymbol applySpecifier(AST.Dsymbol s, ref Specifier specifier) { //printf("applySpecifier() %s\n", s.toChars()); + if (specifier._deprecated) + { + if (specifier.depMsg) + { + // Wrap declaration in a DeprecatedDeclaration + auto decls = new AST.Dsymbols(1); + (*decls)[0] = s; + s = new AST.DeprecatedDeclaration(specifier.depMsg, decls); + } + } + if (specifier.alignExps) { //printf(" applying _Alignas %s, packalign %d\n", (*specifier.alignExps)[0].toChars(), cast(int)specifier.packalign); diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d index 32b3851..40092c3 100644 --- a/gcc/d/dmd/cppmangle.d +++ b/gcc/d/dmd/cppmangle.d @@ -211,7 +211,7 @@ private final class CppMangleVisitor : Visitor */ void mangleReturnType(TypeFunction preSemantic) { - auto tf = cast(TypeFunction)this.context.res.asFuncDecl().type; + auto tf = this.context.res.asFuncDecl().type.isTypeFunction(); Type rt = preSemantic.nextOf(); // https://issues.dlang.org/show_bug.cgi?id=22739 // auto return type means that rt is null. @@ -347,14 +347,14 @@ private final class CppMangleVisitor : Visitor * * Params: * off = Offset to insert at - * fd = Type of the function to mangle the return type of + * tf = Type of the function to mangle the return type of */ void writeRemainingTags(size_t off, TypeFunction tf) { - scope remainingVisitor = new LeftoverVisitor(&this.abiTags.written); - tf.next.accept(remainingVisitor); + Array!StringExp toWrite; + leftOver(tf, &this.abiTags.written, &toWrite); OutBuffer b2; - foreach (se; remainingVisitor.toWrite) + foreach (se; toWrite) { auto tag = se.peekString(); // We can only insert a slice, and each insert is a memmove, @@ -496,9 +496,9 @@ private final class CppMangleVisitor : Visitor mangle_function(d.isFuncDeclaration()); buf.writestring("EE"); } - else if (e && e.op == EXP.variable && (cast(VarExp)e).var.isVarDeclaration()) + else if (e && e.isVarExp() && e.isVarExp().var.isVarDeclaration()) { - VarDeclaration vd = (cast(VarExp)e).var.isVarDeclaration(); + VarDeclaration vd = e.isVarExp().var.isVarDeclaration(); buf.writeByte('L'); mangle_variable(vd, true); buf.writeByte('E'); @@ -757,9 +757,9 @@ private final class CppMangleVisitor : Visitor bool isIdent_char(Identifier ident, RootObject o) { Type t = isType(o); - if (!t || t.ty != Tstruct) + if (!t || !t.isTypeStruct()) return false; - Dsymbol s = (cast(TypeStruct)t).toDsymbol(null); + Dsymbol s = t.toDsymbol(null); if (s.ident != ident) return false; Dsymbol p = s.toParent(); @@ -1059,7 +1059,7 @@ private final class CppMangleVisitor : Visitor * ::= <data name> * ::= <special-name> */ - TypeFunction tf = cast(TypeFunction)d.type; + TypeFunction tf = d.type.isTypeFunction(); if (TemplateDeclaration ftd = getFuncTemplateDecl(d)) { @@ -1173,7 +1173,7 @@ private final class CppMangleVisitor : Visitor this.context.ti = ti; this.context.fd = d; this.context.res = d; - TypeFunction preSemantic = cast(TypeFunction)d.originalType; + TypeFunction preSemantic = d.originalType.isTypeFunction(); auto nspace = ti.toParent(); if (nspace && nspace.isNspace()) this.writeChained(ti.toParent(), () => source_name(ti, true)); @@ -1347,7 +1347,7 @@ private final class CppMangleVisitor : Visitor auto prev = this.context.push({ TypeFunction tf; if (isDsymbol(this.context.res)) - tf = cast(TypeFunction)this.context.res.asFuncDecl().type; + tf = this.context.res.asFuncDecl().type.isTypeFunction(); else tf = this.context.res.asType().isTypeFunction(); assert(tf); @@ -1391,9 +1391,9 @@ private final class CppMangleVisitor : Visitor */ void headOfType(Type t) { - if (t.ty == Tclass) + if (auto tc = t.isTypeClass()) { - mangleTypeClass(cast(TypeClass)t, true); + mangleTypeClass(tc, true); } else { @@ -1960,7 +1960,7 @@ extern(C++): */ override void visit(TypeIdentifier t) { - auto decl = cast(TemplateDeclaration)this.context.ti.tempdecl; + auto decl = this.context.ti.tempdecl.isTemplateDeclaration(); assert(decl.parameters !is null); auto idx = templateParamIndex(t.ident, decl.parameters); // If not found, default to the post-semantic type @@ -2019,7 +2019,7 @@ extern(C++): { // If the resolved AST has more args than the parse one, // we have default arguments - auto oparams = (cast(TemplateDeclaration)analyzed_ti.tempdecl).origParameters; + auto oparams = analyzed_ti.tempdecl.isTemplateDeclaration().origParameters; foreach (idx, arg; (*oparams)[t.tiargs.length .. $]) { this.context.res = (*analyzed_ti.tiargs)[idx + t.tiargs.length]; @@ -2044,7 +2044,7 @@ extern(C++): assert(t.tiargs !is null); bool needsTa; - auto decl = cast(TemplateDeclaration)this.context.ti.tempdecl; + auto decl = this.context.ti.tempdecl.isTemplateDeclaration(); // Attempt to substitute the template itself auto idx = templateParamIndex(t.name, decl.parameters); if (idx < decl.parameters.length) @@ -2125,12 +2125,13 @@ private void visitObject(V : Visitor)(RootObject o, V this_) /// Helper function to safely get a type out of a `RootObject` private Type asType(RootObject o) { - Type ta = isType(o); + if (Type ta = isType(o)) + return ta; + // When called with context.res as argument, it can be `FuncDeclaration` - if (!ta && o.asFuncDecl()) - ta = (cast(FuncDeclaration)o).type; - assert(ta !is null, o.toString()); - return ta; + if (auto fd = o.asFuncDecl()) + return fd.type; + assert(0); } /// Helper function to safely get a `FuncDeclaration` out of a `RootObject` @@ -2183,12 +2184,12 @@ private extern(C++) final class ComponentVisitor : Visitor case DYNCAST.type: auto t = cast(Type)base; - if (t.ty == Tpointer) - this.tpointer = cast(TypePointer)t; - else if (t.ty == Treference) - this.tref = cast(TypeReference)t; - else if (t.ty == Tident) - this.tident = cast(TypeIdentifier)t; + if (auto tp = t.isTypePointer()) + this.tpointer = tp; + else if (auto tr = t.isTypeReference()) + this.tref = tr; + else if (auto ti = t.isTypeIdentifier()) + this.tident = ti; else goto default; break; @@ -2531,58 +2532,70 @@ unittest assert(closestIndex([s1, s2, s4], s5, match) == 3 && !match); } -/** +/*** * Visits the return type of a function and writes leftover ABI tags + * Params: + * tf = Type of the function to mangle the return type of + * previous = already written ones + * toWrite = where to put StringExp's to be written */ -extern(C++) private final class LeftoverVisitor : Visitor +private +void leftOver(TypeFunction tf, const(Array!StringExp)* previous, Array!StringExp* toWrite) { - /// List of tags to write - private Array!StringExp toWrite; - /// List of tags to ignore - private const(Array!StringExp)* ignore; - - /// - public this(const(Array!StringExp)* previous) + extern(C++) final class LeftoverVisitor : Visitor { - this.ignore = previous; - } + /// List of tags to write + private Array!StringExp* toWrite; + /// List of tags to ignore + private const(Array!StringExp)* ignore; - /// Reintroduce base class overloads - public alias visit = Visitor.visit; + /// + public this(const(Array!StringExp)* previous, Array!StringExp* toWrite) + { + this.ignore = previous; + this.toWrite = toWrite; + } - /// Least specialized overload of each direct child of `RootObject` - public override void visit(Dsymbol o) - { - auto ale = ABITagContainer.forSymbol(o); - if (!ale) return; + /// Reintroduce base class overloads + public alias visit = Visitor.visit; - bool match; - foreach (elem; *ale.elements) + /// Least specialized overload of each direct child of `RootObject` + public override void visit(Dsymbol o) { - auto se = elem.toStringExp(); - closestIndex((*this.ignore)[], se, match); - if (match) continue; - auto idx = closestIndex(this.toWrite[], se, match); - if (!match) - this.toWrite.insert(idx, se); + auto ale = ABITagContainer.forSymbol(o); + if (!ale) return; + + bool match; + foreach (elem; *ale.elements) + { + auto se = elem.toStringExp(); + closestIndex((*this.ignore)[], se, match); + if (match) continue; + auto idx = closestIndex((*this.toWrite)[], se, match); + if (!match) + (*this.toWrite).insert(idx, se); + } } - } - /// Ditto - public override void visit(Type o) - { - if (auto sym = o.toDsymbol(null)) - sym.accept(this); - } + /// Ditto + public override void visit(Type o) + { + if (auto sym = o.toDsymbol(null)) + sym.accept(this); + } - /// Composite type - public override void visit(TypePointer o) - { - o.next.accept(this); - } + /// Composite type + public override void visit(TypePointer o) + { + o.next.accept(this); + } - public override void visit(TypeReference o) - { - o.next.accept(this); + public override void visit(TypeReference o) + { + o.next.accept(this); + } } + + scope remainingVisitor = new LeftoverVisitor(previous, toWrite); + tf.next.accept(remainingVisitor); } diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index 8109e12..289ebeb 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -47,7 +47,7 @@ extern (C++) final class ClassReferenceExp : Expression extern (D) this(const ref Loc loc, StructLiteralExp lit, Type type) { - super(loc, EXP.classReference, __traits(classInstanceSize, ClassReferenceExp)); + super(loc, EXP.classReference); assert(lit && lit.sd && lit.sd.isClassDeclaration()); this.value = lit; this.type = type; @@ -132,7 +132,7 @@ extern (C++) final class ThrownExceptionExp : Expression extern (D) this(const ref Loc loc, ClassReferenceExp victim) { - super(loc, EXP.thrownException, __traits(classInstanceSize, ThrownExceptionExp)); + super(loc, EXP.thrownException); this.thrown = victim; this.type = victim.type; } @@ -170,7 +170,7 @@ extern (C++) final class CTFEExp : Expression { extern (D) this(EXP tok) { - super(Loc.initial, tok, __traits(classInstanceSize, CTFEExp)); + super(Loc.initial, tok); type = Type.tvoid; } @@ -369,7 +369,6 @@ UnionExp copyLiteral(Expression e) case EXP.dotVariable: case EXP.int64: case EXP.float64: - case EXP.char_: case EXP.complex80: case EXP.void_: case EXP.vector: @@ -1468,7 +1467,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2) memset(cast(char*)s + len * sz, 0, sz); emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz); StringExp es = ue.exp().isStringExp(); - es.committed = 0; + es.committed = false; es.type = type; return ue; } @@ -1499,7 +1498,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2) emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz); StringExp es = ue.exp().isStringExp(); es.sz = sz; - es.committed = 0; //es1.committed; + es.committed = false; //es1.committed; es.type = type; return ue; } @@ -1837,7 +1836,6 @@ bool isCtfeValueValid(Expression newval) { case EXP.int64: case EXP.float64: - case EXP.char_: case EXP.complex80: return tb.isscalar(); diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 2830b25..8ffbef3 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -1845,7 +1845,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) if (!e.committed) { se = e.copy().isStringExp(); - se.committed = 1; + se.committed = true; copied = 1; } @@ -1887,7 +1887,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) assert(szx <= 255); se.sz = cast(ubyte)szx; se.len = cast(size_t)tb.isTypeSArray().dim.toInteger(); - se.committed = 1; + se.committed = true; se.type = t; /* If larger than source, pad with zeros. diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 7cd8df1..0e5df5e 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -738,7 +738,7 @@ extern (C++) final class AliasDeclaration : Declaration extern (D) this(const ref Loc loc, Identifier ident, Type type) { super(loc, ident); - //printf("AliasDeclaration(id = '%s', type = %p)\n", id.toChars(), type); + //printf("AliasDeclaration(id = '%s', type = %p)\n", ident.toChars(), type); //printf("type = '%s'\n", type.toChars()); this.type = type; assert(type); @@ -747,7 +747,7 @@ extern (C++) final class AliasDeclaration : Declaration extern (D) this(const ref Loc loc, Identifier ident, Dsymbol s) { super(loc, ident); - //printf("AliasDeclaration(id = '%s', s = %p)\n", id.toChars(), s); + //printf("AliasDeclaration(id = '%s', s = %p)\n", ident.toChars(), s); assert(s != this); this.aliassym = s; assert(s); @@ -1149,6 +1149,8 @@ extern (C++) class VarDeclaration : Declaration bool isArgDtorVar; /// temporary created to handle scope destruction of a function argument bool isCmacro; /// it is a C macro turned into a C declaration + bool dllImport; /// __declspec(dllimport) + bool dllExport; /// __declspec(dllexport) version (MARS) { bool inClosure; /// is inserted into a GC allocated closure @@ -1314,7 +1316,7 @@ extern (C++) class VarDeclaration : Declaration override final bool isExport() const { - return visibility.kind == Visibility.Kind.export_; + return visibility.kind == Visibility.Kind.export_ || dllExport; } override final bool isImportedSymbol() const @@ -1325,6 +1327,7 @@ extern (C++) class VarDeclaration : Declaration * export extern int sym3 = 0; // error, extern cannot have initializer */ bool result = + dllImport || visibility.kind == Visibility.Kind.export_ && storage_class & STC.extern_ && (storage_class & STC.static_ || parent.isModule()); @@ -1931,8 +1934,12 @@ extern (C++) class BitFieldDeclaration : VarDeclaration { // If the bit-field spans more units of alignment than its type, // start a new field at the next alignment boundary. - if (fieldState.bitOffset == fieldState.fieldSize * 8) + if (fieldState.bitOffset == fieldState.fieldSize * 8 && + fieldState.bitOffset + fieldWidth > memalignsize * 8) + { + if (log) printf("more units of alignment than its type\n"); startNewField(); // the bit field is full + } else { // if alignment boundary is crossed @@ -1941,7 +1948,7 @@ extern (C++) class BitFieldDeclaration : VarDeclaration //printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize); if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8)) { - //printf("alignment is crossed\n"); + if (log) printf("alignment is crossed\n"); startNewField(); } } @@ -1981,6 +1988,7 @@ extern (C++) class BitFieldDeclaration : VarDeclaration fieldState.bitOffset = pastField; } + //printf("\t%s: offset = %d bitOffset = %d fieldWidth = %d memsize = %d\n", toChars(), offset, bitOffset, fieldWidth, memsize); //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize); //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize); } diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index d75f64f..7a69382 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -623,6 +623,9 @@ public: FuncDeclarations *inlinedNestedCallees; AttributeViolation* safetyViolation; + AttributeViolation* nogcViolation; + AttributeViolation* pureViolation; + AttributeViolation* nothrowViolation; // Formerly FUNCFLAGS uint32_t flags; @@ -672,6 +675,10 @@ public: bool isCrtCtor(bool v); bool isCrtDtor() const; bool isCrtDtor(bool v); + bool dllImport() const; + bool dllImport(bool v); + bool dllExport() const; + bool dllExport(bool v); // Data for a function declaration that is needed for the Objective-C // integration. diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index e6ef704..4ef6a39 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -642,7 +642,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta e = CTFEExp.cantexp; break; } - e = interpret(pue, fd.fbody, &istatex); + e = interpretStatement(pue, fd.fbody, &istatex); if (CTFEExp.isCantExp(e)) { debug (LOG) @@ -738,21 +738,30 @@ void incUsageCtfe(InterState* istate, const ref Loc loc) } } -private extern (C++) final class Interpreter : Visitor +/*********************************** + * Interpret the statement. + * Params: + * s = Statement to interpret + * istate = context + * Returns: + * NULL continue to next statement + * EXP.cantExpression cannot interpret statement at compile time + * !NULL expression from return statement, or thrown exception + */ + +Expression interpretStatement(Statement s, InterState* istate) { - alias visit = Visitor.visit; -public: - InterState* istate; - CTFEGoal goal; - Expression result; - UnionExp* pue; // storage for `result` + UnionExp ue = void; + auto result = interpretStatement(&ue, s, istate); + if (result == ue.exp()) + result = ue.copy(); + return result; +} - extern (D) this(UnionExp* pue, InterState* istate, CTFEGoal goal) scope - { - this.pue = pue; - this.istate = istate; - this.goal = goal; - } +/// +Expression interpretStatement(UnionExp* pue, Statement s, InterState* istate) +{ + Expression result; // If e is EXP.throw_exception or EXP.cantExpression, // set it to 'result' and returns true. @@ -767,26 +776,13 @@ public: return false; } - static Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original) - { - if (exps is original) - { - if (!original) - exps = new Expressions(); - else - exps = original.copy(); - ++ctfeGlobals.numArrayAllocs; - } - return exps; - } - /******************************** Statement ***************************/ - override void visit(Statement s) + void visitDefaultCase(Statement s) { debug (LOG) { - printf("%s Statement::interpret()\n", s.loc.toChars()); + printf("%s Statement::interpret() %s\n", s.loc.toChars(), s.toChars()); } if (istate.start) { @@ -799,7 +795,7 @@ public: result = CTFEExp.cantexp; } - override void visit(ExpStatement s) + void visitExp(ExpStatement s) { debug (LOG) { @@ -819,7 +815,12 @@ public: return; } - override void visit(CompoundStatement s) + void visitDtorExp(DtorExpStatement s) + { + visitExp(s); + } + + void visitCompound(CompoundStatement s) { debug (LOG) { @@ -832,7 +833,7 @@ public: foreach (i; 0 .. dim) { Statement sx = (*s.statements)[i]; - result = interpret(pue, sx, istate); + result = interpretStatement(pue, sx, istate); if (result) break; } @@ -842,7 +843,12 @@ public: } } - override void visit(UnrolledLoopStatement s) + void visitCompoundAsm(CompoundAsmStatement s) + { + visitCompound(s); + } + + void visitUnrolledLoop(UnrolledLoopStatement s) { debug (LOG) { @@ -855,7 +861,7 @@ public: foreach (i; 0 .. dim) { Statement sx = (*s.statements)[i]; - Expression e = interpret(pue, sx, istate); + Expression e = interpretStatement(pue, sx, istate); if (!e) // succeeds to interpret, or goto target was not found continue; if (exceptionOrCant(e)) @@ -888,7 +894,7 @@ public: } } - override void visit(IfStatement s) + void visitIf(IfStatement s) { debug (LOG) { @@ -900,9 +906,9 @@ public: if (istate.start) { Expression e = null; - e = interpret(s.ifbody, istate); + e = interpretStatement(s.ifbody, istate); if (!e && istate.start) - e = interpret(s.elsebody, istate); + e = interpretStatement(s.elsebody, istate); result = e; return; } @@ -914,9 +920,9 @@ public: return; if (isTrueBool(e)) - result = interpret(pue, s.ifbody, istate); + result = interpretStatement(pue, s.ifbody, istate); else if (e.toBool().hasValue(false)) - result = interpret(pue, s.elsebody, istate); + result = interpretStatement(pue, s.elsebody, istate); else { // no error, or assert(0)? @@ -924,7 +930,7 @@ public: } } - override void visit(ScopeStatement s) + void visitScope(ScopeStatement s) { debug (LOG) { @@ -933,78 +939,10 @@ public: if (istate.start == s) istate.start = null; - result = interpret(pue, s.statement, istate); + result = interpretStatement(pue, s.statement, istate); } - /** - Given an expression e which is about to be returned from the current - function, generate an error if it contains pointers to local variables. - - Only checks expressions passed by value (pointers to local variables - may already be stored in members of classes, arrays, or AAs which - were passed as mutable function parameters). - Returns: - true if it is safe to return, false if an error was generated. - */ - static bool stopPointersEscaping(const ref Loc loc, Expression e) - { - if (!e.type.hasPointers()) - return true; - if (isPointer(e.type)) - { - Expression x = e; - if (auto eaddr = e.isAddrExp()) - x = eaddr.e1; - VarDeclaration v; - while (x.op == EXP.variable && (v = x.isVarExp().var.isVarDeclaration()) !is null) - { - if (v.storage_class & STC.ref_) - { - x = getValue(v); - if (auto eaddr = e.isAddrExp()) - eaddr.e1 = x; - continue; - } - if (ctfeGlobals.stack.isInCurrentFrame(v)) - { - error(loc, "returning a pointer to a local stack variable"); - return false; - } - else - break; - } - // TODO: If it is a EXP.dotVariable or EXP.index, we should check that it is not - // pointing to a local struct or static array. - } - if (auto se = e.isStructLiteralExp()) - { - return stopPointersEscapingFromArray(loc, se.elements); - } - if (auto ale = e.isArrayLiteralExp()) - { - return stopPointersEscapingFromArray(loc, ale.elements); - } - if (auto aae = e.isAssocArrayLiteralExp()) - { - if (!stopPointersEscapingFromArray(loc, aae.keys)) - return false; - return stopPointersEscapingFromArray(loc, aae.values); - } - return true; - } - - // Check all elements of an array for escaping local variables. Return false if error - static bool stopPointersEscapingFromArray(const ref Loc loc, Expressions* elems) - { - foreach (e; *elems) - { - if (e && !stopPointersEscaping(loc, e)) - return false; - } - return true; - } - - override void visit(ReturnStatement s) + void visitReturn(ReturnStatement s) { debug (LOG) { @@ -1061,7 +999,7 @@ public: if (isRuntimeHook(s.exp, Id._d_arrayappendT) || isRuntimeHook(s.exp, Id._d_arrayappendTTrace)) { auto rs = new ReturnStatement(s.loc, e); - rs.accept(this); + visitReturn(rs); return; } @@ -1082,20 +1020,7 @@ public: result = e; } - static Statement findGotoTarget(InterState* istate, Identifier ident) - { - Statement target = null; - if (ident) - { - LabelDsymbol label = istate.fd.searchLabel(ident); - assert(label && label.statement); - LabelStatement ls = label.statement; - target = ls.gotoTarget ? ls.gotoTarget : ls.statement; - } - return target; - } - - override void visit(BreakStatement s) + void visitBreak(BreakStatement s) { debug (LOG) { @@ -1113,7 +1038,7 @@ public: result = CTFEExp.breakexp; } - override void visit(ContinueStatement s) + void visitContinue(ContinueStatement s) { debug (LOG) { @@ -1131,7 +1056,7 @@ public: result = CTFEExp.continueexp; } - override void visit(WhileStatement s) + void visitWhile(WhileStatement s) { debug (LOG) { @@ -1140,7 +1065,7 @@ public: assert(0); // rewritten to ForStatement } - override void visit(DoStatement s) + void visitDo(DoStatement s) { debug (LOG) { @@ -1151,7 +1076,7 @@ public: while (1) { - Expression e = interpret(s._body, istate); + Expression e = interpretStatement(s._body, istate); if (!e && istate.start) // goto target was not found return; assert(!istate.start); @@ -1201,7 +1126,7 @@ public: assert(result is null); } - override void visit(ForStatement s) + void visitFor(ForStatement s) { debug (LOG) { @@ -1211,7 +1136,7 @@ public: istate.start = null; UnionExp ueinit = void; - Expression ei = interpret(&ueinit, s._init, istate); + Expression ei = interpretStatement(&ueinit, s._init, istate); if (exceptionOrCant(ei)) return; assert(!ei); // s.init never returns from function, or jumps out from it @@ -1230,7 +1155,7 @@ public: assert(isTrueBool(e)); } - Expression e = interpret(pue, s._body, istate); + Expression e = interpretStatement(pue, s._body, istate); if (!e && istate.start) // goto target was not found return; assert(!istate.start); @@ -1273,17 +1198,17 @@ public: assert(result is null); } - override void visit(ForeachStatement s) + void visitForeach(ForeachStatement s) { assert(0); // rewritten to ForStatement } - override void visit(ForeachRangeStatement s) + void visitForeachRange(ForeachRangeStatement s) { assert(0); // rewritten to ForStatement } - override void visit(SwitchStatement s) + void visitSwitch(SwitchStatement s) { debug (LOG) { @@ -1294,7 +1219,7 @@ public: istate.start = null; if (istate.start) { - Expression e = interpret(s._body, istate); + Expression e = interpretStatement(s._body, istate); if (istate.start) // goto target was not found return; if (exceptionOrCant(e)) @@ -1344,7 +1269,7 @@ public: /* Jump to scase */ istate.start = scase; - Expression e = interpret(pue, s._body, istate); + Expression e = interpretStatement(pue, s._body, istate); assert(!istate.start); // jump must not fail if (e && e.op == EXP.break_) { @@ -1359,7 +1284,7 @@ public: result = e; } - override void visit(CaseStatement s) + void visitCase(CaseStatement s) { debug (LOG) { @@ -1369,10 +1294,10 @@ public: if (istate.start == s) istate.start = null; - result = interpret(pue, s.statement, istate); + result = interpretStatement(pue, s.statement, istate); } - override void visit(DefaultStatement s) + void visitDefault(DefaultStatement s) { debug (LOG) { @@ -1382,10 +1307,10 @@ public: if (istate.start == s) istate.start = null; - result = interpret(pue, s.statement, istate); + result = interpretStatement(pue, s.statement, istate); } - override void visit(GotoStatement s) + void visitGoto(GotoStatement s) { debug (LOG) { @@ -1404,7 +1329,7 @@ public: result = CTFEExp.gotoexp; } - override void visit(GotoCaseStatement s) + void visitGotoCase(GotoCaseStatement s) { debug (LOG) { @@ -1423,7 +1348,7 @@ public: result = CTFEExp.gotoexp; } - override void visit(GotoDefaultStatement s) + void visitGotoDefault(GotoDefaultStatement s) { debug (LOG) { @@ -1442,7 +1367,7 @@ public: result = CTFEExp.gotoexp; } - override void visit(LabelStatement s) + void visitLabel(LabelStatement s) { debug (LOG) { @@ -1451,10 +1376,10 @@ public: if (istate.start == s) istate.start = null; - result = interpret(pue, s.statement, istate); + result = interpretStatement(pue, s.statement, istate); } - override void visit(TryCatchStatement s) + void visitTryCatch(TryCatchStatement s) { debug (LOG) { @@ -1465,18 +1390,18 @@ public: if (istate.start) { Expression e = null; - e = interpret(pue, s._body, istate); + e = interpretStatement(pue, s._body, istate); foreach (ca; *s.catches) { if (e || !istate.start) // goto target was found break; - e = interpret(pue, ca.handler, istate); + e = interpretStatement(pue, ca.handler, istate); } result = e; return; } - Expression e = interpret(s._body, istate); + Expression e = interpretStatement(s._body, istate); // An exception was thrown if (e && e.isThrownExceptionExp()) @@ -1497,7 +1422,7 @@ public: ctfeGlobals.stack.push(ca.var); setValue(ca.var, ex.thrown); } - e = interpret(ca.handler, istate); + e = interpretStatement(ca.handler, istate); if (CTFEExp.isGotoExp(e)) { /* This is an optimization that relies on the locality of the jump target. @@ -1509,7 +1434,7 @@ public: InterState istatex = *istate; istatex.start = istate.gotoTarget; // set starting statement istatex.gotoTarget = null; - Expression eh = interpret(ca.handler, &istatex); + Expression eh = interpretStatement(ca.handler, &istatex); if (!istatex.start) { istate.gotoTarget = null; @@ -1522,39 +1447,7 @@ public: result = e; } - static ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp newest) - { - debug (LOG) - { - printf("Collided exceptions %s %s\n", oldest.thrown.toChars(), newest.thrown.toChars()); - } - // Little sanity check to make sure it's really a Throwable - ClassReferenceExp boss = oldest.thrown; - const next = 5; // index of Throwable.next - assert((*boss.value.elements)[next].type.ty == Tclass); // Throwable.next - ClassReferenceExp collateral = newest.thrown; - if (collateral.originalClass().isErrorException() && !boss.originalClass().isErrorException()) - { - /* Find the index of the Error.bypassException field - */ - auto bypass = next + 1; - if ((*collateral.value.elements)[bypass].type.ty == Tuns32) - bypass += 1; // skip over _refcount field - assert((*collateral.value.elements)[bypass].type.ty == Tclass); - - // The new exception bypass the existing chain - (*collateral.value.elements)[bypass] = boss; - return newest; - } - while ((*boss.value.elements)[next].op == EXP.classReference) - { - boss = (*boss.value.elements)[next].isClassReferenceExp(); - } - (*boss.value.elements)[next] = collateral; - return oldest; - } - - override void visit(TryFinallyStatement s) + void visitTryFinally(TryFinallyStatement s) { debug (LOG) { @@ -1565,14 +1458,14 @@ public: if (istate.start) { Expression e = null; - e = interpret(pue, s._body, istate); + e = interpretStatement(pue, s._body, istate); // Jump into/out from finalbody is disabled in semantic analysis. // and jump inside will be handled by the ScopeStatement == finalbody. result = e; return; } - Expression ex = interpret(s._body, istate); + Expression ex = interpretStatement(s._body, istate); if (CTFEExp.isCantExp(ex)) { result = ex; @@ -1585,7 +1478,7 @@ public: InterState istatex = *istate; istatex.start = istate.gotoTarget; // set starting statement istatex.gotoTarget = null; - Expression bex = interpret(s._body, &istatex); + Expression bex = interpretStatement(s._body, &istatex); if (istatex.start) { // The goto target is outside the current scope. @@ -1601,7 +1494,7 @@ public: ex = bex; } - Expression ey = interpret(s.finalbody, istate); + Expression ey = interpretStatement(s.finalbody, istate); if (CTFEExp.isCantExp(ey)) { result = ey; @@ -1618,7 +1511,7 @@ public: result = ex; } - override void visit(ThrowStatement s) + void visitThrow(ThrowStatement s) { debug (LOG) { @@ -1631,35 +1524,15 @@ public: istate.start = null; } - interpretThrow(s.exp, s.loc); - } - - /// Interpret `throw <exp>` found at the specified location `loc` - private void interpretThrow(Expression exp, const ref Loc loc) - { - incUsageCtfe(istate, loc); - - Expression e = interpretRegion(exp, istate); - if (exceptionOrCant(e)) - return; - - if (e.op == EXP.classReference) - { - result = ctfeEmplaceExp!ThrownExceptionExp(loc, e.isClassReferenceExp()); - } - else - { - exp.error("to be thrown `%s` must be non-null", exp.toChars()); - result = ErrorExp.get(); - } + interpretThrow(result, s.exp, s.loc, istate); } - override void visit(ScopeGuardStatement s) + void visitScopeGuard(ScopeGuardStatement s) { assert(0); } - override void visit(WithStatement s) + void visitWith(WithStatement s) { debug (LOG) { @@ -1669,14 +1542,14 @@ public: istate.start = null; if (istate.start) { - result = s._body ? interpret(s._body, istate) : null; + result = s._body ? interpretStatement(s._body, istate) : null; return; } // If it is with(Enum) {...}, just execute the body. if (s.exp.op == EXP.scope_ || s.exp.op == EXP.type) { - result = interpret(pue, s._body, istate); + result = interpretStatement(pue, s._body, istate); return; } @@ -1692,7 +1565,7 @@ public: } ctfeGlobals.stack.push(s.wthis); setValue(s.wthis, e); - e = interpret(s._body, istate); + e = interpretStatement(s._body, istate); if (CTFEExp.isGotoExp(e)) { /* This is an optimization that relies on the locality of the jump target. @@ -1704,7 +1577,7 @@ public: InterState istatex = *istate; istatex.start = istate.gotoTarget; // set starting statement istatex.gotoTarget = null; - Expression ex = interpret(s._body, &istatex); + Expression ex = interpretStatement(s._body, &istatex); if (!istatex.start) { istate.gotoTarget = null; @@ -1715,7 +1588,7 @@ public: result = e; } - override void visit(AsmStatement s) + void visitAsm(AsmStatement s) { debug (LOG) { @@ -1731,7 +1604,17 @@ public: result = CTFEExp.cantexp; } - override void visit(ImportStatement s) + void visitInlineAsm(InlineAsmStatement s) + { + visitAsm(s); + } + + void visitGccAsm(GccAsmStatement s) + { + visitAsm(s); + } + + void visitImport(ImportStatement s) { debug (LOG) { @@ -1745,6 +1628,45 @@ public: } } + if (!s) + return null; + + mixin VisitStatement!void visit; + visit.VisitStatement(s); + return result; +} + +/// + +private extern (C++) final class Interpreter : Visitor +{ + alias visit = Visitor.visit; +public: + InterState* istate; + CTFEGoal goal; + Expression result; + UnionExp* pue; // storage for `result` + + extern (D) this(UnionExp* pue, InterState* istate, CTFEGoal goal) scope + { + this.pue = pue; + this.istate = istate; + this.goal = goal; + } + + // If e is EXP.throw_exception or EXP.cantExpression, + // set it to 'result' and returns true. + bool exceptionOrCant(Expression e) + { + if (exceptionOrCantInterpret(e)) + { + // Make sure e is not pointing to a stack temporary + result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e; + return true; + } + return false; + } + /******************************** Expression ***************************/ override void visit(Expression e) @@ -2519,7 +2441,7 @@ public: { debug (LOG) { - printf("%s ArrayLiteralExp::interpret() %s\n", e.loc.toChars(), e.toChars()); + printf("%s ArrayLiteralExp::interpret() %s, %s\n", e.loc.toChars(), e.type.toChars(), e.toChars()); } if (e.ownedByCtfe >= OwnedBy.ctfe) // We've already interpreted all the elements { @@ -2527,7 +2449,8 @@ public: return; } - Type tn = e.type.toBasetype().nextOf().toBasetype(); + Type tb = e.type.toBasetype(); + Type tn = tb.nextOf().toBasetype(); bool wantCopy = (tn.ty == Tsarray || tn.ty == Tstruct); auto basis = interpretRegion(e.basis, istate); @@ -2536,6 +2459,7 @@ public: auto expsx = e.elements; size_t dim = expsx ? expsx.length : 0; + for (size_t i = 0; i < dim; i++) { Expression exp = (*expsx)[i]; @@ -4049,6 +3973,8 @@ public: */ private Expression interpretAssignToSlice(UnionExp* pue, BinExp e, Expression e1, Expression newval, bool isBlockAssignment) { + //printf("interpretAssignToSlice(e: %s e1: %s newval: %s\n", e.toChars(), e1.toChars(), newval.toChars()); + dinteger_t lowerbound; dinteger_t upperbound; dinteger_t firstIndex; @@ -4108,7 +4034,7 @@ public: return newval; // For slice assignment, we check that the lengths match. - if (!isBlockAssignment) + if (!isBlockAssignment && e1.type.ty != Tpointer) { const srclen = resolveArrayLength(newval); if (srclen != (upperbound - lowerbound)) @@ -4323,8 +4249,8 @@ public: Expression assignTo(ArrayLiteralExp ae, size_t lwr, size_t upr) { Expressions* w = ae.elements; - assert(ae.type.ty == Tsarray || ae.type.ty == Tarray); - bool directblk = (cast(TypeArray)ae.type).next.equivalent(newval.type); + assert(ae.type.ty == Tsarray || ae.type.ty == Tarray || ae.type.ty == Tpointer); + bool directblk = (cast(TypeNext)ae.type).next.equivalent(newval.type); for (size_t k = lwr; k < upr; k++) { if (!directblk && (*w)[k].op == EXP.arrayLiteral) @@ -4848,25 +4774,6 @@ public: result = CTFEExp.voidexp; return; } - else if (fd.ident == Id._d_arraysetlengthT) - { - // In expressionsem.d `ea.length = eb;` got lowered to `_d_arraysetlengthT(ea, eb);`. - // The following code will rewrite it back to `ea.length = eb` and then interpret that expression. - assert(e.arguments.length == 2); - - Expression ea = (*e.arguments)[0]; - Expression eb = (*e.arguments)[1]; - - auto ale = ctfeEmplaceExp!ArrayLengthExp(e.loc, ea); - ale.type = Type.tsize_t; - AssignExp ae = ctfeEmplaceExp!AssignExp(e.loc, ale, eb); - ae.type = ea.type; - - // if (global.params.verbose) - // message("interpret %s =>\n %s", e.toChars(), ae.toChars()); - result = interpretRegion(ae, istate); - return; - } else if (isArrayConstructionOrAssign(fd.ident)) { // In expressionsem.d, the following lowerings were performed: @@ -5847,7 +5754,25 @@ public: e2 = ue2.copy(); } - *pue = ctfeCat(e.loc, e.type, e1, e2); + Expression prepareCatOperand(Expression exp) + { + /* Convert `elem ~ array` to `[elem] ~ array` if `elem` is itself an + * array. This is needed because interpreting the `CatExp` calls + * `Cat()`, which cannot handle concatenations between different + * types, except for strings and chars. + */ + auto tb = e.type.toBasetype(); + auto tbNext = tb.nextOf(); + auto expTb = exp.type.toBasetype(); + + if (exp.type.implicitConvTo(tbNext) >= MATCH.convert && + (tb.ty == Tarray || tb.ty == Tsarray) && + (expTb.ty == Tarray || expTb.ty == Tsarray)) + return new ArrayLiteralExp(exp.loc, e.type, exp); + return exp; + } + + *pue = ctfeCat(e.loc, e.type, prepareCatOperand(e1), prepareCatOperand(e2)); result = pue.exp(); if (CTFEExp.isCantExp(result)) @@ -6208,15 +6133,18 @@ public: { printf("%s ThrowExpression::interpret()\n", te.loc.toChars()); } - interpretThrow(te.e1, te.loc); + interpretThrow(result, te.e1, te.loc, istate); } override void visit(PtrExp e) { + // Called for both lvalues and rvalues + const lvalue = goal == CTFEGoal.LValue; debug (LOG) { - printf("%s PtrExp::interpret() %s\n", e.loc.toChars(), e.toChars()); + printf("%s PtrExp::interpret(%d) %s, %s\n", e.loc.toChars(), lvalue, e.type.toChars(), e.toChars()); } + // Check for int<->float and long<->double casts. if (auto soe1 = e.e1.isSymOffExp()) if (soe1.offset == 0 && soe1.var.isVarDeclaration() && isFloatIntPaint(e.type, soe1.var.type)) @@ -6274,6 +6202,20 @@ public: return; } + if (!lvalue && result.isArrayLiteralExp() && + result.type.isTypePointer()) + { + /* A pointer variable can point to an array literal like `[3]`. + * Dereferencing it means accessing the first element value. + * Dereference it only if result should be an rvalue + */ + auto ae = result.isArrayLiteralExp(); + if (ae.elements.length == 1) + { + result = (*ae.elements)[0]; + return; + } + } if (result.isStringExp() || result.isArrayLiteralExp()) return; @@ -6514,33 +6456,57 @@ public: { assert(0); // This should never be interpreted } +} - /********************************************* - * Checks if the given expresion is a call to the runtime hook `id`. - * Params: - * e = the expression to check - * id = the identifier of the runtime hook - * Returns: - * `e` cast to `CallExp` if it's the hook, `null` otherwise - */ - private CallExp isRuntimeHook(Expression e, Identifier id) +/// Interpret `throw <exp>` found at the specified location `loc` +private +void interpretThrow(ref Expression result, Expression exp, const ref Loc loc, InterState* istate) +{ + incUsageCtfe(istate, loc); + + Expression e = interpretRegion(exp, istate); + if (exceptionOrCantInterpret(e)) { - if (auto ce = e.isCallExp()) + // Make sure e is not pointing to a stack temporary + result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e; + } + else if (e.op == EXP.classReference) + { + result = ctfeEmplaceExp!ThrownExceptionExp(loc, e.isClassReferenceExp()); + } + else + { + exp.error("to be thrown `%s` must be non-null", exp.toChars()); + result = ErrorExp.get(); + } +} + +/********************************************* + * Checks if the given expresion is a call to the runtime hook `id`. + * + * Params: + * e = the expression to check + * id = the identifier of the runtime hook + * Returns: + * `e` cast to `CallExp` if it's the hook, `null` otherwise + */ +public CallExp isRuntimeHook(Expression e, Identifier id) +{ + if (auto ce = e.isCallExp()) + { + if (auto ve = ce.e1.isVarExp()) { - if (auto ve = ce.e1.isVarExp()) + if (auto fd = ve.var.isFuncDeclaration()) { - if (auto fd = ve.var.isFuncDeclaration()) - { - // If `_d_HookTraceImpl` is found, resolve the underlying - // hook and replace `e` and `fd` with it. - removeHookTraceImpl(ce, fd); - return fd.ident == id ? ce : null; - } + // If `_d_HookTraceImpl` is found, resolve the underlying hook + // and replace `e` and `fd` with it. + removeHookTraceImpl(ce, fd); + return fd.ident == id ? ce : null; } } - - return null; } + + return null; } /******************************************** @@ -6558,10 +6524,12 @@ Expression interpret(UnionExp* pue, Expression e, InterState* istate, CTFEGoal g { if (!e) return null; + //printf("+interpret() e : %s, %s\n", e.type.toChars(), e.toChars()); scope Interpreter v = new Interpreter(pue, istate, goal); e.accept(v); Expression ex = v.result; assert(goal == CTFEGoal.Nothing || ex !is null); + //if (ex) printf("-interpret() ex: %s, %s\n", ex.type.toChars(), ex.toChars()); else printf("-interpret()\n"); return ex; } @@ -6608,34 +6576,135 @@ Expression interpretRegion(Expression e, InterState* istate, CTFEGoal goal = CTF return cast(Expression)memcpy(p, cast(void*)uexp, uexp.size); } -/*********************************** - * Interpret the statement. - * Params: - * pue = non-null pointer to temporary storage that can be used to store the return value - * s = Statement to interpret - * istate = context - * Returns: - * NULL continue to next statement - * EXP.cantExpression cannot interpret statement at compile time - * !NULL expression from return statement, or thrown exception +private +Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original) +{ + if (exps is original) + { + if (!original) + exps = new Expressions(); + else + exps = original.copy(); + ++ctfeGlobals.numArrayAllocs; + } + return exps; +} + +/** + Given an expression e which is about to be returned from the current + function, generate an error if it contains pointers to local variables. + + Only checks expressions passed by value (pointers to local variables + may already be stored in members of classes, arrays, or AAs which + were passed as mutable function parameters). + Returns: + true if it is safe to return, false if an error was generated. */ -Expression interpret(UnionExp* pue, Statement s, InterState* istate) +private +bool stopPointersEscaping(const ref Loc loc, Expression e) { - if (!s) - return null; - scope Interpreter v = new Interpreter(pue, istate, CTFEGoal.Nothing); - s.accept(v); - return v.result; + if (!e.type.hasPointers()) + return true; + if (isPointer(e.type)) + { + Expression x = e; + if (auto eaddr = e.isAddrExp()) + x = eaddr.e1; + VarDeclaration v; + while (x.op == EXP.variable && (v = x.isVarExp().var.isVarDeclaration()) !is null) + { + if (v.storage_class & STC.ref_) + { + x = getValue(v); + if (auto eaddr = e.isAddrExp()) + eaddr.e1 = x; + continue; + } + if (ctfeGlobals.stack.isInCurrentFrame(v)) + { + error(loc, "returning a pointer to a local stack variable"); + return false; + } + else + break; + } + // TODO: If it is a EXP.dotVariable or EXP.index, we should check that it is not + // pointing to a local struct or static array. + } + if (auto se = e.isStructLiteralExp()) + { + return stopPointersEscapingFromArray(loc, se.elements); + } + if (auto ale = e.isArrayLiteralExp()) + { + return stopPointersEscapingFromArray(loc, ale.elements); + } + if (auto aae = e.isAssocArrayLiteralExp()) + { + if (!stopPointersEscapingFromArray(loc, aae.keys)) + return false; + return stopPointersEscapingFromArray(loc, aae.values); + } + return true; } -/// -Expression interpret(Statement s, InterState* istate) +// Check all elements of an array for escaping local variables. Return false if error +private +bool stopPointersEscapingFromArray(const ref Loc loc, Expressions* elems) { - UnionExp ue = void; - auto result = interpret(&ue, s, istate); - if (result == ue.exp()) - result = ue.copy(); - return result; + foreach (e; *elems) + { + if (e && !stopPointersEscaping(loc, e)) + return false; + } + return true; +} + +private +Statement findGotoTarget(InterState* istate, Identifier ident) +{ + Statement target = null; + if (ident) + { + LabelDsymbol label = istate.fd.searchLabel(ident); + assert(label && label.statement); + LabelStatement ls = label.statement; + target = ls.gotoTarget ? ls.gotoTarget : ls.statement; + } + return target; +} + +private +ThrownExceptionExp chainExceptions(ThrownExceptionExp oldest, ThrownExceptionExp newest) +{ + debug (LOG) + { + printf("Collided exceptions %s %s\n", oldest.thrown.toChars(), newest.thrown.toChars()); + } + // Little sanity check to make sure it's really a Throwable + ClassReferenceExp boss = oldest.thrown; + const next = 5; // index of Throwable.next + assert((*boss.value.elements)[next].type.ty == Tclass); // Throwable.next + ClassReferenceExp collateral = newest.thrown; + if (collateral.originalClass().isErrorException() && !boss.originalClass().isErrorException()) + { + /* Find the index of the Error.bypassException field + */ + auto bypass = next + 1; + if ((*collateral.value.elements)[bypass].type.ty == Tuns32) + bypass += 1; // skip over _refcount field + assert((*collateral.value.elements)[bypass].type.ty == Tclass); + + // The new exception bypass the existing chain + (*collateral.value.elements)[bypass] = boss; + return newest; + } + while ((*boss.value.elements)[next].op == EXP.classReference) + { + boss = (*boss.value.elements)[next].isClassReferenceExp(); + } + (*boss.value.elements)[next] = collateral; + return oldest; } /** @@ -6978,7 +7047,6 @@ private Expression copyRegionExp(Expression e) case EXP.null_: case EXP.void_: case EXP.symbolOffset: - case EXP.char_: break; case EXP.cantExpression: diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index a5f7cd3..149a5b1 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -767,7 +767,7 @@ extern (C++) final class Module : Package { filetype = FileType.c; - scope p = new CParser!AST(this, buf, cast(bool) docfile, global.errorSink, target.c, &defines); + scope p = new CParser!AST(this, buf, cast(bool) docfile, global.errorSink, target.c, &defines, &global.compileEnv); p.nextToken(); checkCompiledImport(); members = p.parseModule(); @@ -776,7 +776,9 @@ extern (C++) final class Module : Package } else { - scope p = new Parser!AST(this, buf, cast(bool) docfile, global.errorSink); + const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput; + scope p = new Parser!AST(this, buf, cast(bool) docfile, global.errorSink, &global.compileEnv, doUnittests); + p.transitionIn = global.params.vin; p.nextToken(); p.parseModuleDeclaration(); md = p.md; @@ -1229,8 +1231,7 @@ extern (C++) final class Module : Package return this.importedFrom == this; } - // true if the module source file is directly - // listed in command line. + /// Returns: Whether this module is in the `core` package and has name `ident` bool isCoreModule(Identifier ident) nothrow { return this.ident == ident && parent && parent.ident == Id.core && !parent.parent; @@ -1287,6 +1288,20 @@ extern (C++) final class Module : Package } /**************************** + * A Singleton that loads core.stdc.config + * Returns: + * Module of core.stdc.config, null if couldn't find it + */ + extern (D) static Module loadCoreStdcConfig() + { + __gshared Module core_stdc_config; + auto pkgids = new Identifier[2]; + pkgids[0] = Id.core; + pkgids[1] = Id.stdc; + return loadModuleFromLibrary(core_stdc_config, pkgids, Id.config); + } + + /**************************** * A Singleton that loads core.atomic * Returns: * Module of core.atomic, null if couldn't find it @@ -1294,7 +1309,9 @@ extern (C++) final class Module : Package extern (D) static Module loadCoreAtomic() { __gshared Module core_atomic; - return loadModuleFromLibrary(core_atomic, Id.core, Id.atomic); + auto pkgids = new Identifier[1]; + pkgids[0] = Id.core; + return loadModuleFromLibrary(core_atomic, pkgids, Id.atomic); } /**************************** @@ -1305,26 +1322,26 @@ extern (C++) final class Module : Package extern (D) static Module loadStdMath() { __gshared Module std_math; - return loadModuleFromLibrary(std_math, Id.std, Id.math); + auto pkgids = new Identifier[1]; + pkgids[0] = Id.std; + return loadModuleFromLibrary(std_math, pkgids, Id.math); } /********************************** * Load a Module from the library. * Params: * mod = cached return value of this call - * pkgid = package id + * pkgids = package identifiers * modid = module id * Returns: * Module loaded, null if cannot load it */ - private static Module loadModuleFromLibrary(ref Module mod, Identifier pkgid, Identifier modid) + extern (D) private static Module loadModuleFromLibrary(ref Module mod, Identifier[] pkgids, Identifier modid) { if (mod) return mod; - auto ids = new Identifier[1]; - ids[0] = pkgid; - auto imp = new Import(Loc.initial, ids[], modid, null, true); + auto imp = new Import(Loc.initial, pkgids[], modid, null, true); // Module.load will call fatal() if there's no module available. // Gag the error here, pushing the error handling to the caller. const errors = global.startGagging(); diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index 88e8996..7674f77 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -5184,7 +5184,7 @@ private void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t of scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1, global.errorSink, - global.vendor, global.versionNumber()); + &global.compileEnv); OutBuffer res; const(char)* lastp = cast(char*)buf[].ptr; //printf("highlightCode2('%.*s')\n", cast(int)(buf.length - 1), buf[].ptr); diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index ab422fd..95cfec9 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -813,4 +813,14 @@ extern (C++) struct Scope { return this.intypeof || this.flags & SCOPE.compile; } + + + /** + * Returns: true if the code needs to go all the way through to code generation. + * This implies things like needing lowering to simpler forms. + */ + extern (D) bool needsCodegen() + { + return (flags & (SCOPE.ctfe | SCOPE.ctfeBlock | SCOPE.compile)) == 0; + } } diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index 3268d56..49b9841 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -13,6 +13,8 @@ module dmd.dstruct; +import core.stdc.stdio; + import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; @@ -75,7 +77,7 @@ extern (C++) void semanticTypeInfo(Scope* sc, Type t) { if (sc.intypeof) return; - if (sc.flags & (SCOPE.ctfe | SCOPE.compile | SCOPE.ctfeBlock)) + if (!sc.needsCodegen()) return; } @@ -567,7 +569,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration * Returns: * true if it's all binary 0 */ -private bool _isZeroInit(Expression exp) +bool _isZeroInit(Expression exp) { switch (exp.op) { @@ -575,20 +577,22 @@ private bool _isZeroInit(Expression exp) return exp.toInteger() == 0; case EXP.null_: - case EXP.false_: return true; case EXP.structLiteral: { - auto sle = cast(StructLiteralExp) exp; + auto sle = exp.isStructLiteralExp(); + if (sle.sd.isNested()) + return false; + const isCstruct = sle.sd.isCsymbol(); // C structs are default initialized to all zeros foreach (i; 0 .. sle.sd.fields.length) { auto field = sle.sd.fields[i]; if (field.type.size(field.loc)) { - auto e = (*sle.elements)[i]; + auto e = sle.elements && i < sle.elements.length ? (*sle.elements)[i] : null; if (e ? !_isZeroInit(e) - : !field.type.isZeroInit(field.loc)) + : !isCstruct && !field.type.isZeroInit(field.loc)) return false; } } diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index e7ce93e..2373313 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -1407,7 +1407,7 @@ extern (C++) class Dsymbol : ASTNode inout(CPPNamespaceDeclaration) isCPPNamespaceDeclaration() inout { return null; } inout(VisibilityDeclaration) isVisibilityDeclaration() inout { return null; } inout(OverloadSet) isOverloadSet() inout { return null; } - inout(CompileDeclaration) isCompileDeclaration() inout { return null; } + inout(MixinDeclaration) isMixinDeclaration() inout { return null; } inout(StaticAssert) isStaticAssert() inout { return null; } inout(StaticIfDeclaration) isStaticIfDeclaration() inout { return null; } } diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index 039a288..96fa8fd 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -321,7 +321,7 @@ public: virtual CPPNamespaceDeclaration *isCPPNamespaceDeclaration() { return NULL; } virtual VisibilityDeclaration *isVisibilityDeclaration() { return NULL; } virtual OverloadSet *isOverloadSet() { return NULL; } - virtual CompileDeclaration *isCompileDeclaration() { return NULL; } + virtual MixinDeclaration *isMixinDeclaration() { return NULL; } virtual StaticAssert *isStaticAssert() { return NULL; } virtual StaticIfDeclaration *isStaticIfDeclaration() { return NULL; } void accept(Visitor *v) override { v->visit(this); } diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 0f0ed2a..506946f 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -1321,6 +1321,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (dsym.errors) return; + if (!(global.params.bitfields || sc.flags & SCOPE.Cfile)) + dsym.error("use -preview=bitfields for bitfield support"); + if (!dsym.parent.isStructDeclaration() && !dsym.parent.isClassDeclaration()) { dsym.error("- bit-field must be member of struct, union, or class"); @@ -1923,9 +1926,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor attribSemantic(sfd); } - private Dsymbols* compileIt(CompileDeclaration cd) + private Dsymbols* compileIt(MixinDeclaration cd) { - //printf("CompileDeclaration::compileIt(loc = %d) %s\n", cd.loc.linnum, cd.exp.toChars()); + //printf("MixinDeclaration::compileIt(loc = %d) %s\n", cd.loc.linnum, cd.exp.toChars()); OutBuffer buf; if (expressionsToString(buf, sc, cd.exps)) return null; @@ -1934,7 +1937,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - scope p = new Parser!ASTCodegen(cd.loc, sc._module, str, false, global.errorSink); + const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput; + auto loc = adjustLocForMixin(str, cd.loc, global.params.mixinOut); + scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests); + p.transitionIn = global.params.vin; p.nextToken(); auto d = p.parseDeclDefs(0); @@ -1952,9 +1958,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor /*********************************************************** * https://dlang.org/spec/module.html#mixin-declaration */ - override void visit(CompileDeclaration cd) + override void visit(MixinDeclaration cd) { - //printf("CompileDeclaration::semantic()\n"); + //printf("MixinDeclaration::semantic()\n"); if (!cd.compiled) { cd.decl = compileIt(cd); @@ -2252,32 +2258,39 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { /* C11 6.7.2.2 */ - assert(ed.memtype); - int nextValue = 0; // C11 6.7.2.2-3 first member value defaults to 0 + Type commonType = ed.memtype; + if (!commonType) + commonType = Type.tint32; + ulong nextValue = 0; // C11 6.7.2.2-3 first member value defaults to 0 // C11 6.7.2.2-2 value must be representable as an int. // The sizemask represents all values that int will fit into, // from 0..uint.max. We want to cover int.min..uint.max. - const mask = Type.tint32.sizemask(); - IntRange ir = IntRange(SignExtendedNumber(~(mask >> 1), true), - SignExtendedNumber(mask)); + IntRange ir = IntRange.fromType(commonType); - void emSemantic(EnumMember em, ref int nextValue) + void emSemantic(EnumMember em, ref ulong nextValue) { static void errorReturn(EnumMember em) { + em.value = ErrorExp.get(); em.errors = true; em.semanticRun = PASS.semanticdone; } em.semanticRun = PASS.semantic; - em.type = Type.tint32; + em.type = commonType; em._linkage = LINK.c; em.storage_class |= STC.manifest; if (em.value) { Expression e = em.value; assert(e.dyncast() == DYNCAST.expression); + + /* To merge the type of e with commonType, add 0 of type commonType + */ + if (!ed.memtype) + e = new AddExp(em.loc, e, new IntegerExp(em.loc, 0, commonType)); + e = e.expressionSemantic(sc); e = resolveProperties(sc, e); e = e.integralPromotions(sc); @@ -2291,14 +2304,16 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor em.error("enum member must be an integral constant expression, not `%s` of type `%s`", e.toChars(), e.type.toChars()); return errorReturn(em); } - if (!ir.contains(getIntRange(ie))) + if (ed.memtype && !ir.contains(getIntRange(ie))) { // C11 6.7.2.2-2 - em.error("enum member value `%s` does not fit in an `int`", e.toChars()); + em.error("enum member value `%s` does not fit in `%s`", e.toChars(), commonType.toChars()); return errorReturn(em); } - nextValue = cast(int)ie.toInteger(); - em.value = new IntegerExp(em.loc, nextValue, Type.tint32); + nextValue = ie.toInteger(); + if (!ed.memtype) + commonType = e.type; + em.value = new IntegerExp(em.loc, nextValue, commonType); } else { @@ -2306,17 +2321,17 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor bool first = (em == (*em.ed.members)[0]); if (!first) { - import core.checkedint : adds; - bool overflow; - nextValue = adds(nextValue, 1, overflow); - if (overflow) + Expression max = getProperty(commonType, null, em.loc, Id.max, 0); + if (nextValue == max.toInteger()) { - em.error("initialization with `%d+1` causes overflow for type `int`", nextValue - 1); + em.error("initialization with `%s+1` causes overflow for type `%s`", max.toChars(), commonType.toChars()); return errorReturn(em); } + nextValue += 1; } - em.value = new IntegerExp(em.loc, nextValue, Type.tint32); + em.value = new IntegerExp(em.loc, nextValue, commonType); } + em.type = commonType; em.semanticRun = PASS.semanticdone; } @@ -2325,6 +2340,21 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (EnumMember em = s.isEnumMember()) emSemantic(em, nextValue); }); + + if (!ed.memtype) + { + // cast all members to commonType + ed.members.foreachDsymbol( (s) + { + if (EnumMember em = s.isEnumMember()) + { + em.type = commonType; + em.value = em.value.castTo(sc, commonType); + } + }); + } + + ed.memtype = commonType; ed.semanticRun = PASS.semanticdone; return; } @@ -4662,7 +4692,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { sd.visibility = sc.visibility; - sd.alignment = sc.alignment(); + if (sd.alignment.isUnknown()) // can be set already by `struct __declspec(align(N)) Tag { ... }` + sd.alignment = sc.alignment(); sd.storage_class |= sc.stc; if (sd.storage_class & STC.abstract_) @@ -7228,3 +7259,83 @@ PINLINE evalPragmaInline(Loc loc, Scope* sc, Expressions* args) else return PINLINE.never; } + +/*************************************************** + * Set up loc for a parse of a mixin. Append the input text to the mixin. + * Params: + * input = mixin text + * loc = location to adjust + * mixinOut = sink for mixin text data + * Returns: + * adjusted loc suitable for Parser + */ + +Loc adjustLocForMixin(const(char)[] input, ref const Loc loc, ref Output mixinOut) +{ + Loc result; + if (mixinOut.doOutput) + { + const lines = mixinOut.bufferLines; + writeMixin(input, loc, mixinOut.bufferLines, *mixinOut.buffer); + result = Loc(mixinOut.name.ptr, lines + 2, loc.charnum); + } + else if (loc.filename) + { + /* Create a pseudo-filename for the mixin string, as it may not even exist + * in the source file. + */ + auto len = strlen(loc.filename) + 7 + (loc.linnum).sizeof * 3 + 1; + char* filename = cast(char*)mem.xmalloc(len); + snprintf(filename, len, "%s-mixin-%d", loc.filename, cast(int)loc.linnum); + result = Loc(filename, loc.linnum, loc.charnum); + } + else + result = loc; + return result; +} + +/************************************** + * Append source code text to output for better debugging. + * Canonicalize line endings. + * Params: + * s = source code text + * loc = location of source code text + * lines = line count to update + * output = sink for output + */ +private void writeMixin(const(char)[] s, ref const Loc loc, ref int lines, ref OutBuffer buf) +{ + buf.writestring("// expansion at "); + buf.writestring(loc.toChars()); + buf.writenl(); + + ++lines; + + // write by line to create consistent line endings + size_t lastpos = 0; + for (size_t i = 0; i < s.length; ++i) + { + // detect LF and CRLF + const c = s[i]; + if (c == '\n' || (c == '\r' && i+1 < s.length && s[i+1] == '\n')) + { + buf.writestring(s[lastpos .. i]); + buf.writenl(); + ++lines; + if (c == '\r') + ++i; + lastpos = i + 1; + } + } + + if(lastpos < s.length) + buf.writestring(s[lastpos .. $]); + + if (s.length == 0 || s[$-1] != '\n') + { + buf.writenl(); // ensure empty line after expansion + ++lines; + } + buf.writenl(); + ++lines; +} diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index ad3a6d4..ef743d6 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -741,9 +741,6 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol const(char)* toCharsMaybeConstraints(bool includeConstraints) const { - if (literal) - return Dsymbol.toChars(); - OutBuffer buf; HdrGenState hgs; @@ -1858,19 +1855,16 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol Type taai; if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0)) { - if (farg.op == EXP.string_) + if (StringExp se = farg.isStringExp()) { - StringExp se = cast(StringExp)farg; argtype = se.type.nextOf().sarrayOf(se.len); } - else if (farg.op == EXP.arrayLiteral) + else if (ArrayLiteralExp ae = farg.isArrayLiteralExp()) { - ArrayLiteralExp ae = cast(ArrayLiteralExp)farg; argtype = ae.type.nextOf().sarrayOf(ae.elements.length); } - else if (farg.op == EXP.slice) + else if (SliceExp se = farg.isSliceExp()) { - SliceExp se = cast(SliceExp)farg; if (Type tsa = toStaticArrayType(se)) argtype = tsa; } @@ -2283,18 +2277,23 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol Declaration d; VarDeclaration v = null; - if (ea && ea.op == EXP.type) - ta = ea.type; - else if (ea && ea.op == EXP.scope_) - sa = (cast(ScopeExp)ea).sds; - else if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_)) - sa = (cast(ThisExp)ea).var; - else if (ea && ea.op == EXP.function_) + if (ea) { - if ((cast(FuncExp)ea).td) - sa = (cast(FuncExp)ea).td; - else - sa = (cast(FuncExp)ea).fd; + if (ea.op == EXP.type) + ta = ea.type; + else if (auto se = ea.isScopeExp()) + sa = se.sds; + else if (auto te = ea.isThisExp()) + sa = te.var; + else if (auto se = ea.isSuperExp()) + sa = se.var; + else if (auto fe = ea.isFuncExp()) + { + if (fe.td) + sa = fe.td; + else + sa = fe.fd; + } } if (ta) @@ -3856,9 +3855,9 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param if (tparam.ty == Tsarray) { TypeSArray tsa = cast(TypeSArray)tparam; - if (tsa.dim.op == EXP.variable && (cast(VarExp)tsa.dim).var.storage_class & STC.templateparameter) + if (tsa.dim.isVarExp() && tsa.dim.isVarExp().var.storage_class & STC.templateparameter) { - Identifier id = (cast(VarExp)tsa.dim).var.ident; + Identifier id = tsa.dim.isVarExp().var.ident; i = templateIdentifierLookup(id, parameters); assert(i != IDX_NOTFOUND); tp = (*parameters)[i]; @@ -4250,12 +4249,12 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param /* If it is one of the template parameters for this template, * we should not attempt to interpret it. It already has a value. */ - if (e2.op == EXP.variable && ((cast(VarExp)e2).var.storage_class & STC.templateparameter)) + if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter)) { /* * (T:Number!(e2), int e2) */ - j = templateIdentifierLookup((cast(VarExp)e2).var.ident, parameters); + j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters); if (j != IDX_NOTFOUND) goto L1; // The template parameter was not from this template @@ -5236,7 +5235,7 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam override void visit(DotTemplateInstanceExp e) { //printf("DotTemplateInstanceExp.reliesOnTemplateParameters('%s')\n", e.toChars()); - visit(cast(UnaExp)e); + visit(e.isUnaExp()); if (!result && e.ti.tiargs) { foreach (oa; *e.ti.tiargs) @@ -5254,7 +5253,7 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam override void visit(CallExp e) { //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars()); - visit(cast(UnaExp)e); + visit(e.isUnaExp()); if (!result && e.arguments) { foreach (ea; *e.arguments) @@ -5269,7 +5268,7 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam override void visit(CastExp e) { //printf("CallExp.reliesOnTemplateParameters('%s')\n", e.toChars()); - visit(cast(UnaExp)e); + visit(e.isUnaExp()); // e.to can be null for cast() with no type if (!result && e.to) result = e.to.reliesOnTemplateParameters(tparams); @@ -5278,7 +5277,7 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam override void visit(SliceExp e) { //printf("SliceExp.reliesOnTemplateParameters('%s')\n", e.toChars()); - visit(cast(UnaExp)e); + visit(e.isUnaExp()); if (!result && e.lwr) e.lwr.accept(this); if (!result && e.upr) @@ -5296,7 +5295,7 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam override void visit(ArrayExp e) { //printf("ArrayExp.reliesOnTemplateParameters('%s')\n", e.toChars()); - visit(cast(UnaExp)e); + visit(e.isUnaExp()); if (!result && e.arguments) { foreach (ea; *e.arguments) @@ -5317,7 +5316,7 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam //printf("BinExp.reliesOnTemplateParameters('%s')\n", e.toChars()); e.econd.accept(this); if (!result) - visit(cast(BinExp)e); + visit(e.isBinExp()); } } @@ -6727,7 +6726,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol ea = ea.expressionSemantic(sc); // must not interpret the args, excepting template parameters - if (ea.op != EXP.variable || ((cast(VarExp)ea).var.storage_class & STC.templateparameter)) + if (!ea.isVarExp() || (ea.isVarExp().var.storage_class & STC.templateparameter)) { ea = ea.optimize(WANTvalue); } @@ -6738,13 +6737,13 @@ extern (C++) class TemplateInstance : ScopeDsymbol ea = ea.expressionSemantic(sc); sc = sc.endCTFE(); - if (ea.op == EXP.variable) + if (auto varExp = ea.isVarExp()) { /* If the parameter is a function that is not called * explicitly, i.e. `foo!func` as opposed to `foo!func()`, * then it is a dsymbol, not the return value of `func()` */ - Declaration vd = (cast(VarExp)ea).var; + Declaration vd = varExp.var; if (auto fd = vd.isFuncDeclaration()) { sa = fd; @@ -6767,10 +6766,9 @@ extern (C++) class TemplateInstance : ScopeDsymbol } } //printf("-[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars()); - if (ea.op == EXP.tuple) + if (TupleExp te = ea.isTupleExp()) { // Expand tuple - TupleExp te = cast(TupleExp)ea; size_t dim = te.exps.length; tiargs.remove(j); if (dim) @@ -6796,12 +6794,11 @@ extern (C++) class TemplateInstance : ScopeDsymbol } if (ea.op == EXP.scope_) { - sa = (cast(ScopeExp)ea).sds; + sa = ea.isScopeExp().sds; goto Ldsym; } - if (ea.op == EXP.function_) + if (FuncExp fe = ea.isFuncExp()) { - FuncExp fe = cast(FuncExp)ea; /* A function literal, that is passed to template and * already semanticed as function pointer, never requires * outer frame. So convert it to global function is valid. @@ -6823,23 +6820,23 @@ extern (C++) class TemplateInstance : ScopeDsymbol if (ea.op == EXP.dotVariable && !(flags & 1)) { // translate expression to dsymbol. - sa = (cast(DotVarExp)ea).var; + sa = ea.isDotVarExp().var; goto Ldsym; } - if (ea.op == EXP.template_) + if (auto te = ea.isTemplateExp()) { - sa = (cast(TemplateExp)ea).td; + sa = te.td; goto Ldsym; } if (ea.op == EXP.dotTemplateDeclaration && !(flags & 1)) { // translate expression to dsymbol. - sa = (cast(DotTemplateExp)ea).td; + sa = ea.isDotTemplateExp().td; goto Ldsym; } - if (ea.op == EXP.dot) + if (auto de = ea.isDotExp()) { - if (auto se = (cast(DotExp)ea).e2.isScopeExp()) + if (auto se = de.e2.isScopeExp()) { sa = se.sds; goto Ldsym; @@ -7340,22 +7337,22 @@ extern (C++) class TemplateInstance : ScopeDsymbol Tuple va = isTuple(o); if (ea) { - if (ea.op == EXP.variable) + if (auto ve = ea.isVarExp()) { - sa = (cast(VarExp)ea).var; + sa = ve.var; goto Lsa; } - if (ea.op == EXP.this_) + if (auto te = ea.isThisExp()) { - sa = (cast(ThisExp)ea).var; + sa = te.var; goto Lsa; } - if (ea.op == EXP.function_) + if (auto fe = ea.isFuncExp()) { - if ((cast(FuncExp)ea).td) - sa = (cast(FuncExp)ea).td; + if (fe.td) + sa = fe.td; else - sa = (cast(FuncExp)ea).fd; + sa = fe.fd; goto Lsa; } // Emulate Expression.toMangleBuffer call that had exist in TemplateInstance.genIdent. @@ -7727,13 +7724,13 @@ bool definitelyValueParameter(Expression e) */ // x.y.f cannot be a value - FuncDeclaration f = (cast(DotVarExp)e).var.isFuncDeclaration(); + FuncDeclaration f = e.isDotVarExp().var.isFuncDeclaration(); if (f) return false; while (e.op == EXP.dotVariable) { - e = (cast(DotVarExp)e).e1; + e = e.isDotVarExp().e1; } // this.x.y and super.x.y couldn't possibly be valid values. if (e.op == EXP.this_ || e.op == EXP.super_) @@ -7747,7 +7744,7 @@ bool definitelyValueParameter(Expression e) if (e.op != EXP.variable) return true; - VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); + VarDeclaration v = e.isVarExp().var.isVarDeclaration(); // func.x.y is not an alias if (!v) return true; @@ -8242,10 +8239,15 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ Type ta = isType(oarg); RootObject sa = ta && !ta.deco ? null : getDsymbol(oarg); Expression ea = isExpression(oarg); - if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_)) - sa = (cast(ThisExp)ea).var; - else if (ea && ea.op == EXP.scope_) - sa = (cast(ScopeExp)ea).sds; + if (ea) + { + if (auto te = ea.isThisExp()) + sa = te.var; + else if (auto se = ea.isSuperExp()) + sa = se.var; + else if (auto se = ea.isScopeExp()) + sa = se.sds; + } if (sa) { if ((cast(Dsymbol)sa).isAggregateDeclaration()) diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 7c3ff4b..f00b8db 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -84,9 +84,9 @@ extern(C++) void genCppHdrFiles(ref Modules ms) m.accept(v); if (global.params.cxxhdr.fullOutput) - buf.printf("// Automatically generated by %s Compiler v%d", global.vendor.ptr, global.versionNumber()); + buf.printf("// Automatically generated by %s Compiler v%d", global.compileEnv.vendor.ptr, global.versionNumber()); else - buf.printf("// Automatically generated by %s Compiler", global.vendor.ptr); + buf.printf("// Automatically generated by %s Compiler", global.compileEnv.vendor.ptr); buf.writenl(); buf.writenl(); diff --git a/gcc/d/dmd/errors.d b/gcc/d/dmd/errors.d index f107f7b..287dc49 100644 --- a/gcc/d/dmd/errors.d +++ b/gcc/d/dmd/errors.d @@ -66,6 +66,14 @@ class ErrorSinkCompiler : ErrorSink vdeprecationSupplemental(loc, format, ap); va_end(ap); } + + void message(const ref Loc loc, const(char)* format, ...) + { + va_list ap; + va_start(ap, format); + vmessage(loc, format, ap); + va_end(ap); + } } diff --git a/gcc/d/dmd/errorsink.d b/gcc/d/dmd/errorsink.d index b519db7..e57c2b6 100644 --- a/gcc/d/dmd/errorsink.d +++ b/gcc/d/dmd/errorsink.d @@ -27,6 +27,8 @@ abstract class ErrorSink void warning(const ref Loc loc, const(char)* format, ...); + void message(const ref Loc loc, const(char)* format, ...); + void deprecation(const ref Loc loc, const(char)* format, ...); void deprecationSupplemental(const ref Loc loc, const(char)* format, ...); @@ -47,6 +49,8 @@ class ErrorSinkNull : ErrorSink void warning(const ref Loc loc, const(char)* format, ...) { } + void message(const ref Loc loc, const(char)* format, ...) { } + void deprecation(const ref Loc loc, const(char)* format, ...) { } void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { } @@ -117,5 +121,21 @@ class ErrorSinkStderr : ErrorSink va_end(ap); } + void message(const ref Loc loc, const(char)* format, ...) + { + const p = loc.toChars(); + if (*p) + { + fprintf(stderr, "%s: ", p); + //mem.xfree(cast(void*)p); // loc should provide the free() + } + + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + fputc('\n', stderr); + va_end(ap); + } + void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { } } diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 420fa7f..4f1edaa 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -2377,7 +2377,7 @@ void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f) foreach (u, p; f.parameterList) { auto v = (*funcdecl.parameters)[u]; - if (!v.isScope() && inferScope(v)) + if (!v.isScope() && v.type.hasPointers() && inferScope(v)) { //printf("Inferring scope for %s\n", v.toChars()); p.storageClass |= STC.scope_ | STC.scopeinferred; diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index df5e9dd..067d22f 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -720,20 +720,21 @@ enum WANTexpand = 1; // expand const/immutable variables if possible */ extern (C++) abstract class Expression : ASTNode { - const EXP op; // to minimize use of dynamic_cast - ubyte size; // # of bytes in Expression so we can copy() it - bool parens; // if this is a parenthesized expression Type type; // !=null means that semantic() has been run Loc loc; // file location + const EXP op; // to minimize use of dynamic_cast + bool parens; // if this is a parenthesized expression - extern (D) this(const ref Loc loc, EXP op, int size) scope + extern (D) this(const ref Loc loc, EXP op) scope { //printf("Expression::Expression(op = %d) this = %p\n", op, this); this.loc = loc; this.op = op; - this.size = cast(ubyte)size; } + /// Returns: class instance size of this expression (implemented manually because `extern(C++)`) + final size_t size() nothrow @nogc pure @safe const { return expSize[op]; } + static void _init() { CTFEExp.cantexp = new CTFEExp(EXP.cantExpression); @@ -1219,12 +1220,15 @@ extern (C++) abstract class Expression : ASTNode return false; // If the call has a pure parent, then the called func must be pure. - if (!f.isPure() && checkImpure(sc)) + if (!f.isPure() && checkImpure(sc, loc, null, f)) { error("`pure` %s `%s` cannot call impure %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars()); + if (!f.isDtorDeclaration()) + errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.pure_); + checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure"); return true; } @@ -1355,7 +1359,7 @@ extern (C++) abstract class Expression : ASTNode if (v.ident == Id.gate) return false; - if (checkImpure(sc)) + if (checkImpure(sc, loc, "`pure` %s `%s` cannot access mutable static data `%s`", v)) { error("`pure` %s `%s` cannot access mutable static data `%s`", sc.func.kind(), sc.func.toPrettyChars(), v.toChars()); @@ -1431,11 +1435,11 @@ extern (C++) abstract class Expression : ASTNode Check if sc.func is impure or can be made impure. Returns true on error, i.e. if sc.func is pure and cannot be made impure. */ - private static bool checkImpure(Scope* sc) + private static bool checkImpure(Scope* sc, Loc loc, const(char)* fmt, RootObject arg0) { return sc.func && (isRootTraitsCompilesScope(sc) ? sc.func.isPureBypassingInference() >= PURE.weak - : sc.func.setImpure()); + : sc.func.setImpure(loc, fmt, arg0)); } /********************************************* @@ -1484,7 +1488,8 @@ extern (C++) abstract class Expression : ASTNode error("`@safe` %s `%s` cannot call `@system` %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), f.kind(), prettyChars); - f.errorSupplementalInferredSafety(/*max depth*/ 10, /*deprecation*/ false); + if (!f.isDtorDeclaration) + errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.safe); .errorSupplemental(f.loc, "`%s` is declared here", prettyChars); checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system"); @@ -1498,7 +1503,7 @@ extern (C++) abstract class Expression : ASTNode if (sc.func.isSafeBypassingInference()) { .deprecation(this.loc, "`@safe` function `%s` calling `%s`", sc.func.toChars(), f.toChars()); - errorSupplementalInferredSafety(f, 10, true); + errorSupplementalInferredAttr(f, 10, true, STC.safe); } else if (!sc.func.safetyViolation) { @@ -1528,7 +1533,7 @@ extern (C++) abstract class Expression : ASTNode if (!f.isNogc()) { - if (isRootTraitsCompilesScope(sc) ? sc.func.isNogcBypassingInference() : sc.func.setGC()) + if (isRootTraitsCompilesScope(sc) ? sc.func.isNogcBypassingInference() : sc.func.setGCCall(f)) { if (loc.linnum == 0) // e.g. implicitly generated dtor loc = sc.func.loc; @@ -1537,10 +1542,15 @@ extern (C++) abstract class Expression : ASTNode // so don't print anything to avoid double error messages. if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX - || f.ident == Id._d_newclassT)) + || f.ident == Id._d_arraycatnTX || f.ident == Id._d_newclassT)) + { error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars()); + if (!f.isDtorDeclaration) + f.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC.nogc); + } + checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().isnogc, "non-@nogc"); return true; @@ -1775,6 +1785,7 @@ extern (C++) abstract class Expression : ASTNode inout(PostExp) isPostExp() { return (op == EXP.plusPlus || op == EXP.minusMinus) ? cast(typeof(return))this : null; } inout(PreExp) isPreExp() { return (op == EXP.prePlusPlus || op == EXP.preMinusMinus) ? cast(typeof(return))this : null; } inout(AssignExp) isAssignExp() { return op == EXP.assign ? cast(typeof(return))this : null; } + inout(LoweredAssignExp) isLoweredAssignExp() { return op == EXP.loweredAssignExp ? cast(typeof(return))this : null; } inout(ConstructExp) isConstructExp() { return op == EXP.construct ? cast(typeof(return))this : null; } inout(BlitExp) isBlitExp() { return op == EXP.blit ? cast(typeof(return))this : null; } inout(AddAssignExp) isAddAssignExp() { return op == EXP.addAssign ? cast(typeof(return))this : null; } @@ -1866,7 +1877,7 @@ extern (C++) final class IntegerExp : Expression extern (D) this(const ref Loc loc, dinteger_t value, Type type) { - super(loc, EXP.int64, __traits(classInstanceSize, IntegerExp)); + super(loc, EXP.int64); //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : ""); assert(type); if (!type.isscalar()) @@ -1882,7 +1893,7 @@ extern (C++) final class IntegerExp : Expression extern (D) this(dinteger_t value) { - super(Loc.initial, EXP.int64, __traits(classInstanceSize, IntegerExp)); + super(Loc.initial, EXP.int64); this.type = Type.tint32; this.value = cast(int)value; } @@ -2082,7 +2093,7 @@ extern (C++) final class ErrorExp : Expression { private extern (D) this() { - super(Loc.initial, EXP.error, __traits(classInstanceSize, ErrorExp)); + super(Loc.initial, EXP.error); type = Type.terror; } @@ -2130,7 +2141,7 @@ extern (C++) final class VoidInitExp : Expression extern (D) this(VarDeclaration var) { - super(var.loc, EXP.void_, __traits(classInstanceSize, VoidInitExp)); + super(var.loc, EXP.void_); this.var = var; this.type = var.type; } @@ -2156,7 +2167,7 @@ extern (C++) final class RealExp : Expression extern (D) this(const ref Loc loc, real_t value, Type type) { - super(loc, EXP.float64, __traits(classInstanceSize, RealExp)); + super(loc, EXP.float64); //printf("RealExp::RealExp(%Lg)\n", value); this.value = value; this.type = type; @@ -2239,7 +2250,7 @@ extern (C++) final class ComplexExp : Expression extern (D) this(const ref Loc loc, complex_t value, Type type) { - super(loc, EXP.complex80, __traits(classInstanceSize, ComplexExp)); + super(loc, EXP.complex80); this.value = value; this.type = type; //printf("ComplexExp::ComplexExp(%s)\n", toChars()); @@ -2330,7 +2341,7 @@ extern (C++) class IdentifierExp : Expression extern (D) this(const ref Loc loc, Identifier ident) scope { - super(loc, EXP.identifier, __traits(classInstanceSize, IdentifierExp)); + super(loc, EXP.identifier); this.ident = ident; } @@ -2383,7 +2394,7 @@ extern (C++) final class DsymbolExp : Expression extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true) { - super(loc, EXP.dSymbol, __traits(classInstanceSize, DsymbolExp)); + super(loc, EXP.dSymbol); this.s = s; this.hasOverloads = hasOverloads; } @@ -2413,13 +2424,13 @@ extern (C++) class ThisExp : Expression extern (D) this(const ref Loc loc) { - super(loc, EXP.this_, __traits(classInstanceSize, ThisExp)); + super(loc, EXP.this_); //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum); } this(const ref Loc loc, const EXP tok) { - super(loc, tok, __traits(classInstanceSize, ThisExp)); + super(loc, tok); //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum); } @@ -2485,7 +2496,7 @@ extern (C++) final class NullExp : Expression { extern (D) this(const ref Loc loc, Type type = null) scope { - super(loc, EXP.null_, __traits(classInstanceSize, NullExp)); + super(loc, EXP.null_); this.type = type; } @@ -2529,6 +2540,8 @@ extern (C++) final class NullExp : Expression */ extern (C++) final class StringExp : Expression { + char postfix = NoPostfix; // 'c', 'w', 'd' + OwnedBy ownedByCtfe = OwnedBy.code; private union { char* string; // if sz == 1 @@ -2537,14 +2550,22 @@ extern (C++) final class StringExp : Expression } // (const if ownedByCtfe == OwnedBy.code) size_t len; // number of code units ubyte sz = 1; // 1: char, 2: wchar, 4: dchar - ubyte committed; // !=0 if type is committed + + /** + * Whether the string literal's type is fixed + * Example: + * --- + * wstring x = "abc"; // OK, string literal is flexible + * wstring y = cast(string) "abc"; // Error: type was committed after cast + * --- + */ + bool committed; + enum char NoPostfix = 0; - char postfix = NoPostfix; // 'c', 'w', 'd' - OwnedBy ownedByCtfe = OwnedBy.code; extern (D) this(const ref Loc loc, const(void)[] string) scope { - super(loc, EXP.string_, __traits(classInstanceSize, StringExp)); + super(loc, EXP.string_); this.string = cast(char*)string.ptr; // note that this.string should be const this.len = string.length; this.sz = 1; // work around LDC bug #1286 @@ -2552,7 +2573,7 @@ extern (C++) final class StringExp : Expression extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix) scope { - super(loc, EXP.string_, __traits(classInstanceSize, StringExp)); + super(loc, EXP.string_); this.string = cast(char*)string.ptr; // note that this.string should be const this.len = len; this.sz = sz; @@ -2750,7 +2771,7 @@ extern (C++) final class StringExp : Expression if (sz != 1) { // Convert to UTF-8 string - committed = 0; + committed = false; Expression e = castTo(sc, Type.tchar.arrayOf()); e = e.optimize(WANTvalue); auto se = e.isStringExp(); @@ -2939,7 +2960,7 @@ extern (C++) final class TupleExp : Expression extern (D) this(const ref Loc loc, Expression e0, Expressions* exps) { - super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp)); + super(loc, EXP.tuple); //printf("TupleExp(this = %p)\n", this); this.e0 = e0; this.exps = exps; @@ -2947,14 +2968,14 @@ extern (C++) final class TupleExp : Expression extern (D) this(const ref Loc loc, Expressions* exps) { - super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp)); + super(loc, EXP.tuple); //printf("TupleExp(this = %p)\n", this); this.exps = exps; } extern (D) this(const ref Loc loc, TupleDeclaration tup) { - super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp)); + super(loc, EXP.tuple); this.exps = new Expressions(); this.exps.reserve(tup.objects.length); @@ -3031,6 +3052,9 @@ extern (C++) final class TupleExp : Expression */ extern (C++) final class ArrayLiteralExp : Expression { + OwnedBy ownedByCtfe = OwnedBy.code; + bool onstack = false; + /** If !is null, elements[] can be sparse and basis is used for the * "default" element value. In other words, non-null elements[i] overrides * this 'basis' value. @@ -3038,19 +3062,17 @@ extern (C++) final class ArrayLiteralExp : Expression Expression basis; Expressions* elements; - OwnedBy ownedByCtfe = OwnedBy.code; - bool onstack = false; extern (D) this(const ref Loc loc, Type type, Expressions* elements) { - super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp)); + super(loc, EXP.arrayLiteral); this.type = type; this.elements = elements; } extern (D) this(const ref Loc loc, Type type, Expression e) { - super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp)); + super(loc, EXP.arrayLiteral); this.type = type; elements = new Expressions(); elements.push(e); @@ -3058,7 +3080,7 @@ extern (C++) final class ArrayLiteralExp : Expression extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements) { - super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp)); + super(loc, EXP.arrayLiteral); this.type = type; this.basis = basis; this.elements = elements; @@ -3196,14 +3218,14 @@ extern (C++) final class ArrayLiteralExp : Expression */ extern (C++) final class AssocArrayLiteralExp : Expression { + OwnedBy ownedByCtfe = OwnedBy.code; + Expressions* keys; Expressions* values; - OwnedBy ownedByCtfe = OwnedBy.code; - extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values) { - super(loc, EXP.assocArrayLiteral, __traits(classInstanceSize, AssocArrayLiteralExp)); + super(loc, EXP.assocArrayLiteral); assert(keys.length == values.length); this.keys = keys; this.values = values; @@ -3271,7 +3293,15 @@ extern (C++) final class StructLiteralExp : Expression Expressions* elements; /// parallels sd.fields[] with null entries for fields to skip Type stype; /// final type of result (can be different from sd's type) - Symbol* sym; /// back end symbol to initialize with literal + // `inlineCopy` is only used temporarily in the `inline.d` pass, + // while `sym` is only used in `e2ir/s2ir/tocsym` which comes after + union + { + Symbol* sym; /// back end symbol to initialize with literal + + /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer. + StructLiteralExp inlinecopy; + } /** pointer to the origin instance of the expression. * once a new expression is created, origin is set to 'this'. @@ -3280,15 +3310,13 @@ extern (C++) final class StructLiteralExp : Expression */ StructLiteralExp origin; - /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer. - StructLiteralExp inlinecopy; /** anytime when recursive function is calling, 'stageflags' marks with bit flag of * current stage and unmarks before return from this function. * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline' * (with infinite recursion) of this expression. */ - int stageflags; + ubyte stageflags; bool useStaticInit; /// if this is true, use the StructDeclaration's init symbol bool isOriginal = false; /// used when moving instances to indicate `this is this.origin` @@ -3296,7 +3324,7 @@ extern (C++) final class StructLiteralExp : Expression extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null) { - super(loc, EXP.structLiteral, __traits(classInstanceSize, StructLiteralExp)); + super(loc, EXP.structLiteral); this.sd = sd; if (!elements) elements = new Expressions(); @@ -3475,7 +3503,7 @@ extern (C++) final class CompoundLiteralExp : Expression extern (D) this(const ref Loc loc, Type type_name, Initializer initializer) { - super(loc, EXP.compoundLiteral, __traits(classInstanceSize, CompoundLiteralExp)); + super(loc, EXP.compoundLiteral); super.type = type_name; this.initializer = initializer; //printf("CompoundLiteralExp::CompoundLiteralExp(%s)\n", toChars()); @@ -3494,7 +3522,7 @@ extern (C++) final class TypeExp : Expression { extern (D) this(const ref Loc loc, Type type) { - super(loc, EXP.type, __traits(classInstanceSize, TypeExp)); + super(loc, EXP.type); //printf("TypeExp::TypeExp(%s)\n", type.toChars()); this.type = type; } @@ -3536,7 +3564,7 @@ extern (C++) final class ScopeExp : Expression extern (D) this(const ref Loc loc, ScopeDsymbol sds) { - super(loc, EXP.scope_, __traits(classInstanceSize, ScopeExp)); + super(loc, EXP.scope_); //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars()); //static int count; if (++count == 38) *(char*)0=0; this.sds = sds; @@ -3591,7 +3619,7 @@ extern (C++) final class TemplateExp : Expression extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null) { - super(loc, EXP.template_, __traits(classInstanceSize, TemplateExp)); + super(loc, EXP.template_); //printf("TemplateExp(): %s\n", td.toChars()); this.td = td; this.fd = fd; @@ -3652,7 +3680,7 @@ extern (C++) final class NewExp : Expression extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null) { - super(loc, EXP.new_, __traits(classInstanceSize, NewExp)); + super(loc, EXP.new_); this.thisexp = thisexp; this.newtype = newtype; this.arguments = arguments; @@ -3690,7 +3718,7 @@ extern (C++) final class NewAnonClassExp : Expression extern (D) this(const ref Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments) { - super(loc, EXP.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp)); + super(loc, EXP.newAnonymousClass); this.thisexp = thisexp; this.cd = cd; this.arguments = arguments; @@ -3715,9 +3743,9 @@ extern (C++) class SymbolExp : Expression Dsymbol originalScope; // original scope before inlining bool hasOverloads; - extern (D) this(const ref Loc loc, EXP op, int size, Declaration var, bool hasOverloads) + extern (D) this(const ref Loc loc, EXP op, Declaration var, bool hasOverloads) { - super(loc, op, size); + super(loc, op); assert(var); this.var = var; this.hasOverloads = hasOverloads; @@ -3746,7 +3774,7 @@ extern (C++) final class SymOffExp : SymbolExp .error(loc, "need `this` for address of `%s`", v.toChars()); hasOverloads = false; } - super(loc, EXP.symbolOffset, __traits(classInstanceSize, SymOffExp), var, hasOverloads); + super(loc, EXP.symbolOffset, var, hasOverloads); this.offset = offset; } @@ -3772,7 +3800,7 @@ extern (C++) final class VarExp : SymbolExp if (var.isVarDeclaration()) hasOverloads = false; - super(loc, EXP.variable, __traits(classInstanceSize, VarExp), var, hasOverloads); + super(loc, EXP.variable, var, hasOverloads); //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars()); //if (strcmp(var.ident.toChars(), "func") == 0) assert(0); this.type = var.type; @@ -3856,7 +3884,7 @@ extern (C++) final class OverExp : Expression extern (D) this(const ref Loc loc, OverloadSet s) { - super(loc, EXP.overloadSet, __traits(classInstanceSize, OverExp)); + super(loc, EXP.overloadSet); //printf("OverExp(this = %p, '%s')\n", this, var.toChars()); vars = s; type = Type.tvoid; @@ -3890,7 +3918,7 @@ extern (C++) final class FuncExp : Expression extern (D) this(const ref Loc loc, Dsymbol s) { - super(loc, EXP.function_, __traits(classInstanceSize, FuncExp)); + super(loc, EXP.function_); this.td = s.isTemplateDeclaration(); this.fd = s.isFuncLiteralDeclaration(); if (td) @@ -4189,7 +4217,7 @@ extern (C++) final class DeclarationExp : Expression extern (D) this(const ref Loc loc, Dsymbol declaration) { - super(loc, EXP.declaration, __traits(classInstanceSize, DeclarationExp)); + super(loc, EXP.declaration); this.declaration = declaration; } @@ -4222,7 +4250,7 @@ extern (C++) final class TypeidExp : Expression extern (D) this(const ref Loc loc, RootObject o) { - super(loc, EXP.typeid_, __traits(classInstanceSize, TypeidExp)); + super(loc, EXP.typeid_); this.obj = o; } @@ -4247,7 +4275,7 @@ extern (C++) final class TraitsExp : Expression extern (D) this(const ref Loc loc, Identifier ident, Objects* args) { - super(loc, EXP.traits, __traits(classInstanceSize, TraitsExp)); + super(loc, EXP.traits); this.ident = ident; this.args = args; } @@ -4272,7 +4300,7 @@ extern (C++) final class HaltExp : Expression { extern (D) this(const ref Loc loc) { - super(loc, EXP.halt, __traits(classInstanceSize, HaltExp)); + super(loc, EXP.halt); } override void accept(Visitor v) @@ -4296,7 +4324,7 @@ extern (C++) final class IsExp : Expression extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters) scope { - super(loc, EXP.is_, __traits(classInstanceSize, IsExp)); + super(loc, EXP.is_); this.targ = targ; this.id = id; this.tok = tok; @@ -4332,11 +4360,10 @@ extern (C++) final class IsExp : Expression extern (C++) abstract class UnaExp : Expression { Expression e1; - Type att1; // Save alias this type to detect recursion - extern (D) this(const ref Loc loc, EXP op, int size, Expression e1) scope + extern (D) this(const ref Loc loc, EXP op, Expression e1) scope { - super(loc, op, size); + super(loc, op); this.e1 = e1; } @@ -4407,9 +4434,9 @@ extern (C++) abstract class BinExp : Expression Type att1; // Save alias this type to detect recursion Type att2; // Save alias this type to detect recursion - extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2) scope + extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope { - super(loc, op, size); + super(loc, op); this.e1 = e1; this.e2 = e2; } @@ -4698,9 +4725,9 @@ extern (C++) abstract class BinExp : Expression */ extern (C++) class BinAssignExp : BinExp { - extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2) scope + extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) scope { - super(loc, op, size, e1, e2); + super(loc, op, e1, e2); } override final bool isLvalue() @@ -4737,7 +4764,7 @@ extern (C++) final class MixinExp : Expression extern (D) this(const ref Loc loc, Expressions* exps) { - super(loc, EXP.mixin_, __traits(classInstanceSize, MixinExp)); + super(loc, EXP.mixin_); this.exps = exps; } @@ -4785,7 +4812,7 @@ extern (C++) final class ImportExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { - super(loc, EXP.import_, __traits(classInstanceSize, ImportExp), e); + super(loc, EXP.import_, e); } override void accept(Visitor v) @@ -4805,7 +4832,7 @@ extern (C++) final class AssertExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Expression msg = null) { - super(loc, EXP.assert_, __traits(classInstanceSize, AssertExp), e); + super(loc, EXP.assert_, e); this.msg = msg; } @@ -4830,7 +4857,7 @@ extern (C++) final class ThrowExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { - super(loc, EXP.throw_, __traits(classInstanceSize, ThrowExp), e); + super(loc, EXP.throw_, e); this.type = Type.tnoreturn; } @@ -4856,7 +4883,7 @@ extern (C++) final class DotIdExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Identifier ident) { - super(loc, EXP.dotIdentifier, __traits(classInstanceSize, DotIdExp), e); + super(loc, EXP.dotIdentifier, e); this.ident = ident; } @@ -4880,7 +4907,7 @@ extern (C++) final class DotTemplateExp : UnaExp extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td) { - super(loc, EXP.dotTemplateDeclaration, __traits(classInstanceSize, DotTemplateExp), e); + super(loc, EXP.dotTemplateDeclaration, e); this.td = td; } @@ -4914,7 +4941,7 @@ extern (C++) final class DotVarExp : UnaExp if (var.isVarDeclaration()) hasOverloads = false; - super(loc, EXP.dotVariable, __traits(classInstanceSize, DotVarExp), e); + super(loc, EXP.dotVariable, e); //printf("DotVarExp()\n"); this.var = var; this.hasOverloads = hasOverloads; @@ -4995,14 +5022,14 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs) { - super(loc, EXP.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e); + super(loc, EXP.dotTemplateInstance, e); //printf("DotTemplateInstanceExp()\n"); this.ti = new TemplateInstance(loc, name, tiargs); } extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti) { - super(loc, EXP.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e); + super(loc, EXP.dotTemplateInstance, e); this.ti = ti; } @@ -5095,7 +5122,7 @@ extern (C++) final class DelegateExp : UnaExp extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null) { - super(loc, EXP.delegate_, __traits(classInstanceSize, DelegateExp), e); + super(loc, EXP.delegate_, e); this.func = f; this.hasOverloads = hasOverloads; this.vthis2 = vthis2; @@ -5115,7 +5142,7 @@ extern (C++) final class DotTypeExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Dsymbol s) { - super(loc, EXP.dotType, __traits(classInstanceSize, DotTypeExp), e); + super(loc, EXP.dotType, e); this.sym = s; } @@ -5169,19 +5196,19 @@ extern (C++) final class CallExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Expressions* exps, Identifiers* names = null) { - super(loc, EXP.call, __traits(classInstanceSize, CallExp), e); + super(loc, EXP.call, e); this.arguments = exps; this.names = names; } extern (D) this(const ref Loc loc, Expression e) { - super(loc, EXP.call, __traits(classInstanceSize, CallExp), e); + super(loc, EXP.call, e); } extern (D) this(const ref Loc loc, Expression e, Expression earg1) { - super(loc, EXP.call, __traits(classInstanceSize, CallExp), e); + super(loc, EXP.call, e); this.arguments = new Expressions(); if (earg1) this.arguments.push(earg1); @@ -5189,7 +5216,7 @@ extern (C++) final class CallExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2) { - super(loc, EXP.call, __traits(classInstanceSize, CallExp), e); + super(loc, EXP.call, e); auto arguments = new Expressions(2); (*arguments)[0] = earg1; (*arguments)[1] = earg2; @@ -5345,7 +5372,7 @@ extern (C++) final class AddrExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { - super(loc, EXP.address, __traits(classInstanceSize, AddrExp), e); + super(loc, EXP.address, e); } extern (D) this(const ref Loc loc, Expression e, Type t) @@ -5367,14 +5394,14 @@ extern (C++) final class PtrExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { - super(loc, EXP.star, __traits(classInstanceSize, PtrExp), e); + super(loc, EXP.star, e); //if (e.type) // type = ((TypePointer *)e.type).next; } extern (D) this(const ref Loc loc, Expression e, Type t) { - super(loc, EXP.star, __traits(classInstanceSize, PtrExp), e); + super(loc, EXP.star, e); type = t; } @@ -5420,7 +5447,7 @@ extern (C++) final class NegExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { - super(loc, EXP.negate, __traits(classInstanceSize, NegExp), e); + super(loc, EXP.negate, e); } override void accept(Visitor v) @@ -5436,7 +5463,7 @@ extern (C++) final class UAddExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) scope { - super(loc, EXP.uadd, __traits(classInstanceSize, UAddExp), e); + super(loc, EXP.uadd, e); } override void accept(Visitor v) @@ -5452,7 +5479,7 @@ extern (C++) final class ComExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { - super(loc, EXP.tilde, __traits(classInstanceSize, ComExp), e); + super(loc, EXP.tilde, e); } override void accept(Visitor v) @@ -5468,7 +5495,7 @@ extern (C++) final class NotExp : UnaExp { extern (D) this(const ref Loc loc, Expression e) { - super(loc, EXP.not, __traits(classInstanceSize, NotExp), e); + super(loc, EXP.not, e); } override void accept(Visitor v) @@ -5488,7 +5515,7 @@ extern (C++) final class DeleteExp : UnaExp extern (D) this(const ref Loc loc, Expression e, bool isRAII) { - super(loc, EXP.delete_, __traits(classInstanceSize, DeleteExp), e); + super(loc, EXP.delete_, e); this.isRAII = isRAII; } @@ -5512,7 +5539,7 @@ extern (C++) final class CastExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Type t) { - super(loc, EXP.cast_, __traits(classInstanceSize, CastExp), e); + super(loc, EXP.cast_, e); this.to = t; } @@ -5520,7 +5547,7 @@ extern (C++) final class CastExp : UnaExp */ extern (D) this(const ref Loc loc, Expression e, ubyte mod) { - super(loc, EXP.cast_, __traits(classInstanceSize, CastExp), e); + super(loc, EXP.cast_, e); this.mod = mod; } @@ -5574,7 +5601,7 @@ extern (C++) final class VectorExp : UnaExp extern (D) this(const ref Loc loc, Expression e, Type t) { - super(loc, EXP.vector, __traits(classInstanceSize, VectorExp), e); + super(loc, EXP.vector, e); assert(t.ty == Tvector); to = cast(TypeVector)t; } @@ -5610,7 +5637,7 @@ extern (C++) final class VectorArrayExp : UnaExp { extern (D) this(const ref Loc loc, Expression e1) { - super(loc, EXP.vectorArray, __traits(classInstanceSize, VectorArrayExp), e1); + super(loc, EXP.vectorArray, e1); } override bool isLvalue() @@ -5641,21 +5668,27 @@ extern (C++) final class SliceExp : UnaExp Expression lwr; // null if implicit [length - 1] VarDeclaration lengthVar; - bool upperIsInBounds; // true if upr <= e1.length - bool lowerIsLessThanUpper; // true if lwr <= upr - bool arrayop; // an array operation, rather than a slice + + private extern(D) static struct BitFields + { + bool upperIsInBounds; // true if upr <= e1.length + bool lowerIsLessThanUpper; // true if lwr <= upr + bool arrayop; // an array operation, rather than a slice + } + import dmd.common.bitfields : generateBitFields; + mixin(generateBitFields!(BitFields, ubyte)); /************************************************************/ extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie) { - super(loc, EXP.slice, __traits(classInstanceSize, SliceExp), e1); + super(loc, EXP.slice, e1); this.upr = ie ? ie.upr : null; this.lwr = ie ? ie.lwr : null; } extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr) { - super(loc, EXP.slice, __traits(classInstanceSize, SliceExp), e1); + super(loc, EXP.slice, e1); this.upr = upr; this.lwr = lwr; } @@ -5705,7 +5738,7 @@ extern (C++) final class ArrayLengthExp : UnaExp { extern (D) this(const ref Loc loc, Expression e1) { - super(loc, EXP.arrayLength, __traits(classInstanceSize, ArrayLengthExp), e1); + super(loc, EXP.arrayLength, e1); } override void accept(Visitor v) @@ -5728,7 +5761,7 @@ extern (C++) final class ArrayExp : UnaExp extern (D) this(const ref Loc loc, Expression e1, Expression index = null) { - super(loc, EXP.array, __traits(classInstanceSize, ArrayExp), e1); + super(loc, EXP.array, e1); arguments = new Expressions(); if (index) arguments.push(index); @@ -5736,7 +5769,7 @@ extern (C++) final class ArrayExp : UnaExp extern (D) this(const ref Loc loc, Expression e1, Expressions* args) { - super(loc, EXP.array, __traits(classInstanceSize, ArrayExp), e1); + super(loc, EXP.array, e1); arguments = args; } @@ -5773,7 +5806,7 @@ extern (C++) final class DotExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.dot, __traits(classInstanceSize, DotExp), e1, e2); + super(loc, EXP.dot, e1, e2); } override void accept(Visitor v) @@ -5799,7 +5832,7 @@ extern (C++) final class CommaExp : BinExp extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true) { - super(loc, EXP.comma, __traits(classInstanceSize, CommaExp), e1, e2); + super(loc, EXP.comma, e1, e2); allowCommaExp = isGenerated = generated; } @@ -5868,7 +5901,7 @@ extern (C++) final class IntervalExp : Expression extern (D) this(const ref Loc loc, Expression lwr, Expression upr) { - super(loc, EXP.interval, __traits(classInstanceSize, IntervalExp)); + super(loc, EXP.interval); this.lwr = lwr; this.upr = upr; } @@ -5893,7 +5926,7 @@ extern (C++) final class DelegatePtrExp : UnaExp { extern (D) this(const ref Loc loc, Expression e1) { - super(loc, EXP.delegatePointer, __traits(classInstanceSize, DelegatePtrExp), e1); + super(loc, EXP.delegatePointer, e1); } override bool isLvalue() @@ -5931,7 +5964,7 @@ extern (C++) final class DelegateFuncptrExp : UnaExp { extern (D) this(const ref Loc loc, Expression e1) { - super(loc, EXP.delegateFunctionPointer, __traits(classInstanceSize, DelegateFuncptrExp), e1); + super(loc, EXP.delegateFunctionPointer, e1); } override bool isLvalue() @@ -5971,13 +6004,13 @@ extern (C++) final class IndexExp : BinExp extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.index, __traits(classInstanceSize, IndexExp), e1, e2); + super(loc, EXP.index, e1, e2); //printf("IndexExp::IndexExp('%s')\n", toChars()); } extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool indexIsInBounds) { - super(loc, EXP.index, __traits(classInstanceSize, IndexExp), e1, e2); + super(loc, EXP.index, e1, e2); this.indexIsInBounds = indexIsInBounds; //printf("IndexExp::IndexExp('%s')\n", toChars()); } @@ -6054,7 +6087,7 @@ extern (C++) final class PostExp : BinExp { extern (D) this(EXP op, const ref Loc loc, Expression e) { - super(loc, op, __traits(classInstanceSize, PostExp), e, IntegerExp.literal!1); + super(loc, op, e, IntegerExp.literal!1); assert(op == EXP.minusMinus || op == EXP.plusPlus); } @@ -6071,7 +6104,7 @@ extern (C++) final class PreExp : UnaExp { extern (D) this(EXP op, const ref Loc loc, Expression e) { - super(loc, op, __traits(classInstanceSize, PreExp), e); + super(loc, op, e); assert(op == EXP.preMinusMinus || op == EXP.prePlusPlus); } @@ -6101,12 +6134,12 @@ extern (C++) class AssignExp : BinExp /* op can be EXP.assign, EXP.construct, or EXP.blit */ extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.assign, __traits(classInstanceSize, AssignExp), e1, e2); + super(loc, EXP.assign, e1, e2); } this(const ref Loc loc, EXP tok, Expression e1, Expression e2) { - super(loc, tok, __traits(classInstanceSize, AssignExp), e1, e2); + super(loc, tok, e1, e2); } override final bool isLvalue() @@ -6141,6 +6174,32 @@ extern (C++) class AssignExp : BinExp } /*********************************************************** + * When an assignment expression is lowered to a druntime call + * this class is used to store the lowering. + * It essentially behaves the same as an AssignExp, but it is + * used to not waste space for other AssignExp that are not + * lowered to anything. + */ +extern (C++) final class LoweredAssignExp : AssignExp +{ + Expression lowering; + extern (D) this(AssignExp exp, Expression lowering) + { + super(exp.loc, EXP.loweredAssignExp, exp.e1, exp.e2); + this.lowering = lowering; + } + + override const(char)* toChars() const + { + return lowering.toChars(); + } + override void accept(Visitor v) + { + v.visit(this); + } +} + +/*********************************************************** */ extern (C++) final class ConstructExp : AssignExp { @@ -6204,7 +6263,7 @@ extern (C++) final class AddAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.addAssign, __traits(classInstanceSize, AddAssignExp), e1, e2); + super(loc, EXP.addAssign, e1, e2); } override void accept(Visitor v) @@ -6220,7 +6279,7 @@ extern (C++) final class MinAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.minAssign, __traits(classInstanceSize, MinAssignExp), e1, e2); + super(loc, EXP.minAssign, e1, e2); } override void accept(Visitor v) @@ -6236,7 +6295,7 @@ extern (C++) final class MulAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.mulAssign, __traits(classInstanceSize, MulAssignExp), e1, e2); + super(loc, EXP.mulAssign, e1, e2); } override void accept(Visitor v) @@ -6252,7 +6311,7 @@ extern (C++) final class DivAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.divAssign, __traits(classInstanceSize, DivAssignExp), e1, e2); + super(loc, EXP.divAssign, e1, e2); } override void accept(Visitor v) @@ -6268,7 +6327,7 @@ extern (C++) final class ModAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.modAssign, __traits(classInstanceSize, ModAssignExp), e1, e2); + super(loc, EXP.modAssign, e1, e2); } override void accept(Visitor v) @@ -6284,7 +6343,7 @@ extern (C++) final class AndAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.andAssign, __traits(classInstanceSize, AndAssignExp), e1, e2); + super(loc, EXP.andAssign, e1, e2); } override void accept(Visitor v) @@ -6300,7 +6359,7 @@ extern (C++) final class OrAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.orAssign, __traits(classInstanceSize, OrAssignExp), e1, e2); + super(loc, EXP.orAssign, e1, e2); } override void accept(Visitor v) @@ -6316,7 +6375,7 @@ extern (C++) final class XorAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.xorAssign, __traits(classInstanceSize, XorAssignExp), e1, e2); + super(loc, EXP.xorAssign, e1, e2); } override void accept(Visitor v) @@ -6332,7 +6391,7 @@ extern (C++) final class PowAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.powAssign, __traits(classInstanceSize, PowAssignExp), e1, e2); + super(loc, EXP.powAssign, e1, e2); } override void accept(Visitor v) @@ -6348,7 +6407,7 @@ extern (C++) final class ShlAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.leftShiftAssign, __traits(classInstanceSize, ShlAssignExp), e1, e2); + super(loc, EXP.leftShiftAssign, e1, e2); } override void accept(Visitor v) @@ -6364,7 +6423,7 @@ extern (C++) final class ShrAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.rightShiftAssign, __traits(classInstanceSize, ShrAssignExp), e1, e2); + super(loc, EXP.rightShiftAssign, e1, e2); } override void accept(Visitor v) @@ -6380,7 +6439,7 @@ extern (C++) final class UshrAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.unsignedRightShiftAssign, __traits(classInstanceSize, UshrAssignExp), e1, e2); + super(loc, EXP.unsignedRightShiftAssign, e1, e2); } override void accept(Visitor v) @@ -6405,12 +6464,12 @@ extern (C++) class CatAssignExp : BinAssignExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.concatenateAssign, __traits(classInstanceSize, CatAssignExp), e1, e2); + super(loc, EXP.concatenateAssign, e1, e2); } extern (D) this(const ref Loc loc, EXP tok, Expression e1, Expression e2) { - super(loc, tok, __traits(classInstanceSize, CatAssignExp), e1, e2); + super(loc, tok, e1, e2); } override void accept(Visitor v) @@ -6462,7 +6521,7 @@ extern (C++) final class AddExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.add, __traits(classInstanceSize, AddExp), e1, e2); + super(loc, EXP.add, e1, e2); } override void accept(Visitor v) @@ -6480,7 +6539,7 @@ extern (C++) final class MinExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.min, __traits(classInstanceSize, MinExp), e1, e2); + super(loc, EXP.min, e1, e2); } override void accept(Visitor v) @@ -6496,9 +6555,11 @@ extern (C++) final class MinExp : BinExp */ extern (C++) final class CatExp : BinExp { + Expression lowering; // call to druntime hook `_d_arraycatnTX` + extern (D) this(const ref Loc loc, Expression e1, Expression e2) scope { - super(loc, EXP.concatenate, __traits(classInstanceSize, CatExp), e1, e2); + super(loc, EXP.concatenate, e1, e2); } override Expression resolveLoc(const ref Loc loc, Scope* sc) @@ -6523,7 +6584,7 @@ extern (C++) final class MulExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.mul, __traits(classInstanceSize, MulExp), e1, e2); + super(loc, EXP.mul, e1, e2); } override void accept(Visitor v) @@ -6541,7 +6602,7 @@ extern (C++) final class DivExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.div, __traits(classInstanceSize, DivExp), e1, e2); + super(loc, EXP.div, e1, e2); } override void accept(Visitor v) @@ -6559,7 +6620,7 @@ extern (C++) final class ModExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.mod, __traits(classInstanceSize, ModExp), e1, e2); + super(loc, EXP.mod, e1, e2); } override void accept(Visitor v) @@ -6577,7 +6638,7 @@ extern (C++) final class PowExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.pow, __traits(classInstanceSize, PowExp), e1, e2); + super(loc, EXP.pow, e1, e2); } override void accept(Visitor v) @@ -6595,7 +6656,7 @@ extern (C++) final class ShlExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.leftShift, __traits(classInstanceSize, ShlExp), e1, e2); + super(loc, EXP.leftShift, e1, e2); } override void accept(Visitor v) @@ -6613,7 +6674,7 @@ extern (C++) final class ShrExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.rightShift, __traits(classInstanceSize, ShrExp), e1, e2); + super(loc, EXP.rightShift, e1, e2); } override void accept(Visitor v) @@ -6631,7 +6692,7 @@ extern (C++) final class UshrExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.unsignedRightShift, __traits(classInstanceSize, UshrExp), e1, e2); + super(loc, EXP.unsignedRightShift, e1, e2); } override void accept(Visitor v) @@ -6649,7 +6710,7 @@ extern (C++) final class AndExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.and, __traits(classInstanceSize, AndExp), e1, e2); + super(loc, EXP.and, e1, e2); } override void accept(Visitor v) @@ -6667,7 +6728,7 @@ extern (C++) final class OrExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.or, __traits(classInstanceSize, OrExp), e1, e2); + super(loc, EXP.or, e1, e2); } override void accept(Visitor v) @@ -6685,7 +6746,7 @@ extern (C++) final class XorExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.xor, __traits(classInstanceSize, XorExp), e1, e2); + super(loc, EXP.xor, e1, e2); } override void accept(Visitor v) @@ -6704,7 +6765,7 @@ extern (C++) final class LogicalExp : BinExp { extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2) { - super(loc, op, __traits(classInstanceSize, LogicalExp), e1, e2); + super(loc, op, e1, e2); assert(op == EXP.andAnd || op == EXP.orOr); } @@ -6726,7 +6787,7 @@ extern (C++) final class CmpExp : BinExp { extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) { - super(loc, op, __traits(classInstanceSize, CmpExp), e1, e2); + super(loc, op, e1, e2); assert(op == EXP.lessThan || op == EXP.lessOrEqual || op == EXP.greaterThan || op == EXP.greaterOrEqual); } @@ -6747,7 +6808,7 @@ extern (C++) final class InExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.in_, __traits(classInstanceSize, InExp), e1, e2); + super(loc, EXP.in_, e1, e2); } override void accept(Visitor v) @@ -6765,7 +6826,7 @@ extern (C++) final class RemoveExp : BinExp { extern (D) this(const ref Loc loc, Expression e1, Expression e2) { - super(loc, EXP.remove, __traits(classInstanceSize, RemoveExp), e1, e2); + super(loc, EXP.remove, e1, e2); type = Type.tbool; } @@ -6786,7 +6847,7 @@ extern (C++) final class EqualExp : BinExp { extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) { - super(loc, op, __traits(classInstanceSize, EqualExp), e1, e2); + super(loc, op, e1, e2); assert(op == EXP.equal || op == EXP.notEqual); } @@ -6807,7 +6868,7 @@ extern (C++) final class IdentityExp : BinExp { extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2) { - super(loc, op, __traits(classInstanceSize, IdentityExp), e1, e2); + super(loc, op, e1, e2); assert(op == EXP.identity || op == EXP.notIdentity); } @@ -6828,7 +6889,7 @@ extern (C++) final class CondExp : BinExp extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2) scope { - super(loc, EXP.question, __traits(classInstanceSize, CondExp), e1, e2); + super(loc, EXP.question, e1, e2); this.econd = econd; } @@ -6966,9 +7027,9 @@ bool isDefaultInitOp(EXP op) pure nothrow @safe @nogc */ extern (C++) class DefaultInitExp : Expression { - extern (D) this(const ref Loc loc, EXP op, int size) + extern (D) this(const ref Loc loc, EXP op) { - super(loc, op, size); + super(loc, op); } override void accept(Visitor v) @@ -6984,7 +7045,7 @@ extern (C++) final class FileInitExp : DefaultInitExp { extern (D) this(const ref Loc loc, EXP tok) { - super(loc, tok, __traits(classInstanceSize, FileInitExp)); + super(loc, tok); } override Expression resolveLoc(const ref Loc loc, Scope* sc) @@ -7015,7 +7076,7 @@ extern (C++) final class LineInitExp : DefaultInitExp { extern (D) this(const ref Loc loc) { - super(loc, EXP.line, __traits(classInstanceSize, LineInitExp)); + super(loc, EXP.line); } override Expression resolveLoc(const ref Loc loc, Scope* sc) @@ -7038,7 +7099,7 @@ extern (C++) final class ModuleInitExp : DefaultInitExp { extern (D) this(const ref Loc loc) { - super(loc, EXP.moduleString, __traits(classInstanceSize, ModuleInitExp)); + super(loc, EXP.moduleString); } override Expression resolveLoc(const ref Loc loc, Scope* sc) @@ -7063,7 +7124,7 @@ extern (C++) final class FuncInitExp : DefaultInitExp { extern (D) this(const ref Loc loc) { - super(loc, EXP.functionString, __traits(classInstanceSize, FuncInitExp)); + super(loc, EXP.functionString); } override Expression resolveLoc(const ref Loc loc, Scope* sc) @@ -7094,7 +7155,7 @@ extern (C++) final class PrettyFuncInitExp : DefaultInitExp { extern (D) this(const ref Loc loc) { - super(loc, EXP.prettyFunction, __traits(classInstanceSize, PrettyFuncInitExp)); + super(loc, EXP.prettyFunction); } override Expression resolveLoc(const ref Loc loc, Scope* sc) @@ -7139,8 +7200,7 @@ extern (C++) final class ObjcClassReferenceExp : Expression extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration) { - super(loc, EXP.objcClassReference, - __traits(classInstanceSize, ObjcClassReferenceExp)); + super(loc, EXP.objcClassReference); this.classDeclaration = classDeclaration; type = objc.getRuntimeMetaclass(classDeclaration).getType(); } @@ -7163,7 +7223,7 @@ extern (C++) final class GenericExp : Expression extern (D) this(const ref Loc loc, Expression cntlExp, Types* types, Expressions* exps) { - super(loc, EXP._Generic, __traits(classInstanceSize, GenericExp)); + super(loc, EXP._Generic); this.cntlExp = cntlExp; this.types = types; this.exps = exps; @@ -7398,3 +7458,135 @@ private enum EbinaryAssign = EXP.leftShiftAssign, EXP.rightShiftAssign, EXP.unsignedRightShiftAssign, EXP.concatenateAssign, EXP.concatenateElemAssign, EXP.concatenateDcharAssign, ]; + +/// Given a member of the EXP enum, get the class instance size of the corresponding Expression class. +/// Needed because the classes are `extern(C++)` +private immutable ubyte[EXP.max+1] expSize = [ + EXP.reserved: 0, + EXP.negate: __traits(classInstanceSize, NegExp), + EXP.cast_: __traits(classInstanceSize, CastExp), + EXP.null_: __traits(classInstanceSize, NullExp), + EXP.assert_: __traits(classInstanceSize, AssertExp), + EXP.array: __traits(classInstanceSize, ArrayExp), + EXP.call: __traits(classInstanceSize, CallExp), + EXP.address: __traits(classInstanceSize, AddrExp), + EXP.type: __traits(classInstanceSize, TypeExp), + EXP.throw_: __traits(classInstanceSize, ThrowExp), + EXP.new_: __traits(classInstanceSize, NewExp), + EXP.delete_: __traits(classInstanceSize, DeleteExp), + EXP.star: __traits(classInstanceSize, PtrExp), + EXP.symbolOffset: __traits(classInstanceSize, SymOffExp), + EXP.variable: __traits(classInstanceSize, VarExp), + EXP.dotVariable: __traits(classInstanceSize, DotVarExp), + EXP.dotIdentifier: __traits(classInstanceSize, DotIdExp), + EXP.dotTemplateInstance: __traits(classInstanceSize, DotTemplateInstanceExp), + EXP.dotType: __traits(classInstanceSize, DotTypeExp), + EXP.slice: __traits(classInstanceSize, SliceExp), + EXP.arrayLength: __traits(classInstanceSize, ArrayLengthExp), + EXP.dollar: __traits(classInstanceSize, DollarExp), + EXP.template_: __traits(classInstanceSize, TemplateExp), + EXP.dotTemplateDeclaration: __traits(classInstanceSize, DotTemplateExp), + EXP.declaration: __traits(classInstanceSize, DeclarationExp), + EXP.dSymbol: __traits(classInstanceSize, DsymbolExp), + EXP.typeid_: __traits(classInstanceSize, TypeidExp), + EXP.uadd: __traits(classInstanceSize, UAddExp), + EXP.remove: __traits(classInstanceSize, RemoveExp), + EXP.newAnonymousClass: __traits(classInstanceSize, NewAnonClassExp), + EXP.arrayLiteral: __traits(classInstanceSize, ArrayLiteralExp), + EXP.assocArrayLiteral: __traits(classInstanceSize, AssocArrayLiteralExp), + EXP.structLiteral: __traits(classInstanceSize, StructLiteralExp), + EXP.classReference: __traits(classInstanceSize, ClassReferenceExp), + EXP.thrownException: __traits(classInstanceSize, ThrownExceptionExp), + EXP.delegatePointer: __traits(classInstanceSize, DelegatePtrExp), + EXP.delegateFunctionPointer: __traits(classInstanceSize, DelegateFuncptrExp), + EXP.lessThan: __traits(classInstanceSize, CmpExp), + EXP.greaterThan: __traits(classInstanceSize, CmpExp), + EXP.lessOrEqual: __traits(classInstanceSize, CmpExp), + EXP.greaterOrEqual: __traits(classInstanceSize, CmpExp), + EXP.equal: __traits(classInstanceSize, EqualExp), + EXP.notEqual: __traits(classInstanceSize, EqualExp), + EXP.identity: __traits(classInstanceSize, IdentityExp), + EXP.notIdentity: __traits(classInstanceSize, IdentityExp), + EXP.index: __traits(classInstanceSize, IndexExp), + EXP.is_: __traits(classInstanceSize, IsExp), + EXP.leftShift: __traits(classInstanceSize, ShlExp), + EXP.rightShift: __traits(classInstanceSize, ShrExp), + EXP.leftShiftAssign: __traits(classInstanceSize, ShlAssignExp), + EXP.rightShiftAssign: __traits(classInstanceSize, ShrAssignExp), + EXP.unsignedRightShift: __traits(classInstanceSize, UshrExp), + EXP.unsignedRightShiftAssign: __traits(classInstanceSize, UshrAssignExp), + EXP.concatenate: __traits(classInstanceSize, CatExp), + EXP.concatenateAssign: __traits(classInstanceSize, CatAssignExp), + EXP.concatenateElemAssign: __traits(classInstanceSize, CatElemAssignExp), + EXP.concatenateDcharAssign: __traits(classInstanceSize, CatDcharAssignExp), + EXP.add: __traits(classInstanceSize, AddExp), + EXP.min: __traits(classInstanceSize, MinExp), + EXP.addAssign: __traits(classInstanceSize, AddAssignExp), + EXP.minAssign: __traits(classInstanceSize, MinAssignExp), + EXP.mul: __traits(classInstanceSize, MulExp), + EXP.div: __traits(classInstanceSize, DivExp), + EXP.mod: __traits(classInstanceSize, ModExp), + EXP.mulAssign: __traits(classInstanceSize, MulAssignExp), + EXP.divAssign: __traits(classInstanceSize, DivAssignExp), + EXP.modAssign: __traits(classInstanceSize, ModAssignExp), + EXP.and: __traits(classInstanceSize, AndExp), + EXP.or: __traits(classInstanceSize, OrExp), + EXP.xor: __traits(classInstanceSize, XorExp), + EXP.andAssign: __traits(classInstanceSize, AndAssignExp), + EXP.orAssign: __traits(classInstanceSize, OrAssignExp), + EXP.xorAssign: __traits(classInstanceSize, XorAssignExp), + EXP.assign: __traits(classInstanceSize, AssignExp), + EXP.not: __traits(classInstanceSize, NotExp), + EXP.tilde: __traits(classInstanceSize, ComExp), + EXP.plusPlus: __traits(classInstanceSize, PostExp), + EXP.minusMinus: __traits(classInstanceSize, PostExp), + EXP.construct: __traits(classInstanceSize, ConstructExp), + EXP.blit: __traits(classInstanceSize, BlitExp), + EXP.dot: __traits(classInstanceSize, DotExp), + EXP.comma: __traits(classInstanceSize, CommaExp), + EXP.question: __traits(classInstanceSize, CondExp), + EXP.andAnd: __traits(classInstanceSize, LogicalExp), + EXP.orOr: __traits(classInstanceSize, LogicalExp), + EXP.prePlusPlus: __traits(classInstanceSize, PreExp), + EXP.preMinusMinus: __traits(classInstanceSize, PreExp), + EXP.identifier: __traits(classInstanceSize, IdentifierExp), + EXP.string_: __traits(classInstanceSize, StringExp), + EXP.this_: __traits(classInstanceSize, ThisExp), + EXP.super_: __traits(classInstanceSize, SuperExp), + EXP.halt: __traits(classInstanceSize, HaltExp), + EXP.tuple: __traits(classInstanceSize, TupleExp), + EXP.error: __traits(classInstanceSize, ErrorExp), + EXP.void_: __traits(classInstanceSize, VoidInitExp), + EXP.int64: __traits(classInstanceSize, IntegerExp), + EXP.float64: __traits(classInstanceSize, RealExp), + EXP.complex80: __traits(classInstanceSize, ComplexExp), + EXP.import_: __traits(classInstanceSize, ImportExp), + EXP.delegate_: __traits(classInstanceSize, DelegateExp), + EXP.function_: __traits(classInstanceSize, FuncExp), + EXP.mixin_: __traits(classInstanceSize, MixinExp), + EXP.in_: __traits(classInstanceSize, InExp), + EXP.break_: __traits(classInstanceSize, CTFEExp), + EXP.continue_: __traits(classInstanceSize, CTFEExp), + EXP.goto_: __traits(classInstanceSize, CTFEExp), + EXP.scope_: __traits(classInstanceSize, ScopeExp), + EXP.traits: __traits(classInstanceSize, TraitsExp), + EXP.overloadSet: __traits(classInstanceSize, OverExp), + EXP.line: __traits(classInstanceSize, LineInitExp), + EXP.file: __traits(classInstanceSize, FileInitExp), + EXP.fileFullPath: __traits(classInstanceSize, FileInitExp), + EXP.moduleString: __traits(classInstanceSize, ModuleInitExp), + EXP.functionString: __traits(classInstanceSize, FuncInitExp), + EXP.prettyFunction: __traits(classInstanceSize, PrettyFuncInitExp), + EXP.pow: __traits(classInstanceSize, PowExp), + EXP.powAssign: __traits(classInstanceSize, PowAssignExp), + EXP.vector: __traits(classInstanceSize, VectorExp), + EXP.voidExpression: __traits(classInstanceSize, CTFEExp), + EXP.cantExpression: __traits(classInstanceSize, CTFEExp), + EXP.showCtfeContext: __traits(classInstanceSize, CTFEExp), + EXP.objcClassReference: __traits(classInstanceSize, ObjcClassReferenceExp), + EXP.vectorArray: __traits(classInstanceSize, VectorArrayExp), + EXP.compoundLiteral: __traits(classInstanceSize, CompoundLiteralExp), + EXP._Generic: __traits(classInstanceSize, GenericExp), + EXP.interval: __traits(classInstanceSize, IntervalExp), + EXP.loweredAssignExp : __traits(classInstanceSize, LoweredAssignExp), +]; diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 1bc78e7..a4b18b9 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -38,6 +38,7 @@ class TemplateDeclaration; class ClassDeclaration; class OverloadSet; class StringExp; +class LoweredAssignExp; struct UnionExp; #ifdef IN_GCC typedef union tree_node Symbol; @@ -79,12 +80,12 @@ enum class ModifyFlags class Expression : public ASTNode { public: - EXP op; // to minimize use of dynamic_cast - unsigned char size; // # of bytes in Expression so we can copy() it - d_bool parens; // if this is a parenthesized expression Type *type; // !=NULL means that semantic() has been run Loc loc; // file location + EXP op; // to minimize use of dynamic_cast + d_bool parens; // if this is a parenthesized expression + size_t size() const; static void _init(); Expression *copy(); virtual Expression *syntaxCopy(); @@ -240,6 +241,7 @@ public: UnaExp* isUnaExp(); BinExp* isBinExp(); BinAssignExp* isBinAssignExp(); + LoweredAssignExp* isLoweredAssignExp(); void accept(Visitor *v) override { v->visit(this); } }; @@ -370,12 +372,12 @@ public: class StringExp final : public Expression { public: + utf8_t postfix; // 'c', 'w', 'd' + OwnedBy ownedByCtfe; void *string; // char, wchar, or dchar data size_t len; // number of chars, wchars, or dchars unsigned char sz; // 1: char, 2: wchar, 4: dchar - unsigned char committed; // !=0 if type is committed - utf8_t postfix; // 'c', 'w', 'd' - OwnedBy ownedByCtfe; + bool committed; // if type is committed static StringExp *create(const Loc &loc, const char *s); static StringExp *create(const Loc &loc, const void *s, d_size_t len); @@ -419,10 +421,10 @@ public: class ArrayLiteralExp final : public Expression { public: - Expression *basis; - Expressions *elements; OwnedBy ownedByCtfe; d_bool onstack; + Expression *basis; + Expressions *elements; static ArrayLiteralExp *create(const Loc &loc, Expressions *elements); static void emplace(UnionExp *pue, const Loc &loc, Expressions *elements); @@ -439,9 +441,9 @@ public: class AssocArrayLiteralExp final : public Expression { public: + OwnedBy ownedByCtfe; Expressions *keys; Expressions *values; - OwnedBy ownedByCtfe; bool equals(const RootObject * const o) const override; AssocArrayLiteralExp *syntaxCopy() override; @@ -457,7 +459,13 @@ public: Expressions *elements; // parallels sd->fields[] with NULL entries for fields to skip Type *stype; // final type of result (can be different from sd's type) - Symbol *sym; // back end symbol to initialize with literal + union + { + Symbol *sym; // back end symbol to initialize with literal + + // those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer. + StructLiteralExp *inlinecopy; + }; /** pointer to the origin instance of the expression. * once a new expression is created, origin is set to 'this'. @@ -466,15 +474,13 @@ public: */ StructLiteralExp *origin; - // those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer. - StructLiteralExp *inlinecopy; /** anytime when recursive function is calling, 'stageflags' marks with bit flag of * current stage and unmarks before return from this function. * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline' * (with infinite recursion) of this expression. */ - int stageflags; + uint8_t stageflags; d_bool useStaticInit; // if this is true, use the StructDeclaration's init symbol d_bool isOriginal; // used when moving instances to indicate `this is this.origin` @@ -693,7 +699,6 @@ class UnaExp : public Expression { public: Expression *e1; - Type *att1; // Save alias this type to detect recursion UnaExp *syntaxCopy() override; Expression *incompatibleTypes(); @@ -937,9 +942,15 @@ public: Expression *upr; // NULL if implicit 0 Expression *lwr; // NULL if implicit [length - 1] VarDeclaration *lengthVar; - d_bool upperIsInBounds; // true if upr <= e1.length - d_bool lowerIsLessThanUpper; // true if lwr <= upr - d_bool arrayop; // an array operation, rather than a slice + + bool upperIsInBounds() const; // true if upr <= e1.length + bool upperIsInBounds(bool v); + bool lowerIsLessThanUpper() const; // true if lwr <= upr + bool lowerIsLessThanUpper(bool v); + bool arrayop() const; // an array operation, rather than a slice + bool arrayop(bool v); +private: + uint8_t bitFields; SliceExp *syntaxCopy() override; bool isLvalue() override; @@ -1076,6 +1087,15 @@ public: void accept(Visitor *v) override { v->visit(this); } }; +class LoweredAssignExp final : public AssignExp +{ +public: + Expression *lowering; + + const char *toChars() const override; + void accept(Visitor *v) override { v->visit(this); } +}; + class BlitExp final : public AssignExp { public: @@ -1187,6 +1207,8 @@ public: class CatExp final : public BinExp { public: + Expression *lowering; // call to druntime hook `_d_arraycatnTX` + void accept(Visitor *v) override { v->visit(this); } }; @@ -1372,7 +1394,7 @@ struct UnionExp UnionExp(Expression *e) { - memcpy(this, (void *)e, e->size); + memcpy(this, (void *)e, e->size()); } /* Extract pointer to Expression diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 45dcb97..cf4aac4 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -65,7 +65,6 @@ import dmd.parse; import dmd.printast; import dmd.root.array; import dmd.root.ctfloat; -import dmd.root.file; import dmd.root.filename; import dmd.common.outbuffer; import dmd.root.rootobject; @@ -635,7 +634,7 @@ private Expression resolveUFCS(Scope* sc, CallExp ce) } else if (auto dti = ce.e1.isDotTemplateInstanceExp()) { - if (Expression ey = dti.dotTemplateSemanticProp(sc, 1)) + if (Expression ey = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag)) { ce.e1 = ey; return null; @@ -1221,7 +1220,7 @@ private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc) /*************************************** * Pull out any properties. */ -private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null) +private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null, BinExp saveAtts = null) { //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null); Loc loc = e1.loc; @@ -1295,7 +1294,14 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = { Expression e = new CallExp(loc, e1); if (e2) + { e = new AssignExp(loc, e, e2); + if (saveAtts) + { + (cast(BinExp)e).att1 = saveAtts.att1; + (cast(BinExp)e).att2 = saveAtts.att2; + } + } return e.expressionSemantic(sc); } } @@ -1413,7 +1419,14 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = } Expression e = new CallExp(loc, e1); if (e2) + { e = new AssignExp(loc, e, e2); + if (saveAtts) + { + (cast(BinExp)e).att1 = saveAtts.att1; + (cast(BinExp)e).att2 = saveAtts.att2; + } + } return e.expressionSemantic(sc); } } @@ -2177,7 +2190,11 @@ private bool functionParameters(const ref Loc loc, Scope* sc, } // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along // as lazy parameters to the next function, but that isn't escaping. - else if (!(pStc & STC.lazy_)) + // The arguments of `_d_arraycatnTX` are already handled in + // expressionsem.d, via `checkNewEscape`. Without `-dip1000`, the + // check does not return an error, so the lowering of `a ~ b` to + // `_d_arraycatnTX(a, b)` still occurs. + else if (!(pStc & STC.lazy_) && (!fd || fd.ident != Id._d_arraycatnTX)) { /* Argument value can escape from the called function. * Check arg to see if it matters. @@ -2208,6 +2225,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, // allocate the array literal as temporary static array on the stack ale.type = ale.type.nextOf().sarrayOf(ale.elements.length); auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale); + tmp.storage_class |= STC.exptemp; auto declareTmp = new DeclarationExp(ale.loc, tmp); auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp), p.type.substWildTo(MODFlags.mutable)); @@ -2266,7 +2284,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc, default: break; } - if (tf.parameterList.varargs == VarArg.variadic) + if (tf.parameterList.varargs == VarArg.variadic || + tf.parameterList.varargs == VarArg.KRvariadic) { const(char)* p = tf.linkage == LINK.c ? "extern(C)" : "extern(C++)"; if (arg.type.ty == Tarray) @@ -2348,30 +2367,18 @@ private bool functionParameters(const ref Loc loc, Scope* sc, } /* Remaining problems: - * 1. order of evaluation - some function push L-to-R, others R-to-L. Until we resolve what array assignment does (which is - * implemented by calling a function) we'll defer this for now. - * 2. value structs (or static arrays of them) that need to be copy constructed - * 3. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the + * 1. value structs (or static arrays of them) that need to be copy constructed + * 2. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the * function gets called. - * 4. value structs need to be destructed after the function call for platforms where the caller destroys the arguments. - * 2, 3 and 4 are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned + * 3. value structs need to be destructed after the function call for platforms where the caller destroys the arguments. + * Those are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned * up properly. Pushing arguments on the stack then cannot fail. */ { - /* TODO: tackle problem 1) - */ - const bool leftToRight = true; // TODO: Any cases that need rightToLeft? - if (!leftToRight) - assert(nargs == nparams); // no variadics for RTL order, as they would probably be evaluated LTR and so add complexity - - /* Does Problem (4) apply? + /* Does Problem (3) apply? */ const bool callerDestroysArgs = !target.isCalleeDestroyingArgs(tf); - const ptrdiff_t start = (leftToRight ? 0 : cast(ptrdiff_t)nargs - 1); - const ptrdiff_t end = (leftToRight ? cast(ptrdiff_t)nargs : -1); - const ptrdiff_t step = (leftToRight ? 1 : -1); - /* Compute indices of last throwing argument and first arg needing destruction. * Used to not set up destructors unless an arg needs destruction on a throw * in a later argument. @@ -2379,7 +2386,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, ptrdiff_t lastthrow = -1; // last argument that may throw ptrdiff_t firstdtor = -1; // first argument that needs destruction ptrdiff_t lastdtor = -1; // last argument that needs destruction - for (ptrdiff_t i = start; i != end; i += step) + for (ptrdiff_t i = 0; i != nargs; i++) { Expression arg = (*arguments)[i]; if (canThrow(arg, sc.func, false)) @@ -2396,12 +2403,12 @@ private bool functionParameters(const ref Loc loc, Scope* sc, } } - /* Do we need 'eprefix' for problems 3 or 4? + /* Do we need 'eprefix' for problems 2 or 3? */ const bool needsPrefix = callerDestroysArgs ? firstdtor >= 0 // true if any argument needs destruction : firstdtor >= 0 && lastthrow >= 0 && - (lastthrow - firstdtor) * step > 0; // last throw after first destruction + (lastthrow - firstdtor) > 0; // last throw after first destruction const ptrdiff_t lastPrefix = callerDestroysArgs ? lastdtor // up to last argument requiring destruction : lastthrow; // up to last potentially throwing argument @@ -2421,7 +2428,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, eprefix = ae.expressionSemantic(sc); } - for (ptrdiff_t i = start; i != end; i += step) + for (ptrdiff_t i = 0; i != nargs; i++) { Expression arg = (*arguments)[i]; //printf("arg[%d]: %s\n", cast(int)i, arg.toChars()); @@ -2437,12 +2444,12 @@ private bool functionParameters(const ref Loc loc, Scope* sc, /* Do we have 'eprefix' and aren't past 'lastPrefix' yet? * Then declare a temporary variable for this arg and append that declaration - * to 'eprefix', which will implicitly take care of potential problem 2) for + * to 'eprefix', which will implicitly take care of potential problem 1) for * this arg. * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix', * excluding all lazy parameters. */ - if (needsPrefix && (lastPrefix - i) * step >= 0) + if (needsPrefix && (lastPrefix - i) >= 0) { const bool needsDtor = !isRef && arg.type.needsDestruction() && // Problem 3: last throwing arg doesn't require dtor patching @@ -2465,7 +2472,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, } else { - /* Problem 3: Modify the destructor so it only runs if gate==false, + /* Problem 2: Modify the destructor so it only runs if gate==false, * i.e., only if there was a throw while constructing the args */ if (!needsDtor) @@ -2500,7 +2507,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, arg = arg.expressionSemantic(sc); } - /* Problem 3: Last throwing arg? + /* Problem 2: Last throwing arg? * Then finalize eprefix => (eprefix, gate = true), i.e., disable the * dtors right after constructing the last throwing arg. * From now on, the callee will take care of destructing the args because @@ -2514,7 +2521,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, } else // not part of 'eprefix' { - /* Handle problem 2) by calling the copy constructor for value structs + /* Handle problem 1) by calling the copy constructor for value structs * (or static arrays of them) if appropriate. */ Type tv = arg.type.baseElemOf(); @@ -2671,6 +2678,34 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { if (!e.type) e.type = Type.tfloat64; + else if (e.type.isimaginary && sc.flags & SCOPE.Cfile) + { + /* Convert to core.stdc.config.complex + */ + Type t = getComplexLibraryType(e.loc, sc, e.type.ty); + if (t.ty == Terror) + return setError(); + + Type tf; + switch (e.type.ty) + { + case Timaginary32: tf = Type.tfloat32; break; + case Timaginary64: tf = Type.tfloat64; break; + case Timaginary80: tf = Type.tfloat80; break; + default: + assert(0); + } + + /* Construct ts{re : 0.0, im : e} + */ + TypeStruct ts = t.isTypeStruct; + Expressions* elements = new Expressions(2); + (*elements)[0] = new RealExp(e.loc, CTFloat.zero, tf); + (*elements)[1] = new RealExp(e.loc, e.toImaginary(), tf); + Expression sle = new StructLiteralExp(e.loc, ts.sym, elements); + result = sle.expressionSemantic(sc); + return; + } else e.type = e.type.typeSemantic(e.loc, sc); result = e; @@ -2933,7 +2968,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!s) { e.error("`%s` is not in a class or struct scope", e.toChars()); - goto Lerr; + return setError(); } ClassDeclaration cd = s.isClassDeclaration(); if (cd) @@ -2952,7 +2987,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } if (!fd) - goto Lerr; + { + e.error("`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars()); + return setError(); + } assert(fd.vthis); e.var = fd.vthis; @@ -2967,11 +3005,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); result = e; - return; - - Lerr: - e.error("`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars()); - result = ErrorExp.get(); } override void visit(SuperExp e) @@ -3001,7 +3034,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!s) { e.error("`%s` is not in a class scope", e.toChars()); - goto Lerr; + return setError(); } cd = s.isClassDeclaration(); if (cd) @@ -3010,7 +3043,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!cd) { e.error("class `%s` has no `super`", s.toChars()); - goto Lerr; + return setError(); } e.type = cd.type; result = e; @@ -3109,7 +3142,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor e.type = Type.tuns32.sarrayOf(e.len + 1); else e.type = Type.tdchar.immutableOf().arrayOf(); - e.committed = 1; + e.committed = true; break; case 'w': @@ -3134,11 +3167,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor e.type = Type.tuns16.sarrayOf(e.len + 1); else e.type = Type.twchar.immutableOf().arrayOf(); - e.committed = 1; + e.committed = true; break; case 'c': - e.committed = 1; + e.committed = true; goto default; default: @@ -3860,8 +3893,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = id.expressionSemantic(sc); return; } - else if (!exp.onstack && !exp.type.isscope()) + else if (sc.needsCodegen() && // interpreter doesn't need this lowered + !exp.onstack && !exp.type.isscope()) // these won't use the GC { + /* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)` + * or `_d_newclassTTrace` + */ auto hook = global.params.tracegc ? Id._d_newclassTTrace : Id._d_newclassT; if (!verifyHookExist(exp.loc, *sc, hook, "new class")) return setError(); @@ -4533,6 +4570,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } + Type att = null; Lagain: //printf("Lagain: %s\n", toChars()); exp.f = null; @@ -4743,7 +4781,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // overload of opCall, therefore it's a call if (exp.e1.op != EXP.type) { - if (sd.aliasthis && !isRecursiveAliasThis(exp.att1, exp.e1.type)) + if (sd.aliasthis && !isRecursiveAliasThis(att, exp.e1.type)) { exp.e1 = resolveAliasThis(sc, exp.e1); goto Lagain; @@ -4832,10 +4870,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return null; if (f) { - /* Error if match in more than one overload set, + /* Match in more than one overload set, * even if one is a 'better' match than the other. */ - ScopeDsymbol.multiplyDefined(loc, f, f2); + if (f.isCsymbol() && f2.isCsymbol()) + { + /* C has global name space, so just pick one, such as f. + * If f and f2 are not compatible, that's how C rolls. + */ + } + else + ScopeDsymbol.multiplyDefined(loc, f, f2); // issue error } else f = f2; @@ -5203,13 +5248,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_))) { bool err = false; - if (!tf.purity && sc.func.setImpure()) + if (!tf.purity && sc.func.setImpure(exp.loc, "`pure` %s `%s` cannot call impure `%s`", exp.e1)) { exp.error("`pure` %s `%s` cannot call impure %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); err = true; } - if (!tf.isnogc && sc.func.setGC()) + if (!tf.isnogc && sc.func.setGC(exp.loc, "`@nogc` %s `%s` cannot call non-@nogc `%s`", exp.e1)) { exp.error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars()); @@ -6166,7 +6211,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor uint errors = global.errors; const len = buf.length; const str = buf.extractChars()[0 .. len]; - scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false, global.errorSink); + const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput; + auto loc = adjustLocForMixin(str, exp.loc, global.params.mixinOut); + scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests); + p.transitionIn = global.params.vin; p.nextToken(); //printf("p.loc.linnum = %d\n", p.loc.linnum); @@ -6295,19 +6343,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else { - auto readResult = File.read(resolvedNamez); - if (!readResult.success) - { - e.error("cannot read file `%s`", resolvedNamez.ptr); - return setError(); - } - else - { - // take ownership of buffer (probably leaking) - auto data = readResult.extractSlice(); - se = new StringExp(e.loc, data); - global.fileManager.add(fileName, data); - } + e.error("cannot read file `%s`", resolvedNamez.ptr); + return setError(); } } result = se.expressionSemantic(sc); @@ -6321,7 +6358,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("AssertExp::semantic('%s')\n", exp.toChars()); } - const generateMsg = !exp.msg && global.params.checkAction == CHECKACTION.context && global.params.useAssert == CHECKENABLE.on; + const generateMsg = !exp.msg && + sc.needsCodegen() && // let ctfe interpreter handle the error message + global.params.checkAction == CHECKACTION.context && + global.params.useAssert == CHECKENABLE.on; Expression temporariesPrefix; if (generateMsg) @@ -6634,7 +6674,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { import dmd.statementsem; - if (StatementSemanticVisitor.throwSemantic(te.loc, te.e1, sc)) + if (throwSemantic(te.loc, te.e1, sc)) result = te; else setError(); @@ -6927,7 +6967,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } // Indicate we need to resolve by UFCS. - Expression e = exp.dotTemplateSemanticProp(sc, 1); + Expression e = exp.dotTemplateSemanticProp(sc, DotExpFlag.gag); if (!e) e = resolveUFCSProperties(sc, exp); if (e is exp) @@ -7824,7 +7864,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } - if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && (sc.flags & SCOPE.ctfe) == 0) + if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && sc.needsCodegen()) { auto tFrom = t1b.nextOf(); auto tTo = tob.nextOf(); @@ -8914,6 +8954,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor assert((*ae.arguments)[0].op == EXP.interval); ie = cast(IntervalExp)(*ae.arguments)[0]; } + Type att = null; // first cyclic `alias this` type while (true) { if (ae.e1.op == EXP.error) @@ -8988,7 +9029,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // No operator overloading member function found yet, but // there might be an alias this to try. - if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type)) + if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) { /* Rewrite (a[arguments] op e2) as: * a.aliasthis[arguments] op e2 @@ -9016,7 +9057,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor */ if (auto dti = e1x.isDotTemplateInstanceExp()) { - Expression e = dti.dotTemplateSemanticProp(sc, 1); + Expression e = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag); if (!e) { return setResult(resolveUFCSProperties(sc, e1x, exp.e2)); @@ -9070,7 +9111,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor * or: * f() = value */ - if (Expression e = resolvePropertiesX(sc, e1x, exp.e2)) + if (Expression e = resolvePropertiesX(sc, e1x, exp.e2, exp)) return setResult(e); if (e1x.checkRightThis(sc)) @@ -9764,6 +9805,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setResult(res); } + if (!sc.needsCodegen()) // if compile time creature only + { + exp.type = Type.tsize_t; + return setResult(exp); + } + // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2) Expression id = new IdentifierExp(ale.loc, Id.empty); id = new DotIdExp(ale.loc, id, Id.object); @@ -9785,10 +9832,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor arguments.push(ale.e1); arguments.push(exp.e2); - Expression ce = new CallExp(ale.loc, id, arguments); - auto res = ce.expressionSemantic(sc); + Expression ce = new CallExp(ale.loc, id, arguments).expressionSemantic(sc); + auto res = new LoweredAssignExp(exp, ce); // if (global.params.verbose) // message("lowered %s =>\n %s", exp.toChars(), res.toChars()); + res.type = Type.tsize_t; return setResult(res); } else if (auto se = exp.e1.isSliceExp()) @@ -10117,6 +10165,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } } + + if (!sc.needsCodegen()) // interpreter can handle these + return setResult(res); + const lowerToArrayCtor = ( (rhsType.ty == Tarray && !rhs.isArrayLiteralExp) || (rhsType.ty == Tsarray && rhs.isLvalue) ) && @@ -10505,7 +10557,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = res; if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) && - !(sc.flags & (SCOPE.ctfe | SCOPE.compile))) + sc.needsCodegen()) { // if aa ordering is triggered, `res` will be a CommaExp // and `.e2` will be the rewritten original expression. @@ -10898,6 +10950,86 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } + /** + * If the given expression is a `CatExp`, the function tries to lower it to + * `_d_arraycatnTX`. + * + * Params: + * ee = the `CatExp` to lower + * Returns: + * `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en` + * `ee` otherwise + */ + private Expression lowerToArrayCat(CatExp exp) + { + // String literals are concatenated by the compiler. No lowering is needed. + if ((exp.e1.isStringExp() && (exp.e2.isIntegerExp() || exp.e2.isStringExp())) || + (exp.e2.isStringExp() && (exp.e1.isIntegerExp() || exp.e1.isStringExp()))) + return exp; + + Identifier hook = global.params.tracegc ? Id._d_arraycatnTXTrace : Id._d_arraycatnTX; + if (!verifyHookExist(exp.loc, *sc, hook, "concatenating arrays")) + { + setError(); + return result; + } + + void handleCatArgument(Expressions *arguments, Expression e) + { + if (auto ce = e.isCatExp()) + { + Expression lowering = ce.lowering; + + /* Skip `file`, `line`, and `funcname` if the hook of the parent + * `CatExp` is `_d_arraycatnTXTrace`. + */ + if (auto callExp = isRuntimeHook(lowering, hook)) + { + if (hook == Id._d_arraycatnTX) + arguments.pushSlice((*callExp.arguments)[]); + else + arguments.pushSlice((*callExp.arguments)[3 .. $]); + } + } + else + arguments.push(e); + } + + auto arguments = new Expressions(); + if (global.params.tracegc) + { + auto funcname = (sc.callsc && sc.callsc.func) ? + sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); + arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); + arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); + arguments.push(new StringExp(exp.loc, funcname.toDString())); + } + + handleCatArgument(arguments, exp.e1); + handleCatArgument(arguments, exp.e2); + + Expression id = new IdentifierExp(exp.loc, Id.empty); + id = new DotIdExp(exp.loc, id, Id.object); + + auto tiargs = new Objects(); + tiargs.push(exp.type); + id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs); + id = new CallExp(exp.loc, id, arguments); + return id.expressionSemantic(sc); + } + + void trySetCatExpLowering(Expression exp) + { + /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be + * used with `-betterC`, but only during CTFE. + */ + if (global.params.betterC) + return; + + if (auto ce = exp.isCatExp()) + ce.lowering = lowerToArrayCat(ce); + } + override void visit(CatExp exp) { // https://dlang.org/spec/expression.html#cat_expressions @@ -10985,14 +11117,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.e2 = exp.e2.implicitCastTo(sc, tb1next); exp.type = tb1next.arrayOf(); L2elem: - if (tb2.ty == Tarray || tb2.ty == Tsarray) - { - // Make e2 into [e2] - exp.e2 = new ArrayLiteralExp(exp.e2.loc, exp.type, exp.e2); - } - else if (checkNewEscape(sc, exp.e2, false)) + if (checkNewEscape(sc, exp.e2, false)) return setError(); result = exp.optimize(WANTvalue); + trySetCatExpLowering(result); return; } } @@ -11023,14 +11151,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.e1 = exp.e1.implicitCastTo(sc, tb2next); exp.type = tb2next.arrayOf(); L1elem: - if (tb1.ty == Tarray || tb1.ty == Tsarray) - { - // Make e1 into [e1] - exp.e1 = new ArrayLiteralExp(exp.e1.loc, exp.type, exp.e1); - } - else if (checkNewEscape(sc, exp.e1, false)) + if (checkNewEscape(sc, exp.e1, false)) return setError(); result = exp.optimize(WANTvalue); + trySetCatExpLowering(result); return; } } @@ -11053,6 +11177,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (Expression ex = typeCombine(exp, sc)) { result = ex; + trySetCatExpLowering(result); return; } exp.type = exp.type.toHeadMutable(); @@ -11085,6 +11210,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } result = e; + trySetCatExpLowering(result); } override void visit(MulExp exp) @@ -11895,7 +12021,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.error("array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars()); return setError(); } - if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray)) + + if (sc.needsCodegen() && + (t1.ty == Tarray || t1.ty == Tsarray) && + (t2.ty == Tarray || t2.ty == Tsarray)) { if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays")) return setError(); @@ -12762,7 +12891,7 @@ private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc) if (exp.e1.isVarExp() && exp.e1.type.toBasetype().isTypeSArray() && exp.ident == Id.length) { // bypass checkPurity - return exp.e1.type.dotExp(sc, exp.e1, exp.ident, exp.noderef ? DotExpFlag.noDeref : 0); + return exp.e1.type.dotExp(sc, exp.e1, exp.ident, cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref)); } if (!exp.e1.isDotExp()) @@ -12814,11 +12943,11 @@ private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc) * Params: * exp = expression to resolve * sc = context - * flag = if 1 then do not emit error messages, just return null + * gag = do not emit error messages, just return `null` * Returns: * resolved expression, null if error */ -Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, int flag) +Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag) { //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars()); @@ -13061,9 +13190,9 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, int flag) } if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule()) { - flag = 0; + gag = false; } - if (flag) + if (gag) return null; s = ie.sds.search_correct(exp.ident); if (s && symbolIsVisible(sc, s)) @@ -13089,7 +13218,7 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, int flag) )) { Type t1bn = t1b.nextOf(); - if (flag) + if (gag) { if (AggregateDeclaration ad = isAggregate(t1bn)) { @@ -13103,11 +13232,12 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, int flag) * as: * (*p).ident */ - if (flag && t1bn.ty == Tvoid) + if (gag && t1bn.ty == Tvoid) return null; Expression e = new PtrExp(exp.loc, exp.e1); e = e.expressionSemantic(sc); - return e.type.dotExp(sc, e, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0)); + const newFlag = cast(DotExpFlag) (gag * DotExpFlag.gag | exp.noderef * DotExpFlag.noDeref); + return e.type.dotExp(sc, e, exp.ident, newFlag); } else if (exp.ident == Id.__xalignof && exp.e1.isVarExp() && @@ -13140,8 +13270,11 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, int flag) else { if (exp.e1.isTypeExp() || exp.e1.isTemplateExp()) - flag = 0; - Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag | (exp.noderef ? DotExpFlag.noDeref : 0)); + gag = false; + + const flag = cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref | gag * DotExpFlag.gag); + + Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag); if (e) { e = e.expressionSemantic(sc); @@ -13150,9 +13283,16 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, int flag) } } -// Resolve e1.ident!tiargs without seeing UFCS. -// If flag == 1, stop "not a property" error and return NULL. -Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, int flag) +/** + * Resolve `e1.ident!tiargs` without seeing UFCS. + * Params: + * exp = the `DotTemplateInstanceExp` to resolve + * sc = the semantic scope + * gag = stop "not a property" error and return `null`. + * Returns: + * `null` if error or not found, or the resolved expression. + */ +Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool gag) { static if (LOGSEMANTIC) { @@ -13186,11 +13326,11 @@ Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, int fl /* No built-in type has templatized properties, so do shortcut. * It is necessary in: 1024.max!"a < b" */ - if (flag) + if (gag) return null; } - e = die.dotIdSemanticProp(sc, flag); - if (flag) + e = die.dotIdSemanticProp(sc, gag); + if (gag) { if (!e || isDotOpDispatch(e)) @@ -13905,6 +14045,7 @@ Expression toBoolean(Expression exp, Scope* sc) case EXP.assign: case EXP.construct: case EXP.blit: + case EXP.loweredAssignExp: if (sc.flags & SCOPE.Cfile) return exp; // Things like: diff --git a/gcc/d/dmd/foreachvar.d b/gcc/d/dmd/foreachvar.d index ba2825a..7a96469 100644 --- a/gcc/d/dmd/foreachvar.d +++ b/gcc/d/dmd/foreachvar.d @@ -299,7 +299,7 @@ void foreachExpAndVar(Statement s, case STMT.Conditional: case STMT.While: case STMT.Forwarding: - case STMT.Compile: + case STMT.Mixin: case STMT.Peel: case STMT.Synchronized: assert(0); // should have been rewritten diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 4b6b5b5..8e11ab1 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -204,6 +204,7 @@ private struct FUNCFLAG bool hasCatches; /// function has try-catch statements bool skipCodegen; /// do not generate code for this function. bool printf; /// is a printf-like function + bool scanf; /// is a scanf-like function bool noreturn; /// the function does not return bool isNRVO = true; /// Support for named return value optimization @@ -214,11 +215,14 @@ private struct FUNCFLAG bool hasNoEH; /// No exception unwinding is needed bool inferRetType; /// Return type is to be inferred bool hasDualContext; /// has a dual-context 'this' parameter + bool hasAlwaysInlines; /// Contains references to functions that must be inlined bool isCrtCtor; /// Has attribute pragma(crt_constructor) bool isCrtDtor; /// Has attribute pragma(crt_destructor) bool hasEscapingSiblings;/// Has sibling functions that escape bool computedEscapingSiblings; /// `hasEscapingSiblings` has been computed + bool dllImport; /// __declspec(dllimport) + bool dllExport; /// __declspec(dllexport) } /*********************************************************** @@ -356,6 +360,9 @@ extern (C++) class FuncDeclaration : Declaration /// In case of failed `@safe` inference, store the error that made the function `@system` for /// better diagnostics AttributeViolation* safetyViolation; + AttributeViolation* nogcViolation; + AttributeViolation* pureViolation; + AttributeViolation* nothrowViolation; /// See the `FUNCFLAG` struct import dmd.common.bitfields; @@ -370,8 +377,8 @@ extern (C++) class FuncDeclaration : Declaration extern (D) this(const ref Loc loc, const ref Loc endloc, Identifier ident, StorageClass storage_class, Type type, bool noreturn = false) { super(loc, ident); - //printf("FuncDeclaration(id = '%s', type = %p)\n", id.toChars(), type); - //printf("storage_class = x%x\n", storage_class); + //.printf("FuncDeclaration(id = '%s', type = %s)\n", ident.toChars(), type.toChars()); + //.printf("storage_class = x%llx\n", storage_class); this.storage_class = storage_class; this.type = type; if (type) @@ -1294,14 +1301,14 @@ extern (C++) class FuncDeclaration : Declaration override final bool isExport() const { - return visibility.kind == Visibility.Kind.export_; + return visibility.kind == Visibility.Kind.export_ || dllExport; } override final bool isImportedSymbol() const { //printf("isImportedSymbol()\n"); //printf("protection = %d\n", visibility); - return (visibility.kind == Visibility.Kind.export_) && !fbody; + return (visibility.kind == Visibility.Kind.export_ || dllImport) && !fbody; } override final bool isCodeseg() const pure nothrow @nogc @safe @@ -1441,17 +1448,27 @@ extern (C++) class FuncDeclaration : Declaration } /************************************** - * The function is doing something impure, - * so mark it as impure. - * If there's a purity error, return true. + * The function is doing something impure, so mark it as impure. + * + * Params: + * loc = location of impure action + * fmt = format string for error message. Must include "%s `%s`" for the function kind and name. + * arg0 = (optional) argument to format string + * + * Returns: `true` if there's a purity error */ - extern (D) final bool setImpure() + extern (D) final bool setImpure(Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null) { if (purityInprocess) { purityInprocess = false; + if (fmt) + pureViolation = new AttributeViolation(loc, fmt, this, arg0); // impure action + else if (arg0) + pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function + if (fes) - fes.func.setImpure(); + fes.func.setImpure(loc, fmt, arg0); } else if (isPure()) return true; @@ -1540,7 +1557,7 @@ extern (C++) class FuncDeclaration : Declaration { //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess)); if (nogcInprocess) - setGC(); + setGC(loc, null); return type.toTypeFunction().isnogc; } @@ -1552,10 +1569,16 @@ extern (C++) class FuncDeclaration : Declaration /************************************** * The function is doing something that may allocate with the GC, * so mark it as not nogc (not no-how). + * + * Params: + * loc = location of impure action + * fmt = format string for error message. Must include "%s `%s`" for the function kind and name. + * arg0 = (optional) argument to format string + * * Returns: * true if function is marked as @nogc, meaning a user error occurred */ - extern (D) final bool setGC() + extern (D) final bool setGC(Loc loc, const(char)* fmt, RootObject arg0 = null) { //printf("setGC() %s\n", toChars()); if (nogcInprocess && semanticRun < PASS.semantic3 && _scope) @@ -1567,15 +1590,59 @@ extern (C++) class FuncDeclaration : Declaration if (nogcInprocess) { nogcInprocess = false; + if (fmt) + nogcViolation = new AttributeViolation(loc, fmt, this, arg0); // action that requires GC + else if (arg0) + nogcViolation = new AttributeViolation(loc, fmt, arg0); // call to non-@nogc function + type.toTypeFunction().isnogc = false; if (fes) - fes.func.setGC(); + fes.func.setGC(Loc.init, null, null); } else if (isNogc()) return true; return false; } + /************************************** + * The function calls non-`@nogc` function f, mark it as not nogc. + * Params: + * f = function being called + * Returns: + * true if function is marked as @nogc, meaning a user error occurred + */ + extern (D) final bool setGCCall(FuncDeclaration f) + { + return setGC(loc, null, f); + } + + /************************************** + * The function is doing something that may throw an exception, register that in case nothrow is being inferred + * + * Params: + * loc = location of action + * fmt = format string for error message + * arg0 = (optional) argument to format string + */ + extern (D) final void setThrow(Loc loc, const(char)* fmt, RootObject arg0 = null) + { + if (nothrowInprocess && !nothrowViolation) + { + nothrowViolation = new AttributeViolation(loc, fmt, arg0); // action that requires GC + } + } + + /************************************** + * The function calls non-`nothrow` function f, register that in case nothrow is being inferred + * Params: + * loc = location of call + * f = function being called + */ + extern (D) final void setThrowCall(Loc loc, FuncDeclaration f) + { + return setThrow(loc, null, f); + } + extern (D) final void printGCUsage(const ref Loc loc, const(char)* warn) { if (!global.params.vgc) @@ -2119,7 +2186,7 @@ extern (C++) class FuncDeclaration : Declaration if (!needsClosure()) return false; - if (setGC()) + if (setGC(loc, "%s `%s` is `@nogc` yet allocates closure for `%s()` with the GC", this)) { error("is `@nogc` yet allocates closure for `%s()` with the GC", toChars()); if (global.gag) // need not report supplemental errors @@ -4531,18 +4598,51 @@ struct AttributeViolation /// fd = function to check /// maxDepth = up to how many functions deep to report errors /// deprecation = print deprecations instead of errors -void errorSupplementalInferredSafety(FuncDeclaration fd, int maxDepth, bool deprecation) +/// stc = storage class of attribute to check +void errorSupplementalInferredAttr(FuncDeclaration fd, int maxDepth, bool deprecation, STC stc) { auto errorFunc = deprecation ? &deprecationSupplemental : &errorSupplemental; - if (auto s = fd.safetyViolation) + + AttributeViolation* s; + const(char)* attr; + if (stc & STC.safe) + { + s = fd.safetyViolation; + attr = "@safe"; + } + else if (stc & STC.pure_) + { + s = fd.pureViolation; + attr = "pure"; + } + else if (stc & STC.nothrow_) + { + s = fd.nothrowViolation; + attr = "nothrow"; + } + else if (stc & STC.nogc) + { + s = fd.nogcViolation; + attr = "@nogc"; + } + + if (s) { if (s.fmtStr) { errorFunc(s.loc, deprecation ? - "which would be `@system` because of:" : - "which was inferred `@system` because of:"); - errorFunc(s.loc, s.fmtStr, - s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : ""); + "which wouldn't be `%s` because of:" : + "which wasn't inferred `%s` because of:", attr); + if (stc == STC.nogc || stc == STC.pure_) + { + auto f = (cast(Dsymbol) s.arg0).isFuncDeclaration(); + errorFunc(s.loc, s.fmtStr, f.kind(), f.toPrettyChars(), s.arg1 ? s.arg1.toChars() : ""); + } + else + { + errorFunc(s.loc, s.fmtStr, + s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : ""); + } } else if (s.arg0.dyncast() == DYNCAST.dsymbol) { @@ -4551,7 +4651,7 @@ void errorSupplementalInferredSafety(FuncDeclaration fd, int maxDepth, bool depr if (maxDepth > 0) { errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars()); - errorSupplementalInferredSafety(fd2, maxDepth - 1, deprecation); + errorSupplementalInferredAttr(fd2, maxDepth - 1, deprecation, stc); } } } diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index 1919d9a..45b4528 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -11,7 +11,10 @@ module dmd.globals; +import core.stdc.stdio; import core.stdc.stdint; +import core.stdc.string; + import dmd.root.array; import dmd.root.filename; import dmd.common.outbuffer; @@ -20,6 +23,8 @@ import dmd.errors; import dmd.file_manager; import dmd.identifier; import dmd.location; +import dmd.lexer : CompileEnv; +import dmd.utils; /// Defines a setting for how compiler warnings and deprecations are handled enum DiagnosticReporting : ubyte @@ -149,7 +154,7 @@ extern (C++) struct Param FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params bool ehnogc; // use @nogc exception handling bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md - bool fieldwise; // do struct equality testing field-wise rather than by memcmp() + FeatureState fieldwise; // do struct equality testing field-wise rather than by memcmp() bool fixAliasThis; // if the current scope has an alias this, check it before searching upper scopes FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters // https://dconf.org/2019/talks/alexandrescu.html @@ -209,6 +214,7 @@ extern (C++) struct Param bool run; // run resulting executable Strings runargs; // arguments for executable Array!(const(char)*) cppswitches; // C preprocessor switches + const(char)* cpp; // if not null, then this specifies the C preprocessor // Linker stuff Array!(const(char)*) objfiles; @@ -222,30 +228,6 @@ extern (C++) struct Param const(char)[] mapfile; } -extern (C++) struct structalign_t -{ - private: - ushort value = 0; // unknown - enum STRUCTALIGN_DEFAULT = 1234; // default = match whatever the corresponding C compiler does - bool pack; // use #pragma pack semantics - - public: - pure @safe @nogc nothrow: - bool isDefault() const { return value == STRUCTALIGN_DEFAULT; } - void setDefault() { value = STRUCTALIGN_DEFAULT; } - bool isUnknown() const { return value == 0; } // value is not set - void setUnknown() { value = 0; } - void set(uint value) { this.value = cast(ushort)value; } - uint get() const { return value; } - bool isPack() const { return pack; } - void setPack(bool pack) { this.pack = pack; } -} -//alias structalign_t = uint; - -// magic value means "match whatever the underlying C compiler does" -// other values are all powers of 2 -//enum STRUCTALIGN_DEFAULT = (cast(structalign_t)~0); - enum mars_ext = "d"; // for D source files enum doc_ext = "html"; // for Ddoc generated files enum ddoc_ext = "ddoc"; // for Ddoc macro include files @@ -270,9 +252,7 @@ extern (C++) struct Global Array!(const(char)*)* filePath; /// Array of char*'s which form the file import lookup path private enum string _version = import("VERSION"); - private enum uint _versionNumber = parseVersionNumber(_version); - - const(char)[] vendor; /// Compiler backend name + CompileEnv compileEnv; Param params; /// command line parameters uint errors; /// number of errors reported so far @@ -350,12 +330,12 @@ extern (C++) struct Global extern (C++) void _init() { - global.errorSink = new ErrorSinkCompiler; + errorSink = new ErrorSinkCompiler; this.fileManager = new FileManager(); version (MARS) { - vendor = "Digital Mars D"; + compileEnv.vendor = "Digital Mars D"; // -color=auto is the default value import dmd.console : detectTerminal; @@ -363,8 +343,38 @@ extern (C++) struct Global } else version (IN_GCC) { - vendor = "GNU D"; + compileEnv.vendor = "GNU D"; + } + compileEnv.versionNumber = parseVersionNumber(_version); + + /* Initialize date, time, and timestamp + */ + import core.stdc.time; + import core.stdc.stdlib : getenv; + + time_t ct; + // https://issues.dlang.org/show_bug.cgi?id=20444 + if (auto p = getenv("SOURCE_DATE_EPOCH")) + { + if (!ct.parseDigits(p[0 .. strlen(p)])) + errorSink.error(Loc.initial, "value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p); } + else + core.stdc.time.time(&ct); + const p = ctime(&ct); + assert(p); + + __gshared char[11 + 1] date = 0; // put in BSS segment + __gshared char[8 + 1] time = 0; + __gshared char[24 + 1] timestamp = 0; + + const dsz = snprintf(&date[0], date.length, "%.6s %.4s", p + 4, p + 20); + const tsz = snprintf(&time[0], time.length, "%.8s", p + 11); + const tssz = snprintf(×tamp[0], timestamp.length, "%.24s", p); + assert(dsz > 0 && tsz > 0 && tssz > 0); + compileEnv.time = time[0 .. tsz]; + compileEnv.date = date[0 .. dsz]; + compileEnv.timestamp = timestamp[0 .. tssz]; } /** @@ -415,7 +425,7 @@ extern (C++) struct Global */ extern(C++) uint versionNumber() { - return _versionNumber; + return compileEnv.versionNumber; } /** diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 84fbec6..902cf83 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -151,7 +151,7 @@ struct Param FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params d_bool ehnogc; // use @nogc exception handling d_bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md - d_bool fieldwise; // do struct equality testing field-wise rather than by memcmp() + FeatureState fieldwise; // do struct equality testing field-wise rather than by memcmp() d_bool fixAliasThis; // if the current scope has an alias this, check it before searching upper scopes FeatureState rvalueRefParam; // allow rvalues to be arguments to ref parameters // https://dconf.org/2019/talks/alexandrescu.html @@ -212,6 +212,7 @@ struct Param Strings runargs; // arguments for executable Array<const char *> cppswitches; // preprocessor switches + const char *cpp; // if not null, then this specifies the C preprocessor // Linker stuff Array<const char *> objfiles; @@ -252,6 +253,18 @@ const DString hdr_ext = "di"; // for D 'header' import files const DString json_ext = "json"; // for JSON files const DString map_ext = "map"; // for .map files +struct CompileEnv +{ + uint32_t versionNumber; + DString date; + DString time; + DString vendor; + DString timestamp; + bool previewIn; + bool ddocOutput; + bool shortenedMethods; +}; + struct Global { DString inifilename; @@ -261,7 +274,7 @@ struct Global Array<const char *> *path; // Array of char*'s which form the import lookup path Array<const char *> *filePath; // Array of char*'s which form the file import lookup path - DString vendor; // Compiler backend name + CompileEnv compileEnv; Param params; unsigned errors; // number of errors reported so far diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index e0684e6..a159c2f 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -134,37 +134,19 @@ void moduleToBuffer2(Module m, OutBuffer* buf, HdrGenState* hgs) private void statementToBuffer(Statement s, OutBuffer* buf, HdrGenState* hgs) { - scope v = new StatementPrettyPrintVisitor(buf, hgs); - s.accept(v); -} - -private extern (C++) final class StatementPrettyPrintVisitor : Visitor -{ - alias visit = Visitor.visit; -public: - OutBuffer* buf; - HdrGenState* hgs; - - extern (D) this(OutBuffer* buf, HdrGenState* hgs) scope + void visitDefaultCase(Statement s) { - this.buf = buf; - this.hgs = hgs; + printf("Statement::toCBuffer() %d\n", s.stmt); + assert(0, "unrecognized statement in statementToBuffer()"); } - override void visit(Statement s) - { - buf.writestring("Statement::toCBuffer()"); - buf.writenl(); - assert(0); - } - - override void visit(ErrorStatement s) + void visitError(ErrorStatement s) { buf.writestring("__error__"); buf.writenl(); } - override void visit(ExpStatement s) + void visitExp(ExpStatement s) { if (s.exp && s.exp.op == EXP.declaration && (cast(DeclarationExp)s.exp).declaration) @@ -180,7 +162,12 @@ public: buf.writenl(); } - override void visit(CompileStatement s) + void visitDtorExp(DtorExpStatement s) + { + visitExp(s); + } + + void visitMixin(MixinStatement s) { buf.writestring("mixin("); argsToBuffer(s.exps, buf, hgs, null); @@ -189,25 +176,29 @@ public: buf.writenl(); } - override void visit(CompoundStatement s) + void visitCompound(CompoundStatement s) { foreach (sx; *s.statements) { if (sx) - sx.accept(this); + sx.statementToBuffer(buf, hgs); } } - override void visit(CompoundDeclarationStatement s) + void visitCompoundAsm(CompoundAsmStatement s) + { + visitCompound(s); + } + + void visitCompoundDeclaration(CompoundDeclarationStatement s) { bool anywritten = false; foreach (sx; *s.statements) { auto ds = sx ? sx.isExpStatement() : null; - if (ds && ds.exp.op == EXP.declaration) + if (ds && ds.exp.isDeclarationExp()) { - auto d = (cast(DeclarationExp)ds.exp).declaration; - assert(d.isDeclaration()); + auto d = ds.exp.isDeclarationExp().declaration; if (auto v = d.isVarDeclaration()) { scope ppv = new DsymbolPrettyPrintVisitor(buf, hgs); @@ -223,7 +214,7 @@ public: buf.writenl(); } - override void visit(UnrolledLoopStatement s) + void visitUnrolledLoop(UnrolledLoopStatement s) { buf.writestring("/*unrolled*/ {"); buf.writenl(); @@ -231,26 +222,26 @@ public: foreach (sx; *s.statements) { if (sx) - sx.accept(this); + sx.statementToBuffer(buf, hgs); } buf.level--; buf.writeByte('}'); buf.writenl(); } - override void visit(ScopeStatement s) + void visitScope(ScopeStatement s) { buf.writeByte('{'); buf.writenl(); buf.level++; if (s.statement) - s.statement.accept(this); + s.statement.statementToBuffer(buf, hgs); buf.level--; buf.writeByte('}'); buf.writenl(); } - override void visit(WhileStatement s) + void visitWhile(WhileStatement s) { buf.writestring("while ("); if (auto p = s.param) @@ -271,28 +262,28 @@ public: buf.writeByte(')'); buf.writenl(); if (s._body) - s._body.accept(this); + s._body.statementToBuffer(buf, hgs); } - override void visit(DoStatement s) + void visitDo(DoStatement s) { buf.writestring("do"); buf.writenl(); if (s._body) - s._body.accept(this); + s._body.statementToBuffer(buf, hgs); buf.writestring("while ("); s.condition.expressionToBuffer(buf, hgs); buf.writestring(");"); buf.writenl(); } - override void visit(ForStatement s) + void visitFor(ForStatement s) { buf.writestring("for ("); if (s._init) { hgs.forStmtInit++; - s._init.accept(this); + s._init.statementToBuffer(buf, hgs); hgs.forStmtInit--; } else @@ -314,13 +305,13 @@ public: buf.writenl(); buf.level++; if (s._body) - s._body.accept(this); + s._body.statementToBuffer(buf, hgs); buf.level--; buf.writeByte('}'); buf.writenl(); } - private void foreachWithoutBody(ForeachStatement s) + void foreachWithoutBody(ForeachStatement s) { buf.writestring(Token.toString(s.op)); buf.writestring(" ("); @@ -341,20 +332,20 @@ public: buf.writenl(); } - override void visit(ForeachStatement s) + void visitForeach(ForeachStatement s) { foreachWithoutBody(s); buf.writeByte('{'); buf.writenl(); buf.level++; if (s._body) - s._body.accept(this); + s._body.statementToBuffer(buf, hgs); buf.level--; buf.writeByte('}'); buf.writenl(); } - private void foreachRangeWithoutBody(ForeachRangeStatement s) + void foreachRangeWithoutBody(ForeachRangeStatement s) { buf.writestring(Token.toString(s.op)); buf.writestring(" ("); @@ -370,39 +361,39 @@ public: buf.writenl(); } - override void visit(ForeachRangeStatement s) + void visitForeachRange(ForeachRangeStatement s) { foreachRangeWithoutBody(s); buf.writeByte('{'); buf.writenl(); buf.level++; if (s._body) - s._body.accept(this); + s._body.statementToBuffer(buf, hgs); buf.level--; buf.writeByte('}'); buf.writenl(); } - override void visit(StaticForeachStatement s) + void visitStaticForeach(StaticForeachStatement s) { buf.writestring("static "); if (s.sfe.aggrfe) { - visit(s.sfe.aggrfe); + visitForeach(s.sfe.aggrfe); } else { assert(s.sfe.rangefe); - visit(s.sfe.rangefe); + visitForeachRange(s.sfe.rangefe); } } - override void visit(ForwardingStatement s) + void visitForwarding(ForwardingStatement s) { - s.statement.accept(this); + s.statement.statementToBuffer(buf, hgs); } - override void visit(IfStatement s) + void visitIf(IfStatement s) { buf.writestring("if ("); if (Parameter p = s.prm) @@ -423,12 +414,12 @@ public: buf.writenl(); if (s.ifbody.isScopeStatement()) { - s.ifbody.accept(this); + s.ifbody.statementToBuffer(buf, hgs); } else { buf.level++; - s.ifbody.accept(this); + s.ifbody.statementToBuffer(buf, hgs); buf.level--; } if (s.elsebody) @@ -444,18 +435,18 @@ public: } if (s.elsebody.isScopeStatement() || s.elsebody.isIfStatement()) { - s.elsebody.accept(this); + s.elsebody.statementToBuffer(buf, hgs); } else { buf.level++; - s.elsebody.accept(this); + s.elsebody.statementToBuffer(buf, hgs); buf.level--; } } } - override void visit(ConditionalStatement s) + void visitConditional(ConditionalStatement s) { s.condition.conditionToBuffer(buf, hgs); buf.writenl(); @@ -463,7 +454,7 @@ public: buf.writenl(); buf.level++; if (s.ifbody) - s.ifbody.accept(this); + s.ifbody.statementToBuffer(buf, hgs); buf.level--; buf.writeByte('}'); buf.writenl(); @@ -474,14 +465,14 @@ public: buf.writeByte('{'); buf.level++; buf.writenl(); - s.elsebody.accept(this); + s.elsebody.statementToBuffer(buf, hgs); buf.level--; buf.writeByte('}'); } buf.writenl(); } - override void visit(PragmaStatement s) + void visitPragma(PragmaStatement s) { buf.writestring("pragma ("); buf.writestring(s.ident.toString()); @@ -497,7 +488,7 @@ public: buf.writeByte('{'); buf.writenl(); buf.level++; - s._body.accept(this); + s._body.statementToBuffer(buf, hgs); buf.level--; buf.writeByte('}'); buf.writenl(); @@ -509,12 +500,12 @@ public: } } - override void visit(StaticAssertStatement s) + void visitStaticAssert(StaticAssertStatement s) { s.sa.dsymbolToBuffer(buf, hgs); } - override void visit(SwitchStatement s) + void visitSwitch(SwitchStatement s) { buf.writestring(s.isFinal ? "final switch (" : "switch ("); s.condition.expressionToBuffer(buf, hgs); @@ -527,28 +518,28 @@ public: buf.writeByte('{'); buf.writenl(); buf.level++; - s._body.accept(this); + s._body.statementToBuffer(buf, hgs); buf.level--; buf.writeByte('}'); buf.writenl(); } else { - s._body.accept(this); + s._body.statementToBuffer(buf, hgs); } } } - override void visit(CaseStatement s) + void visitCase(CaseStatement s) { buf.writestring("case "); s.exp.expressionToBuffer(buf, hgs); buf.writeByte(':'); buf.writenl(); - s.statement.accept(this); + s.statement.statementToBuffer(buf, hgs); } - override void visit(CaseRangeStatement s) + void visitCaseRange(CaseRangeStatement s) { buf.writestring("case "); s.first.expressionToBuffer(buf, hgs); @@ -556,23 +547,23 @@ public: s.last.expressionToBuffer(buf, hgs); buf.writeByte(':'); buf.writenl(); - s.statement.accept(this); + s.statement.statementToBuffer(buf, hgs); } - override void visit(DefaultStatement s) + void visitDefault(DefaultStatement s) { buf.writestring("default:"); buf.writenl(); - s.statement.accept(this); + s.statement.statementToBuffer(buf, hgs); } - override void visit(GotoDefaultStatement s) + void visitGotoDefault(GotoDefaultStatement s) { buf.writestring("goto default;"); buf.writenl(); } - override void visit(GotoCaseStatement s) + void visitGotoCase(GotoCaseStatement s) { buf.writestring("goto case"); if (s.exp) @@ -584,13 +575,13 @@ public: buf.writenl(); } - override void visit(SwitchErrorStatement s) + void visitSwitchError(SwitchErrorStatement s) { buf.writestring("SwitchErrorStatement::toCBuffer()"); buf.writenl(); } - override void visit(ReturnStatement s) + void visitReturn(ReturnStatement s) { buf.writestring("return "); if (s.exp) @@ -599,7 +590,7 @@ public: buf.writenl(); } - override void visit(BreakStatement s) + void visitBreak(BreakStatement s) { buf.writestring("break"); if (s.ident) @@ -611,7 +602,7 @@ public: buf.writenl(); } - override void visit(ContinueStatement s) + void visitContinue(ContinueStatement s) { buf.writestring("continue"); if (s.ident) @@ -623,7 +614,7 @@ public: buf.writenl(); } - override void visit(SynchronizedStatement s) + void visitSynchronized(SynchronizedStatement s) { buf.writestring("synchronized"); if (s.exp) @@ -635,21 +626,21 @@ public: if (s._body) { buf.writeByte(' '); - s._body.accept(this); + s._body.statementToBuffer(buf, hgs); } } - override void visit(WithStatement s) + void visitWith(WithStatement s) { buf.writestring("with ("); s.exp.expressionToBuffer(buf, hgs); buf.writestring(")"); buf.writenl(); if (s._body) - s._body.accept(this); + s._body.statementToBuffer(buf, hgs); } - override void visit(TryCatchStatement s) + void visitTryCatch(TryCatchStatement s) { buf.writestring("try"); buf.writenl(); @@ -657,29 +648,44 @@ public: { if (s._body.isScopeStatement()) { - s._body.accept(this); + s._body.statementToBuffer(buf, hgs); } else { buf.level++; - s._body.accept(this); + s._body.statementToBuffer(buf, hgs); buf.level--; } } foreach (c; *s.catches) { - visit(c); + buf.writestring("catch"); + if (c.type) + { + buf.writeByte('('); + typeToBuffer(c.type, c.ident, buf, hgs); + buf.writeByte(')'); + } + buf.writenl(); + buf.writeByte('{'); + buf.writenl(); + buf.level++; + if (c.handler) + c.handler.statementToBuffer(buf, hgs); + buf.level--; + buf.writeByte('}'); + buf.writenl(); } } - override void visit(TryFinallyStatement s) + void visitTryFinally(TryFinallyStatement s) { buf.writestring("try"); buf.writenl(); buf.writeByte('{'); buf.writenl(); buf.level++; - s._body.accept(this); + s._body.statementToBuffer(buf, hgs); buf.level--; buf.writeByte('}'); buf.writenl(); @@ -687,25 +693,25 @@ public: buf.writenl(); if (s.finalbody.isScopeStatement()) { - s.finalbody.accept(this); + s.finalbody.statementToBuffer(buf, hgs); } else { buf.level++; - s.finalbody.accept(this); + s.finalbody.statementToBuffer(buf, hgs); buf.level--; } } - override void visit(ScopeGuardStatement s) + void visitScopeGuard(ScopeGuardStatement s) { buf.writestring(Token.toString(s.tok)); buf.writeByte(' '); if (s.statement) - s.statement.accept(this); + s.statement.statementToBuffer(buf, hgs); } - override void visit(ThrowStatement s) + void visitThrow(ThrowStatement s) { buf.writestring("throw "); s.exp.expressionToBuffer(buf, hgs); @@ -713,15 +719,15 @@ public: buf.writenl(); } - override void visit(DebugStatement s) + void visitDebug(DebugStatement s) { if (s.statement) { - s.statement.accept(this); + s.statement.statementToBuffer(buf, hgs); } } - override void visit(GotoStatement s) + void visitGoto(GotoStatement s) { buf.writestring("goto "); buf.writestring(s.ident.toString()); @@ -729,16 +735,16 @@ public: buf.writenl(); } - override void visit(LabelStatement s) + void visitLabel(LabelStatement s) { buf.writestring(s.ident.toString()); buf.writeByte(':'); buf.writenl(); if (s.statement) - s.statement.accept(this); + s.statement.statementToBuffer(buf, hgs); } - override void visit(AsmStatement s) + void visitAsm(AsmStatement s) { buf.writestring("asm { "); Token* t = s.tokens; @@ -764,33 +770,26 @@ public: buf.writenl(); } - override void visit(ImportStatement s) + void visitInlineAsm(InlineAsmStatement s) { - foreach (imp; *s.imports) - { - imp.dsymbolToBuffer(buf, hgs); - } + visitAsm(s); } - void visit(Catch c) + void visitGccAsm(GccAsmStatement s) { - buf.writestring("catch"); - if (c.type) + visitAsm(s); + } + + void visitImport(ImportStatement s) + { + foreach (imp; *s.imports) { - buf.writeByte('('); - typeToBuffer(c.type, c.ident, buf, hgs); - buf.writeByte(')'); + imp.dsymbolToBuffer(buf, hgs); } - buf.writenl(); - buf.writeByte('{'); - buf.writenl(); - buf.level++; - if (c.handler) - c.handler.accept(this); - buf.level--; - buf.writeByte('}'); - buf.writenl(); } + + mixin VisitStatement!void visit; + visit.VisitStatement(s); } private void dsymbolToBuffer(Dsymbol s, OutBuffer* buf, HdrGenState* hgs) @@ -1160,7 +1159,7 @@ public: } - override void visit(CompileDeclaration d) + override void visit(MixinDeclaration d) { buf.writestring("mixin("); argsToBuffer(d.exps, buf, hgs, null); @@ -2321,6 +2320,16 @@ private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hg expToBuffer(e.e1, precedence[e.op], buf, hgs); } + void visitLoweredAssignExp(LoweredAssignExp e) + { + if (global.params.vcg_ast) + { + expressionToBuffer(e.lowering, buf, hgs); + return; + } + + visit(cast(BinExp)e); + } void visitBin(BinExp e) { expToBuffer(e.e1, precedence[e.op], buf, hgs); @@ -2694,6 +2703,7 @@ private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hg case EXP.remove: return visitRemove(e.isRemoveExp()); case EXP.question: return visitCond(e.isCondExp()); case EXP.classReference: return visitClassReference(e.isClassReferenceExp()); + case EXP.loweredAssignExp: return visitLoweredAssignExp(e.isLoweredAssignExp()); } } @@ -2882,8 +2892,7 @@ public: void toCBuffer(const Statement s, OutBuffer* buf, HdrGenState* hgs) { - scope v = new StatementPrettyPrintVisitor(buf, hgs); - (cast() s).accept(v); + (cast()s).statementToBuffer(buf, hgs); } void toCBuffer(const Type t, OutBuffer* buf, const Identifier ident, HdrGenState* hgs) @@ -3223,6 +3232,7 @@ private void parametersToBuffer(ParameterList pl, OutBuffer* buf, HdrGenState* h final switch (pl.varargs) { case VarArg.none: + case VarArg.KRvariadic: break; case VarArg.variadic: @@ -3817,15 +3827,8 @@ private void initializerToBuffer(Initializer inx, OutBuffer* buf, HdrGenState* h buf.writeByte('}'); } - final switch (inx.kind) - { - case InitKind.error: return visitError (inx.isErrorInitializer ()); - case InitKind.void_: return visitVoid (inx.isVoidInitializer ()); - case InitKind.struct_: return visitStruct(inx.isStructInitializer()); - case InitKind.array: return visitArray (inx.isArrayInitializer ()); - case InitKind.exp: return visitExp (inx.isExpInitializer ()); - case InitKind.C_: return visitC (inx.isCInitializer ()); - } + mixin VisitInitializer!void visit; + visit.VisitInitializer(inx); } @@ -4101,7 +4104,6 @@ string EXPtoString(EXP op) EXP.error : "error", EXP.objcClassReference : "class", - EXP.typeof_ : "typeof", EXP.mixin_ : "mixin", EXP.import_ : "import", @@ -4141,7 +4143,6 @@ string EXPtoString(EXP op) EXP.remove : "remove", EXP.tuple : "tuple", EXP.traits : "__traits", - EXP.default_ : "default", EXP.overloadSet : "__overloadset", EXP.void_ : "void", EXP.vectorArray : "vectorarray", @@ -4232,6 +4233,7 @@ string EXPtoString(EXP op) EXP.declaration : "declaration", EXP.interval : "interval", + EXP.loweredAssignExp : "=" ]; const p = strings[op]; if (!p) diff --git a/gcc/d/dmd/iasm.d b/gcc/d/dmd/iasm.d index 4d780b3..66829da 100644 --- a/gcc/d/dmd/iasm.d +++ b/gcc/d/dmd/iasm.d @@ -13,9 +13,15 @@ module dmd.iasm; +import core.stdc.stdio; + import dmd.dscope; +import dmd.expression; import dmd.func; +import dmd.mtype; +import dmd.tokens; import dmd.statement; +import dmd.statementsem; version (MARS) { @@ -43,6 +49,19 @@ extern(C++) Statement asmSemantic(AsmStatement s, Scope *sc) version (MARS) { + /* If it starts with a string literal, it's gcc inline asm + */ + if (s.tokens.value == TOK.string_) + { + /* Replace the asm statement with an assert(0, msg) that trips at runtime. + */ + const loc = s.loc; + auto e = new IntegerExp(loc, 0, Type.tint32); + auto msg = new StringExp(loc, "Gnu Asm not supported - compile this function with gcc or clang"); + auto ae = new AssertExp(loc, e, msg); + auto se = new ExpStatement(loc, ae); + return statementSemantic(se, sc); + } auto ias = new InlineAsmStatement(s.loc, s.tokens); return inlineAsmSemantic(ias, sc); } diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d index f8c88ab..1d4dea4 100644 --- a/gcc/d/dmd/iasmgcc.d +++ b/gcc/d/dmd/iasmgcc.d @@ -302,7 +302,8 @@ Ldone: extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc) { //printf("GccAsmStatement.semantic()\n"); - scope p = new Parser!ASTCodegen(sc._module, ";", false, global.errorSink); + const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput; + scope p = new Parser!ASTCodegen(sc._module, ";", false, global.errorSink, &global.compileEnv, doUnittests); // Make a safe copy of the token list before parsing. Token *toklist = null; @@ -410,7 +411,8 @@ unittest { const errors = global.errors; scope gas = new GccAsmStatement(Loc.initial, tokens); - scope p = new Parser!ASTCodegen(null, ";", false, global.errorSink); + const bool doUnittests = false; + scope p = new Parser!ASTCodegen(null, ";", false, global.errorSink, &global.compileEnv, doUnittests); p.token = *tokens; p.parseGccAsm(gas); return global.errors - errors; @@ -420,7 +422,8 @@ unittest static void parseAsm(string input, bool expectError) { // Generate tokens from input test. - scope p = new Parser!ASTCodegen(null, input, false, global.errorSink); + const bool doUnittests = false; + scope p = new Parser!ASTCodegen(null, input, false, global.errorSink, &global.compileEnv, doUnittests); p.nextToken(); Token* toklist = null; diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index ec5cb25..a2271d5 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -361,6 +361,8 @@ immutable Msgtable[] msgtable = { "_d_arrayappendcTXImpl" }, { "_d_arrayappendcTX" }, { "_d_arrayappendcTXTrace" }, + { "_d_arraycatnTX" }, + { "_d_arraycatnTXTrace" }, // varargs implementation { "stdc" }, @@ -370,6 +372,10 @@ immutable Msgtable[] msgtable = // Builtin functions { "std" }, { "core" }, + { "config" }, + { "c_complex_float" }, + { "c_complex_double" }, + { "c_complex_real" }, { "etc" }, { "attribute" }, { "atomic" }, @@ -519,9 +525,17 @@ immutable Msgtable[] msgtable = { "__tag" }, { "dllimport" }, { "dllexport" }, + { "naked" }, + { "thread" }, { "vector_size" }, { "__func__" }, + { "always_inline" }, + { "noinline" }, { "noreturn" }, + { "_nothrow", "nothrow" }, + { "_deprecated", "deprecated" }, + { "_align", "align" }, + { "aligned" }, { "__pragma", "pragma" }, { "builtins", "__builtins" }, { "builtin_va_list", "__builtin_va_list" }, @@ -532,6 +546,7 @@ immutable Msgtable[] msgtable = { "show" }, { "push" }, { "pop" }, + { "_pure", "pure" }, { "define" }, { "undef" }, ]; diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d index f646d03..6f20a3c 100644 --- a/gcc/d/dmd/init.d +++ b/gcc/d/dmd/init.d @@ -269,7 +269,22 @@ extern (C++) final class CInitializer : Initializer */ Initializer syntaxCopy(Initializer inx) { - static Initializer copyStruct(StructInitializer vi) + static Initializer visitVoid(VoidInitializer vi) + { + return new VoidInitializer(vi.loc); + } + + static Initializer visitError(ErrorInitializer vi) + { + return vi; + } + + static Initializer visitExp(ExpInitializer vi) + { + return new ExpInitializer(vi.loc, vi.exp.syntaxCopy()); + } + + static Initializer visitStruct(StructInitializer vi) { auto si = new StructInitializer(vi.loc); assert(vi.field.length == vi.value.length); @@ -283,7 +298,7 @@ Initializer syntaxCopy(Initializer inx) return si; } - static Initializer copyArray(ArrayInitializer vi) + static Initializer visitArray(ArrayInitializer vi) { auto ai = new ArrayInitializer(vi.loc); assert(vi.index.length == vi.value.length); @@ -297,7 +312,7 @@ Initializer syntaxCopy(Initializer inx) return ai; } - static Initializer copyC(CInitializer vi) + static Initializer visitC(CInitializer vi) { auto ci = new CInitializer(vi.loc); ci.initializerList.setDim(vi.initializerList.length); @@ -322,13 +337,62 @@ Initializer syntaxCopy(Initializer inx) return ci; } - final switch (inx.kind) + mixin VisitInitializer!Initializer visit; + return visit.VisitInitializer(inx); +} + +/*********************************************************** + * Visit each Initializer in init. Call a function visit%s(init) for + * each node, where %s is the op of the node. Otherwise call visitDefault(init) + * for that node. If the visit function returns R.init, continue + * visiting each node, otherwise return the value of R. + * Params: + * Result = return type + * init = Initializer tree to traverse + * Returns: + * Result.init for continue, value of type Result for early exit + */ + +mixin template VisitInitializer(Result) +{ + Result VisitInitializer(Initializer init) + { + final switch (init.kind) + { + case InitKind.void_: mixin(visitCase("Void")); break; + case InitKind.error: mixin(visitCase("Error")); break; + case InitKind.struct_: mixin(visitCase("Struct")); break; + case InitKind.array: mixin(visitCase("Array")); break; + case InitKind.exp: mixin(visitCase("Exp")); break; + case InitKind.C_: mixin(visitCase("C")); break; + } + static if (is(Result == void)) { } else + return Result.init; + } +} + +/**************************************** + * CTFE-only helper function for VisitInitializer. + * Params: + * handler = string for the name of the visit handler + * Returns: boilerplate code for a case + */ +pure string visitCase(string handler) +{ + if (__ctfe) { - case InitKind.void_: return new VoidInitializer(inx.loc); - case InitKind.error: return inx; - case InitKind.struct_: return copyStruct(cast(StructInitializer)inx); - case InitKind.array: return copyArray(cast(ArrayInitializer)inx); - case InitKind.exp: return new ExpInitializer(inx.loc, (cast(ExpInitializer)inx).exp.syntaxCopy()); - case InitKind.C_: return copyC(cast(CInitializer)inx); + return + " + auto ix = init.is"~handler~"Initializer(); + static if (is(Result == void)) + visit"~handler~"(ix); + else + { + Result r = visit"~handler~"(ix); + if (r !is Result.init) + return r; + } + "; } + assert(0); } diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 18b10b4..893d2a6 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -958,15 +958,9 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ } } - final switch (init.kind) - { - case InitKind.void_: return visitVoid (init.isVoidInitializer()); - case InitKind.error: return visitError (init.isErrorInitializer()); - case InitKind.struct_: return visitStruct(init.isStructInitializer()); - case InitKind.array: return visitArray (init.isArrayInitializer()); - case InitKind.exp: return visitExp (init.isExpInitializer()); - case InitKind.C_: return visitC (init.isCInitializer()); - } + mixin VisitInitializer!Initializer visit; + auto result = visit.VisitInitializer(init); + return (result !is null) ? result : new ErrorInitializer(); } /*********************** @@ -1120,15 +1114,9 @@ Initializer inferType(Initializer init, Scope* sc) return new ErrorInitializer(); } - final switch (init.kind) - { - case InitKind.void_: return visitVoid (init.isVoidInitializer()); - case InitKind.error: return visitError (init.isErrorInitializer()); - case InitKind.struct_: return visitStruct(init.isStructInitializer()); - case InitKind.array: return visitArray (init.isArrayInitializer()); - case InitKind.exp: return visitExp (init.isExpInitializer()); - case InitKind.C_: return visitC (init.isCInitializer()); - } + mixin VisitInitializer!Initializer visit; + auto result = visit.VisitInitializer(init); + return (result !is null) ? result : new ErrorInitializer(); } /*********************** @@ -1333,15 +1321,8 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n return null; } - final switch (init.kind) - { - case InitKind.void_: return visitVoid (init.isVoidInitializer()); - case InitKind.error: return visitError (init.isErrorInitializer()); - case InitKind.struct_: return visitStruct(init.isStructInitializer()); - case InitKind.array: return visitArray (init.isArrayInitializer()); - case InitKind.exp: return visitExp (init.isExpInitializer()); - case InitKind.C_: return visitC (init.isCInitializer()); - } + mixin VisitInitializer!Expression visit; + return visit.VisitInitializer(init); } diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d index 2af7fae..dcf53b8 100644 --- a/gcc/d/dmd/json.d +++ b/gcc/d/dmd/json.d @@ -833,7 +833,7 @@ public: { import dmd.target : target; objectStart(); - requiredProperty("vendor", global.vendor); + requiredProperty("vendor", global.compileEnv.vendor); requiredProperty("version", global.versionString()); property("__VERSION__", global.versionNumber()); requiredProperty("interface", determineCompilerInterface()); @@ -1070,13 +1070,13 @@ Determines and returns the compiler interface which is one of `dmd`, `ldc`, */ private extern(D) string determineCompilerInterface() { - if (global.vendor == "Digital Mars D") + if (global.compileEnv.vendor == "Digital Mars D") return "dmd"; - if (global.vendor == "LDC") + if (global.compileEnv.vendor == "LDC") return "ldc"; - if (global.vendor == "GNU D") + if (global.compileEnv.vendor == "GNU D") return "gdc"; - if (global.vendor == "SDC") + if (global.compileEnv.vendor == "SDC") return "sdc"; return null; } diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index f0f7872..0ec468b 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -14,12 +14,8 @@ module dmd.lexer; import core.stdc.ctype; -import core.stdc.errno; -import core.stdc.stdarg; import core.stdc.stdio; -import core.stdc.stdlib : getenv; import core.stdc.string; -import core.stdc.time; import dmd.entity; import dmd.errorsink; @@ -31,10 +27,8 @@ import dmd.root.ctfloat; import dmd.common.outbuffer; import dmd.root.port; import dmd.root.rmem; -import dmd.root.string; import dmd.root.utf; import dmd.tokens; -import dmd.utils; nothrow: @@ -44,6 +38,22 @@ version (DMDLIB) } /*********************************************************** + * Values to use for various magic identifiers + */ +struct CompileEnv +{ + uint versionNumber; /// __VERSION__ + const(char)[] date; /// __DATE__ + const(char)[] time; /// __TIME__ + const(char)[] vendor; /// __VENDOR__ + const(char)[] timestamp; /// __TIMESTAMP__ + + bool previewIn; /// `in` means `[ref] scope const`, accepts rvalues + bool ddocOutput; /// collect embedded documentation comments + bool shortenedMethods = true; /// allow => in normal function declarations +} + +/*********************************************************** */ class Lexer { @@ -69,6 +79,7 @@ class Lexer ubyte wchar_tsize; /// size of C wchar_t, 2 or 4 ErrorSink eSink; /// send error messages through this interface + CompileEnv compileEnv; /// environment private { @@ -87,8 +98,6 @@ class Lexer int lastDocLine; // last line of previous doc comment Token* tokenFreelist; - uint versionNumber; - const(char)[] vendor; } nothrow: @@ -105,13 +114,12 @@ class Lexer * doDocComment = handle documentation comments * commentToken = comments become TOK.comment's * errorSink = where error messages go, must not be null - * vendor = name of the vendor - * versionNumber = version of the caller + * compileEnv = version, vendor, date, time, etc. */ this(const(char)* filename, const(char)* base, size_t begoffset, size_t endoffset, bool doDocComment, bool commentToken, ErrorSink errorSink, - const(char)[] vendor = "DLF", uint versionNumber = 1) pure scope + const CompileEnv* compileEnv) pure scope { scanloc = Loc(filename, 1, 1); // debug printf("Lexer::Lexer(%p)\n", base); @@ -128,8 +136,13 @@ class Lexer this.lastDocLine = 0; this.eSink = errorSink; assert(errorSink); - this.versionNumber = versionNumber; - this.vendor = vendor; + if (compileEnv) + this.compileEnv = *compileEnv; + else + { + this.compileEnv.versionNumber = 1; + this.compileEnv.vendor = "DLF"; + } //initKeywords(); /* If first line starts with '#!', ignore the line */ @@ -169,10 +182,10 @@ class Lexer */ this(const(char)* filename, const(char)* base, size_t begoffset, size_t endoffset, bool doDocComment, bool commentToken, bool whitespaceToken, - ErrorSink errorSink + ErrorSink errorSink, const CompileEnv* compileEnv = null ) { - this(filename, base, begoffset, endoffset, doDocComment, commentToken, errorSink); + this(filename, base, begoffset, endoffset, doDocComment, commentToken, errorSink, compileEnv); this.whitespaceToken = whitespaceToken; } @@ -380,6 +393,15 @@ class Lexer } } continue; // skip white space + + case '\\': + if (Ccompile && (p[1] == '\r' || p[1] == '\n')) + { + ++p; // ignore \ followed by new line, like VC does + continue; + } + goto default; + case '0': if (!isZeroSecond(p[1])) // if numeric literal does not continue { @@ -571,36 +593,26 @@ class Lexer else if (*t.ptr == '_') // if special identifier token { - // Lazy initialization - TimeStampInfo.initialize(t.loc, eSink); - - if (id == Id.DATE) + void toToken(const(char)[] s) { - t.ustring = TimeStampInfo.date.ptr; - goto Lstr; + t.value = TOK.string_; + t.ustring = s.ptr; + t.len = cast(uint)s.length; + t.postfix = 0; } + + if (id == Id.DATE) + toToken(compileEnv.date); else if (id == Id.TIME) - { - t.ustring = TimeStampInfo.time.ptr; - goto Lstr; - } + toToken(compileEnv.time); else if (id == Id.VENDOR) - { - t.ustring = vendor.xarraydup.ptr; - goto Lstr; - } + toToken(compileEnv.vendor); else if (id == Id.TIMESTAMP) - { - t.ustring = TimeStampInfo.timestamp.ptr; - Lstr: - t.value = TOK.string_; - t.postfix = 0; - t.len = cast(uint)strlen(t.ustring); - } + toToken(compileEnv.timestamp); else if (id == Id.VERSIONX) { t.value = TOK.int64Literal; - t.unsvalue = versionNumber; + t.unsvalue = compileEnv.versionNumber; } else if (id == Id.EOFX) { @@ -2570,6 +2582,14 @@ class Lexer TOK result; bool isOutOfRange = false; t.floatvalue = (isWellformedString ? CTFloat.parse(sbufptr, isOutOfRange) : CTFloat.zero); + + bool imaginary = false; + if (*p == 'i' && Ccompile) + { + ++p; + imaginary = true; + } + switch (*p) { case 'F': @@ -2595,11 +2615,17 @@ class Lexer result = TOK.float80Literal; break; } + if ((*p == 'i' || *p == 'I') && !Ccompile) { if (*p == 'I') error("use 'i' suffix instead of 'I'"); p++; + imaginary = true; + } + + if (imaginary) + { switch (result) { case TOK.float32Literal: @@ -3033,7 +3059,10 @@ class Lexer auto dc = (lineComment && anyToken) ? &t.lineComment : &t.blockComment; // Combine with previous doc comment, if any if (*dc) - *dc = combineComments(*dc, buf[], newParagraph).toDString(); + { + auto p = combineComments(*dc, buf[], newParagraph); + *dc = p ? p[0 .. strlen(p)] : null; + } else *dc = buf.extractSlice(true); } @@ -3081,42 +3110,6 @@ class Lexer private: -/// Support for `__DATE__`, `__TIME__`, and `__TIMESTAMP__` -private struct TimeStampInfo -{ - private __gshared bool initdone = false; - - // Note: Those properties need to be guarded by a call to `init` - // The API isn't safe, and quite brittle, but it was left this way - // over performance concerns. - // This is currently only called once, from the lexer. - __gshared char[11 + 1] date; - __gshared char[8 + 1] time; - __gshared char[24 + 1] timestamp; - - public static void initialize(const ref Loc loc, ErrorSink eSink) nothrow - { - if (initdone) - return; - - initdone = true; - time_t ct; - // https://issues.dlang.org/show_bug.cgi?id=20444 - if (auto p = getenv("SOURCE_DATE_EPOCH")) - { - if (!ct.parseDigits(p.toDString())) - eSink.error(loc, "value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p); - } - else - .time(&ct); - const p = ctime(&ct); - assert(p); - snprintf(&date[0], date.length, "%.6s %.4s", p + 4, p + 20); - snprintf(&time[0], time.length, "%.8s", p + 11); - snprintf(×tamp[0], timestamp.length, "%.24s", p); - } -} - private enum LS = 0x2028; // UTF line separator private enum PS = 0x2029; // UTF paragraph separator @@ -3366,7 +3359,7 @@ unittest */ string text = "int"; // We rely on the implicit null-terminator ErrorSink errorSink = new ErrorSinkStderr; - scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, false, false, errorSink); + scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, false, false, errorSink, null); TOK tok; tok = lex1.nextToken(); //printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOK.int32); @@ -3402,7 +3395,7 @@ unittest foreach (testcase; testcases) { - scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, false, false, errorSink); + scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, false, false, errorSink, null); TOK tok = lex2.nextToken(); size_t iterations = 1; while ((tok != TOK.endOfFile) && (iterations++ < testcase.length)) diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 5939db5..badc579 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -313,6 +313,7 @@ int mutabilityOfType(bool isref, Type t) */ enum DotExpFlag { + none = 0, gag = 1, // don't report "not a property" error and just return null noDeref = 2, // the use of the expression will not attempt a dereference noAliasThis = 4, // don't do 'alias this' resolution @@ -2044,9 +2045,11 @@ extern (C++) abstract class Type : ASTNode t = t.addMod(this.mod); return t; } - if (auto fd = s.isFuncDeclaration()) + Dsymbol callable = s.isFuncDeclaration(); + callable = callable ? callable : s.isTemplateDeclaration(); + if (callable) { - fd = resolveFuncCall(Loc.initial, null, fd, null, this, ArgumentList(), FuncResolveFlag.quiet); + auto fd = resolveFuncCall(Loc.initial, null, callable, null, this, ArgumentList(), FuncResolveFlag.quiet); if (!fd || fd.errors || !fd.functionSemantic()) return Type.terror; @@ -2065,24 +2068,17 @@ extern (C++) abstract class Type : ASTNode { return ed.type; } - if (auto td = s.isTemplateDeclaration()) - { - assert(td._scope); - auto fd = resolveFuncCall(Loc.initial, null, td, null, this, ArgumentList(), FuncResolveFlag.quiet); - if (!fd || fd.errors || !fd.functionSemantic()) - return Type.terror; - - auto t = fd.type.nextOf(); - if (!t) - return Type.terror; - t = t.substWildTo(mod == 0 ? MODFlags.mutable : mod); - return t; - } //printf("%s\n", s.kind()); return null; } + /** + * Check whether this type has endless `alias this` recursion. + * Returns: + * `true` if this type has an `alias this` that can be implicitly + * converted back to this type itself. + */ extern (D) final bool checkAliasThisRec() { Type tb = toBasetype(); @@ -2645,6 +2641,8 @@ extern (C++) abstract class Type : ASTNode if (t.isimaginary() || t.iscomplex()) { + if (sc.flags & SCOPE.Cfile) + return true; // complex/imaginary not deprecated in C code Type rt; switch (t.ty) { @@ -4270,7 +4268,7 @@ extern (C++) final class TypeFunction : TypeNext super(Tfunction, treturn); //if (!treturn) *(char*)0=0; // assert(treturn); - assert(VarArg.none <= pl.varargs && pl.varargs <= VarArg.typesafe); + assert(VarArg.none <= pl.varargs && pl.varargs <= VarArg.max); this.parameterList = pl; this.linkage = linkage; @@ -6513,6 +6511,7 @@ extern (C++) final class TypeTag : Type { Loc loc; /// location of declaration TOK tok; /// TOK.struct_, TOK.union_, TOK.enum_ + structalign_t packalign; /// alignment of struct/union fields Identifier id; /// tag name identifier Type base; /// base type for enums otherwise null Dsymbols* members; /// members of struct, null if none @@ -6522,13 +6521,14 @@ extern (C++) final class TypeTag : Type /// struct S { int a; } s1, *s2; MOD mod; /// modifiers to apply after type is resolved (only MODFlags.const_ at the moment) - extern (D) this(const ref Loc loc, TOK tok, Identifier id, Type base, Dsymbols* members) + extern (D) this(const ref Loc loc, TOK tok, Identifier id, structalign_t packalign, Type base, Dsymbols* members) { //printf("TypeTag ctor %s %p\n", id ? id.toChars() : "null".ptr, this); super(Ttag); this.loc = loc; this.tok = tok; this.id = id; + this.packalign = packalign; this.base = base; this.members = members; this.mod = 0; @@ -7252,7 +7252,7 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct, s ~= "pure "; if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe()) s ~= "@safe "; - if (!f.isNogc && sc.func.setGC()) + if (!f.isNogc && sc.func.setGC(arg.loc, null)) s ~= "nogc "; if (s) { @@ -7579,3 +7579,113 @@ TypeVector toBooleanVector(TypeVector tv) return new TypeVector(new TypeSArray(telem, tsa.dim)); } + +/************************************************* + * Dispatch to function based on static type of Type. + */ +mixin template VisitType(Result) +{ + Result VisitType(Type t) + { + final switch (t.ty) + { + case TY.Tvoid: + case TY.Tint8: + case TY.Tuns8: + case TY.Tint16: + case TY.Tuns16: + case TY.Tint32: + case TY.Tuns32: + case TY.Tint64: + case TY.Tuns64: + case TY.Tfloat32: + case TY.Tfloat64: + case TY.Tfloat80: + case TY.Timaginary32: + case TY.Timaginary64: + case TY.Timaginary80: + case TY.Tcomplex32: + case TY.Tcomplex64: + case TY.Tcomplex80: + case TY.Tbool: + case TY.Tchar: + case TY.Twchar: + case TY.Tdchar: + case TY.Tint128: + case TY.Tuns128: mixin(visitTYCase("Basic")); + case TY.Tarray: mixin(visitTYCase("DArray")); + case TY.Tsarray: mixin(visitTYCase("SArray")); + case TY.Taarray: mixin(visitTYCase("AArray")); + case TY.Tpointer: mixin(visitTYCase("Pointer")); + case TY.Treference: mixin(visitTYCase("Reference")); + case TY.Tfunction: mixin(visitTYCase("Function")); + case TY.Tident: mixin(visitTYCase("Identifier")); + case TY.Tclass: mixin(visitTYCase("Class")); + case TY.Tstruct: mixin(visitTYCase("Struct")); + case TY.Tenum: mixin(visitTYCase("Enum")); + case TY.Tdelegate: mixin(visitTYCase("Delegate")); + case TY.Terror: mixin(visitTYCase("Error")); + case TY.Tinstance: mixin(visitTYCase("Instance")); + case TY.Ttypeof: mixin(visitTYCase("Typeof")); + case TY.Ttuple: mixin(visitTYCase("Tuple")); + case TY.Tslice: mixin(visitTYCase("Slice")); + case TY.Treturn: mixin(visitTYCase("Return")); + case TY.Tnull: mixin(visitTYCase("Null")); + case TY.Tvector: mixin(visitTYCase("Vector")); + case TY.Ttraits: mixin(visitTYCase("Traits")); + case TY.Tmixin: mixin(visitTYCase("Mixin")); + case TY.Tnoreturn: mixin(visitTYCase("Noreturn")); + case TY.Ttag: mixin(visitTYCase("Tag")); + case TY.Tnone: assert(0); + } + } +} + +/**************************************** + * CTFE-only helper function for VisitInitializer. + * Params: + * handler = string for the name of the visit handler + * Returns: boilerplate code for a case + */ +pure string visitTYCase(string handler) +{ + if (__ctfe) + { + return + " + enum isVoid = is(Result == void); + auto tx = t.isType"~handler~"(); + static if (__traits(compiles, visit"~handler~"(tx))) + { + static if (isVoid) + { + visit"~handler~"(tx); + return; + } + else + { + if (Result r = visit"~handler~"(tx)) + return r; + return Result.init; + } + } + else static if (__traits(compiles, visitDefaultCase(t))) + { + static if (isVoid) + { + visitDefaultCase(tx); + return; + } + else + { + if (Result r = visitDefaultCase(t)) + return r; + return Result.init; + } + } + else + static assert(0, "~handler~"); + "; + } + assert(0); +} diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index 201f168..a0f3e60 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/dmd/nogc.d @@ -83,7 +83,7 @@ public: err = true; return true; } - if (f.setGC()) + if (f.setGC(e.loc, format)) { e.error(format, f.kind(), f.toPrettyChars()); err = true; @@ -135,7 +135,7 @@ public: override void visit(NewExp e) { - if (e.member && !e.member.isNogc() && f.setGC()) + if (e.member && !e.member.isNogc() && f.setGC(e.loc, null)) { // @nogc-ness is already checked in NewExp::semantic return; @@ -195,7 +195,7 @@ public: err = true; return; } - if (f.setGC()) + if (f.setGC(e.loc, null)) { err = true; return; diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d index 9cff76b..89728b6 100644 --- a/gcc/d/dmd/ob.d +++ b/gcc/d/dmd/ob.d @@ -844,7 +844,7 @@ void toObNodes(ref ObNodes obnodes, Statement s) case STMT.Conditional: case STMT.While: case STMT.Forwarding: - case STMT.Compile: + case STMT.Mixin: case STMT.Peel: case STMT.Synchronized: debug printf("s: %s\n", s.toChars()); diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index 3c80e5e..d7b90d7 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -293,6 +293,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) { ie = (*ae.arguments)[0].isIntervalExp(); } + Type att = null; // first cyclic `alias this` type while (true) { if (ae.e1.op == EXP.error) @@ -354,7 +355,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) return result; } // Didn't find it. Forward to aliasthis - if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type)) + if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) { /* Rewrite op(a[arguments]) as: * op(a.aliasthis[arguments]) @@ -370,13 +371,18 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) } e.e1 = e.e1.expressionSemantic(sc); e.e1 = resolveProperties(sc, e.e1); - if (e.e1.op == EXP.error) - { - return e.e1; - } - AggregateDeclaration ad = isAggregate(e.e1.type); - if (ad) + Type att = null; // first cyclic `alias this` type + while (1) { + if (e.e1.op == EXP.error) + { + return e.e1; + } + + AggregateDeclaration ad = isAggregate(e.e1.type); + if (!ad) + break; + Dsymbol fd = null; /* Rewrite as: * e1.opUnary!(op)() @@ -404,18 +410,18 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) } } // Didn't find it. Forward to aliasthis - if (ad.aliasthis && !isRecursiveAliasThis(e.att1, e.e1.type)) + if (ad.aliasthis && !isRecursiveAliasThis(att, e.e1.type)) { /* Rewrite op(e1) as: * op(e1.aliasthis) */ //printf("att una %s e1 = %s\n", EXPtoString(op).ptr, this.e1.type.toChars()); - Expression e1 = new DotIdExp(e.loc, e.e1, ad.aliasthis.ident); - UnaExp ue = cast(UnaExp)e.copy(); - ue.e1 = e1; - result = ue.trySemantic(sc); - return result; + e.e1 = resolveAliasThis(sc, e.e1, true); + if (e.e1) + continue; + break; } + break; } return result; } @@ -433,6 +439,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) ie = (*ae.arguments)[0].isIntervalExp(); } Expression result; + Type att = null; // first cyclic `alias this` type while (true) { if (ae.e1.op == EXP.error) @@ -526,7 +533,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) return result; } // Didn't find it. Forward to aliasthis - if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type)) + if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) { //printf("att arr e1 = %s\n", this.e1.type.toChars()); /* Rewrite op(a[arguments]) as: @@ -547,7 +554,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) * This is mostly the same as UnaryExp::op_overload(), but has * a different rewrite. */ - Expression visitCast(CastExp e) + Expression visitCast(CastExp e, Type att = null) { //printf("CastExp::op_overload() (%s)\n", e.toChars()); Expression result; @@ -578,7 +585,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) return result; } // Didn't find it. Forward to aliasthis - if (ad.aliasthis && !isRecursiveAliasThis(e.att1, e.e1.type)) + if (ad.aliasthis && !isRecursiveAliasThis(att, e.e1.type)) { /* Rewrite op(e1) as: * op(e1.aliasthis) @@ -587,7 +594,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) { result = e.copy(); (cast(UnaExp)result).e1 = e1; - result = result.op_overload(sc); + result = visitCast(result.isCastExp(), att); return result; } } @@ -997,7 +1004,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) return null; import dmd.clone : needOpEquals; - if (!global.params.fieldwise && !needOpEquals(sd)) + if (global.params.fieldwise != FeatureState.enabled && !needOpEquals(sd)) { // Use bitwise equality. auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity; @@ -1016,12 +1023,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) * also compare the parent class's equality. Otherwise, compares * the identity of parent context through void*. */ - if (e.att1 && t1.equivalent(e.att1)) return null; - if (e.att2 && t2.equivalent(e.att2)) return null; - e = e.copy().isEqualExp(); - if (!e.att1) e.att1 = t1; - if (!e.att2) e.att2 = t2; e.e1 = new DotIdExp(e.loc, e.e1, Id._tupleof); e.e2 = new DotIdExp(e.loc, e.e2, Id._tupleof); @@ -1029,18 +1031,6 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) sc2.flags |= SCOPE.noaccesscheck; Expression r = e.expressionSemantic(sc2); sc2.pop(); - - /* https://issues.dlang.org/show_bug.cgi?id=15292 - * if the rewrite result is same with the original, - * the equality is unresolvable because it has recursive definition. - */ - if (r.op == e.op && - r.isEqualExp().e1.type.toBasetype() == t1) - { - e.error("cannot compare `%s` because its auto generated member-wise equality has recursive definition", - t1.toChars()); - return ErrorExp.get(); - } return r; } @@ -1071,8 +1061,6 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) auto ex1 = (*tup1.exps)[i]; auto ex2 = (*tup2.exps)[i]; auto eeq = new EqualExp(e.op, e.loc, ex1, ex2); - eeq.att1 = e.att1; - eeq.att2 = e.att2; if (!result) result = eeq; @@ -1114,6 +1102,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) { ie = (*ae.arguments)[0].isIntervalExp(); } + Type att = null; // first cyclic `alias this` type while (true) { if (ae.e1.op == EXP.error) @@ -1185,7 +1174,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) return result; } // Didn't find it. Forward to aliasthis - if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type)) + if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) { /* Rewrite (a[arguments] op= e2) as: * a.aliasthis[arguments] op= e2 diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index b5d32b2..61c385f 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -371,7 +371,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) { if (e.stageflags & stageOptimize) return; - int old = e.stageflags; + const old = e.stageflags; e.stageflags |= stageOptimize; if (e.elements) { diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 36a76f5..68a2506 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -15,14 +15,13 @@ module dmd.parse; import core.stdc.stdio; import core.stdc.string; + import dmd.astenums; import dmd.errorsink; -import dmd.globals; import dmd.id; import dmd.identifier; import dmd.lexer; import dmd.location; -import dmd.errors; import dmd.root.filename; import dmd.common.outbuffer; import dmd.root.rmem; @@ -30,6 +29,8 @@ import dmd.root.rootobject; import dmd.root.string; import dmd.tokens; +alias CompileEnv = dmd.lexer.CompileEnv; + /*********************************************************** */ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer @@ -45,49 +46,38 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer Loc endloc; // set to location of last right curly int inBrackets; // inside [] of array index or slice Loc lookingForElse; // location of lonely if looking for an else + bool doUnittests; // parse unittest blocks } + bool transitionIn = false; /// `-transition=in` is active, `in` parameters are listed + /********************* * Use this constructor for string mixins. * Input: - * loc location in source file of mixin + * loc = location in source file of mixin */ extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, bool doDocComment, - ErrorSink errorSink) scope + ErrorSink errorSink, const CompileEnv* compileEnv, const bool doUnittests) scope { - super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false, - errorSink, - global.vendor, global.versionNumber()); - - //printf("Parser::Parser()\n"); + //printf("Parser::Parser()1 %d\n", doUnittests); + this(_module, input, doDocComment, errorSink, compileEnv, doUnittests); scanloc = loc; - - if (!writeMixin(input, scanloc) && loc.filename) - { - /* Create a pseudo-filename for the mixin string, as it may not even exist - * in the source file. - */ - auto len = strlen(loc.filename) + 7 + (loc.linnum).sizeof * 3 + 1; - char* filename = cast(char*)mem.xmalloc(len); - snprintf(filename, len, "%s-mixin-%d", loc.filename, cast(int)loc.linnum); - scanloc.filename = filename; - } - - mod = _module; - linkage = LINK.d; - //nextToken(); // start up the scanner } - extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment, ErrorSink errorSink) scope + /************************************************** + * Main Parser constructor. + */ + extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment, ErrorSink errorSink, + const CompileEnv* compileEnv, const bool doUnittests) scope { super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false, errorSink, - global.vendor, global.versionNumber()); + compileEnv); - //printf("Parser::Parser()\n"); - mod = _module; - linkage = LINK.d; - //nextToken(); // start up the scanner + //printf("Parser::Parser()2 %d\n", doUnittests); + this.mod = _module; + this.linkage = LINK.d; + this.doUnittests = doUnittests; } /++ @@ -335,6 +325,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer linkage = linksave; Loc startloc; + Loc scdLoc; switch (token.value) { @@ -381,7 +372,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); auto exps = parseArguments(); check(TOK.semicolon); - s = new AST.CompileDeclaration(loc, exps); + s = new AST.MixinDeclaration(loc, exps); break; } case TOK.template_: @@ -497,7 +488,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer * template instantiations in these unittests as candidates for * further codegen culling. */ - if (mod.isRoot() && (global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput)) + // The isRoot check is here because it can change after parsing begins (see dmodule.d) + if (doUnittests && mod.isRoot()) { linkage = LINK.d; // unittests have D linkage s = parseUnitTest(pAttrs); @@ -696,6 +688,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } Lstc: pAttrs.storageClass = appendStorageClass(pAttrs.storageClass, stc); + scdLoc = token.loc; nextToken(); Lautodecl: @@ -748,7 +741,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer auto stc2 = getStorageClass!AST(pAttrs); if (stc2 != STC.undefined_) { - s = new AST.StorageClassDeclaration(stc2, a); + s = new AST.StorageClassDeclaration(scdLoc, stc2, a); } if (pAttrs.udas) { @@ -1219,19 +1212,20 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer return orig | added; } - const Redundant = (STC.const_ | STC.scope_ | - (global.params.previewIn ? STC.ref_ : 0)); + const Redundant = (STC.const_ | STC.scope_ | STC.ref_); orig |= added; if ((orig & STC.in_) && (added & Redundant)) { if (added & STC.const_) error("attribute `const` is redundant with previously-applied `in`"); - else if (global.params.previewIn) + else if (compileEnv.previewIn) { error("attribute `%s` is redundant with previously-applied `in`", (orig & STC.scope_) ? "scope".ptr : "ref".ptr); } + else if (added & STC.ref_) + deprecation("using `in ref` is deprecated, use `-preview=in` and `in` instead"); else error("attribute `scope` cannot be applied with `in`, use `-preview=in` instead"); return orig; @@ -1241,13 +1235,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { if (orig & STC.const_) error("attribute `in` cannot be added after `const`: remove `const`"); - else if (global.params.previewIn) + else if (compileEnv.previewIn) { // Windows `printf` does not support `%1$s` const(char*) stc_str = (orig & STC.scope_) ? "scope".ptr : "ref".ptr; error(token.loc, "attribute `in` cannot be added after `%s`: remove `%s`", stc_str, stc_str); } + else if (orig & STC.ref_) + deprecation("using `ref in` is deprecated, use `-preview=in` and `in` instead"); else error("attribute `in` cannot be added after `scope`: remove `scope` and use `-preview=in`"); return orig; @@ -1302,12 +1298,38 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer return 0; } + AST.Expression templateArgToExp(RootObject o, const ref Loc loc) + { + switch (o.dyncast) + { + case DYNCAST.expression: + return cast(AST.Expression) o; + case DYNCAST.type: + return new AST.TypeExp(loc, cast(AST.Type)o); + default: + assert(0); + } + } + if (token.value == TOK.leftParenthesis) { // Multi-UDAs ( `@( ArgumentList )`) form, concatenate with existing if (peekNext() == TOK.rightParenthesis) error("empty attribute list is not allowed"); - udas = AST.UserAttributeDeclaration.concat(udas, parseArguments()); + + if (udas is null) + udas = new AST.Expressions(); + auto args = parseTemplateArgumentList(); + foreach (arg; *args) + udas.push(templateArgToExp(arg, token.loc)); + return 0; + } + + if (auto o = parseTemplateSingleArgument()) + { + if (udas is null) + udas = new AST.Expressions(); + udas.push(templateArgToExp(o, token.loc)); return 0; } @@ -1764,7 +1786,16 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer else { // ident!template_argument - tiargs = parseTemplateSingleArgument(); + RootObject o = parseTemplateSingleArgument(); + if (!o) + { + error("template argument expected following `!`"); + } + else + { + tiargs = new AST.Objects(); + tiargs.push(o); + } } if (token.value == TOK.not) { @@ -1830,11 +1861,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer * foo!arg * Input: * current token is the arg + * Returns: An AST.Type, AST.Expression, or `null` on error */ - private AST.Objects* parseTemplateSingleArgument() + private RootObject parseTemplateSingleArgument() { //printf("parseTemplateSingleArgument()\n"); - auto tiargs = new AST.Objects(); AST.Type ta; switch (token.value) { @@ -1942,9 +1973,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer ta = AST.Type.tdchar; goto LabelX; LabelX: - tiargs.push(ta); nextToken(); - break; + return ta; case TOK.int32Literal: case TOK.uns32Literal: @@ -1974,15 +2004,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.this_: { // Template argument is an expression - AST.Expression ea = parsePrimaryExp(); - tiargs.push(ea); - break; + return parsePrimaryExp(); } default: - error("template argument expected following `!`"); - break; + return null; } - return tiargs; } /********************************** @@ -2694,7 +2720,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer /** Extract unittest body as a string. Must be done eagerly since memory will be released by the lexer before doc gen. */ char* docline = null; - if (global.params.ddoc.doOutput && endPtr > begPtr) + if (compileEnv.ddocOutput && endPtr > begPtr) { /* Remove trailing whitespaces */ for (const(char)* p = endPtr - 1; begPtr <= p && (*p == ' ' || *p == '\r' || *p == '\n' || *p == '\t'); --p) @@ -2849,8 +2875,8 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer // Don't call nextToken again. } case TOK.in_: - if (global.params.vin) - message(scanloc, "Usage of 'in' on parameter"); + if (transitionIn) + eSink.message(scanloc, "Usage of 'in' on parameter"); stc = STC.in_; goto L2; @@ -4610,8 +4636,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer AST.Dsymbol s; if (width) { - if (!global.params.bitfields) - error("use -preview=bitfields for bitfield support"); if (_init) error("initializer not allowed for bit-field declaration"); if (storage_class) @@ -5144,7 +5168,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.goesTo: if (requireDo) error("missing `do { ... }` after `in` or `out`"); - if (!global.params.shortenedMethods) + if (!compileEnv.shortenedMethods) error("=> shortened method not enabled, compile with compiler switch `-preview=shortenedMethods`"); const returnloc = token.loc; nextToken(); @@ -5156,7 +5180,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.leftCurly: if (requireDo) error("missing `do { ... }` after `in` or `out`"); - f.fbody = parseStatement(ParseStatementFlags.semi); + f.fbody = parseStatement(0); f.endloc = endloc; break; @@ -5801,7 +5825,11 @@ LagainStc: if (token.value != TOK.semicolon && peek(&token).value == TOK.semicolon) error("found `%s` when expecting `;` following statement", token.toChars()); else - check(TOK.semicolon, "statement"); + { + if (token.value != TOK.semicolon) + error("found `%s` when expecting `;` following statement `%s` on line %s", token.toChars(), exp.toChars(), exp.loc.toChars()); + nextToken(); + } } s = new AST.ExpStatement(loc, exp); break; @@ -5959,7 +5987,7 @@ LagainStc: if (e.op == EXP.mixin_) { AST.MixinExp cpe = cast(AST.MixinExp)e; - s = new AST.CompileStatement(loc, cpe.exps); + s = new AST.MixinStatement(loc, cpe.exps); } else { @@ -5992,7 +6020,7 @@ LagainStc: auto statements = new AST.Statements(); while (token.value != TOK.rightCurly && token.value != TOK.endOfFile) { - statements.push(parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope)); + statements.push(parseStatement(ParseStatementFlags.curlyScope)); } if (endPtr) *endPtr = token.ptr; @@ -6025,10 +6053,7 @@ LagainStc: case TOK.semicolon: if (!(flags & ParseStatementFlags.semiOk)) { - if (flags & ParseStatementFlags.semi) - deprecation("use `{ }` for an empty statement, not `;`"); - else - error("use `{ }` for an empty statement, not `;`"); + error("use `{ }` for an empty statement, not `;`"); } nextToken(); s = new AST.ExpStatement(loc, cast(AST.Expression)null); @@ -6245,7 +6270,7 @@ LagainStc: _body = null; } else - _body = parseStatement(ParseStatementFlags.semi); + _body = parseStatement(0); s = new AST.PragmaStatement(loc, ident, args, _body); break; } @@ -6298,7 +6323,7 @@ LagainStc: auto statements = new AST.Statements(); while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly) { - auto cur = parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope); + auto cur = parseStatement(ParseStatementFlags.curlyScope); statements.push(cur); // https://issues.dlang.org/show_bug.cgi?id=21739 @@ -6313,7 +6338,7 @@ LagainStc: } else { - s = parseStatement(ParseStatementFlags.semi); + s = parseStatement(0); } s = new AST.ScopeStatement(loc, s, token.loc); @@ -6342,12 +6367,12 @@ LagainStc: auto statements = new AST.Statements(); while (token.value != TOK.case_ && token.value != TOK.default_ && token.value != TOK.endOfFile && token.value != TOK.rightCurly) { - statements.push(parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope)); + statements.push(parseStatement(ParseStatementFlags.curlyScope)); } s = new AST.CompoundStatement(loc, statements); } else - s = parseStatement(ParseStatementFlags.semi); + s = parseStatement(0); s = new AST.ScopeStatement(loc, s, token.loc); s = new AST.DefaultStatement(loc, s); break; @@ -6891,6 +6916,15 @@ LagainStc: /******************** * Parse inline assembler block. + * Enters with token on the `asm`. + * https://dlang.org/spec/iasm.html + * + * AsmStatement: + * asm FunctionAttributes(opt) { AsmInstructionListopt } + * AsmInstructionList: + * AsmInstruction ; + * AsmInstruction ; AsmInstruction + * * Returns: * inline assembler block as a Statement */ @@ -6905,7 +6939,7 @@ LagainStc: Loc labelloc; nextToken(); - StorageClass stc = parsePostfix(STC.undefined_, null); + StorageClass stc = parsePostfix(STC.undefined_, null); // optional FunctionAttributes if (stc & (STC.const_ | STC.immutable_ | STC.shared_ | STC.wild)) error("`const`/`immutable`/`shared`/`inout` attributes are not allowed on `asm` blocks"); @@ -9181,7 +9215,7 @@ LagainStc: void checkRequiredParens() { if (e.op == EXP.question && !e.parens) - dmd.errors.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`", + eSink.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`", e.toChars(), Token.toChars(token.value)); } @@ -9498,7 +9532,6 @@ immutable PREC[EXP.max + 1] precedence = EXP.error : PREC.expr, EXP.objcClassReference : PREC.expr, // Objective-C class reference, same as EXP.type - EXP.typeof_ : PREC.primary, EXP.mixin_ : PREC.primary, EXP.import_ : PREC.primary, @@ -9538,7 +9571,6 @@ immutable PREC[EXP.max + 1] precedence = EXP.remove : PREC.primary, EXP.tuple : PREC.primary, EXP.traits : PREC.primary, - EXP.default_ : PREC.primary, EXP.overloadSet : PREC.primary, EXP.void_ : PREC.primary, EXP.vectorArray : PREC.primary, @@ -9637,7 +9669,6 @@ immutable PREC[EXP.max + 1] precedence = enum ParseStatementFlags : int { - semi = 1, // empty ';' statements are allowed, but deprecated scope_ = 2, // start a new scope curly = 4, // { } statement is required curlyScope = 8, // { } starts a new scope @@ -9708,52 +9739,3 @@ private StorageClass getStorageClass(AST)(PrefixAttributes!(AST)* pAttrs) } return stc; } - -/************************************** - * dump mixin expansion to file for better debugging - */ -private bool writeMixin(const(char)[] s, ref Loc loc) -{ - if (!global.params.mixinOut.doOutput) - return false; - - OutBuffer* ob = global.params.mixinOut.buffer; - - ob.writestring("// expansion at "); - ob.writestring(loc.toChars()); - ob.writenl(); - - global.params.mixinOut.bufferLines++; - - loc = Loc(global.params.mixinOut.name.ptr, global.params.mixinOut.bufferLines + 1, loc.charnum); - - // write by line to create consistent line endings - size_t lastpos = 0; - for (size_t i = 0; i < s.length; ++i) - { - // detect LF and CRLF - const c = s[i]; - if (c == '\n' || (c == '\r' && i+1 < s.length && s[i+1] == '\n')) - { - ob.writestring(s[lastpos .. i]); - ob.writenl(); - global.params.mixinOut.bufferLines++; - if (c == '\r') - ++i; - lastpos = i + 1; - } - } - - if(lastpos < s.length) - ob.writestring(s[lastpos .. $]); - - if (s.length == 0 || s[$-1] != '\n') - { - ob.writenl(); // ensure empty line after expansion - global.params.mixinOut.bufferLines++; - } - ob.writenl(); - global.params.mixinOut.bufferLines++; - - return true; -} diff --git a/gcc/d/dmd/parsetimevisitor.d b/gcc/d/dmd/parsetimevisitor.d index 387b28c..a4a9434 100644 --- a/gcc/d/dmd/parsetimevisitor.d +++ b/gcc/d/dmd/parsetimevisitor.d @@ -66,7 +66,7 @@ public: void visit(AST.SharedStaticDtorDeclaration s) { visit(cast(AST.StaticDtorDeclaration)s); } // AttribDeclarations - void visit(AST.CompileDeclaration s) { visit(cast(AST.AttribDeclaration)s); } + void visit(AST.MixinDeclaration s) { visit(cast(AST.AttribDeclaration)s); } void visit(AST.UserAttributeDeclaration s) { visit(cast(AST.AttribDeclaration)s); } void visit(AST.LinkDeclaration s) { visit(cast(AST.AttribDeclaration)s); } void visit(AST.AnonDeclaration s) { visit(cast(AST.AttribDeclaration)s); } @@ -99,7 +99,7 @@ public: void visit(AST.ReturnStatement s) { visit(cast(AST.Statement)s); } void visit(AST.LabelStatement s) { visit(cast(AST.Statement)s); } void visit(AST.StaticAssertStatement s) { visit(cast(AST.Statement)s); } - void visit(AST.CompileStatement s) { visit(cast(AST.Statement)s); } + void visit(AST.MixinStatement s) { visit(cast(AST.Statement)s); } void visit(AST.WhileStatement s) { visit(cast(AST.Statement)s); } void visit(AST.ForStatement s) { visit(cast(AST.Statement)s); } void visit(AST.DoStatement s) { visit(cast(AST.Statement)s); } diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d index d85105d..8c01095 100644 --- a/gcc/d/dmd/printast.d +++ b/gcc/d/dmd/printast.d @@ -219,6 +219,25 @@ extern (C++) final class PrintASTVisitor : Visitor printAST(e.value, indent + 2); } + override void visit(ArrayLiteralExp e) + { + visit(cast(Expression)e); + printIndent(indent + 2); + printf(".basis : %s\n", e.basis ? e.basis.toChars() : ""); + if (e.elements) + { + printIndent(indent + 2); + printf("["); + foreach (i, element; (*e.elements)[]) + { + if (i) + printf(", "); + printf("%s", element.toChars()); + } + printf("]\n"); + } + } + static void printIndent(int indent) { foreach (i; 0 .. indent) diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index a912e76..33c2f02 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -467,7 +467,7 @@ private extern(C++) final class Semantic3Visitor : Visitor /* Generate identifier for un-named parameter, * because we need it later on. */ - fparam.ident = id = Identifier.generateId("_param_", i); + fparam.ident = id = Identifier.generateId("__param_", i); stc |= STC.temp; } Type vtype = fparam.type; diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d index 60a74cc..3f3e7e6 100644 --- a/gcc/d/dmd/sideeffect.d +++ b/gcc/d/dmd/sideeffect.d @@ -185,6 +185,7 @@ private bool lambdaHasSideEffect(Expression e, bool assumeImpureCalls = false) case EXP.delete_: case EXP.new_: case EXP.newAnonymousClass: + case EXP.loweredAssignExp: return true; case EXP.call: { diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d index 90728fb..3ccf228 100644 --- a/gcc/d/dmd/statement.d +++ b/gcc/d/dmd/statement.d @@ -373,6 +373,7 @@ extern (C++) abstract class Statement : ASTNode * the downcast statement if it can be downcasted, otherwise `null` */ inout(ErrorStatement) isErrorStatement() { return stmt == STMT.Error ? cast(typeof(return))this : null; } + inout(PeelStatement) isPeelStatement() { return stmt == STMT.Peel ? cast(typeof(return))this : null; } inout(ScopeStatement) isScopeStatement() { return stmt == STMT.Scope ? cast(typeof(return))this : null; } inout(ExpStatement) isExpStatement() { return stmt == STMT.Exp ? cast(typeof(return))this : null; } inout(CompoundStatement) isCompoundStatement() { return stmt == STMT.Compound ? cast(typeof(return))this : null; } @@ -388,7 +389,7 @@ extern (C++) abstract class Statement : ASTNode inout(GotoCaseStatement) isGotoCaseStatement() { return stmt == STMT.GotoCase ? cast(typeof(return))this : null; } inout(BreakStatement) isBreakStatement() { return stmt == STMT.Break ? cast(typeof(return))this : null; } inout(DtorExpStatement) isDtorExpStatement() { return stmt == STMT.DtorExp ? cast(typeof(return))this : null; } - inout(CompileStatement) isCompileStatement() { return stmt == STMT.Compile ? cast(typeof(return))this : null; } + inout(MixinStatement) isMixinStatement() { return stmt == STMT.Mixin ? cast(typeof(return))this : null; } inout(ForwardingStatement) isForwardingStatement() { return stmt == STMT.Forwarding ? cast(typeof(return))this : null; } inout(DoStatement) isDoStatement() { return stmt == STMT.Do ? cast(typeof(return))this : null; } inout(WhileStatement) isWhileStatement() { return stmt == STMT.While ? cast(typeof(return))this : null; } @@ -406,6 +407,15 @@ extern (C++) abstract class Statement : ASTNode inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; } inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; } inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; } + inout(CompoundAsmStatement) isCompoundAsmStatement() { return stmt == STMT.CompoundAsm ? cast(typeof(return))this : null; } + inout(PragmaStatement) isPragmaStatement() { return stmt == STMT.Pragma ? cast(typeof(return))this : null; } + inout(StaticAssertStatement) isStaticAssertStatement() { return stmt == STMT.StaticAssert ? cast(typeof(return))this : null; } + inout(CaseRangeStatement) isCaseRangeStatement() { return stmt == STMT.CaseRange ? cast(typeof(return))this : null; } + inout(SynchronizedStatement) isSynchronizedStatement() { return stmt == STMT.Synchronized ? cast(typeof(return))this : null; } + inout(AsmStatement) isAsmStatement() { return stmt == STMT.Asm ? cast(typeof(return))this : null; } + inout(InlineAsmStatement) isInlineAsmStatement() { return stmt == STMT.InlineAsm ? cast(typeof(return))this : null; } + inout(GccAsmStatement) isGccAsmStatement() { return stmt == STMT.GccAsm ? cast(typeof(return))this : null; } + inout(ImportStatement) isImportStatement() { return stmt == STMT.Import ? cast(typeof(return))this : null; } } /*********************************************************** @@ -518,7 +528,8 @@ extern (C++) final class DtorExpStatement : ExpStatement /*********************************************************** * https://dlang.org/spec/statement.html#mixin-statement */ -extern (C++) final class CompileStatement : Statement +// Note: was called CompileStatement +extern (C++) final class MixinStatement : Statement { Expressions* exps; @@ -531,13 +542,13 @@ extern (C++) final class CompileStatement : Statement extern (D) this(const ref Loc loc, Expressions* exps) { - super(loc, STMT.Compile); + super(loc, STMT.Mixin); this.exps = exps; } - override CompileStatement syntaxCopy() + override MixinStatement syntaxCopy() { - return new CompileStatement(loc, Expression.arraySyntaxCopy(exps)); + return new MixinStatement(loc, Expression.arraySyntaxCopy(exps)); } override void accept(Visitor v) @@ -2084,3 +2095,107 @@ extern (C++) final class ImportStatement : Statement v.visit(this); } } + + +mixin template VisitStatement(Result) +{ + Result VisitStatement(Statement s) + { + final switch (s.stmt) + { + case STMT.Error: mixin(visitStmtCase("Error")); + case STMT.Scope: mixin(visitStmtCase("Scope")); + case STMT.Exp: mixin(visitStmtCase("Exp")); + case STMT.Compound: mixin(visitStmtCase("Compound")); + case STMT.Return: mixin(visitStmtCase("Return")); + case STMT.If: mixin(visitStmtCase("If")); + case STMT.Conditional: mixin(visitStmtCase("Conditional")); + case STMT.StaticForeach: mixin(visitStmtCase("StaticForeach")); + case STMT.Case: mixin(visitStmtCase("Case")); + case STMT.Default: mixin(visitStmtCase("Default")); + case STMT.Label: mixin(visitStmtCase("Label")); + case STMT.Goto: mixin(visitStmtCase("Goto")); + case STMT.GotoDefault: mixin(visitStmtCase("GotoDefault")); + case STMT.GotoCase: mixin(visitStmtCase("GotoCase")); + case STMT.Break: mixin(visitStmtCase("Break")); + case STMT.DtorExp: mixin(visitStmtCase("DtorExp")); + case STMT.Mixin: mixin(visitStmtCase("Mixin")); + case STMT.Forwarding: mixin(visitStmtCase("Forwarding")); + case STMT.Do: mixin(visitStmtCase("Do")); + case STMT.While: mixin(visitStmtCase("While")); + case STMT.For: mixin(visitStmtCase("For")); + case STMT.Foreach: mixin(visitStmtCase("Foreach")); + case STMT.Switch: mixin(visitStmtCase("Switch")); + case STMT.Continue: mixin(visitStmtCase("Continue")); + case STMT.With: mixin(visitStmtCase("With")); + case STMT.TryCatch: mixin(visitStmtCase("TryCatch")); + case STMT.Throw: mixin(visitStmtCase("Throw")); + case STMT.Debug: mixin(visitStmtCase("Debug")); + case STMT.TryFinally: mixin(visitStmtCase("TryFinally")); + case STMT.ScopeGuard: mixin(visitStmtCase("ScopeGuard")); + case STMT.SwitchError: mixin(visitStmtCase("SwitchError")); + case STMT.UnrolledLoop: mixin(visitStmtCase("UnrolledLoop")); + case STMT.ForeachRange: mixin(visitStmtCase("ForeachRange")); + case STMT.CompoundDeclaration: mixin(visitStmtCase("CompoundDeclaration")); + case STMT.Peel: mixin(visitStmtCase("Peel")); + case STMT.CompoundAsm: mixin(visitStmtCase("CompoundAsm")); + case STMT.Pragma: mixin(visitStmtCase("Pragma")); + case STMT.StaticAssert: mixin(visitStmtCase("StaticAssert")); + case STMT.CaseRange: mixin(visitStmtCase("CaseRange")); + case STMT.Synchronized: mixin(visitStmtCase("Synchronized")); + case STMT.Asm: mixin(visitStmtCase("Asm")); + case STMT.InlineAsm: mixin(visitStmtCase("InlineAsm")); + case STMT.GccAsm: mixin(visitStmtCase("GccAsm")); + case STMT.Import: mixin(visitStmtCase("Import")); + } + } +} + +/**************************************** + * CTFE-only helper function for VisitInitializer. + * Params: + * handler = string for the name of the visit handler + * Returns: boilerplate code for a case + */ +pure string visitStmtCase(string handler) +{ + if (__ctfe) + { + return + " + enum isVoid = is(Result == void); + auto sx = s.is"~handler~"Statement(); + static if (__traits(compiles, visit"~handler~"(sx))) + { + static if (isVoid) + { + visit"~handler~"(sx); + return; + } + else + { + if (Result r = visit"~handler~"(sx)) + return r; + return Result.init; + } + } + else static if (__traits(compiles, visitDefaultCase(s))) + { + static if (isVoid) + { + visitDefaultCase(sx); + return; + } + else + { + if (Result r = visitDefaultCase(s)) + return r; + return Result.init; + } + } + else + static assert(0, "~handler~"); + "; + } + assert(0); +} diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h index 6d1f85b3..b7403b5 100644 --- a/gcc/d/dmd/statement.h +++ b/gcc/d/dmd/statement.h @@ -65,7 +65,7 @@ enum STMTerror, STMTpeel, STMTexp, STMTdtorExp, - STMTcompile, + STMTmixin, STMTcompound, STMTcompoundDeclaration, STMTcompoundAsm, STMTunrolledLoop, STMTscope, @@ -143,7 +143,7 @@ public: GotoCaseStatement *isGotoCaseStatement() { return stmt == STMTgotoCase ? (GotoCaseStatement*)this : NULL; } BreakStatement *isBreakStatement() { return stmt == STMTbreak ? (BreakStatement*)this : NULL; } DtorExpStatement *isDtorExpStatement() { return stmt == STMTdtorExp ? (DtorExpStatement*)this : NULL; } - CompileStatement *isCompileStatement() { return stmt == STMTcompile ? (CompileStatement*)this : NULL; } + MixinStatement *isMixinStatement() { return stmt == STMTmixin ? (MixinStatement*)this : NULL; } ForwardingStatement *isForwardingStatement() { return stmt == STMTforwarding ? (ForwardingStatement*)this : NULL; } DoStatement *isDoStatement() { return stmt == STMTdo ? (DoStatement*)this : NULL; } ForStatement *isForStatement() { return stmt == STMTfor ? (ForStatement*)this : NULL; } @@ -206,12 +206,12 @@ public: void accept(Visitor *v) override { v->visit(this); } }; -class CompileStatement final : public Statement +class MixinStatement final : public Statement { public: Expressions *exps; - CompileStatement *syntaxCopy() override; + MixinStatement *syntaxCopy() override; void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 694db28..f849ce1 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -145,43 +145,35 @@ extern(C++) Statement statementSemantic(Statement s, Scope* sc) version (CallbackAPI) Compiler.onStatementSemanticStart(s, sc); - scope v = new StatementSemanticVisitor(sc); - s.accept(v); + Statement result = statementSemanticVisit(s, sc); version (CallbackAPI) Compiler.onStatementSemanticDone(s, sc); - return v.result; + return result; } -package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor +package (dmd) +Statement statementSemanticVisit(Statement s, Scope* sc) { - alias visit = Visitor.visit; - Statement result; - Scope* sc; - - this(Scope* sc) scope - { - this.sc = sc; - } - private void setError() + void setError() { result = new ErrorStatement(); } - override void visit(Statement s) + void visitDefaultCase(Statement s) { result = s; } - override void visit(ErrorStatement s) + void visitError(ErrorStatement s) { result = s; } - override void visit(PeelStatement s) + void visitPeel(PeelStatement s) { /* "peel" off this wrapper, and don't run semantic() * on the result. @@ -189,7 +181,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = s.s; } - override void visit(ExpStatement s) + void visitExp(ExpStatement s) { /* https://dlang.org/spec/statement.html#expression-statement */ @@ -226,12 +218,17 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = s; } - override void visit(CompileStatement cs) + void visitDtorExp(DtorExpStatement s) + { + visitExp(s); + } + + void visitMixin(MixinStatement cs) { /* https://dlang.org/spec/statement.html#mixin-statement */ - //printf("CompileStatement::semantic() %s\n", exp.toChars()); + //printf("MixinStatement::semantic() %s\n", exp.toChars()); Statements* a = cs.flatten(sc); if (!a) return; @@ -239,7 +236,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = s.statementSemantic(sc); } - override void visit(CompoundStatement cs) + void visitCompound(CompoundStatement cs) { //printf("CompoundStatement::semantic(this = %p, sc = %p)\n", cs, sc); version (none) @@ -431,7 +428,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = cs; } - override void visit(UnrolledLoopStatement uls) + void visitUnrolledLoop(UnrolledLoopStatement uls) { //printf("UnrolledLoopStatement::semantic(this = %p, sc = %p)\n", uls, sc); Scope* scd = sc.push(); @@ -454,7 +451,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = serror ? serror : uls; } - override void visit(ScopeStatement ss) + void visitScope(ScopeStatement ss) { //printf("ScopeStatement::semantic(sc = %p)\n", sc); if (!ss.statement) @@ -501,7 +498,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = ss; } - override void visit(ForwardingStatement ss) + void visitForwarding(ForwardingStatement ss) { assert(ss.sym); for (Scope* csc = sc; !ss.sym.parent; csc = csc.enclosing) @@ -517,7 +514,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = ss.statement; } - override void visit(WhileStatement ws) + void visitWhile(WhileStatement ws) { /* Rewrite as a for(;condition;) loop * https://dlang.org/spec/statement.html#while-statement @@ -544,7 +541,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = s; } - override void visit(DoStatement ds) + void visitDo(DoStatement ds) { /* https://dlang.org/spec/statement.html#do-statement */ @@ -580,7 +577,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = ds; } - override void visit(ForStatement fs) + void visitFor(ForStatement fs) { /* https://dlang.org/spec/statement.html#for-statement */ @@ -674,7 +671,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = fs; } - override void visit(ForeachStatement fs) + void visitForeach(ForeachStatement fs) { /* https://dlang.org/spec/statement.html#foreach-statement */ @@ -1349,7 +1346,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor auto exp = (*exps)[i]; version (none) { - printf("[%d] p = %s %s, exp = %s %s\n", i, + printf("[%lu] p = %s %s, exp = %s %s\n", i, p.type ? p.type.toChars() : "?", p.ident.toChars(), exp.type.toChars(), exp.toChars()); } @@ -1360,7 +1357,11 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor if (ignoreRef) sc &= ~STC.ref_; p.type = p.type.addStorageClass(sc).typeSemantic(loc, sc2); if (!exp.implicitConvTo(p.type)) - return rangeError(); + { + fs.error("cannot implicilty convert range element of type `%s` to variable `%s` of type `%s`", + exp.type.toChars(), p.toChars(), p.type.toChars()); + return retError(); + } auto var = new VarDeclaration(loc, p.type, p.ident, new ExpInitializer(loc, exp)); var.storage_class |= STC.ctfe | STC.ref_ | STC.foreach_; @@ -1395,312 +1396,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor } } - private static extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde, - Type tab, Scope* sc2, Dsymbol sapply) - { - version (none) - { - if (global.params.useDIP1000 == FeatureState.enabled) - { - message(loc, "To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`"); - } - (cast(FuncExp)flde).fd.tookAddressOf = 1; - } - else - { - if (global.params.useDIP1000 == FeatureState.enabled) - ++(cast(FuncExp)flde).fd.tookAddressOf; // allocate a closure unless the opApply() uses 'scope' - } - assert(tab.ty == Tstruct || tab.ty == Tclass); - assert(sapply); - /* Call: - * aggr.apply(flde) - */ - Expression ec; - ec = new DotIdExp(fs.loc, fs.aggr, sapply.ident); - ec = new CallExp(fs.loc, ec, flde); - ec = ec.expressionSemantic(sc2); - if (ec.op == EXP.error) - return null; - if (ec.type != Type.tint32) - { - fs.error("`opApply()` function for `%s` must return an `int`", tab.toChars()); - return null; - } - return ec; - } - - private static extern(D) Expression applyDelegate(ForeachStatement fs, Expression flde, - Type tab, Scope* sc2) - { - Expression ec; - /* Call: - * aggr(flde) - */ - if (fs.aggr.op == EXP.delegate_ && (cast(DelegateExp)fs.aggr).func.isNested() && - !(cast(DelegateExp)fs.aggr).func.needThis()) - { - // https://issues.dlang.org/show_bug.cgi?id=3560 - fs.aggr = (cast(DelegateExp)fs.aggr).e1; - } - ec = new CallExp(fs.loc, fs.aggr, flde); - ec = ec.expressionSemantic(sc2); - if (ec.op == EXP.error) - return null; - if (ec.type != Type.tint32) - { - fs.error("`opApply()` function for `%s` must return an `int`", tab.toChars()); - return null; - } - return ec; - } - - private static extern(D) Expression applyArray(ForeachStatement fs, Expression flde, - Type tab, Scope* sc2, Type tn, Type tnv) - { - Expression ec; - const dim = fs.parameters.length; - const loc = fs.loc; - /* Call: - * _aApply(aggr, flde) - */ - static immutable fntab = - [ - "cc", "cw", "cd", - "wc", "cc", "wd", - "dc", "dw", "dd" - ]; - - const(size_t) BUFFER_LEN = 7 + 1 + 2 + dim.sizeof * 3 + 1; - char[BUFFER_LEN] fdname; - int flag; - - switch (tn.ty) - { - case Tchar: flag = 0; break; - case Twchar: flag = 3; break; - case Tdchar: flag = 6; break; - default: - assert(0); - } - switch (tnv.ty) - { - case Tchar: flag += 0; break; - case Twchar: flag += 1; break; - case Tdchar: flag += 2; break; - default: - assert(0); - } - const(char)* r = (fs.op == TOK.foreach_reverse_) ? "R" : ""; - int j = snprintf(fdname.ptr, BUFFER_LEN, "_aApply%s%.*s%llu", r, 2, fntab[flag].ptr, cast(ulong)dim); - assert(j < BUFFER_LEN); - - FuncDeclaration fdapply; - TypeDelegate dgty; - auto params = new Parameters(); - params.push(new Parameter(STC.in_, tn.arrayOf(), null, null, null)); - auto dgparams = new Parameters(); - dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); - if (dim == 2) - dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); - dgty = new TypeDelegate(new TypeFunction(ParameterList(dgparams), Type.tint32, LINK.d)); - params.push(new Parameter(0, dgty, null, null, null)); - fdapply = FuncDeclaration.genCfunc(params, Type.tint32, fdname.ptr); - - if (tab.isTypeSArray()) - fs.aggr = fs.aggr.castTo(sc2, tn.arrayOf()); - // paint delegate argument to the type runtime expects - Expression fexp = flde; - if (!dgty.equals(flde.type)) - { - fexp = new CastExp(loc, flde, flde.type); - fexp.type = dgty; - } - ec = new VarExp(Loc.initial, fdapply, false); - ec = new CallExp(loc, ec, fs.aggr, fexp); - ec.type = Type.tint32; // don't run semantic() on ec - return ec; - } - - private static extern(D) Expression applyAssocArray(ForeachStatement fs, Expression flde, Type tab) - { - auto taa = tab.isTypeAArray(); - Expression ec; - const dim = fs.parameters.length; - // Check types - Parameter p = (*fs.parameters)[0]; - bool isRef = (p.storageClass & STC.ref_) != 0; - Type ta = p.type; - if (dim == 2) - { - Type ti = (isRef ? taa.index.addMod(MODFlags.const_) : taa.index); - if (isRef ? !ti.constConv(ta) : !ti.implicitConvTo(ta)) - { - fs.error("`foreach`: index must be type `%s`, not `%s`", - ti.toChars(), ta.toChars()); - return null; - } - p = (*fs.parameters)[1]; - isRef = (p.storageClass & STC.ref_) != 0; - ta = p.type; - } - Type taav = taa.nextOf(); - if (isRef ? !taav.constConv(ta) : !taav.implicitConvTo(ta)) - { - fs.error("`foreach`: value must be type `%s`, not `%s`", - taav.toChars(), ta.toChars()); - return null; - } - - /* Call: - * extern(C) int _aaApply(void*, in size_t, int delegate(void*)) - * _aaApply(aggr, keysize, flde) - * - * extern(C) int _aaApply2(void*, in size_t, int delegate(void*, void*)) - * _aaApply2(aggr, keysize, flde) - */ - __gshared FuncDeclaration* fdapply = [null, null]; - __gshared TypeDelegate* fldeTy = [null, null]; - ubyte i = (dim == 2 ? 1 : 0); - if (!fdapply[i]) - { - auto params = new Parameters(); - params.push(new Parameter(0, Type.tvoid.pointerTo(), null, null, null)); - params.push(new Parameter(STC.const_, Type.tsize_t, null, null, null)); - auto dgparams = new Parameters(); - dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); - if (dim == 2) - dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); - fldeTy[i] = new TypeDelegate(new TypeFunction(ParameterList(dgparams), Type.tint32, LINK.d)); - params.push(new Parameter(0, fldeTy[i], null, null, null)); - fdapply[i] = FuncDeclaration.genCfunc(params, Type.tint32, i ? Id._aaApply2 : Id._aaApply); - } - - auto exps = new Expressions(); - exps.push(fs.aggr); - auto keysize = taa.index.size(); - if (keysize == SIZE_INVALID) - return null; - assert(keysize < keysize.max - target.ptrsize); - keysize = (keysize + (target.ptrsize - 1)) & ~(target.ptrsize - 1); - // paint delegate argument to the type runtime expects - Expression fexp = flde; - if (!fldeTy[i].equals(flde.type)) - { - fexp = new CastExp(fs.loc, flde, flde.type); - fexp.type = fldeTy[i]; - } - exps.push(new IntegerExp(Loc.initial, keysize, Type.tsize_t)); - exps.push(fexp); - ec = new VarExp(Loc.initial, fdapply[i], false); - ec = new CallExp(fs.loc, ec, exps); - ec.type = Type.tint32; // don't run semantic() on ec - return ec; - } - - private static extern(D) Statement loopReturn(Expression e, Statements* cases, const ref Loc loc) - { - if (!cases.length) - { - // Easy case, a clean exit from the loop - e = new CastExp(loc, e, Type.tvoid); // https://issues.dlang.org/show_bug.cgi?id=13899 - return new ExpStatement(loc, e); - } - // Construct a switch statement around the return value - // of the apply function. - Statement s; - auto a = new Statements(); - - // default: break; takes care of cases 0 and 1 - s = new BreakStatement(Loc.initial, null); - s = new DefaultStatement(Loc.initial, s); - a.push(s); - - // cases 2... - foreach (i, c; *cases) - { - s = new CaseStatement(Loc.initial, new IntegerExp(i + 2), c); - a.push(s); - } - - s = new CompoundStatement(loc, a); - return new SwitchStatement(loc, e, s, false); - } - /************************************* - * Turn foreach body into the function literal: - * int delegate(ref T param) { body } - * Params: - * sc = context - * fs = ForeachStatement - * tfld = type of function literal to be created (type of opApply() function if any), can be null - * Returns: - * Function literal created, as an expression - * null if error. - */ - static FuncExp foreachBodyToFunction(Scope* sc, ForeachStatement fs, TypeFunction tfld) - { - auto params = new Parameters(); - foreach (i, p; *fs.parameters) - { - StorageClass stc = STC.ref_ | (p.storageClass & STC.scope_); - Identifier id; - - p.type = p.type.typeSemantic(fs.loc, sc); - p.type = p.type.addStorageClass(p.storageClass); - if (tfld) - { - Parameter prm = tfld.parameterList[i]; - //printf("\tprm = %s%s\n", (prm.storageClass&STC.ref_?"ref ":"").ptr, prm.ident.toChars()); - stc = (prm.storageClass & STC.ref_) | (p.storageClass & STC.scope_); - if ((p.storageClass & STC.ref_) != (prm.storageClass & STC.ref_)) - { - if (!(prm.storageClass & STC.ref_)) - { - fs.error("`foreach`: cannot make `%s` `ref`", p.ident.toChars()); - return null; - } - goto LcopyArg; - } - id = p.ident; // argument copy is not need. - } - else if (p.storageClass & STC.ref_) - { - // default delegate parameters are marked as ref, then - // argument copy is not need. - id = p.ident; - } - else - { - // Make a copy of the ref argument so it isn't - // a reference. - LcopyArg: - id = Identifier.generateId("__applyArg", cast(int)i); - - Initializer ie = new ExpInitializer(fs.loc, new IdentifierExp(fs.loc, id)); - auto v = new VarDeclaration(fs.loc, p.type, p.ident, ie); - v.storage_class |= STC.temp | (stc & STC.scope_); - Statement s = new ExpStatement(fs.loc, v); - fs._body = new CompoundStatement(fs.loc, s, fs._body); - } - params.push(new Parameter(stc, p.type, id, null, null)); - } - // https://issues.dlang.org/show_bug.cgi?id=13840 - // Throwable nested function inside nothrow function is acceptable. - StorageClass stc = mergeFuncAttrs(STC.safe | STC.pure_ | STC.nogc, fs.func); - auto tf = new TypeFunction(ParameterList(params), Type.tint32, LINK.d, stc); - fs.cases = new Statements(); - fs.gotos = new ScopeStatements(); - auto fld = new FuncLiteralDeclaration(fs.loc, fs.endloc, tf, TOK.delegate_, fs); - fld.fbody = fs._body; - Expression flde = new FuncExp(fs.loc, fld); - flde = flde.expressionSemantic(sc); - fld.tookAddressOf = 0; - if (flde.op == EXP.error) - return null; - return cast(FuncExp)flde; - } - - override void visit(ForeachRangeStatement fs) + void visitForeachRange(ForeachRangeStatement fs) { /* https://dlang.org/spec/statement.html#foreach-range-statement */ @@ -1886,7 +1582,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = s.statementSemantic(sc); } - override void visit(IfStatement ifs) + void visitIf(IfStatement ifs) { /* https://dlang.org/spec/statement.html#IfStatement */ @@ -1959,6 +1655,20 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor // Save 'root' of two branches (then and else) at the point where it forks CtorFlow ctorflow_root = scd.ctorflow.clone(); + /* Rewrite `if (!__ctfe) A else B` as `if (__ctfe) B else A` + */ + NotExp notExp; + if (ifs.elsebody && + (notExp = ifs.condition.isNotExp()) !is null && + notExp.e1.isVarExp() && + notExp.e1.isVarExp().var.ident == Id.ctfe) + { + ifs.condition = notExp.e1; + auto sbody = ifs.ifbody; + ifs.ifbody = ifs.elsebody; + ifs.elsebody = sbody; + } + /* Detect `if (__ctfe)` */ if (ifs.isIfCtfeBlock()) @@ -1991,7 +1701,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = ifs; } - override void visit(ConditionalStatement cs) + void visitConditional(ConditionalStatement cs) { //printf("ConditionalStatement::semantic()\n"); @@ -2020,7 +1730,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor } } - override void visit(PragmaStatement ps) + void visitPragma(PragmaStatement ps) { /* https://dlang.org/spec/statement.html#pragma-statement */ @@ -2104,14 +1814,14 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = ps._body; } - override void visit(StaticAssertStatement s) + void visitStaticAssert(StaticAssertStatement s) { s.sa.semantic2(sc); if (s.sa.errors) return setError(); } - override void visit(SwitchStatement ss) + void visitSwitch(SwitchStatement ss) { /* https://dlang.org/spec/statement.html#switch-statement */ @@ -2288,6 +1998,11 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor { s = new BreakStatement(ss.loc, null); // default for C is `default: break;` } + else if (!sc.needsCodegen()) + { + // something for the interpreter to deal with + s = new ExpStatement(ss.loc, new AssertExp(ss.loc, IntegerExp.literal!0)); + } else if (global.params.useSwitchError == CHECKENABLE.on && global.params.checkAction != CHECKACTION.halt) { @@ -2337,7 +2052,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor } - if (!ss.condition.type.isString()) + if (!(ss.condition.type.isString() && sc.needsCodegen())) { sc.pop(); result = ss; @@ -2420,7 +2135,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = ss; } - override void visit(CaseStatement cs) + void visitCase(CaseStatement cs) { SwitchStatement sw = sc.sw; bool errors = false; @@ -2566,7 +2281,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = cs; } - override void visit(CaseRangeStatement crs) + void visitCaseRange(CaseRangeStatement crs) { SwitchStatement sw = sc.sw; if (sw is null) @@ -2649,7 +2364,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = s; } - override void visit(DefaultStatement ds) + void visitDefault(DefaultStatement ds) { //printf("DefaultStatement::semantic()\n"); bool errors = false; @@ -2693,7 +2408,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = ds; } - override void visit(GotoDefaultStatement gds) + void visitGotoDefault(GotoDefaultStatement gds) { /* https://dlang.org/spec/statement.html#goto-statement */ @@ -2712,7 +2427,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = gds; } - override void visit(GotoCaseStatement gcs) + void visitGotoCase(GotoCaseStatement gcs) { /* https://dlang.org/spec/statement.html#goto-statement */ @@ -2736,7 +2451,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = gcs; } - override void visit(ReturnStatement rs) + void visitReturn(ReturnStatement rs) { /* https://dlang.org/spec/statement.html#return-statement */ @@ -3129,7 +2844,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = rs; } - override void visit(BreakStatement bs) + void visitBreak(BreakStatement bs) { /* https://dlang.org/spec/statement.html#break-statement */ @@ -3207,7 +2922,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = bs; } - override void visit(ContinueStatement cs) + void visitContinue(ContinueStatement cs) { /* https://dlang.org/spec/statement.html#continue-statement */ @@ -3294,7 +3009,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = cs; } - override void visit(SynchronizedStatement ss) + void visitSynchronized(SynchronizedStatement ss) { /* https://dlang.org/spec/statement.html#synchronized-statement */ @@ -3416,7 +3131,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor } } - override void visit(WithStatement ws) + void visitWith(WithStatement ws) { /* https://dlang.org/spec/statement.html#with-statement */ @@ -3451,14 +3166,16 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor } else { - Type t = ws.exp.type.toBasetype(); + Type texp = ws.exp.type; + Type t = texp.toBasetype(); Expression olde = ws.exp; if (t.ty == Tpointer) { ws.exp = new PtrExp(ws.loc, ws.exp); ws.exp = ws.exp.expressionSemantic(sc); - t = ws.exp.type.toBasetype(); + texp = ws.exp.type; + t = texp.toBasetype(); } assert(t); @@ -3506,9 +3223,16 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor sym.parent = sc.scopesym; sym.endlinnum = ws.endloc.linnum; } + else if (auto tenum = texp.isTypeEnum()) + { + ws.exp = new TypeExp(ws.exp.loc, tenum); + sym = new WithScopeSymbol(ws); + sym.parent = sc.scopesym; + sym.endlinnum = ws.endloc.linnum; + } else { - ws.error("`with` expressions must be aggregate types or pointers to them, not `%s`", olde.type.toChars()); + ws.error("`with` expression types must be enums or aggregates or pointers to them, not `%s`", olde.type.toChars()); return setError(); } } @@ -3531,7 +3255,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor } // https://dlang.org/spec/statement.html#TryStatement - override void visit(TryCatchStatement tcs) + void visitTryCatch(TryCatchStatement tcs) { //printf("TryCatchStatement.semantic()\n"); @@ -3635,7 +3359,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = tcs; } - override void visit(TryFinallyStatement tfs) + void visitTryFinally(TryFinallyStatement tfs) { //printf("TryFinallyStatement::semantic()\n"); tfs.tryBody = sc.tryBody; // chain on in-flight tryBody @@ -3675,7 +3399,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = tfs; } - override void visit(ScopeGuardStatement oss) + void visitScopeGuard(ScopeGuardStatement oss) { /* https://dlang.org/spec/statement.html#scope-guard-statement */ @@ -3725,7 +3449,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = oss; } - override void visit(ThrowStatement ts) + void visitThrow(ThrowStatement ts) { /* https://dlang.org/spec/statement.html#throw-statement */ @@ -3738,57 +3462,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor } - /** - * Run semantic on `throw <exp>`. - * - * Params: - * loc = location of the `throw` - * exp = value to be thrown - * sc = enclosing scope - * - * Returns: true if the `throw` is valid, or false if an error was found - */ - extern(D) static bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc) - { - if (!global.params.useExceptions) - { - loc.error("cannot use `throw` statements with -betterC"); - return false; - } - - if (!ClassDeclaration.throwable) - { - loc.error("cannot use `throw` statements because `object.Throwable` was not declared"); - return false; - } - - if (FuncDeclaration fd = sc.parent.isFuncDeclaration()) - fd.hasReturnExp |= 2; - - if (exp.op == EXP.new_) - { - NewExp ne = cast(NewExp) exp; - ne.thrownew = true; - } - - exp = exp.expressionSemantic(sc); - exp = resolveProperties(sc, exp); - exp = checkGC(sc, exp); - if (exp.op == EXP.error) - return false; - - checkThrowEscape(sc, exp, false); - - ClassDeclaration cd = exp.type.toBasetype().isClassHandle(); - if (!cd || ((cd != ClassDeclaration.throwable) && !ClassDeclaration.throwable.isBaseOf(cd, null))) - { - loc.error("can only throw class objects derived from `Throwable`, not type `%s`", exp.type.toChars()); - return false; - } - return true; - } - - override void visit(DebugStatement ds) + void visitDebug(DebugStatement ds) { if (ds.statement) { @@ -3800,7 +3474,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = ds.statement; } - override void visit(GotoStatement gs) + void visitGoto(GotoStatement gs) { /* https://dlang.org/spec/statement.html#goto-statement */ @@ -3844,7 +3518,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = gs; } - override void visit(LabelStatement ls) + void visitLabel(LabelStatement ls) { //printf("LabelStatement::semantic()\n"); FuncDeclaration fd = sc.parent.isFuncDeclaration(); @@ -3878,7 +3552,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = ls; } - override void visit(AsmStatement s) + void visitAsm(AsmStatement s) { /* https://dlang.org/spec/statement.html#asm */ @@ -3887,7 +3561,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = asmSemantic(s, sc); } - override void visit(CompoundAsmStatement cas) + void visitCompoundAsm(CompoundAsmStatement cas) { //printf("CompoundAsmStatement()::semantic()\n"); // Apply postfix attributes of the asm block to each statement. @@ -3915,9 +3589,9 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor } assert(sc.func); - if (!(cas.stc & STC.pure_) && sc.func.setImpure()) + if (!(cas.stc & STC.pure_) && sc.func.setImpure(cas.loc, "`asm` statement is assumed to be impure - mark it with `pure` if it is not")) cas.error("`asm` statement is assumed to be impure - mark it with `pure` if it is not"); - if (!(cas.stc & STC.nogc) && sc.func.setGC()) + if (!(cas.stc & STC.nogc) && sc.func.setGC(cas.loc, "`asm` statement in %s `%s` is assumed to use the GC - mark it with `@nogc` if it does not")) cas.error("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not"); if (!(cas.stc & (STC.trusted | STC.safe))) { @@ -3928,7 +3602,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor result = cas; } - override void visit(ImportStatement imps) + void visitImport(ImportStatement imps) { /* https://dlang.org/spec/module.html#ImportDeclaration */ @@ -3967,8 +3641,375 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor } result = imps; } + + mixin VisitStatement!void visit; + visit.VisitStatement(s); + return result; } +/** + * Run semantic on `throw <exp>`. + * + * Params: + * loc = location of the `throw` + * exp = value to be thrown + * sc = enclosing scope + * + * Returns: true if the `throw` is valid, or false if an error was found + */ +public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc) +{ + if (!global.params.useExceptions) + { + loc.error("cannot use `throw` statements with -betterC"); + return false; + } + + if (!ClassDeclaration.throwable) + { + loc.error("cannot use `throw` statements because `object.Throwable` was not declared"); + return false; + } + + if (FuncDeclaration fd = sc.parent.isFuncDeclaration()) + fd.hasReturnExp |= 2; + + if (exp.op == EXP.new_) + { + NewExp ne = cast(NewExp) exp; + ne.thrownew = true; + } + + exp = exp.expressionSemantic(sc); + exp = resolveProperties(sc, exp); + exp = checkGC(sc, exp); + if (exp.op == EXP.error) + return false; + if (!exp.type.isNaked()) + { + // @@@DEPRECATED_2.112@@@ + // Deprecated in 2.102, change into an error & return false in 2.112 + exp.loc.deprecation("cannot throw object of qualified type `%s`", exp.type.toChars()); + //return false; + } + checkThrowEscape(sc, exp, false); + + ClassDeclaration cd = exp.type.toBasetype().isClassHandle(); + if (!cd || ((cd != ClassDeclaration.throwable) && !ClassDeclaration.throwable.isBaseOf(cd, null))) + { + loc.error("can only throw class objects derived from `Throwable`, not type `%s`", exp.type.toChars()); + return false; + } + return true; +} + +private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde, + Type tab, Scope* sc2, Dsymbol sapply) +{ + version (none) + { + if (global.params.useDIP1000 == FeatureState.enabled) + { + message(loc, "To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`"); + } + (cast(FuncExp)flde).fd.tookAddressOf = 1; + } + else + { + if (global.params.useDIP1000 == FeatureState.enabled) + ++(cast(FuncExp)flde).fd.tookAddressOf; // allocate a closure unless the opApply() uses 'scope' + } + assert(tab.ty == Tstruct || tab.ty == Tclass); + assert(sapply); + /* Call: + * aggr.apply(flde) + */ + Expression ec; + ec = new DotIdExp(fs.loc, fs.aggr, sapply.ident); + ec = new CallExp(fs.loc, ec, flde); + ec = ec.expressionSemantic(sc2); + if (ec.op == EXP.error) + return null; + if (ec.type != Type.tint32) + { + fs.error("`opApply()` function for `%s` must return an `int`", tab.toChars()); + return null; + } + return ec; +} + +private extern(D) Expression applyDelegate(ForeachStatement fs, Expression flde, + Type tab, Scope* sc2) +{ + Expression ec; + /* Call: + * aggr(flde) + */ + if (fs.aggr.op == EXP.delegate_ && (cast(DelegateExp)fs.aggr).func.isNested() && + !(cast(DelegateExp)fs.aggr).func.needThis()) + { + // https://issues.dlang.org/show_bug.cgi?id=3560 + fs.aggr = (cast(DelegateExp)fs.aggr).e1; + } + ec = new CallExp(fs.loc, fs.aggr, flde); + ec = ec.expressionSemantic(sc2); + if (ec.op == EXP.error) + return null; + if (ec.type != Type.tint32) + { + fs.error("`opApply()` function for `%s` must return an `int`", tab.toChars()); + return null; + } + return ec; +} + +private extern(D) Expression applyArray(ForeachStatement fs, Expression flde, + Type tab, Scope* sc2, Type tn, Type tnv) +{ + Expression ec; + const dim = fs.parameters.length; + const loc = fs.loc; + /* Call: + * _aApply(aggr, flde) + */ + static immutable fntab = + [ + "cc", "cw", "cd", + "wc", "cc", "wd", + "dc", "dw", "dd" + ]; + + const(size_t) BUFFER_LEN = 7 + 1 + 2 + dim.sizeof * 3 + 1; + char[BUFFER_LEN] fdname; + int flag; + + switch (tn.ty) + { + case Tchar: flag = 0; break; + case Twchar: flag = 3; break; + case Tdchar: flag = 6; break; + default: + assert(0); + } + switch (tnv.ty) + { + case Tchar: flag += 0; break; + case Twchar: flag += 1; break; + case Tdchar: flag += 2; break; + default: + assert(0); + } + const(char)* r = (fs.op == TOK.foreach_reverse_) ? "R" : ""; + int j = snprintf(fdname.ptr, BUFFER_LEN, "_aApply%s%.*s%llu", r, 2, fntab[flag].ptr, cast(ulong)dim); + assert(j < BUFFER_LEN); + + FuncDeclaration fdapply; + TypeDelegate dgty; + auto params = new Parameters(); + params.push(new Parameter(STC.in_, tn.arrayOf(), null, null, null)); + auto dgparams = new Parameters(); + dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); + if (dim == 2) + dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); + dgty = new TypeDelegate(new TypeFunction(ParameterList(dgparams), Type.tint32, LINK.d)); + params.push(new Parameter(0, dgty, null, null, null)); + fdapply = FuncDeclaration.genCfunc(params, Type.tint32, fdname.ptr); + + if (tab.isTypeSArray()) + fs.aggr = fs.aggr.castTo(sc2, tn.arrayOf()); + // paint delegate argument to the type runtime expects + Expression fexp = flde; + if (!dgty.equals(flde.type)) + { + fexp = new CastExp(loc, flde, flde.type); + fexp.type = dgty; + } + ec = new VarExp(Loc.initial, fdapply, false); + ec = new CallExp(loc, ec, fs.aggr, fexp); + ec.type = Type.tint32; // don't run semantic() on ec + return ec; +} + +private extern(D) Expression applyAssocArray(ForeachStatement fs, Expression flde, Type tab) +{ + auto taa = tab.isTypeAArray(); + Expression ec; + const dim = fs.parameters.length; + // Check types + Parameter p = (*fs.parameters)[0]; + bool isRef = (p.storageClass & STC.ref_) != 0; + Type ta = p.type; + if (dim == 2) + { + Type ti = (isRef ? taa.index.addMod(MODFlags.const_) : taa.index); + if (isRef ? !ti.constConv(ta) : !ti.implicitConvTo(ta)) + { + fs.error("`foreach`: index must be type `%s`, not `%s`", + ti.toChars(), ta.toChars()); + return null; + } + p = (*fs.parameters)[1]; + isRef = (p.storageClass & STC.ref_) != 0; + ta = p.type; + } + Type taav = taa.nextOf(); + if (isRef ? !taav.constConv(ta) : !taav.implicitConvTo(ta)) + { + fs.error("`foreach`: value must be type `%s`, not `%s`", + taav.toChars(), ta.toChars()); + return null; + } + + /* Call: + * extern(C) int _aaApply(void*, in size_t, int delegate(void*)) + * _aaApply(aggr, keysize, flde) + * + * extern(C) int _aaApply2(void*, in size_t, int delegate(void*, void*)) + * _aaApply2(aggr, keysize, flde) + */ + __gshared FuncDeclaration* fdapply = [null, null]; + __gshared TypeDelegate* fldeTy = [null, null]; + ubyte i = (dim == 2 ? 1 : 0); + if (!fdapply[i]) + { + auto params = new Parameters(); + params.push(new Parameter(0, Type.tvoid.pointerTo(), null, null, null)); + params.push(new Parameter(STC.const_, Type.tsize_t, null, null, null)); + auto dgparams = new Parameters(); + dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); + if (dim == 2) + dgparams.push(new Parameter(0, Type.tvoidptr, null, null, null)); + fldeTy[i] = new TypeDelegate(new TypeFunction(ParameterList(dgparams), Type.tint32, LINK.d)); + params.push(new Parameter(0, fldeTy[i], null, null, null)); + fdapply[i] = FuncDeclaration.genCfunc(params, Type.tint32, i ? Id._aaApply2 : Id._aaApply); + } + + auto exps = new Expressions(); + exps.push(fs.aggr); + auto keysize = taa.index.size(); + if (keysize == SIZE_INVALID) + return null; + assert(keysize < keysize.max - target.ptrsize); + keysize = (keysize + (target.ptrsize - 1)) & ~(target.ptrsize - 1); + // paint delegate argument to the type runtime expects + Expression fexp = flde; + if (!fldeTy[i].equals(flde.type)) + { + fexp = new CastExp(fs.loc, flde, flde.type); + fexp.type = fldeTy[i]; + } + exps.push(new IntegerExp(Loc.initial, keysize, Type.tsize_t)); + exps.push(fexp); + ec = new VarExp(Loc.initial, fdapply[i], false); + ec = new CallExp(fs.loc, ec, exps); + ec.type = Type.tint32; // don't run semantic() on ec + return ec; +} + +private extern(D) Statement loopReturn(Expression e, Statements* cases, const ref Loc loc) +{ + if (!cases.length) + { + // Easy case, a clean exit from the loop + e = new CastExp(loc, e, Type.tvoid); // https://issues.dlang.org/show_bug.cgi?id=13899 + return new ExpStatement(loc, e); + } + // Construct a switch statement around the return value + // of the apply function. + Statement s; + auto a = new Statements(); + + // default: break; takes care of cases 0 and 1 + s = new BreakStatement(Loc.initial, null); + s = new DefaultStatement(Loc.initial, s); + a.push(s); + + // cases 2... + foreach (i, c; *cases) + { + s = new CaseStatement(Loc.initial, new IntegerExp(i + 2), c); + a.push(s); + } + + s = new CompoundStatement(loc, a); + return new SwitchStatement(loc, e, s, false); +} + +/************************************* + * Turn foreach body into the function literal: + * int delegate(ref T param) { body } + * Params: + * sc = context + * fs = ForeachStatement + * tfld = type of function literal to be created (type of opApply() function if any), can be null + * Returns: + * Function literal created, as an expression + * null if error. + */ +private FuncExp foreachBodyToFunction(Scope* sc, ForeachStatement fs, TypeFunction tfld) +{ + auto params = new Parameters(); + foreach (i, p; *fs.parameters) + { + StorageClass stc = STC.ref_ | (p.storageClass & STC.scope_); + Identifier id; + + p.type = p.type.typeSemantic(fs.loc, sc); + p.type = p.type.addStorageClass(p.storageClass); + if (tfld) + { + Parameter prm = tfld.parameterList[i]; + //printf("\tprm = %s%s\n", (prm.storageClass&STC.ref_?"ref ":"").ptr, prm.ident.toChars()); + stc = (prm.storageClass & STC.ref_) | (p.storageClass & STC.scope_); + if ((p.storageClass & STC.ref_) != (prm.storageClass & STC.ref_)) + { + if (!(prm.storageClass & STC.ref_)) + { + fs.error("`foreach`: cannot make `%s` `ref`", p.ident.toChars()); + return null; + } + goto LcopyArg; + } + id = p.ident; // argument copy is not need. + } + else if (p.storageClass & STC.ref_) + { + // default delegate parameters are marked as ref, then + // argument copy is not need. + id = p.ident; + } + else + { + // Make a copy of the ref argument so it isn't + // a reference. + LcopyArg: + id = Identifier.generateId("__applyArg", cast(int)i); + + Initializer ie = new ExpInitializer(fs.loc, new IdentifierExp(fs.loc, id)); + auto v = new VarDeclaration(fs.loc, p.type, p.ident, ie); + v.storage_class |= STC.temp | (stc & STC.scope_); + Statement s = new ExpStatement(fs.loc, v); + fs._body = new CompoundStatement(fs.loc, s, fs._body); + } + params.push(new Parameter(stc, p.type, id, null, null)); + } + // https://issues.dlang.org/show_bug.cgi?id=13840 + // Throwable nested function inside nothrow function is acceptable. + StorageClass stc = mergeFuncAttrs(STC.safe | STC.pure_ | STC.nogc, fs.func); + auto tf = new TypeFunction(ParameterList(params), Type.tint32, LINK.d, stc); + fs.cases = new Statements(); + fs.gotos = new ScopeStatements(); + auto fld = new FuncLiteralDeclaration(fs.loc, fs.endloc, tf, TOK.delegate_, fs); + fld.fbody = fs._body; + Expression flde = new FuncExp(fs.loc, fld); + flde = flde.expressionSemantic(sc); + fld.tookAddressOf = 0; + if (flde.op == EXP.error) + return null; + return cast(FuncExp)flde; +} + + void catchSemantic(Catch c, Scope* sc) { //printf("Catch::semantic(%s)\n", ident.toChars()); @@ -4735,8 +4776,8 @@ private Statements* flatten(Statement statement, Scope* sc) (*a)[0] = ls; return a; - case STMT.Compile: - auto cs = statement.isCompileStatement(); + case STMT.Mixin: + auto cs = statement.isMixinStatement(); OutBuffer buf; @@ -4747,13 +4788,16 @@ private Statements* flatten(Statement statement, Scope* sc) const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - scope p = new Parser!ASTCodegen(cs.loc, sc._module, str, false, global.errorSink); + const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput; + auto loc = adjustLocForMixin(str, cs.loc, global.params.mixinOut); + scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests); + p.transitionIn = global.params.vin; p.nextToken(); auto a = new Statements(); while (p.token.value != TOK.endOfFile) { - Statement s = p.parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope); + Statement s = p.parseStatement(ParseStatementFlags.curlyScope); if (!s || global.errors != errors) return errorStatements(); a.push(s); diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index aec3a77..352c89e 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -274,6 +274,7 @@ enum TOK : ubyte __cdecl, __declspec, __stdcall, + __thread, __pragma, __int128, __attribute__, @@ -289,8 +290,6 @@ enum EXP : ubyte cast_, null_, assert_, - true_, - false_, array, call, address, @@ -307,13 +306,10 @@ enum EXP : ubyte dotType, slice, arrayLength, - version_, dollar, template_, dotTemplateDeclaration, declaration, - typeof_, - pragma_, dSymbol, typeid_, uadd, @@ -394,13 +390,11 @@ enum EXP : ubyte int64, float64, complex80, - char_, import_, delegate_, function_, mixin_, in_, - default_, break_, continue_, goto_, @@ -414,7 +408,6 @@ enum EXP : ubyte moduleString, // __MODULE__ functionString, // __FUNCTION__ prettyFunction, // __PRETTY_FUNCTION__ - shared_, pow, powAssign, vector, @@ -424,10 +417,11 @@ enum EXP : ubyte showCtfeContext, objcClassReference, vectorArray, - arrow, // -> compoundLiteral, // ( type-name ) { initializer-list } _Generic, interval, + + loweredAssignExp, } enum FirstCKeyword = TOK.inline; @@ -586,6 +580,7 @@ private immutable TOK[] keywords = TOK.__cdecl, TOK.__declspec, TOK.__stdcall, + TOK.__thread, TOK.__pragma, TOK.__int128, TOK.__attribute__, @@ -617,7 +612,7 @@ static immutable TOK[TOK.max + 1] Ckeywords = union_, unsigned, void_, volatile, while_, asm_, typeof_, _Alignas, _Alignof, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn, _Static_assert, _Thread_local, - _import, __cdecl, __declspec, __stdcall, __pragma, __int128, __attribute__, + _import, __cdecl, __declspec, __stdcall, __thread, __pragma, __int128, __attribute__, _assert ]; foreach (kw; Ckwds) @@ -889,6 +884,7 @@ extern (C++) struct Token TOK.__cdecl : "__cdecl", TOK.__declspec : "__declspec", TOK.__stdcall : "__stdcall", + TOK.__thread : "__thread", TOK.__pragma : "__pragma", TOK.__int128 : "__int128", TOK.__attribute__ : "__attribute__", diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index 87361f32..6c1b979 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -283,6 +283,7 @@ enum class TOK : unsigned char cdecl_, declspec, stdcall, + thread, pragma, int128_, attribute__, @@ -299,8 +300,6 @@ enum class EXP : unsigned char cast_, null_, assert_, - true_, - false_, array, call, address, @@ -317,13 +316,10 @@ enum class EXP : unsigned char dotType, slice, arrayLength, - version_, dollar, template_, dotTemplateDeclaration, declaration, - typeof_, - pragma_, dSymbol, typeid_, uadd, @@ -404,13 +400,11 @@ enum class EXP : unsigned char int64, float64, complex80, - char_, import_, delegate_, function_, mixin_, in_, - default_, break_, continue_, goto_, @@ -424,7 +418,6 @@ enum class EXP : unsigned char moduleString, // __MODULE__ functionString, // __FUNCTION__ prettyFunction, // __PRETTY_FUNCTION__ - shared_, pow, powAssign, vector, @@ -434,7 +427,6 @@ enum class EXP : unsigned char showCtfeContext, objcClassReference, vectorArray, - arrow, // -> compoundLiteral, // ( type-name ) { initializer-list } _Generic_, interval, diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index de0129b..0f36353 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -118,55 +118,40 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data) data.setDim(cast(size_t)cntdata); data.zero(); - extern (C++) final class PointerBitmapVisitor : Visitor - { - alias visit = Visitor.visit; - public: - extern (D) this(Array!(ulong)* _data, ulong _sz_size_t) scope - { - this.data = _data; - this.sz_size_t = _sz_size_t; - } + ulong offset; + bool error; + void visit(Type t) + { void setpointer(ulong off) { ulong ptroff = off / sz_size_t; (*data)[cast(size_t)(ptroff / (8 * sz_size_t))] |= 1L << (ptroff % (8 * sz_size_t)); } - override void visit(Type t) + void visitType(Type t) { Type tb = t.toBasetype(); if (tb != t) - tb.accept(this); + visit(tb); } - override void visit(TypeError t) + void visitError(TypeError t) { - visit(cast(Type)t); + visitType(t); } - override void visit(TypeNext t) - { - assert(0); - } - - override void visit(TypeBasic t) + void visitBasic(TypeBasic t) { if (t.ty == Tvoid) setpointer(offset); } - override void visit(TypeVector t) - { - } - - override void visit(TypeArray t) + void visitVector(TypeVector t) { - assert(0); } - override void visit(TypeSArray t) + void visitSArray(TypeSArray t) { ulong arrayoff = offset; ulong nextsize = t.next.size(); @@ -176,95 +161,67 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data) for (ulong i = 0; i < dim; i++) { offset = arrayoff + i * nextsize; - t.next.accept(this); + visit(t.next); } offset = arrayoff; } - override void visit(TypeDArray t) + void visitDArray(TypeDArray t) { setpointer(offset + sz_size_t); } // dynamic array is {length,ptr} - override void visit(TypeAArray t) + void visitAArray(TypeAArray t) { setpointer(offset); } - override void visit(TypePointer t) + void visitPointer(TypePointer t) { if (t.nextOf().ty != Tfunction) // don't mark function pointers setpointer(offset); } - override void visit(TypeReference t) + void visitReference(TypeReference t) { setpointer(offset); } - override void visit(TypeClass t) + void visitClass(TypeClass t) { setpointer(offset); } - override void visit(TypeFunction t) + void visitFunction(TypeFunction t) { } - override void visit(TypeDelegate t) + void visitDelegate(TypeDelegate t) { setpointer(offset); } - // delegate is {context, function} - override void visit(TypeQualified t) + void visitEnum(TypeEnum t) { - assert(0); + visitType(t); } - // assume resolved - override void visit(TypeIdentifier t) + void visitTuple(TypeTuple t) { - assert(0); + visitType(t); } - override void visit(TypeInstance t) + void visitNull(TypeNull t) { - assert(0); - } - - override void visit(TypeTypeof t) - { - assert(0); - } - - override void visit(TypeReturn t) - { - assert(0); - } - - override void visit(TypeEnum t) - { - visit(cast(Type)t); - } - - override void visit(TypeTuple t) - { - visit(cast(Type)t); + // always a null pointer } - override void visit(TypeSlice t) + void visitNoreturn(TypeNoreturn t) { - assert(0); } - override void visit(TypeNull t) - { - // always a null pointer - } - - override void visit(TypeStruct t) + void visitStruct(TypeStruct t) { ulong structoff = offset; foreach (v; t.sym.fields) @@ -273,38 +230,43 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data) if (v.type.ty == Tclass) setpointer(offset); else - v.type.accept(this); + visit(v.type); } offset = structoff; } + void visitDefaultCase(Type t) + { + //printf("ty = %d\n", t.ty); + assert(0); + } + + mixin VisitType!void visit; + visit.VisitType(t); + } + + if (auto tc = t.isTypeClass()) + { // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references - void visitClass(TypeClass t) + void visitTopLevelClass(TypeClass t) { ulong classoff = offset; // skip vtable-ptr and monitor if (t.sym.baseClass) - visitClass(cast(TypeClass)t.sym.baseClass.type); + visitTopLevelClass(t.sym.baseClass.type.isTypeClass()); foreach (v; t.sym.fields) { offset = classoff + v.offset; - v.type.accept(this); + visit(v.type); } offset = classoff; } - Array!(ulong)* data; - ulong offset; - ulong sz_size_t; - bool error; + visitTopLevelClass(tc); } - - scope PointerBitmapVisitor pbv = new PointerBitmapVisitor(data, sz_size_t); - if (t.ty == Tclass) - pbv.visitClass(cast(TypeClass)t); else - t.accept(pbv); - return pbv.error ? ulong.max : sz; + visit(t); + return error ? ulong.max : sz; } /** @@ -1314,6 +1276,19 @@ Expression semanticTraits(TraitsExp e, Scope* sc) return ErrorExp.get(); } + // https://issues.dlang.org/show_bug.cgi?id=19706 + // When getting the attributes of the instance of a + // templated member function semantic tiargs does + // not perform semantic3 on the instance. + // For more information see FuncDeclaration.functionSemantic. + // For getFunctionAttributes it is mandatory to do + // attribute inference. + if (fd && fd.parent && fd.parent.isTemplateInstance) + { + fd.functionSemantic3(); + tf = cast(TypeFunction)fd.type; + } + auto mods = new Expressions(); void addToMods(string str) @@ -1354,6 +1329,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) * "argptr" extern(D) void dstyle(...), use `__argptr` and `__arguments` * "stdarg" extern(C) void cstyle(int, ...), use core.stdc.stdarg * "typesafe" void typesafe(T[] ...) + * "KR" old K+R style */ // get symbol linkage as a string if (dim != 1) @@ -1388,6 +1364,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) case VarArg.variadic: style = (link == LINK.d) ? "argptr" : "stdarg"; break; + case VarArg.KRvariadic: style = "KR"; break; case VarArg.typesafe: style = "typesafe"; break; } auto se = new StringExp(e.loc, style); @@ -2246,65 +2223,65 @@ private void traitNotFound(TraitsExp e) // All possible traits __gshared Identifier*[59] idents = [ + &Id.allMembers, + &Id.child, + &Id.classInstanceAlignment, + &Id.classInstanceSize, + &Id.compiles, + &Id.derivedMembers, + &Id.fullyQualifiedName, + &Id.getAliasThis, + &Id.getAttributes, + &Id.getFunctionAttributes, + &Id.getFunctionVariadicStyle, + &Id.getLinkage, + &Id.getLocation, + &Id.getMember, + &Id.getOverloads, + &Id.getParameterStorageClasses, + &Id.getPointerBitmap, + &Id.getProtection, + &Id.getTargetInfo, + &Id.getUnitTests, + &Id.getVirtualFunctions, + &Id.getVirtualIndex, + &Id.getVirtualMethods, + &Id.getVisibility, + &Id.hasCopyConstructor, + &Id.hasMember, + &Id.hasPostblit, + &Id.identifier, &Id.isAbstractClass, + &Id.isAbstractFunction, &Id.isArithmetic, &Id.isAssociativeArray, - &Id.isDisabled, + &Id.isCopyable, &Id.isDeprecated, - &Id.isFuture, + &Id.isDisabled, &Id.isFinalClass, - &Id.isPOD, - &Id.isNested, + &Id.isFinalFunction, &Id.isFloating, + &Id.isFuture, &Id.isIntegral, - &Id.isScalar, - &Id.isStaticArray, - &Id.isUnsigned, - &Id.isVirtualFunction, - &Id.isVirtualMethod, - &Id.isAbstractFunction, - &Id.isFinalFunction, - &Id.isOverrideFunction, - &Id.isStaticFunction, + &Id.isLazy, &Id.isModule, + &Id.isNested, + &Id.isOut, + &Id.isOverrideFunction, &Id.isPackage, + &Id.isPOD, &Id.isRef, - &Id.isOut, - &Id.isLazy, &Id.isReturnOnStack, - &Id.hasMember, - &Id.identifier, - &Id.fullyQualifiedName, - &Id.getProtection, - &Id.getVisibility, - &Id.parent, - &Id.child, - &Id.getLinkage, - &Id.getMember, - &Id.getOverloads, - &Id.getVirtualFunctions, - &Id.getVirtualMethods, - &Id.classInstanceSize, - &Id.classInstanceAlignment, - &Id.allMembers, - &Id.derivedMembers, &Id.isSame, - &Id.compiles, - &Id.getAliasThis, - &Id.getAttributes, - &Id.getFunctionAttributes, - &Id.getFunctionVariadicStyle, - &Id.getParameterStorageClasses, - &Id.getUnitTests, - &Id.getVirtualIndex, - &Id.getPointerBitmap, + &Id.isScalar, + &Id.isStaticArray, + &Id.isStaticFunction, + &Id.isUnsigned, + &Id.isVirtualFunction, + &Id.isVirtualMethod, &Id.isZeroInit, - &Id.getTargetInfo, - &Id.getLocation, - &Id.hasPostblit, - &Id.hasCopyConstructor, - &Id.isCopyable, &Id.parameters, + &Id.parent, ]; StringTable!(bool)* stringTable = cast(StringTable!(bool)*) &traitsStringTable; diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d index 5844911..c588270 100644 --- a/gcc/d/dmd/transitivevisitor.d +++ b/gcc/d/dmd/transitivevisitor.d @@ -44,9 +44,9 @@ package mixin template ParseVisitMethods(AST) } } - override void visit(AST.CompileStatement s) + override void visit(AST.MixinStatement s) { - //printf("Visiting CompileStatement\n"); + //printf("Visiting MixinStatement\n"); visitArgs(s.exps.peekSlice()); } @@ -579,7 +579,7 @@ package mixin template ParseVisitMethods(AST) de.accept(this); } - override void visit(AST.CompileDeclaration d) + override void visit(AST.MixinDeclaration d) { //printf("Visiting compileDeclaration\n"); visitArgs(d.exps.peekSlice()); diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index c668199..f0decf2 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -290,6 +290,8 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb if (!sm) return helper3(); + if (sm.isAliasDeclaration) + sm.checkDeprecated(loc, sc); s = sm.toAlias(); } @@ -456,6 +458,17 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) return t.merge(); } + Type visitComplex(TypeBasic t) + { + if (!(sc.flags & SCOPE.Cfile)) + return visitType(t); + + auto tc = getComplexLibraryType(loc, sc, t.ty); + if (tc.ty == Terror) + return tc; + return tc.addMod(t.mod).merge(); + } + Type visitVector(TypeVector mtype) { const errors = global.errors; @@ -1185,19 +1198,31 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) // -preview=in: Always add `ref` when used with `extern(C++)` functions // Done here to allow passing opaque types with `in` - if (global.params.previewIn && (fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_) + if ((fparam.storageClass & (STC.in_ | STC.ref_)) == STC.in_) { switch (tf.linkage) { case LINK.cpp: - fparam.storageClass |= STC.ref_; + if (global.params.previewIn) + fparam.storageClass |= STC.ref_; break; case LINK.default_, LINK.d: break; default: - .error(loc, "cannot use `in` parameters with `extern(%s)` functions", - linkageToChars(tf.linkage)); - .errorSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars()); + if (global.params.previewIn) + { + .error(loc, "cannot use `in` parameters with `extern(%s)` functions", + linkageToChars(tf.linkage)); + .errorSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars()); + } + else + { + // Note that this deprecation will not trigger on `in ref` / `ref in` + // parameters, however the parser will trigger a deprecation on them. + .deprecation(loc, "using `in` parameters with `extern(%s)` functions is deprecated", + linkageToChars(tf.linkage)); + .deprecationSupplemental(loc, "parameter `%s` declared as `in` here", fparam.toChars()); + } break; } } @@ -1292,28 +1317,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) // error(loc, "inout on parameter means inout must be on return type as well (if from D1 code, replace with `ref`)"); } - /* Scope attribute is not necessary if the parameter type does not have pointers - */ - const sr = buildScopeRef(fparam.storageClass); - switch (sr) - { - case ScopeRef.Scope: - case ScopeRef.RefScope: - case ScopeRef.ReturnRef_Scope: - if (!fparam.type.hasPointers()) - fparam.storageClass &= ~STC.scope_; - break; - - case ScopeRef.ReturnScope: - case ScopeRef.Ref_ReturnScope: - if (!fparam.type.hasPointers()) - fparam.storageClass &= ~(STC.return_ | STC.scope_ | STC.returnScope); - break; - - default: - break; - } - // Remove redundant storage classes for type, they are already applied fparam.storageClass &= ~(STC.TYPECTOR); @@ -1786,12 +1789,14 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) case TOK.struct_: auto sd = new StructDeclaration(mtype.loc, mtype.id, false); + sd.alignment = mtype.packalign; declare(sd); mtype.resolved = visitStruct(new TypeStruct(sd)); break; case TOK.union_: auto ud = new UnionDeclaration(mtype.loc, mtype.id); + ud.alignment = mtype.packalign; declare(ud); mtype.resolved = visitStruct(new TypeStruct(ud)); break; @@ -1928,6 +1933,9 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) switch (type.ty) { default: return visitType(type); + case Tcomplex32: + case Tcomplex64: + case Tcomplex80: return visitComplex(type.isTypeBasic()); case Tvector: return visitVector(type.isTypeVector()); case Tsarray: return visitSArray(type.isTypeSArray()); case Tarray: return visitDArray(type.isTypeDArray()); @@ -2697,7 +2705,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type { void semanticOnMixin(Dsymbol member) { - if (auto compileDecl = member.isCompileDeclaration()) + if (auto compileDecl = member.isMixinDeclaration()) compileDecl.dsymbolSemantic(sc); else if (auto mixinTempl = member.isTemplateMixin()) mixinTempl.dsymbolSemantic(sc); @@ -2796,8 +2804,10 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type } mt.exp = exp2; - if (mt.exp.op == EXP.type || - mt.exp.op == EXP.scope_) + if ((mt.exp.op == EXP.type || mt.exp.op == EXP.scope_) && + // https://issues.dlang.org/show_bug.cgi?id=23863 + // compile time sequences are valid types + !mt.exp.type.isTypeTuple()) { if (!(sc.flags & SCOPE.Cfile) && // in (extended) C typeof may be used on types as with sizeof mt.exp.checkType()) @@ -3126,7 +3136,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type * Returns: * resulting expression with e.ident resolved */ -Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) +Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag flag) { Expression visitType(Type mt) { @@ -3624,7 +3634,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) * template opDispatch(name) if (isValid!name) { ... } */ uint errors = gagError ? global.startGagging() : 0; - e = dti.dotTemplateSemanticProp(sc, 0); + e = dti.dotTemplateSemanticProp(sc, DotExpFlag.none); if (gagError && global.endGagging(errors)) e = null; return returnExp(e); @@ -3730,6 +3740,9 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) { return noMember(mt, sc, e, ident, flag); } + // check before alias resolution; the alias itself might be deprecated! + if (s.isAliasDeclaration) + e.checkDeprecated(sc, s); s = s.toAlias(); if (auto em = s.isEnumMember()) @@ -3917,7 +3930,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) return mt.getProperty(sc, e.loc, ident, flag & 1); } - Expression res = mt.sym.getMemtype(Loc.initial).dotExp(sc, e, ident, 1); + Expression res = mt.sym.getMemtype(Loc.initial).dotExp(sc, e, ident, DotExpFlag.gag); if (!(flag & 1) && !res) { if (auto ns = mt.sym.search_correct(ident)) @@ -4599,6 +4612,74 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi } } + +/********************************************** + * Extract complex type from core.stdc.config + * Params: + * loc = for error messages + * sc = context + * ty = a complex or imaginary type + * Returns: + * Complex!float, Complex!double, Complex!real or null for error + */ + +Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty) +{ + // singleton + __gshared Type complex_float; + __gshared Type complex_double; + __gshared Type complex_real; + + Type* pt; + Identifier id; + switch (ty) + { + case Timaginary32: + case Tcomplex32: id = Id.c_complex_float; pt = &complex_float; break; + case Timaginary64: + case Tcomplex64: id = Id.c_complex_double; pt = &complex_double; break; + case Timaginary80: + case Tcomplex80: id = Id.c_complex_real; pt = &complex_real; break; + default: + return Type.terror; + } + + if (*pt) + return *pt; + *pt = Type.terror; + + Module mConfig = Module.loadCoreStdcConfig(); + if (!mConfig) + { + error(loc, "`core.stdc.config` is required for complex numbers"); + return *pt; + } + + Dsymbol s = mConfig.searchX(Loc.initial, sc, id, IgnorePrivateImports); + if (!s) + { + error(loc, "`%s` not found in core.stdc.config", id.toChars()); + return *pt; + } + s = s.toAlias(); + if (auto t = s.getType()) + { + if (auto ts = t.toBasetype().isTypeStruct()) + { + *pt = ts; + return ts; + } + } + if (auto sd = s.isStructDeclaration()) + { + *pt = sd.type; + return sd.type; + } + + error(loc, "`%s` must be an alias for a complex struct", s.toChars()); + return *pt; +} + /******************************* Private *****************************************/ private: @@ -4909,7 +4990,7 @@ Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id) * Return: * null if error, else RootObject AST as parsed */ -RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc) +RootObject compileTypeMixin(TypeMixin tm, ref const Loc loc, Scope* sc) { OutBuffer buf; if (expressionsToString(buf, sc, tm.exps)) @@ -4919,7 +5000,10 @@ RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc) const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink); + const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput; + auto locm = adjustLocForMixin(str, loc, global.params.mixinOut); + scope p = new Parser!ASTCodegen(locm, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests); + p.transitionIn = global.params.vin; p.nextToken(); //printf("p.loc.linnum = %d\n", p.loc.linnum); diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d index 38a39b4..4f87d92 100644 --- a/gcc/d/dmd/typinf.d +++ b/gcc/d/dmd/typinf.d @@ -47,6 +47,7 @@ extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope { if (!global.params.useTypeInfo) { + global.gag = 0; if (e) .error(loc, "expression `%s` uses the GC and cannot be used with switch `-betterC`", e.toChars()); else diff --git a/gcc/d/dmd/visitor.d b/gcc/d/dmd/visitor.d index 8990ce4..7b059a0 100644 --- a/gcc/d/dmd/visitor.d +++ b/gcc/d/dmd/visitor.d @@ -89,6 +89,7 @@ public: void visit(ASTCodegen.ClassReferenceExp e) { visit(cast(ASTCodegen.Expression)e); } void visit(ASTCodegen.VoidInitExp e) { visit(cast(ASTCodegen.Expression)e); } void visit(ASTCodegen.ThrownExceptionExp e) { visit(cast(ASTCodegen.Expression)e); } + void visit(ASTCodegen.LoweredAssignExp e) { visit(cast(ASTCodegen.AssignExp)e); } } /** @@ -152,7 +153,7 @@ extern (C++) class SemanticTimeTransitiveVisitor : SemanticTimePermissiveVisitor // need to avoid infinite recursion. if (!(e.stageflags & stageToCBuffer)) { - int old = e.stageflags; + const old = e.stageflags; e.stageflags |= stageToCBuffer; foreach (el; *e.elements) if (el) @@ -240,6 +241,12 @@ extern (C++) class SemanticTimeTransitiveVisitor : SemanticTimePermissiveVisitor e.e1.accept(this); e.e2.accept(this); } + + override void visit(ASTCodegen.LoweredAssignExp e) + { + e.lowering.accept(this); + visit(cast(AssignExp)e); + } } extern (C++) class StoppableVisitor : Visitor diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h index ed9f9ce..3d8c3e6 100644 --- a/gcc/d/dmd/visitor.h +++ b/gcc/d/dmd/visitor.h @@ -17,7 +17,7 @@ class ErrorStatement; class PeelStatement; class ExpStatement; class DtorExpStatement; -class CompileStatement; +class MixinStatement; class CompoundStatement; class CompoundDeclarationStatement; class UnrolledLoopStatement; @@ -110,7 +110,7 @@ class AnonDeclaration; class PragmaDeclaration; class ConditionalDeclaration; class StaticIfDeclaration; -class CompileDeclaration; +class MixinDeclaration; class StaticForeachDeclaration; class UserAttributeDeclaration; class ForwardingAttribDeclaration; @@ -268,6 +268,7 @@ class UshrAssignExp; class CatAssignExp; class CatElemAssignExp; class CatDcharAssignExp; +class LoweredAssignExp; class AddExp; class MinExp; class CatExp; @@ -365,7 +366,7 @@ public: virtual void visit(SharedStaticDtorDeclaration *s) { visit((StaticDtorDeclaration *)s); } // AttribDeclarations - virtual void visit(CompileDeclaration *s) { visit((AttribDeclaration *)s); } + virtual void visit(MixinDeclaration *s) { visit((AttribDeclaration *)s); } virtual void visit(UserAttributeDeclaration *s) { visit((AttribDeclaration *)s); } virtual void visit(LinkDeclaration *s) { visit((AttribDeclaration *)s); } virtual void visit(AnonDeclaration *s) { visit((AttribDeclaration *)s); } @@ -396,7 +397,7 @@ public: virtual void visit(ReturnStatement *s) { visit((Statement *)s); } virtual void visit(LabelStatement *s) { visit((Statement *)s); } virtual void visit(StaticAssertStatement *s) { visit((Statement *)s); } - virtual void visit(CompileStatement *s) { visit((Statement *)s); } + virtual void visit(MixinStatement *s) { visit((Statement *)s); } virtual void visit(WhileStatement *s) { visit((Statement *)s); } virtual void visit(ForStatement *s) { visit((Statement *)s); } virtual void visit(DoStatement *s) { visit((Statement *)s); } @@ -659,6 +660,7 @@ public: virtual void visit(ClassReferenceExp *e) { visit((Expression *)e); } virtual void visit(VoidInitExp *e) { visit((Expression *)e); } virtual void visit(ThrownExceptionExp *e) { visit((Expression *)e); } + virtual void visit(LoweredAssignExp *e) { visit((AssignExp *)e); } }; class StoppableVisitor : public Visitor diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index aeafe43..23f2f0b 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -693,78 +693,22 @@ public: void visit (CatExp *e) final override { - Type *tb1 = e->e1->type->toBasetype (); - Type *tb2 = e->e2->type->toBasetype (); - Type *etype; - - if (tb1->ty == TY::Tarray || tb1->ty == TY::Tsarray) - etype = tb1->nextOf (); - else - etype = tb2->nextOf (); - - tree result; - - if (e->e1->op == EXP::concatenate) + /* This error is only emitted during the code generation pass because + concatentation is allowed in CTFE. */ + if (global.params.betterC) { - /* Flatten multiple concatenations to an array. - So the expression ((a ~ b) ~ c) becomes [a, b, c] */ - int ndims = 2; - - for (Expression *ex = e->e1; ex->op == EXP::concatenate;) - { - if (ex->op == EXP::concatenate) - { - ex = ex->isCatExp ()->e1; - ndims++; - } - } - - /* Store all concatenation args to a temporary byte[][ndims] array. */ - Type *targselem = Type::tint8->arrayOf (); - tree var = build_local_temp (make_array_type (targselem, ndims)); - - /* Loop through each concatenation from right to left. */ - vec <constructor_elt, va_gc> *elms = NULL; - CatExp *ce = e; - int dim = ndims - 1; - - for (Expression *oe = ce->e2; oe != NULL; - (ce->e1->op != EXP::concatenate - ? (oe = ce->e1) - : (ce = ce->e1->isCatExp (), oe = ce->e2))) - { - tree arg = d_array_convert (etype, oe); - tree index = size_int (dim); - CONSTRUCTOR_APPEND_ELT (elms, index, d_save_expr (arg)); - - /* Finished pushing all arrays. */ - if (oe == ce->e1) - break; - - dim -= 1; - } - - /* Check there is no logic bug in constructing byte[][] of arrays. */ - gcc_assert (dim == 0); - tree init = build_constructor (TREE_TYPE (var), elms); - var = compound_expr (modify_expr (var, init), var); - - tree arrs = d_array_value (build_ctype (targselem->arrayOf ()), - size_int (ndims), build_address (var)); - - result = build_libcall (LIBCALL_ARRAYCATNTX, e->type, 2, - build_typeinfo (e, e->type), arrs); - } - else - { - /* Handle single concatenation (a ~ b). */ - result = build_libcall (LIBCALL_ARRAYCATT, e->type, 3, - build_typeinfo (e, e->type), - d_array_convert (etype, e->e1), - d_array_convert (etype, e->e2)); + error_at (make_location_t (e->loc), + "array concatenation of expression %qs requires the GC and " + "cannot be used with %<-fno-druntime%>", e->toChars ()); + this->result_ = error_mark_node; + return; } - this->result_ = result; + /* All concat expressions should have been rewritten to `_d_arraycatnTX` in + the semantic phase. */ + gcc_assert (e->lowering); + + this->result_ = build_expr (e->lowering); } /* Build an assignment operator expression. The right operand is implicitly @@ -1150,6 +1094,13 @@ public: this->result_ = build_assign (modifycode, t1, t2); } + /* Build an assignment expression that has been lowered in the front-end. */ + + void visit (LoweredAssignExp *e) final override + { + this->result_ = build_expr (e->lowering); + } + /* Build a throw expression. */ void visit (ThrowExp *e) final override @@ -2828,7 +2779,7 @@ public: /* Building sinit trees are delayed until after frontend semantic processing has complete. Build the static initializer now. */ - if (e->useStaticInit && !this->constp_) + if (e->useStaticInit && !this->constp_ && !e->sd->isCsymbol ()) { tree init = aggregate_initializer_decl (e->sd); diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def index 23f8b64..fd83cc9 100644 --- a/gcc/d/runtime.def +++ b/gcc/d/runtime.def @@ -112,13 +112,6 @@ DEF_D_RUNTIME (ALLOCMEMORY, "_d_allocmemory", RT(VOIDPTR), P1(SIZE_T), DEF_D_RUNTIME (ARRAYCOPY, "_d_arraycopy", RT(ARRAY_VOID), P3(SIZE_T, ARRAY_VOID, ARRAY_VOID), 0) -/* Used for concatenating two or more arrays together. Then `n' variant is - for when there is more than two arrays to handle. */ -DEF_D_RUNTIME (ARRAYCATT, "_d_arraycatT", RT(ARRAY_BYTE), - P3(CONST_TYPEINFO, ARRAY_BYTE, ARRAY_BYTE), 0) -DEF_D_RUNTIME (ARRAYCATNTX, "_d_arraycatnTX", RT(ARRAY_VOID), - P2(CONST_TYPEINFO, ARRAYARRAY_BYTE), 0) - /* Used for appending a single element to an array. */ DEF_D_RUNTIME (ARRAYAPPENDCTX, "_d_arrayappendcTX", RT(ARRAY_BYTE), P3(CONST_TYPEINFO, ARRAYPTR_BYTE, SIZE_T), 0) diff --git a/gcc/testsuite/gdc.dg/nogc1.d b/gcc/testsuite/gdc.dg/nogc1.d new file mode 100644 index 0000000..2894ef0 --- /dev/null +++ b/gcc/testsuite/gdc.dg/nogc1.d @@ -0,0 +1,8 @@ +// { dg-do compile } +// { dg-options "-fno-druntime" } +// { dg-shouldfail "expressions depend on GC" } + +string testConcat(string a, string b) +{ + return a ~ b; // { dg-error "requires the GC and cannot be used with .-fno-druntime." } +} diff --git a/gcc/testsuite/gdc.dg/rtti1.d b/gcc/testsuite/gdc.dg/rtti1.d index ed5f344..29b8265 100644 --- a/gcc/testsuite/gdc.dg/rtti1.d +++ b/gcc/testsuite/gdc.dg/rtti1.d @@ -11,8 +11,3 @@ bool testAAEqual(int[string] aa1, int[string] aa2) { return aa1 == aa2; // { dg-error "requires .object.TypeInfo. and cannot be used with .-fno-rtti." } } - -string testConcat(string a, string b) -{ - return a ~ b; // { dg-error "requires .object.TypeInfo. and cannot be used with .-fno-rtti." } -} diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d index 870387c..0436371 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_CPPNamespaceDeclaration.d @@ -48,7 +48,7 @@ namespace nameSpace extern void fn2(); } - extern double identity(double _param_0); + extern double identity(double __param_0_); } --- @@ -63,5 +63,5 @@ extern(C++, "nameSpace") void fn2() {} } - double identity(double) { return _param_0; } + double identity(double) { return __param_0; } } diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_functions.d b/gcc/testsuite/gdc.test/compilable/dtoh_functions.d index 1feff40..38607f6 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_functions.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_functions.d @@ -159,7 +159,7 @@ extern int32_t(*f)(int32_t ); extern void special(int32_t a = ptr->i, int32_t b = ptr->get(1, 2), int32_t j = (*f)(1)); -extern void variadic(int32_t _param_0, ...); +extern void variadic(int32_t __param_0_, ...); --- +/ diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d b/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d index b8e8d05..a8f5b99 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_invalid_identifiers.d @@ -110,7 +110,7 @@ struct InvalidNames final } }; -extern void useInvalid(InvalidNames<int32_t > _param_0); +extern void useInvalid(InvalidNames<int32_t > __param_0_); extern size_t offsetof(); diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d b/gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d index 37b4507..ee86a5e 100644 --- a/gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d +++ b/gcc/testsuite/gdc.test/compilable/dtoh_special_enum.d @@ -40,25 +40,25 @@ struct _d_dynamicArray final #endif enum class __c_not_special; -extern "C" void fn_long(long _param_0); +extern "C" void fn_long(long __param_0_); -extern "C" void fn_ulong(unsigned long _param_0); +extern "C" void fn_ulong(unsigned long __param_0_); -extern "C" void fn_longlong(long long _param_0); +extern "C" void fn_longlong(long long __param_0_); -extern "C" void fn_ulonglong(unsigned long long _param_0); +extern "C" void fn_ulonglong(unsigned long long __param_0_); -extern "C" void fn_long_double(long double _param_0); +extern "C" void fn_long_double(long double __param_0_); -extern "C" void fn_wchar_t(wchar_t _param_0); +extern "C" void fn_wchar_t(wchar_t __param_0_); -extern "C" void fn_complex_float(_Complex float _param_0); +extern "C" void fn_complex_float(_Complex float __param_0_); -extern "C" void fn_complex_double(_Complex double _param_0); +extern "C" void fn_complex_double(_Complex double __param_0_); -extern "C" void fn_complex_real(_Complex long double _param_0); +extern "C" void fn_complex_real(_Complex long double __param_0_); -extern "C" void fn_not_special(__c_not_special _param_0); +extern "C" void fn_not_special(__c_not_special __param_0_); --- +/ diff --git a/gcc/testsuite/gdc.test/compilable/imports/c23789.i b/gcc/testsuite/gdc.test/compilable/imports/c23789.i new file mode 100644 index 0000000..74d7e80 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/c23789.i @@ -0,0 +1,31 @@ +// https://issues.dlang.org/show_bug.cgi?id=23789 + +struct __declspec(align(64)) M128A { + char c; +}; + +typedef struct __declspec(align(32)) _M128B { + int x; +} M128B, *PM128A; + + +void testpl(p) +struct __declspec(align(2)) S *p; +{ +} + +///// + +struct __attribute__((aligned(64))) N128A { + char c; +}; + +typedef struct __attribute__((aligned(32))) _N128B { + int x; +} N128B, *PN128A; + + +void testpl2(p) +struct __attribute__((aligned(2))) S *p; +{ +} diff --git a/gcc/testsuite/gdc.test/compilable/interpret3.d b/gcc/testsuite/gdc.test/compilable/interpret3.d index 2c9a84e..1414263 100644 --- a/gcc/testsuite/gdc.test/compilable/interpret3.d +++ b/gcc/testsuite/gdc.test/compilable/interpret3.d @@ -7208,7 +7208,7 @@ struct S13630(T) { T[3] arr; - this(A...)(auto ref in A args) + this(A...)(const auto ref A args) { auto p = arr.ptr; @@ -7238,7 +7238,7 @@ struct Matrix13827(T, uint N) T[N] flat; } - this(A...)(auto ref in A args) + this(A...)(const auto ref A args) { uint k; diff --git a/gcc/testsuite/gdc.test/compilable/test18493.d b/gcc/testsuite/gdc.test/compilable/test18493.d new file mode 100644 index 0000000..558bf44 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test18493.d @@ -0,0 +1,19 @@ +// https://issues.dlang.org/show_bug.cgi?id=18493 +// REQUIRED_ARGS: -betterC + +struct S +{ + this(this) + { + } + + ~this() + { + } +} + +struct C +{ + S s1; + S s2; +} diff --git a/gcc/testsuite/gdc.test/runnable/test19688.d b/gcc/testsuite/gdc.test/compilable/test19688.d index 9cc4dd7..9cc4dd7 100644 --- a/gcc/testsuite/gdc.test/runnable/test19688.d +++ b/gcc/testsuite/gdc.test/compilable/test19688.d diff --git a/gcc/testsuite/gdc.test/compilable/test21667.d b/gcc/testsuite/gdc.test/compilable/test21667.d new file mode 100644 index 0000000..6d83dc0 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test21667.d @@ -0,0 +1,19 @@ +// Issue 21667 - scope parameter causes 'no size because of forward references' +// https://issues.dlang.org/show_bug.cgi?id=21667 +@safe: + +struct Foo +{ + void delegate(scope Foo) dg; +} + +struct M +{ + F.Type f; +} + +struct F +{ + enum Type {a} + void foo(scope M m) {} +} diff --git a/gcc/testsuite/gdc.test/compilable/test23789.d b/gcc/testsuite/gdc.test/compilable/test23789.d new file mode 100644 index 0000000..ddf7351 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23789.d @@ -0,0 +1,12 @@ +// https://issues.dlang.org/show_bug.cgi?id=23789 +// EXTRA_FILES: imports/c23789.i + +import imports.c23789; + +static assert(M128A.alignof == 64); +static assert(_M128B.alignof == 32); +static assert(M128B.alignof == 32); + +static assert(N128A.alignof == 64); +static assert(_N128B.alignof == 32); +static assert(N128B.alignof == 32); diff --git a/gcc/testsuite/gdc.test/compilable/test23862.d b/gcc/testsuite/gdc.test/compilable/test23862.d new file mode 100644 index 0000000..c5b063b --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23862.d @@ -0,0 +1,15 @@ +// https://issues.dlang.org/show_bug.cgi?id=23862 + +enum E { A, B } + +void test(E e) +{ + with (e) + switch (e) + { + case A: + case B: + default: + break; + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test23863.d b/gcc/testsuite/gdc.test/compilable/test23863.d new file mode 100644 index 0000000..c3941ce --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23863.d @@ -0,0 +1,15 @@ +// https://issues.dlang.org/show_bug.cgi?id=23863 + +alias AliasSeq(T...) = T; + +struct S +{ +} +alias Empty = S.tupleof; +Empty x; // accepts valid + +static assert(is(typeof(x))); +static assert(is(typeof(Empty))); +static assert(is(typeof(AliasSeq!(int)))); +static assert(is(typeof(Empty) == AliasSeq!())); +static assert(is(typeof(AliasSeq!()) == AliasSeq!())); diff --git a/gcc/testsuite/gdc.test/compilable/traits_getFunctionAttributes.d b/gcc/testsuite/gdc.test/compilable/traits_getFunctionAttributes.d index 1f25b26..f4defb4 100644 --- a/gcc/testsuite/gdc.test/compilable/traits_getFunctionAttributes.d +++ b/gcc/testsuite/gdc.test/compilable/traits_getFunctionAttributes.d @@ -1,9 +1,10 @@ module traits_getFunctionAttributes; +alias tuple(T...) = T; + void test_getFunctionAttributes() { - alias tuple(T...) = T; struct S { @@ -118,3 +119,14 @@ void test_getFunctionAttributes() static assert(__traits(getFunctionAttributes, systemDel) == tuple!("pure", "nothrow", "@nogc", "@system")); static assert(__traits(getFunctionAttributes, typeof(systemDel)) == tuple!("pure", "nothrow", "@nogc", "@system")); } + +void bug19706() +{ + struct S + { + static int fImpl(Ret)() { return Ret.init; } + + // tells us: `fImpl!int` is @system + static assert(__traits(getFunctionAttributes, fImpl!int) == tuple!("pure", "nothrow", "@nogc", "@safe")); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/user_defined_attributes.d b/gcc/testsuite/gdc.test/compilable/user_defined_attributes.d new file mode 100644 index 0000000..169ca49 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/user_defined_attributes.d @@ -0,0 +1,22 @@ + +enum Test; + +@true @null @byte int x; +@(int) int y; +@"test" @`test2` @30 @'a' @__LINE__ void f(); + +@Test void h(); + +static assert( __traits(getAttributes, x)[0] == true); +static assert( __traits(getAttributes, x)[1] == null); +static assert(is(__traits(getAttributes, x)[2] == byte)); + +static assert(is(__traits(getAttributes, y)[0] == int)); + +static assert( __traits(getAttributes, f)[0] == "test"); +static assert( __traits(getAttributes, f)[1] == "test2"); +static assert( __traits(getAttributes, f)[2] == 30); +static assert( __traits(getAttributes, f)[3] == 'a'); +static assert( __traits(getAttributes, f)[4] == 6); + +static assert(is(__traits(getAttributes, h)[0] == enum)); diff --git a/gcc/testsuite/gdc.test/compilable/warn3882.d b/gcc/testsuite/gdc.test/compilable/warn3882.d index f02a87b..0474315 100644 --- a/gcc/testsuite/gdc.test/compilable/warn3882.d +++ b/gcc/testsuite/gdc.test/compilable/warn3882.d @@ -12,7 +12,7 @@ void test3882() /******************************************/ // https://issues.dlang.org/show_bug.cgi?id=12619 -extern (C) @system nothrow pure void* memcpy(void* s1, in void* s2, size_t n); +extern (C) @system nothrow pure void* memcpy(void* s1, const void* s2, size_t n); // -> weakly pure void test12619() pure @@ -64,7 +64,7 @@ void test12909() const struct Foo13899 { - int opApply(immutable int delegate(in ref int) pure nothrow dg) pure nothrow + int opApply(immutable int delegate(const ref int) pure nothrow dg) pure nothrow { return 1; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d index 8360e1a..523a183 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d +++ b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic.d @@ -4,15 +4,15 @@ TEST_OUTPUT: fail_compilation/attributediagnostic.d(24): Error: `@safe` function `attributediagnostic.layer2` cannot call `@system` function `attributediagnostic.layer1` fail_compilation/attributediagnostic.d(26): which calls `attributediagnostic.layer0` fail_compilation/attributediagnostic.d(28): which calls `attributediagnostic.system` -fail_compilation/attributediagnostic.d(30): which was inferred `@system` because of: +fail_compilation/attributediagnostic.d(30): which wasn't inferred `@safe` because of: fail_compilation/attributediagnostic.d(30): `asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not fail_compilation/attributediagnostic.d(25): `attributediagnostic.layer1` is declared here fail_compilation/attributediagnostic.d(46): Error: `@safe` function `D main` cannot call `@system` function `attributediagnostic.system1` -fail_compilation/attributediagnostic.d(35): which was inferred `@system` because of: +fail_compilation/attributediagnostic.d(35): which wasn't inferred `@safe` because of: fail_compilation/attributediagnostic.d(35): cast from `uint` to `int*` not allowed in safe code fail_compilation/attributediagnostic.d(33): `attributediagnostic.system1` is declared here fail_compilation/attributediagnostic.d(47): Error: `@safe` function `D main` cannot call `@system` function `attributediagnostic.system2` -fail_compilation/attributediagnostic.d(41): which was inferred `@system` because of: +fail_compilation/attributediagnostic.d(41): which wasn't inferred `@safe` because of: fail_compilation/attributediagnostic.d(41): `@safe` function `system2` cannot call `@system` `fsys` fail_compilation/attributediagnostic.d(39): `attributediagnostic.system2` is declared here --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_nogc.d b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_nogc.d new file mode 100644 index 0000000..e3dbee8 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_nogc.d @@ -0,0 +1,56 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/attributediagnostic_nogc.d(21): Error: `@nogc` function `attributediagnostic_nogc.layer2` cannot call non-@nogc function `attributediagnostic_nogc.layer1` +fail_compilation/attributediagnostic_nogc.d(22): which calls `attributediagnostic_nogc.layer0` +fail_compilation/attributediagnostic_nogc.d(23): which calls `attributediagnostic_nogc.gc` +fail_compilation/attributediagnostic_nogc.d(27): which wasn't inferred `@nogc` because of: +fail_compilation/attributediagnostic_nogc.d(27): `asm` statement in function `attributediagnostic_nogc.gc` is assumed to use the GC - mark it with `@nogc` if it does not +fail_compilation/attributediagnostic_nogc.d(43): Error: `@nogc` function `D main` cannot call non-@nogc function `attributediagnostic_nogc.gc1` +fail_compilation/attributediagnostic_nogc.d(32): which wasn't inferred `@nogc` because of: +fail_compilation/attributediagnostic_nogc.d(32): cannot use `new` in `@nogc` function `attributediagnostic_nogc.gc1` +fail_compilation/attributediagnostic_nogc.d(44): Error: `@nogc` function `D main` cannot call non-@nogc function `attributediagnostic_nogc.gc2` +fail_compilation/attributediagnostic_nogc.d(38): which wasn't inferred `@nogc` because of: +fail_compilation/attributediagnostic_nogc.d(38): `@nogc` function `attributediagnostic_nogc.gc2` cannot call non-@nogc `fgc` +fail_compilation/attributediagnostic_nogc.d(45): Error: `@nogc` function `D main` cannot call non-@nogc function `attributediagnostic_nogc.gcClosure` +fail_compilation/attributediagnostic_nogc.d(48): which wasn't inferred `@nogc` because of: +fail_compilation/attributediagnostic_nogc.d(48): function `attributediagnostic_nogc.gcClosure` is `@nogc` yet allocates closure for `gcClosure()` with the GC +--- +*/ +#line 18 +// Issue 17374 - Improve inferred attribute error message +// https://issues.dlang.org/show_bug.cgi?id=17374 + +auto layer2() @nogc { layer1(); } +auto layer1() { layer0(); } +auto layer0() { gc(); } + +auto gc() +{ + asm {} +} + +auto gc1() +{ + int* x = new int; +} + +auto fgc = function void() {new int[10];}; +auto gc2() +{ + fgc(); +} + +void main() @nogc +{ + gc1(); + gc2(); + gcClosure(); +} + +auto gcClosure() +{ + int x; + int bar() { return x; } + return &bar; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_nothrow.d b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_nothrow.d new file mode 100644 index 0000000..7fea322 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_nothrow.d @@ -0,0 +1,45 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/attributediagnostic_nothrow.d(21): Error: function `attributediagnostic_nothrow.layer1` is not `nothrow` +fail_compilation/attributediagnostic_nothrow.d(22): which calls `attributediagnostic_nothrow.layer0` +fail_compilation/attributediagnostic_nothrow.d(23): which calls `attributediagnostic_nothrow.gc` +fail_compilation/attributediagnostic_nothrow.d(27): which wasn't inferred `nothrow` because of: +fail_compilation/attributediagnostic_nothrow.d(27): `asm` statement is assumed to throw - mark it with `nothrow` if it does not +fail_compilation/attributediagnostic_nothrow.d(21): Error: function `attributediagnostic_nothrow.layer2` may throw but is marked as `nothrow` +fail_compilation/attributediagnostic_nothrow.d(43): Error: function `attributediagnostic_nothrow.gc1` is not `nothrow` +fail_compilation/attributediagnostic_nothrow.d(32): which wasn't inferred `nothrow` because of: +fail_compilation/attributediagnostic_nothrow.d(32): `object.Exception` is thrown but not caught +fail_compilation/attributediagnostic_nothrow.d(44): Error: function `attributediagnostic_nothrow.gc2` is not `nothrow` +fail_compilation/attributediagnostic_nothrow.d(41): Error: function `D main` may throw but is marked as `nothrow` +--- +*/ + +// Issue 17374 - Improve inferred attribute error message +// https://issues.dlang.org/show_bug.cgi?id=17374 + +auto layer2() nothrow { layer1(); } +auto layer1() { layer0(); } +auto layer0() { gc(); } + +auto gc() +{ + asm {} +} + +auto gc1() +{ + throw new Exception("msg"); +} + +auto fgc = function void() {throw new Exception("msg");}; +auto gc2() +{ + fgc(); +} + +void main() nothrow +{ + gc1(); + gc2(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_pure.d b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_pure.d new file mode 100644 index 0000000..a120dab --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/attributediagnostic_pure.d @@ -0,0 +1,21 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/attributediagnostic_pure.d(20): Error: `pure` function `D main` cannot call impure function `attributediagnostic_pure.gc` +fail_compilation/attributediagnostic_pure.d(15): which wasn't inferred `pure` because of: +fail_compilation/attributediagnostic_pure.d(15): `asm` statement is assumed to be impure - mark it with `pure` if it is not +--- +*/ + +// Issue 17374 - Improve inferred attribute error message +// https://issues.dlang.org/show_bug.cgi?id=17374 + +auto gc() +{ + asm {} +} + +void main() pure +{ + gc(); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d index c980d76..802d1c2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d +++ b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d @@ -66,8 +66,8 @@ fail_compilation/bug9631.d(79): Error: function `bug9631.arg.f(int i, S s)` is n fail_compilation/bug9631.d(79): cannot pass argument `y` of type `bug9631.tem!().S` to parameter `bug9631.S s` fail_compilation/bug9631.d(80): Error: function literal `__lambda4(S s)` is not callable using argument types `(S)` fail_compilation/bug9631.d(80): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S s` -fail_compilation/bug9631.d(86): Error: constructor `bug9631.arg.A.this(S _param_0)` is not callable using argument types `(S)` -fail_compilation/bug9631.d(86): cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `bug9631.S _param_0` +fail_compilation/bug9631.d(86): Error: constructor `bug9631.arg.A.this(S __param_0)` is not callable using argument types `(S)` +fail_compilation/bug9631.d(86): cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `bug9631.S __param_0` --- */ void arg() @@ -89,8 +89,8 @@ void arg() /* TEST_OUTPUT: --- -fail_compilation/bug9631.d(106): Error: function `bug9631.targ.ft!().ft(S _param_0)` is not callable using argument types `(S)` -fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S _param_0` +fail_compilation/bug9631.d(106): Error: function `bug9631.targ.ft!().ft(S __param_0)` is not callable using argument types `(S)` +fail_compilation/bug9631.d(106): cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S __param_0` fail_compilation/bug9631.d(107): Error: none of the overloads of template `bug9631.targ.ft` are callable using argument types `!()(S)` fail_compilation/bug9631.d(105): Candidate is: `ft()(tem!().S)` fail_compilation/bug9631.d(109): Error: none of the overloads of template `bug9631.targ.ft2` are callable using argument types `!()(S, int)` diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfeblock.d b/gcc/testsuite/gdc.test/fail_compilation/ctfeblock.d index 2d8bf7a..9c90103 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ctfeblock.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ctfeblock.d @@ -19,7 +19,7 @@ struct T { } { L1: new T(); - a = 3; + a = 3; } goto L1; } @@ -31,3 +31,14 @@ L1: new T(); } } + +@nogc void test3() +{ + if (!__ctfe) + { + } + else + { + int* p = new int; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecatedinref.d b/gcc/testsuite/gdc.test/fail_compilation/deprecatedinref.d new file mode 100644 index 0000000..20c3666 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/deprecatedinref.d @@ -0,0 +1,10 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/deprecatedinref.d(9): Deprecation: using `in ref` is deprecated, use `-preview=in` and `in` instead +fail_compilation/deprecatedinref.d(10): Deprecation: using `ref in` is deprecated, use `-preview=in` and `in` instead +--- +*/ +void foo(in ref int); +void foor(ref in int); diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecations_preview_in.d b/gcc/testsuite/gdc.test/fail_compilation/deprecations_preview_in.d new file mode 100644 index 0000000..33cc904 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/deprecations_preview_in.d @@ -0,0 +1,11 @@ +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/deprecations_preview_in.d(1): Deprecation: using `in` parameters with `extern(C)` functions is deprecated +fail_compilation/deprecations_preview_in.d(1): parameter `__anonymous_param` declared as `in` here +--- +*/ + +#line 1 +extern(C) void fun1(in char*); diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10319.d b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d index 7b2eca7..efc818f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag10319.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d @@ -1,17 +1,21 @@ /* TEST_OUTPUT: --- -fail_compilation/diag10319.d(29): Error: `pure` function `D main` cannot call impure function `diag10319.foo` -fail_compilation/diag10319.d(29): Error: `@safe` function `D main` cannot call `@system` function `diag10319.foo` -fail_compilation/diag10319.d(18): `diag10319.foo` is declared here -fail_compilation/diag10319.d(30): Error: `pure` function `D main` cannot call impure function `diag10319.bar!int.bar` -fail_compilation/diag10319.d(30): Error: `@safe` function `D main` cannot call `@system` function `diag10319.bar!int.bar` -fail_compilation/diag10319.d(23): which was inferred `@system` because of: -fail_compilation/diag10319.d(23): cannot take address of local `x` in `@safe` function `bar` -fail_compilation/diag10319.d(20): `diag10319.bar!int.bar` is declared here -fail_compilation/diag10319.d(29): Error: function `diag10319.foo` is not `nothrow` -fail_compilation/diag10319.d(30): Error: function `diag10319.bar!int.bar` is not `nothrow` -fail_compilation/diag10319.d(27): Error: function `D main` may throw but is marked as `nothrow` +fail_compilation/diag10319.d(33): Error: `pure` function `D main` cannot call impure function `diag10319.foo` +fail_compilation/diag10319.d(33): Error: `@safe` function `D main` cannot call `@system` function `diag10319.foo` +fail_compilation/diag10319.d(22): `diag10319.foo` is declared here +fail_compilation/diag10319.d(34): Error: `pure` function `D main` cannot call impure function `diag10319.bar!int.bar` +fail_compilation/diag10319.d(26): which wasn't inferred `pure` because of: +fail_compilation/diag10319.d(26): `pure` function `diag10319.bar!int.bar` cannot access mutable static data `g` +fail_compilation/diag10319.d(34): Error: `@safe` function `D main` cannot call `@system` function `diag10319.bar!int.bar` +fail_compilation/diag10319.d(27): which wasn't inferred `@safe` because of: +fail_compilation/diag10319.d(27): cannot take address of local `x` in `@safe` function `bar` +fail_compilation/diag10319.d(24): `diag10319.bar!int.bar` is declared here +fail_compilation/diag10319.d(33): Error: function `diag10319.foo` is not `nothrow` +fail_compilation/diag10319.d(34): Error: function `diag10319.bar!int.bar` is not `nothrow` +fail_compilation/diag10319.d(28): which wasn't inferred `nothrow` because of: +fail_compilation/diag10319.d(28): `object.Exception` is thrown but not caught +fail_compilation/diag10319.d(31): Error: function `D main` may throw but is marked as `nothrow` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10415.d b/gcc/testsuite/gdc.test/fail_compilation/diag10415.d index 1fde171..207f6a4 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag10415.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag10415.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/diag10415.d(36): Error: none of the overloads of `x` are callable using argument types `(int) const` fail_compilation/diag10415.d(13): Candidates are: `diag10415.C.x()` -fail_compilation/diag10415.d(18): `diag10415.C.x(int _param_0)` +fail_compilation/diag10415.d(18): `diag10415.C.x(int __param_0)` fail_compilation/diag10415.d(39): Error: d.x is not an lvalue --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11769.d b/gcc/testsuite/gdc.test/fail_compilation/diag11769.d index 2717de4..75047f5 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag11769.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag11769.d @@ -2,9 +2,9 @@ TEST_OUTPUT: --- fail_compilation/diag11769.d(18): Error: `diag11769.foo!string.bar` called with argument types `(string)` matches both: -fail_compilation/diag11769.d(13): `diag11769.foo!string.bar(wstring _param_0)` +fail_compilation/diag11769.d(13): `diag11769.foo!string.bar(wstring __param_0)` and: -fail_compilation/diag11769.d(14): `diag11769.foo!string.bar(dstring _param_0)` +fail_compilation/diag11769.d(14): `diag11769.foo!string.bar(dstring __param_0)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14818.d b/gcc/testsuite/gdc.test/fail_compilation/diag14818.d index f9b535a..6147f32 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag14818.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag14818.d @@ -2,8 +2,8 @@ TEST_OUTPUT: --- fail_compilation/diag14818.d(40): Error: none of the overloads of `func` are callable using argument types `(string)` -fail_compilation/diag14818.d(18): Candidates are: `diag14818.foo(int _param_0)` -fail_compilation/diag14818.d(19): `diag14818.bar(double _param_0)` +fail_compilation/diag14818.d(18): Candidates are: `diag14818.foo(int __param_0)` +fail_compilation/diag14818.d(19): `diag14818.bar(double __param_0)` fail_compilation/diag14818.d(41): Error: template instance `diag14818.X!string` does not match any template declaration fail_compilation/diag14818.d(41): Candidates are: fail_compilation/diag14818.d(24): Foo(T) if (is(T == int)) diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag20268.d b/gcc/testsuite/gdc.test/fail_compilation/diag20268.d new file mode 100644 index 0000000..a314561 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/diag20268.d @@ -0,0 +1,12 @@ +// https://issues.dlang.org/show_bug.cgi?id=20268 + +/* +TEST_OUTPUT: +--- +fail_compilation/diag20268.d(12): Error: none of the overloads of template `diag20268.__lambda4` are callable using argument types `!()(int)` +fail_compilation/diag20268.d(11): Candidate is: `__lambda4(__T1, __T2)(x, y)` +--- +*/ + +alias f = (x,y) => true; +auto x = f(1); diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d b/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d index bc0ee9d..a55ef73 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d @@ -2,13 +2,13 @@ TEST_OUTPUT: --- fail_compilation/diag8101b.d(28): Error: none of the overloads of `foo` are callable using argument types `(double)` -fail_compilation/diag8101b.d(19): Candidates are: `diag8101b.S.foo(int _param_0)` -fail_compilation/diag8101b.d(20): `diag8101b.S.foo(int _param_0, int _param_1)` -fail_compilation/diag8101b.d(30): Error: function `diag8101b.S.bar(int _param_0)` is not callable using argument types `(double)` -fail_compilation/diag8101b.d(30): cannot pass argument `1.0` of type `double` to parameter `int _param_0` +fail_compilation/diag8101b.d(19): Candidates are: `diag8101b.S.foo(int __param_0)` +fail_compilation/diag8101b.d(20): `diag8101b.S.foo(int __param_0, int __param_1)` +fail_compilation/diag8101b.d(30): Error: function `diag8101b.S.bar(int __param_0)` is not callable using argument types `(double)` +fail_compilation/diag8101b.d(30): cannot pass argument `1.0` of type `double` to parameter `int __param_0` fail_compilation/diag8101b.d(33): Error: none of the overloads of `foo` are callable using a `const` object -fail_compilation/diag8101b.d(19): Candidates are: `diag8101b.S.foo(int _param_0)` -fail_compilation/diag8101b.d(20): `diag8101b.S.foo(int _param_0, int _param_1)` +fail_compilation/diag8101b.d(19): Candidates are: `diag8101b.S.foo(int __param_0)` +fail_compilation/diag8101b.d(20): `diag8101b.S.foo(int __param_0, int __param_1)` fail_compilation/diag8101b.d(35): Error: mutable method `diag8101b.S.bar` is not callable using a `const` object fail_compilation/diag8101b.d(22): Consider adding `const` or `inout` here --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9312.d b/gcc/testsuite/gdc.test/fail_compilation/diag9312.d index 94e3d3f..9830813 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag9312.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9312.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag9312.d(10): Error: `with` expressions must be aggregate types or pointers to them, not `int` +fail_compilation/diag9312.d(10): Error: `with` expression types must be enums or aggregates or pointers to them, not `int` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9620.d b/gcc/testsuite/gdc.test/fail_compilation/diag9620.d index d99290c..4af87df 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag9620.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9620.d @@ -1,8 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/diag9620.d(18): Error: `pure` function `diag9620.main.bar` cannot call impure function `diag9620.foo1` -fail_compilation/diag9620.d(19): Error: `pure` function `diag9620.main.bar` cannot call impure function `diag9620.foo2!().foo2` +fail_compilation/diag9620.d(20): Error: `pure` function `diag9620.main.bar` cannot call impure function `diag9620.foo1` +fail_compilation/diag9620.d(21): Error: `pure` function `diag9620.main.bar` cannot call impure function `diag9620.foo2!().foo2` +fail_compilation/diag9620.d(14): which wasn't inferred `pure` because of: +fail_compilation/diag9620.d(14): `pure` function `diag9620.foo2!().foo2` cannot access mutable static data `x` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9831.d b/gcc/testsuite/gdc.test/fail_compilation/diag9831.d index b990ced..c93a06a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag9831.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag9831.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag9831.d(13): Error: function `diag9831.main.__lambda3` cannot access variable `c` in frame of function `D main` +fail_compilation/diag9831.d(13): Error: function `diag9831.main.__lambda3(__T1)(x)` cannot access variable `c` in frame of function `D main` fail_compilation/diag9831.d(11): `c` declared here --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d b/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d index bf51363..6117439 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d +++ b/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d @@ -3,11 +3,11 @@ REQUIRED_ARGS: -de TEST_OUTPUT: --- fail_compilation/dip1000_deprecation.d(20): Deprecation: `@safe` function `main` calling `inferred` -fail_compilation/dip1000_deprecation.d(28): which would be `@system` because of: +fail_compilation/dip1000_deprecation.d(28): which wouldn't be `@safe` because of: fail_compilation/dip1000_deprecation.d(28): scope variable `x0` may not be returned fail_compilation/dip1000_deprecation.d(22): Deprecation: `@safe` function `main` calling `inferredC` fail_compilation/dip1000_deprecation.d(39): which calls `dip1000_deprecation.inferred` -fail_compilation/dip1000_deprecation.d(28): which would be `@system` because of: +fail_compilation/dip1000_deprecation.d(28): which wouldn't be `@safe` because of: fail_compilation/dip1000_deprecation.d(28): scope variable `x0` may not be returned fail_compilation/dip1000_deprecation.d(54): Deprecation: escaping reference to stack allocated value returned by `S(null)` fail_compilation/dip1000_deprecation.d(55): Deprecation: escaping reference to stack allocated value returned by `createS()` diff --git a/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d b/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d index ce81d6b..21a12ed 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d +++ b/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d @@ -8,8 +8,6 @@ fail_compilation/dtor_attributes.d(113): generated `Strict.~this` is impu fail_compilation/dtor_attributes.d(111): - HasDtor member fail_compilation/dtor_attributes.d(103): impure `HasDtor.~this` is declared here fail_compilation/dtor_attributes.d(118): Error: `@safe` function `dtor_attributes.test1` cannot call `@system` destructor `dtor_attributes.Strict.~this` -fail_compilation/dtor_attributes.d(113): which calls `dtor_attributes.Strict.~this` -fail_compilation/dtor_attributes.d(103): which calls `dtor_attributes.HasDtor.~this` fail_compilation/dtor_attributes.d(113): `dtor_attributes.Strict.~this` is declared here fail_compilation/dtor_attributes.d(113): generated `Strict.~this` is @system because of the following field's destructors: fail_compilation/dtor_attributes.d(111): - HasDtor member diff --git a/gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d b/gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d index 45b23ce..f6cab89 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d +++ b/gcc/testsuite/gdc.test/fail_compilation/dtorfields_attributes.d @@ -9,7 +9,6 @@ fail_compilation/dtorfields_attributes.d(119): generated `Strict.~this` i fail_compilation/dtorfields_attributes.d(115): - HasDtor member fail_compilation/dtorfields_attributes.d(103): impure `HasDtor.~this` is declared here fail_compilation/dtorfields_attributes.d(117): Error: `@safe` constructor `dtorfields_attributes.Strict.this` cannot call `@system` destructor `dtorfields_attributes.Strict.~this` -fail_compilation/dtorfields_attributes.d(103): which calls `dtorfields_attributes.HasDtor.~this` fail_compilation/dtorfields_attributes.d(119): `dtorfields_attributes.Strict.~this` is declared here fail_compilation/dtorfields_attributes.d(119): generated `Strict.~this` is @system because of the following field's destructors: fail_compilation/dtorfields_attributes.d(115): - HasDtor member diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10968.d b/gcc/testsuite/gdc.test/fail_compilation/fail10968.d index cfda8f4..a436197 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail10968.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail10968.d @@ -8,10 +8,14 @@ fail_compilation/fail10968.d(44): Error: `pure` function `fail10968.bar` cannot fail_compilation/fail10968.d(44): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here fail_compilation/fail10968.d(44): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.arrayassign._d_arraysetassign!(SA[], SA)._d_arraysetassign` +$p:druntime/import/core/internal/array/arrayassign.d$($n$): which calls `core.lifetime.copyEmplace!(SA, SA).copyEmplace` +$p:druntime/import/core/lifetime.d$($n$): which calls `fail10968.SA.__postblit` fail_compilation/fail10968.d(45): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` fail_compilation/fail10968.d(45): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here fail_compilation/fail10968.d(45): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.arrayassign._d_arrayassign_l!(SA[], SA)._d_arrayassign_l` +$p:druntime/import/core/internal/array/arrayassign.d$-mixin-$n$($n$): which calls `core.lifetime.copyEmplace!(SA, SA).copyEmplace` +$p:druntime/import/core/lifetime.d$($n$): which calls `fail10968.SA.__postblit` fail_compilation/fail10968.d(48): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` fail_compilation/fail10968.d(48): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here @@ -19,13 +23,18 @@ fail_compilation/fail10968.d(49): Error: `pure` function `fail10968.bar` cannot fail_compilation/fail10968.d(49): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here fail_compilation/fail10968.d(49): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arraysetctor!(SA[], SA)._d_arraysetctor` +$p:druntime/import/core/internal/array/construction.d$($n$): which calls `core.lifetime.copyEmplace!(SA, SA).copyEmplace` +$p:druntime/import/core/lifetime.d$($n$): which calls `fail10968.SA.__postblit` fail_compilation/fail10968.d(50): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit` fail_compilation/fail10968.d(50): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit` fail_compilation/fail10968.d(31): `fail10968.SA.__postblit` is declared here fail_compilation/fail10968.d(50): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arrayctor!(SA[], SA)._d_arrayctor` +$p:druntime/import/core/internal/array/construction.d$($n$): which calls `core.lifetime.copyEmplace!(SA, SA).copyEmplace` +$p:druntime/import/core/lifetime.d$($n$): which calls `fail10968.SA.__postblit` --- */ +#line 29 struct SA { this(this) diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11375.d b/gcc/testsuite/gdc.test/fail_compilation/fail11375.d index 7592a5a..cabf87a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail11375.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail11375.d @@ -1,8 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/fail11375.d(17): Error: constructor `fail11375.D!().D.this` is not `nothrow` -fail_compilation/fail11375.d(15): Error: function `D main` may throw but is marked as `nothrow` +fail_compilation/fail11375.d(18): Error: constructor `fail11375.D!().D.this` is not `nothrow` + which calls `fail11375.B.this` +fail_compilation/fail11375.d(16): Error: function `D main` may throw but is marked as `nothrow` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12236.d b/gcc/testsuite/gdc.test/fail_compilation/fail12236.d index 738864c..824f5e4 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail12236.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail12236.d @@ -7,7 +7,7 @@ fail_compilation/fail12236.d(21): Error: forward reference to inferred return ty fail_compilation/fail12236.d(21): while evaluating `pragma(msg, f2(T)(T).mangleof)` fail_compilation/fail12236.d(27): Error: template instance `fail12236.f2!int` error instantiating fail_compilation/fail12236.d(31): Error: forward reference to inferred return type of function `__lambda1` -fail_compilation/fail12236.d(31): while evaluating `pragma(msg, __lambda1.mangleof)` +fail_compilation/fail12236.d(31): while evaluating `pragma(msg, __lambda1(__T1)(a).mangleof)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13120.d b/gcc/testsuite/gdc.test/fail_compilation/fail13120.d index f1cf340..6a1335e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail13120.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13120.d @@ -17,13 +17,13 @@ void g1(char[] s) pure @nogc TEST_OUTPUT: --- fail_compilation/fail13120.d(35): Error: `pure` function `fail13120.h2` cannot call impure function `fail13120.g2!().g2` +fail_compilation/fail13120.d(30): which calls `fail13120.f2` fail_compilation/fail13120.d(35): Error: `@safe` function `fail13120.h2` cannot call `@system` function `fail13120.g2!().g2` fail_compilation/fail13120.d(27): `fail13120.g2!().g2` is declared here fail_compilation/fail13120.d(35): Error: `@nogc` function `fail13120.h2` cannot call non-@nogc function `fail13120.g2!().g2` --- */ void f2() {} - void g2()(char[] s) { foreach (dchar dc; s) diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13577.d b/gcc/testsuite/gdc.test/fail_compilation/fail13577.d new file mode 100644 index 0000000..79f9068 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13577.d @@ -0,0 +1,28 @@ +// https://issues.dlang.org/show_bug.cgi?id=13577 + +/* +TEST_OUTPUT: +--- +fail_compilation/fail13577.d(27): Error: cannot implicilty convert range element of type `int[]` to variable `x` of type `immutable(int[])` +--- +*/ + +struct Tuple(Types...) +{ + Types items; + alias items this; +} + +struct Range(T) +{ + T[] arr; + alias ElemType = Tuple!(int, T); + ElemType front() { return typeof(return)(0, arr[0]); } + bool empty() { return false; } + void popFront() {} +} + +void main() +{ + foreach (immutable i, immutable x; Range!(int[])()) {} // Error +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail16600.d b/gcc/testsuite/gdc.test/fail_compilation/fail16600.d index eb341c6..3bd600e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail16600.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail16600.d @@ -1,9 +1,9 @@ /* TEST_OUTPUT: --- fail_compilation/fail16600.d(22): Error: `fail16600.S.__ctor` called with argument types `(string) const` matches both: -fail_compilation/fail16600.d(16): `fail16600.S.this(string _param_0)` +fail_compilation/fail16600.d(16): `fail16600.S.this(string __param_0)` and: -fail_compilation/fail16600.d(17): `fail16600.S.this(string _param_0) immutable` +fail_compilation/fail16600.d(17): `fail16600.S.this(string __param_0) immutable` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17518.d b/gcc/testsuite/gdc.test/fail_compilation/fail17518.d index 385483c..cf2648d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail17518.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17518.d @@ -1,8 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail17518.d(21): Error: constructor `fail17518.S.this(inout(Correct) _param_0) inout` is not callable using argument types `(Wrong)` -fail_compilation/fail17518.d(21): cannot pass argument `Wrong()` of type `Wrong` to parameter `inout(Correct) _param_0` +fail_compilation/fail17518.d(21): Error: constructor `fail17518.S.this(inout(Correct) __param_0) inout` is not callable using argument types `(Wrong)` +fail_compilation/fail17518.d(21): cannot pass argument `Wrong()` of type `Wrong` to parameter `inout(Correct) __param_0` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17955.d b/gcc/testsuite/gdc.test/fail_compilation/fail17955.d index 95eb5cc..0832919 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail17955.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail17955.d @@ -11,7 +11,7 @@ fail_compilation/fail17955.d(49): instantiated from here: `toRedis!(SysTi fail_compilation/fail17955.d(40): ... (2 instantiations, -v to show) ... fail_compilation/fail17955.d(32): instantiated from here: `indicesOf!(isRedisType, resetCodeExpireTime)` fail_compilation/fail17955.d(67): instantiated from here: `RedisStripped!(User, true)` -fail_compilation/fail17955.d(93): Error: need `this` for `fromISOExtString` of type `pure nothrow @nogc @safe immutable(SimpleTimeZone)(dstring _param_0)` +fail_compilation/fail17955.d(93): Error: need `this` for `fromISOExtString` of type `pure nothrow @nogc @safe immutable(SimpleTimeZone)(dstring __param_0)` fail_compilation/fail17955.d(95): Error: undefined identifier `DateTimeException` fail_compilation/fail17955.d(25): Error: variable `fail17955.isISOExtStringSerializable!(SysTime).isISOExtStringSerializable` - type `void` is inferred from initializer `fromISOExtString("")`, and variables cannot be of type `void` fail_compilation/fail17955.d(54): Error: function `fail17955.toRedis!(SysTime).toRedis` has no `return` statement, but is expected to return a value of type `string` diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail196.d b/gcc/testsuite/gdc.test/fail_compilation/fail196.d index 2c7d93f..53505f4 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail196.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail196.d @@ -6,15 +6,15 @@ fail_compilation/fail196.d(27): Error: implicit string concatenation is error-pr fail_compilation/fail196.d(27): Use the explicit syntax instead (concatenating literals is `@nogc`): "foo(xxx)" ~ ";\n assert(s == " fail_compilation/fail196.d(28): Error: semicolon needed to end declaration of `s`, instead of `foo` fail_compilation/fail196.d(27): `s` declared here -fail_compilation/fail196.d(28): Error: found `");\n\n s = q"` when expecting `;` following statement -fail_compilation/fail196.d(30): Error: found `";\n assert(s == "` when expecting `;` following statement -fail_compilation/fail196.d(31): Error: found `");\n\n s = q"` when expecting `;` following statement -fail_compilation/fail196.d(33): Error: found `{` when expecting `;` following statement -fail_compilation/fail196.d(33): Error: found `}` when expecting `;` following statement -fail_compilation/fail196.d(34): Error: found `foo` when expecting `;` following statement -fail_compilation/fail196.d(34): Error: found `}` when expecting `;` following statement -fail_compilation/fail196.d(36): Error: found `<` when expecting `;` following statement -fail_compilation/fail196.d(37): Error: found `foo` when expecting `;` following statement +fail_compilation/fail196.d(28): Error: found `");\n\n s = q"` when expecting `;` following statement `foo(xxx)` on line fail_compilation/fail196.d(28) +fail_compilation/fail196.d(30): Error: found `";\n assert(s == "` when expecting `;` following statement `[foo[xxx]]` on line fail_compilation/fail196.d(30) +fail_compilation/fail196.d(31): Error: found `");\n\n s = q"` when expecting `;` following statement `foo[xxx]` on line fail_compilation/fail196.d(31) +fail_compilation/fail196.d(33): Error: found `{` when expecting `;` following statement `foo` on line fail_compilation/fail196.d(33) +fail_compilation/fail196.d(33): Error: found `}` when expecting `;` following statement `xxx` on line fail_compilation/fail196.d(33) +fail_compilation/fail196.d(34): Error: found `foo` when expecting `;` following statement `";\n assert(s == "` on line fail_compilation/fail196.d(33) +fail_compilation/fail196.d(34): Error: found `}` when expecting `;` following statement `xxx` on line fail_compilation/fail196.d(34) +fail_compilation/fail196.d(36): Error: found `<` when expecting `;` following statement `");\n\n s = q" < foo` on line fail_compilation/fail196.d(34) +fail_compilation/fail196.d(37): Error: found `foo` when expecting `;` following statement `xxx >> ";\n assert(s == "` on line fail_compilation/fail196.d(36) fail_compilation/fail196.d(37): Error: found `<` instead of statement fail_compilation/fail196.d(43): Error: unterminated string constant starting at fail_compilation/fail196.d(43) fail_compilation/fail196.d(45): Error: found `End of File` when expecting `}` following compound statement diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19948.d b/gcc/testsuite/gdc.test/fail_compilation/fail19948.d index e8a9e77..ae67443 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19948.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail19948.d @@ -1,5 +1,5 @@ // https://issues.dlang.org/show_bug.cgi?id=19948 - +// DISABLED: win32 /* TEST_OUTPUT: --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20609.d b/gcc/testsuite/gdc.test/fail_compilation/fail20609.d index 05b7c85..80a5d46 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20609.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20609.d @@ -4,7 +4,7 @@ fail_compilation/fail20609.d(26): Error: none of the overloads of `this` are callable using argument types `(int)` fail_compilation/fail20609.d(23): Candidate is: `fail20609.Foo.this(string[] args)` fail_compilation/fail20609.d(27): Error: none of the overloads of `this` are callable using argument types `(int)` -fail_compilation/fail20609.d(22): Candidates are: `fail20609.Foo.this(Object _param_0)` +fail_compilation/fail20609.d(22): Candidates are: `fail20609.Foo.this(Object __param_0)` fail_compilation/fail20609.d(23): `fail20609.Foo.this(string[] args)` fail_compilation/fail20609.d(37): Error: none of the overloads of `this` are callable using argument types `(int)` fail_compilation/fail20609.d(37): All possible candidates are marked as `deprecated` or `@disable` diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22202.d b/gcc/testsuite/gdc.test/fail_compilation/fail22202.d index 167d362..d865fd9 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail22202.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22202.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail22202.d(21): Error: function `fail22202.fun(SystemCopy _param_0)` is not callable using argument types `(SystemCopy)` +fail_compilation/fail22202.d(21): Error: function `fail22202.fun(SystemCopy __param_0)` is not callable using argument types `(SystemCopy)` fail_compilation/fail22202.d(21): `inout ref inout(SystemCopy)(ref inout(SystemCopy) other)` copy constructor cannot be called from a `pure @safe nogc` context --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23773.d b/gcc/testsuite/gdc.test/fail_compilation/fail23773.d new file mode 100644 index 0000000..e6cdc3e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23773.d @@ -0,0 +1,15 @@ +// https://issues.dlang.org/show_bug.cgi?id=23773 + +/* +TEST_OUTPUT: +--- +fail_compilation/fail23773.d(14): Error: assignment cannot be used as a condition, perhaps `==` was meant? +--- +*/ + +void main() +{ + int i; + int[] arr; + assert(arr.length = i); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23822.d b/gcc/testsuite/gdc.test/fail_compilation/fail23822.d new file mode 100644 index 0000000..5cdd1fe --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23822.d @@ -0,0 +1,22 @@ +// https://issues.dlang.org/show_bug.cgi?id=23822 + +// REQUIRED_ARGS: -de + +/* +TEST_OUTPUT: +--- +fail_compilation/fail23822.d(21): Deprecation: alias `fail23822.S.value` is deprecated +--- +*/ + +alias Alias(alias A) = A; + +struct S +{ + deprecated alias value = Alias!5; +} + +void main() +{ + auto a = S.value; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23826.d b/gcc/testsuite/gdc.test/fail_compilation/fail23826.d new file mode 100644 index 0000000..3db243a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23826.d @@ -0,0 +1,24 @@ +// https://issues.dlang.org/show_bug.cgi?id=23826 + +// REQUIRED_ARGS: -de + +/* +TEST_OUTPUT: +--- +fail_compilation/fail23826.d(23): Deprecation: alias `fail23826.S.value` is deprecated +--- +*/ + +alias Alias(alias A) = A; + +class S +{ + deprecated alias value = Alias!5; +} + +enum identity(alias A) = A; + +void main() +{ + auto a = identity!(S.value); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23861.d b/gcc/testsuite/gdc.test/fail_compilation/fail23861.d new file mode 100644 index 0000000..23c5407 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23861.d @@ -0,0 +1,25 @@ +// https://issues.dlang.org/show_bug.cgi?id=23861 + +/* +TEST_OUTPUT: +--- +fail_compilation/fail23861.d(24): Error: cannot implicitly convert expression `3` of type `int` to `Foo` +--- +*/ + +Foo global; + +struct Foo +{ + ref Foo get() + { + return global; + } + alias get this; +} + +void main() +{ + Foo g; + g = 3; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail332.d b/gcc/testsuite/gdc.test/fail_compilation/fail332.d index 91f8046..77e8cd8 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail332.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail332.d @@ -1,14 +1,14 @@ /* TEST_OUTPUT: --- -fail_compilation/fail332.d(22): Error: function `fail332.foo(int _param_0, ...)` is not callable using argument types `()` -fail_compilation/fail332.d(22): missing argument for parameter #1: `int _param_0` -fail_compilation/fail332.d(23): Error: function `fail332.foo(int _param_0, ...)` is not callable using argument types `(typeof(null))` -fail_compilation/fail332.d(23): cannot pass argument `null` of type `typeof(null)` to parameter `int _param_0` -fail_compilation/fail332.d(25): Error: function `fail332.baz(int[] _param_0...)` is not callable using argument types `(string)` -fail_compilation/fail332.d(25): cannot pass argument `""` of type `string` to parameter `int[] _param_0...` -fail_compilation/fail332.d(26): Error: function `fail332.baz(int[] _param_0...)` is not callable using argument types `(int, typeof(null))` -fail_compilation/fail332.d(26): cannot pass argument `null` of type `typeof(null)` to parameter `int[] _param_0...` +fail_compilation/fail332.d(22): Error: function `fail332.foo(int __param_0, ...)` is not callable using argument types `()` +fail_compilation/fail332.d(22): missing argument for parameter #1: `int __param_0` +fail_compilation/fail332.d(23): Error: function `fail332.foo(int __param_0, ...)` is not callable using argument types `(typeof(null))` +fail_compilation/fail332.d(23): cannot pass argument `null` of type `typeof(null)` to parameter `int __param_0` +fail_compilation/fail332.d(25): Error: function `fail332.baz(int[] __param_0...)` is not callable using argument types `(string)` +fail_compilation/fail332.d(25): cannot pass argument `""` of type `string` to parameter `int[] __param_0...` +fail_compilation/fail332.d(26): Error: function `fail332.baz(int[] __param_0...)` is not callable using argument types `(int, typeof(null))` +fail_compilation/fail332.d(26): cannot pass argument `null` of type `typeof(null)` to parameter `int[] __param_0...` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375q.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375q.d index b02fbb1..f57e746 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail4375q.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375q.d @@ -4,7 +4,7 @@ TEST_OUTPUT: --- fail_compilation/fail4375q.d(17): Warning: else is dangling, add { } after condition at fail_compilation/fail4375q.d(13) -fail_compilation/fail4375q.d(14): Error: `with` expressions must be aggregate types or pointers to them, not `int` +fail_compilation/fail4375q.d(14): Error: `with` expression types must be enums or aggregates or pointers to them, not `int` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4559.d b/gcc/testsuite/gdc.test/fail_compilation/fail4559.d index 0101ae9..657c184 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail4559.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail4559.d @@ -1,10 +1,10 @@ /* -REQUIRED_ARGS: -o- -de +REQUIRED_ARGS: TEST_OUTPUT: --- -fail_compilation/fail4559.d(13): Deprecation: use `{ }` for an empty statement, not `;` -fail_compilation/fail4559.d(19): Deprecation: use `{ }` for an empty statement, not `;` -fail_compilation/fail4559.d(21): Deprecation: use `{ }` for an empty statement, not `;` +fail_compilation/fail4559.d(13): Error: use `{ }` for an empty statement, not `;` +fail_compilation/fail4559.d(19): Error: use `{ }` for an empty statement, not `;` +fail_compilation/fail4559.d(21): Error: use `{ }` for an empty statement, not `;` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d b/gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d index 392cebd..a3b4d1a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d @@ -1,17 +1,14 @@ /* TEST_OUTPUT: --- -fail_compilation/fail_typeof.d(18): Error: undefined identifier `this` -fail_compilation/fail_typeof.d(23): Error: `this` is not in a class or struct scope -fail_compilation/fail_typeof.d(23): Error: `this` is only defined in non-static member functions, not `fail_typeof` -fail_compilation/fail_typeof.d(28): Error: undefined identifier `super` -fail_compilation/fail_typeof.d(33): Error: `super` is not in a class scope -fail_compilation/fail_typeof.d(33): Error: `super` is only allowed in non-static class member functions -fail_compilation/fail_typeof.d(40): Error: undefined identifier `this`, did you mean `typeof(this)`? -fail_compilation/fail_typeof.d(50): Error: undefined identifier `super` -fail_compilation/fail_typeof.d(55): Error: `super` is not in a class scope -fail_compilation/fail_typeof.d(55): Error: `super` is only allowed in non-static class member functions -fail_compilation/fail_typeof.d(63): Error: undefined identifier `this`, did you mean `typeof(this)`? -fail_compilation/fail_typeof.d(73): Error: undefined identifier `super`, did you mean `typeof(super)`? +fail_compilation/fail_typeof.d(15): Error: undefined identifier `this` +fail_compilation/fail_typeof.d(20): Error: `this` is not in a class or struct scope +fail_compilation/fail_typeof.d(25): Error: undefined identifier `super` +fail_compilation/fail_typeof.d(30): Error: `super` is not in a class scope +fail_compilation/fail_typeof.d(37): Error: undefined identifier `this`, did you mean `typeof(this)`? +fail_compilation/fail_typeof.d(47): Error: undefined identifier `super` +fail_compilation/fail_typeof.d(52): Error: `super` is not in a class scope +fail_compilation/fail_typeof.d(60): Error: undefined identifier `this`, did you mean `typeof(this)`? +fail_compilation/fail_typeof.d(70): Error: undefined identifier `super`, did you mean `typeof(super)`? --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10651.d b/gcc/testsuite/gdc.test/fail_compilation/ice10651.d index 1f87955..8b6c720 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice10651.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice10651.d @@ -1,7 +1,9 @@ /* TEST_OUTPUT: --- -fail_compilation/ice10651.d(11): Error: can only throw class objects derived from `Throwable`, not type `int*` +fail_compilation/ice10651.d(13): Error: can only throw class objects derived from `Throwable`, not type `int*` +fail_compilation/ice10651.d(19): Deprecation: cannot throw object of qualified type `immutable(Exception)` +fail_compilation/ice10651.d(20): Deprecation: cannot throw object of qualified type `const(Dummy)` --- */ @@ -10,3 +12,20 @@ void main() alias T = int; throw new T(); // ICE } + +void f() +{ + immutable c = new Exception(""); + if (c) throw c; + throw new const Dummy([]); +} + +class Dummy: Exception +{ + int[] data; + @safe pure nothrow this(immutable int[] data) immutable + { + super("Dummy"); + this.data = data; + } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11626.d b/gcc/testsuite/gdc.test/fail_compilation/ice11626.d index 5dc5d5c..6d347bc 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice11626.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11626.d @@ -5,4 +5,4 @@ fail_compilation/ice11626.d(8): Error: undefined identifier `Bar` --- */ -void foo(in ref Bar) {} +void foo(const ref Bar) {} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11982.d b/gcc/testsuite/gdc.test/fail_compilation/ice11982.d index ff5fae4..0f2ce41 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice11982.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice11982.d @@ -1,16 +1,19 @@ /* TEST_OUTPUT: --- -fail_compilation/ice11982.d(16): Error: basic type expected, not `scope` -fail_compilation/ice11982.d(16): Error: found `scope` when expecting `;` following statement -fail_compilation/ice11982.d(16): Error: basic type expected, not `}` -fail_compilation/ice11982.d(16): Error: missing `{ ... }` for function literal -fail_compilation/ice11982.d(16): Error: C style cast illegal, use `cast(funk)function _error_() +fail_compilation/ice11982.d(19): Error: basic type expected, not `scope` +fail_compilation/ice11982.d(19): Error: found `scope` when expecting `;` following statement `new _error_` on line fail_compilation/ice11982.d(19) +fail_compilation/ice11982.d(19): Error: basic type expected, not `}` +fail_compilation/ice11982.d(19): Error: missing `{ ... }` for function literal +fail_compilation/ice11982.d(19): Error: C style cast illegal, use `cast(funk)function _error_() { } ` -fail_compilation/ice11982.d(16): Error: found `}` when expecting `;` following statement -fail_compilation/ice11982.d(17): Error: found `End of File` when expecting `}` following compound statement +fail_compilation/ice11982.d(19): Error: found `}` when expecting `;` following statement `cast(funk)function _error_() +{ +} +` on line fail_compilation/ice11982.d(19) +fail_compilation/ice11982.d(20): Error: found `End of File` when expecting `}` following compound statement --- */ void main() { new scope ( funk ) function } diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13225.d b/gcc/testsuite/gdc.test/fail_compilation/ice13225.d index 6988cd7..abc30ea 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice13225.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice13225.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice13225.d(12): Error: mixin `ice13225.S.M!(function (S _param_0) pure nothrow @nogc @safe => 0)` does not match template declaration `M(T)` +fail_compilation/ice13225.d(12): Error: mixin `ice13225.S.M!(function (S __param_0) pure nothrow @nogc @safe => 0)` does not match template declaration `M(T)` fail_compilation/ice13225.d(16): Error: undefined identifier `undefined` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice23097.d b/gcc/testsuite/gdc.test/fail_compilation/ice23097.d index 4fd1f61..90cf03f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice23097.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice23097.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/ice23097.d(12): Error: undefined identifier `ICE` fail_compilation/ice23097.d(27): Error: template instance `ice23097.ice23097!(S23097)` error instantiating -fail_compilation/ice23097.d(27): Error: function `ice23097.ice23097!(S23097).ice23097(S23097 _param_0)` is not callable using argument types `(S23097)` +fail_compilation/ice23097.d(27): Error: function `ice23097.ice23097!(S23097).ice23097(S23097 __param_0)` is not callable using argument types `(S23097)` fail_compilation/ice23097.d(27): generating a copy constructor for `struct S23097` failed, therefore instances of it are uncopyable --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9540.d b/gcc/testsuite/gdc.test/fail_compilation/ice9540.d index 5276e83..456d3e12 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice9540.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice9540.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice9540.d(35): Error: function `ice9540.A.test.AddFront!(this, f).AddFront.dg(int _param_0)` is not callable using argument types `()` +fail_compilation/ice9540.d(35): Error: function `ice9540.A.test.AddFront!(this, f).AddFront.dg(int __param_0)` is not callable using argument types `()` fail_compilation/ice9540.d(35): too few arguments, expected 1, got 0 fail_compilation/ice9540.d(26): Error: template instance `ice9540.A.test.AddFront!(this, f)` error instantiating --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d b/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d index 11fddf0..d136144 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d +++ b/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d @@ -23,7 +23,7 @@ fail_compilation/misc_parser_err_cov1.d(40): Error: semicolon expected following fail_compilation/misc_parser_err_cov1.d(40): Error: identifier or `new` expected following `.`, not `+` fail_compilation/misc_parser_err_cov1.d(41): Error: identifier or new keyword expected following `(...)`. fail_compilation/misc_parser_err_cov1.d(41): Error: expression expected, not `;` -fail_compilation/misc_parser_err_cov1.d(42): Error: found `}` when expecting `;` following statement +fail_compilation/misc_parser_err_cov1.d(42): Error: found `}` when expecting `;` following statement `(__error) + 0` on line fail_compilation/misc_parser_err_cov1.d(41) fail_compilation/misc_parser_err_cov1.d(43): Error: found `End of File` when expecting `}` following compound statement --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/named_arguments_parse.d b/gcc/testsuite/gdc.test/fail_compilation/named_arguments_parse.d index 19e230e..096c499 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/named_arguments_parse.d +++ b/gcc/testsuite/gdc.test/fail_compilation/named_arguments_parse.d @@ -1,13 +1,13 @@ /** TEST_OUTPUT: --- -fail_compilation/named_arguments_parse.d(10): Error: named arguments not allowed here fail_compilation/named_arguments_parse.d(13): Error: named arguments not allowed here fail_compilation/named_arguments_parse.d(14): Error: named arguments not allowed here --- */ -@(attribute: 3) + +// @(attribute: 3) Currently gives an ugly parse error, will be better when named template arguments are implemented void main() { mixin(thecode: "{}"); diff --git a/gcc/testsuite/gdc.test/fail_compilation/parseStc.d b/gcc/testsuite/gdc.test/fail_compilation/parseStc.d index c9c4288..d13006d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/parseStc.d +++ b/gcc/testsuite/gdc.test/fail_compilation/parseStc.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/parseStc.d(12): Error: missing closing `)` after `if (x` fail_compilation/parseStc.d(12): Error: use `{ }` for an empty statement, not `;` -fail_compilation/parseStc.d(12): Error: found `)` when expecting `;` following statement +fail_compilation/parseStc.d(12): Error: found `)` when expecting `;` following statement `1` on line fail_compilation/parseStc.d(12) fail_compilation/parseStc.d(13): Error: redundant attribute `const` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/previewin.d b/gcc/testsuite/gdc.test/fail_compilation/previewin.d index ca54093..d0e97c8 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/previewin.d +++ b/gcc/testsuite/gdc.test/fail_compilation/previewin.d @@ -4,10 +4,10 @@ TEST_OUTPUT: --- fail_compilation/previewin.d(4): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(real x) pure nothrow @nogc @safe)` fail_compilation/previewin.d(4): cannot pass argument `__lambda1` of type `void function(real x) pure nothrow @nogc @safe` to parameter `void function(in real) f` -fail_compilation/previewin.d(5): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(const(real) x) pure nothrow @nogc @safe)` -fail_compilation/previewin.d(5): cannot pass argument `__lambda2` of type `void function(const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f` -fail_compilation/previewin.d(6): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(ref const(real) x) pure nothrow @nogc @safe)` -fail_compilation/previewin.d(6): cannot pass argument `__lambda3` of type `void function(ref const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f` +fail_compilation/previewin.d(5): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(scope const(real) x) pure nothrow @nogc @safe)` +fail_compilation/previewin.d(5): cannot pass argument `__lambda2` of type `void function(scope const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f` +fail_compilation/previewin.d(6): Error: function `previewin.takeFunction(void function(in real) f)` is not callable using argument types `(void function(ref scope const(real) x) pure nothrow @nogc @safe)` +fail_compilation/previewin.d(6): cannot pass argument `__lambda3` of type `void function(ref scope const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f` fail_compilation/previewin.d(15): Error: scope variable `arg` assigned to global variable `myGlobal` fail_compilation/previewin.d(16): Error: scope variable `arg` assigned to global variable `myGlobal` fail_compilation/previewin.d(17): Error: scope parameter `arg` may not be returned diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope2.d b/gcc/testsuite/gdc.test/fail_compilation/retscope2.d index 829fb6a..2e7940f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/retscope2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/retscope2.d @@ -86,8 +86,8 @@ fail_compilation/retscope2.d(504): Error: scope variable `c` may not be returned /* TEST_OUTPUT: --- -fail_compilation/retscope2.d(604): Error: scope variable `_param_0` assigned to non-scope anonymous parameter calling `foo600` -fail_compilation/retscope2.d(604): Error: scope variable `_param_1` assigned to non-scope anonymous parameter calling `foo600` +fail_compilation/retscope2.d(604): Error: scope variable `__param_0` assigned to non-scope anonymous parameter calling `foo600` +fail_compilation/retscope2.d(604): Error: scope variable `__param_1` assigned to non-scope anonymous parameter calling `foo600` fail_compilation/retscope2.d(614): Error: template instance `retscope2.test600!(int*, int*)` error instantiating --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope6.d b/gcc/testsuite/gdc.test/fail_compilation/retscope6.d index 5c581d1..ddeae81 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/retscope6.d +++ b/gcc/testsuite/gdc.test/fail_compilation/retscope6.d @@ -25,7 +25,7 @@ int* test() @safe --- fail_compilation/retscope6.d(7034): Error: address of variable `i` assigned to `s` with longer lifetime fail_compilation/retscope6.d(7035): Error: address of variable `i` assigned to `s` with longer lifetime -fail_compilation/retscope6.d(7025): Error: scope variable `_param_2` assigned to `ref` variable `t` with longer lifetime +fail_compilation/retscope6.d(7025): Error: scope variable `__param_2` assigned to `ref` variable `t` with longer lifetime fail_compilation/retscope6.d(7037): Error: template instance `retscope6.S.emplace4!(int*)` error instantiating fail_compilation/retscope6.d(7037): Error: address of variable `i` assigned to `s` with longer lifetime --- diff --git a/gcc/testsuite/gdc.test/fail_compilation/systemvariables_deprecation.d b/gcc/testsuite/gdc.test/fail_compilation/systemvariables_deprecation.d index 75dbe2d..b511535 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/systemvariables_deprecation.d +++ b/gcc/testsuite/gdc.test/fail_compilation/systemvariables_deprecation.d @@ -4,7 +4,7 @@ TEST_OUTPUT: --- fail_compilation/systemvariables_deprecation.d(16): Deprecation: `@safe` function `main` calling `middle` fail_compilation/systemvariables_deprecation.d(21): which calls `systemvariables_deprecation.inferred` -fail_compilation/systemvariables_deprecation.d(27): which would be `@system` because of: +fail_compilation/systemvariables_deprecation.d(27): which wouldn't be `@safe` because of: fail_compilation/systemvariables_deprecation.d(27): cannot access `@system` variable `x0` in @safe code --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/testInference.d b/gcc/testsuite/gdc.test/fail_compilation/testInference.d index c0d5a05..145fc9e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/testInference.d +++ b/gcc/testsuite/gdc.test/fail_compilation/testInference.d @@ -138,8 +138,13 @@ immutable(void)* g10063(inout int* p) pure TEST_OUTPUT: --- fail_compilation/testInference.d(154): Error: `pure` function `testInference.bar14049` cannot call impure function `testInference.foo14049!int.foo14049` +fail_compilation/testInference.d(149): which calls `testInference.foo14049!int.foo14049.__lambda2` +fail_compilation/testInference.d(148): which calls `testInference.impure14049` +fail_compilation/testInference.d(143): which wasn't inferred `pure` because of: +fail_compilation/testInference.d(143): `pure` function `testInference.impure14049` cannot access mutable static data `i` --- */ +#line 143 auto impure14049() { static int i = 1; return i; } void foo14049(T)(T val) @@ -170,8 +175,10 @@ int* f14160() pure TEST_OUTPUT: --- fail_compilation/testInference.d(180): Error: `pure` function `testInference.test12422` cannot call impure function `testInference.test12422.bar12422!().bar12422` +fail_compilation/testInference.d(179): which calls `testInference.foo12422` --- */ +#line 175 int g12422; void foo12422() { ++g12422; } void test12422() pure @@ -184,9 +191,15 @@ void test12422() pure TEST_OUTPUT: --- fail_compilation/testInference.d(198): Error: `pure` function `testInference.test13729a` cannot call impure function `testInference.test13729a.foo` +fail_compilation/testInference.d(196): which wasn't inferred `pure` because of: +fail_compilation/testInference.d(196): `pure` function `testInference.test13729a.foo` cannot access mutable static data `g13729` fail_compilation/testInference.d(206): Error: `pure` function `testInference.test13729b` cannot call impure function `testInference.test13729b.foo!().foo` +fail_compilation/testInference.d(204): which wasn't inferred `pure` because of: +fail_compilation/testInference.d(204): `pure` function `testInference.test13729b.foo!().foo` cannot access mutable static data `g13729` --- */ + +#line 190 int g13729; void test13729a() pure @@ -229,8 +242,10 @@ void test17086_call () TEST_OUTPUT: --- fail_compilation/testInference.d(238): Error: `pure` function `testInference.test20047_pure_function` cannot call impure function `testInference.test20047_pure_function.bug` +fail_compilation/testInference.d(237): which calls `testInference.test20047_impure_function` --- */ +#line 234 void test20047_impure_function() {} void test20047_pure_function() pure { diff --git a/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d b/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d index 96511f5..50cebab 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d +++ b/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d @@ -6,7 +6,7 @@ TEST_OUTPUT: fail_compilation/testrvaluecpctor.d(16): Error: cannot define both an rvalue constructor and a copy constructor for `struct Foo` fail_compilation/testrvaluecpctor.d(24): Template instance `testrvaluecpctor.Foo!int.Foo.__ctor!(immutable(Foo!int), immutable(Foo!int))` creates an rvalue constructor for `struct Foo` fail_compilation/testrvaluecpctor.d(24): Error: none of the overloads of `__ctor` are callable using a `immutable` object -fail_compilation/testrvaluecpctor.d(18): Candidates are: `testrvaluecpctor.Foo!int.Foo.this(ref Foo!int rhs)` +fail_compilation/testrvaluecpctor.d(18): Candidates are: `testrvaluecpctor.Foo!int.Foo.this(ref scope Foo!int rhs)` fail_compilation/testrvaluecpctor.d(16): `__ctor(Rhs, this This)(scope Rhs rhs)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/var_func_attr.d b/gcc/testsuite/gdc.test/fail_compilation/var_func_attr.d new file mode 100644 index 0000000..8609d29 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/var_func_attr.d @@ -0,0 +1,35 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/var_func_attr.d(19): Error: cannot implicitly convert expression `__lambda8` of type `void function() nothrow @nogc @safe` to `void function() pure` +--- +*/ + +// Test the effect of function attributes on variables +// See: +// https://issues.dlang.org/show_bug.cgi?id=7432 +// https://github.com/dlang/dmd/pull/14199 +// Usually it's a no-op, but the attribute can apply to the function/delegate type of the variable +// The current behavior is weird, so this is a test of the current behavior, not necessarily the desired behavior + +// No-op +pure int x; + +// Applies to function type (existing code in dmd and Phobos relies on this) +pure void function() pf = () { + static int g; + g++; +}; + +// Function attributes currently don't apply to inferred types (somewhat surprisingly) +nothrow nf = () { + throw new Exception(""); +}; + +// Neither do they apply to indirections +alias F = void function(); + +pure F pf2 = () { + static int g; + g++; +}; diff --git a/gcc/testsuite/gdc.test/runnable/eh2.d b/gcc/testsuite/gdc.test/runnable/eh2.d index dc285a5..2b469d2 100644 --- a/gcc/testsuite/gdc.test/runnable/eh2.d +++ b/gcc/testsuite/gdc.test/runnable/eh2.d @@ -24,7 +24,7 @@ class Abc : Throwable { printf("foo 1\n"); x |= 4; - throw this; + throw cast() this; printf("foo 2\n"); x |= 8; } diff --git a/gcc/testsuite/gdc.test/runnable/imports/link11069z.d b/gcc/testsuite/gdc.test/runnable/imports/link11069z.d index 5987cb4..02301b9 100644 --- a/gcc/testsuite/gdc.test/runnable/imports/link11069z.d +++ b/gcc/testsuite/gdc.test/runnable/imports/link11069z.d @@ -1,7 +1,7 @@ module imports.link11069z; struct Matrix(T, uint _M) { - int opCmp()(auto ref in Matrix b) const + int opCmp()(const auto ref Matrix b) const { return 0; } diff --git a/gcc/testsuite/gdc.test/runnable/imports/link13415a.d b/gcc/testsuite/gdc.test/runnable/imports/link13415a.d index de3bbe2..077671b 100644 --- a/gcc/testsuite/gdc.test/runnable/imports/link13415a.d +++ b/gcc/testsuite/gdc.test/runnable/imports/link13415a.d @@ -7,7 +7,7 @@ struct S(alias func) } } -extern(C) int printf(in char*, ...); +extern(C) int printf(const char*, ...); void f(int i = 77) { diff --git a/gcc/testsuite/gdc.test/runnable/imports/mainx23837.c b/gcc/testsuite/gdc.test/runnable/imports/mainx23837.c new file mode 100644 index 0000000..0c446ab --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/imports/mainx23837.c @@ -0,0 +1,10 @@ +// https://issues.dlang.org/show_bug?id=23837 + +struct stbrp_context +{ + int width; + int height; + int align; + int init_mode; + int heuristic; +}; diff --git a/gcc/testsuite/gdc.test/runnable/mangle.d b/gcc/testsuite/gdc.test/runnable/mangle.d index 7599e0e..6e8f2b2 100644 --- a/gcc/testsuite/gdc.test/runnable/mangle.d +++ b/gcc/testsuite/gdc.test/runnable/mangle.d @@ -571,12 +571,6 @@ void test12231() /***************************************************/ -int test2a(scope int a) { return a; } - -static assert(test2a.mangleof == "_D6mangle6test2aFiZi"); - -/***************************************************/ - class CC { int* p; diff --git a/gcc/testsuite/gdc.test/runnable/test23837.d b/gcc/testsuite/gdc.test/runnable/test23837.d new file mode 100644 index 0000000..4e155b6 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test23837.d @@ -0,0 +1,15 @@ +// https://issues.dlang.org/show_bug.cgi?id=23837 +// EXTRA_FILES: imports/mainx23837.c + +import imports.mainx23837; + +struct TexturePacker +{ + stbrp_context _context; +} + +int main() +{ + auto res = TexturePacker(); + return 0; +} diff --git a/gcc/testsuite/gdc.test/runnable/test42.d b/gcc/testsuite/gdc.test/runnable/test42.d index 57045ba..436f707 100644 --- a/gcc/testsuite/gdc.test/runnable/test42.d +++ b/gcc/testsuite/gdc.test/runnable/test42.d @@ -2113,7 +2113,7 @@ void test12725() struct Matrix12728(T, uint m, uint n = m, ubyte f = 0) { - void foo(uint r)(auto ref in Matrix12728!(T, n, r) b) + void foo(uint r)(const auto ref Matrix12728!(T, n, r) b) { } } diff --git a/gcc/testsuite/gdc.test/runnable/xtest46.d b/gcc/testsuite/gdc.test/runnable/xtest46.d index e57f52f..5017a76 100644 --- a/gcc/testsuite/gdc.test/runnable/xtest46.d +++ b/gcc/testsuite/gdc.test/runnable/xtest46.d @@ -5016,18 +5016,18 @@ void test6763() { int n; - f6763(0); //With D2: Error: function main.f ((ref const const(int) _param_0)) is not callable using argument types (int) + f6763(0); //With D2: Error: function main.f ((ref const const(int) __param_0)) is not callable using argument types (int) c6763(0); r6763(n); static assert(__traits(compiles, r6763(0))); i6763(0); o6763(n); static assert(!__traits(compiles, o6763(0))); // https://issues.dlang.org/show_bug.cgi?id=6755 - static assert(typeof(f6763).stringof == "void(int _param_0)"); - static assert(typeof(c6763).stringof == "void(const(int) _param_0)"); - static assert(typeof(r6763).stringof == "void(ref int _param_0)"); - static assert(typeof(i6763).stringof == "void(in int _param_0)"); - static assert(typeof(o6763).stringof == "void(out int _param_0)"); + static assert(typeof(f6763).stringof == "void(int __param_0)"); + static assert(typeof(c6763).stringof == "void(const(int) __param_0)"); + static assert(typeof(r6763).stringof == "void(ref int __param_0)"); + static assert(typeof(i6763).stringof == "void(in int __param_0)"); + static assert(typeof(o6763).stringof == "void(out int __param_0)"); } /***************************************************/ @@ -5997,7 +5997,7 @@ void test7618(const int x = 1) { int func(ref int x) { return 1; } static assert(!__traits(compiles, func(x))); - // Error: function test.foo.func (ref int _param_0) is not callable using argument types (const(int)) + // Error: function test.foo.func (ref int __param_0) is not callable using argument types (const(int)) int delegate(ref int) dg = (ref int x) => 1; static assert(!__traits(compiles, dg(x))); @@ -6170,14 +6170,6 @@ static assert(!__traits(compiles, foo8220(typeof(0)))); // fail /***************************************************/ -void func8105(in ref int x) { } - -void test8105() -{ -} - -/***************************************************/ - template ParameterTypeTuple159(alias foo) { static if (is(typeof(foo) P == __parameters)) @@ -8300,7 +8292,6 @@ int main() test12503(); test8004(); test8064(); - test8105(); test159(); test12824(); test8283(); |