diff --git a/.cirrus.yml b/.cirrus.yml index 27f66f90dc2..761e55e5c02 100644 --- a/.cirrus.yml +++ b/.cirrus.yml @@ -126,7 +126,7 @@ packaging_steps_template: &PACKAGING_STEPS_TEMPLATE # Build & copy reggae build_reggae_script: | cd $CIRRUS_WORKING_DIR/.. - git clone --recursive https://github.com/atilaneves/reggae.git + git clone --recursive https://github.com/kinke/reggae.git cd reggae git checkout "$(cat $CIRRUS_WORKING_DIR/packaging/reggae_version)" # needs rdmd in PATH diff --git a/.github/actions/7-package/action.yml b/.github/actions/7-package/action.yml index e2d1e109cb7..99fbe2b1159 100644 --- a/.github/actions/7-package/action.yml +++ b/.github/actions/7-package/action.yml @@ -60,7 +60,7 @@ runs: run: | set -eux cd .. - git clone --recursive https://github.com/atilaneves/reggae.git + git clone --recursive https://github.com/kinke/reggae.git cd reggae git checkout "$(cat ../ldc/packaging/reggae_version)" diff --git a/CHANGELOG.md b/CHANGELOG.md index 38851cdddd2..c0a3e8111ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # LDC master #### Big news +- Frontend, druntime and Phobos are at version [2.110.0](https://dlang.org/changelog/2.110.0.html). (#4707) - LLVM for prebuilt packages bumped to v18.1.8 (incl. macOS arm64). (#4712) - Android: NDK for prebuilt package bumped from r26d to r27. (#4711) - ldc2.conf: %%ldcconfigpath%% placeholder added - specifies the directory where current configuration file is located. (#4717) diff --git a/CMakeLists.txt b/CMakeLists.txt index c6974fc62c6..91a805aeef1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -117,10 +117,10 @@ include(GetLinuxDistribution) # # Version information -set(LDC_VERSION "1.39.0") # May be overridden by git hash tag +set(LDC_VERSION "1.40.0") # May be overridden by git hash tag set(DMDFE_MAJOR_VERSION 2) -set(DMDFE_MINOR_VERSION 109) -set(DMDFE_PATCH_VERSION 1) +set(DMDFE_MINOR_VERSION 110) +set(DMDFE_PATCH_VERSION 0) set(DMD_VERSION ${DMDFE_MAJOR_VERSION}.${DMDFE_MINOR_VERSION}.${DMDFE_PATCH_VERSION}) diff --git a/dmd/README.md b/dmd/README.md index d784d07df21..07875943151 100644 --- a/dmd/README.md +++ b/dmd/README.md @@ -201,11 +201,9 @@ Note that these groups have no strict meaning, the category assignments are a bi | [libelf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/libelf.d) | Library in ELF format (Unix) | | [libmach.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/libmach.d) | Library in Mach-O format (macOS) | | [libmscoff.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/libmscoff.d) | Library in COFF format (32/64-bit Windows) | -| [libomf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/libomf.d) | Library in OMF format (legacy 32-bit Windows) | | [scanelf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/scanelf.d) | Extract symbol names from a library in ELF format | | [scanmach.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/scanmach.d) | Extract symbol names from a library in Mach-O format | | [scanmscoff.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/scanmscoff.d) | Extract symbol names from a library in COFF format | -| [scanomf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/scanomf.d) | Extract symbol names from a library in OMF format | ### Code generation / back-end interfacing @@ -253,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/dmd/aggregate.d b/dmd/aggregate.d index 975279a7b65..7475954a32f 100644 --- a/dmd/aggregate.d +++ b/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/dmd/argtypes_aarch64.d b/dmd/argtypes_aarch64.d index 42c32ac61fb..f1cda8d18d5 100644 --- a/dmd/argtypes_aarch64.d +++ b/dmd/argtypes_aarch64.d @@ -13,6 +13,7 @@ module dmd.argtypes_aarch64; import dmd.astenums; import dmd.mtype; +import dmd.typesem; /**************************************************** * This breaks a type down into 'simpler' types that can be passed to a function diff --git a/dmd/argtypes_sysv_x64.d b/dmd/argtypes_sysv_x64.d index ddc9f107349..47c2cf930b6 100644 --- a/dmd/argtypes_sysv_x64.d +++ b/dmd/argtypes_sysv_x64.d @@ -15,6 +15,7 @@ import dmd.astenums; import dmd.declaration; import dmd.globals; import dmd.mtype; +import dmd.typesem; import dmd.target; import dmd.visitor; diff --git a/dmd/argtypes_x86.d b/dmd/argtypes_x86.d index f3c21612904..179831e138d 100644 --- a/dmd/argtypes_x86.d +++ b/dmd/argtypes_x86.d @@ -19,6 +19,7 @@ import dmd.declaration; import dmd.globals; import dmd.location; import dmd.mtype; +import dmd.typesem; import dmd.target; import dmd.visitor; diff --git a/dmd/arrayop.d b/dmd/arrayop.d index d0ec5ebcdbe..e30160d72b9 100644 --- a/dmd/arrayop.d +++ b/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/dmd/chkformat.d b/dmd/chkformat.d index 5024f9bb210..bbc7b867c55 100644 --- a/dmd/chkformat.d +++ b/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/dmd/cli.d b/dmd/cli.d index 9c5e1d8364c..e8a4815b1ca 100644 --- a/dmd/cli.d +++ b/dmd/cli.d @@ -692,7 +692,7 @@ dmd -cov -unittest myprog.d Option("P=", "pass preprocessorflag to C preprocessor", `Pass $(I preprocessorflag) to - $(WINDOWS sppn.exe or cl.exe) + $(WINDOWS cl.exe) $(UNIX cpp)`, ), Option("preview=", @@ -775,12 +775,11 @@ dmd -cov -unittest myprog.d `darwin` or `osx` for MacOS, `dragonfly` or `dragonflybsd` for DragonflyBSD, `freebsd`, `openbsd`, `linux`, `solaris` or `windows` for their respective operating systems. $(I cenv) is the C runtime environment and is optional: `musl` for musl-libc, - `msvc` for the MSVC runtime (the default for windows with this option), - `bionic` for the Andriod libc, `digital_mars` for the Digital Mars runtime for Windows - `gnu` or `glibc` for the GCC C runtime, `newlib` or `uclibc` for their respective C runtimes. - ($ I cppenv) is the C++ runtime environment: `clang` for the LLVM C++ runtime - `gcc` for GCC's C++ runtime, `msvc` for microsoft's MSVC C++ runtime (the default for windows with this switch), - `sun` for Sun's C++ runtime and `digital_mars` for the Digital Mars C++ runtime for windows. + `msvc` for the MSVC runtime, `bionic` for the Andriod libc, `gnu` or `glibc` + for the GCC C runtime, `newlib` or `uclibc` for their respective C runtimes. + ($ I cppenv) is the C++ runtime environment: `clang` for the LLVM C++ runtime, + `gcc` for GCC's C++ runtime, `msvc` for microsoft's MSVC C++ runtime, + `sun` for Sun's C++ runtime. " ), Option("transition=", @@ -965,8 +964,8 @@ dmd -cov -unittest myprog.d "allow use of => for methods and top-level functions in addition to lambdas", "https://dlang.org/spec/function.html#ShortenedFunctionBody", false, true), Feature("fixImmutableConv", "fixImmutableConv", - "disallow functions with a mutable `void[]` parameter to be strongly pure", - "https://dlang.org/changelog/2.101.0.html#dmd.fix-immutable-conv"), + "disallow `void[]` data from holding immutable data", + "https://dlang.org/changelog/2.101.0.html#dmd.fix-immutable-conv, https://issues.dlang.org/show_bug.cgi?id=17148"), Feature("systemVariables", "systemVariables", "disable access to variables marked '@system' from @safe code", "https://dlang.org/spec/attribute.html#system-variables"), diff --git a/dmd/clone.d b/dmd/clone.d index 2e4833e8fdd..17b33d839df 100644 --- a/dmd/clone.d +++ b/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/dmd/compiler.d b/dmd/compiler.d index 010d323aaa8..8d42e28d285 100644 --- a/dmd/compiler.d +++ b/dmd/compiler.d @@ -23,6 +23,7 @@ import dmd.globals; import dmd.id; import dmd.identifier; import dmd.mtype; +import dmd.typesem; import dmd.root.array; import dmd.root.ctfloat; diff --git a/dmd/cond.d b/dmd/cond.d index e194664383e..02dde1b4c0f 100644 --- a/dmd/cond.d +++ b/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/dmd/constfold.d b/dmd/constfold.d index 6ec31d5f9bb..54d50cf4a34 100644 --- a/dmd/constfold.d +++ b/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/dmd/cparse.d b/dmd/cparse.d index 358b0f58739..e88d9cd4c87 100644 --- a/dmd/cparse.d +++ b/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; version (LDC) private enum LDC_pre_2084 = __VERSION__ < 2084; // workaround bug with LDC < v1.14 host compilers else private enum LDC_pre_2084 = false; @@ -1875,22 +1876,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. */ @@ -3629,6 +3638,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; @@ -3977,7 +3992,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; @@ -3991,6 +4006,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)); @@ -4022,8 +4055,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) @@ -4034,7 +4068,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/dmd/cppmangle.d b/dmd/cppmangle.d index 334088b381c..0609778e4c7 100644 --- a/dmd/cppmangle.d +++ b/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/dmd/cppmanglewin.d b/dmd/cppmanglewin.d index 0835c1d687b..196e886982b 100644 --- a/dmd/cppmanglewin.d +++ b/dmd/cppmanglewin.d @@ -41,7 +41,7 @@ import dmd.visitor; const(char)* toCppMangleMSVC(Dsymbol s) { - scope VisualCPPMangler v = new VisualCPPMangler(false, s.loc, global.errorSink); + scope VisualCPPMangler v = new VisualCPPMangler(s.loc, global.errorSink); auto p = v.mangleOf(s); if (v.errors) fatal(); // because this error should be handled in frontend @@ -55,7 +55,7 @@ version (IN_LLVM) { // Return the mangled name of the RTTI Type Descriptor. // Reverse-engineered using a few C++ exception classes. - scope VisualCPPMangler v = new VisualCPPMangler(false, s.loc, global.errorSink); + scope VisualCPPMangler v = new VisualCPPMangler(s.loc, global.errorSink); v.buf.writestring("\1??_R0?AV"); v.mangleIdent(s); v.buf.writestring("@8"); @@ -67,21 +67,6 @@ else } } -const(char)* toCppMangleDMC(Dsymbol s) -{ - scope VisualCPPMangler v = new VisualCPPMangler(true, s.loc, global.errorSink); - auto p = v.mangleOf(s); - if (v.errors) - fatal(); // because this error should be handled in frontend - return p; -} - -const(char)* cppTypeInfoMangleDMC(Dsymbol s) @safe -{ - //printf("cppTypeInfoMangle(%s)\n", s.toChars()); - assert(0); -} - private extern (C++) final class VisualCPPMangler : Visitor { alias visit = Visitor.visit; @@ -98,7 +83,6 @@ private extern (C++) final class VisualCPPMangler : Visitor bool ignoreConst; /// in some cases we should ignore CV-modifiers. bool escape; /// toplevel const non-pointer types need a '$$C' escape in addition to a cv qualifier. bool mangleReturnType; /// return type shouldn't be saved and substituted in arguments - bool isDmc; /// Digital Mars C++ name mangling bool errors; /// errors occurred OutBuffer buf; @@ -107,16 +91,14 @@ private extern (C++) final class VisualCPPMangler : Visitor { saved_idents[] = rvl.saved_idents[]; saved_types[] = rvl.saved_types[]; - isDmc = rvl.isDmc; loc = rvl.loc; } public: - extern (D) this(bool isDmc, Loc loc, ErrorSink eSink) scope @safe + extern (D) this(Loc loc, ErrorSink eSink) scope @safe { saved_idents[] = null; saved_types[] = null; - this.isDmc = isDmc; this.loc = loc; this.eSink = eSink; } @@ -160,7 +142,7 @@ public: if (checkImmutableShared(type, loc)) return; - if (type.isConst() && (isNotTopType || isDmc)) + if (type.isConst() && isNotTopType) { if (checkTypeSaved(type)) return; @@ -169,26 +151,23 @@ public: { return; } - if (!isDmc) + switch (type.ty) { - switch (type.ty) - { - case Tint64: - case Tuns64: - case Tint128: - case Tuns128: + case Tint64: + case Tuns64: + case Tint128: + case Tuns128: version (IN_LLVM) {} else { - case Tfloat80: + case Tfloat80: } - case Twchar: - if (checkTypeSaved(type)) - return; - break; + case Twchar: + if (checkTypeSaved(type)) + return; + break; - default: - break; - } + default: + break; } mangleModifier(type); switch (type.ty) @@ -237,14 +216,11 @@ version (IN_LLVM) { // unlike DMD, LDC uses 64-bit `real` for Windows/MSVC targets, // corresponding to MSVC++ long double - buf.writeByte('O'); // Visual C++ long double + buf.writeByte('O'); // Visual C++ long double } else { - if (isDmc) - buf.writestring("_Z"); // DigitalMars long double - else - buf.writestring("_T"); // Intel long double + buf.writestring("_T"); // Intel long double } break; case Tbool: @@ -285,10 +261,7 @@ else if (checkTypeSaved(type)) return; // first dimension always mangled as const pointer - if (isDmc) - buf.writeByte('Q'); - else - buf.writeByte('P'); + buf.writeByte('P'); isNotTopType = true; assert(type.next); if (type.next.ty == Tsarray) @@ -334,10 +307,7 @@ else if (checkTypeSaved(type)) return; mangleModifier(type); - if (type.isConst() || !isDmc) - buf.writeByte('Q'); // const - else - buf.writeByte('P'); // mutable + buf.writeByte('Q'); // const if (target.isLP64) buf.writeByte('E'); isNotTopType = true; @@ -391,15 +361,7 @@ else override void visit(TypeFunction type) { const(char)* arg = mangleFunctionType(type); - if (isDmc) - { - if (checkTypeSaved(type)) - return; - } - else - { - buf.writestring("$$A6"); - } + buf.writestring("$$A6"); buf.writestring(arg); isNotTopType = false; ignoreConst = false; @@ -439,16 +401,14 @@ else else if (id == Id.__c_char) c = "D"; // VC++ char else if (id == Id.__c_wchar_t) - { - c = isDmc ? "_Y" : "_W"; - } + c = "_W"; if (c.length) { if (checkImmutableShared(type, loc)) return; - if (type.isConst() && (isNotTopType || isDmc)) + if (type.isConst() && isNotTopType) { if (checkTypeSaved(type)) return; @@ -607,9 +567,8 @@ extern(D): * Params: * o = expression that represents the value * tv = template value - * is_dmc_template = use DMC mangling */ - void mangleTemplateValue(RootObject o, TemplateValueParameter tv, Dsymbol sym, bool is_dmc_template) + void mangleTemplateValue(RootObject o, TemplateValueParameter tv, Dsymbol sym) { if (!tv.valType.isintegral()) { @@ -625,12 +584,6 @@ extern(D): { mangleNumber(buf, e.toUInteger()); } - else if (is_dmc_template) - { - // NOTE: DMC mangles everything based on - // unsigned int - mangleNumber(buf, e.toInteger()); - } else { sinteger_t val = e.toInteger(); @@ -663,40 +616,30 @@ extern(D): else if (e && e.op == EXP.variable && (cast(VarExp)e).var.isVarDeclaration()) { buf.writeByte('$'); - if (isDmc) - buf.writeByte('1'); - else - buf.writeByte('E'); + buf.writeByte('E'); mangleVariable((cast(VarExp)e).var.isVarDeclaration()); } else if (d && d.isTemplateDeclaration() && d.isTemplateDeclaration().onemember) { Dsymbol ds = d.isTemplateDeclaration().onemember; - if (isDmc) + if (ds.isUnionDeclaration()) + { + buf.writeByte('T'); + } + else if (ds.isStructDeclaration()) + { + buf.writeByte('U'); + } + else if (ds.isClassDeclaration()) { buf.writeByte('V'); } else { - if (ds.isUnionDeclaration()) - { - buf.writeByte('T'); - } - else if (ds.isStructDeclaration()) - { - buf.writeByte('U'); - } - else if (ds.isClassDeclaration()) - { - buf.writeByte('V'); - } - else - { - eSink.error(sym.loc, "%s `%s` internal compiler error: C++ templates support only integral value, type parameters, alias templates and alias function parameters", - sym.kind, sym.toPrettyChars); - errors = true; - return; - } + eSink.error(sym.loc, "%s `%s` internal compiler error: C++ templates support only integral value, type parameters, alias templates and alias function parameters", + sym.kind, sym.toPrettyChars); + errors = true; + return; } mangleIdent(d); } @@ -732,7 +675,6 @@ extern(D): void mangleName(Dsymbol sym, bool dont_use_back_reference) { //printf("mangleName('%s')\n", sym.toChars()); - bool is_dmc_template = false; if (string s = mangleSpecialName(sym)) { @@ -743,7 +685,7 @@ extern(D): void writeName(Identifier name) { assert(name); - if (!is_dmc_template && dont_use_back_reference) + if (dont_use_back_reference) saveIdent(name); else if (checkAndSaveIdent(name)) return; @@ -805,18 +747,13 @@ extern(D): } } - scope VisualCPPMangler tmp = new VisualCPPMangler(isDmc ? true : false, loc, eSink); + scope VisualCPPMangler tmp = new VisualCPPMangler(loc, eSink); tmp.buf.writeByte('?'); tmp.buf.writeByte('$'); tmp.buf.writestring(symName); tmp.saved_idents[0] = id; if (symName == id.toString()) tmp.buf.writeByte('@'); - if (isDmc) - { - tmp.mangleIdent(sym.parent, true); - is_dmc_template = true; - } bool is_var_arg = false; for (size_t i = firstTemplateArg; i < actualti.tiargs.length; i++) { @@ -839,7 +776,7 @@ extern(D): } if (tv) { - tmp.mangleTemplateValue(o, tv, actualti, is_dmc_template); + tmp.mangleTemplateValue(o, tv, actualti); } else if (!tp || tp.isTemplateTypeParameter()) { @@ -1004,8 +941,6 @@ extern(D): buf.writestring("$$CB"); else if (isNotTopType) buf.writeByte('B'); // const - else if (isDmc && type.ty != Tpointer) - buf.writestring("_O"); } else if (isNotTopType) buf.writeByte('A'); // mutable diff --git a/dmd/ctfeexpr.d b/dmd/ctfeexpr.d index d2fcf5f7960..8ed70c6639e 100644 --- a/dmd/ctfeexpr.d +++ b/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/dmd/cxxfrontend.d b/dmd/cxxfrontend.d index 49a975412a3..47a443e3787 100644 --- a/dmd/cxxfrontend.d +++ b/dmd/cxxfrontend.d @@ -265,6 +265,12 @@ bool functionSemantic3(FuncDeclaration fd) return dmd.funcsem.functionSemantic3(fd); } +MATCH leastAsSpecialized(FuncDeclaration fd, FuncDeclaration g, Identifiers* names) +{ + import dmd.funcsem; + return dmd.funcsem.leastAsSpecialized(fd, g, names); +} + /*********************************************************** * hdrgen.d */ @@ -624,6 +630,18 @@ 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); +} + /*********************************************************** * typinf.d */ diff --git a/dmd/dcast.d b/dmd/dcast.d index 78781f4ced7..b682c75429a 100644 --- a/dmd/dcast.d +++ b/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; @@ -703,7 +704,7 @@ MATCH implicitConvTo(Expression e, Type t) return MATCH.nomatch; m = MATCH.constant; } - if (e.hexString && tn.isintegral && (tn.size == e.sz || (!e.committed && (e.len % tn.size) == 0))) + if (e.type != t && e.hexString && tn.isintegral && (tn.size == e.sz || (!e.committed && (e.len % tn.size) == 0))) { m = MATCH.convert; return m; @@ -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/dmd/declaration.h b/dmd/declaration.h index bb5ddd50a20..1e21c17bc1e 100644 --- a/dmd/declaration.h +++ b/dmd/declaration.h @@ -34,6 +34,8 @@ 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: @@ -733,7 +735,6 @@ class FuncDeclaration : public Declaration bool overloadInsert(Dsymbol *s) override; bool inUnittest(); - static MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, Identifiers *names); LabelDsymbol *searchLabel(Identifier *ident, const Loc &loc); const char *toPrettyChars(bool QualifyTypes = false) override; const char *toFullSignature(); // for diagnostics, e.g. 'int foo(int x, int y) pure' @@ -746,7 +747,6 @@ class FuncDeclaration : public Declaration 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/dmd/dimport.d b/dmd/dimport.d index 2efdd31bbba..4c4c063cbf2 100644 --- a/dmd/dimport.d +++ b/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/dmd/dinterpret.d b/dmd/dinterpret.d index 2f0d0a1ff9d..2331b2af678 100644 --- a/dmd/dinterpret.d +++ b/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/dmd/dmodule.d b/dmd/dmodule.d index 807395a12c2..8c660ee3862 100644 --- a/dmd/dmodule.d +++ b/dmd/dmodule.d @@ -830,7 +830,7 @@ else { filetype = FileType.c; - global.compileEnv.masm = target.os == Target.OS.Windows && !target.omfobj; // Microsoft inline assembler format + global.compileEnv.masm = target.os == Target.OS.Windows; // Microsoft inline assembler format scope p = new CParser!AST(this, buf, cast(bool) docfile, global.errorSink, target.c, &defines, &global.compileEnv); global.compileEnv.masm = false; p.nextToken(); diff --git a/dmd/doc.d b/dmd/doc.d index dab6f4757ee..fecf6e0c239 100644 --- a/dmd/doc.d +++ b/dmd/doc.d @@ -2592,7 +2592,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/dmd/dstruct.d b/dmd/dstruct.d index cf45ef5c593..32ebdf40e1c 100644 --- a/dmd/dstruct.d +++ b/dmd/dstruct.d @@ -329,11 +329,6 @@ version (IN_LLVM) {} else */ structsize = 4; } - else if (target.c.bitFieldStyle == TargetC.BitFieldStyle.DM) - { - structsize = 0; - alignsize = 0; - } else structsize = 0; break; @@ -470,7 +465,7 @@ version (IN_LLVM) {} else 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()) { @@ -622,7 +617,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/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index 6848ba72af4..30ab98f6f4a 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -1820,7 +1820,7 @@ else { //printf("MixinDeclaration::compileIt(loc = %d) %s\n", cd.loc.linnum, cd.exp.toChars()); OutBuffer buf; - if (expressionsToString(buf, sc, cd.exps)) + if (expressionsToString(buf, sc, cd.exps, cd.loc, null, true)) return null; const errors = global.errors; @@ -7240,12 +7240,19 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor error(bfd.loc, "bit field width %d is larger than type", bfd.fieldWidth); const style = target.c.bitFieldStyle; + if (style != TargetC.BitFieldStyle.MS && style != TargetC.BitFieldStyle.Gcc_Clang) + assert(0, "unsupported bit-field style"); + + const isMicrosoftStyle = style == TargetC.BitFieldStyle.MS; + const contributesToAggregateAlignment = target.c.contributesToAggregateAlignment(bfd); void startNewField() { if (log) printf("startNewField()\n"); uint alignsize; - if (style == TargetC.BitFieldStyle.Gcc_Clang) + if (isMicrosoftStyle) + alignsize = memsize; // not memalignsize + else { if (bfd.fieldWidth > 32) alignsize = memalignsize; @@ -7256,15 +7263,13 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor else alignsize = 1; } - else - alignsize = memsize; // not memalignsize uint dummy; bfd.offset = placeField( fieldState.offset, memsize, alignsize, bfd.alignment, ad.structsize, - (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize, + contributesToAggregateAlignment ? ad.alignsize : dummy, isunion); fieldState.inFlight = true; @@ -7273,64 +7278,30 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor fieldState.fieldSize = memsize; } - if (style == TargetC.BitFieldStyle.Gcc_Clang) - { - if (bfd.fieldWidth == 0) - { - if (!isunion) - { - // Use type of zero width field to align to next field - fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1); - ad.structsize = fieldState.offset; - } + if (ad.alignsize == 0) + ad.alignsize = 1; + if (!isMicrosoftStyle && contributesToAggregateAlignment && ad.alignsize < memalignsize) + ad.alignsize = memalignsize; - fieldState.inFlight = false; - return; - } - - if (ad.alignsize == 0) - ad.alignsize = 1; - if (!anon && - ad.alignsize < memalignsize) - ad.alignsize = memalignsize; - } - else if (style == TargetC.BitFieldStyle.MS) + if (bfd.fieldWidth == 0) { - if (ad.alignsize == 0) - ad.alignsize = 1; - if (bfd.fieldWidth == 0) + if (!isMicrosoftStyle && !isunion) { - if (fieldState.inFlight && !isunion) - { - // documentation says align to next int - //const alsz = cast(uint)Type.tint32.size(); - const alsz = memsize; // but it really does this - fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1); - ad.structsize = fieldState.offset; - } - - fieldState.inFlight = false; - return; + // Use type of zero width field to align to next field + fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1); + ad.structsize = fieldState.offset; } - } - else if (style == TargetC.BitFieldStyle.DM) - { - if (anon && bfd.fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0)) - return; // this probably should be a bug in DMC - if (ad.alignsize == 0) - ad.alignsize = 1; - if (bfd.fieldWidth == 0) + else if (isMicrosoftStyle && fieldState.inFlight && !isunion) { - if (fieldState.inFlight && !isunion) - { - const alsz = memsize; - fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1); - ad.structsize = fieldState.offset; - } - - fieldState.inFlight = false; - return; + // documentation says align to next int + //const alsz = cast(uint)Type.tint32.size(); + const alsz = memsize; // but it really does this + fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1); + ad.structsize = fieldState.offset; } + + fieldState.inFlight = false; + return; } if (!fieldState.inFlight) @@ -7338,12 +7309,12 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor //printf("not in flight\n"); startNewField(); } - else if (style == TargetC.BitFieldStyle.Gcc_Clang) + else if (!isMicrosoftStyle) { // 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 @@ -7351,18 +7322,17 @@ 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(); } } } - else if (style == TargetC.BitFieldStyle.DM || - style == TargetC.BitFieldStyle.MS) + else { if (memsize != fieldState.fieldSize || fieldState.bitOffset + bfd.fieldWidth > fieldState.fieldSize * 8) @@ -7371,14 +7341,14 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor startNewField(); } } - else - assert(0); bfd.offset = fieldState.fieldOffset; bfd.bitOffset = fieldState.bitOffset; const pastField = bfd.bitOffset + bfd.fieldWidth; - if (style == TargetC.BitFieldStyle.Gcc_Clang) + if (isMicrosoftStyle) + fieldState.fieldSize = memsize; + else { auto size = (pastField + 7) / 8; fieldState.fieldSize = size; @@ -7392,8 +7362,6 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor else ad.structsize = bfd.offset + size; } - else - fieldState.fieldSize = memsize; //printf("at end: ad.structsize = %d\n", cast(int)ad.structsize); //print(fieldState); diff --git a/dmd/dtemplate.d b/dmd/dtemplate.d index 588fd85baaf..95656ce5775 100644 --- a/dmd/dtemplate.d +++ b/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(); } /************************************ @@ -767,6 +776,17 @@ else return buf.extractChars(); } + /**************************** + * Similar to `toChars`, but does not print the template constraints + */ + const(char)* toCharsNoConstraints() const + { + HdrGenState hgs = { skipConstraints: true }; + OutBuffer buf; + toCharsMaybeConstraints(this, buf, hgs); + return buf.extractChars(); + } + override Visibility visible() pure nothrow @nogc @safe { return visibility; @@ -3695,7 +3715,22 @@ extern (C++) class TemplateInstance : ScopeDsymbol Dsymbol tempdecl; // referenced by foo.bar.abc Dsymbol enclosing; // if referencing local symbols, this is the context Dsymbol aliasdecl; // !=null if instance is an alias for its sole member - TemplateInstance inst; // refer to existing instance + + /** + If this is not null and it has a value that is not the current object, + then this field points to an existing template instance + and that object has been duplicated into us. + + If this object is a duplicate, + the ``memberOf`` field will be set to a root module (passed on CLI). + + This information is useful to deduplicate analysis that may occur + after semantic 3 has completed. + + See_Also: memberOf + */ + TemplateInstance inst; + ScopeDsymbol argsym; // argument symbol table size_t hash; // cached result of toHash() @@ -3707,7 +3742,15 @@ extern (C++) class TemplateInstance : ScopeDsymbol TemplateInstances* deferred; - Module memberOf; // if !null, then this TemplateInstance appears in memberOf.members[] + /** + If this is not null then this template instance appears in a root module's members. + + Note: This is not useful for determining duplication status of this template instance. + Use the field ``inst`` for determining if a template instance has been duplicated into this object. + + See_Also: inst + */ + Module memberOf; // Used to determine the instance needs code generation. // Note that these are inaccurate until semantic analysis phase completed. diff --git a/dmd/errors.d b/dmd/errors.d index 4dd000409fd..c7f647de9be 100644 --- a/dmd/errors.d +++ b/dmd/errors.d @@ -616,7 +616,7 @@ private void verrorPrint(const(char)* format, va_list ap, ref ErrorInfo info) if (global.params.v.showGaggedErrors && global.gag) fprintf(stderr, "(spec:%d) ", global.gag); - Console con = cast(Console) global.console; + auto con = cast(Console) global.console; const p = info.loc.toChars(); if (con) con.setColorBright(true); diff --git a/dmd/expression.d b/dmd/expression.d index faeff2bdf42..570b1c321d1 100644 --- a/dmd/expression.d +++ b/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; @@ -427,7 +428,7 @@ extern (C++) /* IN_LLVM 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) { @@ -723,7 +724,7 @@ version (IN_LLVM) 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; } @@ -3901,7 +3902,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/dmd/expressionsem.d b/dmd/expressionsem.d index 0ef5233316e..5e9baf53431 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -137,16 +137,26 @@ private bool isNeedThisScope(Scope* sc, Declaration d) * buf = append generated string to buffer * sc = context * exps = array of Expressions + * loc = location of the pragma / mixin where this conversion was requested, for supplemental error + * fmt = format string for supplemental error. May contain 1 `%s` which prints the faulty expression + * expandTuples = whether tuples should be expanded rather than printed as tuple syntax * Returns: * true on error */ -bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps) +bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps, + Loc loc, const(char)* fmt, bool expandTuples) { if (!exps) return false; foreach (ex; *exps) { + bool error() + { + if (loc != Loc.initial && fmt) + errorSupplemental(loc, fmt, ex.toChars()); + return true; + } if (!ex) continue; auto sc2 = sc.startCTFE(); @@ -159,15 +169,16 @@ bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps) // allowed to contain types as well as expressions auto e4 = ctfeInterpretForPragmaMsg(e3); if (!e4 || e4.op == EXP.error) - return true; + return error(); // expand tuple - if (auto te = e4.isTupleExp()) - { - if (expressionsToString(buf, sc, te.exps)) - return true; - continue; - } + if (expandTuples) + if (auto te = e4.isTupleExp()) + { + if (expressionsToString(buf, sc, te.exps, loc, fmt, true)) + return error(); + continue; + } // char literals exp `.toStringExp` return `null` but we cant override it // because in most contexts we don't want the conversion to succeed. IntegerExp ie = e4.isIntegerExp(); @@ -178,9 +189,11 @@ bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps) e4 = new ArrayLiteralExp(ex.loc, tsa, ie); } - if (StringExp se = e4.toStringExp()) + StringExp se = e4.toStringExp(); + + if (se && se.type.nextOf().ty.isSomeChar) buf.writestring(se.toUTF8(sc).peekString()); - else + else if (!(se && se.len == 0)) // don't print empty array literal `[]` buf.writestring(e4.toString()); } return false; @@ -333,6 +346,7 @@ StringExp toUTF8(StringExp se, Scope* sc) Expression e = castTo(se, sc, Type.tchar.arrayOf()); e = e.optimize(WANTvalue); auto result = e.isStringExp(); + assert(result); assert(result.sz == 1); return result; } @@ -7097,17 +7111,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Handle this in the glue layer e = new TypeidExp(exp.loc, ta); - bool genObjCode = true; - - // https://issues.dlang.org/show_bug.cgi?id=23650 - // We generate object code for typeinfo, required - // by typeid, only if in non-speculative context - if (sc.flags & SCOPE.compile) - { - genObjCode = false; - } - - e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode); + e.type = getTypeInfoType(exp.loc, ta, sc); semanticTypeInfo(sc, ta); if (ea) @@ -7614,7 +7618,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor private Expression compileIt(MixinExp exp, Scope *sc) { OutBuffer buf; - if (expressionsToString(buf, sc, exp.exps)) + if (expressionsToString(buf, sc, exp.exps, exp.loc, null, true)) return null; uint errors = global.errors; @@ -7758,6 +7762,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 { @@ -9267,13 +9272,27 @@ version (IN_LLVM) } // 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. @@ -11429,11 +11448,6 @@ version (IN_LLVM) 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 { @@ -11465,6 +11479,33 @@ version (IN_LLVM) } } } + + 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; @@ -11853,6 +11894,8 @@ version (IN_LLVM) (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 @@ -12602,7 +12645,9 @@ version (IN_LLVM) 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/dmd/frontend.h b/dmd/frontend.h index de2156ffe44..845e4889e95 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -1487,6 +1487,7 @@ class TemplateDeclaration final : public ScopeDsymbol bool hasStaticCtorOrDtor() override; const char* kind() const override; const char* toChars() const override; + const char* toCharsNoConstraints() const; Visibility visible() override; const char* getConstraintEvalError(const char*& tip); TemplateDeclaration* isTemplateDeclaration() override; @@ -1825,8 +1826,6 @@ class Type : public ASTNode char* toPrettyChars(bool QualifyTypes = false); static void _init(); static void deinitialize(); - uinteger_t size(); - virtual uinteger_t size(const Loc& loc); virtual uint32_t alignsize(); void modToBuffer(OutBuffer& buf) const; char* modToChars() const; @@ -1862,7 +1861,6 @@ class Type : public ASTNode virtual Type* makeSharedWildConst(); virtual Type* makeMutable(); Type* toBasetype(); - virtual MATCH implicitConvTo(Type* to); virtual MATCH constConv(Type* to); virtual uint8_t deduceWild(Type* t, bool isRef); virtual ClassDeclaration* isClassHandle(); @@ -3620,14 +3618,6 @@ struct ObjcFuncDeclaration final {} }; -enum class PURE : uint8_t -{ - impure = 0u, - fwdref = 1u, - weak = 2u, - const_ = 3u, -}; - enum class VarArg : uint8_t { none = 0u, @@ -3781,7 +3771,6 @@ class FuncDeclaration : public Declaration bool equals(const RootObject* const o) const final override; bool overloadInsert(Dsymbol* s) override; bool inUnittest(); - static MATCH leastAsSpecialized(FuncDeclaration* f, FuncDeclaration* g, Array* names); LabelDsymbol* searchLabel(Identifier* ident, const Loc& loc); enum : int32_t { LevelError = -2 }; @@ -3798,7 +3787,6 @@ class FuncDeclaration : public Declaration bool isOverloadable() const final override; bool isAbstract() final override; void initInferAttributes(); - PURE isPure(); bool isSafe(); bool isTrusted(); bool isNogc(); @@ -3815,7 +3803,6 @@ class FuncDeclaration : public Declaration bool needsClosure(); bool checkClosure(); bool hasNestedFrameRefs(); - static bool needsFensure(FuncDeclaration* fd); ParameterList getParameterList(); static FuncDeclaration* genCfunc(Array* fparams, Type* treturn, const char* name, StorageClass stc = 0); static FuncDeclaration* genCfunc(Array* fparams, Type* treturn, Identifier* id, StorageClass stc = 0); @@ -3983,6 +3970,7 @@ struct HdrGenState final bool doFuncBodies; bool vcg_ast; bool skipConstraints; + bool showOneMember; bool fullQual; int32_t tpltMember; int32_t autoMember; @@ -3999,6 +3987,7 @@ struct HdrGenState final doFuncBodies(), vcg_ast(), skipConstraints(), + showOneMember(true), fullQual(), tpltMember(), autoMember(), @@ -4009,7 +3998,7 @@ struct HdrGenState final inEnumDecl() { } - HdrGenState(bool hdrgen, bool ddoc = false, bool fullDump = false, bool importcHdr = false, bool doFuncBodies = false, bool vcg_ast = false, bool skipConstraints = false, bool fullQual = false, int32_t tpltMember = 0, int32_t autoMember = 0, int32_t forStmtInit = 0, int32_t insideFuncBody = 0, int32_t insideAggregate = 0, bool declstring = false, EnumDeclaration* inEnumDecl = nullptr) : + HdrGenState(bool hdrgen, bool ddoc = false, bool fullDump = false, bool importcHdr = false, bool doFuncBodies = false, bool vcg_ast = false, bool skipConstraints = false, bool showOneMember = true, bool fullQual = false, int32_t tpltMember = 0, int32_t autoMember = 0, int32_t forStmtInit = 0, int32_t insideFuncBody = 0, int32_t insideAggregate = 0, bool declstring = false, EnumDeclaration* inEnumDecl = nullptr) : hdrgen(hdrgen), ddoc(ddoc), fullDump(fullDump), @@ -4017,6 +4006,7 @@ struct HdrGenState final doFuncBodies(doFuncBodies), vcg_ast(vcg_ast), skipConstraints(skipConstraints), + showOneMember(showOneMember), fullQual(fullQual), tpltMember(tpltMember), autoMember(autoMember), @@ -4225,10 +4215,8 @@ class TypeAArray final : public TypeArray static TypeAArray* create(Type* t, Type* index); const char* kind() const 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; }; @@ -4240,7 +4228,6 @@ class TypeBasic final : public Type uint32_t flags; const char* kind() const override; TypeBasic* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; uint32_t alignsize() override; bool isintegral() override; bool isfloating() override; @@ -4249,7 +4236,6 @@ class TypeBasic final : public Type bool iscomplex() override; bool isscalar() override; bool isunsigned() override; - MATCH implicitConvTo(Type* to) override; bool isZeroInit(const Loc& loc) override; bool hasUnsafeBitpatterns() override; TypeBasic* isTypeBasic() override; @@ -4273,10 +4259,8 @@ class TypeClass final : public Type AliasThisRec att; CPPMANGLE cppmangle; const char* kind() const override; - uinteger_t size(const Loc& loc) override; TypeClass* syntaxCopy() override; ClassDeclaration* isClassHandle() override; - MATCH implicitConvTo(Type* to) override; MATCH constConv(Type* to) override; uint8_t deduceWild(Type* t, bool isRef) override; bool isZeroInit(const Loc& loc) override; @@ -4290,12 +4274,10 @@ class TypeDArray final : public TypeArray public: const char* kind() const override; TypeDArray* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; uint32_t alignsize() override; bool isString() override; bool isZeroInit(const Loc& loc) override; bool isBoolean() override; - MATCH implicitConvTo(Type* to) override; void accept(Visitor* v) override; }; @@ -4305,9 +4287,7 @@ class TypeDelegate final : public TypeNext static TypeDelegate* create(TypeFunction* t); const char* kind() const override; TypeDelegate* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; uint32_t alignsize() override; - MATCH implicitConvTo(Type* to) override; bool isZeroInit(const Loc& loc) override; bool isBoolean() override; void accept(Visitor* v) override; @@ -4319,7 +4299,6 @@ class TypeEnum final : public Type EnumDeclaration* sym; const char* kind() const override; TypeEnum* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; Type* memType(); uint32_t alignsize() override; bool isintegral() override; @@ -4335,7 +4314,6 @@ class TypeEnum final : public Type 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; @@ -4350,7 +4328,6 @@ class TypeError final : public Type public: const char* kind() const override; TypeError* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; Expression* defaultInitLiteral(const Loc& loc) override; void accept(Visitor* v) override; }; @@ -4363,6 +4340,14 @@ enum class TRUST : uint8_t safe = 3u, }; +enum class PURE : uint8_t +{ + impure = 0u, + fwdref = 1u, + weak = 2u, + const_ = 3u, +}; + class TypeFunction final : public TypeNext { public: @@ -4472,7 +4457,6 @@ class TypeQualified : public Type Loc loc; Array idents; TypeQualified* syntaxCopy() override = 0; - uinteger_t size(const Loc& loc) override; void accept(Visitor* v) override; }; @@ -4512,10 +4496,8 @@ class TypeNoreturn final : public Type public: const char* kind() const override; TypeNoreturn* syntaxCopy() override; - MATCH implicitConvTo(Type* to) override; MATCH constConv(Type* to) override; bool isBoolean() override; - uinteger_t size(const Loc& loc) override; uint32_t alignsize() override; void accept(Visitor* v) override; }; @@ -4525,9 +4507,7 @@ class TypeNull final : public Type public: const char* kind() const override; TypeNull* syntaxCopy() override; - MATCH implicitConvTo(Type* to) override; bool isBoolean() override; - uinteger_t size(const Loc& loc) override; void accept(Visitor* v) override; }; @@ -4537,8 +4517,6 @@ class TypePointer final : public TypeNext static TypePointer* create(Type* t); const char* kind() const 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; @@ -4550,7 +4528,6 @@ class TypeReference final : public TypeNext public: const char* kind() const override; TypeReference* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; bool isZeroInit(const Loc& loc) override; void accept(Visitor* v) override; }; @@ -4570,13 +4547,11 @@ class TypeSArray final : public TypeArray const char* kind() const override; TypeSArray* syntaxCopy() override; bool isIncomplete(); - uinteger_t size(const Loc& loc) override; uint32_t 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; @@ -4605,7 +4580,6 @@ class TypeStruct final : public Type bool inuse; static TypeStruct* create(StructDeclaration* sym); const char* kind() const override; - uinteger_t size(const Loc& loc) override; uint32_t alignsize() override; TypeStruct* syntaxCopy() override; structalign_t alignment() override; @@ -4619,7 +4593,6 @@ class TypeStruct final : public Type bool hasVoidInitPointers() override; bool hasUnsafeBitpatterns() override; bool hasInvariant() override; - MATCH implicitConvTo(Type* to) override; MATCH constConv(Type* to) override; uint8_t deduceWild(Type* t, bool isRef) override; void accept(Visitor* v) override; @@ -4650,7 +4623,6 @@ class TypeTraits final : public Type const char* kind() const override; TypeTraits* syntaxCopy() override; void accept(Visitor* v) override; - uinteger_t size(const Loc& loc) override; }; class TypeTuple final : public Type @@ -4665,7 +4637,6 @@ class TypeTuple final : public Type const char* kind() const override; TypeTuple* syntaxCopy() override; bool equals(const RootObject* const o) const override; - MATCH implicitConvTo(Type* to) override; void accept(Visitor* v) override; }; @@ -4676,7 +4647,6 @@ class TypeTypeof final : public TypeQualified int32_t inuse; const char* kind() const override; TypeTypeof* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; void accept(Visitor* v) override; }; @@ -4687,14 +4657,12 @@ class TypeVector final : public Type static TypeVector* create(Type* basetype); const char* kind() const override; TypeVector* syntaxCopy() override; - uinteger_t size(const Loc& loc) override; uint32_t 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; @@ -5957,21 +5925,19 @@ struct TargetC final { Unspecified = 0u, Bionic = 1u, - DigitalMars = 2u, - Glibc = 3u, - Microsoft = 4u, - Musl = 5u, - Newlib = 6u, - UClibc = 7u, - WASI = 8u, + Glibc = 2u, + Microsoft = 3u, + Musl = 4u, + Newlib = 5u, + UClibc = 6u, + WASI = 7u, }; enum class BitFieldStyle : uint8_t { Unspecified = 0u, - DM = 1u, - MS = 2u, - Gcc_Clang = 3u, + MS = 1u, + Gcc_Clang = 2u, }; bool crtDestructorsSupported; @@ -5984,6 +5950,7 @@ struct TargetC final uint8_t wchar_tsize; Runtime runtime; BitFieldStyle bitFieldStyle; + bool contributesToAggregateAlignment(BitFieldDeclaration* bfd); TargetC() : crtDestructorsSupported(true), boolsize(), @@ -6014,11 +5981,10 @@ struct TargetCPP final enum class Runtime : uint8_t { Unspecified = 0u, - Clang = 1u, - DigitalMars = 2u, - Gcc = 3u, - Microsoft = 4u, - Sun = 5u, + LLVM = 1u, + GNU = 2u, + Microsoft = 3u, + Sun = 4u, }; bool reverseOverloads; @@ -7547,12 +7513,12 @@ struct Target final _d_dynamicArray< const char > architectureName; CPU cpu; bool isX86_64; + bool isX86; bool isLP64; _d_dynamicArray< const char > obj_ext; _d_dynamicArray< const char > lib_ext; _d_dynamicArray< const char > dll_ext; bool run_noext; - bool omfobj; template struct FPTypeProperties final { @@ -7619,12 +7585,12 @@ struct Target final objc(), architectureName(), isX86_64(), + isX86(), isLP64(), obj_ext(), lib_ext(), dll_ext(), run_noext(), - omfobj(), FloatProperties(), DoubleProperties(), RealProperties(), @@ -7632,7 +7598,7 @@ struct Target final params() { } - Target(OS os, uint8_t osMajor = 0u, uint8_t ptrsize = 0u, uint8_t realsize = 0u, uint8_t realpad = 0u, uint8_t realalignsize = 0u, uint8_t classinfosize = 0u, uint64_t maxStaticDataSize = 0LLU, TargetC c = TargetC(), TargetCPP cpp = TargetCPP(), TargetObjC objc = TargetObjC(), _d_dynamicArray< const char > architectureName = {}, CPU cpu = (CPU)0u, bool isX86_64 = false, bool isLP64 = false, _d_dynamicArray< const char > obj_ext = {}, _d_dynamicArray< const char > lib_ext = {}, _d_dynamicArray< const char > dll_ext = {}, bool run_noext = false, bool omfobj = false, FPTypeProperties FloatProperties = FPTypeProperties(), FPTypeProperties DoubleProperties = FPTypeProperties(), FPTypeProperties<_d_real > RealProperties = FPTypeProperties<_d_real >(), Type* tvalist = nullptr, const Param* params = nullptr) : + Target(OS os, uint8_t osMajor = 0u, uint8_t ptrsize = 0u, uint8_t realsize = 0u, uint8_t realpad = 0u, uint8_t realalignsize = 0u, uint8_t classinfosize = 0u, uint64_t maxStaticDataSize = 0LLU, TargetC c = TargetC(), TargetCPP cpp = TargetCPP(), TargetObjC objc = TargetObjC(), _d_dynamicArray< const char > architectureName = {}, CPU cpu = (CPU)0u, bool isX86_64 = false, bool isX86 = false, bool isLP64 = false, _d_dynamicArray< const char > obj_ext = {}, _d_dynamicArray< const char > lib_ext = {}, _d_dynamicArray< const char > dll_ext = {}, bool run_noext = false, FPTypeProperties FloatProperties = FPTypeProperties(), FPTypeProperties DoubleProperties = FPTypeProperties(), FPTypeProperties<_d_real > RealProperties = FPTypeProperties<_d_real >(), Type* tvalist = nullptr, const Param* params = nullptr) : os(os), osMajor(osMajor), ptrsize(ptrsize), @@ -7647,12 +7613,12 @@ struct Target final architectureName(architectureName), cpu(cpu), isX86_64(isX86_64), + isX86(isX86), isLP64(isLP64), obj_ext(obj_ext), lib_ext(lib_ext), dll_ext(dll_ext), run_noext(run_noext), - omfobj(omfobj), FloatProperties(FloatProperties), DoubleProperties(DoubleProperties), RealProperties(RealProperties), @@ -7663,7 +7629,7 @@ struct Target final extern Target target; -extern Type* getTypeInfoType(const Loc& loc, Type* t, Scope* sc, bool genObjCode = true); +extern Type* getTypeInfoType(const Loc& loc, Type* t, Scope* sc); class SemanticTimeTransitiveVisitor : public SemanticTimePermissiveVisitor { @@ -7807,6 +7773,7 @@ class SemanticTimeTransitiveVisitor : public SemanticTimePermissiveVisitor void visit(DebugStatement* s) override; void visit(ForwardingStatement* s) override; void visit(StructLiteralExp* e) override; + void visit(ClassReferenceExp* e) override; void visit(CompoundLiteralExp* e) override; void visit(DotTemplateExp* e) override; void visit(DotVarExp* e) override; @@ -8800,6 +8767,7 @@ struct Id final static Identifier* define; static Identifier* undef; static Identifier* ident; + static Identifier* packed; static void initialize(); Id() { diff --git a/dmd/func.d b/dmd/func.d index 035b7142169..434c6b1202f 100644 --- a/dmd/func.d +++ b/dmd/func.d @@ -471,27 +471,6 @@ version (IN_LLVM) return false; } - /**************************************************** - * Determine if 'this' overrides fd. - * Return !=0 if it does. - */ - extern (D) final int overrides(FuncDeclaration fd) - { - int result = 0; - if (fd.ident == ident) - { - const cov = type.covariant(fd.type); - if (cov != Covariant.distinct) - { - ClassDeclaration cd1 = toParent().isClassDeclaration(); - ClassDeclaration cd2 = fd.toParent().isClassDeclaration(); - if (cd1 && cd2 && cd2.isBaseOf(cd1, null)) - result = 1; - } - } - return result; - } - /**************************************************** * Overload this FuncDeclaration with the new one f. * Return true if successful; i.e. no conflict. @@ -595,91 +574,6 @@ version (IN_LLVM) return false; } - /************************************* - * Determine partial specialization order of functions `f` vs `g`. - * This is very similar to TemplateDeclaration::leastAsSpecialized(). - * Params: - * f = first function - * g = second function - * names = names of parameters - * Returns: - * match 'this' is at least as specialized as g - * 0 g is more specialized than 'this' - */ - static MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* names) - { - enum LOG_LEASTAS = 0; - static if (LOG_LEASTAS) - { - import core.stdc.stdio : printf; - printf("leastAsSpecialized(%s, %s, %s)\n", f.toChars(), g.toChars(), names ? names.toChars() : "null"); - printf("%s, %s\n", f.type.toChars(), g.type.toChars()); - } - - /* This works by calling g() with f()'s parameters, and - * if that is possible, then f() is at least as specialized - * as g() is. - */ - - TypeFunction tf = f.type.toTypeFunction(); - TypeFunction tg = g.type.toTypeFunction(); - - /* If both functions have a 'this' pointer, and the mods are not - * the same and g's is not const, then this is less specialized. - */ - if (f.needThis() && g.needThis() && tf.mod != tg.mod) - { - if (f.isCtorDeclaration()) - { - if (!MODimplicitConv(tg.mod, tf.mod)) - return MATCH.nomatch; - } - else - { - if (!MODimplicitConv(tf.mod, tg.mod)) - return MATCH.nomatch; - } - } - - /* Create a dummy array of arguments out of the parameters to f() - */ - Expressions args; - foreach (u, p; tf.parameterList) - { - Expression e; - if (p.isReference()) - { - e = new IdentifierExp(Loc.initial, p.ident); - e.type = p.type; - } - else - e = p.type.defaultInitLiteral(Loc.initial); - args.push(e); - } - - MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1); - if (m > MATCH.nomatch) - { - /* A variadic parameter list is less specialized than a - * non-variadic one. - */ - if (tf.parameterList.varargs && !tg.parameterList.varargs) - goto L1; // less specialized - - static if (LOG_LEASTAS) - { - printf(" matches %d, so is least as specialized\n", m); - } - return m; - } - L1: - static if (LOG_LEASTAS) - { - printf(" doesn't match, so is not as specialized\n"); - } - return MATCH.nomatch; - } - /******************************** * Searches for a label with the given identifier. This function will insert a new * `LabelDsymbol` into `labtab` if it does not contain a mapping for `ident`. @@ -885,72 +779,6 @@ version (IN_LLVM) 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; @@ -1131,187 +959,6 @@ version (IN_LLVM) } } - /******************************************** - * 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: @@ -1655,27 +1302,6 @@ version (IN_LLVM) return false; } - /**************************************************** - * Determine whether an 'out' contract is declared inside - * the given function or any of its overrides. - * Params: - * fd = the function to search - * Returns: - * true found an 'out' contract - */ - static bool needsFensure(FuncDeclaration fd) @safe - { - if (fd.fensures) - return true; - - foreach (fdv; fd.foverrides) - { - if (needsFensure(fdv)) - return true; - } - return false; - } - /********************************************* * Returns: the function's parameter list, and whether * it is variadic or not. @@ -1732,179 +1358,6 @@ version (IN_LLVM) return fd; } - /+ - + Checks the parameter and return types iff this is a `main` function. - + - + The following signatures are allowed for a `D main`: - + - Either no or a single parameter of type `string[]` - + - Return type is either `void`, `int` or `noreturn` - + - + The following signatures are standard C: - + - `int main()` - + - `int main(int, char**)` - + - + This function accepts the following non-standard extensions: - + - `char** envp` as a third parameter - + - `void` / `noreturn` as return type - + - + This function will issue errors for unexpected arguments / return types. - +/ - extern (D) final void checkMain() - { - if (ident != Id.main || isMember() || isNested()) - return; // Not a main function - - TypeFunction tf = type.toTypeFunction(); - - Type retType = tf.nextOf(); - if (!retType) - { - // auto main(), check after semantic - assert(this.inferRetType); - return; - } - - /// Checks whether `t` is equivalent to `char**` - /// Ignores qualifiers and treats enums according to their base type - static bool isCharPtrPtr(Type t) - { - auto tp = t.toBasetype().isTypePointer(); - if (!tp) - return false; - - tp = tp.next.toBasetype().isTypePointer(); - if (!tp) - return false; - - return tp.next.toBasetype().ty == Tchar; - } - - // Neither of these qualifiers is allowed because they affect the ABI - enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_; - - const nparams = tf.parameterList.length; - bool argerr; - - const linkage = resolvedLinkage(); - if (linkage == LINK.d) - { - if (nparams == 1) - { - auto fparam0 = tf.parameterList[0]; - auto t = fparam0.type.toBasetype(); - if (t.ty != Tarray || - t.nextOf().ty != Tarray || - t.nextOf().nextOf().ty != Tchar || - fparam0.storageClass & invalidSTC) - { - argerr = true; - } - } - - if (tf.parameterList.varargs || nparams >= 2 || argerr) - .error(loc, "%s `%s` parameter list must be empty or accept one parameter of type `string[]`", kind, toPrettyChars); - } - - else if (linkage == LINK.c) - { - if (nparams == 2 || nparams == 3) - { - // Argument count must be int - auto argCount = tf.parameterList[0]; - argerr |= !!(argCount.storageClass & invalidSTC); - argerr |= argCount.type.toBasetype().ty != Tint32; - - // Argument pointer must be char** - auto argPtr = tf.parameterList[1]; - argerr |= !!(argPtr.storageClass & invalidSTC); - argerr |= !isCharPtrPtr(argPtr.type); - - // `char** environ` is a common extension, see J.5.1 of the C standard - if (nparams == 3) - { - auto envPtr = tf.parameterList[2]; - argerr |= !!(envPtr.storageClass & invalidSTC); - argerr |= !isCharPtrPtr(envPtr.type); - } - } - else - argerr = nparams != 0; - - // Disallow variadic main() - except for K&R declarations in C files. - // E.g. int main(), int main(argc, argv) int argc, char** argc { ... } - if (tf.parameterList.varargs && (!this.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams))) - argerr |= true; - - if (argerr) - { - .error(loc, "%s `%s` parameters must match one of the following signatures", kind, toPrettyChars); - loc.errorSupplemental("`main()`"); - loc.errorSupplemental("`main(int argc, char** argv)`"); - loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]"); - } - } - else - return; // Neither C nor D main, ignore (should probably be an error) - - // Allow enums with appropriate base types (same ABI) - retType = retType.toBasetype(); - - if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn) - .error(loc, "%s `%s` must return `int`, `void` or `noreturn`, not `%s`", kind, toPrettyChars, tf.nextOf().toChars()); - } - - /*********************************************** - * Check all return statements for a function to verify that returning - * using NRVO is possible. - * - * Returns: - * `false` if the result cannot be returned by hidden reference. - */ - extern (D) final bool checkNRVO() - { - if (!isNRVO() || returns is null) - return false; - - auto tf = type.toTypeFunction(); - if (tf.isref) - return false; - - foreach (rs; *returns) - { - if (auto ve = rs.exp.isVarExp()) - { - auto v = ve.var.isVarDeclaration(); - if (!v || v.isReference()) - return false; - else if (nrvo_var is null) - { - // Variables in the data segment (e.g. globals, TLS or not), - // parameters and closure variables cannot be NRVOed. - if (v.isDataseg() || v.isParameter() || v.toParent2() != this) - return false; - if (v.nestedrefs.length && needsClosure()) - return false; - // don't know if the return storage is aligned - version (MARS) - { - if (alignSectionVars && (*alignSectionVars).contains(v)) - return false; - } - // The variable type needs to be equivalent to the return type. - if (!v.type.equivalent(tf.next)) - return false; - //printf("Setting nrvo to %s\n", v.toChars()); - nrvo_var = v; - } - else if (nrvo_var != v) - return false; - } - else //if (!exp.isLvalue()) // keep NRVO-ability - return false; - } - return true; - } - override final inout(FuncDeclaration) isFuncDeclaration() inout { return this; @@ -2114,133 +1567,6 @@ unittest assert(mismatches.isMutable); } -/************************************** - * Returns an indirect type one step from t. - */ -Type getIndirection(Type t) -{ - t = t.baseElemOf(); - if (t.ty == Tarray || t.ty == Tpointer) - return t.nextOf().toBasetype(); - if (t.ty == Taarray || t.ty == Tclass) - return t; - if (t.ty == Tstruct) - return t.hasPointers() ? t : null; // TODO - - // should consider TypeDelegate? - return null; -} - -/************************************** - * 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/dmd/funcsem.d b/dmd/funcsem.d index 1aa8ff8f1c1..bc7cf5f2340 100644 --- a/dmd/funcsem.d +++ b/dmd/funcsem.d @@ -65,6 +65,10 @@ import dmd.tokens; import dmd.typesem; import dmd.visitor; +version (IN_GCC) {} +else version (IN_LLVM) {} +else version = MARS; + /* Tweak all return statements and dtor call for nrvo_var, for correct NRVO. */ extern (C++) final class NrvoWalker : StatementRewriteWalker @@ -1753,10 +1757,24 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) // max num of overloads to print (-v or -verror-supplements overrides this). const uint DisplayLimit = global.params.v.errorSupplementCount(); const(char)* constraintsTip; - // determine if the first candidate was printed - int printed; - bool matchSymbol(Dsymbol s, bool print, bool single_candidate = false) + int printed = 0; // number of candidates printed + int count = 0; // total candidates + bool child; // true if inside an eponymous template + const(char)* errorPrefix() @safe + { + if (child) + return " - Containing: "; + + // align with blank spaces after first message + enum plural = "Candidates are: "; + enum spaces = " "; + if (printed) + return spaces; + + return (count == 1) ? "Candidate is: " : plural; + } + bool matchSymbol(Dsymbol s, bool print) { if (auto fd = s.isFuncDeclaration()) { @@ -1772,16 +1790,14 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) return true; auto tf = cast(TypeFunction) fd.type; OutBuffer buf; - buf.writestring(fd.toPrettyChars()); + buf.writestring(child ? fd.toChars() : fd.toPrettyChars()); buf.writestring(parametersTypeToChars(tf.parameterList)); if (tf.mod) { buf.writeByte(' '); buf.MODtoBuffer(tf.mod); } - .errorSupplemental(fd.loc, - printed ? " `%s`" : - single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars()); + .errorSupplemental(fd.loc, "%s`%s`", errorPrefix(), buf.peekChars()); } else if (auto td = s.isTemplateDeclaration()) { @@ -1789,35 +1805,43 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) if (!print) return true; + + // td.onemember may not have overloads set + // (see fail_compilation/onemember_overloads.d) + // assume if more than one member it is overloaded internally + bool recurse = td.onemember && td.members.length > 1; OutBuffer buf; HdrGenState hgs; hgs.skipConstraints = true; + hgs.showOneMember = !recurse; toCharsMaybeConstraints(td, buf, hgs); const tmsg = buf.peekChars(); - const cmsg = td.getConstraintEvalError(constraintsTip); - - // add blank space if there are multiple candidates - // the length of the blank space is `strlen("Candidates are: ")` + const cmsg = child ? null : td.getConstraintEvalError(constraintsTip); if (cmsg) - { - .errorSupplemental(td.loc, - printed ? " `%s`\n%s" : - single_candidate ? "Candidate is: `%s`\n%s" : "Candidates are: `%s`\n%s", - tmsg, cmsg); - } + .errorSupplemental(td.loc, "%s`%s`\n%s", errorPrefix(), tmsg, cmsg); else + .errorSupplemental(td.loc, "%s`%s`", errorPrefix(), tmsg); + + if (recurse) { - .errorSupplemental(td.loc, - printed ? " `%s`" : - single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", - tmsg); + child = true; + foreach (d; *td.members) + { + if (d.ident != td.ident) + continue; + + if (auto fd2 = d.isFuncDeclaration()) + matchSymbol(fd2, print); + else if (auto td2 = d.isTemplateDeclaration()) + matchSymbol(td2, print); + } + child = false; } } return true; } // determine if there's > 1 candidate - int count = 0; overloadApply(declaration, (s) { if (matchSymbol(s, false)) count++; @@ -1827,7 +1851,7 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) overloadApply(declaration, (s) { if (global.params.v.verbose || printed < DisplayLimit) { - if (matchSymbol(s, true, count == 1)) + if (matchSymbol(s, true)) printed++; } else @@ -1938,6 +1962,112 @@ FuncDeclaration overloadExactMatch(FuncDeclaration thisfd, Type t) return fd; } +/**************************************************** + * Determine if fd1 overrides fd2. + * Return !=0 if it does. + */ +int overrides(FuncDeclaration fd1, FuncDeclaration fd2) +{ + int result = 0; + if (fd1.ident == fd2.ident) + { + const cov = fd1.type.covariant(fd2.type); + if (cov != Covariant.distinct) + { + ClassDeclaration cd1 = fd1.toParent().isClassDeclaration(); + ClassDeclaration cd2 = fd2.toParent().isClassDeclaration(); + if (cd1 && cd2 && cd2.isBaseOf(cd1, null)) + result = 1; + } + } + return result; +} + +/************************************* + * Determine partial specialization order of functions `f` vs `g`. + * This is very similar to TemplateDeclaration::leastAsSpecialized(). + * Params: + * f = first function + * g = second function + * names = names of parameters + * Returns: + * match 'this' is at least as specialized as g + * 0 g is more specialized than 'this' + */ +MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* names) +{ + enum LOG_LEASTAS = 0; + static if (LOG_LEASTAS) + { + import core.stdc.stdio : printf; + printf("leastAsSpecialized(%s, %s, %s)\n", f.toChars(), g.toChars(), names ? names.toChars() : "null"); + printf("%s, %s\n", f.type.toChars(), g.type.toChars()); + } + + /* This works by calling g() with f()'s parameters, and + * if that is possible, then f() is at least as specialized + * as g() is. + */ + + TypeFunction tf = f.type.toTypeFunction(); + TypeFunction tg = g.type.toTypeFunction(); + + /* If both functions have a 'this' pointer, and the mods are not + * the same and g's is not const, then this is less specialized. + */ + if (f.needThis() && g.needThis() && tf.mod != tg.mod) + { + if (f.isCtorDeclaration()) + { + if (!MODimplicitConv(tg.mod, tf.mod)) + return MATCH.nomatch; + } + else + { + if (!MODimplicitConv(tf.mod, tg.mod)) + return MATCH.nomatch; + } + } + + /* Create a dummy array of arguments out of the parameters to f() + */ + Expressions args; + foreach (u, p; tf.parameterList) + { + Expression e; + if (p.isReference()) + { + e = new IdentifierExp(Loc.initial, p.ident); + e.type = p.type; + } + else + e = p.type.defaultInitLiteral(Loc.initial); + args.push(e); + } + + MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1); + if (m > MATCH.nomatch) + { + /* A variadic parameter list is less specialized than a + * non-variadic one. + */ + if (tf.parameterList.varargs && !tg.parameterList.varargs) + goto L1; // less specialized + + static if (LOG_LEASTAS) + { + printf(" matches %d, so is least as specialized\n", m); + } + return m; + } +L1: + static if (LOG_LEASTAS) + { + printf(" doesn't match, so is not as specialized\n"); + } + return MATCH.nomatch; +} + /******************************************** * Find function in overload list that matches to the 'this' modifier. * There's four result types. @@ -2416,7 +2546,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) { @@ -2503,6 +2633,27 @@ void buildEnsureRequire(FuncDeclaration thisfd) } } +/**************************************************** + * Determine whether an 'out' contract is declared inside + * the given function or any of its overrides. + * Params: + * fd = the function to search + * Returns: + * true found an 'out' contract + */ +bool needsFensure(FuncDeclaration fd) @safe +{ + if (fd.fensures) + return true; + + foreach (fdv; fd.foverrides) + { + if (needsFensure(fdv)) + return true; + } + return false; +} + /**************************************************** * Merge into this function the 'out' contracts of all it overrides. * 'out's are AND'd together, i.e. all of them need to pass. @@ -2525,7 +2676,7 @@ Statement mergeFensure(FuncDeclaration fd, Statement sf, Identifier oid, Express * https://issues.dlang.org/show_bug.cgi?id=3602 and * https://issues.dlang.org/show_bug.cgi?id=5230 */ - if (fd.needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done) + if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done) { assert(fdv._scope); Scope* sc = fdv._scope.push(); @@ -2745,3 +2896,535 @@ bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char) return false; } } + +/+ + + Checks the parameter and return types iff this is a `main` function. + + + + The following signatures are allowed for a `D main`: + + - Either no or a single parameter of type `string[]` + + - Return type is either `void`, `int` or `noreturn` + + + + The following signatures are standard C: + + - `int main()` + + - `int main(int, char**)` + + + + This function accepts the following non-standard extensions: + + - `char** envp` as a third parameter + + - `void` / `noreturn` as return type + + + + This function will issue errors for unexpected arguments / return types. + +/ +extern (D) void checkMain(FuncDeclaration fd) +{ + if (fd.ident != Id.main || fd.isMember() || fd.isNested()) + return; // Not a main function + + TypeFunction tf = fd.type.toTypeFunction(); + + Type retType = tf.nextOf(); + if (!retType) + { + // auto main(), check after semantic + assert(fd.inferRetType); + return; + } + + /// Checks whether `t` is equivalent to `char**` + /// Ignores qualifiers and treats enums according to their base type + static bool isCharPtrPtr(Type t) + { + auto tp = t.toBasetype().isTypePointer(); + if (!tp) + return false; + + tp = tp.next.toBasetype().isTypePointer(); + if (!tp) + return false; + + return tp.next.toBasetype().ty == Tchar; + } + + // Neither of these qualifiers is allowed because they affect the ABI + enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_; + + const nparams = tf.parameterList.length; + bool argerr; + + const linkage = fd.resolvedLinkage(); + if (linkage == LINK.d) + { + if (nparams == 1) + { + auto fparam0 = tf.parameterList[0]; + auto t = fparam0.type.toBasetype(); + if (t.ty != Tarray || + t.nextOf().ty != Tarray || + t.nextOf().nextOf().ty != Tchar || + fparam0.storageClass & invalidSTC) + { + argerr = true; + } + } + + if (tf.parameterList.varargs || nparams >= 2 || argerr) + .error(fd.loc, "%s `%s` parameter list must be empty or accept one parameter of type `string[]`", fd.kind, fd.toPrettyChars); + } + + else if (linkage == LINK.c) + { + if (nparams == 2 || nparams == 3) + { + // Argument count must be int + auto argCount = tf.parameterList[0]; + argerr |= !!(argCount.storageClass & invalidSTC); + argerr |= argCount.type.toBasetype().ty != Tint32; + + // Argument pointer must be char** + auto argPtr = tf.parameterList[1]; + argerr |= !!(argPtr.storageClass & invalidSTC); + argerr |= !isCharPtrPtr(argPtr.type); + + // `char** environ` is a common extension, see J.5.1 of the C standard + if (nparams == 3) + { + auto envPtr = tf.parameterList[2]; + argerr |= !!(envPtr.storageClass & invalidSTC); + argerr |= !isCharPtrPtr(envPtr.type); + } + } + else + argerr = nparams != 0; + + // Disallow variadic main() - except for K&R declarations in C files. + // E.g. int main(), int main(argc, argv) int argc, char** argc { ... } + if (tf.parameterList.varargs && (!fd.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams))) + argerr |= true; + + if (argerr) + { + .error(fd.loc, "%s `%s` parameters must match one of the following signatures", fd.kind, fd.toPrettyChars); + fd.loc.errorSupplemental("`main()`"); + fd.loc.errorSupplemental("`main(int argc, char** argv)`"); + fd.loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]"); + } + } + else + return; // Neither C nor D main, ignore (should probably be an error) + + // Allow enums with appropriate base types (same ABI) + retType = retType.toBasetype(); + + if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn) + .error(fd.loc, "%s `%s` must return `int`, `void` or `noreturn`, not `%s`", fd.kind, fd.toPrettyChars, tf.nextOf().toChars()); +} + +/*********************************************** + * Check all return statements for a function to verify that returning + * using NRVO is possible. + * + * Returns: + * `false` if the result cannot be returned by hidden reference. + */ +extern (D) bool checkNRVO(FuncDeclaration fd) +{ + if (!fd.isNRVO() || fd.returns is null) + return false; + + auto tf = fd.type.toTypeFunction(); + if (tf.isref) + return false; + + foreach (rs; *fd.returns) + { + if (auto ve = rs.exp.isVarExp()) + { + auto v = ve.var.isVarDeclaration(); + if (!v || v.isReference()) + return false; + else if (fd.nrvo_var is null) + { + // Variables in the data segment (e.g. globals, TLS or not), + // parameters and closure variables cannot be NRVOed. + if (v.isDataseg() || v.isParameter() || v.toParent2() != fd) + return false; + if (v.nestedrefs.length && fd.needsClosure()) + return false; + // don't know if the return storage is aligned + version (MARS) + { + if (fd.alignSectionVars && (*fd.alignSectionVars).contains(v)) + return false; + } + // The variable type needs to be equivalent to the return type. + if (!v.type.equivalent(tf.next)) + return false; + //printf("Setting nrvo to %s\n", v.toChars()); + fd.nrvo_var = v; + } + else if (fd.nrvo_var != v) + return false; + } + else //if (!exp.isLvalue()) // keep NRVO-ability + return false; + } + 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/dmd/gluelayer.d b/dmd/gluelayer.d index 9cd4fc49877..450c0070416 100644 --- a/dmd/gluelayer.d +++ b/dmd/gluelayer.d @@ -40,7 +40,7 @@ else version (NoBackend) struct Symbol; struct code; struct block; - struct Blockx; + struct BlockState; struct elem; struct TYPE; alias type = TYPE; @@ -66,9 +66,9 @@ else version (IN_GCC) } else { - public import dmd.backend.cc : block, Blockx, Symbol; + public import dmd.backend.cc : block, BlockState, Symbol; public import dmd.backend.type : type; public import dmd.backend.el : elem; - public import dmd.backend.code_x86 : code; + public import dmd.backend.x86.code_x86 : code; public import dmd.objc_glue : ObjcGlue; } diff --git a/dmd/hdrgen.d b/dmd/hdrgen.d index f50904db666..82479ce5d16 100644 --- a/dmd/hdrgen.d +++ b/dmd/hdrgen.d @@ -62,6 +62,7 @@ struct HdrGenState bool doFuncBodies; /// include function bodies in output bool vcg_ast; /// write out codegen-ast bool skipConstraints; // skip constraints when doing templates + bool showOneMember = true; bool fullQual; /// fully qualify types when printing int tpltMember; @@ -1980,7 +1981,7 @@ void toCharsMaybeConstraints(const TemplateDeclaration td, ref OutBuffer buf, re } buf.writeByte(')'); - if (td.onemember) + if (hgs.showOneMember && td.onemember) { if (const fd = td.onemember.isFuncDeclaration()) { @@ -3938,9 +3939,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") @@ -3949,7 +3950,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) { @@ -3982,7 +3983,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/dmd/id.d b/dmd/id.d index 4a897ae3da9..50273798458 100644 --- a/dmd/id.d +++ b/dmd/id.d @@ -574,6 +574,7 @@ immutable Msgtable[] msgtable = { "define" }, { "undef" }, { "ident" }, + { "packed" }, // IN_LLVM: LDC-specific pragmas { "LDC_intrinsic" }, diff --git a/dmd/main.d b/dmd/main.d index 9b51c4d26ba..b1588b8a0cd 100644 --- a/dmd/main.d +++ b/dmd/main.d @@ -383,7 +383,8 @@ version (IN_LLVM) {} else if (params.jsonFieldFlags) { Modules modules; // empty - generateJson(modules); + if (generateJson(modules, global.errorSink)) + fatal(); return EXIT_SUCCESS; } version (IN_LLVM) @@ -405,7 +406,7 @@ version (IN_LLVM) } else { - setDefaultLibrary(params, target); + setDefaultLibraries(target, driverParams.defaultlibname, driverParams.debuglibname); } // Initialization @@ -467,7 +468,11 @@ else buildPath(params.fileImppath, global.filePath); // Create Modules - Modules modules = createModules(files, libmodules, target); + Modules modules; + modules.reserve(files.length); + if (createModules(files, libmodules, target, global.errorSink, modules)) + fatal(); + // Read files foreach (m; modules) { @@ -627,7 +632,7 @@ version (IN_LLVM) version (IN_LLVM) {} else { - backend_init(); + backend_init(params, driverParams, target); } // Do semantic analysis @@ -743,7 +748,8 @@ version (IN_LLVM) // Generate output files if (params.json.doOutput) { - generateJson(modules); + if (generateJson(modules, global.errorSink)) + fatal(); } if (!global.errors && params.ddoc.doOutput) { @@ -987,7 +993,6 @@ bool parseCommandlineAndConfig(size_t argc, const(char)** argv, ref Param params bool isX86_64 = arch[0] == '6'; version(Windows) // delete LIB entry in [Environment] (necessary for optlink) to allow inheriting environment for MS-COFF - if (arch != "32omf") environment.update("LIB", 3).value = null; // read from DFLAGS in [Environment{arch}] section @@ -1000,7 +1005,7 @@ bool parseCommandlineAndConfig(size_t argc, const(char)** argv, ref Param params updateRealEnvironment(environment); environment.reset(1); // don't need environment cache any more - if (parseCommandLine(arguments, argc, params, files, target)) + if (parseCommandLine(arguments, argc, params, files, target, driverParams, global.errorSink)) { Loc loc; errorSupplemental(loc, "run `dmd` to print the compiler manual"); @@ -1163,8 +1168,6 @@ else } else { - if (target.omfobj) - error(Loc.initial, "`-m32omf` can only be used when targetting windows"); if (driverParams.mscrtlib) error(Loc.initial, "`-mscrtlib` can only be used when targetting windows"); } diff --git a/dmd/mars.d b/dmd/mars.d index 26266d8fcf7..33988885562 100644 --- a/dmd/mars.d +++ b/dmd/mars.d @@ -34,7 +34,7 @@ import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.dtoh; -import dmd.errors; +import dmd.errorsink; import dmd.expression; import dmd.globals; import dmd.hdrgen; @@ -128,7 +128,15 @@ Where: } // !IN_LLVM -extern (C++) void generateJson(ref Modules modules) +/******************************************* + * Generate JSON file. + * Params: + * modules = Modules + * eSink = error message sink + * Returns: + * true on error + */ +extern (C++) bool generateJson(ref Modules modules, ErrorSink eSink) { OutBuffer buf; json_generate(modules, buf); @@ -154,8 +162,8 @@ extern (C++) void generateJson(ref Modules modules) { if (global.params.objfiles.length == 0) { - error(Loc.initial, "cannot determine JSON filename, use `-Xf=` or provide a source file"); - fatal(); + eSink.error(Loc.initial, "cannot determine JSON filename, use `-Xf=` or provide a source file"); + return true; } // Generate json file name from first obj name const(char)[] n = global.params.objfiles[0].toDString; @@ -165,8 +173,9 @@ extern (C++) void generateJson(ref Modules modules) jsonfilename = FileName.forceExt(n, json_ext); } if (!writeFile(Loc.initial, jsonfilename, buf[])) - fatal(); + return true; } + return false; } @@ -358,40 +367,40 @@ const(char)[] parse_conf_arg(Strings* args) * override any value. * Note that if `-defaultlib=` or `-debuglib=` was used, * we don't override that either. + * Params: + * target = parameters set by user + * defaultlibname = set based on `target` + * debuglibname = set based on `target` */ -void setDefaultLibrary(ref Param params, const ref Target target) +pure @safe +void setDefaultLibraries(const ref Target target, ref const(char)[] defaultlibname, ref const(char)[] debuglibname) { - if (driverParams.defaultlibname is null) + if (defaultlibname is null) { if (target.os == Target.OS.Windows) { - if (target.isX86_64) - driverParams.defaultlibname = "phobos64"; - else if (!target.omfobj) - driverParams.defaultlibname = "phobos32mscoff"; - else - driverParams.defaultlibname = "phobos"; + defaultlibname = target.isX86_64 ? "phobos64" : "phobos32mscoff"; } else if (target.os & (Target.OS.linux | Target.OS.FreeBSD | Target.OS.OpenBSD | Target.OS.Solaris | Target.OS.DragonFlyBSD)) { - driverParams.defaultlibname = "libphobos2.a"; + defaultlibname = "libphobos2.a"; } else if (target.os == Target.OS.OSX) { - driverParams.defaultlibname = "phobos2"; + defaultlibname = "phobos2"; } else { assert(0, "fix this"); } } - else if (!driverParams.defaultlibname.length) // if `-defaultlib=` (i.e. an empty defaultlib) - driverParams.defaultlibname = null; + else if (!defaultlibname.length) // if `-defaultlib=` (i.e. an empty defaultlib) + defaultlibname = null; - if (driverParams.debuglibname is null) - driverParams.debuglibname = driverParams.defaultlibname; - else if (!driverParams.debuglibname.length) // if `-debuglib=` (i.e. an empty debuglib) - driverParams.debuglibname = null; + if (debuglibname is null) + debuglibname = defaultlibname; + else if (!debuglibname.length) // if `-debuglib=` (i.e. an empty debuglib) + debuglibname = null; } } // !IN_LLVM @@ -466,6 +475,7 @@ extern(C) void flushMixins() version (IN_LLVM) { import dmd.cli : Usage; + import dmd.errors : deprecation, error; private bool parseCLIOption(string groupName, Usage.Feature[] features)(ref Param params, const(char)* name) { @@ -567,17 +577,20 @@ else // !IN_LLVM * params = set to result of parsing `arguments` * files = set to files pulled from `arguments` * target = more things set to result of parsing `arguments` + * driverParams = even more things to set + * eSink = error sink * Returns: * true if errors in command line */ -bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param params, ref Strings files, ref Target target) +bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param params, ref Strings files, + ref Target target, ref DMDparams driverParams, ErrorSink eSink) { bool errors; void error(Args ...)(const(char)* format, Args args) { - dmd.errors.error(Loc.initial, format, args); + eSink.error(Loc.initial, format, args); errors = true; } @@ -594,7 +607,7 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param { error("switch `%s` is invalid", p); if (availableOptions !is null) - errorSupplemental(Loc.initial, "%.*s", cast(int)availableOptions.length, availableOptions.ptr); + eSink.errorSupplemental(Loc.initial, "%.*s", cast(int)availableOptions.length, availableOptions.ptr); } enum CheckOptions { success, error, help } @@ -618,7 +631,7 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param // Checks whether a flag has no options (e.g. -foo or -foo=) if (p.length == 0 || p == "=") { - .error(Loc.initial, "%.*s", cast(int)missingMsg.length, missingMsg.ptr); + eSink.error(Loc.initial, "%.*s", cast(int)missingMsg.length, missingMsg.ptr); errors = true; usageFlag = true; return CheckOptions.help; @@ -679,7 +692,7 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param { buf ~= `case "`~t.name~`":`; if (t.deprecated_) - buf ~= "deprecation(Loc.initial, \"`-"~name~"="~t.name~"` no longer has any effect.\"); "; + buf ~= "eSink.deprecation(Loc.initial, \"`-"~name~"="~t.name~"` no longer has any effect.\"); "; buf ~= `setFlagFor(name, params.`~t.paramName~`); return true;`; } return buf; @@ -999,18 +1012,18 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param } else if (arg == "-m32") // https://dlang.org/dmd.html#switch-m32 { + target.isX86 = true; target.isX86_64 = false; - target.omfobj = false; } else if (arg == "-m64") // https://dlang.org/dmd.html#switch-m64 { + target.isX86 = false; target.isX86_64 = true; - target.omfobj = false; } else if (arg == "-m32mscoff") // https://dlang.org/dmd.html#switch-m32mscoff { + target.isX86 = true; target.isX86_64 = false; - target.omfobj = false; } else if (startsWith(p + 1, "mscrtlib=")) { @@ -1244,7 +1257,7 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param case 14_488: break; case 16_997: - deprecation(Loc.initial, "`-transition=16997` is now the default behavior"); + eSink.deprecation(Loc.initial, "`-transition=16997` is now the default behavior"); break; default: error("transition `%s` is invalid", p); @@ -1261,7 +1274,7 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param params.dtorFields = FeatureState.enabled; break; case "intpromote": - deprecation(Loc.initial, "`-transition=intpromote` is now the default behavior"); + eSink.deprecation(Loc.initial, "`-transition=intpromote` is now the default behavior"); break; default: error("transition `%s` is invalid", p); @@ -1563,7 +1576,7 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param else if (arg == "-dip25") // https://dlang.org/dmd.html#switch-dip25 { // @@@ DEPRECATION 2.112 @@@ - deprecation(Loc.initial, "`-dip25` no longer has any effect"); + eSink.deprecation(Loc.initial, "`-dip25` no longer has any effect"); params.useDIP25 = FeatureState.enabled; } else if (arg == "-dip1000") @@ -1658,7 +1671,7 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param // @@@DEPRECATED_2.111@@@ // Deprecated in 2.101, remove in 2.111 - deprecation(Loc.initial, "`-debug=number` is deprecated, use debug identifiers instead"); + eSink.deprecation(Loc.initial, "`-debug=number` is deprecated, use debug identifiers instead"); } else if (Identifier.isValidIdentifier(p + 7)) { @@ -1686,7 +1699,7 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param // @@@DEPRECATED_2.111@@@ // Deprecated in 2.101, remove in 2.111 - deprecation(Loc.initial, "`-version=number` is deprecated, use version identifiers instead"); + eSink.deprecation(Loc.initial, "`-version=number` is deprecated, use version identifiers instead"); } else if (Identifier.isValidIdentifier(p + 9)) { @@ -1866,12 +1879,12 @@ Params: libmodules = Array to which binaries (shared/static libs and object files) will be appended target = target system - + m = created Module Returns: - A D module + true on error */ private -Module createModule(const(char)* file, ref Strings libmodules, const ref Target target) +bool createModule(const(char)* file, ref Strings libmodules, const ref Target target, ErrorSink eSink, out Module m) { version (IN_LLVM) {} else { @@ -1886,11 +1899,12 @@ version (IN_LLVM) {} else { if (!p.length) { - error(Loc.initial, "invalid file name '%s'", file); - fatal(); + eSink.error(Loc.initial, "invalid file name '%s'", file); + return true; } auto id = Identifier.idPool(p); - return new Module(file.toDString, id, global.params.ddoc.doOutput, global.params.dihdr.doOutput); + m = new Module(file.toDString, id, global.params.ddoc.doOutput, global.params.dihdr.doOutput); + return false; } /* Deduce what to do with a file based on its extension @@ -1899,19 +1913,19 @@ version (IN_LLVM) {} else { global.params.objfiles.push(file); libmodules.push(file); - return null; + return false; } // Detect LLVM bitcode files on commandline if (IN_LLVM && FileName.equals(ext, bc_ext)) { global.params.bitcodeFiles.push(file); - return null; + return false; } if (FileName.equals(ext, target.lib_ext)) { global.params.libfiles.push(file); libmodules.push(file); - return null; + return false; } // IN_LLVM replaced: if (target.os & (Target.OS.linux | Target.OS.OSX| Target.OS.FreeBSD | Target.OS.OpenBSD | Target.OS.Solaris | Target.OS.DragonFlyBSD)) if (target.os != Target.OS.Windows) @@ -1920,36 +1934,36 @@ version (IN_LLVM) {} else { global.params.dllfiles.push(file); libmodules.push(file); - return null; + return false; } } if (FileName.equals(ext, ddoc_ext)) { global.params.ddoc.files.push(file); - return null; + return false; } if (FileName.equals(ext, json_ext)) { global.params.json.doOutput = true; global.params.json.name = file.toDString; - return null; + return false; } if (FileName.equals(ext, map_ext)) { global.params.mapfile = file.toDString; - return null; + return false; } if (target.os == Target.OS.Windows) { if (FileName.equals(ext, "res")) { global.params.resfile = file.toDString; - return null; + return false; } if (FileName.equals(ext, "def")) { global.params.deffile = file.toDString; - return null; + return false; } if (FileName.equals(ext, "exe")) { @@ -1969,19 +1983,19 @@ version (IN_LLVM) {} else const(char)[] name = p[0 .. p.length - ext.length - 1]; // -1 for the . if (!name.length || name == ".." || name == ".") { - error(Loc.initial, "invalid file name '%s'", file); - fatal(); + eSink.error(Loc.initial, "invalid file name '%s'", file); + return true; } /* name is the D source file name stripped of * its path and extension. */ auto id = Identifier.idPool(name); - return new Module(file.toDString, id, global.params.ddoc.doOutput, global.params.dihdr.doOutput); + m = new Module(file.toDString, id, global.params.ddoc.doOutput, global.params.dihdr.doOutput); + return false; } - error(Loc.initial, "unrecognized file extension %.*s", cast(int)ext.length, ext.ptr); - fatal(); - assert(0); + eSink.error(Loc.initial, "unrecognized file extension %.*s", cast(int)ext.length, ext.ptr); + return true; } /** @@ -1997,14 +2011,14 @@ Params: libmodules = Array to which binaries (shared/static libs and object files) will be appended target = target system + eSink = error message sink + modules = empty array of modules to be filled in Returns: - An array of path to D modules + true on error */ -Modules createModules(ref Strings files, ref Strings libmodules, const ref Target target) +bool createModules(ref Strings files, ref Strings libmodules, const ref Target target, ErrorSink eSink, ref Modules modules) { - Modules modules; - modules.reserve(files.length); version (IN_LLVM) { size_t firstModuleObjectFileIndex = size_t.max; @@ -2015,7 +2029,9 @@ else } foreach(file; files) { - auto m = createModule(file, libmodules, target); + Module m; + if (createModule(file, libmodules, target, eSink, m)) + return true; if (m is null) continue; @@ -2050,7 +2066,7 @@ version (IN_LLVM) global.params.objfiles.insert(0, fn); } } - return modules; + return false; } /// Returns: a compiled module (semantic3) containing an empty main() function, for the -main flag diff --git a/dmd/mtype.d b/dmd/mtype.d index 4afc5312c70..b7106d6eec0 100644 --- a/dmd/mtype.d +++ b/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; @@ -601,6 +601,14 @@ version (IN_LLVM) tsize_t = basic[isLP64 ? Tuns64 : Tuns32]; tptrdiff_t = basic[isLP64 ? Tint64 : Tint32]; thash_t = tsize_t; + + static if (__VERSION__ == 2081) + { + // Related issue: https://issues.dlang.org/show_bug.cgi?id=19134 + // D 2.081.x regressed initializing class objects at compile time. + // As a workaround initialize this global at run-time instead. + TypeTuple.empty = new TypeTuple(); + } } /** @@ -614,20 +622,9 @@ version (IN_LLVM) 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); } /********************************* @@ -1289,22 +1286,6 @@ version (IN_LLVM) 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. @@ -1578,7 +1559,7 @@ version (IN_LLVM) } } - 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; } @@ -1652,11 +1633,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(); @@ -2112,83 +2088,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); @@ -2230,98 +2129,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) @@ -2392,11 +2199,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(); @@ -2428,29 +2230,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"); @@ -2541,22 +2320,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(); @@ -2588,65 +2351,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) @@ -2732,12 +2436,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 @@ -2761,35 +2459,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); @@ -2831,11 +2500,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; @@ -2846,30 +2510,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()) @@ -2918,50 +2558,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) @@ -3016,11 +2612,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; @@ -3281,47 +2872,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) { @@ -3443,39 +2993,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; @@ -3530,11 +3052,6 @@ extern (C++) final class TypeTraits : Type { v.visit(this); } - - override uinteger_t size(const ref Loc loc) - { - return SIZE_INVALID; - } } /****** @@ -3644,12 +3161,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); @@ -3755,14 +3266,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); @@ -3821,11 +3324,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 @@ -3891,7 +3389,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; @@ -4024,7 +3522,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 @@ -4061,13 +3559,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)) @@ -4125,11 +3616,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); @@ -4208,19 +3694,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)) @@ -4288,11 +3761,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; @@ -4333,13 +3801,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)) @@ -4409,7 +3870,10 @@ extern (C++) final class TypeClass : Type extern (C++) final class TypeTuple : Type { // 'logically immutable' cached global - don't modify! - __gshared TypeTuple empty = new TypeTuple(); + static if (__VERSION__ == 2081) + __gshared TypeTuple empty; // See comment in Type._init + else + __gshared TypeTuple empty = new TypeTuple(); Parameters* arguments; // types making up the tuple @@ -4535,29 +3999,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); @@ -4619,36 +4060,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); @@ -4676,22 +4092,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 @@ -4703,11 +4103,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/dmd/mtype.h b/dmd/mtype.h index 540772a98a5..01b934ecec0 100644 --- a/dmd/mtype.h +++ b/dmd/mtype.h @@ -233,8 +233,6 @@ class Type : public ASTNode 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; @@ -271,7 +269,6 @@ class Type : public ASTNode 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); @@ -328,7 +325,6 @@ class TypeError final : public Type 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); } }; @@ -363,7 +359,6 @@ class TypeBasic final : public Type const char *kind() override; TypeBasic *syntaxCopy() override; - uinteger_t size(const Loc &loc) override; unsigned alignsize() override; bool isintegral() override; bool isfloating() override; @@ -372,7 +367,6 @@ class TypeBasic final : public Type bool iscomplex() override; bool isscalar() override; bool isunsigned() override; - MATCH implicitConvTo(Type *to) override; bool isZeroInit(const Loc &loc) override; // For eliminating dynamic_cast @@ -388,14 +382,12 @@ class TypeVector final : public Type 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; @@ -418,13 +410,11 @@ class TypeSArray final : public TypeArray 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; @@ -442,12 +432,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); } }; @@ -461,10 +449,8 @@ class TypeAArray final : public TypeArray 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); } @@ -476,8 +462,6 @@ class TypePointer final : public TypeNext 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; @@ -490,7 +474,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); } }; @@ -620,9 +603,7 @@ class TypeDelegate final : public TypeNext 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; @@ -639,7 +620,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); } }; @@ -662,7 +642,6 @@ class TypeQualified : public Type // representing ident.ident!tiargs.ident. ... etc. Objects idents; - uinteger_t size(const Loc &loc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -699,7 +678,6 @@ class TypeTypeof final : public TypeQualified const char *kind() override; TypeTypeof *syntaxCopy() override; - uinteger_t size(const Loc &loc) override; void accept(Visitor *v) override { v->visit(this); } }; @@ -732,7 +710,6 @@ class TypeStruct final : public Type 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; @@ -746,7 +723,6 @@ class TypeStruct final : public Type 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; @@ -760,7 +736,6 @@ class TypeEnum final : public Type 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; @@ -776,7 +751,6 @@ class TypeEnum final : public Type 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; @@ -795,10 +769,8 @@ class TypeClass final : public Type 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; @@ -843,10 +815,8 @@ class TypeNull final : public Type 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); } }; @@ -855,10 +825,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); } @@ -907,4 +875,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/dmd/objc.d b/dmd/objc.d index 967de79d51b..2e18303e4dc 100644 --- a/dmd/objc.d +++ b/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 @@ -577,7 +577,7 @@ version (IN_LLVM) {} else { 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/dmd/optimize.d b/dmd/optimize.d index 649ef10b6ad..ab1b67c53be 100644 --- a/dmd/optimize.d +++ b/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) { diff --git a/dmd/pragmasem.d b/dmd/pragmasem.d index f4e7b902188..11f42efc7ed 100644 --- a/dmd/pragmasem.d +++ b/dmd/pragmasem.d @@ -628,32 +628,19 @@ private uint setMangleOverride(Dsymbol s, const(char)[] sym) private bool pragmaMsgSemantic(Loc loc, Scope* sc, Expressions* args) { import dmd.tokens; + import dmd.common.outbuffer; if (!args) return true; - foreach (arg; *args) - { - sc = sc.startCTFE(); - auto e = arg.expressionSemantic(sc); - e = resolveProperties(sc, e); - sc = sc.endCTFE(); - // pragma(msg) is allowed to contain types as well as expressions - e = ctfeInterpretForPragmaMsg(e); - if (e.op == EXP.error) - { - errorSupplemental(loc, "while evaluating `pragma(msg, %s)`", arg.toChars()); - return false; - } - if (auto se = e.toStringExp()) - { - const slice = se.toUTF8(sc).peekString(); - fprintf(stderr, "%.*s", cast(int)slice.length, slice.ptr); - } - else - fprintf(stderr, "%s", e.toChars()); + OutBuffer buf; + if (expressionsToString(buf, sc, args, loc, "while evaluating `pragma(msg, %s)`", false)) + return false; + else + { + buf.writestring("\n"); + fprintf(stderr, buf.extractChars); } - fprintf(stderr, "\n"); return true; } diff --git a/dmd/safe.d b/dmd/safe.d index 5064ac2d9cd..f1bd6c98c80 100644 --- a/dmd/safe.d +++ b/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/dmd/semantic2.d b/dmd/semantic2.d index 63292dd510f..97f939282bb 100644 --- a/dmd/semantic2.d +++ b/dmd/semantic2.d @@ -325,7 +325,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); } diff --git a/dmd/semantic3.d b/dmd/semantic3.d index caa73b28c29..024040f829f 100644 --- a/dmd/semantic3.d +++ b/dmd/semantic3.d @@ -324,7 +324,7 @@ private extern(C++) final class Semantic3Visitor : Visitor fds.checkInContractOverrides(); // Remember whether we need to generate an 'out' contract. - immutable bool needEnsure = FuncDeclaration.needsFensure(funcdecl); + immutable bool needEnsure = funcdecl.needsFensure(); if (funcdecl.fbody || funcdecl.frequires || needEnsure) { diff --git a/dmd/sideeffect.d b/dmd/sideeffect.d index 1d4745afbc1..57a6639575c 100644 --- a/dmd/sideeffect.d +++ b/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/dmd/statement.d b/dmd/statement.d index 03a2c3a716e..4a89cbefa5a 100644 --- a/dmd/statement.d +++ b/dmd/statement.d @@ -273,57 +273,58 @@ version (IN_LLVM) inout(CompoundAsmStatement) endsWithAsm() 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/dmd/statementsem.d b/dmd/statementsem.d index 401b7ca3ad2..95395d27195 100644 --- a/dmd/statementsem.d +++ b/dmd/statementsem.d @@ -1382,7 +1382,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(); } @@ -3578,6 +3578,7 @@ version (IN_LLVM) ls2.statement = ls; sc = sc.push(); + sc.lastVar = sc.enclosing.lastVar; sc.scopesym = sc.enclosing.scopesym; sc.ctorflow.orCSX(CSX.label); @@ -3585,6 +3586,10 @@ version (IN_LLVM) sc.slabel = ls; if (ls.statement) ls.statement = ls.statement.statementSemantic(sc); + + //issue 24534: lastVar may have been updated in the nested scope + sc.enclosing.lastVar = sc.lastVar; + sc.pop(); result = ls; @@ -4866,7 +4871,7 @@ private Statements* flatten(Statement statement, Scope* sc) OutBuffer buf; - if (expressionsToString(buf, sc, cs.exps)) + if (expressionsToString(buf, sc, cs.exps, cs.loc, null, true)) return errorStatements(); const errors = global.errors; diff --git a/dmd/target.d b/dmd/target.d index 2dc8d503ec5..295cb5dbe25 100644 --- a/dmd/target.d +++ b/dmd/target.d @@ -25,6 +25,8 @@ module dmd.target; +import core.stdc.stdio; + import dmd.astenums : CHECKENABLE; import dmd.globals : Param; @@ -257,7 +259,6 @@ void addCRuntimePredefinedGlobalIdent(const ref TargetC c) default: case Unspecified: return; case Bionic: return predef("CRuntime_Bionic"); - case DigitalMars: return predef("CRuntime_DigitalMars"); case Glibc: return predef("CRuntime_Glibc"); case Microsoft: return predef("CRuntime_Microsoft"); case Musl: return predef("CRuntime_Musl"); @@ -276,12 +277,22 @@ void addCppRuntimePredefinedGlobalIdent(const ref TargetCPP cpp) with (TargetCPP.Runtime) switch (cpp.runtime) { default: - case Unspecified: return; - case Clang: return predef("CppRuntime_Clang"); - case DigitalMars: return predef("CppRuntime_DigitalMars"); - case Gcc: return predef("CppRuntime_Gcc"); - case Microsoft: return predef("CppRuntime_Microsoft"); - case Sun: return predef("CppRuntime_Sun"); + case Unspecified: + return; + case LLVM: + predef("CppRuntime_LLVM"); + predef("CppRuntime_Clang"); // legacy + return; + case GNU: + predef("CppRuntime_GNU"); + predef("CppRuntime_Gcc"); // legacy + return; + case Microsoft: + predef("CppRuntime_Microsoft"); + return; + case Sun: + predef("CppRuntime_Sun"); + return; } } @@ -305,7 +316,7 @@ extern (C++) struct Target import dmd.location; import dmd.astenums : LINK, TY; import dmd.mtype : Type, TypeFunction, TypeTuple; - import dmd.typesem : pointerTo; + import dmd.typesem : pointerTo, size; import dmd.root.ctfloat : real_t; import dmd.statement : Statement; import dmd.tokens : EXP; @@ -335,7 +346,6 @@ extern (C++) struct Target elf, macho, coff, - omf } OS os; @@ -368,6 +378,7 @@ version (IN_LLVM) {} else { CPU cpu; // CPU instruction set to target bool isX86_64; // generate 64 bit code for x86_64; true by default for 64 bit dmd + bool isX86; // generate 32 bit Intel x86 code } bool isLP64; // pointers are 64 bits @@ -376,7 +387,6 @@ version (IN_LLVM) {} else const(char)[] lib_ext; /// extension for static library files const(char)[] dll_ext; /// extension for dynamic library files bool run_noext; /// allow -run sources without extensions - bool omfobj; // for Win32: write OMF object files instead of MsCoff /** * Values representing all properties for floating point types */ @@ -445,7 +455,8 @@ else // !IN_LLVM */ extern (C++) void _init(ref const Param params) { - // isX86_64, omfobj and cpu are initialized in parseCommandLine + // isX86_64 and cpu are initialized in parseCommandLine + isX86 = !isX86_64; this.params = ¶ms; @@ -490,13 +501,6 @@ else // !IN_LLVM realsize = 10; realpad = 0; realalignsize = 2; - if (omfobj) - { - /* Optlink cannot deal with individual data chunks - * larger than 16Mb - */ - maxStaticDataSize = 0x100_0000; // 16Mb - } } else assert(0); @@ -543,14 +547,14 @@ else // !IN_LLVM /** Determine the object format to be used */ - extern(D) Target.ObjectFormat objectFormat() @safe + extern(D) Target.ObjectFormat objectFormat() const @safe { if (os == Target.OS.OSX) return Target.ObjectFormat.macho; else if (os & Target.OS.Posix) return Target.ObjectFormat.elf; else if (os == Target.OS.Windows) - return omfobj ? Target.ObjectFormat.omf : Target.ObjectFormat.coff; + return Target.ObjectFormat.coff; else assert(0, "unkown object format"); } @@ -621,7 +625,7 @@ else // !IN_LLVM case TY.Timaginary64: case TY.Tcomplex64: if (os & Target.OS.Posix) - return isX86_64 ? 8 : 4; + return isX86 ? 4 : 8; break; default: break; @@ -1131,6 +1135,8 @@ else // !IN_LLVM auto sd = ts.sym; if (tf.linkage == LINK.cpp && needsThis) return true; + if (tf.linkage == LINK.cpp && sd.ctor) + return true; if (!sd.isPOD() || sz > 8) return true; if (sd.fields.length == 0) @@ -1165,7 +1171,7 @@ else // !IN_LLVM if (tns.ty != TY.Tstruct) { L2: - if (os == Target.OS.linux && tf.linkage != LINK.d && !isX86_64) + if (os == Target.OS.linux && tf.linkage != LINK.d && isX86) { // 32 bit C/C++ structs always on stack } @@ -1192,12 +1198,12 @@ else // !IN_LLVM if (auto ts = tns.isTypeStruct()) { auto sd = ts.sym; - if (os == Target.OS.linux && tf.linkage != LINK.d && !isX86_64) + if (os == Target.OS.linux && tf.linkage != LINK.d && isX86) { //printf(" 2 true\n"); return true; // 32 bit C/C++ structs always on stack } - if (os == Target.OS.Windows && tf.linkage == LINK.cpp && !isX86_64 && + if (os == Target.OS.Windows && tf.linkage == LINK.cpp && isX86 && sd.isPOD() && sd.ctor) { // win32 returns otherwise POD structs with ctors via memory @@ -1245,7 +1251,7 @@ else // !IN_LLVM return true; } else if (os == Target.OS.Windows && - !isX86_64 && + isX86 && tf.linkage == LINK.cpp && tf.isfloating()) { @@ -1353,7 +1359,7 @@ else // !IN_LLVM { case objectFormat.stringof: if (os == Target.OS.Windows) - return stringExp(omfobj ? "omf" : "coff" ); + return stringExp("coff"); else if (os == Target.OS.OSX) return stringExp("macho"); else @@ -1362,11 +1368,7 @@ else // !IN_LLVM return stringExp("hard"); case cppRuntimeLibrary.stringof: if (os == Target.OS.Windows) - { - if (omfobj) - return stringExp("snn"); return stringExp(driverParams.mscrtlib); - } return stringExp(""); case cppStd.stringof: return new IntegerExp(params.cplusplus); @@ -1408,7 +1410,7 @@ else // !IN_LLVM */ extern (C++) bool libraryObjectMonitors(FuncDeclaration fd, Statement fbody) { - if (!isX86_64 && os == Target.OS.Windows && !fd.isStatic() && !fbody.usesEH() && !params.trace) + if (isX86 && os == Target.OS.Windows && !fd.isStatic() && !fbody.usesEH() && !params.trace) { /* The back end uses the "jmonitor" hack for syncing; * no need to do the sync in the library. @@ -1425,7 +1427,7 @@ else // !IN_LLVM */ extern (C++) bool supportsLinkerDirective() const @safe { - return os == Target.OS.Windows && !omfobj; + return os == Target.OS.Windows; } //////////////////////////////////////////////////////////////////////////// @@ -1439,7 +1441,7 @@ else // !IN_LLVM */ extern (D) bool isXmmSupported() @safe { - return isX86_64 || os == Target.OS.OSX; + return isX86_64 || (isX86 && os == Target.OS.OSX); } /** @@ -1459,7 +1461,11 @@ else // !IN_LLVM */ extern (D) uint stackAlign() @safe { - return isXmmSupported() ? 16 : (isX86_64 ? 8 : 4); + uint sz = isXmmSupported() ? 16 : + isX86_64 ? 8 : + isX86 ? 4 : 0; + assert(sz); + return sz; } } // !IN_LLVM } @@ -1470,11 +1476,12 @@ else // !IN_LLVM */ struct TargetC { + import dmd.declaration : BitFieldDeclaration; + enum Runtime : ubyte { Unspecified, Bionic, - DigitalMars, Glibc, Microsoft, Musl, @@ -1486,7 +1493,6 @@ struct TargetC enum BitFieldStyle : ubyte { Unspecified, - DM, /// Digital Mars 32 bit C compiler MS, /// Microsoft 32 and 64 bit C compilers /// https://docs.microsoft.com/en-us/cpp/c-language/c-bit-fields?view=msvc-160 /// https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-160 @@ -1539,7 +1545,7 @@ version (IN_LLVM) {} else wchar_tsize = 4; if (os == Target.OS.Windows) - runtime = target.omfobj ? Runtime.DigitalMars : Runtime.Microsoft; + runtime = Runtime.Microsoft; else if (os == Target.OS.linux) { // Note: This is overridden later by `-target=` if supplied. @@ -1551,7 +1557,7 @@ version (IN_LLVM) {} else } if (os == Target.OS.Windows) - bitFieldStyle = target.omfobj ? BitFieldStyle.DM : BitFieldStyle.MS; + bitFieldStyle = BitFieldStyle.MS; else if (os & (Target.OS.linux | Target.OS.FreeBSD | Target.OS.OSX | Target.OS.OpenBSD | Target.OS.DragonFlyBSD | Target.OS.Solaris)) bitFieldStyle = BitFieldStyle.Gcc_Clang; @@ -1565,6 +1571,32 @@ version (IN_LLVM) {} else crtDestructorsSupported = false; } } + +version (IN_LLVM) +{ + // implemented in gen/target.cpp + extern (C++) bool contributesToAggregateAlignment(BitFieldDeclaration bfd); +} +else +{ + /** + * Indicates whether the specified bit-field contributes to the alignment + * of the containing aggregate. + * E.g., (not all) ARM ABIs do NOT ignore anonymous (incl. 0-length) + * bit-fields. + */ + extern (C++) bool contributesToAggregateAlignment(BitFieldDeclaration bfd) + { + if (bitFieldStyle == BitFieldStyle.MS) + return true; + if (bitFieldStyle == BitFieldStyle.Gcc_Clang) + { + // sufficient for DMD's currently supported architectures + return !bfd.isAnonymous(); + } + assert(0); + } +} } //////////////////////////////////////////////////////////////////////////////// @@ -1581,9 +1613,8 @@ struct TargetCPP enum Runtime : ubyte { Unspecified, - Clang, - DigitalMars, - Gcc, + LLVM, + GNU, Microsoft, Sun } @@ -1608,23 +1639,23 @@ version (IN_LLVM) {} else else if (os == Target.OS.Windows) { reverseOverloads = true; - splitVBasetable = !target.omfobj; + splitVBasetable = true; } else assert(0); exceptions = (os & Target.OS.Posix) != 0; if (os == Target.OS.Windows) - runtime = target.omfobj ? Runtime.DigitalMars : Runtime.Microsoft; + runtime = Runtime.Microsoft; else if (os & (Target.OS.linux | Target.OS.DragonFlyBSD)) - runtime = Runtime.Gcc; + runtime = Runtime.GNU; else if (os & (Target.OS.OSX | Target.OS.FreeBSD | Target.OS.OpenBSD)) - runtime = Runtime.Clang; + runtime = Runtime.LLVM; else if (os == Target.OS.Solaris) - runtime = Runtime.Gcc; + runtime = Runtime.GNU; else assert(0); // C++ and D ABI incompatible on all (?) x86 32-bit platforms - wrapDtorInExternD = !target.isX86_64; + wrapDtorInExternD = target.isX86; } /** @@ -1637,7 +1668,7 @@ version (IN_LLVM) {} else extern (C++) const(char)* toMangle(Dsymbol s) { import dmd.cppmangle : toCppMangleItanium; - import dmd.cppmanglewin : toCppMangleDMC, toCppMangleMSVC; + import dmd.cppmanglewin : toCppMangleMSVC; version (IN_LLVM) { @@ -1651,12 +1682,7 @@ else if (target.os & (Target.OS.linux | Target.OS.OSX | Target.OS.FreeBSD | Target.OS.OpenBSD | Target.OS.Solaris | Target.OS.DragonFlyBSD)) return toCppMangleItanium(s); if (target.os == Target.OS.Windows) - { - if (target.omfobj) - return toCppMangleDMC(s); - else - return toCppMangleMSVC(s); - } + return toCppMangleMSVC(s); else assert(0, "fix this"); } @@ -1672,7 +1698,7 @@ else extern (C++) const(char)* typeInfoMangle(ClassDeclaration cd) { import dmd.cppmangle : cppTypeInfoMangleItanium; - import dmd.cppmanglewin : cppTypeInfoMangleDMC, cppTypeInfoMangleMSVC; + import dmd.cppmanglewin : cppTypeInfoMangleMSVC; version (IN_LLVM) { @@ -1686,12 +1712,7 @@ else if (target.os & (Target.OS.linux | Target.OS.OSX | Target.OS.FreeBSD | Target.OS.OpenBSD | Target.OS.Solaris | Target.OS.DragonFlyBSD)) return cppTypeInfoMangleItanium(cd); if (target.os == Target.OS.Windows) - { - if (target.omfobj) - return cppTypeInfoMangleDMC(cd); - else - return cppTypeInfoMangleMSVC(cd); - } + return cppTypeInfoMangleMSVC(cd); else assert(0, "fix this"); } diff --git a/dmd/target.h b/dmd/target.h index 20a905d18ef..ad9a3891c6b 100644 --- a/dmd/target.h +++ b/dmd/target.h @@ -16,6 +16,7 @@ #include "globals.h" #include "tokens.h" +class BitFieldDeclaration; class ClassDeclaration; class Dsymbol; class Expression; @@ -54,7 +55,6 @@ struct TargetC { Unspecified, Bionic, - DigitalMars, Glibc, Microsoft, Musl, @@ -66,7 +66,6 @@ struct TargetC enum class BitFieldStyle : unsigned char { Unspecified, - DM, // Digital Mars 32 bit C compiler MS, // Microsoft 32 and 64 bit C compilers // https://docs.microsoft.com/en-us/cpp/c-language/c-bit-fields?view=msvc-160 // https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-160 @@ -85,6 +84,8 @@ struct TargetC Runtime runtime; #endif BitFieldStyle bitFieldStyle; // different C compilers do it differently + + bool contributesToAggregateAlignment(BitFieldDeclaration *bfd); }; struct TargetCPP @@ -92,9 +93,8 @@ struct TargetCPP enum class Runtime : unsigned char { Unspecified, - Clang, - DigitalMars, - Gcc, + LLVM, + GNU, Microsoft, Sun }; @@ -169,6 +169,7 @@ struct Target #if !IN_LLVM CPU cpu; // CPU instruction set to target d_bool isX86_64; // generate 64 bit code for x86_64; true by default for 64 bit dmd + d_bool isX86; // generate 32 bit Intel x86 code #endif d_bool isLP64; // pointers are 64 bits @@ -177,7 +178,6 @@ struct Target DString lib_ext; /// extension for static library files DString dll_ext; /// extension for dynamic library files d_bool run_noext; /// allow -run sources without extensions - d_bool omfobj; /// for Win32: write OMF object files instead of COFF template struct FPTypeProperties diff --git a/dmd/templatesem.d b/dmd/templatesem.d index 0d6ef465fc2..3737141dd04 100644 --- a/dmd/templatesem.d +++ b/dmd/templatesem.d @@ -56,6 +56,8 @@ import dmd.tokens; import dmd.typesem; import dmd.visitor; +alias funcLeastAsSpecialized = dmd.funcsem.leastAsSpecialized; + /************************************ * Perform semantic analysis on template. * Params: @@ -2023,8 +2025,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, * This is because f() is "more specialized." */ { - MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names); - MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names); + MATCH c1 = funcLeastAsSpecialized(fd, m.lastf, argumentList.names); + MATCH c2 = funcLeastAsSpecialized(m.lastf, fd, argumentList.names); //printf("c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) return firstIsBetter(); if (c1 < c2) return 0; @@ -2303,8 +2305,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, } { // Disambiguate by picking the most specialized FunctionDeclaration - MATCH c1 = FuncDeclaration.leastAsSpecialized(fd, m.lastf, argumentList.names); - MATCH c2 = FuncDeclaration.leastAsSpecialized(m.lastf, fd, argumentList.names); + MATCH c1 = funcLeastAsSpecialized(fd, m.lastf, argumentList.names); + MATCH c2 = funcLeastAsSpecialized(m.lastf, fd, argumentList.names); //printf("3: c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; diff --git a/dmd/typesem.d b/dmd/typesem.d index 7643dc59c10..a909fcf14c1 100644 --- a/dmd/typesem.d +++ b/dmd/typesem.d @@ -1282,6 +1282,169 @@ bool hasPointers(Type t) } } +/************************************** + * Returns an indirect type one step from t. + */ +Type getIndirection(Type t) +{ + t = t.baseElemOf(); + if (t.ty == Tarray || t.ty == Tpointer) + return t.nextOf().toBasetype(); + if (t.ty == Taarray || t.ty == Tclass) + return t; + if (t.ty == Tstruct) + return t.hasPointers() ? t : null; // TODO + + // should consider TypeDelegate? + 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: @@ -6704,7 +6867,7 @@ Type substWildTo(Type type, uint mod) t = new TypeSArray(t, (cast(TypeSArray)type).dim.syntaxCopy()); else if (type.ty == Taarray) { - t = new TypeAArray(t, (cast(TypeAArray)type).index.syntaxCopy()); + t = new TypeAArray(t, (cast(TypeAArray)type).index.substWildTo(mod)); } else if (type.ty == Tdelegate) { @@ -7286,7 +7449,7 @@ Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id) RootObject compileTypeMixin(TypeMixin tm, ref const Loc loc, Scope* sc) { OutBuffer buf; - if (expressionsToString(buf, sc, tm.exps)) + if (expressionsToString(buf, sc, tm.exps, tm.loc, null, true)) return null; const errors = global.errors; diff --git a/dmd/typinf.d b/dmd/typinf.d index 97671fa38d0..7666d356b6a 100644 --- a/dmd/typinf.d +++ b/dmd/typinf.d @@ -107,14 +107,13 @@ else * loc = the location for reporting line nunbers in errors * t = the type to get the type of the `TypeInfo` object for * sc = the scope - * genObjCode = if true, object code will be generated for the obtained TypeInfo * Returns: * The type of the `TypeInfo` object associated with `t` */ -extern (C++) Type getTypeInfoType(const ref Loc loc, Type t, Scope* sc, bool genObjCode = true) +extern (C++) Type getTypeInfoType(const ref Loc loc, Type t, Scope* sc) { assert(t.ty != Terror); - if (genTypeInfo(null, loc, t, sc) && genObjCode) + if (genTypeInfo(null, loc, t, sc)) { // Find module that will go all the way to an object file Module m = sc._module.importedFrom; diff --git a/dmd/typinf.h b/dmd/typinf.h index dd9572aab42..6414ecdd36a 100644 --- a/dmd/typinf.h +++ b/dmd/typinf.h @@ -22,4 +22,4 @@ namespace dmd bool isSpeculativeType(Type *t); bool builtinTypeInfo(Type *t); } -Type *getTypeInfoType(const Loc &loc, Type *t, Scope *sc, bool genObjCode = true); +Type *getTypeInfoType(const Loc &loc, Type *t, Scope *sc); diff --git a/dmd/visitor.d b/dmd/visitor.d index abfd8caa584..9082909ba2e 100644 --- a/dmd/visitor.d +++ b/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/driver/main.cpp b/driver/main.cpp index ea89e8cba4d..ef9299afa4d 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -830,17 +830,20 @@ void registerPredefinedTargetVersions() { if (triple.getEnvironment() == llvm::Triple::Android) { VersionCondition::addPredefinedGlobalIdent("Android"); VersionCondition::addPredefinedGlobalIdent("CRuntime_Bionic"); - VersionCondition::addPredefinedGlobalIdent("CppRuntime_Clang"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_LLVM"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_Clang"); // legacy } else if (triple.isMusl()) { VersionCondition::addPredefinedGlobalIdent("CRuntime_Musl"); - VersionCondition::addPredefinedGlobalIdent("CppRuntime_Gcc"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_GNU"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_Gcc"); // legacy // use libunwind for backtraces VersionCondition::addPredefinedGlobalIdent("DRuntime_Use_Libunwind"); } else if (global.params.isUClibcEnvironment) { VersionCondition::addPredefinedGlobalIdent("CRuntime_UClibc"); } else { VersionCondition::addPredefinedGlobalIdent("CRuntime_Glibc"); - VersionCondition::addPredefinedGlobalIdent("CppRuntime_Gcc"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_GNU"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_Gcc"); // legacy } break; case llvm::Triple::Haiku: @@ -853,7 +856,8 @@ void registerPredefinedTargetVersions() { VersionCondition::addPredefinedGlobalIdent( "darwin"); // For backwards compatibility. VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("CppRuntime_Clang"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_LLVM"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_Clang"); // legacy break; case llvm::Triple::FreeBSD: VersionCondition::addPredefinedGlobalIdent("FreeBSD"); @@ -864,7 +868,8 @@ void registerPredefinedTargetVersions() { warning(Loc(), "FreeBSD major version not specified in target triple"); } VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("CppRuntime_Clang"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_LLVM"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_Clang"); // legacy break; case llvm::Triple::Solaris: VersionCondition::addPredefinedGlobalIdent("Solaris"); @@ -874,7 +879,8 @@ void registerPredefinedTargetVersions() { case llvm::Triple::DragonFly: VersionCondition::addPredefinedGlobalIdent("DragonFlyBSD"); VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("CppRuntime_Gcc"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_GNU"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_Gcc"); // legacy break; case llvm::Triple::NetBSD: VersionCondition::addPredefinedGlobalIdent("NetBSD"); @@ -883,7 +889,8 @@ void registerPredefinedTargetVersions() { case llvm::Triple::OpenBSD: VersionCondition::addPredefinedGlobalIdent("OpenBSD"); VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("CppRuntime_Gcc"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_GNU"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_Gcc"); // legacy break; case llvm::Triple::AIX: VersionCondition::addPredefinedGlobalIdent("AIX"); @@ -892,17 +899,20 @@ void registerPredefinedTargetVersions() { case llvm::Triple::IOS: VersionCondition::addPredefinedGlobalIdent("iOS"); VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("CppRuntime_Clang"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_LLVM"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_Clang"); // legacy break; case llvm::Triple::TvOS: VersionCondition::addPredefinedGlobalIdent("TVOS"); VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("CppRuntime_Clang"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_LLVM"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_Clang"); // legacy break; case llvm::Triple::WatchOS: VersionCondition::addPredefinedGlobalIdent("WatchOS"); VersionCondition::addPredefinedGlobalIdent("Posix"); - VersionCondition::addPredefinedGlobalIdent("CppRuntime_Clang"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_LLVM"); + VersionCondition::addPredefinedGlobalIdent("CppRuntime_Clang"); // legacy break; case llvm::Triple::WASI: VersionCondition::addPredefinedGlobalIdent("WASI"); diff --git a/gen/abi/aarch64.cpp b/gen/abi/aarch64.cpp index e6d501c8016..285bc56668b 100644 --- a/gen/abi/aarch64.cpp +++ b/gen/abi/aarch64.cpp @@ -17,6 +17,8 @@ #include "gen/abi/abi.h" #include "gen/abi/generic.h" +using namespace dmd; + /** * AAPCS64 uses a special native va_list type, a struct aliased as * object.__va_list in druntime. Apple diverges and uses a simple char* @@ -100,7 +102,7 @@ struct AArch64TargetABI : TargetABI { if (!arg->byref) { auto tb = arg->type->toBasetype(); - if (tb->size() == 0) { + if (size(tb) == 0) { fty.args.erase(fty.args.begin() + i); continue; } diff --git a/gen/abi/abi.cpp b/gen/abi/abi.cpp index 5fb04c5330d..1ecff84dcb6 100644 --- a/gen/abi/abi.cpp +++ b/gen/abi/abi.cpp @@ -125,8 +125,8 @@ bool TargetABI::isPOD(Type *t, bool excludeStructsWithCtor) { } bool TargetABI::canRewriteAsInt(Type *t, bool include64bit) { - auto size = t->toBasetype()->size(); - return size == 1 || size == 2 || size == 4 || (include64bit && size == 8); + auto sz = size(t->toBasetype()); + return sz == 1 || sz == 2 || sz == 4 || (include64bit && sz == 8); } bool TargetABI::isExternD(TypeFunction *tf) { @@ -159,7 +159,7 @@ llvm::CallingConv::ID TargetABI::callingConv(FuncDeclaration *fdecl) { bool TargetABI::preferPassByRef(Type *t) { // simple base heuristic: use a ref for all types > 2 machine words - return t->size() > 2 * target.ptrsize; + return size(t) > 2 * target.ptrsize; } ////////////////////////////////////////////////////////////////////////////// diff --git a/gen/abi/arm.cpp b/gen/abi/arm.cpp index 21e8b3436fe..8821ff8a340 100644 --- a/gen/abi/arm.cpp +++ b/gen/abi/arm.cpp @@ -18,6 +18,8 @@ #include "gen/abi/generic.h" #include "llvm/Target/TargetMachine.h" +using namespace dmd; + struct ArmTargetABI : TargetABI { HFVAToArray hfvaToArray; CompositeToArray32 compositeToArray32; @@ -36,7 +38,7 @@ struct ArmTargetABI : TargetABI { return true; return rt->ty == TY::Tsarray || - (rt->ty == TY::Tstruct && rt->size() > 4 && + (rt->ty == TY::Tstruct && size(rt) > 4 && (gTargetMachine->Options.FloatABIType == llvm::FloatABI::Soft || !isHFVA(rt, hfvaToArray.maxElements))); } @@ -47,7 +49,7 @@ struct ArmTargetABI : TargetABI { // converts back to non-byval. Without this special handling the // optimzer generates bad code (e.g. std.random unittest crash). t = t->toBasetype(); - return ((t->ty == TY::Tsarray || t->ty == TY::Tstruct) && t->size() > 64); + return ((t->ty == TY::Tsarray || t->ty == TY::Tstruct) && size(t) > 64); // Note: byval can have a codegen problem with -O1 and higher. // What happens is that load instructions are being incorrectly diff --git a/gen/abi/generic.h b/gen/abi/generic.h index 02c664e525e..6f772e434c3 100644 --- a/gen/abi/generic.h +++ b/gen/abi/generic.h @@ -218,7 +218,7 @@ struct IntegerRewrite : BaseBitcastABIRewrite { return LLIntegerType::get(gIR->context(), size * 8); } - LLType *type(Type *t) override { return getIntegerType(t->size()); } + LLType *type(Type *t) override { return getIntegerType(dmd::size(t)); } }; ////////////////////////////////////////////////////////////////////////////// @@ -292,7 +292,7 @@ struct HFVAToArray : BaseBitcastABIRewrite { */ template struct CompositeToArray : BaseBitcastABIRewrite { LLType *type(Type *t) override { - size_t length = (t->size() + elementSize - 1) / elementSize; + size_t length = (dmd::size(t) + elementSize - 1) / elementSize; return LLArrayType::get(LLIntegerType::get(gIR->context(), elementSize * 8), length); } diff --git a/gen/abi/loongarch64.cpp b/gen/abi/loongarch64.cpp index 4141bd124f2..b27a7b89be8 100644 --- a/gen/abi/loongarch64.cpp +++ b/gen/abi/loongarch64.cpp @@ -64,7 +64,7 @@ FlattenedFields visitStructFields(Type *ty, unsigned baseOffset) { result.length = 2; break; default: - if (ty->size() > 8) { + if (size(ty) > 8) { // field larger than GRLEN and FRLEN result.length = -1; break; @@ -88,7 +88,7 @@ struct HardfloatRewrite : BaseBitcastABIRewrite { t[i] = flat.fields[i]->isfloating() ? DtoType(flat.fields[i]) - : LLIntegerType::get(gIR->context(), flat.fields[i]->size() * 8); + : LLIntegerType::get(gIR->context(), size(flat.fields[i]) * 8); } return LLStructType::get(gIR->context(), {t[0], t[1]}, false); } @@ -126,14 +126,14 @@ struct LoongArch64TargetABI : TargetABI { return true; } // pass by reference when > 2*GRLEN - return rt->size() > 16; + return size(rt) > 16; } auto passByVal(TypeFunction *, Type *t) -> bool override { if (!isPOD(t)) { return false; } - return t->size() > 16; + return size(t) > 16; } void rewriteFunctionType(IrFuncTy &fty) override { @@ -174,8 +174,8 @@ struct LoongArch64TargetABI : TargetABI { // return values should have the `signext` attribute. // C example: https://godbolt.org/z/vcjErxj76 arg.attrs.addAttribute(LLAttribute::SExt); - } else if (isAggregate(ty) && ty->size() && ty->size() <= 16) { - if (ty->size() > 8 && DtoAlignment(ty) < 16) { + } else if (isAggregate(ty) && size(ty) && size(ty) <= 16) { + if (size(ty) > 8 && DtoAlignment(ty) < 16) { // pass the aggregate as {int64, int64} to avoid wrong alignment integer2Rewrite.applyToIfNotObsolete(arg); } else { diff --git a/gen/abi/nvptx.cpp b/gen/abi/nvptx.cpp index c9978ec3549..7c4878aaea5 100644 --- a/gen/abi/nvptx.cpp +++ b/gen/abi/nvptx.cpp @@ -14,6 +14,8 @@ #include "gen/tollvm.h" #include "gen/dcompute/abi-rewrites.h" +using namespace dmd; + struct NVPTXTargetABI : TargetABI { DComputePointerRewrite pointerRewite; llvm::CallingConv::ID callingConv(LINK l) override { @@ -26,7 +28,7 @@ struct NVPTXTargetABI : TargetABI { } bool passByVal(TypeFunction *, Type *t) override { t = t->toBasetype(); - return ((t->ty == TY::Tsarray || t->ty == TY::Tstruct) && t->size() > 64); + return ((t->ty == TY::Tsarray || t->ty == TY::Tstruct) && size(t) > 64); } void rewriteFunctionType(IrFuncTy &fty) override { for (auto arg : fty.args) { diff --git a/gen/abi/ppc.cpp b/gen/abi/ppc.cpp index 34442ce9998..81b1c9ce1b6 100644 --- a/gen/abi/ppc.cpp +++ b/gen/abi/ppc.cpp @@ -26,6 +26,8 @@ #include "gen/llvmhelpers.h" #include "gen/tollvm.h" +using namespace dmd; + struct PPCTargetABI : TargetABI { CompositeToArray32 compositeToArray32; CompositeToArray64 compositeToArray64; @@ -54,7 +56,7 @@ struct PPCTargetABI : TargetABI { // used byval for type > 64 bytes. t = t->toBasetype(); return (t->ty == TY::Tsarray || t->ty == TY::Tstruct) && - (!Is64Bit || t->size() > 64); + (!Is64Bit || size(t) > 64); } void rewriteFunctionType(IrFuncTy &fty) override { diff --git a/gen/abi/ppc64le.cpp b/gen/abi/ppc64le.cpp index f644f827ede..129e1719bc3 100644 --- a/gen/abi/ppc64le.cpp +++ b/gen/abi/ppc64le.cpp @@ -20,6 +20,8 @@ #include "gen/llvmhelpers.h" #include "gen/tollvm.h" +using namespace dmd; + struct PPC64LETargetABI : TargetABI { HFVAToArray hfvaToArray; CompositeToArray64 compositeToArray64; @@ -42,7 +44,7 @@ struct PPC64LETargetABI : TargetABI { bool passByVal(TypeFunction *, Type *t) override { t = t->toBasetype(); - return t->ty == TY::Tsarray || (t->ty == TY::Tstruct && t->size() > 16 && + return t->ty == TY::Tsarray || (t->ty == TY::Tstruct && size(t) > 16 && !isHFVA(t, hfvaToArray.maxElements)); } diff --git a/gen/abi/riscv64.cpp b/gen/abi/riscv64.cpp index 7c36eb100cb..158bfaeba2f 100644 --- a/gen/abi/riscv64.cpp +++ b/gen/abi/riscv64.cpp @@ -73,7 +73,7 @@ FlattenedFields visitStructFields(Type *ty, unsigned baseOffset) { result.length = 2; break; default: - if (ty->toBasetype()->size() > 8) { + if (size(ty->toBasetype()) > 8) { // field larger than XLEN and FLEN result.length = -1; break; @@ -111,7 +111,7 @@ struct HardfloatRewrite : ABIRewrite { for (unsigned i = 0; i < (unsigned)flat.length; ++i) { DtoMemCpy(DtoGEP(asType, buffer, 0, i), DtoGEP1(getI8Type(), address, flat.fields[i].offset), - DtoConstSize_t(flat.fields[i].ty->size())); + DtoConstSize_t(size(flat.fields[i].ty))); } return DtoLoad(asType, buffer, ".HardfloatRewrite_arg"); } @@ -127,7 +127,7 @@ struct HardfloatRewrite : ABIRewrite { for (unsigned i = 0; i < (unsigned)flat.length; ++i) { DtoMemCpy(DtoGEP1(getI8Type(), ret, flat.fields[i].offset), DtoGEP(asType, buffer, 0, i), - DtoConstSize_t(flat.fields[i].ty->size())); + DtoConstSize_t(size(flat.fields[i].ty))); } return ret; } @@ -142,7 +142,7 @@ struct HardfloatRewrite : ABIRewrite { t[i] = flat.fields[i].ty->isfloating() ? DtoType(flat.fields[i].ty) : LLIntegerType::get(gIR->context(), - flat.fields[i].ty->size() * 8); + size(flat.fields[i].ty) * 8); } return LLStructType::get(gIR->context(), {t[0], t[1]}, false); } @@ -167,20 +167,20 @@ struct RISCV64TargetABI : TargetABI { return false; } Type *rt = tf->next->toBasetype(); - if (!rt->size()) + if (!size(rt)) return false; if (!isPOD(rt)) return true; - return rt->size() > 16; + return size(rt) > 16; } bool passByVal(TypeFunction *, Type *t) override { - if (!t->size()) + if (!size(t)) return false; if (t->toBasetype()->ty == TY::Tcomplex80) { // rewrite it later to bypass the RVal problem return false; } - return t->size() > 16; + return size(t) > 16; } void rewriteFunctionType(IrFuncTy &fty) override { if (!fty.ret->byref) { @@ -224,8 +224,8 @@ struct RISCV64TargetABI : TargetABI { return; } - if (isAggregate(ty) && ty->size() && ty->size() <= 16) { - if (ty->size() > 8 && DtoAlignment(ty) < 16) { + if (isAggregate(ty) && size(ty) && size(ty) <= 16) { + if (size(ty) > 8 && DtoAlignment(ty) < 16) { // pass the aggregate as {int64, int64} to avoid wrong alignment integer2Rewrite.applyToIfNotObsolete(arg); } else { diff --git a/gen/abi/spirv.cpp b/gen/abi/spirv.cpp index d944b6fd2db..1dd09f3cd8a 100644 --- a/gen/abi/spirv.cpp +++ b/gen/abi/spirv.cpp @@ -14,6 +14,8 @@ #include "gen/tollvm.h" #include "gen/dcompute/abi-rewrites.h" +using namespace dmd; + struct SPIRVTargetABI : TargetABI { DComputePointerRewrite pointerRewite; llvm::CallingConv::ID callingConv(LINK l) override { @@ -26,7 +28,7 @@ struct SPIRVTargetABI : TargetABI { } bool passByVal(TypeFunction *, Type *t) override { t = t->toBasetype(); - return ((t->ty == TY::Tsarray || t->ty == TY::Tstruct) && t->size() > 64); + return ((t->ty == TY::Tsarray || t->ty == TY::Tstruct) && size(t) > 64); } void rewriteFunctionType(IrFuncTy &fty) override { for (auto arg : fty.args) { diff --git a/gen/abi/x86-64.cpp b/gen/abi/x86-64.cpp index 253d0c2ab8c..1a49791df5a 100644 --- a/gen/abi/x86-64.cpp +++ b/gen/abi/x86-64.cpp @@ -216,7 +216,7 @@ bool X86_64TargetABI::returnInArg(TypeFunction *tf, bool) { // Prefer a ref if the POD cannot be passed in registers, i.e., if the LLVM // ByVal attribute would be applied, *and* the size is > 16. bool X86_64TargetABI::preferPassByRef(Type *t) { - return t->size() > 16 && passInMemory(t->toBasetype()); + return size(t) > 16 && passInMemory(t->toBasetype()); } bool X86_64TargetABI::passByVal(TypeFunction *tf, Type *t) { diff --git a/gen/abi/x86.cpp b/gen/abi/x86.cpp index 5965a7f38d2..cd9acbe76f2 100644 --- a/gen/abi/x86.cpp +++ b/gen/abi/x86.cpp @@ -20,6 +20,8 @@ #include "ir/irfunction.h" #include "ir/irfuncty.h" +using namespace dmd; + struct X86TargetABI : TargetABI { const bool isDarwin; const bool isMSVC; @@ -208,7 +210,7 @@ struct X86TargetABI : TargetABI { first.attrs.addAttribute(LLAttribute::InReg); } else { Type *firstTy = first.type->toBasetype(); - auto sz = firstTy->size(); + auto sz = size(firstTy); if (!firstTy->isfloating() && (sz == 1 || sz == 2 || sz == 4)) { // rewrite aggregates as integers to make inreg work if (firstTy->ty == TY::Tstruct || firstTy->ty == TY::Tsarray) { diff --git a/gen/arrays.cpp b/gen/arrays.cpp index 0f86908b4ea..dbc1acdba54 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -620,7 +620,7 @@ DSliceValue *DtoNewDynArray(const Loc &loc, Type *arrayType, DValue *dim, Type *eltType = arrayType->toBasetype()->nextOf(); - if (eltType->size() == 0) + if (size(eltType) == 0) return DtoNullValue(arrayType, loc)->isSlice(); // get runtime function @@ -970,8 +970,8 @@ DValue *DtoCastArray(const Loc &loc, DValue *u, Type *to) { ptr = DtoArrayPtr(u); } - const auto fsize = fromtype->nextOf()->size(); - const auto tsize = totype->nextOf()->size(); + const auto fsize = size(fromtype->nextOf()); + const auto tsize = size(totype->nextOf()); if (fsize != tsize) { if (auto constLength = isaConstantInt(length)) { // compute new constant length: (constLength * fsize) / tsize @@ -1004,7 +1004,7 @@ DValue *DtoCastArray(const Loc &loc, DValue *u, Type *to) { } else { size_t tosize = static_cast(totype)->dim->toInteger(); size_t i = - (tosize * totype->nextOf()->size() - 1) / fromtype->nextOf()->size(); + (tosize * size(totype->nextOf()) - 1) / size(fromtype->nextOf()); DConstValue index(Type::tsize_t, DtoConstSize_t(i)); DtoIndexBoundsCheck(loc, u, &index); ptr = DtoArrayPtr(u); diff --git a/gen/asm-x86.h b/gen/asm-x86.h index 2eb805a6d2e..db148f39ddc 100644 --- a/gen/asm-x86.h +++ b/gen/asm-x86.h @@ -3240,7 +3240,7 @@ struct AsmProcessor { (ty == TY::Tfloat80 || ty == TY::Timaginary80) && !global.params.targetTriple->isWindowsMSVCEnvironment() ? Extended_Ptr - : static_cast(v->type->size(Loc())); + : static_cast(dmd::size(v->type)); } if (!operand->symbolDisplacement.length) { diff --git a/gen/binops.cpp b/gen/binops.cpp index f4e4f344712..80064ecfd2f 100644 --- a/gen/binops.cpp +++ b/gen/binops.cpp @@ -19,6 +19,8 @@ #include "gen/logger.h" #include "gen/tollvm.h" +using namespace dmd; + ////////////////////////////////////////////////////////////////////////////// namespace { @@ -91,7 +93,7 @@ DValue *emitPointerOffset(Loc loc, DValue *base, Expression *offset, if (byteOffset == 0) { llResult = llBase; } else { - const auto pointeeSize = pointeeType->size(loc); + const auto pointeeSize = size(pointeeType, loc); if (pointeeSize && byteOffset % pointeeSize == 0) { // can do a nice GEP llOffset = DtoConstSize_t(byteOffset / pointeeSize); } else { // need to cast base to i8* @@ -101,7 +103,7 @@ DValue *emitPointerOffset(Loc loc, DValue *base, Expression *offset, } } else { Expression *noStrideInc = - extractNoStrideInc(offset, pointeeType->size(loc), negateOffset); + extractNoStrideInc(offset, size(pointeeType, loc), negateOffset); auto rvals = evalSides(base, noStrideInc ? noStrideInc : offset, loadLhsAfterRhs); llBase = DtoRVal(rvals.lhs); diff --git a/gen/complex.cpp b/gen/complex.cpp index 109087e90a0..af060af79df 100644 --- a/gen/complex.cpp +++ b/gen/complex.cpp @@ -20,6 +20,8 @@ #include "gen/logger.h" #include "gen/tollvm.h" +using namespace dmd; + //////////////////////////////////////////////////////////////////////////////// llvm::StructType *DtoComplexType(Type *type) { @@ -435,7 +437,7 @@ DValue *DtoCastComplex(const Loc &loc, DValue *val, Type *_to) { Type *to = _to->toBasetype(); Type *vty = val->type->toBasetype(); if (to->iscomplex()) { - if (vty->size() == to->size()) { + if (size(vty) == size(to)) { return val; } @@ -443,7 +445,7 @@ DValue *DtoCastComplex(const Loc &loc, DValue *val, Type *_to) { DtoGetComplexParts(loc, val->type, val, re, im); LLType *toty = DtoComplexBaseType(to); - if (to->size() < vty->size()) { + if (size(to) < size(vty)) { re = gIR->ir->CreateFPTrunc(re, toty); im = gIR->ir->CreateFPTrunc(im, toty); } else { diff --git a/gen/dcompute/targetOCL.cpp b/gen/dcompute/targetOCL.cpp index 0bc69a49430..e69aff40eab 100644 --- a/gen/dcompute/targetOCL.cpp +++ b/gen/dcompute/targetOCL.cpp @@ -39,6 +39,8 @@ "-v128:128:128-v192:256:256-v256:256:256" \ "-v512:512:512-v1024:1024:1024" +using namespace dmd; + namespace { class TargetOCL : public DComputeTarget { bool usedImage; @@ -157,7 +159,6 @@ class TargetOCL : public DComputeTarget { ss << "uchar"; else if (ty == TY::Tvector) { TypeVector *vec = static_cast(t); - auto size = vec->size(Loc()); auto basety = vec->basetype->ty; if (basety == TY::Tint8) ss << "char"; @@ -165,7 +166,7 @@ class TargetOCL : public DComputeTarget { ss << "uchar"; else ss << vec->basetype->toChars(); - ss << (int)size; + ss << (int)size(vec); } else ss << t->toChars(); return ss.str(); diff --git a/gen/functions.cpp b/gen/functions.cpp index 55174bb6acc..ad7fc21456b 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -198,7 +198,7 @@ llvm::FunctionType *DtoFunctionType(Type *type, IrFuncTy &irFty, Type *thistype, attrs.addAttribute(LLAttribute::NonNull); attrs.addAttribute(LLAttribute::NoUndef); } else { - attrs.addDereferenceableAttr(loweredDType->size()); + attrs.addDereferenceableAttr(size(loweredDType)); } } else { if (abi->passByVal(f, loweredDType)) { diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 85a1f7deead..0cc63e70b8f 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -500,8 +500,8 @@ DValue *DtoCastInt(const Loc &loc, DValue *val, Type *_to) { return new DImValue(_to, rval); } - size_t fromsz = from->size(); - size_t tosz = to->size(); + size_t fromsz = size(from); + size_t tosz = size(to); if (to->ty == TY::Tbool) { LLValue *zero = LLConstantInt::get(rval->getType(), 0, false); @@ -583,8 +583,8 @@ DValue *DtoCastFloat(const Loc &loc, DValue *val, Type *to) { Type *fromtype = val->type->toBasetype(); assert(fromtype->isfloating()); - size_t fromsz = fromtype->size(); - size_t tosz = totype->size(); + size_t fromsz = size(fromtype); + size_t tosz = size(totype); LLValue *rval; @@ -655,7 +655,7 @@ DValue *DtoCastVector(const Loc &loc, DValue *val, Type *to) { LLValue *array = DtoAllocaDump(vector, tolltype, DtoAlignment(val->type)); return new DLValue(to, array); } - if (totype->ty == TY::Tvector && to->size() == val->type->size()) { + if (totype->ty == TY::Tvector && size(to) == size(val->type)) { return new DImValue(to, DtoBitCast(DtoRVal(val), tolltype)); } error(loc, "invalid cast from `%s` to `%s`", val->type->toChars(), @@ -917,7 +917,7 @@ void DtoVarDeclaration(VarDeclaration *vd) { if (isRealAlloca) { // The lifetime of a stack variable starts from the point it is declared gIR->funcGen().localVariableLifetimeAnnotator.addLocalVariable( - allocainst, DtoConstUlong(type->size())); + allocainst, DtoConstUlong(size(type))); } } @@ -1145,9 +1145,9 @@ LLConstant *DtoConstExpInit(const Loc &loc, Type *targetType, Expression *exp) { if (baseTargetType->ty == TY::Tsarray) { Logger::println("Building constant array initializer from scalar."); - assert(baseValType->size() > 0); - const auto numTotalVals = baseTargetType->size() / baseValType->size(); - assert(baseTargetType->size() % baseValType->size() == 0); + assert(size(baseValType) > 0); + const auto numTotalVals = size(baseTargetType) / size(baseValType); + assert(size(baseTargetType) % size(baseValType) == 0); // may be a multi-dimensional array init, e.g., `char[2][3] x = 0xff` baseValType = stripModifiers(baseValType); diff --git a/gen/naked.cpp b/gen/naked.cpp index 2eb338b94f0..4d9ed26cc08 100644 --- a/gen/naked.cpp +++ b/gen/naked.cpp @@ -272,7 +272,7 @@ void emitABIReturnAsmStmt(IRAsmBlock *asmblock, const Loc &loc, if (triple.getArch() == llvm::Triple::x86) { if (rt->isintegral() || rt->ty == TY::Tpointer || rt->ty == TY::Tclass || rt->ty == TY::Taarray) { - if (rt->size() == 8) { + if (size(rt) == 8) { as->out.c = "=A,"; } else { as->out.c = "={ax},"; diff --git a/gen/target.cpp b/gen/target.cpp index 234d8f14f44..3b141fd1e96 100644 --- a/gen/target.cpp +++ b/gen/target.cpp @@ -340,3 +340,31 @@ bool Target::supportsLinkerDirective() const { return global.params.targetTriple->isWindowsMSVCEnvironment() || global.params.targetTriple->isOSBinFormatMachO(); } + +bool TargetC::contributesToAggregateAlignment(BitFieldDeclaration *bfd) { + if (bitFieldStyle == BitFieldStyle::MS) + return true; + + if (bitFieldStyle == BitFieldStyle::Gcc_Clang) { + // special case for most ARM ABIs: + // anonymous (incl. 0-length) bit-fields are NOT ignored + // (see e.g. https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst#1018bit-fields) + const auto &triple = *global.params.targetTriple; + switch (triple.getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: // TODO: correct? + return true; + + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + // Apple diverges + return !triple.isOSDarwin() || !bfd->isAnonymous(); + + default: + return !bfd->isAnonymous(); + } + } + + llvm_unreachable("Unsupported bit-field style"); +} diff --git a/gen/toconstelem.cpp b/gen/toconstelem.cpp index 1e7fb936d2d..c215d5769a9 100644 --- a/gen/toconstelem.cpp +++ b/gen/toconstelem.cpp @@ -199,7 +199,7 @@ class ToConstElemVisitor : public Visitor { const dinteger_t byteOffset = e->e2->toInteger(); LLConstant *llResult = nullptr; - const auto pointeeSize = pointeeType->size(e->loc); + const auto pointeeSize = size(pointeeType, e->loc); if (pointeeSize && byteOffset % pointeeSize == 0) { // can do a nice GEP LLConstant *llOffset = DtoConstSize_t(byteOffset / pointeeSize); if (negateOffset) @@ -286,11 +286,11 @@ class ToConstElemVisitor : public Visitor { StringExp *strexp = static_cast(e1); size_t datalen = strexp->sz * strexp->len; Type* eltype = tb->nextOf()->toBasetype(); - if (datalen % eltype->size() != 0) { + if (datalen % size(eltype) != 0) { error("the sizes don't line up"); return e1->toConstElem(p); } - size_t arrlen = datalen / eltype->size(); + size_t arrlen = datalen / size(eltype); #endif error( e->loc, diff --git a/gen/toir.cpp b/gen/toir.cpp index 3e5181a3917..be09d2a682b 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -97,7 +97,7 @@ static void write_struct_literal(Loc loc, LLValue *mem, StructDeclaration *sd, // Skip zero-sized fields such as zero-length static arrays: `ubyte[0] // data`. - if (field->type->size() == 0) + if (size(field->type) == 0) continue; // the initializer expression may be null for overridden overlapping fields diff --git a/gen/tollvm.cpp b/gen/tollvm.cpp index 90b6385d62d..656ea4f4654 100644 --- a/gen/tollvm.cpp +++ b/gen/tollvm.cpp @@ -58,7 +58,7 @@ bool DtoIsReturnInArg(CallExp *ce) { void DtoAddExtendAttr(Type *type, llvm::AttrBuilder &attrs) { type = type->toBasetype(); - if (type->isintegral() && type->ty != TY::Tvector && type->size() <= 2) { + if (type->isintegral() && type->ty != TY::Tvector && size(type) <= 2) { attrs.addAttribute(type->isunsigned() ? LLAttribute::ZExt : LLAttribute::SExt); } diff --git a/ir/iraggr.cpp b/ir/iraggr.cpp index 482dc027c0a..faca04f25c4 100644 --- a/ir/iraggr.cpp +++ b/ir/iraggr.cpp @@ -172,7 +172,7 @@ static llvm::Constant *FillSArrayDims(Type *arrTypeD, llvm::Constant *init) { // the size without doing an expensive recursive D <-> LLVM type comparison. // The better way to solve this would be to just fix the initializer // codegen in any place where a scalar initializer might still be generated. - if (gDataLayout->getTypeAllocSize(init->getType()) >= arrTypeD->size()) { + if (gDataLayout->getTypeAllocSize(init->getType()) >= size(arrTypeD)) { return init; } diff --git a/ir/irclass.cpp b/ir/irclass.cpp index 0db3d2039fa..064d59b9f4e 100644 --- a/ir/irclass.cpp +++ b/ir/irclass.cpp @@ -248,8 +248,8 @@ LLConstant *IrClass::getVtblInit() { if (fd2->isFuture()) { continue; } - if (FuncDeclaration::leastAsSpecialized(fd, fd2, nullptr) != MATCH::nomatch || - FuncDeclaration::leastAsSpecialized(fd2, fd, nullptr) != MATCH::nomatch) { + if (leastAsSpecialized(fd, fd2, nullptr) != MATCH::nomatch || + leastAsSpecialized(fd2, fd, nullptr) != MATCH::nomatch) { TypeFunction *tf = static_cast(fd->type); if (tf->ty == TY::Tfunction) { error(cd->loc, diff --git a/ir/irtypeaggr.cpp b/ir/irtypeaggr.cpp index 02745b38e17..500896b61a4 100644 --- a/ir/irtypeaggr.cpp +++ b/ir/irtypeaggr.cpp @@ -17,6 +17,8 @@ #include "gen/llvmhelpers.h" #include "llvm/IR/DerivedTypes.h" +using namespace dmd; + ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// @@ -101,7 +103,7 @@ void AggrTypeBuilder::addAggregate( bool haveExplicitInit = explicitInits && explicitInits->find(field) != explicitInits->end(); - uint64_t fieldSize = field->type->size(); + uint64_t fieldSize = size(field->type); const bool isBitField = field->isBitFieldDeclaration() != nullptr; if (isBitField) { diff --git a/packaging/dlang-tools_version b/packaging/dlang-tools_version index 8403edf4672..ea5f37a3b82 100644 --- a/packaging/dlang-tools_version +++ b/packaging/dlang-tools_version @@ -1 +1 @@ -v2.109.1 \ No newline at end of file +v2.110.0-beta.1 \ No newline at end of file diff --git a/packaging/dub_version b/packaging/dub_version index f49415ca625..394832d2878 100644 --- a/packaging/dub_version +++ b/packaging/dub_version @@ -1 +1 @@ -v1.38.0 \ No newline at end of file +v1.39.0-beta.1 \ No newline at end of file diff --git a/packaging/reggae_version b/packaging/reggae_version index 727cb92bf3b..5a886276a6f 100644 --- a/packaging/reggae_version +++ b/packaging/reggae_version @@ -1 +1 @@ -04de9e91182970543e6bd6ab6c8e7bb756ef3409 \ No newline at end of file +6bfbead1b82af50b620fb1caa6612c82bfc2ae7e \ No newline at end of file diff --git a/runtime/druntime/Makefile b/runtime/druntime/Makefile index 5aac2b73ef8..df9543950fc 100644 --- a/runtime/druntime/Makefile +++ b/runtime/druntime/Makefile @@ -375,10 +375,7 @@ $(abspath ../generated/$(OS)/$(BUILD)/$(MODEL)/dmd$(DOTEXE)): ../generated/$(OS) ################### C/ASM Targets ############################ OBJS:=$(ROOT)/errno_c$(DOTOBJ) -ifeq (32omf,$(MODEL)) - # minit.asm is only used for -m32omf on Windows; there's a pre-built minit.obj - OBJS+=src/rt/minit$(DOTOBJ) -else ifneq (windows,$(OS)) +ifneq (windows,$(OS)) OBJS+=$(ROOT)/threadasm$(DOTOBJ) $(ROOT)/valgrind$(DOTOBJ) endif @@ -434,12 +431,7 @@ endif .PHONY : unittest ifeq (1,$(BUILD_WAS_SPECIFIED)) -ifeq (32omf,$(MODEL)) -unittest : - @echo "Skipping druntime unittests because they cannot be linked on Win32 + OMF due to OPTLINK issues." -else unittest : $(UT_MODULES) $(addsuffix /.run,$(ADDITIONAL_TESTS)) -endif else unittest : unittest-debug unittest-release unittest-%: target @@ -504,6 +496,12 @@ test/%/.run: test/%/Makefile $(DMD) DRUNTIME=$(abspath $(DRUNTIME)) DRUNTIMESO=$(abspath $(DRUNTIMESO)) LINKDL=$(LINKDL) \ QUIET=$(QUIET) TIMELIMIT='$(TIMELIMIT)' PIC=$(PIC) SHARED=$(SHARED) +test/%/.clean: test/%/Makefile + $(QUIET)$(MAKE) -C test/$* MODEL=$(MODEL) OS=$(OS) BUILD=$(BUILD) clean +ifeq (0,$(BUILD_WAS_SPECIFIED)) + $(QUIET)$(MAKE) -C test/$* MODEL=$(MODEL) OS=$(OS) BUILD=debug clean +endif + #################### benchmark suite ########################## $(ROOT)/benchmark$(DOTEXE): benchmark/runbench.d target $(DMD) @@ -519,7 +517,7 @@ benchmark-compile-only: $(ROOT)/benchmark$(DOTEXE) $(DMD) MANIFEST = $(shell git ls-tree --name-only -r HEAD) CWS_MAKEFILES = $(filter mak/% %.mak %/Makefile,$(MANIFEST)) -NOT_MAKEFILES = $(filter-out $(CWS_MAKEFILES) src/rt/minit.obj test/%.exp,$(MANIFEST)) +NOT_MAKEFILES = $(filter-out $(CWS_MAKEFILES) test/%.exp,$(MANIFEST)) GREP = grep checkwhitespace: @@ -555,9 +553,6 @@ endif clean: $(addsuffix /.clean,$(ADDITIONAL_TESTS)) rm -rf $(ROOT_OF_THEM_ALL) $(IMPDIR) $(DOC_OUTPUT_DIR) druntime.zip -test/%/.clean: test/%/Makefile - $(MAKE) -C test/$* clean - %/.directory : mkdir -p $* || exists $* touch $@ diff --git a/runtime/druntime/src/core/checkedint.d b/runtime/druntime/src/core/checkedint.d index 1193b675d49..9970968f379 100644 --- a/runtime/druntime/src/core/checkedint.d +++ b/runtime/druntime/src/core/checkedint.d @@ -233,8 +233,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/runtime/druntime/src/core/demangle.d b/runtime/druntime/src/core/demangle.d index a920bb107e3..6b4b1f77b68 100644 --- a/runtime/druntime/src/core/demangle.d +++ b/runtime/druntime/src/core/demangle.d @@ -2874,56 +2874,6 @@ unittest assert(demangle(aggr.mangleof) == "pure nothrow @nogc @safe void " ~ parent ~ "().aggr(" ~ parent ~ "().S!(noreturn).S)"); } -/* - * Expand an OMF, DMD-generated compressed identifier into its full form - * - * This function only has a visible effect for OMF binaries (Win32), - * as compression is otherwise not used. - * - * See_Also: `compiler/src/dmd/backend/compress.d` - */ -string decodeDmdString( const(char)[] ln, ref size_t p ) nothrow pure @safe -{ - string s; - uint zlen, zpos; - - // decompress symbol - while ( p < ln.length ) - { - int ch = cast(ubyte) ln[p++]; - if ( (ch & 0xc0) == 0xc0 ) - { - zlen = (ch & 0x7) + 1; - zpos = ((ch >> 3) & 7) + 1; // + zlen; - if ( zpos > s.length ) - break; - s ~= s[$ - zpos .. $ - zpos + zlen]; - } - else if ( ch >= 0x80 ) - { - if ( p >= ln.length ) - break; - int ch2 = cast(ubyte) ln[p++]; - zlen = (ch2 & 0x7f) | ((ch & 0x38) << 4); - if ( p >= ln.length ) - break; - int ch3 = cast(ubyte) ln[p++]; - zpos = (ch3 & 0x7f) | ((ch & 7) << 7); - if ( zpos > s.length ) - break; - s ~= s[$ - zpos .. $ - zpos + zlen]; - } - else if ( Demangle!().isAlpha(cast(char)ch) || Demangle!().isDigit(cast(char)ch) || ch == '_' ) - s ~= cast(char) ch; - else - { - p--; - break; - } - } - return s; -} - // locally purified for internal use here only extern (C) private { diff --git a/runtime/druntime/src/core/internal/newaa.d b/runtime/druntime/src/core/internal/newaa.d index 2fd93651a22..7c858f33522 100644 --- a/runtime/druntime/src/core/internal/newaa.d +++ b/runtime/druntime/src/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/runtime/druntime/src/core/internal/parseoptions.d b/runtime/druntime/src/core/internal/parseoptions.d index ac0eb826b35..2dd3ec8375b 100644 --- a/runtime/druntime/src/core/internal/parseoptions.d +++ b/runtime/druntime/src/core/internal/parseoptions.d @@ -219,13 +219,12 @@ do return overflowedError(optname, str); i++; - break; } else // unexpected non-digit character { i = 0; - break; } + break; } } @@ -290,32 +289,8 @@ do assert(n > 4 && n < fmt.length); int nscanned; - version (CRuntime_DigitalMars) - { - /* Older sscanf's in snn.lib can write to its first argument, causing a crash - * if the string is in readonly memory. Recent updates to DMD - * https://github.com/dlang/dmd/pull/6546 - * put string literals in readonly memory. - * Although sscanf has been fixed, - * http://ftp.digitalmars.com/snn.lib - * this workaround is here so it still works with the older snn.lib. - */ - // Create mutable copy of str - const length = str.length; - char* mptr = cast(char*)malloc(length + 1); - assert(mptr); - memcpy(mptr, str.ptr, length); - mptr[length] = 0; - const result = sscanf(mptr, fmt.ptr, &res, &nscanned); - free(mptr); - if (result < 1) - return parseError("a float", optname, str, errName); - } - else - { - if (sscanf(str.ptr, fmt.ptr, &res, &nscanned) < 1) - return parseError("a float", optname, str, errName); - } + if (sscanf(str.ptr, fmt.ptr, &res, &nscanned) < 1) + return parseError("a float", optname, str, errName); str = str[nscanned .. $]; return true; } diff --git a/runtime/druntime/src/core/internal/traits.d b/runtime/druntime/src/core/internal/traits.d index 0b2eb1f21a7..f0d9ebc9a81 100644 --- a/runtime/druntime/src/core/internal/traits.d +++ b/runtime/druntime/src/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/runtime/druntime/src/core/lifetime.d b/runtime/druntime/src/core/lifetime.d index 9e563ad43a3..f3dab3624ac 100644 --- a/runtime/druntime/src/core/lifetime.d +++ b/runtime/druntime/src/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/runtime/druntime/src/core/runtime.d b/runtime/druntime/src/core/runtime.d index 8ece9d26133..2a5e980b08b 100644 --- a/runtime/druntime/src/core/runtime.d +++ b/runtime/druntime/src/core/runtime.d @@ -576,7 +576,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 ); @@ -997,7 +997,7 @@ version (Posix) private class DefaultTraceInfo : Throwable.TraceInfo private: int numframes; - static enum MAXFRAMES = 128; + enum MAXFRAMES = 128; void*[MAXFRAMES] callstack = void; private: diff --git a/runtime/druntime/src/core/stdc/assert_.d b/runtime/druntime/src/core/stdc/assert_.d index c6d9d9f6cc2..ac237d9c897 100644 --- a/runtime/druntime/src/core/stdc/assert_.d +++ b/runtime/druntime/src/core/stdc/assert_.d @@ -30,14 +30,7 @@ extern (C): nothrow: @nogc: -version (CRuntime_DigitalMars) -{ - /*** - * Assert failure function in the Digital Mars C library. - */ - noreturn _assert(const(void)* exp, const(void)* file, uint line); -} -else version (CRuntime_Microsoft) +version (CRuntime_Microsoft) { /*** * Assert failure function in the Microsoft C library. diff --git a/runtime/druntime/src/core/stdc/errno.d b/runtime/druntime/src/core/stdc/errno.d index ddec70f7af3..0430e6b33e9 100644 --- a/runtime/druntime/src/core/stdc/errno.d +++ b/runtime/druntime/src/core/stdc/errno.d @@ -43,15 +43,7 @@ version (X86_64) version = X86_Any; nothrow: @nogc: -version (CRuntime_DigitalMars) -{ - extern (C) - { - ref int _errno(); - alias errno = _errno; - } -} -else version (CRuntime_Microsoft) +version (CRuntime_Microsoft) { extern (C) { @@ -172,93 +164,7 @@ else extern (C): -version (CRuntime_DigitalMars) -{ - enum EPERM = 1; /// Operation not permitted - enum ENOENT = 2; /// No such file or directory - enum ESRCH = 3; /// No such process - enum EINTR = 4; /// Interrupted system call - enum EIO = 5; /// I/O error - enum ENXIO = 6; /// No such device or address - enum E2BIG = 7; /// Argument list too long - enum ENOEXEC = 8; /// Exec format error - enum EBADF = 9; /// Bad file number - enum ECHILD = 10; /// No child processes - enum EAGAIN = 11; /// Try again - enum ENOMEM = 12; /// Out of memory - enum EACCES = 13; /// Permission denied - enum EFAULT = 14; /// Bad address - enum EBUSY = 16; /// Device or resource busy - enum EEXIST = 17; /// File exists - enum EXDEV = 18; /// Cross-device link - enum ENODEV = 19; /// No such device - enum ENOTDIR = 20; /// Not a directory - enum EISDIR = 21; /// Is a directory - enum EINVAL = 22; /// Invalid argument - enum ENFILE = 23; /// File table overflow - enum EMFILE = 24; /// Too many open files - enum ENOTTY = 25; /// Not a typewriter - enum EFBIG = 27; /// File too large - enum ENOSPC = 28; /// No space left on device - enum ESPIPE = 29; /// Illegal seek - enum EROFS = 30; /// Read-only file system - enum EMLINK = 31; /// Too many links - enum EPIPE = 32; /// Broken pipe - enum EDOM = 33; /// Math argument out of domain of func - enum ERANGE = 34; /// Math result not representable - enum EDEADLK = 36; /// Resource deadlock would occur - enum ENAMETOOLONG = 38; /// File name too long - enum ENOLCK = 39; /// No record locks available - enum ENOSYS = 40; /// Function not implemented - enum ENOTEMPTY = 41; /// Directory not empty - enum EILSEQ = 42; /// Illegal byte sequence - enum EDEADLOCK = EDEADLK; /// Resource deadlock would occur - - // POSIX compatibility - // See_Also: https://docs.microsoft.com/en-us/cpp/c-runtime-library/errno-constants - enum EADDRINUSE = 100; - enum EADDRNOTAVAIL = 101; - enum EAFNOSUPPORT = 102; - enum EALREADY = 103; - enum EBADMSG = 104; - enum ECANCELED = 105; - enum ECONNABORTED = 106; - enum ECONNREFUSED = 107; - enum ECONNRESET = 108; - enum EDESTADDRREQ = 109; - enum EHOSTUNREACH = 110; - enum EIDRM = 111; - enum EINPROGRESS = 112; - enum EISCONN = 113; - enum ELOOP = 114; - enum EMSGSIZE = 115; - enum ENETDOWN = 116; - enum ENETRESET = 117; - enum ENETUNREACH = 118; - enum ENOBUFS = 119; - enum ENODATA = 120; - enum ENOLINK = 121; - enum ENOMSG = 122; - enum ENOPROTOOPT = 123; - enum ENOSR = 124; - enum ENOSTR = 125; - enum ENOTCONN = 126; - enum ENOTRECOVERABLE = 127; - enum ENOTSOCK = 128; - enum ENOTSUP = 129; - enum EOPNOTSUPP = 130; - enum EOTHER = 131; - enum EOVERFLOW = 132; - enum EOWNERDEAD = 133; - enum EPROTO = 134; - enum EPROTONOSUPPORT = 135; - enum EPROTOTYPE = 136; - enum ETIME = 137; - enum ETIMEDOUT = 138; - enum ETXTBSY = 139; - enum EWOULDBLOCK = 140; -} -else version (CRuntime_Microsoft) +version (CRuntime_Microsoft) { enum EPERM = 1; /// Operation not permitted enum ENOENT = 2; /// No such file or directory diff --git a/runtime/druntime/src/core/stdc/fenv.d b/runtime/druntime/src/core/stdc/fenv.d index a7364c0a211..6cd75f3a791 100644 --- a/runtime/druntime/src/core/stdc/fenv.d +++ b/runtime/druntime/src/core/stdc/fenv.d @@ -180,17 +180,6 @@ version (GNUFP) static assert(0, "Unimplemented architecture"); } } -else version (CRuntime_DigitalMars) -{ - struct fenv_t - { - ushort status; - ushort control; - ushort round; - ushort[2] reserved; - } - alias fexcept_t = int; -} else version (CRuntime_Microsoft) { struct fenv_t @@ -872,12 +861,6 @@ version (GNUFP) /// enum FE_DFL_ENV = cast(fenv_t*)(-1); } -else version (CRuntime_DigitalMars) -{ - private extern __gshared fenv_t _FE_DFL_ENV; - /// - enum fenv_t* FE_DFL_ENV = &_FE_DFL_ENV; -} else version (CRuntime_Microsoft) { private extern __gshared fenv_t _Fenv0; diff --git a/runtime/druntime/src/core/stdc/math.d b/runtime/druntime/src/core/stdc/math.d index c5eaf79a827..e54d5813995 100644 --- a/runtime/druntime/src/core/stdc/math.d +++ b/runtime/druntime/src/core/stdc/math.d @@ -284,102 +284,7 @@ version (none) pure int isunordered(real x, real y); } -version (CRuntime_DigitalMars) -{ - enum - { - /// - FP_NANS = 0, - /// - FP_NANQ = 1, - /// - FP_INFINITE = 2, - /// - FP_NORMAL = 3, - /// - FP_SUBNORMAL = 4, - /// - FP_ZERO = 5, - /// - FP_NAN = FP_NANQ, - /// - FP_EMPTY = 6, - /// - FP_UNSUPPORTED = 7, - } - - enum - { - /// - FP_FAST_FMA = 0, - /// - FP_FAST_FMAF = 0, - /// - FP_FAST_FMAL = 0, - } - - pure uint __fpclassify_f(float x); - pure uint __fpclassify_d(double x); - pure uint __fpclassify_ld(real x); - - //int fpclassify(real-floating x); - /// - pragma(mangle, "__fpclassify_f") pure int fpclassify(float x); - /// - pragma(mangle, "__fpclassify_d") pure int fpclassify(double x); - /// - pragma(mangle, real.sizeof == double.sizeof ? "__fpclassify_d" : "__fpclassify_ld") - pure int fpclassify(real x); - - extern (D) - { - //int isfinite(real-floating x); - /// - pure int isfinite(float x) { return fpclassify(x) >= FP_NORMAL; } - /// - pure int isfinite(double x) { return fpclassify(x) >= FP_NORMAL; } - /// - pure int isfinite(real x) { return fpclassify(x) >= FP_NORMAL; } - - //int isinf(real-floating x); - /// - pure int isinf(float x) { return fpclassify(x) == FP_INFINITE; } - /// - pure int isinf(double x) { return fpclassify(x) == FP_INFINITE; } - /// - pure int isinf(real x) { return fpclassify(x) == FP_INFINITE; } - - //int isnan(real-floating x); - /// - pure int isnan(float x) { return fpclassify(x) <= FP_NANQ; } - /// - pure int isnan(double x) { return fpclassify(x) <= FP_NANQ; } - /// - pure int isnan(real x) { return fpclassify(x) <= FP_NANQ; } - - //int isnormal(real-floating x); - /// - pure int isnormal(float x) { return fpclassify(x) == FP_NORMAL; } - /// - pure int isnormal(double x) { return fpclassify(x) == FP_NORMAL; } - /// - pure int isnormal(real x) { return fpclassify(x) == FP_NORMAL; } - - //int signbit(real-floating x); - /// - pure int signbit(float x) { return (cast(short*)&(x))[1] & 0x8000; } - /// - pure int signbit(double x) { return (cast(short*)&(x))[3] & 0x8000; } - /// - pure int signbit(real x) - { - return (real.sizeof == double.sizeof) - ? (cast(short*)&(x))[3] & 0x8000 - : (cast(short*)&(x))[4] & 0x8000; - } - } -} -else version (CRuntime_Microsoft) // fully supported since MSVCRT 12 (VS 2013) only +version (CRuntime_Microsoft) // fully supported since MSVCRT 12 (VS 2013) only { version (all) // legacy stuff to be removed in the future { diff --git a/runtime/druntime/src/core/stdc/stdint.d b/runtime/druntime/src/core/stdc/stdint.d index 476c42f08ee..1776269378f 100644 --- a/runtime/druntime/src/core/stdc/stdint.d +++ b/runtime/druntime/src/core/stdc/stdint.d @@ -49,16 +49,8 @@ version (Windows) alias int16_t = short; /// alias uint8_t = ubyte; /// alias uint16_t = ushort; /// - version (CRuntime_DigitalMars) - { - alias int32_t = cpp_long; /// - alias uint32_t = cpp_ulong; /// - } - else - { - alias int32_t = int; /// - alias uint32_t = uint; /// - } + alias int32_t = int; /// + alias uint32_t = uint; /// alias int64_t = long; /// alias uint64_t = ulong; /// diff --git a/runtime/druntime/src/core/stdc/stdio.d b/runtime/druntime/src/core/stdc/stdio.d index 1fc046163ee..8afb68f8585 100644 --- a/runtime/druntime/src/core/stdc/stdio.d +++ b/runtime/druntime/src/core/stdc/stdio.d @@ -52,34 +52,7 @@ extern (C): nothrow: @nogc: -version (CRuntime_DigitalMars) -{ - enum - { - /// - BUFSIZ = 0x4000, - /// - EOF = -1, - /// - FOPEN_MAX = 20, - /// - FILENAME_MAX = 256, // 255 plus NULL - /// - TMP_MAX = 32767, - /// - SYS_OPEN = 20, // non-standard - } - - /// - enum int _NFILE = 60; // non-standard - /// - enum string _P_tmpdir = "\\"; // non-standard - /// - enum wstring _wP_tmpdir = "\\"; // non-standard - /// - enum int L_tmpnam = _P_tmpdir.length + 12; -} -else version (CRuntime_Microsoft) +version (CRuntime_Microsoft) { enum { @@ -403,28 +376,7 @@ enum SEEK_END } -version (CRuntime_DigitalMars) -{ - /// - alias c_long fpos_t; - - /// - struct _iobuf - { - char* _ptr; - int _cnt; - char* _base; - int _flag; - int _file; - int _charbuf; - int _bufsiz; - char* __tmpnum; - } - - /// - alias shared(_iobuf) FILE; -} -else version (CRuntime_Microsoft) +version (CRuntime_Microsoft) { /// alias long fpos_t; @@ -926,52 +878,7 @@ enum _F_TERM = 0x0200, // non-standard } -version (CRuntime_DigitalMars) -{ - enum - { - /// - _IOFBF = 0, - /// - _IOLBF = 0x40, - /// - _IONBF = 4, - /// - _IOREAD = 1, // non-standard - /// - _IOWRT = 2, // non-standard - /// - _IOMYBUF = 8, // non-standard - /// - _IOEOF = 0x10, // non-standard - /// - _IOERR = 0x20, // non-standard - /// - _IOSTRG = 0x40, // non-standard - /// - _IORW = 0x80, // non-standard - /// - _IOTRAN = 0x100, // non-standard - /// - _IOAPP = 0x200, // non-standard - } - - extern shared void function() _fcloseallp; - - private extern shared FILE[_NFILE] _iob; - - /// - enum stdin = &_iob[0]; - /// - enum stdout = &_iob[1]; - /// - enum stderr = &_iob[2]; - /// - enum stdaux = &_iob[3]; - /// - enum stdprn = &_iob[4]; -} -else version (CRuntime_Microsoft) +version (CRuntime_Microsoft) { enum { @@ -1539,55 +1446,7 @@ size_t fwrite(scope const void* ptr, size_t size, size_t nmemb, FILE* stream); c_long ftell(FILE* stream); } -version (CRuntime_DigitalMars) -{ - // No unsafe pointer manipulation. - extern (D) @trusted - { - /// - void rewind()(FILE* stream) { fseek(stream,0L,SEEK_SET); stream._flag= stream._flag & ~_IOERR; } - /// - pure void clearerr()(FILE* stream) { stream._flag = stream._flag & ~(_IOERR|_IOEOF); } - /// - pure int feof()(FILE* stream) { return stream._flag&_IOEOF; } - /// - pure int ferror()(FILE* stream) { return stream._flag&_IOERR; } - /// - pure int fileno()(FILE* stream) { return stream._file; } - } - /// - pragma(printf) - int _snprintf(scope char* s, size_t n, scope const char* fmt, scope const ...); - /// - alias _snprintf snprintf; - - /// - pragma(printf) - int _vsnprintf(scope char* s, size_t n, scope const char* format, va_list arg); - /// - alias _vsnprintf vsnprintf; - - // - // Digital Mars under-the-hood C I/O functions. Uses _iobuf* for the - // unshared version of FILE*, usable when the FILE is locked. - // - - /// - int _fputc_nlock(int c, _iobuf* fp); - /// - int _fputwc_nlock(int c, _iobuf* fp); - /// - int _fgetc_nlock(_iobuf* fp); - /// - int _fgetwc_nlock(_iobuf* fp); - /// - int __fp_lock(FILE* fp); - /// - void __fp_unlock(FILE* fp); - /// - int setmode(int fd, int mode); -} -else version (CRuntime_Microsoft) +version (CRuntime_Microsoft) { // No unsafe pointer manipulation. @trusted @@ -2073,130 +1932,7 @@ else /// void perror(scope const char* s); -version (CRuntime_DigitalMars) -{ - version (none) - import core.sys.windows.windows : HANDLE, _WaitSemaphore, _ReleaseSemaphore; - else - { - // too slow to import windows - private alias void* HANDLE; - private void _WaitSemaphore(int iSemaphore); - private void _ReleaseSemaphore(int iSemaphore); - } - - enum - { - /// - FHND_APPEND = 0x04, - /// - FHND_DEVICE = 0x08, - /// - FHND_TEXT = 0x10, - /// - FHND_BYTE = 0x20, - /// - FHND_WCHAR = 0x40, - } - - private enum _MAX_SEMAPHORES = 10 + _NFILE; - private enum _semIO = 3; - - private extern __gshared short[_MAX_SEMAPHORES] _iSemLockCtrs; - private extern __gshared int[_MAX_SEMAPHORES] _iSemThreadIds; - private extern __gshared int[_MAX_SEMAPHORES] _iSemNestCount; - private extern __gshared HANDLE[_NFILE] _osfhnd; - extern shared ubyte[_NFILE] __fhnd_info; - - // this is copied from semlock.h in DMC's runtime. - private void LockSemaphore()(uint num) - { - asm nothrow @nogc - { - mov EDX, num; - lock; - inc _iSemLockCtrs[EDX * 2]; - jz lsDone; - push EDX; - call _WaitSemaphore; - add ESP, 4; - } - - lsDone: {} - } - - // this is copied from semlock.h in DMC's runtime. - private void UnlockSemaphore()(uint num) - { - asm nothrow @nogc - { - mov EDX, num; - lock; - dec _iSemLockCtrs[EDX * 2]; - js usDone; - push EDX; - call _ReleaseSemaphore; - add ESP, 4; - } - - usDone: {} - } - - // This converts a HANDLE to a file descriptor in DMC's runtime - /// - int _handleToFD()(HANDLE h, int flags) - { - LockSemaphore(_semIO); - scope(exit) UnlockSemaphore(_semIO); - - foreach (fd; 0 .. _NFILE) - { - if (!_osfhnd[fd]) - { - _osfhnd[fd] = h; - __fhnd_info[fd] = cast(ubyte)flags; - return fd; - } - } - - return -1; - } - - /// - HANDLE _fdToHandle()(int fd) - { - // no semaphore is required, once inserted, a file descriptor - // doesn't change. - if (fd < 0 || fd >= _NFILE) - return null; - - return _osfhnd[fd]; - } - - enum - { - /// - STDIN_FILENO = 0, - /// - STDOUT_FILENO = 1, - /// - STDERR_FILENO = 2, - } - - int open(scope const(char)* filename, int flags, ...); /// - alias _open = open; /// - int _wopen(scope const wchar* filename, int oflag, ...); /// - int sopen(scope const char* filename, int oflag, int shflag, ...); /// - alias _sopen = sopen; /// - int _wsopen(scope const wchar* filename, int oflag, int shflag, ...); /// - int close(int fd); /// - alias _close = close; /// - FILE *fdopen(int fd, scope const(char)* flags); /// - alias _fdopen = fdopen; /// - FILE *_wfdopen(int fd, scope const(wchar)* flags); /// - -} -else version (CRuntime_Microsoft) +version (CRuntime_Microsoft) { int _open(scope const char* filename, int oflag, ...); /// int _wopen(scope const wchar* filename, int oflag, ...); /// diff --git a/runtime/druntime/src/core/stdcpp/allocator.d b/runtime/druntime/src/core/stdcpp/allocator.d index 67b3ac657eb..f9e84688a30 100644 --- a/runtime/druntime/src/core/stdcpp/allocator.d +++ b/runtime/druntime/src/core/stdcpp/allocator.d @@ -12,9 +12,9 @@ module core.stdcpp.allocator; // LDC: empty module for unsupported C++ runtimes -version (CppRuntime_Microsoft) version = Supported; -else version (CppRuntime_Gcc) version = Supported; -else version (CppRuntime_Clang) version = Supported; +version (CppRuntime_Microsoft) version = Supported; +else version (CppRuntime_GNU) version = Supported; +else version (CppRuntime_LLVM) version = Supported; version (Supported): import core.stdcpp.new_; @@ -153,7 +153,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 @@ -180,7 +180,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 @@ -366,7 +366,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/runtime/druntime/src/core/stdcpp/array.d b/runtime/druntime/src/core/stdcpp/array.d index c96fb5d4ca9..f9241c40a27 100644 --- a/runtime/druntime/src/core/stdcpp/array.d +++ b/runtime/druntime/src/core/stdcpp/array.d @@ -12,24 +12,13 @@ module core.stdcpp.array; // LDC: empty module for unsupported C++ runtimes -version (CppRuntime_Microsoft) version = Supported; -else version (CppRuntime_Gcc) version = Supported; -else version (CppRuntime_Clang) version = Supported; +version (CppRuntime_Microsoft) version = Supported; +else version (CppRuntime_GNU) version = Supported; +else version (CppRuntime_LLVM) version = Supported; version (Supported): import core.stdcpp.xutility : StdNamespace; -// hacks to support DMD on Win32 -version (CppRuntime_Microsoft) -{ - version = CppRuntime_Windows; // use the MS runtime ABI for win32 -} -else version (CppRuntime_DigitalMars) -{ - version = CppRuntime_Windows; // use the MS runtime ABI for win32 - pragma(msg, "std::array not supported by DMC"); -} - extern(C++, (StdNamespace)): /** @@ -79,7 +68,7 @@ pure nothrow @nogc: /// ref inout(T) back() inout @safe { static if (N > 0) { return this[N-1]; } else { return as_array()[][0]; /* HACK: force OOB */ } } - version (CppRuntime_Windows) + version (CppRuntime_Microsoft) { /// inout(T)* data() inout @safe { return &_Elems[0]; } @@ -91,7 +80,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; } } @@ -111,7 +100,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/runtime/druntime/src/core/stdcpp/exception.d b/runtime/druntime/src/core/stdcpp/exception.d index e5d159fcbb8..edcf403f0cc 100644 --- a/runtime/druntime/src/core/stdcpp/exception.d +++ b/runtime/druntime/src/core/stdcpp/exception.d @@ -13,17 +13,17 @@ module core.stdcpp.exception; // LDC: empty module for unsupported C++ runtimes -version (CppRuntime_Microsoft) version = Supported; -else version (CppRuntime_Gcc) version = Supported; -else version (CppRuntime_Clang) version = Supported; +version (CppRuntime_Microsoft) version = Supported; +else version (CppRuntime_GNU) version = Supported; +else version (CppRuntime_LLVM) version = Supported; version (Supported): 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; @@ -86,24 +86,6 @@ version (GenericBaseException) extern(D) this(const(char)*, int = 1) nothrow { this(); } // compat with MS derived classes } } -else version (CppRuntime_DigitalMars) -{ - /// - class exception - { - @nogc: - /// - extern(D) this() nothrow {} - //virtual ~this(); - void dtor() { } // reserve slot in vtbl[] - - /// - const(char)* what() const nothrow; - - protected: - this(const(char)*, int = 1) nothrow { this(); } // compat with MS derived classes - } -} else version (CppRuntime_Microsoft) { /// diff --git a/runtime/druntime/src/core/stdcpp/memory.d b/runtime/druntime/src/core/stdcpp/memory.d index 982f2ba600c..7f52fd9e19f 100644 --- a/runtime/druntime/src/core/stdcpp/memory.d +++ b/runtime/druntime/src/core/stdcpp/memory.d @@ -12,9 +12,9 @@ module core.stdcpp.memory; // LDC: empty module for unsupported C++ runtimes -version (CppRuntime_Microsoft) version = Supported; -else version (CppRuntime_Gcc) version = Supported; -else version (CppRuntime_Clang) version = Supported; +version (CppRuntime_Microsoft) version = Supported; +else version (CppRuntime_GNU) version = Supported; +else version (CppRuntime_LLVM) version = Supported; version (Supported): public import core.stdcpp.allocator; @@ -129,7 +129,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; } @@ -142,7 +142,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/runtime/druntime/src/core/stdcpp/new_.d b/runtime/druntime/src/core/stdcpp/new_.d index 929f3726995..0507c005db3 100644 --- a/runtime/druntime/src/core/stdcpp/new_.d +++ b/runtime/druntime/src/core/stdcpp/new_.d @@ -12,9 +12,9 @@ module core.stdcpp.new_; // LDC: empty module for unsupported C++ runtimes -version (CppRuntime_Microsoft) version = Supported; -else version (CppRuntime_Gcc) version = Supported; -else version (CppRuntime_Clang) version = Supported; +version (CppRuntime_Microsoft) version = Supported; +else version (CppRuntime_GNU) version = Supported; +else version (CppRuntime_LLVM) version = Supported; version (Supported): import core.stdcpp.xutility : __cpp_sized_deallocation, __cpp_aligned_new; diff --git a/runtime/druntime/src/core/stdcpp/string.d b/runtime/druntime/src/core/stdcpp/string.d index 9260328e5f8..a41ce3e8978 100644 --- a/runtime/druntime/src/core/stdcpp/string.d +++ b/runtime/druntime/src/core/stdcpp/string.d @@ -13,9 +13,9 @@ module core.stdcpp.string; // LDC: empty module for unsupported C++ runtimes -version (CppRuntime_Microsoft) version = Supported; -else version (CppRuntime_Gcc) version = Supported; -else version (CppRuntime_Clang) version = Supported; +version (CppRuntime_Microsoft) version = Supported; +else version (CppRuntime_GNU) version = Supported; +else version (CppRuntime_LLVM) version = Supported; version (Supported): import core.stdcpp.allocator; @@ -37,7 +37,7 @@ version (Darwin) version = _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT; } -version (CppRuntime_Gcc) +version (CppRuntime_GNU) { version (_GLIBCXX_USE_CXX98_ABI) { @@ -900,7 +900,7 @@ extern(D): _String_alloc!(_String_base_types!(T, Alloc)) _Base; } - else version (CppRuntime_Gcc) + else version (CppRuntime_GNU) { version (_GLIBCXX_USE_CXX98_ABI) { @@ -1879,10 +1879,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/runtime/druntime/src/core/stdcpp/string_view.d b/runtime/druntime/src/core/stdcpp/string_view.d index 7c2cf06f4a9..7aa0ec19f3d 100644 --- a/runtime/druntime/src/core/stdcpp/string_view.d +++ b/runtime/druntime/src/core/stdcpp/string_view.d @@ -12,25 +12,14 @@ module core.stdcpp.string_view; // LDC: empty module for unsupported C++ runtimes -version (CppRuntime_Microsoft) version = Supported; -else version (CppRuntime_Gcc) version = Supported; -else version (CppRuntime_Clang) version = Supported; +version (CppRuntime_Microsoft) version = Supported; +else version (CppRuntime_GNU) version = Supported; +else version (CppRuntime_LLVM) version = Supported; version (Supported): import core.stdc.stddef : wchar_t; import core.stdcpp.xutility : StdNamespace; -// hacks to support DMD on Win32 -version (CppRuntime_Microsoft) -{ - version = CppRuntime_Windows; // use the MS runtime ABI for win32 -} -else version (CppRuntime_DigitalMars) -{ - version = CppRuntime_Windows; // use the MS runtime ABI for win32 - pragma(msg, "std::basic_string_view not supported by DMC"); -} - extern(C++, (StdNamespace)): @nogc: @@ -108,7 +97,7 @@ pure nothrow @nogc: private: // use the proper field names from C++ so debugging doesn't get weird - version (CppRuntime_Windows) + version (CppRuntime_Microsoft) { const_pointer _Mydata; size_type _Mysize; @@ -116,7 +105,7 @@ private: alias __data = _Mydata; alias __size = _Mysize; } - else version (CppRuntime_Gcc) + else version (CppRuntime_GNU) { size_t _M_len; const(T)* _M_str; @@ -124,7 +113,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/runtime/druntime/src/core/stdcpp/typeinfo.d b/runtime/druntime/src/core/stdcpp/typeinfo.d index 80c9d6f502b..39d08cf934c 100644 --- a/runtime/druntime/src/core/stdcpp/typeinfo.d +++ b/runtime/druntime/src/core/stdcpp/typeinfo.d @@ -13,53 +13,7 @@ module core.stdcpp.typeinfo; import core.attribute : weak; -version (CppRuntime_DigitalMars) -{ - import core.stdcpp.exception; - - extern (C++, "std"): - - class type_info - { - @nogc: - void* pdata; - - public: - //virtual ~this(); - void dtor() { } // reserve slot in vtbl[] - - //bool operator==(const type_info rhs) const; - //bool operator!=(const type_info rhs) const; - final bool before(const type_info rhs) const nothrow; - final const(char)* name() const nothrow; - protected: - //type_info(); - private: - //this(const type_info rhs); - //type_info operator=(const type_info rhs); - } - - class bad_cast : exception - { - @nogc: - extern(D) this() nothrow { } - extern(D) this(const bad_cast) nothrow { } - //bad_cast operator=(const bad_cast) nothrow { return this; } - //virtual ~this() nothrow; - override const(char)* what() const nothrow; - } - - class bad_typeid : exception - { - @nogc: - extern(D) this() nothrow { } - extern(D) this(const bad_typeid) nothrow { } - //bad_typeid operator=(const bad_typeid) nothrow { return this; } - //virtual ~this() nothrow; - override const (char)* what() const nothrow; - } -} -else version (CppRuntime_Microsoft) +version (CppRuntime_Microsoft) { import core.stdcpp.exception; @@ -102,7 +56,7 @@ else version (CppRuntime_Microsoft) //virtual ~this(); } } -else version (CppRuntime_Gcc) +else version (CppRuntime_GNU) { import core.stdcpp.exception; @@ -156,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/runtime/druntime/src/core/stdcpp/xutility.d b/runtime/druntime/src/core/stdcpp/xutility.d index 0142d0b9455..5e2e711ba67 100644 --- a/runtime/druntime/src/core/stdcpp/xutility.d +++ b/runtime/druntime/src/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/runtime/druntime/src/core/sys/posix/dirent.d b/runtime/druntime/src/core/sys/posix/dirent.d index c7e8649d6c5..cb76573a95b 100644 --- a/runtime/druntime/src/core/sys/posix/dirent.d +++ b/runtime/druntime/src/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/runtime/druntime/src/core/sys/posix/sys/stat.d b/runtime/druntime/src/core/sys/posix/sys/stat.d index b89478fe7d7..328f620a42a 100644 --- a/runtime/druntime/src/core/sys/posix/sys/stat.d +++ b/runtime/druntime/src/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/runtime/druntime/src/core/sys/windows/dll.d b/runtime/druntime/src/core/sys/windows/dll.d index e37d5bf22cd..cb692f500ea 100644 --- a/runtime/druntime/src/core/sys/windows/dll.d +++ b/runtime/druntime/src/core/sys/windows/dll.d @@ -29,13 +29,7 @@ extern (C) { version (Win32) { - version (CRuntime_DigitalMars) - { - extern __gshared byte _tlsstart; - extern __gshared byte _tlsend; - extern __gshared void* _tls_callbacks_a; - } - else version (CRuntime_Microsoft) + version (CRuntime_Microsoft) { extern __gshared byte _tls_start; extern __gshared byte _tls_end; diff --git a/runtime/druntime/src/core/sys/windows/stacktrace.d b/runtime/druntime/src/core/sys/windows/stacktrace.d index 0608dbbbd7e..238e508e88c 100644 --- a/runtime/druntime/src/core/sys/windows/stacktrace.d +++ b/runtime/druntime/src/core/sys/windows/stacktrace.d @@ -48,11 +48,11 @@ public: if (context is null) { version (LDC) - static enum INTERNALFRAMES = 0; + enum INTERNALFRAMES = 0; else 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 } @@ -60,9 +60,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; } @@ -330,13 +330,6 @@ private: auto res = formatStackFrame(pc); res ~= " in "; const(char)[] tempSymName = symName[0 .. strlen(symName)]; - // Deal with dmd mangling of long names for OMF 32 bits builds - // Note that `target.d` only defines `CRuntime_DigitalMars` for OMF builds - version (CRuntime_DigitalMars) - { - size_t decodeIndex = 0; - tempSymName = decodeDmdString(tempSymName, decodeIndex); - } res ~= demangle(tempSymName, demangleBuf); return res; } @@ -360,34 +353,6 @@ private: } -// Workaround OPTLINK bug (Bugzilla 8263) -extern(Windows) BOOL FixupDebugHeader(HANDLE hProcess, ULONG ActionCode, - ulong CallbackContext, ulong UserContext) -{ - if (ActionCode == CBA_READ_MEMORY) - { - auto p = cast(IMAGEHLP_CBA_READ_MEMORY*)CallbackContext; - if (!(p.addr & 0xFF) && p.bytes == 0x1C && - // IMAGE_DEBUG_DIRECTORY.PointerToRawData - (*cast(DWORD*)(p.addr + 24) & 0xFF) == 0x20) - { - immutable base = DbgHelp.get().SymGetModuleBase64(hProcess, p.addr); - // IMAGE_DEBUG_DIRECTORY.AddressOfRawData - if (base + *cast(DWORD*)(p.addr + 20) == p.addr + 0x1C && - *cast(DWORD*)(p.addr + 0x1C) == 0 && - *cast(DWORD*)(p.addr + 0x20) == ('N'|'B'<<8|'0'<<16|'9'<<24)) - { - debug(PRINTF) printf("fixup IMAGE_DEBUG_DIRECTORY.AddressOfRawData\n"); - memcpy(p.buf, cast(void*)p.addr, 0x1C); - *cast(DWORD*)(p.buf + 20) = cast(DWORD)(p.addr - base) + 0x20; - *p.bytesread = 0x1C; - return TRUE; - } - } - } - return FALSE; -} - private string generateSearchPath() { __gshared string[3] defaultPathList = ["_NT_SYMBOL_PATH", @@ -448,9 +413,6 @@ shared static this() if (!dbghelp.SymInitialize(hProcess, generateSearchPath().ptr, TRUE)) return; - version (LDC) {} else - dbghelp.SymRegisterCallback64(hProcess, &FixupDebugHeader, 0); - InitializeCriticalSection(&mutex); initialized = true; } diff --git a/runtime/druntime/src/core/sys/windows/stat.d b/runtime/druntime/src/core/sys/windows/stat.d index c87c7498873..85ed24f93d8 100644 --- a/runtime/druntime/src/core/sys/windows/stat.d +++ b/runtime/druntime/src/core/sys/windows/stat.d @@ -31,29 +31,7 @@ int S_ISDIR(int m) { return (m & S_IFMT) == S_IFDIR; } int S_ISCHR(int m) { return (m & S_IFMT) == S_IFCHR; } } -version (CRuntime_DigitalMars) -{ - struct struct_stat - { - short st_dev; - ushort st_ino; - ushort st_mode; - short st_nlink; - ushort st_uid; - ushort st_gid; - short st_rdev; - short dummy; - int st_size; - time_t st_atime; - time_t st_mtime; - time_t st_ctime; - } - - int stat(const(char)*, struct_stat *); - int fstat(int, struct_stat *) @trusted; - int _wstat(const(wchar)*, struct_stat *); -} -else version (CRuntime_Microsoft) +version (CRuntime_Microsoft) { struct struct_stat { diff --git a/runtime/druntime/src/core/thread/osthread.d b/runtime/druntime/src/core/thread/osthread.d index c8c69325008..8b07397296a 100644 --- a/runtime/druntime/src/core/thread/osthread.d +++ b/runtime/druntime/src/core/thread/osthread.d @@ -2319,7 +2319,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()); } @@ -2761,11 +2761,7 @@ private bool ll_dllHasExternalReferences() nothrow { - version (CRuntime_DigitalMars) - enum internalReferences = 1; // only the watchdog thread - else - int internalReferences = msvcUsesUCRT ? 1 + ll_countLowLevelThreadsWithDLLUnloadCallback() : 1; - + int internalReferences = msvcUsesUCRT ? 1 + ll_countLowLevelThreadsWithDLLUnloadCallback() : 1; int refcnt = dll_getRefCount(ll_dllModule); return refcnt > internalReferences; } @@ -2826,10 +2822,7 @@ private // if a thread is created from a DLL, the MS runtime (starting with VC2015) increments the DLL reference count // to avoid the DLL being unloaded while the thread is still running. Mimick this behavior here for all // runtimes not doing this - version (CRuntime_DigitalMars) - enum needRef = true; - else - bool needRef = !msvcUsesUCRT; + bool needRef = !msvcUsesUCRT; if (needRef) { diff --git a/runtime/druntime/src/core/thread/threadbase.d b/runtime/druntime/src/core/thread/threadbase.d index 36d58b4b549..143eca7f5b6 100644 --- a/runtime/druntime/src/core/thread/threadbase.d +++ b/runtime/druntime/src/core/thread/threadbase.d @@ -790,7 +790,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/runtime/druntime/src/importc.h b/runtime/druntime/src/importc.h index 9de87e7c191..89140d7f3f9 100644 --- a/runtime/druntime/src/importc.h +++ b/runtime/druntime/src/importc.h @@ -8,6 +8,13 @@ * Source: $(DRUNTIMESRC importc.h) */ +/********************** + * Silence noisy warnings for this file + */ +#ifdef __GNUC__ +#pragma GCC system_header +#endif + /********************** * For special casing ImportC code. */ diff --git a/runtime/druntime/src/rt/aaA.d b/runtime/druntime/src/rt/aaA.d index 291e1a62c87..cd20b232bbc 100644 --- a/runtime/druntime/src/rt/aaA.d +++ b/runtime/druntime/src/rt/aaA.d @@ -702,7 +702,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 @@ -724,7 +724,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/runtime/druntime/src/rt/alloca.d b/runtime/druntime/src/rt/alloca.d index 0bfdf84e999..108379919d6 100644 --- a/runtime/druntime/src/rt/alloca.d +++ b/runtime/druntime/src/rt/alloca.d @@ -13,20 +13,6 @@ module rt.alloca; version (LDC) {} else: -version (Posix) -{ - version = alloca; -} -else version (CRuntime_Microsoft) -{ - version = alloca; -} - -// Use DMC++'s alloca() for Win32 - -version (alloca) -{ - /******************************************* * Allocate data from the caller's stack frame. * This is a 'magic' function that needs help from the compiler to @@ -217,5 +203,3 @@ extern (C) void* __alloca(int nbytes) else static assert(0); } - -} diff --git a/runtime/druntime/src/rt/cover.d b/runtime/druntime/src/rt/cover.d index ef1d505d8f5..94c8ea2bb6c 100644 --- a/runtime/druntime/src/rt/cover.d +++ b/runtime/druntime/src/rt/cover.d @@ -473,10 +473,7 @@ FILE* openOrCreateFile(string name) version (Windows) HANDLE handle(int fd) { - version (CRuntime_DigitalMars) - return _fdToHandle(fd); - else - return cast(HANDLE)_get_osfhandle(fd); + return cast(HANDLE)_get_osfhandle(fd); } void lockFile(int fd) diff --git a/runtime/druntime/src/rt/dmain2.d b/runtime/druntime/src/rt/dmain2.d index 94593cae1a5..00a8235ae4c 100644 --- a/runtime/druntime/src/rt/dmain2.d +++ b/runtime/druntime/src/rt/dmain2.d @@ -99,7 +99,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. @@ -179,6 +179,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/runtime/druntime/src/rt/dwarfeh.d b/runtime/druntime/src/rt/dwarfeh.d index c497ff5d850..27023fac445 100644 --- a/runtime/druntime/src/rt/dwarfeh.d +++ b/runtime/druntime/src/rt/dwarfeh.d @@ -1210,7 +1210,7 @@ int actionTableLookup(_Unwind_Exception* exceptionObject, uint actionRecordPtr, ClassInfo ci = cast(ClassInfo)cast(void*)(entry); if (typeid(ci) is typeid(__cpp_type_info_ptr)) { - version (CppRuntime_Gcc) + version (CppRuntime_GNU) { if (exceptionClass == cppExceptionClass || exceptionClass == cppExceptionClass1) { @@ -1256,7 +1256,7 @@ void terminate(uint line) @nogc /****************************** C++ Support *****************************/ -version (CppRuntime_Gcc) +version (CppRuntime_GNU) { enum _Unwind_Exception_Class cppExceptionClass = (cast(_Unwind_Exception_Class)'G' << 56) | diff --git a/runtime/druntime/src/rt/lifetime.d b/runtime/druntime/src/rt/lifetime.d index f0d6453db69..2a841888bf2 100644 --- a/runtime/druntime/src/rt/lifetime.d +++ b/runtime/druntime/src/rt/lifetime.d @@ -148,7 +148,7 @@ private extern (D) Object _d_newclass(bool initialize)(const ClassInfo ci) static if (initialize) // LDC { // initialize it - p[0 .. init.length] = init[]; + p[0 .. init.length] = cast(void[]) init[]; } debug(PRINTF) printf("initialization done\n"); @@ -1334,7 +1334,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/runtime/druntime/src/rt/minit.asm b/runtime/druntime/src/rt/minit.asm deleted file mode 100644 index 1b86f287b0a..00000000000 --- a/runtime/druntime/src/rt/minit.asm +++ /dev/null @@ -1,114 +0,0 @@ -;_ minit.asm -; Module initialization support. -; -; Copyright: Copyright Digital Mars 2000 - 2010. -; License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). -; Authors: Walter Bright -; -; Copyright Digital Mars 2000 - 2010. -; Distributed under the Boost Software License, Version 1.0. -; (See accompanying file LICENSE or copy at -; http://www.boost.org/LICENSE_1_0.txt) -; -; With VC installed, build with: -; ml /omf minit.asm - - .model FLAT - -ifdef _WIN32 - DATAGRP EQU FLAT -else - DATAGRP EQU DGROUP -endif - -; Provide a default resolution for weak extern records, no way in C -; to define an omf symbol with a specific value -public __nullext -__nullext equ 0 - - extrn __moduleinfo_array:near - -; This bit of assembler is needed because, from C or D, one cannot -; specify the names of data segments. Why does this matter? -; All the ModuleInfo pointers are placed into a segment named 'FM'. -; The order in which they are placed in 'FM' is arbitrarily up to the linker. -; In order to walk all the pointers, we need to be able to find the -; beginning and the end of the 'FM' segment. -; This is done by bracketing the 'FM' segment with two other, empty, -; segments named 'FMB' and 'FME'. Since this module is the only one that -; ever refers to 'FMB' and 'FME', we get to control the order in which -; these segments appear relative to 'FM' by using a GROUP statement. -; So, we have in memory: -; FMB empty segment -; FM contains all the pointers -; FME empty segment -; and finding the limits of FM is as easy as taking the address of FMB -; and the address of FME. - -; These segments bracket FM, which contains the list of ModuleInfo pointers -FMB segment dword use32 public 'DATA' -FMB ends -FM segment dword use32 public 'DATA' -FM ends -FME segment dword use32 public 'DATA' -FME ends - -; This leaves room in the _fatexit() list for _moduleDtor() -XOB segment dword use32 public 'BSS' -XOB ends -XO segment dword use32 public 'BSS' - dd ? -XO ends -XOE segment dword use32 public 'BSS' -XOE ends - -DGROUP group FMB,FM,FME - -; These segments bracket DP, which contains the _DATA pointer references - public __DPbegin, __DPend -DPB segment dword use32 public 'CODE' -__DPbegin: -DPB ends -DP segment dword use32 public 'CODE' -DP ends -DPE segment dword use32 public 'CODE' -__DPend: -DPE ends - -CGROUP group DPB,DP,DPE - -; These segments bracket TP, which contains the TLS pointer references - public __TPbegin, __TPend -TPB segment dword use32 public 'CODE' -__TPbegin: -TPB ends -TP segment dword use32 public 'CODE' -TP ends -TPE segment dword use32 public 'CODE' -__TPend: -TPE ends - -CGROUP group TPB,TP,TPE - -_TEXT segment para use32 public 'CODE' - assume CS:_TEXT - -; extern (C) void _minit(); -; Converts array of ModuleInfo pointers to a D dynamic array of them, -; so they can be accessed via D. -; Result is written to: -; extern (C) ModuleInfo[] _moduleinfo_array; - - public __minit -__minit: - mov EDX,offset DATAGRP:FMB - mov EAX,offset DATAGRP:FME - mov dword ptr __moduleinfo_array+4,EDX - sub EAX,EDX ; size in bytes of FM segment - shr EAX,2 ; convert to array length - mov dword ptr __moduleinfo_array,EAX - ret - -_TEXT ends - - end diff --git a/runtime/druntime/src/rt/minit.obj b/runtime/druntime/src/rt/minit.obj deleted file mode 100644 index 9aaa62d036f..00000000000 Binary files a/runtime/druntime/src/rt/minit.obj and /dev/null differ diff --git a/runtime/druntime/src/rt/monitor_.d b/runtime/druntime/src/rt/monitor_.d index c1f3f3cb9a7..cbe2a484402 100644 --- a/runtime/druntime/src/rt/monitor_.d +++ b/runtime/druntime/src/rt/monitor_.d @@ -173,10 +173,6 @@ alias DEvent = void delegate(Object); version (Windows) { - version (CRuntime_DigitalMars) - { - pragma(lib, "snn.lib"); - } import core.sys.windows.winbase /+: CRITICAL_SECTION, DeleteCriticalSection, EnterCriticalSection, InitializeCriticalSection, LeaveCriticalSection+/; diff --git a/runtime/druntime/src/rt/sections.d b/runtime/druntime/src/rt/sections.d index e285cb08b0d..7dbfd24a939 100644 --- a/runtime/druntime/src/rt/sections.d +++ b/runtime/druntime/src/rt/sections.d @@ -54,8 +54,6 @@ else version (Darwin) else static assert(0, "unimplemented"); } -else version (CRuntime_DigitalMars) - public import rt.sections_win32; else version (CRuntime_Microsoft) { version (LDC) diff --git a/runtime/druntime/src/rt/sections_android.d b/runtime/druntime/src/rt/sections_android.d deleted file mode 100644 index 65019acd99e..00000000000 --- a/runtime/druntime/src/rt/sections_android.d +++ /dev/null @@ -1,299 +0,0 @@ -/** - * Written in the D programming language. - * This module provides bionic-specific support for sections. - * - * Copyright: Copyright Martin Nowak 2012-2013. - * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). - * Authors: Martin Nowak - * Source: $(DRUNTIMESRC rt/_sections_android.d) - */ - -module rt.sections_android; - -version (LDC) { /* implemented in rt.sections_elf_shared */ } else: - -version (CRuntime_Bionic): - -// debug = PRINTF; -debug(PRINTF) import core.stdc.stdio; -import core.internal.elf.dl : SharedObject; -import core.sys.posix.pthread; -import core.stdc.stdlib : calloc, malloc, free; -import core.stdc.string : memcpy; -import rt.deh; -import rt.minfo; -import rt.util.utility : safeAssert; - -struct SectionGroup -{ - static int opApply(scope int delegate(ref SectionGroup) dg) - { - return dg(_sections); - } - - static int opApplyReverse(scope int delegate(ref SectionGroup) dg) - { - return dg(_sections); - } - - @property immutable(ModuleInfo*)[] modules() const nothrow @nogc - { - return _moduleGroup.modules; - } - - @property ref inout(ModuleGroup) moduleGroup() inout return nothrow @nogc - { - return _moduleGroup; - } - - version (DigitalMars) - @property immutable(FuncTable)[] ehTables() const nothrow @nogc - { - auto pbeg = cast(immutable(FuncTable)*)&__start_deh; - auto pend = cast(immutable(FuncTable)*)&__stop_deh; - return pbeg[0 .. pend - pbeg]; - } - - @property inout(void[])[] gcRanges() inout return nothrow @nogc - { - return _gcRanges[]; - } - -private: - ModuleGroup _moduleGroup; - void[][1] _gcRanges; -} - -void initSections() nothrow @nogc -{ - pthread_key_create(&_tlsKey, null); - - SharedObject object; - const success = SharedObject.findForAddress(&_sections, object); - safeAssert(success, "cannot find ELF object"); - - _staticTLSRange = getStaticTLSRange(object, _tlsAlignment); - // prevent the linker from stripping the TLS alignment symbols - if (_staticTLSRange is null) // should never happen - safeAssert(alignmentForTDATA == alignmentForTBSS, "unreachable"); - - version (LDC) - { - auto mbeg = cast(immutable ModuleInfo**)&__start___minfo; - auto mend = cast(immutable ModuleInfo**)&__stop___minfo; - } - else - { - auto mbeg = cast(immutable ModuleInfo**)&__start_minfo; - auto mend = cast(immutable ModuleInfo**)&__stop_minfo; - } - _sections.moduleGroup = ModuleGroup(mbeg[0 .. mend - mbeg]); - - // iterate over ELF segments to determine data segment range - import core.sys.linux.elf; - foreach (ref phdr; object) - { - if (phdr.p_type == PT_LOAD && (phdr.p_flags & PF_W)) // writeable data segment - { - safeAssert(_sections._gcRanges[0] is null, "expected a single data segment"); - - void* start = object.baseAddress + phdr.p_vaddr; - void* end = start + phdr.p_memsz; - debug(PRINTF) printf("data segment: %p - %p\n", start, end); - - // pointer-align up - enum mask = size_t.sizeof - 1; - start = cast(void*) ((cast(size_t)start + mask) & ~mask); - - _sections._gcRanges[0] = start[0 .. end-start]; - } - } -} - -void finiSections() nothrow @nogc -{ - pthread_key_delete(_tlsKey); -} - -void[]* initTLSRanges() nothrow @nogc -{ - return &getTLSBlock(); -} - -void finiTLSRanges(void[]* rng) nothrow @nogc -{ - free(rng.ptr); - free(rng); -} - -void scanTLSRanges(void[]* rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow -{ - dg(rng.ptr, rng.ptr + rng.length); -} - -/* NOTE: The Bionic C library ignores thread-local data stored in the normal - * .tdata/.tbss ELF sections, which are marked with the SHF_TLS/STT_TLS - * flags. So instead we roll our own emulation (e.g., in LDC's LLVM fork) - * by keeping static TLS data in the .tdata/.tbss sections but removing - * the SHF_TLS/STT_TLS flags, and access the TLS data using this function. - * - * This function is called by the code emitted by the compiler. It is - * expected to translate an address in the TLS static data to the - * corresponding address in the TLS dynamic per-thread data. - */ -extern(C) void* __tls_get_addr(void* p) nothrow @nogc -{ - debug(PRINTF) printf(" __tls_get_addr input - %p\n", p); - const offset = cast(size_t) (p - _staticTLSRange.ptr); - assert(offset < _staticTLSRange.length, - "invalid TLS address or initSections() not called yet"); - // The following would only be safe if no TLS variables are accessed - // before calling initTLSRanges(): - //return (cast(void[]*) pthread_getspecific(_tlsKey)).ptr + offset; - return getTLSBlock().ptr + offset; -} - -private: - -__gshared pthread_key_t _tlsKey; -__gshared void[] _staticTLSRange; -__gshared uint _tlsAlignment; -__gshared SectionGroup _sections; - -/* The following code relies on the .tdata (non-zero initialized) and .tbss - * (zero-initialized) sections to end up adjacent to each other in the final - * linked binary. - * This allows to merge both (and thus all TLS data) to a single contiguous - * memory block. - */ - -/* Enforce some minimum alignment for both sections. - * The relative offset of the 2nd section from the first (in memory) needs to be - * a multiple of the 2nd section's alignment, so that the 2nd section ends up - * suitably aligned in each thread's TLS block. - */ -enum minAlignment = 16; -align(minAlignment) -{ - byte alignmentForTDATA = 1; - byte alignmentForTBSS; -} - -// aligned_alloc is only available since API level 28 -extern(C) int posix_memalign(void** memptr, size_t alignment, size_t size) nothrow @nogc; - -ref void[] getTLSBlock() nothrow @nogc -{ - auto pary = cast(void[]*) pthread_getspecific(_tlsKey); - - version (LDC) - { - import ldc.intrinsics; - const isUninitialized = llvm_expect(pary is null, false); - } - else - const isUninitialized = pary is null; - - if (isUninitialized) - { - pary = cast(void[]*) calloc(1, (void[]).sizeof); - safeAssert(pary !is null, "cannot allocate TLS block slice"); - - if (pthread_setspecific(_tlsKey, pary) != 0) - { - import core.stdc.stdio; - perror("pthread_setspecific failed with"); - assert(0); - } - - safeAssert(_staticTLSRange.ptr !is null, "initSections() not called yet"); - if (const size = _staticTLSRange.length) - { - void* p; - const error = posix_memalign(&p, _tlsAlignment, size); - safeAssert(error == 0, "cannot allocate TLS block"); - memcpy(p, _staticTLSRange.ptr, size); - *pary = p[0 .. size]; - } - } - - return *pary; -} - -// Returns the static TLS data range (.tdata and .tbss sections). -// `alignment` is set to the max overall TLS alignment, to be used to align each -// thread's TLS block. -void[] getStaticTLSRange(const ref SharedObject object, out uint alignment) nothrow @nogc -{ - import core.internal.elf.io; - - const(char)[] path = object.name(); - char[512] pathBuffer = void; - if (path[0] != '/') - { - path = object.getPath(pathBuffer); - safeAssert(path !is null, "cannot get path of ELF object"); - } - debug(PRINTF) printf("ELF file path: %s\n", path.ptr); - - ElfFile file; - const success = ElfFile.open(path.ptr, file); - safeAssert(success, "cannot open ELF file"); - - void* start, end; - alignment = minAlignment; - foreach (index, name, sectionHeader; file.namedSections) - { - if (name == ".tdata" || name == ".tbss") - { - void* sectionStart = object.baseAddress + sectionHeader.sh_addr; - void* sectionEnd = sectionStart + sectionHeader.sh_size; - const sectionAlignment = cast(uint) sectionHeader.sh_addralign; - debug(PRINTF) printf("section %s: %p - %p, alignment: %u\n", name.ptr, sectionStart, sectionEnd, sectionAlignment); - - if (sectionAlignment > alignment) - alignment = sectionAlignment; - - if (!start) - { - start = sectionStart; - end = sectionEnd; - } - else - { - const bytesInbetweenSections = sectionStart - end; - safeAssert(bytesInbetweenSections >= 0 && bytesInbetweenSections < alignment, - "expected .tdata and .tbss sections to be adjacent (hint: try ld.bfd linker)"); - safeAssert(sectionAlignment == 0 || ((sectionStart - start) & (sectionAlignment - 1)) == 0, - "offset of .tbss section from .tdata isn't a multiple of the .tbss alignment (workaround: align .tdata manually)"); - end = sectionEnd; - break; // we've found both sections - } - } - } - - // return an empty but non-null slice if there's no TLS data - return start ? start[0 .. end-start] : object.baseAddress[0..0]; -} - -extern(C) -{ - /* Symbols created by the linker and inserted into the object file that - * 'bracket' sections. - */ - extern __gshared - { - version (LDC) - { - void* __start___minfo; - void* __stop___minfo; - } - else - { - void* __start_deh; - void* __stop_deh; - void* __start_minfo; - void* __stop_minfo; - } - } -} diff --git a/runtime/druntime/src/rt/sections_elf_shared.d b/runtime/druntime/src/rt/sections_elf_shared.d index 958b0ce0318..ddccf7fbc3f 100644 --- a/runtime/druntime/src/rt/sections_elf_shared.d +++ b/runtime/druntime/src/rt/sections_elf_shared.d @@ -210,11 +210,6 @@ private: } } -/**** - * Boolean flag set to true while the runtime is initialized. - */ -__gshared bool _isRuntimeInitialized; - version (FreeBSD) private __gshared void* dummy_ref; version (DragonFlyBSD) private __gshared void* dummy_ref; @@ -225,7 +220,6 @@ version (NetBSD) private __gshared void* dummy_ref; */ void initSections() nothrow @nogc { - _isRuntimeInitialized = true; // reference symbol to support weak linkage version (FreeBSD) dummy_ref = &_d_dso_registry; version (DragonFlyBSD) dummy_ref = &_d_dso_registry; @@ -238,7 +232,6 @@ void initSections() nothrow @nogc */ void finiSections() nothrow @nogc { - _isRuntimeInitialized = false; } alias ScanDG = void delegate(void* pbeg, void* pend) nothrow; @@ -614,7 +607,7 @@ package extern(C) void _d_dso_registry(void* arg) } // 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 @@ -629,7 +622,7 @@ package extern(C) void _d_dso_registry(void* arg) *data._slot = null; // don't finalizes modules after rt_term was called (see Bugzilla 11378) - bool doFinalize = _isRuntimeInitialized; + bool doFinalize = isRuntimeInitialized(); version (Shared) {} else version (Windows) { /* If a DLL with its own static druntime has been loaded via diff --git a/runtime/druntime/src/rt/sections_win32.d b/runtime/druntime/src/rt/sections_win32.d deleted file mode 100644 index a09eda4cadc..00000000000 --- a/runtime/druntime/src/rt/sections_win32.d +++ /dev/null @@ -1,252 +0,0 @@ -/** - * Written in the D programming language. - * This module provides Win32-specific support for sections. - * - * Copyright: Copyright Digital Mars 2008 - 2012. - * License: Distributed under the - * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0). - * (See accompanying file LICENSE) - * Authors: Walter Bright, Sean Kelly, Martin Nowak - * Source: $(DRUNTIMESRC rt/_sections_win32.d) - */ - -module rt.sections_win32; - -version (CRuntime_DigitalMars): - -// debug = PRINTF; -debug(PRINTF) import core.stdc.stdio; -import rt.minfo; -import core.stdc.stdlib : malloc, free; -import core.sys.windows.winbase : FreeLibrary, GetProcAddress, LoadLibraryA, LoadLibraryW; -import core.sys.windows.winnt : WCHAR; - -struct SectionGroup -{ - static int opApply(scope int delegate(ref SectionGroup) dg) - { - return dg(_sections); - } - - static int opApplyReverse(scope int delegate(ref SectionGroup) dg) - { - return dg(_sections); - } - - @property immutable(ModuleInfo*)[] modules() const nothrow @nogc - { - return _moduleGroup.modules; - } - - @property ref inout(ModuleGroup) moduleGroup() inout return nothrow @nogc - { - return _moduleGroup; - } - - @property inout(void[])[] gcRanges() inout nothrow @nogc - { - return _gcRanges[]; - } - -private: - ModuleGroup _moduleGroup; - void[][] _gcRanges; -} - -shared(bool) conservative; - -/**** - * Gets called on program startup just before GC is initialized. - */ -void initSections() nothrow @nogc -{ - _sections._moduleGroup = ModuleGroup(getModuleInfos()); - - import rt.sections; - conservative = !scanDataSegPrecisely(); - - if (conservative) - { - _sections._gcRanges = (cast(void[]*) malloc(2 * (void[]).sizeof))[0..2]; - - auto databeg = cast(void*)&_xi_a; - auto dataend = cast(void*)_moduleinfo_array.ptr; - _sections._gcRanges[0] = databeg[0 .. dataend - databeg]; - - // skip module info and CONST segment - auto bssbeg = cast(void*)&_edata; - auto bssend = cast(void*)&_end; - _sections._gcRanges[1] = bssbeg[0 .. bssend - bssbeg]; - } - else - { - size_t count = &_DPend - &_DPbegin; - auto ranges = cast(void[]*) malloc(count * (void[]).sizeof); - size_t r = 0; - void* prev = null; - for (size_t i = 0; i < count; i++) - { - void* addr = (&_DPbegin)[i]; - if (prev + (void*).sizeof == addr) - ranges[r-1] = ranges[r-1].ptr[0 .. ranges[r-1].length + (void*).sizeof]; - else - ranges[r++] = (cast(void**)addr)[0..1]; - prev = addr; - } - _sections._gcRanges = ranges[0..r]; - } -} - -/*** - * Gets called on program shutdown just after GC is terminated. - */ -void finiSections() nothrow @nogc -{ - free(_sections._gcRanges.ptr); -} - -/*** - * Called once per thread; returns array of thread local storage ranges - */ -void[] initTLSRanges() nothrow @nogc -{ - auto pbeg = cast(void*)&_tlsstart; - auto pend = cast(void*)&_tlsend; - return pbeg[0 .. pend - pbeg]; -} - -void finiTLSRanges(void[] rng) nothrow @nogc -{ -} - -void scanTLSRanges(void[] rng, scope void delegate(void* pbeg, void* pend) nothrow dg) nothrow -{ - if (conservative) - { - dg(rng.ptr, rng.ptr + rng.length); - } - else - { - for (auto p = &_TPbegin; p < &_TPend; ) - { - uint beg = *p++; - uint end = beg + cast(uint)((void*).sizeof); - while (p < &_TPend && *p == end) - { - end += (void*).sizeof; - p++; - } - dg(rng.ptr + beg, rng.ptr + end); - } - } -} - -private: - -/////////////////////////////////////////////////////////////////////////////// -// Compiler to runtime interface. -/////////////////////////////////////////////////////////////////////////////// - -__gshared SectionGroup _sections; - -// Windows: this gets initialized by minit.asm -extern(C) __gshared immutable(ModuleInfo*)[] _moduleinfo_array; -extern(C) void _minit() nothrow @nogc; - -immutable(ModuleInfo*)[] getModuleInfos() nothrow @nogc -out (result) -{ - foreach (m; result) - assert(m !is null); -} -do -{ - // _minit directly alters the global _moduleinfo_array - _minit(); - return _moduleinfo_array; -} - -extern(C) -{ - extern __gshared - { - int _xi_a; // &_xi_a just happens to be start of data segment - int _edata; // &_edata is start of BSS segment - int _end; // &_end is past end of BSS - - void* _DPbegin; // first entry in the array of pointers addresses - void* _DPend; // &_DPend points after last entry of array - uint _TPbegin; // first entry in the array of TLS offsets of pointers - uint _TPend; // &_DPend points after last entry of array - } - - extern - { - int _tlsstart; - int _tlsend; - } -} - -/////////////////////////////////////////////////////////////////////////////// -// dynamic loading -/////////////////////////////////////////////////////////////////////////////// - -/*********************************** - * These are a temporary means of providing a GC hook for DLL use. They may be - * replaced with some other similar functionality later. - */ -extern (C) -{ - void* gc_getProxy(); - void gc_setProxy(void* p); - void gc_clrProxy(); - - alias void function(void*) gcSetFn; - alias void function() gcClrFn; -} - -/******************************************* - * Loads a DLL written in D with the name 'name'. - * Returns: - * opaque handle to the DLL if successfully loaded - * null if failure - */ -extern (C) void* rt_loadLibrary(const char* name) -{ - return initLibrary(.LoadLibraryA(name)); -} - -extern (C) void* rt_loadLibraryW(const WCHAR* name) -{ - return initLibrary(.LoadLibraryW(name)); -} - -void* initLibrary(void* mod) -{ - // BUG: LoadLibrary() call calls rt_init(), which fails if proxy is not set! - // (What? LoadLibrary() is a Windows API call, it shouldn't call rt_init().) - if (mod is null) - return mod; - gcSetFn gcSet = cast(gcSetFn) GetProcAddress(mod, "gc_setProxy"); - if (gcSet !is null) - { // BUG: Set proxy, but too late - gcSet(gc_getProxy()); - } - return mod; -} - -/************************************* - * Unloads DLL that was previously loaded by rt_loadLibrary(). - * Input: - * ptr the handle returned by rt_loadLibrary() - * Returns: - * 1 succeeded - * 0 some failure happened - */ -extern (C) int rt_unloadLibrary(void* ptr) -{ - gcClrFn gcClr = cast(gcClrFn) GetProcAddress(ptr, "gc_clrProxy"); - if (gcClr !is null) - gcClr(); - return FreeLibrary(ptr) != 0; -} diff --git a/runtime/druntime/src/rt/tracegc.d b/runtime/druntime/src/rt/tracegc.d index f3b1bf2e6f2..c230e21e6ec 100644 --- a/runtime/druntime/src/rt/tracegc.d +++ b/runtime/druntime/src/rt/tracegc.d @@ -122,7 +122,7 @@ private string generateTraceWrappers() return code; } -static enum ParamPos { front, back } +enum ParamPos { front, back } private string generateWrapper(alias Declaration, ParamPos pos = ParamPos.front)() { diff --git a/runtime/druntime/test/aa/Makefile b/runtime/druntime/test/aa/Makefile index 839237a9292..ff86fd9fcc7 100644 --- a/runtime/druntime/test/aa/Makefile +++ b/runtime/druntime/test/aa/Makefile @@ -14,4 +14,4 @@ $(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: - rm -rf $(GENERATED) + rm -rf $(ROOT) diff --git a/runtime/druntime/test/allocations/Makefile b/runtime/druntime/test/allocations/Makefile index 99936bf1482..53507da0e50 100644 --- a/runtime/druntime/test/allocations/Makefile +++ b/runtime/druntime/test/allocations/Makefile @@ -25,4 +25,4 @@ $(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: - rm -rf $(GENERATED) + rm -rf $(ROOT) diff --git a/runtime/druntime/test/coverage/Makefile b/runtime/druntime/test/coverage/Makefile index ba5da368a63..9af60369e53 100644 --- a/runtime/druntime/test/coverage/Makefile +++ b/runtime/druntime/test/coverage/Makefile @@ -74,4 +74,4 @@ $(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $^ clean: - rm -rf $(GENERATED) *.lst + rm -rf $(ROOT) *.lst diff --git a/runtime/druntime/test/cpuid/Makefile b/runtime/druntime/test/cpuid/Makefile index 98c499518f6..eec92e31d07 100644 --- a/runtime/druntime/test/cpuid/Makefile +++ b/runtime/druntime/test/cpuid/Makefile @@ -14,4 +14,4 @@ $(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: - rm -rf $(GENERATED) + rm -rf $(ROOT) diff --git a/runtime/druntime/test/cycles/Makefile b/runtime/druntime/test/cycles/Makefile index 1079ad8ca0f..948998838a9 100644 --- a/runtime/druntime/test/cycles/Makefile +++ b/runtime/druntime/test/cycles/Makefile @@ -25,4 +25,4 @@ $(ROOT)/test_cycles$(DOTEXE): $(SRC)/*.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $^ clean: - rm -rf $(GENERATED) + rm -rf $(ROOT) diff --git a/runtime/druntime/test/exceptions/Makefile b/runtime/druntime/test/exceptions/Makefile index fbcf0df032b..2eb5ca0f653 100644 --- a/runtime/druntime/test/exceptions/Makefile +++ b/runtime/druntime/test/exceptions/Makefile @@ -146,4 +146,4 @@ $(ROOT)/%$(DOTEXE): $(SRC)/%.d $(DMD) $(DRUNTIME) $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: - rm -rf $(GENERATED) + rm -rf $(ROOT) diff --git a/runtime/druntime/test/hash/Makefile b/runtime/druntime/test/hash/Makefile index 53e0e37936a..506b73a59f5 100644 --- a/runtime/druntime/test/hash/Makefile +++ b/runtime/druntime/test/hash/Makefile @@ -14,4 +14,4 @@ $(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: - rm -rf $(GENERATED) + rm -rf $(ROOT) diff --git a/runtime/druntime/test/imports/Makefile b/runtime/druntime/test/imports/Makefile index 078c863798f..bcd1ae773e3 100644 --- a/runtime/druntime/test/imports/Makefile +++ b/runtime/druntime/test/imports/Makefile @@ -11,4 +11,4 @@ $(ROOT)/%.done: $(QUIET)$(DMD) -version=Shared -o- -deps=$@ -Isrc -I../../import src/$*.d clean: - rm -rf $(GENERATED) + rm -rf $(ROOT) diff --git a/runtime/druntime/test/profile/Makefile b/runtime/druntime/test/profile/Makefile index b8e42365dcb..4c263336e3c 100644 --- a/runtime/druntime/test/profile/Makefile +++ b/runtime/druntime/test/profile/Makefile @@ -70,4 +70,4 @@ $(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$(ROOT)/$* $< clean: - rm -rf $(GENERATED) *.log *.def + rm -rf $(ROOT) *.log *.def diff --git a/runtime/druntime/test/shared/Makefile b/runtime/druntime/test/shared/Makefile index afe1cb8900c..0ba78e6ff92 100644 --- a/runtime/druntime/test/shared/Makefile +++ b/runtime/druntime/test/shared/Makefile @@ -160,4 +160,4 @@ $(ROOT)/%$(DOTDLL): $(SRC)/%.d $(DRUNTIMESO) $(QUIET)$(DMD) -shared $(DFLAGS) -of$@ $< $(LINKDL) clean: - rm -rf $(GENERATED) + rm -rf $(ROOT) diff --git a/runtime/druntime/test/stdcpp/Makefile b/runtime/druntime/test/stdcpp/Makefile index 0aea85c80fa..1fc6d235671 100644 --- a/runtime/druntime/test/stdcpp/Makefile +++ b/runtime/druntime/test/stdcpp/Makefile @@ -118,4 +118,4 @@ $(ROOT)/%_old$(DOTEXE): $(SRC)/%.cpp $(SRC)/%_test.d endif # end Posix clean: - rm -rf $(GENERATED) + rm -rf $(ROOT) diff --git a/runtime/druntime/test/thread/Makefile b/runtime/druntime/test/thread/Makefile index 041c527c56a..fbdefffa7c4 100644 --- a/runtime/druntime/test/thread/Makefile +++ b/runtime/druntime/test/thread/Makefile @@ -43,4 +43,4 @@ $(ROOT)/%$(DOTEXE): $(SRC)/%.d $(QUIET)$(DMD) $(DFLAGS) -of$@ $< clean: - rm -rf $(GENERATED) + rm -rf $(ROOT) diff --git a/runtime/druntime/test/unittest/Makefile b/runtime/druntime/test/unittest/Makefile index e7c8f032cbf..bb4551ff3ff 100644 --- a/runtime/druntime/test/unittest/Makefile +++ b/runtime/druntime/test/unittest/Makefile @@ -42,4 +42,4 @@ $(ROOT)/%.done: customhandler.d $(QUIET)test -n "$(TESTTEXT)" || ! grep -q "unittests" $@ clean: - rm -rf $(GENERATED) + rm -rf $(ROOT) diff --git a/runtime/phobos b/runtime/phobos index 654241bed8f..11bf089f6cd 160000 --- a/runtime/phobos +++ b/runtime/phobos @@ -1 +1 @@ -Subproject commit 654241bed8f1b1460762e55412d9a9ea623f3cc7 +Subproject commit 11bf089f6cdbc8cca375569e6e638ea88fcfd5ed diff --git a/tests/dmd/README.md b/tests/dmd/README.md index 70e8cee5c86..75855a35aac 100644 --- a/tests/dmd/README.md +++ b/tests/dmd/README.md @@ -191,7 +191,7 @@ void main(string[] args) Test parameters can be restricted to certain targets by adding a brace-enclosed condition after the name, i.e. `REQUIRED_ARGS(): ...`. The `` consists of the target operating system followed by an optional model suffix, -e.g. `linux`, `win32mscoff`, `freebsd64`. +e.g. `linux`, `win32`, `freebsd64`. Valid platforms: - win @@ -203,8 +203,6 @@ Valid platforms: Valid models: - 32 -- 32mscoff (windows only) -- 32omf (windows only) - 64 Note that test parameters *MUST* be followed by a colon (intermediate whitespace is allowed). @@ -358,7 +356,7 @@ Environment variables ARGS: set to execute all combinations of AUTO_UPDATE: set to 1 to auto-update mismatching test output - CC: C++ compiler to use, ex: dmc, g++ + CC: C++ compiler to use, ex: cl, g++ DMD: compiler to use, ex: ../src/dmd (required) MODEL: 32 or 64 (required) OS: windows, linux, freebsd, osx, netbsd, dragonflybsd @@ -430,7 +428,7 @@ depend on the current platform and target: Supported conditions: - OS: posix, windows, ... - - Model: 64, 32mscoff, 32omf and 32 (also matches 32mscoff + 32omf) + - Model: 64, 32 $r:$ any text matching (using $ inside of is not supported, use multiple regexes instead) diff --git a/tests/dmd/compilable/b20243.d b/tests/dmd/compilable/b20243.d new file mode 100644 index 00000000000..792dcf302d1 --- /dev/null +++ b/tests/dmd/compilable/b20243.d @@ -0,0 +1,9 @@ +module b20243; + +inout(int) f(inout(int)[inout(string)] x); +const(int)[const(string)] x; +static assert(is(typeof(f(x)) == const(int))); + +inout(int)[inout(string)] g(inout(int) y); +const(int) y; +static assert(is(typeof(g(y)) == const(int)[const(string)])); diff --git a/tests/dmd/compilable/cppmangle.d b/tests/dmd/compilable/cppmangle.d index 9501b4f3b04..c1ca34f43d4 100644 --- a/tests/dmd/compilable/cppmangle.d +++ b/tests/dmd/compilable/cppmangle.d @@ -7,9 +7,8 @@ import core.stdc.stdio; -version (CppRuntime_Clang) version = CppMangle_Itanium; -version (CppRuntime_DigitalMars) version = CppMangle_MSVC; -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/tests/dmd/compilable/cppmangle3.d b/tests/dmd/compilable/cppmangle3.d index 82c68f7a3a5..94de1fa9ff4 100644 --- a/tests/dmd/compilable/cppmangle3.d +++ b/tests/dmd/compilable/cppmangle3.d @@ -3,9 +3,8 @@ // https://issues.dlang.org/show_bug.cgi?id=19920 module cppmangle3; -version (CppRuntime_Clang) version = CppMangle_Itanium; -version (CppRuntime_DigitalMars) version = CppMangle_MSVC; -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/tests/dmd/compilable/extra-files/header1.d b/tests/dmd/compilable/extra-files/header1.d index 93f05a50c31..9756264fcc3 100644 --- a/tests/dmd/compilable/extra-files/header1.d +++ b/tests/dmd/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/tests/dmd/compilable/extra-files/header1.di b/tests/dmd/compilable/extra-files/header1.di index 11186409ddf..91422fed8ab 100644 --- a/tests/dmd/compilable/extra-files/header1.di +++ b/tests/dmd/compilable/extra-files/header1.di @@ -517,8 +517,9 @@ struct SafeS @safe { ref SafeS foo() return; - scope SafeS foo2() return; - ref scope SafeS foo3() return; + SafeS foo2() return scope; + ref SafeS foo3() scope; + ref SafeS foo4() scope return; int* p; } } diff --git a/tests/dmd/compilable/extra-files/header1i.di b/tests/dmd/compilable/extra-files/header1i.di index 1be656fa88f..a77f3cb0945 100644 --- a/tests/dmd/compilable/extra-files/header1i.di +++ b/tests/dmd/compilable/extra-files/header1i.di @@ -653,15 +653,19 @@ struct SafeS { return this; } - scope SafeS foo2() return + SafeS foo2() return scope { return this; } - ref scope SafeS foo3() return + ref SafeS foo3() scope { static SafeS s; return s; } + ref SafeS foo4() scope return + { + return this; + } int* p; } } diff --git a/tests/dmd/compilable/ident_UAX31.c b/tests/dmd/compilable/ident_UAX31.c index 4536031e78c..8f1631fbe72 100644 --- a/tests/dmd/compilable/ident_UAX31.c +++ b/tests/dmd/compilable/ident_UAX31.c @@ -1,8 +1,5 @@ // REQUIRED_ARGS: -identifiers-importc=UAX31 -// sppn doesn't support anything newer than c99 -// DISABLED: win32omf - // verify that the UAX31 identifier set is applied. int \u00F8ide\u00F9nt; diff --git a/tests/dmd/compilable/ident_all.c b/tests/dmd/compilable/ident_all.c index 5c3dee4bbf6..5e2af82f36d 100644 --- a/tests/dmd/compilable/ident_all.c +++ b/tests/dmd/compilable/ident_all.c @@ -1,8 +1,5 @@ // REQUIRED_ARGS: -identifiers-importc=all -// sppn doesn't support anything newer than c99 -// DISABLED: win32omf - // verify that the All identifier set is applied. int \u00F8ide\u00F9nt; diff --git a/tests/dmd/compilable/ident_c11.c b/tests/dmd/compilable/ident_c11.c index 5ef3cf3b73b..d098da10e68 100644 --- a/tests/dmd/compilable/ident_c11.c +++ b/tests/dmd/compilable/ident_c11.c @@ -1,8 +1,5 @@ // REQUIRED_ARGS: -identifiers-importc=c11 -// sppn doesn't support anything newer than c99 -// DISABLED: win32omf - // verify that the C11 identifier set is applied. int \u00A8ide\u00AFnt; diff --git a/tests/dmd/compilable/import_exp.d b/tests/dmd/compilable/import_exp.d new file mode 100644 index 00000000000..d29fc67ed66 --- /dev/null +++ b/tests/dmd/compilable/import_exp.d @@ -0,0 +1,44 @@ +// 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;"); + +// https://issues.dlang.org/show_bug.cgi?id=24687 + +void foo(string path); +void foo(const(ubyte[]) data); + +void bar1() { foo(import("imp16088.d")); } // matches both +void bar2() { foo(cast(const(ubyte[])) import("imp16088.d")); } // matches both! diff --git a/tests/dmd/compilable/issue17167.sh b/tests/dmd/compilable/issue17167.sh index 5f7df7b53db..3b94feb0a7b 100755 --- a/tests/dmd/compilable/issue17167.sh +++ b/tests/dmd/compilable/issue17167.sh @@ -13,7 +13,7 @@ src="$bin_base.d" echo 'void main() {}' > "${src}" -# Only compile, not link, since optlink can't handle long file names +# Only compile, don't link, since the Microsoft linker doesn't implicitly support long paths $DMD -m"${MODEL}" "${DFLAGS}" -c -of"${bin}" "${src}" rm_retry -r "${OUTPUT_BASE}" diff --git a/tests/dmd/compilable/issue21203.d b/tests/dmd/compilable/issue21203.d index 30291a35e62..ee394b310a5 100644 --- a/tests/dmd/compilable/issue21203.d +++ b/tests/dmd/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/tests/dmd/compilable/issue21340.d b/tests/dmd/compilable/issue21340.d index 03d37bdc61a..26280998692 100644 --- a/tests/dmd/compilable/issue21340.d +++ b/tests/dmd/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/tests/dmd/compilable/previewhelp.d b/tests/dmd/compilable/previewhelp.d index c50118a8a25..14d5781964e 100644 --- a/tests/dmd/compilable/previewhelp.d +++ b/tests/dmd/compilable/previewhelp.d @@ -16,7 +16,7 @@ Upcoming language changes listed by -preview=name: =nosharedaccess disable access to shared memory objects (https://dlang.org/spec/const3.html#shared) =in `in` on parameters means `scope const [ref]` and accepts rvalues (https://dlang.org/spec/function.html#in-params) =inclusiveincontracts 'in' contracts of overridden methods must be a superset of parent contract (https://dlang.org/changelog/2.095.0.html#inclusive-incontracts) - =fixImmutableConv disallow functions with a mutable `void[]` parameter to be strongly pure (https://dlang.org/changelog/2.101.0.html#dmd.fix-immutable-conv) + =fixImmutableConv disallow `void[]` data from holding immutable data (https://dlang.org/changelog/2.101.0.html#dmd.fix-immutable-conv, https://issues.dlang.org/show_bug.cgi?id=17148) =systemVariables disable access to variables marked '@system' from @safe code (https://dlang.org/spec/attribute.html#system-variables) ---- */ diff --git a/tests/dmd/compilable/staticforeach.d b/tests/dmd/compilable/staticforeach.d index ce9eb74a1ef..5b23446f89b 100644 --- a/tests/dmd/compilable/staticforeach.d +++ b/tests/dmd/compilable/staticforeach.d @@ -117,8 +117,8 @@ foo2 T2 TestStaticForeach2 issue22007 -1 2 '3' -2 3 '4' +1 2 3 +2 3 4 0 1 1 2 2 3 diff --git a/tests/dmd/compilable/stdcheaders.c b/tests/dmd/compilable/stdcheaders.c index 703917f9753..8405469ff49 100644 --- a/tests/dmd/compilable/stdcheaders.c +++ b/tests/dmd/compilable/stdcheaders.c @@ -4,9 +4,7 @@ #include -#ifndef __DMC__ // D:\a\1\s\tools\dm\include\complex.h(105): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead #include -#endif #include #include @@ -36,13 +34,10 @@ float x = NAN; #include #endif -#ifndef __DMC__ // no stdalign.h #include -#endif #include -#ifndef __DMC__ // no stdatomic.h #ifndef __linux__ #ifndef _MSC_VER #ifndef __APPLE__ // /Applications/Xcode-14.2.0.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.0/include/stdatomic.h(80): Error: type-specifier is missing @@ -50,7 +45,6 @@ float x = NAN; #endif #endif #endif -#endif #include #include @@ -61,15 +55,13 @@ float x = NAN; #include #endif -#ifndef __DMC__ // no stdnoreturn.h #include -#endif #include -#ifndef __DMC__ // no tgmath.h #ifndef _MSC_VER // C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt\tgmath.h(33): Error: no type for declarator before `)` #ifndef __APPLE__ // /Applications/Xcode-14.2.0.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/tgmath.h(39): Error: named parameter required before `...` +#ifndef __OpenBSD__ // /usr/lib/clang/13.0.0/include/tgmath.h(34): Error: named parameter required before `...` #if !(defined(__linux__) && defined(__aarch64__)) // /tmp/clang/lib/clang/15.0.3/include/tgmath.h(34): Error: named parameter required before `...` #ifndef __FreeBSD__ // /usr/local/llvm15/lib/clang/15.0.7/include/tgmath.h(34): Error: named parameter required before `...` #include @@ -79,9 +71,9 @@ float x = NAN; #endif #endif -#ifndef __DMC__ #ifndef __linux__ #ifndef __APPLE__ +#ifndef __OpenBSD__ #ifndef _MSC_VER #include #endif @@ -91,14 +83,10 @@ float x = NAN; #include -#ifndef __DMC__ // no uchar.h #ifndef __APPLE__ // no uchar.h #include #endif -#endif #include -#ifndef __DMC__ // wctype.h(102): Error: unterminated string constant starting at #defines(780) #include -#endif diff --git a/tests/dmd/compilable/test11559upgradeoptlink.d b/tests/dmd/compilable/test11559upgradeoptlink.d index b61ffc81d27..774176e4545 100644 --- a/tests/dmd/compilable/test11559upgradeoptlink.d +++ b/tests/dmd/compilable/test11559upgradeoptlink.d @@ -1,7 +1,5 @@ // REQUIRED_ARGS: -g -// If this is failing, you need optlink 8.00.14 or higher - string gen() { string m; diff --git a/tests/dmd/compilable/test16088.d b/tests/dmd/compilable/test16088.d deleted file mode 100644 index 97326f1fcd7..00000000000 --- a/tests/dmd/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/tests/dmd/compilable/test18955.d b/tests/dmd/compilable/test18955.d index af8908fc1b0..7fb1c176ca1 100644 --- a/tests/dmd/compilable/test18955.d +++ b/tests/dmd/compilable/test18955.d @@ -15,10 +15,5 @@ version(Windows) version(D_LP64) static assert(test.mangleof == "?test@@YAXAEBV?$basic_string@DU?$char_traits@D@std@@@std@@@Z"); else - { - version(CRuntime_DigitalMars) - static assert(test.mangleof == "?test@@YAXABV?$basic_string@std@DU?$char_traits@std@D@1@@std@@@Z"); - else - static assert(test.mangleof == "?test@@YAXABV?$basic_string@DU?$char_traits@D@std@@@std@@@Z"); - } + static assert(test.mangleof == "?test@@YAXABV?$basic_string@DU?$char_traits@D@std@@@std@@@Z"); } diff --git a/tests/dmd/compilable/test21227.d b/tests/dmd/compilable/test21227.d deleted file mode 100644 index 29dd2af29c3..00000000000 --- a/tests/dmd/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/tests/dmd/compilable/test21672.d b/tests/dmd/compilable/test21672.d index b74629065e7..4254dd20a8a 100644 --- a/tests/dmd/compilable/test21672.d +++ b/tests/dmd/compilable/test21672.d @@ -1,6 +1,6 @@ // LDC: removed required arg `-mcpu=avx2` // REQUIRED_ARGS: -O -// DISABLED: win32 linux32 freebsd32 +// DISABLED: win32 linux32 freebsd32 openbsd32 // https://issues.dlang.org/show_bug.cgi?id=21672 diff --git a/tests/dmd/compilable/test22346.c b/tests/dmd/compilable/test22346.c index e24e713fa91..9d1444ad740 100644 --- a/tests/dmd/compilable/test22346.c +++ b/tests/dmd/compilable/test22346.c @@ -1,4 +1,4 @@ -/* DISABLED: win32 win64 linux32 osx32 osx64 freebsd32 +/* DISABLED: win32 win64 linux32 osx32 osx64 freebsd32 openbsd32 */ // https://issues.dlang.org/show_bug.cgi?id=23346 diff --git a/tests/dmd/compilable/test24337.d b/tests/dmd/compilable/test24337.d new file mode 100644 index 00000000000..a31f665f352 --- /dev/null +++ b/tests/dmd/compilable/test24337.d @@ -0,0 +1,11 @@ +/* +TEST_OUTPUT: +--- +"ab"w x"11223344556677" +--- +*/ +// https://issues.dlang.org/show_bug.cgi?id=24337 + +immutable ushort[] y = cast(immutable ushort[]) "ab"w; +immutable ulong[] z = x"00 11 22 33 44 55 66 77"; +pragma(msg, y, " ", z); diff --git a/tests/dmd/compilable/test24594.c b/tests/dmd/compilable/test24594.c new file mode 100644 index 00000000000..caa85779c28 --- /dev/null +++ b/tests/dmd/compilable/test24594.c @@ -0,0 +1,28 @@ +#include + +struct S1 +{ + uint32_t a; + uint64_t b; +} __attribute__((packed)); + +_Static_assert(sizeof(S1) == 12, "S1 size"); +_Static_assert(&((struct S1*)0)->b == 4, "S1::b offset"); + +struct __attribute__((packed)) S2 +{ + uint8_t a; + uint16_t b; +}; + +_Static_assert(sizeof(S2) == 3, "S2 size"); +_Static_assert(&((struct S2*)0)->b == 1, "S2::b offset"); + +struct __attribute__((packed)) S3 +{ + uint32_t a; + uint8_t b; +}; + +_Static_assert(sizeof(S3) == 5, "S3 size"); +_Static_assert(&((struct S3*)0)->b == 4, "S3::b offset"); diff --git a/tests/dmd/compilable/testcstuff2.c b/tests/dmd/compilable/testcstuff2.c index c4d362b8a6c..2af2bec2b4a 100644 --- a/tests/dmd/compilable/testcstuff2.c +++ b/tests/dmd/compilable/testcstuff2.c @@ -759,3 +759,8 @@ typedef enum DISPLAYCONFIG_OUTPUT_TECHNOLOGY_SVIDEO = 1, DISPLAYCONFIG_OUTPUT_TECHNOLOGY_INTERNAL = 0x80000000, } DISPLAYCONFIG_VIDEO_OUTPUT_TECHNOLOGY; + +/************************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=24580 + +int ioctl(int __fd, unsigned __request, ...) __attribute__((overloadable)) __attribute__((enable_if(1, ""))) asm("ioctl"); diff --git a/tests/dmd/compilable/testcstuff4.i b/tests/dmd/compilable/testcstuff4.i index b2c078dc7b8..0e8d2cc013e 100644 --- a/tests/dmd/compilable/testcstuff4.i +++ b/tests/dmd/compilable/testcstuff4.i @@ -18,4 +18,4 @@ struct S21944 #1040 "cstuff3.c" 3 4 }; -_Static_assert(U'\U00011234' == 0x11234, "ok"); // sppn.exe doesn't support U character literals +_Static_assert(U'\U00011234' == 0x11234, "ok"); diff --git a/tests/dmd/compilable/zerosize.d b/tests/dmd/compilable/zerosize.d index 6e26deb5490..7986c92c7f8 100644 --- a/tests/dmd/compilable/zerosize.d +++ b/tests/dmd/compilable/zerosize.d @@ -6,10 +6,7 @@ version (CRuntime_Microsoft) else static assert(S.sizeof == 0); -version (CRuntime_DigitalMars) - static assert(S.alignof == 0); -else - static assert(S.alignof == 1); +static assert(S.alignof == 1); extern (C++) struct T { } diff --git a/tests/dmd/dshell/cpp_header_gen.d b/tests/dmd/dshell/cpp_header_gen.d index 86548e276aa..dcf8681451a 100644 --- a/tests/dmd/dshell/cpp_header_gen.d +++ b/tests/dmd/dshell/cpp_header_gen.d @@ -9,16 +9,6 @@ int main() writeln("CPP header generation test was skipped because $CXX is empty!"); return DISABLED; } - // DMC cannot compile the generated headers ... - version (Windows) - { - import std.algorithm : canFind; - if (CXX.canFind("dmc")) - { - writeln("CPP header generation test was skipped because DMC is not supported!"); - return DISABLED; - } - } Vars.set("SOURCE_DIR", "$EXTRA_FILES/cpp_header_gen"); Vars.set("LIB", "$OUTPUT_BASE/library$LIBEXT"); diff --git a/tests/dmd/dshell/defaults.d b/tests/dmd/dshell/defaults.d index 4dec8963bca..e13cd2fbc7e 100644 --- a/tests/dmd/dshell/defaults.d +++ b/tests/dmd/dshell/defaults.d @@ -49,13 +49,6 @@ void testConfigurations() "-conf=" ~ configPath ]; - version (Windows) if (MODEL == "32omf") - { - // 32-OMF tries to use `optlink.exe` located next to `sc.ini` - // and also doesn't like the LIB setup, so skip it for now - extraFlags = [""]; - } - foreach (const target; targets) { foreach (const flags; extraFlags) diff --git a/tests/dmd/dshell/dll.d b/tests/dmd/dshell/dll.d index f30e49a5394..930b5ed8715 100644 --- a/tests/dmd/dshell/dll.d +++ b/tests/dmd/dshell/dll.d @@ -7,8 +7,6 @@ int main() if (Vars.BUILD_SHARED_LIBS == "OFF") return DISABLED; } - else version (Windows) if (Vars.MODEL == "32omf") // Avoid optlink - return DISABLED; version (DigitalMars) { diff --git a/tests/dmd/dshell/dll_cxx.d b/tests/dmd/dshell/dll_cxx.d index 3c7c108718c..c8922b72e88 100644 --- a/tests/dmd/dshell/dll_cxx.d +++ b/tests/dmd/dshell/dll_cxx.d @@ -25,18 +25,9 @@ int main() version (Windows) { Vars.set(`DLL_LIB`, `$OUTPUT_BASE${SEP}mydll.lib`); - if (Vars.MODEL == "32omf") - { - // CXX should be dmc for win32omf. - dllCmd ~= [`-mn`, `-L/implib:` ~ Vars.DLL_LIB, `-WD`, `-o` ~ Vars.DLL, `kernel32.lib`, `user32.lib`]; - mainExtra = `$DLL_LIB`; - } - else - { - // CXX should be cl for win32mscoff. - dllCmd ~= [`/LD`, `/nologo`, `/Fe` ~ Vars.DLL]; - mainExtra = `$DLL_LIB`; - } + // CXX should be cl + dllCmd ~= [`/LD`, `/nologo`, `/Fe` ~ Vars.DLL]; + mainExtra = `$DLL_LIB`; } else version(OSX) { @@ -55,7 +46,7 @@ int main() // The arguments have to be passed as an array, because run would replace '/' with '\\' otherwise. run(dllCmd); - run(`$DMD -m$MODEL -I$SRC -g -od=$OUTPUT_BASE -of=$EXE_NAME $SRC/testdll.d $SRC/cppnew.d ` ~ mainExtra); + run(`$DMD -m$MODEL -g -od=$OUTPUT_BASE -of=$EXE_NAME $SRC/testdll.d ` ~ mainExtra); run(`$EXE_NAME`, stdout, stderr, [`LD_LIBRARY_PATH`: Vars.OUTPUT_BASE]); diff --git a/tests/dmd/dshell/extra-files/dll_cxx/cppnew.d b/tests/dmd/dshell/extra-files/dll_cxx/cppnew.d deleted file mode 100644 index cae1822404e..00000000000 --- a/tests/dmd/dshell/extra-files/dll_cxx/cppnew.d +++ /dev/null @@ -1,81 +0,0 @@ -module cppnew; - -/* This module contains copies from core.stdcpp.new_.d, but with - * modifications for DMC. */ - -T* cpp_new(T, Args...)(auto ref Args args) if (!is(T == class)) -{ - import core.lifetime : emplace, forward; - - T* mem = cast(T*)__cpp_new(T.sizeof); - return mem.emplace(forward!args); -} - -T cpp_new(T, Args...)(auto ref Args args) if (is(T == class)) -{ - import core.lifetime : emplace, forward; - - T mem = cast(T)__cpp_new(__traits(classInstanceSize, T)); - return mem.emplace(forward!args); -} - -void cpp_delete(T)(T* ptr) if (!is(T == class)) -{ - destroy!false(*ptr); - __cpp_delete(ptr); -} - -void cpp_delete(T)(T instance) if (is(T == class)) -{ - destroy!false(instance); - __cpp_delete(cast(void*) instance); -} - -/// Binding for ::operator new(std::size_t count) -pragma(mangle, __new_mangle) -extern(C++) void* __cpp_new(size_t count); - -/// Binding for ::operator delete(void* ptr) -pragma(mangle, __delete_mangle) -extern(C++) void __cpp_delete(void* ptr); - -// we have to hard-code the mangling for the global new/delete operators -version (CppRuntime_Microsoft) -{ - version (D_LP64) - { - enum __new_mangle = "??2@YAPEAX_K@Z"; - enum __delete_mangle = "??3@YAXPEAX@Z"; - } - else - { - enum __new_mangle = "??2@YAPAXI@Z"; - enum __delete_mangle = "??3@YAXPAX@Z"; - } -} -else version (CppRuntime_DigitalMars) -{ - version (D_LP64) - { - enum __new_mangle = "??2@YAPEAX_K@Z"; - enum __delete_mangle = "??3@YAXPEAX@Z"; - } - else - { - enum __new_mangle = "??2@YAPAXI@Z"; - enum __delete_mangle = "??3@YAXPAX@Z"; - } -} -else -{ - version (D_LP64) - { - enum __new_mangle = "_Znwm"; - enum __delete_mangle = "_ZdlPv"; - } - else - { - enum __new_mangle = "_Znwj"; - enum __delete_mangle = "_ZdlPv"; - } -} diff --git a/tests/dmd/dshell/extra-files/dll_cxx/testdll.d b/tests/dmd/dshell/extra-files/dll_cxx/testdll.d index 287176dce05..1c852aa1048 100644 --- a/tests/dmd/dshell/extra-files/dll_cxx/testdll.d +++ b/tests/dmd/dshell/extra-files/dll_cxx/testdll.d @@ -24,7 +24,7 @@ extern(C++) struct S22323 void test22323() { - import cppnew; + import core.stdcpp.new_; assert(C22323.ctorCount == 0); assert(C22323.dtorCount == 0); diff --git a/tests/dmd/dshell/linker_flag_with_spaces.d b/tests/dmd/dshell/linker_flag_with_spaces.d index a904ef3d1cd..187532661a7 100644 --- a/tests/dmd/dshell/linker_flag_with_spaces.d +++ b/tests/dmd/dshell/linker_flag_with_spaces.d @@ -2,15 +2,6 @@ import dshell; int main() { - version (DigitalMars) - { - if (OS == "windows" && MODEL == "32omf") - { - writeln("Skipping test when using Optlink."); - return DISABLED; - } - } - Vars.set("lib", "$OUTPUT_BASE/dir with spaces/b$LIBEXT"); run("$DMD -m$MODEL -of$lib -lib $EXTRA_FILES/linker_flag_with_spaces_b.d"); diff --git a/tests/dmd/fail_compilation/bool_cast.d b/tests/dmd/fail_compilation/bool_cast.d new file mode 100644 index 00000000000..830360a74c3 --- /dev/null +++ b/tests/dmd/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/tests/dmd/fail_compilation/cast_qual.d b/tests/dmd/fail_compilation/cast_qual.d index 19932f81165..5821dc14994 100644 --- a/tests/dmd/fail_compilation/cast_qual.d +++ b/tests/dmd/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/tests/dmd/fail_compilation/cpp_cast.d b/tests/dmd/fail_compilation/cpp_cast.d new file mode 100644 index 00000000000..3802ebd5e92 --- /dev/null +++ b/tests/dmd/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/tests/dmd/fail_compilation/fail13577.d b/tests/dmd/fail_compilation/fail13577.d index 79f9068c759..f1048073591 100644 --- a/tests/dmd/fail_compilation/fail13577.d +++ b/tests/dmd/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/tests/dmd/fail_compilation/fail17105.d b/tests/dmd/fail_compilation/fail17105.d index 7fe6129d98a..4ea8a8a4f6a 100644 --- a/tests/dmd/fail_compilation/fail17105.d +++ b/tests/dmd/fail_compilation/fail17105.d @@ -1,5 +1,5 @@ /* REQUIRED_ARGS: -m64 -DISABLED: win32 linux32 osx32 freebsd32 LDC +DISABLED: win32 linux32 osx32 freebsd32 openbsd32 LDC TEST_OUTPUT: --- fail_compilation/fail17105.d(20): Error: missing 4th parameter to `__simd()` diff --git a/tests/dmd/fail_compilation/fail18372.d b/tests/dmd/fail_compilation/fail18372.d index c492a6082ae..b5eb200f43b 100644 --- a/tests/dmd/fail_compilation/fail18372.d +++ b/tests/dmd/fail_compilation/fail18372.d @@ -1,5 +1,5 @@ /* -DISABLED: win32 win64 linux32 osx32 freebsd32 LDC +DISABLED: win32 win64 linux32 osx32 freebsd32 openbsd32 LDC TEST_OUTPUT: --- fail_compilation/fail18372.d(103): Error: `__va_list_tag` is not defined, perhaps `import core.stdc.stdarg;` ? diff --git a/tests/dmd/fail_compilation/fail20000.d b/tests/dmd/fail_compilation/fail20000.d index fe481216be6..a049dacb2e6 100644 --- a/tests/dmd/fail_compilation/fail20000.d +++ b/tests/dmd/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/tests/dmd/fail_compilation/fail6451.d b/tests/dmd/fail_compilation/fail6451.d index 6cc6ad7b22c..79b35244b6b 100644 --- a/tests/dmd/fail_compilation/fail6451.d +++ b/tests/dmd/fail_compilation/fail6451.d @@ -1,5 +1,5 @@ /* -DISABLED: win32 win64 linux32 osx32 freebsd32 LDC +DISABLED: win32 win64 linux32 osx32 freebsd32 openbsd32 LDC TEST_OUTPUT: --- fail_compilation/fail6451.d(9): Error: `__va_list_tag` is not defined, perhaps `import core.stdc.stdarg;` ? diff --git a/tests/dmd/fail_compilation/ice20042.d b/tests/dmd/fail_compilation/ice20042.d index 6b71903c9ca..7a674b3c546 100644 --- a/tests/dmd/fail_compilation/ice20042.d +++ b/tests/dmd/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/tests/dmd/fail_compilation/ice20264.d b/tests/dmd/fail_compilation/ice20264.d index df6667d9e4b..a8a1e7119be 100644 --- a/tests/dmd/fail_compilation/ice20264.d +++ b/tests/dmd/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/tests/dmd/fail_compilation/impconv.d b/tests/dmd/fail_compilation/impconv.d index cb1cb8e21ee..0cc2deb13d8 100644 --- a/tests/dmd/fail_compilation/impconv.d +++ b/tests/dmd/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/tests/dmd/fail_compilation/issue24534.d b/tests/dmd/fail_compilation/issue24534.d new file mode 100644 index 00000000000..1689b6c5d1b --- /dev/null +++ b/tests/dmd/fail_compilation/issue24534.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/issue24534.d(12): Error: `goto` skips declaration of variable `issue24534.f1.y1` +fail_compilation/issue24534.d(13): declared here +fail_compilation/issue24534.d(20): Error: `goto` skips declaration of variable `issue24534.f2.y2` +fail_compilation/issue24534.d(22): declared here +--- +*/ +void f1(){ //always failed with error about skipping a declaration + int x1; + goto Label1; + int y1; + Label1: + int z1; +} + +void f2(){ //compiled fine before this bug was fixed + int x2; + goto Label2; + Dummy2: + int y2; + Label2: + int z2; +} diff --git a/tests/dmd/fail_compilation/onemember_overloads.d b/tests/dmd/fail_compilation/onemember_overloads.d new file mode 100644 index 00000000000..40d23b3f01e --- /dev/null +++ b/tests/dmd/fail_compilation/onemember_overloads.d @@ -0,0 +1,38 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/onemember_overloads.d(29): Error: none of the overloads of `skipOver` are callable using argument types `()` +fail_compilation/onemember_overloads.d(25): Candidates are: `onemember_overloads.skipOver(string)` +fail_compilation/onemember_overloads.d(18): `skipOver(alias pred = (a, b) => a == b)` +fail_compilation/onemember_overloads.d(20): - Containing: `skipOver(Haystack, Needles...)(ref Haystack haystack, Needles needles)` +fail_compilation/onemember_overloads.d(21): - Containing: `skipOver(R)(ref R r1)` +fail_compilation/onemember_overloads.d(22): - Containing: `skipOver(R, Es...)(ref R r, Es es)` +fail_compilation/onemember_overloads.d(30): Error: template `t2` is not callable using argument types `!()()` +fail_compilation/onemember_overloads.d(33): Candidate is: `t2(T)` +fail_compilation/onemember_overloads.d(35): - Containing: `t2(string)` +fail_compilation/onemember_overloads.d(36): - Containing: `t2(int[])` +fail_compilation/onemember_overloads.d(37): - Containing: `t2(R)(R)` +--- +*/ + +template skipOver(alias pred = (a, b) => a == b) +{ + bool skipOver(Haystack, Needles...)(ref Haystack haystack, Needles needles) => true; + bool skipOver(R)(ref R r1) => true; + bool skipOver(R, Es...)(ref R r, Es es) => true; +} + +void skipOver(string); + +void main() +{ + skipOver(); + t2(); +} + +template t2(T) +{ + bool t2(string); + bool t2(int[]); + bool t2(R)(R); +} diff --git a/tests/dmd/fail_compilation/reserved_version.d b/tests/dmd/fail_compilation/reserved_version.d index ac00b4d3b50..502ae4a5bca 100644 --- a/tests/dmd/fail_compilation/reserved_version.d +++ b/tests/dmd/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/tests/dmd/fail_compilation/reserved_version_switch.d b/tests/dmd/fail_compilation/reserved_version_switch.d index 44db4041028..2b6bb5e5351 100644 --- a/tests/dmd/fail_compilation/reserved_version_switch.d +++ b/tests/dmd/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/tests/dmd/fail_compilation/retref2.d b/tests/dmd/fail_compilation/retref2.d index aaa5b41e306..ca64653efae 100644 --- a/tests/dmd/fail_compilation/retref2.d +++ b/tests/dmd/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/tests/dmd/fail_compilation/shared.d b/tests/dmd/fail_compilation/shared.d index 8b94a7981a1..13b24c81cf8 100644 --- a/tests/dmd/fail_compilation/shared.d +++ b/tests/dmd/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/tests/dmd/fail_compilation/system_ptr_cast.d b/tests/dmd/fail_compilation/system_ptr_cast.d new file mode 100644 index 00000000000..fc10b2a7801 --- /dev/null +++ b/tests/dmd/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/tests/dmd/fail_compilation/test15660.d b/tests/dmd/fail_compilation/test15660.d index ae573b2af2a..9bf05d12538 100644 --- a/tests/dmd/fail_compilation/test15660.d +++ b/tests/dmd/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/tests/dmd/fail_compilation/test15672.d b/tests/dmd/fail_compilation/test15672.d index 1c3bedfc2a2..c3d14db2100 100644 --- a/tests/dmd/fail_compilation/test15672.d +++ b/tests/dmd/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/tests/dmd/fail_compilation/test15703.d b/tests/dmd/fail_compilation/test15703.d index 88a510dfed2..4e47c3d7945 100644 --- a/tests/dmd/fail_compilation/test15703.d +++ b/tests/dmd/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/tests/dmd/fail_compilation/test15704.d b/tests/dmd/fail_compilation/test15704.d index 2be9d30f0a0..04d4be4aa93 100644 --- a/tests/dmd/fail_compilation/test15704.d +++ b/tests/dmd/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/tests/dmd/fail_compilation/test19646.d b/tests/dmd/fail_compilation/test19646.d index c9d0e08f6e0..766b387a559 100644 --- a/tests/dmd/fail_compilation/test19646.d +++ b/tests/dmd/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/tests/dmd/fail_compilation/union_conv.d b/tests/dmd/fail_compilation/union_conv.d new file mode 100644 index 00000000000..f08809c4850 --- /dev/null +++ b/tests/dmd/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/tests/dmd/fail_compilation/vector_types.d b/tests/dmd/fail_compilation/vector_types.d index 2babdb60713..92284d884e6 100644 --- a/tests/dmd/fail_compilation/vector_types.d +++ b/tests/dmd/fail_compilation/vector_types.d @@ -1,7 +1,7 @@ /* REQUIRED_ARGS: -o- TEST_OUTPUT: -DISABLED: LDC freebsd32 linux32 osx32 win32 +DISABLED: LDC freebsd32 openbsd32 linux32 osx32 win32 --- fail_compilation/vector_types.d(15): Error: 32 byte vector type `__vector(double[4])` is not supported on this platform fail_compilation/vector_types.d(16): Error: 32 byte vector type `__vector(float[8])` is not supported on this platform diff --git a/tests/dmd/fail_compilation/void_cat.d b/tests/dmd/fail_compilation/void_cat.d new file mode 100644 index 00000000000..da92d3b75b4 --- /dev/null +++ b/tests/dmd/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/tests/dmd/fail_compilation/xmmslice.d b/tests/dmd/fail_compilation/xmmslice.d index bd9f52e914a..f40a84865ae 100644 --- a/tests/dmd/fail_compilation/xmmslice.d +++ b/tests/dmd/fail_compilation/xmmslice.d @@ -1,6 +1,6 @@ /* REQUIRED_ARGS: -mcpu=avx -DISABLED: win32 freebsd32 linux32 osx32 LDC_not_x86 +DISABLED: win32 freebsd32 openbsd32 linux32 osx32 LDC_not_x86 TEST_OUTPUT: --- fail_compilation/xmmslice.d(110): Error: `__vector(int[4])` cannot be sliced with `[]` diff --git a/tests/dmd/run.d b/tests/dmd/run.d index 3bed3fd03fe..1ef15b82e6b 100755 --- a/tests/dmd/run.d +++ b/tests/dmd/run.d @@ -319,12 +319,9 @@ void ensureToolsExists(const string[string] env, const TestTool[] tools ...) } else { - string model = env["MODEL"]; - if (model == "32omf") model = "32"; - buildCommand = [ hostDMD, - "-m"~model, + "-m"~env["MODEL"], "-of"~targetBin, sourceFile ] ~ getPicFlags(env) ~ tool.extraArgs; diff --git a/tests/dmd/runnable/arm.d b/tests/dmd/runnable/arm.d new file mode 100644 index 00000000000..f994cde4f42 --- /dev/null +++ b/tests/dmd/runnable/arm.d @@ -0,0 +1,63 @@ + +/************************************** + * Tests aimed at the Arm code generator, even though they also + * need to pass the x86 compiler. + */ + +import core.stdc.stdio; + +/******************************************************/ + +pragma(inline, false) +{ +ulong movregconst64_0() { return 0x123456789abcdef0; } +ulong movregconst64_1() { return 0x12345678; } +ulong movregconst64_2() { return 0xFFFF5678; } +ulong movregconst64_3() { return 0x1234FFFF; } +ulong movregconst64_4() { return 0xFFFF_FFFF_FFFF_1234; } +ulong movregconst64_5() { return 0xFFFF_FFFF_1234_FFFF; } +ulong movregconst64_6() { return 0xFFFF_1234_FFFF_FFFF; } +ulong movregconst64_7() { return 0x1234_FFFF_FFFF_FFFF; } +ulong movregconst64_8() { return 0x5555_5555_5555_5555; } +ulong movregconst64_9() { return 0xAAAA_AAAA_AAAA_AAAA; } +ulong movregconst64_10() { return 0xFFFF_FFFF_FFFF_FFFE; } + +uint movregconst32_0() { return 0x12345678; } +uint movregconst32_1() { return 0xFFFF5678; } +uint movregconst32_2() { return 0x1234FFFF; } +uint movregconst32_3() { return 0x55555555; } +uint movregconst32_4() { return 0xAAAAAAAA; } +uint movregconst32_5() { return 0xFFFFFFFF; } +} + +void testmovregconst() +{ + assert(movregconst64_0() == 0x123456789abcdef0); + assert(movregconst64_1() == 0x12345678); + assert(movregconst64_2() == 0xFFFF5678); + assert(movregconst64_3() == 0x1234FFFF); + assert(movregconst64_4() == 0xFFFF_FFFF_FFFF_1234); + assert(movregconst64_5() == 0xFFFF_FFFF_1234_FFFF); + assert(movregconst64_6() == 0xFFFF_1234_FFFF_FFFF); + assert(movregconst64_7() == 0x1234_FFFF_FFFF_FFFF); + assert(movregconst64_8() == 0x5555_5555_5555_5555); + assert(movregconst64_9() == 0xAAAA_AAAA_AAAA_AAAA); + assert(movregconst64_10() == 0xFFFF_FFFF_FFFF_FFFE); + + assert(movregconst32_0() == 0x12345678); + assert(movregconst32_1() == 0xFFFF5678); + assert(movregconst32_2() == 0x1234FFFF); + assert(movregconst32_3() == 0x55555555); + assert(movregconst32_4() == 0xAAAAAAAA); + assert(movregconst32_5() == 0xFFFFFFFF); +} + +/******************************************************/ + +int main() +{ + testmovregconst(); + + printf("Success\n"); + return 0; +} diff --git a/tests/dmd/runnable/bitfieldsdm.c b/tests/dmd/runnable/bitfieldsdm.c deleted file mode 100644 index 65fd85cd38f..00000000000 --- a/tests/dmd/runnable/bitfieldsdm.c +++ /dev/null @@ -1,206 +0,0 @@ -/* test bitfields for Digital Mars C - * Note that this test is for win32 only - * - * REQUIRED_ARGS: - * DISABLED: win32mscoff win64 linux freebsd osx LDC - * RUN_OUTPUT: ---- - DM | MS | P32 | P64 -T0 = 1 1 || 1 1 | 1 1 | 1 1 | 1 1 -T1 = 2 2 || 2 2 | 2 2 | 2 2 | 2 2 -T2 = 4 4 || 4 4 | 4 4 | 4 4 | 4 4 -T3 = 16 8 || 16 8 | 16 8 | 8 4 | 8 8 -T4 = 16 8 || 16 8 | 16 8 | 12 4 | 16 8 -T5 = 16 8 || 16 8 | 16 8 | 8 4 | 8 8 -S1 = 8 8 || 8 8 | 8 8 | 4 4 | 8 8 -S2 = 4 4 || 4 4 | 4 4 | 4 4 | 4 4 -S3 = 8 4 || 8 4 | 8 4 | 4 4 | 4 4 -S4 = 8 4 || 8 4 | 8 4 | 4 4 | 4 4 -S5 = 8 4 || 8 4 | 8 4 | 4 4 | 4 4 -S6 = 2 2 || 2 2 | 2 2 | 2 2 | 2 2 -S7 = 16 8 || 16 8 | 16 8 | 4 4 | 8 8 -S8 = 4 2 || 4 2 | 4 2 | 2 2 | 2 2 -S8A = 4 2 || 4 2 | 4 2 | 2 2 | 2 2 -S8B = 6 2 || 6 2 | 6 2 | 2 2 | 2 2 -S8C = 8 4 || 8 4 | 8 4 | 4 4 | 4 4 -S9 = 4 2 || 4 2 | 4 2 | 4 2 | 4 2 -S10 = 0 0 || 0 0 | * * | 0 1 | 0 1 -S11 = 0 0 || 0 0 | 4 1 | 0 1 | 0 1 -S12 = 4 4 || 4 4 | 4 4 | 4 4 | 4 4 -S13 = 8 4 || 8 4 | 8 4 | 8 4 | 8 4 -S14 = 8 4 || 8 4 | 8 4 | 8 4 | 8 4 -S15 = 8 4 || 8 4 | 8 4 | 4 4 | 4 4 -S16 = 0 0 || 0 0 | 4 4 | 4 1 | 4 1 -S17 = 4 4 || 4 4 | 4 4 | 4 4 | 4 4 -S18 = 2 1 || 2 1 | 2 1 | 5 1 | 9 1 -A0 = 16 8 || 16 8 | 16 8 | 12 4 | 16 8 -A1 = 12 4 || 12 4 | 12 4 | 12 4 | 12 4 -A2 = 12 4 || 12 4 | 12 4 | 12 4 | 12 4 -A3 = 16 4 || 16 4 | 16 4 | 16 4 | 16 4 -A4 = 12 4 || 12 4 | 12 4 | 8 4 | 8 4 -A5 = 2 1 || 2 1 | 2 1 | 2 1 | 2 1 -A6 = 4 2 || 4 2 | 4 2 | 2 2 | 2 2 -A7 = 16 4 || 16 4 | 16 4 | 12 4 | 16 8 -A8 = 12 4 || 12 4 | 12 4 | 8 4 | 8 8 -A9 = 32 8 || 32 8 | 32 8 | 16 4 | 16 8 -A10 = 4 2 || 4 2 | 4 2 | 2 2 | 2 2 -A11 = 16 4 || 16 4 | 16 4 | 12 4 | 12 4 -S9 = x30200 -S14 = x300000201 -S15 = x201 -S18 = 1 should be 4 -A0 = x1 ---- - */ - -int printf(const char *fmt, ...); -void exit(int); - -void assert(int n, int b) -{ - if (!b) - { - printf("assert fail %d\n", n); - exit(1); - } -} - -int is64bit() { return sizeof(long) == 8; } // otherwise assume 32 bit - -/*************************************************************/ - -struct T0 { char x:1; }; // -struct T1 { short x:1; }; // -struct T2 { int x:1; }; // -struct T3 { char a,b,c,d; long long x:1; }; // -struct T4 { char a,b,c,d,e,f,g,h; long long x:1; }; // -struct T5 { char a,b,c,d,e,f,g; long long x:1; }; // -struct S1 { long long int f:1; }; // -struct S2 { int x:1; int y:1; }; // -struct S3 { short c; int x:1; unsigned y:1; }; // -struct S4 { int x:1; short y:1; }; // -struct S5 { short x:1; int y:1; }; // -struct S6 { short x:1; short y:1; }; // -struct S7 { short x:1; int y:1; long long z:1; }; // -struct S8 { char a; char b:1; short c:2; }; // -struct S8A { char b:1; short c:2; }; // -struct S8B { char a; short b:1; char c:2; }; // -struct S8C { char a; int b:1; }; // -struct S9 { char a; char b:2; short c:9; }; // -struct S10 { }; // -struct S11 { int :0; }; // -struct S12 { int :0; int x; }; // -struct S13 { unsigned x:12; unsigned x1:1; unsigned x2:1; unsigned x3:1; unsigned x4:1; int w; }; // -struct S14 { char a; char b:4; int c:30; }; // -struct S15 { char a; char b:2; int c:9; }; // -struct S16 { int :32; }; // -struct S17 { int a:32; }; // -struct S18 { char a; long long :0; char b; }; // -struct A0 { int a; long long b:34, c:4; }; // -struct A1 { int a; unsigned b:11; int c; }; // -struct A2 { int a; unsigned b:11, c:5, d:16; // - int e; }; -struct A3 { int a; unsigned b:11, c:5, :0, d:16; // - int e; }; -struct A4 { int a:8; short b:7; // - unsigned int c:29; }; -struct A5 { char a:7, b:2; }; // -struct A6 { char a:7; short b:2; }; // -struct A7 { short a:8; long b:16; int c; // - char d:7; }; -struct A8 { short a:8; long b:16; int :0; // - char c:7; }; -struct A9 { unsigned short a:8; long b:16; // - unsigned long c:29; long long d:9; - unsigned long e:2, f:31; }; -struct A10 { unsigned short a:8; char b; }; // -struct A11 { char a; int b:5, c:11, :0, d:8; // - struct { int ee:8; } e; }; - -int main() -{ - /* MS produces identical results for 32 and 64 bit compiles, - * DM is 32 bit only - */ - printf(" DM | MS | P32 | P64\n"); - printf("T0 = %2d %d || 1 1 | 1 1 | 1 1 | 1 1\n", (int)sizeof(struct T0), (int)_Alignof(struct T0)); - printf("T1 = %2d %d || 2 2 | 2 2 | 2 2 | 2 2\n", (int)sizeof(struct T1), (int)_Alignof(struct T1)); - printf("T2 = %2d %d || 4 4 | 4 4 | 4 4 | 4 4\n", (int)sizeof(struct T2), (int)_Alignof(struct T2)); - printf("T3 = %2d %d || 16 8 | 16 8 | 8 4 | 8 8\n", (int)sizeof(struct T3), (int)_Alignof(struct T3)); - printf("T4 = %2d %d || 16 8 | 16 8 | 12 4 | 16 8\n", (int)sizeof(struct T4), (int)_Alignof(struct T4)); - printf("T5 = %2d %d || 16 8 | 16 8 | 8 4 | 8 8\n", (int)sizeof(struct T5), (int)_Alignof(struct T5)); - printf("S1 = %2d %d || 8 8 | 8 8 | 4 4 | 8 8\n", (int)sizeof(struct S1), (int)_Alignof(struct S1)); - printf("S2 = %2d %d || 4 4 | 4 4 | 4 4 | 4 4\n", (int)sizeof(struct S2), (int)_Alignof(struct S2)); - printf("S3 = %2d %d || 8 4 | 8 4 | 4 4 | 4 4\n", (int)sizeof(struct S3), (int)_Alignof(struct S3)); - printf("S4 = %2d %d || 8 4 | 8 4 | 4 4 | 4 4\n", (int)sizeof(struct S4), (int)_Alignof(struct S4)); - printf("S5 = %2d %d || 8 4 | 8 4 | 4 4 | 4 4\n", (int)sizeof(struct S5), (int)_Alignof(struct S5)); - printf("S6 = %2d %d || 2 2 | 2 2 | 2 2 | 2 2\n", (int)sizeof(struct S6), (int)_Alignof(struct S6)); - printf("S7 = %2d %d || 16 8 | 16 8 | 4 4 | 8 8\n", (int)sizeof(struct S7), (int)_Alignof(struct S7)); - printf("S8 = %2d %d || 4 2 | 4 2 | 2 2 | 2 2\n", (int)sizeof(struct S8), (int)_Alignof(struct S8)); - printf("S8A = %2d %d || 4 2 | 4 2 | 2 2 | 2 2\n", (int)sizeof(struct S8A), (int)_Alignof(struct S8A)); - printf("S8B = %2d %d || 6 2 | 6 2 | 2 2 | 2 2\n", (int)sizeof(struct S8B), (int)_Alignof(struct S8B)); - printf("S8C = %2d %d || 8 4 | 8 4 | 4 4 | 4 4\n", (int)sizeof(struct S8C), (int)_Alignof(struct S8C)); - printf("S9 = %2d %d || 4 2 | 4 2 | 4 2 | 4 2\n", (int)sizeof(struct S9), (int)_Alignof(struct S9)); - printf("S10 = %2d %d || 0 0 | * * | 0 1 | 0 1\n", (int)sizeof(struct S10), (int)_Alignof(struct S10)); // MS doesn't compile - printf("S11 = %2d %d || 0 0 | 4 1 | 0 1 | 0 1\n", (int)sizeof(struct S11), (int)_Alignof(struct S11)); - printf("S12 = %2d %d || 4 4 | 4 4 | 4 4 | 4 4\n", (int)sizeof(struct S12), (int)_Alignof(struct S12)); - printf("S13 = %2d %d || 8 4 | 8 4 | 8 4 | 8 4\n", (int)sizeof(struct S13), (int)_Alignof(struct S13)); - printf("S14 = %2d %d || 8 4 | 8 4 | 8 4 | 8 4\n", (int)sizeof(struct S14), (int)_Alignof(struct S14)); - printf("S15 = %2d %d || 8 4 | 8 4 | 4 4 | 4 4\n", (int)sizeof(struct S15), (int)_Alignof(struct S15)); - printf("S16 = %2d %d || 0 0 | 4 4 | 4 1 | 4 1\n", (int)sizeof(struct S16), (int)_Alignof(struct S16)); - printf("S17 = %2d %d || 4 4 | 4 4 | 4 4 | 4 4\n", (int)sizeof(struct S17), (int)_Alignof(struct S17)); - printf("S18 = %2d %d || 2 1 | 2 1 | 5 1 | 9 1\n", (int)sizeof(struct S18), (int)_Alignof(struct S18)); - printf("A0 = %2d %d || 16 8 | 16 8 | 12 4 | 16 8\n", (int)sizeof(struct A0), (int)_Alignof(struct A0)); - printf("A1 = %2d %d || 12 4 | 12 4 | 12 4 | 12 4\n", (int)sizeof(struct A1), (int)_Alignof(struct A1)); - printf("A2 = %2d %d || 12 4 | 12 4 | 12 4 | 12 4\n", (int)sizeof(struct A2), (int)_Alignof(struct A2)); - printf("A3 = %2d %d || 16 4 | 16 4 | 16 4 | 16 4\n", (int)sizeof(struct A3), (int)_Alignof(struct A3)); - printf("A4 = %2d %d || 12 4 | 12 4 | 8 4 | 8 4\n", (int)sizeof(struct A4), (int)_Alignof(struct A4)); - printf("A5 = %2d %d || 2 1 | 2 1 | 2 1 | 2 1\n", (int)sizeof(struct A5), (int)_Alignof(struct A5)); - printf("A6 = %2d %d || 4 2 | 4 2 | 2 2 | 2 2\n", (int)sizeof(struct A6), (int)_Alignof(struct A6)); - printf("A7 = %2d %d || 16 4 | 16 4 | 12 4 | 16 8\n", (int)sizeof(struct A7), (int)_Alignof(struct A7)); - printf("A8 = %2d %d || 12 4 | 12 4 | 8 4 | 8 8\n", (int)sizeof(struct A8), (int)_Alignof(struct A8)); - printf("A9 = %2d %d || 32 8 | 32 8 | 16 4 | 16 8\n", (int)sizeof(struct A9), (int)_Alignof(struct A9)); - printf("A10 = %2d %d || 4 2 | 4 2 | 2 2 | 2 2\n", (int)sizeof(struct A10), (int)_Alignof(struct A10)); - printf("A11 = %2d %d || 16 4 | 16 4 | 12 4 | 12 4\n", (int)sizeof(struct A11), (int)_Alignof(struct A11)); - - { - struct S9 s; - unsigned x; - *(unsigned *)&s = 0; - s.b = 2; s.c = 3; - x = *(unsigned *)&s; - printf("S9 = x%x\n", x); - } - { - struct S14 s = { 1, 2, 3 }; - unsigned long long v; - *(long long *)&s = 0; - s.a = 1; - s.b = 2; - s.c = 3; - v = *(unsigned long long *)&s; - printf("S14 = x%llx\n", v); - } - { - struct S15 s = { 1,2,3 }; - unsigned x; - *(unsigned *)&s = 0; - s.a = 1; s.b = 2; s.c = 3; - x = *(unsigned *)&s; - printf("S15 = x%x\n", x); - } - { - struct S18 s; - printf("S18 = %d should be %d\n", (int)(&s.b - &s.a), is64bit() ? 8 : 4); - } - { - struct A0 s; - long long x; - *(long long *)&s = 0; - s.a = 1; s.b = 15; - x = *(long long *)&s; - printf("A0 = x%llx\n", x); - } - - return 0; -} diff --git a/tests/dmd/runnable/bitfieldsms.c b/tests/dmd/runnable/bitfieldsms.c index eb408442368..5aee443d558 100644 --- a/tests/dmd/runnable/bitfieldsms.c +++ b/tests/dmd/runnable/bitfieldsms.c @@ -1,5 +1,5 @@ /* test bitfields for Microsoft C - * DISABLED: win32 linux32 freebsd32 osx32 linux64 freebsd64 osx64 + * DISABLED: win32 linux freebsd openbsd osx * RUN_OUTPUT: --- DM | MS | P32 | P64 diff --git a/tests/dmd/runnable/bitfieldsposix32.c b/tests/dmd/runnable/bitfieldsposix32.c index b3aef1e9bdd..790b594912c 100644 --- a/tests/dmd/runnable/bitfieldsposix32.c +++ b/tests/dmd/runnable/bitfieldsposix32.c @@ -1,5 +1,5 @@ /* test bitfields - * DISABLED: win32 win64 linux64 freebsd64 osx64 + * DISABLED: win32 win64 linux64 freebsd64 openbsd64 osx64 * RUN_OUTPUT: --- T0 = 1 1 | 1 1 @@ -41,6 +41,10 @@ A8 = 8 4 | 8 4 A9 = 16 4 | 16 4 A10 = 2 2 | 2 2 A11 = 12 4 | 12 4 +Issue24592a = 8 4 | 8 4 +Issue24592b = 12 4 | 12 4 +Issue24592c = 24 4 | 24 4 +Issue24592d = 12 4 | 12 4 S9 = x30200 S14 = x300000201 S15 = xe01 @@ -112,6 +116,10 @@ struct A9 { unsigned short a:8; long b:16; // 16 4 (32 bit) 16 8 (64 b struct A10 { unsigned short a:8; char b; }; // 2 2 struct A11 { char a; int b:5, c:11, :0, d:8; // 12 4 struct { int ee:8; } e; }; +struct Issue24592a { unsigned long long a:20, b:20, c:24; }; +struct Issue24592b { unsigned int x; unsigned long long a:20, b:20, c:24; }; +struct Issue24592c { unsigned long long a:20, b:32, c:32, d:32, e:32, f:32; }; +struct Issue24592d { unsigned long long a:10, b:16, c:16, d:16, e:16, f:16; }; int main() { @@ -154,6 +162,10 @@ int main() printf("A9 = %d %d | 16 4\n", (int)sizeof(struct A9), (int)_Alignof(struct A9)); printf("A10 = %d %d | 2 2\n", (int)sizeof(struct A10), (int)_Alignof(struct A10)); printf("A11 = %d %d | 12 4\n", (int)sizeof(struct A11), (int)_Alignof(struct A11)); + printf("Issue24592a = %d %d | 8 4\n", (int)sizeof(struct Issue24592a), (int)_Alignof(struct Issue24592a)); + printf("Issue24592b = %d %d | 12 4\n", (int)sizeof(struct Issue24592b), (int)_Alignof(struct Issue24592b)); + printf("Issue24592c = %d %d | 24 4\n", (int)sizeof(struct Issue24592c), (int)_Alignof(struct Issue24592c)); + printf("Issue24592d = %d %d | 12 4\n", (int)sizeof(struct Issue24592d), (int)_Alignof(struct Issue24592d)); { struct S9 s; diff --git a/tests/dmd/runnable/bitfieldsposix64.c b/tests/dmd/runnable/bitfieldsposix64.c index e3a3b24c7f3..429be713899 100644 --- a/tests/dmd/runnable/bitfieldsposix64.c +++ b/tests/dmd/runnable/bitfieldsposix64.c @@ -1,5 +1,5 @@ /* test bitfields - * DISABLED: win32 win64 linux32 freebsd32 osx32 + * DISABLED: win32 win64 linux32 freebsd32 openbsd32 osx32 LDC_not_x86 // LDC: these bad tests fail for non-Apple AArch64 targets * RUN_OUTPUT: --- T0 = 1 1 | 1 1 @@ -41,6 +41,10 @@ A8 = 8 8 | 8 8 A9 = 16 8 | 16 8 A10 = 2 2 | 2 2 A11 = 12 4 | 12 4 +Issue24592a = 8 8 | 8 8 +Issue24592b = 16 8 | 16 8 +Issue24592c = 24 8 | 24 8 +Issue24592d = 16 8 | 16 8 S9 = x30200 S14 = x300000201 S15 = xe01 @@ -112,6 +116,10 @@ struct A9 { unsigned short a:8; long b:16; // 16 4 (32 bit) 16 8 (64 b struct A10 { unsigned short a:8; char b; }; // 2 2 struct A11 { char a; int b:5, c:11, :0, d:8; // 12 4 struct { int ee:8; } e; }; +struct Issue24592a { unsigned long long a:20, b:20, c:24; }; +struct Issue24592b { unsigned int x; unsigned long long a:20, b:20, c:24; }; +struct Issue24592c { unsigned long long a:20, b:32, c:32, d:32, e:32, f:32; }; +struct Issue24592d { unsigned long long a:10, b:16, c:16, d:16, e:16, f:16; }; int main() { @@ -154,6 +162,10 @@ int main() printf("A9 = %d %d | 16 8\n", (int)sizeof(struct A9), (int)_Alignof(struct A9)); printf("A10 = %d %d | 2 2\n", (int)sizeof(struct A10), (int)_Alignof(struct A10)); printf("A11 = %d %d | 12 4\n", (int)sizeof(struct A11), (int)_Alignof(struct A11)); + printf("Issue24592a = %d %d | 8 8\n", (int)sizeof(struct Issue24592a), (int)_Alignof(struct Issue24592a)); + printf("Issue24592b = %d %d | 16 8\n", (int)sizeof(struct Issue24592b), (int)_Alignof(struct Issue24592b)); + printf("Issue24592c = %d %d | 24 8\n", (int)sizeof(struct Issue24592c), (int)_Alignof(struct Issue24592c)); + printf("Issue24592d = %d %d | 16 8\n", (int)sizeof(struct Issue24592d), (int)_Alignof(struct Issue24592d)); { struct S9 s; diff --git a/tests/dmd/runnable/dbitfieldsdm.d b/tests/dmd/runnable/dbitfieldsdm.d deleted file mode 100644 index 24c402a98bc..00000000000 --- a/tests/dmd/runnable/dbitfieldsdm.d +++ /dev/null @@ -1,196 +0,0 @@ -/* test bitfields for Digital Mars - * Note that this test is for win32 only - * - * REQUIRED_ARGS: -preview=bitfields - * DISABLED: win32mscoff win64 linux freebsd osx LDC - * RUN_OUTPUT: ---- - DM | MS | P32 | P64 -T0 = 1 1 || 1 1 | 1 1 | 1 1 | 1 1 -T1 = 2 2 || 2 2 | 2 2 | 2 2 | 2 2 -T2 = 4 4 || 4 4 | 4 4 | 4 4 | 4 4 -T3 = 16 8 || 16 8 | 16 8 | 8 4 | 8 8 -T4 = 16 8 || 16 8 | 16 8 | 12 4 | 16 8 -T5 = 16 8 || 16 8 | 16 8 | 8 4 | 8 8 -S1 = 8 8 || 8 8 | 8 8 | 4 4 | 8 8 -S2 = 4 4 || 4 4 | 4 4 | 4 4 | 4 4 -S3 = 8 4 || 8 4 | 8 4 | 4 4 | 4 4 -S4 = 8 4 || 8 4 | 8 4 | 4 4 | 4 4 -S5 = 8 4 || 8 4 | 8 4 | 4 4 | 4 4 -S6 = 2 2 || 2 2 | 2 2 | 2 2 | 2 2 -S7 = 16 8 || 16 8 | 16 8 | 4 4 | 8 8 -S8 = 4 2 || 4 2 | 4 2 | 2 2 | 2 2 -S8A = 4 2 || 4 2 | 4 2 | 2 2 | 2 2 -S8B = 6 2 || 6 2 | 6 2 | 2 2 | 2 2 -S8C = 8 4 || 8 4 | 8 4 | 4 4 | 4 4 -S9 = 4 2 || 4 2 | 4 2 | 4 2 | 4 2 -S10 = 1 1 || 0 0 | * * | 0 1 | 0 1 -S11 = 1 1 || 0 0 | 4 1 | 0 1 | 0 1 -S12 = 4 4 || 4 4 | 4 4 | 4 4 | 4 4 -S13 = 8 4 || 8 4 | 8 4 | 8 4 | 8 4 -S14 = 8 4 || 8 4 | 8 4 | 8 4 | 8 4 -S15 = 8 4 || 8 4 | 8 4 | 4 4 | 4 4 -S16 = 1 1 || 0 0 | 4 4 | 4 1 | 4 1 -S17 = 4 4 || 4 4 | 4 4 | 4 4 | 4 4 -S18 = 2 1 || 2 1 | 2 1 | 5 1 | 9 1 -A0 = 16 8 || 16 8 | 16 8 | 12 4 | 16 8 -A1 = 12 4 || 12 4 | 12 4 | 12 4 | 12 4 -A2 = 12 4 || 12 4 | 12 4 | 12 4 | 12 4 -A3 = 16 4 || 16 4 | 16 4 | 16 4 | 16 4 -A4 = 12 4 || 12 4 | 12 4 | 8 4 | 8 4 -A5 = 2 1 || 2 1 | 2 1 | 2 1 | 2 1 -A6 = 4 2 || 4 2 | 4 2 | 2 2 | 2 2 -A7 = 16 4 || 16 4 | 16 4 | 12 4 | 16 8 -A8 = 12 4 || 12 4 | 12 4 | 8 4 | 8 8 -A9 = 32 8 || 32 8 | 32 8 | 16 4 | 16 8 -A10 = 4 2 || 4 2 | 4 2 | 2 2 | 2 2 -A11 = 16 4 || 16 4 | 16 4 | 12 4 | 12 4 -S9 = x30200 -S14 = x300000201 -S15 = x201 -S18 = 1 should be 4 -A0 = x1 ---- - */ - -import core.stdc.stdio; - -int is64bit() { return size_t.sizeof == 8; } // otherwise assume 32 bit - -/*************************************************************/ - -struct T0 { ubyte x:1; }; // -struct T1 { short x:1; }; // -struct T2 { int x:1; }; // -struct T3 { ubyte a,b,c,d; long x:1; }; // -struct T4 { ubyte a,b,c,d,e,f,g,h; long x:1; }; // -struct T5 { ubyte a,b,c,d,e,f,g; long x:1; }; // -struct S1 { long f:1; }; // -struct S2 { int x:1; int y:1; }; // -struct S3 { short c; int x:1; uint y:1; }; // -struct S4 { int x:1; short y:1; }; // -struct S5 { short x:1; int y:1; }; // -struct S6 { short x:1; short y:1; }; // -struct S7 { short x:1; int y:1; long z:1; }; // -struct S8 { ubyte a; ubyte b:1; short c:2; }; // -struct S8A { ubyte b:1; short c:2; }; // -struct S8B { ubyte a; short b:1; ubyte c:2; }; // -struct S8C { ubyte a; int b:1; }; // -struct S9 { ubyte a; ubyte b:2; short c:9; }; // -struct S10 { }; // sizeof differs from C treatment -struct S11 { int :0; }; // sizeof differs from C treatment -struct S12 { int :0; int x; }; // -struct S13 { uint x:12; uint x1:1; uint x2:1; uint x3:1; uint x4:1; int w; }; // -struct S14 { ubyte a; ubyte b:4; int c:30; }; // -struct S15 { ubyte a; ubyte b:2; int c:9; }; // -struct S16 { int :32; }; // sizeof differs from C treatment -struct S17 { int a:32; }; // -struct S18 { ubyte a; long :0; ubyte b; }; // -struct A0 { int a; long b:34, c:4; }; // -struct A1 { int a; uint b:11; int c; }; // -struct A2 { int a; uint b:11, c:5, d:16; // - int e; }; -struct A3 { int a; uint b:11, c:5, :0, d:16; // - int e; }; -struct A4 { int a:8; short b:7; // - uint c:29; }; -struct A5 { ubyte a:7, b:2; }; // -struct A6 { ubyte a:7; short b:2; }; // -struct A7 { short a:8; int b:16; int c; // - ubyte d:7; }; -struct A8 { short a:8; int b:16; int :0; // - ubyte c:7; }; -struct A9 { ushort a:8; int b:16; // - uint c:29; long d:9; - uint e:2, f:31; }; -struct A10 { ushort a:8; ubyte b; }; // -struct A11 { ubyte a; int b:5, c:11, :0, d:8; // - struct { int ee:8; } }; - -int main() -{ - /* MS produces identical results for 32 and 64 bit compiles, - * DM is 32 bit only - */ - printf(" DM | MS | P32 | P64\n"); - printf("T0 = %2d %d || 1 1 | 1 1 | 1 1 | 1 1\n", cast(int)T0.sizeof, cast(int)T0.alignof); - printf("T1 = %2d %d || 2 2 | 2 2 | 2 2 | 2 2\n", cast(int)T1.sizeof, cast(int)T1.alignof); - printf("T2 = %2d %d || 4 4 | 4 4 | 4 4 | 4 4\n", cast(int)T2.sizeof, cast(int)T2.alignof); - printf("T3 = %2d %d || 16 8 | 16 8 | 8 4 | 8 8\n", cast(int)T3.sizeof, cast(int)T3.alignof); - printf("T4 = %2d %d || 16 8 | 16 8 | 12 4 | 16 8\n", cast(int)T4.sizeof, cast(int)T4.alignof); - printf("T5 = %2d %d || 16 8 | 16 8 | 8 4 | 8 8\n", cast(int)T5.sizeof, cast(int)T5.alignof); - printf("S1 = %2d %d || 8 8 | 8 8 | 4 4 | 8 8\n", cast(int)S1.sizeof, cast(int)S1.alignof); - printf("S2 = %2d %d || 4 4 | 4 4 | 4 4 | 4 4\n", cast(int)S2.sizeof, cast(int)S2.alignof); - printf("S3 = %2d %d || 8 4 | 8 4 | 4 4 | 4 4\n", cast(int)S3.sizeof, cast(int)S3.alignof); - printf("S4 = %2d %d || 8 4 | 8 4 | 4 4 | 4 4\n", cast(int)S4.sizeof, cast(int)S4.alignof); - printf("S5 = %2d %d || 8 4 | 8 4 | 4 4 | 4 4\n", cast(int)S5.sizeof, cast(int)S5.alignof); - printf("S6 = %2d %d || 2 2 | 2 2 | 2 2 | 2 2\n", cast(int)S6.sizeof, cast(int)S6.alignof); - printf("S7 = %2d %d || 16 8 | 16 8 | 4 4 | 8 8\n", cast(int)S7.sizeof, cast(int)S7.alignof); - printf("S8 = %2d %d || 4 2 | 4 2 | 2 2 | 2 2\n", cast(int)S8.sizeof, cast(int)S8.alignof); - printf("S8A = %2d %d || 4 2 | 4 2 | 2 2 | 2 2\n", cast(int)S8A.sizeof, cast(int)S8A.alignof); - printf("S8B = %2d %d || 6 2 | 6 2 | 2 2 | 2 2\n", cast(int)S8B.sizeof, cast(int)S8B.alignof); - printf("S8C = %2d %d || 8 4 | 8 4 | 4 4 | 4 4\n", cast(int)S8C.sizeof, cast(int)S8C.alignof); - printf("S9 = %2d %d || 4 2 | 4 2 | 4 2 | 4 2\n", cast(int)S9.sizeof, cast(int)S9.alignof); - printf("S10 = %2d %d || 0 0 | * * | 0 1 | 0 1\n", cast(int)S10.sizeof, cast(int)S10.alignof); // MS doesn't compile - printf("S11 = %2d %d || 0 0 | 4 1 | 0 1 | 0 1\n", cast(int)S11.sizeof, cast(int)S11.alignof); - printf("S12 = %2d %d || 4 4 | 4 4 | 4 4 | 4 4\n", cast(int)S12.sizeof, cast(int)S12.alignof); - printf("S13 = %2d %d || 8 4 | 8 4 | 8 4 | 8 4\n", cast(int)S13.sizeof, cast(int)S13.alignof); - printf("S14 = %2d %d || 8 4 | 8 4 | 8 4 | 8 4\n", cast(int)S14.sizeof, cast(int)S14.alignof); - printf("S15 = %2d %d || 8 4 | 8 4 | 4 4 | 4 4\n", cast(int)S15.sizeof, cast(int)S15.alignof); - printf("S16 = %2d %d || 0 0 | 4 4 | 4 1 | 4 1\n", cast(int)S16.sizeof, cast(int)S16.alignof); - printf("S17 = %2d %d || 4 4 | 4 4 | 4 4 | 4 4\n", cast(int)S17.sizeof, cast(int)S17.alignof); - printf("S18 = %2d %d || 2 1 | 2 1 | 5 1 | 9 1\n", cast(int)S18.sizeof, cast(int)S18.alignof); - printf("A0 = %2d %d || 16 8 | 16 8 | 12 4 | 16 8\n", cast(int)A0.sizeof, cast(int)A0.alignof); - printf("A1 = %2d %d || 12 4 | 12 4 | 12 4 | 12 4\n", cast(int)A1.sizeof, cast(int)A1.alignof); - printf("A2 = %2d %d || 12 4 | 12 4 | 12 4 | 12 4\n", cast(int)A2.sizeof, cast(int)A2.alignof); - printf("A3 = %2d %d || 16 4 | 16 4 | 16 4 | 16 4\n", cast(int)A3.sizeof, cast(int)A3.alignof); - printf("A4 = %2d %d || 12 4 | 12 4 | 8 4 | 8 4\n", cast(int)A4.sizeof, cast(int)A4.alignof); - printf("A5 = %2d %d || 2 1 | 2 1 | 2 1 | 2 1\n", cast(int)A5.sizeof, cast(int)A5.alignof); - printf("A6 = %2d %d || 4 2 | 4 2 | 2 2 | 2 2\n", cast(int)A6.sizeof, cast(int)A6.alignof); - printf("A7 = %2d %d || 16 4 | 16 4 | 12 4 | 16 8\n", cast(int)A7.sizeof, cast(int)A7.alignof); - printf("A8 = %2d %d || 12 4 | 12 4 | 8 4 | 8 8\n", cast(int)A8.sizeof, cast(int)A8.alignof); - printf("A9 = %2d %d || 32 8 | 32 8 | 16 4 | 16 8\n", cast(int)A9.sizeof, cast(int)A9.alignof); - printf("A10 = %2d %d || 4 2 | 4 2 | 2 2 | 2 2\n", cast(int)A10.sizeof, cast(int)A10.alignof); - printf("A11 = %2d %d || 16 4 | 16 4 | 12 4 | 12 4\n", cast(int)A11.sizeof, cast(int)A11.alignof); - - { - S9 s; - uint x; - *cast(uint *)&s = 0; - s.b = 2; s.c = 3; - x = *cast(uint *)&s; - printf("S9 = x%x\n", x); - } - { - S14 s = { 1, 2, 3 }; - ulong v; - *cast(long *)&s = 0; - s.a = 1; - s.b = 2; - s.c = 3; - v = *cast(ulong *)&s; - printf("S14 = x%llx\n", v); - } - { - S15 s = { 1,2,3 }; - uint x; - *cast(uint *)&s = 0; - s.a = 1; s.b = 2; s.c = 3; - x = *cast(uint *)&s; - printf("S15 = x%x\n", x); - } - { - S18 s; - printf("S18 = %d should be %d\n", cast(int)(&s.b - &s.a), is64bit() ? 8 : 4); - } - { - A0 s; - long x; - *cast(long *)&s = 0; - s.a = 1; s.b = 15; - x = *cast(long *)&s; - printf("A0 = x%llx\n", x); - } - - return 0; -} diff --git a/tests/dmd/runnable/dbitfieldsms.d b/tests/dmd/runnable/dbitfieldsms.d index b323ce37f82..42157f7c7bb 100644 --- a/tests/dmd/runnable/dbitfieldsms.d +++ b/tests/dmd/runnable/dbitfieldsms.d @@ -1,6 +1,6 @@ /* test bitfields for Microsoft C * REQUIRED_ARGS: -preview=bitfields - * DISABLED: win32 linux32 freebsd32 osx32 linux64 freebsd64 osx64 + * DISABLED: win32 linux freebsd openbsd osx * RUN_OUTPUT: --- DM | MS | P32 | P64 diff --git a/tests/dmd/runnable/dbitfieldsposix32.d b/tests/dmd/runnable/dbitfieldsposix32.d index 5af9b6127ea..33ef3acdb41 100644 --- a/tests/dmd/runnable/dbitfieldsposix32.d +++ b/tests/dmd/runnable/dbitfieldsposix32.d @@ -1,6 +1,6 @@ /* test bitfields * REQUIRED_ARGS: -preview=bitfields - * DISABLED: win32 win64 linux64 freebsd64 osx64 + * DISABLED: win32 win64 linux64 freebsd64 openbsd64 osx64 * RUN_OUTPUT: --- T0 = 1 1 | 1 1 diff --git a/tests/dmd/runnable/dbitfieldsposix64.d b/tests/dmd/runnable/dbitfieldsposix64.d index 4633b757245..7d9d87419ee 100644 --- a/tests/dmd/runnable/dbitfieldsposix64.d +++ b/tests/dmd/runnable/dbitfieldsposix64.d @@ -1,6 +1,6 @@ /* test bitfields * REQUIRED_ARGS: -preview=bitfields - * DISABLED: win32 win64 linux32 freebsd32 osx32 + * DISABLED: win32 win64 linux32 freebsd32 openbsd32 osx32 LDC_not_x86 // LDC: these bad tests fail for non-Apple AArch64 targets * RUN_OUTPUT: --- T0 = 1 1 | 1 1 diff --git a/tests/dmd/runnable/dhry.d b/tests/dmd/runnable/dhry.d index 1eb463ce8cc..4d2e1b3c644 100644 --- a/tests/dmd/runnable/dhry.d +++ b/tests/dmd/runnable/dhry.d @@ -1,7 +1,7 @@ /* PERMUTE_ARGS: REQUIRED_ARGS: -release -O -g -inline -DISABLED: freebsd dragonflybsd +DISABLED: freebsd openbsd dragonflybsd Deprecation caused by https://issues.dlang.org/show_bug.cgi?id=20645 */ diff --git a/tests/dmd/runnable/extra-files/hello-profile-postscript.sh b/tests/dmd/runnable/extra-files/hello-profile-postscript.sh index cb986e0a4fe..d986ba5939a 100755 --- a/tests/dmd/runnable/extra-files/hello-profile-postscript.sh +++ b/tests/dmd/runnable/extra-files/hello-profile-postscript.sh @@ -5,7 +5,7 @@ source tools/common_funcs.sh # strip out Dmain since it's symbol differs between windows and non-windows # strip out _d_arraycatnTX and _d_arraysetlengthT since they are part of the # lowering of the array concatenation operator -grep -v 'Dmain\|_d_arraycatnTX\|_d_arraysetlengthT' ${OUTPUT_BASE}.d.trace.def > ${OUTPUT_BASE}.d.trace.def2 +grep -Ev 'Dmain|_d_arraycatnTX|_d_arraysetlengthT' ${OUTPUT_BASE}.d.trace.def > ${OUTPUT_BASE}.d.trace.def2 diff -up --strip-trailing-cr ${EXTRA_FILES}/${TEST_NAME}.d.trace.def ${OUTPUT_BASE}.d.trace.def2 diff --git a/tests/dmd/runnable/extra-files/test24590.d b/tests/dmd/runnable/extra-files/test24590.d new file mode 100644 index 00000000000..5ea04f572fa --- /dev/null +++ b/tests/dmd/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/tests/dmd/runnable/ice21727.d b/tests/dmd/runnable/ice21727.d index 5b5745f9df0..c373c53c254 100644 --- a/tests/dmd/runnable/ice21727.d +++ b/tests/dmd/runnable/ice21727.d @@ -1,5 +1,5 @@ // REQUIRED_ARGS: -m64 -O -inline -// DISABLED: win32 linux32 freebsd32 osx32 netbsd32 dragonflybsd32 +// DISABLED: win32 linux32 freebsd32 osx32 openbsd32 netbsd32 dragonflybsd32 // https://issues.dlang.org/show_bug.cgi?id=21727 import core.simd; diff --git a/tests/dmd/runnable/test12.d b/tests/dmd/runnable/test12.d index 22f4b849226..9f99d1cc844 100644 --- a/tests/dmd/runnable/test12.d +++ b/tests/dmd/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/tests/dmd/runnable/test13613.d b/tests/dmd/runnable/test13613.d index ea57df4e915..1382f00a178 100644 --- a/tests/dmd/runnable/test13613.d +++ b/tests/dmd/runnable/test13613.d @@ -4,9 +4,9 @@ /* TEST_OUTPUT: --- -CT x.offsetof = < CT y.offsetof = < 0 > y +CT x.offsetof = < 0 > x --- */ diff --git a/tests/dmd/runnable/test17338.d b/tests/dmd/runnable/test17338.d index 87c640599a9..9f277857a36 100644 --- a/tests/dmd/runnable/test17338.d +++ b/tests/dmd/runnable/test17338.d @@ -11,9 +11,6 @@ version (LDC) { /* will fail because of missing main */ } else: // COMDAT folding increases runtime by > 80x // REQUIRED_ARGS(windows): -L/OPT:NOICF -// Apparently omf or optlink does not support more than 32767 symbols. -// DISABLED: win32 - // Generate \sum_{i=0}^{14} 2^i = 32767 template instantiations // (each with 3 sections) to use more than 64Ki sections in total. diff --git a/tests/dmd/runnable/test17559.d b/tests/dmd/runnable/test17559.d index 822ef940248..22e512166c2 100644 --- a/tests/dmd/runnable/test17559.d +++ b/tests/dmd/runnable/test17559.d @@ -1,6 +1,6 @@ // REQUIRED_ARGS: -g -// REQUIRED_ARGS(linux freebsd dragonflybsd): -L-export-dynamic -// LDC (required for Win32 and -O): REQUIRED_ARGS(windows32mscoff): -link-defaultlib-debug +// REQUIRED_ARGS(linux freebsd openbsd dragonflybsd): -L-export-dynamic +// LDC (required for Win32 and -O): REQUIRED_ARGS(windows32): -link-defaultlib-debug // LDC (FreeBSD's libexecinfo apparently doesn't like elided frame pointers): REQUIRED_ARGS(freebsd): -link-defaultlib-debug -frame-pointer=all // PERMUTE_ARGS: // DISABLED: osx diff --git a/tests/dmd/runnable/test19086.d b/tests/dmd/runnable/test19086.d index fce9a43a91a..6ac2e657fa1 100644 --- a/tests/dmd/runnable/test19086.d +++ b/tests/dmd/runnable/test19086.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 // LDC (FreeBSD's libexecinfo apparently doesn't like elided frame pointers): REQUIRED_ARGS(freebsd): -link-defaultlib-debug -frame-pointer=all // DISABLED: LDC_win32 // no file/line info for the `run19086` frame (and only that frame), even without -O // PERMUTE_ARGS: diff --git a/tests/dmd/runnable/test22597.c b/tests/dmd/runnable/test22597.c index 799740bfe98..2dac36177a4 100644 --- a/tests/dmd/runnable/test22597.c +++ b/tests/dmd/runnable/test22597.c @@ -1,4 +1,5 @@ // https://issues.dlang.org/show_bug.cgi?id=22597 +// TRANSFORM_OUTPUT: remove_lines("warning: vsprintf\(\) is often misused") typedef __builtin_va_list va_list; int vsprintf(char *s, const char *format, va_list va); diff --git a/tests/dmd/runnable/test23343.c b/tests/dmd/runnable/test23343.c index 69004d61b82..27ff5a7cb80 100644 --- a/tests/dmd/runnable/test23343.c +++ b/tests/dmd/runnable/test23343.c @@ -1,4 +1,4 @@ -/* DISABLED: win32 win64 linux32 linux64 freebsd32 freebsd64 osx32 dragonflybsd32 netbsd32 +/* DISABLED: win linux freebsd openbsd osx32 dragonflybsd netbsd */ /* https://issues.dlang.org/show_bug.cgi?id=23343 diff --git a/tests/dmd/runnable/test23650.d b/tests/dmd/runnable/test23650.d deleted file mode 100644 index 3ce8f5f0759..00000000000 --- a/tests/dmd/runnable/test23650.d +++ /dev/null @@ -1,13 +0,0 @@ -// https://issues.dlang.org/show_bug.cgi?id=23650 - -__gshared int x; - -void main() -{ - - static assert(__traits(compiles, - { - struct S { int *p = &x; } - auto t = typeid(S); - })); -} diff --git a/tests/dmd/runnable/test23889.c b/tests/dmd/runnable/test23889.c index 8e875833bef..2648286d3d6 100644 --- a/tests/dmd/runnable/test23889.c +++ b/tests/dmd/runnable/test23889.c @@ -1,4 +1,4 @@ -// DISABLED: win32mscoff win64 freebsd +// DISABLED: win freebsd openbsd // https://issues.dlang.org/show_bug.cgi?id=23886 diff --git a/tests/dmd/runnable/test24590.sh b/tests/dmd/runnable/test24590.sh new file mode 100755 index 00000000000..b83e2d49090 --- /dev/null +++ b/tests/dmd/runnable/test24590.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +# https://issues.dlang.org/show_bug.cgi?id=24590 +# Make sure module destructors aren't run if druntime initialization failed, +# e.g., due to a throwing module constructor. + +exePath="${OUTPUT_BASE}${EXE}" +outputPath="${OUTPUT_BASE}.out" + +$DMD -m${MODEL} "-of$exePath" ${EXTRA_FILES}/test24590.d + +ec=0 +"$exePath" &> "$outputPath" || ec=$? + +if [[ $ec -ne 1 ]]; then + echo "Unexpected exit code $ec, expected 1" >&2 + exit 1 +fi + +if ! grep -q "module constructor" "$outputPath"; then + echo "Module constructor didn't run" >&2 + exit 1 +fi + +if grep -q "module destructor" "$outputPath"; then + echo "Module destructor unexpectedly ran" >&2 + exit 1 +fi + +rm_retry "$exePath" "$outputPath" diff --git a/tests/dmd/runnable/test24599.d b/tests/dmd/runnable/test24599.d new file mode 100644 index 00000000000..257773846eb --- /dev/null +++ b/tests/dmd/runnable/test24599.d @@ -0,0 +1,24 @@ +module mod; + +struct Variable +{ + size_t toHash() const { return 0; } +} + +enum hasInoutConstruction(T) = __traits(compiles, { struct S { T a; } }); + +struct Algebraic(T) +{ + static if (hasInoutConstruction!T) + { + } +} + +Algebraic!Variable foo(); + +struct S +{ + Variable[] symbols; +} + +void main() {} diff --git a/tests/dmd/runnable/test_cdstrpar.d b/tests/dmd/runnable/test_cdstrpar.d index 20bc223c5c9..d77627d8f36 100644 --- a/tests/dmd/runnable/test_cdstrpar.d +++ b/tests/dmd/runnable/test_cdstrpar.d @@ -1,7 +1,7 @@ // REQUIRED_ARGS: -O -fPIC // PERMUTE_ARGS: // only testing on SYSV-ABI, but backend code is identical across platforms -// DISABLED: win32 win64 osx linux32 freebsd32 LDC +// DISABLED: win32 win64 osx linux32 freebsd32 openbsd32 LDC debug = PRINTF; debug (PRINTF) import core.stdc.stdio; diff --git a/tests/dmd/runnable/testargtypes.d b/tests/dmd/runnable/testargtypes.d index 6905e56941e..ed78eac7236 100644 --- a/tests/dmd/runnable/testargtypes.d +++ b/tests/dmd/runnable/testargtypes.d @@ -1,5 +1,5 @@ /* -DISABLED: win32 win64 osx32 linux32 freebsd32 +DISABLED: win32 win64 osx32 linux32 freebsd32 openbsd32 */ version (X86_64) {} else version = not_X86_64; diff --git a/tests/dmd/runnable/testthread.d b/tests/dmd/runnable/testthread.d index 139a891072c..811b6c22220 100644 --- a/tests/dmd/runnable/testthread.d +++ b/tests/dmd/runnable/testthread.d @@ -3,15 +3,6 @@ import core.stdc.stdio; import core.thread; -version (CRuntime_DigitalMars) -{ - extern (C) - { - extern int _tlsstart; - extern int _tlsend; - } -} - int tlsx; class Foo @@ -25,8 +16,6 @@ class Foo tlsx = 5; Thread t = Thread.getThis(); - version (CRuntime_DigitalMars) - printf("thread ptr=%p, %p &tlsx = %p %p\n", t, &_tlsstart, &tlsx, &_tlsend); x = 3; printf("-bar()\n"); } diff --git a/tests/dmd/runnable/testthread2.d b/tests/dmd/runnable/testthread2.d index 2c87ecd8a7d..346e3862e59 100644 --- a/tests/dmd/runnable/testthread2.d +++ b/tests/dmd/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/tests/dmd/runnable/variadic.d b/tests/dmd/runnable/variadic.d index 7e9473c332e..ddfd92c1676 100644 --- a/tests/dmd/runnable/variadic.d +++ b/tests/dmd/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/tests/dmd/runnable/whetstone.d b/tests/dmd/runnable/whetstone.d index 9145c74bcfd..48f6010b9ff 100644 --- a/tests/dmd/runnable/whetstone.d +++ b/tests/dmd/runnable/whetstone.d @@ -1,5 +1,6 @@ /* PERMUTE_ARGS: -O +TRANSFORM_OUTPUT: remove_lines("warning: sprintf\(\) is often misused") */ /* diff --git a/tests/dmd/runnable_cxx/cpp_abi_tests.d b/tests/dmd/runnable_cxx/cpp_abi_tests.d index c0f4e6dd780..4e241749fbc 100644 --- a/tests/dmd/runnable_cxx/cpp_abi_tests.d +++ b/tests/dmd/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 @@ -272,7 +272,6 @@ void main() foreach(byte val; values!byte()) check(val); foreach(ubyte val; values!ubyte()) check(val); foreach(char val; values!char()) check(val); -version(CppRuntime_DigitalMars){} else version(CppRuntime_Microsoft) { // TODO: figure out how to detect VS2013 which doesn't support char16_t/char32_t diff --git a/tests/dmd/runnable_cxx/cpp_stdlib.d b/tests/dmd/runnable_cxx/cpp_stdlib.d index dd7bb11fc64..5b7d00a3819 100644 --- a/tests/dmd/runnable_cxx/cpp_stdlib.d +++ b/tests/dmd/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/tests/dmd/runnable_cxx/cppa.d b/tests/dmd/runnable_cxx/cppa.d index a040939cedb..d66644dfcfa 100644 --- a/tests/dmd/runnable_cxx/cppa.d +++ b/tests/dmd/runnable_cxx/cppa.d @@ -2,15 +2,13 @@ // 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 -// Broken for unknown reasons since the OMF => MsCOFF switch -// DISABLED: win32omf - import core.stdc.stdio; import core.stdc.stdarg; import core.stdc.config; @@ -457,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) @@ -908,9 +906,7 @@ void fuzz2() } //////// -version(CppRuntime_DigitalMars) - enum UNICODE = false; -else version(CppRuntime_Microsoft) +version(CppRuntime_Microsoft) enum UNICODE = false; //VS2013 doesn't support them else enum UNICODE = true; @@ -953,7 +949,7 @@ version (LDC) { version (CRuntime_Microsoft) version = LDC_CppEH; - else version (CppRuntime_Gcc) + else version (CppRuntime_GNU) version = LDC_CppEH; // FIXME: support libc++ too } diff --git a/tests/dmd/runnable_cxx/externmangle.d b/tests/dmd/runnable_cxx/externmangle.d index ef132dcca72..266cad9f6c1 100644 --- a/tests/dmd/runnable_cxx/externmangle.d +++ b/tests/dmd/runnable_cxx/externmangle.d @@ -239,39 +239,31 @@ void test39() extern(C++, "foo", "bar", "baz") int doStuff(int); -version(CppRuntime_DigitalMars) // DMC doesn't support c++11 -{ - void test40() {} - void test41() {} -} -else -{ - void test40(); +void test40(); - void foovargs(T...)(T args) +void foovargs(T...)(T args) +{ + static if (is(T[0] == char*)) { - static if (is(T[0] == char*)) - { - assert(*args[0] == 'a'); - } - else - { - float ret = args[0] + args[1]; - assert(ret == 3.0f); - } + assert(*args[0] == 'a'); } - - alias FooVargs = foovargs!(int, float); - alias FooVargs2 = foovargs!(char*); - - void test41(); - void make_shared_poc(T, Args...)(ref Args args) + else { - assert(args[0] + args[1] == 3); + float ret = args[0] + args[1]; + assert(ret == 3.0f); } - alias Make_Shared_Poc = make_shared_poc!(int, int, int); } +alias FooVargs = foovargs!(int, float); +alias FooVargs2 = foovargs!(char*); + +void test41(); +void make_shared_poc(T, Args...)(ref Args args) +{ + assert(args[0] + args[1] == 3); +} +alias Make_Shared_Poc = make_shared_poc!(int, int, int); + void main() { test1(Foo!int()); diff --git a/tests/dmd/runnable_cxx/extra-files/cpp7925.cpp b/tests/dmd/runnable_cxx/extra-files/cpp7925.cpp index f3a9a8552a9..282faec797a 100644 --- a/tests/dmd/runnable_cxx/extra-files/cpp7925.cpp +++ b/tests/dmd/runnable_cxx/extra-files/cpp7925.cpp @@ -90,14 +90,10 @@ void runCPPTests() int (C2::*fp1)(int) = &C2::f1; int (C2::*fp2)(int, int) = &C2::f2; int (C2::*fp3)(int, int) = &C2::f3; -#ifndef __DMC__ int (C2::*fp4)(int, ...) = &C2::f4; -#endif assert((c2->*(fp0))() == 100); assert((c2->*(fp1))(1) == 101); assert((c2->*(fp2))(20, 3) == 123); assert((c2->*(fp3))(20, 3) == 123); -#ifndef __DMC__ assert((c2->*(fp4))(20, 3, 0) == 123); -#endif } diff --git a/tests/dmd/runnable_cxx/extra-files/cpp_abi_tests.cpp b/tests/dmd/runnable_cxx/extra-files/cpp_abi_tests.cpp index e1dcc28b8b1..cbde23378f2 100644 --- a/tests/dmd/runnable_cxx/extra-files/cpp_abi_tests.cpp +++ b/tests/dmd/runnable_cxx/extra-files/cpp_abi_tests.cpp @@ -10,9 +10,7 @@ namespace std struct test19248 {int a;}; }; -#ifdef __DMC__ -// DMC doesn't support c++11 -#elif defined (_MSC_VER) && _MSC_VER <= 1800 +#if defined (_MSC_VER) && _MSC_VER <= 1800 // MSVC2013 doesn't support char16_t/char32_t #else #define TEST_UNICODE @@ -26,11 +24,7 @@ struct S18784 S18784::S18784(int n) : i(n) {} -#ifdef __DMC__ // DMC doesn't support c++11 -template -#else template -#endif struct SPack { int i; diff --git a/tests/dmd/runnable_cxx/extra-files/cpp_nonpod_byval.cpp b/tests/dmd/runnable_cxx/extra-files/cpp_nonpod_byval.cpp new file mode 100644 index 00000000000..c320ec55821 --- /dev/null +++ b/tests/dmd/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/tests/dmd/runnable_cxx/extra-files/cppb.cpp b/tests/dmd/runnable_cxx/extra-files/cppb.cpp index 8fcc47b6569..68845947745 100644 --- a/tests/dmd/runnable_cxx/extra-files/cppb.cpp +++ b/tests/dmd/runnable_cxx/extra-files/cppb.cpp @@ -374,9 +374,7 @@ wchar_t f13289_cpp_wchar_t(wchar_t ch) return ch; } } -#ifdef __DMC__ -// DMC doesn't support c++11 -#elif defined (_MSC_VER) //&& _MSC_VER <= 1800 +#if defined (_MSC_VER) //&& _MSC_VER <= 1800 // MSVC2013 doesn't support char16_t/char32_t #else #define TEST_UNICODE diff --git a/tests/dmd/runnable_cxx/extra-files/externmangle.cpp b/tests/dmd/runnable_cxx/extra-files/externmangle.cpp index 37c98ea8fdd..df10a9cd88c 100644 --- a/tests/dmd/runnable_cxx/extra-files/externmangle.cpp +++ b/tests/dmd/runnable_cxx/extra-files/externmangle.cpp @@ -426,7 +426,6 @@ namespace foo } } -#ifndef __DMC__ // DMC doesn't support c++11 template void foovargs(T... args); void test40() @@ -446,4 +445,3 @@ void test41() make_shared_poc(a, b); } -#endif diff --git a/tests/dmd/runnable_cxx/extra-files/test20652.cpp b/tests/dmd/runnable_cxx/extra-files/test20652.cpp index 91ab66aaf19..b35b3f51b15 100644 --- a/tests/dmd/runnable_cxx/extra-files/test20652.cpp +++ b/tests/dmd/runnable_cxx/extra-files/test20652.cpp @@ -1,6 +1,3 @@ -#if defined(__DMC__) // DMC doesn't support immintrin.h -#else - #include // Inline the typedef of __m128 instead of including immintrin.h. @@ -30,5 +27,3 @@ void test20652(const __m128& a) assert(b.array[2] == 1); assert(b.array[3] == 1); } - -#endif diff --git a/tests/dmd/runnable_cxx/extra-files/testbitfields_cpp.cpp b/tests/dmd/runnable_cxx/extra-files/testbitfields_cpp.cpp new file mode 100644 index 00000000000..7302ca6df98 --- /dev/null +++ b/tests/dmd/runnable_cxx/extra-files/testbitfields_cpp.cpp @@ -0,0 +1,84 @@ +extern "C" +{ +#include "testbitfields_importc.c" +} + +#include +#include + +template +size_t getStructSize(); +template +size_t getStructAlign(); +template +void resetBitfield(T &data, const char *member); + +#define BEGIN_STRUCT(S) \ + template<> \ + size_t getStructSize() \ + { \ + return sizeof(S); \ + } \ + template<> \ + size_t getStructAlign() \ + { \ + return alignof(S); \ + } \ + template<> \ + void resetBitfield(S &data, const char *member) \ + { + +#define FIELD(name) if (strcmp(member, #name) == 0) data.name = 0; +#define END_STRUCT } + +BEGIN_STRUCT(T0) FIELD(x) END_STRUCT +BEGIN_STRUCT(T1) FIELD(x) END_STRUCT +BEGIN_STRUCT(T2) FIELD(x) END_STRUCT +BEGIN_STRUCT(T3) FIELD(a) FIELD(b) FIELD(c) FIELD(d) FIELD(x) END_STRUCT +BEGIN_STRUCT(T4) FIELD(a) FIELD(b) FIELD(c) FIELD(d) FIELD(e) FIELD(f) FIELD(g) FIELD(h) FIELD(x) END_STRUCT +BEGIN_STRUCT(T5) FIELD(a) FIELD(b) FIELD(c) FIELD(d) FIELD(e) FIELD(f) FIELD(g) FIELD(x) END_STRUCT +BEGIN_STRUCT(S1) FIELD(f) END_STRUCT +BEGIN_STRUCT(S2) FIELD(x) FIELD(y) END_STRUCT +BEGIN_STRUCT(S3) FIELD(c) FIELD(x) FIELD(y) END_STRUCT +BEGIN_STRUCT(S4) FIELD(x) FIELD(y) END_STRUCT +BEGIN_STRUCT(S5) FIELD(x) FIELD(y) END_STRUCT +BEGIN_STRUCT(S6) FIELD(x) FIELD(y) END_STRUCT +BEGIN_STRUCT(S7) FIELD(x) FIELD(y) FIELD(z) END_STRUCT +BEGIN_STRUCT(S8) FIELD(a) FIELD(b) FIELD(c) END_STRUCT +BEGIN_STRUCT(S8A) FIELD(b) FIELD(c) END_STRUCT +BEGIN_STRUCT(S8B) FIELD(a) FIELD(b) FIELD(c) END_STRUCT +BEGIN_STRUCT(S8C) FIELD(a) FIELD(b) END_STRUCT +BEGIN_STRUCT(S9) FIELD(a) FIELD(b) FIELD(c) END_STRUCT +//BEGIN_STRUCT(S10) END_STRUCT +//BEGIN_STRUCT(S11) END_STRUCT +BEGIN_STRUCT(S12) FIELD(x) END_STRUCT +BEGIN_STRUCT(S13) FIELD(x) FIELD(x1) FIELD(x2) FIELD(x3) FIELD(x4) FIELD(w) END_STRUCT +BEGIN_STRUCT(S14) FIELD(a) FIELD(b) FIELD(c) END_STRUCT +BEGIN_STRUCT(S15) FIELD(a) FIELD(b) FIELD(c) END_STRUCT +BEGIN_STRUCT(S16) END_STRUCT +BEGIN_STRUCT(S17) FIELD(a) END_STRUCT +BEGIN_STRUCT(S18) FIELD(a) FIELD(b) END_STRUCT +BEGIN_STRUCT(A0) FIELD(a) FIELD(b) FIELD(c) END_STRUCT +BEGIN_STRUCT(A1) FIELD(a) FIELD(b) FIELD(c) END_STRUCT +BEGIN_STRUCT(A2) FIELD(a) FIELD(b) FIELD(c) FIELD(d) + FIELD(e) END_STRUCT +BEGIN_STRUCT(A3) FIELD(a) FIELD(b) FIELD(c) FIELD(d) + FIELD(e) END_STRUCT +BEGIN_STRUCT(A4) FIELD(a) FIELD(b) + FIELD(c) END_STRUCT +BEGIN_STRUCT(A5) FIELD(a) FIELD(b) END_STRUCT +BEGIN_STRUCT(A6) FIELD(a) FIELD(b) END_STRUCT +BEGIN_STRUCT(A7) FIELD(a) FIELD(b) FIELD(c) + FIELD(d) END_STRUCT +BEGIN_STRUCT(A8) FIELD(a) FIELD(b) + FIELD(c) END_STRUCT +BEGIN_STRUCT(A9) FIELD(a) FIELD(b) + FIELD(c) FIELD(d) + FIELD(e) FIELD(f) END_STRUCT +BEGIN_STRUCT(A10) FIELD(a) FIELD(b) END_STRUCT +BEGIN_STRUCT(A11) FIELD(a) FIELD(b) FIELD(c) FIELD(d) + END_STRUCT +BEGIN_STRUCT(Issue24592a) FIELD(a) FIELD(b) FIELD(c) END_STRUCT +BEGIN_STRUCT(Issue24592b) FIELD(x) FIELD(a) FIELD(b) FIELD(c) END_STRUCT +BEGIN_STRUCT(Issue24592c) FIELD(a) FIELD(b) FIELD(c) FIELD(d) FIELD(e) FIELD(f) END_STRUCT +BEGIN_STRUCT(Issue24592d) FIELD(a) FIELD(b) FIELD(c) FIELD(d) FIELD(e) FIELD(f) END_STRUCT diff --git a/tests/dmd/runnable_cxx/extra-files/testbitfields_importc.c b/tests/dmd/runnable_cxx/extra-files/testbitfields_importc.c new file mode 100644 index 00000000000..2bc7569067d --- /dev/null +++ b/tests/dmd/runnable_cxx/extra-files/testbitfields_importc.c @@ -0,0 +1,52 @@ + +struct T0 { char x:1; }; +struct T1 { short x:1; }; +struct T2 { int x:1; }; +struct T3 { char a,b,c,d; long long x:1; }; +struct T4 { char a,b,c,d,e,f,g,h; long long x:1; }; +struct T5 { char a,b,c,d,e,f,g; long long x:1; }; +struct S1 { long long int f:1; }; +struct S2 { int x:1; int y:1; }; +struct S3 { short c; int x:1; unsigned y:1; }; +struct S4 { int x:1; short y:1; }; +struct S5 { short x:1; int y:1; }; +struct S6 { short x:1; short y:1; }; +struct S7 { short x:1; int y:1; long long z:1; }; +struct S8 { char a; char b:1; short c:2; }; +struct S8A { char b:1; short c:2; }; +struct S8B { char a; short b:1; char c:2; }; +struct S8C { char a; int b:1; }; +struct S9 { char a; char b:2; short c:9; }; +//struct S10 { }; +//struct S11 { int :0; }; +struct S12 { int :0; int x; }; +struct S13 { unsigned x:12; unsigned x1:1; unsigned x2:1; unsigned x3:1; unsigned x4:1; int w; }; +struct S14 { char a; char b:4; int c:30; }; +struct S15 { char a; char b:2; int c:9; }; +struct S16 { int :32; }; +struct S17 { int a:32; }; +struct S18 { char a; long long :0; char b; }; +struct A0 { int a; long long b:34, c:4; }; +struct A1 { int a; unsigned b:11; int c; }; +struct A2 { int a; unsigned b:11, c:5, d:16; + int e; }; +struct A3 { int a; unsigned b:11, c:5, :0, d:16; + int e; }; +struct A4 { int a:8; short b:7; + unsigned int c:29; }; +struct A5 { char a:7, b:2; }; +struct A6 { char a:7; short b:2; }; +struct A7 { short a:8; long b:16; int c; + char d:7; }; +struct A8 { short a:8; long b:16; int :0; + char c:7; }; +struct A9 { unsigned short a:8; long b:16; + unsigned long c:29; long long d:9; + unsigned long e:2, f:31; }; +struct A10 { unsigned short a:8; char b; }; +struct A11 { char a; int b:5, c:11, :0, d:8; + struct { int ee:8; } e; }; +struct Issue24592a { unsigned long long a:20, b:20, c:24; }; +struct Issue24592b { unsigned int x; unsigned long long a:20, b:20, c:24; }; +struct Issue24592c { unsigned long long a:20, b:32, c:32, d:32, e:32, f:32; }; +struct Issue24592d { unsigned long long a:10, b:16, c:16, d:16, e:16, f:16; }; diff --git a/tests/dmd/runnable_cxx/nonpod_byval.d b/tests/dmd/runnable_cxx/nonpod_byval.d new file mode 100644 index 00000000000..c7fac46a040 --- /dev/null +++ b/tests/dmd/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/tests/dmd/runnable_cxx/test20652.d b/tests/dmd/runnable_cxx/test20652.d index 68bb0a711e4..a4962f664e7 100644 --- a/tests/dmd/runnable_cxx/test20652.d +++ b/tests/dmd/runnable_cxx/test20652.d @@ -3,11 +3,7 @@ import core.simd; -version (CRuntime_DigitalMars) // DMC doesn't support immintrin.h -{ - void main() {} -} -else static if (!__traits(compiles, float4)) // No __vector support +static if (!__traits(compiles, float4)) // No __vector support { void main() {} } diff --git a/tests/dmd/runnable_cxx/testbitfields.d b/tests/dmd/runnable_cxx/testbitfields.d new file mode 100644 index 00000000000..2dd3a297c31 --- /dev/null +++ b/tests/dmd/runnable_cxx/testbitfields.d @@ -0,0 +1,90 @@ +// EXTRA_CPP_SOURCES: testbitfields_cpp.cpp +// EXTRA_SOURCES: extra-files/testbitfields_importc.c +// CXXFLAGS(linux osx freebsd dragonflybsd): -std=c++11 + +import core.stdc.stdio; +import core.stdc.stdlib; +import core.stdc.string; + +static import testbitfields_importc; + +extern(C++) size_t getStructSize(T)(); +extern(C++) size_t getStructAlign(T)(); +extern(C++) void resetBitfield(T)(ref T data, const(char) *member); + +bool checkType(S)() +{ + bool different; + if (S.sizeof != getStructSize!S) + different = true; + if (S.alignof != getStructAlign!S) + different = true; + static foreach (member; __traits(allMembers, S)) + {{ + static if (member[0] != '_' && typeof(__traits(getMember, S, member)).stringof[0] != '_') + { + S dummyD; + memset(&dummyD, 0xff, S.sizeof); + __traits(getMember, dummyD, member) = 0; + + S* dummyC = cast(S*) malloc(getStructSize!S); + memset(dummyC, 0xff, getStructSize!S); + resetBitfield!S(*dummyC, member.ptr); + if (S.sizeof == getStructSize!S && memcmp(&dummyD, dummyC, S.sizeof) != 0) + different = true; + free(dummyC); + } + }} + if (different) + { + printf("Struct %s has different bitfield layout for C and D:\n", __traits(identifier, S).ptr); + printf(" D: size=%zd align=%zd\n", S.sizeof, S.alignof); + printf(" C: size=%zd align=%zd\n", getStructSize!S, getStructAlign!S); + static foreach (member; __traits(allMembers, S)) + {{ + static if (member[0] != '_' && typeof(__traits(getMember, S, member)).stringof[0] != '_') + { + printf(" %s %s:\n", typeof(__traits(getMember, S, member)).stringof.ptr, member.ptr); + printf(" D:"); + S dummyD; + memset(&dummyD, 0xff, S.sizeof); + __traits(getMember, dummyD, member) = 0; + foreach (i; 0 .. S.sizeof) + { + if (i % 4 == 0) + printf(" "); + printf("%02X", 0xff & ~(cast(ubyte*) &dummyD)[i]); + } + + printf("\n C:"); + S* dummyC = cast(S*) malloc(getStructSize!S); + memset(dummyC, 0xff, getStructSize!S); + resetBitfield!S(*dummyC, member.ptr); + foreach (i; 0 .. getStructSize!S) + { + if (i % 4 == 0) + printf(" "); + printf("%02X", 0xff & ~(cast(ubyte*) dummyC)[i]); + } + free(dummyC); + printf("\n"); + } + }} + } + return different; +} + +int main() +{ + int ret; + static foreach (name; __traits(allMembers, testbitfields_importc)) + {{ + alias S = __traits(getMember, testbitfields_importc, name); + static if (is(S == struct) && name[0] != '_') + { + if (checkType!S) + ret = 1; + } + }} + return ret; +} diff --git a/tests/dmd/tools/d_do_test.d b/tests/dmd/tools/d_do_test.d index 7c4d06513b1..d362e76c820 100755 --- a/tests/dmd/tools/d_do_test.d +++ b/tests/dmd/tools/d_do_test.d @@ -62,9 +62,9 @@ void usage() ~ " ARGS: set to execute all combinations of\n" ~ " REQUIRED_ARGS: arguments always passed to the compiler\n" ~ " DMD: compiler to use, ex: ../src/dmd (required)\n" - ~ " CC: C compiler to use, ex: dmc, cc\n" - ~ " CXX: C++ compiler to use, ex: dmc, g++\n" - ~ " OS: windows, linux, freebsd, osx, netbsd, dragonflybsd\n" + ~ " CC: C compiler to use, ex: cl, cc\n" + ~ " CXX: C++ compiler to use, ex: cl, g++\n" + ~ " OS: windows, linux, freebsd, osx, openbsd, netbsd, dragonflybsd\n" ~ " RESULTS_DIR: base directory for test results\n" ~ " MODEL: 32 or 64 (required)\n" ~ " AUTO_UPDATE: set to 1 to auto-update mismatching test output\n" @@ -178,15 +178,6 @@ immutable(EnvData) processEnvironment() envData.ccompiler = environment.get("CC"); envData.cxxcompiler = environment.get("CXX"); envData.model = envGetRequired("MODEL"); - if (envData.os == "windows" && envData.model == "32") - { - // FIXME: we need to translate the default 32-bit model (COFF) on Windows to legacy `32mscoff`. - // Reason: OMF-specific tests are currently specified like this: - // DISABLED: win32mscoff win64 … - // and `DISABLED: win32` would disable it for `win32omf` too. - // So we'd need something like an `ENABLED: win32omf` parameter to restrict tests to specific platforms. - envData.model = "32mscoff"; - } envData.required_args = environment.get("REQUIRED_ARGS"); envData.dobjc = environment.get("D_OBJC") == "1"; envData.coverage_build = environment.get("DMD_TEST_COVERAGE") == "1"; @@ -200,35 +191,17 @@ immutable(EnvData) processEnvironment() if (envData.ccompiler.empty) { - if (envData.os != "windows") - envData.ccompiler = "cc"; - else if (envData.model == "32omf") - envData.ccompiler = "dmc"; - else if (envData.model == "64") - envData.ccompiler = "cl"; - else if (envData.model == "32mscoff") + if (envData.os == "windows") envData.ccompiler = "cl"; else - { - writeln("Can't determine C compiler (CC). Unknown $OS$MODEL combination: ", envData.os, envData.model); - throw new SilentQuit(); - } + envData.ccompiler = "cc"; } if (envData.cxxcompiler.empty) { - if (envData.os != "windows") - envData.cxxcompiler = "c++"; - else if (envData.model == "32omf") - envData.cxxcompiler = "dmc"; - else if (envData.model == "64") - envData.cxxcompiler = "cl"; - else if (envData.model == "32mscoff") + if (envData.os == "windows") envData.cxxcompiler = "cl"; else - { - writeln("Can't determine C++ compiler (CXX). Unknown $OS$MODEL combination: ", envData.os, envData.model); - throw new SilentQuit(); - } + envData.cxxcompiler = "c++"; } version (Windows) {} else @@ -243,7 +216,11 @@ immutable(EnvData) processEnvironment() { case "dmd": case "ldc": - version (CppRuntime_Gcc) + version (CppRuntime_GNU) + envData.cxxCompatFlags = " -L-lstdc++ -L--no-demangle"; + else version (CppRuntime_LLVM) + envData.cxxCompatFlags = " -L-lc++ -L--no-demangle"; + else version (CppRuntime_Gcc) envData.cxxCompatFlags = " -L-lstdc++ -L--no-demangle"; else version (CppRuntime_Clang) envData.cxxCompatFlags = " -L-lc++ -L--no-demangle"; @@ -551,9 +528,7 @@ private bool consumeNextToken(ref string file, const string token, ref const Env file = file.stripLeft!(ch => ch == ' '); // Don't read line breaks // Check if the current environment matches an entry in oss, which can either - // be an OS (e.g. "linux") or a combination of OS + MODEL (e.g. "windows32omf"). - // The latter is important on windows because m32omf might require other - // parameters than m32mscoff/m64. + // be an OS (e.g. "linux") or a combination of OS + MODEL (e.g. "windows32"). if (!oss.canFind!(o => o.skipOver(envData.os) && (o.empty || o == envData.model))) continue; // Parameter was skipped } @@ -670,9 +645,8 @@ string getDisabledReason(string[] disabledPlatforms, const ref EnvData envData) unittest { - immutable EnvData win32omf = { os: "windows", model: "32omf" }; - immutable EnvData win32mscoff = { os: "windows", model: "32mscoff" }; - immutable EnvData win64 = { os: "windows", model: "64" }; + immutable EnvData win32 = { os: "windows", model: "32" }; + immutable EnvData win64 = { os: "windows", model: "64" }; assert(getDisabledReason(null, win64) is null); @@ -682,11 +656,8 @@ unittest assert(getDisabledReason([ "linux", "win64" ], win64) == "on win64"); assert(getDisabledReason([ "linux", "win32" ], win64) is null); - assert(getDisabledReason([ "win32mscoff" ], win32mscoff) == "on win32mscoff"); - assert(getDisabledReason([ "win32mscoff" ], win32omf) is null); - - assert(getDisabledReason([ "win32" ], win32mscoff) == "on win32"); - assert(getDisabledReason([ "win32" ], win32omf) == "on win32"); + assert(getDisabledReason([ "win32" ], win32) == "on win32"); + assert(getDisabledReason([ "win32" ], win64) is null); } /** * Reads the test configuration from the source code (using `findTestParameter` and @@ -1188,11 +1159,7 @@ bool collectExtraSources (in string input_dir, in string output_dir, in string[] auto curObj = output_dir ~ envData.sep ~ cur ~ envData.obj; bool is_cpp_file = cur.extension() == ".cpp"; string command = quoteSpaces(is_cpp_file ? cxxcompiler : ccompiler); - if (envData.model == "32omf") // dmc.exe - { - command ~= " -c "~curSrc~" -o"~curObj; - } - else if (envData.os == "windows") // cl.exe + if (envData.os == "windows") // cl.exe { command ~= ` /c /nologo `~curSrc~` /Fo`~curObj; } @@ -1479,8 +1446,8 @@ bool compareOutput(string output, string refoutput, const ref EnvData envData) toSkip = chunk; break; } - // Match against OS or model (accepts "32mscoff" as "32") - else if (searchResult[0].splitter('+').all!(c => c.among(envData.os, envData.model, envData.model[0 .. min(2, $)]))) + // Match against OS or model + else if (searchResult[0].splitter('+').all!(c => c.among(envData.os, envData.model))) { toSkip = searchResult[2]; break; @@ -1556,7 +1523,7 @@ unittest const emptyFmt = "On <$?:windows=abc|$> use <$?:posix=$>!"; assert(compareOutput("On <> use <>!", emptyFmt, ed)); - ed.model = "32mscoff"; + ed.model = "32"; assert(compareOutput("size_t is uint!", "size_t is $?:32=uint|64=ulong$!", ed)); assert(compareOutput("no", "$?:posix+64=yes|no$", ed)); @@ -1778,18 +1745,7 @@ int tryMain(string[] args) // Clear the DFLAGS environment variable if it was specified in the test file if (testArgs.clearDflags) - { - // `environment["DFLAGS"] = "";` doesn't seem to work on Win32 (might be a bug - // in std.process). So, resorting to `putenv` in snn.lib - version(Win32) - { - putenv("DFLAGS="); - } - else - { - environment["DFLAGS"] = ""; - } - } + environment["DFLAGS"] = ""; writef(" ... %-30s %s%s(%s)", input_file, @@ -1976,11 +1932,10 @@ int tryMain(string[] args) { toCleanup ~= test_app_dmd; version(Windows) - if (envData.model != "32omf") - { - toCleanup ~= test_app_dmd_base ~ to!string(permuteIndex) ~ ".ilk"; - toCleanup ~= test_app_dmd_base ~ to!string(permuteIndex) ~ ".pdb"; - } + { + toCleanup ~= test_app_dmd_base ~ to!string(permuteIndex) ~ ".ilk"; + toCleanup ~= test_app_dmd_base ~ to!string(permuteIndex) ~ ".pdb"; + } if (testArgs.gdbScript is null) { diff --git a/tests/dmd/tools/exported_vars.sh b/tests/dmd/tools/exported_vars.sh index 3e039b3c6e7..415b9632a8a 100644 --- a/tests/dmd/tools/exported_vars.sh +++ b/tests/dmd/tools/exported_vars.sh @@ -36,8 +36,8 @@ else export SOEXT=.so fi -# Default to DigitalMars C++ on Win32 -if [ "$OS" == "win32" ] && [ -z "${CC+set}" ] ; then - CC="dmc" +# Default to Microsoft cl on Windows +if [[ "$OS" == "win"* && -z "${CC+set}" ]] ; then + CC="cl" fi export CC="${CC:-c++}" # C++ compiler to use diff --git a/tests/dmd/tools/unit_test_runner.d b/tests/dmd/tools/unit_test_runner.d index c66f107286f..31a339649fe 100755 --- a/tests/dmd/tools/unit_test_runner.d +++ b/tests/dmd/tools/unit_test_runner.d @@ -259,6 +259,7 @@ string[] buildCmdArgs(string runnerPath, string outputPath, const string[] testF "-version=NoMain", "-version=MARS", "-version=DMDLIB", + "-g", "-unittest", // LDC: no `"-J" ~ buildOutputPath,` "-J" ~ compilerRootDir.buildPath("dmd/res"), // LDC: was `"-Jsrc/dmd/res",` @@ -277,10 +278,6 @@ string[] buildCmdArgs(string runnerPath, string outputPath, const string[] testF if (environment.get("DMD_TEST_COVERAGE", "0") == "1") flags ~= "-cov"; - // older versions of Optlink causes: "Error 45: Too Much DEBUG Data for Old CodeView format" - if (!usesOptlink) - flags ~= "-g"; - return flags; } @@ -306,15 +303,6 @@ bool missingTestFiles(Range)(Range givenFiles) return false; } -bool usesOptlink() -{ - version (DigitalMars) - return os == "windows" && model == "32"; - - else - return false; -} - int main(string[] args) { string unitTestFilter; diff --git a/tests/dmd/unit/semantic/imports.d b/tests/dmd/unit/semantic/imports.d index 80c5266406a..2de5c026d27 100644 --- a/tests/dmd/unit/semantic/imports.d +++ b/tests/dmd/unit/semantic/imports.d @@ -10,10 +10,21 @@ import dmd.common.outbuffer; import support; +@beforeEach void initializeFrontend() +{ + import dmd.frontend : initDMD; + initDMD(); +} + +@afterEach void deinitializeFrontend() +{ + import dmd.frontend : deinitializeDMD; + deinitializeDMD(); +} + @("semantics - imported modules") unittest { - initDMD(); defaultImportPaths.each!addImport; auto t = parseModule!ASTCodegen("test.d", q{ diff --git a/tests/dmd/unit/triple.d b/tests/dmd/unit/triple.d index a95145bff88..72ca86f8288 100644 --- a/tests/dmd/unit/triple.d +++ b/tests/dmd/unit/triple.d @@ -37,14 +37,24 @@ unittest assert(triple.cpu == CPU.avx2); } -@("-target=x86_64-unknown-linux-musl-clang") +@("-target=x86_64-unknown-linux-musl-libcxx") unittest { - auto triple = Triple("x86_64-unknown-linux-musl-clang"); + auto triple = Triple("x86_64-unknown-linux-musl-libcxx"); assert(triple.isX86_64 == true); assert(triple.os == Target.OS.linux); assert(triple.cenv == TargetC.Runtime.Musl); - assert(triple.cppenv == TargetCPP.Runtime.Clang); + assert(triple.cppenv == TargetCPP.Runtime.LLVM); +} + +@("-target=x86_64-unknown-linux-musl-libc++") +unittest +{ + auto triple = Triple("x86_64-unknown-linux-musl-libc++"); + assert(triple.isX86_64 == true); + assert(triple.os == Target.OS.linux); + assert(triple.cenv == TargetC.Runtime.Musl); + assert(triple.cppenv == TargetCPP.Runtime.LLVM); } @("-target=x86_64-freebsd12")