diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-03-29 16:57:10 +0200 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-04-02 23:56:52 +0200 |
commit | 235d5a96cb8dad0b4c427602346fcf966a4ec914 (patch) | |
tree | ca19c774a19ad923e5d6f09d43ee8d89c275a96e /gcc/d | |
parent | be07535d0f43390b8906826cc119473dea514b54 (diff) | |
download | gcc-235d5a96cb8dad0b4c427602346fcf966a4ec914.zip gcc-235d5a96cb8dad0b4c427602346fcf966a4ec914.tar.gz gcc-235d5a96cb8dad0b4c427602346fcf966a4ec914.tar.bz2 |
d: Merge upstream dmd 47871363d, druntime, c52e28b7, phobos 99e9c1b77.
D front-end changes:
- Import dmd v2.099.1-beta.1.
- The address of NRVO variables is now stored in scoped closures
when they have nested references.
- Using `__traits(parameters)' in foreach loops now always returns
the parameters to the function the foreach appears within.
Previously, when used inside a `foreach' using an overloaded
`opApply', the trait would yield the parameters to the delegate.
- The deprecation period of unannotated `asm' blocks has been ended.
- The `inout' attribute no longer implies the `return' attribute.
- Added new `D_PreConditions', `D_PostConditions', and
`D_Invariants' version identifiers.
D runtime changes:
- Import druntime v2.099.1-beta.1.
Phobos changes:
- Import phobos v2.099.1-beta.1.
- `Nullable' in `std.typecons' can now act as a range.
- std.experimental.logger default level changed to `info' instead of
`warning'.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd 47871363d.
* d-builtins.cc (d_init_versions): Add predefined version identifiers
D_PreConditions, D_PostConditions, and D_Invariants.
* d-codegen.cc (d_build_call): Update for new front-end interface.
(build_frame_type): Generate reference field for NRVO variables with
nested references.
(build_closure): Generate assignment of return address to closure.
* d-tree.h (DECL_INSTANTIATED): Use DECL_LANG_FLAG_2.
(bind_expr): Remove.
* decl.cc (DeclVisitor::visit (FuncDeclaration *)): Update for new
front-end interface.
(get_symbol_decl): Likewise.
(get_decl_tree): Check DECL_LANG_FRAME_FIELD before DECL_LANG_NRVO.
Dereference the field when both are set.
* expr.cc (ExprVisitor::visit (DeleteExp *)): Update for new front-end
interface.
* modules.cc (get_internal_fn): Likewise.
* toir.cc (IRVisitor::visit (ReturnStatement *)): Likewise.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime c52e28b7.
* libdruntime/Makefile.am (DRUNTIME_DSOURCES_OPENBSD): Add
core/sys/openbsd/pwd.d.
* libdruntime/Makefile.in: Regenerate.
* src/MERGE: Merge upstream phobos 99e9c1b77.
* testsuite/libphobos.exceptions/message_with_null.d: New test.
gcc/testsuite/ChangeLog:
* gdc.dg/nrvo1.d: New test.
Diffstat (limited to 'gcc/d')
67 files changed, 1324 insertions, 1146 deletions
diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index 73b4766..7e7fb75 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -484,6 +484,15 @@ d_init_versions (void) if (global.params.useAssert == CHECKENABLEon) VersionCondition::addPredefinedGlobalIdent ("assert"); + if (global.params.useIn == CHECKENABLEon) + VersionCondition::addPredefinedGlobalIdent("D_PreConditions"); + + if (global.params.useOut == CHECKENABLEon) + VersionCondition::addPredefinedGlobalIdent("D_PostConditions"); + + if (global.params.useInvariants == CHECKENABLEon) + VersionCondition::addPredefinedGlobalIdent("D_Invariants"); + if (global.params.useArrayBounds == CHECKENABLEoff) VersionCondition::addPredefinedGlobalIdent ("D_NoBoundsChecks"); diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 3206edd..bb96b2f 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -2207,9 +2207,9 @@ d_build_call (TypeFunction *tf, tree callable, tree object, build_address (targ)); } - /* Type `noreturn` is a terminator, as no other arguments can possibly - be evaluated after it. */ - if (TREE_TYPE (targ) == noreturn_type_node) + /* Type `noreturn` is a terminator, as no other arguments can possibly + be evaluated after it. */ + if (TREE_TYPE (targ) == noreturn_type_node) noreturn_call = true; vec_safe_push (args, targ); @@ -2690,9 +2690,15 @@ build_frame_type (tree ffi, FuncDeclaration *fd) DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (vsym); TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (vsym); - /* Can't do nrvo if the variable is put in a frame. */ - if (fd->nrvo_can && fd->nrvo_var == v) - fd->nrvo_can = 0; + if (DECL_LANG_NRVO (vsym)) + { + /* Store the nrvo variable in the frame by reference. */ + TREE_TYPE (field) = build_reference_type (TREE_TYPE (field)); + + /* Can't do nrvo if the variable is put in a closure, since what the + return slot points to may no longer exist. */ + gcc_assert (!FRAMEINFO_IS_CLOSURE (ffi)); + } if (FRAMEINFO_IS_CLOSURE (ffi)) { @@ -2769,13 +2775,17 @@ build_closure (FuncDeclaration *fd) for (size_t i = 0; i < fd->closureVars.length; i++) { VarDeclaration *v = fd->closureVars[i]; + tree vsym = get_symbol_decl (v); - if (!v->isParameter ()) + if (TREE_CODE (vsym) != PARM_DECL && !DECL_LANG_NRVO (vsym)) continue; - tree vsym = get_symbol_decl (v); - tree field = component_ref (decl_ref, DECL_LANG_FRAME_FIELD (vsym)); + + /* Variable is an alias for the NRVO slot, store the reference. */ + if (DECL_LANG_NRVO (vsym)) + vsym = build_address (DECL_LANG_NRVO (vsym)); + tree expr = modify_expr (field, vsym); add_stmt (expr); } diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h index 5dec2e6..d93d02c 100644 --- a/gcc/d/d-tree.h +++ b/gcc/d/d-tree.h @@ -392,7 +392,7 @@ lang_tree_node /* True if the decl comes from a template instance. */ #define DECL_INSTANTIATED(NODE) \ - (DECL_LANG_FLAG_1 (VAR_OR_FUNCTION_DECL_CHECK (NODE))) + (DECL_LANG_FLAG_2 (VAR_OR_FUNCTION_DECL_CHECK (NODE))) enum d_tree_index { @@ -580,7 +580,6 @@ extern tree build_bounds_index_condition (IndexExp *, tree, tree); extern tree build_bounds_slice_condition (SliceExp *, tree, tree, tree); extern bool array_bounds_check (void); extern bool checkaction_trap_p (void); -extern tree bind_expr (tree, tree); extern TypeFunction *get_function_type (Type *); extern bool call_by_alias_p (FuncDeclaration *, FuncDeclaration *); extern tree d_build_call_expr (FuncDeclaration *, tree, Expressions *); diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 7ec0caf..ea8baef 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -791,7 +791,7 @@ public: return; } - if (d->semantic3Errors) + if (d->hasSemantic3Errors ()) return; if (d->isNested ()) @@ -805,7 +805,7 @@ public: break; /* Parent failed to compile, but errors were gagged. */ - if (fdp->semantic3Errors) + if (fdp->hasSemantic3Errors ()) return; } } @@ -921,15 +921,6 @@ public: } } - /* May change cfun->static_chain. */ - build_closure (d); - - if (d->vresult) - declare_local_var (d->vresult); - - if (d->v_argptr) - push_stmt_list (); - /* Named return value optimisation support for D. Implemented by overriding all the RETURN_EXPRs and replacing all occurrences of VAR with the RESULT_DECL for the function. @@ -951,7 +942,7 @@ public: else d->shidden = resdecl; - if (d->nrvo_can && d->nrvo_var) + if (d->isNRVO () && d->nrvo_var) { tree var = get_symbol_decl (d->nrvo_var); @@ -966,6 +957,15 @@ public: } } + /* May change cfun->static_chain. */ + build_closure (d); + + if (d->vresult) + declare_local_var (d->vresult); + + if (d->v_argptr) + push_stmt_list (); + build_function_body (d); /* Initialize the _argptr variable. */ @@ -1284,26 +1284,26 @@ get_symbol_decl (Declaration *decl) /* In [pragma/crtctor], Annotates a function so it is run after the C runtime library is initialized and before the D runtime library is initialized. */ - if (fd->isCrtCtorDtor == 1) + if (fd->isCrtCtor ()) { DECL_STATIC_CONSTRUCTOR (decl->csym) = 1; decl_init_priority_insert (decl->csym, DEFAULT_INIT_PRIORITY); } - else if (fd->isCrtCtorDtor == 2) + else if (fd->isCrtDtor ()) { DECL_STATIC_DESTRUCTOR (decl->csym) = 1; decl_fini_priority_insert (decl->csym, DEFAULT_INIT_PRIORITY); - } + } /* Function was declared `naked'. */ - if (fd->naked) + if (fd->isNaked ()) { insert_decl_attribute (decl->csym, "naked"); DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl->csym) = 1; } /* Mark compiler generated functions as artificial. */ - if (fd->generated) + if (fd->isGenerated ()) DECL_ARTIFICIAL (decl->csym) = 1; /* Ensure and require contracts are lexically nested in the function they @@ -1486,20 +1486,26 @@ get_decl_tree (Declaration *decl) if (vd == NULL || fd == NULL) return t; - /* Get the named return value. */ - if (DECL_LANG_NRVO (t)) - return DECL_LANG_NRVO (t); - /* Get the closure holding the var decl. */ if (DECL_LANG_FRAME_FIELD (t)) { FuncDeclaration *parent = vd->toParent2 ()->isFuncDeclaration (); tree frame_ref = get_framedecl (fd, parent); - return component_ref (build_deref (frame_ref), - DECL_LANG_FRAME_FIELD (t)); + tree field = component_ref (build_deref (frame_ref), + DECL_LANG_FRAME_FIELD (t)); + /* Frame field can also be a reference to the DECL_RESULT of a function. + Dereference it to get the value. */ + if (DECL_LANG_NRVO (t)) + field = build_deref (field); + + return field; } + /* Get the named return value. */ + if (DECL_LANG_NRVO (t)) + return DECL_LANG_NRVO (t); + /* Get the non-local `this' value by going through parent link of nested classes, this routine pretty much undoes what getRightThis in the frontend removes from codegen. */ diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 3e3e113..ca409df 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -2503f17e5767bc4fcd0cf3889c90fa0415b0edaa +47871363d804f54b29ccfd444b082c19716c2301 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/VERSION b/gcc/d/dmd/VERSION index 17724c6..16f49a7 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.099.0 +v2.099.1-beta.1 diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d index f790730..8895aa5 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -547,7 +547,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol if (overflow) assert(0); // Skip no-op for noreturn without custom aligment - if (memsize != 0 || !alignment.isDefault()) + if (memalignsize != 0 || !alignment.isDefault()) alignmember(alignment, memalignsize, &ofs); uint memoffset = ofs; @@ -570,7 +570,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol * definitions exposed some issues in their TypeInfo generation in DMD. * Related PR: https://github.com/dlang/dmd/pull/13312 */ - if (semanticRun == PASS.init && !isInterfaceDeclaration()) + if (semanticRun == PASS.initial && !isInterfaceDeclaration()) { auto stc = storage_class; if (_scope) @@ -747,7 +747,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol extern (C++) static int fp(Dsymbol s, void* ctxt) { auto f = s.isCtorDeclaration(); - if (f && f.semanticRun == PASS.init) + if (f && f.semanticRun == PASS.initial) f.dsymbolSemantic(null); return 0; } diff --git a/gcc/d/dmd/aliasthis.d b/gcc/d/dmd/aliasthis.d index 458e821..2771071b 100644 --- a/gcc/d/dmd/aliasthis.d +++ b/gcc/d/dmd/aliasthis.d @@ -100,9 +100,9 @@ Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool find if (tthis && ad.aliasthis.sym.needThis()) { - if (e.op == EXP.variable) + if (auto ve = e.isVarExp()) { - if (auto fd = (cast(VarExp)e).var.isFuncDeclaration()) + if (auto fd = ve.var.isFuncDeclaration()) { // https://issues.dlang.org/show_bug.cgi?id=13009 // Support better match for the overloaded alias this. diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d index e82413f..52f39d3 100644 --- a/gcc/d/dmd/arrayop.d +++ b/gcc/d/dmd/arrayop.d @@ -52,16 +52,16 @@ bool isArrayOpValid(Expression e) { if (isUnaArrayOp(e.op)) { - return isArrayOpValid((cast(UnaExp)e).e1); + return isArrayOpValid(e.isUnaExp().e1); } if (isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || e.op == EXP.assign) { - BinExp be = cast(BinExp)e; + BinExp be = e.isBinExp(); return isArrayOpValid(be.e1) && isArrayOpValid(be.e2); } if (e.op == EXP.construct) { - BinExp be = cast(BinExp)e; + BinExp be = e.isBinExp(); return be.e1.op == EXP.slice && isArrayOpValid(be.e2); } // if (e.op == EXP.call) @@ -76,7 +76,7 @@ bool isArrayOpValid(Expression e) bool isNonAssignmentArrayOp(Expression e) { if (e.op == EXP.slice) - return isNonAssignmentArrayOp((cast(SliceExp)e).e1); + return isNonAssignmentArrayOp(e.isSliceExp().e1); Type tb = e.type.toBasetype(); if (tb.ty == Tarray || tb.ty == Tsarray) @@ -176,7 +176,7 @@ Expression arrayOp(BinAssignExp e, Scope* sc) return e.e1.modifiableLvalue(sc, e.e1); } - return arrayOp(cast(BinExp)e, sc); + return arrayOp(e.isBinExp(), sc); } /****************************************** diff --git a/gcc/d/dmd/arraytypes.d b/gcc/d/dmd/arraytypes.d index ffbaf95..29b3a3d 100644 --- a/gcc/d/dmd/arraytypes.d +++ b/gcc/d/dmd/arraytypes.d @@ -54,4 +54,3 @@ alias TemplateInstances = Array!(TemplateInstance); alias Ensures = Array!(Ensure); alias Designators = Array!(Designator); alias DesigInits = Array!(DesigInit); - diff --git a/gcc/d/dmd/arraytypes.h b/gcc/d/dmd/arraytypes.h index d7dfa0b..ca2051c 100644 --- a/gcc/d/dmd/arraytypes.h +++ b/gcc/d/dmd/arraytypes.h @@ -67,4 +67,3 @@ typedef Array<struct Ensure> Ensures; typedef Array<struct Designator> Designators; typedef Array<struct DesigInit> DesigInits; - diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d index 5c01204..afd7ac0 100644 --- a/gcc/d/dmd/blockexit.d +++ b/gcc/d/dmd/blockexit.d @@ -99,9 +99,8 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) result = BE.halt; return; } - if (s.exp.op == EXP.assert_) + if (AssertExp a = s.exp.isAssertExp()) { - AssertExp a = cast(AssertExp)s.exp; if (a.e1.toBool().hasValue(false)) // if it's an assert(0) { result = BE.halt; @@ -505,7 +504,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) if (!(s.stc & STC.nothrow_)) { if (mustNotThrow && !(s.stc & STC.nothrow_)) - s.deprecation("`asm` statement is assumed to throw - mark it with `nothrow` if it does not"); + s.error("`asm` statement is assumed to throw - mark it with `nothrow` if it does not"); else result |= BE.throw_; } diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index a6dbd8e..2ed0dc7 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -301,7 +301,7 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc) auto tf = new TypeFunction(ParameterList(fparams), sd.handleType(), LINK.d, stc | STC.ref_); auto fop = new FuncDeclaration(declLoc, Loc.initial, Id.assign, stc, tf); fop.storage_class |= STC.inference; - fop.generated = true; + fop.flags |= FUNCFLAG.generated; Expression e; if (stc & STC.disable) { @@ -575,7 +575,7 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc) tf = tf.addSTC(STC.const_).toTypeFunction(); Identifier id = Id.xopEquals; auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf); - fop.generated = true; + fop.flags |= FUNCFLAG.generated; fop.parent = sd; Expression e1 = new IdentifierExp(loc, Id.This); Expression e2 = new IdentifierExp(loc, Id.p); @@ -644,13 +644,13 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc) switch (e.op) { case EXP.overloadSet: - s = (cast(OverExp)e).vars; + s = e.isOverExp().vars; break; case EXP.scope_: - s = (cast(ScopeExp)e).sds; + s = e.isScopeExp().sds; break; case EXP.variable: - s = (cast(VarExp)e).var; + s = e.isVarExp().var; break; default: break; @@ -696,7 +696,7 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc) tf = tf.addSTC(STC.const_).toTypeFunction(); Identifier id = Id.xopCmp; auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf); - fop.generated = true; + fop.flags |= FUNCFLAG.generated; fop.parent = sd; Expression e1 = new IdentifierExp(loc, Id.This); Expression e2 = new IdentifierExp(loc, Id.p); @@ -814,7 +814,7 @@ FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc) auto tf = new TypeFunction(ParameterList(parameters), Type.thash_t, LINK.d, STC.nothrow_ | STC.trusted); Identifier id = Id.xtoHash; auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf); - fop.generated = true; + fop.flags |= FUNCFLAG.generated; /* Do memberwise hashing. * @@ -937,13 +937,13 @@ void buildDtors(AggregateDeclaration ad, Scope* sc) if (stc & STC.safe) stc = (stc & ~STC.safe) | STC.trusted; - ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t), + SliceExp se = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t), new IntegerExp(loc, n, Type.tsize_t)); // Prevent redundant bounds check - (cast(SliceExp)ex).upperIsInBounds = true; - (cast(SliceExp)ex).lowerIsLessThanUpper = true; + se.upperIsInBounds = true; + se.lowerIsLessThanUpper = true; - ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), ex); + ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se); } e = Expression.combine(ex, e); // combine in reverse order } @@ -952,7 +952,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc) { //printf("Building __fieldDtor(), %s\n", e.toChars()); auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__fieldDtor); - dd.generated = true; + dd.flags |= FUNCFLAG.generated; dd.storage_class |= STC.inference; dd.fbody = new ExpStatement(loc, e); ad.members.push(dd); @@ -1008,7 +1008,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc) e = Expression.combine(e, ce); } auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__aggrDtor); - dd.generated = true; + dd.flags |= FUNCFLAG.generated; dd.storage_class |= STC.inference; dd.fbody = new ExpStatement(loc, e); ad.members.push(dd); @@ -1079,7 +1079,7 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara stmts.push(new ExpStatement(loc, call)); stmts.push(new ReturnStatement(loc, new CastExp(loc, new ThisExp(loc), Type.tvoidptr))); func.fbody = new CompoundStatement(loc, stmts); - func.generated = true; + func.flags |= FUNCFLAG.generated; auto sc2 = sc.push(); sc2.stc &= ~STC.static_; // not a static destructor @@ -1127,7 +1127,7 @@ private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc) auto call = new CallExp(dtor.loc, dtor, null); call.directcall = true; // non-virtual call Class.__dtor(); func.fbody = new ExpStatement(dtor.loc, call); - func.generated = true; + func.flags |= FUNCFLAG.generated; func.storage_class |= STC.inference; auto sc2 = sc.push(); @@ -1403,7 +1403,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) //printf("Building __fieldPostBlit()\n"); checkShared(); auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__fieldPostblit); - dd.generated = true; + dd.flags |= FUNCFLAG.generated; dd.storage_class |= STC.inference | STC.scope_; dd.fbody = (stc & STC.disable) ? null : new CompoundStatement(loc, postblitCalls); sd.postblits.shift(dd); @@ -1441,7 +1441,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) checkShared(); auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__aggrPostblit); - dd.generated = true; + dd.flags |= FUNCFLAG.generated; dd.storage_class |= STC.inference; dd.fbody = new ExpStatement(loc, e); sd.members.push(dd); @@ -1504,7 +1504,7 @@ private CtorDeclaration generateCopyCtorDeclaration(StructDeclaration sd, const auto ccd = new CtorDeclaration(sd.loc, Loc.initial, STC.ref_, tf, true); ccd.storage_class |= funcStc; ccd.storage_class |= STC.inference; - ccd.generated = true; + ccd.flags |= FUNCFLAG.generated; return ccd; } @@ -1691,5 +1691,3 @@ bool buildCopyCtor(StructDeclaration sd, Scope* sc) } return true; } - - diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 9941c16..75ba9ea 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -217,15 +217,13 @@ UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2) } emplaceExp!(ComplexExp)(&ue, loc, v, type); } - else if (e1.op == EXP.symbolOffset) + else if (SymOffExp soe = e1.isSymOffExp()) { - SymOffExp soe = cast(SymOffExp)e1; emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e2.toInteger()); ue.exp().type = type; } - else if (e2.op == EXP.symbolOffset) + else if (SymOffExp soe = e2.isSymOffExp()) { - SymOffExp soe = cast(SymOffExp)e2; emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger()); ue.exp().type = type; } @@ -320,9 +318,8 @@ UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2) } emplaceExp!(ComplexExp)(&ue, loc, v, type); } - else if (e1.op == EXP.symbolOffset) + else if (SymOffExp soe = e1.isSymOffExp()) { - SymOffExp soe = cast(SymOffExp)e1; emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset - e2.toInteger()); ue.exp().type = type; } @@ -731,14 +728,12 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e { if (e2.op == EXP.null_) cmp = 1; - else if (e2.op == EXP.string_) + else if (StringExp es2 = e2.isStringExp()) { - StringExp es2 = cast(StringExp)e2; cmp = (0 == es2.len); } - else if (e2.op == EXP.arrayLiteral) + else if (ArrayLiteralExp es2 = e2.isArrayLiteralExp()) { - ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; cmp = !es2.elements || (0 == es2.elements.dim); } else @@ -749,14 +744,12 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e } else if (e2.op == EXP.null_) { - if (e1.op == EXP.string_) + if (StringExp es1 = e1.isStringExp()) { - StringExp es1 = cast(StringExp)e1; cmp = (0 == es1.len); } - else if (e1.op == EXP.arrayLiteral) + else if (ArrayLiteralExp es1 = e1.isArrayLiteralExp()) { - ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; cmp = !es1.elements || (0 == es1.elements.dim); } else @@ -767,8 +760,8 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e } else if (e1.op == EXP.string_ && e2.op == EXP.string_) { - StringExp es1 = cast(StringExp)e1; - StringExp es2 = cast(StringExp)e2; + StringExp es1 = e1.isStringExp(); + StringExp es2 = e2.isStringExp(); if (es1.sz != es2.sz) { assert(global.errors); @@ -784,8 +777,8 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e } else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral) { - ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; - ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; + ArrayLiteralExp es1 = e1.isArrayLiteralExp(); + ArrayLiteralExp es2 = e2.isArrayLiteralExp(); if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim)) cmp = 1; // both arrays are empty else if (!es1.elements || !es2.elements) @@ -818,8 +811,8 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral) { Lsa: - StringExp es1 = cast(StringExp)e1; - ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; + StringExp es1 = e1.isStringExp(); + ArrayLiteralExp es2 = e2.isArrayLiteralExp(); size_t dim1 = es1.len; size_t dim2 = es2.elements ? es2.elements.dim : 0; if (dim1 != dim2) @@ -844,8 +837,8 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e } else if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral) { - StructLiteralExp es1 = cast(StructLiteralExp)e1; - StructLiteralExp es2 = cast(StructLiteralExp)e2; + StructLiteralExp es1 = e1.isStructLiteralExp(); + StructLiteralExp es2 = e2.isStructLiteralExp(); if (es1.sd != es2.sd) cmp = 0; else if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim)) @@ -935,8 +928,8 @@ UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expressio } else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset) { - SymOffExp es1 = cast(SymOffExp)e1; - SymOffExp es2 = cast(SymOffExp)e2; + SymOffExp es1 = e1.isSymOffExp(); + SymOffExp es2 = e2.isSymOffExp(); cmp = (es1.var == es2.var && es1.offset == es2.offset); } else @@ -976,8 +969,8 @@ UnionExp Cmp(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2) //printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars()); if (e1.op == EXP.string_ && e2.op == EXP.string_) { - StringExp es1 = cast(StringExp)e1; - StringExp es2 = cast(StringExp)e2; + StringExp es1 = e1.isStringExp(); + StringExp es2 = e2.isStringExp(); size_t sz = es1.sz; assert(sz == es2.sz); size_t len = es1.len; @@ -1045,7 +1038,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1) } if (e1.op == EXP.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to)) { - Expression ex = (cast(VectorExp)e1).e1; + Expression ex = e1.isVectorExp().e1; emplaceExp!(UnionExp)(&ue, ex); return ue; } @@ -1201,20 +1194,17 @@ UnionExp ArrayLength(Type type, Expression e1) { UnionExp ue = void; Loc loc = e1.loc; - if (e1.op == EXP.string_) + if (StringExp es1 = e1.isStringExp()) { - StringExp es1 = cast(StringExp)e1; emplaceExp!(IntegerExp)(&ue, loc, es1.len, type); } - else if (e1.op == EXP.arrayLiteral) + else if (ArrayLiteralExp ale = e1.isArrayLiteralExp()) { - ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; size_t dim = ale.elements ? ale.elements.dim : 0; emplaceExp!(IntegerExp)(&ue, loc, dim, type); } - else if (e1.op == EXP.assocArrayLiteral) + else if (AssocArrayLiteralExp ale = e1.isAssocArrayLiteralExp) { - AssocArrayLiteralExp ale = cast(AssocArrayLiteralExp)e1; size_t dim = ale.keys.dim; emplaceExp!(IntegerExp)(&ue, loc, dim, type); } @@ -1238,7 +1228,7 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds) assert(e1.type); if (e1.op == EXP.string_ && e2.op == EXP.int64) { - StringExp es1 = cast(StringExp)e1; + StringExp es1 = e1.isStringExp(); uinteger_t i = e2.toInteger(); if (i >= es1.len) { @@ -1261,9 +1251,8 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds) e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length); emplaceExp!(ErrorExp)(&ue); } - else if (e1.op == EXP.arrayLiteral) + else if (ArrayLiteralExp ale = e1.isArrayLiteralExp()) { - ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; auto e = ale[cast(size_t)i]; e.type = type; e.loc = loc; @@ -1278,9 +1267,8 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds) else if (e1.type.toBasetype().ty == Tarray && e2.op == EXP.int64) { uinteger_t i = e2.toInteger(); - if (e1.op == EXP.arrayLiteral) + if (ArrayLiteralExp ale = e1.isArrayLiteralExp()) { - ArrayLiteralExp ale = cast(ArrayLiteralExp)e1; if (i >= ale.elements.dim) { e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), cast(ulong) ale.elements.dim); @@ -1300,9 +1288,8 @@ UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds) else cantExp(ue); } - else if (e1.op == EXP.assocArrayLiteral) + else if (AssocArrayLiteralExp ae = e1.isAssocArrayLiteralExp()) { - AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e1; /* Search the keys backwards, in case there are duplicate keys */ for (size_t i = ae.keys.dim; i;) @@ -1350,7 +1337,7 @@ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr) if (e1.op == EXP.string_ && lwr.op == EXP.int64 && upr.op == EXP.int64) { - StringExp es1 = cast(StringExp)e1; + StringExp es1 = e1.isStringExp(); const uinteger_t ilwr = lwr.toInteger(); const uinteger_t iupr = upr.toInteger(); if (sliceBoundsCheck(0, es1.len, ilwr, iupr)) @@ -1363,14 +1350,14 @@ UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr) const data1 = es1.peekData(); memcpy(s, data1.ptr + ilwr * sz, len * sz); emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz, es1.postfix); - StringExp es = cast(StringExp)ue.exp(); + StringExp es = ue.exp().isStringExp(); es.committed = es1.committed; es.type = type; } } else if (e1.op == EXP.arrayLiteral && lwr.op == EXP.int64 && upr.op == EXP.int64 && !hasSideEffect(e1)) { - ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; + ArrayLiteralExp es1 = e1.isArrayLiteralExp(); const uinteger_t ilwr = lwr.toInteger(); const uinteger_t iupr = upr.toInteger(); if (sliceBoundsCheck(0, es1.elements.dim, ilwr, iupr)) @@ -1491,15 +1478,15 @@ private Expressions* copyElements(Expression e1, Expression e2 = null) } } - if (e1.op == EXP.arrayLiteral) - append(cast(ArrayLiteralExp)e1); + if (auto ale = e1.isArrayLiteralExp()) + append(ale); else elems.push(e1); if (e2) { - if (e2.op == EXP.arrayLiteral) - append(cast(ArrayLiteralExp)e2); + if (auto ale = e2.isArrayLiteralExp()) + append(ale); else elems.push(e2); } @@ -1544,7 +1531,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) else utf_encode(sz, s, cast(dchar)v); emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz); - StringExp es = cast(StringExp)ue.exp(); + StringExp es = ue.exp().isStringExp(); es.type = type; es.committed = 1; } @@ -1589,8 +1576,8 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) else if (e1.op == EXP.string_ && e2.op == EXP.string_) { // Concatenate the strings - StringExp es1 = cast(StringExp)e1; - StringExp es2 = cast(StringExp)e2; + StringExp es1 = e1.isStringExp(); + StringExp es2 = e2.isStringExp(); size_t len = es1.len + es2.len; ubyte sz = es1.sz; if (sz != es2.sz) @@ -1609,7 +1596,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) memcpy(cast(char*)s, data1.ptr, es1.len * sz); memcpy(cast(char*)s + es1.len * sz, data2.ptr, es2.len * sz); emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz); - StringExp es = cast(StringExp)ue.exp(); + StringExp es = ue.exp().isStringExp(); es.committed = es1.committed | es2.committed; es.type = type; assert(ue.exp().type); @@ -1618,8 +1605,8 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) else if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral()) { // [chars] ~ string --> [chars] - StringExp es = cast(StringExp)e2; - ArrayLiteralExp ea = cast(ArrayLiteralExp)e1; + StringExp es = e2.isStringExp(); + ArrayLiteralExp ea = e1.isArrayLiteralExp(); size_t len = es.len + ea.elements.dim; auto elems = new Expressions(len); for (size_t i = 0; i < ea.elements.dim; ++i) @@ -1627,7 +1614,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) (*elems)[i] = ea[i]; } emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems); - ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp(); + ArrayLiteralExp dest = ue.exp().isArrayLiteralExp(); sliceAssignArrayLiteralFromString(dest, es, ea.elements.dim); assert(ue.exp().type); return ue; @@ -1635,8 +1622,8 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral()) { // string ~ [chars] --> [chars] - StringExp es = cast(StringExp)e1; - ArrayLiteralExp ea = cast(ArrayLiteralExp)e2; + StringExp es = e1.isStringExp(); + ArrayLiteralExp ea = e2.isArrayLiteralExp(); size_t len = es.len + ea.elements.dim; auto elems = new Expressions(len); for (size_t i = 0; i < ea.elements.dim; ++i) @@ -1644,7 +1631,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) (*elems)[es.len + i] = ea[i]; } emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems); - ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp(); + ArrayLiteralExp dest = ue.exp().isArrayLiteralExp(); sliceAssignArrayLiteralFromString(dest, es, 0); assert(ue.exp().type); return ue; @@ -1652,7 +1639,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) else if (e1.op == EXP.string_ && e2.op == EXP.int64) { // string ~ char --> string - StringExp es1 = cast(StringExp)e1; + StringExp es1 = e1.isStringExp(); StringExp es; const sz = es1.sz; dinteger_t v = e2.toInteger(); @@ -1668,7 +1655,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) else utf_encode(sz, cast(char*)s + (sz * es1.len), cast(dchar)v); emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz); - es = cast(StringExp)ue.exp(); + es = ue.exp().isStringExp(); es.committed = es1.committed; es.type = type; assert(ue.exp().type); @@ -1679,7 +1666,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) // [w|d]?char ~ string --> string // We assume that we only ever prepend one char of the same type // (wchar,dchar) as the string's characters. - StringExp es2 = cast(StringExp)e2; + StringExp es2 = e2.isStringExp(); const len = 1 + es2.len; const sz = es2.sz; dinteger_t v = e1.toInteger(); @@ -1688,7 +1675,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) const data2 = es2.peekData(); memcpy(cast(char*)s + sz, data2.ptr, data2.length); emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz); - StringExp es = cast(StringExp)ue.exp(); + StringExp es = ue.exp().isStringExp(); es.sz = sz; es.committed = es2.committed; es.type = type; @@ -1796,7 +1783,7 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2) } if (!e.type.equals(type)) { - StringExp se = cast(StringExp)e.copy(); + StringExp se = e.copy().isStringExp(); e = se.castTo(null, type); emplaceExp!(UnionExp)(&ue, e); e = ue.exp(); @@ -1812,23 +1799,21 @@ UnionExp Ptr(Type type, Expression e1) { //printf("Ptr(e1 = %s)\n", e1.toChars()); UnionExp ue = void; - if (e1.op == EXP.add) + if (AddExp ae = e1.isAddExp()) { - AddExp ae = cast(AddExp)e1; - if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64) + if (AddrExp ade = ae.e1.isAddrExp()) { - AddrExp ade = cast(AddrExp)ae.e1; - if (ade.e1.op == EXP.structLiteral) - { - StructLiteralExp se = cast(StructLiteralExp)ade.e1; - uint offset = cast(uint)ae.e2.toInteger(); - Expression e = se.getField(type, offset); - if (e) + if (ae.e2.op == EXP.int64) + if (StructLiteralExp se = ade.e1.isStructLiteralExp()) { - emplaceExp!(UnionExp)(&ue, e); - return ue; + uint offset = cast(uint)ae.e2.toInteger(); + Expression e = se.getField(type, offset); + if (e) + { + emplaceExp!(UnionExp)(&ue, e); + return ue; + } } - } } } cantExp(ue); diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index fb52b63..bb12aa7 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -981,7 +981,12 @@ final class CParser(AST) : Parser!AST e = new AST.DotIdExp(loc, e, Id.__sizeof); break; } + // must be an expression + e = cparsePrimaryExp(); + e = new AST.DotIdExp(loc, e, Id.__sizeof); + break; } + e = cparseUnaryExp(); e = new AST.DotIdExp(loc, e, Id.__sizeof); break; @@ -1016,10 +1021,16 @@ final class CParser(AST) : Parser!AST { if (token.value == TOK.leftParenthesis) { + //printf("cparseCastExp()\n"); auto tk = peek(&token); - if (tk.value == TOK.identifier && - !isTypedef(tk.ident) && - peek(tk).value == TOK.rightParenthesis) + bool iscast; + bool isexp; + if (tk.value == TOK.identifier) + { + iscast = isTypedef(tk.ident); + isexp = !iscast; + } + if (isexp) { // ( identifier ) is an expression return cparseUnaryExp(); @@ -1045,9 +1056,18 @@ final class CParser(AST) : Parser!AST auto ce = new AST.CompoundLiteralExp(loc, t, ci); return cparsePostfixOperators(ce); } - else if (t.isTypeIdentifier() && - token.value == TOK.leftParenthesis && - !isCastExpression(pt)) + + if (iscast) + { + // ( type-name ) cast-expression + auto ce = cparseCastExp(); + return new AST.CastExp(loc, ce, t); + } + + if (t.isTypeIdentifier() && + isexp && + token.value == TOK.leftParenthesis && + !isCastExpression(pt)) { /* (t)(...)... might be a cast expression or a function call, * with different grammars: a cast would be cparseCastExp(), @@ -1061,12 +1081,10 @@ final class CParser(AST) : Parser!AST AST.Expression e = new AST.CallExp(loc, ie, cparseArguments()); return cparsePostfixOperators(e); } - else - { - // ( type-name ) cast-expression - auto ce = cparseCastExp(); - return new AST.CastExp(loc, ce, t); - } + + // ( type-name ) cast-expression + auto ce = cparseCastExp(); + return new AST.CastExp(loc, ce, t); } } return cparseUnaryExp(); @@ -1764,8 +1782,6 @@ final class CParser(AST) : Parser!AST symbols.push(stag); if (tt.tok == TOK.enum_) { - if (!stag.members) - error(tt.loc, "`enum %s` has no members", stag.toChars()); isalias = false; s = new AST.AliasDeclaration(token.loc, id, stag); } @@ -2382,7 +2398,19 @@ final class CParser(AST) : Parser!AST const idx = previd.toString(); if (idx.length > 2 && idx[0] == '_' && idx[1] == '_') // leading double underscore importBuiltins = true; // probably one of those compiler extensions - t = new AST.TypeIdentifier(loc, previd); + t = null; + if (scw & SCW.xtypedef) + { + /* Punch through to what the typedef is, to support things like: + * typedef T* T; + */ + auto pt = lookupTypedef(previd); + if (pt && *pt) // if previd is a known typedef + t = *pt; + } + + if (!t) + t = new AST.TypeIdentifier(loc, previd); break; } @@ -4767,7 +4795,8 @@ final class CParser(AST) : Parser!AST scan(&n); if (n.value == TOK.identifier && n.ident == Id.pack) return pragmaPack(loc); - skipToNextLine(); + if (n.value != TOK.endOfLine) + skipToNextLine(); } /********* @@ -4786,7 +4815,8 @@ final class CParser(AST) : Parser!AST if (n.value != TOK.leftParenthesis) { error(loc, "left parenthesis expected to follow `#pragma pack`"); - skipToNextLine(); + if (n.value != TOK.endOfLine) + skipToNextLine(); return; } @@ -4796,7 +4826,8 @@ final class CParser(AST) : Parser!AST { error(loc, "right parenthesis expected to close `#pragma pack(`"); } - skipToNextLine(); + if (n.value != TOK.endOfLine) + skipToNextLine(); } void setPackAlign(ref const Token t) @@ -4923,7 +4954,8 @@ final class CParser(AST) : Parser!AST } error(loc, "unrecognized `#pragma pack(%s)`", n.toChars()); - skipToNextLine(); + if (n.value != TOK.endOfLine) + skipToNextLine(); } //} diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index 9078f90..32aed16 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -232,11 +232,11 @@ bool needToCopyLiteral(const Expression expr) switch (e.op) { case EXP.arrayLiteral: - return (cast(ArrayLiteralExp)e).ownedByCtfe == OwnedBy.code; + return e.isArrayLiteralExp().ownedByCtfe == OwnedBy.code; case EXP.assocArrayLiteral: - return (cast(AssocArrayLiteralExp)e).ownedByCtfe == OwnedBy.code; + return e.isAssocArrayLiteralExp().ownedByCtfe == OwnedBy.code; case EXP.structLiteral: - return (cast(StructLiteralExp)e).ownedByCtfe == OwnedBy.code; + return e.isStructLiteralExp().ownedByCtfe == OwnedBy.code; case EXP.string_: case EXP.this_: case EXP.variable: @@ -247,14 +247,14 @@ bool needToCopyLiteral(const Expression expr) case EXP.dotVariable: case EXP.slice: case EXP.cast_: - e = (cast(UnaExp)e).e1; + e = e.isUnaExp().e1; continue; case EXP.concatenate: - return needToCopyLiteral((cast(BinExp)e).e1) || needToCopyLiteral((cast(BinExp)e).e2); + return needToCopyLiteral(e.isBinExp().e1) || needToCopyLiteral(e.isBinExp().e2); case EXP.concatenateAssign: case EXP.concatenateElemAssign: case EXP.concatenateDcharAssign: - e = (cast(BinExp)e).e2; + e = e.isBinExp().e2; continue; default: return false; @@ -286,7 +286,7 @@ UnionExp copyLiteral(Expression e) const slice = se.peekData(); memcpy(s, slice.ptr, slice.length); emplaceExp!(StringExp)(&ue, se.loc, s[0 .. se.len * se.sz], se.len, se.sz); - StringExp se2 = cast(StringExp)ue.exp(); + StringExp se2 = ue.exp().isStringExp(); se2.committed = se.committed; se2.postfix = se.postfix; se2.type = se.type; @@ -299,14 +299,14 @@ UnionExp copyLiteral(Expression e) emplaceExp!(ArrayLiteralExp)(&ue, e.loc, e.type, elements); - ArrayLiteralExp r = cast(ArrayLiteralExp)ue.exp(); + ArrayLiteralExp r = ue.exp().isArrayLiteralExp(); r.ownedByCtfe = OwnedBy.ctfe; return ue; } if (auto aae = e.isAssocArrayLiteralExp()) { emplaceExp!(AssocArrayLiteralExp)(&ue, e.loc, copyLiteralArray(aae.keys), copyLiteralArray(aae.values)); - AssocArrayLiteralExp r = cast(AssocArrayLiteralExp)ue.exp(); + AssocArrayLiteralExp r = ue.exp().isAssocArrayLiteralExp(); r.type = e.type; r.ownedByCtfe = OwnedBy.ctfe; return ue; @@ -482,7 +482,7 @@ private UnionExp paintTypeOntoLiteralCopy(Type type, Expression lit) // just a ref to the keys and values. OwnedBy wasOwned = aae.ownedByCtfe; emplaceExp!(AssocArrayLiteralExp)(&ue, lit.loc, aae.keys, aae.values); - aae = cast(AssocArrayLiteralExp)ue.exp(); + aae = ue.exp().isAssocArrayLiteralExp(); aae.ownedByCtfe = wasOwned; } else @@ -526,7 +526,7 @@ Expression resolveSlice(Expression e, UnionExp* pue = null) * It's very wasteful to resolve the slice when we only * need the length. */ -uinteger_t resolveArrayLength(const Expression e) +uinteger_t resolveArrayLength(Expression e) { switch (e.op) { @@ -538,7 +538,7 @@ uinteger_t resolveArrayLength(const Expression e) case EXP.slice: { - auto se = cast(SliceExp)e; + auto se = e.isSliceExp(); const ilo = se.lwr.toInteger(); const iup = se.upr.toInteger(); return iup - ilo; @@ -720,16 +720,16 @@ Expression getAggregateFromPointer(Expression e, dinteger_t* ofs) *ofs = soe.offset; if (auto dve = e.isDotVarExp()) { - const ex = dve.e1; + auto ex = dve.e1; const v = dve.var.isVarDeclaration(); assert(v); StructLiteralExp se = (ex.op == EXP.classReference) - ? (cast(ClassReferenceExp)ex).value - : cast(StructLiteralExp)ex; + ? ex.isClassReferenceExp().value + : ex.isStructLiteralExp(); // We can't use getField, because it makes a copy const i = (ex.op == EXP.classReference) - ? (cast(ClassReferenceExp)ex).getFieldIndex(e.type, v.offset) + ? ex.isClassReferenceExp().getFieldIndex(e.type, v.offset) : se.getFieldIndex(e.type, v.offset); e = (*se.elements)[i]; } @@ -777,11 +777,11 @@ bool pointToSameMemoryBlock(Expression agg1, Expression agg2) } // Note that type painting can occur with VarExp, so we // must compare the variables being pointed to. - if (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var) + if (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var) { return true; } - if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var) + if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && agg1.isSymOffExp().var == agg2.isSymOffExp().var) { return true; } @@ -801,14 +801,14 @@ Expression pointerDifference(UnionExp* pue, const ref Loc loc, Type type, Expres emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type); } else if (agg1.op == EXP.string_ && agg2.op == EXP.string_ && - (cast(StringExp)agg1).peekString().ptr == (cast(StringExp)agg2).peekString().ptr) + agg1.isStringExp().peekString().ptr == agg2.isStringExp().peekString().ptr) { Type pointee = (cast(TypePointer)agg1.type).next; const sz = pointee.size(); emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type); } else if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && - (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var) + agg1.isSymOffExp().var == agg2.isSymOffExp().var) { emplaceExp!(IntegerExp)(pue, loc, ofs1 - ofs2, type); } @@ -832,12 +832,12 @@ Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type return pue.exp(); } if (eptr.op == EXP.address) - eptr = (cast(AddrExp)eptr).e1; + eptr = eptr.isAddrExp().e1; dinteger_t ofs1; Expression agg1 = getAggregateFromPointer(eptr, &ofs1); if (agg1.op == EXP.symbolOffset) { - if ((cast(SymOffExp)agg1).var.type.ty != Tsarray) + if (agg1.isSymOffExp().var.type.ty != Tsarray) { error(loc, "cannot perform pointer arithmetic on arrays of unknown length at compile time"); goto Lcant; @@ -856,7 +856,7 @@ Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type if (agg1.op == EXP.symbolOffset) { indx = ofs1 / sz; - len = (cast(TypeSArray)(cast(SymOffExp)agg1).var.type).dim.toInteger(); + len = (cast(TypeSArray)agg1.isSymOffExp().var.type).dim.toInteger(); } else { @@ -881,8 +881,8 @@ Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type } if (agg1.op == EXP.symbolOffset) { - emplaceExp!(SymOffExp)(pue, loc, (cast(SymOffExp)agg1).var, indx * sz); - SymOffExp se = cast(SymOffExp)pue.exp(); + emplaceExp!(SymOffExp)(pue, loc, agg1.isSymOffExp().var, indx * sz); + SymOffExp se = pue.exp().isSymOffExp(); se.type = type; return pue.exp(); } @@ -1016,7 +1016,7 @@ Expression paintFloatInt(UnionExp* pue, Expression fromVal, Type to) bool isCtfeComparable(Expression e) { if (e.op == EXP.slice) - e = (cast(SliceExp)e).e1; + e = e.isSliceExp().e1; if (e.isConst() != 1) { if (e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.function_ || e.op == EXP.delegate_ || e.op == EXP.arrayLiteral || e.op == EXP.structLiteral || e.op == EXP.assocArrayLiteral || e.op == EXP.classReference) @@ -1191,7 +1191,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide if (e1.op == EXP.classReference || e2.op == EXP.classReference) { if (e1.op == EXP.classReference && e2.op == EXP.classReference && - (cast(ClassReferenceExp)e1).value == (cast(ClassReferenceExp)e2).value) + e1.isClassReferenceExp().value == e2.isClassReferenceExp().value) return 0; return 1; } @@ -1199,8 +1199,8 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide { // printf("e1: %s\n", e1.toChars()); // printf("e2: %s\n", e2.toChars()); - Type t1 = isType((cast(TypeidExp)e1).obj); - Type t2 = isType((cast(TypeidExp)e2).obj); + Type t1 = isType(e1.isTypeidExp().obj); + Type t2 = isType(e2.isTypeidExp().obj); assert(t1); assert(t2); return t1 != t2; @@ -1214,7 +1214,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide dinteger_t ofs1, ofs2; Expression agg1 = getAggregateFromPointer(e1, &ofs1); Expression agg2 = getAggregateFromPointer(e2, &ofs2); - if ((agg1 == agg2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)) + if ((agg1 == agg2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var)) { if (ofs1 == ofs2) return 0; @@ -1232,13 +1232,13 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide return 0; assert(e1.op == EXP.delegate_ && e2.op == EXP.delegate_); // Same .funcptr. Do they have the same .ptr? - Expression ptr1 = (cast(DelegateExp)e1).e1; - Expression ptr2 = (cast(DelegateExp)e2).e1; + Expression ptr1 = e1.isDelegateExp().e1; + Expression ptr2 = e2.isDelegateExp().e1; dinteger_t ofs1, ofs2; Expression agg1 = getAggregateFromPointer(ptr1, &ofs1); Expression agg2 = getAggregateFromPointer(ptr2, &ofs2); // If they are EXP.variable, it means they are FuncDeclarations - if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)) + if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var)) { return 0; } @@ -1291,8 +1291,8 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide } if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral) { - StructLiteralExp es1 = cast(StructLiteralExp)e1; - StructLiteralExp es2 = cast(StructLiteralExp)e2; + StructLiteralExp es1 = e1.isStructLiteralExp(); + StructLiteralExp es2 = e2.isStructLiteralExp(); // For structs, we only need to return 0 or 1 (< and > aren't legal). if (es1.sd != es2.sd) return 1; @@ -1326,8 +1326,8 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide } if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.assocArrayLiteral) { - AssocArrayLiteralExp es1 = cast(AssocArrayLiteralExp)e1; - AssocArrayLiteralExp es2 = cast(AssocArrayLiteralExp)e2; + AssocArrayLiteralExp es1 = e1.isAssocArrayLiteralExp(); + AssocArrayLiteralExp es2 = e2.isAssocArrayLiteralExp(); size_t dim = es1.keys.dim; if (es2.keys.dim != dim) return 1; @@ -1394,8 +1394,8 @@ bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2) } else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset) { - SymOffExp es1 = cast(SymOffExp)e1; - SymOffExp es2 = cast(SymOffExp)e2; + SymOffExp es1 = e1.isSymOffExp(); + SymOffExp es2 = e2.isSymOffExp(); cmp = (es1.var == es2.var && es1.offset == es2.offset); } else if (e1.type.isreal()) @@ -1443,8 +1443,8 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2) if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral()) { // [chars] ~ string => string (only valid for CTFE) - StringExp es1 = cast(StringExp)e2; - ArrayLiteralExp es2 = cast(ArrayLiteralExp)e1; + StringExp es1 = e2.isStringExp(); + ArrayLiteralExp es2 = e1.isArrayLiteralExp(); const len = es1.len + es2.elements.dim; const sz = es1.sz; void* s = mem.xmalloc((len + 1) * sz); @@ -1464,7 +1464,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2) // Add terminating 0 memset(cast(char*)s + len * sz, 0, sz); emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz); - StringExp es = cast(StringExp)ue.exp(); + StringExp es = ue.exp().isStringExp(); es.committed = 0; es.type = type; return ue; @@ -1473,8 +1473,8 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2) { // string ~ [chars] => string (only valid for CTFE) // Concatenate the strings - StringExp es1 = cast(StringExp)e1; - ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; + StringExp es1 = e1.isStringExp(); + ArrayLiteralExp es2 = e2.isArrayLiteralExp(); const len = es1.len + es2.elements.dim; const sz = es1.sz; void* s = mem.xmalloc((len + 1) * sz); @@ -1494,7 +1494,7 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2) // Add terminating 0 memset(cast(char*)s + len * sz, 0, sz); emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz); - StringExp es = cast(StringExp)ue.exp(); + StringExp es = ue.exp().isStringExp(); es.sz = sz; es.committed = 0; //es1.committed; es.type = type; @@ -1503,10 +1503,10 @@ UnionExp ctfeCat(const ref Loc loc, Type type, Expression e1, Expression e2) if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf())) { // [ e1 ] ~ [ e2 ] ---> [ e1, e2 ] - ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1; - ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2; + ArrayLiteralExp es1 = e1.isArrayLiteralExp(); + ArrayLiteralExp es2 = e2.isArrayLiteralExp(); emplaceExp!(ArrayLiteralExp)(&ue, es1.loc, type, copyLiteralArray(es1.elements)); - es1 = cast(ArrayLiteralExp)ue.exp(); + es1 = ue.exp().isArrayLiteralExp(); es1.elements.insert(es1.elements.dim, copyLiteralArray(es2.elements)); return ue; } @@ -1594,7 +1594,7 @@ Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expres // Disallow reinterpreting class casts. Do this by ensuring that // the original class can implicitly convert to the target class. // Also do not check 'alias this' for explicit cast expressions. - auto tclass = (cast(ClassReferenceExp)e).originalClass().type.isTypeClass(); + auto tclass = e.isClassReferenceExp().originalClass().type.isTypeClass(); auto match = explicitCast ? tclass.implicitConvToWithoutAliasThis(to.mutableOf()) : tclass.implicitConvTo(to.mutableOf()); if (match) @@ -1665,9 +1665,9 @@ void assignInPlace(Expression dest, Expression src) if (dest.op == EXP.structLiteral) { assert(dest.op == src.op); - oldelems = (cast(StructLiteralExp)dest).elements; - newelems = (cast(StructLiteralExp)src).elements; - auto sd = (cast(StructLiteralExp)dest).sd; + oldelems = dest.isStructLiteralExp().elements; + newelems = src.isStructLiteralExp().elements; + auto sd = dest.isStructLiteralExp().sd; const nfields = sd.nonHiddenFields(); const nvthis = sd.fields.dim - nfields; if (nvthis && oldelems.dim >= nfields && oldelems.dim < newelems.dim) @@ -1676,22 +1676,22 @@ void assignInPlace(Expression dest, Expression src) } else if (dest.op == EXP.arrayLiteral && src.op == EXP.arrayLiteral) { - oldelems = (cast(ArrayLiteralExp)dest).elements; - newelems = (cast(ArrayLiteralExp)src).elements; + oldelems = dest.isArrayLiteralExp().elements; + newelems = src.isArrayLiteralExp().elements; } else if (dest.op == EXP.string_ && src.op == EXP.string_) { - sliceAssignStringFromString(cast(StringExp)dest, cast(StringExp)src, 0); + sliceAssignStringFromString(dest.isStringExp(), src.isStringExp(), 0); return; } else if (dest.op == EXP.arrayLiteral && src.op == EXP.string_) { - sliceAssignArrayLiteralFromString(cast(ArrayLiteralExp)dest, cast(StringExp)src, 0); + sliceAssignArrayLiteralFromString(dest.isArrayLiteralExp(), src.isStringExp(), 0); return; } else if (src.op == EXP.arrayLiteral && dest.op == EXP.string_) { - sliceAssignStringFromArrayLiteral(cast(StringExp)dest, cast(ArrayLiteralExp)src, 0); + sliceAssignStringFromArrayLiteral(dest.isStringExp(), src.isArrayLiteralExp(), 0); return; } else @@ -1761,13 +1761,13 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray size_t indxlo = 0; if (oldval.op == EXP.slice) { - indxlo = cast(size_t)(cast(SliceExp)oldval).lwr.toInteger(); - oldval = (cast(SliceExp)oldval).e1; + indxlo = cast(size_t)oldval.isSliceExp().lwr.toInteger(); + oldval = oldval.isSliceExp().e1; } size_t copylen = oldlen < newlen ? oldlen : newlen; if (oldval.op == EXP.string_) { - StringExp oldse = cast(StringExp)oldval; + StringExp oldse = oldval.isStringExp(); void* s = mem.xcalloc(newlen + 1, oldse.sz); const data = oldse.peekData(); memcpy(s, data.ptr, copylen * oldse.sz); @@ -1790,7 +1790,7 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray } } emplaceExp!(StringExp)(pue, loc, s[0 .. newlen * oldse.sz], newlen, oldse.sz); - StringExp se = cast(StringExp)pue.exp(); + StringExp se = pue.exp().isStringExp(); se.type = arrayType; se.sz = oldse.sz; se.committed = oldse.committed; @@ -1801,7 +1801,7 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray if (oldlen != 0) { assert(oldval.op == EXP.arrayLiteral); - ArrayLiteralExp ae = cast(ArrayLiteralExp)oldval; + ArrayLiteralExp ae = oldval.isArrayLiteralExp(); foreach (size_t i; 0 .. copylen) (*elements)[i] = (*ae.elements)[indxlo + i]; } @@ -1819,7 +1819,7 @@ Expression changeArrayLiteralLength(UnionExp* pue, const ref Loc loc, TypeArray (*elements)[i] = defaultElem; } emplaceExp!(ArrayLiteralExp)(pue, loc, arrayType, elements); - ArrayLiteralExp aae = cast(ArrayLiteralExp)pue.exp(); + ArrayLiteralExp aae = pue.exp().isArrayLiteralExp(); aae.ownedByCtfe = OwnedBy.ctfe; } return pue.exp(); @@ -1874,14 +1874,14 @@ bool isCtfeValueValid(Expression newval) { // &struct.func or &clasinst.func // &nestedfunc - Expression ethis = (cast(DelegateExp)newval).e1; - return (ethis.op == EXP.structLiteral || ethis.op == EXP.classReference || ethis.op == EXP.variable && (cast(VarExp)ethis).var == (cast(DelegateExp)newval).func); + Expression ethis = newval.isDelegateExp().e1; + return (ethis.op == EXP.structLiteral || ethis.op == EXP.classReference || ethis.op == EXP.variable && ethis.isVarExp().var == newval.isDelegateExp().func); } case EXP.symbolOffset: { // function pointer, or pointer to static variable - Declaration d = (cast(SymOffExp)newval).var; + Declaration d = newval.isSymOffExp().var; return d.isFuncDeclaration() || d.isDataseg(); } @@ -1894,7 +1894,7 @@ bool isCtfeValueValid(Expression newval) case EXP.address: { // e1 should be a CTFE reference - Expression e1 = (cast(AddrExp)newval).e1; + Expression e1 = newval.isAddrExp().e1; return tb.ty == Tpointer && ( (e1.op == EXP.structLiteral || e1.op == EXP.arrayLiteral) && isCtfeValueValid(e1) || @@ -1908,7 +1908,7 @@ bool isCtfeValueValid(Expression newval) case EXP.slice: { // e1 should be an array aggregate - const SliceExp se = cast(SliceExp)newval; + const SliceExp se = newval.isSliceExp(); assert(se.lwr && se.lwr.op == EXP.int64); assert(se.upr && se.upr.op == EXP.int64); return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral); @@ -1932,7 +1932,7 @@ bool isCtfeReferenceValid(Expression newval) case EXP.variable: { - const VarDeclaration v = (cast(VarExp)newval).var.isVarDeclaration(); + const VarDeclaration v = newval.isVarExp().var.isVarDeclaration(); assert(v); // Must not be a reference to a reference return true; @@ -1940,13 +1940,13 @@ bool isCtfeReferenceValid(Expression newval) case EXP.index: { - const Expression eagg = (cast(IndexExp)newval).e1; + const Expression eagg = newval.isIndexExp().e1; return eagg.op == EXP.string_ || eagg.op == EXP.arrayLiteral || eagg.op == EXP.assocArrayLiteral; } case EXP.dotVariable: { - Expression eagg = (cast(DotVarExp)newval).e1; + Expression eagg = newval.isDotVarExp().e1; return (eagg.op == EXP.structLiteral || eagg.op == EXP.classReference) && isCtfeValueValid(eagg); } @@ -1968,19 +1968,19 @@ void showCtfeExpr(Expression e, int level = 0) ClassDeclaration cd = null; if (e.op == EXP.structLiteral) { - elements = (cast(StructLiteralExp)e).elements; - sd = (cast(StructLiteralExp)e).sd; + elements = e.isStructLiteralExp().elements; + sd = e.isStructLiteralExp().sd; printf("STRUCT type = %s %p:\n", e.type.toChars(), e); } else if (e.op == EXP.classReference) { - elements = (cast(ClassReferenceExp)e).value.elements; - cd = (cast(ClassReferenceExp)e).originalClass(); - printf("CLASS type = %s %p:\n", e.type.toChars(), (cast(ClassReferenceExp)e).value); + elements = e.isClassReferenceExp().value.elements; + cd = e.isClassReferenceExp().originalClass(); + printf("CLASS type = %s %p:\n", e.type.toChars(), e.isClassReferenceExp().value); } else if (e.op == EXP.arrayLiteral) { - elements = (cast(ArrayLiteralExp)e).elements; + elements = e.isArrayLiteralExp().elements; printf("ARRAY LITERAL type=%s %p:\n", e.type.toChars(), e); } else if (e.op == EXP.assocArrayLiteral) @@ -1994,19 +1994,19 @@ void showCtfeExpr(Expression e, int level = 0) else if (e.op == EXP.slice) { printf("SLICE %p: %s\n", e, e.toChars()); - showCtfeExpr((cast(SliceExp)e).e1, level + 1); + showCtfeExpr(e.isSliceExp().e1, level + 1); } else if (e.op == EXP.variable) { printf("VAR %p %s\n", e, e.toChars()); - VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration(); + VarDeclaration v = e.isVarExp().var.isVarDeclaration(); if (v && getValue(v)) showCtfeExpr(getValue(v), level + 1); } else if (e.op == EXP.address) { // This is potentially recursive. We mustn't try to print the thing we're pointing to. - printf("POINTER %p to %p: %s\n", e, (cast(AddrExp)e).e1, e.toChars()); + printf("POINTER %p to %p: %s\n", e, e.isAddrExp().e1, e.toChars()); } else printf("VALUE %p: %s\n", e, e.toChars()); @@ -2086,7 +2086,7 @@ UnionExp voidInitLiteral(Type t, VarDeclaration var) (*elements)[i] = elem; } emplaceExp!(ArrayLiteralExp)(&ue, var.loc, tsa, elements); - ArrayLiteralExp ae = cast(ArrayLiteralExp)ue.exp(); + ArrayLiteralExp ae = ue.exp().isArrayLiteralExp(); ae.ownedByCtfe = OwnedBy.ctfe; } else if (t.ty == Tstruct) @@ -2098,7 +2098,7 @@ UnionExp voidInitLiteral(Type t, VarDeclaration var) (*exps)[i] = voidInitLiteral(ts.sym.fields[i].type, ts.sym.fields[i]).copy(); } emplaceExp!(StructLiteralExp)(&ue, var.loc, ts.sym, exps); - StructLiteralExp se = cast(StructLiteralExp)ue.exp(); + StructLiteralExp se = ue.exp().isStructLiteralExp(); se.type = ts; se.ownedByCtfe = OwnedBy.ctfe; } diff --git a/gcc/d/dmd/ctorflow.d b/gcc/d/dmd/ctorflow.d index cc251b0..c04793d 100644 --- a/gcc/d/dmd/ctorflow.d +++ b/gcc/d/dmd/ctorflow.d @@ -222,4 +222,3 @@ bool mergeFieldInit(ref CSX a, const CSX b) pure nothrow } return ok; } - diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 887bb89..685987b 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -3880,4 +3880,3 @@ IntRange getIntRange(Expression e) case EXP.negate : return visitNeg(e.isNegExp()); } } - diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 82a5f3b..c0e40a5 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -292,7 +292,7 @@ extern (C++) abstract class Declaration : Dsymbol * postblit. Print the first field that has * a disabled postblit. */ - if (postblit.generated) + if (postblit.isGenerated()) { auto sd = p.isStructDeclaration(); assert(sd); @@ -334,7 +334,7 @@ extern (C++) abstract class Declaration : Dsymbol if (auto ctor = isCtorDeclaration()) { - if (ctor.isCpCtor && ctor.generated) + if (ctor.isCpCtor && ctor.isGenerated()) { .error(loc, "Generating an `inout` copy constructor for `struct %s` failed, therefore instances of it are uncopyable", parent.toPrettyChars()); return true; @@ -1060,24 +1060,51 @@ extern (C++) class VarDeclaration : Declaration enum AdrOnStackNone = ~0u; uint ctfeAdrOnStack; - bool isargptr; // if parameter that _argptr points to - bool ctorinit; // it has been initialized in a ctor - bool iscatchvar; // this is the exception object variable in catch() clause - bool isowner; // this is an Owner, despite it being `scope` - bool setInCtorOnly; // field can only be set in a constructor, as it is const or immutable + // `bool` fields that are compacted into bit fields in a string mixin + private extern (D) static struct BitFields + { + bool isargptr; /// if parameter that _argptr points to + bool ctorinit; /// it has been initialized in a ctor + bool iscatchvar; /// this is the exception object variable in catch() clause + bool isowner; /// this is an Owner, despite it being `scope` + bool setInCtorOnly; /// field can only be set in a constructor, as it is const or immutable + + /// It is a class that was allocated on the stack + /// + /// This means the var is not rebindable once assigned, + /// and the destructor gets run when it goes out of scope + bool onstack; - // Both these mean the var is not rebindable once assigned, - // and the destructor gets run when it goes out of scope - bool onstack; // it is a class that was allocated on the stack + bool overlapped; /// if it is a field and has overlapping + bool overlapUnsafe; /// if it is an overlapping field and the overlaps are unsafe + bool doNotInferScope; /// do not infer 'scope' for this variable + bool doNotInferReturn; /// do not infer 'return' for this variable + + bool isArgDtorVar; /// temporary created to handle scope destruction of a function argument + } + private ushort bitFields; // stores multiple booleans for BitFields byte canassign; // it can be assigned to - bool overlapped; // if it is a field and has overlapping - bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe - bool doNotInferScope; // do not infer 'scope' for this variable - bool doNotInferReturn; // do not infer 'return' for this variable ubyte isdataseg; // private data for isDataseg 0 unset, 1 true, 2 false - bool isArgDtorVar; // temporary created to handle scope destruction of a function argument + // Generate getter and setter functions for `bitFields` + extern (D) mixin(() { + string result = "extern (C++) pure nothrow @nogc @safe final {"; + foreach (size_t i, mem; __traits(allMembers, BitFields)) + { + result ~= " + /// set or get the corresponding BitFields member + bool "~mem~"() const { return !!(bitFields & (1 << "~i.stringof~")); } + /// ditto + bool "~mem~"(bool v) + { + v ? (bitFields |= (1 << "~i.stringof~")) : (bitFields &= ~(1 << "~i.stringof~")); + return v; + }"; + } + return result ~ "}"; + }()); + final extern (D) this(const ref Loc loc, Type type, Identifier ident, Initializer _init, StorageClass storage_class = STC.undefined_) in @@ -1642,64 +1669,6 @@ extern (C++) class VarDeclaration : Declaration { v.visit(this); } - - /********************************** - * Determine if `this` has a lifetime that lasts past - * the destruction of `v` - * Params: - * v = variable to test against - * Returns: - * true if it does - */ - final bool enclosesLifetimeOf(VarDeclaration v) const pure - { - // VarDeclaration's with these STC's need special treatment - enum special = STC.temp | STC.foreach_; - - // Sequence numbers work when there are no special VarDeclaration's involved - if (!((this.storage_class | v.storage_class) & special)) - { - assert(this.sequenceNumber != this.sequenceNumber.init); - assert(v.sequenceNumber != v.sequenceNumber.init); - - return (this.sequenceNumber < v.sequenceNumber); - } - - // Assume that semantic produces temporaries according to their lifetime - // (It won't create a temporary before the actual content) - if ((this.storage_class & special) && (v.storage_class & special)) - return this.sequenceNumber < v.sequenceNumber; - - // Fall back to lexical order - assert(this.loc != Loc.initial); - assert(v.loc != Loc.initial); - - if (this.loc.linnum != v.loc.linnum) - return this.loc.linnum < v.loc.linnum; - - if (this.loc.charnum != v.loc.charnum) - return this.loc.charnum < v.loc.charnum; - - // Default fallback - return this.sequenceNumber < v.sequenceNumber; - } - - /*************************************** - * Add variable to maybes[]. - * When a maybescope variable `v` is assigned to a maybescope variable `this`, - * we cannot determine if `this` is actually scope until the semantic - * analysis for the function is completed. Thus, we save the data - * until then. - * Params: - * v = an STC.maybescope variable that was assigned to `this` - */ - final void addMaybe(VarDeclaration v) - { - //printf("add %s to %s's list of dependencies\n", v.toChars(), toChars()); - if (!maybes) - maybes = new VarDeclarations(); - maybes.push(v); - } } /******************************************************* diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 9986ea3..441a966 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -241,22 +241,33 @@ public: // When interpreting, these point to the value (NULL if value not determinable) // The index of this variable on the CTFE stack, ~0u if not allocated unsigned ctfeAdrOnStack; - - bool isargptr; // if parameter that _argptr points to - bool ctorinit; // it has been initialized in a ctor - bool iscatchvar; // this is the exception object variable in catch() clause - bool isowner; // this is an Owner, despite it being `scope` - bool setInCtorOnly; // field can only be set in a constructor, as it is const or immutable - bool onstack; // it is a class that was allocated on the stack - char canassign; // it can be assigned to - bool overlapped; // if it is a field and has overlapping - bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe - bool doNotInferScope; // do not infer 'scope' for this variable - bool doNotInferReturn; // do not infer 'return' for this variable - unsigned char isdataseg; // private data for isDataseg - bool isArgDtorVar; // temporary created to handle scope destruction of a function argument - -public: +private: + uint16_t bitFields; +public: + int8_t canassign; // // it can be assigned to + uint8_t isdataseg; // private data for isDataseg + bool isargptr() const; // if parameter that _argptr points to + bool isargptr(bool v); + bool ctorinit() const; // it has been initialized in a ctor + bool ctorinit(bool v); + bool iscatchvar() const; // this is the exception object variable in catch() clause + bool iscatchvar(bool v); + bool isowner() const; // this is an Owner, despite it being `scope` + bool isowner(bool v); + bool setInCtorOnly() const; // field can only be set in a constructor, as it is const or immutable + bool setInCtorOnly(bool v); + bool onstack() const; // it is a class that was allocated on the stack + bool onstack(bool v); + bool overlapped() const; // if it is a field and has overlapping + bool overlapped(bool v); + bool overlapUnsafe() const; // if it is an overlapping field and the overlaps are unsafe + bool overlapUnsafe(bool v); + bool doNotInferScope() const; // do not infer 'scope' for this variable + bool doNotInferScope(bool v); + bool doNotInferReturn() const; // do not infer 'return' for this variable + bool doNotInferReturn(bool v); + bool isArgDtorVar() const; // temporary created to handle scope destruction of a function argument + bool isArgDtorVar(bool v); static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined); VarDeclaration *syntaxCopy(Dsymbol *); void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion); @@ -273,7 +284,6 @@ public: bool hasPointers(); bool canTakeAddressOf(); bool needsScopeDtor(); - bool enclosesLifetimeOf(VarDeclaration *v) const; void checkCtorConstInit(); Dsymbol *toAlias(); // Eliminate need for dynamic_cast @@ -541,7 +551,6 @@ public: // scopes from having the same name DsymbolTable *localsymtab; VarDeclaration *vthis; // 'this' parameter (member and nested) - bool isThis2; // has a dual-context 'this' parameter VarDeclaration *v_arguments; // '_arguments' parameter VarDeclaration *v_argptr; // '_argptr' variable @@ -551,29 +560,20 @@ public: FuncDeclaration *overnext0; // next in overload list (only used during IFTI) Loc endloc; // location of closing curly bracket int vtblIndex; // for member functions, index into vtbl[] - bool naked; // true if naked - bool generated; // true if function was generated by the compiler rather than - // supplied by the user - bool hasAlwaysInlines; // contains references to functions that must be inlined - unsigned char isCrtCtorDtor; // has attribute pragma(crt_constructor(1)/crt_destructor(2)) - // not set before the glue layer + ILS inlineStatusStmt; ILS inlineStatusExp; PINLINE inlining; int inlineNest; // !=0 if nested inline - bool eh_none; /// true if no exception unwinding is needed // true if errors in semantic3 this function's frame ptr - bool semantic3Errors; ForeachStatement *fes; // if foreach body, this is the foreach BaseClass* interfaceVirtual; // if virtual, but only appears in interface vtbl[] - bool introducing; // true if 'introducing' function // if !=NULL, then this is the type // of the 'introducing' function // this one is overriding Type *tintro; - bool inferRetType; // true if return type is to be inferred StorageClass storage_class2; // storage class for template onemember's // Things that should really go into Scope @@ -585,8 +585,6 @@ public: // 16 if there are multiple return statements int hasReturnExp; - // Support for NRVO (named return value optimization) - bool nrvo_can; // true means we can do it VarDeclaration *nrvo_var; // variable to replace with shidden Symbol *shidden; // hidden pointer passed to function @@ -654,6 +652,19 @@ public: bool isNogc(); bool isNogcBypassingInference(); + bool isNRVO() const; + void isNRVO(bool v); + bool isNaked() const; + bool isGenerated() const; + void isGenerated(bool v); + bool isIntroducing() const; + bool hasSemantic3Errors() const; + bool hasNoEH() const; + bool inferRetType() const; + bool hasDualContext() const; + bool hasAlwaysInlines() const; + bool isCrtCtor() const; + bool isCrtDtor() const; virtual bool isNested() const; AggregateDeclaration *isThis(); diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d index 90e48f8..aba290b 100644 --- a/gcc/d/dmd/denum.d +++ b/gcc/d/dmd/denum.d @@ -96,7 +96,7 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol override void setScope(Scope* sc) { - if (semanticRun > PASS.init) + if (semanticRun > PASS.initial) return; ScopeDsymbol.setScope(sc); } @@ -163,6 +163,9 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol if (defaultval) return defaultval; + if (isCsymbol()) + return memtype.defaultInit(loc, true); + if (_scope) dsymbolSemantic(this, _scope); if (errors) diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index 30a8a44..3cfc07a 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -535,7 +535,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta istatex.caller = istate; istatex.fd = fd; - if (fd.isThis2) + if (fd.hasDualContext()) { Expression arg0 = thisarg; if (arg0 && arg0.type.ty == Tstruct) @@ -678,7 +678,7 @@ private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta e = CTFEExp.voidexp; if (tf.isref && e.op == EXP.variable && e.isVarExp().var == fd.vthis) e = thisarg; - if (tf.isref && fd.isThis2 && e.op == EXP.index) + if (tf.isref && fd.hasDualContext() && e.op == EXP.index) { auto ie = e.isIndexExp(); auto pe = ie.e1.isPtrExp(); @@ -944,7 +944,7 @@ public: if (auto eaddr = e.isAddrExp()) x = eaddr.e1; VarDeclaration v; - while (x.op == EXP.variable && (v = (cast(VarExp)x).var.isVarDeclaration()) !is null) + while (x.op == EXP.variable && (v = x.isVarExp().var.isVarDeclaration()) !is null) { if (v.storage_class & STC.ref_) { @@ -1526,7 +1526,7 @@ public: } while ((*boss.value.elements)[next].op == EXP.classReference) { - boss = cast(ClassReferenceExp)(*boss.value.elements)[next]; + boss = (*boss.value.elements)[next].isClassReferenceExp(); } (*boss.value.elements)[next] = collateral; return oldest; @@ -1752,7 +1752,7 @@ public: if (istate && istate.fd.vthis) { result = ctfeEmplaceExp!VarExp(e.loc, istate.fd.vthis); - if (istate.fd.isThis2) + if (istate.fd.hasDualContext()) { result = ctfeEmplaceExp!PtrExp(e.loc, result); result.type = Type.tvoidptr.sarrayOf(2); @@ -1768,15 +1768,15 @@ public: result = ctfeGlobals.stack.getThis(); if (result) { - if (istate && istate.fd.isThis2) + if (istate && istate.fd.hasDualContext()) { assert(result.op == EXP.address); - result = (cast(AddrExp)result).e1; + result = result.isAddrExp().e1; assert(result.op == EXP.arrayLiteral); - result = (*(cast(ArrayLiteralExp)result).elements)[0]; + result = (*result.isArrayLiteralExp().elements)[0]; if (e.type.ty == Tstruct) { - result = (cast(AddrExp)result).e1; + result = result.isAddrExp().e1; } return; } @@ -1873,7 +1873,9 @@ public: { fromType = (cast(TypeArray)e.var.type).next; } - if (e.var.isDataseg() && ((e.offset == 0 && isSafePointerCast(e.var.type, pointee)) || (fromType && isSafePointerCast(fromType, pointee)))) + if (e.var.isDataseg() && ((e.offset == 0 && isSafePointerCast(e.var.type, pointee)) || + (fromType && isSafePointerCast(fromType, pointee)) || + (e.var.isCsymbol() && e.offset + pointee.size() <= e.var.type.size()))) { result = e; return; @@ -1980,7 +1982,7 @@ public: if (decl.isDataseg()) { // Normally this is already done by optimize() // Do it here in case optimize(WANTvalue) wasn't run before CTFE - emplaceExp!(SymOffExp)(pue, e.loc, (cast(VarExp)e.e1).var, 0); + emplaceExp!(SymOffExp)(pue, e.loc, e.e1.isVarExp().var, 0); result = pue.exp(); result.type = e.type; return; @@ -2399,7 +2401,7 @@ public: return; } - ClassDeclaration cd = (cast(ClassReferenceExp)result).originalClass(); + ClassDeclaration cd = result.isClassReferenceExp().originalClass(); assert(cd); emplaceExp!(TypeidExp)(pue, e.loc, cd.type); @@ -2487,7 +2489,7 @@ public: else { // segfault bug 6250 - assert(exp.op != EXP.index || (cast(IndexExp)exp).e1 != e); + assert(exp.op != EXP.index || exp.isIndexExp().e1 != e); ex = interpretRegion(exp, istate); if (exceptionOrCant(ex)) @@ -2521,7 +2523,7 @@ public: return; } emplaceExp!(ArrayLiteralExp)(pue, e.loc, e.type, basis, expsx); - auto ale = cast(ArrayLiteralExp)pue.exp(); + auto ale = pue.exp().isArrayLiteralExp(); ale.ownedByCtfe = OwnedBy.ctfe; result = ale; } @@ -2705,7 +2707,7 @@ public: return; } emplaceExp!(StructLiteralExp)(pue, e.loc, e.sd, expsx); - auto sle = cast(StructLiteralExp)pue.exp(); + auto sle = pue.exp().isStructLiteralExp(); sle.type = e.type; sle.ownedByCtfe = OwnedBy.ctfe; sle.origin = e.origin; @@ -2737,7 +2739,7 @@ public: foreach (ref element; *elements) element = copyLiteral(elem).copy(); emplaceExp!(ArrayLiteralExp)(pue, loc, newtype, elements); - auto ae = cast(ArrayLiteralExp)pue.exp(); + auto ae = pue.exp().isArrayLiteralExp(); ae.ownedByCtfe = OwnedBy.ctfe; return ae; } @@ -2959,7 +2961,7 @@ public: result = e; // optimize: reuse this CTFE reference else { - auto edt = cast(DotTypeExp)e.copy(); + auto edt = e.copy().isDotTypeExp(); edt.e1 = (e1 == ue.exp()) ? e1.copy() : e1; // don't return pointer to ue result = edt; } @@ -3335,7 +3337,7 @@ public: if (exceptionOrCant(newval)) return; - VarDeclaration v = (cast(VarExp)e1).var.isVarDeclaration(); + VarDeclaration v = e1.isVarExp().var.isVarDeclaration(); setValue(v, newval); // Get the value to return. Note that 'newval' is an Lvalue, @@ -3351,7 +3353,7 @@ public: { while (e1.op == EXP.cast_) { - CastExp ce = cast(CastExp)e1; + CastExp ce = e1.isCastExp(); e1 = ce.e1; } } @@ -3362,7 +3364,7 @@ public: AssocArrayLiteralExp existingAA = null; Expression lastIndex = null; Expression oldval = null; - if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray) + if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray) { // --------------------------------------- // Deal with AA index assignment @@ -3374,12 +3376,12 @@ public: * (2) If the ultimate AA is null, no insertion happens at all. Instead, * we create nested AA literals, and change it into a assignment. */ - IndexExp ie = cast(IndexExp)e1; + IndexExp ie = e1.isIndexExp(); int depth = 0; // how many nested AA indices are there? - while (ie.e1.op == EXP.index && (cast(IndexExp)ie.e1).e1.type.toBasetype().ty == Taarray) + while (ie.e1.op == EXP.index && ie.e1.isIndexExp().e1.type.toBasetype().ty == Taarray) { assert(ie.modifiable); - ie = cast(IndexExp)ie.e1; + ie = ie.e1.isIndexExp(); ++depth; } @@ -3392,7 +3394,7 @@ public: // Normal case, ultimate parent AA already exists // We need to walk from the deepest index up, checking that an AA literal // already exists on each level. - lastIndex = interpretRegion((cast(IndexExp)e1).e2, istate); + lastIndex = interpretRegion(e1.isIndexExp().e2, istate); lastIndex = resolveSlice(lastIndex); // only happens with AA assignment if (exceptionOrCant(lastIndex)) return; @@ -3400,9 +3402,9 @@ public: while (depth > 0) { // Walk the syntax tree to find the indexExp at this depth - IndexExp xe = cast(IndexExp)e1; + IndexExp xe = e1.isIndexExp(); foreach (d; 0 .. depth) - xe = cast(IndexExp)xe.e1; + xe = xe.e1.isIndexExp(); Expression ekey = interpretRegion(xe.e2, istate); if (exceptionOrCant(ekey)) @@ -3450,9 +3452,9 @@ public: oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy(); Expression newaae = oldval; - while (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray) + while (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray) { - Expression ekey = interpretRegion((cast(IndexExp)e1).e2, istate); + Expression ekey = interpretRegion(e1.isIndexExp().e2, istate); if (exceptionOrCant(ekey)) return; ekey = resolveSlice(ekey); // only happens with AA assignment @@ -3463,7 +3465,7 @@ public: valuesx.push(newaae); auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx); - aae.type = (cast(IndexExp)e1).e1.type; + aae.type = e1.isIndexExp().e1.type; aae.ownedByCtfe = OwnedBy.ctfe; if (!existingAA) { @@ -3471,7 +3473,7 @@ public: lastIndex = ekey; } newaae = aae; - e1 = (cast(IndexExp)e1).e1; + e1 = e1.isIndexExp().e1; } // We must set to aggregate with newaae @@ -3521,11 +3523,11 @@ public: if (exceptionOrCant(e1)) return; - if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray) + if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray) { - IndexExp ie = cast(IndexExp)e1; + IndexExp ie = e1.isIndexExp(); assert(ie.e1.op == EXP.assocArrayLiteral); - existingAA = cast(AssocArrayLiteralExp)ie.e1; + existingAA = ie.e1.isAssocArrayLiteralExp(); lastIndex = ie.e2; } } @@ -3657,7 +3659,7 @@ public: // We have changed it into a reference assignment // Note that returnValue is still the new length. - e1 = (cast(ArrayLengthExp)e1).e1; + e1 = e1.isArrayLengthExp().e1; Type t = e1.type.toBasetype(); if (t.ty != Tarray) { @@ -3733,8 +3735,8 @@ public: if (auto dve = e1x.isDotVarExp()) { auto ex = dve.e1; - auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex) - : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value + auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp() + : ex.op == EXP.classReference ? ex.isClassReferenceExp().value : null; auto v = dve.var.isVarDeclaration(); if (!sle || !v) @@ -3792,10 +3794,10 @@ public: * e.v = newval */ auto ex = dve.e1; - auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex) - : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value + auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp() + : ex.op == EXP.classReference ? ex.isClassReferenceExp().value : null; - auto v = (cast(DotVarExp)e1).var.isVarDeclaration(); + auto v = e1.isDotVarExp().var.isVarDeclaration(); if (!sle || !v) { e.error("CTFE internal error: dotvar assignment"); @@ -3808,7 +3810,7 @@ public: } int fieldi = ex.op == EXP.structLiteral ? findFieldIndexByName(sle.sd, v) - : (cast(ClassReferenceExp)ex).findFieldIndexByName(v); + : ex.isClassReferenceExp().findFieldIndexByName(v); if (fieldi == -1) { e.error("CTFE internal error: cannot find field `%s` in `%s`", v.toChars(), ex.toChars()); @@ -3865,7 +3867,7 @@ public: return CTFEExp.cantexp; } - ArrayLiteralExp existingAE = cast(ArrayLiteralExp)aggregate; + ArrayLiteralExp existingAE = aggregate.isArrayLiteralExp(); if (existingAE.ownedByCtfe != OwnedBy.ctfe) { e.error("cannot modify read-only constant `%s`", existingAE.toChars()); @@ -3920,8 +3922,8 @@ public: assert(oldval.op == EXP.arrayLiteral); assert(newval.op == EXP.arrayLiteral); - Expressions* oldelems = (cast(ArrayLiteralExp)oldval).elements; - Expressions* newelems = (cast(ArrayLiteralExp)newval).elements; + Expressions* oldelems = oldval.isArrayLiteralExp().elements; + Expressions* newelems = newval.isArrayLiteralExp().elements; assert(oldelems.dim == newelems.dim); Type elemtype = oldval.type.nextOf(); @@ -4124,7 +4126,7 @@ public: if (newval.op == EXP.slice && !isBlockAssignment) { - auto se = cast(SliceExp)newval; + auto se = newval.isSliceExp(); auto aggr2 = se.e1; const srclower = se.lwr.toInteger(); const srcupper = se.upr.toInteger(); @@ -4140,7 +4142,7 @@ public: // https://issues.dlang.org/show_bug.cgi?id=14024 assert(aggr2.op == EXP.arrayLiteral); Expressions* oldelems = existingAE.elements; - Expressions* newelems = (cast(ArrayLiteralExp)aggr2).elements; + Expressions* newelems = aggr2.isArrayLiteralExp().elements; Type elemtype = aggregate.type.nextOf(); bool needsPostblit = e.e2.isLvalue(); @@ -4213,13 +4215,13 @@ public: /* Mixed slice: it was initialized as an array literal of chars/integers. * Now a slice of it is being set with a string. */ - sliceAssignArrayLiteralFromString(existingAE, cast(StringExp)newval, cast(size_t)firstIndex); + sliceAssignArrayLiteralFromString(existingAE, newval.isStringExp(), cast(size_t)firstIndex); return newval; } if (newval.op == EXP.arrayLiteral && !isBlockAssignment) { Expressions* oldelems = existingAE.elements; - Expressions* newelems = (cast(ArrayLiteralExp)newval).elements; + Expressions* newelems = newval.isArrayLiteralExp().elements; Type elemtype = existingAE.type.nextOf(); bool needsPostblit = e.op != EXP.blit && e.e2.isLvalue(); foreach (j, newelem; *newelems) @@ -4264,7 +4266,7 @@ public: if (!directblk && (*w)[k].op == EXP.arrayLiteral) { // Multidimensional array block assign - if (Expression ex = assignTo(cast(ArrayLiteralExp)(*w)[k])) + if (Expression ex = assignTo((*w)[k].isArrayLiteralExp())) return ex; } else if (refCopy) @@ -4420,7 +4422,7 @@ public: while (e.op == EXP.not) { ret *= -1; - e = (cast(NotExp)e).e1; + e = e.isNotExp().e1; } switch (e.op) { @@ -4430,8 +4432,8 @@ public: goto case; /+ fall through +/ case EXP.greaterThan: case EXP.greaterOrEqual: - *p1 = (cast(BinExp)e).e1; - *p2 = (cast(BinExp)e).e2; + *p1 = e.isBinExp().e1; + *p2 = e.isBinExp().e2; if (!(isPointer((*p1).type) && isPointer((*p2).type))) ret = 0; break; @@ -4898,7 +4900,7 @@ public: } } - if (fd && fd.semanticRun >= PASS.semantic3done && fd.semantic3Errors) + if (fd && fd.semanticRun >= PASS.semantic3done && fd.hasSemantic3Errors()) { e.error("CTFE failed because of previous errors in `%s`", fd.toChars()); result = CTFEExp.cantexp; @@ -5201,7 +5203,7 @@ public: // Pointer to a non-array variable if (agg.op == EXP.symbolOffset) { - e.error("mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), (cast(SymOffExp)agg).var.toChars()); + e.error("mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), agg.isSymOffExp().var.toChars()); return false; } @@ -5285,7 +5287,7 @@ public: e.error("index %llu exceeds array length %llu", index, iupr - ilwr); return false; } - *pagg = (cast(SliceExp)e1).e1; + *pagg = e1.isSliceExp().e1; *pidx = index + ilwr; } else @@ -5377,7 +5379,7 @@ public: assert(e1.op == EXP.assocArrayLiteral); UnionExp e2tmp = void; e2 = resolveSlice(e2, &e2tmp); - result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e1, e2); + result = findKeyInAA(e.loc, e1.isAssocArrayLiteralExp(), e2); if (!result) { e.error("key `%s` not found in associative array `%s`", e2.toChars(), e.e1.toChars()); @@ -5637,7 +5639,7 @@ public: } e1 = resolveSlice(e1); - result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e2, e1); + result = findKeyInAA(e.loc, e2.isAssocArrayLiteralExp(), e1); if (exceptionOrCant(result)) return; if (!result) @@ -5742,7 +5744,7 @@ public: return; } - auto cre = cast(ClassReferenceExp)result; + auto cre = result.isClassReferenceExp(); auto cd = cre.originalClass(); // Find dtor(s) in inheritance chain @@ -5859,10 +5861,10 @@ public: result = pue.exp(); return; } - if (e1.op == EXP.index && !(cast(IndexExp)e1).e1.type.equals(e1.type)) + if (e1.op == EXP.index && !e1.isIndexExp().e1.type.equals(e1.type)) { // type painting operation - IndexExp ie = cast(IndexExp)e1; + IndexExp ie = e1.isIndexExp(); if (castBackFromVoid) { // get the original type. For strings, it's just the type... @@ -5870,7 +5872,7 @@ public: // ..but for arrays of type void*, it's the type of the element if (ie.e1.op == EXP.arrayLiteral && ie.e2.op == EXP.int64) { - ArrayLiteralExp ale = cast(ArrayLiteralExp)ie.e1; + ArrayLiteralExp ale = ie.e1.isArrayLiteralExp(); const indx = cast(size_t)ie.e2.toInteger(); if (indx < ale.elements.dim) { @@ -5912,7 +5914,7 @@ public: { // &val[idx] dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger(); - IndexExp ie = cast(IndexExp)ae.e1; + IndexExp ie = ae.e1.isIndexExp(); Expression lwr = ie.e2; Expression upr = ctfeEmplaceExp!IntegerExp(ie.e2.loc, ie.e2.toInteger() + dim, Type.tsize_t); @@ -5938,7 +5940,7 @@ public: if (auto ve = e1.isVarExp()) emplaceExp!(VarExp)(pue, e.loc, ve.var); else - emplaceExp!(SymOffExp)(pue, e.loc, (cast(SymOffExp)e1).var, (cast(SymOffExp)e1).offset); + emplaceExp!(SymOffExp)(pue, e.loc, e1.isSymOffExp().var, e1.isSymOffExp().offset); result = pue.exp(); result.type = e.to; return; @@ -5966,7 +5968,7 @@ public: { // Note that the slice may be void[], so when checking for dangerous // casts, we need to use the original type, which is se.e1. - SliceExp se = cast(SliceExp)e1; + SliceExp se = e1.isSliceExp(); if (!isSafePointerCast(se.e1.type.nextOf(), e.to.nextOf())) { e.error("array cast from `%s` to `%s` is not supported at compile time", se.e1.type.toChars(), e.to.toChars()); @@ -6086,7 +6088,7 @@ public: { if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64) { - AddrExp ade = cast(AddrExp)ae.e1; + AddrExp ade = ae.e1.isAddrExp(); Expression ex = interpretRegion(ade.e1, istate); if (exceptionOrCant(ex)) return; @@ -6131,7 +6133,7 @@ public: } // *(&x) ==> x - result = (cast(AddrExp)result).e1; + result = result.isAddrExp().e1; if (result.op == EXP.slice && e.type.toBasetype().ty == Tsarray) { @@ -6211,8 +6213,8 @@ public: // We can't use getField, because it makes a copy if (ex.op == EXP.classReference) { - se = (cast(ClassReferenceExp)ex).value; - i = (cast(ClassReferenceExp)ex).findFieldIndexByName(v); + se = ex.isClassReferenceExp().value; + i = ex.isClassReferenceExp().findFieldIndexByName(v); } else if (ex.op == EXP.typeid_) { @@ -6233,7 +6235,7 @@ public: } else { - se = cast(StructLiteralExp)ex; + se = ex.isStructLiteralExp(); i = findFieldIndexByName(se.sd, v); } if (i == -1) @@ -6540,7 +6542,7 @@ private Expression scrubReturnValue(const ref Loc loc, Expression e) if (e.op == EXP.classReference) { - StructLiteralExp sle = (cast(ClassReferenceExp)e).value; + StructLiteralExp sle = e.isClassReferenceExp().value; if (auto ex = scrubSE(sle)) return ex; } @@ -6620,7 +6622,7 @@ private Expression scrubCacheValue(Expression e) if (e.op == EXP.classReference) { - if (auto ex = scrubSE((cast(ClassReferenceExp)e).value)) + if (auto ex = scrubSE(e.isClassReferenceExp().value)) return ex; } else if (auto sle = e.isStructLiteralExp()) @@ -6767,14 +6769,14 @@ private Expression copyRegionExp(Expression e) case EXP.vector: case EXP.dotVariable: { - UnaExp ue = cast(UnaExp)e; + UnaExp ue = e.isUnaExp(); ue.e1 = copyRegionExp(ue.e1); break; } case EXP.index: { - BinExp be = cast(BinExp)e; + BinExp be = e.isBinExp(); be.e1 = copyRegionExp(be.e1); be.e2 = copyRegionExp(be.e2); break; @@ -6939,7 +6941,7 @@ private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expressi Expressions args = Expressions(numParams); - AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)aa; + AssocArrayLiteralExp ae = aa.isAssocArrayLiteralExp(); if (!ae.keys || ae.keys.dim == 0) return ctfeEmplaceExp!IntegerExp(deleg.loc, 0, Type.tsize_t); Expression eresult; @@ -7298,7 +7300,7 @@ private Expression evaluateIfBuiltin(UnionExp* pue, InterState* istate, const re { // At present, the constructors just copy their arguments into the struct. // But we might need some magic if stack tracing gets added to druntime. - StructLiteralExp se = (cast(ClassReferenceExp)pthis).value; + StructLiteralExp se = pthis.isClassReferenceExp().value; assert(arguments.dim <= se.elements.dim); foreach (i, arg; *arguments) { diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d index 1e6799f..c3662a7 100644 --- a/gcc/d/dmd/dmangle.d +++ b/gcc/d/dmd/dmangle.d @@ -991,10 +991,6 @@ public: if (stc & STC.returninferred) stc &= ~(STC.return_ | STC.returninferred); - // 'return inout ref' is the same as 'inout ref' - if ((stc & (STC.return_ | STC.wild)) == (STC.return_ | STC.wild)) - stc &= ~STC.return_; - // much like hdrgen.stcToBuffer() string rrs; const isout = (stc & STC.out_) != 0; @@ -1365,5 +1361,3 @@ extern (D) const(char)[] externallyMangledIdentifier(Declaration d) } return null; } - - diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 35d2aba..c7e6418 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -662,7 +662,7 @@ extern (C++) final class Module : Package return true; // already read //printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars()); - if (auto result = FileManager.fileManager.lookup(srcfile)) + if (auto result = global.fileManager.lookup(srcfile)) { this.src = result.data; if (global.params.emitMakeDeps) diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index aa30b5d..c3a1d05 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -708,6 +708,31 @@ struct Scope return null; } + /******************************************** + * Find the lexically enclosing function (if any). + * + * This function skips through generated FuncDeclarations, + * e.g. rewritten foreach bodies. + * + * Returns: the function or null + */ + inout(FuncDeclaration) getEnclosingFunction() inout + { + if (!this.func) + return null; + + auto fd = cast(FuncDeclaration) this.func; + + // Look through foreach bodies rewritten as delegates + while (fd.fes) + { + assert(fd.fes.func); + fd = fd.fes.func; + } + + return cast(inout(FuncDeclaration)) fd; + } + /******************************************* * For TemplateDeclarations, we need to remember the Scope * where it was declared. So mark the Scope as not diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 9e50bd5..cb6c278 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -190,7 +190,7 @@ struct Visibility enum PASS : ubyte { - init, // initial state + initial, // initial state semantic, // semantic() started semanticdone, // semantic() done semantic2, // semantic2() started @@ -249,7 +249,7 @@ extern (C++) class Dsymbol : ASTNode Scope* _scope; // !=null means context to use for semantic() const(char)* prettystring; // cached value of toPrettyChars() bool errors; // this symbol failed to pass semantic() - PASS semanticRun = PASS.init; + PASS semanticRun = PASS.initial; ushort localNum; /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab DeprecatedDeclaration depdecl; // customized deprecation message @@ -621,7 +621,7 @@ extern (C++) class Dsymbol : ASTNode static bool has2This(Dsymbol s) { if (auto f = s.isFuncDeclaration()) - return f.isThis2; + return f.hasDualContext(); if (auto ad = s.isAggregateDeclaration()) return ad.vthis2 !is null; return false; @@ -2399,6 +2399,7 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds) { enum log = false; if (log) printf("handleTagSymbols('%s') add %p existing %p\n", s.toChars(), s, s2); + if (log) printf(" add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars()); auto sd = s.isScopeDsymbol(); // new declaration auto sd2 = s2.isScopeDsymbol(); // existing declaration @@ -2457,6 +2458,7 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds) sc._module.tagSymTab[cast(void*)s] = s2; return s; } + // neither s2 nor s is a tag if (log) printf(" collision\n"); return null; } @@ -2483,6 +2485,7 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy { enum log = false; if (log) printf("handleSymbolRedeclarations('%s')\n", s.toChars()); + if (log) printf(" add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars()); static Dsymbol collision() { @@ -2552,8 +2555,16 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy if (fd.fbody) // fd is the definition { + if (log) printf(" replace existing with new\n"); sds.symtab.update(fd); // replace fd2 in symbol table with fd fd.overnext = fd2; + + /* If fd2 is covering a tag symbol, then fd has to cover the same one + */ + auto ps = cast(void*)fd2 in sc._module.tagSymTab; + if (ps) + sc._module.tagSymTab[cast(void*)fd] = *ps; + return fd; } diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index aad0f2d..35500af 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -111,7 +111,7 @@ struct Visibility */ enum class PASS : uint8_t { - init, // initial state + initial, // initial state semantic, // semantic() started semanticdone, // semantic() done semantic2, // semantic2() started diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index b31dc9d..c990636 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -231,7 +231,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(AliasThis dsym) { - if (dsym.semanticRun != PASS.init) + if (dsym.semanticRun != PASS.initial) return; if (dsym._scope) @@ -346,7 +346,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor printf("linkage = %d\n", dsym.linkage); //if (strcmp(toChars(), "mul") == 0) assert(0); } - //if (semanticRun > PASS.init) + //if (semanticRun > PASS.initial) // return; //semanticRun = PSSsemantic; @@ -417,7 +417,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } //printf("inferring type for %s with init %s\n", dsym.toChars(), dsym._init.toChars()); dsym._init = dsym._init.inferType(sc); - dsym.type = dsym._init.initializerToExpression().type; + dsym.type = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0).type; if (needctfe) sc = sc.endCTFE(); @@ -527,7 +527,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor * and add those. */ size_t nelems = Parameter.dim(tt.arguments); - Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression() : null; + Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0) : null; if (ie) ie = ie.expressionSemantic(sc); if (nelems > 0 && ie) @@ -987,12 +987,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (ai && tb.ty == Taarray) e = ai.toAssocArrayLiteral(); else - e = dsym._init.initializerToExpression(); + e = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0); if (!e) { // Run semantic, but don't need to interpret dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITnointerpret); - e = dsym._init.initializerToExpression(); + e = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0); if (!e) { dsym.error("is not a static and cannot have static initializer"); @@ -1162,23 +1162,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor dsym.edtor = dsym.callScopeDtor(sc); if (dsym.edtor) { - /* If dsym is a local variable, who's type is a struct with a scope destructor, - * then make dsym scope, too. - */ - if (global.params.useDIP1000 == FeatureState.enabled && - !(dsym.storage_class & (STC.parameter | STC.temp | STC.field | STC.in_ | STC.foreach_ | STC.result | STC.manifest)) && - !dsym.isDataseg() && - !dsym.doNotInferScope && - dsym.type.hasPointers()) - { - auto tv = dsym.type.baseElemOf(); - if (tv.ty == Tstruct && - tv.isTypeStruct().sym.dtor.storage_class & STC.scope_) - { - dsym.storage_class |= STC.scope_; - } - } - if (sc.func && dsym.storage_class & (STC.static_ | STC.gshared)) dsym.edtor = dsym.edtor.expressionSemantic(sc._module._scope); else @@ -1256,7 +1239,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(Import imp) { //printf("Import::semantic('%s') %s\n", toPrettyChars(), id.toChars()); - if (imp.semanticRun > PASS.init) + if (imp.semanticRun > PASS.initial) return; if (imp._scope) @@ -1433,7 +1416,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor void attribSemantic(AttribDeclaration ad) { - if (ad.semanticRun != PASS.init) + if (ad.semanticRun != PASS.initial) return; ad.semanticRun = PASS.semantic; Dsymbols* d = ad.include(sc); @@ -1776,7 +1759,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } else if (auto f = s.isFuncDeclaration()) { - f.isCrtCtorDtor |= isCtor ? 1 : 2; + f.flags |= isCtor ? FUNCFLAG.CRTCtor : FUNCFLAG.CRTDtor; return 1; } else @@ -1990,7 +1973,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(Module m) { - if (m.semanticRun != PASS.init) + if (m.semanticRun != PASS.initial) return; //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent); m.semanticRun = PASS.semantic; @@ -2099,7 +2082,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor deferDsymbolSemantic(ed, scx); Module.dprogress = dprogress_save; //printf("\tdeferring %s\n", toChars()); - ed.semanticRun = PASS.init; + ed.semanticRun = PASS.initial; return; } else @@ -2503,7 +2486,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor printf("sc.stc = %llx\n", sc.stc); printf("sc.module = %s\n", sc._module.toChars()); } - if (tempdecl.semanticRun != PASS.init) + if (tempdecl.semanticRun != PASS.initial) return; // semantic() already run if (tempdecl._scope) @@ -2648,11 +2631,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor printf("+TemplateMixin.dsymbolSemantic('%s', this=%p)\n", tm.toChars(), tm); fflush(stdout); } - if (tm.semanticRun != PASS.init) + if (tm.semanticRun != PASS.initial) { // When a class/struct contains mixin members, and is done over // because of forward references, never reach here so semanticRun - // has been reset to PASS.init. + // has been reset to PASS.initial. static if (LOG) { printf("\tsemantic done\n"); @@ -2678,7 +2661,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor */ if (!tm.findTempDecl(sc) || !tm.semanticTiargs(sc) || !tm.findBestMatch(sc, null)) { - if (tm.semanticRun == PASS.init) // forward reference had occurred + if (tm.semanticRun == PASS.initial) // forward reference had occurred { //printf("forward reference - deferring\n"); return deferDsymbolSemantic(tm, scx); @@ -2865,7 +2848,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(Nspace ns) { - if (ns.semanticRun != PASS.init) + if (ns.semanticRun != PASS.initial) return; static if (LOG) { @@ -2989,7 +2972,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor printf("type: %p, %s\n", funcdecl.type, funcdecl.type.toChars()); } - if (funcdecl.semanticRun != PASS.init && funcdecl.isFuncLiteralDeclaration()) + if (funcdecl.semanticRun != PASS.initial && funcdecl.isFuncLiteralDeclaration()) { /* Member functions that have return types that are * forward references can have semantic() run more than @@ -3023,7 +3006,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor AggregateDeclaration ad = funcdecl.isThis(); // Don't nest structs b/c of generated methods which should not access the outer scopes. // https://issues.dlang.org/show_bug.cgi?id=16627 - if (ad && !funcdecl.generated) + if (ad && !funcdecl.isGenerated()) { funcdecl.storage_class |= ad.storage_class & (STC.TYPECTOR | STC.synchronized_); ad.makeNested(); @@ -3061,12 +3044,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor funcdecl.inlining = pragmadecl.evalPragmaInline(sc); // check pragma(crt_constructor) - if (funcdecl.isCrtCtorDtor) + if (funcdecl.flags & (FUNCFLAG.CRTCtor | FUNCFLAG.CRTDtor)) { if (funcdecl.linkage != LINK.c) { funcdecl.error("must be `extern(C)` for `pragma(%s)`", - funcdecl.isCrtCtorDtor == 1 ? "crt_constructor".ptr : "crt_destructor".ptr); + (funcdecl.flags & FUNCFLAG.CRTCtor) ? "crt_constructor".ptr : "crt_destructor".ptr); } } @@ -3293,7 +3276,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (sc.scopesym && sc.scopesym.isAggregateDeclaration()) funcdecl.error("`static` member has no `this` to which `return` can apply"); else - error(funcdecl.loc, "Top-level function `%s` has no `this` to which `return` can apply", funcdecl.toChars()); + error(funcdecl.loc, "top-level function `%s` has no `this` to which `return` can apply", funcdecl.toChars()); } if (funcdecl.isAbstract() && !funcdecl.isVirtual()) @@ -3524,7 +3507,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor else { //printf("\tintroducing function %s\n", funcdecl.toChars()); - funcdecl.introducing = 1; + funcdecl.flags |= FUNCFLAG.introducing; if (cd.classKind == ClassKind.cpp && target.cpp.reverseOverloads) { /* Overloaded functions with same name are grouped and in reverse order. @@ -3916,8 +3899,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } } - if (funcdecl.isMain()) - funcdecl.checkDmain(); // Check main() parameters and return type + funcdecl.checkMain(); // Check main() parameters and return type /* Purity and safety can be inferred for some functions by examining * the function body. @@ -4525,7 +4507,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (sd.errors) sd.type = Type.terror; - if (sd.semanticRun == PASS.init) + if (sd.semanticRun == PASS.initial) sd.type = sd.type.addSTC(sc.stc | sd.storage_class); sd.type = sd.type.typeSemantic(sd.loc, sc); if (auto ts = sd.type.isTypeStruct()) @@ -4539,7 +4521,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // Ungag errors when not speculative Ungag ungag = sd.ungagSpeculative(); - if (sd.semanticRun == PASS.init) + if (sd.semanticRun == PASS.initial) { sd.visibility = sc.visibility; @@ -4747,7 +4729,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (cldec.errors) cldec.type = Type.terror; - if (cldec.semanticRun == PASS.init) + if (cldec.semanticRun == PASS.initial) cldec.type = cldec.type.addSTC(sc.stc | cldec.storage_class); cldec.type = cldec.type.typeSemantic(cldec.loc, sc); if (auto tc = cldec.type.isTypeClass()) @@ -4761,7 +4743,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // Ungag errors when not speculative Ungag ungag = cldec.ungagSpeculative(); - if (cldec.semanticRun == PASS.init) + if (cldec.semanticRun == PASS.initial) { cldec.visibility = sc.visibility; @@ -5259,7 +5241,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor auto ctor = new CtorDeclaration(cldec.loc, Loc.initial, 0, tf); ctor.storage_class |= STC.inference; - ctor.generated = true; + ctor.flags |= FUNCFLAG.generated; ctor.fbody = new CompoundStatement(Loc.initial, new Statements()); cldec.members.push(ctor); @@ -5416,7 +5398,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // Ungag errors when not speculative Ungag ungag = idec.ungagSpeculative(); - if (idec.semanticRun == PASS.init) + if (idec.semanticRun == PASS.initial) { idec.visibility = sc.visibility; @@ -5750,7 +5732,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* } return; } - if (tempinst.semanticRun != PASS.init) + if (tempinst.semanticRun != PASS.initial) { static if (LOG) { @@ -5761,7 +5743,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* global.gag = 0; tempinst.error(tempinst.loc, "recursive template expansion"); if (tempinst.gagged) - tempinst.semanticRun = PASS.init; + tempinst.semanticRun = PASS.initial; else tempinst.inst = tempinst; tempinst.errors = true; @@ -5800,7 +5782,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* { // https://issues.dlang.org/show_bug.cgi?id=13220 // Roll back status for later semantic re-running - tempinst.semanticRun = PASS.init; + tempinst.semanticRun = PASS.initial; } else tempinst.inst = tempinst; @@ -6034,7 +6016,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* // Create our own scope for the template parameters Scope* _scope = tempdecl._scope; - if (tempdecl.semanticRun == PASS.init) + if (tempdecl.semanticRun == PASS.initial) { tempinst.error("template instantiation `%s` forward references template declaration `%s`", tempinst.toChars(), tempdecl.toChars()); return; @@ -6332,7 +6314,7 @@ Laftersemantic: target_symbol_list.remove(target_symbol_list_idx); tempinst.memberOf = null; // no longer a member } - tempinst.semanticRun = PASS.init; + tempinst.semanticRun = PASS.initial; tempinst.inst = null; tempinst.symtab = null; } @@ -6495,10 +6477,10 @@ void aliasSemantic(AliasDeclaration ds, Scope* sc) // Ungag errors when not instantiated DeclDefs scope alias auto ungag = Ungag(global.gag); - //printf("%s parent = %s, gag = %d, instantiated = %d\n", toChars(), parent, global.gag, isInstantiated()); - if (ds.parent && global.gag && !ds.isInstantiated() && !ds.toParent2().isFuncDeclaration()) + //printf("%s parent = %s, gag = %d, instantiated = %d\n", ds.toChars(), ds.parent.toChars(), global.gag, ds.isInstantiated() !is null); + if (ds.parent && global.gag && !ds.isInstantiated() && !ds.toParent2().isFuncDeclaration() && (sc.minst || sc.tinst)) { - //printf("%s type = %s\n", toPrettyChars(), type.toChars()); + //printf("%s type = %s\n", ds.toPrettyChars(), ds.type.toChars()); global.gag = 0; } @@ -6572,13 +6554,13 @@ void aliasSemantic(AliasDeclaration ds, Scope* sc) } if (s) // it's a symbolic alias { - //printf("alias %s resolved to %s %s\n", toChars(), s.kind(), s.toChars()); + //printf("alias %s resolved to %s %s\n", ds.toChars(), s.kind(), s.toChars()); ds.type = null; ds.aliassym = s; } else // it's a type alias { - //printf("alias %s resolved to type %s\n", toChars(), type.toChars()); + //printf("alias %s resolved to type %s\n", ds.toChars(), ds.type.toChars()); ds.type = ds.type.typeSemantic(ds.loc, sc); ds.aliassym = null; } diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 366ed60..a5ec63c 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -1173,7 +1173,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf); fd.parent = ti; - fd.inferRetType = true; + fd.flags |= FUNCFLAG.inferRetType; // Shouldn't run semantic on default arguments and return type. foreach (ref param; *tf.parameterList.parameters) @@ -2827,13 +2827,13 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, if (!sc) sc = td._scope; // workaround for Type.aliasthisOf - if (td.semanticRun == PASS.init && td._scope) + if (td.semanticRun == PASS.initial && td._scope) { // Try to fix forward reference. Ungag errors while doing so. Ungag ungag = td.ungagSpeculative(); td.dsymbolSemantic(td._scope); } - if (td.semanticRun == PASS.init) + if (td.semanticRun == PASS.initial) { .error(loc, "forward reference to template `%s`", td.toChars()); Lerror: @@ -2851,7 +2851,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, tiargs = new Objects(); auto ti = new TemplateInstance(loc, td, tiargs); Objects dedtypes = Objects(td.parameters.dim); - assert(td.semanticRun != PASS.init); + assert(td.semanticRun != PASS.initial); MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, fargs, 0); //printf("matchWithInstance = %d\n", mta); if (mta == MATCH.nomatch || mta < ta_last) // no match or less match @@ -6425,7 +6425,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol if (!td) return 0; - if (td.semanticRun == PASS.init) + if (td.semanticRun == PASS.initial) { if (td._scope) { @@ -6433,7 +6433,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol Ungag ungag = td.ungagSpeculative(); td.dsymbolSemantic(td._scope); } - if (td.semanticRun == PASS.init) + if (td.semanticRun == PASS.initial) { error("`%s` forward references template declaration `%s`", toChars(), td.toChars()); @@ -6786,7 +6786,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol (*tiargs)[j] = sa; TemplateDeclaration td = sa.isTemplateDeclaration(); - if (td && td.semanticRun == PASS.init && td.literal) + if (td && td.semanticRun == PASS.initial && td.literal) { td.dsymbolSemantic(sc); } @@ -6915,7 +6915,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol dedtypes.setDim(td.parameters.dim); dedtypes.zero(); - assert(td.semanticRun != PASS.init); + assert(td.semanticRun != PASS.initial); MATCH m = td.matchWithInstance(sc, this, &dedtypes, fargs, 0); //printf("matchWithInstance = %d\n", m); @@ -7093,7 +7093,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol extern (D) final bool needsTypeInference(Scope* sc, int flag = 0) { //printf("TemplateInstance.needsTypeInference() %s\n", toChars()); - if (semanticRun != PASS.init) + if (semanticRun != PASS.initial) return false; uint olderrs = global.errors; @@ -7174,7 +7174,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol */ dedtypes.setDim(td.parameters.dim); dedtypes.zero(); - if (td.semanticRun == PASS.init) + if (td.semanticRun == PASS.initial) { if (td._scope) { @@ -7182,7 +7182,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol Ungag ungag = td.ungagSpeculative(); td.dsymbolSemantic(td._scope); } - if (td.semanticRun == PASS.init) + if (td.semanticRun == PASS.initial) { error("`%s` forward references template declaration `%s`", toChars(), td.toChars()); return 1; @@ -7740,13 +7740,13 @@ extern (C++) final class TemplateMixin : TemplateInstance if (!td) return 0; - if (td.semanticRun == PASS.init) + if (td.semanticRun == PASS.initial) { if (td._scope) td.dsymbolSemantic(td._scope); else { - semanticRun = PASS.init; + semanticRun = PASS.initial; return 1; } } diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 46982e3..41fb82b 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -445,6 +445,9 @@ public: */ private void writeIdentifier(const AST.Dsymbol s, const bool canFix = false) { + if (const mn = getMangleOverride(s)) + return buf.writestring(mn); + writeIdentifier(s.ident, s.loc, s.kind(), canFix); } @@ -719,15 +722,20 @@ public: visited[cast(void*)fd] = true; // silently ignore non-user-defined destructors - if (fd.generated && fd.isDtorDeclaration()) + if (fd.isGenerated && fd.isDtorDeclaration()) return; // Note that tf might be null for templated (member) functions auto tf = cast(AST.TypeFunction)fd.type; - if ((tf && tf.linkage != LINK.c && tf.linkage != LINK.cpp) || (!tf && fd.isPostBlitDeclaration())) + if ((tf && (tf.linkage != LINK.c || adparent) && tf.linkage != LINK.cpp) || (!tf && fd.isPostBlitDeclaration())) { ignored("function %s because of linkage", fd.toPrettyChars()); - return checkVirtualFunction(fd); + return checkFunctionNeedsPlaceholder(fd); + } + if (fd.mangleOverride && tf && tf.linkage != LINK.c) + { + ignored("function %s because C++ doesn't support explicit mangling", fd.toPrettyChars()); + return checkFunctionNeedsPlaceholder(fd); } if (!adparent && !fd.fbody) { @@ -742,7 +750,7 @@ public: if (tf && !isSupportedType(tf.next)) { ignored("function %s because its return type cannot be mapped to C++", fd.toPrettyChars()); - return checkVirtualFunction(fd); + return checkFunctionNeedsPlaceholder(fd); } if (tf) foreach (i, fparam; tf.parameterList) { @@ -750,7 +758,7 @@ public: { ignored("function %s because one of its parameters has type `%s` which cannot be mapped to C++", fd.toPrettyChars(), fparam.type.toChars()); - return checkVirtualFunction(fd); + return checkFunctionNeedsPlaceholder(fd); } } @@ -822,13 +830,19 @@ public: } - /// Checks whether `fd` is a virtual function and emits a dummy declaration - /// if required to ensure proper vtable layout - private void checkVirtualFunction(AST.FuncDeclaration fd) + /++ + + Checks whether `fd` is a function that requires a dummy declaration + + instead of simply emitting the declaration (because it would cause + + ABI / behaviour issues). This includes: + + + + - virtual functions to ensure proper vtable layout + + - destructors that would break RAII + +/ + private void checkFunctionNeedsPlaceholder(AST.FuncDeclaration fd) { // Omit redundant declarations - the slot was already // reserved in the base class - if (fd.isVirtual() && fd.introducing) + if (fd.isVirtual() && fd.isIntroducing()) { // Hide placeholders because they are not ABI compatible writeProtection(AST.Visibility.Kind.private_); @@ -837,6 +851,15 @@ public: buf.printf("virtual void __vtable_slot_%u();", counter++); buf.writenl(); } + else if (fd.isDtorDeclaration()) + { + // Create inaccessible dtor to prevent code from keeping instances that + // need to be destroyed on the C++ side (but cannot call the dtor) + writeProtection(AST.Visibility.Kind.private_); + buf.writeByte('~'); + buf.writestring(adparent.ident.toString()); + buf.writestringln("();"); + } } override void visit(AST.UnitTestDeclaration utd) @@ -948,6 +971,11 @@ public: ignored("variable %s because of linkage", vd.toPrettyChars()); return; } + if (vd.mangleOverride && vd.linkage != LINK.c) + { + ignored("variable %s because C++ doesn't support explicit mangling", vd.toPrettyChars()); + return; + } if (!isSupportedType(type)) { ignored("variable %s because its type cannot be mapped to C++", vd.toPrettyChars()); @@ -1073,7 +1101,7 @@ public: auto fd = ad.aliassym.isFuncDeclaration(); - if (fd && (fd.generated || fd.isDtorDeclaration())) + if (fd && (fd.isGenerated() || fd.isDtorDeclaration())) { // Ignore. It's taken care of while visiting FuncDeclaration return; @@ -1106,7 +1134,7 @@ public: // Print prefix of the base class if this function originates from a superclass // because alias might be resolved through multiple classes, e.g. // e.g. for alias visit = typeof(super).visit in the visitors - if (!fd.introducing) + if (!fd.isIntroducing()) printPrefix(ad.toParent().isClassDeclaration().baseClass); else printPrefix(pd); @@ -1655,7 +1683,16 @@ public: scope(exit) printf("[typeToBuffer(AST.Type, AST.Dsymbol) exit] %s sym %s\n", t.toChars(), s.toChars()); } - this.ident = s.ident; + // The context pointer (represented as `ThisDeclaration`) is named + // `this` but accessible via `outer` + if (auto td = s.isThisDeclaration()) + { + import dmd.id; + this.ident = Id.outer; + } + else + this.ident = s.ident; + auto type = origType !is null ? origType : t; AST.Dsymbol customLength; @@ -1702,7 +1739,12 @@ public: if (this.ident) { buf.writeByte(' '); - writeIdentifier(s, canFixup); + // Custom identifier doesn't need further checks + if (this.ident !is s.ident) + buf.writestring(this.ident.toString()); + else + writeIdentifier(s, canFixup); + } this.ident = null; @@ -2922,6 +2964,10 @@ public: scope(exit) printf("[writeFullName exit] %s\n", sym.toPrettyChars()); } + // Explicit `pragma(mangle, "<some string>` overrides the declared name + if (auto mn = getMangleOverride(sym)) + return buf.writestring(mn); + /// Checks whether `sym` is nested in `par` and hence doesn't need the FQN static bool isNestedIn(AST.Dsymbol sym, AST.Dsymbol par) { @@ -2970,6 +3016,15 @@ public: else buf.writestring(sym.ident.toString()); } + + /// Returns: Explicit mangling for `sym` if present + extern(D) static const(char)[] getMangleOverride(const AST.Dsymbol sym) + { + if (auto decl = sym.isDeclaration()) + return decl.mangleOverride; + + return null; + } } /// Namespace for identifiers used to represent special enums in C++ @@ -3037,7 +3092,7 @@ void hashEndIf(ref OutBuffer buf) /// Writes `#define <content>` into the supplied buffer void hashDefine(ref OutBuffer buf, string content) { - buf.writestring("# define "); + buf.writestring("#define "); buf.writestringln(content); } diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index e9dcdc0..4196c05 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -692,9 +692,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag) // If va's lifetime encloses v's, then error if (va && !va.isDataseg() && - (va.enclosesLifetimeOf(v) && !(v.storage_class & STC.temp) || - vaIsRef || - va.isReference() && !(v.storage_class & (STC.parameter | STC.temp))) && + ((va.enclosesLifetimeOf(v) && !(v.storage_class & STC.temp)) || vaIsRef) && fd.setUnsafe()) { if (!gag) @@ -793,7 +791,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag) // If va's lifetime encloses v's, then error if (va && - (va.enclosesLifetimeOf(v) || (va.isRef() && !(va.storage_class & STC.temp)) || va.isDataseg()) && + (va.enclosesLifetimeOf(v) || (va.isReference() && !(va.storage_class & STC.temp)) || va.isDataseg()) && fd.setUnsafe()) { if (!gag) @@ -1284,27 +1282,24 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) { if (!gag) { - const(char)* msg, supplemental; - if (v.storage_class & STC.parameter && - (v.type.hasPointers() || v.storage_class & STC.ref_)) - { - msg = "returning `%s` escapes a reference to parameter `%s`"; - supplemental = vsr == ScopeRef.Ref_ReturnScope - ? "perhaps remove `scope` parameter annotation so `return` applies to `ref`" - : v.ident is Id.This - ? "perhaps annotate the function with `return`" - : "perhaps annotate the parameter with `return`"; - } - else + const(char)* varKind = v.isParameter() ? "parameter" : "local variable"; + previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, + "returning `%s` escapes a reference to %s `%s`", e.toChars(), varKind, v.toChars()); + + if (v.isParameter() && v.isReference()) { - msg = "returning `%s` escapes a reference to local variable `%s`"; - if (v.ident is Id.This) - supplemental = "perhaps annotate the function with `return`"; + if (v.storage_class & STC.returnScope) + { + previewSupplementalFunc(sc.isDeprecated(), featureState)(v.loc, + "perhaps change the `return scope` into `scope return`"); + } + else + { + const(char)* annotateKind = (v.ident is Id.This) ? "function" : "parameter"; + previewSupplementalFunc(sc.isDeprecated(), featureState)(v.loc, + "perhaps annotate the %s with `return`", annotateKind); + } } - - previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, msg, e.toChars(), v.toChars()); - if (supplemental) - previewSupplementalFunc(sc.isDeprecated(), featureState)(e.loc, supplemental); } result = true; } @@ -1897,7 +1892,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false) override void visit(ThisExp e) { - if (e.var && e.var.toParent2().isFuncDeclaration().isThis2) + if (e.var && e.var.toParent2().isFuncDeclaration().hasDualContext()) escapeByValue(e, er, live); else if (e.var) er.byref.push(e.var); @@ -2297,3 +2292,37 @@ bool isReferenceToMutable(Parameter p, Type t) } return isReferenceToMutable(p.type); } + +/********************************** +* Determine if `va` has a lifetime that lasts past +* the destruction of `v` +* Params: +* va = variable assigned to +* v = variable being assigned +* Returns: +* true if it does +*/ +private bool enclosesLifetimeOf(const VarDeclaration va, const VarDeclaration v) pure +{ + assert(va.sequenceNumber != va.sequenceNumber.init); + assert(v.sequenceNumber != v.sequenceNumber.init); + return va.sequenceNumber < v.sequenceNumber; +} + +/*************************************** + * Add variable `v` to maybes[] + * + * When a maybescope variable `v` is assigned to a maybescope variable `va`, + * we cannot determine if `this` is actually scope until the semantic + * analysis for the function is completed. Thus, we save the data + * until then. + * Params: + * v = an `STC.maybescope` variable that was assigned to `this` + */ +private void addMaybe(VarDeclaration va, VarDeclaration v) +{ + //printf("add %s to %s's list of dependencies\n", v.toChars(), toChars()); + if (!va.maybes) + va.maybes = new VarDeclarations(); + va.maybes.push(v); +} diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 7abfe7f..07d885b 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -170,7 +170,7 @@ FuncDeclaration hasThis(Scope* sc) { return null; } - if (!fd.isNested() || fd.isThis() || (fd.isThis2 && fd.isMember2())) + if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2())) break; Dsymbol parent = fd.parent; @@ -187,7 +187,7 @@ FuncDeclaration hasThis(Scope* sc) fd = parent.isFuncDeclaration(); } - if (!fd.isThis() && !(fd.isThis2 && fd.isMember2())) + if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2())) { return null; } @@ -1210,7 +1210,7 @@ extern (C++) abstract class Expression : ASTNode scope bool function(DtorDeclaration) check, const string checkName ) { auto dd = f.isDtorDeclaration(); - if (!dd || !dd.generated) + if (!dd || !dd.isGenerated()) return; // DtorDeclaration without parents should fail at an earlier stage @@ -1227,7 +1227,7 @@ extern (C++) abstract class Expression : ASTNode } dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:", - dd.generated ? "generated " : "".ptr, + dd.isGenerated() ? "generated " : "".ptr, ad.toChars, cast(int) checkName.length, checkName.ptr); @@ -1258,7 +1258,7 @@ extern (C++) abstract class Expression : ASTNode { field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars()); - if (fieldSd.dtor.generated) + if (fieldSd.dtor.isGenerated()) checkOverridenDtor(sc, fieldSd.dtor, check, checkName); else fieldSd.dtor.loc.errorSupplemental(" %.*s `%s.~this` is declared here", @@ -1288,7 +1288,7 @@ extern (C++) abstract class Expression : ASTNode return false; // magic variable never violates pure and safe if (v.isImmutable()) return false; // always safe and pure to access immutables... - if (v.isConst() && !v.isRef() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf())) + if (v.isConst() && !v.isReference() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf())) return false; // or const global/parameter values which have no mutable indirections if (v.storage_class & STC.manifest) return false; // ...or manifest constants @@ -3461,7 +3461,7 @@ extern (C++) final class ScopeExp : Expression //assert(ti.needsTypeInference(sc)); if (ti.tempdecl && ti.semantictiargsdone && - ti.semanticRun == PASS.init) + ti.semanticRun == PASS.initial) { error("partial %s `%s` has no type", sds.kind(), toChars()); return true; @@ -3859,7 +3859,7 @@ extern (C++) final class FuncExp : Expression { if (td) return new FuncExp(loc, td.syntaxCopy(null)); - else if (fd.semanticRun == PASS.init) + else if (fd.semanticRun == PASS.initial) return new FuncExp(loc, fd.syntaxCopy(null)); else // https://issues.dlang.org/show_bug.cgi?id=13481 // Prevent multiple semantic analysis of lambda body. @@ -4950,7 +4950,7 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp // Same logic as ScopeExp.checkType() if (ti.tempdecl && ti.semantictiargsdone && - ti.semanticRun == PASS.init) + ti.semanticRun == PASS.initial) { error("partial %s `%s` has no type", ti.kind(), toChars()); return true; @@ -4962,7 +4962,7 @@ extern (C++) final class DotTemplateInstanceExp : UnaExp { if (ti.tempdecl && ti.semantictiargsdone && - ti.semanticRun == PASS.init) + ti.semanticRun == PASS.initial) error("partial %s `%s` has no value", ti.kind(), toChars()); else diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 5802816..7b7c489 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -1046,7 +1046,7 @@ L1: if (e1.op == EXP.this_) { FuncDeclaration f = hasThis(sc); - if (f && f.isThis2) + if (f && f.hasDualContext()) { if (f.followInstantiationContext(ad)) { @@ -1444,13 +1444,6 @@ private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps) Expression ex = condexp.expressionSemantic(sc); if (ex.op == EXP.error) e = ex; - else if (e.op == EXP.function_ || e.op == EXP.delegate_) - { - // https://issues.dlang.org/show_bug.cgi?id=21285 - // Functions and delegates don't convert correctly with castTo below - exps[i] = condexp.e1; - e = condexp.e2; - } else { // Convert to common type @@ -1723,7 +1716,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, if (sc._module) sc._module.hasAlwaysInlines = true; if (sc.func) - sc.func.hasAlwaysInlines = true; + sc.func.flags |= FUNCFLAG.hasAlwaysInline; } const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration(); @@ -3743,7 +3736,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } - if (sd.hasRegularCtor() && nargs) + // https://issues.dlang.org/show_bug.cgi?id=22639 + // If the new expression has arguments, we either should call a + // regular constructor of a copy constructor if the first argument + // is the same type as the struct + if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf()))) { FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard); if (!f || f.errors) @@ -4201,30 +4198,27 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Type tthis = null; Expression e1org = exp.e1; - if (exp.e1.op == EXP.comma) + if (auto ce = exp.e1.isCommaExp()) { /* Rewrite (a,b)(args) as (a,(b(args))) */ - auto ce = cast(CommaExp)exp.e1; exp.e1 = ce.e2; ce.e2 = exp; result = ce.expressionSemantic(sc); return; } - if (exp.e1.op == EXP.delegate_) + if (DelegateExp de = exp.e1.isDelegateExp()) { - DelegateExp de = cast(DelegateExp)exp.e1; exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads); visit(exp); return; } - if (exp.e1.op == EXP.function_) + if (FuncExp fe = exp.e1.isFuncExp()) { if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments)) return setError(); // Run e1 semantic even if arguments have any errors - FuncExp fe = cast(FuncExp)exp.e1; exp.e1 = callExpSemantic(fe, sc, exp.arguments); if (exp.e1.op == EXP.error) { @@ -4252,9 +4246,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* This recognizes: * foo!(tiargs)(funcargs) */ - if (exp.e1.op == EXP.scope_) + if (ScopeExp se = exp.e1.isScopeExp()) { - ScopeExp se = cast(ScopeExp)exp.e1; TemplateInstance ti = se.sds.isTemplateInstance(); if (ti) { @@ -4300,9 +4293,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor * expr.foo!(tiargs)(funcargs) */ Ldotti: - if (exp.e1.op == EXP.dotTemplateInstance) + if (DotTemplateInstanceExp se = exp.e1.isDotTemplateInstanceExp()) { - DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)exp.e1; TemplateInstance ti = se.ti; { /* Attempt to instantiate ti. If that works, go with it. @@ -4347,9 +4339,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else { - if (exp.e1.op == EXP.dotIdentifier) + if (DotIdExp die = exp.e1.isDotIdExp()) { - DotIdExp die = cast(DotIdExp)exp.e1; exp.e1 = die.expressionSemantic(sc); /* Look for e1 having been rewritten to expr.opDispatch!(string) * We handle such earlier, so go back. @@ -4380,9 +4371,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* Look for e1 being a lazy parameter */ - if (exp.e1.op == EXP.variable) + if (VarExp ve = exp.e1.isVarExp()) { - VarExp ve = cast(VarExp)exp.e1; if (ve.var.storage_class & STC.lazy_) { // lazy parameters can be called without violating purity and safety @@ -4404,10 +4394,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.e1 = new VarExp(se.loc, se.var, true); exp.e1 = exp.e1.expressionSemantic(sc); } - else if (exp.e1.op == EXP.dot) + else if (DotExp de = exp.e1.isDotExp()) { - DotExp de = cast(DotExp)exp.e1; - if (de.e2.op == EXP.overloadSet) { ethis = de.e1; @@ -4490,7 +4478,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (sd.ctor) { auto ctor = sd.ctor.isCtorDeclaration(); - if (ctor && ctor.isCpCtor && ctor.generated) + if (ctor && ctor.isCpCtor && ctor.isGenerated()) sd.ctor = null; } @@ -4504,7 +4492,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor If all constructors are copy constructors, then try default construction. */ - if (!sd.hasRegularCtor) + if (!sd.hasRegularCtor && + // https://issues.dlang.org/show_bug.cgi?id=22639 + // we might still have a copy constructor that could be called + (*exp.arguments)[0].type.mutableOf != sd.type.mutableOf()) goto Lx; auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type); @@ -4850,10 +4841,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } } - else if (exp.e1.op == EXP.overloadSet) + else if (auto oe = exp.e1.isOverExp()) { - auto os = (cast(OverExp)exp.e1).vars; - exp.f = resolveOverloadSet(exp.loc, sc, os, tiargs, tthis, exp.arguments); + exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.arguments); if (!exp.f) return setError(); if (ethis) @@ -4877,11 +4867,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor const(char)* p; Dsymbol s; exp.f = null; - if (exp.e1.op == EXP.function_) + if (auto fe = exp.e1.isFuncExp()) { // function literal that direct called is always inferred. - assert((cast(FuncExp)exp.e1).fd); - exp.f = (cast(FuncExp)exp.e1).fd; + assert(fe.fd); + exp.f = fe.fd; tf = cast(TypeFunction)exp.f.type; p = "function literal"; } @@ -5011,11 +5001,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } t1 = tf; } - else if (exp.e1.op == EXP.variable) + else if (VarExp ve = exp.e1.isVarExp()) { // Do overload resolution - VarExp ve = cast(VarExp)exp.e1; - exp.f = ve.var.isFuncDeclaration(); assert(exp.f); tiargs = null; @@ -5162,7 +5150,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // declare dual-context container - if (exp.f && exp.f.isThis2 && !sc.intypeof && sc.func) + if (exp.f && exp.f.hasDualContext() && !sc.intypeof && sc.func) { // check access to second `this` if (AggregateDeclaration ad2 = exp.f.isMember2()) @@ -6042,13 +6030,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { auto fileName = FileName(name.toDString); - if (auto fmResult = FileManager.fileManager.lookup(fileName)) + if (auto fmResult = global.fileManager.lookup(fileName)) { se = new StringExp(e.loc, fmResult.data); } else { - auto readResult = File.read(name); + auto readResult = File.read(name.toDString); if (!readResult.success) { e.error("cannot read file `%s`", name); @@ -6060,9 +6048,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor auto data = readResult.extractSlice(); se = new StringExp(e.loc, data); - FileBuffer* fileBuffer = FileBuffer.create(); - fileBuffer.data = data; - FileManager.fileManager.add(fileName, fileBuffer); + FileBuffer* fileBuffer = new FileBuffer(data); + global.fileManager.add(fileName, fileBuffer); } } } @@ -6200,10 +6187,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor const op = exp.e1.op; bool isEqualsCallExpression; - if (op == EXP.call) + if (const callExp = exp.e1.isCallExp()) { - const callExp = cast(CallExp) exp.e1; - // https://issues.dlang.org/show_bug.cgi?id=20331 // callExp.f may be null if the assert contains a call to // a function pointer or literal @@ -6436,7 +6421,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else if (t) { - result = new IntegerExp(exp.loc, t.alignsize, Type.tsize_t); + // Note similarity to getProperty() implementation of __xalignof + const explicitAlignment = t.alignment(); + const naturalAlignment = t.alignsize(); + const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get()); + result = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t); } else if (s) { @@ -6643,7 +6632,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238 - (!v.needThis() && v.semanticRun > PASS.init))) // fix https://issues.dlang.org/show_bug.cgi?id=17258 + (!v.needThis() && v.semanticRun > PASS.initial))) // fix https://issues.dlang.org/show_bug.cgi?id=17258 { // (e1, v) checkAccess(exp.loc, sc, exp.e1, v); @@ -6736,7 +6725,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } result = e; // declare dual-context container - if (f.isThis2 && !sc.intypeof && sc.func) + if (f.hasDualContext() && !sc.intypeof && sc.func) { // check access to second `this` if (AggregateDeclaration ad2 = f.isMember2()) @@ -7311,7 +7300,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (checkNonAssignmentArrayOp(e.e1)) return setError(); - e.type = Type.tbool; + e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool; result = e; } @@ -7323,7 +7312,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // 3. Removal of keyword, "delete" can be used for other identities if (!exp.isRAII) { - error(exp.loc, "The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead."); + error(exp.loc, "the `delete` keyword is obsolete"); + errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead"); return setError(); } @@ -7847,9 +7837,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor */ if (VarDeclaration v = expToVariable(exp.e1)) { - if (exp.e1.op == EXP.dotVariable) + if (DotVarExp dve = exp.e1.isDotVarExp()) { - DotVarExp dve = cast(DotVarExp)exp.e1; + if ((dve.e1.op == EXP.this_ || dve.e1.op == EXP.super_) && !(v.storage_class & STC.ref_)) { @@ -8140,10 +8130,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = exp.e2; return; } - if (exp.e2.op == EXP.template_) + if (auto te = exp.e2.isTemplateExp()) { - auto td = (cast(TemplateExp)exp.e2).td; - Expression e = new DotTemplateExp(exp.loc, exp.e1, td); + Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td); result = e.expressionSemantic(sc); return; } @@ -8182,11 +8171,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor e.e2 = e.e2.arrayFuncConv(sc); e.type = e.e2.type; + result = e; + + if (sc.flags & SCOPE.Cfile) + return; + if (e.type is Type.tvoid) discardValue(e.e1); - else if (!e.allowCommaExp && !e.isGenerated && !(sc.flags & SCOPE.Cfile)) + else if (!e.allowCommaExp && !e.isGenerated) e.error("Using the result of a comma expression is not allowed"); - result = e; } override void visit(IntervalExp e) @@ -8472,6 +8465,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // OR it in, because it might already be set for C array indexing exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2)); } + else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray) + { + if (auto ve = exp.e1.isVarExp()) + { + /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2) + */ + auto vp = ve.castTo(sc, t1b.isTypeSArray().next.pointerTo()); + auto e = new AddExp(exp.loc, vp, exp.e2); + auto pe = new PtrExp(exp.loc, e); + result = pe.expressionSemantic(sc).optimize(WANTvalue); + return; + } + } } } @@ -10024,9 +10030,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } - if (exp.e1.op == EXP.slice) + if (SliceExp se = exp.e1.isSliceExp()) { - SliceExp se = cast(SliceExp)exp.e1; if (se.e1.type.toBasetype().ty == Tsarray) { exp.error("cannot append to static array `%s`", se.e1.type.toChars()); @@ -11270,7 +11275,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor e1x = e1x.optimize(WANTvalue); if (e1x.toBool().hasValue(exp.op == EXP.orOr)) { - result = IntegerExp.createBool(exp.op == EXP.orOr); + if (sc.flags & SCOPE.Cfile) + result = new IntegerExp(exp.op == EXP.orOr); + else + result = IntegerExp.createBool(exp.op == EXP.orOr); return; } } @@ -11315,7 +11323,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (e2x.type.ty == Tvoid) exp.type = Type.tvoid; else - exp.type = Type.tbool; + exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool; exp.e1 = e1x; exp.e2 = e2x; @@ -11412,7 +11420,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (f1 || f2) return setError(); - exp.type = Type.tbool; + exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool; // Special handling for array comparisons Expression arrayLowering = null; @@ -11690,7 +11698,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (f1 || f2) return setError(); - exp.type = Type.tbool; + exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool; if (!isArrayComparison) { @@ -11825,8 +11833,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } - if (exp.econd.op == EXP.dotIdentifier) - (cast(DotIdExp)exp.econd).noderef = true; + if (auto die = exp.econd.isDotIdExp()) + die.noderef = true; Expression ec = exp.econd.expressionSemantic(sc); ec = resolveProperties(sc, ec); @@ -12654,9 +12662,8 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag) if (e.op == EXP.error) return e; - if (e.op == EXP.dotVariable) + if (DotVarExp dve = e.isDotVarExp()) { - DotVarExp dve = cast(DotVarExp)e; if (FuncDeclaration fd = dve.var.isFuncDeclaration()) { if (TemplateDeclaration td = fd.findTemplateDeclRoot()) @@ -12707,9 +12714,8 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag) } } - if (e.op == EXP.dotTemplateDeclaration) + if (DotTemplateExp dte = e.isDotTemplateExp()) { - DotTemplateExp dte = cast(DotTemplateExp)e; exp.e1 = dte.e1; // pull semantic() result exp.ti.tempdecl = dte.td; @@ -12738,10 +12744,8 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag) return new ScopeExp(exp.loc, exp.ti) .expressionSemantic(sc); } - else if (e.op == EXP.dot) + else if (DotExp de = e.isDotExp()) { - DotExp de = cast(DotExp)e; - if (de.e2.op == EXP.overloadSet) { if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc)) @@ -12765,9 +12769,8 @@ Expression semanticY(DotTemplateInstanceExp exp, Scope* sc, int flag) .expressionSemantic(sc); } } - else if (e.op == EXP.overloadSet) + else if (OverExp oe = e.isOverExp()) { - OverExp oe = cast(OverExp)e; exp.ti.tempdecl = oe.vars; return new ScopeExp(exp.loc, exp.ti) .expressionSemantic(sc); @@ -13055,7 +13058,7 @@ Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, Aggre { n++; e1 = new VarExp(loc, f.vthis); - if (f.isThis2) + if (f.hasDualContext()) { // (*__this)[i] if (n > 1) @@ -13355,8 +13358,8 @@ Expression toBoolean(Expression exp, Scope* sc) default: // Default is 'yes' - do nothing - Expression e = exp; - Type t = exp.type; + Expression e = arrayFuncConv(exp, sc); + Type t = e.type; Type tb = t.toBasetype(); Type att = null; diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d index 9ba3807..b86c799 100644 --- a/gcc/d/dmd/file_manager.d +++ b/gcc/d/dmd/file_manager.d @@ -20,10 +20,15 @@ import dmd.identifier; enum package_d = "package." ~ mars_ext; enum package_di = "package." ~ hdr_ext; -struct FileManager +final class FileManager { private StringTable!(FileBuffer*) files; - private __gshared bool initialized = false; + + /// + public this () nothrow + { + this.files._init(); + } nothrow: /******************************************** @@ -143,9 +148,6 @@ nothrow: */ const(FileBuffer)* lookup(FileName filename) { - if (!initialized) - FileManager._init(); - const name = filename.toString; if (auto val = files.lookup(name)) return val.value; @@ -182,9 +184,6 @@ nothrow: */ const(char)[][] getLines(FileName file) { - if (!initialized) - FileManager._init(); - const(char)[][] lines; if (const buffer = lookup(file)) { @@ -241,29 +240,9 @@ nothrow: */ FileBuffer* add(FileName filename, FileBuffer* filebuffer) { - if (!initialized) - FileManager._init(); - auto val = files.insert(filename.toString, filebuffer); return val == null ? null : val.value; } - - __gshared fileManager = FileManager(); - - // Initialize the global FileManager singleton - private void _init() - { - if (!initialized) - { - fileManager.initialize(); - initialized = true; - } - } - - void initialize() - { - files._init(); - } } private FileBuffer readFromStdin() nothrow diff --git a/gcc/d/dmd/foreachvar.d b/gcc/d/dmd/foreachvar.d index b779eae..53ed62e 100644 --- a/gcc/d/dmd/foreachvar.d +++ b/gcc/d/dmd/foreachvar.d @@ -320,4 +320,3 @@ void foreachExpAndVar(Statement s, visit(s); } - diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index afc0ebb..8d83951 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -140,7 +140,7 @@ public: override void visit(TryFinallyStatement s) { DtorExpStatement des; - if (fd.nrvo_can && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null && + if (fd.isNRVO() && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null && fd.nrvo_var == des.var) { if (!(global.params.useExceptions && ClassDeclaration.throwable)) @@ -182,7 +182,7 @@ public: catches.push(ctch); Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches); - fd.eh_none = false; + fd.flags &= ~FUNCFLAG.noEH; replaceCurrent(s2); s2.accept(this); } @@ -205,6 +205,17 @@ enum FUNCFLAG : uint printf = 0x200, /// is a printf-like function scanf = 0x400, /// is a scanf-like function noreturn = 0x800, /// the function does not return + NRVO = 0x1000, /// Support for named return value optimization + naked = 0x2000, /// The function is 'naked' (see inline ASM) + generated = 0x4000, /// The function is compiler generated (e.g. `opCmp`) + introducing = 0x8000, /// If this function introduces the overload set + semantic3Errors = 0x10000, /// If errors in semantic3 this function's frame ptr + noEH = 0x20000, /// No exception unwinding is needed + inferRetType = 0x40000, /// Return type is to be inferred + dualContext = 0x80000, /// has a dual-context 'this' parameter + hasAlwaysInline = 0x100000, /// Contains references to functions that must be inlined + CRTCtor = 0x200000, /// Has attribute pragma(crt_constructor) + CRTDtor = 0x400000, /// Has attribute pragma(crt_destructor) } /*********************************************************** @@ -268,7 +279,6 @@ extern (C++) class FuncDeclaration : Declaration // scopes from having the same name DsymbolTable localsymtab; VarDeclaration vthis; /// 'this' parameter (member and nested) - bool isThis2; /// has a dual-context 'this' parameter VarDeclaration v_arguments; /// '_arguments' parameter VarDeclaration v_argptr; /// '_argptr' variable @@ -278,31 +288,21 @@ extern (C++) class FuncDeclaration : Declaration FuncDeclaration overnext0; /// next in overload list (only used during IFTI) Loc endloc; /// location of closing curly bracket int vtblIndex = -1; /// for member functions, index into vtbl[] - bool naked; /// true if naked - bool generated; /// true if function was generated by the compiler rather than - /// supplied by the user - bool hasAlwaysInlines; /// contains references to functions that must be inlined - ubyte isCrtCtorDtor; /// has attribute pragma(crt_constructor(1)/crt_destructor(2)) - /// not set before the glue layer ILS inlineStatusStmt = ILS.uninitialized; ILS inlineStatusExp = ILS.uninitialized; PINLINE inlining = PINLINE.default_; int inlineNest; /// !=0 if nested inline - bool eh_none; /// true if no exception unwinding is needed - bool semantic3Errors; /// true if errors in semantic3 this function's frame ptr ForeachStatement fes; /// if foreach body, this is the foreach BaseClass* interfaceVirtual; /// if virtual, but only appears in base interface vtbl[] - bool introducing; /// true if 'introducing' function /** if !=NULL, then this is the type of the 'introducing' function this one is overriding */ Type tintro; - bool inferRetType; /// true if return type is to be inferred StorageClass storage_class2; /// storage class for template onemember's // Things that should really go into Scope @@ -314,8 +314,6 @@ extern (C++) class FuncDeclaration : Declaration /// 16 if there are multiple return statements int hasReturnExp; - // Support for NRVO (named return value optimization) - bool nrvo_can = true; /// true means we can do NRVO VarDeclaration nrvo_var; /// variable to replace with shidden Symbol* shidden; /// hidden pointer passed to function @@ -346,7 +344,9 @@ extern (C++) class FuncDeclaration : Declaration FuncDeclarations *inlinedNestedCallees; - uint flags; /// FUNCFLAG.xxxxx + /// Function flags: A collection of boolean packed for memory efficiency + /// See the `FUNCFLAG` enum + uint flags = FUNCFLAG.NRVO; /** * Data for a function declaration that is needed for the Objective-C @@ -374,7 +374,8 @@ extern (C++) class FuncDeclaration : Declaration /* The type given for "infer the return type" is a TypeFunction with * NULL for the return type. */ - inferRetType = (type && type.nextOf() is null); + if (type && type.nextOf() is null) + this.flags |= FUNCFLAG.inferRetType; } static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false) @@ -480,7 +481,7 @@ extern (C++) class FuncDeclaration : Declaration return false; } - return !errors && !semantic3Errors; + return !errors && !this.hasSemantic3Errors(); } /**************************************************** @@ -515,9 +516,11 @@ extern (C++) class FuncDeclaration : Declaration */ extern (D) final void declareThis(Scope* sc) { - isThis2 = toParent2() != toParentLocal(); + const bool dualCtx = (toParent2() != toParentLocal()); + if (dualCtx) + this.flags |= FUNCFLAG.dualContext; auto ad = isThis(); - if (!isThis2 && !ad && !isNested()) + if (!dualCtx && !ad && !isNested()) { vthis = null; objc.selectorParameter = null; @@ -529,16 +532,16 @@ extern (C++) class FuncDeclaration : Declaration return t.addMod(type.mod).addStorageClass(storage_class); } - if (isThis2 || isNested()) + if (dualCtx || isNested()) { /* The 'this' for a nested function is the link to the * enclosing function's stack frame. * Note that nested functions and member functions are disjoint. */ - Type tthis = addModStc(isThis2 ? + Type tthis = addModStc(dualCtx ? Type.tvoidptr.sarrayOf(2).pointerTo() : Type.tvoid.pointerTo()); - vthis = new VarDeclaration(loc, tthis, isThis2 ? Id.this2 : Id.capture, null); + vthis = new VarDeclaration(loc, tthis, dualCtx ? Id.this2 : Id.capture, null); vthis.storage_class |= STC.parameter | STC.nodtor; } else if (ad) @@ -549,22 +552,6 @@ extern (C++) class FuncDeclaration : Declaration if (thandle.ty == Tstruct) { vthis.storage_class |= STC.ref_; - - /* if member function is marked 'inout', then 'this' is 'return ref' - * The same thing is done for `ref inout` parameters in TypeFunction's semantic routine. - */ - if (auto tf = type.isTypeFunction()) - { - /* This feature was a mistake, but existing code relies on it. - * So only disable it in @safe code and DIP1000 code - */ - if (!(global.params.useDIP1000 == FeatureState.enabled && - tf.trust == TRUST.safe)) - { - if (tf.isInOutQual()) - vthis.storage_class |= STC.return_; - } - } } } @@ -574,19 +561,8 @@ extern (C++) class FuncDeclaration : Declaration vthis.storage_class |= STC.return_; if (tf.isScopeQual) vthis.storage_class |= STC.scope_; - - /* Add STC.returnScope like typesem.d does for TypeFunction parameters, - * at least it should be the same. At the moment, we'll just - * do existing practice. But we should examine how TypeFunction does - * it, for consistency. - */ - if (global.params.useDIP1000 != FeatureState.enabled && - !tf.isref && isRefReturnScope(vthis.storage_class)) - { - /* if `ref return scope`, evaluate to `ref` `return scope` - */ + if (tf.isreturnscope) vthis.storage_class |= STC.returnScope; - } } if (flags & FUNCFLAG.inferScope && !(vthis.storage_class & STC.scope_)) vthis.storage_class |= STC.maybescope; @@ -1369,7 +1345,7 @@ extern (C++) class FuncDeclaration : Declaration if (!tf.isnogc) flags |= FUNCFLAG.nogcInprocess; - if (!isVirtual() || introducing) + if (!isVirtual() || this.isIntroducing()) flags |= FUNCFLAG.returnInprocess; // Initialize for inferring STC.scope_ @@ -1482,6 +1458,73 @@ extern (C++) class FuncDeclaration : Declaration return !(flags & FUNCFLAG.nogcInprocess) && isNogc(); } + final bool isNRVO() const scope @safe pure nothrow @nogc + { + return !!(this.flags & FUNCFLAG.NRVO); + } + + final void isNRVO(bool v) pure nothrow @safe @nogc + { + if (v) this.flags |= FUNCFLAG.NRVO; + else this.flags &= ~FUNCFLAG.NRVO; + } + + final bool isNaked() const scope @safe pure nothrow @nogc + { + return !!(this.flags & FUNCFLAG.naked); + } + + final bool isGenerated() const scope @safe pure nothrow @nogc + { + return !!(this.flags & FUNCFLAG.generated); + } + + final void isGenerated(bool v) pure nothrow @safe @nogc + { + if (v) this.flags |= FUNCFLAG.generated; + else this.flags &= ~FUNCFLAG.generated; + } + + final bool isIntroducing() const scope @safe pure nothrow @nogc + { + return !!(this.flags & FUNCFLAG.introducing); + } + + final bool hasSemantic3Errors() const scope @safe pure nothrow @nogc + { + return !!(this.flags & FUNCFLAG.semantic3Errors); + } + + final bool hasNoEH() const scope @safe pure nothrow @nogc + { + return !!(this.flags & FUNCFLAG.noEH); + } + + final bool inferRetType() const scope @safe pure nothrow @nogc + { + return !!(this.flags & FUNCFLAG.inferRetType); + } + + final bool hasDualContext() const scope @safe pure nothrow @nogc + { + return !!(this.flags & FUNCFLAG.dualContext); + } + + final bool hasAlwaysInlines() const scope @safe pure nothrow @nogc + { + return !!(this.flags & FUNCFLAG.hasAlwaysInline); + } + + final bool isCrtCtor() const scope @safe pure nothrow @nogc + { + return !!(this.flags & FUNCFLAG.CRTCtor); + } + + final bool isCrtDtor() const scope @safe pure nothrow @nogc + { + return !!(this.flags & FUNCFLAG.CRTDtor); + } + /************************************** * The function is doing something that may allocate with the GC, * so mark it as not nogc (not no-how). @@ -1809,19 +1852,19 @@ extern (C++) class FuncDeclaration : Declaration { auto ad = isThis(); ClassDeclaration cd = ad ? ad.isClassDeclaration() : null; - return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !naked); + return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !this.isNaked()); } bool addPostInvariant() { auto ad = isThis(); ClassDeclaration cd = ad ? ad.isClassDeclaration() : null; - return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !naked); + return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !this.isNaked()); } override const(char)* kind() const { - return generated ? "generated function" : "function"; + return this.isGenerated() ? "generated function" : "function"; } /******************************************** @@ -2163,7 +2206,7 @@ extern (C++) class FuncDeclaration : Declaration vresult.parent = this; } - if (sc && vresult.semanticRun == PASS.init) + if (sc && vresult.semanticRun == PASS.initial) { TypeFunction tf = type.toTypeFunction(); if (tf.isref) @@ -2609,35 +2652,124 @@ extern (C++) class FuncDeclaration : Declaration return fd; } - /****************** - * Check parameters and return type of D main() function. - * Issue error messages. - */ - extern (D) final void checkDmain() - { + /+ + + Checks the parameter and return types iff this is a `main` function. + + + + The following signatures are allowed for a `D main`: + + - Either no or a single parameter of type `string[]` + + - Return type is either `void`, `int` or `noreturn` + + + + The following signatures are standard C: + + - `int main()` + + - `int main(int, char**)` + + + + This function accepts the following non-standard extensions: + + - `char** envp` as a third parameter + + - `void` / `noreturn` as return type + + + + This function will issue errors for unexpected arguments / return types. + +/ + extern (D) final void checkMain() + { + if (ident != Id.main || isMember() || isNested()) + return; // Not a main function + TypeFunction tf = type.toTypeFunction(); + + Type retType = tf.nextOf(); + if (!retType) + { + // auto main(), check after semantic + assert(this.inferRetType); + return; + } + + /// Checks whether `t` is equivalent to `char**` + /// Ignores qualifiers and treats enums according to their base type + static bool isCharPtrPtr(Type t) + { + auto tp = t.toBasetype().isTypePointer(); + if (!tp) + return false; + + tp = tp.next.toBasetype().isTypePointer(); + if (!tp) + return false; + + return tp.next.toBasetype().ty == Tchar; + } + + // Neither of these qualifiers is allowed because they affect the ABI + enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_; + const nparams = tf.parameterList.length; bool argerr; - if (nparams == 1) + + if (linkage == LINK.d) { - auto fparam0 = tf.parameterList[0]; - auto t = fparam0.type.toBasetype(); - if (t.ty != Tarray || - t.nextOf().ty != Tarray || - t.nextOf().nextOf().ty != Tchar || - fparam0.storageClass & (STC.out_ | STC.ref_ | STC.lazy_)) + if (nparams == 1) { - argerr = true; + auto fparam0 = tf.parameterList[0]; + auto t = fparam0.type.toBasetype(); + if (t.ty != Tarray || + t.nextOf().ty != Tarray || + t.nextOf().nextOf().ty != Tchar || + fparam0.storageClass & invalidSTC) + { + argerr = true; + } } + + if (tf.parameterList.varargs || nparams >= 2 || argerr) + error("parameter list must be empty or accept one parameter of type `string[]`"); } - if (!tf.nextOf()) - // auto main(), check after semantic - assert(this.inferRetType); - else if (tf.nextOf().ty != Tint32 && tf.nextOf().ty != Tvoid && tf.nextOf().ty != Tnoreturn) + else if (linkage == LINK.c) + { + if (nparams == 2 || nparams == 3) + { + // Argument count must be int + auto argCount = tf.parameterList[0]; + argerr |= !!(argCount.storageClass & invalidSTC); + argerr |= argCount.type.toBasetype().ty != Tint32; + + // Argument pointer must be char** + auto argPtr = tf.parameterList[1]; + argerr |= !!(argPtr.storageClass & invalidSTC); + argerr |= !isCharPtrPtr(argPtr.type); + + // `char** environ` is a common extension, see J.5.1 of the C standard + if (nparams == 3) + { + auto envPtr = tf.parameterList[2]; + argerr |= !!(envPtr.storageClass & invalidSTC); + argerr |= !isCharPtrPtr(envPtr.type); + } + } + else + argerr = nparams != 0; + + // Disallow variadic main() - except for K&R declarations in C files. + // E.g. int main(), int main(argc, argv) int argc, char** argc { ... } + if (tf.parameterList.varargs && (!this.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams))) + argerr |= true; + + if (argerr) + { + error("parameters must match one of the following signatures"); + loc.errorSupplemental("`main()`"); + loc.errorSupplemental("`main(int argc, char** argv)`"); + loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]"); + } + } + else + return; // Neither C nor D main, ignore (should probably be an error) + + // Allow enums with appropriate base types (same ABI) + retType = retType.toBasetype(); + + if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn) error("must return `int`, `void` or `noreturn`, not `%s`", tf.nextOf().toChars()); - else if (tf.parameterList.varargs || nparams >= 2 || argerr) - error("parameters must be `main()` or `main(string[] args)`"); } /*********************************************** @@ -2649,7 +2781,7 @@ extern (C++) class FuncDeclaration : Declaration */ final bool checkNRVO() { - if (!nrvo_can || returns is null) + if (!isNRVO() || returns is null) return false; auto tf = type.toTypeFunction(); @@ -2661,7 +2793,7 @@ extern (C++) class FuncDeclaration : Declaration if (auto ve = rs.exp.isVarExp()) { auto v = ve.var.isVarDeclaration(); - if (!v || v.isOut() || v.isRef()) + if (!v || v.isReference()) return false; else if (nrvo_var is null) { @@ -2669,6 +2801,8 @@ extern (C++) class FuncDeclaration : Declaration // parameters and closure variables cannot be NRVOed. if (v.isDataseg() || v.isParameter() || v.toParent2() != this) return false; + if (v.nestedrefs.length && needsClosure()) + return false; // The variable type needs to be equivalent to the return type. if (!v.type.equivalent(tf.next)) return false; diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index 6697a05..6b6655c 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -15,6 +15,7 @@ import core.stdc.stdint; import dmd.root.array; import dmd.root.filename; import dmd.common.outbuffer; +import dmd.file_manager; import dmd.identifier; /// Defines a setting for how compiler warnings and deprecations are handled @@ -329,6 +330,9 @@ extern (C++) struct Global bool hasMainFunction; /// Whether a main function has already been compiled in (for -main switch) uint varSequenceNumber = 1; /// Relative lifetime of `VarDeclaration` within a function, used for `scope` checks + /// Cache files read from disk + FileManager fileManager; + enum recursionLimit = 500; /// number of recursive template expansions before abort nothrow: @@ -383,6 +387,7 @@ extern (C++) struct Global extern (C++) void _init() { + this.fileManager = new FileManager(); version (MARS) { vendor = "Digital Mars D"; diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 9bbe0c9..2a33692 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -19,6 +19,8 @@ // Can't include arraytypes.h here, need to declare these directly. template <typename TYPE> struct Array; +class FileManager; + typedef unsigned char Diagnostic; enum { @@ -292,6 +294,8 @@ struct Global bool hasMainFunction; unsigned varSequenceNumber; + FileManager* fileManager; + /* Start gagging. Return the current number of gagged errors */ unsigned startGagging(); diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index f2552d4..a3afbe5 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -1836,25 +1836,12 @@ public: t = te.sym.memtype; goto L1; } + case Tchar: case Twchar: - // BUG: need to cast(wchar) case Tdchar: - // BUG: need to cast(dchar) - if (cast(uinteger_t)v > 0xFF) - { - buf.printf("'\\U%08llx'", cast(long)v); - break; - } - goto case; - case Tchar: { - size_t o = buf.length; - if (v == '\'') - buf.writestring("'\\''"); - else if (isprint(cast(int)v) && v != '\\') - buf.printf("'%c'", cast(int)v); - else - buf.printf("'\\x%02x'", cast(int)v); + const o = buf.length; + writeSingleCharLiteral(*buf, cast(dchar) v); if (hgs.ddoc) escapeDdocString(buf, o); break; @@ -2761,9 +2748,15 @@ bool stcToBuffer(OutBuffer* buf, StorageClass stc) bool result = false; if (stc & STC.scopeinferred) + { + //buf.writestring("scope-inferred "); stc &= ~(STC.scope_ | STC.scopeinferred); + } if (stc & STC.returninferred) + { + //buf.writestring("return-inferred "); stc &= ~(STC.return_ | STC.returninferred); + } /* Put scope ref return into a standard order */ diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d index ec44ee0..bcfbd9a 100644 --- a/gcc/d/dmd/importc.d +++ b/gcc/d/dmd/importc.d @@ -285,7 +285,7 @@ bool cFuncEquivalence(TypeFunction tf1, TypeFunction tf2) if (tf1.parameterList.length == 0 && tf2.parameterList.length == 0) return true; - if (!tf1.nextOf().equals(tf2.nextOf())) + if (!cTypeEquivalence(tf1.next, tf2.next)) return false; // function return types don't match if (tf1.parameterList.length != tf2.parameterList.length) @@ -318,3 +318,40 @@ bool cFuncEquivalence(TypeFunction tf1, TypeFunction tf2) //printf("t2: %s\n", tf2.toChars()); return true; } + +/******************************* + * Types haven't been merged yet, because we haven't done + * semantic() yet. + * But we still need to see if t1 and t2 are the same type. + * Params: + * t1 = first type + * t2 = second type + * Returns: + * true if they are equivalent types + */ +bool cTypeEquivalence(Type t1, Type t2) +{ + if (t1.equals(t2)) + return true; // that was easy + + if (t1.ty != t2.ty || t1.mod != t2.mod) + return false; + + if (auto tp = t1.isTypePointer()) + return cTypeEquivalence(tp.next, t2.nextOf()); + + if (auto ta = t1.isTypeSArray()) + // Bug: should check array dimension + return cTypeEquivalence(ta.next, t2.nextOf()); + + if (auto ts = t1.isTypeStruct()) + return ts.sym is t2.isTypeStruct().sym; + + if (auto te = t1.isTypeEnum()) + return te.sym is t2.isTypeEnum().sym; + + if (auto tf = t1.isTypeFunction()) + return cFuncEquivalence(tf, tf.isTypeFunction()); + + return false; +} diff --git a/gcc/d/dmd/init.h b/gcc/d/dmd/init.h index c6c8c62..73dc4bb 100644 --- a/gcc/d/dmd/init.h +++ b/gcc/d/dmd/init.h @@ -114,4 +114,4 @@ public: void accept(Visitor *v) { v->visit(this); } }; -Expression *initializerToExpression(Initializer *init, Type *t = NULL); +Expression *initializerToExpression(Initializer *init, Type *t = NULL, const bool isCfile = false); diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index bc02bf9..649d88e 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -1080,10 +1080,11 @@ Initializer inferType(Initializer init, Scope* sc) * Params: * init = `Initializer` AST node * itype = if not `null`, type to coerce expression to + * isCfile = default initializers are different with C * Returns: * `Expression` created, `null` if cannot, `ErrorExp` for other errors */ -extern (C++) Expression initializerToExpression(Initializer init, Type itype = null) +extern (C++) Expression initializerToExpression(Initializer init, Type itype = null, const bool isCfile = false) { Expression visitVoid(VoidInitializer) { @@ -1204,7 +1205,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n if (!init.type) // don't know what type to use return null; if (!defaultInit) - defaultInit = (cast(TypeNext)t).next.defaultInit(Loc.initial); + defaultInit = (cast(TypeNext)t).next.defaultInit(Loc.initial, isCfile); element = defaultInit; } } diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index 3ff2eae..7cd4bfd 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -77,6 +77,7 @@ class Lexer bool doDocComment; // collect doc comment information bool anyToken; // seen at least one token bool commentToken; // comments are TOK.comment's + bool tokenizeNewlines; // newlines are turned into TOK.endOfLine's version (DMDLIB) { @@ -116,6 +117,7 @@ class Lexer line = p; this.doDocComment = doDocComment; this.commentToken = commentToken; + this.tokenizeNewlines = false; this.inTokenStringConstant = 0; this.lastDocLine = 0; //initKeywords(); @@ -227,6 +229,8 @@ class Lexer /**************************** * Turn next token in buffer into a token. + * Params: + * t = the token to set the resulting Token to */ final void scan(Token* t) { @@ -286,7 +290,15 @@ class Lexer case '\r': p++; if (*p != '\n') // if CR stands by itself + { endOfLine(); + if (tokenizeNewlines) + { + t.value = TOK.endOfLine; + tokenizeNewlines = false; + return; + } + } version (DMDLIB) { if (whitespaceToken) @@ -299,6 +311,12 @@ class Lexer case '\n': p++; endOfLine(); + if (tokenizeNewlines) + { + t.value = TOK.endOfLine; + tokenizeNewlines = false; + return; + } version (DMDLIB) { if (whitespaceToken) @@ -1045,6 +1063,10 @@ class Lexer return; case '#': { + // https://issues.dlang.org/show_bug.cgi?id=22825 + // Special token sequences are terminated by newlines, + // and should not be skipped over. + this.tokenizeNewlines = true; p++; if (parseSpecialTokenSequence()) continue; @@ -1064,6 +1086,12 @@ class Lexer { endOfLine(); p++; + if (tokenizeNewlines) + { + t.value = TOK.endOfLine; + tokenizeNewlines = false; + return; + } continue; } } @@ -2607,16 +2635,19 @@ class Lexer { auto linnum = this.scanloc.linnum; const(char)* filespec = null; - const loc = this.loc(); bool flags; if (!linemarker) scan(&tok); if (tok.value == TOK.int32Literal || tok.value == TOK.int64Literal) { - const lin = cast(int)(tok.unsvalue - 1); - if (lin != tok.unsvalue - 1) - error("line number `%lld` out of range", cast(ulong)tok.unsvalue); + const lin = cast(int)(tok.unsvalue); + if (lin != tok.unsvalue) + { + error(tok.loc, "line number `%lld` out of range", cast(ulong)tok.unsvalue); + skipToNextLine(); + return; + } else linnum = lin; } @@ -2624,15 +2655,19 @@ class Lexer { } else - goto Lerr; + { + error(tok.loc, "positive integer argument expected following `#line`"); + if (tok.value != TOK.endOfLine) + skipToNextLine(); + return; + } while (1) { - switch (*p) + scan(&tok); + switch (tok.value) { - case 0: - case 0x1A: - case '\n': - Lnewline: + case TOK.endOfFile: + case TOK.endOfLine: if (!inTokenStringConstant) { this.scanloc.linnum = linnum; @@ -2640,93 +2675,40 @@ class Lexer this.scanloc.filename = filespec; } return; - case '\r': - p++; - if (*p != '\n') - { - p--; - goto Lnewline; - } - continue; - case ' ': - case '\t': - case '\v': - case '\f': - p++; - continue; // skip white space - case '_': + case TOK.file: if (filespec || flags) goto Lerr; - if (memcmp(p, "__FILE__".ptr, 8) == 0) - { - p += 8; - filespec = mem.xstrdup(scanloc.filename); - continue; - } - goto Lerr; - case '"': + filespec = mem.xstrdup(scanloc.filename); + continue; + case TOK.string_: if (filespec || flags) goto Lerr; - stringbuffer.setsize(0); - p++; - while (1) - { - uint c; - c = *p; - switch (c) - { - case '\n': - case '\r': - case 0: - case 0x1A: - goto Lerr; - case '"': - stringbuffer.writeByte(0); - filespec = mem.xstrdup(cast(const(char)*)stringbuffer[].ptr); - p++; - break; - default: - if (c & 0x80) - { - uint u = decodeUTF(); - if (u == PS || u == LS) - goto Lerr; - } - stringbuffer.writeByte(c); - p++; - continue; - } - break; - } - continue; - - case '1': - case '2': - case '3': - case '4': - if (!linemarker) + if (tok.ptr[0] != '"' || tok.postfix != 0) goto Lerr; - flags = true; // linemarker flags seen - ++p; - if ('0' <= *p && *p <= '9') - goto Lerr; // only one digit allowed + filespec = tok.ustring; continue; - - default: - if (*p & 0x80) + case TOK.int32Literal: + if (!filespec) + goto Lerr; + if (linemarker && tok.unsvalue >= 1 && tok.unsvalue <= 4) { - uint u = decodeUTF(); - if (u == PS || u == LS) - goto Lnewline; + flags = true; // linemarker flags seen + continue; } goto Lerr; + default: + goto Lerr; } } Lerr: - if (linemarker) - error(loc, "# integer [\"filespec\"] { 1 | 2 | 3 | 4 }\\n expected"); - else - error(loc, "#line integer [\"filespec\"]\\n expected"); + if (filespec is null) + error(tok.loc, "invalid filename for `#line` directive"); + else if (linemarker) + error(tok.loc, "invalid flag for line marker directive"); + else if (!Ccompile) + error(tok.loc, "found `%s` when expecting new line following `#line` directive", tok.toChars()); + if (tok.value != TOK.endOfLine) + skipToNextLine(); } /*************************************** @@ -2768,6 +2750,7 @@ class Lexer break; } endOfLine(); + tokenizeNewlines = false; } /******************************************** @@ -3004,7 +2987,7 @@ private struct TimeStampInfo if (auto p = getenv("SOURCE_DATE_EPOCH")) { if (!ct.parseDigits(p.toDString())) - error(loc, "Value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p); + error(loc, "value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p); } else .time(&ct); diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 1494044..b2c7aa4 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -4198,6 +4198,8 @@ extern (C++) final class TypeFunction : TypeNext ParameterList parameterList; // function parameters + // These flags can be accessed like `bool` properties, + // getters and setters are generated for them private enum FunctionFlag : uint { none = 0, @@ -4206,13 +4208,13 @@ extern (C++) final class TypeFunction : TypeNext isproperty = 0x0004, // can be called without parentheses isref = 0x0008, // returns a reference isreturn = 0x0010, // 'this' is returned by ref - isscope = 0x0020, // 'this' is scope + isScopeQual = 0x0020, // 'this' is scope isreturninferred= 0x0040, // 'this' is return from inference isscopeinferred = 0x0080, // 'this' is scope from inference islive = 0x0100, // is @live incomplete = 0x0200, // return type or default arguments removed - inoutParam = 0x0400, // inout on the parameters - inoutQual = 0x0800, // inout on the qualifier + isInOutParam = 0x0400, // inout on the parameters + isInOutQual = 0x0800, // inout on the qualifier isctor = 0x1000, // the function is a constructor isreturnscope = 0x2000, // `this` is returned by value } @@ -4480,7 +4482,7 @@ extern (C++) final class TypeFunction : TypeNext { // Check escaping through return value Type tret = nextOf().toBasetype(); - if (isref || tret.hasPointers()) + if (isref || tret.hasPointers() || !isnothrow()) { return stc; } @@ -5084,177 +5086,29 @@ extern (C++) final class TypeFunction : TypeNext return false; } - /// set or get if the function has the `nothrow` attribute - bool isnothrow() const pure nothrow @safe @nogc - { - return (funcFlags & FunctionFlag.isnothrow) != 0; - } - /// ditto - void isnothrow(bool v) pure nothrow @safe @nogc - { - if (v) funcFlags |= FunctionFlag.isnothrow; - else funcFlags &= ~FunctionFlag.isnothrow; - } - - /// set or get if the function has the `@nogc` attribute - bool isnogc() const pure nothrow @safe @nogc - { - return (funcFlags & FunctionFlag.isnogc) != 0; - } - /// ditto - void isnogc(bool v) pure nothrow @safe @nogc - { - if (v) funcFlags |= FunctionFlag.isnogc; - else funcFlags &= ~FunctionFlag.isnogc; - } - - /// set or get if the function has the `@property` attribute - bool isproperty() const pure nothrow @safe @nogc - { - return (funcFlags & FunctionFlag.isproperty) != 0; - } - /// ditto - void isproperty(bool v) pure nothrow @safe @nogc - { - if (v) funcFlags |= FunctionFlag.isproperty; - else funcFlags &= ~FunctionFlag.isproperty; - } - - /// set or get if the function has the `ref` attribute - bool isref() const pure nothrow @safe @nogc - { - return (funcFlags & FunctionFlag.isref) != 0; - } - /// ditto - void isref(bool v) pure nothrow @safe @nogc - { - if (v) funcFlags |= FunctionFlag.isref; - else funcFlags &= ~FunctionFlag.isref; - } - - /// set or get if the function has the `return` attribute - bool isreturn() const pure nothrow @safe @nogc - { - return (funcFlags & FunctionFlag.isreturn) != 0; - } - /// ditto - void isreturn(bool v) pure nothrow @safe @nogc - { - if (v) funcFlags |= FunctionFlag.isreturn; - else funcFlags &= ~FunctionFlag.isreturn; - } - - /// set or get if the function has the `returnscope` attribute - bool isreturnscope() const pure nothrow @safe @nogc - { - return (funcFlags & FunctionFlag.isreturnscope) != 0; - } - /// ditto - void isreturnscope(bool v) pure nothrow @safe @nogc - { - if (v) funcFlags |= FunctionFlag.isreturnscope; - else funcFlags &= ~FunctionFlag.isreturnscope; - } - - /// set or get if the function has the `scope` attribute - bool isScopeQual() const pure nothrow @safe @nogc - { - return (funcFlags & FunctionFlag.isscope) != 0; - } - /// ditto - void isScopeQual(bool v) pure nothrow @safe @nogc - { - if (v) funcFlags |= FunctionFlag.isscope; - else funcFlags &= ~FunctionFlag.isscope; - } - - /// set or get if the function has the `return` attribute inferred - bool isreturninferred() const pure nothrow @safe @nogc - { - return (funcFlags & FunctionFlag.isreturninferred) != 0; - } - /// ditto - void isreturninferred(bool v) pure nothrow @safe @nogc - { - if (v) funcFlags |= FunctionFlag.isreturninferred; - else funcFlags &= ~FunctionFlag.isreturninferred; - } - - /// set or get if the function has the `scope` attribute inferred - bool isscopeinferred() const pure nothrow @safe @nogc - { - return (funcFlags & FunctionFlag.isscopeinferred) != 0; - } - /// ditoo - void isscopeinferred(bool v) pure nothrow @safe @nogc - { - if (v) funcFlags |= FunctionFlag.isscopeinferred; - else funcFlags &= ~FunctionFlag.isscopeinferred; - } - - /// set or get if the function has the `@live` attribute - bool islive() const pure nothrow @safe @nogc - { - return (funcFlags & FunctionFlag.islive) != 0; - } - /// ditto - void islive(bool v) pure nothrow @safe @nogc - { - if (v) funcFlags |= FunctionFlag.islive; - else funcFlags &= ~FunctionFlag.islive; - } - - /// set or get if the return type or the default arguments are removed - bool incomplete() const pure nothrow @safe @nogc - { - return (funcFlags & FunctionFlag.incomplete) != 0; - } - /// ditto - void incomplete(bool v) pure nothrow @safe @nogc - { - if (v) funcFlags |= FunctionFlag.incomplete; - else funcFlags &= ~FunctionFlag.incomplete; - } - - /// set or get if the function has the `inout` on the parameters - bool isInOutParam() const pure nothrow @safe @nogc - { - return (funcFlags & FunctionFlag.inoutParam) != 0; - } - /// ditto - void isInOutParam(bool v) pure nothrow @safe @nogc - { - if (v) funcFlags |= FunctionFlag.inoutParam; - else funcFlags &= ~FunctionFlag.inoutParam; - } + // Generate getter / setter functions for `FunctionFlag` members so they can be + // treated like regular `bool` fields, instead of requiring bit twiddling to read/write + extern (D) mixin(() { + string result = "extern(C++) pure nothrow @safe @nogc {"; + foreach (string mem; __traits(allMembers, FunctionFlag)) + { + result ~= " + /// set or get if the function has the FunctionFlag attribute of the same name + bool "~mem~"() const { return (funcFlags & FunctionFlag."~mem~") != 0; } + /// ditto + void "~mem~"(bool v) + { + if (v) funcFlags |= FunctionFlag."~mem~"; + else funcFlags &= ~FunctionFlag."~mem~"; + }"; + } + return result ~ "}\n"; + }()); - /// set or get if the function has the `inout` on the parameters - bool isInOutQual() const pure nothrow @safe @nogc - { - return (funcFlags & FunctionFlag.inoutQual) != 0; - } - /// ditto - void isInOutQual(bool v) pure nothrow @safe @nogc - { - if (v) funcFlags |= FunctionFlag.inoutQual; - else funcFlags &= ~FunctionFlag.inoutQual; - } /// Returns: `true` the function is `isInOutQual` or `isInOutParam` ,`false` otherwise. bool iswild() const pure nothrow @safe @nogc { - return (funcFlags & (FunctionFlag.inoutParam | FunctionFlag.inoutQual)) != 0; - } - - /// set or get if the function is a constructor - bool isctor() const pure nothrow @safe @nogc - { - return (funcFlags & FunctionFlag.isctor) != 0; - } - /// ditto - void isctor(bool v) pure nothrow @safe @nogc - { - if (v) funcFlags |= FunctionFlag.isctor; - else funcFlags &= ~FunctionFlag.isctor; + return (funcFlags & (FunctionFlag.isInOutParam | FunctionFlag.isInOutQual)) != 0; } /// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other` @@ -6418,9 +6272,6 @@ extern (C++) final class TypeClass : Type override MOD deduceWild(Type t, bool isRef) { - // If sym is forward referenced: - if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete()) - sym.dsymbolSemantic(null); ClassDeclaration cd = t.isClassHandle(); if (cd && (sym == cd || cd.isBaseOf(sym, null))) return Type.deduceWild(t, isRef); @@ -7176,6 +7027,17 @@ extern (C++) final class Parameter : ASTNode extern (D) private static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe { + // Workaround for failing covariance when finding a common type of delegates, + // some of which have parameters with inferred scope + // https://issues.dlang.org/show_bug.cgi?id=21285 + // The root cause is that scopeinferred is not part of the mangle, and mangle + // is used for type equality checks + if (to & STC.returninferred) + to &= ~STC.return_; + // note: f(return int* x) currently 'infers' scope without inferring `return`, in that case keep STC.scope + if (to & STC.scopeinferred && !(to & STC.return_)) + to &= ~STC.scope_; + if (from == to) return true; diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index d6735d4..2957b3a 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/dmd/nogc.d @@ -137,9 +137,9 @@ public: override void visit(DeleteExp e) { - if (e.e1.op == EXP.variable) + if (VarExp ve = e.e1.isVarExp()) { - VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration(); + VarDeclaration v = ve.var.isVarDeclaration(); if (v && v.onstack) return; // delete for scope allocated class object } diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d index c2594fe..121a266 100644 --- a/gcc/d/dmd/ob.d +++ b/gcc/d/dmd/ob.d @@ -1747,7 +1747,7 @@ PtrState toPtrState(VarDeclaration v) */ auto t = v.type; - if (v.isRef()) + if (v.isReference()) { return t.hasMutableFields() ? PtrState.Borrowed : PtrState.Readonly; } @@ -1775,7 +1775,7 @@ bool hasPointersToMutableFields(Type t) { foreach (v; ts.sym.fields) { - if (v.isRef()) + if (v.isReference()) { if (v.type.hasMutableFields()) return true; @@ -1977,7 +1977,12 @@ void checkObErrors(ref ObState obstate) else if (isReadonlyPtr(v)) pvs.state = PtrState.Readonly; else + { + if (pvs.state == PtrState.Owner && v.type.hasPointersToMutableFields()) + v.error(e.loc, "assigning to Owner without disposing of owned value"); + pvs.state = PtrState.Owner; + } pvs.deps.zero(); EscapeByResults er; diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index fc64377..dbd761f 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -711,7 +711,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (s) { functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2); - if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) + if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); } @@ -720,7 +720,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (s_r) { functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1); - if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) + if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); } @@ -793,7 +793,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (s_r) { functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, &args2); - if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) + if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); } @@ -802,7 +802,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (s) { functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, &args1); - if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) + if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); } @@ -1250,7 +1250,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) if (s) { functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2); - if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) + if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); } @@ -1344,7 +1344,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop if (s) { functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2); - if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) + if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) return ErrorExp.get(); } FuncDeclaration lastf = m.lastf; @@ -1352,7 +1352,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop if (s_r) { functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1); - if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors)) + if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) return ErrorExp.get(); } if (m.count > 1) diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index 5a86931..3745a15d 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -504,6 +504,16 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) { eint = ei; } + else if (auto se = ep.e1.isSymOffExp()) + { + if (!se.var.isReference() && + !se.var.isImportedSymbol() && + se.var.isDataseg()) + { + var = se.var.isVarDeclaration(); + offset += se.offset; + } + } } return false; } @@ -531,7 +541,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) if (auto ae = e.e1.isIndexExp()) { // Convert &array[n] to &array+n - if (ae.e2.op == EXP.int64 && ae.e1.isVarExp()) + if (ae.e2.isIntegerExp() && ae.e1.isVarExp()) { sinteger_t index = ae.e2.toInteger(); VarExp ve = ae.e1.isVarExp(); @@ -541,8 +551,13 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) sinteger_t dim = ts.dim.toInteger(); if (index < 0 || index >= dim) { - e.error("array index %lld is out of bounds `[0..%lld]`", index, dim); - return error(); + /* 0 for C static arrays means size is unknown, no need to check + */ + if (!(dim == 0 && ve.var.isCsymbol())) + { + e.error("array index %lld is out of bounds `[0..%lld]`", index, dim); + return error(); + } } import core.checkedint : mulu; @@ -559,6 +574,33 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) return; } } + // Convert &((a.b)[n]) to (&a.b)+n + else if (ae.e2.isIntegerExp() && ae.e1.isDotVarExp()) + { + sinteger_t index = ae.e2.toInteger(); + DotVarExp ve = ae.e1.isDotVarExp(); + if (ve.type.isTypeSArray() && ve.var.isField() && ve.e1.isPtrExp()) + { + TypeSArray ts = ve.type.isTypeSArray(); + sinteger_t dim = ts.dim.toInteger(); + if (index < 0 || index >= dim) + { + /* 0 for C static arrays means size is unknown, no need to check + */ + if (!(dim == 0 && ve.var.isCsymbol())) + { + e.error("array index %lld is out of bounds `[0..%lld]`", index, dim); + return error(); + } + } + + auto pe = new AddrExp(e.loc, ve); + pe.type = e.type; + ret = new AddExp(e.loc, pe, ae.e2); + ret.type = e.type; + return; + } + } } } diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index f6472bf..7b1b63c 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -3651,7 +3651,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.traits: if (AST.TraitsExp te = cast(AST.TraitsExp) parsePrimaryExp()) - if (te.ident && te.args) + if (te.ident) { t = new AST.TypeTraits(token.loc, te); break; diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d index 571c3fc..bba3481 100644 --- a/gcc/d/dmd/printast.d +++ b/gcc/d/dmd/printast.d @@ -209,5 +209,3 @@ extern (C++) final class PrintASTVisitor : Visitor putc(' ', stdout); } } - - diff --git a/gcc/d/dmd/root/aav.d b/gcc/d/dmd/root/aav.d index 5b8cc82..ba5d331 100644 --- a/gcc/d/dmd/root/aav.d +++ b/gcc/d/dmd/root/aav.d @@ -20,7 +20,7 @@ private size_t hash(size_t a) pure nothrow @nogc @safe return a ^ (a >> 7) ^ (a >> 4); } -struct KeyValueTemplate(K,V) +private struct KeyValueTemplate(K,V) { K key; V value; @@ -31,15 +31,17 @@ alias Value = void*; alias KeyValue = KeyValueTemplate!(Key, Value); -struct aaA +private struct aaA { +private: aaA* next; KeyValue keyValue; alias keyValue this; } -struct AA +private struct AA { +private: aaA** b; size_t b_length; size_t nodes; // total number of aaA nodes diff --git a/gcc/d/dmd/root/array.h b/gcc/d/dmd/root/array.h index 866b952..52bed5e 100644 --- a/gcc/d/dmd/root/array.h +++ b/gcc/d/dmd/root/array.h @@ -205,4 +205,3 @@ struct Array return data.ptr[--length]; } }; - diff --git a/gcc/d/dmd/root/bitarray.d b/gcc/d/dmd/root/bitarray.d index 42c09fa..90cbaed 100644 --- a/gcc/d/dmd/root/bitarray.d +++ b/gcc/d/dmd/root/bitarray.d @@ -187,6 +187,3 @@ nothrow pure unittest a = b; assert(a == b); } - - - diff --git a/gcc/d/dmd/root/file.d b/gcc/d/dmd/root/file.d index 1f33c18..a01cfdc 100644 --- a/gcc/d/dmd/root/file.d +++ b/gcc/d/dmd/root/file.d @@ -45,11 +45,6 @@ struct FileBuffer data = null; return result; } - - extern (C++) static FileBuffer* create() pure nothrow @safe - { - return new FileBuffer(); - } } /// @@ -78,12 +73,6 @@ struct File nothrow: /// Read the full content of a file. - extern (C++) static ReadResult read(const(char)* name) - { - return read(name.toDString()); - } - - /// Ditto static ReadResult read(const(char)[] name) { ReadResult result; @@ -179,24 +168,18 @@ nothrow: } /// Write a file, returning `true` on success. - extern (D) static bool write(const(char)* name, const void[] data) + static bool write(const(char)* name, const void[] data) { import dmd.common.file : writeFile; return writeFile(name, data); } ///ditto - extern(D) static bool write(const(char)[] name, const void[] data) + static bool write(const(char)[] name, const void[] data) { return name.toCStringThen!((fname) => write(fname.ptr, data)); } - /// ditto - extern (C++) static bool write(const(char)* name, const(void)* data, size_t size) - { - return write(name, data[0 .. size]); - } - /// Delete a file. extern (C++) static void remove(const(char)* name) { @@ -229,7 +212,7 @@ nothrow: * Returns: * `true` on success */ - extern (D) static bool update(const(char)* namez, const void[] data) + static bool update(const(char)* namez, const void[] data) { enum log = false; if (log) printf("update %s\n", namez); @@ -252,17 +235,11 @@ nothrow: } ///ditto - extern(D) static bool update(const(char)[] name, const void[] data) + static bool update(const(char)[] name, const void[] data) { return name.toCStringThen!(fname => update(fname.ptr, data)); } - /// ditto - extern (C++) static bool update(const(char)* name, const(void)* data, size_t size) - { - return update(name, data[0 .. size]); - } - /// Size of a file in bytes. /// Params: namez = null-terminated filename /// Returns: `ulong.max` on any error, the length otherwise. diff --git a/gcc/d/dmd/root/stringtable.d b/gcc/d/dmd/root/stringtable.d index 884a9f1..20316fa 100644 --- a/gcc/d/dmd/root/stringtable.d +++ b/gcc/d/dmd/root/stringtable.d @@ -224,7 +224,7 @@ public: } /// ditto - extern(D) int opApply(scope int delegate(const(StringValue!T)*) nothrow dg) nothrow + int opApply(scope int delegate(const(StringValue!T)*) nothrow dg) nothrow { foreach (const se; table) { diff --git a/gcc/d/dmd/sapply.d b/gcc/d/dmd/sapply.d index 7314d5b..26fba8f 100644 --- a/gcc/d/dmd/sapply.d +++ b/gcc/d/dmd/sapply.d @@ -177,4 +177,3 @@ public: doCond(s.statement) || applyTo(s); } } - diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index d237caf..5119576 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -275,7 +275,7 @@ private extern(C++) final class Semantic3Visitor : Visitor // Disable generated opAssign, because some members forbid identity assignment. funcdecl.storage_class |= STC.disable; funcdecl.fbody = null; // remove fbody which contains the error - funcdecl.semantic3Errors = false; + funcdecl.flags &= ~FUNCFLAG.semantic3Errors; } return; } @@ -285,7 +285,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if (funcdecl.semanticRun >= PASS.semantic3) return; funcdecl.semanticRun = PASS.semantic3; - funcdecl.semantic3Errors = false; + funcdecl.flags &= ~FUNCFLAG.semantic3Errors; if (!funcdecl.type || funcdecl.type.ty != Tfunction) return; @@ -386,7 +386,7 @@ private extern(C++) final class Semantic3Visitor : Visitor // functions may be widely used by dmd-compiled projects. // It also gives more time for the implementation of dual-context // functions to be reworked as a frontend-only feature. - if (funcdecl.isThis2) + if (funcdecl.hasDualContext()) { funcdecl.deprecation("function requires a dual-context, which is deprecated"); if (auto ti = sc2.parent ? sc2.parent.isInstantiated() : null) @@ -603,7 +603,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if (!funcdecl.fbody) funcdecl.fbody = new CompoundStatement(Loc.initial, new Statements()); - if (funcdecl.naked) + if (funcdecl.isNaked()) { fpreinv = null; // can't accommodate with no stack frame fpostinv = null; @@ -619,8 +619,8 @@ private extern(C++) final class Semantic3Visitor : Visitor f.next = Type.tvoid; if (f.checkRetType(funcdecl.loc)) funcdecl.fbody = new ErrorStatement(); - else if (funcdecl.isMain()) - funcdecl.checkDmain(); // Check main() parameters and return type + else + funcdecl.checkMain(); // Check main() parameters and return type } if (f.next !is null) @@ -654,7 +654,7 @@ private extern(C++) final class Semantic3Visitor : Visitor // handle NRVO if (!target.isReturnOnStack(f, funcdecl.needThis()) || !funcdecl.checkNRVO()) - funcdecl.nrvo_can = 0; + funcdecl.flags &= ~FUNCFLAG.NRVO; if (funcdecl.fbody.isErrorStatement()) { @@ -762,7 +762,7 @@ private extern(C++) final class Semantic3Visitor : Visitor /* Don't generate unwind tables for this function * https://issues.dlang.org/show_bug.cgi?id=17997 */ - funcdecl.eh_none = true; + funcdecl.flags |= FUNCFLAG.noEH; } if (funcdecl.flags & FUNCFLAG.nothrowInprocess) @@ -927,7 +927,7 @@ private extern(C++) final class Semantic3Visitor : Visitor /* https://issues.dlang.org/show_bug.cgi?id=10789 * If NRVO is not possible, all returned lvalues should call their postblits. */ - if (!funcdecl.nrvo_can) + if (!funcdecl.isNRVO()) exp = doCopyOrMove(sc2, exp, f.next); if (tret.hasPointers()) @@ -996,7 +996,7 @@ private extern(C++) final class Semantic3Visitor : Visitor freq = freq.statementSemantic(sc2); freq.blockExit(funcdecl, false); - funcdecl.eh_none = false; + funcdecl.flags &= ~FUNCFLAG.noEH; sc2 = sc2.pop(); @@ -1030,7 +1030,7 @@ private extern(C++) final class Semantic3Visitor : Visitor fens = fens.statementSemantic(sc2); fens.blockExit(funcdecl, false); - funcdecl.eh_none = false; + funcdecl.flags &= ~FUNCFLAG.noEH; sc2 = sc2.pop(); @@ -1159,7 +1159,7 @@ private extern(C++) final class Semantic3Visitor : Visitor const blockexit = s.blockExit(funcdecl, isnothrow); if (blockexit & BE.throw_) { - funcdecl.eh_none = false; + funcdecl.flags &= ~FUNCFLAG.noEH; if (isnothrow) error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars()); else if (funcdecl.flags & FUNCFLAG.nothrowInprocess) @@ -1195,7 +1195,7 @@ private extern(C++) final class Semantic3Visitor : Visitor { // 'this' is the monitor vsync = new VarExp(funcdecl.loc, funcdecl.vthis); - if (funcdecl.isThis2) + if (funcdecl.hasDualContext()) { vsync = new PtrExp(funcdecl.loc, vsync); vsync = new IndexExp(funcdecl.loc, vsync, IntegerExp.literal!0); @@ -1230,7 +1230,7 @@ private extern(C++) final class Semantic3Visitor : Visitor } // Fix up forward-referenced gotos - if (funcdecl.gotos) + if (funcdecl.gotos && !funcdecl.isCsymbol()) { for (size_t i = 0; i < funcdecl.gotos.dim; ++i) { @@ -1238,7 +1238,7 @@ private extern(C++) final class Semantic3Visitor : Visitor } } - if (funcdecl.naked && (funcdecl.fensures || funcdecl.frequires)) + if (funcdecl.isNaked() && (funcdecl.fensures || funcdecl.frequires)) funcdecl.error("naked assembly functions with contracts are not supported"); sc2.ctorflow.callSuper = CSX.none; @@ -1370,7 +1370,10 @@ private extern(C++) final class Semantic3Visitor : Visitor * Otherwise, error gagging should be temporarily ungagged by functionSemantic3. */ funcdecl.semanticRun = PASS.semantic3done; - funcdecl.semantic3Errors = (global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement()); + if ((global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement())) + funcdecl.flags |= FUNCFLAG.semantic3Errors; + else + funcdecl.flags &= ~FUNCFLAG.semantic3Errors; if (funcdecl.type.ty == Terror) funcdecl.errors = true; //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent.toChars(), toChars(), sc, loc.toChars()); diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d index 8b271f8..ae03b8a 100644 --- a/gcc/d/dmd/statement.d +++ b/gcc/d/dmd/statement.d @@ -1761,6 +1761,9 @@ extern (C++) final class GotoStatement : Statement return new GotoStatement(loc, ident); } + /************** + * Returns: true for error + */ extern (D) bool checkLabel() { if (!label.statement) diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 6ffba68..c2967d6 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -211,7 +211,8 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor if (f.checkForwardRef(s.exp.loc)) s.exp = ErrorExp.get(); } - if (discardValue(s.exp)) + + if (!(sc.flags & SCOPE.Cfile) && discardValue(s.exp)) s.exp = ErrorExp.get(); s.exp = s.exp.optimize(WANTvalue); @@ -728,12 +729,12 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor Dsymbol sapply = null; // the inferred opApply() or front() function if (!inferForeachAggregate(sc, fs.op == TOK.foreach_, fs.aggr, sapply)) { - const(char)* msg = ""; - if (fs.aggr.type && isAggregate(fs.aggr.type)) - { - msg = ", define `opApply()`, range primitives, or use `.tupleof`"; - } - fs.error("invalid `foreach` aggregate `%s`%s", oaggr.toChars(), msg); + assert(oaggr.type); + + fs.error("invalid `foreach` aggregate `%s` of type `%s`", oaggr.toChars(), oaggr.type.toPrettyChars()); + if (isAggregate(fs.aggr.type)) + fs.loc.errorSupplemental("maybe define `opApply()`, range primitives, or use `.tupleof`"); + return setError(); } @@ -2310,12 +2311,12 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor needswitcherror = true; } - if (!sc.sw.sdefault && !(sc.flags & SCOPE.Cfile) && + if (!sc.sw.sdefault && (!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on)) { ss.hasNoDefault = 1; - if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement())) + if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement()) && !(sc.flags & SCOPE.Cfile)) ss.error("`switch` statement without a `default`; use `final switch` or add `default: assert(0);` or add `default: break;`"); // Generate runtime error if the default is hit @@ -2323,7 +2324,11 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor CompoundStatement cs; Statement s; - if (global.params.useSwitchError == CHECKENABLE.on && + if (sc.flags & SCOPE.Cfile) + { + s = new BreakStatement(ss.loc, null); // default for C is `default: break;` + } + else if (global.params.useSwitchError == CHECKENABLE.on && global.params.checkAction != CHECKACTION.halt) { if (global.params.checkAction == CHECKACTION.C) @@ -2365,7 +2370,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor ss._body = cs; } - if (ss.checkLabel()) + if (!(sc.flags & SCOPE.Cfile) && ss.checkLabel()) { sc.pop(); return setError(); @@ -3840,7 +3845,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor fd.gotos = new GotoStatements(); fd.gotos.push(gs); } - else if (gs.checkLabel()) + else if (!(sc.flags & SCOPE.Cfile) && gs.checkLabel()) return setError(); result = gs; @@ -3916,12 +3921,10 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor } assert(sc.func); - // use setImpure/setGC when the deprecation cycle is over - PURE purity; - if (!(cas.stc & STC.pure_) && (purity = sc.func.isPureBypassingInference()) != PURE.impure && purity != PURE.fwdref) - cas.deprecation("`asm` statement is assumed to be impure - mark it with `pure` if it is not"); - if (!(cas.stc & STC.nogc) && sc.func.isNogcBypassingInference()) - cas.deprecation("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not"); + if (!(cas.stc & STC.pure_) && sc.func.setImpure()) + 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()) + 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)) && sc.func.setUnsafe()) cas.error("`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not"); diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 1790996..43feab1 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -245,6 +245,7 @@ enum TOK : ubyte arrow, // -> colonColon, // :: wchar_tLiteral, + endOfLine, // \n, \r, \u2028, \u2029 whitespace, // C only keywords @@ -851,6 +852,7 @@ extern (C++) struct Token TOK.wcharLiteral: "wcharv", TOK.dcharLiteral: "dcharv", TOK.wchar_tLiteral: "wchar_tv", + TOK.endOfLine: "\\n", TOK.whitespace: "whitespace", // C only keywords @@ -945,20 +947,19 @@ nothrow: sprintf(&buffer[0], "%d", cast(int)intvalue); break; case TOK.uns32Literal: - case TOK.wcharLiteral: - case TOK.dcharLiteral: case TOK.wchar_tLiteral: sprintf(&buffer[0], "%uU", cast(uint)unsvalue); break; + case TOK.wcharLiteral: + case TOK.dcharLiteral: case TOK.charLiteral: - { - const v = cast(int)intvalue; - if (v >= ' ' && v <= '~') - sprintf(&buffer[0], "'%c'", v); - else - sprintf(&buffer[0], "'\\x%02x'", v); + { + OutBuffer buf; + buf.writeSingleCharLiteral(cast(dchar) intvalue); + buf.writeByte('\0'); + p = buf.extractSlice().ptr; + } break; - } case TOK.int64Literal: sprintf(&buffer[0], "%lldL", cast(long)intvalue); break; @@ -1090,7 +1091,7 @@ void writeCharLiteral(ref OutBuffer buf, dchar c) buf.writeByte('\\'); goto default; default: - if (c <= 0x7F) + if (c <= 0xFF) { if (isprint(c)) buf.writeByte(c); @@ -1114,3 +1115,40 @@ unittest } assert(buf.extractSlice() == `a\n\r\t\b\f\0\x11\u7233\U00017233`); } + +/** + * Write a single-quoted character literal + * + * Useful for printing '' char literals in e.g. error messages, ddoc, or the `.stringof` property + * + * Params: + * buf = buffer to append character in + * c = code point to write + */ +nothrow +void writeSingleCharLiteral(ref OutBuffer buf, dchar c) +{ + buf.writeByte('\''); + if (c == '\'') + buf.writeByte('\\'); + + if (c == '"') + buf.writeByte('"'); + else + writeCharLiteral(buf, c); + + buf.writeByte('\''); +} + +unittest +{ + OutBuffer buf; + writeSingleCharLiteral(buf, '\''); + assert(buf.extractSlice() == `'\''`); + buf.reset(); + writeSingleCharLiteral(buf, '"'); + assert(buf.extractSlice() == `'"'`); + buf.reset(); + writeSingleCharLiteral(buf, '\n'); + assert(buf.extractSlice() == `'\n'`); +} diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index c404cab..f9b6062 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -254,6 +254,7 @@ enum class TOK : unsigned char arrow, // -> colonColon, // :: wchar_tLiteral, + endOfLine, // \n, \r, \u2028, \u2029 whitespace, // C only keywords diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index dbdcfd4..4b15e8c 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -80,10 +80,10 @@ private Dsymbol getDsymbolWithoutExpCtx(RootObject oarg) { if (auto e = isExpression(oarg)) { - if (e.op == EXP.dotVariable) - return (cast(DotVarExp)e).var; - if (e.op == EXP.dotTemplateDeclaration) - return (cast(DotTemplateExp)e).td; + if (auto dve = e.isDotVarExp()) + return dve.var; + if (auto dte = e.isDotTemplateExp()) + return dte.td; } return getDsymbol(oarg); } @@ -833,7 +833,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) e.error("argument `%s` has no visibility", o.toChars()); return ErrorExp.get(); } - if (s.semanticRun == PASS.init) + if (s.semanticRun == PASS.initial) s.dsymbolSemantic(null); auto protName = visibilityToString(s.visible().kind); // TODO: How about package(names) @@ -1053,9 +1053,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } else if (e.ident == Id.getMember) { - if (ex.op == EXP.dotIdentifier) + if (auto die = ex.isDotIdExp()) // Prevent semantic() from replacing Symbol with its initializer - (cast(DotIdExp)ex).wantsym = true; + die.wantsym = true; ex = ex.expressionSemantic(scx); return ex; } @@ -2101,13 +2101,14 @@ Expression semanticTraits(TraitsExp e, Scope* sc) return ErrorExp.get(); } - if (sc.func is null) + auto fd = sc.getEnclosingFunction(); + if (!fd) { e.error("`__traits(parameters)` may only be used inside a function"); return ErrorExp.get(); } - assert(sc.func && sc.parent.isFuncDeclaration()); - auto tf = sc.parent.isFuncDeclaration.type.isTypeFunction(); + + auto tf = fd.type.isTypeFunction(); assert(tf); auto exps = new Expressions(0); int addParameterDG(size_t idx, Parameter x) @@ -2162,7 +2163,7 @@ private bool isSame(RootObject o1, RootObject o2, Scope* sc) { if (ea.op == EXP.function_) { - if (auto fe = cast(FuncExp)ea) + if (auto fe = ea.isFuncExp()) return fe.fd; } } diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index e5f839b..bcdbec5 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -978,7 +978,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) // duplicate a part of StructDeclaration::semanticTypeInfoMembers //printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash); - if (sd.xeq && sd.xeq.generated && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done) + if (sd.xeq && sd.xeq.isGenerated() && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done) { uint errors = global.startGagging(); sd.xeq.semantic3(sd.xeq._scope); @@ -1431,12 +1431,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) errors = true; } - if ((fparam.storageClass & (STC.ref_ | STC.wild)) == (STC.ref_ | STC.wild)) - { - // 'ref inout' implies 'return' - fparam.storageClass |= STC.return_; - } - if (fparam.storageClass & STC.return_) { if (fparam.isReference()) @@ -1799,6 +1793,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) mtype.exp.ident != Id.derivedMembers && mtype.exp.ident != Id.getMember && mtype.exp.ident != Id.parent && + mtype.exp.ident != Id.parameters && mtype.exp.ident != Id.child && mtype.exp.ident != Id.toType && mtype.exp.ident != Id.getOverloads && @@ -3088,7 +3083,7 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type //static int nest; if (++nest == 50) *(char*)0=0; if (sc is null) { - error(loc, "Invalid scope."); + error(loc, "invalid scope"); return returnError(); } if (mt.inuse) @@ -4076,7 +4071,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) return e.expressionSemantic(sc); } } - if (d.semanticRun == PASS.init) + if (d.semanticRun == PASS.initial) d.dsymbolSemantic(null); checkAccess(e.loc, sc, e, d); auto ve = new VarExp(e.loc, d); @@ -4307,7 +4302,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) if (ident == Id.outer && mt.sym.vthis) { - if (mt.sym.vthis.semanticRun == PASS.init) + if (mt.sym.vthis.semanticRun == PASS.initial) mt.sym.vthis.dsymbolSemantic(null); if (auto cdp = mt.sym.toParentLocal().isClassDeclaration()) @@ -4503,7 +4498,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) Expression e1; Type t; /* returns: true to continue, false to return */ - if (f.isThis2) + if (f.hasDualContext()) { if (f.followInstantiationContext(ad)) { @@ -4560,7 +4555,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) } } //printf("e = %s, d = %s\n", e.toChars(), d.toChars()); - if (d.semanticRun == PASS.init) + if (d.semanticRun == PASS.initial) d.dsymbolSemantic(null); // If static function, get the most visible overload. diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d index f8e7e48..67e4d86 100644 --- a/gcc/d/dmd/utils.d +++ b/gcc/d/dmd/utils.d @@ -63,7 +63,7 @@ FileBuffer readFile(Loc loc, const(char)[] filename) auto result = File.read(filename); if (!result.success) { - error(loc, "Error reading file `%.*s`", cast(int)filename.length, filename.ptr); + error(loc, "error reading file `%.*s`", cast(int)filename.length, filename.ptr); fatal(); } return FileBuffer(result.extractSlice()); diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 2a7fb69..61a2b50 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -1441,7 +1441,7 @@ public: gcc_assert (e->e1->op == EXP::variable); VarDeclaration *v = e->e1->isVarExp ()->var->isVarDeclaration (); - gcc_assert (v && v->onstack); + gcc_assert (v && v->onstack ()); libcall_fn libcall = tb1->isClassHandle ()->isInterfaceDeclaration () ? LIBCALL_CALLINTERFACEFINALIZER : LIBCALL_CALLFINALIZER; diff --git a/gcc/d/modules.cc b/gcc/d/modules.cc index 899648f..edc7912 100644 --- a/gcc/d/modules.cc +++ b/gcc/d/modules.cc @@ -141,7 +141,7 @@ get_internal_fn (tree ident, const Visibility &visibility) FuncDeclaration *fd = FuncDeclaration::genCfunc (NULL, Type::tvoid, Identifier::idPool (name)); - fd->generated = true; + fd->isGenerated (true); fd->loc = Loc (mod->srcfile.toChars (), 1, 0); fd->parent = mod; fd->visibility = visibility; diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc index a25f7a5..d20c5c3 100644 --- a/gcc/d/toir.cc +++ b/gcc/d/toir.cc @@ -958,7 +958,7 @@ public: /* If returning via NRVO, just refer to the DECL_RESULT; this differs from using NULL_TREE in that it indicates that we care about the value of the DECL_RESULT. */ - if (this->func_->nrvo_can && this->func_->nrvo_var) + if (this->func_->isNRVO () && this->func_->nrvo_var) { add_stmt (return_expr (decl)); return; |