From 7e7ebe3e350fde90fe49ab41ce3b92a811bb6370 Mon Sep 17 00:00:00 2001 From: Iain Buclaw Date: Sat, 29 Oct 2022 09:05:54 +0200 Subject: d: Merge upstream dmd, druntime e4f8919591, phobos 3ad507b51. D front-end changes: - Import dmd v2.101.0-beta.1. - Add predefined version `D_Optimized' when compiling with `-O'. - Shortened method syntax (DIP1043) is now enabled by default. - Array literals assigned to `scope' array variables are now allocated on the stack. - Implement `@system' variables (DIP1035), available behind the preview feature flag `-fpreview=systemvariables'. D runtime changes: - Import druntime v2.101.0-beta.1. Phobos changes: - Import phobos v2.101.0-beta.1. - Added `std.typecons.SafeRefCounted', that can be used in `@safe' code with `-fpreview=dip1000'. gcc/d/ChangeLog: * d-attribs.cc (apply_user_attributes): Update for new front-end interface. * d-builtins.cc (d_init_versions): Predefine `D_Optimized' with compiling with optimizations enabled. * d-lang.cc (d_handle_option): Update for new front-end interface. Handle new option `-fpreview=systemvariables'. * dmd/MERGE: Merge upstream dmd e4f8919591. * dmd/VERSION: Bump version to v2.101.0-beta.1. * expr.cc (ExprVisitor::visit (AssignExp *)): Treat construction of static arrays from a call expression as a simple assignment. (ExprVisitor::visit (ArrayLiteralExp *)): Handle array literals with `scope' storage. * gdc.texi: Update documentation of `-fpreview=' options. * lang.opt (fpreview=shortenedmethods): Remove. (fpreview=systemvariables): New option. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime e4f8919591. * src/MERGE: Merge upstream phobos 3ad507b51. gcc/testsuite/ChangeLog: * gdc.dg/simd19630.d: Move tests with errors to ... * gdc.dg/simd19630b.d: ... here. New test. * gdc.dg/simd19630c.d: New test. * gdc.dg/simd_ctfe.d: Removed. * gdc.dg/simd18867.d: New test. * gdc.dg/simd19788.d: New test. * gdc.dg/simd21469.d: New test. * gdc.dg/simd21672.d: New test. * gdc.dg/simd23077.d: New test. * gdc.dg/simd23084.d: New test. * gdc.dg/simd23085.d: New test. * gdc.dg/torture/simd19632.d: New test. * gdc.dg/torture/simd20041.d: New test. * gdc.dg/torture/simd21673.d: New test. * gdc.dg/torture/simd21676.d: New test. * gdc.dg/torture/simd22438.d: New test. * gdc.dg/torture/simd23009.d: New test. * gdc.dg/torture/simd23077.d: New test. * gdc.dg/torture/simd8.d: New test. * gdc.dg/torture/simd9.d: New test. * gdc.dg/torture/simd_prefetch.d: New test. --- gcc/d/d-attribs.cc | 5 +- gcc/d/d-builtins.cc | 3 + gcc/d/d-lang.cc | 10 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/VERSION | 2 +- gcc/d/dmd/aggregate.d | 2 +- gcc/d/dmd/aggregate.h | 4 +- gcc/d/dmd/attrib.d | 41 ---- gcc/d/dmd/attrib.h | 1 - gcc/d/dmd/clone.d | 22 +-- gcc/d/dmd/common/bitfields.d | 9 +- gcc/d/dmd/common/file.d | 11 +- gcc/d/dmd/cparse.d | 39 +++- gcc/d/dmd/cppmangle.d | 10 +- gcc/d/dmd/dcast.d | 114 +++++------ gcc/d/dmd/declaration.d | 59 ++++-- gcc/d/dmd/declaration.h | 66 +++++-- gcc/d/dmd/dinterpret.d | 6 + gcc/d/dmd/dmodule.d | 435 ++++++++++++++++++++---------------------- gcc/d/dmd/dscope.d | 6 +- gcc/d/dmd/dstruct.d | 33 +++- gcc/d/dmd/dsymbol.d | 54 +++++- gcc/d/dmd/dsymbol.h | 16 +- gcc/d/dmd/dsymbolsem.d | 204 +++++++++++++------- gcc/d/dmd/dtemplate.d | 4 +- gcc/d/dmd/entity.d | 236 ++++++++++------------- gcc/d/dmd/escape.d | 369 +++++++++++++++-------------------- gcc/d/dmd/expression.d | 2 +- gcc/d/dmd/expression.h | 1 + gcc/d/dmd/expressionsem.d | 173 +++++++++++------ gcc/d/dmd/func.d | 276 +++++++++++++-------------- gcc/d/dmd/globals.d | 5 +- gcc/d/dmd/globals.h | 6 +- gcc/d/dmd/hdrgen.d | 27 ++- gcc/d/dmd/lexer.d | 48 +++-- gcc/d/dmd/module.h | 2 +- gcc/d/dmd/mtype.d | 69 +++---- gcc/d/dmd/mtype.h | 5 + gcc/d/dmd/nogc.d | 4 +- gcc/d/dmd/parse.d | 6 +- gcc/d/dmd/printast.d | 7 + gcc/d/dmd/root/utf.d | 2 +- gcc/d/dmd/safe.d | 10 +- gcc/d/dmd/semantic3.d | 44 ++--- gcc/d/dmd/statementsem.d | 188 +++++++++--------- gcc/d/dmd/templateparamsem.d | 9 + gcc/d/dmd/transitivevisitor.d | 9 + gcc/d/expr.cc | 9 + gcc/d/gdc.texi | 8 +- gcc/d/lang.opt | 4 +- 50 files changed, 1441 insertions(+), 1236 deletions(-) (limited to 'gcc/d') diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc index 04f7f16..90e72e3 100644 --- a/gcc/d/d-attribs.cc +++ b/gcc/d/d-attribs.cc @@ -426,7 +426,8 @@ build_attributes (Expressions *eattrs) void apply_user_attributes (Dsymbol *sym, tree node) { - if (!sym->userAttribDecl) + UserAttributeDeclaration *uda = sym->userAttribDecl (); + if (uda == NULL) return; location_t saved_location = input_location; @@ -436,7 +437,7 @@ apply_user_attributes (Dsymbol *sym, tree node) if (TYPE_P (node) && !COMPLETE_TYPE_P (node)) attr_flags |= ATTR_FLAG_TYPE_IN_PLACE; - Expressions *attrs = sym->userAttribDecl->getAttributes (); + Expressions *attrs = uda->getAttributes (); decl_attributes (&node, build_attributes (attrs), attr_flags); input_location = saved_location; diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index 5997e5d..51e562a 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -505,6 +505,9 @@ d_init_versions (void) VersionCondition::addPredefinedGlobalIdent ("D_TypeInfo"); } + if (optimize) + VersionCondition::addPredefinedGlobalIdent ("D_Optimized"); + VersionCondition::addPredefinedGlobalIdent ("all"); /* Emit all target-specific version identifiers. */ diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index dcc465f..3b61301 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -567,10 +567,10 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.fixAliasThis = value; global.params.previewIn = value; global.params.fix16997 = value; - global.params.noSharedAccess = value; + global.params.noSharedAccess = FeatureState::enabled; global.params.rvalueRefParam = FeatureState::enabled; global.params.inclusiveInContracts = value; - global.params.shortenedMethods = value; + global.params.systemVariables = FeatureState::enabled; global.params.fixImmutableConv = value; break; @@ -619,15 +619,15 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, break; case OPT_fpreview_nosharedaccess: - global.params.noSharedAccess = value; + global.params.noSharedAccess = FeatureState::enabled; break; case OPT_fpreview_rvaluerefparam: global.params.rvalueRefParam = FeatureState::enabled; break; - case OPT_fpreview_shortenedmethods: - global.params.shortenedMethods = value; + case OPT_fpreview_systemvariables: + global.params.systemVariables = FeatureState::enabled; break; case OPT_frelease: diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index a4c46f3..2398875 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -4219ba670ce9ff92f3e874f0f048f2c28134c008 +e4f89195913be1dc638707b1abb24c4f3ae7e0bf 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 83a14f5..50adf9c 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.100.1 +v2.101.0-beta.1 diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d index edca17f..e9e8bbe 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -109,7 +109,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol CPPMANGLE cppmangle; /// overridden symbol with pragma(mangle, "...") if not null - MangleOverride* mangleOverride; + MangleOverride* pMangleOverride; /** * !=null if is nested diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h index f0909e3..d4432b5 100644 --- a/gcc/d/dmd/aggregate.h +++ b/gcc/d/dmd/aggregate.h @@ -82,7 +82,7 @@ public: CPPMANGLE cppmangle; // overridden symbol with pragma(mangle, "...") - MangleOverride *mangleOverride; + MangleOverride *pMangleOverride; /* !=NULL if is nested * pointing to the dsymbol that directly enclosing it. * 1. The function that enclosing it (nested struct and class) @@ -174,7 +174,7 @@ public: structalign_t alignment; // alignment applied outside of the struct ThreeState ispod; // if struct is POD private: - uint8_t bitFields; + uint16_t bitFields; public: static StructDeclaration *create(const Loc &loc, Identifier *id, bool inObject); StructDeclaration *syntaxCopy(Dsymbol *s) override; diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index 3472d1c..3f27cb9 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -894,50 +894,9 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration // then it's evaluated on demand in function semantic return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, sc.aligndecl, this); } - if (ident == Id.printf || ident == Id.scanf) - { - auto sc2 = sc.push(); - - if (ident == Id.printf) - // Override previous setting, never let both be set - sc2.flags = (sc2.flags & ~SCOPE.scanf) | SCOPE.printf; - else - sc2.flags = (sc2.flags & ~SCOPE.printf) | SCOPE.scanf; - - return sc2; - } return sc; } - PINLINE evalPragmaInline(Scope* sc) - { - if (!args || args.dim == 0) - return PINLINE.default_; - - Expression e = (*args)[0]; - if (!e.type) - { - - sc = sc.startCTFE(); - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); - e = e.ctfeInterpret(); - e = e.toBoolean(sc); - if (e.isErrorExp()) - error("pragma(`inline`, `true` or `false`) expected, not `%s`", (*args)[0].toChars()); - (*args)[0] = e; - } - - const opt = e.toBool(); - if (opt.isEmpty()) - return PINLINE.default_; - else if (opt.get()) - return PINLINE.always; - else - return PINLINE.never; - } - override const(char)* kind() const { return "pragma"; diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h index 1fe33a6..b153229 100644 --- a/gcc/d/dmd/attrib.h +++ b/gcc/d/dmd/attrib.h @@ -154,7 +154,6 @@ public: PragmaDeclaration *syntaxCopy(Dsymbol *s) override; Scope *newScope(Scope *sc) override; - PINLINE evalPragmaInline(Scope* sc); const char *kind() const override; void accept(Visitor *v) override { v->visit(this); } }; diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index ba7d590..c999048 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -300,7 +300,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.flags |= FUNCFLAG.generated; + fop.isGenerated = true; Expression e; if (stc & STC.disable) { @@ -581,7 +581,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.flags |= FUNCFLAG.generated; + fop.isGenerated = true; fop.parent = sd; Expression e1 = new IdentifierExp(loc, Id.This); Expression e2 = new IdentifierExp(loc, Id.p); @@ -705,7 +705,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.flags |= FUNCFLAG.generated; + fop.isGenerated = true; fop.parent = sd; Expression e1 = new IdentifierExp(loc, Id.This); Expression e2 = new IdentifierExp(loc, Id.p); @@ -823,7 +823,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.flags |= FUNCFLAG.generated; + fop.isGenerated = true; /* Do memberwise hashing. * @@ -961,7 +961,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.flags |= FUNCFLAG.generated; + dd.isGenerated = true; dd.storage_class |= STC.inference; dd.fbody = new ExpStatement(loc, e); ad.members.push(dd); @@ -1017,7 +1017,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc) e = Expression.combine(e, ce); } auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__aggrDtor); - dd.flags |= FUNCFLAG.generated; + dd.isGenerated = true; dd.storage_class |= STC.inference; dd.fbody = new ExpStatement(loc, e); ad.members.push(dd); @@ -1088,7 +1088,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.flags |= FUNCFLAG.generated; + func.isGenerated = true; auto sc2 = sc.push(); sc2.stc &= ~STC.static_; // not a static destructor @@ -1140,7 +1140,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.flags |= FUNCFLAG.generated; + func.isGenerated = true; func.storage_class |= STC.inference; auto sc2 = sc.push(); @@ -1416,7 +1416,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) //printf("Building __fieldPostBlit()\n"); checkShared(); auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__fieldPostblit); - dd.flags |= FUNCFLAG.generated; + dd.isGenerated = true; dd.storage_class |= STC.inference | STC.scope_; dd.fbody = (stc & STC.disable) ? null : new CompoundStatement(loc, postblitCalls); sd.postblits.shift(dd); @@ -1454,7 +1454,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) checkShared(); auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__aggrPostblit); - dd.flags |= FUNCFLAG.generated; + dd.isGenerated = true; dd.storage_class |= STC.inference; dd.fbody = new ExpStatement(loc, e); sd.members.push(dd); @@ -1517,7 +1517,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.flags |= FUNCFLAG.generated; + ccd.isGenerated = true; return ccd; } diff --git a/gcc/d/dmd/common/bitfields.d b/gcc/d/dmd/common/bitfields.d index cccaabd..bba61ad 100644 --- a/gcc/d/dmd/common/bitfields.d +++ b/gcc/d/dmd/common/bitfields.d @@ -23,6 +23,7 @@ if (__traits(isUnsigned, T)) string result = "extern (C++) pure nothrow @nogc @safe final {"; enum structName = __traits(identifier, S); + string initialValue = ""; foreach (size_t i, mem; __traits(allMembers, S)) { static assert(is(typeof(__traits(getMember, S, mem)) == bool)); @@ -37,8 +38,10 @@ if (__traits(isUnsigned, T)) v ? (bitFields |= "~mask~") : (bitFields &= ~"~mask~"); return v; }"; + + initialValue = (__traits(getMember, S.init, mem) ? "1" : "0") ~ initialValue; } - return result ~ "}\n private "~T.stringof~" bitFields;\n"; + return result ~ "}\n private "~T.stringof~" bitFields = 0b" ~ initialValue ~ ";\n"; } /// @@ -48,7 +51,7 @@ unittest { bool x; bool y; - bool z; + bool z = 1; } static struct S @@ -66,5 +69,5 @@ unittest s.y = true; assert(s.y); assert(!s.x); - assert(!s.z); + assert(s.z); } diff --git a/gcc/d/dmd/common/file.d b/gcc/d/dmd/common/file.d index 8f34b53..89e7027 100644 --- a/gcc/d/dmd/common/file.d +++ b/gcc/d/dmd/common/file.d @@ -144,9 +144,14 @@ struct FileMapping(Datum) import core.stdc.string : strlen; import core.stdc.stdlib : malloc; import core.stdc.string : memcpy; - auto totalNameLength = filename.strlen() + 1; - name = cast(char*) memcpy(malloc(totalNameLength), filename, totalNameLength); - name || assert(0, "FileMapping: Out of memory."); + const totalNameLength = filename.strlen() + 1; + auto namex = cast(char*) malloc(totalNameLength); + if (!namex) + { + fprintf(stderr, "FileMapping: Out of memory."); + exit(1); + } + name = cast(char*) memcpy(namex, filename, totalNameLength); } /** diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 2c5a4f0..ad1ad67 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -1906,6 +1906,8 @@ final class CParser(AST) : Parser!AST { auto str = asmName.peekString(); p.mangleOverride = str; +// p.adFlags |= AST.VarDeclaration.nounderscore; + p.adFlags |= 4; // cannot get above line to compile on Ubuntu } } s = applySpecifier(s, specifier); @@ -5164,18 +5166,40 @@ final class CParser(AST) : Parser!AST if (n.value == TOK.identifier && n.ident == Id.pop) { scan(&n); - while (n.value == TOK.comma) + size_t len = this.records.length; + if (n.value == TOK.rightParenthesis) // #pragma pack ( pop ) + { + if (len == 0) // nothing to pop + return closingParen(); + + this.records.setDim(len - 1); + this.packs.setDim(len - 1); + if (len == 1) // stack is now empty + packalign.setDefault(); + else + packalign = (*this.packs)[len - 1]; + return closingParen(); + } + while (n.value == TOK.comma) // #pragma pack ( pop , { scan(&n); if (n.value == TOK.identifier) { - for (size_t len = this.records.length; len; --len) + /* pragma pack(pop, identifier + * Pop until identifier is found, pop that one too, and set + * alignment to the new top of the stack. + * If identifier is not found, do nothing. + */ + for ( ; len; --len) { if ((*this.records)[len - 1] == n.ident) { - packalign = (*this.packs)[len - 1]; this.records.setDim(len - 1); this.packs.setDim(len - 1); + if (len > 1) + packalign = (*this.packs)[len - 2]; + else + packalign.setDefault(); // stack empty, use default break; } } @@ -5184,14 +5208,18 @@ final class CParser(AST) : Parser!AST else if (n.value == TOK.int32Literal) { setPackAlign(n); - this.records.push(null); - this.packs.push(packalign); + scan(&n); + } + else + { + error(loc, "identifier or alignment value expected following `#pragma pack(pop,` not `%s`", n.toChars()); scan(&n); } } return closingParen(); } /* # pragma pack ( integer ) + * Sets alignment to integer */ if (n.value == TOK.int32Literal) { @@ -5200,6 +5228,7 @@ final class CParser(AST) : Parser!AST return closingParen(); } /* # pragma pack ( ) + * Sets alignment to default */ if (n.value == TOK.rightParenthesis) { diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d index fed83b8..7c130e9 100644 --- a/gcc/d/dmd/cppmangle.d +++ b/gcc/d/dmd/cppmangle.d @@ -615,7 +615,7 @@ private final class CppMangleVisitor : Visitor if (!ti) { auto ag = s.isAggregateDeclaration(); - const ident = (ag && ag.mangleOverride) ? ag.mangleOverride.id : s.ident; + const ident = (ag && ag.pMangleOverride) ? ag.pMangleOverride.id : s.ident; this.writeNamespace(s.cppnamespace, () { this.writeIdentifier(ident); this.abiTags.writeSymbol(s, this); @@ -654,14 +654,14 @@ private final class CppMangleVisitor : Visitor } auto ag = ti.aliasdecl ? ti.aliasdecl.isAggregateDeclaration() : null; - if (ag && ag.mangleOverride) + if (ag && ag.pMangleOverride) { this.writeNamespace( ti.toAlias().cppnamespace, () { - this.writeIdentifier(ag.mangleOverride.id); - if (ag.mangleOverride.agg && ag.mangleOverride.agg.isInstantiated()) + this.writeIdentifier(ag.pMangleOverride.id); + if (ag.pMangleOverride.agg && ag.pMangleOverride.agg.isInstantiated()) { - auto to = ag.mangleOverride.agg.isInstantiated(); + auto to = ag.pMangleOverride.agg.isInstantiated(); append(to); this.abiTags.writeSymbol(to.tempdecl, this); template_args(to); diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 8ab3873..ba3afb7 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -327,6 +327,45 @@ MATCH implicitConvTo(Expression e, Type t) return MATCH.nomatch; } + // Apply mod bits to each function parameter, + // and see if we can convert the function argument to the modded type + static bool parametersModMatch(Expressions* args, TypeFunction tf, MOD mod) + { + const size_t nparams = tf.parameterList.length; + const size_t j = tf.isDstyleVariadic(); // if TypeInfoArray was prepended + foreach (const i; j .. args.dim) + { + Expression earg = (*args)[i]; + Type targ = earg.type.toBasetype(); + static if (LOG) + { + printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); + } + if (i - j < nparams) + { + Parameter fparam = tf.parameterList[i - j]; + if (fparam.isLazy()) + return false; // not sure what to do with this + Type tparam = fparam.type; + if (!tparam) + continue; + if (fparam.isReference()) + { + if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch) + return false; + continue; + } + } + static if (LOG) + { + printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); + } + if (implicitMod(earg, targ, mod) == MATCH.nomatch) + return false; + } + return true; + } + MATCH visitAdd(AddExp e) { version (none) @@ -894,9 +933,6 @@ MATCH implicitConvTo(Expression e, Type t) /* Apply mod bits to each function parameter, * and see if we can convert the function argument to the modded type */ - - size_t nparams = tf.parameterList.length; - size_t j = tf.isDstyleVariadic(); // if TypeInfoArray was prepended if (auto dve = e.e1.isDotVarExp()) { /* Treat 'this' as just another function argument @@ -905,36 +941,9 @@ MATCH implicitConvTo(Expression e, Type t) if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch) return result; } - foreach (const i; j .. e.arguments.dim) - { - Expression earg = (*e.arguments)[i]; - Type targ = earg.type.toBasetype(); - static if (LOG) - { - printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); - } - if (i - j < nparams) - { - Parameter fparam = tf.parameterList[i - j]; - if (fparam.isLazy()) - return result; // not sure what to do with this - Type tparam = fparam.type; - if (!tparam) - continue; - if (fparam.isReference()) - { - if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch) - return result; - continue; - } - } - static if (LOG) - { - printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); - } - if (implicitMod(earg, targ, mod) == MATCH.nomatch) - return result; - } + + if (!parametersModMatch(e.arguments, tf, mod)) + return result; /* Success */ @@ -1206,47 +1215,16 @@ MATCH implicitConvTo(Expression e, Type t) if (tf.purity == PURE.impure) return MATCH.nomatch; // impure + // Allow a conversion to immutable type, or + // conversions of mutable types between thread-local and shared. if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant) { return MATCH.nomatch; } - // Allow a conversion to immutable type, or - // conversions of mutable types between thread-local and shared. - - Expressions* args = e.arguments; - size_t nparams = tf.parameterList.length; - // if TypeInfoArray was prepended - size_t j = tf.isDstyleVariadic(); - for (size_t i = j; i < e.arguments.dim; ++i) + if (!parametersModMatch(e.arguments, tf, mod)) { - Expression earg = (*args)[i]; - Type targ = earg.type.toBasetype(); - static if (LOG) - { - printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars()); - } - if (i - j < nparams) - { - Parameter fparam = tf.parameterList[i - j]; - if (fparam.isLazy()) - return MATCH.nomatch; // not sure what to do with this - Type tparam = fparam.type; - if (!tparam) - continue; - if (fparam.isReference()) - { - if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch) - return MATCH.nomatch; - continue; - } - } - static if (LOG) - { - printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars()); - } - if (implicitMod(earg, targ, mod) == MATCH.nomatch) - return MATCH.nomatch; + return MATCH.nomatch; } } diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index ff27e37..07d58f0 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -227,6 +227,7 @@ extern (C++) abstract class Declaration : Dsymbol ubyte adFlags; // control re-assignment of AliasDeclaration (put here for packing reasons) enum wasRead = 1; // set if AliasDeclaration was read enum ignoreRead = 2; // ignore any reads of AliasDeclaration + enum nounderscore = 4; // don't prepend _ to mangled name Symbol* isym; // import version of csym @@ -481,6 +482,11 @@ extern (C++) abstract class Declaration : Dsymbol return (storage_class & STC.scope_) != 0; } + final bool isReturn() const pure nothrow @nogc @safe + { + return (storage_class & STC.return_) != 0; + } + final bool isSynchronized() const pure nothrow @nogc @safe { return (storage_class & STC.synchronized_) != 0; @@ -542,6 +548,11 @@ extern (C++) abstract class Declaration : Dsymbol return (storage_class & STC.future) != 0; } + final extern(D) bool isSystem() const pure nothrow @nogc @safe + { + return (storage_class & STC.system) != 0; + } + override final Visibility visible() pure nothrow @nogc @safe { return visibility; @@ -780,7 +791,17 @@ extern (C++) final class AliasDeclaration : Declaration * is not overloadable. */ if (type) - return false; + { + /* + If type has been resolved already we could + still be inserting an alias from an import. + + If we are handling an alias then pretend + it was inserting and return true, if not then + false since we didn't even pretend to insert something. + */ + return this._import && this.equals(s); + } /* When s is added in member scope by static if, mixin("code") or others, * aliassym is determined already. See the case in: test/compilable/test61.d @@ -1634,7 +1655,7 @@ extern (C++) class VarDeclaration : Declaration // Add this VarDeclaration to fdv.closureVars[] if not already there if (!sc.intypeof && !(sc.flags & SCOPE.compile) && // https://issues.dlang.org/show_bug.cgi?id=17605 - (fdv.flags & FUNCFLAG.compileTimeOnly || !(fdthis.flags & FUNCFLAG.compileTimeOnly)) + (fdv.isCompileTimeOnly || !fdthis.isCompileTimeOnly) ) { if (!fdv.closureVars.contains(this)) @@ -1754,16 +1775,21 @@ extern (C++) class BitFieldDeclaration : VarDeclaration override final void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion) { - //printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars()); - static void print(const ref FieldState fieldState) + enum log = false; + static if (log) { - printf("FieldState.offset = %d bytes\n", fieldState.offset); - printf(" .fieldOffset = %d bytes\n", fieldState.fieldOffset); - printf(" .bitOffset = %d bits\n", fieldState.bitOffset); - printf(" .fieldSize = %d bytes\n", fieldState.fieldSize); - printf(" .inFlight = %d\n\n", fieldState.inFlight); + printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars()); + void print(const ref FieldState fieldState) + { + printf("FieldState.offset = %d bytes\n", fieldState.offset); + printf(" .fieldOffset = %d bytes\n", fieldState.fieldOffset); + printf(" .bitOffset = %d bits\n", fieldState.bitOffset); + printf(" .fieldSize = %d bytes\n", fieldState.fieldSize); + printf(" .inFlight = %d\n", fieldState.inFlight); + printf(" fieldWidth = %d bits\n", fieldWidth); + } + print(fieldState); } - //print(fieldState); Type t = type.toBasetype(); const bool anon = isAnonymous(); @@ -1780,6 +1806,7 @@ extern (C++) class BitFieldDeclaration : VarDeclaration assert(sz != SIZE_INVALID && sz < uint.max); uint memsize = cast(uint)sz; // size of member uint memalignsize = target.fieldalign(t); // size of member for alignment purposes + if (log) printf(" memsize: %u memalignsize: %u\n", memsize, memalignsize); if (fieldWidth == 0 && !anon) error(loc, "named bit fields cannot have 0 width"); @@ -1790,6 +1817,7 @@ extern (C++) class BitFieldDeclaration : VarDeclaration void startNewField() { + if (log) printf("startNewField()\n"); uint alignsize; if (style == TargetC.BitFieldStyle.Gcc_Clang) { @@ -1881,15 +1909,15 @@ extern (C++) class BitFieldDeclaration : VarDeclaration if (!fieldState.inFlight) { + //printf("not in flight\n"); startNewField(); } else if (style == TargetC.BitFieldStyle.Gcc_Clang) { - if (fieldState.bitOffset + fieldWidth > memsize * 8) - { - //printf("start1 fieldState.bitOffset:%u fieldWidth:%u memsize:%u\n", fieldState.bitOffset, fieldWidth, memsize); - startNewField(); - } + // If the bit-field spans more units of alignment than its type, + // start a new field at the next alignment boundary. + if (fieldState.bitOffset == fieldState.fieldSize * 8) + startNewField(); // the bit field is full else { // if alignment boundary is crossed @@ -1909,6 +1937,7 @@ extern (C++) class BitFieldDeclaration : VarDeclaration if (memsize != fieldState.fieldSize || fieldState.bitOffset + fieldWidth > fieldState.fieldSize * 8) { + //printf("new field\n"); startNewField(); } } diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 5bce6b0..2668b6e 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -139,6 +139,7 @@ public: bool isWild() const { return (storage_class & STCwild) != 0; } bool isAuto() const { return (storage_class & STCauto) != 0; } bool isScope() const { return (storage_class & STCscope) != 0; } + bool isReturn() const { return (storage_class & STCreturn) != 0; } bool isSynchronized() const { return (storage_class & STCsynchronized) != 0; } bool isParameter() const { return (storage_class & STCparameter) != 0; } bool isDeprecated() const override final { return (storage_class & STCdeprecated) != 0; } @@ -615,7 +616,54 @@ public: AttributeViolation* safetyViolation; - unsigned flags; // FUNCFLAGxxxxx + // Formerly FUNCFLAGS + uint32_t flags; + bool purityInprocess() const; + bool purityInprocess(bool v); + bool safetyInprocess() const; + bool safetyInprocess(bool v); + bool nothrowInprocess() const; + bool nothrowInprocess(bool v); + bool nogcInprocess() const; + bool nogcInprocess(bool v); + bool returnInprocess() const; + bool returnInprocess(bool v); + bool inlineScanned() const; + bool inlineScanned(bool v); + bool inferScope() const; + bool inferScope(bool v); + bool hasCatches() const; + bool hasCatches(bool v); + bool isCompileTimeOnly() const; + bool isCompileTimeOnly(bool v); + bool printf() const; + bool printf(bool v); + bool scanf() const; + bool scanf(bool v); + bool noreturn() const; + bool noreturn(bool v); + bool isNRVO() const; + bool isNRVO(bool v); + bool isNaked() const; + bool isNaked(bool v); + bool isGenerated() const; + bool isGenerated(bool v); + bool isIntroducing() const; + bool isIntroducing(bool v); + bool hasSemantic3Errors() const; + bool hasSemantic3Errors(bool v); + bool hasNoEH() const; + bool hasNoEH(bool v); + bool inferRetType() const; + bool inferRetType(bool v); + bool hasDualContext() const; + bool hasDualContext(bool v); + bool hasAlwaysInlines() const; + bool hasAlwaysInlines(bool v); + bool isCrtCtor() const; + bool isCrtCtor(bool v); + bool isCrtDtor() const; + bool isCrtDtor(bool v); // Data for a function declaration that is needed for the Objective-C // integration. @@ -655,22 +703,6 @@ public: bool isNogc(); bool isNogcBypassingInference(); - bool isNRVO() const; - void isNRVO(bool v); - bool isNaked() const; - void isNaked(bool v); - 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; - void isCrtCtor(bool v); - bool isCrtDtor() const; - void isCrtDtor(bool v); virtual bool isNested() const; AggregateDeclaration *isThis() override; diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index a95d9de..63b70009 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -2872,6 +2872,12 @@ public: else m = v.getConstInitializer(true); } + else if (v.type.isTypeNoreturn()) + { + // Noreturn field with default initializer + (*elems)[fieldsSoFar + i] = null; + continue; + } else m = v.type.defaultInitLiteral(e.loc); if (exceptionOrCant(m)) diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 2cb1cc7..b2908ce 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -98,13 +98,13 @@ private const(char)[] getFilename(Identifier[] packages, Identifier ident) nothr { const(char)[] filename = ident.toString(); - if (packages.length == 0) - return filename; - OutBuffer buf; OutBuffer dotmods; auto modAliases = &global.params.modFileAliasStrings; + if (packages.length == 0 && modAliases.length == 0) + return filename; + void checkModFileAlias(const(char)[] p) { /* Check and replace the contents of buf[] with @@ -308,7 +308,7 @@ extern (C++) class Package : ScopeDsymbol packages ~= s.ident; reverse(packages); - if (FileManager.lookForSourceFile(getFilename(packages, ident), global.path ? (*global.path)[] : null)) + if (Module.find(getFilename(packages, ident))) Module.load(Loc.initial, packages, this.ident); else isPkgMod = PKG.package_; @@ -492,6 +492,16 @@ extern (C++) final class Module : Package return new Module(Loc.initial, filename, ident, doDocComment, doHdrGen); } + static const(char)* find(const(char)* filename) + { + return find(filename.toDString).ptr; + } + + extern (D) static const(char)[] find(const(char)[] filename) + { + return FileManager.lookForSourceFile(filename, global.path ? (*global.path)[] : null); + } + extern (C++) static Module load(const ref Loc loc, Identifiers* packages, Identifier ident) { return load(loc, packages ? (*packages)[] : null, ident); @@ -506,7 +516,7 @@ extern (C++) final class Module : Package // foo\bar\baz const(char)[] filename = getFilename(packages, ident); // Look for the source file - if (const result = FileManager.lookForSourceFile(filename, global.path ? (*global.path)[] : null)) + if (const result = find(filename)) filename = result; // leaks auto m = new Module(loc, filename, ident, 0, 0); @@ -703,232 +713,12 @@ extern (C++) final class Module : Package /// ditto extern (D) Module parseModule(AST)() { - enum Endian { little, big} - enum SourceEncoding { utf16, utf32} - - /* - * Convert a buffer from UTF32 to UTF8 - * Params: - * Endian = is the buffer big/little endian - * buf = buffer of UTF32 data - * Returns: - * input buffer reencoded as UTF8 - */ - - char[] UTF32ToUTF8(Endian endian)(const(char)[] buf) - { - static if (endian == Endian.little) - alias readNext = Port.readlongLE; - else - alias readNext = Port.readlongBE; - - if (buf.length & 3) - { - error("odd length of UTF-32 char source %llu", cast(ulong) buf.length); - return null; - } - - const (uint)[] eBuf = cast(const(uint)[])buf; - - OutBuffer dbuf; - dbuf.reserve(eBuf.length); - - foreach (i; 0 .. eBuf.length) - { - const u = readNext(&eBuf[i]); - if (u & ~0x7F) - { - if (u > 0x10FFFF) - { - error("UTF-32 value %08x greater than 0x10FFFF", u); - return null; - } - dbuf.writeUTF8(u); - } - else - dbuf.writeByte(u); - } - dbuf.writeByte(0); //add null terminator - return dbuf.extractSlice(); - } - - /* - * Convert a buffer from UTF16 to UTF8 - * Params: - * Endian = is the buffer big/little endian - * buf = buffer of UTF16 data - * Returns: - * input buffer reencoded as UTF8 - */ - - char[] UTF16ToUTF8(Endian endian)(const(char)[] buf) - { - static if (endian == Endian.little) - alias readNext = Port.readwordLE; - else - alias readNext = Port.readwordBE; - - if (buf.length & 1) - { - error("odd length of UTF-16 char source %llu", cast(ulong) buf.length); - return null; - } - - const (ushort)[] eBuf = cast(const(ushort)[])buf; - - OutBuffer dbuf; - dbuf.reserve(eBuf.length); - - //i will be incremented in the loop for high codepoints - foreach (ref i; 0 .. eBuf.length) - { - uint u = readNext(&eBuf[i]); - if (u & ~0x7F) - { - if (0xD800 <= u && u < 0xDC00) - { - i++; - if (i >= eBuf.length) - { - error("surrogate UTF-16 high value %04x at end of file", u); - return null; - } - const u2 = readNext(&eBuf[i]); - if (u2 < 0xDC00 || 0xE000 <= u2) - { - error("surrogate UTF-16 low value %04x out of range", u2); - return null; - } - u = (u - 0xD7C0) << 10; - u |= (u2 - 0xDC00); - } - else if (u >= 0xDC00 && u <= 0xDFFF) - { - error("unpaired surrogate UTF-16 value %04x", u); - return null; - } - else if (u == 0xFFFE || u == 0xFFFF) - { - error("illegal UTF-16 value %04x", u); - return null; - } - dbuf.writeUTF8(u); - } - else - dbuf.writeByte(u); - } - dbuf.writeByte(0); //add a terminating null byte - return dbuf.extractSlice(); - } - const(char)* srcname = srcfile.toChars(); //printf("Module::parse(srcname = '%s')\n", srcname); isPackageFile = isPackageFileName(srcfile); - const(char)[] buf = cast(const(char)[]) this.src; - - bool needsReencoding = true; - bool hasBOM = true; //assume there's a BOM - Endian endian; - SourceEncoding sourceEncoding; - - if (buf.length >= 2) - { - /* Convert all non-UTF-8 formats to UTF-8. - * BOM : https://www.unicode.org/faq/utf_bom.html - * 00 00 FE FF UTF-32BE, big-endian - * FF FE 00 00 UTF-32LE, little-endian - * FE FF UTF-16BE, big-endian - * FF FE UTF-16LE, little-endian - * EF BB BF UTF-8 - */ - if (buf[0] == 0xFF && buf[1] == 0xFE) - { - endian = Endian.little; - - sourceEncoding = buf.length >= 4 && buf[2] == 0 && buf[3] == 0 - ? SourceEncoding.utf32 - : SourceEncoding.utf16; - } - else if (buf[0] == 0xFE && buf[1] == 0xFF) - { - endian = Endian.big; - sourceEncoding = SourceEncoding.utf16; - } - else if (buf.length >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF) - { - endian = Endian.big; - sourceEncoding = SourceEncoding.utf32; - } - else if (buf.length >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) - { - needsReencoding = false;//utf8 with BOM - } - else - { - /* There is no BOM. Make use of Arcane Jill's insight that - * the first char of D source must be ASCII to - * figure out the encoding. - */ - hasBOM = false; - if (buf.length >= 4 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0) - { - endian = Endian.little; - sourceEncoding = SourceEncoding.utf32; - } - else if (buf.length >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0) - { - endian = Endian.big; - sourceEncoding = SourceEncoding.utf32; - } - else if (buf.length >= 2 && buf[1] == 0) //try to check for UTF-16 - { - endian = Endian.little; - sourceEncoding = SourceEncoding.utf16; - } - else if (buf[0] == 0) - { - endian = Endian.big; - sourceEncoding = SourceEncoding.utf16; - } - else { - // It's UTF-8 - needsReencoding = false; - if (buf[0] >= 0x80) - { - error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]); - return null; - } - } - } - //throw away BOM - if (hasBOM) - { - if (!needsReencoding) buf = buf[3..$];// utf-8 already - else if (sourceEncoding == SourceEncoding.utf32) buf = buf[4..$]; - else buf = buf[2..$]; //utf 16 - } - } - // Assume the buffer is from memory and has not be read from disk. Assume UTF-8. - else if (buf.length >= 1 && (buf[0] == '\0' || buf[0] == 0x1A)) - needsReencoding = false; - //printf("%s, %d, %d, %d\n", srcfile.name.toChars(), needsReencoding, endian == Endian.little, sourceEncoding == SourceEncoding.utf16); - if (needsReencoding) - { - if (sourceEncoding == SourceEncoding.utf16) - { - buf = endian == Endian.little - ? UTF16ToUTF8!(Endian.little)(buf) - : UTF16ToUTF8!(Endian.big)(buf); - } - else - { - buf = endian == Endian.little - ? UTF32ToUTF8!(Endian.little)(buf) - : UTF32ToUTF8!(Endian.big)(buf); - } - // an error happened on UTF conversion - if (buf is null) return null; - } + const(char)[] buf = processSource(src, this); + // an error happened on UTF conversion + if (buf is null) return null; /* If it starts with the string "Ddoc", then it's a documentation * source file. @@ -1533,3 +1323,192 @@ extern (C++) struct ModuleDeclaration return this.toChars().toDString; } } + +/** + * Process the content of a source file + * + * Attempts to find which encoding it is using, if it has BOM, + * and then normalize the source to UTF-8. If no encoding is required, + * a slice of `src` will be returned without extra allocation. + * + * Params: + * src = Content of the source file to process + * mod = Module matching `src`, used for error handling + * + * Returns: + * UTF-8 encoded variant of `src`, stripped of any BOM, + * or `null` if an error happened. + */ +private const(char)[] processSource (const(ubyte)[] src, Module mod) +{ + enum SourceEncoding { utf16, utf32} + enum Endian { little, big} + + /* + * Convert a buffer from UTF32 to UTF8 + * Params: + * Endian = is the buffer big/little endian + * buf = buffer of UTF32 data + * Returns: + * input buffer reencoded as UTF8 + */ + + char[] UTF32ToUTF8(Endian endian)(const(char)[] buf) + { + static if (endian == Endian.little) + alias readNext = Port.readlongLE; + else + alias readNext = Port.readlongBE; + + if (buf.length & 3) + { + mod.error("odd length of UTF-32 char source %llu", cast(ulong) buf.length); + return null; + } + + const (uint)[] eBuf = cast(const(uint)[])buf; + + OutBuffer dbuf; + dbuf.reserve(eBuf.length); + + foreach (i; 0 .. eBuf.length) + { + const u = readNext(&eBuf[i]); + if (u & ~0x7F) + { + if (u > 0x10FFFF) + { + mod.error("UTF-32 value %08x greater than 0x10FFFF", u); + return null; + } + dbuf.writeUTF8(u); + } + else + dbuf.writeByte(u); + } + dbuf.writeByte(0); //add null terminator + return dbuf.extractSlice(); + } + + /* + * Convert a buffer from UTF16 to UTF8 + * Params: + * Endian = is the buffer big/little endian + * buf = buffer of UTF16 data + * Returns: + * input buffer reencoded as UTF8 + */ + + char[] UTF16ToUTF8(Endian endian)(const(char)[] buf) + { + static if (endian == Endian.little) + alias readNext = Port.readwordLE; + else + alias readNext = Port.readwordBE; + + if (buf.length & 1) + { + mod.error("odd length of UTF-16 char source %llu", cast(ulong) buf.length); + return null; + } + + const (ushort)[] eBuf = cast(const(ushort)[])buf; + + OutBuffer dbuf; + dbuf.reserve(eBuf.length); + + //i will be incremented in the loop for high codepoints + foreach (ref i; 0 .. eBuf.length) + { + uint u = readNext(&eBuf[i]); + if (u & ~0x7F) + { + if (0xD800 <= u && u < 0xDC00) + { + i++; + if (i >= eBuf.length) + { + mod.error("surrogate UTF-16 high value %04x at end of file", u); + return null; + } + const u2 = readNext(&eBuf[i]); + if (u2 < 0xDC00 || 0xE000 <= u2) + { + mod.error("surrogate UTF-16 low value %04x out of range", u2); + return null; + } + u = (u - 0xD7C0) << 10; + u |= (u2 - 0xDC00); + } + else if (u >= 0xDC00 && u <= 0xDFFF) + { + mod.error("unpaired surrogate UTF-16 value %04x", u); + return null; + } + else if (u == 0xFFFE || u == 0xFFFF) + { + mod.error("illegal UTF-16 value %04x", u); + return null; + } + dbuf.writeUTF8(u); + } + else + dbuf.writeByte(u); + } + dbuf.writeByte(0); //add a terminating null byte + return dbuf.extractSlice(); + } + + const(char)[] buf = cast(const(char)[]) src; + + // Assume the buffer is from memory and has not be read from disk. Assume UTF-8. + if (buf.length < 2) + return buf; + + /* Convert all non-UTF-8 formats to UTF-8. + * BOM : https://www.unicode.org/faq/utf_bom.html + * 00 00 FE FF UTF-32BE, big-endian + * FF FE 00 00 UTF-32LE, little-endian + * FE FF UTF-16BE, big-endian + * FF FE UTF-16LE, little-endian + * EF BB BF UTF-8 + */ + if (buf[0] == 0xFF && buf[1] == 0xFE) + { + if (buf.length >= 4 && buf[2] == 0 && buf[3] == 0) + return UTF32ToUTF8!(Endian.little)(buf[4 .. $]); + return UTF16ToUTF8!(Endian.little)(buf[2 .. $]); + } + + if (buf[0] == 0xFE && buf[1] == 0xFF) + return UTF16ToUTF8!(Endian.big)(buf[2 .. $]); + + if (buf.length >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0xFE && buf[3] == 0xFF) + return UTF32ToUTF8!(Endian.big)(buf[4 .. $]); + + if (buf.length >= 3 && buf[0] == 0xEF && buf[1] == 0xBB && buf[2] == 0xBF) + return buf[3 .. $]; + + /* There is no BOM. Make use of Arcane Jill's insight that + * the first char of D source must be ASCII to + * figure out the encoding. + */ + if (buf.length >= 4 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0) + return UTF32ToUTF8!(Endian.little)(buf); + if (buf.length >= 4 && buf[0] == 0 && buf[1] == 0 && buf[2] == 0) + return UTF32ToUTF8!(Endian.big)(buf); + // try to check for UTF-16 + if (buf.length >= 2 && buf[1] == 0) + return UTF16ToUTF8!(Endian.little)(buf); + if (buf[0] == 0) + return UTF16ToUTF8!(Endian.big)(buf); + + // It's UTF-8 + if (buf[0] >= 0x80) + { + mod.error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]); + return null; + } + + return buf; +} diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index 9c30978..c816759 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -63,17 +63,13 @@ enum SCOPE free = 0x8000, /// is on free list fullinst = 0x10000, /// fully instantiate templates - - // The following are mutually exclusive - printf = 0x4_0000, /// printf-style function - scanf = 0x8_0000, /// scanf-style function } /// Flags that are carried along with a scope push() private enum PersistentFlags = SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint | SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility | - SCOPE.printf | SCOPE.scanf | SCOPE.Cfile; + SCOPE.Cfile; struct Scope { diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index 4126a8a..1c2f226 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -216,6 +216,11 @@ extern (C++) class StructDeclaration : AggregateDeclaration bool hasIdentityEquals; // true if has identity opEquals bool hasNoFields; // has no fields bool hasCopyCtor; // copy constructor + bool hasPointerField; // members with indirections + bool hasVoidInitPointers; // void-initialized unsafe fields + bool hasSystemFields; // @system members + bool hasFieldWithInvariant; // invariants + bool computedTypeProperties;// the above 3 fields are computed // Even if struct is defined as non-root symbol, some built-in operations // (e.g. TypeidExp, NewExp, ArrayLiteralExp, etc) request its TypeInfo. // For those, today TypeInfo_Struct is generated in COMDAT. @@ -223,7 +228,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration } import dmd.common.bitfields : generateBitFields; - mixin(generateBitFields!(BitFields, ubyte)); + mixin(generateBitFields!(BitFields, ushort)); extern (D) this(const ref Loc loc, Identifier id, bool inObject) { @@ -391,9 +396,35 @@ extern (C++) class StructDeclaration : AggregateDeclaration } } + argTypes = target.toArgTypes(type); } + /// Compute cached type properties for `TypeStruct` + extern(D) final void determineTypeProperties() + { + if (computedTypeProperties) + return; + foreach (vd; fields) + { + if (vd.storage_class & STC.ref_ || vd.hasPointers()) + hasPointerField = true; + + if (vd._init && vd._init.isVoidInitializer() && vd.type.hasPointers()) + hasVoidInitPointers = true; + + if (vd.storage_class & STC.system || vd.type.hasSystemFields()) + hasSystemFields = true; + + if (!vd._init && vd.type.hasVoidInitPointers()) + hasVoidInitPointers = true; + + if (vd.type.hasInvariant()) + hasFieldWithInvariant = true; + } + computedTypeProperties = true; + } + /*************************************** * Determine if struct is POD (Plain Old Data). * diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 7e2d02f..2f10e83 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -236,25 +236,33 @@ struct FieldState bool inFlight; /// bit field is in flight } +// 99.9% of Dsymbols don't have attributes (at least in druntime and Phobos), +// so save memory by grouping them into a separate struct +private struct DsymbolAttributes +{ + /// C++ namespace this symbol belongs to + CPPNamespaceDeclaration cppnamespace; + /// customized deprecation message + DeprecatedDeclaration depdecl_; + /// user defined attributes + UserAttributeDeclaration userAttribDecl; +} + /*********************************************************** */ extern (C++) class Dsymbol : ASTNode { Identifier ident; Dsymbol parent; - /// C++ namespace this symbol belongs to - CPPNamespaceDeclaration cppnamespace; Symbol* csym; // symbol for code generator const Loc loc; // where defined Scope* _scope; // !=null means context to use for semantic() const(char)* prettystring; // cached value of toPrettyChars() + private DsymbolAttributes* atts; /// attached attribute declarations bool errors; // this symbol failed to pass semantic() PASS semanticRun = PASS.initial; ushort localNum; /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab - DeprecatedDeclaration depdecl; // customized deprecation message - UserAttributeDeclaration userAttribDecl; // user defined attributes - final extern (D) this() nothrow { //printf("Dsymbol::Dsymbol(%p)\n", this); @@ -285,6 +293,42 @@ extern (C++) class Dsymbol : ASTNode return ident ? ident.toChars() : "__anonymous"; } + // Getters / setters for fields stored in `DsymbolAttributes` + final nothrow pure @safe + { + private ref DsymbolAttributes getAtts() + { + if (!atts) + atts = new DsymbolAttributes(); + return *atts; + } + + inout(DeprecatedDeclaration) depdecl() inout { return atts ? atts.depdecl_ : null; } + inout(CPPNamespaceDeclaration) cppnamespace() inout { return atts ? atts.cppnamespace : null; } + inout(UserAttributeDeclaration) userAttribDecl() inout { return atts ? atts.userAttribDecl : null; } + + DeprecatedDeclaration depdecl(DeprecatedDeclaration dd) + { + if (!dd && !atts) + return null; + return getAtts().depdecl_ = dd; + } + + CPPNamespaceDeclaration cppnamespace(CPPNamespaceDeclaration ns) + { + if (!ns && !atts) + return null; + return getAtts().cppnamespace = ns; + } + + UserAttributeDeclaration userAttribDecl(UserAttributeDeclaration uad) + { + if (!uad && !atts) + return null; + return getAtts().userAttribDecl = uad; + } + } + // helper to print fully qualified (template) arguments const(char)* toPrettyCharsHelper() { diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index acf0004..3e9b634 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -167,25 +167,31 @@ struct FieldState bool inFlight; }; +struct DsymbolAttributes; + class Dsymbol : public ASTNode { public: Identifier *ident; Dsymbol *parent; - /// C++ namespace this symbol belongs to - CPPNamespaceDeclaration *namespace_; Symbol *csym; // symbol for code generator Loc loc; // where defined Scope *_scope; // !=NULL means context to use for semantic() const utf8_t *prettystring; +private: + DsymbolAttributes* atts; +public: bool errors; // this symbol failed to pass semantic() PASS semanticRun; unsigned short localNum; // perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab - DeprecatedDeclaration *depdecl; // customized deprecation message - UserAttributeDeclaration *userAttribDecl; // user defined attributes - static Dsymbol *create(Identifier *); const char *toChars() const override; + DeprecatedDeclaration* depdecl(); + CPPNamespaceDeclaration* cppnamespace(); + UserAttributeDeclaration* userAttribDecl(); + DeprecatedDeclaration* depdecl(DeprecatedDeclaration* dd); + CPPNamespaceDeclaration* cppnamespace(CPPNamespaceDeclaration* ns); + UserAttributeDeclaration* userAttribDecl(UserAttributeDeclaration* uad); virtual const char *toPrettyCharsHelper(); // helper to print fully qualified (template) arguments Loc getLoc(); const char *locToChars(); diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 701f06a..b877828 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -98,6 +98,29 @@ private uint setMangleOverride(Dsymbol s, const(char)[] sym) return 0; } +/** + * Apply pragma printf/scanf to FuncDeclarations under `s`, + * poking through attribute declarations such as `extern(C)` + * but not through aggregates or function bodies. + * + * Params: + * s = symbol to apply + * printf = `true` for printf, `false` for scanf + */ +private void setPragmaPrintf(Dsymbol s, bool printf) +{ + if (auto fd = s.isFuncDeclaration()) + { + fd.printf = printf; + fd.scanf = !printf; + } + + if (auto ad = s.isAttribDeclaration()) + { + ad.include(null).foreachDsymbol( (s) { setPragmaPrintf(s, printf); } ); + } +} + /************************************* * Does semantic analysis on the public face of declarations. */ @@ -855,17 +878,20 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } // Calculate type size + safety checks - if (1) + if (sc && sc.func) { - if (dsym._init && dsym._init.isVoidInitializer() && - (dsym.type.hasPointers() || dsym.type.hasInvariant())) // also computes type size + if (dsym._init && dsym._init.isVoidInitializer()) { - if (dsym.type.hasPointers()) + + if (dsym.type.hasPointers()) // also computes type size sc.setUnsafe(false, dsym.loc, "`void` initializers for pointers not allowed in safe functions"); - else + else if (dsym.type.hasInvariant()) sc.setUnsafe(false, dsym.loc, "`void` initializers for structs with invariants are not allowed in safe functions"); + else if (dsym.type.hasSystemFields()) + sc.setUnsafePreview(global.params.systemVariables, false, dsym.loc, + "`void` initializers for `@system` variables not allowed in safe functions"); } else if (!dsym._init && !(dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field | STC.parameter)) && @@ -1036,6 +1062,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (f.tookAddressOf) f.tookAddressOf--; } + else if (auto ale = ex.isArrayLiteralExp()) + { + // or an array literal assigned to a `scope` variable + if (!dsym.type.nextOf().needsDestruction()) + ale.onstack = true; + } } Expression exp = ei.exp; @@ -1200,7 +1232,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(BitFieldDeclaration dsym) { - //printf("BitField::semantic('%s') %s\n", toPrettyChars(), id.toChars()); + //printf("BitField::semantic('%s')\n", dsym.toChars()); if (dsym.semanticRun >= PASS.semanticdone) return; @@ -1558,6 +1590,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor foreach (s; (*pd.decl)[]) { + if (pd.ident == Id.printf || pd.ident == Id.scanf) + { + s.setPragmaPrintf(pd.ident == Id.printf); + continue; + } + s.dsymbolSemantic(sc2); if (pd.ident != Id.mangle) continue; @@ -1574,13 +1612,13 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor agg = tc.sym; else if (auto ts = e.type.isTypeStruct()) agg = ts.sym; - ad.mangleOverride = new MangleOverride; + ad.pMangleOverride = new MangleOverride; void setString(ref Expression e) { if (auto se = verifyMangleString(e)) { const name = (cast(const(char)[])se.peekData()).xarraydup; - ad.mangleOverride.id = Identifier.idPool(name); + ad.pMangleOverride.id = Identifier.idPool(name); e = se; } else @@ -1588,13 +1626,13 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } if (agg) { - ad.mangleOverride.agg = agg; + ad.pMangleOverride.agg = agg; if (pd.args.dim == 2) { setString((*pd.args)[1]); } else - ad.mangleOverride.id = agg.ident; + ad.pMangleOverride.id = agg.ident; } else setString((*pd.args)[0]); @@ -1649,29 +1687,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (!pd.args) return noDeclarations(); - for (size_t i = 0; i < pd.args.dim; i++) - { - Expression e = (*pd.args)[i]; - sc = sc.startCTFE(); - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); - e = ctfeInterpretForPragmaMsg(e); - if (e.op == EXP.error) - { - errorSupplemental(pd.loc, "while evaluating `pragma(msg, %s)`", (*pd.args)[i].toChars()); - return; - } - StringExp se = e.toStringExp(); - if (se) - { - se = se.toUTF8(sc); - fprintf(stderr, "%.*s", cast(int)se.len, se.peekString().ptr); - } - else - fprintf(stderr, "%s", e.toChars()); - } - fprintf(stderr, "\n"); + if (!pragmaMsgSemantic(pd.loc, sc, pd.args)) + return; return noDeclarations(); } @@ -1707,33 +1724,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } else if (pd.ident == Id.startaddress) { - if (!pd.args || pd.args.dim != 1) - pd.error("function name expected for start address"); - else - { - /* https://issues.dlang.org/show_bug.cgi?id=11980 - * resolveProperties and ctfeInterpret call are not necessary. - */ - Expression e = (*pd.args)[0]; - sc = sc.startCTFE(); - e = e.expressionSemantic(sc); - sc = sc.endCTFE(); - (*pd.args)[0] = e; - Dsymbol sa = getDsymbol(e); - if (!sa || !sa.isFuncDeclaration()) - pd.error("function name expected for start address, not `%s`", e.toChars()); - } + pragmaStartAddressSemantic(pd.loc, sc, pd.args); return noDeclarations(); } else if (pd.ident == Id.Pinline) { - if (pd.args && pd.args.dim > 1) - { - pd.error("one boolean expression expected for `pragma(inline)`, not %llu", cast(ulong) pd.args.dim); - pd.args.setDim(1); - (*pd.args)[0] = ErrorExp.get(); - } - // this pragma now gets evaluated on demand in function semantic return declarations(); @@ -1774,7 +1769,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } else if (auto f = s.isFuncDeclaration()) { - f.flags |= isCtor ? FUNCFLAG.CRTCtor : FUNCFLAG.CRTDtor; + if (isCtor) + f.isCrtCtor = true; + else + f.isCrtDtor = true; + return 1; } else @@ -3048,7 +3047,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor //printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration.isFinal()); if (sc.flags & SCOPE.compile) - funcdecl.flags |= FUNCFLAG.compileTimeOnly; // don't emit code for this function + funcdecl.isCompileTimeOnly = true; // don't emit code for this function funcdecl._linkage = sc.linkage; if (auto fld = funcdecl.isFuncLiteralDeclaration()) @@ -3069,7 +3068,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // evaluate pragma(inline) if (auto pragmadecl = sc.inlining) - funcdecl.inlining = pragmadecl.evalPragmaInline(sc); + funcdecl.inlining = evalPragmaInline(pragmadecl.loc, sc, pragmadecl.args); funcdecl.visibility = sc.visibility; funcdecl.userAttribDecl = sc.userAttribDecl; @@ -3269,9 +3268,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } // check pragma(crt_constructor) signature - if (funcdecl.flags & (FUNCFLAG.CRTCtor | FUNCFLAG.CRTDtor)) + if (funcdecl.isCrtCtor || funcdecl.isCrtDtor) { - const idStr = (funcdecl.flags & FUNCFLAG.CRTCtor) ? "crt_constructor" : "crt_destructor"; + const idStr = funcdecl.isCrtCtor ? "crt_constructor" : "crt_destructor"; if (f.nextOf().ty != Tvoid) funcdecl.error("must return `void` for `pragma(%s)`", idStr.ptr); if (funcdecl._linkage != LINK.c && f.parameterList.length != 0) @@ -3351,7 +3350,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } } - if (const pors = sc.flags & (SCOPE.printf | SCOPE.scanf)) + if (funcdecl.printf || funcdecl.scanf) { /* printf/scanf-like functions must be of the form: * extern (C/C++) T printf([parameters...], const(char)* format, ...); @@ -3387,11 +3386,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor ) ) { - funcdecl.flags |= (pors == SCOPE.printf) ? FUNCFLAG.printf : FUNCFLAG.scanf; + // the signature is valid for printf/scanf, no error } else { - const p = (pors == SCOPE.printf ? Id.printf : Id.scanf).toChars(); + const p = (funcdecl.printf ? Id.printf : Id.scanf).toChars(); if (f.parameterList.varargs == VarArg.variadic) { funcdecl.error("`pragma(%s)` functions must be `extern(C) %s %s([parameters...], const(char)*, ...)`" @@ -3538,7 +3537,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor else { //printf("\tintroducing function %s\n", funcdecl.toChars()); - funcdecl.flags |= FUNCFLAG.introducing; + funcdecl.isIntroducing = true; if (cd.classKind == ClassKind.cpp && target.cpp.reverseOverloads) { /* Overloaded functions with same name are grouped and in reverse order. @@ -4555,13 +4554,16 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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()) + auto ts = sd.type.isTypeStruct(); + if (ts) + { if (ts.sym != sd) { auto ti = ts.sym.isInstantiated(); if (ti && isError(ti)) ts.sym = sd; } + } // Ungag errors when not speculative Ungag ungag = sd.ungagSpeculative(); @@ -4699,16 +4701,26 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } } - if (sd.type.ty == Tstruct && (cast(TypeStruct)sd.type).sym != sd) + if (ts && ts.sym != sd) { - // https://issues.dlang.org/show_bug.cgi?id=19024 - StructDeclaration sym = (cast(TypeStruct)sd.type).sym; - version (none) + StructDeclaration sym = ts.sym; + if (sd.isCsymbol() && sym.isCsymbol()) + { + /* This is two structs imported from different C files. + * Just ignore sd, the second one. The first one will always + * be found when going through the type. + */ + } + else { - printf("this = %p %s\n", sd, sd.toChars()); - printf("type = %d sym = %p, %s\n", sd.type.ty, sym, sym.toPrettyChars()); + version (none) + { + printf("this = %p %s\n", sd, sd.toChars()); + printf("type = %d sym = %p, %s\n", sd.type.ty, sym, sym.toPrettyChars()); + } + // https://issues.dlang.org/show_bug.cgi?id=19024 + sd.error("already exists at %s. Perhaps in another function with the same name?", sym.loc.toChars()); } - sd.error("already exists at %s. Perhaps in another function with the same name?", sym.loc.toChars()); } if (global.errors != errors) @@ -5291,7 +5303,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor auto ctor = new CtorDeclaration(cldec.loc, Loc.initial, 0, tf); ctor.storage_class |= STC.inference; - ctor.flags |= FUNCFLAG.generated; + ctor.isGenerated = true; ctor.fbody = new CompoundStatement(Loc.initial, new Statements()); cldec.members.push(ctor); @@ -7099,3 +7111,47 @@ private CallExp doAtomicOp (string op, Identifier var, Expression arg) return CallExp.create(loc, dti, args); } + +/*************************************** + * Interpret a `pragma(inline, x)` + * + * Params: + * loc = location for error messages + * sc = scope for evaluation of argument + * args = pragma arguments + * Returns: corresponding `PINLINE` state + */ +PINLINE evalPragmaInline(Loc loc, Scope* sc, Expressions* args) +{ + if (!args || args.dim == 0) + return PINLINE.default_; + + if (args && args.dim > 1) + { + .error(loc, "one boolean expression expected for `pragma(inline)`, not %llu", cast(ulong) args.dim); + args.setDim(1); + (*args)[0] = ErrorExp.get(); + } + + Expression e = (*args)[0]; + if (!e.type) + { + sc = sc.startCTFE(); + e = e.expressionSemantic(sc); + e = resolveProperties(sc, e); + sc = sc.endCTFE(); + e = e.ctfeInterpret(); + e = e.toBoolean(sc); + if (e.isErrorExp()) + .error(loc, "pragma(`inline`, `true` or `false`) expected, not `%s`", (*args)[0].toChars()); + (*args)[0] = e; + } + + const opt = e.toBool(); + if (opt.isEmpty()) + return PINLINE.default_; + else if (opt.get()) + return PINLINE.always; + else + return PINLINE.never; +} diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 13efc1c..1f99c58 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.flags |= FUNCFLAG.inferRetType; + fd.inferRetType = true; // Shouldn't run semantic on default arguments and return type. foreach (ref param; *tf.parameterList.parameters) @@ -3901,7 +3901,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param // https://issues.dlang.org/show_bug.cgi?id=2579 // Apply function parameter storage classes to parameter types fparam.type = fparam.type.addStorageClass(fparam.storageClass); - fparam.storageClass &= ~(STC.TYPECTOR | STC.in_); + fparam.storageClass &= ~STC.TYPECTOR; // https://issues.dlang.org/show_bug.cgi?id=15243 // Resolve parameter type if it's not related with template parameters diff --git a/gcc/d/dmd/entity.d b/gcc/d/dmd/entity.d index c29d499..2b499c1 100644 --- a/gcc/d/dmd/entity.d +++ b/gcc/d/dmd/entity.d @@ -25,7 +25,7 @@ nothrow: * code point corresponding to the named entity * ~0 for not recognized as a named entity */ -public uint HtmlNamedEntity(scope const char[] name) pure @nogc @safe +public uint[2] HtmlNamedEntity(scope const char[] name) pure @nogc @safe { const firstC = tolower(name[0]); if (firstC >= 'a' && firstC <= 'z') @@ -34,10 +34,10 @@ public uint HtmlNamedEntity(scope const char[] name) pure @nogc @safe foreach (entity; namesTable[firstC - 'a']) { if (entity.name == name) - return entity.value; + return [entity.value, entity.value2]; } } - return ~0; + return [0, 0]; } private: @@ -52,6 +52,7 @@ struct NameId { string name; uint value; + uint value2; } // @todo@ order namesTable and names? by frequency @@ -72,7 +73,7 @@ immutable NameId[] namesA = {"abreve", 0x00103}, // LATIN SMALL LETTER A WITH BREVE {"ac", 0x0223E}, // INVERTED LAZY S {"acd", 0x0223F}, // SINE WAVE -// {"acE", 0x0223E;0x00333}, // INVERTED LAZY S with double underline + {"acE", 0x0223E, 0x00333}, // INVERTED LAZY S with double underline {"Acirc", 0x000C2}, // LATIN CAPITAL LETTER A WITH CIRCUMFLEX {"acirc", 0x000E2}, // LATIN SMALL LETTER A WITH CIRCUMFLEX {"acute", 0x000B4}, // ACUTE ACCENT @@ -157,42 +158,30 @@ immutable NameId[] namesB = {"backsim", 0x0223D}, // REVERSED TILDE {"backsimeq", 0x022CD}, // REVERSED TILDE EQUALS {"Backslash", 0x02216}, // SET MINUS -// "b.alpha", 0x1D6C2}, // MATHEMATICAL BOLD SMALL ALPHA {"Barv", 0x02AE7}, // SHORT DOWN TACK WITH OVERBAR {"barvee", 0x022BD}, // NOR {"barwed", 0x02305}, // PROJECTIVE {"Barwed", 0x02306}, // PERSPECTIVE {"barwedge", 0x02305}, // PROJECTIVE -// "b.beta", 0x1D6C3}, // MATHEMATICAL BOLD SMALL BETA {"bbrk", 0x023B5}, // BOTTOM SQUARE BRACKET {"bbrktbrk", 0x023B6}, // BOTTOM SQUARE BRACKET OVER TOP SQUARE BRACKET -// "b.chi", 0x1D6D8}, // MATHEMATICAL BOLD SMALL CHI {"bcong", 0x0224C}, // ALL EQUAL TO {"Bcy", 0x00411}, // CYRILLIC CAPITAL LETTER BE {"bcy", 0x00431}, // CYRILLIC SMALL LETTER BE -// "b.Delta", 0x1D6AB}, // MATHEMATICAL BOLD CAPITAL DELTA -// "b.delta", 0x1D6C5}, // MATHEMATICAL BOLD SMALL DELTA {"bdquo", 0x0201E}, // DOUBLE LOW-9 QUOTATION MARK {"becaus", 0x02235}, // BECAUSE {"because", 0x02235}, // BECAUSE {"Because", 0x02235}, // BECAUSE {"bemptyv", 0x029B0}, // REVERSED EMPTY SET {"bepsi", 0x003F6}, // GREEK REVERSED LUNATE EPSILON SYMBOL -// "b.epsi", 0x1D6C6}, // MATHEMATICAL BOLD SMALL EPSILON -// "b.epsiv", 0x1D6DC}, // MATHEMATICAL BOLD EPSILON SYMBOL {"bernou", 0x0212C}, // SCRIPT CAPITAL B {"Bernoullis", 0x0212C}, // SCRIPT CAPITAL B {"Beta", 0x00392}, // GREEK CAPITAL LETTER BETA {"beta", 0x003B2}, // GREEK SMALL LETTER BETA -// "b.eta", 0x1D6C8}, // MATHEMATICAL BOLD SMALL ETA {"beth", 0x02136}, // BET SYMBOL {"between", 0x0226C}, // BETWEEN {"Bfr", 0x1D505}, // MATHEMATICAL FRAKTUR CAPITAL B {"bfr", 0x1D51F}, // MATHEMATICAL FRAKTUR SMALL B -// "b.Gamma", 0x1D6AA}, // MATHEMATICAL BOLD CAPITAL GAMMA -// "b.gamma", 0x1D6C4}, // MATHEMATICAL BOLD SMALL GAMMA -// "b.Gammad", 0x1D7CA}, // MATHEMATICAL BOLD CAPITAL DIGAMMA -// "b.gammad", 0x1D7CB}, // MATHEMATICAL BOLD SMALL DIGAMMA {"Bgr", 0x00392}, // GREEK CAPITAL LETTER BETA {"bgr", 0x003B2}, // GREEK SMALL LETTER BETA {"bigcap", 0x022C2}, // N-ARY INTERSECTION @@ -208,9 +197,6 @@ immutable NameId[] namesB = {"biguplus", 0x02A04}, // N-ARY UNION OPERATOR WITH PLUS {"bigvee", 0x022C1}, // N-ARY LOGICAL OR {"bigwedge", 0x022C0}, // N-ARY LOGICAL AND -// "b.iota", 0x1D6CA}, // MATHEMATICAL BOLD SMALL IOTA -// "b.kappa", 0x1D6CB}, // MATHEMATICAL BOLD SMALL KAPPA -// "b.kappav", 0x1D6DE}, // MATHEMATICAL BOLD KAPPA SYMBOL {"bkarow", 0x0290D}, // RIGHTWARDS DOUBLE DASH ARROW {"blacklozenge", 0x029EB}, // BLACK LOZENGE {"blacksquare", 0x025AA}, // BLACK SMALL SQUARE @@ -218,21 +204,15 @@ immutable NameId[] namesB = {"blacktriangledown", 0x025BE}, // BLACK DOWN-POINTING SMALL TRIANGLE {"blacktriangleleft", 0x025C2}, // BLACK LEFT-POINTING SMALL TRIANGLE {"blacktriangleright", 0x025B8}, // BLACK RIGHT-POINTING SMALL TRIANGLE -// "b.Lambda", 0x1D6B2}, // MATHEMATICAL BOLD CAPITAL LAMDA -// "b.lambda", 0x1D6CC}, // MATHEMATICAL BOLD SMALL LAMDA {"blank", 0x02423}, // OPEN BOX {"blk12", 0x02592}, // MEDIUM SHADE {"blk14", 0x02591}, // LIGHT SHADE {"blk34", 0x02593}, // DARK SHADE {"block", 0x02588}, // FULL BLOCK -// "b.mu", 0x1D6CD}, // MATHEMATICAL BOLD SMALL MU -// "bne", 0x0003D;0x020E5}, // EQUALS SIGN with reverse slash -// "bnequiv", 0x02261;0x020E5}, // IDENTICAL TO with reverse slash + {"bne", 0x0003D, 0x020E5}, // EQUALS SIGN with reverse slash + {"bnequiv", 0x02261, 0x020E5}, // IDENTICAL TO with reverse slash {"bnot", 0x02310}, // REVERSED NOT SIGN {"bNot", 0x02AED}, // REVERSED DOUBLE STROKE NOT SIGN -// "b.nu", 0x1D6CE}, // MATHEMATICAL BOLD SMALL NU -// "b.Omega", 0x1D6C0}, // MATHEMATICAL BOLD CAPITAL OMEGA -// "b.omega", 0x1D6DA}, // MATHEMATICAL BOLD SMALL OMEGA {"Bopf", 0x1D539}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL B {"bopf", 0x1D553}, // MATHEMATICAL DOUBLE-STRUCK SMALL B {"bot", 0x022A5}, // UP TACK @@ -282,35 +262,18 @@ immutable NameId[] namesB = {"boxvR", 0x0255E}, // BOX DRAWINGS VERTICAL SINGLE AND RIGHT DOUBLE {"boxVr", 0x0255F}, // BOX DRAWINGS VERTICAL DOUBLE AND RIGHT SINGLE {"boxVR", 0x02560}, // BOX DRAWINGS DOUBLE VERTICAL AND RIGHT -// "b.Phi", 0x1D6BD}, // MATHEMATICAL BOLD CAPITAL PHI -// "b.phi", 0x1D6D7}, // MATHEMATICAL BOLD SMALL PHI -// "b.phiv", 0x1D6DF}, // MATHEMATICAL BOLD PHI SYMBOL -// "b.Pi", 0x1D6B7}, // MATHEMATICAL BOLD CAPITAL PI -// "b.pi", 0x1D6D1}, // MATHEMATICAL BOLD SMALL PI -// "b.piv", 0x1D6E1}, // MATHEMATICAL BOLD PI SYMBOL {"bprime", 0x02035}, // REVERSED PRIME -// "b.Psi", 0x1D6BF}, // MATHEMATICAL BOLD CAPITAL PSI -// "b.psi", 0x1D6D9}, // MATHEMATICAL BOLD SMALL PSI {"breve", 0x002D8}, // BREVE {"Breve", 0x002D8}, // BREVE -// "b.rho", 0x1D6D2}, // MATHEMATICAL BOLD SMALL RHO -// "b.rhov", 0x1D6E0}, // MATHEMATICAL BOLD RHO SYMBOL {"brvbar", 0x000A6}, // BROKEN BAR {"Bscr", 0x0212C}, // SCRIPT CAPITAL B {"bscr", 0x1D4B7}, // MATHEMATICAL SCRIPT SMALL B {"bsemi", 0x0204F}, // REVERSED SEMICOLON -// "b.Sigma", 0x1D6BA}, // MATHEMATICAL BOLD CAPITAL SIGMA -// "b.sigma", 0x1D6D4}, // MATHEMATICAL BOLD SMALL SIGMA -// "b.sigmav", 0x1D6D3}, // MATHEMATICAL BOLD SMALL FINAL SIGMA {"bsim", 0x0223D}, // REVERSED TILDE {"bsime", 0x022CD}, // REVERSED TILDE EQUALS {"bsol", 0x0005C}, // REVERSE SOLIDUS {"bsolb", 0x029C5}, // SQUARED FALLING DIAGONAL SLASH {"bsolhsub", 0x027C8}, // REVERSE SOLIDUS PRECEDING SUBSET -// "b.tau", 0x1D6D5}, // MATHEMATICAL BOLD SMALL TAU -// "b.Theta", 0x1D6AF}, // MATHEMATICAL BOLD CAPITAL THETA -// "b.thetas", 0x1D6C9}, // MATHEMATICAL BOLD SMALL THETA -// "b.thetav", 0x1D6DD}, // MATHEMATICAL BOLD THETA SYMBOL {"bull", 0x02022}, // BULLET {"bullet", 0x02022}, // BULLET {"bump", 0x0224E}, // GEOMETRICALLY EQUIVALENT TO @@ -318,11 +281,6 @@ immutable NameId[] namesB = {"bumpE", 0x02AAE}, // EQUALS SIGN WITH BUMPY ABOVE {"Bumpeq", 0x0224E}, // GEOMETRICALLY EQUIVALENT TO {"bumpeq", 0x0224F}, // DIFFERENCE BETWEEN -// "b.Upsi", 0x1D6BC}, // MATHEMATICAL BOLD CAPITAL UPSILON -// "b.upsi", 0x1D6D6}, // MATHEMATICAL BOLD SMALL UPSILON -// "b.Xi", 0x1D6B5}, // MATHEMATICAL BOLD CAPITAL XI -// "b.xi", 0x1D6CF}, // MATHEMATICAL BOLD SMALL XI -// "b.zeta", 0x1D6C7}, // MATHEMATICAL BOLD SMALL ZETA ]; immutable NameId[] namesC = @@ -337,7 +295,7 @@ immutable NameId[] namesC = {"capcup", 0x02A47}, // INTERSECTION ABOVE UNION {"capdot", 0x02A40}, // INTERSECTION WITH DOT {"CapitalDifferentialD", 0x02145}, // DOUBLE-STRUCK ITALIC CAPITAL D -// "caps", 0x02229;0x0FE00}, // INTERSECTION with serifs + {"caps", 0x02229, 0x0FE00}, // INTERSECTION with serifs {"caret", 0x02041}, // CARET INSERTION POINT {"caron", 0x002C7}, // CARON {"Cayleys", 0x0212D}, // BLACK-LETTER CAPITAL C @@ -440,7 +398,7 @@ immutable NameId[] namesC = {"cupcup", 0x02A4A}, // UNION BESIDE AND JOINED WITH UNION {"cupdot", 0x0228D}, // MULTISET MULTIPLICATION {"cupor", 0x02A45}, // UNION WITH LOGICAL OR -// "cups", 0x0222A;0x0FE00}, // UNION with serifs + {"cups", 0x0222A, 0x0FE00}, // UNION with serifs {"curarr", 0x021B7}, // CLOCKWISE TOP SEMICIRCLE ARROW {"curarrm", 0x0293C}, // TOP ARC CLOCKWISE ARROW WITH MINUS {"curlyeqprec", 0x022DE}, // EQUAL TO OR PRECEDES @@ -694,7 +652,7 @@ immutable NameId[] namesF = {"filig", 0x0FB01}, // LATIN SMALL LIGATURE FI {"FilledSmallSquare", 0x025FC}, // BLACK MEDIUM SQUARE {"FilledVerySmallSquare", 0x025AA}, // BLACK SMALL SQUARE -// "fjlig", 0x00066;0x0006A}, // fj ligature + {"fjlig", 0x00066, 0x0006A}, // fj ligature {"flat", 0x0266D}, // MUSIC FLAT SIGN {"fllig", 0x0FB02}, // LATIN SMALL LIGATURE FL {"fltns", 0x025B1}, // WHITE PARALLELOGRAM @@ -757,7 +715,7 @@ immutable NameId[] namesG = {"gesdot", 0x02A80}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT INSIDE {"gesdoto", 0x02A82}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE {"gesdotol", 0x02A84}, // GREATER-THAN OR SLANTED EQUAL TO WITH DOT ABOVE LEFT -// "gesl", 0x022DB;0x0FE00}, // GREATER-THAN slanted EQUAL TO OR LESS-THAN + {"gesl", 0x022DB, 0x0FE00}, // GREATER-THAN slanted EQUAL TO OR LESS-THAN {"gesles", 0x02A94}, // GREATER-THAN ABOVE SLANTED EQUAL ABOVE LESS-THAN ABOVE SLANTED EQUAL {"Gfr", 0x1D50A}, // MATHEMATICAL FRAKTUR CAPITAL G {"gfr", 0x1D524}, // MATHEMATICAL FRAKTUR SMALL G @@ -810,8 +768,8 @@ immutable NameId[] namesG = {"gtreqqless", 0x02A8C}, // GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN {"gtrless", 0x02277}, // GREATER-THAN OR LESS-THAN {"gtrsim", 0x02273}, // GREATER-THAN OR EQUIVALENT TO -// "gvertneqq", 0x02269;0x0FE00}, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke -// "gvnE", 0x02269;0x0FE00}, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke + {"gvertneqq", 0x02269, 0x0FE00}, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke + {"gvnE", 0x02269, 0x0FE00}, // GREATER-THAN BUT NOT EQUAL TO - with vertical stroke ]; immutable NameId[] namesH = @@ -1020,7 +978,7 @@ immutable NameId[] namesL = {"latail", 0x02919}, // LEFTWARDS ARROW-TAIL {"lAtail", 0x0291B}, // LEFTWARDS DOUBLE ARROW-TAIL {"late", 0x02AAD}, // LARGER THAN OR EQUAL TO -// "lates", 0x02AAD;0x0FE00}, // LARGER THAN OR slanted EQUAL + {"lates", 0x02AAD, 0x0FE00}, // LARGER THAN OR slanted EQUAL {"lbarr", 0x0290C}, // LEFTWARDS DOUBLE DASH ARROW {"lBarr", 0x0290E}, // LEFTWARDS TRIPLE DASH ARROW {"lbbrk", 0x02772}, // LIGHT LEFT TORTOISE SHELL BRACKET ORNAMENT @@ -1091,7 +1049,7 @@ immutable NameId[] namesL = {"lesdot", 0x02A7F}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT INSIDE {"lesdoto", 0x02A81}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE {"lesdotor", 0x02A83}, // LESS-THAN OR SLANTED EQUAL TO WITH DOT ABOVE RIGHT -// "lesg", 0x022DA;0x0FE00}, // LESS-THAN slanted EQUAL TO OR GREATER-THAN + {"lesg", 0x022DA, 0x0FE00}, // LESS-THAN slanted EQUAL TO OR GREATER-THAN {"lesges", 0x02A93}, // LESS-THAN ABOVE SLANTED EQUAL ABOVE GREATER-THAN ABOVE SLANTED EQUAL {"lessapprox", 0x02A85}, // LESS-THAN OR APPROXIMATE {"lessdot", 0x022D6}, // LESS-THAN WITH DOT @@ -1202,8 +1160,8 @@ immutable NameId[] namesL = {"ltrPar", 0x02996}, // DOUBLE RIGHT ARC LESS-THAN BRACKET {"lurdshar", 0x0294A}, // LEFT BARB UP RIGHT BARB DOWN HARPOON {"luruhar", 0x02966}, // LEFTWARDS HARPOON WITH BARB UP ABOVE RIGHTWARDS HARPOON WITH BARB UP -// "lvertneqq", 0x02268;0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke -// "lvnE", 0x02268;0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke + {"lvertneqq", 0x02268, 0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke + {"lvnE", 0x02268, 0x0FE00}, // LESS-THAN BUT NOT EQUAL TO - with vertical stroke ]; immutable NameId[] namesM = @@ -1263,25 +1221,25 @@ immutable NameId[] namesN = {"nabla", 0x02207}, // NABLA {"Nacute", 0x00143}, // LATIN CAPITAL LETTER N WITH ACUTE {"nacute", 0x00144}, // LATIN SMALL LETTER N WITH ACUTE -// "nang", 0x02220;0x020D2}, // ANGLE with vertical line + {"nang", 0x02220, 0x020D2}, // ANGLE with vertical line {"nap", 0x02249}, // NOT ALMOST EQUAL TO -// "napE", 0x02A70;0x00338}, // APPROXIMATELY EQUAL OR EQUAL TO with slash -// "napid", 0x0224B;0x00338}, // TRIPLE TILDE with slash + {"napE", 0x02A70, 0x00338}, // APPROXIMATELY EQUAL OR EQUAL TO with slash + {"napid", 0x0224B, 0x00338}, // TRIPLE TILDE with slash {"napos", 0x00149}, // LATIN SMALL LETTER N PRECEDED BY APOSTROPHE {"napprox", 0x02249}, // NOT ALMOST EQUAL TO {"natur", 0x0266E}, // MUSIC NATURAL SIGN {"natural", 0x0266E}, // MUSIC NATURAL SIGN {"naturals", 0x02115}, // DOUBLE-STRUCK CAPITAL N {"nbsp", 0x000A0}, // NO-BREAK SPACE -// "nbump", 0x0224E;0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash -// "nbumpe", 0x0224F;0x00338}, // DIFFERENCE BETWEEN with slash + {"nbump", 0x0224E, 0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash + {"nbumpe", 0x0224F, 0x00338}, // DIFFERENCE BETWEEN with slash {"ncap", 0x02A43}, // INTERSECTION WITH OVERBAR {"Ncaron", 0x00147}, // LATIN CAPITAL LETTER N WITH CARON {"ncaron", 0x00148}, // LATIN SMALL LETTER N WITH CARON {"Ncedil", 0x00145}, // LATIN CAPITAL LETTER N WITH CEDILLA {"ncedil", 0x00146}, // LATIN SMALL LETTER N WITH CEDILLA {"ncong", 0x02247}, // NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO -// "ncongdot", 0x02A6D;0x00338}, // CONGRUENT WITH DOT ABOVE with slash + {"ncongdot", 0x02A6D, 0x00338}, // CONGRUENT WITH DOT ABOVE with slash {"ncup", 0x02A42}, // UNION WITH OVERBAR {"Ncy", 0x0041D}, // CYRILLIC CAPITAL LETTER EN {"ncy", 0x0043D}, // CYRILLIC SMALL LETTER EN @@ -1291,14 +1249,14 @@ immutable NameId[] namesN = {"nearr", 0x02197}, // NORTH EAST ARROW {"neArr", 0x021D7}, // NORTH EAST DOUBLE ARROW {"nearrow", 0x02197}, // NORTH EAST ARROW -// "nedot", 0x02250;0x00338}, // APPROACHES THE LIMIT with slash + {"nedot", 0x02250, 0x00338}, // APPROACHES THE LIMIT with slash {"NegativeMediumSpace", 0x0200B}, // ZERO WIDTH SPACE {"NegativeThickSpace", 0x0200B}, // ZERO WIDTH SPACE {"NegativeThinSpace", 0x0200B}, // ZERO WIDTH SPACE {"NegativeVeryThinSpace", 0x0200B}, // ZERO WIDTH SPACE {"nequiv", 0x02262}, // NOT IDENTICAL TO {"nesear", 0x02928}, // NORTH EAST ARROW AND SOUTH EAST ARROW -// "nesim", 0x02242;0x00338}, // MINUS TILDE with slash + {"nesim", 0x02242, 0x00338}, // MINUS TILDE with slash {"NestedGreaterGreater", 0x0226B}, // MUCH GREATER-THAN {"NestedLessLess", 0x0226A}, // MUCH LESS-THAN {"NewLine", 0x0000A}, // LINE FEED (LF) @@ -1306,20 +1264,20 @@ immutable NameId[] namesN = {"nexists", 0x02204}, // THERE DOES NOT EXIST {"Nfr", 0x1D511}, // MATHEMATICAL FRAKTUR CAPITAL N {"nfr", 0x1D52B}, // MATHEMATICAL FRAKTUR SMALL N -// "ngE", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash + {"ngE", 0x02267, 0x00338}, // GREATER-THAN OVER EQUAL TO with slash {"nge", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO {"ngeq", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO -// "ngeqq", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash -// "ngeqslant", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash -// "nges", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash -// "nGg", 0x022D9;0x00338}, // VERY MUCH GREATER-THAN with slash + {"ngeqq", 0x02267, 0x00338}, // GREATER-THAN OVER EQUAL TO with slash + {"ngeqslant", 0x02A7E, 0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash + {"nges", 0x02A7E, 0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash + {"nGg", 0x022D9, 0x00338}, // VERY MUCH GREATER-THAN with slash {"Ngr", 0x0039D}, // GREEK CAPITAL LETTER NU {"ngr", 0x003BD}, // GREEK SMALL LETTER NU {"ngsim", 0x02275}, // NEITHER GREATER-THAN NOR EQUIVALENT TO -// "nGt", 0x0226B;0x020D2}, // MUCH GREATER THAN with vertical line + {"nGt", 0x0226B, 0x020D2}, // MUCH GREATER THAN with vertical line {"ngt", 0x0226F}, // NOT GREATER-THAN {"ngtr", 0x0226F}, // NOT GREATER-THAN -// "nGtv", 0x0226B;0x00338}, // MUCH GREATER THAN with slash + {"nGtv", 0x0226B, 0x00338}, // MUCH GREATER THAN with slash {"nharr", 0x021AE}, // LEFT RIGHT ARROW WITH STROKE {"nhArr", 0x021CE}, // LEFT RIGHT DOUBLE ARROW WITH STROKE {"nhpar", 0x02AF2}, // PARALLEL WITH HORIZONTAL STROKE @@ -1332,24 +1290,24 @@ immutable NameId[] namesN = {"nlarr", 0x0219A}, // LEFTWARDS ARROW WITH STROKE {"nlArr", 0x021CD}, // LEFTWARDS DOUBLE ARROW WITH STROKE {"nldr", 0x02025}, // TWO DOT LEADER -// "nlE", 0x02266;0x00338}, // LESS-THAN OVER EQUAL TO with slash + {"nlE", 0x02266, 0x00338}, // LESS-THAN OVER EQUAL TO with slash {"nle", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO {"nleftarrow", 0x0219A}, // LEFTWARDS ARROW WITH STROKE {"nLeftarrow", 0x021CD}, // LEFTWARDS DOUBLE ARROW WITH STROKE {"nleftrightarrow", 0x021AE}, // LEFT RIGHT ARROW WITH STROKE {"nLeftrightarrow", 0x021CE}, // LEFT RIGHT DOUBLE ARROW WITH STROKE {"nleq", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO -// "nleqq", 0x02266;0x00338}, // LESS-THAN OVER EQUAL TO with slash -// "nleqslant", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash -// "nles", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash + {"nleqq", 0x02266, 0x00338}, // LESS-THAN OVER EQUAL TO with slash + {"nleqslant", 0x02A7D, 0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash + {"nles", 0x02A7D, 0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash {"nless", 0x0226E}, // NOT LESS-THAN -// "nLl", 0x022D8;0x00338}, // VERY MUCH LESS-THAN with slash + {"nLl", 0x022D8, 0x00338}, // VERY MUCH LESS-THAN with slash {"nlsim", 0x02274}, // NEITHER LESS-THAN NOR EQUIVALENT TO -// "nLt", 0x0226A;0x020D2}, // MUCH LESS THAN with vertical line + {"nLt", 0x0226A, 0x020D2}, // MUCH LESS THAN with vertical line {"nlt", 0x0226E}, // NOT LESS-THAN {"nltri", 0x022EA}, // NOT NORMAL SUBGROUP OF {"nltrie", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO -// "nLtv", 0x0226A;0x00338}, // MUCH LESS THAN with slash + {"nLtv", 0x0226A, 0x00338}, // MUCH LESS THAN with slash {"nmid", 0x02224}, // DOES NOT DIVIDE {"NoBreak", 0x02060}, // WORD JOINER {"NonBreakingSpace", 0x000A0}, // NO-BREAK SPACE @@ -1362,56 +1320,56 @@ immutable NameId[] namesN = {"NotDoubleVerticalBar", 0x02226}, // NOT PARALLEL TO {"NotElement", 0x02209}, // NOT AN ELEMENT OF {"NotEqual", 0x02260}, // NOT EQUAL TO -// "NotEqualTilde", 0x02242;0x00338}, // MINUS TILDE with slash + {"NotEqualTilde", 0x02242, 0x00338}, // MINUS TILDE with slash {"NotExists", 0x02204}, // THERE DOES NOT EXIST {"NotGreater", 0x0226F}, // NOT GREATER-THAN {"NotGreaterEqual", 0x02271}, // NEITHER GREATER-THAN NOR EQUAL TO -// "NotGreaterFullEqual", 0x02267;0x00338}, // GREATER-THAN OVER EQUAL TO with slash -// "NotGreaterGreater", 0x0226B;0x00338}, // MUCH GREATER THAN with slash + {"NotGreaterFullEqual", 0x02267, 0x00338}, // GREATER-THAN OVER EQUAL TO with slash + {"NotGreaterGreater", 0x0226B, 0x00338}, // MUCH GREATER THAN with slash {"NotGreaterLess", 0x02279}, // NEITHER GREATER-THAN NOR LESS-THAN -// "NotGreaterSlantEqual", 0x02A7E;0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash + {"NotGreaterSlantEqual", 0x02A7E, 0x00338}, // GREATER-THAN OR SLANTED EQUAL TO with slash {"NotGreaterTilde", 0x02275}, // NEITHER GREATER-THAN NOR EQUIVALENT TO -// "NotHumpDownHump", 0x0224E;0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash -// "NotHumpEqual", 0x0224F;0x00338}, // DIFFERENCE BETWEEN with slash + {"NotHumpDownHump", 0x0224E, 0x00338}, // GEOMETRICALLY EQUIVALENT TO with slash + {"NotHumpEqual", 0x0224F, 0x00338}, // DIFFERENCE BETWEEN with slash {"notin", 0x02209}, // NOT AN ELEMENT OF -// "notindot", 0x022F5;0x00338}, // ELEMENT OF WITH DOT ABOVE with slash -// "notinE", 0x022F9;0x00338}, // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash + {"notindot", 0x022F5, 0x00338}, // ELEMENT OF WITH DOT ABOVE with slash + {"notinE", 0x022F9, 0x00338}, // ELEMENT OF WITH TWO HORIZONTAL STROKES with slash {"notinva", 0x02209}, // NOT AN ELEMENT OF {"notinvb", 0x022F7}, // SMALL ELEMENT OF WITH OVERBAR {"notinvc", 0x022F6}, // ELEMENT OF WITH OVERBAR {"NotLeftTriangle", 0x022EA}, // NOT NORMAL SUBGROUP OF -// "NotLeftTriangleBar", 0x029CF;0x00338}, // LEFT TRIANGLE BESIDE VERTICAL BAR with slash + {"NotLeftTriangleBar", 0x029CF, 0x00338}, // LEFT TRIANGLE BESIDE VERTICAL BAR with slash {"NotLeftTriangleEqual", 0x022EC}, // NOT NORMAL SUBGROUP OF OR EQUAL TO {"NotLess", 0x0226E}, // NOT LESS-THAN {"NotLessEqual", 0x02270}, // NEITHER LESS-THAN NOR EQUAL TO {"NotLessGreater", 0x02278}, // NEITHER LESS-THAN NOR GREATER-THAN -// "NotLessLess", 0x0226A;0x00338}, // MUCH LESS THAN with slash -// "NotLessSlantEqual", 0x02A7D;0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash + {"NotLessLess", 0x0226A, 0x00338}, // MUCH LESS THAN with slash + {"NotLessSlantEqual", 0x02A7D, 0x00338}, // LESS-THAN OR SLANTED EQUAL TO with slash {"NotLessTilde", 0x02274}, // NEITHER LESS-THAN NOR EQUIVALENT TO -// "NotNestedGreaterGreater", 0x02AA2;0x00338}, // DOUBLE NESTED GREATER-THAN with slash -// "NotNestedLessLess", 0x02AA1;0x00338}, // DOUBLE NESTED LESS-THAN with slash + {"NotNestedGreaterGreater", 0x02AA2, 0x00338}, // DOUBLE NESTED GREATER-THAN with slash + {"NotNestedLessLess", 0x02AA1, 0x00338}, // DOUBLE NESTED LESS-THAN with slash {"notni", 0x0220C}, // DOES NOT CONTAIN AS MEMBER {"notniva", 0x0220C}, // DOES NOT CONTAIN AS MEMBER {"notnivb", 0x022FE}, // SMALL CONTAINS WITH OVERBAR {"notnivc", 0x022FD}, // CONTAINS WITH OVERBAR {"NotPrecedes", 0x02280}, // DOES NOT PRECEDE -// "NotPrecedesEqual", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash + {"NotPrecedesEqual", 0x02AAF, 0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash {"NotPrecedesSlantEqual", 0x022E0}, // DOES NOT PRECEDE OR EQUAL {"NotReverseElement", 0x0220C}, // DOES NOT CONTAIN AS MEMBER {"NotRightTriangle", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP -// "NotRightTriangleBar", 0x029D0;0x00338}, // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash + {"NotRightTriangleBar", 0x029D0, 0x00338}, // VERTICAL BAR BESIDE RIGHT TRIANGLE with slash {"NotRightTriangleEqual", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL -// "NotSquareSubset", 0x0228F;0x00338}, // SQUARE IMAGE OF with slash + {"NotSquareSubset", 0x0228F, 0x00338}, // SQUARE IMAGE OF with slash {"NotSquareSubsetEqual", 0x022E2}, // NOT SQUARE IMAGE OF OR EQUAL TO -// "NotSquareSuperset", 0x02290;0x00338}, // SQUARE ORIGINAL OF with slash + {"NotSquareSuperset", 0x02290, 0x00338}, // SQUARE ORIGINAL OF with slash {"NotSquareSupersetEqual", 0x022E3}, // NOT SQUARE ORIGINAL OF OR EQUAL TO -// "NotSubset", 0x02282;0x020D2}, // SUBSET OF with vertical line + {"NotSubset", 0x02282, 0x020D2}, // SUBSET OF with vertical line {"NotSubsetEqual", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO {"NotSucceeds", 0x02281}, // DOES NOT SUCCEED -// "NotSucceedsEqual", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash + {"NotSucceedsEqual", 0x02AB0, 0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash {"NotSucceedsSlantEqual", 0x022E1}, // DOES NOT SUCCEED OR EQUAL -// "NotSucceedsTilde", 0x0227F;0x00338}, // SUCCEEDS OR EQUIVALENT TO with slash -// "NotSuperset", 0x02283;0x020D2}, // SUPERSET OF with vertical line + {"NotSucceedsTilde", 0x0227F, 0x00338}, // SUCCEEDS OR EQUIVALENT TO with slash + {"NotSuperset", 0x02283, 0x020D2}, // SUPERSET OF with vertical line {"NotSupersetEqual", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO {"NotTilde", 0x02241}, // NOT TILDE {"NotTildeEqual", 0x02244}, // NOT ASYMPTOTICALLY EQUAL TO @@ -1420,25 +1378,25 @@ immutable NameId[] namesN = {"NotVerticalBar", 0x02224}, // DOES NOT DIVIDE {"npar", 0x02226}, // NOT PARALLEL TO {"nparallel", 0x02226}, // NOT PARALLEL TO -// "nparsl", 0x02AFD;0x020E5}, // DOUBLE SOLIDUS OPERATOR with reverse slash -// "npart", 0x02202;0x00338}, // PARTIAL DIFFERENTIAL with slash + {"nparsl", 0x02AFD, 0x020E5}, // DOUBLE SOLIDUS OPERATOR with reverse slash + {"npart", 0x02202, 0x00338}, // PARTIAL DIFFERENTIAL with slash {"npolint", 0x02A14}, // LINE INTEGRATION NOT INCLUDING THE POLE {"npr", 0x02280}, // DOES NOT PRECEDE {"nprcue", 0x022E0}, // DOES NOT PRECEDE OR EQUAL -// "npre", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash + {"npre", 0x02AAF, 0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash {"nprec", 0x02280}, // DOES NOT PRECEDE -// "npreceq", 0x02AAF;0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash + {"npreceq", 0x02AAF, 0x00338}, // PRECEDES ABOVE SINGLE-LINE EQUALS SIGN with slash {"nrarr", 0x0219B}, // RIGHTWARDS ARROW WITH STROKE {"nrArr", 0x021CF}, // RIGHTWARDS DOUBLE ARROW WITH STROKE -// "nrarrc", 0x02933;0x00338}, // WAVE ARROW POINTING DIRECTLY RIGHT with slash -// "nrarrw", 0x0219D;0x00338}, // RIGHTWARDS WAVE ARROW with slash + {"nrarrc", 0x02933, 0x00338}, // WAVE ARROW POINTING DIRECTLY RIGHT with slash + {"nrarrw", 0x0219D, 0x00338}, // RIGHTWARDS WAVE ARROW with slash {"nrightarrow", 0x0219B}, // RIGHTWARDS ARROW WITH STROKE {"nRightarrow", 0x021CF}, // RIGHTWARDS DOUBLE ARROW WITH STROKE {"nrtri", 0x022EB}, // DOES NOT CONTAIN AS NORMAL SUBGROUP {"nrtrie", 0x022ED}, // DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL {"nsc", 0x02281}, // DOES NOT SUCCEED {"nsccue", 0x022E1}, // DOES NOT SUCCEED OR EQUAL -// "nsce", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash + {"nsce", 0x02AB0, 0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash {"Nscr", 0x1D4A9}, // MATHEMATICAL SCRIPT CAPITAL N {"nscr", 0x1D4C3}, // MATHEMATICAL SCRIPT SMALL N {"nshortmid", 0x02224}, // DOES NOT DIVIDE @@ -1452,18 +1410,18 @@ immutable NameId[] namesN = {"nsqsupe", 0x022E3}, // NOT SQUARE ORIGINAL OF OR EQUAL TO {"nsub", 0x02284}, // NOT A SUBSET OF {"nsube", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO -// "nsubE", 0x02AC5;0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash -// "nsubset", 0x02282;0x020D2}, // SUBSET OF with vertical line + {"nsubE", 0x02AC5, 0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash + {"nsubset", 0x02282, 0x020D2}, // SUBSET OF with vertical line {"nsubseteq", 0x02288}, // NEITHER A SUBSET OF NOR EQUAL TO -// "nsubseteqq", 0x02AC5;0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash + {"nsubseteqq", 0x02AC5, 0x00338}, // SUBSET OF ABOVE EQUALS SIGN with slash {"nsucc", 0x02281}, // DOES NOT SUCCEED -// "nsucceq", 0x02AB0;0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash + {"nsucceq", 0x02AB0, 0x00338}, // SUCCEEDS ABOVE SINGLE-LINE EQUALS SIGN with slash {"nsup", 0x02285}, // NOT A SUPERSET OF {"nsupe", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO -// "nsupE", 0x02AC6;0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash -// "nsupset", 0x02283;0x020D2}, // SUPERSET OF with vertical line + {"nsupE", 0x02AC6, 0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash + {"nsupset", 0x02283, 0x020D2}, // SUPERSET OF with vertical line {"nsupseteq", 0x02289}, // NEITHER A SUPERSET OF NOR EQUAL TO -// "nsupseteqq", 0x02AC6;0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash + {"nsupseteqq", 0x02AC6, 0x00338}, // SUPERSET OF ABOVE EQUALS SIGN with slash {"ntgl", 0x02279}, // NEITHER GREATER-THAN NOR LESS-THAN {"Ntilde", 0x000D1}, // LATIN CAPITAL LETTER N WITH TILDE {"ntilde", 0x000F1}, // LATIN SMALL LETTER N WITH TILDE @@ -1477,22 +1435,22 @@ immutable NameId[] namesN = {"num", 0x00023}, // NUMBER SIGN {"numero", 0x02116}, // NUMERO SIGN {"numsp", 0x02007}, // FIGURE SPACE -// "nvap", 0x0224D;0x020D2}, // EQUIVALENT TO with vertical line + {"nvap", 0x0224D, 0x020D2}, // EQUIVALENT TO with vertical line {"nvdash", 0x022AC}, // DOES NOT PROVE {"nvDash", 0x022AD}, // NOT TRUE {"nVdash", 0x022AE}, // DOES NOT FORCE {"nVDash", 0x022AF}, // NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE -// "nvge", 0x02265;0x020D2}, // GREATER-THAN OR EQUAL TO with vertical line -// "nvgt", 0x0003E;0x020D2}, // GREATER-THAN SIGN with vertical line + {"nvge", 0x02265, 0x020D2}, // GREATER-THAN OR EQUAL TO with vertical line + {"nvgt", 0x0003E, 0x020D2}, // GREATER-THAN SIGN with vertical line {"nvHarr", 0x02904}, // LEFT RIGHT DOUBLE ARROW WITH VERTICAL STROKE {"nvinfin", 0x029DE}, // INFINITY NEGATED WITH VERTICAL BAR {"nvlArr", 0x02902}, // LEFTWARDS DOUBLE ARROW WITH VERTICAL STROKE -// "nvle", 0x02264;0x020D2}, // LESS-THAN OR EQUAL TO with vertical line -// "nvlt", 0x0003C;0x020D2}, // LESS-THAN SIGN with vertical line -// "nvltrie", 0x022B4;0x020D2}, // NORMAL SUBGROUP OF OR EQUAL TO with vertical line + {"nvle", 0x02264, 0x020D2}, // LESS-THAN OR EQUAL TO with vertical line + {"nvlt", 0x0003C, 0x020D2}, // LESS-THAN SIGN with vertical line + {"nvltrie", 0x022B4, 0x020D2}, // NORMAL SUBGROUP OF OR EQUAL TO with vertical line {"nvrArr", 0x02903}, // RIGHTWARDS DOUBLE ARROW WITH VERTICAL STROKE -// "nvrtrie", 0x022B5;0x020D2}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line -// "nvsim", 0x0223C;0x020D2}, // TILDE OPERATOR with vertical line + {"nvrtrie", 0x022B5, 0x020D2}, // CONTAINS AS NORMAL SUBGROUP OR EQUAL TO with vertical line + {"nvsim", 0x0223C, 0x020D2}, // TILDE OPERATOR with vertical line {"nwarhk", 0x02923}, // NORTH WEST ARROW WITH HOOK {"nwarr", 0x02196}, // NORTH WEST ARROW {"nwArr", 0x021D6}, // NORTH WEST DOUBLE ARROW @@ -1704,7 +1662,7 @@ immutable NameId[] namesQ = immutable NameId[] namesR = [ {"rAarr", 0x021DB}, // RIGHTWARDS TRIPLE ARROW -// "race", 0x0223D;0x00331}, // REVERSED TILDE with underline + {"race", 0x0223D, 0x00331}, // REVERSED TILDE with underline {"Racute", 0x00154}, // LATIN CAPITAL LETTER R WITH ACUTE {"racute", 0x00155}, // LATIN SMALL LETTER R WITH ACUTE {"radic", 0x0221A}, // SQUARE ROOT @@ -1932,7 +1890,7 @@ immutable NameId[] namesS = {"smile", 0x02323}, // SMILE {"smt", 0x02AAA}, // SMALLER THAN {"smte", 0x02AAC}, // SMALLER THAN OR EQUAL TO -// "smtes", 0x02AAC;0x0FE00}, // SMALLER THAN OR slanted EQUAL + {"smtes", 0x02AAC, 0x0FE00}, // SMALLER THAN OR slanted EQUAL {"SOFTcy", 0x0042C}, // CYRILLIC CAPITAL LETTER SOFT SIGN {"softcy", 0x0044C}, // CYRILLIC SMALL LETTER SOFT SIGN {"sol", 0x0002F}, // SOLIDUS @@ -1944,9 +1902,9 @@ immutable NameId[] namesS = {"spadesuit", 0x02660}, // BLACK SPADE SUIT {"spar", 0x02225}, // PARALLEL TO {"sqcap", 0x02293}, // SQUARE CAP -// "sqcaps", 0x02293;0x0FE00}, // SQUARE CAP with serifs + {"sqcaps", 0x02293, 0x0FE00}, // SQUARE CAP with serifs {"sqcup", 0x02294}, // SQUARE CUP -// "sqcups", 0x02294;0x0FE00}, // SQUARE CUP with serifs + {"sqcups", 0x02294, 0x0FE00}, // SQUARE CUP with serifs {"Sqrt", 0x0221A}, // SQUARE ROOT {"sqsub", 0x0228F}, // SQUARE IMAGE OF {"sqsube", 0x02291}, // SQUARE IMAGE OF OR EQUAL TO @@ -2082,7 +2040,7 @@ immutable NameId[] namesT = {"thgr", 0x003B8}, // GREEK SMALL LETTER THETA {"thickapprox", 0x02248}, // ALMOST EQUAL TO {"thicksim", 0x0223C}, // TILDE OPERATOR -// "ThickSpace", 0x0205F;0x0200A}, // space of width 5/18 em + {"ThickSpace", 0x0205F, 0x0200A}, // space of width 5/18 em {"thinsp", 0x02009}, // THIN SPACE {"ThinSpace", 0x02009}, // THIN SPACE {"thkap", 0x02248}, // ALMOST EQUAL TO @@ -2245,10 +2203,10 @@ immutable NameId[] namesV = {"vArr", 0x021D5}, // UP DOWN DOUBLE ARROW {"varrho", 0x003F1}, // GREEK RHO SYMBOL {"varsigma", 0x003C2}, // GREEK SMALL LETTER FINAL SIGMA -// "varsubsetneq", 0x0228A;0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members -// "varsubsetneqq", 0x02ACB;0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members -// "varsupsetneq", 0x0228B;0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members -// "varsupsetneqq", 0x02ACC;0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + {"varsubsetneq", 0x0228A, 0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + {"varsubsetneqq", 0x02ACB, 0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + {"varsupsetneq", 0x0228B, 0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + {"varsupsetneqq", 0x02ACC, 0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members {"vartheta", 0x003D1}, // GREEK THETA SYMBOL {"vartriangleleft", 0x022B2}, // NORMAL SUBGROUP OF {"vartriangleright", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP @@ -2279,18 +2237,18 @@ immutable NameId[] namesV = {"Vfr", 0x1D519}, // MATHEMATICAL FRAKTUR CAPITAL V {"vfr", 0x1D533}, // MATHEMATICAL FRAKTUR SMALL V {"vltri", 0x022B2}, // NORMAL SUBGROUP OF -// "vnsub", 0x02282;0x020D2}, // SUBSET OF with vertical line -// "vnsup", 0x02283;0x020D2}, // SUPERSET OF with vertical line + {"vnsub", 0x02282, 0x020D2}, // SUBSET OF with vertical line + {"vnsup", 0x02283, 0x020D2}, // SUPERSET OF with vertical line {"Vopf", 0x1D54D}, // MATHEMATICAL DOUBLE-STRUCK CAPITAL V {"vopf", 0x1D567}, // MATHEMATICAL DOUBLE-STRUCK SMALL V {"vprop", 0x0221D}, // PROPORTIONAL TO {"vrtri", 0x022B3}, // CONTAINS AS NORMAL SUBGROUP {"Vscr", 0x1D4B1}, // MATHEMATICAL SCRIPT CAPITAL V {"vscr", 0x1D4CB}, // MATHEMATICAL SCRIPT SMALL V -// "vsubne", 0x0228A;0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members -// "vsubnE", 0x02ACB;0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members -// "vsupne", 0x0228B;0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members -// "vsupnE", 0x02ACC;0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + {"vsubne", 0x0228A, 0x0FE00}, // SUBSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + {"vsubnE", 0x02ACB, 0x0FE00}, // SUBSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members + {"vsupne", 0x0228B, 0x0FE00}, // SUPERSET OF WITH NOT EQUAL TO - variant with stroke through bottom members + {"vsupnE", 0x02ACC, 0x0FE00}, // SUPERSET OF ABOVE NOT EQUAL TO - variant with stroke through bottom members {"Vvdash", 0x022AA}, // TRIPLE VERTICAL BAR RIGHT TURNSTILE {"vzigzag", 0x0299A}, // VERTICAL ZIGZAG LINE ]; diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 7ba0a96..e7626b0 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -409,23 +409,9 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Var { unsafeAssign!"scope variable"(v); } - else if (v.isTypesafeVariadicParameter && p == sc.func) + else if (v.isTypesafeVariadicArray && p == sc.func) { - Type tb = v.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) - { - unsafeAssign!"variadic variable"(v); - } - } - else - { - /* v is not 'scope', and is assigned to a parameter that may escape. - * Therefore, v can never be 'scope'. - */ - if (log) printf("no infer for %s in %s loc %s, fdc %s, %d\n", - v.toChars(), sc.func.ident.toChars(), sc.func.loc.toChars(), fdc.ident.toChars(), __LINE__); - - doNotInferScope(v, vPar); + unsafeAssign!"variadic variable"(v); } } @@ -673,9 +659,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) FuncDeclaration fd = sc.func; - // Determine if va is a parameter that is an indirect reference - const bool vaIsRef = va && va.storage_class & STC.parameter && - (va.isReference() || va.type.toBasetype().isTypeClass()); // ref, out, or class + // Determine if va is a `ref` parameter, so it has a lifetime exceding the function scope + const bool vaIsRef = va && va.isParameter() && va.isReference(); if (log && vaIsRef) printf("va is ref `%s`\n", va.toChars()); /* Determine if va is the first parameter, through which other 'return' parameters @@ -717,7 +702,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) Dsymbol p = v.toParent2(); if (va && !vaIsRef && !va.isScope() && !v.isScope() && - !v.isTypesafeVariadicParameter && !va.isTypesafeVariadicParameter && + !v.isTypesafeVariadicArray && !va.isTypesafeVariadicArray && (va.isParameter() && va.maybeScope && v.isParameter() && v.maybeScope) && p == fd) { @@ -727,16 +712,9 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) continue; } - if (vaIsFirstRef && - (v.isScope() || v.maybeScope) && - !(v.storage_class & STC.return_) && - v.isParameter() && - fd.flags & FUNCFLAG.returnInprocess && - p == fd && - !v.isTypesafeVariadicParameter) + if (vaIsFirstRef && p == fd) { - if (log) printf("inferring 'return' for parameter %s in function %s\n", v.toChars(), fd.toChars()); - inferReturn(fd, v, /*returnScope:*/ true); // infer addition of 'return' to make `return scope` + inferReturn(fd, v, /*returnScope:*/ true); } if (!(va && va.isScope()) || vaIsRef) @@ -744,82 +722,66 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) if (v.isScope()) { - if (vaIsFirstRef && v.isParameter() && v.storage_class & STC.return_) + if (vaIsFirstRef && v.isParameter() && v.isReturn()) { // va=v, where v is `return scope` - if (va.isScope()) + if (inferScope(va)) continue; - - if (va.maybeScope) - { - if (log) printf("inferring scope for lvalue %s\n", va.toChars()); - va.storage_class |= STC.scope_ | STC.scopeinferred; - continue; - } } - if (va && va.isScope() && va.storage_class & STC.return_ && !(v.storage_class & STC.return_)) + // If va's lifetime encloses v's, then error + if (EnclosedBy eb = va.enclosesLifetimeOf(v)) { - // va may return its value, but v does not allow that, so this is an error - if (sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to return scope `%s`", v, va)) + const(char)* msg; + final switch (eb) { - result = true; - continue; + case EnclosedBy.none: assert(0); + case EnclosedBy.returnScope: + msg = "scope variable `%s` assigned to return scope `%s`"; + break; + case EnclosedBy.longerScope: + if (v.storage_class & STC.temp) + continue; + msg = "scope variable `%s` assigned to `%s` with longer lifetime"; + break; + case EnclosedBy.refVar: + msg = "scope variable `%s` assigned to `ref` variable `%s` with longer lifetime"; + break; + case EnclosedBy.global: + msg = "scope variable `%s` assigned to global variable `%s`"; + break; } - } - // If va's lifetime encloses v's, then error - if (va && !va.isDataseg() && - ((va.enclosesLifetimeOf(v) && !(v.storage_class & STC.temp)) || vaIsRef)) - { - if (sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to `%s` with longer lifetime", v, va)) + if (sc.setUnsafeDIP1000(gag, ae.loc, msg, v, va)) { result = true; continue; } } - if (va && !va.isDataseg() && (va.isScope() || va.maybeScope)) + // v = scope, va should be scope as well + const vaWasScope = va && va.isScope(); + if (inferScope(va)) { - if (!va.isScope()) - { /* v is scope, and va is not scope, so va needs to - * infer scope - */ - if (log) printf("inferring scope for %s\n", va.toChars()); - va.storage_class |= STC.scope_ | STC.scopeinferred; - /* v returns, and va does not return, so va needs - * to infer return - */ - if (v.storage_class & STC.return_ && - !(va.storage_class & STC.return_)) - { - if (log) printf("infer return for %s\n", va.toChars()); - va.storage_class |= STC.return_ | STC.returninferred; + // In case of `scope local = returnScopeParam`, do not infer return scope for `x` + if (!vaWasScope && v.isReturn() && !va.isReturn()) + { + if (log) printf("infer return for %s\n", va.toChars()); + va.storage_class |= STC.return_ | STC.returninferred; - // Added "return scope" so don't confuse it with "return ref" - if (isRefReturnScope(va.storage_class)) - va.storage_class |= STC.returnScope; - } + // Added "return scope" so don't confuse it with "return ref" + if (isRefReturnScope(va.storage_class)) + va.storage_class |= STC.returnScope; } continue; } result |= sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to non-scope `%s`", v, e1); } - else if (v.isTypesafeVariadicParameter && p == fd) + else if (v.isTypesafeVariadicArray && p == fd) { - Type tb = v.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) - { - if (va && !va.isDataseg() && (va.isScope() || va.maybeScope)) - { - if (!va.isScope()) - { //printf("inferring scope for %s\n", va.toChars()); - va.storage_class |= STC.scope_ | STC.scopeinferred; - } - continue; - } - result |= sc.setUnsafeDIP1000(gag, ae.loc, "variadic variable `%s` assigned to non-scope `%s`", v, e1); - } + if (inferScope(va)) + continue; + result |= sc.setUnsafeDIP1000(gag, ae.loc, "variadic variable `%s` assigned to non-scope `%s`", v, e1); } else { @@ -845,7 +807,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) if (va && va.isScope() && !v.isReference()) { - if (!(va.storage_class & STC.return_)) + if (!va.isReturn()) { va.doNotInferReturn = true; } @@ -858,19 +820,14 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) Dsymbol p = v.toParent2(); - if (vaIsFirstRef && v.isParameter() && - !(v.storage_class & STC.return_) && - fd.flags & FUNCFLAG.returnInprocess && - p == fd) + if (vaIsFirstRef && p == fd) { //if (log) printf("inferring 'return' for parameter %s in function %s\n", v.toChars(), fd.toChars()); inferReturn(fd, v, /*returnScope:*/ false); } // If va's lifetime encloses v's, then error - if (va && - !(vaIsFirstRef && (v.storage_class & STC.return_)) && - (va.enclosesLifetimeOf(v) || (va.isReference() && !(va.storage_class & STC.temp)) || va.isDataseg())) + if (va && !(vaIsFirstRef && v.isReturn()) && va.enclosesLifetimeOf(v)) { if (sc.setUnsafeDIP1000(gag, ae.loc, "address of variable `%s` assigned to `%s` with longer lifetime", v, va)) { @@ -885,13 +842,9 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) if (p != sc.func) continue; - if (va && !va.isDataseg() && (va.isScope() || va.maybeScope)) + if (inferScope(va)) { - if (!va.isScope()) - { //printf("inferring scope for %s\n", va.toChars()); - va.storage_class |= STC.scope_ | STC.scopeinferred; - } - if (v.storage_class & STC.return_ && !(va.storage_class & STC.return_)) + if (v.isReturn() && !va.isReturn()) va.storage_class |= STC.return_ | STC.returninferred; continue; } @@ -912,7 +865,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) * then uncount that address of. This is so it won't cause a * closure to be allocated. */ - if (va && va.isScope() && !(va.storage_class & STC.return_) && func.tookAddressOf) + if (va && va.isScope() && !va.isReturn() && func.tookAddressOf) --func.tookAddressOf; foreach (v; vars) @@ -978,14 +931,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) } } - if (va && !va.isDataseg() && (va.isScope() || va.maybeScope)) - { - if (!va.isScope()) - { //printf("inferring scope for %s\n", va.toChars()); - va.storage_class |= STC.scope_ | STC.scopeinferred; - } + if (inferScope(va)) continue; - } result |= sc.setUnsafeDIP1000(gag, ee.loc, "reference to stack allocated value returned by `%s` assigned to non-scope `%s`", ee, e1); @@ -1091,14 +1038,10 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) continue; } } - else if (v.isTypesafeVariadicParameter && p == sc.func) + else if (v.isTypesafeVariadicArray && p == sc.func) { - Type tb = v.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) - { - result |= sc.setUnsafeDIP1000(gag, e.loc, - "copying `%s` into allocated memory escapes a reference to variadic parameter `%s`", e, v); - } + result |= sc.setUnsafeDIP1000(gag, e.loc, + "copying `%s` into allocated memory escapes a reference to variadic parameter `%s`", e, v); } else { @@ -1258,15 +1201,8 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) Dsymbol p = v.toParent2(); - if ((v.isScope() || v.maybeScope) && - !(v.storage_class & STC.return_) && - v.isParameter() && - !v.doNotInferReturn && - sc.func.flags & FUNCFLAG.returnInprocess && - p == sc.func && - !v.isTypesafeVariadicParameter) + if (p == sc.func && inferReturn(sc.func, v, /*returnScope:*/ true)) { - inferReturn(sc.func, v, /*returnScope:*/ true); // infer addition of 'return' continue; } @@ -1300,7 +1236,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) !(!refs && sc.func.isFuncDeclaration().getLevel(pfunc, sc.intypeof) > 0) ) { - if (v.isParameter() && !(v.storage_class & STC.return_)) + if (v.isParameter() && !v.isReturn()) { // https://issues.dlang.org/show_bug.cgi?id=23191 if (!gag) @@ -1320,15 +1256,11 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) } } } - else if (v.isTypesafeVariadicParameter && p == sc.func) + else if (v.isTypesafeVariadicArray && p == sc.func) { - Type tb = v.type.toBasetype(); - if (tb.ty == Tarray || tb.ty == Tsarray) - { - if (!gag) - error(e.loc, "returning `%s` escapes a reference to variadic parameter `%s`", e.toChars(), v.toChars()); - result = false; - } + if (!gag) + error(e.loc, "returning `%s` escapes a reference to variadic parameter `%s`", e.toChars(), v.toChars()); + result = false; } else { @@ -1414,7 +1346,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) continue; } FuncDeclaration fd = p.isFuncDeclaration(); - if (fd && sc.func.flags & FUNCFLAG.returnInprocess) + if (fd && sc.func.returnInprocess) { /* Code like: * int x; @@ -1435,10 +1367,10 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) vsr == ScopeRef.Ref_ReturnScope) && !(v.storage_class & STC.foreach_)) { - if (sc.func.flags & FUNCFLAG.returnInprocess && p == sc.func && - (vsr == ScopeRef.Ref || vsr == ScopeRef.RefScope)) + if (p == sc.func && (vsr == ScopeRef.Ref || vsr == ScopeRef.RefScope) && + inferReturn(sc.func, v, /*returnScope:*/ false)) { - inferReturn(sc.func, v, /*returnScope:*/ false); // infer addition of 'return' + continue; } else { @@ -1488,6 +1420,26 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) return result; } +/*********************************** + * Infer `scope` for a variable + * + * Params: + * va = variable to infer scope for + * Returns: `true` if succesful or already `scope` + */ +bool inferScope(VarDeclaration va) +{ + if (!va) + return false; + if (!va.isDataseg() && va.maybeScope && !va.isScope()) + { + //printf("inferring scope for %s\n", va.toChars()); + va.maybeScope = false; + va.storage_class |= STC.scope_ | STC.scopeinferred; + return true; + } + return va.isScope(); +} /************************************* * Variable v needs to have 'return' inferred for it. @@ -1495,10 +1447,22 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) * fd = function that v is a parameter to * v = parameter that needs to be STC.return_ * returnScope = infer `return scope` instead of `return ref` + * + * Returns: whether the inference on `v` was successful or `v` already was `return` */ -private void inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope) +private bool inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope) { - // v is a local in the current function + if (v.isReturn()) + return !!(v.storage_class & STC.returnScope) == returnScope; + + if (!v.isParameter() || v.isTypesafeVariadicArray || (returnScope && v.doNotInferReturn)) + return false; + + if (!fd.returnInprocess) + return false; + + if (returnScope && !(v.isScope() || v.maybeScope)) + return false; //printf("for function '%s' inferring 'return' for variable '%s', returnScope: %d\n", fd.toChars(), v.toChars(), returnScope); auto newStcs = STC.return_ | STC.returninferred | (returnScope ? STC.returnScope : 0); @@ -1532,6 +1496,7 @@ private void inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope) } } } + return true; } @@ -1694,7 +1659,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re { if (tb.ty == Tsarray) return; - if (v.isTypesafeVariadicParameter) + if (v.isTypesafeVariadicArray) { er.byvalue.push(v); return; @@ -2008,13 +1973,10 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR if (auto ve = e.e1.isVarExp()) { VarDeclaration v = ve.var.isVarDeclaration(); - if (tb.ty == Tarray || tb.ty == Tsarray) + if (v && v.isTypesafeVariadicArray) { - if (v && v.isTypesafeVariadicParameter) - { - er.pushRef(v, retRefTransition); - return; - } + er.pushRef(v, retRefTransition); + return; } } if (tb.ty == Tsarray) @@ -2339,9 +2301,9 @@ private void doNotInferScope(VarDeclaration v, RootObject o) void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f) { - if (funcdecl.flags & FUNCFLAG.returnInprocess) + if (funcdecl.returnInprocess) { - funcdecl.flags &= ~FUNCFLAG.returnInprocess; + funcdecl.returnInprocess = false; if (funcdecl.storage_class & STC.return_) { if (funcdecl.type == f) @@ -2353,9 +2315,9 @@ void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f) } } - if (!(funcdecl.flags & FUNCFLAG.inferScope)) + if (!funcdecl.inferScope) return; - funcdecl.flags &= ~FUNCFLAG.inferScope; + funcdecl.inferScope = false; // Eliminate maybescope's { @@ -2387,22 +2349,19 @@ void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f) foreach (u, p; f.parameterList) { auto v = (*funcdecl.parameters)[u]; - if (v.maybeScope) + if (!v.isScope() && inferScope(v)) { //printf("Inferring scope for %s\n", v.toChars()); - notMaybeScope(v, null); - v.storage_class |= STC.scope_ | STC.scopeinferred; p.storageClass |= STC.scope_ | STC.scopeinferred; } } } - if (funcdecl.vthis && funcdecl.vthis.maybeScope) + if (funcdecl.vthis) { - notMaybeScope(funcdecl.vthis, null); - funcdecl.vthis.storage_class |= STC.scope_ | STC.scopeinferred; - f.isScopeQual = true; - f.isscopeinferred = true; + inferScope(funcdecl.vthis); + f.isScopeQual = funcdecl.vthis.isScope(); + f.isscopeinferred = !!(funcdecl.vthis.storage_class & STC.scopeinferred); } } @@ -2542,20 +2501,45 @@ bool isReferenceToMutable(Parameter p, Type t) return isReferenceToMutable(p.type); } +/// When checking lifetime for assignment `va=v`, the way `va` encloses `v` +private enum EnclosedBy +{ + none = 0, + refVar, // `va` is a `ref` variable, which may link to a global variable + global, // `va` is a global variable + returnScope, // `va` is a scope variable that may be returned + longerScope, // `va` is another scope variable declared earlier than `v` +} + /********************************** -* 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 + * Determine if `va` has a lifetime that lasts past + * the destruction of `v` + * Params: + * va = variable assigned to + * v = variable being assigned + * Returns: + * The way `va` encloses `v` (if any) + */ +private EnclosedBy enclosesLifetimeOf(VarDeclaration va, VarDeclaration v) { + if (!va) + return EnclosedBy.none; + + if (va.isDataseg()) + return EnclosedBy.global; + + if (va.isScope() && va.isReturn() && !v.isReturn()) + return EnclosedBy.returnScope; + + if (va.isReference() && va.isParameter()) + return EnclosedBy.refVar; + assert(va.sequenceNumber != va.sequenceNumber.init); assert(v.sequenceNumber != v.sequenceNumber.init); - return va.sequenceNumber < v.sequenceNumber; + if (va.sequenceNumber < v.sequenceNumber) + return EnclosedBy.longerScope; + + return EnclosedBy.none; } /*************************************** @@ -2576,53 +2560,6 @@ private void addMaybe(VarDeclaration va, VarDeclaration v) va.maybes.push(v); } -/*************************************** - * Like `FuncDeclaration.setUnsafe`, but modified for dip25 / dip1000 by default transitions - * - * With `-preview=dip1000` it actually sets the function as unsafe / prints an error, while - * without it, it only prints a deprecation in a `@safe` function. - * With `-revert=preview=dip1000`, it doesn't do anything. - * - * Params: - * sc = used for checking whether we are in a deprecated scope - * fs = command line setting of dip1000 / dip25 - * gag = surpress error message - * loc = location of error - * fmt = printf-style format string - * arg0 = (optional) argument for first %s format specifier - * arg1 = (optional) argument for second %s format specifier - * arg2 = (optional) argument for third %s format specifier - * Returns: whether an actual safe error (not deprecation) occured - */ -private bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg, - RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null) -{ - if (fs == FeatureState.disabled) - { - return false; - } - else if (fs == FeatureState.enabled) - { - return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2); - } - else - { - if (sc.func.isSafeBypassingInference()) - { - if (!gag) - previewErrorFunc(sc.isDeprecated(), fs)( - loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "" - ); - } - else if (!sc.func.safetyViolation) - { - import dmd.func : AttributeViolation; - sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2); - } - return false; - } -} - // `setUnsafePreview` partially evaluated for dip1000 private bool setUnsafeDIP1000(Scope* sc, bool gag, Loc loc, const(char)* msg, RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null) @@ -2671,13 +2608,19 @@ private bool checkScopeVarAddr(VarDeclaration v, Expression e, Scope* sc, bool g } /**************************** - * Determine if `v` is a typesafe variadic parameter. + * Determine if `v` is a typesafe variadic array, which is implicitly `scope` * Params: * v = variable to check * Returns: * true if `v` is a variadic parameter */ -bool isTypesafeVariadicParameter(VarDeclaration v) +private bool isTypesafeVariadicArray(VarDeclaration v) { - return !!(v.storage_class & STC.variadic); + if (v.storage_class & STC.variadic) + { + Type tb = v.type.toBasetype(); + if (tb.ty == Tarray || tb.ty == Tsarray) + return true; + } + return false; } diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 42b4dd4..21f5cc7 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -2949,7 +2949,7 @@ extern (C++) final class ArrayLiteralExp : Expression Expressions* elements; OwnedBy ownedByCtfe = OwnedBy.code; - + bool onstack = false; extern (D) this(const ref Loc loc, Type type, Expressions* elements) { diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index c9e3978..79bc528 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -419,6 +419,7 @@ public: Expression *basis; Expressions *elements; OwnedBy ownedByCtfe; + bool onstack; static ArrayLiteralExp *create(const Loc &loc, Expressions *elements); static void emplace(UnionExp *pue, const Loc &loc, Expressions *elements); diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 8a4a13c..f899bd7 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -353,6 +353,37 @@ extern(D) bool arrayExpressionSemantic( return err; } +/* +Checks if `exp` contains a direct access to a `noreturn` +variable. If that is the case, an `assert(0)` expression +is generated and returned. This function should be called +only after semantic analysis has been performed on `exp`. + +Params: + exp = expression that is checked + +Returns: + An `assert(0)` expression if `exp` contains a `noreturn` + variable access, `exp` otherwise. +*/ + +Expression checkNoreturnVarAccess(Expression exp) +{ + assert(exp.type); + + Expression result = exp; + if (exp.type.isTypeNoreturn() && !exp.isAssertExp() && + !exp.isThrowExp() && !exp.isCallExp()) + { + auto msg = new StringExp(exp.loc, "Accessed expression of type `noreturn`"); + msg.type = Type.tstring; + result = new AssertExp(exp.loc, IntegerExp.literal!0, msg); + result.type = exp.type; + } + + return result; +} + /****************************** * Check the tail CallExp is really property function call. * Bugs: @@ -848,6 +879,18 @@ Lagain: if (d) d.checkDisabled(loc, sc); } + + if (auto sd = s.isDeclaration()) + { + if (sd.isSystem()) + { + if (sc.setUnsafePreview(global.params.systemVariables, false, loc, + "cannot access `@system` variable `%s` in @safe code", sd)) + { + return ErrorExp.get(); + } + } + } } if (auto em = s.isEnumMember()) @@ -1714,7 +1757,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc, if (sc._module) sc._module.hasAlwaysInlines = true; if (sc.func) - sc.func.flags |= FUNCFLAG.hasAlwaysInline; + sc.func.hasAlwaysInlines = true; } const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration(); @@ -2200,14 +2243,14 @@ private bool functionParameters(const ref Loc loc, Scope* sc, /* If calling C scanf(), printf(), or any variants, check the format string against the arguments */ const isVa_list = tf.parameterList.varargs == VarArg.none; - if (fd && fd.flags & FUNCFLAG.printf) + if (fd && fd.printf) { if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp()) { checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list); } } - else if (fd && fd.flags & FUNCFLAG.scanf) + else if (fd && fd.scanf) { if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp()) { @@ -4628,8 +4671,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else if (exp.arguments.dim == 1) { e = (*exp.arguments)[0]; - e = e.implicitCastTo(sc, t1); - e = new CastExp(exp.loc, e, t1); + if (!e.type.isTypeNoreturn()) + e = e.implicitCastTo(sc, t1); } else { @@ -7474,6 +7517,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } + if (exp.e1.type.isTypeNoreturn() && (!exp.to || !exp.to.isTypeNoreturn())) + { + result = exp.e1; + return; + } if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction()) exp.e1 = exp.e1.arrayFuncConv(sc); @@ -7889,7 +7937,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } } - else if (t1b.ty == Tvector) + else if (t1b.ty == Tvector && exp.e1.isLvalue()) { // Convert e1 to corresponding static array TypeVector tv1 = cast(TypeVector)t1b; @@ -8896,7 +8944,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.e1 = e1x; assert(exp.e1.type); } - Type t1 = exp.e1.type.toBasetype(); + Type t1 = exp.e1.type.isTypeEnum() ? exp.e1.type : exp.e1.type.toBasetype(); /* Run this.e2 semantic. * Different from other binary expressions, the analysis of e2 @@ -8918,14 +8966,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor e2x.checkSharedAccess(sc)) return setError(); - if (e2x.type.isTypeNoreturn() && !e2x.isAssertExp() && !e2x.isThrowExp() && !e2x.isCallExp()) - { - auto msg = new StringExp(e2x.loc, "Accessed expression of type `noreturn`"); - msg.type = Type.tstring; - e2x = new AssertExp(e2x.loc, IntegerExp.literal!0, msg); - e2x.type = Type.tnoreturn; - return setResult(e2x); - } + auto etmp = checkNoreturnVarAccess(e2x); + if (etmp != e2x) + return setResult(etmp); + exp.e2 = e2x; } @@ -9890,14 +9934,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.type = exp.e1.type; assert(exp.type); + auto assignElem = exp.e2; auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp; - Expression tmp; /* https://issues.dlang.org/show_bug.cgi?id=22366 * * `reorderSettingAAElem` creates a tree of comma expressions, however, * `checkAssignExp` expects only AssignExps. */ - checkAssignEscape(sc, Expression.extractLast(res, tmp), false, false); + if (res == exp) // no `AA[k] = v` rewrite was performed + checkAssignEscape(sc, res, false, false); + else + checkNewEscape(sc, assignElem, false); // assigning to AA puts it on heap if (auto ae = res.isConstructExp()) { @@ -9905,40 +9952,48 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (t1b.ty != Tsarray && t1b.ty != Tarray) return setResult(res); - /* Do not lower Rvalues and references, as they need to be moved, - * not copied. - * Skip the lowering when the RHS is an array literal, as e2ir - * already handles such cases more elegantly. - */ - const isArrayCtor = - (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) && - ae.e2.isLvalue && - !(ae.e1.isVarExp && - ae.e1.isVarExp.var.isVarDeclaration.isReference) && - (ae.e2.isVarExp || - ae.e2.isSliceExp || - (ae.e2.type.ty == Tsarray && !ae.e2.isArrayLiteralExp)) && - ae.e1.type.nextOf && - ae.e2.type.nextOf && - ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf); - - /* Unlike isArrayCtor above, lower all Rvalues. If the RHS is a literal, - * then we do want to make a temporary for it and call its destructor. - */ - const isArraySetCtor = - (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) && - (ae.e2.type.ty == Tstruct || ae.e2.type.ty == Tsarray) && - ae.e1.type.nextOf && - ae.e1.type.nextOf.equivalent(ae.e2.type); + // only non-trivial array constructions may need to be lowered (non-POD elements basically) + Type t1e = t1b.nextOf(); + TypeStruct ts = t1e.baseElemOf().isTypeStruct(); + if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor)) + return setResult(res); - if (isArrayCtor || isArraySetCtor) + // don't lower ref-constructions etc. + if (!(t1b.ty == Tsarray || ae.e1.isSliceExp) || + (ae.e1.isVarExp && ae.e1.isVarExp.var.isVarDeclaration.isReference)) + return setResult(res); + + // Construction from an equivalent other array? + // Only lower with lvalue RHS elements; let the glue layer move rvalue elements. + Type t2b = ae.e2.type.toBasetype(); + // skip over a (possibly implicit) cast of a static array RHS to a slice + Expression rhs = ae.e2; + Type rhsType = t2b; + if (t2b.ty == Tarray) { - const ts = t1b.nextOf().baseElemOf().isTypeStruct(); - if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor)) - return setResult(res); + if (auto ce = rhs.isCastExp()) + { + auto ct = ce.e1.type.toBasetype(); + if (ct.ty == Tsarray) + { + rhs = ce.e1; + rhsType = ct; + } + } + } + const lowerToArrayCtor = + ( (rhsType.ty == Tarray && !rhs.isArrayLiteralExp) || + (rhsType.ty == Tsarray && rhs.isLvalue) ) && + t1e.equivalent(t2b.nextOf); + + // Construction from a single element? + // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times). + const lowerToArraySetCtor = !lowerToArrayCtor && t1e.equivalent(t2b); - auto func = isArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor; - const other = isArrayCtor ? "other array" : "value"; + if (lowerToArrayCtor || lowerToArraySetCtor) + { + auto func = lowerToArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor; + const other = lowerToArrayCtor ? "other array" : "value"; if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object)) return setError(); @@ -9948,18 +10003,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor id = new DotIdExp(exp.loc, id, func); auto arguments = new Expressions(); - arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf).expressionSemantic(sc)); - if (isArrayCtor) + arguments.push(new CastExp(ae.loc, ae.e1, t1e.arrayOf).expressionSemantic(sc)); + if (lowerToArrayCtor) { - arguments.push(new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf).expressionSemantic(sc)); + arguments.push(new CastExp(ae.loc, rhs, t2b.nextOf.arrayOf).expressionSemantic(sc)); Expression ce = new CallExp(exp.loc, id, arguments); res = ce.expressionSemantic(sc); } else { Expression e0; - // If ae.e2 is not a variable, construct a temp variable, as _d_arraysetctor requires `ref` access - if (!ae.e2.isVarExp) + // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor + if (!ae.e2.isLvalue) { auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2); e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc); @@ -11759,6 +11814,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = arrayLowering; return; } + + if (t1.isTypeVector()) + exp.type = t1; + result = exp; return; } @@ -12038,6 +12097,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } + if (t1.isTypeVector()) + exp.type = t1; + result = exp; } @@ -12490,8 +12552,7 @@ Expression semanticX(DotIdExp exp, Scope* sc) if (f.checkForwardRef(loc)) return ErrorExp.get(); - if (f.flags & (FUNCFLAG.purityInprocess | FUNCFLAG.safetyInprocess | - FUNCFLAG.nothrowInprocess | FUNCFLAG.nogcInprocess)) + if (f.purityInprocess || f.safetyInprocess || f.nothrowInprocess || f.nogcInprocess) { f.error(loc, "cannot retrieve its `.mangleof` while inferring attributes"); return ErrorExp.get(); @@ -13099,7 +13160,7 @@ Lerr: */ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) { - if (!global.params.noSharedAccess || + if (global.params.noSharedAccess != FeatureState.enabled || sc.intypeof || sc.flags & SCOPE.ctfe) { diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index bcae282..3b0b34e 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -182,7 +182,7 @@ public: catches.push(ctch); Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches); - fd.flags &= ~FUNCFLAG.noEH; + fd.hasNoEH = false; replaceCurrent(s2); s2.accept(this); } @@ -191,31 +191,31 @@ public: } } -enum FUNCFLAG : uint +private struct FUNCFLAG { - purityInprocess = 1, /// working on determining purity - safetyInprocess = 2, /// working on determining safety - nothrowInprocess = 4, /// working on determining nothrow - nogcInprocess = 8, /// working on determining @nogc - returnInprocess = 0x10, /// working on inferring 'return' for parameters - inlineScanned = 0x20, /// function has been scanned for inline possibilities - inferScope = 0x40, /// infer 'scope' for parameters - hasCatches = 0x80, /// function has try-catch statements - compileTimeOnly = 0x100, /// is a compile time only function; no code will be generated for it - 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) + bool purityInprocess; /// working on determining purity + bool safetyInprocess; /// working on determining safety + bool nothrowInprocess; /// working on determining nothrow + bool nogcInprocess; /// working on determining @nogc + bool returnInprocess; /// working on inferring 'return' for parameters + bool inlineScanned; /// function has been scanned for inline possibilities + bool inferScope; /// infer 'scope' for parameters + bool hasCatches; /// function has try-catch statements + bool isCompileTimeOnly; /// is a compile time only function; no code will be generated for it + bool printf; /// is a printf-like function + bool scanf; /// is a scanf-like function + bool noreturn; /// the function does not return + bool isNRVO = true; /// Support for named return value optimization + bool isNaked; /// The function is 'naked' (see inline ASM) + bool isGenerated; /// The function is compiler generated (e.g. `opCmp`) + bool isIntroducing; /// If this function introduces the overload set + bool hasSemantic3Errors; /// If errors in semantic3 this function's frame ptr + bool hasNoEH; /// No exception unwinding is needed + bool inferRetType; /// Return type is to be inferred + bool hasDualContext; /// has a dual-context 'this' parameter + bool hasAlwaysInlines; /// Contains references to functions that must be inlined + bool isCrtCtor; /// Has attribute pragma(crt_constructor) + bool isCrtDtor; /// Has attribute pragma(crt_destructor) } /*********************************************************** @@ -348,9 +348,9 @@ extern (C++) class FuncDeclaration : Declaration /// better diagnostics AttributeViolation* safetyViolation; - /// Function flags: A collection of boolean packed for memory efficiency - /// See the `FUNCFLAG` enum - uint flags = FUNCFLAG.NRVO; + /// See the `FUNCFLAG` struct + import dmd.common.bitfields; + mixin(generateBitFields!(FUNCFLAG, uint)); /** * Data for a function declaration that is needed for the Objective-C @@ -373,13 +373,13 @@ extern (C++) class FuncDeclaration : Declaration } this.endloc = endloc; if (noreturn) - this.flags |= FUNCFLAG.noreturn; + this.noreturn = true; /* The type given for "infer the return type" is a TypeFunction with * NULL for the return type. */ if (type && type.nextOf() is null) - this.flags |= FUNCFLAG.inferRetType; + this.inferRetType = true; } static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false) @@ -391,7 +391,7 @@ extern (C++) class FuncDeclaration : Declaration { //printf("FuncDeclaration::syntaxCopy('%s')\n", toChars()); FuncDeclaration f = s ? cast(FuncDeclaration)s - : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy(), (flags & FUNCFLAG.noreturn) != 0); + : new FuncDeclaration(loc, endloc, ident, storage_class, type.syntaxCopy(), this.noreturn != 0); f.frequires = frequires ? Statement.arraySyntaxCopy(frequires) : null; f.fensures = fensures ? Ensure.arraySyntaxCopy(fensures) : null; f.fbody = fbody ? fbody.syntaxCopy() : null; @@ -522,7 +522,7 @@ extern (C++) class FuncDeclaration : Declaration { const bool dualCtx = (toParent2() != toParentLocal()); if (dualCtx) - this.flags |= FUNCFLAG.dualContext; + this.hasDualContext = true; auto ad = isThis(); if (!dualCtx && !ad && !isNested()) { @@ -1376,29 +1376,29 @@ extern (C++) class FuncDeclaration : Declaration //printf("initInferAttributes() for %s (%s)\n", toPrettyChars(), ident.toChars()); TypeFunction tf = type.toTypeFunction(); if (tf.purity == PURE.impure) // purity not specified - flags |= FUNCFLAG.purityInprocess; + purityInprocess = true; if (tf.trust == TRUST.default_) - flags |= FUNCFLAG.safetyInprocess; + safetyInprocess = true; if (!tf.isnothrow) - flags |= FUNCFLAG.nothrowInprocess; + nothrowInprocess = true; if (!tf.isnogc) - flags |= FUNCFLAG.nogcInprocess; + nogcInprocess = true; if (!isVirtual() || this.isIntroducing()) - flags |= FUNCFLAG.returnInprocess; + returnInprocess = true; // Initialize for inferring STC.scope_ - flags |= FUNCFLAG.inferScope; + inferScope = true; } final PURE isPure() { //printf("FuncDeclaration::isPure() '%s'\n", toChars()); TypeFunction tf = type.toTypeFunction(); - if (flags & FUNCFLAG.purityInprocess) + if (purityInprocess) setImpure(); if (tf.purity == PURE.fwdref) tf.purityLevel(); @@ -1424,7 +1424,7 @@ extern (C++) class FuncDeclaration : Declaration final PURE isPureBypassingInference() { - if (flags & FUNCFLAG.purityInprocess) + if (purityInprocess) return PURE.fwdref; else return isPure(); @@ -1437,9 +1437,9 @@ extern (C++) class FuncDeclaration : Declaration */ extern (D) final bool setImpure() { - if (flags & FUNCFLAG.purityInprocess) + if (purityInprocess) { - flags &= ~FUNCFLAG.purityInprocess; + purityInprocess = false; if (fes) fes.func.setImpure(); } @@ -1448,21 +1448,32 @@ extern (C++) class FuncDeclaration : Declaration return false; } + extern (D) final uint flags() + { + return bitFields; + } + + extern (D) final uint flags(uint f) + { + bitFields = f; + return bitFields; + } + final bool isSafe() { - if (flags & FUNCFLAG.safetyInprocess) + if (safetyInprocess) setUnsafe(); return type.toTypeFunction().trust == TRUST.safe; } final bool isSafeBypassingInference() { - return !(flags & FUNCFLAG.safetyInprocess) && isSafe(); + return !(safetyInprocess) && isSafe(); } final bool isTrusted() { - if (flags & FUNCFLAG.safetyInprocess) + if (safetyInprocess) setUnsafe(); return type.toTypeFunction().trust == TRUST.trusted; } @@ -1483,9 +1494,9 @@ extern (C++) class FuncDeclaration : Declaration bool gag = false, Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null) { - if (flags & FUNCFLAG.safetyInprocess) + if (safetyInprocess) { - flags &= ~FUNCFLAG.safetyInprocess; + safetyInprocess = false; type.toTypeFunction().trust = TRUST.system; if (fmt || arg0) safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1, arg2); @@ -1518,99 +1529,14 @@ extern (C++) class FuncDeclaration : Declaration final bool isNogc() { //printf("isNogc() %s, inprocess: %d\n", toChars(), !!(flags & FUNCFLAG.nogcInprocess)); - if (flags & FUNCFLAG.nogcInprocess) + if (nogcInprocess) setGC(); return type.toTypeFunction().isnogc; } final bool isNogcBypassingInference() { - 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 void isNaked(bool v) @safe pure nothrow @nogc - { - if (v) this.flags |= FUNCFLAG.naked; - else 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 void isCrtCtor(bool v) @safe pure nothrow @nogc - { - if (v) this.flags |= FUNCFLAG.CRTCtor; - else this.flags &= ~FUNCFLAG.CRTCtor; - } - - final bool isCrtDtor() const scope @safe pure nothrow @nogc - { - return !!(this.flags & FUNCFLAG.CRTDtor); - } - - final void isCrtDtor(bool v) @safe pure nothrow @nogc - { - if (v) this.flags |= FUNCFLAG.CRTDtor; - else this.flags &= ~FUNCFLAG.CRTDtor; + return !nogcInprocess && isNogc(); } /************************************** @@ -1622,15 +1548,15 @@ extern (C++) class FuncDeclaration : Declaration extern (D) final bool setGC() { //printf("setGC() %s\n", toChars()); - if (flags & FUNCFLAG.nogcInprocess && semanticRun < PASS.semantic3 && _scope) + if (nogcInprocess && semanticRun < PASS.semantic3 && _scope) { this.semantic2(_scope); this.semantic3(_scope); } - if (flags & FUNCFLAG.nogcInprocess) + if (nogcInprocess) { - flags &= ~FUNCFLAG.nogcInprocess; + nogcInprocess = false; type.toTypeFunction().isnogc = false; if (fes) fes.func.setGC(); @@ -3384,6 +3310,28 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, // re-resolve to check for supplemental message if (!global.gag || global.params.showGaggedErrors) { + if (tthis) + { + if (auto classType = tthis.isTypeClass()) + { + if (auto baseClass = classType.sym.baseClass) + { + if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident)) + { + MatchAccumulator mErr; + functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, fargs, null); + if (mErr.last > MATCH.nomatch && mErr.lastf) + { + errorSupplemental(loc, "%s `%s` hides base class function `%s`", + fd.kind, fd.toPrettyChars(), mErr.lastf.toPrettyChars()); + errorSupplemental(loc, "add `alias %s = %s` to `%s`'s body to merge the overload sets", + fd.toChars(), mErr.lastf.toPrettyChars(), tthis.toChars()); + return null; + } + } + } + } + } const(char)* failMessage; functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage); if (failMessage) @@ -3767,7 +3715,7 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration this.fes = fes; // Always infer scope for function literals // See https://issues.dlang.org/show_bug.cgi?id=20362 - this.flags |= FUNCFLAG.inferScope; + this.inferScope = true; //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars()); } @@ -4431,6 +4379,58 @@ bool setUnsafe(Scope* sc, return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2); } +/*************************************** + * Like `setUnsafe`, but for safety errors still behind preview switches + * + * Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables, + * the behavior changes based on the setting: + * + * - In case of `-revert=fs`, it does nothing. + * - In case of `-preview=fs`, it's the same as `setUnsafe` + * - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions. + * + * Params: + * sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope + * fs = feature state from the preview flag + * gag = surpress error message + * loc = location of error + * msg = printf-style format string + * arg0 = (optional) argument for first %s format specifier + * arg1 = (optional) argument for second %s format specifier + * arg2 = (optional) argument for third %s format specifier + * Returns: whether an actual safe error (not deprecation) occured + */ +bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg, + RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null) +{ + if (fs == FeatureState.disabled) + { + return false; + } + else if (fs == FeatureState.enabled) + { + return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2); + } + else + { + if (!sc.func) + return false; + if (sc.func.isSafeBypassingInference()) + { + if (!gag) + previewErrorFunc(sc.isDeprecated(), fs)( + loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "" + ); + } + else if (!sc.func.safetyViolation) + { + import dmd.func : AttributeViolation; + sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2); + } + return false; + } +} + /// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure` /// /// Has two modes: diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index 745d5eb..2770f5a 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -160,15 +160,16 @@ extern (C++) struct Param // https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a // https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html // Implementation: https://github.com/dlang/dmd/pull/9817 - bool noSharedAccess; // read/write access to shared memory objects + FeatureState noSharedAccess; // read/write access to shared memory objects bool previewIn; // `in` means `[ref] scope const`, accepts rvalues bool inclusiveInContracts; // 'in' contracts of overridden methods must be a superset of parent contract - bool shortenedMethods; // allow => in normal function declarations + bool shortenedMethods = true; // allow => in normal function declarations bool fixImmutableConv; // error on unsound immutable conversion - https://github.com/dlang/dmd/pull/14070 bool fix16997 = true; // fix integral promotions for unary + - ~ operators // https://issues.dlang.org/show_bug.cgi?id=16997 FeatureState dtorFields; // destruct fields of partially constructed objects // https://issues.dlang.org/show_bug.cgi?id=14246 + FeatureState systemVariables; // limit access to variables marked @system from @safe code CHECKENABLE useInvariants = CHECKENABLE._default; // generate class invariant checks CHECKENABLE useIn = CHECKENABLE._default; // generate precondition checks diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index a6b1c90..d9cb76c 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -158,7 +158,7 @@ struct Param // https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a // https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html // Implementation: https://github.com/dlang/dmd/pull/9817 - bool noSharedAccess; // read/write access to shared memory objects + FeatureState noSharedAccess; // read/write access to shared memory objects bool previewIn; // `in` means `[ref] scope const`, accepts rvalues bool inclusiveInContracts; // 'in' contracts of overridden methods must be a superset of parent contract bool shortenedMethods; // allow => in normal function declarations @@ -166,7 +166,9 @@ struct Param bool fix16997; // fix integral promotions for unary + - ~ operators // https://issues.dlang.org/show_bug.cgi?id=16997 FeatureState dtorFields; // destruct fields of partially constructed objects - // https://issues.dlang.org/show_bug.cgi?id=14246 + // https://issues.dlang.org/show_bug.cgi?id=14246 + FeatureState systemVariables; // limit access to variables marked @system from @safe code + CHECKENABLE useInvariants; // generate class invariant checks CHECKENABLE useIn; // generate precondition checks CHECKENABLE useOut; // generate postcondition checks diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 48995db..debf01d 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -64,6 +64,7 @@ struct HdrGenState int tpltMember; int autoMember; int forStmtInit; + int insideFuncBody; bool declstring; // set while declaring alias for string,wstring or dstring EnumDeclaration inEnumDecl; @@ -1045,8 +1046,18 @@ public: buf.writestring(", "); argsToBuffer(d.args, buf, hgs); } + buf.writeByte(')'); + + // https://issues.dlang.org/show_bug.cgi?id=14690 + // Unconditionally perform a full output dump + // for `pragma(inline)` declarations. + bool savedFullDump = global.params.dihdr.fullOutput; + if (d.ident == Id.Pinline) + global.params.dihdr.fullOutput = true; + visit(cast(AttribDeclaration)d); + global.params.dihdr.fullOutput = savedFullDump; } override void visit(ConditionalDeclaration d) @@ -1549,7 +1560,7 @@ public: bodyToBuffer(f); hgs.autoMember--; } - else if (hgs.tpltMember == 0 && global.params.dihdr.fullOutput == false) + else if (hgs.tpltMember == 0 && global.params.dihdr.fullOutput == false && !hgs.insideFuncBody) { if (!f.fbody) { @@ -1634,7 +1645,7 @@ public: void bodyToBuffer(FuncDeclaration f) { - if (!f.fbody || (hgs.hdrgen && global.params.dihdr.fullOutput == false && !hgs.autoMember && !hgs.tpltMember)) + if (!f.fbody || (hgs.hdrgen && global.params.dihdr.fullOutput == false && !hgs.autoMember && !hgs.tpltMember && !hgs.insideFuncBody)) { if (!f.fbody && (f.fensures || f.frequires)) { @@ -1645,6 +1656,18 @@ public: buf.writenl(); return; } + + // there is no way to know if a function is nested + // or not after parsing. We need scope information + // for that, which is avaible during semantic + // analysis. To overcome that, a simple mechanism + // is implemented: everytime we print a function + // body (templated or not) we increment a counter. + // We decredement the counter when we stop + // printing the function body. + ++hgs.insideFuncBody; + scope(exit) { --hgs.insideFuncBody; } + const savetlpt = hgs.tpltMember; const saveauto = hgs.autoMember; hgs.tpltMember = 0; diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index 1de89d4..451e227 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -1197,9 +1197,9 @@ class Lexer /******************************************* * Parse escape sequence. */ - private uint escapeSequence() + private uint escapeSequence(out dchar c2) { - return Lexer.escapeSequence(token.loc, p, Ccompile); + return Lexer.escapeSequence(token.loc, p, Ccompile, c2); } /******** @@ -1211,10 +1211,11 @@ class Lexer * sequence = pointer to string with escape sequence to parse. Updated to * point past the end of the escape sequence * Ccompile = true for compile C11 escape sequences + * c2 = returns second `dchar` of html entity with 2 code units, otherwise stays `dchar.init` * Returns: * the escape sequence as a single character */ - private dchar escapeSequence(const ref Loc loc, ref const(char)* sequence, bool Ccompile) + private dchar escapeSequence(const ref Loc loc, ref const(char)* sequence, bool Ccompile, out dchar c2) { const(char)* p = sequence; // cache sequence reference on stack scope(exit) sequence = p; @@ -1326,12 +1327,16 @@ class Lexer switch (*p) { case ';': - c = HtmlNamedEntity(idstart[0 .. p - idstart]); - if (c == ~0) + auto entity = HtmlNamedEntity(idstart[0 .. p - idstart]); + c = entity[0]; + if (entity == entity.init) { error(loc, "unnamed character entity &%.*s;", cast(int)(p - idstart), idstart); c = '?'; } + if (entity[1] != entity.init[1]) + c2 = entity[1]; + p++; break; default: @@ -1665,6 +1670,7 @@ class Lexer while (1) { dchar c = *p++; + dchar c2; switch (c) { case '\\': @@ -1673,15 +1679,19 @@ class Lexer case '&': if (Ccompile) goto default; - goto case; + c = escapeSequence(c2); + stringbuffer.writeUTF8(c); + if (c2 != dchar.init) + stringbuffer.writeUTF8(c2); + continue; case 'u': case 'U': - c = escapeSequence(); + c = escapeSequence(c2); stringbuffer.writeUTF8(c); continue; default: - c = escapeSequence(); + c = escapeSequence(c2); break; } break; @@ -1746,22 +1756,26 @@ class Lexer //printf("Lexer::charConstant\n"); p++; dchar c = *p++; + dchar c2; switch (c) { case '\\': switch (*p) { case 'u': - t.unsvalue = escapeSequence(); tk = TOK.wcharLiteral; - break; + goto default; case 'U': case '&': - t.unsvalue = escapeSequence(); tk = TOK.dcharLiteral; - break; + goto default; default: - t.unsvalue = escapeSequence(); + t.unsvalue = escapeSequence(c2); + if (c2 != c2.init) + { + error("html entity requires 2 code units, use a string instead of a character"); + t.unsvalue = '?'; + } break; } break; @@ -1978,8 +1992,6 @@ class Lexer break; case 'b': case 'B': - if (Ccompile) - error("binary constants not allowed"); ++p; base = 2; break; @@ -3185,8 +3197,9 @@ unittest static void test(T)(string sequence, T expected, bool Ccompile = false) { auto p = cast(const(char)*)sequence.ptr; + dchar c2; Lexer lexer = new Lexer(); - assert(expected == lexer.escapeSequence(Loc.initial, p, Ccompile)); + assert(expected == lexer.escapeSequence(Loc.initial, p, Ccompile, c2)); assert(p == sequence.ptr + sequence.length); } @@ -3253,7 +3266,8 @@ unittest expected = expectedError; auto p = cast(const(char)*)sequence.ptr; Lexer lexer = new Lexer(); - auto actualReturnValue = lexer.escapeSequence(Loc.initial, p, Ccompile); + dchar c2; + auto actualReturnValue = lexer.escapeSequence(Loc.initial, p, Ccompile, c2); assert(gotError); assert(expectedReturnValue == actualReturnValue); diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index 341ce36..48046de 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -116,7 +116,7 @@ public: size_t namelen; // length of module name in characters static Module* create(const char *arg, Identifier *ident, int doDocComment, int doHdrGen); - + static const char *find(const char *filename); static Module *load(const Loc &loc, Identifiers *packages, Identifier *ident); const char *kind() const override; diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 1240f5a..265f731c 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -2488,6 +2488,16 @@ extern (C++) abstract class Type : ASTNode return false; } + /************************************* + * Detect if this is an unsafe type because of the presence of `@system` members + * Returns: + * true if so + */ + bool hasSystemFields() + { + return false; + } + /*************************************** * Returns: true if type has any invariants */ @@ -3821,6 +3831,16 @@ extern (C++) final class TypeSArray : TypeArray return next.hasPointers(); } + override bool hasSystemFields() + { + return next.hasSystemFields(); + } + + override bool hasVoidInitPointers() + { + return next.hasVoidInitPointers(); + } + override bool hasInvariant() { return next.hasInvariant(); @@ -5532,52 +5552,32 @@ extern (C++) final class TypeStruct : Type override bool hasPointers() { - // Probably should cache this information in sym rather than recompute - StructDeclaration s = sym; - if (sym.members && !sym.determineFields() && sym.type != Type.terror) error(sym.loc, "no size because of forward references"); - foreach (VarDeclaration v; s.fields) - { - if (v.storage_class & STC.ref_ || v.hasPointers()) - return true; - } - return false; + sym.determineTypeProperties(); + return sym.hasPointerField; } override bool hasVoidInitPointers() { - // Probably should cache this information in sym rather than recompute - StructDeclaration s = sym; + sym.size(Loc.initial); // give error for forward references + sym.determineTypeProperties(); + return sym.hasVoidInitPointers; + } + override bool hasSystemFields() + { sym.size(Loc.initial); // give error for forward references - foreach (VarDeclaration v; s.fields) - { - if (v._init && v._init.isVoidInitializer() && v.type.hasPointers()) - return true; - if (!v._init && v.type.hasVoidInitPointers()) - return true; - } - return false; + sym.determineTypeProperties(); + return sym.hasSystemFields; } override bool hasInvariant() { - // Probably should cache this information in sym rather than recompute - StructDeclaration s = sym; - sym.size(Loc.initial); // give error for forward references - - if (s.hasInvariant()) - return true; - - foreach (VarDeclaration v; s.fields) - { - if (v.type.hasInvariant()) - return true; - } - return false; + sym.determineTypeProperties(); + return sym.hasInvariant() || sym.hasFieldWithInvariant; } extern (D) MATCH implicitConvToWithoutAliasThis(Type to) @@ -5857,6 +5857,11 @@ extern (C++) final class TypeEnum : Type return memType().hasVoidInitPointers(); } + override bool hasSystemFields() + { + return memType().hasSystemFields(); + } + override bool hasInvariant() { return memType().hasInvariant(); diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index 2b9c94c..c81c25a 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -311,6 +311,7 @@ public: virtual int hasWild() const; virtual bool hasPointers(); virtual bool hasVoidInitPointers(); + virtual bool hasSystemFields(); virtual bool hasInvariant(); virtual Type *nextOf(); Type *baseElemOf(); @@ -458,6 +459,8 @@ public: MATCH implicitConvTo(Type *to) override; Expression *defaultInitLiteral(const Loc &loc) override; bool hasPointers() override; + bool hasSystemFields() override; + bool hasVoidInitPointers() override; bool hasInvariant() override; bool needsDestruction() override; bool needsCopyOrPostblit() override; @@ -794,6 +797,7 @@ public: bool needsNested() override; bool hasPointers() override; bool hasVoidInitPointers() override; + bool hasSystemFields() override; bool hasInvariant() override; MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; @@ -832,6 +836,7 @@ public: bool isZeroInit(const Loc &loc) override; bool hasPointers() override; bool hasVoidInitPointers() override; + bool hasSystemFields() override; bool hasInvariant() override; Type *nextOf() override; diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index 8cf3585..7ddeeec 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/dmd/nogc.d @@ -99,7 +99,7 @@ public: override void visit(ArrayLiteralExp e) { - if (e.type.ty != Tarray || !e.elements || !e.elements.dim) + if (e.type.ty != Tarray || !e.elements || !e.elements.dim || e.onstack) return; if (f.setGC()) { @@ -221,7 +221,7 @@ Expression checkGC(Scope* sc, Expression e) FuncDeclaration f = sc.func; if (e && e.op != EXP.error && f && sc.intypeof != 1 && !(sc.flags & SCOPE.ctfe) && (f.type.ty == Tfunction && - (cast(TypeFunction)f.type).isnogc || (f.flags & FUNCFLAG.nogcInprocess) || global.params.vgc) && + (cast(TypeFunction)f.type).isnogc || f.nogcInprocess || global.params.vgc) && !(sc.flags & SCOPE.debug_)) { scope NOGCVisitor gcv = new NOGCVisitor(f); diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index ed85a5d..6fb542f 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -888,6 +888,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer error("redundant visibility attribute `%s`", AST.visibilityToChars(prot)); } pAttrs.visibility.kind = prot; + const attrloc = token.loc; nextToken(); @@ -908,7 +909,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } } - const attrloc = token.loc; a = parseBlock(pLastDecl, pAttrs); if (pAttrs.visibility.kind != AST.Visibility.Kind.undefined) { @@ -3168,9 +3168,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (udas) { - auto s = new AST.Dsymbols(); - s.push(em); - auto uad = new AST.UserAttributeDeclaration(udas, s); + auto uad = new AST.UserAttributeDeclaration(udas, new AST.Dsymbols()); em.userAttribDecl = uad; } diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d index bba3481..8c71a1a 100644 --- a/gcc/d/dmd/printast.d +++ b/gcc/d/dmd/printast.d @@ -203,6 +203,13 @@ extern (C++) final class PrintASTVisitor : Visitor printf(".func: %s\n", e.func ? e.func.toChars() : ""); } + override void visit(CompoundLiteralExp e) + { + visit(cast(Expression)e); + printIndent(indent + 2); + printf(".init: %s\n", e.initializer ? e.initializer.toChars() : ""); + } + static void printIndent(int indent) { foreach (i; 0 .. indent) diff --git a/gcc/d/dmd/root/utf.d b/gcc/d/dmd/root/utf.d index 15838e9..eb198fc 100644 --- a/gcc/d/dmd/root/utf.d +++ b/gcc/d/dmd/root/utf.d @@ -288,7 +288,7 @@ bool isUniAlpha(dchar c) // Binary search while (low <= high) { - size_t mid = (low + high) >> 1; + const size_t mid = low + ((high - low) >> 1); if (c < ALPHA_TABLE[mid][0]) high = mid - 1; else if (ALPHA_TABLE[mid][1] < c) diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d index 4446b5e..397fd2ef 100644 --- a/gcc/d/dmd/safe.d +++ b/gcc/d/dmd/safe.d @@ -26,7 +26,7 @@ import dmd.identifier; import dmd.mtype; import dmd.target; import dmd.tokens; -import dmd.func : setUnsafe; +import dmd.func : setUnsafe, setUnsafePreview; /************************************************************* * Check for unsafe access in @safe code: @@ -57,6 +57,14 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg) if (!ad) return false; + import dmd.globals : global; + if (v.isSystem()) + { + if (sc.setUnsafePreview(global.params.systemVariables, !printmsg, e.loc, + "cannot access `@system` field `%s.%s` in `@safe` code", ad, v)) + return true; + } + // needed to set v.overlapped and v.overlapUnsafe if (ad.sizeok != Sizeok.done) ad.determineSize(ad.loc); diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index d2f9c0a..8ea419a 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -282,7 +282,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.flags &= ~FUNCFLAG.semantic3Errors; + funcdecl.hasSemantic3Errors = false; } return; } @@ -292,7 +292,7 @@ private extern(C++) final class Semantic3Visitor : Visitor if (funcdecl.semanticRun >= PASS.semantic3) return; funcdecl.semanticRun = PASS.semantic3; - funcdecl.flags &= ~FUNCFLAG.semantic3Errors; + funcdecl.hasSemantic3Errors = false; if (!funcdecl.type || funcdecl.type.ty != Tfunction) return; @@ -650,7 +650,7 @@ private extern(C++) final class Semantic3Visitor : Visitor // handle NRVO if (!target.isReturnOnStack(f, funcdecl.needThis()) || !funcdecl.checkNRVO()) - funcdecl.flags &= ~FUNCFLAG.NRVO; + funcdecl.isNRVO = false; if (funcdecl.fbody.isErrorStatement()) { @@ -753,15 +753,15 @@ private extern(C++) final class Semantic3Visitor : Visitor if (f.isnothrow && blockexit & BE.throw_) error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars()); - if (!(blockexit & (BE.throw_ | BE.halt) || funcdecl.flags & FUNCFLAG.hasCatches)) + if (!(blockexit & (BE.throw_ | BE.halt) || funcdecl.hasCatches)) { /* Don't generate unwind tables for this function * https://issues.dlang.org/show_bug.cgi?id=17997 */ - funcdecl.flags |= FUNCFLAG.noEH; + funcdecl.hasNoEH = true; } - if (funcdecl.flags & FUNCFLAG.nothrowInprocess) + if (funcdecl.nothrowInprocess) { if (funcdecl.type == f) f = cast(TypeFunction)f.copy(); @@ -976,7 +976,7 @@ private extern(C++) final class Semantic3Visitor : Visitor /* Do the semantic analysis on the [in] preconditions and * [out] postconditions. */ - immutable bool isnothrow = f.isnothrow && !(funcdecl.flags & FUNCFLAG.nothrowInprocess); + immutable bool isnothrow = f.isnothrow && !funcdecl.nothrowInprocess; if (freq) { /* frequire is composed of the [in] contracts @@ -1001,11 +1001,11 @@ private extern(C++) final class Semantic3Visitor : Visitor // Deprecated in 2.101, can be made an error in 2.111 deprecation(funcdecl.loc, "`%s`: `in` contract may throw but function is marked as `nothrow`", funcdecl.toPrettyChars()); - else if (funcdecl.flags & FUNCFLAG.nothrowInprocess) + else if (funcdecl.nothrowInprocess) f.isnothrow = false; } - funcdecl.flags &= ~FUNCFLAG.noEH; + funcdecl.hasNoEH = false; sc2 = sc2.pop(); @@ -1048,11 +1048,11 @@ private extern(C++) final class Semantic3Visitor : Visitor // Deprecated in 2.101, can be made an error in 2.111 deprecation(funcdecl.loc, "`%s`: `out` contract may throw but function is marked as `nothrow`", funcdecl.toPrettyChars()); - else if (funcdecl.flags & FUNCFLAG.nothrowInprocess) + else if (funcdecl.nothrowInprocess) f.isnothrow = false; } - funcdecl.flags &= ~FUNCFLAG.noEH; + funcdecl.hasNoEH = false; sc2 = sc2.pop(); @@ -1180,10 +1180,10 @@ private extern(C++) final class Semantic3Visitor : Visitor const blockexit = s.blockExit(funcdecl, isnothrow); if (blockexit & BE.throw_) { - funcdecl.flags &= ~FUNCFLAG.noEH; + funcdecl.hasNoEH = false; if (isnothrow) error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars()); - else if (funcdecl.flags & FUNCFLAG.nothrowInprocess) + else if (funcdecl.nothrowInprocess) f.isnothrow = false; } @@ -1195,7 +1195,7 @@ private extern(C++) final class Semantic3Visitor : Visitor } } // from this point on all possible 'throwers' are checked - funcdecl.flags &= ~FUNCFLAG.nothrowInprocess; + funcdecl.nothrowInprocess = false; if (funcdecl.isSynchronized()) { @@ -1274,25 +1274,25 @@ private extern(C++) final class Semantic3Visitor : Visitor /* If function survived being marked as impure, then it is pure */ - if (funcdecl.flags & FUNCFLAG.purityInprocess) + if (funcdecl.purityInprocess) { - funcdecl.flags &= ~FUNCFLAG.purityInprocess; + funcdecl.purityInprocess = false; if (funcdecl.type == f) f = cast(TypeFunction)f.copy(); f.purity = PURE.fwdref; } - if (funcdecl.flags & FUNCFLAG.safetyInprocess) + if (funcdecl.safetyInprocess) { - funcdecl.flags &= ~FUNCFLAG.safetyInprocess; + funcdecl.safetyInprocess = false; if (funcdecl.type == f) f = cast(TypeFunction)f.copy(); f.trust = TRUST.safe; } - if (funcdecl.flags & FUNCFLAG.nogcInprocess) + if (funcdecl.nogcInprocess) { - funcdecl.flags &= ~FUNCFLAG.nogcInprocess; + funcdecl.nogcInprocess = false; if (funcdecl.type == f) f = cast(TypeFunction)f.copy(); f.isnogc = true; @@ -1395,9 +1395,9 @@ private extern(C++) final class Semantic3Visitor : Visitor */ funcdecl.semanticRun = PASS.semantic3done; if ((global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement())) - funcdecl.flags |= FUNCFLAG.semantic3Errors; + funcdecl.hasSemantic3Errors = true; else - funcdecl.flags &= ~FUNCFLAG.semantic3Errors; + funcdecl.hasSemantic3Errors = false; if (funcdecl.type.ty == Terror) funcdecl.errors = true; //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", funcdecl.parent.toChars(), funcdecl.toChars(), sc, funcdecl.loc.toChars()); diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index e5e5753..4f9baf8 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -2010,32 +2010,8 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor //printf("body = %p\n", ps._body); if (ps.ident == Id.msg) { - if (ps.args) - { - foreach (arg; *ps.args) - { - sc = sc.startCTFE(); - auto e = arg.expressionSemantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); - - // pragma(msg) is allowed to contain types as well as expressions - e = ctfeInterpretForPragmaMsg(e); - if (e.op == EXP.error) - { - errorSupplemental(ps.loc, "while evaluating `pragma(msg, %s)`", arg.toChars()); - return setError(); - } - if (auto se = e.toStringExp()) - { - const slice = se.toUTF8(sc).peekString(); - fprintf(stderr, "%.*s", cast(int)slice.length, slice.ptr); - } - else - fprintf(stderr, "%s", e.toChars()); - } - fprintf(stderr, "\n"); - } + if (!pragmaMsgSemantic(ps.loc, sc, ps.args)) + return setError(); } else if (ps.ident == Id.lib) { @@ -2075,75 +2051,19 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor } else if (ps.ident == Id.startaddress) { - if (!ps.args || ps.args.dim != 1) - ps.error("function name expected for start address"); - else - { - Expression e = (*ps.args)[0]; - sc = sc.startCTFE(); - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); - - e = e.ctfeInterpret(); - (*ps.args)[0] = e; - Dsymbol sa = getDsymbol(e); - if (!sa || !sa.isFuncDeclaration()) - { - ps.error("function name expected for start address, not `%s`", e.toChars()); - return setError(); - } - if (ps._body) - { - ps._body = ps._body.statementSemantic(sc); - if (ps._body.isErrorStatement()) - { - result = ps._body; - return; - } - } - result = ps; - return; - } + if (!pragmaStartAddressSemantic(ps.loc, sc, ps.args)) + return setError(); } else if (ps.ident == Id.Pinline) { - PINLINE inlining = PINLINE.default_; - if (!ps.args || ps.args.dim == 0) - inlining = PINLINE.default_; - else if (!ps.args || ps.args.dim != 1) + if (auto fd = sc.func) { - ps.error("boolean expression expected for `pragma(inline)`"); - return setError(); + fd.inlining = evalPragmaInline(ps.loc, sc, ps.args); } else { - Expression e = (*ps.args)[0]; - sc = sc.startCTFE(); - e = e.expressionSemantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); - e = e.ctfeInterpret(); - e = e.toBoolean(sc); - if (e.isErrorExp()) - { - ps.error("pragma(`inline`, `true` or `false`) expected, not `%s`", (*ps.args)[0].toChars()); - return setError(); - } - - const opt = e.toBool(); - if (opt.hasValue(true)) - inlining = PINLINE.always; - else if (opt.hasValue(false)) - inlining = PINLINE.never; - - FuncDeclaration fd = sc.func; - if (!fd) - { - ps.error("`pragma(inline)` is not inside a function"); - return setError(); - } - fd.inlining = inlining; + ps.error("`pragma(inline)` is not inside a function"); + return setError(); } } else if (!global.params.ignoreUnsupportedPragmas) @@ -2932,13 +2852,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor } // https://issues.dlang.org/show_bug.cgi?id=23063 - if (texp.isTypeNoreturn() && !rs.exp.isAssertExp() && !rs.exp.isThrowExp() && !rs.exp.isCallExp()) - { - auto msg = new StringExp(rs.exp.loc, "Accessed expression of type `noreturn`"); - msg.type = Type.tstring; - rs.exp = new AssertExp(rs.loc, IntegerExp.literal!0, msg); - rs.exp.type = texp; - } + rs.exp = checkNoreturnVarAccess(rs.exp); // @@@DEPRECATED_2.111@@@ const olderrors = global.startGagging(); @@ -3022,7 +2936,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor // If we previously assumed the function could be ref when // checking for `shared`, make sure we were right - if (global.params.noSharedAccess && rs.exp.type.isShared()) + if (global.params.noSharedAccess == FeatureState.enabled && rs.exp.type.isShared()) { fd.error("function returns `shared` but cannot be inferred `ref`"); supplemental(); @@ -3648,7 +3562,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor if (sc.func) { - sc.func.flags |= FUNCFLAG.hasCatches; + sc.func.hasCatches = true; if (flags == (FLAGcpp | FLAGd)) { tcs.error("cannot mix catching D and C++ exceptions in the same try-catch"); @@ -4925,3 +4839,83 @@ private void debugThrowWalker(Statement s) scope walker = new DebugWalker(); s.accept(walker); } + +/*********************************************************** + * Evaluate and print a `pragma(msg, args)` + * + * Params: + * loc = location for error messages + * sc = scope for argument interpretation + * args = expressions to print + * Returns: + * `true` on success + */ +bool pragmaMsgSemantic(Loc loc, Scope* sc, Expressions* args) +{ + if (!args) + return true; + foreach (arg; *args) + { + sc = sc.startCTFE(); + auto e = arg.expressionSemantic(sc); + e = resolveProperties(sc, e); + sc = sc.endCTFE(); + + // pragma(msg) is allowed to contain types as well as expressions + e = ctfeInterpretForPragmaMsg(e); + if (e.op == EXP.error) + { + errorSupplemental(loc, "while evaluating `pragma(msg, %s)`", arg.toChars()); + return false; + } + if (auto se = e.toStringExp()) + { + const slice = se.toUTF8(sc).peekString(); + fprintf(stderr, "%.*s", cast(int)slice.length, slice.ptr); + } + else + fprintf(stderr, "%s", e.toChars()); + } + fprintf(stderr, "\n"); + return true; +} + +/*********************************************************** + * Evaluate `pragma(startAddress, func)` and store the resolved symbol in `args` + * + * Params: + * loc = location for error messages + * sc = scope for argument interpretation + * args = pragma arguments + * Returns: + * `true` on success + */ +bool pragmaStartAddressSemantic(Loc loc, Scope* sc, Expressions* args) +{ + if (!args || args.dim != 1) + { + .error(loc, "function name expected for start address"); + return false; + } + else + { + /* https://issues.dlang.org/show_bug.cgi?id=11980 + * resolveProperties and ctfeInterpret call are not necessary. + */ + Expression e = (*args)[0]; + sc = sc.startCTFE(); + e = e.expressionSemantic(sc); + // e = resolveProperties(sc, e); + sc = sc.endCTFE(); + + // e = e.ctfeInterpret(); + (*args)[0] = e; + Dsymbol sa = getDsymbol(e); + if (!sa || !sa.isFuncDeclaration()) + { + .error(loc, "function name expected for start address, not `%s`", e.toChars()); + return false; + } + } + return true; +} diff --git a/gcc/d/dmd/templateparamsem.d b/gcc/d/dmd/templateparamsem.d index e093260..e79a9ec 100644 --- a/gcc/d/dmd/templateparamsem.d +++ b/gcc/d/dmd/templateparamsem.d @@ -73,6 +73,15 @@ private extern (C++) final class TemplateParameterSemanticVisitor : Visitor result = !(ttp.specType && isError(ttp.specType)); } + override void visit(TemplateThisParameter ttp) + { + import dmd.errors; + + if (!sc.getStructClassScope()) + error(ttp.loc, "cannot use `this` outside an aggregate type"); + visit(cast(TemplateTypeParameter)ttp); + } + override void visit(TemplateValueParameter tvp) { tvp.valType = tvp.valType.typeSemantic(tvp.loc, sc); diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d index 0d7240f..cbe6daa 100644 --- a/gcc/d/dmd/transitivevisitor.d +++ b/gcc/d/dmd/transitivevisitor.d @@ -799,6 +799,15 @@ package mixin template ParseVisitMethods(AST) s.accept(this); } + override void visit(AST.InterfaceDeclaration d) + { + //printf("Visiting InterfaceDeclaration\n"); + visitBaseClasses(d); + if (d.members) + foreach (s; *d.members) + s.accept(this); + } + override void visit(AST.AliasDeclaration d) { //printf("Visting AliasDeclaration\n"); diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index fa5ec90..e939e77 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -1099,6 +1099,7 @@ public: this assignment should call dtors on old assigned elements. */ if ((!postblit && !destructor) || (e->op == EXP::construct && e->e2->op == EXP::arrayLiteral) + || (e->op == EXP::construct && e->e2->op == EXP::call) || (e->op == EXP::construct && !lvalue && postblit) || (e->op == EXP::blit || e->e1->type->size () == 0)) { @@ -2704,6 +2705,14 @@ public: this->result_ = compound_expr (saved_elems, d_convert (type, ctor)); } + else if (e->onstack) + { + /* Array literal for a `scope' dynamic array. */ + gcc_assert (tb->ty == TY::Tarray); + ctor = force_target_expr (ctor); + this->result_ = d_array_value (type, size_int (e->elements->length), + build_address (ctor)); + } else { /* Allocate space on the memory managed heap. */ diff --git a/gcc/d/gdc.texi b/gcc/d/gdc.texi index 2bff627..d3bf75c 100644 --- a/gcc/d/gdc.texi +++ b/gcc/d/gdc.texi @@ -344,6 +344,9 @@ Turns on generation of struct equality to use field-wise comparisons. @item fixaliasthis Implements new lookup rules that check the current scope for @code{alias this} before searching in upper scopes. +@item fiximmutableconv +Disallows unsound immutable conversions that were formerly incorrectly +permitted. @item in Implements @code{in} parameters to mean @code{scope const [ref]} and accepts rvalues. @@ -357,9 +360,8 @@ expressions. Turns off and disallows all access to shared memory objects. @item rvaluerefparam Implements rvalue arguments to @code{ref} parameters. -@item shortenedmethods -Implements use of @code{=>} for methods and top-level functions in addition to -lambdas. +@item systemvariables +Disables access to variables marked @code{@@system} from @code{@@safe} code. @end table @item -frelease diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt index da65239..15ab725 100644 --- a/gcc/d/lang.opt +++ b/gcc/d/lang.opt @@ -396,9 +396,9 @@ fpreview=rvaluerefparam D RejectNegative Enable rvalue arguments to ref parameters. -fpreview=shortenedmethods +fpreview=systemvariables D RejectNegative -Allow use of '=>' for methods and top-level functions in addition to lambdas. +Disable access to variables marked `@system' from @safe code. frelease D -- cgit v1.1