diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2025-01-05 14:40:13 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2025-01-05 14:40:13 +0100 |
commit | f5351b38a8aff438b41cae0d133fd38d56d8cd1f (patch) | |
tree | 6c3ebcd181efe8e57c3e6fe4af8f595996b713ff /gcc/d/dmd | |
parent | a676a516701789730aa482bcef4adcb683ba0140 (diff) | |
download | gcc-f5351b38a8aff438b41cae0d133fd38d56d8cd1f.zip gcc-f5351b38a8aff438b41cae0d133fd38d56d8cd1f.tar.gz gcc-f5351b38a8aff438b41cae0d133fd38d56d8cd1f.tar.bz2 |
d: Merge upstream dmd, druntime 66b93fc24a, phobos 0c28620c3
Synchronizing with the upstream release of v2.109.1.
D front-end changes:
- Import dmd v2.109.1.
- Copying from `const(void)[]' to `void[]' is now disallowed
with `-fpreview=fiximmutableconv'.
- Import expressions are now treated as hex strings.
- Using boolean values other than 0 or 1 in `@safe' code is now
deprecated.
D runtime changes:
- Import dmd v2.109.1.
Phobos changes:
- Import dmd v2.109.1.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd 66b93fc24a.
* dmd/VERSION: Bump version to v2.109.1.
* d-builtins.cc (build_frontend_type): Update for new front-end
interface.
(matches_builtin_type): Likewise.
* d-codegen.cc (identity_compare_p): Likewise.
(call_side_effect_free_p): Likewise.
* d-convert.cc (convert_expr): Likewise.
(check_valist_conversion): Likewise.
* d-lang.cc (d_types_compatible_p): Likewise.
* d-target.cc (Target::isVectorTypeSupported): Likewise.
(Target::isReturnOnStack): Likewise.
(Target::preferPassByRef): Likewise.
* decl.cc (class DeclVisitor): Likewise.
* expr.cc (class ExprVisitor): Likewise.
* typeinfo.cc (class TypeInfoVisitor): Likewise.
* types.cc (class TypeVisitor): Likewise.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime 66b93fc24a.
* src/MERGE: Merge upstream phobos 0c28620c3.
* src/Makefile.am (PHOBOS_DSOURCES): Add
std/internal/test/sumtype_example_overloads.d.
* src/Makefile.in: Regenerate.
Diffstat (limited to 'gcc/d/dmd')
41 files changed, 1339 insertions, 1163 deletions
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 77e8562..d458bea 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -07bc5b9b3c81cc0d4314e0040de981124b363ea5 +66b93fc24a7ab5e2a8aa7f53c613df4abddc188b The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/README.md b/gcc/d/dmd/README.md index baac0d7..0787594 100644 --- a/gcc/d/dmd/README.md +++ b/gcc/d/dmd/README.md @@ -251,6 +251,8 @@ Note that these groups have no strict meaning, the category assignments are a bi | [hdrgen.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/hdrgen.d) | Convert an AST into D source code for `.di` header generation, as well as `-vcg-ast` and error messages | | [json.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/json.d) | Describe the module in a `.json` file for the `-X` flag | | [dtoh.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dtoh.d) | C++ header generation from D source files | +| [disasm86.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/backend/disasm86.d) | x86-64 dissassembly generation +| [disasmarm.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/backend/arm/disasmarm.d) | AArch64 disassembly generation ### Utility diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index 3d80c3d..ffc1c3e 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.109.0 +v2.109.1 diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d index 2c7622a..78cb87f 100644 --- a/gcc/d/dmd/aggregate.d +++ b/gcc/d/dmd/aggregate.d @@ -37,7 +37,7 @@ import dmd.identifier; import dmd.location; import dmd.mtype; import dmd.tokens; -import dmd.typesem : defaultInit, addMod; +import dmd.typesem : defaultInit, addMod, size; import dmd.visitor; /** diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d index d0ec5eb..e30160d 100644 --- a/gcc/d/dmd/arrayop.d +++ b/gcc/d/dmd/arrayop.d @@ -16,6 +16,7 @@ module dmd.arrayop; import core.stdc.stdio; import dmd.arraytypes; import dmd.astenums; +import dmd.dcast : implicitConvTo; import dmd.declaration; import dmd.dscope; import dmd.dsymbol; diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d index 5024f9b..bbc7b86 100644 --- a/gcc/d/dmd/chkformat.d +++ b/gcc/d/dmd/chkformat.d @@ -21,6 +21,7 @@ import dmd.globals; import dmd.identifier; import dmd.location; import dmd.mtype; +import dmd.typesem; import dmd.target; diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index 2e4833e..17b33d8 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/dmd/clone.d @@ -57,7 +57,7 @@ StorageClass mergeFuncAttrs(StorageClass s1, const FuncDeclaration f) pure return s1; StorageClass s2 = (f.storage_class & STC.disable); - TypeFunction tf = cast(TypeFunction)f.type; + auto tf = cast(TypeFunction)f.type; if (tf.trust == TRUST.safe) s2 |= STC.safe; else if (tf.trust == TRUST.system) @@ -177,7 +177,7 @@ private bool needOpAssign(StructDeclaration sd) Type tv = v.type.baseElemOf(); if (tv.ty == Tstruct) { - TypeStruct ts = cast(TypeStruct)tv; + auto ts = cast(TypeStruct)tv; if (ts.sym.isUnionDeclaration()) continue; if (needOpAssign(ts.sym)) @@ -314,7 +314,7 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc) else if (sd.dtor) { //printf("\tswap copy\n"); - TypeFunction tdtor = cast(TypeFunction)sd.dtor.type; + auto tdtor = cast(TypeFunction)sd.dtor.type; assert(tdtor.ty == Tfunction); auto idswap = Identifier.generateId("__swap"); @@ -435,7 +435,7 @@ bool needOpEquals(StructDeclaration sd) auto tvbase = tv.baseElemOf(); if (tvbase.ty == Tstruct) { - TypeStruct ts = cast(TypeStruct)tvbase; + auto ts = cast(TypeStruct)tvbase; if (ts.sym.isUnionDeclaration() && ts.sym.fields.length != 1) continue; if (needOpEquals(ts.sym)) @@ -762,7 +762,7 @@ private bool needToHash(StructDeclaration sd) auto tvbase = tv.baseElemOf(); if (tvbase.ty == Tstruct) { - TypeStruct ts = cast(TypeStruct)tvbase; + auto ts = cast(TypeStruct)tvbase; if (ts.sym.isUnionDeclaration()) continue; if (needToHash(ts.sym)) diff --git a/gcc/d/dmd/compiler.d b/gcc/d/dmd/compiler.d index 65330cf..3b00194 100644 --- a/gcc/d/dmd/compiler.d +++ b/gcc/d/dmd/compiler.d @@ -16,6 +16,7 @@ import dmd.ctfeexpr; import dmd.dmodule; import dmd.expression; import dmd.mtype; +import dmd.typesem; import dmd.root.array; extern (C++) __gshared diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d index e194664..02dde1b 100644 --- a/gcc/d/dmd/cond.d +++ b/gcc/d/dmd/cond.d @@ -659,9 +659,9 @@ extern (C++) final class VersionCondition : DVCondition case "AVR": case "BigEndian": case "BSD": - case "CppRuntime_Clang": + case "CppRuntime_LLVM": case "CppRuntime_DigitalMars": - case "CppRuntime_Gcc": + case "CppRuntime_GNU": case "CppRuntime_Microsoft": case "CppRuntime_Sun": case "CRuntime_Bionic": diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 6ec31d5..54d50cf 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -36,7 +36,7 @@ import dmd.root.utf; import dmd.sideeffect; import dmd.target; import dmd.tokens; -import dmd.typesem : toDsymbol, equivalent, sarrayOf; +import dmd.typesem : toDsymbol, equivalent, sarrayOf, size; private enum LOG = false; diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 7fbcd6d..a4e3c7e 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -27,6 +27,7 @@ import dmd.root.array; import dmd.common.outbuffer; import dmd.root.rmem; import dmd.tokens; +import dmd.typesem : size; /*********************************************************** */ @@ -1872,22 +1873,30 @@ final class CParser(AST) : Parser!AST * init-declarator: * declarator simple-asm-expr (opt) gnu-attributes (opt) * declarator simple-asm-expr (opt) gnu-attributes (opt) = initializer + * + * Clang also allows simple-asm-expr after gnu-attributes. */ + while (1) + { + if (token.value == TOK.asm_) + { + asmName = cparseGnuAsmLabel(); + /* This is a data definition, there cannot now be a + * function definition. + */ + first = false; + } + else if (token.value == TOK.__attribute__) + cparseGnuAttributes(specifier); + else + break; + } + switch (token.value) { case TOK.assign: case TOK.comma: case TOK.semicolon: - case TOK.asm_: - case TOK.__attribute__: - if (token.value == TOK.asm_) - asmName = cparseGnuAsmLabel(); - if (token.value == TOK.__attribute__) - { - cparseGnuAttributes(specifier); - if (token.value == TOK.leftCurly) - break; // function definition - } /* This is a data definition, there cannot now be a * function definition. */ @@ -3626,6 +3635,12 @@ final class CParser(AST) : Parser!AST * type on the target machine. It's the opposite of __attribute__((packed)) */ } + else if (token.ident == Id.packed) + { + specifier.packalign.set(1); + specifier.packalign.setPack(true); + nextToken(); + } else if (token.ident == Id.always_inline) // https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html { specifier.scw |= SCW.xinline; @@ -3974,7 +3989,7 @@ final class CParser(AST) : Parser!AST members = new AST.Dsymbols(); // so `members` will be non-null even with 0 members while (token.value != TOK.rightCurly) { - cparseStructDeclaration(members); + cparseStructDeclaration(members, packalign); if (token.value == TOK.endOfFile) break; @@ -3988,6 +4003,24 @@ final class CParser(AST) : Parser!AST * struct-declarator (opt) */ } + + /* GNU Extensions + * Parse the postfix gnu-attributes (opt) + */ + Specifier specifier; + if (token.value == TOK.__attribute__) + cparseGnuAttributes(specifier); + if (!specifier.packalign.isUnknown) + { + packalign.set(specifier.packalign.get()); + packalign.setPack(specifier.packalign.isPack()); + foreach (ref d; (*members)[]) + { + auto decls = new AST.Dsymbols(1); + (*decls)[0] = d; + d = new AST.AlignDeclaration(d.loc, specifier.packalign, decls); + } + } } else if (!tag) error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion)); @@ -4019,8 +4052,9 @@ final class CParser(AST) : Parser!AST * declarator (opt) : constant-expression * Params: * members = where to put the fields (members) + * packalign = alignment to use for struct members */ - void cparseStructDeclaration(AST.Dsymbols* members) + void cparseStructDeclaration(AST.Dsymbols* members, structalign_t packalign) { //printf("cparseStructDeclaration()\n"); if (token.value == TOK._Static_assert) @@ -4031,7 +4065,7 @@ final class CParser(AST) : Parser!AST } Specifier specifier; - specifier.packalign = this.packalign; + specifier.packalign = packalign.isUnknown ? this.packalign : packalign; auto tspec = cparseSpecifierQualifierList(LVL.member, specifier); if (!tspec) { diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d index 334088b..0609778 100644 --- a/gcc/d/dmd/cppmangle.d +++ b/gcc/d/dmd/cppmangle.d @@ -2197,7 +2197,7 @@ private extern(C++) final class ComponentVisitor : Visitor /// Set to the result of the comparison private bool result; - public this(RootObject base) @safe + public this(RootObject base) @trusted { switch (base.dyncast()) { diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index d2fcf5f..8ed70c6 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -17,6 +17,7 @@ import dmd.arraytypes; import dmd.astenums; import dmd.constfold; import dmd.compiler; +import dmd.dcast : implicitConvTo; import dmd.dclass; import dmd.declaration; import dmd.dinterpret; diff --git a/gcc/d/dmd/cxxfrontend.d b/gcc/d/dmd/cxxfrontend.d index 403588b..0b3096d 100644 --- a/gcc/d/dmd/cxxfrontend.d +++ b/gcc/d/dmd/cxxfrontend.d @@ -265,10 +265,16 @@ bool functionSemantic3(FuncDeclaration fd) return dmd.funcsem.functionSemantic3(fd); } -MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* names) +MATCH leastAsSpecialized(FuncDeclaration fd, FuncDeclaration g, Identifiers* names) { import dmd.funcsem; - return dmd.funcsem.leastAsSpecialized(f, g, names); + return dmd.funcsem.leastAsSpecialized(fd, g, names); +} + +PURE isPure(FuncDeclaration fd) +{ + import dmd.funcsem; + return dmd.funcsem.isPure(fd); } /*********************************************************** @@ -627,6 +633,24 @@ Type referenceTo(Type type) return dmd.typesem.referenceTo(type); } +uinteger_t size(Type type) +{ + import dmd.typesem; + return dmd.typesem.size(type); +} + +uinteger_t size(Type type, const ref Loc loc) +{ + import dmd.typesem; + return dmd.typesem.size(type, loc); +} + +MATCH implicitConvTo(Type from, Type to) +{ + import dmd.dcast; + return dmd.dcast.implicitConvTo(from, to); +} + /*********************************************************** * typinf.d */ diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 78781f4..2905967 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -20,6 +20,7 @@ import dmd.arraytypes; import dmd.astenums; import dmd.dclass; import dmd.declaration; +import dmd.denum; import dmd.dinterpret; import dmd.dscope; import dmd.dstruct; @@ -1468,6 +1469,463 @@ MATCH implicitConvTo(Expression e, Type t) } } +/******************************** + * Determine if 'from' can be implicitly converted + * to type 'to'. + * Returns: + * MATCH.nomatch, MATCH.convert, MATCH.constant, MATCH.exact + */ +MATCH implicitConvTo(Type from, Type to) +{ + MATCH visitType(Type from) + { + //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to); + //printf("from: %s\n", from.toChars()); + //printf("to : %s\n", to.toChars()); + if (from.equals(to)) + return MATCH.exact; + return MATCH.nomatch; + + } + + MATCH visitBasic(TypeBasic from) + { + //printf("TypeBasic::implicitConvTo(%s) from %s\n", to.toChars(), from.toChars()); + if (from == to) + return MATCH.exact; + + if (from.ty == to.ty) + { + if (from.mod == to.mod) + return MATCH.exact; + else if (MODimplicitConv(from.mod, to.mod)) + return MATCH.constant; + else if (!((from.mod ^ to.mod) & MODFlags.shared_)) // for wild matching + return MATCH.constant; + else + return MATCH.convert; + } + + if (from.ty == Tvoid || to.ty == Tvoid) + return MATCH.nomatch; + if (to.ty == Tbool) + return MATCH.nomatch; + + TypeBasic tob; + if (to.ty == Tvector && to.deco) + { + TypeVector tv = cast(TypeVector)to; + tob = tv.elementType(); + } + else if (auto te = to.isTypeEnum()) + { + EnumDeclaration ed = te.sym; + if (ed.isSpecial()) + { + /* Special enums that allow implicit conversions to them + * with a MATCH.convert + */ + tob = to.toBasetype().isTypeBasic(); + } + else + return MATCH.nomatch; + } + else + tob = to.isTypeBasic(); + if (!tob) + return MATCH.nomatch; + + if (from.flags & TFlags.integral) + { + // Disallow implicit conversion of integers to imaginary or complex + if (tob.flags & (TFlags.imaginary | TFlags.complex)) + return MATCH.nomatch; + + // If converting from integral to integral + if (tob.flags & TFlags.integral) + { + const sz = size(from, Loc.initial); + const tosz = tob.size(Loc.initial); + + /* Can't convert to smaller size + */ + if (sz > tosz) + return MATCH.nomatch; + /* Can't change sign if same size + */ + //if (sz == tosz && (flags ^ tob.flags) & TFlags.unsigned) + // return MATCH.nomatch; + } + } + else if (from.flags & TFlags.floating) + { + // Disallow implicit conversion of floating point to integer + if (tob.flags & TFlags.integral) + return MATCH.nomatch; + + assert(tob.flags & TFlags.floating || to.ty == Tvector); + + // Disallow implicit conversion from complex to non-complex + if (from.flags & TFlags.complex && !(tob.flags & TFlags.complex)) + return MATCH.nomatch; + + // Disallow implicit conversion of real or imaginary to complex + if (from.flags & (TFlags.real_ | TFlags.imaginary) && tob.flags & TFlags.complex) + return MATCH.nomatch; + + // Disallow implicit conversion to-from real and imaginary + if ((from.flags & (TFlags.real_ | TFlags.imaginary)) != (tob.flags & (TFlags.real_ | TFlags.imaginary))) + return MATCH.nomatch; + } + return MATCH.convert; + + } + + MATCH visitVector(TypeVector from) + { + //printf("TypeVector::implicitConvTo(%s) from %s\n", to.toChars(), from.toChars()); + if (from == to) + return MATCH.exact; + if (to.ty != Tvector) + return MATCH.nomatch; + + TypeVector tv = cast(TypeVector)to; + assert(from.basetype.ty == Tsarray && tv.basetype.ty == Tsarray); + + // Can't convert to a vector which has different size. + if (from.basetype.size() != tv.basetype.size()) + return MATCH.nomatch; + + // Allow conversion to void[] + if (tv.basetype.nextOf().ty == Tvoid) + return MATCH.convert; + + // Otherwise implicitly convertible only if basetypes are. + return from.basetype.implicitConvTo(tv.basetype); + } + + MATCH visitSArray(TypeSArray from) + { + //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), from.toChars()); + if (auto ta = to.isTypeDArray()) + { + if (!MODimplicitConv(from.next.mod, ta.next.mod)) + return MATCH.nomatch; + + /* Allow conversion to void[] + */ + if (ta.next.ty == Tvoid) + { + return MATCH.convert; + } + + MATCH m = from.next.constConv(ta.next); + if (m > MATCH.nomatch) + { + return MATCH.convert; + } + return MATCH.nomatch; + } + if (auto tsa = to.isTypeSArray()) + { + if (from == to) + return MATCH.exact; + + if (from.dim.equals(tsa.dim)) + { + MATCH m = from.next.implicitConvTo(tsa.next); + + /* Allow conversion to non-interface base class. + */ + if (m == MATCH.convert && + from.next.ty == Tclass) + { + if (auto toc = tsa.next.isTypeClass) + { + if (!toc.sym.isInterfaceDeclaration) + return MATCH.convert; + } + } + + /* Since static arrays are value types, allow + * conversions from const elements to non-const + * ones, just like we allow conversion from const int + * to int. + */ + if (m >= MATCH.constant) + { + if (from.mod != to.mod) + m = MATCH.constant; + return m; + } + } + } + return MATCH.nomatch; + } + + MATCH visitDArray(TypeDArray from) + { + //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), from.toChars()); + if (from.equals(to)) + return MATCH.exact; + + if (auto ta = to.isTypeDArray()) + { + if (!MODimplicitConv(from.next.mod, ta.next.mod)) + return MATCH.nomatch; // not const-compatible + + /* Allow conversion to void[] + */ + if (from.next.ty != Tvoid && ta.next.ty == Tvoid) + { + return MATCH.convert; + } + + MATCH m = from.next.constConv(ta.next); + if (m > MATCH.nomatch) + { + if (m == MATCH.exact && from.mod != to.mod) + m = MATCH.constant; + return m; + } + } + + return visitType(from); + } + + MATCH visitAArray(TypeAArray from) + { + //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), from.toChars()); + if (from.equals(to)) + return MATCH.exact; + + if (auto ta = to.isTypeAArray()) + { + if (!MODimplicitConv(from.next.mod, ta.next.mod)) + return MATCH.nomatch; // not const-compatible + + if (!MODimplicitConv(from.index.mod, ta.index.mod)) + return MATCH.nomatch; // not const-compatible + + MATCH m = from.next.constConv(ta.next); + MATCH mi = from.index.constConv(ta.index); + if (m > MATCH.nomatch && mi > MATCH.nomatch) + { + return MODimplicitConv(from.mod, to.mod) ? MATCH.constant : MATCH.nomatch; + } + } + return visitType(from); + } + + /+ + + Checks whether this function type is convertible to ` to` + + when used in a function pointer / delegate. + + + + Params: + + to = target type + + + + Returns: + + MATCH.nomatch: `to` is not a covaraint function + + MATCH.convert: `to` is a covaraint function + + MATCH.exact: `to` is identical to this function + +/ + MATCH implicitPointerConv(TypeFunction tf, Type to) + { + assert(to); + + if (tf.equals(to)) + return MATCH.constant; + + if (tf.covariant(to) == Covariant.yes) + { + Type tret = tf.nextOf(); + Type toret = to.nextOf(); + if (tret.ty == Tclass && toret.ty == Tclass) + { + /* https://issues.dlang.org/show_bug.cgi?id=10219 + * Check covariant interface return with offset tweaking. + * interface I {} + * class C : Object, I {} + * I function() dg = function C() {} // should be error + */ + int offset = 0; + if (toret.isBaseOf(tret, &offset) && offset != 0) + return MATCH.nomatch; + } + return MATCH.convert; + } + + return MATCH.nomatch; + } + + MATCH visitPointer(TypePointer from) + { + //printf("TypePointer::implicitConvTo(to = %s) %s\n", to.toChars(), from.toChars()); + if (from.equals(to)) + return MATCH.exact; + + // Only convert between pointers + auto tp = to.isTypePointer(); + if (!tp) + return MATCH.nomatch; + + assert(from.next); + assert(tp.next); + + // Conversion to void* + if (tp.next.ty == Tvoid) + { + // Function pointer conversion doesn't check constness? + if (from.next.ty == Tfunction) + return MATCH.convert; + + if (!MODimplicitConv(from.next.mod, tp.next.mod)) + return MATCH.nomatch; // not const-compatible + + return from.next.ty == Tvoid ? MATCH.constant : MATCH.convert; + } + + // Conversion between function pointers + if (auto thisTf = from.next.isTypeFunction()) + return implicitPointerConv(thisTf, tp.next); + + // Default, no implicit conversion between the pointer targets + MATCH m = from.next.constConv(tp.next); + + if (m == MATCH.exact && from.mod != to.mod) + m = MATCH.constant; + return m; + } + + MATCH visitDelegate(TypeDelegate from) + { + //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", from, to); + //printf("from: %s\n", from.toChars()); + //printf("to : %s\n", to.toChars()); + if (from.equals(to)) + return MATCH.exact; + + if (auto toDg = to.isTypeDelegate()) + { + MATCH m = implicitPointerConv(from.next.isTypeFunction(), toDg.next); + + // Retain the old behaviour for this refactoring + // Should probably be changed to constant to match function pointers + if (m > MATCH.convert) + m = MATCH.convert; + + return m; + } + + return MATCH.nomatch; + } + + MATCH visitStruct(TypeStruct from) + { + //printf("TypeStruct::implicitConvTo(%s => %s)\n", from.toChars(), to.toChars()); + MATCH m = from.implicitConvToWithoutAliasThis(to); + return m == MATCH.nomatch ? from.implicitConvToThroughAliasThis(to) : m; + } + + MATCH visitEnum(TypeEnum from) + { + import dmd.enumsem : getMemtype; + + MATCH m; + //printf("TypeEnum::implicitConvTo() %s to %s\n", from.toChars(), to.toChars()); + if (from.ty == to.ty && from.sym == (cast(TypeEnum)to).sym) + m = (from.mod == to.mod) ? MATCH.exact : MATCH.constant; + else if (from.sym.getMemtype(Loc.initial).implicitConvTo(to)) + m = MATCH.convert; // match with conversions + else + m = MATCH.nomatch; // no match + return m; + } + + MATCH visitClass(TypeClass from) + { + //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to.toChars(), from.toChars()); + MATCH m = from.implicitConvToWithoutAliasThis(to); + return m ? m : from.implicitConvToThroughAliasThis(to); + } + + MATCH visitTuple(TypeTuple from) + { + if (from == to) + return MATCH.exact; + if (auto tt = to.isTypeTuple()) + { + if (from.arguments.length == tt.arguments.length) + { + MATCH m = MATCH.exact; + for (size_t i = 0; i < tt.arguments.length; i++) + { + Parameter arg1 = (*from.arguments)[i]; + Parameter arg2 = (*tt.arguments)[i]; + MATCH mi = arg1.type.implicitConvTo(arg2.type); + if (mi < m) + m = mi; + } + return m; + } + } + return MATCH.nomatch; + } + + MATCH visitNull(TypeNull from) + { + //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", from, to); + //printf("from: %s\n", from.toChars()); + //printf("to : %s\n", to.toChars()); + MATCH m = visitType(cast(Type)from); + if (m != MATCH.nomatch) + return m; + + //NULL implicitly converts to any pointer type or dynamic array + //if (type.ty == Tpointer && type.nextOf().ty == Tvoid) + { + Type tb = to.toBasetype(); + if (tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tclass || tb.ty == Tdelegate) + return MATCH.constant; + } + + return MATCH.nomatch; + } + + MATCH visitNoreturn(TypeNoreturn from) + { + //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", from, to); + //printf("from: %s\n", from.toChars()); + //printf("to : %s\n", to.toChars()); + if (from.equals(to)) + return MATCH.exact; + + // Different qualifiers? + if (to.ty == Tnoreturn) + return MATCH.constant; + + // Implicitly convertible to any type + return MATCH.convert; + } + + switch(from.ty) + { + default: return from.isTypeBasic() ? visitBasic(from.isTypeBasic()) : visitType(from); + case Tvector: return visitVector(from.isTypeVector()); + case Tsarray: return visitSArray(from.isTypeSArray()); + case Tarray: return visitDArray(from.isTypeDArray()); + case Taarray: return visitAArray(from.isTypeAArray()); + case Tpointer: return visitPointer(from.isTypePointer()); + case Tdelegate: return visitDelegate(from.isTypeDelegate()); + case Tstruct: return visitStruct(from.isTypeStruct()); + case Tenum: return visitEnum(from.isTypeEnum()); + case Tclass: return visitClass(from.isTypeClass()); + case Ttuple: return visitTuple(from.isTypeTuple()); + case Tnull: return visitNull(from.isTypeNull()); + case Tnoreturn: return visitNoreturn(from.isTypeNoreturn()); + } +} + /** * Same as implicitConvTo(); except follow C11 rules, which are quite a bit * more permissive than D. diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index fdfe8a8..8f706fb 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -35,6 +35,7 @@ namespace dmd bool functionSemantic(FuncDeclaration* fd); bool functionSemantic3(FuncDeclaration* fd); MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, Identifiers *names); + PURE isPure(FuncDeclaration *f); } //enum STC : ulong from astenums.d: @@ -719,7 +720,6 @@ public: bool isCodeseg() const override final; bool isOverloadable() const override final; bool isAbstract() override final; - PURE isPure(); bool isSafe(); bool isTrusted(); bool isNogc(); diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d index 2efdd31..4c4c063 100644 --- a/gcc/d/dmd/dimport.d +++ b/gcc/d/dmd/dimport.d @@ -165,11 +165,10 @@ extern (C++) final class Import : Dsymbol * https://issues.dlang.org/show_bug.cgi?id=5412 */ assert(ident && ident == s.ident); - Import imp; - if (!aliasId && (imp = s.isImport()) !is null && !imp.aliasId) - return true; - else + if (aliasId) return false; + const imp = s.isImport(); + return imp && !imp.aliasId; } override inout(Import) isImport() inout diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index 5493fc1..52520be 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -50,7 +50,7 @@ import dmd.rootobject; import dmd.root.utf; import dmd.statement; import dmd.tokens; -import dmd.typesem : mutableOf, equivalent, pointerTo, sarrayOf, arrayOf; +import dmd.typesem : mutableOf, equivalent, pointerTo, sarrayOf, arrayOf, size; import dmd.utils : arrayCastBigEndian; import dmd.visitor; diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index a8b43da..84048af 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -2587,7 +2587,7 @@ TypeFunction isTypeFunction(Dsymbol s) @safe { Type t = f.originalType ? f.originalType : f.type; if (t.ty == Tfunction) - return cast(TypeFunction)t; + return (() @trusted => cast(TypeFunction)t)(); } return null; } diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index 416bd57..64f19d9 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -456,7 +456,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration Type tv = v.type.baseElemOf(); if (tv.ty == Tstruct) { - TypeStruct ts = cast(TypeStruct)tv; + auto ts = cast(TypeStruct)tv; StructDeclaration sd = ts.sym; if (!sd.isPOD()) { @@ -608,7 +608,7 @@ bool _isZeroInit(Expression exp) case EXP.string_: { - StringExp se = cast(StringExp)exp; + auto se = cast(StringExp)exp; if (se.type.toBasetype().ty == Tarray) // if initializing a dynamic array return se.len == 0; diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 4a21b14..e32f5fa 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -7270,7 +7270,7 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor // 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 && - fieldState.bitOffset + bfd.fieldWidth > memalignsize * 8) + fieldState.bitOffset + bfd.fieldWidth > memsize * 8) { if (log) printf("more units of alignment than its type\n"); startNewField(); // the bit field is full @@ -7278,10 +7278,10 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor else { // if alignment boundary is crossed - uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset; + uint start = (fieldState.fieldOffset * 8 + fieldState.bitOffset) % (memalignsize * 8); uint end = start + bfd.fieldWidth; //printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize); - if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8)) + if (start / (memsize * 8) != (end - 1) / (memsize * 8)) { if (log) printf("alignment is crossed\n"); startNewField(); diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 33ec6b1..8fcbbad 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -89,7 +89,7 @@ private enum LOG = false; enum IDX_NOTFOUND = 0x12345678; -pure nothrow @nogc @safe +pure nothrow @nogc @trusted { /******************************************** @@ -143,6 +143,11 @@ inout(TemplateParameter) isTemplateParameter(inout RootObject o) return cast(inout(TemplateParameter))o; } +} // end @trusted casts + +pure nothrow @nogc @safe +{ + /************************************** * Is this Object an error? */ @@ -282,6 +287,18 @@ private bool match(RootObject o1, RootObject o2) o1, o1.toChars(), o1.dyncast(), o2, o2.toChars(), o2.dyncast()); } + bool yes() + { + static if (log) + printf("\t. match\n"); + return true; + } + bool no() + { + static if (log) + printf("\t. nomatch\n"); + return false; + } /* A proper implementation of the various equals() overrides * should make it possible to just do o1.equals(o2), but * we'll do that another day. @@ -294,7 +311,7 @@ private bool match(RootObject o1, RootObject o2) { auto t2 = isType(o2); if (!t2) - goto Lnomatch; + return no(); static if (log) { @@ -302,15 +319,15 @@ private bool match(RootObject o1, RootObject o2) printf("\tt2 = %s\n", t2.toChars()); } if (!t1.equals(t2)) - goto Lnomatch; + return no(); - goto Lmatch; + return yes(); } if (auto e1 = getExpression(o1)) { auto e2 = getExpression(o2); if (!e2) - goto Lnomatch; + return no(); static if (log) { @@ -323,15 +340,15 @@ private bool match(RootObject o1, RootObject o2) // as well as expression equality to ensure templates are properly // matched. if (!(e1.type && e2.type && e1.type.equals(e2.type)) || !e1.equals(e2)) - goto Lnomatch; + return no(); - goto Lmatch; + return yes(); } if (auto s1 = isDsymbol(o1)) { auto s2 = isDsymbol(o2); if (!s2) - goto Lnomatch; + return no(); static if (log) { @@ -339,17 +356,17 @@ private bool match(RootObject o1, RootObject o2) printf("\ts2 = %s \n", s2.kind(), s2.toChars()); } if (!s1.equals(s2)) - goto Lnomatch; + return no(); if (s1.parent != s2.parent && !s1.isFuncDeclaration() && !s2.isFuncDeclaration()) - goto Lnomatch; + return no(); - goto Lmatch; + return yes(); } if (auto u1 = isTuple(o1)) { auto u2 = isTuple(o2); if (!u2) - goto Lnomatch; + return no(); static if (log) { @@ -357,19 +374,11 @@ private bool match(RootObject o1, RootObject o2) printf("\tu2 = %s\n", u2.toChars()); } if (!arrayObjectMatch(u1.objects, u2.objects)) - goto Lnomatch; + return no(); - goto Lmatch; + return yes(); } -Lmatch: - static if (log) - printf("\t. match\n"); - return true; - -Lnomatch: - static if (log) - printf("\t. nomatch\n"); - return false; + return yes(); } /************************************ diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index a26f3ab..b5fb0e2 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -21,6 +21,7 @@ import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; +import dmd.dcast : implicitConvTo; import dmd.dclass; import dmd.declaration; import dmd.dimport; @@ -426,7 +427,7 @@ extern (C++) abstract class Expression : ASTNode * is returned via e0. * Otherwise 'e' is directly returned and e0 is set to NULL. */ - extern (D) static Expression extractLast(Expression e, out Expression e0) @safe + extern (D) static Expression extractLast(Expression e, out Expression e0) @trusted { if (e.op != EXP.comma) { @@ -709,7 +710,7 @@ extern (C++) abstract class Expression : ASTNode return true; } - final pure inout nothrow @nogc @safe + final pure inout nothrow @nogc @trusted { inout(IntegerExp) isIntegerExp() { return op == EXP.int64 ? cast(typeof(return))this : null; } inout(ErrorExp) isErrorExp() { return op == EXP.error ? cast(typeof(return))this : null; } @@ -3868,7 +3869,7 @@ extern (C++) final class VectorExp : UnaExp uint dim = ~0; // number of elements in the vector OwnedBy ownedByCtfe = OwnedBy.code; - extern (D) this(const ref Loc loc, Expression e, Type t) @safe + extern (D) this(const ref Loc loc, Expression e, Type t) @trusted { super(loc, EXP.vector, e); assert(t.ty == Tvector); diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 481806d..a69b64d 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -7752,6 +7752,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (auto fmResult = global.fileManager.getFileContents(fileName)) { se = new StringExp(e.loc, fmResult); + se.hexString = true; } else { @@ -9251,13 +9252,27 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // Check for unsafe casts - if (!isSafeCast(ex, t1b, tob)) + string msg; + if (!isSafeCast(ex, t1b, tob, msg)) { - if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to)) + if (sc.setUnsafe(false, exp.loc, + "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to)) { + if (msg.length) + errorSupplemental(exp.loc, "%s", (msg ~ '\0').ptr); return setError(); } } + else if (msg.length) // deprecated unsafe + { + const err = sc.setUnsafePreview(FeatureState.default_, false, exp.loc, + "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to); + // if message was printed + if (sc.func && sc.func.isSafeBypassingInference() && !sc.isDeprecated()) + deprecationSupplemental(exp.loc, "%s", (msg ~ '\0').ptr); + if (err) + return setError(); + } // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built // to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out. @@ -11413,11 +11428,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else e2x = e2x.implicitCastTo(sc, exp.e1.type); } - if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid) - { - if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code")) - return setError(); - } } else { @@ -11449,6 +11459,33 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } } } + + if (exp.e1.op == EXP.slice && + (t1.ty == Tarray || t1.ty == Tsarray) && + t1.nextOf().toBasetype().ty == Tvoid) + { + if (t2.nextOf().implicitConvTo(t1.nextOf())) + { + if (sc.setUnsafe(false, exp.loc, "cannot copy `%s` to `%s` in `@safe` code", t2, t1)) + return setError(); + } + else + { + // copying from non-void to void was overlooked, deprecate + if (sc.setUnsafePreview(FeatureState.default_, false, exp.loc, + "cannot copy `%s` to `%s` in `@safe` code", t2, t1)) + return setError(); + } + if (global.params.fixImmutableConv && !t2.implicitConvTo(t1)) + { + error(exp.loc, "cannot copy `%s` to `%s`", + t2.toChars(), t1.toChars()); + errorSupplemental(exp.loc, + "Source data has incompatible type qualifier(s)"); + errorSupplemental(exp.loc, "Use `cast(%s)` to force copy", t1.toChars()); + return setError(); + } + } if (e2x.op == EXP.error) { result = e2x; @@ -11837,6 +11874,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor (tb2.ty == Tarray || tb2.ty == Tsarray) && (exp.e2.implicitConvTo(exp.e1.type) || (tb2.nextOf().implicitConvTo(tb1next) && + // Do not strip const(void)[] + (!global.params.fixImmutableConv || tb1next.ty != Tvoid) && (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial))))) { // EXP.concatenateAssign @@ -12586,7 +12625,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.type = tb.nextOf().arrayOf(); if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod) { - exp.type = exp.type.nextOf().toHeadMutable().arrayOf(); + // Do not strip const(void)[] + if (!global.params.fixImmutableConv || tb.nextOf().ty != Tvoid) + exp.type = exp.type.nextOf().toHeadMutable().arrayOf(); } if (Type tbn = tb.nextOf()) { diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index cb19b14..54ff826 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -731,72 +731,6 @@ extern (C++) class FuncDeclaration : Declaration inferScope = true; } - final PURE isPure() - { - //printf("FuncDeclaration::isPure() '%s'\n", toChars()); - - - TypeFunction tf = type.toTypeFunction(); - if (purityInprocess) - setImpure(); - if (tf.purity == PURE.fwdref) - tf.purityLevel(); - PURE purity = tf.purity; - if (purity > PURE.weak && isNested()) - purity = PURE.weak; - if (purity > PURE.weak && needThis()) - { - // The attribute of the 'this' reference affects purity strength - if (type.mod & MODFlags.immutable_) - { - } - else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_) - purity = PURE.const_; - else - purity = PURE.weak; - } - tf.purity = purity; - // ^ This rely on the current situation that every FuncDeclaration has a - // unique TypeFunction. - return purity; - } - - extern (D) final PURE isPureBypassingInference() - { - if (purityInprocess) - return PURE.fwdref; - else - return isPure(); - } - - /************************************** - * The function is doing something impure, so mark it as impure. - * - * Params: - * loc = location of impure action - * fmt = format string for error message. Must include "%s `%s`" for the function kind and name. - * arg0 = (optional) argument to format string - * - * Returns: `true` if there's a purity error - */ - extern (D) final bool setImpure(Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null) - { - if (purityInprocess) - { - purityInprocess = false; - if (fmt) - pureViolation = new AttributeViolation(loc, fmt, this, arg0); // impure action - else if (arg0) - pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function - - if (fes) - fes.func.setImpure(loc, fmt, arg0); - } - else if (isPure()) - return true; - return false; - } - extern (D) final uint flags() { return bitFields; @@ -977,187 +911,6 @@ extern (C++) class FuncDeclaration : Declaration } } - /******************************************** - * See if pointers from function parameters, mutable globals, or uplevel functions - * could leak into return value. - * Returns: - * true if the function return value is isolated from - * any inputs to the function - */ - extern (D) final bool isReturnIsolated() - { - //printf("isReturnIsolated(this: %s)\n", this.toChars); - TypeFunction tf = type.toTypeFunction(); - assert(tf.next); - - Type treti = tf.next; - if (tf.isref) - return isTypeIsolatedIndirect(treti); // check influence from parameters - - return isTypeIsolated(treti); - } - - /******************** - * See if pointers from function parameters, mutable globals, or uplevel functions - * could leak into type `t`. - * Params: - * t = type to check if it is isolated - * Returns: - * true if `t` is isolated from - * any inputs to the function - */ - extern (D) final bool isTypeIsolated(Type t) - { - StringTable!Type parentTypes; - const uniqueTypeID = t.getUniqueID(); - if (uniqueTypeID) - { - const cacheResultPtr = uniqueTypeID in isTypeIsolatedCache; - if (cacheResultPtr !is null) - return *cacheResultPtr; - - parentTypes._init(); - const isIsolated = isTypeIsolated(t, parentTypes); - isTypeIsolatedCache[uniqueTypeID] = isIsolated; - return isIsolated; - } - else - { - parentTypes._init(); - return isTypeIsolated(t, parentTypes); - } - } - - ///ditto - extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes) - { - //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars()); - - t = t.baseElemOf(); - switch (t.ty) - { - case Tarray: - case Tpointer: - return isTypeIsolatedIndirect(t.nextOf()); // go down one level - - case Taarray: - case Tclass: - return isTypeIsolatedIndirect(t); - - case Tstruct: - /* Drill down and check the struct's fields - */ - auto sym = t.toDsymbol(null).isStructDeclaration(); - const tName = t.toChars.toDString; - const entry = parentTypes.insert(tName, t); - if (entry == null) - { - //we've already seen this type in a parent, not isolated - return false; - } - foreach (v; sym.fields) - { - Type tmi = v.type.addMod(t.mod); - //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n", - // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars()); - if (!isTypeIsolated(tmi, parentTypes)) - return false; - } - return true; - - default: - return true; - } - } - - /******************************************** - * Params: - * t = type of object to test one level of indirection down - * Returns: - * true if an object typed `t` has no indirections - * which could have come from the function's parameters, mutable - * globals, or uplevel functions. - */ - private bool isTypeIsolatedIndirect(Type t) - { - //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars()); - assert(t); - - /* Since `t` is one level down from an indirection, it could pick - * up a reference to a mutable global or an outer function, so - * return false. - */ - if (!isPureBypassingInference() || isNested()) - return false; - - TypeFunction tf = type.toTypeFunction(); - - //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars()); - - foreach (i, fparam; tf.parameterList) - { - Type tp = fparam.type; - if (!tp) - continue; - - if (fparam.isLazy() || fparam.isReference()) - { - if (!traverseIndirections(tp, t)) - return false; - continue; - } - - /* Goes down one level of indirection, then calls traverseIndirection() on - * the result. - * Returns: - * true if t is isolated from tp - */ - static bool traverse(Type tp, Type t) - { - tp = tp.baseElemOf(); - switch (tp.ty) - { - case Tarray: - case Tpointer: - return traverseIndirections(tp.nextOf(), t); - - case Taarray: - case Tclass: - return traverseIndirections(tp, t); - - case Tstruct: - /* Drill down and check the struct's fields - */ - auto sym = tp.toDsymbol(null).isStructDeclaration(); - foreach (v; sym.fields) - { - Type tprmi = v.type.addMod(tp.mod); - //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars()); - if (!traverse(tprmi, t)) - return false; - } - return true; - - default: - return true; - } - } - - if (!traverse(tp, t)) - return false; - } - // The 'this' reference is a parameter, too - if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis()) - { - Type tthis = ad.getType().addMod(tf.mod); - //printf("\ttthis = %s\n", tthis.toChars()); - if (!traverseIndirections(tthis, t)) - return false; - } - - return true; - } - /**************************************** * Determine if function needs a static frame pointer. * Returns: @@ -1766,116 +1519,6 @@ unittest assert(mismatches.isMutable); } -/************************************** - * Performs type-based alias analysis between a newly created value and a pre- - * existing memory reference: - * - * Assuming that a reference A to a value of type `ta` was available to the code - * that created a reference B to a value of type `tb`, it returns whether B - * might alias memory reachable from A based on the types involved (either - * directly or via any number of indirections in either A or B). - * - * This relation is not symmetric in the two arguments. For example, a - * a `const(int)` reference can point to a pre-existing `int`, but not the other - * way round. - * - * Examples: - * - * ta, tb, result - * `const(int)`, `int`, `false` - * `int`, `const(int)`, `true` - * `int`, `immutable(int)`, `false` - * const(immutable(int)*), immutable(int)*, false // BUG: returns true - * - * Params: - * ta = value type being referred to - * tb = referred to value type that could be constructed from ta - * - * Returns: - * true if reference to `tb` is isolated from reference to `ta` - */ -private bool traverseIndirections(Type ta, Type tb) -{ - //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars()); - - static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass) - { - //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars()); - ta = ta.baseElemOf(); - tb = tb.baseElemOf(); - - // First, check if the pointed-to types are convertible to each other such - // that they might alias directly. - static bool mayAliasDirect(Type source, Type target) - { - return - // if source is the same as target or can be const-converted to target - source.constConv(target) != MATCH.nomatch || - // if target is void and source can be const-converted to target - (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod)); - } - - if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb)) - { - //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass); - return false; - } - if (ta.nextOf() && ta.nextOf() == tb.nextOf()) - { - //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass); - return true; - } - - if (tb.ty == Tclass || tb.ty == Tstruct) - { - /* Traverse the type of each field of the aggregate - */ - bool* found = table.getLvalue(tb.deco); - if (*found == true) - return true; // We have already seen this symbol, break the cycle - else - *found = true; - - AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration(); - foreach (v; sym.fields) - { - Type tprmi = v.type.addMod(tb.mod); - //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars()); - if (!traverse(ta, tprmi, table, reversePass)) - return false; - } - } - else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer) - { - Type tind = tb.nextOf(); - if (!traverse(ta, tind, table, reversePass)) - return false; - } - else if (tb.hasPointers()) - { - // BUG: consider the context pointer of delegate types - return false; - } - - // Still no match, so try breaking up ta if we have not done so yet. - if (!reversePass) - { - scope newTable = AssocArray!(const(char)*, bool)(); - return traverse(tb, ta, newTable, true); - } - - return true; - } - - // To handle arbitrary levels of indirections in both parameters, we - // recursively descend into aggregate members/levels of indirection in both - // `ta` and `tb` while avoiding cycles. Start with the original types. - scope table = AssocArray!(const(char)*, bool)(); - const result = traverse(ta, tb, table, false); - //printf(" returns %d\n", result); - return result; -} - /* For all functions between outerFunc and f, mark them as needing * a closure. */ diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d index ee36a16..594e481 100644 --- a/gcc/d/dmd/funcsem.d +++ b/gcc/d/dmd/funcsem.d @@ -2539,7 +2539,7 @@ void buildEnsureRequire(FuncDeclaration thisfd) /* Rewrite contracts as nested functions, then call them. Doing it as nested * functions means that overriding functions can call them. */ - TypeFunction f = cast(TypeFunction) thisfd.type; + auto f = cast(TypeFunction) thisfd.type; /* Make a copy of the parameters and make them all ref */ static Parameters* toRefCopy(ParameterList parameterList) { @@ -3062,3 +3062,362 @@ extern (D) bool checkNRVO(FuncDeclaration fd) } return true; } + +/************************************** + * The function is doing something impure, so mark it as impure. + * + * Params: + * fd = function declaration to mark + * loc = location of impure action + * fmt = format string for error message. Must include "%s `%s`" for the function kind and name. + * arg0 = (optional) argument to format string + * + * Returns: `true` if there's a purity error + */ +extern (D) bool setImpure(FuncDeclaration fd, Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null) +{ + if (fd.purityInprocess) + { + fd.purityInprocess = false; + if (fmt) + fd.pureViolation = new AttributeViolation(loc, fmt, fd, arg0); // impure action + else if (arg0) + fd.pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function + + if (fd.fes) + fd.fes.func.setImpure(loc, fmt, arg0); + } + else if (fd.isPure()) + return true; + return false; +} + +PURE isPure(FuncDeclaration fd) +{ + //printf("FuncDeclaration::isPure() '%s'\n", toChars()); + + + TypeFunction tf = fd.type.toTypeFunction(); + if (fd.purityInprocess) + fd.setImpure(); + if (tf.purity == PURE.fwdref) + tf.purityLevel(); + PURE purity = tf.purity; + if (purity > PURE.weak && fd.isNested()) + purity = PURE.weak; + if (purity > PURE.weak && fd.needThis()) + { + // The attribute of the 'this' reference affects purity strength + if (fd.type.mod & MODFlags.immutable_) + { + } + else if (fd.type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_) + purity = PURE.const_; + else + purity = PURE.weak; + } + tf.purity = purity; + // ^ This rely on the current situation that every FuncDeclaration has a + // unique TypeFunction. + return purity; +} + +extern (D) PURE isPureBypassingInference(FuncDeclaration fd) +{ + if (fd.purityInprocess) + return PURE.fwdref; + else + return fd.isPure(); +} + +/************************************** + * Performs type-based alias analysis between a newly created value and a pre- + * existing memory reference: + * + * Assuming that a reference A to a value of type `ta` was available to the code + * that created a reference B to a value of type `tb`, it returns whether B + * might alias memory reachable from A based on the types involved (either + * directly or via any number of indirections in either A or B). + * + * This relation is not symmetric in the two arguments. For example, a + * a `const(int)` reference can point to a pre-existing `int`, but not the other + * way round. + * + * Examples: + * + * ta, tb, result + * `const(int)`, `int`, `false` + * `int`, `const(int)`, `true` + * `int`, `immutable(int)`, `false` + * const(immutable(int)*), immutable(int)*, false // BUG: returns true + * + * Params: + * ta = value type being referred to + * tb = referred to value type that could be constructed from ta + * + * Returns: + * true if reference to `tb` is isolated from reference to `ta` + */ +bool traverseIndirections(Type ta, Type tb) +{ + //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars()); + + static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass) + { + //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars()); + ta = ta.baseElemOf(); + tb = tb.baseElemOf(); + + // First, check if the pointed-to types are convertible to each other such + // that they might alias directly. + static bool mayAliasDirect(Type source, Type target) + { + return + // if source is the same as target or can be const-converted to target + source.constConv(target) != MATCH.nomatch || + // if target is void and source can be const-converted to target + (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod)); + } + + if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb)) + { + //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass); + return false; + } + if (ta.nextOf() && ta.nextOf() == tb.nextOf()) + { + //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass); + return true; + } + + if (tb.ty == Tclass || tb.ty == Tstruct) + { + /* Traverse the type of each field of the aggregate + */ + bool* found = table.getLvalue(tb.deco); + if (*found == true) + return true; // We have already seen this symbol, break the cycle + else + *found = true; + + AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration(); + foreach (v; sym.fields) + { + Type tprmi = v.type.addMod(tb.mod); + //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars()); + if (!traverse(ta, tprmi, table, reversePass)) + return false; + } + } + else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer) + { + Type tind = tb.nextOf(); + if (!traverse(ta, tind, table, reversePass)) + return false; + } + else if (tb.hasPointers()) + { + // BUG: consider the context pointer of delegate types + return false; + } + + // Still no match, so try breaking up ta if we have not done so yet. + if (!reversePass) + { + scope newTable = AssocArray!(const(char)*, bool)(); + return traverse(tb, ta, newTable, true); + } + + return true; + } + + // To handle arbitrary levels of indirections in both parameters, we + // recursively descend into aggregate members/levels of indirection in both + // `ta` and `tb` while avoiding cycles. Start with the original types. + scope table = AssocArray!(const(char)*, bool)(); + const result = traverse(ta, tb, table, false); + //printf(" returns %d\n", result); + return result; +} + +/******************************************** + * Params: + * fd = function declaration to check + * t = type of object to test one level of indirection down + * Returns: + * true if an object typed `t` has no indirections + * which could have come from the function's parameters, mutable + * globals, or uplevel functions. + */ +bool isTypeIsolatedIndirect(FuncDeclaration fd, Type t) +{ + //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars()); + assert(t); + + /* Since `t` is one level down from an indirection, it could pick + * up a reference to a mutable global or an outer function, so + * return false. + */ + if (!fd.isPureBypassingInference() || fd.isNested()) + return false; + + TypeFunction tf = fd.type.toTypeFunction(); + + //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars()); + + foreach (i, fparam; tf.parameterList) + { + Type tp = fparam.type; + if (!tp) + continue; + + if (fparam.isLazy() || fparam.isReference()) + { + if (!traverseIndirections(tp, t)) + return false; + continue; + } + + /* Goes down one level of indirection, then calls traverseIndirection() on + * the result. + * Returns: + * true if t is isolated from tp + */ + static bool traverse(Type tp, Type t) + { + tp = tp.baseElemOf(); + switch (tp.ty) + { + case Tarray: + case Tpointer: + return traverseIndirections(tp.nextOf(), t); + + case Taarray: + case Tclass: + return traverseIndirections(tp, t); + + case Tstruct: + /* Drill down and check the struct's fields + */ + auto sym = tp.toDsymbol(null).isStructDeclaration(); + foreach (v; sym.fields) + { + Type tprmi = v.type.addMod(tp.mod); + //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars()); + if (!traverse(tprmi, t)) + return false; + } + return true; + + default: + return true; + } + } + + if (!traverse(tp, t)) + return false; + } + // The 'this' reference is a parameter, too + if (AggregateDeclaration ad = fd.isCtorDeclaration() ? null : fd.isThis()) + { + Type tthis = ad.getType().addMod(tf.mod); + //printf("\ttthis = %s\n", tthis.toChars()); + if (!traverseIndirections(tthis, t)) + return false; + } + + return true; +} + +/******************************************** + * See if pointers from function parameters, mutable globals, or uplevel functions + * could leak into return value. + * Returns: + * true if the function return value is isolated from + * any inputs to the function + */ +extern (D) bool isReturnIsolated(FuncDeclaration fd) +{ + //printf("isReturnIsolated(this: %s)\n", this.toChars); + TypeFunction tf = fd.type.toTypeFunction(); + assert(tf.next); + + Type treti = tf.next; + if (tf.isref) + return fd.isTypeIsolatedIndirect(treti); // check influence from parameters + + return fd.isTypeIsolated(treti); +} + +/******************** + * See if pointers from function parameters, mutable globals, or uplevel functions + * could leak into type `t`. + * Params: + * t = type to check if it is isolated + * Returns: + * true if `t` is isolated from + * any inputs to the function + */ +extern (D) bool isTypeIsolated(FuncDeclaration fd, Type t) +{ + StringTable!Type parentTypes; + const uniqueTypeID = t.getUniqueID(); + if (uniqueTypeID) + { + const cacheResultPtr = uniqueTypeID in fd.isTypeIsolatedCache; + if (cacheResultPtr !is null) + return *cacheResultPtr; + + parentTypes._init(); + const isIsolated = fd.isTypeIsolated(t, parentTypes); + fd.isTypeIsolatedCache[uniqueTypeID] = isIsolated; + return isIsolated; + } + else + { + parentTypes._init(); + return fd.isTypeIsolated(t, parentTypes); + } +} + +///ditto +extern (D) bool isTypeIsolated(FuncDeclaration fd, Type t, ref StringTable!Type parentTypes) +{ + //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars()); + + t = t.baseElemOf(); + switch (t.ty) + { + case Tarray: + case Tpointer: + return fd.isTypeIsolatedIndirect(t.nextOf()); // go down one level + + case Taarray: + case Tclass: + return fd.isTypeIsolatedIndirect(t); + + case Tstruct: + /* Drill down and check the struct's fields + */ + auto sym = t.toDsymbol(null).isStructDeclaration(); + const tName = t.toChars.toDString; + const entry = parentTypes.insert(tName, t); + if (entry == null) + { + //we've already seen this type in a parent, not isolated + return false; + } + foreach (v; sym.fields) + { + Type tmi = v.type.addMod(t.mod); + //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n", + // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars()); + if (!fd.isTypeIsolated(tmi, parentTypes)) + return false; + } + return true; + + default: + return true; + } +} diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 1e72cf7..a44fb28 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/dmd/hdrgen.d @@ -3933,9 +3933,9 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te buf.writeByte(' '); } - void ignoreReturn(string str) + void dg(string str) { - if (str != "return") + if (str != "return" && str != "scope") { // don't write 'ref' for ctors if ((ident == Id.ctor) && str == "ref") @@ -3944,7 +3944,7 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te buf.writeByte(' '); } } - t.attributesApply(&ignoreReturn); + t.attributesApply(&dg); if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen) { @@ -3977,7 +3977,15 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te buf.writeByte(')'); } parametersToBuffer(t.parameterList, buf, hgs); - if (t.isreturn) + if (t.isreturnscope && !t.isreturninferred) + { + buf.writestring(" return scope"); + } + else if (t.isScopeQual && !t.isscopeinferred) + { + buf.writestring(" scope"); + } + if (t.isreturn && !t.isreturnscope && !t.isreturninferred) { buf.writestring(" return"); } diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index dfaf8f5..f676361 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -574,6 +574,7 @@ immutable Msgtable[] msgtable = { "define" }, { "undef" }, { "ident" }, + { "packed" }, ]; diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index a91a0a4..6a2d349 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -21,6 +21,7 @@ import dmd.aggregate; import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; +import dmd.dcast : implicitConvTo; import dmd.dclass; import dmd.declaration; import dmd.denum; @@ -30,7 +31,6 @@ import dmd.dtemplate; import dmd.enumsem; import dmd.errors; import dmd.expression; -import dmd.funcsem; import dmd.globals; import dmd.hdrgen; import dmd.id; @@ -618,20 +618,9 @@ extern (C++) abstract class Type : ASTNode stringtable = stringtable.init; } - final uinteger_t size() - { - return size(Loc.initial); - } - - uinteger_t size(const ref Loc loc) - { - error(loc, "no size for type `%s`", toChars()); - return SIZE_INVALID; - } - uint alignsize() { - return cast(uint)size(Loc.initial); + return cast(uint)size(this, Loc.initial); } /********************************* @@ -1293,22 +1282,6 @@ extern (C++) abstract class Type : ASTNode return ((te = isTypeEnum()) !is null) ? te.toBasetype2() : this; } - /******************************** - * Determine if 'this' can be implicitly converted - * to type 'to'. - * Returns: - * MATCH.nomatch, MATCH.convert, MATCH.constant, MATCH.exact - */ - MATCH implicitConvTo(Type to) - { - //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to); - //printf("from: %s\n", toChars()); - //printf("to : %s\n", to.toChars()); - if (this.equals(to)) - return MATCH.exact; - return MATCH.nomatch; - } - /******************************* * Determine if converting 'this' to 'to' is an identity operation, * a conversion to const operation, or the types aren't the same. @@ -1582,7 +1555,7 @@ extern (C++) abstract class Type : ASTNode } } - final pure inout nothrow @nogc @safe + final pure inout nothrow @nogc @trusted { inout(TypeError) isTypeError() { return ty == Terror ? cast(typeof(return))this : null; } inout(TypeVector) isTypeVector() { return ty == Tvector ? cast(typeof(return))this : null; } @@ -1656,11 +1629,6 @@ extern (C++) final class TypeError : Type return this; } - override uinteger_t size(const ref Loc loc) - { - return SIZE_INVALID; - } - override Expression defaultInitLiteral(const ref Loc loc) { return ErrorExp.get(); @@ -2116,83 +2084,6 @@ extern (C++) final class TypeBasic : Type return this; } - override uinteger_t size(const ref Loc loc) - { - uint size; - //printf("TypeBasic::size()\n"); - switch (ty) - { - case Tint8: - case Tuns8: - size = 1; - break; - - case Tint16: - case Tuns16: - size = 2; - break; - - case Tint32: - case Tuns32: - case Tfloat32: - case Timaginary32: - size = 4; - break; - - case Tint64: - case Tuns64: - case Tfloat64: - case Timaginary64: - size = 8; - break; - - case Tfloat80: - case Timaginary80: - size = target.realsize; - break; - - case Tcomplex32: - size = 8; - break; - - case Tcomplex64: - case Tint128: - case Tuns128: - size = 16; - break; - - case Tcomplex80: - size = target.realsize * 2; - break; - - case Tvoid: - //size = Type::size(); // error message - size = 1; - break; - - case Tbool: - size = 1; - break; - - case Tchar: - size = 1; - break; - - case Twchar: - size = 2; - break; - - case Tdchar: - size = 4; - break; - - default: - assert(0); - } - //printf("TypeBasic::size() = %d\n", size); - return size; - } - override uint alignsize() { return target.alignsize(this); @@ -2234,98 +2125,6 @@ extern (C++) final class TypeBasic : Type return (flags & TFlags.unsigned) != 0; } - override MATCH implicitConvTo(Type to) - { - //printf("TypeBasic::implicitConvTo(%s) from %s\n", to.toChars(), toChars()); - if (this == to) - return MATCH.exact; - - if (ty == to.ty) - { - if (mod == to.mod) - return MATCH.exact; - else if (MODimplicitConv(mod, to.mod)) - return MATCH.constant; - else if (!((mod ^ to.mod) & MODFlags.shared_)) // for wild matching - return MATCH.constant; - else - return MATCH.convert; - } - - if (ty == Tvoid || to.ty == Tvoid) - return MATCH.nomatch; - if (to.ty == Tbool) - return MATCH.nomatch; - - TypeBasic tob; - if (to.ty == Tvector && to.deco) - { - TypeVector tv = cast(TypeVector)to; - tob = tv.elementType(); - } - else if (auto te = to.isTypeEnum()) - { - EnumDeclaration ed = te.sym; - if (ed.isSpecial()) - { - /* Special enums that allow implicit conversions to them - * with a MATCH.convert - */ - tob = to.toBasetype().isTypeBasic(); - } - else - return MATCH.nomatch; - } - else - tob = to.isTypeBasic(); - if (!tob) - return MATCH.nomatch; - - if (flags & TFlags.integral) - { - // Disallow implicit conversion of integers to imaginary or complex - if (tob.flags & (TFlags.imaginary | TFlags.complex)) - return MATCH.nomatch; - - // If converting from integral to integral - if (tob.flags & TFlags.integral) - { - const sz = size(Loc.initial); - const tosz = tob.size(Loc.initial); - - /* Can't convert to smaller size - */ - if (sz > tosz) - return MATCH.nomatch; - /* Can't change sign if same size - */ - //if (sz == tosz && (flags ^ tob.flags) & TFlags.unsigned) - // return MATCH.nomatch; - } - } - else if (flags & TFlags.floating) - { - // Disallow implicit conversion of floating point to integer - if (tob.flags & TFlags.integral) - return MATCH.nomatch; - - assert(tob.flags & TFlags.floating || to.ty == Tvector); - - // Disallow implicit conversion from complex to non-complex - if (flags & TFlags.complex && !(tob.flags & TFlags.complex)) - return MATCH.nomatch; - - // Disallow implicit conversion of real or imaginary to complex - if (flags & (TFlags.real_ | TFlags.imaginary) && tob.flags & TFlags.complex) - return MATCH.nomatch; - - // Disallow implicit conversion to-from real and imaginary - if ((flags & (TFlags.real_ | TFlags.imaginary)) != (tob.flags & (TFlags.real_ | TFlags.imaginary))) - return MATCH.nomatch; - } - return MATCH.convert; - } - override bool isZeroInit(const ref Loc loc) { switch (ty) @@ -2396,11 +2195,6 @@ extern (C++) final class TypeVector : Type return new TypeVector(basetype.syntaxCopy()); } - override uinteger_t size(const ref Loc loc) - { - return basetype.size(); - } - override uint alignsize() { return cast(uint)basetype.size(); @@ -2432,29 +2226,6 @@ extern (C++) final class TypeVector : Type return false; } - override MATCH implicitConvTo(Type to) - { - //printf("TypeVector::implicitConvTo(%s) from %s\n", to.toChars(), toChars()); - if (this == to) - return MATCH.exact; - if (to.ty != Tvector) - return MATCH.nomatch; - - TypeVector tv = cast(TypeVector)to; - assert(basetype.ty == Tsarray && tv.basetype.ty == Tsarray); - - // Can't convert to a vector which has different size. - if (basetype.size() != tv.basetype.size()) - return MATCH.nomatch; - - // Allow conversion to void[] - if (tv.basetype.nextOf().ty == Tvoid) - return MATCH.convert; - - // Otherwise implicitly convertible only if basetypes are. - return basetype.implicitConvTo(tv.basetype); - } - override Expression defaultInitLiteral(const ref Loc loc) { //printf("TypeVector::defaultInitLiteral()\n"); @@ -2545,22 +2316,6 @@ extern (C++) final class TypeSArray : TypeArray return dim.isIntegerExp() && dim.isIntegerExp().getInteger() == 0; } - override uinteger_t size(const ref Loc loc) - { - //printf("TypeSArray::size()\n"); - const n = numberOfElems(loc); - const elemsize = baseElemOf().size(loc); - bool overflow = false; - const sz = mulu(n, elemsize, overflow); - if (overflow || sz >= uint.max) - { - if (elemsize != SIZE_INVALID && n != uint.max) - error(loc, "static array `%s` size overflowed to %lld", toChars(), cast(long)sz); - return SIZE_INVALID; - } - return sz; - } - override uint alignsize() { return next.alignsize(); @@ -2592,65 +2347,6 @@ extern (C++) final class TypeSArray : TypeArray return TypeNext.constConv(to); } - override MATCH implicitConvTo(Type to) - { - //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); - if (auto ta = to.isTypeDArray()) - { - if (!MODimplicitConv(next.mod, ta.next.mod)) - return MATCH.nomatch; - - /* Allow conversion to void[] - */ - if (ta.next.ty == Tvoid) - { - return MATCH.convert; - } - - MATCH m = next.constConv(ta.next); - if (m > MATCH.nomatch) - { - return MATCH.convert; - } - return MATCH.nomatch; - } - if (auto tsa = to.isTypeSArray()) - { - if (this == to) - return MATCH.exact; - - if (dim.equals(tsa.dim)) - { - MATCH m = next.implicitConvTo(tsa.next); - - /* Allow conversion to non-interface base class. - */ - if (m == MATCH.convert && - next.ty == Tclass) - { - if (auto toc = tsa.next.isTypeClass) - { - if (!toc.sym.isInterfaceDeclaration) - return MATCH.convert; - } - } - - /* Since static arrays are value types, allow - * conversions from const elements to non-const - * ones, just like we allow conversion from const int - * to int. - */ - if (m >= MATCH.constant) - { - if (mod != to.mod) - m = MATCH.constant; - return m; - } - } - } - return MATCH.nomatch; - } - override Expression defaultInitLiteral(const ref Loc loc) { static if (LOGDEFAULTINIT) @@ -2736,12 +2432,6 @@ extern (C++) final class TypeDArray : TypeArray return result; } - override uinteger_t size(const ref Loc loc) - { - //printf("TypeDArray::size()\n"); - return target.ptrsize * 2; - } - override uint alignsize() { // A DArray consists of two ptr-sized values, so align it on pointer size @@ -2765,35 +2455,6 @@ extern (C++) final class TypeDArray : TypeArray return true; } - override MATCH implicitConvTo(Type to) - { - //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); - if (equals(to)) - return MATCH.exact; - - if (auto ta = to.isTypeDArray()) - { - if (!MODimplicitConv(next.mod, ta.next.mod)) - return MATCH.nomatch; // not const-compatible - - /* Allow conversion to void[] - */ - if (next.ty != Tvoid && ta.next.ty == Tvoid) - { - return MATCH.convert; - } - - MATCH m = next.constConv(ta.next); - if (m > MATCH.nomatch) - { - if (m == MATCH.exact && mod != to.mod) - m = MATCH.constant; - return m; - } - } - return Type.implicitConvTo(to); - } - override void accept(Visitor v) { v.visit(this); @@ -2835,11 +2496,6 @@ extern (C++) final class TypeAArray : TypeArray return result; } - override uinteger_t size(const ref Loc loc) - { - return target.ptrsize; - } - override bool isZeroInit(const ref Loc loc) { return true; @@ -2850,30 +2506,6 @@ extern (C++) final class TypeAArray : TypeArray return true; } - override MATCH implicitConvTo(Type to) - { - //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars()); - if (equals(to)) - return MATCH.exact; - - if (auto ta = to.isTypeAArray()) - { - if (!MODimplicitConv(next.mod, ta.next.mod)) - return MATCH.nomatch; // not const-compatible - - if (!MODimplicitConv(index.mod, ta.index.mod)) - return MATCH.nomatch; // not const-compatible - - MATCH m = next.constConv(ta.next); - MATCH mi = index.constConv(ta.index); - if (m > MATCH.nomatch && mi > MATCH.nomatch) - { - return MODimplicitConv(mod, to.mod) ? MATCH.constant : MATCH.nomatch; - } - } - return Type.implicitConvTo(to); - } - override MATCH constConv(Type to) { if (auto taa = to.isTypeAArray()) @@ -2922,50 +2554,6 @@ extern (C++) final class TypePointer : TypeNext return result; } - override uinteger_t size(const ref Loc loc) - { - return target.ptrsize; - } - - override MATCH implicitConvTo(Type to) - { - //printf("TypePointer::implicitConvTo(to = %s) %s\n", to.toChars(), toChars()); - if (equals(to)) - return MATCH.exact; - - // Only convert between pointers - auto tp = to.isTypePointer(); - if (!tp) - return MATCH.nomatch; - - assert(this.next); - assert(tp.next); - - // Conversion to void* - if (tp.next.ty == Tvoid) - { - // Function pointer conversion doesn't check constness? - if (this.next.ty == Tfunction) - return MATCH.convert; - - if (!MODimplicitConv(next.mod, tp.next.mod)) - return MATCH.nomatch; // not const-compatible - - return this.next.ty == Tvoid ? MATCH.constant : MATCH.convert; - } - - // Conversion between function pointers - if (auto thisTf = this.next.isTypeFunction()) - return thisTf.implicitPointerConv(tp.next); - - // Default, no implicit conversion between the pointer targets - MATCH m = next.constConv(tp.next); - - if (m == MATCH.exact && mod != to.mod) - m = MATCH.constant; - return m; - } - override MATCH constConv(Type to) { if (next.ty == Tfunction) @@ -3020,11 +2608,6 @@ extern (C++) final class TypeReference : TypeNext return result; } - override uinteger_t size(const ref Loc loc) - { - return target.ptrsize; - } - override bool isZeroInit(const ref Loc loc) { return true; @@ -3285,47 +2868,6 @@ extern (C++) final class TypeFunction : TypeNext return newArgs; } - /+ - + Checks whether this function type is convertible to ` to` - + when used in a function pointer / delegate. - + - + Params: - + to = target type - + - + Returns: - + MATCH.nomatch: `to` is not a covaraint function - + MATCH.convert: `to` is a covaraint function - + MATCH.exact: `to` is identical to this function - +/ - private MATCH implicitPointerConv(Type to) - { - assert(to); - - if (this.equals(to)) - return MATCH.constant; - - if (this.covariant(to) == Covariant.yes) - { - Type tret = this.nextOf(); - Type toret = to.nextOf(); - if (tret.ty == Tclass && toret.ty == Tclass) - { - /* https://issues.dlang.org/show_bug.cgi?id=10219 - * Check covariant interface return with offset tweaking. - * interface I {} - * class C : Object, I {} - * I function() dg = function C() {} // should be error - */ - int offset = 0; - if (toret.isBaseOf(tret, &offset) && offset != 0) - return MATCH.nomatch; - } - return MATCH.convert; - } - - return MATCH.nomatch; - } - /** Extends TypeNext.constConv by also checking for matching attributes **/ override MATCH constConv(Type to) { @@ -3447,39 +2989,11 @@ extern (C++) final class TypeDelegate : TypeNext return result; } - override uinteger_t size(const ref Loc loc) - { - return target.ptrsize * 2; - } - override uint alignsize() { return target.ptrsize; } - override MATCH implicitConvTo(Type to) - { - //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", this, to); - //printf("from: %s\n", toChars()); - //printf("to : %s\n", to.toChars()); - if (this.equals(to)) - return MATCH.exact; - - if (auto toDg = to.isTypeDelegate()) - { - MATCH m = this.next.isTypeFunction().implicitPointerConv(toDg.next); - - // Retain the old behaviour for this refactoring - // Should probably be changed to constant to match function pointers - if (m > MATCH.convert) - m = MATCH.convert; - - return m; - } - - return MATCH.nomatch; - } - override bool isZeroInit(const ref Loc loc) { return true; @@ -3534,11 +3048,6 @@ extern (C++) final class TypeTraits : Type { v.visit(this); } - - override uinteger_t size(const ref Loc loc) - { - return SIZE_INVALID; - } } /****** @@ -3648,12 +3157,6 @@ extern (C++) abstract class TypeQualified : Type idents.push(e); } - override uinteger_t size(const ref Loc loc) - { - error(this.loc, "size of type `%s` is not known", toChars()); - return SIZE_INVALID; - } - override void accept(Visitor v) { v.visit(this); @@ -3759,14 +3262,6 @@ extern (C++) final class TypeTypeof : TypeQualified return t; } - override uinteger_t size(const ref Loc loc) - { - if (exp.type) - return exp.type.size(loc); - else - return TypeQualified.size(loc); - } - override void accept(Visitor v) { v.visit(this); @@ -3825,11 +3320,6 @@ extern (C++) final class TypeStruct : Type return "struct"; } - override uinteger_t size(const ref Loc loc) - { - return sym.size(loc); - } - override uint alignsize() { sym.size(Loc.initial); // give error for forward references @@ -3895,7 +3385,7 @@ extern (C++) final class TypeStruct : Type /* Copy from the initializer symbol for larger symbols, * otherwise the literals expressed as code get excessively large. */ - if (size(loc) > target.ptrsize * 4 && !needsNested()) + if (size(this, loc) > target.ptrsize * 4 && !needsNested()) structinit.useStaticInit = true; structinit.type = this; @@ -4028,7 +3518,7 @@ extern (C++) final class TypeStruct : Type * The check should check for overlap of v with the previous field, * not just starting at the same point */ - if (v.offset == offset) // v is at same offset as previous field + if (!global.params.fixImmutableConv && v.offset == offset) // v is at same offset as previous field continue; // ignore Type tvf = v.type.addMod(mod); // from type @@ -4065,13 +3555,6 @@ extern (C++) final class TypeStruct : Type return MATCH.nomatch; } - override MATCH implicitConvTo(Type to) - { - //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to.toChars()); - MATCH m = implicitConvToWithoutAliasThis(to); - return m == MATCH.nomatch ? implicitConvToThroughAliasThis(to) : m; - } - override MATCH constConv(Type to) { if (equals(to)) @@ -4129,11 +3612,6 @@ extern (C++) final class TypeEnum : Type return this; } - override uinteger_t size(const ref Loc loc) - { - return sym.getMemtype(loc).size(loc); - } - Type memType() { return sym.getMemtype(Loc.initial); @@ -4212,19 +3690,6 @@ extern (C++) final class TypeEnum : Type return memType().needsNested(); } - override MATCH implicitConvTo(Type to) - { - MATCH m; - //printf("TypeEnum::implicitConvTo() %s to %s\n", toChars(), to.toChars()); - if (ty == to.ty && sym == (cast(TypeEnum)to).sym) - m = (mod == to.mod) ? MATCH.exact : MATCH.constant; - else if (sym.getMemtype(Loc.initial).implicitConvTo(to)) - m = MATCH.convert; // match with conversions - else - m = MATCH.nomatch; // no match - return m; - } - override MATCH constConv(Type to) { if (equals(to)) @@ -4292,11 +3757,6 @@ extern (C++) final class TypeClass : Type return "class"; } - override uinteger_t size(const ref Loc loc) - { - return target.ptrsize; - } - override TypeClass syntaxCopy() { return this; @@ -4337,13 +3797,6 @@ extern (C++) final class TypeClass : Type return m; } - override MATCH implicitConvTo(Type to) - { - //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to.toChars(), toChars()); - MATCH m = implicitConvToWithoutAliasThis(to); - return m ? m : implicitConvToThroughAliasThis(to); - } - override MATCH constConv(Type to) { if (equals(to)) @@ -4542,29 +3995,6 @@ extern (C++) final class TypeTuple : Type return false; } - override MATCH implicitConvTo(Type to) - { - if (this == to) - return MATCH.exact; - if (auto tt = to.isTypeTuple()) - { - if (arguments.length == tt.arguments.length) - { - MATCH m = MATCH.exact; - for (size_t i = 0; i < tt.arguments.length; i++) - { - Parameter arg1 = (*arguments)[i]; - Parameter arg2 = (*tt.arguments)[i]; - MATCH mi = arg1.type.implicitConvTo(arg2.type); - if (mi < m) - m = mi; - } - return m; - } - } - return MATCH.nomatch; - } - override void accept(Visitor v) { v.visit(this); @@ -4626,36 +4056,11 @@ extern (C++) final class TypeNull : Type return this; } - override MATCH implicitConvTo(Type to) - { - //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", this, to); - //printf("from: %s\n", toChars()); - //printf("to : %s\n", to.toChars()); - MATCH m = Type.implicitConvTo(to); - if (m != MATCH.nomatch) - return m; - - // NULL implicitly converts to any pointer type or dynamic array - //if (type.ty == Tpointer && type.nextOf().ty == Tvoid) - { - Type tb = to.toBasetype(); - if (tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tclass || tb.ty == Tdelegate) - return MATCH.constant; - } - - return MATCH.nomatch; - } - override bool isBoolean() { return true; } - override uinteger_t size(const ref Loc loc) - { - return tvoidptr.size(loc); - } - override void accept(Visitor v) { v.visit(this); @@ -4683,22 +4088,6 @@ extern (C++) final class TypeNoreturn : Type return this; } - override MATCH implicitConvTo(Type to) - { - //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", this, to); - //printf("from: %s\n", toChars()); - //printf("to : %s\n", to.toChars()); - if (this.equals(to)) - return MATCH.exact; - - // Different qualifiers? - if (to.ty == Tnoreturn) - return MATCH.constant; - - // Implicitly convertible to any type - return MATCH.convert; - } - override MATCH constConv(Type to) { // Either another noreturn or conversion to any type @@ -4710,11 +4099,6 @@ extern (C++) final class TypeNoreturn : Type return true; // bottom type can be implicitly converted to any other type } - override uinteger_t size(const ref Loc loc) - { - return 0; - } - override uint alignsize() { return 0; diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index 1121711..11c27c6 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -228,8 +228,6 @@ public: char *toPrettyChars(bool QualifyTypes = false); static void _init(); - uinteger_t size(); - virtual uinteger_t size(const Loc &loc); virtual unsigned alignsize(); void modToBuffer(OutBuffer& buf) const; char *modToChars() const; @@ -266,7 +264,6 @@ public: virtual Type *makeSharedWildConst(); virtual Type *makeMutable(); Type *toBasetype(); - virtual MATCH implicitConvTo(Type *to); virtual MATCH constConv(Type *to); virtual unsigned char deduceWild(Type *t, bool isRef); @@ -323,7 +320,6 @@ public: const char *kind() override; TypeError *syntaxCopy() override; - uinteger_t size(const Loc &loc) override; Expression *defaultInitLiteral(const Loc &loc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -358,7 +354,6 @@ public: const char *kind() override; TypeBasic *syntaxCopy() override; - uinteger_t size(const Loc &loc) override; unsigned alignsize() override; bool isintegral() override; bool isfloating() override; @@ -367,7 +362,6 @@ public: bool iscomplex() override; bool isscalar() override; bool isunsigned() override; - MATCH implicitConvTo(Type *to) override; bool isZeroInit(const Loc &loc) override; // For eliminating dynamic_cast @@ -383,14 +377,12 @@ public: static TypeVector *create(Type *basetype); const char *kind() override; TypeVector *syntaxCopy() override; - uinteger_t size(const Loc &loc) override; unsigned alignsize() override; bool isintegral() override; bool isfloating() override; bool isscalar() override; bool isunsigned() override; bool isBoolean() override; - MATCH implicitConvTo(Type *to) override; Expression *defaultInitLiteral(const Loc &loc) override; TypeBasic *elementType(); bool isZeroInit(const Loc &loc) override; @@ -413,13 +405,11 @@ public: const char *kind() override; TypeSArray *syntaxCopy() override; bool isIncomplete(); - uinteger_t size(const Loc &loc) override; unsigned alignsize() override; bool isString() override; bool isZeroInit(const Loc &loc) override; structalign_t alignment() override; MATCH constConv(Type *to) override; - MATCH implicitConvTo(Type *to) override; Expression *defaultInitLiteral(const Loc &loc) override; bool hasUnsafeBitpatterns() override; bool hasVoidInitPointers() override; @@ -437,12 +427,10 @@ class TypeDArray final : public TypeArray public: const char *kind() override; TypeDArray *syntaxCopy() override; - uinteger_t size(const Loc &loc) override; unsigned alignsize() override; bool isString() override; bool isZeroInit(const Loc &loc) override; bool isBoolean() override; - MATCH implicitConvTo(Type *to) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -456,10 +444,8 @@ public: static TypeAArray *create(Type *t, Type *index); const char *kind() override; TypeAArray *syntaxCopy() override; - uinteger_t size(const Loc &loc) override; bool isZeroInit(const Loc &loc) override; bool isBoolean() override; - MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; void accept(Visitor *v) override { v->visit(this); } @@ -471,8 +457,6 @@ public: static TypePointer *create(Type *t); const char *kind() override; TypePointer *syntaxCopy() override; - uinteger_t size(const Loc &loc) override; - MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; bool isscalar() override; bool isZeroInit(const Loc &loc) override; @@ -485,7 +469,6 @@ class TypeReference final : public TypeNext public: const char *kind() override; TypeReference *syntaxCopy() override; - uinteger_t size(const Loc &loc) override; bool isZeroInit(const Loc &loc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -615,9 +598,7 @@ public: static TypeDelegate *create(TypeFunction *t); const char *kind() override; TypeDelegate *syntaxCopy() override; - uinteger_t size(const Loc &loc) override; unsigned alignsize() override; - MATCH implicitConvTo(Type *to) override; bool isZeroInit(const Loc &loc) override; bool isBoolean() override; @@ -634,7 +615,6 @@ class TypeTraits final : public Type const char *kind() override; TypeTraits *syntaxCopy() override; - uinteger_t size(const Loc &loc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -657,7 +637,6 @@ public: // representing ident.ident!tiargs.ident. ... etc. Objects idents; - uinteger_t size(const Loc &loc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -694,7 +673,6 @@ public: const char *kind() override; TypeTypeof *syntaxCopy() override; - uinteger_t size(const Loc &loc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -727,7 +705,6 @@ public: static TypeStruct *create(StructDeclaration *sym); const char *kind() override; - uinteger_t size(const Loc &loc) override; unsigned alignsize() override; TypeStruct *syntaxCopy() override; structalign_t alignment() override; @@ -741,7 +718,6 @@ public: bool hasVoidInitPointers() override; bool hasUnsafeBitpatterns() override; bool hasInvariant() override; - MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; unsigned char deduceWild(Type *t, bool isRef) override; @@ -755,7 +731,6 @@ public: const char *kind() override; TypeEnum *syntaxCopy() override; - uinteger_t size(const Loc &loc) override; unsigned alignsize() override; Type *memType(const Loc &loc); bool isintegral() override; @@ -771,7 +746,6 @@ public: bool needsDestruction() override; bool needsCopyOrPostblit() override; bool needsNested() override; - MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; bool isZeroInit(const Loc &loc) override; bool hasVoidInitPointers() override; @@ -790,10 +764,8 @@ public: CPPMANGLE cppmangle; const char *kind() override; - uinteger_t size(const Loc &loc) override; TypeClass *syntaxCopy() override; ClassDeclaration *isClassHandle() override; - MATCH implicitConvTo(Type *to) override; MATCH constConv(Type *to) override; unsigned char deduceWild(Type *t, bool isRef) override; bool isZeroInit(const Loc &loc) override; @@ -838,10 +810,8 @@ public: const char *kind() override; TypeNull *syntaxCopy() override; - MATCH implicitConvTo(Type *to) override; bool isBoolean() override; - uinteger_t size(const Loc &loc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -850,10 +820,8 @@ class TypeNoreturn final : public Type public: const char *kind() override; TypeNoreturn *syntaxCopy() override; - MATCH implicitConvTo(Type* to) override; MATCH constConv(Type* to) override; bool isBoolean() override; - uinteger_t size(const Loc& loc) override; unsigned alignsize() override; void accept(Visitor *v) override { v->visit(this); } @@ -902,4 +870,7 @@ namespace dmd Type *addMod(Type *type, MOD mod); Type *addStorageClass(Type *type, StorageClass stc); Type *substWildTo(Type *type, unsigned mod); + uinteger_t size(Type *type); + uinteger_t size(Type *type, const Loc &loc); + MATCH implicitConvTo(Type* from, Type* to); } diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d index 624210b..a922719 100644 --- a/gcc/d/dmd/objc.d +++ b/gcc/d/dmd/objc.d @@ -96,7 +96,7 @@ struct ObjcSelector extern (C++) static ObjcSelector* create(FuncDeclaration fdecl) { OutBuffer buf; - TypeFunction ftype = cast(TypeFunction)fdecl.type; + auto ftype = cast(TypeFunction)fdecl.type; const id = fdecl.ident.toString(); const nparams = ftype.parameterList.length; // Special case: property setter @@ -571,7 +571,7 @@ extern(C++) private final class Supported : Objc { if (!fd.objc.selector) return; - TypeFunction tf = cast(TypeFunction)fd.type; + auto tf = cast(TypeFunction)fd.type; if (fd.objc.selector.paramCount != tf.parameterList.parameters.length) .error(fd.loc, "%s `%s` number of colons in Objective-C selector must match number of parameters", fd.kind, fd.toPrettyChars); if (fd.parent && fd.parent.isTemplateInstance()) diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index 2c89a58..ab1b67c 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -110,7 +110,7 @@ Expression expandVar(int result, VarDeclaration v) } if (ei.op == EXP.construct || ei.op == EXP.blit) { - AssignExp ae = cast(AssignExp)ei; + auto ae = cast(AssignExp)ei; ei = ae.e2; if (ei.isConst() == 1) { @@ -1238,18 +1238,21 @@ Expression optimize(Expression e, int result, bool keepLvalue = false) if (expOptimize(e.e1, WANTvalue)) return; const oror = e.op == EXP.orOr; - if (e.e1.toBool().hasValue(oror)) + void returnE_e1() { - // Replace with (e1, oror) - ret = IntegerExp.createBool(oror); - ret = Expression.combine(e.e1, ret); - if (e.type.toBasetype().ty == Tvoid) + ret = e.e1; + if (!e.e1.type.equals(e.type)) { - ret = new CastExp(e.loc, ret, Type.tvoid); + ret = new CastExp(e.loc, ret, e.type); ret.type = e.type; + ret = optimize(ret, result, false); } - ret = optimize(ret, result, false); - return; + } + if (e.e1.toBool().hasValue(oror)) + { + // e_true || e2 -> e_true + // e_false && e2 -> e_false + return returnE_e1(); } expOptimize(e.e2, WANTvalue); if (e.e1.isConst()) @@ -1263,6 +1266,7 @@ Expression optimize(Expression e, int result, bool keepLvalue = false) } else if (e1Opt.hasValue(!oror)) { + if (e.type.toBasetype().ty == Tvoid) ret = e.e2; else @@ -1272,6 +1276,29 @@ Expression optimize(Expression e, int result, bool keepLvalue = false) } } } + else if (e.e2.isConst()) + { + const e2Opt = e.e2.toBool(); + if (e2Opt.hasValue(oror)) + { + // e1 || true -> (e1, true) + // e1 && false -> (e1, false) + ret = IntegerExp.createBool(oror); + ret = Expression.combine(e.e1, ret); + if (e.type.toBasetype().ty == Tvoid) + { + ret = new CastExp(e.loc, ret, Type.tvoid); + ret.type = e.type; + } + ret = optimize(ret, result, false); + } + else if (e2Opt.hasValue(!oror)) + { + // e1 || false -> e1 + // e1 && true -> e1 + return returnE_e1(); + } + } } void visitCmp(CmpExp e) diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d index 5064ac2..f1bd6c9 100644 --- a/gcc/d/dmd/safe.d +++ b/gcc/d/dmd/safe.d @@ -17,6 +17,7 @@ import core.stdc.stdio; import dmd.aggregate; import dmd.astenums; +import dmd.dcast : implicitConvTo; import dmd.dclass; import dmd.declaration; import dmd.dscope; @@ -26,7 +27,7 @@ import dmd.identifier; import dmd.mtype; import dmd.target; import dmd.tokens; -import dmd.typesem : hasPointers, arrayOf; +import dmd.typesem : hasPointers, arrayOf, size; import dmd.funcsem : setUnsafe, setUnsafePreview; /************************************************************* @@ -49,7 +50,7 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg) //printf("checkUnsafeAccess(e: '%s', readonly: %d, printmsg: %d)\n", e.toChars(), readonly, printmsg); if (e.op != EXP.dotVariable) return false; - DotVarExp dve = cast(DotVarExp)e; + auto dve = cast(DotVarExp)e; if (VarDeclaration v = dve.var.isVarDeclaration()) { if (!sc.func) @@ -156,10 +157,11 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg) * e = expression to be cast * tfrom = type of e * tto = type to cast e to + * msg = reason why cast is unsafe or deprecated * Returns: - * true if @safe + * true if @safe or deprecated */ -bool isSafeCast(Expression e, Type tfrom, Type tto) +bool isSafeCast(Expression e, Type tfrom, Type tto, ref string msg) { // Implicit conversions are always safe if (tfrom.implicitConvTo(tto)) @@ -175,18 +177,34 @@ bool isSafeCast(Expression e, Type tfrom, Type tto) { ClassDeclaration cdfrom = tfromb.isClassHandle(); ClassDeclaration cdto = ttob.isClassHandle(); - int offset; + + if (cdfrom == cdto) + goto Lsame; + if (!cdfrom.isBaseOf(cdto, &offset) && !((cdfrom.isInterfaceDeclaration() || cdto.isInterfaceDeclaration()) && cdfrom.classKind == ClassKind.d && cdto.classKind == ClassKind.d)) + { + msg = "Source object type is incompatible with target type"; return false; + } + // no RTTI if (cdfrom.isCPPinterface() || cdto.isCPPinterface()) + { + msg = "No dynamic type information for extern(C++) classes"; return false; + } + if (cdfrom.classKind == ClassKind.cpp || cdto.classKind == ClassKind.cpp) + msg = "No dynamic type information for extern(C++) classes"; + Lsame: if (!MODimplicitConv(tfromb.mod, ttob.mod)) + { + msg = "Incompatible type qualifier"; return false; + } return true; } @@ -210,22 +228,52 @@ bool isSafeCast(Expression e, Type tfrom, Type tto) { if (ttob.ty == Tarray && e.op == EXP.arrayLiteral) return true; + msg = "`void` data may contain pointers and target element type is mutable"; return false; } // If the struct is opaque we don't know about the struct members then the cast becomes unsafe - if (ttobn.ty == Tstruct && !(cast(TypeStruct)ttobn).sym.members || - tfromn.ty == Tstruct && !(cast(TypeStruct)tfromn).sym.members) + if (ttobn.ty == Tstruct && !(cast(TypeStruct)ttobn).sym.members) + { + msg = "Target element type is opaque"; + return false; + } + if (tfromn.ty == Tstruct && !(cast(TypeStruct)tfromn).sym.members) + { + msg = "Source element type is opaque"; return false; + } + + if (e.op != EXP.arrayLiteral) + { + // For bool, only 0 and 1 are safe values + // Runtime array cast reinterprets data + if (ttobn.ty == Tbool && tfromn.ty != Tbool) + msg = "Source element may have bytes which are not 0 or 1"; + else if (ttobn.hasUnsafeBitpatterns()) + msg = "Target element type has unsafe bit patterns"; + + // Can't alias a bool pointer with a non-bool pointer + if (ttobn.ty != Tbool && tfromn.ty == Tbool && ttobn.isMutable()) + msg = "Target element could be assigned a byte which is not 0 or 1"; + else if (tfromn.hasUnsafeBitpatterns() && ttobn.isMutable()) + msg = "Source element type has unsafe bit patterns and target element type is mutable"; + } const frompointers = tfromn.hasPointers(); const topointers = ttobn.hasPointers(); if (frompointers && !topointers && ttobn.isMutable()) + { + msg = "Target element type is mutable and source element type contains a pointer"; return false; + } if (!frompointers && topointers) + { + msg = "Target element type contains a pointer"; return false; + } if (!topointers && ttobn.ty != Tfunction && tfromn.ty != Tfunction && @@ -235,6 +283,7 @@ bool isSafeCast(Expression e, Type tfrom, Type tto) return true; } } + msg = "Source type is incompatible with target type containing a pointer"; return false; } diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d index 4bb3902..06a5eef 100644 --- a/gcc/d/dmd/semantic2.d +++ b/gcc/d/dmd/semantic2.d @@ -315,7 +315,7 @@ private extern(C++) final class Semantic2Visitor : Visitor return arrayHasInvalidEnumInitializer((cast(StructLiteralExp)e).elements); if (e.op == EXP.assocArrayLiteral) { - AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e; + auto ae = cast(AssocArrayLiteralExp)e; return arrayHasInvalidEnumInitializer(ae.values) || arrayHasInvalidEnumInitializer(ae.keys); } @@ -888,4 +888,11 @@ private extern(C++) final class StaticAAVisitor : SemanticTimeTransitiveVisitor aaExp.lowering = loweredExp; } + + // https://issues.dlang.org/show_bug.cgi?id=24602 + // TODO: Is this intionally not visited by SemanticTimeTransitiveVisitor? + override void visit(ClassReferenceExp crExp) + { + this.visit(crExp.value); + } } diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d index 1d4745a..57a6639 100644 --- a/gcc/d/dmd/sideeffect.d +++ b/gcc/d/dmd/sideeffect.d @@ -18,6 +18,7 @@ import dmd.errors; import dmd.expression; import dmd.expressionsem; import dmd.func; +import dmd.funcsem; import dmd.globals; import dmd.id; import dmd.identifier; diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d index a79b78a..81891ff 100644 --- a/gcc/d/dmd/statement.d +++ b/gcc/d/dmd/statement.d @@ -267,57 +267,58 @@ extern (C++) abstract class Statement : ASTNode pure nothrow @nogc inout(ReturnStatement) endsWithReturnStatement() inout { return null; } - final pure inout nothrow @nogc @safe: - - /******************** - * A cheaper method of doing downcasting of Statements. - * Returns: - * the downcast statement if it can be downcasted, otherwise `null` - */ - inout(ErrorStatement) isErrorStatement() { return stmt == STMT.Error ? cast(typeof(return))this : null; } - inout(PeelStatement) isPeelStatement() { return stmt == STMT.Peel ? cast(typeof(return))this : null; } - inout(ScopeStatement) isScopeStatement() { return stmt == STMT.Scope ? cast(typeof(return))this : null; } - inout(ExpStatement) isExpStatement() { return stmt == STMT.Exp ? cast(typeof(return))this : null; } - inout(CompoundStatement) isCompoundStatement() { return stmt == STMT.Compound ? cast(typeof(return))this : null; } - inout(ReturnStatement) isReturnStatement() { return stmt == STMT.Return ? cast(typeof(return))this : null; } - inout(IfStatement) isIfStatement() { return stmt == STMT.If ? cast(typeof(return))this : null; } - inout(ConditionalStatement) isConditionalStatement() { return stmt == STMT.Conditional ? cast(typeof(return))this : null; } - inout(StaticForeachStatement) isStaticForeachStatement() { return stmt == STMT.StaticForeach ? cast(typeof(return))this : null; } - inout(CaseStatement) isCaseStatement() { return stmt == STMT.Case ? cast(typeof(return))this : null; } - inout(DefaultStatement) isDefaultStatement() { return stmt == STMT.Default ? cast(typeof(return))this : null; } - inout(LabelStatement) isLabelStatement() { return stmt == STMT.Label ? cast(typeof(return))this : null; } - inout(GotoStatement) isGotoStatement() { return stmt == STMT.Goto ? cast(typeof(return))this : null; } - inout(GotoDefaultStatement) isGotoDefaultStatement() { return stmt == STMT.GotoDefault ? cast(typeof(return))this : null; } - inout(GotoCaseStatement) isGotoCaseStatement() { return stmt == STMT.GotoCase ? cast(typeof(return))this : null; } - inout(BreakStatement) isBreakStatement() { return stmt == STMT.Break ? cast(typeof(return))this : null; } - inout(DtorExpStatement) isDtorExpStatement() { return stmt == STMT.DtorExp ? cast(typeof(return))this : null; } - inout(MixinStatement) isMixinStatement() { return stmt == STMT.Mixin ? cast(typeof(return))this : null; } - inout(ForwardingStatement) isForwardingStatement() { return stmt == STMT.Forwarding ? cast(typeof(return))this : null; } - inout(DoStatement) isDoStatement() { return stmt == STMT.Do ? cast(typeof(return))this : null; } - inout(WhileStatement) isWhileStatement() { return stmt == STMT.While ? cast(typeof(return))this : null; } - inout(ForStatement) isForStatement() { return stmt == STMT.For ? cast(typeof(return))this : null; } - inout(ForeachStatement) isForeachStatement() { return stmt == STMT.Foreach ? cast(typeof(return))this : null; } - inout(SwitchStatement) isSwitchStatement() { return stmt == STMT.Switch ? cast(typeof(return))this : null; } - inout(ContinueStatement) isContinueStatement() { return stmt == STMT.Continue ? cast(typeof(return))this : null; } - inout(WithStatement) isWithStatement() { return stmt == STMT.With ? cast(typeof(return))this : null; } - inout(TryCatchStatement) isTryCatchStatement() { return stmt == STMT.TryCatch ? cast(typeof(return))this : null; } - inout(ThrowStatement) isThrowStatement() { return stmt == STMT.Throw ? cast(typeof(return))this : null; } - inout(DebugStatement) isDebugStatement() { return stmt == STMT.Debug ? cast(typeof(return))this : null; } - inout(TryFinallyStatement) isTryFinallyStatement() { return stmt == STMT.TryFinally ? cast(typeof(return))this : null; } - inout(ScopeGuardStatement) isScopeGuardStatement() { return stmt == STMT.ScopeGuard ? cast(typeof(return))this : null; } - inout(SwitchErrorStatement) isSwitchErrorStatement() { return stmt == STMT.SwitchError ? cast(typeof(return))this : null; } - inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; } - inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; } - inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; } - inout(CompoundAsmStatement) isCompoundAsmStatement() { return stmt == STMT.CompoundAsm ? cast(typeof(return))this : null; } - inout(PragmaStatement) isPragmaStatement() { return stmt == STMT.Pragma ? cast(typeof(return))this : null; } - inout(StaticAssertStatement) isStaticAssertStatement() { return stmt == STMT.StaticAssert ? cast(typeof(return))this : null; } - inout(CaseRangeStatement) isCaseRangeStatement() { return stmt == STMT.CaseRange ? cast(typeof(return))this : null; } - inout(SynchronizedStatement) isSynchronizedStatement() { return stmt == STMT.Synchronized ? cast(typeof(return))this : null; } - inout(AsmStatement) isAsmStatement() { return stmt == STMT.Asm ? cast(typeof(return))this : null; } - inout(InlineAsmStatement) isInlineAsmStatement() { return stmt == STMT.InlineAsm ? cast(typeof(return))this : null; } - inout(GccAsmStatement) isGccAsmStatement() { return stmt == STMT.GccAsm ? cast(typeof(return))this : null; } - inout(ImportStatement) isImportStatement() { return stmt == STMT.Import ? cast(typeof(return))this : null; } + final pure inout nothrow @nogc @trusted + { + /******************** + * A cheaper method of doing downcasting of Statements. + * Returns: + * the downcast statement if it can be downcasted, otherwise `null` + */ + inout(ErrorStatement) isErrorStatement() { return stmt == STMT.Error ? cast(typeof(return))this : null; } + inout(PeelStatement) isPeelStatement() { return stmt == STMT.Peel ? cast(typeof(return))this : null; } + inout(ScopeStatement) isScopeStatement() { return stmt == STMT.Scope ? cast(typeof(return))this : null; } + inout(ExpStatement) isExpStatement() { return stmt == STMT.Exp ? cast(typeof(return))this : null; } + inout(CompoundStatement) isCompoundStatement() { return stmt == STMT.Compound ? cast(typeof(return))this : null; } + inout(ReturnStatement) isReturnStatement() { return stmt == STMT.Return ? cast(typeof(return))this : null; } + inout(IfStatement) isIfStatement() { return stmt == STMT.If ? cast(typeof(return))this : null; } + inout(ConditionalStatement) isConditionalStatement() { return stmt == STMT.Conditional ? cast(typeof(return))this : null; } + inout(StaticForeachStatement) isStaticForeachStatement() { return stmt == STMT.StaticForeach ? cast(typeof(return))this : null; } + inout(CaseStatement) isCaseStatement() { return stmt == STMT.Case ? cast(typeof(return))this : null; } + inout(DefaultStatement) isDefaultStatement() { return stmt == STMT.Default ? cast(typeof(return))this : null; } + inout(LabelStatement) isLabelStatement() { return stmt == STMT.Label ? cast(typeof(return))this : null; } + inout(GotoStatement) isGotoStatement() { return stmt == STMT.Goto ? cast(typeof(return))this : null; } + inout(GotoDefaultStatement) isGotoDefaultStatement() { return stmt == STMT.GotoDefault ? cast(typeof(return))this : null; } + inout(GotoCaseStatement) isGotoCaseStatement() { return stmt == STMT.GotoCase ? cast(typeof(return))this : null; } + inout(BreakStatement) isBreakStatement() { return stmt == STMT.Break ? cast(typeof(return))this : null; } + inout(DtorExpStatement) isDtorExpStatement() { return stmt == STMT.DtorExp ? cast(typeof(return))this : null; } + inout(MixinStatement) isMixinStatement() { return stmt == STMT.Mixin ? cast(typeof(return))this : null; } + inout(ForwardingStatement) isForwardingStatement() { return stmt == STMT.Forwarding ? cast(typeof(return))this : null; } + inout(DoStatement) isDoStatement() { return stmt == STMT.Do ? cast(typeof(return))this : null; } + inout(WhileStatement) isWhileStatement() { return stmt == STMT.While ? cast(typeof(return))this : null; } + inout(ForStatement) isForStatement() { return stmt == STMT.For ? cast(typeof(return))this : null; } + inout(ForeachStatement) isForeachStatement() { return stmt == STMT.Foreach ? cast(typeof(return))this : null; } + inout(SwitchStatement) isSwitchStatement() { return stmt == STMT.Switch ? cast(typeof(return))this : null; } + inout(ContinueStatement) isContinueStatement() { return stmt == STMT.Continue ? cast(typeof(return))this : null; } + inout(WithStatement) isWithStatement() { return stmt == STMT.With ? cast(typeof(return))this : null; } + inout(TryCatchStatement) isTryCatchStatement() { return stmt == STMT.TryCatch ? cast(typeof(return))this : null; } + inout(ThrowStatement) isThrowStatement() { return stmt == STMT.Throw ? cast(typeof(return))this : null; } + inout(DebugStatement) isDebugStatement() { return stmt == STMT.Debug ? cast(typeof(return))this : null; } + inout(TryFinallyStatement) isTryFinallyStatement() { return stmt == STMT.TryFinally ? cast(typeof(return))this : null; } + inout(ScopeGuardStatement) isScopeGuardStatement() { return stmt == STMT.ScopeGuard ? cast(typeof(return))this : null; } + inout(SwitchErrorStatement) isSwitchErrorStatement() { return stmt == STMT.SwitchError ? cast(typeof(return))this : null; } + inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; } + inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; } + inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; } + inout(CompoundAsmStatement) isCompoundAsmStatement() { return stmt == STMT.CompoundAsm ? cast(typeof(return))this : null; } + inout(PragmaStatement) isPragmaStatement() { return stmt == STMT.Pragma ? cast(typeof(return))this : null; } + inout(StaticAssertStatement) isStaticAssertStatement() { return stmt == STMT.StaticAssert ? cast(typeof(return))this : null; } + inout(CaseRangeStatement) isCaseRangeStatement() { return stmt == STMT.CaseRange ? cast(typeof(return))this : null; } + inout(SynchronizedStatement) isSynchronizedStatement() { return stmt == STMT.Synchronized ? cast(typeof(return))this : null; } + inout(AsmStatement) isAsmStatement() { return stmt == STMT.Asm ? cast(typeof(return))this : null; } + inout(InlineAsmStatement) isInlineAsmStatement() { return stmt == STMT.InlineAsm ? cast(typeof(return))this : null; } + inout(GccAsmStatement) isGccAsmStatement() { return stmt == STMT.GccAsm ? cast(typeof(return))this : null; } + inout(ImportStatement) isImportStatement() { return stmt == STMT.Import ? cast(typeof(return))this : null; } + } } /*********************************************************** diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index d0e1b9a..c5c8a12 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -1381,7 +1381,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) p.type = p.type.addStorageClass(sc).typeSemantic(loc, sc2); if (!exp.implicitConvTo(p.type)) { - error(fs.loc, "cannot implicilty convert range element of type `%s` to variable `%s` of type `%s`", + error(fs.loc, "cannot implicitly convert tuple element of type `%s` to variable `%s` of type `%s`", exp.type.toChars(), p.toChars(), p.type.toChars()); return retError(); } diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d index dadf519..d86be85 100644 --- a/gcc/d/dmd/target.d +++ b/gcc/d/dmd/target.d @@ -25,6 +25,8 @@ module dmd.target; +import core.stdc.stdio; + import dmd.astenums : CHECKENABLE; import dmd.globals : Param; @@ -344,8 +346,8 @@ struct TargetCPP enum Runtime : ubyte { Unspecified, - Clang, - Gcc, + LLVM, + GNU, Microsoft, Sun } diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h index a5caa74..a380bb8 100644 --- a/gcc/d/dmd/target.h +++ b/gcc/d/dmd/target.h @@ -84,8 +84,8 @@ struct TargetCPP enum class Runtime : unsigned char { Unspecified, - Clang, - Gcc, + LLVM, + GNU, Microsoft, Sun }; diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 31ebc4c..33d825a 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -1299,6 +1299,152 @@ Type getIndirection(Type t) return null; } +uinteger_t size(Type t) +{ + return size(t, Loc.initial); +} + +uinteger_t size(Type t, const ref Loc loc) +{ + + uinteger_t visitType(Type t) + { + error(loc, "no size for type `%s`", t.toChars()); + return SIZE_INVALID; + } + + uinteger_t visitBasic(TypeBasic t) + { + uint size; + //printf("TypeBasic::size()\n"); + switch (t.ty) + { + case Tint8: + case Tuns8: + size = 1; + break; + + case Tint16: + case Tuns16: + size = 2; + break; + + case Tint32: + case Tuns32: + case Tfloat32: + case Timaginary32: + size = 4; + break; + + case Tint64: + case Tuns64: + case Tfloat64: + case Timaginary64: + size = 8; + break; + + case Tfloat80: + case Timaginary80: + size = target.realsize; + break; + + case Tcomplex32: + size = 8; + break; + + case Tcomplex64: + case Tint128: + case Tuns128: + size = 16; + break; + + case Tcomplex80: + size = target.realsize * 2; + break; + + case Tvoid: + //size = Type::size(); // error message + size = 1; + break; + + case Tbool: + size = 1; + break; + + case Tchar: + size = 1; + break; + + case Twchar: + size = 2; + break; + + case Tdchar: + size = 4; + break; + + default: + assert(0); + } + + //printf("TypeBasic::size() = %d\n", size); + return size; + } + + uinteger_t visitSArray(TypeSArray t) + { + //printf("TypeSArray::size()\n"); + const n = t.numberOfElems(loc); + const elemsize = t.baseElemOf().size(loc); + bool overflow = false; + const sz = mulu(n, elemsize, overflow); + if (overflow || sz >= uint.max) + { + if (elemsize != SIZE_INVALID && n != uint.max) + error(loc, "static array `%s` size overflowed to %lld", t.toChars(), cast(long)sz); + return SIZE_INVALID; + } + return sz; + + } + + uinteger_t visitTypeQualified(TypeQualified t) + { + if (t.ty == Ttypeof) + { + auto type = (cast(TypeTypeof)t).exp.type; + if (type) + return type.size(loc); + } + + error(t.loc, "size of type `%s` is not known", t.toChars()); + return SIZE_INVALID; + } + + switch(t.ty) + { + default: return t.isTypeBasic() ? visitBasic(t.isTypeBasic()) : visitType(t); + case Ttraits: + case Terror: return SIZE_INVALID; + case Tvector: return t.isTypeVector().basetype.size(); + case Tsarray: return visitSArray(t.isTypeSArray()); + case Tdelegate: + case Tarray: return target.ptrsize * 2; + case Tpointer: + case Treference: + case Tclass: + case Taarray: return target.ptrsize; + case Tident: + case Tinstance: + case Ttypeof: + case Treturn: return visitTypeQualified(cast(TypeQualified)t); + case Tstruct: return t.isTypeStruct().sym.size(loc); + case Tenum: return t.isTypeEnum().sym.getMemtype(loc).size(loc); + case Tnull: return t.tvoidptr.size(loc); + case Tnoreturn: return 0; + } +} + /****************************************** * Perform semantic analysis on a type. * Params: diff --git a/gcc/d/dmd/visitor.d b/gcc/d/dmd/visitor.d index abfd8ca..9082909 100644 --- a/gcc/d/dmd/visitor.d +++ b/gcc/d/dmd/visitor.d @@ -162,6 +162,11 @@ extern (C++) class SemanticTimeTransitiveVisitor : SemanticTimePermissiveVisitor } } + override void visit(ASTCodegen.ClassReferenceExp e) + { + e.value.accept(this); + } + override void visit(ASTCodegen.CompoundLiteralExp e) { if (e.initializer) |