diff --git a/ddmd/access.d b/ddmd/access.d index 0d760b13fc..e7d460ba33 100644 --- a/ddmd/access.d +++ b/ddmd/access.d @@ -228,10 +228,15 @@ extern (C++) bool isFriendOf(AggregateDeclaration ad, AggregateDeclaration cd) * Determine if scope sc has package level access to s. */ extern (C++) bool hasPackageAccess(Scope* sc, Dsymbol s) +{ + return hasPackageAccess(sc._module, s); +} + +extern (C++) bool hasPackageAccess(Module mod, Dsymbol s) { static if (LOG) { - printf("hasPackageAccess(s = '%s', sc = '%p', s->protection.pkg = '%s')\n", s.toChars(), sc, s.prot().pkg ? s.prot().pkg.toChars() : "NULL"); + printf("hasPackageAccess(s = '%s', mod = '%s', s->protection.pkg = '%s')\n", s.toChars(), mod.toChars(), s.prot().pkg ? s.prot().pkg.toChars() : "NULL"); } Package pkg = null; if (s.prot().pkg) @@ -265,7 +270,7 @@ extern (C++) bool hasPackageAccess(Scope* sc, Dsymbol s) } if (pkg) { - if (pkg == sc._module.parent) + if (pkg == mod.parent) { static if (LOG) { @@ -273,7 +278,7 @@ extern (C++) bool hasPackageAccess(Scope* sc, Dsymbol s) } return true; } - if (pkg.isPackageMod() == sc._module) + if (pkg.isPackageMod() == mod) { static if (LOG) { @@ -281,7 +286,7 @@ extern (C++) bool hasPackageAccess(Scope* sc, Dsymbol s) } return true; } - Dsymbol ancestor = sc._module.parent; + Dsymbol ancestor = mod.parent; for (; ancestor; ancestor = ancestor.parent) { if (ancestor == pkg) @@ -301,6 +306,25 @@ extern (C++) bool hasPackageAccess(Scope* sc, Dsymbol s) return false; } +/**************************************** + * Determine if scope sc has protected level access to cd. + */ +bool hasProtectedAccess(Scope *sc, Dsymbol s) +{ + if (auto cd = s.isClassMember()) // also includes interfaces + { + for (auto scx = sc; scx; scx = scx.enclosing) + { + if (!scx.scopesym) + continue; + auto cd2 = scx.scopesym.isClassDeclaration(); + if (cd2 && cd.isBaseOf(cd2, null)) + return true; + } + } + return sc._module == s.getAccessModule(); +} + /********************************** * Determine if smember has access to private members of this declaration. */ @@ -393,7 +417,7 @@ extern (C++) bool checkAccess(Loc loc, Scope* sc, Expression e, Declaration d) else if (e.type.ty == Tclass) { // Do access check - ClassDeclaration cd = cast(ClassDeclaration)(cast(TypeClass)e.type).sym; + ClassDeclaration cd = (cast(TypeClass)e.type).sym; if (e.op == TOKsuper) { ClassDeclaration cd2 = sc.func.toParent().isClassDeclaration(); @@ -405,8 +429,112 @@ extern (C++) bool checkAccess(Loc loc, Scope* sc, Expression e, Declaration d) else if (e.type.ty == Tstruct) { // Do access check - StructDeclaration cd = cast(StructDeclaration)(cast(TypeStruct)e.type).sym; + StructDeclaration cd = (cast(TypeStruct)e.type).sym; return checkAccess(cd, loc, sc, d); } return false; } + +/**************************************** + * Check access to package/module `p` from scope `sc`. + * + * Params: + * loc = source location for issued error message + * sc = scope from which to access to a fully qualified package name + * p = the package/module to check access for + * Returns: true if the package is not accessible. + * + * Because a global symbol table tree is used for imported packages/modules, + * access to them needs to be checked based on the imports in the scope chain + * (see Bugzilla 313). + * + */ +extern (C++) bool checkAccess(Loc loc, Scope* sc, Package p) +{ + if (sc._module == p) + return false; + for (; sc; sc = sc.enclosing) + { + if (sc.scopesym && sc.scopesym.isPackageAccessible(p)) + return false; + } + auto name = p.toPrettyChars(); + if (p.isPkgMod == PKGmodule || p.isModule()) + deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'", p.kind(), name, name); + else + deprecation(loc, "%s %s is not accessible here", p.kind(), name); + return true; +} + +/** + * Check whether symbols `s` is visible in `mod`. + * + * Params: + * mod = lookup origin + * s = symbol to check for visibility + * Returns: true if s is visible in mod + */ +extern (C++) bool symbolIsVisible(Module mod, Dsymbol s) +{ + // should sort overloads by ascending protection instead of iterating here + if (s.isOverloadable()) + { + // Use the least protected overload to determine visibility + // and perform an access check after overload resolution. + overloadApply(s, (s2) { + if (s.prot().isMoreRestrictiveThan(s2.prot())) + s = s2; + return 0; + }); + } + final switch (s.prot().kind) + { + case PROTundefined: return true; + case PROTnone: return false; // no access + case PROTprivate: return s.getAccessModule() == mod; + case PROTpackage: return hasPackageAccess(mod, s); + case PROTprotected: return s.getAccessModule() == mod; + case PROTpublic, PROTexport: return true; + } +} + +/** + * Same as above, but determines the lookup module from symbols `origin`. + */ +extern (C++) bool symbolIsVisible(Dsymbol origin, Dsymbol s) +{ + return symbolIsVisible(origin.getAccessModule(), s); +} + +/** + * Same as above but also checks for protected symbols visible from scope `sc`. + * Used for qualified name lookup. + * + * Params: + * sc = lookup scope + * s = symbol to check for visibility + * Returns: true if s is visible by origin + */ +extern (C++) bool symbolIsVisible(Scope *sc, Dsymbol s) +{ + // should sort overloads by ascending protection instead of iterating here + if (s.isOverloadable()) + { + // Use the least protected overload to determine visibility + // and perform an access check after overload resolution. + overloadApply(s, (s2) { + if (s.prot().isMoreRestrictiveThan(s2.prot())) + s = s2; + return 0; + }); + } + final switch (s.prot().kind) + { + case PROTundefined: return true; + case PROTnone: return false; // no access + case PROTprivate: return sc._module == s.getAccessModule(); + case PROTpackage: return hasPackageAccess(sc._module, s); + case PROTprotected: return hasProtectedAccess(sc, s); + case PROTpublic, PROTexport: return true; + } +} diff --git a/ddmd/aggregate.d b/ddmd/aggregate.d index 8a33043181..07f8bd8179 100644 --- a/ddmd/aggregate.d +++ b/ddmd/aggregate.d @@ -122,7 +122,7 @@ public: override final void semantic2(Scope* sc) { - //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", toChars(), type->toChars(), errors); + //printf("AggregateDeclaration::semantic2(%s) type = %s, errors = %d\n", toChars(), type.toChars(), errors); if (!members) return; @@ -138,7 +138,7 @@ public: sc2.stc &= STCsafe | STCtrusted | STCsystem; sc2.parent = this; //if (isUnionDeclaration()) // TODO - // sc2->inunion = 1; + // sc2.inunion = 1; sc2.protection = Prot(PROTpublic); sc2.explicitProtection = 0; sc2.structalign = STRUCTALIGN_DEFAULT; @@ -147,7 +147,7 @@ public: for (size_t i = 0; i < members.dim; i++) { Dsymbol s = (*members)[i]; - //printf("\t[%d] %s\n", i, s->toChars()); + //printf("\t[%d] %s\n", i, s.toChars()); s.semantic2(sc2); } @@ -215,6 +215,8 @@ public: sd.semanticTypeInfoMembers(); } + abstract void finalizeSize(); + override final uint size(Loc loc) { //printf("AggregateDeclaration::size() %s, scope = %p\n", toChars(), scope); @@ -271,7 +273,7 @@ public: if (s.apply(&SV.func, &sv)) goto L1; } - finalizeSize(null); + finalizeSize(); L1: } @@ -288,8 +290,6 @@ public: return structsize; } - abstract void finalizeSize(Scope* sc); - /*************************************** * Calculate field[i].overlapped, and check that all of explicit * field initializers have unique memory space on instance. @@ -331,7 +331,7 @@ public: // vd and v2 are overlapping. If either has destructors, postblits, etc., then error //printf("overlapping fields %s and %s\n", vd->toChars(), v2->toChars()); - foreach (k; 0.. 2) + foreach (k; 0 .. 2) { auto v = k == 0 ? vd : v2; Type tv = v.type.baseElemOf(); @@ -608,6 +608,8 @@ public: return enclosing !is null; } + /* Append vthis field (this.tupleof[$-1]) to make this aggregate type nested. + */ final void makeNested() { if (enclosing) // if already nested @@ -620,19 +622,20 @@ public: return; // If nested struct, add in hidden 'this' pointer to outer scope - Dsymbol s = toParent2(); + auto s = toParent2(); if (!s) return; - AggregateDeclaration ad = s.isAggregateDeclaration(); - FuncDeclaration fd = s.isFuncDeclaration(); Type t = null; - if (fd) + if (auto fd = s.isFuncDeclaration()) { enclosing = fd; - AggregateDeclaration agg = fd.isMember2(); - t = agg ? agg.handleType() : Type.tvoidptr; + + /* Bugzilla 14422: If a nested class parent is a function, its + * context pointer (== `outer`) should be void* always. + */ + t = Type.tvoidptr; } - else if (ad) + else if (auto ad = s.isAggregateDeclaration()) { if (isClassDeclaration() && ad.isClassDeclaration()) { @@ -640,7 +643,7 @@ public: } else if (isStructDeclaration()) { - if (TemplateInstance ti = ad.parent.isTemplateInstance()) + if (auto ti = ad.parent.isTemplateInstance()) { enclosing = ti.enclosing; } @@ -649,7 +652,7 @@ public: } if (enclosing) { - //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing->toChars()); + //printf("makeNested %s, enclosing = %s\n", toChars(), enclosing.toChars()); assert(t); if (t.ty == Tstruct) t = Type.tvoidptr; // t should not be a ref type @@ -700,7 +703,7 @@ public: Symbol* stag; // tag symbol for debug data Symbol* sinit; - override final AggregateDeclaration isAggregateDeclaration() + override final inout(AggregateDeclaration) isAggregateDeclaration() inout { return this; } diff --git a/ddmd/aggregate.h b/ddmd/aggregate.h index 0d69f30ab5..d2908eb29d 100644 --- a/ddmd/aggregate.h +++ b/ddmd/aggregate.h @@ -115,8 +115,8 @@ public: void setScope(Scope *sc); void semantic2(Scope *sc); void semantic3(Scope *sc); + virtual void finalizeSize() = 0; unsigned size(Loc loc); - virtual void finalizeSize(Scope *sc) = 0; bool checkOverlappedFields(); bool fill(Loc loc, Expressions *elements, bool ctorinit); static void alignmember(structalign_t salign, unsigned size, unsigned *poffset); @@ -185,7 +185,7 @@ public: void semanticTypeInfoMembers(); Dsymbol *search(Loc, Identifier *ident, int flags = IgnoreNone); const char *kind(); - void finalizeSize(Scope *sc); + void finalizeSize(); bool fit(Loc loc, Scope *sc, Expressions *elements, Type *stype); bool isPOD(); @@ -251,6 +251,7 @@ public: static ClassDeclaration *throwable; static ClassDeclaration *exception; static ClassDeclaration *errorException; + static ClassDeclaration *cpp_type_info_ptr; ClassDeclaration *baseClass; // NULL only if this is Object FuncDeclaration *staticCtor; @@ -261,8 +262,7 @@ public: BaseClasses *baseclasses; // Array of BaseClass's; first is super, // rest are Interface's - size_t interfaces_dim; - BaseClass **interfaces; // interfaces[interfaces_dim] for this class + DArray interfaces; // interfaces[interfaces_dim] for this class // (does not include baseClass) BaseClasses *vtblInterfaces; // array of base interfaces that have @@ -276,6 +276,7 @@ public: int inuse; // to prevent recursive attempts Baseok baseok; // set the progress of base classes resolving Objc_ClassDeclaration objc; + Symbol *cpp_type_info_ptr_sym; // cached instance of class Id.cpp_type_info_ptr ClassDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses, bool inObject = false); Dsymbol *syntaxCopy(Dsymbol *s); @@ -288,17 +289,17 @@ public: bool isBaseInfoComplete(); Dsymbol *search(Loc, Identifier *ident, int flags = IgnoreNone); ClassDeclaration *searchBase(Loc, Identifier *ident); - void finalizeSize(Scope *sc); + void finalizeSize(); bool isFuncHidden(FuncDeclaration *fd); FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf); void interfaceSemantic(Scope *sc); unsigned setBaseInterfaceOffsets(unsigned baseOffset); - bool isCOMclass(); - virtual bool isCOMinterface(); - bool isCPPclass(); - virtual bool isCPPinterface(); + bool isCOMclass() const; + virtual bool isCOMinterface() const; + bool isCPPclass() const; + virtual bool isCPPinterface() const; bool isAbstract(); - virtual int vtblOffset(); + virtual int vtblOffset() const; const char *kind(); void addLocalClass(ClassDeclarations *); @@ -316,13 +317,12 @@ public: InterfaceDeclaration(Loc loc, Identifier *id, BaseClasses *baseclasses); Dsymbol *syntaxCopy(Dsymbol *s); void semantic(Scope *sc); - void finalizeSize(Scope *sc); bool isBaseOf(ClassDeclaration *cd, int *poffset); bool isBaseOf(BaseClass *bc, int *poffset); const char *kind(); - int vtblOffset(); - bool isCPPinterface(); - bool isCOMinterface(); + int vtblOffset() const; + bool isCPPinterface() const; + bool isCOMinterface() const; InterfaceDeclaration *isInterfaceDeclaration() { return this; } void accept(Visitor *v) { v->visit(this); } diff --git a/ddmd/aliasthis.d b/ddmd/aliasthis.d index 4d690f3eeb..1747db4514 100644 --- a/ddmd/aliasthis.d +++ b/ddmd/aliasthis.d @@ -98,7 +98,7 @@ public: ad.aliasthis = s; } - override const(char)* kind() + override const(char)* kind() const { return "alias this"; } diff --git a/ddmd/argtypes.d b/ddmd/argtypes.d index b8ca8ec70b..eedfd07b9b 100644 --- a/ddmd/argtypes.d +++ b/ddmd/argtypes.d @@ -18,7 +18,11 @@ import ddmd.visitor; * This breaks a type down into 'simpler' types that can be passed to a function * in registers, and returned in registers. * It's highly platform dependent. - * Returning a tuple of zero length means the type cannot be passed/returned in registers. + * Params: + * t = type to break down + * Returns: + * tuple of types, each element can be passed in a register. + * A tuple of zero length means the type cannot be passed/returned in registers. */ extern (C++) TypeTuple toArgTypes(Type t) { @@ -173,10 +177,16 @@ extern (C++) TypeTuple toArgTypes(Type t) /************************************* * This merges two types into an 8byte type. + * Params: + * t1 = first type (can be null) + * t2 = second type (can be null) + * offset2 = offset of t2 from start of t1 + * Returns: + * type that encompasses both t1 and t2, null if cannot be done */ static Type argtypemerge(Type t1, Type t2, uint offset2) { - //printf("argtypemerge(%s, %s, %d)\n", t1 ? t1->toChars() : "", t2 ? t2->toChars() : "", offset2); + //printf("argtypemerge(%s, %s, %d)\n", t1 ? t1.toChars() : "", t2 ? t2.toChars() : "", offset2); if (!t1) { assert(!t2 || offset2 == 0); @@ -217,14 +227,9 @@ extern (C++) TypeTuple toArgTypes(Type t) case 4: t = Type.tint32; break; - case 5: - case 6: - case 7: - case 8: + default: t = Type.tint64; break; - default: - assert(0); } } return t; @@ -270,7 +275,7 @@ extern (C++) TypeTuple toArgTypes(Type t) override void visit(TypeStruct t) { - //printf("TypeStruct::toArgTypes() %s\n", t->toChars()); + //printf("TypeStruct.toArgTypes() %s\n", t.toChars()); if (!t.sym.isPOD() || t.sym.fields.dim == 0) { Lmemory: @@ -293,6 +298,7 @@ extern (C++) TypeTuple toArgTypes(Type t) case 3: if (!global.params.is64bit) goto Lmemory; + goto case; case 4: t1 = Type.tint32; break; @@ -301,6 +307,7 @@ extern (C++) TypeTuple toArgTypes(Type t) case 7: if (!global.params.is64bit) goto Lmemory; + goto case; case 8: t1 = Type.tint64; break; @@ -329,7 +336,7 @@ extern (C++) TypeTuple toArgTypes(Type t) for (size_t i = 0; i < t.sym.fields.dim; i++) { VarDeclaration f = t.sym.fields[i]; - //printf("f->type = %s\n", f->type->toChars()); + //printf(" [%d] %s f.type = %s\n", cast(int)i, f.toChars(), f.type.toChars()); TypeTuple tup = toArgTypes(f.type); if (!tup) goto Lmemory; @@ -364,6 +371,8 @@ extern (C++) TypeTuple toArgTypes(Type t) } // First field in 8byte must be at start of 8byte assert(t1 || f.offset == 0); + //printf("ft1 = %s\n", ft1 ? ft1.toChars() : "null"); + //printf("ft2 = %s\n", ft2 ? ft2.toChars() : "null"); if (ft1) { t1 = argtypemerge(t1, ft1, f.offset); diff --git a/ddmd/arrayop.d b/ddmd/arrayop.d index ab20a87b12..4e5d1602cc 100644 --- a/ddmd/arrayop.d +++ b/ddmd/arrayop.d @@ -18,7 +18,6 @@ import ddmd.globals; import ddmd.id; import ddmd.identifier; import ddmd.mtype; -import ddmd.root.aav; import ddmd.root.outbuffer; import ddmd.statement; import ddmd.tokens; @@ -27,9 +26,9 @@ import ddmd.visitor; /************************************** * Hash table of array op functions already generated or known about. */ -version(IN_LLVM) {} -else -extern (C++) __gshared AA* arrayfuncs; +version(IN_LLVM) {} else +private __gshared FuncDeclaration[void*] arrayfuncs; + /************************************** * Structure to contain information needed to insert an array op call @@ -179,19 +178,19 @@ extern (C++) Expression arrayOp(BinExp e, Scope* sc) /* Append deco of array element type */ buf.writestring(e.type.toBasetype().nextOf().toBasetype().mutableOf().deco); - char* name = buf.peekString(); - Identifier ident = Identifier.idPool(name); + auto ident = Identifier.idPool(buf.peekSlice()); + version(IN_LLVM) { - FuncDeclaration* pFd = cast(FuncDeclaration*)dmd_aaGet(&(sc._module.arrayfuncs), cast(void*)ident); + auto arrayfuncs = sc._module.arrayfuncs; } + FuncDeclaration* pFd = cast(void*)ident in arrayfuncs; + FuncDeclaration fd; + if (pFd) + fd = *pFd; else - { - FuncDeclaration* pFd = cast(FuncDeclaration*)dmd_aaGet(&arrayfuncs, cast(void*)ident); - } - FuncDeclaration fd = *pFd; - if (!fd) fd = buildArrayOp(ident, e, sc, e.loc); + if (fd && fd.errors) { const(char)* fmt; @@ -204,7 +203,8 @@ extern (C++) Expression arrayOp(BinExp e, Scope* sc) e.error(fmt, e.toChars(), tbn.toChars()); return new ErrorExp(); } - *pFd = fd; + if (!pFd) + arrayfuncs[cast(void*)ident] = fd; Expression ev = new VarExp(e.loc, fd); Expression ec = new CallExp(e.loc, ev, arguments); return ec.semantic(sc); diff --git a/ddmd/attrib.d b/ddmd/attrib.d index 5d1ec89a0d..8d3982156d 100644 --- a/ddmd/attrib.d +++ b/ddmd/attrib.d @@ -228,7 +228,7 @@ public: } } - override const(char)* kind() + override const(char)* kind() const { return "attribute"; } @@ -310,7 +310,7 @@ public: } } - override final AttribDeclaration isAttribDeclaration() + override final inout(AttribDeclaration) isAttribDeclaration() inout { return this; } @@ -340,7 +340,7 @@ public: return new StorageClassDeclaration(stc, Dsymbol.arraySyntaxCopy(decl)); } - override final Scope* newScope(Scope* sc) + override Scope* newScope(Scope* sc) { StorageClass scstc = sc.stc; /* These sets of storage classes are mutually exclusive, @@ -400,6 +400,7 @@ extern (C++) final class DeprecatedDeclaration : StorageClassDeclaration { public: Expression msg; + const(char)* msgstr; extern (D) this(Expression msg, Dsymbols* decl) { @@ -413,19 +414,67 @@ public: return new DeprecatedDeclaration(msg.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl)); } + /** + * Provides a new scope with `STCdeprecated` and `Scope.depdecl` set + * + * Calls `StorageClassDeclaration.newScope` (as it must be called or copied + * in any function overriding `newScope`), then set the `Scope`'s depdecl. + * + * Returns: + * Always a new scope, to use for this `DeprecatedDeclaration`'s members. + */ + override Scope* newScope(Scope* sc) + { + auto scx = super.newScope(sc); + // The enclosing scope is deprecated as well + if (scx == sc) + scx = sc.push(); + scx.depdecl = this; + return scx; + } + override void setScope(Scope* sc) { - assert(msg); - char* depmsg = null; - StringExp se = msg.toStringExp(); - if (se) - depmsg = se.toStringz(); - else - msg.error("string expected, not '%s'", msg.toChars()); - Scope* scx = sc.push(); - scx.depmsg = depmsg; - StorageClassDeclaration.setScope(scx); - scx.pop(); + //printf("DeprecatedDeclaration::setScope() %p\n", this); + if (decl) + Dsymbol.setScope(sc); // for forward reference + return AttribDeclaration.setScope(sc); + } + + /** + * Run the DeprecatedDeclaration's semantic2 phase then its members. + * + * The message set via a `DeprecatedDeclaration` can be either of: + * - a string literal + * - an enum + * - a static immutable + * So we need to call ctfe to resolve it. + * Afterward forwards to the members' semantic2. + */ + override void semantic2(Scope* sc) + { + getMessage(); + super.semantic2(sc); + } + + const(char)* getMessage() + { + if (auto sc = _scope) + { + _scope = null; + + sc = sc.startCTFE(); + msg = msg.semantic(sc); + msg = resolveProperties(sc, msg); + sc = sc.endCTFE(); + msg = msg.ctfeInterpret(); + + if (auto se = msg.toStringExp()) + msgstr = se.toStringz(); + else + msg.error("compile time constant expected, not '%s'", msg.toChars()); + } + return msgstr; } override void accept(Visitor v) @@ -459,9 +508,9 @@ public: return createNewScope(sc, sc.stc, this.linkage, sc.protection, sc.explicitProtection, sc.structalign, sc.inlining); } - override char* toChars() + override const(char)* toChars() const { - return cast(char*)"extern ()"; + return "extern ()"; } override void accept(Visitor v) @@ -542,7 +591,7 @@ public: return AttribDeclaration.addMember(sc, sds); } - override const(char)* kind() + override const(char)* kind() const { return "protection attribute"; } @@ -690,27 +739,33 @@ public: anonstructsize = 1; anonalignsize = 1; } + /* Given the anon 'member's size and alignment, * go ahead and place it. */ - anonoffset = AggregateDeclaration.placeField(poffset, anonstructsize, anonalignsize, alignment, &ad.structsize, &ad.alignsize, isunion); + anonoffset = AggregateDeclaration.placeField( + poffset, + anonstructsize, anonalignsize, alignment, + &ad.structsize, &ad.alignsize, + isunion); + // Add to the anon fields the base offset of this anonymous aggregate //printf("anon fields, anonoffset = %d\n", anonoffset); for (size_t i = fieldstart; i < ad.fields.dim; i++) { VarDeclaration v = ad.fields[i]; - //printf("\t[%d] %s %d\n", i, v->toChars(), v->offset); + //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset); v.offset += anonoffset; } } } - override const(char)* kind() + override const(char)* kind() const { return (isunion ? "anonymous union" : "anonymous struct"); } - override final AnonDeclaration isAnonDeclaration() + override final inout(AnonDeclaration) isAnonDeclaration() inout { return this; } @@ -776,7 +831,7 @@ public: if (se) { se = se.toUTF8(sc); - fprintf(stderr, "%.*s", cast(int)se.len, cast(char*)se.string); + fprintf(stderr, "%.*s", cast(int)se.len, se.string); } else fprintf(stderr, "%s", e.toChars()); @@ -819,7 +874,7 @@ public: ob.writestring(" ("); escapePath(ob, imod.srcfile.toChars()); ob.writestring(") : "); - ob.writestring(cast(char*)name); + ob.writestring(name); ob.writenl(); } mem.xfree(name); @@ -893,8 +948,8 @@ public: */ for (size_t i = 0; i < se.len;) { - char* p = cast(char*)se.string; - dchar_t c = p[i]; + char* p = se.string; + dchar c = p[i]; if (c < 0x80) { if (c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9' || c != 0 && strchr("$%().:?@[]_", c)) @@ -908,7 +963,7 @@ public: break; } } - if (const(char)* msg = utf_decodeChar(cast(char*)se.string, se.len, &i, &c)) + if (const msg = utf_decodeChar(se.string, se.len, i, c)) { error("%s", msg); break; @@ -1045,7 +1100,7 @@ public: return sc; } - override const(char)* kind() + override const(char)* kind() const { return "pragma"; } @@ -1238,7 +1293,7 @@ public: Dsymbol.setScope(sc); } - override const(char)* kind() + override const(char)* kind() const { return "static if"; } @@ -1337,7 +1392,7 @@ public: AttribDeclaration.semantic(sc); } - override const(char)* kind() + override const(char)* kind() const { return "mixin"; } @@ -1433,9 +1488,8 @@ public: Expressions* getAttributes() { - if (_scope) + if (auto sc = _scope) { - Scope* sc = _scope; _scope = null; arrayExpressionSemantic(atts, sc); } @@ -1447,7 +1501,7 @@ public: return exps; } - override const(char)* kind() + override const(char)* kind() const { return "UserAttribute"; } diff --git a/ddmd/canthrow.d b/ddmd/canthrow.d index ccdcc194e0..c130b94d5d 100644 --- a/ddmd/canthrow.d +++ b/ddmd/canthrow.d @@ -8,6 +8,7 @@ module ddmd.canthrow; +import ddmd.aggregate; import ddmd.apply; import ddmd.arraytypes; import ddmd.attrib; @@ -64,50 +65,119 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow */ Type t = ce.e1.type.toBasetype(); if (ce.f && ce.f == func) + return; + if (t.ty == Tfunction && (cast(TypeFunction)t).isnothrow) + return; + if (t.ty == Tdelegate && (cast(TypeFunction)(cast(TypeDelegate)t).next).isnothrow) + return; + + if (mustNotThrow) { - } - else if (t.ty == Tfunction && (cast(TypeFunction)t).isnothrow) - { - } - else if (t.ty == Tdelegate && (cast(TypeFunction)(cast(TypeDelegate)t).next).isnothrow) - { - } - else - { - if (mustNotThrow) + if (ce.f) { - const(char)* s; - if (ce.f) - s = ce.f.toPrettyChars(); - else if (ce.e1.op == TOKstar) - { - // print 'fp' if ce->e1 is (*fp) - s = (cast(PtrExp)ce.e1).e1.toChars(); - } - else - s = ce.e1.toChars(); - ce.error("'%s' is not nothrow", s); + ce.error("%s '%s' is not nothrow", + ce.f.kind(), ce.f.toPrettyChars()); + } + else + { + auto e1 = ce.e1; + if (e1.op == TOKstar) // print 'fp' if e1 is (*fp) + e1 = (cast(PtrExp)e1).e1; + ce.error("'%s' is not nothrow", e1.toChars()); } - stop = true; } + stop = true; } override void visit(NewExp ne) { if (ne.member) { + if (ne.allocator) + { + // Bugzilla 14407 + Type t = ne.allocator.type.toBasetype(); + if (t.ty == Tfunction && !(cast(TypeFunction)t).isnothrow) + { + if (mustNotThrow) + { + ne.error("%s '%s' is not nothrow", + ne.allocator.kind(), ne.allocator.toPrettyChars()); + } + stop = true; + } + } // See if constructor call can throw Type t = ne.member.type.toBasetype(); if (t.ty == Tfunction && !(cast(TypeFunction)t).isnothrow) { if (mustNotThrow) - ne.error("constructor %s is not nothrow", ne.member.toChars()); + { + ne.error("%s '%s' is not nothrow", + ne.member.kind(), ne.member.toPrettyChars()); + } stop = true; } } // regard storage allocation failures as not recoverable } + override void visit(DeleteExp de) + { + Type tb = de.e1.type.toBasetype(); + AggregateDeclaration ad = null; + switch (tb.ty) + { + case Tclass: + ad = (cast(TypeClass)tb).sym; + break; + + case Tpointer: + tb = (cast(TypePointer)tb).next.toBasetype(); + if (tb.ty == Tstruct) + ad = (cast(TypeStruct)tb).sym; + break; + + case Tarray: + Type tv = tb.nextOf().baseElemOf(); + if (tv.ty == Tstruct) + ad = (cast(TypeStruct)tv).sym; + break; + + default: + break; + } + if (!ad) + return; + + if (ad.dtor) + { + Type t = ad.dtor.type.toBasetype(); + if (t.ty == Tfunction && !(cast(TypeFunction)t).isnothrow) + { + if (mustNotThrow) + { + de.error("%s '%s' is not nothrow", + ad.dtor.kind(), ad.dtor.toPrettyChars()); + } + stop = true; + } + } + if (ad.aggDelete && tb.ty != Tarray) + { + Type t = ad.aggDelete.type; + if (t.ty == Tfunction && !(cast(TypeFunction)t).isnothrow) + { + if (mustNotThrow) + { + de.error("%s '%s' is not nothrow", + ad.aggDelete.kind(), ad.aggDelete.toPrettyChars()); + } + stop = true; + } + } + } + override void visit(AssignExp ae) { // blit-init cannot throw @@ -138,7 +208,10 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow else { if (mustNotThrow) - ae.error("'%s' is not nothrow", sd.postblit.toPrettyChars()); + { + ae.error("%s '%s' is not nothrow", + sd.postblit.kind(), sd.postblit.toPrettyChars()); + } stop = true; } } @@ -197,7 +270,7 @@ extern (C++) bool Dsymbol_canThrow(Dsymbol s, FuncDeclaration func, bool mustNot if (ie && canThrow(ie.exp, func, mustNotThrow)) return true; } - if (vd.edtor && !vd.noscope) + if (vd.needsScopeDtor()) return canThrow(vd.edtor, func, mustNotThrow); } } diff --git a/ddmd/clone.d b/ddmd/clone.d index 1ed5305ecb..a24faeeccb 100644 --- a/ddmd/clone.d +++ b/ddmd/clone.d @@ -8,6 +8,7 @@ module ddmd.clone; +import core.stdc.stdio; import ddmd.aggregate; import ddmd.arraytypes; import ddmd.declaration; @@ -72,6 +73,11 @@ extern (C++) StorageClass mergeFuncAttrs(StorageClass s1, FuncDeclaration f) /******************************************* * Check given aggregate actually has an identity opAssign or not. + * Params: + * ad = struct or class + * sc = current scope + * Returns: + * if found, returns FuncDeclaration of opAssign, otherwise null */ extern (C++) FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* sc) { @@ -80,23 +86,24 @@ extern (C++) FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* { /* check identity opAssign exists */ - Expression er = new NullExp(ad.loc, ad.type); // dummy rvalue - Expression el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue + scope er = new NullExp(ad.loc, ad.type); // dummy rvalue + scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue el.type = ad.type; - auto a = new Expressions(); + Expressions a; a.setDim(1); - FuncDeclaration f = null; - uint errors = global.startGagging(); // Do not report errors, even if the + const errors = global.startGagging(); // Do not report errors, even if the sc = sc.push(); sc.tinst = null; sc.minst = null; - for (size_t i = 0; i < 2; i++) + + a[0] = er; + auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, &a, 1); + if (!f) { - (*a)[0] = (i == 0 ? er : el); - f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, a, 1); - if (f) - break; + a[0] = el; + f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, &a, 1); } + sc = sc.pop(); global.endGagging(errors); if (f) @@ -104,10 +111,10 @@ extern (C++) FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* if (f.errors) return null; int varargs; - Parameters* fparams = f.getParameters(&varargs); + auto fparams = f.getParameters(&varargs); if (fparams.dim >= 1) { - Parameter fparam0 = Parameter.getNth(fparams, 0); + auto fparam0 = Parameter.getNth(fparams, 0); if (fparam0.type.toDsymbol(null) != ad) f = null; } @@ -126,10 +133,10 @@ extern (C++) FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* */ extern (C++) bool needOpAssign(StructDeclaration sd) { - //printf("StructDeclaration::needOpAssign() %s\n", sd->toChars()); + //printf("StructDeclaration::needOpAssign() %s\n", sd.toChars()); if (sd.hasIdentityAssign) - goto Lneed; - // because has identity==elaborate opAssign + goto Lneed; // because has identity==elaborate opAssign + if (sd.dtor || sd.postblit) goto Lneed; /* If any of the fields need an opAssign, then we @@ -186,7 +193,8 @@ extern (C++) FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc) // will be defined. if (!needOpAssign(sd)) return null; - //printf("StructDeclaration::buildOpAssign() %s\n", sd->toChars()); + + //printf("StructDeclaration::buildOpAssign() %s\n", sd.toChars()); StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc; Loc declLoc = sd.loc; Loc loc = Loc(); // internal code should have no loc to prevent coverage @@ -224,7 +232,7 @@ extern (C++) FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc) } else if (sd.dtor || sd.postblit) { - /* Do swap this and rhs + /* Do swap this and rhs. * __swap = this; this = s; __swap.dtor(); */ //printf("\tswap copy\n"); @@ -234,7 +242,7 @@ extern (C++) FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc) if (sd.dtor) { tmp = new VarDeclaration(loc, sd.type, idtmp, new VoidInitializer(loc)); - tmp.noscope = 1; + tmp.noscope = true; tmp.storage_class |= STCtemp | STCctfe; e = new DeclarationExp(loc, tmp); ec = new BlitExp(loc, new VarExp(loc, tmp), new ThisExp(loc)); @@ -247,21 +255,28 @@ extern (C++) FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc) /* Instead of running the destructor on s, run it * on tmp. This avoids needing to copy tmp back in to s. */ - Expression ec2 = new DotVarExp(loc, new VarExp(loc, tmp), sd.dtor, 0); + Expression ec2 = new DotVarExp(loc, new VarExp(loc, tmp), sd.dtor, false); ec2 = new CallExp(loc, ec2); e = Expression.combine(e, ec2); } } else { - /* Do memberwise copy + /* Do memberwise copy. + * + * If sd is a nested struct, its vthis field assignment is: + * 1. If it's nested in a class, it's a rebind of class reference. + * 2. If it's nested in a function or struct, it's an update of void*. + * In both cases, it will change the parent context. */ //printf("\tmemberwise copy\n"); for (size_t i = 0; i < sd.fields.dim; i++) { VarDeclaration v = sd.fields[i]; // this.v = s.v; - auto ec = new AssignExp(loc, new DotVarExp(loc, new ThisExp(loc), v, 0), new DotVarExp(loc, new IdentifierExp(loc, Id.p), v, 0)); + auto ec = new AssignExp(loc, + new DotVarExp(loc, new ThisExp(loc), v), + new DotVarExp(loc, new IdentifierExp(loc, Id.p), v)); e = Expression.combine(e, ec); } } @@ -285,7 +300,7 @@ extern (C++) FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc) sc2.linkage = LINKd; fop.semantic(sc2); fop.semantic2(sc2); - // Bugzilla 15044: fop->semantic3 isn't run here for lazy forward reference resolution. + // Bugzilla 15044: fop.semantic3 isn't run here for lazy forward reference resolution. sc2.pop(); if (global.endGagging(errors)) // if errors happened @@ -294,7 +309,8 @@ extern (C++) FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc) fop.storage_class |= STCdisable; fop.fbody = null; // remove fbody which contains the error } - //printf("-StructDeclaration::buildOpAssign() %s, errors = %d\n", sd->toChars(), (fop->storage_class & STCdisable) != 0); + + //printf("-StructDeclaration::buildOpAssign() %s, errors = %d\n", sd.toChars(), (fop.storage_class & STCdisable) != 0); return fop; } @@ -305,7 +321,7 @@ extern (C++) FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc) */ extern (C++) bool needOpEquals(StructDeclaration sd) { - //printf("StructDeclaration::needOpEquals() %s\n", sd->toChars()); + //printf("StructDeclaration::needOpEquals() %s\n", sd.toChars()); if (sd.hasIdentityEquals) goto Lneed; if (sd.isUnionDeclaration()) @@ -360,35 +376,31 @@ extern (C++) FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* { /* check identity opEquals exists */ - Expression er = new NullExp(ad.loc, null); // dummy rvalue - Expression el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue - auto a = new Expressions(); + scope er = new NullExp(ad.loc, null); // dummy rvalue + scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue + Expressions a; a.setDim(1); - for (size_t i = 0;; i++) + foreach (i; 0 .. 5) { Type tthis = null; // dead-store to prevent spurious warning - if (i == 0) - tthis = ad.type; - if (i == 1) - tthis = ad.type.constOf(); - if (i == 2) - tthis = ad.type.immutableOf(); - if (i == 3) - tthis = ad.type.sharedOf(); - if (i == 4) - tthis = ad.type.sharedConstOf(); - if (i == 5) - break; + final switch (i) + { + case 0: tthis = ad.type; break; + case 1: tthis = ad.type.constOf(); break; + case 2: tthis = ad.type.immutableOf(); break; + case 3: tthis = ad.type.sharedOf(); break; + case 4: tthis = ad.type.sharedConstOf(); break; + } FuncDeclaration f = null; - uint errors = global.startGagging(); // Do not report errors, even if the + const errors = global.startGagging(); // Do not report errors, even if the sc = sc.push(); sc.tinst = null; sc.minst = null; - for (size_t j = 0; j < 2; j++) + foreach (j; 0 .. 2) { - (*a)[0] = (j == 0 ? er : el); - (*a)[0].type = tthis; - f = resolveFuncCall(ad.loc, sc, eq, null, tthis, a, 1); + a[0] = (j == 0 ? er : el); + a[0].type = tthis; + f = resolveFuncCall(ad.loc, sc, eq, null, tthis, &a, 1); if (f) break; } @@ -412,7 +424,7 @@ extern (C++) FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* * By fixing bugzilla 3789, opEquals is changed to be never implicitly generated. * Now, struct objects comparison s1 == s2 is translated to: * s1.tupleof == s2.tupleof - * to calculate structural equality. See EqualExp::semantic. + * to calculate structural equality. See EqualExp.op_overload. */ extern (C++) FuncDeclaration buildOpEquals(StructDeclaration sd, Scope* sc) { @@ -437,7 +449,8 @@ extern (C++) FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc) { if (!needOpEquals(sd)) return null; // bitwise comparison would work - //printf("StructDeclaration::buildXopEquals() %s\n", sd->toChars()); + + //printf("StructDeclaration::buildXopEquals() %s\n", sd.toChars()); if (Dsymbol eq = search_function(sd, Id.eq)) { if (FuncDeclaration fd = eq.isFuncDeclaration()) @@ -529,9 +542,8 @@ extern (C++) FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc) } else { - version (none) + version (none) // FIXME: doesn't work for recursive alias this { - // FIXME: doesn't work for recursive alias this /* Check opCmp member exists. * Consider 'alias this', but except opDispatch. */ @@ -621,11 +633,12 @@ extern (C++) FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc) */ extern (C++) bool needToHash(StructDeclaration sd) { - //printf("StructDeclaration::needToHash() %s\n", sd->toChars()); + //printf("StructDeclaration::needToHash() %s\n", sd.toChars()); if (sd.xhash) goto Lneed; if (sd.isUnionDeclaration()) goto Ldontneed; + /* If any of the fields has an opEquals, then we * need it too. */ @@ -689,7 +702,8 @@ extern (C++) FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc) } if (!needToHash(sd)) return null; - //printf("StructDeclaration::buildXtoHash() %s\n", sd->toPrettyChars()); + + //printf("StructDeclaration::buildXtoHash() %s\n", sd.toPrettyChars()); Loc declLoc = Loc(); // loc is unnecessary so __xtoHash is never called directly Loc loc = Loc(); // internal code should have no loc to prevent coverage auto parameters = new Parameters(); @@ -697,7 +711,17 @@ extern (C++) FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc) auto tf = new TypeFunction(parameters, Type.thash_t, 0, LINKd, STCnothrow | STCtrusted); Identifier id = Id.xtoHash; auto fop = new FuncDeclaration(declLoc, Loc(), id, STCstatic, tf); - const(char)* code = "size_t h = 0;foreach (i, T; typeof(p.tupleof)) h += typeid(T).getHash(cast(const void*)&p.tupleof[i]);return h;"; + + /* Do memberwise hashing. + * + * If sd is a nested struct, and if it's nested in a class, the calculated + * hash value will also contain the result of parent class's toHash(). + */ + const(char)* code = + "size_t h = 0;" ~ + "foreach (i, T; typeof(p.tupleof))" ~ + " h += typeid(T).getHash(cast(const void*)&p.tupleof[i]);" ~ + "return h;"; fop.fbody = new CompileStatement(loc, new StringExp(loc, cast(char*)code)); Scope* sc2 = sc.push(); sc2.stc = 0; @@ -705,7 +729,8 @@ extern (C++) FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc) fop.semantic(sc2); fop.semantic2(sc2); sc2.pop(); - //printf("%s fop = %s %s\n", sd->toChars(), fop->toChars(), fop->type->toChars()); + + //printf("%s fop = %s %s\n", sd.toChars(), fop.toChars(), fop.type.toChars()); return fop; } @@ -718,7 +743,7 @@ extern (C++) FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc) */ extern (C++) FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) { - //printf("StructDeclaration::buildPostBlit() %s\n", sd->toChars()); + //printf("StructDeclaration::buildPostBlit() %s\n", sd.toChars()); StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc; Loc declLoc = sd.postblits.dim ? sd.postblits[0].loc : sd.loc; Loc loc = Loc(); // internal code should have no loc to prevent coverage @@ -750,7 +775,7 @@ extern (C++) FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) if (!a) a = new Statements(); Expression ex = new ThisExp(loc); - ex = new DotVarExp(loc, ex, v, 0); + ex = new DotVarExp(loc, ex, v); if (v.type.toBasetype().ty == Tstruct) { // this.v.__xpostblit() @@ -760,7 +785,7 @@ extern (C++) FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) ex = new PtrExp(loc, ex); if (stc & STCsafe) stc = (stc & ~STCsafe) | STCtrusted; - ex = new DotVarExp(loc, ex, sdv.postblit, 0); + ex = new DotVarExp(loc, ex, sdv.postblit, false); ex = new CallExp(loc, ex); } else @@ -787,7 +812,7 @@ extern (C++) FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) sdv.dtor.functionSemantic(); ex = new ThisExp(loc); - ex = new DotVarExp(loc, ex, v, 0); + ex = new DotVarExp(loc, ex, v); if (v.type.toBasetype().ty == Tstruct) { // this.v.__xdtor() @@ -797,7 +822,7 @@ extern (C++) FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) ex = new PtrExp(loc, ex); if (stc & STCsafe) stc = (stc & ~STCsafe) | STCtrusted; - ex = new DotVarExp(loc, ex, sdv.dtor, 0); + ex = new DotVarExp(loc, ex, sdv.dtor, false); ex = new CallExp(loc, ex); } else @@ -842,7 +867,7 @@ extern (C++) FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) stc = STCsafe | STCnothrow | STCpure | STCnogc; for (size_t i = 0; i < sd.postblits.dim; i++) { - FuncDeclaration fd = sd.postblits[i]; + auto fd = sd.postblits[i]; stc = mergeFuncAttrs(stc, fd); if (stc & STCdisable) { @@ -850,7 +875,7 @@ extern (C++) FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) break; } Expression ex = new ThisExp(loc); - ex = new DotVarExp(loc, ex, fd, 0); + ex = new DotVarExp(loc, ex, fd, false); ex = new CallExp(loc, ex); e = Expression.combine(e, ex); } @@ -882,7 +907,7 @@ extern (C++) FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) */ extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc) { - //printf("AggregateDeclaration::buildDtor() %s\n", ad->toChars()); + //printf("AggregateDeclaration::buildDtor() %s\n", ad.toChars()); StorageClass stc = STCsafe | STCnothrow | STCpure | STCnogc; Loc declLoc = ad.dtors.dim ? ad.dtors[0].loc : ad.loc; Loc loc = Loc(); // internal code should have no loc to prevent coverage @@ -907,7 +932,7 @@ extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc) break; } Expression ex = new ThisExp(loc); - ex = new DotVarExp(loc, ex, v, 0); + ex = new DotVarExp(loc, ex, v); if (v.type.toBasetype().ty == Tstruct) { // this.v.__xdtor() @@ -917,7 +942,7 @@ extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc) ex = new PtrExp(loc, ex); if (stc & STCsafe) stc = (stc & ~STCsafe) | STCtrusted; - ex = new DotVarExp(loc, ex, sdv.dtor, 0); + ex = new DotVarExp(loc, ex, sdv.dtor, false); ex = new CallExp(loc, ex); } else @@ -970,7 +995,7 @@ extern (C++) FuncDeclaration buildDtor(AggregateDeclaration ad, Scope* sc) break; } Expression ex = new ThisExp(loc); - ex = new DotVarExp(loc, ex, fd, 0); + ex = new DotVarExp(loc, ex, fd, false); ex = new CallExp(loc, ex); e = Expression.combine(ex, e); } @@ -1036,7 +1061,7 @@ extern (C++) FuncDeclaration buildInv(AggregateDeclaration ad, Scope* sc) break; } } - e = Expression.combine(e, new CallExp(loc, new VarExp(loc, ad.invs[i]))); + e = Expression.combine(e, new CallExp(loc, new VarExp(loc, ad.invs[i], false))); } InvariantDeclaration inv; inv = new InvariantDeclaration(declLoc, Loc(), stc | stcx, Id.classInvariant); diff --git a/ddmd/cond.d b/ddmd/cond.d index ffdc40f07e..12f58e4c1d 100644 --- a/ddmd/cond.d +++ b/ddmd/cond.d @@ -25,6 +25,20 @@ import ddmd.root.outbuffer; import ddmd.tokens; import ddmd.visitor; +private __gshared Identifier idUnitTest; +private __gshared Identifier idAssert; + +static this() +{ + const(char)* s; + + s = Token.toChars(TOKunittest); + idUnitTest = Identifier.idPool(s, strlen(s)); + + s = Token.toChars(TOKassert); + idAssert = Identifier.idPool(s, strlen(s)); +} + /*********************************************************** */ extern (C++) class Condition @@ -171,6 +185,9 @@ public: "Win64", "linux", "OSX", + "iOS", + "TVOS", + "WatchOS", "FreeBSD", "OpenBSD", "NetBSD", @@ -233,7 +250,7 @@ public: "ELFv1", "ELFv2", "CRuntime_Bionic", - "CRuntime_Digitalmars", + "CRuntime_DigitalMars", "CRuntime_Glibc", "CRuntime_Microsoft", "D_Coverage", @@ -314,8 +331,11 @@ public: } else if (level <= global.params.versionlevel || level <= mod.versionlevel) inc = 1; - if (!definedInModule && (!ident || (!isPredefined(ident.toChars()) && ident != Identifier.idPool(Token.toChars(TOKunittest)) && ident != Identifier.idPool(Token.toChars(TOKassert))))) + if (!definedInModule && + (!ident || (!isPredefined(ident.toChars()) && ident != idUnitTest && ident != idAssert))) + { printDepsConditional(sc, this, "depsVersion "); + } } return (inc == 1); } diff --git a/ddmd/cond.h b/ddmd/cond.h index a3bc16a39e..4b4b49452b 100644 --- a/ddmd/cond.h +++ b/ddmd/cond.h @@ -70,11 +70,7 @@ class VersionCondition : public DVCondition public: static void setGlobalLevel(unsigned level); static bool isPredefined(const char *ident); - static void checkPredefined(Loc loc, const char *ident) - { - if (isPredefined(ident)) - error(loc, "version identifier '%s' is reserved and cannot be set", ident); - } + static void checkPredefined(Loc loc, const char *ident); static void addGlobalIdent(const char *ident); static void addPredefinedGlobalIdent(const char *ident); diff --git a/ddmd/constfold.d b/ddmd/constfold.d index e75e3c3f0a..69f0d9ec24 100644 --- a/ddmd/constfold.d +++ b/ddmd/constfold.d @@ -870,11 +870,6 @@ extern (C++) UnionExp Equal(TOK op, Loc loc, Type type, Expression e1, Expressio break; } } - if (cmp && es1.type.needsNested()) - { - if ((es1.sinit !is null) != (es2.sinit !is null)) - cmp = 0; - } } else if (e1.isConst() != 1 || e2.isConst() != 1) { @@ -1344,9 +1339,8 @@ extern (C++) UnionExp Slice(Type type, Expression e1, Expression lwr, Expression { size_t len = cast(size_t)(iupr - ilwr); ubyte sz = es1.sz; - void* s = mem.xmalloc((len + 1) * sz); - memcpy(cast(char*)s, cast(char*)es1.string + ilwr * sz, len * sz); - memset(cast(char*)s + len * sz, 0, sz); + void* s = mem.xmalloc(len * sz); + memcpy(cast(char*)s, es1.string + ilwr * sz, len * sz); emplaceExp!(StringExp)(&ue, loc, s, len, es1.postfix); StringExp es = cast(StringExp)ue.exp(); es.sz = sz; @@ -1382,29 +1376,13 @@ extern (C++) UnionExp Slice(Type type, Expression e1, Expression lwr, Expression /* Set a slice of char/integer array literal 'existingAE' from a string 'newval'. * existingAE[firstIndex..firstIndex+newval.length] = newval. */ -extern (C++) void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE, StringExp newval, size_t firstIndex) +extern (C++) void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE, const StringExp newval, size_t firstIndex) { - size_t newlen = newval.len; - size_t sz = newval.sz; - void* s = newval.string; + const len = newval.len; Type elemType = existingAE.type.nextOf(); - for (size_t j = 0; j < newlen; j++) + foreach (j; 0 .. len) { - dinteger_t val; - switch (sz) - { - case 1: - val = (cast(char*)s)[j]; - break; - case 2: - val = (cast(utf16_t*)s)[j]; - break; - case 4: - val = (cast(utf32_t*)s)[j]; - break; - default: - assert(0); - } + const val = newval.getCodeUnit(j); (*existingAE.elements)[j + firstIndex] = new IntegerExp(newval.loc, val, elemType); } } @@ -1414,76 +1392,44 @@ extern (C++) void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE, */ extern (C++) void sliceAssignStringFromArrayLiteral(StringExp existingSE, ArrayLiteralExp newae, size_t firstIndex) { - void* s = existingSE.string; - for (size_t j = 0; j < newae.elements.dim; j++) + assert(existingSE.ownedByCtfe != OWNEDcode); + foreach (j; 0 .. newae.elements.dim) { - uint val = cast(uint)newae.getElement(j).toInteger(); - switch (existingSE.sz) - { - case 1: - (cast(char*)s)[j + firstIndex] = cast(char)val; - break; - case 2: - (cast(utf16_t*)s)[j + firstIndex] = cast(utf16_t)val; - break; - case 4: - (cast(utf32_t*)s)[j + firstIndex] = cast(utf32_t)val; - break; - default: - assert(0); - } + existingSE.setCodeUnit(firstIndex + j, cast(dchar)newae.getElement(j).toInteger()); } } /* Set a slice of string 'existingSE' from a string 'newstr'. * existingSE[firstIndex..firstIndex+newstr.length] = newstr. */ -extern (C++) void sliceAssignStringFromString(StringExp existingSE, StringExp newstr, size_t firstIndex) +extern (C++) void sliceAssignStringFromString(StringExp existingSE, const StringExp newstr, size_t firstIndex) { - void* s = existingSE.string; + assert(existingSE.ownedByCtfe != OWNEDcode); size_t sz = existingSE.sz; assert(sz == newstr.sz); - memcpy(cast(char*)s + firstIndex * sz, newstr.string, sz * newstr.len); + memcpy(existingSE.string + firstIndex * sz, newstr.string, sz * newstr.len); } /* Compare a string slice with another string slice. * Conceptually equivalent to memcmp( se1[lo1..lo1+len], se2[lo2..lo2+len]) */ -extern (C++) int sliceCmpStringWithString(StringExp se1, StringExp se2, size_t lo1, size_t lo2, size_t len) +extern (C++) int sliceCmpStringWithString(const StringExp se1, const StringExp se2, size_t lo1, size_t lo2, size_t len) { - void* s1 = se1.string; - void* s2 = se2.string; size_t sz = se1.sz; assert(sz == se2.sz); - return memcmp(cast(char*)s1 + sz * lo1, cast(char*)s2 + sz * lo2, sz * len); + return memcmp(se1.string + sz * lo1, se2.string + sz * lo2, sz * len); } /* Compare a string slice with an array literal slice * Conceptually equivalent to memcmp( se1[lo1..lo1+len], ae2[lo2..lo2+len]) */ -extern (C++) int sliceCmpStringWithArray(StringExp se1, ArrayLiteralExp ae2, size_t lo1, size_t lo2, size_t len) +extern (C++) int sliceCmpStringWithArray(const StringExp se1, ArrayLiteralExp ae2, size_t lo1, size_t lo2, size_t len) { - void* s = se1.string; - size_t sz = se1.sz; - for (size_t j = 0; j < len; j++) + foreach (j; 0 .. len) { - uint val2 = cast(uint)ae2.getElement(j + lo2).toInteger(); - uint val1; - switch (sz) - { - case 1: - val1 = (cast(char*)s)[j + lo1]; - break; - case 2: - val1 = (cast(utf16_t*)s)[j + lo1]; - break; - case 4: - val1 = (cast(utf32_t*)s)[j + lo1]; - break; - default: - assert(0); - } - int c = val1 - val2; + const val2 = cast(dchar)ae2.getElement(j + lo2).toInteger(); + const val1 = se1.getCodeUnit(j + lo1); + const int c = val1 - val2; if (c) return c; } @@ -1521,24 +1467,12 @@ extern (C++) UnionExp Cat(Type type, Expression e1, Expression e2) t = t.nextOf().toBasetype(); ubyte sz = cast(ubyte)t.size(); dinteger_t v = e.toInteger(); - size_t len = (t.ty == tn.ty) ? 1 : utf_codeLength(sz, cast(dchar_t)v); - void* s = mem.xmalloc((len + 1) * sz); + size_t len = (t.ty == tn.ty) ? 1 : utf_codeLength(sz, cast(dchar)v); + void* s = mem.xmalloc(len * sz); if (t.ty == tn.ty) - { -version(IN_LLVM) { - version(LittleEndian) { - memcpy(s, &v, sz); - } else { - memcpy(s, cast(char *)&v + (dinteger_t.sizeof - sz), sz); - } -} else { - memcpy(s, &v, sz); -} - } + Port.valcpy(s, v, sz); else - utf_encode(sz, s, cast(dchar_t)v); - // Add terminating 0 - memset(cast(char*)s + len * sz, 0, sz); + utf_encode(sz, s, cast(dchar)v); emplaceExp!(StringExp)(&ue, loc, s, len); StringExp es = cast(StringExp)ue.exp(); es.sz = sz; @@ -1601,11 +1535,9 @@ version(IN_LLVM) { assert(ue.exp().type); return ue; } - void* s = mem.xmalloc((len + 1) * sz); + void* s = mem.xmalloc(len * sz); memcpy(cast(char*)s, es1.string, es1.len * sz); memcpy(cast(char*)s + es1.len * sz, es2.string, es2.len * sz); - // Add terminating 0 - memset(cast(char*)s + len * sz, 0, sz); emplaceExp!(StringExp)(&ue, loc, s, len); StringExp es = cast(StringExp)ue.exp(); es.sz = sz; @@ -1663,26 +1595,13 @@ version(IN_LLVM) { // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar) bool homoConcat = (sz == t2.size()); size_t len = es1.len; - len += homoConcat ? 1 : utf_codeLength(sz, cast(dchar_t)v); - void* s = mem.xmalloc((len + 1) * sz); + len += homoConcat ? 1 : utf_codeLength(sz, cast(dchar)v); + void* s = mem.xmalloc(len * sz); memcpy(s, es1.string, es1.len * sz); if (homoConcat) - { -version(IN_LLVM) { - version(LittleEndian) { - memcpy(cast(char *)s + (sz * es1.len), &v, sz); - } else { - memcpy(cast(char *)s + (sz * es1.len), - cast(char *)&v + (dinteger_t.sizeof - sz), sz); - } -} else { - memcpy(cast(char*)s + (sz * es1.len), &v, sz); -} - } + Port.valcpy(cast(char*)s + (sz * es1.len), v, sz); else - utf_encode(sz, cast(char*)s + (sz * es1.len), cast(dchar_t)v); - // Add terminating 0 - memset(cast(char*)s + len * sz, 0, sz); + utf_encode(sz, cast(char*)s + (sz * es1.len), cast(dchar)v); emplaceExp!(StringExp)(&ue, loc, s, len); es = cast(StringExp)ue.exp(); es.sz = sz; @@ -1698,20 +1617,9 @@ version(IN_LLVM) { size_t len = 1 + es2.len; ubyte sz = es2.sz; dinteger_t v = e1.toInteger(); - void* s = mem.xmalloc((len + 1) * sz); -version(IN_LLVM) { - version(LittleEndian) { - memcpy(cast(char *)s, &v, sz); - } else { - memcpy(cast(char *)s, - cast(char *)&v + (dinteger_t.sizeof - sz), sz); - } -} else { + void* s = mem.xmalloc(len * sz); memcpy(cast(char*)s, &v, sz); -} memcpy(cast(char*)s + sz, es2.string, es2.len * sz); - // Add terminating 0 - memset(cast(char*)s + len * sz, 0, sz); emplaceExp!(StringExp)(&ue, loc, s, len); StringExp es = cast(StringExp)ue.exp(); es.sz = sz; diff --git a/ddmd/cppmangle.d b/ddmd/cppmangle.d index 9d5771e8d3..2e34d935aa 100644 --- a/ddmd/cppmangle.d +++ b/ddmd/cppmangle.d @@ -1,19 +1,23 @@ -// Compiler implementation of the D programming language -// Copyright (c) 1999-2015 by Digital Mars -// All Rights Reserved -// written by Walter Bright -// http://www.digitalmars.com -// Distributed under the Boost Software License, Version 1.0. -// http://www.boost.org/LICENSE_1_0.txt +/** + * Compiler implementation of the $(LINK2 http://www.dlang.org, D programming language) + * + * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved + * Authors: Walter Bright, http://www.digitalmars.com + * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(DMDSRC cppmangle.d) + */ module ddmd.cppmangle; import core.stdc.string; +import core.stdc.stdio; + import ddmd.arraytypes; import ddmd.declaration; import ddmd.dstruct; import ddmd.dsymbol; import ddmd.dtemplate; +import ddmd.errors; import ddmd.expression; import ddmd.func; import ddmd.globals; @@ -69,12 +73,14 @@ static if (IN_LLVM || TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPE bool substitute(RootObject p) { - //printf("substitute %s\n", p ? p->toChars() : NULL); + //printf("substitute %s\n", p ? p.toChars() : null); if (components_on) for (size_t i = 0; i < components.dim; i++) { + //printf(" component[%d] = %s\n", i, components[i] ? components[i].toChars() : null); if (p == components[i]) { + //printf("\tmatch\n"); /* Sequence is S_, S0_, .., S9_, SA_, ..., SZ_, S10_, ... */ buf.writeByte('S'); @@ -89,7 +95,7 @@ static if (IN_LLVM || TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPE bool exist(RootObject p) { - //printf("exist %s\n", p ? p->toChars() : NULL); + //printf("exist %s\n", p ? p.toChars() : null); if (components_on) for (size_t i = 0; i < components.dim; i++) { @@ -103,14 +109,14 @@ static if (IN_LLVM || TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPE void store(RootObject p) { - //printf("store %s\n", p ? p->toChars() : NULL); + //printf("store %s\n", p ? p.toChars() : "null"); if (components_on) components.push(p); } void source_name(Dsymbol s, bool skipname = false) { - //printf("source_name(%s)\n", s->toChars()); + //printf("source_name(%s)\n", s.toChars()); TemplateInstance ti = s.isTemplateInstance(); if (ti) { @@ -174,11 +180,7 @@ static if (IN_LLVM || TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPE else { s.error("Internal Compiler Error: C++ %s template value parameter is not supported", tv.valType.toChars()); -version(IN_LLVM) { fatal(); -} else { - assert(0); -} } } else if (!tp || tp.isTemplateTypeParameter()) @@ -194,11 +196,7 @@ version(IN_LLVM) { if (!d && !e) { s.error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o.toChars()); -version(IN_LLVM) { fatal(); -} else { - assert(0); -} } if (d && d.isFuncDeclaration()) { @@ -228,21 +226,13 @@ version(IN_LLVM) { else { s.error("Internal Compiler Error: %s is unsupported parameter for C++ template", o.toChars()); -version(IN_LLVM) { fatal(); -} else { - assert(0); -} } } else { s.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); -version(IN_LLVM) { fatal(); -} else { - assert(0); -} } } if (is_var_arg) @@ -261,7 +251,7 @@ version(IN_LLVM) { void prefix_name(Dsymbol s) { - //printf("prefix_name(%s)\n", s->toChars()); + //printf("prefix_name(%s)\n", s.toChars()); if (!substitute(s)) { Dsymbol p = s.toParent(); @@ -279,9 +269,13 @@ version(IN_LLVM) { } if (p && !p.isModule()) { - prefix_name(p); + if (p.ident == Id.std && is_initial_qualifier(p)) + buf.writestring("St"); + else + prefix_name(p); } - store(s); + if (!(s.ident == Id.std && is_initial_qualifier(s))) + store(s); source_name(s); } } @@ -304,7 +298,7 @@ version(IN_LLVM) { void cpp_mangle_name(Dsymbol s, bool qualified) { - //printf("cpp_mangle_name(%s, %d)\n", s->toChars(), qualified); + //printf("cpp_mangle_name(%s, %d)\n", s.toChars(), qualified); Dsymbol p = s.toParent(); Dsymbol se = s; bool dont_write_prefix = false; @@ -340,10 +334,10 @@ version(IN_LLVM) { // Replace ::std::basic_string < char, ::std::char_traits, ::std::allocator > // with Ss //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); - if (buf.offset - off >= 26 && memcmp(buf.data + off, cast(char*)"IcSt11char_traitsIcESaIcEE", 26) == 0) + if (buf.offset - off >= 26 && memcmp(buf.data + off, "IcSt11char_traitsIcESaIcEE".ptr, 26) == 0) { buf.remove(off - 2, 28); - buf.insert(off - 2, cast(const(char)*)"Ss", 2); + buf.insert(off - 2, "Ss".ptr, 2); return; } buf.setsize(off); @@ -361,7 +355,7 @@ version(IN_LLVM) { source_name(se, true); components_on = true; //printf("xx: '%.*s'\n", (int)(buf.offset - off), buf.data + off); - if (buf.offset - off >= 21 && memcmp(buf.data + off, cast(char*)"IcSt11char_traitsIcEE", 21) == 0) + if (buf.offset - off >= 21 && memcmp(buf.data + off, "IcSt11char_traitsIcEE".ptr, 21) == 0) { buf.remove(off, 21); char[2] mbuf; @@ -403,11 +397,7 @@ version(IN_LLVM) { if (!(d.storage_class & (STCextern | STCgshared))) { d.error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported"); -version(IN_LLVM) { fatal(); -} else { - assert(0); -} } Dsymbol p = d.toParent(); if (p && !p.isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE" @@ -433,7 +423,7 @@ version(IN_LLVM) { void mangle_function(FuncDeclaration d) { - //printf("mangle_function(%s)\n", d->toChars()); + //printf("mangle_function(%s)\n", d.toChars()); /* * ::= _Z * ::= @@ -451,22 +441,27 @@ version(IN_LLVM) { prefix_name(p); // See ABI 5.1.8 Compression // Replace ::std::allocator with Sa - if (buf.offset >= 17 && memcmp(buf.data, cast(char*)"_ZN3std9allocator", 17) == 0) + if (buf.offset >= 17 && memcmp(buf.data, "_ZN3std9allocator".ptr, 17) == 0) { buf.remove(3, 14); - buf.insert(3, cast(const(char)*)"Sa", 2); + buf.insert(3, "Sa".ptr, 2); } // Replace ::std::basic_string with Sb - if (buf.offset >= 21 && memcmp(buf.data, cast(char*)"_ZN3std12basic_string", 21) == 0) + if (buf.offset >= 21 && memcmp(buf.data, "_ZN3std12basic_string".ptr, 21) == 0) { buf.remove(3, 18); - buf.insert(3, cast(const(char)*)"Sb", 2); + buf.insert(3, "Sb".ptr, 2); } // Replace ::std with St - if (buf.offset >= 7 && memcmp(buf.data, cast(char*)"_ZN3std", 7) == 0) + if (buf.offset >= 7 && memcmp(buf.data, "_ZN3std".ptr, 7) == 0) { buf.remove(3, 4); - buf.insert(3, cast(const(char)*)"St", 2); + buf.insert(3, "St".ptr, 2); + } + if (buf.offset >= 8 && memcmp(buf.data, "_ZNK3std".ptr, 8) == 0) + { + buf.remove(4, 4); + buf.insert(4, "St".ptr, 2); } if (d.isDtorDeclaration()) { @@ -508,12 +503,8 @@ version(IN_LLVM) { // Mangle static arrays as pointers t.error(Loc(), "Internal Compiler Error: unable to pass static array to extern(C++) function."); t.error(Loc(), "Use pointer instead."); -version(IN_LLVM) { fatal(); -} else { - assert(0); -} - //t = t->nextOf()->pointerTo(); + //t = t.nextOf().pointerTo(); } /* If it is a basic, enum or struct type, * then don't mark it const @@ -541,7 +532,7 @@ version(IN_LLVM) { this.components_on = true; } - char* mangleOf(Dsymbol s) + const(char)* mangleOf(Dsymbol s) { VarDeclaration vd = s.isVarDeclaration(); FuncDeclaration fd = s.isFuncDeclaration(); @@ -571,11 +562,7 @@ version(IN_LLVM) { { t.error(Loc(), "Internal Compiler Error: unsupported type %s\n", t.toChars()); } -version(IN_LLVM) { - fatal(); -} else { - assert(0); //Assert, because this error should be handled in frontend -} + fatal(); //Fatal, because this error should be handled in frontend } override void visit(TypeBasic t) @@ -733,7 +720,7 @@ version(IN_LLVM) { buf.writeByte('K'); assert(t.basetype && t.basetype.ty == Tsarray); assert((cast(TypeSArray)t.basetype).dim); - //buf.printf("Dv%llu_", ((TypeSArray *)t->basetype)->dim->toInteger());// -- Gnu ABI v.4 + //buf.printf("Dv%llu_", ((TypeSArray *)t.basetype).dim.toInteger());// -- Gnu ABI v.4 buf.writestring("U8__vector"); //-- Gnu ABI v.3 t.basetype.nextOf().accept(this); } @@ -809,7 +796,7 @@ version(IN_LLVM) { BUG: Right now, types of functions are never merged, so our simplistic component matcher always finds them to be different. - We should use Type::equals on these, and use different + We should use Type.equals on these, and use different TypeFunctions for non-static member functions, and non-static member functions of different classes. */ @@ -834,8 +821,8 @@ version(IN_LLVM) { override void visit(TypeStruct t) { - Identifier id = t.sym.ident; - //printf("struct id = '%s'\n", id->toChars()); + const id = t.sym.ident; + //printf("struct id = '%s'\n", id.toChars()); char c; if (id == Id.__c_long) c = 'l'; @@ -927,23 +914,37 @@ version(IN_LLVM) { store(null); store(t); } + + final const(char)* mangle_typeinfo(Dsymbol s) + { + buf.writestring("_ZTI"); + cpp_mangle_name(s, false); + return buf.extractString(); + } } version(IN_LLVM) {} else { - extern (C++) char* toCppMangle(Dsymbol s) + extern (C++) const(char)* toCppMangle(Dsymbol s) { - //printf("toCppMangle(%s)\n", s->toChars()); + //printf("toCppMangle(%s)\n", s.toChars()); scope CppMangleVisitor v = new CppMangleVisitor(); return v.mangleOf(s); } + + extern (C++) const(char)* cppTypeInfoMangle(Dsymbol s) + { + //printf("cppTypeInfoMangle(%s)\n", s.toChars()); + scope CppMangleVisitor v = new CppMangleVisitor(); + return v.mangle_typeinfo(s); + } } } static if (IN_LLVM || TARGET_WINDOS) { // Windows DMC and Microsoft Visual C++ mangling - enum VC_SAVED_TYPE_CNT = 10; - enum VC_SAVED_IDENT_CNT = 10; + enum VC_SAVED_TYPE_CNT = 10u; + enum VC_SAVED_IDENT_CNT = 10u; extern (C++) final class VisualCPPMangler : Visitor { @@ -995,11 +996,7 @@ static if (IN_LLVM || TARGET_WINDOS) { type.error(Loc(), "Internal Compiler Error: unsupported type %s\n", type.toChars()); } -version(IN_LLVM) { - fatal(); -} else { - assert(0); // Assert, because this error should be handled in frontend -} + fatal(); //Fatal, because this error should be handled in frontend } override void visit(TypeBasic type) @@ -1023,15 +1020,18 @@ version(IN_LLVM) { { switch (type.ty) { - case Tint64: - case Tuns64: - case Tint128: - case Tuns128: - case Tfloat80: - case Twchar: - if (checkTypeSaved(type)) - return; - default: + case Tint64: + case Tuns64: + case Tint128: + case Tuns128: + case Tfloat80: + case Twchar: + if (checkTypeSaved(type)) + return; + break; + + default: + break; } } mangleModifier(type); @@ -1206,7 +1206,7 @@ version(IN_LLVM) { override void visit(TypeReference type) { - //printf("visit(TypeReference); type = %s\n", type->toChars()); + //printf("visit(TypeReference); type = %s\n", type.toChars()); if (checkTypeSaved(type)) return; if (type.isImmutable() || type.isShared()) @@ -1247,7 +1247,7 @@ version(IN_LLVM) { override void visit(TypeStruct type) { - Identifier id = type.sym.ident; + const id = type.sym.ident; char c; if (id == Id.__c_long_double) c = 'O'; // VC++ long double @@ -1354,7 +1354,7 @@ version(IN_LLVM) { flags &= ~IGNORE_CONST; } - char* mangleOf(Dsymbol s) + const(char)* mangleOf(Dsymbol s) { version(IN_LLVM) { buf.writeByte('\01'); // disable further mangling by the backend @@ -1386,7 +1386,9 @@ version(IN_LLVM) { if (d.needThis()) // ::= { // Pivate methods always non-virtual in D and it should be mangled as non-virtual in C++ - if (d.isVirtual() && d.vtblIndex != -1) + //printf("%s: isVirtualMethod = %d, isVirtual = %d, vtblIndex = %d, interfaceVirtual = %p\n", + //d.toChars(), d.isVirtualMethod(), d.isVirtual(), cast(int)d.vtblIndex, d.interfaceVirtual); + if (d.isVirtual() && (d.vtblIndex != -1 || d.interfaceVirtual || d.overrideInterface())) { switch (d.protection.kind) { @@ -1448,7 +1450,7 @@ version(IN_LLVM) { // ::= Y buf.writeByte('Y'); } - const(char)* args = mangleFunctionType(cast(TypeFunction)d.type, cast(bool)d.needThis(), d.isCtorDeclaration() || d.isDtorDeclaration()); + const(char)* args = mangleFunctionType(cast(TypeFunction)d.type, d.needThis(), d.isCtorDeclaration() || d.isDtorDeclaration()); buf.writestring(args); } @@ -1459,11 +1461,7 @@ version(IN_LLVM) { if (!(d.storage_class & (STCextern | STCgshared))) { d.error("Internal Compiler Error: C++ static non- __gshared non-extern variables not supported"); -version(IN_LLVM) { fatal(); -} else { - assert(0); -} } buf.writeByte('?'); mangleIdent(d); @@ -1491,7 +1489,7 @@ version(IN_LLVM) { Type t = d.type; if (t.isImmutable() || t.isShared()) { - visit(cast(Type)t); + visit(t); return; } if (t.isConst()) @@ -1514,7 +1512,7 @@ version(IN_LLVM) { void mangleName(Dsymbol sym, bool dont_use_back_reference = false) { - //printf("mangleName('%s')\n", sym->toChars()); + //printf("mangleName('%s')\n", sym.toChars()); const(char)* name = null; bool is_dmc_template = false; if (sym.isDtorDeclaration()) @@ -1587,11 +1585,7 @@ version(IN_LLVM) { else { sym.error("Internal Compiler Error: C++ %s template value parameter is not supported", tv.valType.toChars()); -version(IN_LLVM) { fatal(); -} else { - assert(0); -} } } else if (!tp || tp.isTemplateTypeParameter()) @@ -1607,11 +1601,7 @@ version(IN_LLVM) { if (!d && !e) { sym.error("Internal Compiler Error: %s is unsupported parameter for C++ template", o.toChars()); -version(IN_LLVM) { fatal(); -} else { - assert(0); -} } if (d && d.isFuncDeclaration()) { @@ -1652,11 +1642,7 @@ version(IN_LLVM) { else { sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); -version(IN_LLVM) { fatal(); -} else { - assert(0); -} } } tmp.mangleIdent(d); @@ -1664,21 +1650,13 @@ version(IN_LLVM) { else { sym.error("Internal Compiler Error: %s is unsupported parameter for C++ template: (%s)", o.toChars()); -version(IN_LLVM) { fatal(); -} else { - assert(0); -} } } else { sym.error("Internal Compiler Error: C++ templates support only integral value, type parameters, alias templates and alias function parameters"); -version(IN_LLVM) { fatal(); -} else { - assert(0); -} } } name = tmp.buf.extractString(); @@ -1707,7 +1685,7 @@ version(IN_LLVM) { // returns true if name already saved bool checkAndSaveIdent(const(char)* name) { - for (uint i = 0; i < VC_SAVED_IDENT_CNT; i++) + foreach (i; 0 .. VC_SAVED_IDENT_CNT) { if (!saved_idents[i]) // no saved same name { @@ -1725,7 +1703,7 @@ version(IN_LLVM) { void saveIdent(const(char)* name) { - for (size_t i = 0; i < VC_SAVED_IDENT_CNT; i++) + foreach (i; 0 .. VC_SAVED_IDENT_CNT) { if (!saved_idents[i]) // no saved same name { @@ -1752,7 +1730,7 @@ version(IN_LLVM) { // ::=