diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index 233342aab015a985908ce2be4bec79875a00316f..a0545d66c1c420e2fb17136611eac6238a247d2f 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -140,7 +140,7 @@ build_frontend_type (tree type) /* Search for type matching size and signedness. */ if (unsignedp != dtype->isunsigned () - || size != dtype->size ()) + || size != dmd::size (dtype)) continue; return dmd::addMod (dtype, mod); @@ -157,7 +157,7 @@ build_frontend_type (tree type) dtype = Type::basic[i]; /* Search for type matching size. */ - if (dtype->size () != size) + if (dmd::size (dtype) != size) continue; return dmd::addMod (dtype, mod); @@ -174,7 +174,7 @@ build_frontend_type (tree type) dtype = Type::basic[i]; /* Search for type matching size. */ - if (dtype->size () != size) + if (dmd::size (dtype) != size) continue; return dmd::addMod (dtype, mod); @@ -215,7 +215,7 @@ build_frontend_type (tree type) break; dtype = dmd::addMod (dmd::sarrayOf (dtype, nunits), mod); - if (target.isVectorTypeSupported (dtype->size (), dtype->nextOf ())) + if (target.isVectorTypeSupported (dmd::size (dtype), dtype->nextOf ())) break; dtype = dmd::addMod (TypeVector::create (dtype), mod); @@ -712,11 +712,11 @@ matches_builtin_type (Type *t1, Type *t2) if (((tb1->isTypePointer () && tb2->isTypePointer ()) || (tb1->isTypeVector () && tb2->isTypeVector ())) - && tb1->implicitConvTo (tb2) != MATCH::nomatch) + && dmd::implicitConvTo (tb1, tb2) != MATCH::nomatch) return true; if (tb1->isintegral () == tb2->isintegral () - && tb1->size () == tb2->size ()) + && dmd::size (tb1) == dmd::size (tb2)) return true; return false; diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc index 2ccd8f90a92c9d7226d14bb0713ebcbe6b962b87..5c9d01d8f018119e25a7be8223d86ea11cc13194 100644 --- a/gcc/d/d-codegen.cc +++ b/gcc/d/d-codegen.cc @@ -904,7 +904,7 @@ identity_compare_p (StructDeclaration *sd) if (offset != vd->offset) return false; - offset += vd->type->size (); + offset += dmd::size (vd->type); } } @@ -2128,7 +2128,7 @@ call_side_effect_free_p (FuncDeclaration *func, Type *type) return false; /* Only consider it as `pure' if it can't modify its arguments. */ - if (func->isPure () == PURE::const_) + if (dmd::isPure (func) == PURE::const_) return true; } diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc index 1e15c037916ba94ee9edfb3cc4e7f66772a24c36..e996c91d344e568d4b6dda389840f9a7fd11e5cb 100644 --- a/gcc/d/d-convert.cc +++ b/gcc/d/d-convert.cc @@ -384,7 +384,7 @@ convert_expr (tree exp, Type *etype, Type *totype) case TY::Tstruct: if (tbtype->ty == TY::Tstruct) { - if (totype->size () == etype->size ()) + if (dmd::size (totype) == dmd::size (etype)) { /* Allowed to cast to structs with same type size. */ result = build_vconvert (build_ctype (totype), exp); @@ -467,8 +467,8 @@ convert_expr (tree exp, Type *etype, Type *totype) else if (tbtype->ty == TY::Tarray) { dinteger_t dim = ebtype->isTypeSArray ()->dim->toInteger (); - dinteger_t esize = ebtype->nextOf ()->size (); - dinteger_t tsize = tbtype->nextOf ()->size (); + dinteger_t esize = dmd::size (ebtype->nextOf ()); + dinteger_t tsize = dmd::size (tbtype->nextOf ()); tree ptrtype = build_ctype (dmd::pointerTo (tbtype->nextOf ())); @@ -498,10 +498,11 @@ convert_expr (tree exp, Type *etype, Type *totype) { /* And allows casting a static array to any struct type too. Type sizes should have already been checked by the frontend. */ - gcc_assert (totype->size () == etype->size ()); + gcc_assert (dmd::size (totype) == dmd::size (etype)); result = build_vconvert (build_ctype (totype), exp); } - else if (tbtype->ty == TY::Tvector && tbtype->size () == ebtype->size ()) + else if (tbtype->ty == TY::Tvector + && dmd::size (tbtype) == dmd::size (ebtype)) { /* Allow casting from array to vector as if its an unaligned load. */ tree type = build_ctype (totype); @@ -526,8 +527,8 @@ convert_expr (tree exp, Type *etype, Type *totype) else if (tbtype->ty == TY::Tarray) { /* Assume tvoid->size() == 1. */ - dinteger_t fsize = ebtype->nextOf ()->toBasetype ()->size (); - dinteger_t tsize = tbtype->nextOf ()->toBasetype ()->size (); + dinteger_t fsize = dmd::size (ebtype->nextOf ()->toBasetype ()); + dinteger_t tsize = dmd::size (tbtype->nextOf ()->toBasetype ()); if (fsize != tsize) { @@ -594,7 +595,7 @@ convert_expr (tree exp, Type *etype, Type *totype) case TY::Tvector: if (tbtype->ty == TY::Tsarray) { - if (tbtype->size () == ebtype->size ()) + if (dmd::size (tbtype) == dmd::size (ebtype)) return build_vconvert (build_ctype (totype), exp); } break; @@ -740,7 +741,7 @@ check_valist_conversion (Expression *expr, Type *totype, bool in_assignment) && valist_array_p (decl->type)); /* OK if conversion between types is allowed. */ - if (type->implicitConvTo (totype) != MATCH::nomatch) + if (dmd::implicitConvTo (type, totype) != MATCH::nomatch) return; if (in_assignment) diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index f642248055813be57024a3a9a8d3aa558a42e183..b6724c3afbcf364c704be9012b14de9204a3b850 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -1709,8 +1709,8 @@ d_types_compatible_p (tree x, tree y) return true; /* Type system allows implicit conversion between. */ - if (tx->implicitConvTo (ty) != MATCH::nomatch - || ty->implicitConvTo (tx) != MATCH::nomatch) + if (dmd::implicitConvTo (tx, ty) != MATCH::nomatch + || dmd::implicitConvTo (ty, tx) != MATCH::nomatch) return true; } diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc index 83775347d36c7ffa6f139b6807465282d38ede79..07131f4095feb048b428d83318ccc18610a6ae0d 100644 --- a/gcc/d/d-target.cc +++ b/gcc/d/d-target.cc @@ -280,7 +280,7 @@ Target::isVectorTypeSupported (int sz, Type *type) /* In [simd/vector extensions], which vector types are supported depends on the target. The implementation is expected to only support the vector types that are implemented in the target's hardware. */ - unsigned HOST_WIDE_INT nunits = sz / type->size (); + unsigned HOST_WIDE_INT nunits = sz / dmd::size (type); tree ctype = build_vector_type (build_ctype (type), nunits); if (!targetm.vector_mode_supported_p (TYPE_MODE (ctype))) @@ -453,7 +453,7 @@ Target::isReturnOnStack (TypeFunction *tf, bool) return false; Type *tn = tf->next->toBasetype (); - if (tn->size () == SIZE_INVALID) + if (dmd::size (tn) == SIZE_INVALID) return false; return (tn->ty == TY::Tstruct || tn->ty == TY::Tsarray); @@ -583,7 +583,7 @@ Target::preferPassByRef (Type *param_type) { /* See note in Target::isReturnOnStack. */ Type *tb = param_type->toBasetype (); - if (tb->size () == SIZE_INVALID) + if (dmd::size (tb) == SIZE_INVALID) return false; return (tb->ty == TY::Tstruct || tb->ty == TY::Tsarray); diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index fa9c429a7ce10c9fa1780c81443fe061b6d4d9ed..6f1be64ba042756b0371d4ead37dcfc04469b968 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -803,7 +803,7 @@ public: return; /* How big a symbol can be should depend on back-end. */ - tree size = build_integer_cst (d->type->size (d->loc), + tree size = build_integer_cst (dmd::size (d->type, d->loc), build_ctype (Type::tsize_t)); if (!valid_constant_size_p (size)) { diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 77e8562abcc346f344c4d264393c1bce0f9dd798..d458bea5e1a593bfcd3455a9fe99cdc29f4c5b09 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 baac0d79b30d975385373a7d18fac21ed81f2946..078759431515ad79f2e4b2d3a2157f62a912a9f7 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 3d80c3d19134c2b48cc52e74a31a7ab6602293d8..ffc1c3e86dfacfcd9c22c09e361b073286358f7e 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 2c7622a9aa016c0ec389022621856ffdc47ce49d..78cb87f2fe7d9b772bc950c9aa0d0da733e9063a 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 d0ec5ebcdbe91db144c3be6ff795b1013444f3ef..e30160d72b92e04bc3c8fd37831009e993fe2b3c 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 5024f9bb210038245eca36bd416a63e8f5fe2cd9..bbc7b867c5531087972a039199e9f83c879c5036 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 2e4833e8fdd7477faf0623d4e922a5b4b0a11f49..17b33d839df82abf7d94a4c1a892752bd6dd1425 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 65330cf5d11fe75e0565e259fc5b65c1b0489165..3b00194ba8a6372923ce7b2f8865411338e415a0 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 e194664383e9a91dccfa9be33c18ad64fddd2597..02dde1b4c0f6fc4b794f5ca6875401b1f77675b9 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 6ec31d5f9bb446a091da61ab9f4105c42f9f258d..54d50cf4a34b1cdc4c344a1778c98668ef68bcc0 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 7fbcd6d9bc1f581898cf9659d3b426ebce9a4635..a4e3c7ecc0350627516b81b8a4dfa88eb26a6789 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 334088b381cd6d979aa61b74c60b24e1cd25f870..0609778e4c774428d880285dbe812adf53ea46ba 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 d2fcf5f796080da6203d27afaccef5bb23a6629e..8ed70c6639e0a0e93444579e185b097dd9d1b70f 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 403588b35e772a1606da5e0f00a15da55325e6f6..0b3096d1f5c7fbf9f30ef8067ed018ea600dce20 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 78781f4ced7c3b3dd47224c47a04e3ba90e19b03..29059678fc2512ac6db401a77c9a94d47f687910 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 fdfe8a86a48b83cff626b5b8515f40384a2c95df..8f706fba33277c5391421f93741d03ff36f5fb44 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 2efdd31bbba011766bd9c107edb628b4cfe442d8..4c4c063cbf2731fd72897a9e9873482b9c8b7380 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 5493fc188812bf1c1892dfec8877d23c848a304c..52520be01df6059aea6c8eb17cf8d2adbb4f64af 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 a8b43da625b3b1fc520ccfe3a9e6e7952c8c93c6..84048af033796ab9a561732f2e830f6c1a15a301 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 416bd57f24bb4e5aa55c3445e8f3efd8ba6aea57..64f19d932ebfe8f374817e03fc708e9e6a35244d 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 4a21b14734235c58dc18e089e21ca32eb05a5adc..e32f5fa221c72ba1f8010815e6cba0d098923fea 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 33ec6b1849f653012b686f9bdb878fece82493eb..8fcbbad2f76953e5e0ee1848fa72568c0cf94bed 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 a26f3ab83b998c5ed8852d411821b0f7d7a9e8b3..b5fb0e2b9b32dbc84825aa51952beb3785a8b1c8 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 481806d392bd0bbb66005e29d2780eddb70c2e77..a69b64d6b784f068e56c54a985b1dac7a8cc216e 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 cb19b14dfb411d1d6d3bb8dfff4287d66f2a1596..54ff82670aebbf87193dbe3e3097a108575fe34a 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 ee36a165d62ced4476ae9cad43c24dadfdc4019a..594e481e4694fce896b69b8cef2021f4e7e684f8 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 1e72cf709c664583663ec7335bd6cae3e0003f89..a44fb2877a95b14003f4656f3d9f07fa169e4af4 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 dfaf8f5200b346a470826831138cd973823b1173..f676361d958bba49dda83dfa6df59cefa7219a52 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 a91a0a4ef630ded0e1ae7e1d688dcd19664939fa..6a2d349f15b5e6b2f581920024237b94f7bb1f2f 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 1121711a99fa6ecfb26a2169e3b0283a89cb1509..11c27c67abadd82e8bf789f51dc51c59f63b0b89 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 624210bf527905a2d11f0e5c76400e2ac7f64d93..a9227195e816336f099356d85730de7dbf7ebead 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 2c89a58d5d23f3b2fa6f66ae151f5303bd81408a..ab1b67c53be1dd994acd73e9e7ad6f22d59cd88b 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 5064ac2d9cdbf5ff41ea7d8855d96ecb4a66c28e..f1bd6c98c80fced7c3c45dba45ae3fce43c14b95 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 4bb39028f0418a9da1a66fc4106d077790e1ac3b..06a5eef47bf18a02f41fae9f11f4017eb81ccf54 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 1d4745afbc1996a717d20469376e817c68c53f56..57a6639575c9c5693aa26691c23cf69e4da1fec0 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 a79b78acf247830fdf4353f5274d75cfb9508f2e..81891ff7aa6b87f1540782206c8d3644a625667f 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 d0e1b9a23d9e8d29c27fe392386f9b40aedf3d06..c5c8a12593653faef4833d642b4d26c167213ea7 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 dadf51912db45b6c1fd4160fdfdcd6802e98fa4d..d86be85b7330446984f73a09c44f09ce8ff3340b 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 a5caa74c80e882e196661e36b7451c131fdeefda..a380bb8bbe5007fff8470a41ac101b73ab9e7b63 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 31ebc4c809c62ee8834056c4739a6f70c6ff6b14..33d825a2b848b933ed44fe936123e86d364e7ea9 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 abfd8caa5844ee34804b5ba32c45d8577fe7b6bb..9082909ba2e2e5d427264bb990c78114081e1cec 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) diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc index 9ec83500a8c5a49c297699b968155252f38ce43e..46d30514287396aea3c5a36517705f828ad6e102 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -414,7 +414,8 @@ public: if (t1elem->ty != TY::Tstruct || identity_compare_p (t1elem->isTypeStruct ()->sym)) { - tree size = size_mult_expr (t1len, size_int (t1elem->size ())); + tree size = + size_mult_expr (t1len, size_int (dmd::size (t1elem))); result = build_memcmp_call (t1ptr, t2ptr, size); result = build_boolop (code, result, integer_zero_node); @@ -442,7 +443,7 @@ public: The frontend should have already guaranteed that static arrays have same size. */ if (tb1->ty == TY::Tsarray && tb2->ty == TY::Tsarray) - gcc_assert (tb1->size () == tb2->size ()); + gcc_assert (dmd::size (tb1) == dmd::size (tb2)); else { tree tlencmp = build_boolop (code, t1len, t2len); @@ -917,7 +918,7 @@ public: if (integer_zerop (t2)) { tree size = size_mult_expr (d_array_length (t1), - size_int (etype->size ())); + size_int (dmd::size (etype))); result = build_memset_call (d_array_ptr (t1), size); } else @@ -943,7 +944,8 @@ public: tree t2ptr = d_array_ptr (t2); /* Generate: memcpy(to, from, size) */ - tree size = size_mult_expr (t1len, size_int (etype->size ())); + tree size = + size_mult_expr (t1len, size_int (dmd::size (etype))); tree result = build_memcpy_call (t1ptr, t2ptr, size); /* Insert check that array lengths match and do not overlap. */ @@ -986,7 +988,7 @@ public: { /* Generate: _d_arraycopy() */ this->result_ = build_libcall (LIBCALL_ARRAYCOPY, e->type, 3, - size_int (etype->size ()), + size_int (dmd::size (etype)), d_array_convert (e->e2), d_array_convert (e->e1)); } @@ -1100,7 +1102,7 @@ public: || (e->op == EXP::construct && e->e2->op == EXP::arrayLiteral) || (e->op == EXP::construct && e->e2->op == EXP::call) || (e->op == EXP::construct && !lvalue && postblit) - || (e->op == EXP::blit || e->e1->type->size () == 0)) + || (e->op == EXP::blit || dmd::size (e->e1->type) == 0)) { tree t1 = build_expr (e->e1); tree t2 = convert_for_assignment (e->e2, e->e1->type); @@ -1190,7 +1192,7 @@ public: /* Index the associative array. */ tree result = build_libcall (libcall, dmd::pointerTo (e->type), 4, ptr, tinfo, - size_int (tb1->nextOf ()->size ()), + size_int (dmd::size (tb1->nextOf ())), build_address (key)); if (!e->indexIsInBounds && array_bounds_check ()) @@ -2391,7 +2393,7 @@ public: /* Allocating memory for a new pointer. */ TypePointer *tpointer = tb->isTypePointer (); - if (tpointer->next->size () == 0) + if (dmd::size (tpointer->next) == 0) { /* Pointer element size is unknown. */ this->result_ = d_convert (build_ctype (e->type), @@ -2692,7 +2694,7 @@ public: /* Now copy the constructor into memory. */ tree size = size_mult_expr (size_int (e->elements->length), - size_int (tb->nextOf ()->size ())); + size_int (dmd::size (tb->nextOf ()))); tree result = build_memcpy_call (mem, build_address (ctor), size); diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc index ea2e4b5deec46717acc8bbda9648d704b8d3525b..982d7cc95dd52104d26b9c1f165817274572d20c 100644 --- a/gcc/d/typeinfo.cc +++ b/gcc/d/typeinfo.cc @@ -664,7 +664,7 @@ public: /* Default initializer for enum. */ if (ed->members && !d->tinfo->isZeroInit ()) { - tree length = size_int (ed->type->size ()); + tree length = size_int (dmd::size (ed->type)); tree ptr = build_address (enum_initializer_decl (ed)); this->layout_field (d_array_value (array_type_node, length, ptr)); } diff --git a/gcc/d/types.cc b/gcc/d/types.cc index 6689278061992f07484e810658fd7245b8c4e389..ad461cb6969bde374933f15f0cf065214b35ead6 100644 --- a/gcc/d/types.cc +++ b/gcc/d/types.cc @@ -1181,7 +1181,7 @@ public: TYPE_UNSIGNED (t->ctype) = TYPE_UNSIGNED (basetype); SET_TYPE_ALIGN (t->ctype, TYPE_ALIGN (basetype)); TYPE_SIZE (t->ctype) = NULL_TREE; - TYPE_PRECISION (t->ctype) = t->size (t->sym->loc) * 8; + TYPE_PRECISION (t->ctype) = dmd::size (t, t->sym->loc) * 8; layout_type (t->ctype); diff --git a/gcc/testsuite/gdc.test/compilable/cppmangle.d b/gcc/testsuite/gdc.test/compilable/cppmangle.d index 948fee2cfdaacbe8dbedb072561c11d9bb2ad9d3..4b9046e81102728e40485cd9d64b9a04448f235c 100644 --- a/gcc/testsuite/gdc.test/compilable/cppmangle.d +++ b/gcc/testsuite/gdc.test/compilable/cppmangle.d @@ -7,8 +7,8 @@ import core.stdc.stdio; -version (CppRuntime_Clang) version = CppMangle_Itanium; -version (CppRuntime_Gcc) version = CppMangle_Itanium; +version (CppRuntime_LLVM) version = CppMangle_Itanium; +version (CppRuntime_GNU) version = CppMangle_Itanium; version (CppRuntime_Microsoft) version = CppMangle_MSVC; version (CppRuntime_Sun) version = CppMangle_Itanium; diff --git a/gcc/testsuite/gdc.test/compilable/cppmangle3.d b/gcc/testsuite/gdc.test/compilable/cppmangle3.d index 92c858854f0cd291b848faf930fb6813203e1ceb..94de1fa9ff43fe0294efabcd83661daf1693bf2c 100644 --- a/gcc/testsuite/gdc.test/compilable/cppmangle3.d +++ b/gcc/testsuite/gdc.test/compilable/cppmangle3.d @@ -3,8 +3,8 @@ // https://issues.dlang.org/show_bug.cgi?id=19920 module cppmangle3; -version (CppRuntime_Clang) version = CppMangle_Itanium; -version (CppRuntime_Gcc) version = CppMangle_Itanium; +version (CppRuntime_LLVM) version = CppMangle_Itanium; +version (CppRuntime_GNU) version = CppMangle_Itanium; version (CppRuntime_Microsoft) version = CppMangle_MSVC; version (CppRuntime_Sun) version = CppMangle_Itanium; diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/header1.d b/gcc/testsuite/gdc.test/compilable/extra-files/header1.d index 93f05a50c31f71558122cc198f53327cb5b8e9de..9756264fcc3e753b29f363eade539aad8a94cb27 100644 --- a/gcc/testsuite/gdc.test/compilable/extra-files/header1.d +++ b/gcc/testsuite/gdc.test/compilable/extra-files/header1.d @@ -575,12 +575,17 @@ struct SafeS return this; } - ref SafeS foo3() return scope + ref SafeS foo3() scope { static SafeS s; return s; } + ref SafeS foo4() scope return + { + return this; + } + int* p; } diff --git a/gcc/testsuite/gdc.test/compilable/import_exp.d b/gcc/testsuite/gdc.test/compilable/import_exp.d new file mode 100644 index 0000000000000000000000000000000000000000..014d0f65f6f9ac626f60b8a32c528cb9d4a0ed8a --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/import_exp.d @@ -0,0 +1,36 @@ +// REQUIRED_ARGS: -Jcompilable/imports/ +// EXTRA_FILES: imports/imp16088.d imports/test21227/a..b.txt imports/test21227/a.txt imports/test21227/..foo/a.txt + +// https://issues.dlang.org/show_bug.cgi?id=16088 + +void bar(string x) {} +auto foo() +{ + import("imp16088.d").bar; +} + + +// https://issues.dlang.org/show_bug.cgi?id=21227 + +void test21227() +{ + import("./test21227/a.txt").bar; + import("test21227//a..b.txt").bar; + import("test21227/..foo/a.txt").bar; + + version(Windows) + { + import(r".\test21227\a.txt").bar; + import(r"test21227\\a..b.txt").bar; + import(r"test21227\..foo\a.txt").bar; + } +} + +// Test that it's treated like a hex string, allowing implicit conversion to byte array + +// Can't test whole contents because line endings may vary +enum expectedStart = "module imports.imp16088;"; + +immutable ubyte[] s0 = import("imp16088.d"); + +static assert(s0[0 .. expectedStart.length] == "module imports.imp16088;"); diff --git a/gcc/testsuite/gdc.test/compilable/issue21203.d b/gcc/testsuite/gdc.test/compilable/issue21203.d index 30291a35e626c2ea1acd329c15663b29b8a74f3c..ee394b310a5dc3c3e8b4b9ed532f769b547f2162 100644 --- a/gcc/testsuite/gdc.test/compilable/issue21203.d +++ b/gcc/testsuite/gdc.test/compilable/issue21203.d @@ -1,6 +1,6 @@ -version (CppRuntime_Clang) version = CppMangle_Itanium; -version (CppRuntime_Gcc) version = CppMangle_Itanium; -version (CppRuntime_Sun) version = CppMangle_Itanium; +version (CppRuntime_LLVM) version = CppMangle_Itanium; +version (CppRuntime_GNU) version = CppMangle_Itanium; +version (CppRuntime_Sun) version = CppMangle_Itanium; template ScopeClass(C , string name = C.stringof) //if (is(C == class) && __traits(getLinkage, C) == "C++") diff --git a/gcc/testsuite/gdc.test/compilable/issue21340.d b/gcc/testsuite/gdc.test/compilable/issue21340.d index 03d37bdc61a4bfb792c959ba354cc78a3743a9cd..26280998692b287fd904754371a9501a4d111e29 100644 --- a/gcc/testsuite/gdc.test/compilable/issue21340.d +++ b/gcc/testsuite/gdc.test/compilable/issue21340.d @@ -1,5 +1,5 @@ -version (CppRuntime_Clang) version = CppMangle_Itanium; -version (CppRuntime_Gcc) version = CppMangle_Itanium; +version (CppRuntime_LLVM) version = CppMangle_Itanium; +version (CppRuntime_GNU) version = CppMangle_Itanium; version (CppRuntime_Sun) version = CppMangle_Itanium; template ScopeClass(C) diff --git a/gcc/testsuite/gdc.test/compilable/issue24566.d b/gcc/testsuite/gdc.test/compilable/issue24566.d new file mode 100644 index 0000000000000000000000000000000000000000..df1bf6f0e183a1431dec370fdb06136c231af639 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/issue24566.d @@ -0,0 +1,23 @@ +// https://issues.dlang.org/show_bug.cgi?id=24566 + +void test24566a() +{ + enum a = true; + bool b = true; + enum str = "a"; + if (a && str.length > 1 && str[1] == 'a') {} + if (b && str.length > 1 && str[1] == 'a') {} + if (!b && str.length > 1 && str[1] == 'a') {} + if (str.length > 1 && b && str[1] == 'a') {} +} + +void test24566b() +{ + enum a = false; + bool b = false; + enum str = "a"; + if (a || str.length <= 1 || str[1] == 'a') {} + if (b || str.length <= 1 || str[1] == 'a') {} + if (!b || str.length <= 1 || str[1] == 'a') {} + if (str.length <= 1 || b || str[1] == 'a') {} +} diff --git a/gcc/testsuite/gdc.test/compilable/test16088.d b/gcc/testsuite/gdc.test/compilable/test16088.d deleted file mode 100644 index 97326f1fcd7a19afa43567d1f7c70d2b77eb5bb9..0000000000000000000000000000000000000000 --- a/gcc/testsuite/gdc.test/compilable/test16088.d +++ /dev/null @@ -1,10 +0,0 @@ -// REQUIRED_ARGS: -Jcompilable/imports/ -// EXTRA_FILES: imports/imp16088.d - -// https://issues.dlang.org/show_bug.cgi?id=16088 - -void bar(string x) {} -auto foo() -{ - import("imp16088.d").bar; -} diff --git a/gcc/testsuite/gdc.test/compilable/test21227.d b/gcc/testsuite/gdc.test/compilable/test21227.d deleted file mode 100644 index 29dd2af29c37cb91d5c27be54249d1ffac3fbab6..0000000000000000000000000000000000000000 --- a/gcc/testsuite/gdc.test/compilable/test21227.d +++ /dev/null @@ -1,19 +0,0 @@ -// REQUIRED_ARGS: -Jcompilable/imports -// EXTRA_FILES: imports/test21227/a..b.txt imports/test21227/a.txt imports/test21227/..foo/a.txt - -// https://issues.dlang.org/show_bug.cgi?id=21227 - -void bar(string x) {} -void test21227() -{ - import("./test21227/a.txt").bar; - import("test21227//a..b.txt").bar; - import("test21227/..foo/a.txt").bar; - - version(Windows) - { - import(r".\test21227\a.txt").bar; - import(r"test21227\\a..b.txt").bar; - import(r"test21227\..foo\a.txt").bar; - } -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/bool_cast.d b/gcc/testsuite/gdc.test/fail_compilation/bool_cast.d new file mode 100644 index 0000000000000000000000000000000000000000..830360a74c34a43c7a4f2cac3b8034d72e646862 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/bool_cast.d @@ -0,0 +1,26 @@ +/* +REQUIRED_ARGS: -de -preview=dip1000 +TEST_OUTPUT: +--- +fail_compilation/bool_cast.d(17): Deprecation: cast from `ubyte[]` to `bool[]` not allowed in safe code +fail_compilation/bool_cast.d(17): Source element may have bytes which are not 0 or 1 +fail_compilation/bool_cast.d(22): Deprecation: cast from `int*` to `bool*` not allowed in safe code +fail_compilation/bool_cast.d(22): Source element may have bytes which are not 0 or 1 +fail_compilation/bool_cast.d(24): Deprecation: cast from `bool*` to `byte*` not allowed in safe code +fail_compilation/bool_cast.d(24): Target element could be assigned a byte which is not 0 or 1 +--- +*/ + +void main() @safe +{ + ubyte[] a = [2, 4]; + auto b = cast(bool[]) a; // reinterprets a's data + auto c = cast(bool[]) [2, 4]; // OK, literal cast applies to each element + auto d = cast(const(byte)[]) b; // OK, result's elements are const + + int i = 2; + auto p = cast(bool*) &i; + bool v; + auto bp = cast(byte*) &v; + *bp = 2; // v is now invalid +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/cast_qual.d b/gcc/testsuite/gdc.test/fail_compilation/cast_qual.d index 19932f811653ecc9907e33af1a43c7edefde8189..5821dc14994031cbac754abcf0150f3fcc93bb17 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/cast_qual.d +++ b/gcc/testsuite/gdc.test/fail_compilation/cast_qual.d @@ -2,8 +2,10 @@ REQUIRED_ARGS: -preview=dip1000 -de TEST_OUTPUT: --- -fail_compilation/cast_qual.d(15): Deprecation: cast from `const(int)` to `int` cannot be used as an lvalue in @safe code fail_compilation/cast_qual.d(17): Deprecation: cast from `const(int)` to `int` cannot be used as an lvalue in @safe code +fail_compilation/cast_qual.d(19): Deprecation: cast from `const(int)` to `int` cannot be used as an lvalue in @safe code +fail_compilation/cast_qual.d(25): Error: cast from `const(Object)` to `object.Object` not allowed in safe code +fail_compilation/cast_qual.d(25): Incompatible type qualifier --- */ @@ -17,3 +19,8 @@ void main() { cast() i = 5; // NG auto q = &cast(const) j; // OK, int* to const int* } + +void test() { + const Object co; + auto o = cast() co; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/cpp_cast.d b/gcc/testsuite/gdc.test/fail_compilation/cpp_cast.d new file mode 100644 index 0000000000000000000000000000000000000000..3802ebd5e92fadf207849ef14939c3ffd06ce312 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/cpp_cast.d @@ -0,0 +1,23 @@ +// See also: fail20000.d +/* +REQUIRED_ARGS: -de +TEST_OUTPUT: +--- +fail_compilation/cpp_cast.d(19): Error: cast from `cpp_cast.I` to `cpp_cast.C` not allowed in safe code +fail_compilation/cpp_cast.d(19): No dynamic type information for extern(C++) classes +fail_compilation/cpp_cast.d(21): Deprecation: cast from `cpp_cast.C` to `cpp_cast.D` not allowed in safe code +fail_compilation/cpp_cast.d(21): No dynamic type information for extern(C++) classes +--- +*/ +extern(C++) interface I { void f(); } +extern(C++) class C : I { void f() { } } +extern(C++) class D : C { } + +void main() @safe +{ + I i; + C c = cast(C) i; // unsafe + i = cast(I) c; // OK + c = cast(D) c; // reinterpret cast + c = cast(C) new D; // OK +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13577.d b/gcc/testsuite/gdc.test/fail_compilation/fail13577.d index 79f9068c759317a147d57ecbb15e98c3dab598e5..f1048073591e991724b5ea5859cad722205928e7 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail13577.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail13577.d @@ -3,7 +3,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail13577.d(27): Error: cannot implicilty convert range element of type `int[]` to variable `x` of type `immutable(int[])` +fail_compilation/fail13577.d(27): Error: cannot implicitly convert tuple element of type `int[]` to variable `x` of type `immutable(int[])` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20000.d b/gcc/testsuite/gdc.test/fail_compilation/fail20000.d index fe481216be65aaa6856301cf3fe6606387712ada..a049dacb2e6d05fef5f432767e54c3b49be6e70c 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail20000.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20000.d @@ -1,18 +1,30 @@ /* TEST_OUTPUT: --- -fail_compilation/fail20000.d(25): Error: cast from `fail20000.DClass` to `fail20000.CppClass` not allowed in safe code -fail_compilation/fail20000.d(26): Error: cast from `fail20000.DInterface` to `fail20000.CppClass` not allowed in safe code -fail_compilation/fail20000.d(27): Error: cast from `fail20000.CppClass2` to `fail20000.CppClass` not allowed in safe code -fail_compilation/fail20000.d(28): Error: cast from `fail20000.CppInterface2` to `fail20000.CppClass` not allowed in safe code -fail_compilation/fail20000.d(30): Error: cast from `fail20000.DClass` to `fail20000.CppInterface` not allowed in safe code -fail_compilation/fail20000.d(31): Error: cast from `fail20000.DInterface` to `fail20000.CppInterface` not allowed in safe code -fail_compilation/fail20000.d(32): Error: cast from `fail20000.CppClass2` to `fail20000.CppInterface` not allowed in safe code -fail_compilation/fail20000.d(33): Error: cast from `fail20000.CppInterface2` to `fail20000.CppInterface` not allowed in safe code -fail_compilation/fail20000.d(35): Error: cast from `fail20000.CppClass` to `fail20000.DClass` not allowed in safe code -fail_compilation/fail20000.d(36): Error: cast from `fail20000.CppInterface` to `fail20000.DClass` not allowed in safe code -fail_compilation/fail20000.d(38): Error: cast from `fail20000.CppClass` to `fail20000.DInterface` not allowed in safe code -fail_compilation/fail20000.d(39): Error: cast from `fail20000.CppInterface` to `fail20000.DInterface` not allowed in safe code +fail_compilation/fail20000.d(37): Error: cast from `fail20000.DClass` to `fail20000.CppClass` not allowed in safe code +fail_compilation/fail20000.d(37): Source object type is incompatible with target type +fail_compilation/fail20000.d(38): Error: cast from `fail20000.DInterface` to `fail20000.CppClass` not allowed in safe code +fail_compilation/fail20000.d(38): Source object type is incompatible with target type +fail_compilation/fail20000.d(39): Error: cast from `fail20000.CppClass2` to `fail20000.CppClass` not allowed in safe code +fail_compilation/fail20000.d(39): Source object type is incompatible with target type +fail_compilation/fail20000.d(40): Error: cast from `fail20000.CppInterface2` to `fail20000.CppClass` not allowed in safe code +fail_compilation/fail20000.d(40): Source object type is incompatible with target type +fail_compilation/fail20000.d(42): Error: cast from `fail20000.DClass` to `fail20000.CppInterface` not allowed in safe code +fail_compilation/fail20000.d(42): Source object type is incompatible with target type +fail_compilation/fail20000.d(43): Error: cast from `fail20000.DInterface` to `fail20000.CppInterface` not allowed in safe code +fail_compilation/fail20000.d(43): Source object type is incompatible with target type +fail_compilation/fail20000.d(44): Error: cast from `fail20000.CppClass2` to `fail20000.CppInterface` not allowed in safe code +fail_compilation/fail20000.d(44): Source object type is incompatible with target type +fail_compilation/fail20000.d(45): Error: cast from `fail20000.CppInterface2` to `fail20000.CppInterface` not allowed in safe code +fail_compilation/fail20000.d(45): Source object type is incompatible with target type +fail_compilation/fail20000.d(47): Error: cast from `fail20000.CppClass` to `fail20000.DClass` not allowed in safe code +fail_compilation/fail20000.d(47): Source object type is incompatible with target type +fail_compilation/fail20000.d(48): Error: cast from `fail20000.CppInterface` to `fail20000.DClass` not allowed in safe code +fail_compilation/fail20000.d(48): Source object type is incompatible with target type +fail_compilation/fail20000.d(50): Error: cast from `fail20000.CppClass` to `fail20000.DInterface` not allowed in safe code +fail_compilation/fail20000.d(50): Source object type is incompatible with target type +fail_compilation/fail20000.d(51): Error: cast from `fail20000.CppInterface` to `fail20000.DInterface` not allowed in safe code +fail_compilation/fail20000.d(51): Source object type is incompatible with target type --- */ extern(C++) class CppClass { int a; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice20042.d b/gcc/testsuite/gdc.test/fail_compilation/ice20042.d index 6b71903c9ca233fb8af74c63f05b10fbcc6183ad..7a674b3c546418869a9f3abf9fda15e7a18e28e5 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice20042.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice20042.d @@ -1,5 +1,5 @@ /* -DISABLED: freebsd32 linux32 osx32 win32 +DISABLED: freebsd32 openbsd32 linux32 osx32 win32 TEST_OUTPUT: --- fail_compilation/ice20042.d(18): Error: slice operation `cast(__vector(float[4]))[nanF, nanF, nanF, nanF] = [1.0F, 2.0F, 3.0F, 4.0F][0..4]` cannot be evaluated at compile time diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice20264.d b/gcc/testsuite/gdc.test/fail_compilation/ice20264.d index df6667d9e4b1f73b7eb1e7b0bf3451e533bb726c..a8a1e7119bee14a2efb19650903335cb00581344 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice20264.d +++ b/gcc/testsuite/gdc.test/fail_compilation/ice20264.d @@ -1,5 +1,5 @@ /* -DISABLED: freebsd32 linux32 osx32 win32 +DISABLED: freebsd32 openbsd32 linux32 osx32 win32 TEST_OUTPUT: --- fail_compilation/ice20264.d(12): Error: cannot modify expression `cast(__vector(float[4]))a` because it is not an lvalue diff --git a/gcc/testsuite/gdc.test/fail_compilation/impconv.d b/gcc/testsuite/gdc.test/fail_compilation/impconv.d index cb1cb8e21eecd6e1b571642c91a4c0c6480b0cbb..0cc2deb13d867046f26260d273633aaa911fd044 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/impconv.d +++ b/gcc/testsuite/gdc.test/fail_compilation/impconv.d @@ -3,7 +3,7 @@ FIXME: DMD host compilers < 2.073 with faulty optimization lead to unfortunate test failures, see https://github.com/dlang/dmd/pull/6831#issuecomment-304495842. -DISABLED: win32 win64 linux osx freebsd +DISABLED: win32 win64 linux osx freebsd openbsd */ /* diff --git a/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d b/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d index ac00b4d3b5004f36656100064006bf50e3033f01..502ae4a5bcaec26a59a0e44466e2ddc510b73ea2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d +++ b/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d @@ -110,9 +110,9 @@ fail_compilation/reserved_version.d(211): Error: version identifier `AsmJS` is r fail_compilation/reserved_version.d(212): Error: version identifier `Emscripten` is reserved and cannot be set fail_compilation/reserved_version.d(213): Error: version identifier `WebAssembly` is reserved and cannot be set fail_compilation/reserved_version.d(214): Error: version identifier `WASI` is reserved and cannot be set -fail_compilation/reserved_version.d(215): Error: version identifier `CppRuntime_Clang` is reserved and cannot be set +fail_compilation/reserved_version.d(215): Error: version identifier `CppRuntime_LLVM` is reserved and cannot be set fail_compilation/reserved_version.d(216): Error: version identifier `CppRuntime_DigitalMars` is reserved and cannot be set -fail_compilation/reserved_version.d(217): Error: version identifier `CppRuntime_Gcc` is reserved and cannot be set +fail_compilation/reserved_version.d(217): Error: version identifier `CppRuntime_GNU` is reserved and cannot be set fail_compilation/reserved_version.d(218): Error: version identifier `CppRuntime_Microsoft` is reserved and cannot be set fail_compilation/reserved_version.d(219): Error: version identifier `CppRuntime_Sun` is reserved and cannot be set fail_compilation/reserved_version.d(220): Error: version identifier `D_PIE` is reserved and cannot be set @@ -239,9 +239,9 @@ version = AsmJS; version = Emscripten; version = WebAssembly; version = WASI; -version = CppRuntime_Clang; +version = CppRuntime_LLVM; version = CppRuntime_DigitalMars; -version = CppRuntime_Gcc; +version = CppRuntime_GNU; version = CppRuntime_Microsoft; version = CppRuntime_Sun; version = D_PIE; @@ -339,9 +339,9 @@ debug = CRuntime_Musl; debug = CRuntime_Newlib; debug = CRuntime_UClibc; debug = CRuntime_WASI; -debug = CppRuntime_Clang; +debug = CppRuntime_LLVM; debug = CppRuntime_DigitalMars; -debug = CppRuntime_Gcc; +debug = CppRuntime_GNU; debug = CppRuntime_Microsoft; debug = CppRuntime_Sun; debug = D_Coverage; diff --git a/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d b/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d index 44db40410289566a04ef6b7b85107bc16d9a1c5a..2b6bb5e5351f7f680aad18eb234e295cd902ca18 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d +++ b/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d @@ -86,9 +86,9 @@ // REQUIRED_ARGS: -version=CRuntime_Newlib // REQUIRED_ARGS: -version=CRuntime_UClibc // REQUIRED_ARGS: -version=CRuntime_WASI -// REQUIRED_ARGS: -version=CppRuntime_Clang +// REQUIRED_ARGS: -version=CppRuntime_LLVM // REQUIRED_ARGS: -version=CppRuntime_DigitalMars -// REQUIRED_ARGS: -version=CppRuntime_Gcc +// REQUIRED_ARGS: -version=CppRuntime_GNU // REQUIRED_ARGS: -version=CppRuntime_Microsoft // REQUIRED_ARGS: -version=CppRuntime_Sun // REQUIRED_ARGS: -version=D_Coverage @@ -195,9 +195,9 @@ // REQUIRED_ARGS: -debug=CRuntime_Newlib // REQUIRED_ARGS: -debug=CRuntime_UClibc // REQUIRED_ARGS: -debug=CRuntime_WASI -// REQUIRED_ARGS: -debug=CppRuntime_Clang +// REQUIRED_ARGS: -debug=CppRuntime_LLVM // REQUIRED_ARGS: -debug=CppRuntime_DigitalMars -// REQUIRED_ARGS: -debug=CppRuntime_Gcc +// REQUIRED_ARGS: -debug=CppRuntime_GNU // REQUIRED_ARGS: -debug=CppRuntime_Microsoft // REQUIRED_ARGS: -debug=CppRuntime_Sun // REQUIRED_ARGS: -debug=D_Coverage @@ -310,9 +310,9 @@ Error: version identifier `CRuntime_Musl` is reserved and cannot be set Error: version identifier `CRuntime_Newlib` is reserved and cannot be set Error: version identifier `CRuntime_UClibc` is reserved and cannot be set Error: version identifier `CRuntime_WASI` is reserved and cannot be set -Error: version identifier `CppRuntime_Clang` is reserved and cannot be set +Error: version identifier `CppRuntime_LLVM` is reserved and cannot be set Error: version identifier `CppRuntime_DigitalMars` is reserved and cannot be set -Error: version identifier `CppRuntime_Gcc` is reserved and cannot be set +Error: version identifier `CppRuntime_GNU` is reserved and cannot be set Error: version identifier `CppRuntime_Microsoft` is reserved and cannot be set Error: version identifier `CppRuntime_Sun` is reserved and cannot be set Error: version identifier `D_Coverage` is reserved and cannot be set diff --git a/gcc/testsuite/gdc.test/fail_compilation/retref2.d b/gcc/testsuite/gdc.test/fail_compilation/retref2.d index aaa5b41e306c69b639f839783c417e1e101c4232..ca64653efaec8e8a13da80fd26ad7f8252dcf98d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/retref2.d +++ b/gcc/testsuite/gdc.test/fail_compilation/retref2.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/retref2.d(18): Error: function `ref int retref2.D.foo(return ref int)` does not override any function, did you mean to override `ref int retref2.C.foo(ref int)`? -fail_compilation/retref2.d(19): Error: function `ref scope int retref2.D.bar() return` does not override any function, did you mean to override `ref int retref2.C.bar()`? +fail_compilation/retref2.d(19): Error: function `ref int retref2.D.bar() scope return` does not override any function, did you mean to override `ref int retref2.C.bar()`? --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/shared.d b/gcc/testsuite/gdc.test/fail_compilation/shared.d index 8b94a7981a1fd26a183980f68615f04618b29ff8..13b24c81cf833455dbf71c2270f5fbd283947395 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/shared.d +++ b/gcc/testsuite/gdc.test/fail_compilation/shared.d @@ -241,9 +241,13 @@ struct BitRange TEST_OUTPUT: --- fail_compilation/shared.d(3004): Error: cast from `void*` to `shared(int*)` not allowed in safe code +fail_compilation/shared.d(3004): `void` data may contain pointers and target element type is mutable fail_compilation/shared.d(3005): Error: cast from `void*` to `shared(const(int*))` not allowed in safe code +fail_compilation/shared.d(3005): Source type is incompatible with target type containing a pointer fail_compilation/shared.d(3008): Error: cast from `shared(void*)` to `int*` not allowed in safe code +fail_compilation/shared.d(3008): `void` data may contain pointers and target element type is mutable fail_compilation/shared.d(3009): Error: cast from `shared(void*)` to `shared(const(int*))` not allowed in safe code +fail_compilation/shared.d(3009): Source type is incompatible with target type containing a pointer --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/system_ptr_cast.d b/gcc/testsuite/gdc.test/fail_compilation/system_ptr_cast.d new file mode 100644 index 0000000000000000000000000000000000000000..fc10b2a78010265a1d04605ac6c613f658b1aab5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/system_ptr_cast.d @@ -0,0 +1,25 @@ +/* +REQUIRED_ARGS: -preview=dip1000 -de +TEST_OUTPUT: +--- +fail_compilation/system_ptr_cast.d(20): Deprecation: cast from `S*` to `int*` not allowed in safe code +fail_compilation/system_ptr_cast.d(20): Source element type has unsafe bit patterns and target element type is mutable +fail_compilation/system_ptr_cast.d(24): Deprecation: cast from `int*` to `S*` not allowed in safe code +fail_compilation/system_ptr_cast.d(24): Target element type has unsafe bit patterns +--- +*/ + +struct S +{ + @system int i; +} + +void main() @safe +{ + S s; + auto p = cast(int*) &s; + *p = 8; + + int i = 8; + auto ps = cast(S*) &i; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15660.d b/gcc/testsuite/gdc.test/fail_compilation/test15660.d index ae573b2af2a77e87185d7e617876412c74ac5aa3..9bf05d125384265af1ffd9dc5e66dc9c34a14386 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test15660.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test15660.d @@ -1,7 +1,13 @@ /* REQUIRED_ARGS: -preview=fixImmutableConv TEST_OUTPUT: --- -fail_compilation/test15660.d(20): Error: cannot implicitly convert expression `f(v)` of type `int[]` to `immutable(int[])` +fail_compilation/test15660.d(26): Error: cannot implicitly convert expression `f(v)` of type `int[]` to `immutable(int[])` +fail_compilation/test15660.d(34): Error: cannot copy `const(void)[]` to `void[]` +fail_compilation/test15660.d(34): Source data has incompatible type qualifier(s) +fail_compilation/test15660.d(34): Use `cast(void[])` to force copy +fail_compilation/test15660.d(36): Error: cannot copy `const(int*)[]` to `void[]` +fail_compilation/test15660.d(36): Source data has incompatible type qualifier(s) +fail_compilation/test15660.d(36): Use `cast(void[])` to force copy --- */ @@ -19,3 +25,13 @@ void main() void[] v; immutable x = f(v); } + +// https://issues.dlang.org/show_bug.cgi?id=17148 +void f(int*[] a, const int*[] b) @system +{ + void[] a1 = a; + const(void)[] b1 = b; + a1[] = b1[]; + *a[0] = 0; //modify const data + a1[] = new const(int*)[2]; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15672.d b/gcc/testsuite/gdc.test/fail_compilation/test15672.d index 1c3bedfc2a2aa9f595b10c2e0c494bcadfaac908..c3d14db21000f3d5c6259484b5cd98fc8ccf769f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test15672.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test15672.d @@ -1,8 +1,10 @@ /* * TEST_OUTPUT: --- -fail_compilation/test15672.d(15): Error: cast from `void[]` to `byte[]` not allowed in safe code -fail_compilation/test15672.d(25): Error: cast from `void*` to `byte*` not allowed in safe code +fail_compilation/test15672.d(17): Error: cast from `void[]` to `byte[]` not allowed in safe code +fail_compilation/test15672.d(17): `void` data may contain pointers and target element type is mutable +fail_compilation/test15672.d(27): Error: cast from `void*` to `byte*` not allowed in safe code +fail_compilation/test15672.d(27): `void` data may contain pointers and target element type is mutable --- */ // https://issues.dlang.org/show_bug.cgi?id=15672 diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15703.d b/gcc/testsuite/gdc.test/fail_compilation/test15703.d index dd07857dbe6d4e957b822e9cb7ffea0b308cb7d0..9ee9ac52ec75b25c3b20776d17918daa83a1b273 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test15703.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test15703.d @@ -2,9 +2,16 @@ REQUIRED_ARGS: -m32 TEST_OUTPUT: --- -fail_compilation/test15703.d(16): Error: cast from `Object[]` to `uint[]` not allowed in safe code -fail_compilation/test15703.d(18): Error: cast from `object.Object` to `const(uint)*` not allowed in safe code -fail_compilation/test15703.d(21): Error: cast from `uint[]` to `Object[]` not allowed in safe code +fail_compilation/test15703.d(23): Error: cast from `Object[]` to `uint[]` not allowed in safe code +fail_compilation/test15703.d(23): Target element type is mutable and source element type contains a pointer +fail_compilation/test15703.d(25): Error: cast from `object.Object` to `const(uint)*` not allowed in safe code +fail_compilation/test15703.d(25): Source type is incompatible with target type containing a pointer +fail_compilation/test15703.d(28): Error: cast from `uint[]` to `Object[]` not allowed in safe code +fail_compilation/test15703.d(28): Target element type contains a pointer +fail_compilation/test15703.d(44): Error: cast from `int[]` to `S[]` not allowed in safe code +fail_compilation/test15703.d(44): Target element type is opaque +fail_compilation/test15703.d(45): Error: cast from `S[]` to `int[]` not allowed in safe code +fail_compilation/test15703.d(45): Source element type is opaque --- */ @@ -28,3 +35,12 @@ void test2() @safe const(ubyte)[] a; auto b = cast(const(uint[])) a; } + +struct S; + +void opaque() @safe +{ + auto a = [1, 2]; + S[] b = cast(S[]) a; + a = cast(int[]) b; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15704.d b/gcc/testsuite/gdc.test/fail_compilation/test15704.d index 2be9d30f0a00c80a5920ae92f8c297a2a16ac519..04d4be4aa93ab40b08427ccb51439574cde49004 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test15704.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test15704.d @@ -1,7 +1,9 @@ /* * TEST_OUTPUT: --- -fail_compilation/test15704.d(15): Error: cannot copy `void[]` to `void[]` in `@safe` code +fail_compilation/test15704.d(17): Error: cannot copy `void[]` to `void[]` in `@safe` code +fail_compilation/test15704.d(18): Error: cannot copy `const(void)[]` to `void[]` in `@safe` code +fail_compilation/test15704.d(19): Deprecation: cannot copy `int[]` to `void[]` in `@safe` code --- */ @@ -13,4 +15,6 @@ void main() @safe { void[] arr2 = [ 123, 345, 567 ]; arr1[] = arr2[]; // overwrites pointers with arbitrary ints + arr1[] = new const(void)[3]; + arr1[] = [5]; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19646.d b/gcc/testsuite/gdc.test/fail_compilation/test19646.d index c9d0e08f6e0e6f65fc63c304c68f8871f595f337..766b387a559e6f619fc767aa962c943f04743edc 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test19646.d +++ b/gcc/testsuite/gdc.test/fail_compilation/test19646.d @@ -1,7 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/test19646.d(11): Error: cast from `const(int)*` to `int*` not allowed in safe code -fail_compilation/test19646.d(17): Error: `@safe` variable `z` cannot be initialized by calling `@system` function `f` +fail_compilation/test19646.d(12): Error: cast from `const(int)*` to `int*` not allowed in safe code +fail_compilation/test19646.d(12): Source type is incompatible with target type containing a pointer +fail_compilation/test19646.d(18): Error: `@safe` variable `z` cannot be initialized by calling `@system` function `f` --- https://issues.dlang.org/show_bug.cgi?id=19646 */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/union_conv.d b/gcc/testsuite/gdc.test/fail_compilation/union_conv.d new file mode 100644 index 0000000000000000000000000000000000000000..f08809c4850052540972a8ef9af6f0252fff3c8e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/union_conv.d @@ -0,0 +1,19 @@ +/* +REQUIRED_ARGS: -preview=fixImmutableConv +TEST_OUTPUT: +--- +fail_compilation/union_conv.d(18): Error: cannot implicitly convert expression `c` of type `const(U)` to `U` +--- +*/ + +union U +{ + int i; + int* p; +} + +void main() +{ + const U c; + U m = c; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/void_cat.d b/gcc/testsuite/gdc.test/fail_compilation/void_cat.d new file mode 100644 index 0000000000000000000000000000000000000000..da92d3b75b4c341b0ebddbe9e81f92700bd63ded --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/void_cat.d @@ -0,0 +1,21 @@ +/* +REQUIRED_ARGS: -preview=fixImmutableConv +TEST_OUTPUT: +--- +fail_compilation/void_cat.d(15): Error: cannot copy `const(void)[]` to `void[]` +fail_compilation/void_cat.d(15): Source data has incompatible type qualifier(s) +fail_compilation/void_cat.d(15): Use `cast(void[])` to force copy +fail_compilation/void_cat.d(19): Error: cannot append type `const(void)[]` to type `void[]` +--- +*/ + +void g(int*[] a, const(int*)[] b) @system +{ + void[] va = a; + va[] = va.init ~ b; // a now contains b's data + *a[0] = 0; // modify const data + + const(void)[] vb = b; + va ~= vb; // also leaks const pointers into void[] + // va could be copied into `a` via another void[] +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/xmmslice.d b/gcc/testsuite/gdc.test/fail_compilation/xmmslice.d index 6cf0e238f29bd6c2afaf5d0fdd59730f8d1372ad..f91ac1f52521ffd4678168bf3cec0a93d342ad9b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/xmmslice.d +++ b/gcc/testsuite/gdc.test/fail_compilation/xmmslice.d @@ -1,6 +1,6 @@ /* REQUIRED_ARGS: -mcpu=avx -DISABLED: win32 freebsd32 linux32 osx32 +DISABLED: win32 freebsd32 openbsd32 linux32 osx32 TEST_OUTPUT: --- fail_compilation/xmmslice.d(110): Error: `__vector(int[4])` cannot be sliced with `[]` diff --git a/gcc/testsuite/gdc.test/runnable/extra-files/test24590.d b/gcc/testsuite/gdc.test/runnable/extra-files/test24590.d new file mode 100644 index 0000000000000000000000000000000000000000..5ea04f572fa0ec7177724a3704d3539790e8b0fd --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/extra-files/test24590.d @@ -0,0 +1,10 @@ +shared static this() { + throw new Exception("module constructor"); +} + +shared static ~this() { + import core.stdc.stdio; + puts("module destructor"); +} + +void main() {} diff --git a/gcc/testsuite/gdc.test/runnable/staticaa.d b/gcc/testsuite/gdc.test/runnable/staticaa.d index 089144c4fb5c336084d8e74f5d6ceea4249c5e1f..6b8fb458075affac7042d6fd947528c9cb0a2844 100644 --- a/gcc/testsuite/gdc.test/runnable/staticaa.d +++ b/gcc/testsuite/gdc.test/runnable/staticaa.d @@ -181,6 +181,32 @@ void testStaticArray() ///////////////////////////////////////////// +// https://issues.dlang.org/show_bug.cgi?id=24602 + +class Set +{ + bool[string] aa; + + this(bool[string] aa) + { + this.aa = aa; + } +} + +class Bar +{ + Set x = new Set(["a": 1, "b": 0]); +} + +void testClassLiteral() +{ + assert(new Bar().x.aa["a"] == 1); + assert(new Bar().x.aa["b"] == 0); +} + +///////////////////////////////////////////// + + void main() { testSimple(); @@ -192,4 +218,5 @@ void main() testLocalStatic(); testEnumInit(); testStaticArray(); + testClassLiteral(); } diff --git a/gcc/testsuite/gdc.test/runnable/test12.d b/gcc/testsuite/gdc.test/runnable/test12.d index 22f4b849226744347cf9514366218f9e87d07a82..9f99d1cc844d582b678fb60a73eb05004e61e057 100644 --- a/gcc/testsuite/gdc.test/runnable/test12.d +++ b/gcc/testsuite/gdc.test/runnable/test12.d @@ -1,4 +1,5 @@ // PERMUTE_ARGS: -unittest -O -release -inline -fPIC -g +// TRANSFORM_OUTPUT: remove_lines("warning: sprintf\(\) is often misused") extern(C) int printf(const char*, ...); extern(C) int sprintf(char*, const char*, ...); diff --git a/gcc/testsuite/gdc.test/runnable/test17559.d b/gcc/testsuite/gdc.test/runnable/test17559.d index a759f1564c6cabc1d90f478dd34f1064c8b6bd39..e485a683349d21962dd0939c5d47290f30c62c0d 100644 --- a/gcc/testsuite/gdc.test/runnable/test17559.d +++ b/gcc/testsuite/gdc.test/runnable/test17559.d @@ -1,5 +1,5 @@ // REQUIRED_ARGS: -g -// REQUIRED_ARGS(linux freebsd dragonflybsd): -L-export-dynamic +// REQUIRED_ARGS(linux freebsd openbsd dragonflybsd): -L-export-dynamic // PERMUTE_ARGS: // DISABLED: osx diff --git a/gcc/testsuite/gdc.test/runnable/test19086.d b/gcc/testsuite/gdc.test/runnable/test19086.d index 026aee436c8c7cc232c70b22666f75a318328d97..9935f552921f150aea1f62f8b9221f7a95d942e7 100644 --- a/gcc/testsuite/gdc.test/runnable/test19086.d +++ b/gcc/testsuite/gdc.test/runnable/test19086.d @@ -1,64 +1,64 @@ -// REQUIRED_ARGS: -g -// REQUIRED_ARGS(linux freebsd dragonflybsd): -L-export-dynamic -// PERMUTE_ARGS: -// DISABLED: osx - -void run19086() -{ - long x = 1; - int y = 0; -#line 20 - throw newException(); -} - -// moved here to keep run19086 short -Exception newException() { return new Exception("hi"); } - -void test19086() -{ - try - { - run19086(); - } - catch(Exception e) - { - int line = findLineStackTrace(e.toString(), "run19086"); - assert(line >= 20 && line <= 21); - } -} - -int findLineStackTrace(string msg, string func) -{ - // find line number of _Dmain in stack trace - // on linux: file.d:line _Dmain [addr] - // on windows: addr in _Dmain at file.d(line) - int line = 0; - bool found = false; - for (size_t pos = 0; pos + func.length < msg.length; pos++) - { - if (msg[pos] == '\n') - { - line = 0; - found = false; - } - else if ((msg[pos] == ':' || msg[pos] == '(') && line == 0) - { - for (pos++; pos < msg.length && msg[pos] >= '0' && msg[pos] <= '9'; pos++) - line = line * 10 + msg[pos] - '0'; - if (line > 0 && found) - return line; - } - else if (msg[pos .. pos + func.length] == func) - { - found = true; - if (line > 0 && found) - return line; - } - } - return 0; -} - -void main() -{ - test19086(); -} +// REQUIRED_ARGS: -g +// REQUIRED_ARGS(linux freebsd openbsd dragonflybsd): -L-export-dynamic +// PERMUTE_ARGS: +// DISABLED: osx + +void run19086() +{ + long x = 1; + int y = 0; +#line 20 + throw newException(); +} + +// moved here to keep run19086 short +Exception newException() { return new Exception("hi"); } + +void test19086() +{ + try + { + run19086(); + } + catch(Exception e) + { + int line = findLineStackTrace(e.toString(), "run19086"); + assert(line >= 20 && line <= 21); + } +} + +int findLineStackTrace(string msg, string func) +{ + // find line number of _Dmain in stack trace + // on linux: file.d:line _Dmain [addr] + // on windows: addr in _Dmain at file.d(line) + int line = 0; + bool found = false; + for (size_t pos = 0; pos + func.length < msg.length; pos++) + { + if (msg[pos] == '\n') + { + line = 0; + found = false; + } + else if ((msg[pos] == ':' || msg[pos] == '(') && line == 0) + { + for (pos++; pos < msg.length && msg[pos] >= '0' && msg[pos] <= '9'; pos++) + line = line * 10 + msg[pos] - '0'; + if (line > 0 && found) + return line; + } + else if (msg[pos .. pos + func.length] == func) + { + found = true; + if (line > 0 && found) + return line; + } + } + return 0; +} + +void main() +{ + test19086(); +} diff --git a/gcc/testsuite/gdc.test/runnable/testthread2.d b/gcc/testsuite/gdc.test/runnable/testthread2.d index 2c87ecd8a7dfa46194593f20f847f58720ace943..346e3862e59ac26bf38d1dab4f199b1ccc8e1f12 100644 --- a/gcc/testsuite/gdc.test/runnable/testthread2.d +++ b/gcc/testsuite/gdc.test/runnable/testthread2.d @@ -1,4 +1,5 @@ // PERMUTE_ARGS: +// TRANSFORM_OUTPUT: remove_lines("warning: rand\(\) may return deterministic values") // Quick, dirty and inefficient AA using linear search, useful for testing. struct LinearAA(K, V) { diff --git a/gcc/testsuite/gdc.test/runnable/variadic.d b/gcc/testsuite/gdc.test/runnable/variadic.d index 7e9473c332edc50db1dd21ed329f426ac8d018a3..ddfd92c1676f164ae7fe2a75aa74591b7bbd7223 100644 --- a/gcc/testsuite/gdc.test/runnable/variadic.d +++ b/gcc/testsuite/gdc.test/runnable/variadic.d @@ -1,3 +1,5 @@ +// TRANSFORM_OUTPUT: remove_lines("warning: vsprintf\(\) is often misused") + alias TypeTuple(T...) = T; class A { } diff --git a/gcc/testsuite/gdc.test/runnable/whetstone.d b/gcc/testsuite/gdc.test/runnable/whetstone.d index 9145c74bcfd1327bc6de07a8159b1d49283e136b..48f6010b9ffd5fd67a4740b3d3ba6a84236cd45f 100644 --- a/gcc/testsuite/gdc.test/runnable/whetstone.d +++ b/gcc/testsuite/gdc.test/runnable/whetstone.d @@ -1,5 +1,6 @@ /* PERMUTE_ARGS: -O +TRANSFORM_OUTPUT: remove_lines("warning: sprintf\(\) is often misused") */ /* diff --git a/gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d b/gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d index 5d4bc99c1bd4b731c5c36a39fe366a686d383df3..4e241749fbc9d9cac2fe8005eed8f4c2918c1f08 100644 --- a/gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d +++ b/gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d @@ -1,5 +1,5 @@ // EXTRA_CPP_SOURCES: cpp_abi_tests.cpp -// CXXFLAGS(linux freebsd osx netbsd dragonflybsd): -std=c++11 +// CXXFLAGS(linux freebsd osx openbsd netbsd dragonflybsd): -std=c++11 // N.B MSVC doesn't have a C++11 switch, but it defaults to the latest fully-supported standard // N.B MSVC 2013 doesn't support char16_t/char32_t diff --git a/gcc/testsuite/gdc.test/runnable_cxx/cpp_stdlib.d b/gcc/testsuite/gdc.test/runnable_cxx/cpp_stdlib.d index dd7bb11fc648e44b91b78cd73ba8faac855bcf5d..5b7d00a381941a5414bc6bf69300cc5641d64b7a 100644 --- a/gcc/testsuite/gdc.test/runnable_cxx/cpp_stdlib.d +++ b/gcc/testsuite/gdc.test/runnable_cxx/cpp_stdlib.d @@ -5,7 +5,7 @@ import core.stdc.stdio; // Disabled on windows because it needs bindings -version (CppRuntime_Clang) +version (CppRuntime_LLVM) { extern(C++, `std`, `__1`) { diff --git a/gcc/testsuite/gdc.test/runnable_cxx/cppa.d b/gcc/testsuite/gdc.test/runnable_cxx/cppa.d index 34c295590e391b4b8e5f23fa887df362c1597365..c62bc6face183837da1a1585a816dc47032f6ec6 100644 --- a/gcc/testsuite/gdc.test/runnable_cxx/cppa.d +++ b/gcc/testsuite/gdc.test/runnable_cxx/cppa.d @@ -2,9 +2,10 @@ // PERMUTE_ARGS: -g // EXTRA_CPP_SOURCES: cppb.cpp // EXTRA_FILES: extra-files/cppb.h -// CXXFLAGS(linux freebsd osx netbsd dragonflybsd): -std=c++11 +// CXXFLAGS(linux freebsd osx openbsd netbsd dragonflybsd): -std=c++11 // druntime isn't linked, this prevents missing symbols '_d_arraybounds_slicep': // REQUIRED_ARGS: -checkaction=C +// TRANSFORM_OUTPUT: remove_lines("warning: vsprintf\(\) is often misused") // N.B MSVC doesn't have a C++11 switch, but it defaults to the latest fully-supported standard @@ -454,7 +455,7 @@ extern (C++, std) { } - version (CppRuntime_Gcc) + version (CppRuntime_GNU) { // https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html static if (__traits(getTargetInfo, "cppStd") >= 201103) diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_nonpod_byval.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_nonpod_byval.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c320ec5582166d1a2a4b2563b5df0902dda6b52c --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_nonpod_byval.cpp @@ -0,0 +1,74 @@ +extern "C" int printf(const char *, ...); + +#define Foo(T) \ + T fooD(T param); \ + T fooCpp(T param) \ + { \ + printf("fooCpp %d [%p]\n", param.a, ¶m); \ + return fooD(T{2 * param.a}); \ + } + +struct POD +{ + int a; +}; +Foo(POD); + +struct CtorOnly +{ + int a; + CtorOnly() : a(0) {} + CtorOnly(int a) : a(a) {} +}; +Foo(CtorOnly); + +struct DtorOnly +{ + int a; + ~DtorOnly(); // implemented in D +}; +Foo(DtorOnly); + +struct CtorDtor +{ + int a; + CtorDtor(int a) : a(a) {} + ~CtorDtor(); // implemented in D +}; +Foo(CtorDtor); + +struct Copy +{ + int a; + Copy(int a) : a(a) {} + ~Copy(); // implemented in D + Copy(const Copy &rhs) : a(rhs.a) { printf("cppcpy %d [%p]\n", a, this); } +}; +Foo(Copy); + +struct CopyAndMove +{ + int a; + CopyAndMove(int a) : a(a) {} + ~CopyAndMove(); // implemented in D + CopyAndMove(const CopyAndMove &rhs) : a(rhs.a) { printf("cppcpy %d [%p]\n", a, this); } + CopyAndMove(CopyAndMove &&) = default; +}; +Foo(CopyAndMove); + +struct MoveOnly +{ + int a; + MoveOnly(int a) : a(a) {} + ~MoveOnly(); // implemented in D + MoveOnly(const MoveOnly &) = delete; + MoveOnly(MoveOnly &&) = default; +}; +Foo(MoveOnly); + +struct MemberWithCtor +{ + int a; + CtorOnly m; +}; +Foo(MemberWithCtor); diff --git a/gcc/testsuite/gdc.test/runnable_cxx/nonpod_byval.d b/gcc/testsuite/gdc.test/runnable_cxx/nonpod_byval.d new file mode 100644 index 0000000000000000000000000000000000000000..c7fac46a040a2844df9956f7886584100d7b9a90 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable_cxx/nonpod_byval.d @@ -0,0 +1,118 @@ +// EXTRA_CPP_SOURCES: cpp_nonpod_byval.cpp +// CXXFLAGS(linux osx freebsd dragonflybsd): -std=c++11 + +extern (C) int printf(const(char)*, ...); + +extern (C++): + +template Foo(T) +{ + T fooCpp(T param); // calls fooD() with a new, doubled literal + + T fooD(T param) + { + printf("fooD %d [%p]\n", param.a, ¶m); + assert(param.a == 2 * 123); + static if (__traits(compiles, { T copy = param; })) + return param; // invokes postblit + else + return T(param.a); + } +} + +void test(T)() +{ + printf(".: %.*s\n", cast(int) T.stringof.length, T.stringof.ptr); + + { + auto result = fooCpp(T(123)); + assert(result.a == 246); + } + + static if (__traits(hasMember, T, "numDtor")) + { + // fooCpp param + fooD param + result => 3 T instances. + // There may be an additional destruction of the moved-from T literal + // in fooCpp, depending on in-place construction vs. move. + assert(T.numDtor == 3 || T.numDtor == 4); + } +} + +struct POD +{ + int a; +} +mixin Foo!POD; + +struct CtorOnly +{ + int a; + this(int a) { this.a = a; } +} +mixin Foo!CtorOnly; + +struct DtorOnly +{ + static __gshared int numDtor = 0; + int a; + ~this() { printf("dtor %d [%p]\n", a, &this); ++numDtor; } +} +mixin Foo!DtorOnly; + +struct CtorDtor +{ + static __gshared int numDtor = 0; + int a; + this(int a) { this.a = a; } + ~this() { printf("dtor %d [%p]\n", a, &this); ++numDtor; } +} +mixin Foo!CtorDtor; + +struct Copy +{ + static __gshared int numDtor = 0; + int a; + this(int a) { this.a = a; } + ~this() { printf("dtor %d [%p]\n", a, &this); ++numDtor; } + this(this) { printf("post %d [%p]\n", a, &this); } +} +mixin Foo!Copy; + +struct CopyAndMove +{ + static __gshared int numDtor = 0; + int a; + this(int a) { this.a = a; } + ~this() { printf("dtor %d [%p]\n", a, &this); ++numDtor; } + this(this) { printf("post %d [%p]\n", a, &this); } +} +mixin Foo!CopyAndMove; + +struct MoveOnly +{ + static __gshared int numDtor = 0; + int a; + this(int a) { this.a = a; } + ~this() { printf("dtor %d [%p]\n", a, &this); ++numDtor; } + this(this) @disable; +} +mixin Foo!MoveOnly; + +struct MemberWithCtor +{ + int a; + CtorOnly m; +} +mixin Foo!MemberWithCtor; + +void main() +{ + test!POD(); + test!CtorOnly(); + test!DtorOnly(); + test!CtorDtor(); + test!Copy(); + test!CopyAndMove(); + test!MoveOnly(); + test!MemberWithCtor(); +} diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index 77e8562abcc346f344c4d264393c1bce0f9dd798..d458bea5e1a593bfcd3455a9fe99cdc29f4c5b09 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/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/libphobos/libdruntime/core/checkedint.d b/libphobos/libdruntime/core/checkedint.d index 49a5c11d1373bd96ba27db3b9e60135282338546..4c40b9957a994096109537bf5d88b02072bb5814 100644 --- a/libphobos/libdruntime/core/checkedint.d +++ b/libphobos/libdruntime/core/checkedint.d @@ -186,8 +186,8 @@ unittest { bool overflow; immutable uint r = addu (uint.max - i, uint.max - i, overflow); - assert (r == 2 * (uint.max - i)); - assert (overflow); + assert(r == 2 * (uint.max - i)); + assert(overflow); } bool overflow; diff --git a/libphobos/libdruntime/core/internal/newaa.d b/libphobos/libdruntime/core/internal/newaa.d index 2fd93651a22b40456b28563eac63db3e048390e9..7c858f33522ceaade006076c39350a20ed660f4f 100644 --- a/libphobos/libdruntime/core/internal/newaa.d +++ b/libphobos/libdruntime/core/internal/newaa.d @@ -102,7 +102,7 @@ AAShell makeAA(K, V)(V[K] src) @trusted dim = dim * GROW_FAC; // used during runtime. - size_t delegate(scope const void *) nothrow hashFn = (scope const void* val) { + typeof(Impl.hashFn) hashFn = (scope const void* val) { auto x = cast(K*)val; return hashOf(*x); }; diff --git a/libphobos/libdruntime/core/internal/parseoptions.d b/libphobos/libdruntime/core/internal/parseoptions.d index 2bf1da2fbfa5845cd60e0a7dba19f66d229553bc..2dd3ec8375b2bba484344ba8b53febee6aa6b73a 100644 --- a/libphobos/libdruntime/core/internal/parseoptions.d +++ b/libphobos/libdruntime/core/internal/parseoptions.d @@ -219,13 +219,12 @@ do return overflowedError(optname, str); i++; - break; } else // unexpected non-digit character { i = 0; - break; } + break; } } diff --git a/libphobos/libdruntime/core/internal/traits.d b/libphobos/libdruntime/core/internal/traits.d index 0b2eb1f21a711a3b2bd6ee473013ffc56fc00eec..f0d9ebc9a81362b41005ea76f7607373c377698e 100644 --- a/libphobos/libdruntime/core/internal/traits.d +++ b/libphobos/libdruntime/core/internal/traits.d @@ -51,7 +51,7 @@ unittest static assert(is(BaseElemOf!(int[1][2]) == int)); static assert(is(BaseElemOf!(int[1][]) == int[1][])); static assert(is(BaseElemOf!(int[][1]) == int[])); - static enum E : int[2]{ test = [0, 1] } + enum E : int[2]{ test = [0, 1] } static assert(is(BaseElemOf!(E) == int)); } @@ -809,30 +809,23 @@ unittest template hasUDA(alias symbol, alias attribute) { - alias attrs = __traits(getAttributes, symbol); + enum isAttr(T) = is(T == attribute); - static foreach (a; attrs) - { - static if (is(a == attribute)) - { - enum hasUDA = true; - } - } - - static if (!__traits(compiles, (hasUDA == true))) - enum hasUDA = false; + enum hasUDA = anySatisfy!(isAttr, __traits(getAttributes, symbol)); } unittest { - struct SomeUDA{} + enum SomeUDA; struct Test { int woUDA; - @SomeUDA int withUDA; + @SomeUDA int oneUDA; + @SomeUDA @SomeUDA int twoUDAs; } - static assert(hasUDA!(Test.withUDA, SomeUDA)); + static assert(hasUDA!(Test.oneUDA, SomeUDA)); + static assert(hasUDA!(Test.twoUDAs, SomeUDA)); static assert(!hasUDA!(Test.woUDA, SomeUDA)); } diff --git a/libphobos/libdruntime/core/lifetime.d b/libphobos/libdruntime/core/lifetime.d index 9e563ad43a30622fe58c04f77b13ca56e5761037..f3dab3624acc08ae5914316d089662b63c076599 100644 --- a/libphobos/libdruntime/core/lifetime.d +++ b/libphobos/libdruntime/core/lifetime.d @@ -104,7 +104,7 @@ T emplace(T, Args...)(T chunk, auto ref Args args) // Initialize the object in its pre-ctor state const initializer = __traits(initSymbol, T); - (() @trusted { (cast(void*) chunk)[0 .. initializer.length] = initializer[]; })(); + () @trusted { (cast(void*) chunk)[0 .. initializer.length] = cast(void[]) initializer[]; }(); static if (isInnerClass!T) { @@ -2683,7 +2683,7 @@ T _d_newThrowable(T)() @trusted debug(PRINTF) printf(" p = %p\n", p); // initialize it - p[0 .. init.length] = init[]; + p[0 .. init.length] = cast(void[]) init[]; import core.internal.traits : hasIndirections; if (hasIndirections!T) @@ -2776,7 +2776,7 @@ if (is(T == class)) } // initialize it - p[0 .. init.length] = init[]; + p[0 .. init.length] = cast(void[]) init[]; debug(PRINTF) printf("initialization done\n"); return cast(T) p; diff --git a/libphobos/libdruntime/core/runtime.d b/libphobos/libdruntime/core/runtime.d index 4ff728cc38c3df0ff9451330b4097917d78a5f5d..182886175a6b2232b23b2f91ff8b1fbd8d1ceca5 100644 --- a/libphobos/libdruntime/core/runtime.d +++ b/libphobos/libdruntime/core/runtime.d @@ -613,7 +613,7 @@ extern (C) UnitTestResult runModuleUnitTests() static extern (C) void unittestSegvHandler( int signum, siginfo_t* info, void* ptr ) nothrow { - static enum MAXFRAMES = 128; + enum MAXFRAMES = 128; void*[MAXFRAMES] callstack; auto numframes = backtrace( callstack.ptr, MAXFRAMES ); @@ -942,7 +942,7 @@ else static if (hasExecinfo) private class DefaultTraceInfo : Throwable.TraceInf private: int numframes; - static enum MAXFRAMES = 128; + enum MAXFRAMES = 128; void*[MAXFRAMES] callstack = void; private: diff --git a/libphobos/libdruntime/core/stdcpp/allocator.d b/libphobos/libdruntime/core/stdcpp/allocator.d index abf97c48b0b57acd759a0c102539c66772f95268..a574cd39e8b48723f379242e2358acebc7268398 100644 --- a/libphobos/libdruntime/core/stdcpp/allocator.d +++ b/libphobos/libdruntime/core/stdcpp/allocator.d @@ -147,7 +147,7 @@ extern(D): /// enum size_t max_size = size_t.max / T.sizeof; } - else version (CppRuntime_Gcc) + else version (CppRuntime_GNU) { /// T* allocate(size_t count, const(void)* = null) @nogc @@ -174,7 +174,7 @@ extern(D): /// enum size_t max_size = (ptrdiff_t.max < size_t.max ? cast(size_t)ptrdiff_t.max : size_t.max) / T.sizeof; } - else version (CppRuntime_Clang) + else version (CppRuntime_LLVM) { /// T* allocate(size_t count, const(void)* = null) @nogc @@ -360,7 +360,7 @@ version (CppRuntime_Microsoft) } } } -version (CppRuntime_Clang) +version (CppRuntime_LLVM) { // Helper for container swap package(core.stdcpp) void __swap_allocator(Alloc)(ref Alloc __a1, ref Alloc __a2) diff --git a/libphobos/libdruntime/core/stdcpp/array.d b/libphobos/libdruntime/core/stdcpp/array.d index 4cb0c56ec5fff00f2f3793feeb408685ee52ff87..912587c6c75bed299924e25d062079f2bfd24262 100644 --- a/libphobos/libdruntime/core/stdcpp/array.d +++ b/libphobos/libdruntime/core/stdcpp/array.d @@ -74,7 +74,7 @@ pure nothrow @nogc: private: T[N ? N : 1] _Elems; } - else version (CppRuntime_Gcc) + else version (CppRuntime_GNU) { /// inout(T)* data() inout @safe { static if (N > 0) { return &_M_elems[0]; } else { return null; } } @@ -94,7 +94,7 @@ pure nothrow @nogc: _Placeholder _M_placeholder; } } - else version (CppRuntime_Clang) + else version (CppRuntime_LLVM) { /// inout(T)* data() inout @trusted { static if (N > 0) { return &__elems_[0]; } else { return cast(inout(T)*)__elems_.ptr; } } diff --git a/libphobos/libdruntime/core/stdcpp/exception.d b/libphobos/libdruntime/core/stdcpp/exception.d index 4774b98615bf675c9ec3a15a3b5258823a92c5ea..bd3be0937f639eb1c802b8c1e9bc4c40bf640a0c 100644 --- a/libphobos/libdruntime/core/stdcpp/exception.d +++ b/libphobos/libdruntime/core/stdcpp/exception.d @@ -15,9 +15,9 @@ module core.stdcpp.exception; import core.stdcpp.xutility : __cplusplus, CppStdRevision; import core.attribute : weak; -version (CppRuntime_Gcc) +version (CppRuntime_GNU) version = GenericBaseException; -version (CppRuntime_Clang) +version (CppRuntime_LLVM) version = GenericBaseException; version (CppRuntime_Sun) version = GenericBaseException; diff --git a/libphobos/libdruntime/core/stdcpp/memory.d b/libphobos/libdruntime/core/stdcpp/memory.d index bd7976cfbc59694e8e1ba3900cba9b9174e61af1..d7b6f173878ed909995d11bf1291f8d715565abd 100644 --- a/libphobos/libdruntime/core/stdcpp/memory.d +++ b/libphobos/libdruntime/core/stdcpp/memory.d @@ -123,7 +123,7 @@ nothrow pure @safe @nogc: _Compressed_pair!(Deleter, pointer) _Mypair; } - else version (CppRuntime_Gcc) + else version (CppRuntime_GNU) { /// ref inout(deleter_type) get_deleter() inout nothrow { return _M_t.get!1; } @@ -136,7 +136,7 @@ nothrow pure @safe @nogc: tuple!(pointer, Deleter) _M_t; } - else version (CppRuntime_Clang) + else version (CppRuntime_LLVM) { /// ref inout(deleter_type) get_deleter() inout nothrow { return __ptr_.second; } diff --git a/libphobos/libdruntime/core/stdcpp/string.d b/libphobos/libdruntime/core/stdcpp/string.d index 722b82fe41848267ebb1a22fd4b0d3d96038f945..0315867da60c8228b58ea789216003f30887d5fa 100644 --- a/libphobos/libdruntime/core/stdcpp/string.d +++ b/libphobos/libdruntime/core/stdcpp/string.d @@ -31,7 +31,7 @@ version (Darwin) version = _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT; } -version (CppRuntime_Gcc) +version (CppRuntime_GNU) { version (_GLIBCXX_USE_CXX98_ABI) { @@ -894,7 +894,7 @@ extern(D): _String_alloc!(_String_base_types!(T, Alloc)) _Base; } - else version (CppRuntime_Gcc) + else version (CppRuntime_GNU) { version (_GLIBCXX_USE_CXX98_ABI) { @@ -1873,10 +1873,10 @@ extern(D): __d[0 .. __n] = __s[0 .. __n]; } } - else version (CppRuntime_Clang) + else version (CppRuntime_LLVM) { //---------------------------------------------------------------------------------- - // Clang/libc++ implementation + // libc++ implementation //---------------------------------------------------------------------------------- /// diff --git a/libphobos/libdruntime/core/stdcpp/string_view.d b/libphobos/libdruntime/core/stdcpp/string_view.d index 47f58b014ef1e9efde512511b0aac38fa8cf18d5..fd79a121be51f2ca43c8fffee4674c020d38a1c4 100644 --- a/libphobos/libdruntime/core/stdcpp/string_view.d +++ b/libphobos/libdruntime/core/stdcpp/string_view.d @@ -99,7 +99,7 @@ private: alias __data = _Mydata; alias __size = _Mysize; } - else version (CppRuntime_Gcc) + else version (CppRuntime_GNU) { size_t _M_len; const(T)* _M_str; @@ -107,7 +107,7 @@ private: alias __data = _M_str; alias __size = _M_len; } - else version (CppRuntime_Clang) + else version (CppRuntime_LLVM) { const value_type* __data; size_type __size; diff --git a/libphobos/libdruntime/core/stdcpp/typeinfo.d b/libphobos/libdruntime/core/stdcpp/typeinfo.d index b8478b39414acd9d43cc2e11f93eb5aae2b2a90b..463a813bc968c5923f5458db23fe460b344d2615 100644 --- a/libphobos/libdruntime/core/stdcpp/typeinfo.d +++ b/libphobos/libdruntime/core/stdcpp/typeinfo.d @@ -56,7 +56,7 @@ version (CppRuntime_Microsoft) //virtual ~this(); } } -else version (CppRuntime_Gcc) +else version (CppRuntime_GNU) { import core.stdcpp.exception; @@ -110,7 +110,7 @@ else version (CppRuntime_Gcc) @weak override const(char)* what() const nothrow { return "bad typeid"; } } } -else version (CppRuntime_Clang) +else version (CppRuntime_LLVM) { import core.stdcpp.exception; diff --git a/libphobos/libdruntime/core/stdcpp/xutility.d b/libphobos/libdruntime/core/stdcpp/xutility.d index 0142d0b9455feb4155488373218fefda3152f0e9..5e2e711ba67bf8dff123989779fe83eced2b728d 100644 --- a/libphobos/libdruntime/core/stdcpp/xutility.d +++ b/libphobos/libdruntime/core/stdcpp/xutility.d @@ -13,7 +13,7 @@ module core.stdcpp.xutility; @nogc: -version (CppRuntime_Clang) +version (CppRuntime_LLVM) { import core.internal.traits : AliasSeq; enum StdNamespace = AliasSeq!("std", "__1"); @@ -349,7 +349,7 @@ package: void _Xoverflow_error(const(char)* message) nothrow; void _Xruntime_error(const(char)* message) nothrow; } -else version (CppRuntime_Clang) +else version (CppRuntime_LLVM) { import core.stdcpp.type_traits : is_empty; @@ -379,7 +379,7 @@ extern(C++, "std"): @property ref inout(_T2) __value2_() inout nothrow @trusted @nogc { return *__get_base2(); } } } -version (CppRuntime_Gcc) +version (CppRuntime_GNU) { import core.atomic; diff --git a/libphobos/libdruntime/core/sys/posix/dirent.d b/libphobos/libdruntime/core/sys/posix/dirent.d index c7e8649d6c58b9258839e44e3fb1184b42f26565..cb76573a95b5391a6e73e027acdb31de502ddab5 100644 --- a/libphobos/libdruntime/core/sys/posix/dirent.d +++ b/libphobos/libdruntime/core/sys/posix/dirent.d @@ -42,7 +42,18 @@ struct dirent } */ -version (linux) +version (CRuntime_Bionic) +{ + struct dirent + { + ulong d_ino; + long d_off; + ushort d_reclen; + ubyte d_type; + char[256] d_name = 0; + } +} +else version (linux) { struct dirent { diff --git a/libphobos/libdruntime/core/sys/posix/dlfcn.d b/libphobos/libdruntime/core/sys/posix/dlfcn.d index f457c1f22b776aba714ee18d14f9503748585514..76542c64c8a3edd82db8cee21110d227ae313d57 100644 --- a/libphobos/libdruntime/core/sys/posix/dlfcn.d +++ b/libphobos/libdruntime/core/sys/posix/dlfcn.d @@ -372,12 +372,20 @@ else version (Solaris) } else version (CRuntime_Bionic) { - enum + enum RTLD_LOCAL = 0; + enum RTLD_LAZY = 0x00001; + enum RTLD_NOLOAD = 0x00004; + enum RTLD_NODELETE = 0x01000; + + version (D_LP64) + { + enum RTLD_NOW = 0x00002; + enum RTLD_GLOBAL = 0x00100; + } + else // NDK: 'LP32 is broken for historical reasons' { - RTLD_NOW = 0, - RTLD_LAZY = 1, - RTLD_LOCAL = 0, - RTLD_GLOBAL = 2 + enum RTLD_NOW = 0; + enum RTLD_GLOBAL = 0x00002; } int dladdr(const scope void*, Dl_info*); diff --git a/libphobos/libdruntime/core/sys/posix/sys/stat.d b/libphobos/libdruntime/core/sys/posix/sys/stat.d index b89478fe7d7515b745232bc5e82f9346d22cc22e..328f620a42a2234e9652d49c71360f1148730522 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/stat.d +++ b/libphobos/libdruntime/core/sys/posix/sys/stat.d @@ -33,6 +33,11 @@ version (RISCV64) version = RISCV_Any; version (SPARC) version = SPARC_Any; version (SPARC64) version = SPARC_Any; +// Android uses 64-bit offsets for stat, but 32-bit offsets for most +// other types on 32-bit architectures. +version (CRuntime_Bionic) + private enum __USE_FILE_OFFSET64 = true; + version (Posix): extern (C) nothrow @nogc: diff --git a/libphobos/libdruntime/core/sys/posix/sys/statvfs.d b/libphobos/libdruntime/core/sys/posix/sys/statvfs.d index eae0e5c95c6ba2ee9010b80ae7b34e7a15d22235..9405a6d5387ebdfd6ef9619b85040a92ebaed193 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/statvfs.d +++ b/libphobos/libdruntime/core/sys/posix/sys/statvfs.d @@ -84,7 +84,57 @@ version (CRuntime_Glibc) { int statvfs (const char * file, statvfs_t* buf); int fstatvfs (int fildes, statvfs_t *buf); } +} +else version (CRuntime_Musl) +{ + struct statvfs_t + { + c_ulong f_bsize; + c_ulong f_frsize; + fsblkcnt_t f_blocks; + fsblkcnt_t f_bfree; + fsblkcnt_t f_bavail; + fsfilcnt_t f_files; + fsfilcnt_t f_ffree; + fsfilcnt_t f_favail; + static if (true /+__BYTE_ORDER == __LITTLE_ENDIAN+/) + { + c_ulong f_fsid; + byte[2*int.sizeof-c_long.sizeof] __padding; + } + else + { + byte[2*int.sizeof-c_long.sizeof] __padding; + c_ulong f_fsid; + } + c_ulong f_flag; + c_ulong f_namemax; + uint f_type; + int[5] __reserved; + } + + enum FFlag + { + ST_RDONLY = 1, /* Mount read-only. */ + ST_NOSUID = 2, + ST_NODEV = 4, /* Disallow access to device special files. */ + ST_NOEXEC = 8, /* Disallow program execution. */ + ST_SYNCHRONOUS = 16, /* Writes are synced at once. */ + ST_MANDLOCK = 64, /* Allow mandatory locks on an FS. */ + ST_WRITE = 128, /* Write on file/directory/symlink. */ + ST_APPEND = 256, /* Append-only file. */ + ST_IMMUTABLE = 512, /* Immutable file. */ + ST_NOATIME = 1024, /* Do not update access times. */ + ST_NODIRATIME = 2048, /* Do not update directory access times. */ + ST_RELATIME = 4096 /* Update atime relative to mtime/ctime. */ + + } + + int statvfs (const char * file, statvfs_t* buf); + int fstatvfs (int fildes, statvfs_t *buf); + alias statvfs statvfs64; + alias fstatvfs fstatvfs64; } else version (NetBSD) { diff --git a/libphobos/libdruntime/core/sys/windows/stacktrace.d b/libphobos/libdruntime/core/sys/windows/stacktrace.d index 29ffc1b078546d4c613675a3796c78fa2ea6f322..04aafd3f6022d136bd0997760dbd8d0497d88ca8 100644 --- a/libphobos/libdruntime/core/sys/windows/stacktrace.d +++ b/libphobos/libdruntime/core/sys/windows/stacktrace.d @@ -48,9 +48,9 @@ public: if (context is null) { version (Win64) - static enum INTERNALFRAMES = 3; + enum INTERNALFRAMES = 3; else version (Win32) - static enum INTERNALFRAMES = 2; + enum INTERNALFRAMES = 2; skip += INTERNALFRAMES; //skip the stack frames within the StackTrace class } @@ -58,9 +58,9 @@ public: { //When a exception context is given the first stack frame is repeated for some reason version (Win64) - static enum INTERNALFRAMES = 1; + enum INTERNALFRAMES = 1; else version (Win32) - static enum INTERNALFRAMES = 1; + enum INTERNALFRAMES = 1; skip += INTERNALFRAMES; } diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d index 0bdb45a343fa9133db372f5e3944ef64ae54ee45..307048135b8546a5c9f2987bde47dcb6ff042888 100644 --- a/libphobos/libdruntime/core/thread/osthread.d +++ b/libphobos/libdruntime/core/thread/osthread.d @@ -2211,7 +2211,7 @@ extern (C) void thread_init() @nogc nothrow status = sem_init( &suspendCount, 0, 0 ); assert( status == 0 ); } - _mainThreadStore[] = __traits(initSymbol, Thread)[]; + _mainThreadStore[] = cast(void[]) __traits(initSymbol, Thread)[]; Thread.sm_main = attachThread((cast(Thread)_mainThreadStore.ptr).__ctor()); } diff --git a/libphobos/libdruntime/core/thread/threadbase.d b/libphobos/libdruntime/core/thread/threadbase.d index f593387c755a00e93f78c567f16a662f1c4346a9..58dd259e30ddb458fbca17abb9840a04f7fe696b 100644 --- a/libphobos/libdruntime/core/thread/threadbase.d +++ b/libphobos/libdruntime/core/thread/threadbase.d @@ -778,7 +778,7 @@ package void thread_term_tpl(ThreadT, MainThreadStore)(ref MainThreadStore _main // destruct manually as object.destroy is not @nogc (cast(ThreadT) cast(void*) ThreadBase.sm_main).__dtor(); _d_monitordelete_nogc(ThreadBase.sm_main); - _mainThreadStore[] = __traits(initSymbol, ThreadT)[]; + _mainThreadStore[] = cast(void[]) __traits(initSymbol, ThreadT)[]; ThreadBase.sm_main = null; assert(ThreadBase.sm_tbeg && ThreadBase.sm_tlen == 1); diff --git a/libphobos/libdruntime/gcc/sections/elf.d b/libphobos/libdruntime/gcc/sections/elf.d index 1a3ff409d5802b2c0fc18b71adeefbef31976efe..bbebedf345ecbb6ed293f83e45d988ba18a7fe8d 100644 --- a/libphobos/libdruntime/gcc/sections/elf.d +++ b/libphobos/libdruntime/gcc/sections/elf.d @@ -161,18 +161,11 @@ private: } } -/**** - * Boolean flag set to true while the runtime is initialized. - */ -__gshared bool _isRuntimeInitialized; - - /**** * Gets called on program startup just before GC is initialized. */ void initSections() nothrow @nogc { - _isRuntimeInitialized = true; } @@ -181,7 +174,6 @@ void initSections() nothrow @nogc */ void finiSections() nothrow @nogc { - _isRuntimeInitialized = false; } alias ScanDG = void delegate(void* pbeg, void* pend) nothrow; @@ -482,7 +474,7 @@ extern(C) void _d_dso_registry(CompilerDSOData* data) } // don't initialize modules before rt_init was called (see Bugzilla 11378) - if (_isRuntimeInitialized) + if (isRuntimeInitialized()) { registerGCRanges(pdso); // rt_loadLibrary will run tls ctors, so do this only for dlopen @@ -497,7 +489,7 @@ extern(C) void _d_dso_registry(CompilerDSOData* data) *data._slot = null; // don't finalizes modules after rt_term was called (see Bugzilla 11378) - if (_isRuntimeInitialized) + if (isRuntimeInitialized()) { // rt_unloadLibrary already ran tls dtors, so do this only for dlclose immutable runTlsDtors = !_rtLoading; diff --git a/libphobos/libdruntime/gcc/sections/macho.d b/libphobos/libdruntime/gcc/sections/macho.d index 645c0f48350cdbbb0dec25dae93bdd4027f082ff..7211fa773905e556d946e9124d791ab63eba310b 100644 --- a/libphobos/libdruntime/gcc/sections/macho.d +++ b/libphobos/libdruntime/gcc/sections/macho.d @@ -30,6 +30,7 @@ import core.sys.darwin.dlfcn; import core.sys.darwin.mach.dyld; import core.sys.darwin.mach.getsect; import core.sys.posix.pthread; +import rt.dmain2; import rt.minfo; import core.internal.container.array; import core.internal.container.hashtab; @@ -95,17 +96,11 @@ private: } } -/**** - * Boolean flag set to true while the runtime is initialized. - */ -__gshared bool _isRuntimeInitialized; - /**** * Gets called on program startup just before GC is initialized. */ void initSections() nothrow @nogc { - _isRuntimeInitialized = true; } /*** @@ -113,7 +108,6 @@ void initSections() nothrow @nogc */ void finiSections() nothrow @nogc { - _isRuntimeInitialized = false; } alias ScanDG = void delegate(void* pbeg, void* pend) nothrow; @@ -379,7 +373,7 @@ extern(C) void _d_dso_registry(CompilerDSOData* data) } // don't initialize modules before rt_init was called - if (_isRuntimeInitialized) + if (isRuntimeInitialized()) { registerGCRanges(pdso); // rt_loadLibrary will run tls ctors, so do this only for dlopen @@ -394,7 +388,7 @@ extern(C) void _d_dso_registry(CompilerDSOData* data) *data._slot = null; // don't finalizes modules after rt_term was called (see Bugzilla 11378) - if (_isRuntimeInitialized) + if (isRuntimeInitialized()) { // rt_unloadLibrary already ran tls dtors, so do this only for dlclose immutable runTlsDtors = !_rtLoading; diff --git a/libphobos/libdruntime/gcc/sections/pecoff.d b/libphobos/libdruntime/gcc/sections/pecoff.d index 038e37398ed63d92db096f620c9037abab6c7cb6..fb49f6201e0666dece1b000b990ba39883c02011 100644 --- a/libphobos/libdruntime/gcc/sections/pecoff.d +++ b/libphobos/libdruntime/gcc/sections/pecoff.d @@ -29,6 +29,7 @@ import core.stdc.stdlib; import core.sys.windows.winbase; import core.sys.windows.windef; import core.sys.windows.winnt; +import rt.dmain2; import rt.minfo; import core.internal.container.array; import core.internal.container.hashtab; @@ -94,17 +95,11 @@ private: } } -/**** - * Boolean flag set to true while the runtime is initialized. - */ -__gshared bool _isRuntimeInitialized; - /**** * Gets called on program startup just before GC is initialized. */ void initSections() nothrow @nogc { - _isRuntimeInitialized = true; } /*** @@ -112,7 +107,6 @@ void initSections() nothrow @nogc */ void finiSections() nothrow @nogc { - _isRuntimeInitialized = false; } alias ScanDG = void delegate(void* pbeg, void* pend) nothrow; @@ -372,7 +366,7 @@ extern(C) void _d_dso_registry(CompilerDSOData* data) } // don't initialize modules before rt_init was called - if (_isRuntimeInitialized) + if (isRuntimeInitialized()) { registerGCRanges(pdso); // rt_loadLibrary will run tls ctors, so do this only for dlopen @@ -387,7 +381,7 @@ extern(C) void _d_dso_registry(CompilerDSOData* data) *data._slot = null; // don't finalizes modules after rt_term was called (see Bugzilla 11378) - if (_isRuntimeInitialized) + if (isRuntimeInitialized()) { // rt_unloadLibrary already ran tls dtors, so do this only for dlclose immutable runTlsDtors = !_rtLoading; diff --git a/libphobos/libdruntime/rt/aaA.d b/libphobos/libdruntime/rt/aaA.d index 5903d9cd754b1bf8dddd20ec7355ef5143a21a95..26c16d3af0a400aa1d13f24b1c208b0ba30df1cc 100644 --- a/libphobos/libdruntime/rt/aaA.d +++ b/libphobos/libdruntime/rt/aaA.d @@ -688,7 +688,7 @@ extern (C) inout(void[]) _aaValues(inout AA aa, const size_t keysz, const size_t { if (!b.filled) continue; - pval[0 .. valsz] = b.entry[off .. valsz + off]; + pval[0 .. valsz] = cast(void[]) b.entry[off .. valsz + off]; pval += valsz; } // postblit is done in object.values @@ -710,7 +710,7 @@ extern (C) inout(void[]) _aaKeys(inout AA aa, const size_t keysz, const TypeInfo { if (!b.filled) continue; - pkey[0 .. keysz] = b.entry[0 .. keysz]; + pkey[0 .. keysz] = cast(void[]) b.entry[0 .. keysz]; pkey += keysz; } // postblit is done in object.keys diff --git a/libphobos/libdruntime/rt/dmain2.d b/libphobos/libdruntime/rt/dmain2.d index 5ac053cef152dbe90f027c6e355ef528d84921f2..052b859fd4905a746a603c74d04966af910fe1ff 100644 --- a/libphobos/libdruntime/rt/dmain2.d +++ b/libphobos/libdruntime/rt/dmain2.d @@ -102,7 +102,7 @@ alias void delegate(Throwable) ExceptionHandler; /** * Keep track of how often rt_init/rt_term were called. */ -shared size_t _initCount; +private shared size_t _initCount; /********************************************** * Initialize druntime. @@ -177,6 +177,13 @@ extern (C) int rt_term() return 0; } +/** + * Indicates whether druntime has been or is being initialized. + */ +bool isRuntimeInitialized() @nogc nothrow { + return atomicLoad!(MemoryOrder.raw)(_initCount) != 0; +} + /********************************************** * Trace handler */ diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d index 4a071f3d81bb0acdfcd4c9a8dafdea36ae849047..676f88d5ae403e10c6ba715541daba6e6c8cb186 100644 --- a/libphobos/libdruntime/rt/lifetime.d +++ b/libphobos/libdruntime/rt/lifetime.d @@ -129,7 +129,7 @@ extern (C) Object _d_newclass(const ClassInfo ci) @weak } // initialize it - p[0 .. init.length] = init[]; + p[0 .. init.length] = cast(void[]) init[]; debug(PRINTF) printf("initialization done\n"); return cast(Object) p; @@ -1294,7 +1294,7 @@ extern (C) void rt_finalize2(void* p, bool det = true, bool resetMemory = true) if (resetMemory) { auto w = (*pc).initializer; - p[0 .. w.length] = w[]; + p[0 .. w.length] = cast(void[]) w[]; } } catch (Exception e) diff --git a/libphobos/libdruntime/rt/sections.d b/libphobos/libdruntime/rt/sections.d index 6a15552034042f160a7377557c64612419ae95f0..a7b75d4ba81e793c4ecafa916373e09f758b496b 100644 --- a/libphobos/libdruntime/rt/sections.d +++ b/libphobos/libdruntime/rt/sections.d @@ -57,7 +57,7 @@ else version (Darwin) else version (CRuntime_Microsoft) public import rt.sections_win64; else version (CRuntime_Bionic) - public import rt.sections_android; + public import rt.sections_elf_shared; else version (CRuntime_UClibc) public import rt.sections_elf_shared; else diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index a431ca1e43e67c094b91b2d547ebc75caf5dfdca..46e244379e16ce05a04989b3db105f90a7fee868 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -de1dea109f40fe4a551578369c474e48845daec1 +0c28620c301c9ae3136b1e1e5af55c290dbc7aae The first line of this file holds the git revision number of the last merge done from the dlang/phobos repository. diff --git a/libphobos/src/Makefile.am b/libphobos/src/Makefile.am index d45d116c691f7d98e4694c325eb29f87f37f2f4e..a8a5ed3a357ddef17f9642af4f244051fbcd0e6e 100644 --- a/libphobos/src/Makefile.am +++ b/libphobos/src/Makefile.am @@ -138,18 +138,18 @@ PHOBOS_DSOURCES = etc/c/curl.d etc/c/zlib.d std/algorithm/comparison.d \ std/internal/math/errorfunction.d std/internal/math/gammafunction.d \ std/internal/memory.d std/internal/scopebuffer.d \ std/internal/test/dummyrange.d std/internal/test/range.d \ - std/internal/test/uda.d std/internal/unicode_comp.d \ - std/internal/unicode_decomp.d std/internal/unicode_grapheme.d \ - std/internal/unicode_norm.d std/internal/unicode_tables.d \ - std/internal/windows/advapi32.d std/json.d std/logger/core.d \ - std/logger/filelogger.d std/logger/multilogger.d \ - std/logger/nulllogger.d std/logger/package.d std/math/algebraic.d \ - std/math/constants.d std/math/exponential.d std/math/hardware.d \ - std/math/operations.d std/math/package.d std/math/remainder.d \ - std/math/rounding.d std/math/traits.d std/math/trigonometry.d \ - std/mathspecial.d std/meta.d std/mmfile.d std/net/curl.d \ - std/net/isemail.d std/numeric.d std/outbuffer.d std/package.d \ - std/parallelism.d std/path.d std/process.d std/random.d \ + std/internal/test/sumtype_example_overloads.d std/internal/test/uda.d \ + std/internal/unicode_comp.d std/internal/unicode_decomp.d \ + std/internal/unicode_grapheme.d std/internal/unicode_norm.d \ + std/internal/unicode_tables.d std/internal/windows/advapi32.d \ + std/json.d std/logger/core.d std/logger/filelogger.d \ + std/logger/multilogger.d std/logger/nulllogger.d std/logger/package.d \ + std/math/algebraic.d std/math/constants.d std/math/exponential.d \ + std/math/hardware.d std/math/operations.d std/math/package.d \ + std/math/remainder.d std/math/rounding.d std/math/traits.d \ + std/math/trigonometry.d std/mathspecial.d std/meta.d std/mmfile.d \ + std/net/curl.d std/net/isemail.d std/numeric.d std/outbuffer.d \ + std/package.d std/parallelism.d std/path.d std/process.d std/random.d \ std/range/interfaces.d std/range/package.d std/range/primitives.d \ std/regex/internal/backtracking.d std/regex/internal/generator.d \ std/regex/internal/ir.d std/regex/internal/kickstart.d \ diff --git a/libphobos/src/Makefile.in b/libphobos/src/Makefile.in index cc3358b437e15d237c6571661816704bd1399aae..52f2d1a2e3b8f49c12cc66a6f3ea71056845de6a 100644 --- a/libphobos/src/Makefile.in +++ b/libphobos/src/Makefile.in @@ -237,6 +237,7 @@ am__dirstamp = $(am__leading_dot)dirstamp @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/scopebuffer.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/test/dummyrange.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/test/range.lo \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/test/sumtype_example_overloads.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/test/uda.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_comp.lo \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_decomp.lo \ @@ -599,18 +600,18 @@ libgphobos_la_LINK = $(LIBTOOL) --tag=D $(libgphobos_la_LIBTOOLFLAGS) \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/math/errorfunction.d std/internal/math/gammafunction.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/memory.d std/internal/scopebuffer.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/test/dummyrange.d std/internal/test/range.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/test/uda.d std/internal/unicode_comp.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_decomp.d std/internal/unicode_grapheme.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_norm.d std/internal/unicode_tables.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/windows/advapi32.d std/json.d std/logger/core.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/logger/filelogger.d std/logger/multilogger.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/logger/nulllogger.d std/logger/package.d std/math/algebraic.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/constants.d std/math/exponential.d std/math/hardware.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/operations.d std/math/package.d std/math/remainder.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/rounding.d std/math/traits.d std/math/trigonometry.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/mathspecial.d std/meta.d std/mmfile.d std/net/curl.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/net/isemail.d std/numeric.d std/outbuffer.d std/package.d \ -@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/parallelism.d std/path.d std/process.d std/random.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/test/sumtype_example_overloads.d std/internal/test/uda.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_comp.d std/internal/unicode_decomp.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_grapheme.d std/internal/unicode_norm.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_tables.d std/internal/windows/advapi32.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/json.d std/logger/core.d std/logger/filelogger.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/logger/multilogger.d std/logger/nulllogger.d std/logger/package.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/algebraic.d std/math/constants.d std/math/exponential.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/hardware.d std/math/operations.d std/math/package.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/remainder.d std/math/rounding.d std/math/traits.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/trigonometry.d std/mathspecial.d std/meta.d std/mmfile.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/net/curl.d std/net/isemail.d std/numeric.d std/outbuffer.d \ +@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/package.d std/parallelism.d std/path.d std/process.d std/random.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/range/interfaces.d std/range/package.d std/range/primitives.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/internal/backtracking.d std/regex/internal/generator.d \ @ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/internal/ir.d std/regex/internal/kickstart.d \ @@ -868,6 +869,8 @@ std/internal/test/$(am__dirstamp): @: > std/internal/test/$(am__dirstamp) std/internal/test/dummyrange.lo: std/internal/test/$(am__dirstamp) std/internal/test/range.lo: std/internal/test/$(am__dirstamp) +std/internal/test/sumtype_example_overloads.lo: \ + std/internal/test/$(am__dirstamp) std/internal/test/uda.lo: std/internal/test/$(am__dirstamp) std/internal/unicode_comp.lo: std/internal/$(am__dirstamp) std/internal/unicode_decomp.lo: std/internal/$(am__dirstamp) diff --git a/libphobos/src/std/format/spec.d b/libphobos/src/std/format/spec.d index b129686f8a3aadc2d7f47e6190902b2e33ea3e17..e5564c99d8fce9f0a765783ad043fb89ee91a1b3 100644 --- a/libphobos/src/std/format/spec.d +++ b/libphobos/src/std/format/spec.d @@ -681,7 +681,7 @@ if (is(Unqual!Char == Char)) auto fmt = "Number: %6.4e\nString: %s"; auto f = FormatSpec!char(fmt); - assert(f.writeUpToNextSpec(a) == true); + assert(f.writeUpToNextSpec(a)); assert(a.data == "Number: "); assert(f.trailing == "\nString: %s"); @@ -689,13 +689,13 @@ if (is(Unqual!Char == Char)) assert(f.width == 6); assert(f.precision == 4); - assert(f.writeUpToNextSpec(a) == true); + assert(f.writeUpToNextSpec(a)); assert(a.data == "Number: \nString: "); assert(f.trailing == ""); assert(f.spec == 's'); - assert(f.writeUpToNextSpec(a) == false); + assert(!f.writeUpToNextSpec(a)); assert(a.data == "Number: \nString: "); } diff --git a/libphobos/src/std/internal/test/sumtype_example_overloads.d b/libphobos/src/std/internal/test/sumtype_example_overloads.d new file mode 100644 index 0000000000000000000000000000000000000000..235659dc8b7d8e66767d57b464c63be96288ff93 --- /dev/null +++ b/libphobos/src/std/internal/test/sumtype_example_overloads.d @@ -0,0 +1,17 @@ +/++ +For testing only. + +Overload set used in std.sumtype example. Needs its own internal module so that +it can be available for `make publictests` without polluting the public API. ++/ +module std.internal.test.sumtype_example_overloads; + +import std.sumtype; + +@safe +{ + string handle(int) { return "got an int"; } + string handle(string) { return "got a string"; } + string handle(double) { return "got a double"; } + alias handle = match!handle; +} diff --git a/libphobos/src/std/math/exponential.d b/libphobos/src/std/math/exponential.d index 5e90f0de897db18bb2047ecc4ae7b0c3816f895f..8fcd88f4c6867969520df67fabe0cd6f244209d3 100644 --- a/libphobos/src/std/math/exponential.d +++ b/libphobos/src/std/math/exponential.d @@ -256,7 +256,7 @@ if (isFloatingPoint!(F) && isIntegral!(G)) * If x is 0 and n is negative, the result is the same as the result of a * division by zero. */ -typeof(Unqual!(F).init * Unqual!(G).init) pow(F, G)(F x, G n) @nogc @trusted pure nothrow +typeof(Unqual!(F).init * Unqual!(G).init) pow(F, G)(F x, G n) @nogc @safe pure nothrow if (isIntegral!(F) && isIntegral!(G)) { import std.traits : isSigned; diff --git a/libphobos/src/std/net/curl.d b/libphobos/src/std/net/curl.d index 3f823013e650e891e243edf02c41ad72f055a5fe..07905fc7003838eef44782b100bd4232644d9569 100644 --- a/libphobos/src/std/net/curl.d +++ b/libphobos/src/std/net/curl.d @@ -1063,7 +1063,7 @@ private auto _basicHTTP(T)(const(char)[] url, const(void)[] sendData, HTTP clien { size_t minLen = min(buf.length, remainingData.length); if (minLen == 0) return 0; - buf[0 .. minLen] = remainingData[0 .. minLen]; + buf[0 .. minLen] = cast(void[]) remainingData[0 .. minLen]; remainingData = remainingData[minLen..$]; return minLen; }; @@ -1202,7 +1202,7 @@ private auto _basicFTP(T)(const(char)[] url, const(void)[] sendData, FTP client) { size_t minLen = min(buf.length, sendData.length); if (minLen == 0) return 0; - buf[0 .. minLen] = sendData[0 .. minLen]; + buf[0 .. minLen] = cast(void[]) sendData[0 .. minLen]; sendData = sendData[minLen..$]; return minLen; }; diff --git a/libphobos/src/std/range/package.d b/libphobos/src/std/range/package.d index 995bf1e6c9b5acb04c3df282ec6e2fc8a46e807d..b6fddf76559bf250ec0a748cfdc7faae165473c2 100644 --- a/libphobos/src/std/range/package.d +++ b/libphobos/src/std/range/package.d @@ -13539,10 +13539,10 @@ if (isInputRange!R && isIntegral!(ElementType!R)) { size_t bitsNum = IntegralType.sizeof * 8; - auto first = cast(IntegralType)(1); + auto first = IntegralType(1); // 2 ^ (bitsNum - 1) - auto second = cast(IntegralType)(cast(IntegralType)(1) << (bitsNum - 2)); + auto second = cast(IntegralType)(IntegralType(1) << (bitsNum - 2)); IntegralType[] a = [first, second]; auto bw = Bitwise!(IntegralType[])(a); @@ -13571,7 +13571,7 @@ if (isInputRange!R && isIntegral!(ElementType!R)) auto bw2 = bw[0 .. $ - 5]; auto bw3 = bw2[]; - assert(bw2.length == (bw.length - 5)); + assert(bw2.length == bw.length - 5); assert(bw2.length == bw3.length); bw2.popFront(); assert(bw2.length != bw3.length); diff --git a/libphobos/src/std/string.d b/libphobos/src/std/string.d index b350d6b7134c69da6b75eadf201ebd58a8b9baeb..21e1ca356f8605f3fb01ee0b28ef952fb58b4d0d 100644 --- a/libphobos/src/std/string.d +++ b/libphobos/src/std/string.d @@ -6331,42 +6331,42 @@ if (isSomeString!S || assertCTFEable!( { // Test the isNumeric(in string) function - assert(isNumeric("1") == true ); - assert(isNumeric("1.0") == true ); - assert(isNumeric("1e-1") == true ); - assert(isNumeric("12345xxxx890") == false ); - assert(isNumeric("567L") == true ); - assert(isNumeric("23UL") == true ); - assert(isNumeric("-123..56f") == false ); - assert(isNumeric("12.3.5.6") == false ); - assert(isNumeric(" 12.356") == false ); - assert(isNumeric("123 5.6") == false ); - assert(isNumeric("1233E-1+1.0e-1i") == true ); - - assert(isNumeric("123.00E-5+1234.45E-12Li") == true); - assert(isNumeric("123.00e-5+1234.45E-12iL") == false); - assert(isNumeric("123.00e-5+1234.45e-12uL") == false); - assert(isNumeric("123.00E-5+1234.45e-12lu") == false); - - assert(isNumeric("123fi") == true); - assert(isNumeric("123li") == true); - assert(isNumeric("--123L") == false); - assert(isNumeric("+123.5UL") == false); - assert(isNumeric("123f") == true); - assert(isNumeric("123.u") == false); + assert(isNumeric("1")); + assert(isNumeric("1.0")); + assert(isNumeric("1e-1")); + assert(!isNumeric("12345xxxx890")); + assert(isNumeric("567L")); + assert(isNumeric("23UL")); + assert(!isNumeric("-123..56f")); + assert(!isNumeric("12.3.5.6")); + assert(!isNumeric(" 12.356")); + assert(!isNumeric("123 5.6")); + assert(isNumeric("1233E-1+1.0e-1i")); + + assert(isNumeric("123.00E-5+1234.45E-12Li")); + assert(!isNumeric("123.00e-5+1234.45E-12iL")); + assert(!isNumeric("123.00e-5+1234.45e-12uL")); + assert(!isNumeric("123.00E-5+1234.45e-12lu")); + + assert(isNumeric("123fi")); + assert(isNumeric("123li")); + assert(!isNumeric("--123L")); + assert(!isNumeric("+123.5UL")); + assert(isNumeric("123f")); + assert(!isNumeric("123.u")); // @@@BUG@@ to!string(float) is not CTFEable. // Related: formatValue(T) if (is(FloatingPointTypeOf!T)) if (!__ctfe) { - assert(isNumeric(to!string(real.nan)) == true); - assert(isNumeric(to!string(-real.infinity)) == true); + assert(isNumeric(to!string(real.nan))); + assert(isNumeric(to!string(-real.infinity))); } string s = "$250.99-"; - assert(isNumeric(s[1 .. s.length - 2]) == true); - assert(isNumeric(s) == false); - assert(isNumeric(s[0 .. s.length - 1]) == false); + assert(isNumeric(s[1 .. $ - 2])); + assert(!isNumeric(s)); + assert(!isNumeric(s[0 .. $ - 1])); }); assert(!isNumeric("-")); diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d index 80ce73d6a75fa4ce880f554757f2099154f98a4c..69c2a49dd7faed5b62c00e69ccb9eb6beaf78d62 100644 --- a/libphobos/src/std/sumtype.d +++ b/libphobos/src/std/sumtype.d @@ -11,6 +11,15 @@ include: * No dependency on runtime type information (`TypeInfo`). * Compatibility with BetterC. +$(H3 List of examples) + +* [Basic usage](#basic-usage) +* [Matching with an overload set](#matching-with-an-overload-set) +* [Recursive SumTypes](#recursive-sumtypes) +* [Memory corruption](#memory-corruption) (why assignment can be `@system`) +* [Avoiding unintentional matches](#avoiding-unintentional-matches) +* [Multiple dispatch](#multiple-dispatch) + License: Boost License 1.0 Authors: Paul Backus Source: $(PHOBOSSRC std/sumtype.d) @@ -77,52 +86,38 @@ version (D_BetterC) {} else assert(!isFahrenheit(t3)); } -/** $(DIVID introspection-based-matching, $(H3 Introspection-based matching)) +/** $(DIVID matching-with-an-overload-set, $(H3 Matching with an overload set)) + * + * Instead of writing `match` handlers inline as lambdas, you can write them as + * overloads of a function. An `alias` can be used to create an additional + * overload for the `SumType` itself. + * + * For example, with this overload set: * - * In the `length` and `horiz` functions below, the handlers for `match` do not - * specify the types of their arguments. Instead, matching is done based on how - * the argument is used in the body of the handler: any type with `x` and `y` - * properties will be matched by the `rect` handlers, and any type with `r` and - * `theta` properties will be matched by the `polar` handlers. + * --- + * string handle(int n) { return "got an int"; } + * string handle(string s) { return "got a string"; } + * string handle(double d) { return "got a double"; } + * alias handle = match!handle; + * --- + * + * Usage would look like this: */ version (D_BetterC) {} else @safe unittest { - import std.math.operations : isClose; - import std.math.trigonometry : cos; - import std.math.constants : PI; - import std.math.algebraic : sqrt; - - struct Rectangular { double x, y; } - struct Polar { double r, theta; } - alias Vector = SumType!(Rectangular, Polar); - - double length(Vector v) - { - return v.match!( - rect => sqrt(rect.x^^2 + rect.y^^2), - polar => polar.r - ); - } - - double horiz(Vector v) - { - return v.match!( - rect => rect.x, - polar => polar.r * cos(polar.theta) - ); - } + alias ExampleSumType = SumType!(int, string, double); - Vector u = Rectangular(1, 1); - Vector v = Polar(1, PI/4); + ExampleSumType a = 123; + ExampleSumType b = "hello"; + ExampleSumType c = 3.14; - assert(length(u).isClose(sqrt(2.0))); - assert(length(v).isClose(1)); - assert(horiz(u).isClose(1)); - assert(horiz(v).isClose(sqrt(0.5))); + assert(a.handle == "got an int"); + assert(b.handle == "got a string"); + assert(c.handle == "got a double"); } -/** $(DIVID arithmetic-expression-evaluator, $(H3 Arithmetic expression evaluator)) +/** $(DIVID recursive-sumtypes, $(H3 Recursive SumTypes)) * * This example makes use of the special placeholder type `This` to define a * [recursive data type](https://en.wikipedia.org/wiki/Recursive_data_type): an @@ -227,6 +222,10 @@ version (D_BetterC) {} else assert(pprint(*myExpr) == "(a + (2 * b))"); } +// For the "Matching with an overload set" example above +// Needs public import to work with `make publictests` +version (unittest) public import std.internal.test.sumtype_example_overloads; + import std.format.spec : FormatSpec, singleSpec; import std.meta : AliasSeq, Filter, IndexOf = staticIndexOf, Map = staticMap; import std.meta : NoDuplicates; @@ -266,8 +265,7 @@ private enum isInout(T) = is(T == inout); * * The special type `This` can be used as a placeholder to create * self-referential types, just like with `Algebraic`. See the - * ["Arithmetic expression evaluator" example](#arithmetic-expression-evaluator) for - * usage. + * ["Recursive SumTypes" example](#recursive-sumtypes) for usage. * * A `SumType` is initialized by default to hold the `.init` value of its * first member type, just like a regular union. The version identifier @@ -1619,9 +1617,9 @@ enum bool isSumType(T) = is(T : SumType!Args, Args...); * overloads are considered as potential matches. * * Templated handlers are also accepted, and will match any type for which they - * can be [implicitly instantiated](https://dlang.org/glossary.html#ifti). See - * ["Introspection-based matching"](#introspection-based-matching) for an - * example of templated handler usage. + * can be [implicitly instantiated](https://dlang.org/glossary.html#ifti). + * (Remember that a $(DDSUBLINK spec/expression,function_literals, function literal) + * without an explicit argument type is considered a template.) * * If multiple [SumType]s are passed to match, their values are passed to the * handlers as separate arguments, and matching is done for each possible diff --git a/libphobos/src/std/utf.d b/libphobos/src/std/utf.d index c0cd3863b329ecdfc0c52b100f00ef086126b786..f0d5d4d268bec6ad7b916d14b4e26a97ea87ac3d 100644 --- a/libphobos/src/std/utf.d +++ b/libphobos/src/std/utf.d @@ -2528,8 +2528,8 @@ size_t encode(UseReplacementDchar useReplacementDchar = No.useReplacementDchar)( encode(buf, '\u0000'); assert(buf[0] == '\u0000'); encode(buf, '\uD7FF'); assert(buf[0] == '\uD7FF'); encode(buf, '\uE000'); assert(buf[0] == '\uE000'); - encode(buf, 0xFFFE ); assert(buf[0] == 0xFFFE); - encode(buf, 0xFFFF ); assert(buf[0] == 0xFFFF); + encode(buf, 0xFFFE); assert(buf[0] == 0xFFFE); + encode(buf, 0xFFFF); assert(buf[0] == 0xFFFF); encode(buf, '\U0010FFFF'); assert(buf[0] == '\U0010FFFF'); assertThrown!UTFException(encode(buf, cast(dchar) 0xD800)); @@ -2749,8 +2749,8 @@ void encode(UseReplacementDchar useReplacementDchar = No.useReplacementDchar)( encode(buf, '\u0000'); assert(buf[0] == '\u0000'); encode(buf, '\uD7FF'); assert(buf[1] == '\uD7FF'); encode(buf, '\uE000'); assert(buf[2] == '\uE000'); - encode(buf, 0xFFFE ); assert(buf[3] == 0xFFFE); - encode(buf, 0xFFFF ); assert(buf[4] == 0xFFFF); + encode(buf, 0xFFFE); assert(buf[3] == 0xFFFE); + encode(buf, 0xFFFF); assert(buf[4] == 0xFFFF); encode(buf, '\U0010FFFF'); assert(buf[5] == '\U0010FFFF'); assertThrown!UTFException(encode(buf, cast(dchar) 0xD800));