diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index afdcac8600..57b986cd59 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -51,10 +51,12 @@ jobs: # macOS - job_name: macOS 13 x64, DMD (latest) os: macos-13 - host_dmd: dmd + # FIXME: Revert this back to "dmd" after 2.107.1 is released. + host_dmd: ldc - job_name: macOS 13 x64, DMD (coverage) os: macos-13 - host_dmd: dmd + # FIXME: Revert this back to "dmd" after 2.107.1 is released. + host_dmd: ldc coverage: true - job_name: macOS 12 x64, DMD (bootstrap) os: macos-12 @@ -104,6 +106,13 @@ jobs: with: arch: ${{ env.MODEL == '64' && 'x64' || 'x86' }} + # NOTE: Linker ICEs with Xcode 15.0.1 (default version on macos-13) + # * https://issues.dlang.org/show_bug.cgi?id=24407 + # Remove this step if the default gets changed to 15.1 in actions/runner-images. + - name: 'macOS 13: Switch to Xcode v15.1' + if: matrix.os == 'macos-13' + run: sudo xcode-select -switch /Applications/Xcode_15.1.app + - name: 'Posix: Install host compiler' if: runner.os != 'Windows' run: ci/run.sh install_host_compiler @@ -174,18 +183,18 @@ jobs: freebsd_version: '13.2' host_dmd: dmd-2.095.0 name: ${{ matrix.job_name }} - runs-on: macos-latest + runs-on: ubuntu-latest timeout-minutes: 60 steps: - uses: actions/checkout@v4 with: fetch-depth: 50 - name: Run in VM - uses: cross-platform-actions/action@v0.22.0 + uses: cross-platform-actions/action@v0.23.0 with: operating_system: freebsd hypervisor: qemu - memory: 8G + memory: 12G sync_files: runner-to-vm version: ${{ matrix.freebsd_version }} shell: bash diff --git a/VERSION b/VERSION index 1880c9808c..ff56162fdd 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v2.107.1-rc.1 +v2.107.1 diff --git a/compiler/src/dmd/backend/cgelem.d b/compiler/src/dmd/backend/cgelem.d index 7e34fe7375..3e99f8fb31 100644 --- a/compiler/src/dmd/backend/cgelem.d +++ b/compiler/src/dmd/backend/cgelem.d @@ -5035,14 +5035,9 @@ private elem * el64_32(elem *e, goal_t goal) } break; - case OPmul: - if (config.exe & (EX_OSX | EX_OSX64)) // https://issues.dlang.org/show_bug.cgi?id=21047 - break; - else - goto case; - case OPadd: case OPmin: + case OPmul: case OPor: case OPand: case OPxor: diff --git a/compiler/src/dmd/backend/dwarfdbginf.d b/compiler/src/dmd/backend/dwarfdbginf.d index 7bde5120e0..a7790a2b92 100644 --- a/compiler/src/dmd/backend/dwarfdbginf.d +++ b/compiler/src/dmd/backend/dwarfdbginf.d @@ -16,15 +16,19 @@ Some generic information for debug info on macOS: The linker on macOS will remove any debug info, i.e. every section with the -`S_ATTR_DEBUG` flag, this includes everything in the `__DWARF` section. By using -the `S_REGULAR` flag the linker will not remove this section. This allows to get -the filenames and line numbers for backtraces from the executable. +`S_ATTR_DEBUG` flag, this includes everything in the `__DWARF` section. +Because of this, it is not possible to get filenames and line numbers for +backtraces from the executable alone. Normally the linker removes all the debug info but adds a reference to the object files. The debugger can then read the object files to get filename and line number information. It's also possible to use an additional tool that generates a separate `.dSYM` file. This file can then later be deployed with the application if debug info is needed when the application is deployed. + +Support in core.runtime for getting filename and line number for backtraces +from these `.dSYM` files will need to be investigated. +See: https://issues.dlang.org/show_bug.cgi?id=20510 */ module dmd.backend.dwarfdbginf; @@ -478,7 +482,7 @@ static if (1) { name = n; if (config.objfmt == OBJ_MACH) - flags = S_ATTR_DEBUG; + flags = S_REGULAR | S_ATTR_DEBUG; else flags = SHT_PROGBITS; } @@ -552,10 +556,7 @@ static if (1) debug_abbrev = Section("__debug_abbrev"); debug_info = Section("__debug_info"); debug_str = Section("__debug_str"); - // We use S_REGULAR to make sure the linker doesn't remove this section. Needed - // for filenames and line numbers in backtraces. debug_line = Section("__debug_line"); - debug_line.flags = S_REGULAR; } void elfDebugSectionsInit() { diff --git a/compiler/src/dmd/backend/mach.d b/compiler/src/dmd/backend/mach.d index 1686537942..a7078e2766 100644 --- a/compiler/src/dmd/backend/mach.d +++ b/compiler/src/dmd/backend/mach.d @@ -94,6 +94,12 @@ enum LC_SYMTAB = 2, LC_DYSYMTAB = 11, LC_SEGMENT_64 = 0x19, + + /// Build for MacOSX min OS version. + LC_VERSION_MIN_MACOSX = 0x24, + + /// Build for platform min OS version. + LC_BUILD_VERSION = 0x32, } struct load_command @@ -407,3 +413,62 @@ struct scattered_relocation_info int r_value; } + +/** + * The version_min_command contains the min OS version on which this binary was + * built to run. + */ +struct version_min_command +{ + /// + uint cmd = LC_VERSION_MIN_MACOSX; + + /// + uint cmdsize = typeof(this).sizeof; + + /// X.Y.Z is encoded in nibbles xxxx.yy.zz + uint version_; + + /// X.Y.Z is encoded in nibbles xxxx.yy.zz + uint sdk = 0; +} + +/** + * The `build_version_command` contains the min OS version on which this binary + * was built to run for its platform. + */ +struct build_version_command +{ + /// + uint cmd = LC_BUILD_VERSION; + + /// + uint cmdsize = typeof(this).sizeof; + + /// Platform + uint platform = PLATFORM_MACOS; + + /// X.Y.Z is encoded in nibbles xxxx.yy.zz + uint minos; + + /// X.Y.Z is encoded in nibbles xxxx.yy.zz + uint sdk = 0; + + /// Number of tool entries following this + uint ntools = 0; +} + +/// Known values for the platform field in `build_version_command` +enum +{ + PLATFORM_MACOS = 1, + PLATFORM_IOS = 2, + PLATFORM_TVOS = 3, + PLATFORM_WATCHOS = 4, + PLATFORM_BRIDGEOS = 5, + PLATFORM_MACCATALYST = 6, + PLATFORM_IOSSIMULATOR = 7, + PLATFORM_TVOSSIMULATOR = 8, + PLATFORM_WATCHOSSIMULATOR = 9, + PLATFORM_DRIVERKIT = 10 +} diff --git a/compiler/src/dmd/backend/machobj.d b/compiler/src/dmd/backend/machobj.d index 517d088583..7443f7eb8f 100644 --- a/compiler/src/dmd/backend/machobj.d +++ b/compiler/src/dmd/backend/machobj.d @@ -625,6 +625,7 @@ void MachObj_term(const(char)* objfilename) * { sections } * symtab_command * dysymtab_command + * build_version_command/version_min_command * { segment contents } * { relocations } * symbol table @@ -632,6 +633,7 @@ void MachObj_term(const(char)* objfilename) * indirect symbol table */ + auto version_command = VersionCommand(operatingSystemVersion); uint foffset; uint headersize; uint sizeofcmds; @@ -645,9 +647,10 @@ void MachObj_term(const(char)* objfilename) header.cputype = CPU_TYPE_X86_64; header.cpusubtype = CPU_SUBTYPE_I386_ALL; header.filetype = MH_OBJECT; - header.ncmds = 3; + header.ncmds = 4; header.sizeofcmds = cast(uint)(segment_command_64.sizeof + (section_cnt - 1) * section_64.sizeof + + version_command.size + symtab_command.sizeof + dysymtab_command.sizeof); header.flags = MH_SUBSECTIONS_VIA_SYMBOLS; @@ -669,9 +672,10 @@ void MachObj_term(const(char)* objfilename) header.cputype = CPU_TYPE_I386; header.cpusubtype = CPU_SUBTYPE_I386_ALL; header.filetype = MH_OBJECT; - header.ncmds = 3; + header.ncmds = 4; header.sizeofcmds = cast(uint)(segment_command.sizeof + (section_cnt - 1) * section.sizeof + + version_command.size + symtab_command.sizeof + dysymtab_command.sizeof); header.flags = MH_SUBSECTIONS_VIA_SYMBOLS; @@ -864,6 +868,8 @@ void MachObj_term(const(char)* objfilename) } // Put out relocation data + // See mach-o/reloc.h for some examples of what should be generated and when: + // https://github.com/apple-oss-distributions/xnu/blob/rel/xnu-10002/EXTERNAL_HEADERS/mach-o/x86_64/reloc.h mach_numbersyms(); for (int seg = 1; seg < SegData.length; seg++) { @@ -975,12 +981,8 @@ void MachObj_term(const(char)* objfilename) rel.r_type = X86_64_RELOC_SIGNED; else if ((s.Sfl == FLfunc || s.Sfl == FLextern || s.Sclass == SC.global || s.Sclass == SC.comdat || s.Sclass == SC.comdef) && r.rtype == RELaddr) - { - rel.r_type = X86_64_RELOC_GOT_LOAD; - if (seg == eh_frame_seg || - seg == except_table_seg) - rel.r_type = X86_64_RELOC_GOT; - } + rel.r_type = X86_64_RELOC_GOT; + rel.r_address = cast(int)r.offset; rel.r_symbolnum = s.Sxtrnnum; rel.r_pcrel = 1; @@ -1352,6 +1354,7 @@ void MachObj_term(const(char)* objfilename) sym32.n_sect = sym.n_sect; fobjbuf.write(&sym32, sym32.sizeof); } + dysymtab_cmd.nundefsym++; symtab_cmd.nsyms++; } foffset += symtab_cmd.nsyms * (I64 ? nlist_64.sizeof : nlist.sizeof); @@ -1399,6 +1402,7 @@ void MachObj_term(const(char)* objfilename) fobjbuf.write(&segment_cmd, segment_cmd.sizeof); fobjbuf.write(SECbuf.buf + section.sizeof, cast(uint)((section_cnt - 1) * section.sizeof)); } + fobjbuf.write(version_command.data, version_command.size); fobjbuf.write(&symtab_cmd, symtab_cmd.sizeof); fobjbuf.write(&dysymtab_cmd, dysymtab_cmd.sizeof); fobjbuf.position(foffset, 0); @@ -2823,3 +2827,170 @@ int dwarf_eh_frame_fixup(int dfseg, targ_size_t offset, Symbol *s, targ_size_t v return I64 ? 8 : 4; } + + +private: + +/** + * Encapsulates the build_version_command/version_min_command load commands. + * + * For the 10.14 and later SDK, the `build_version_command` load command is used. + * For earlier versions, the `version_min_command` load command is used. + */ +const struct VersionCommand +{ + pure: + nothrow: + @nogc: + @safe: + + private + { + /** + * This is the absolute minimum supported version of macOS (64 bit) for DMD, + * as documented at: https://dlang.org/dmd-osx.html#requirements + * NOTE: Versions earlier than 10.7 do not support thread local storage. + */ + enum fallbackOSVersion = Version(10, 9).encode; + + /// The first minor version that uses the `build_version_command`. + enum firstMinorUsingBuildVersionCommand = 14; + + /// `true` if the `build_version_command` load command should be used. + bool useBuild; + + /// The `build_version_command` load command. + build_version_command buildVersionCommand; + + /// The `version_min_command` load command. + version_min_command versionMinCommand; + } + + /** + * Initializes the VersionCommand. + * + * Params: + * os = the version of the operating system + */ + this(Version os) + { + useBuild = os.minor >= firstMinorUsingBuildVersionCommand; + + const encodedOs = os.isValid ? os.encode : fallbackOSVersion; + + const build_version_command buildVersionCommand = { minos: encodedOs }; + const version_min_command versionMinCommand = { version_: encodedOs }; + + this.buildVersionCommand = buildVersionCommand; + this.versionMinCommand = versionMinCommand; + } + + /// Returns: the size of the load command. + size_t size() + { + return useBuild ? build_version_command.sizeof : version_min_command.sizeof; + } + + /// Returns: the data for the load command. + const(void)* data() return + { + return useBuild ? cast(const(void)*) &buildVersionCommand : cast(const(void)*) &versionMinCommand; + } +} + +/// Holds an operating system version or a SDK version. +immutable struct Version +{ + /// + int major; + + /// + int minor; + + /// + int build; + + /// Returns: `true` if the version is valid + bool isValid() pure nothrow @nogc @safe + { + return major >= 10 && major < 100 && + minor >= 0 && minor < 100 && + build >= 0 && build < 100; + } +} + +/** + * Returns the given version encoded as a single integer. + * + * Params: + * version_ = the version to encode. Needs to be a valid version + * (`version_.isValid`) + * + * Returns: the encoded version + */ +int encode(Version version_) pure @nogc @safe +in +{ + assert(version_.isValid); +} +do +{ + with (version_) + return major * 2^^16 + minor * 2^^8 + build * 2^^0; +} + +unittest +{ + assert(Version(10, 14, 0).encode == 0x0a0e00); + assert(Version(10, 14, 1).encode == 0x0a0e01); + assert(Version(10, 14, 6).encode == 0x0a0e06); + assert(Version(10, 14, 99).encode == 0x0a0e63); + + assert(Version(10, 15, 6).encode == 0x0a0f06); + + assert(Version(10, 16, 0).encode == 0x0a1000); + assert(Version(10, 16, 6).encode == 0x0a1006); + + assert(Version(10, 17, 0).encode == 0x0a1100); +} + +/// Returns: the version of the currently running operating system. +@trusted +Version operatingSystemVersion() +{ + if (const deploymentTarget = getenv("MACOSX_DEPLOYMENT_TARGET")) + { + const version_ = toVersion(deploymentTarget); + + if (version_.isValid) + return version_; + + error(null, 0, 0, "invalid version number in 'MACOSX_DEPLOYMENT_TARGET=%s'", deploymentTarget); + } + return Version(); +} + +/** + * Converts the given string to a `Version`. + * + * Params: + * str = the string to convert. Should have the format `XX.YY(.ZZ)`. Needs to + * be `\0` terminated. + * + * Returns: the converted `Version`. + */ +@trusted +Version toVersion(const char* str) @nogc +{ + import core.stdc.stdio : sscanf; + + if (!str) + return Version(); + + Version version_; + + with (version_) + str.sscanf("%d.%d.%d", &major, &minor, &build); + + return version_; +} diff --git a/compiler/src/dmd/cparse.d b/compiler/src/dmd/cparse.d index e917d2cb7e..aeedb493ef 100644 --- a/compiler/src/dmd/cparse.d +++ b/compiler/src/dmd/cparse.d @@ -2155,7 +2155,7 @@ final class CParser(AST) : Parser!AST error("function identifier-list cannot end with `...`"); ft.parameterList.varargs = AST.VarArg.KRvariadic; // but C11 allows extra arguments auto plLength = pl.length; - if (symbols.length != plLength) + if (symbols && symbols.length != plLength) error(token.loc, "%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length); /* Transfer the types and storage classes from symbols[] to pl[] @@ -2176,6 +2176,12 @@ final class CParser(AST) : Parser!AST if (p.type || !(p.storageClass & STC.parameter)) error("storage class and type are not allowed in identifier-list"); + if (!symbols) + { + // Error already given in cparseDeclaration + p.type = AST.Type.terror; + continue; + } foreach (s; (*symbols)[]) // yes, quadratic { auto ad = s.isAttribDeclaration(); diff --git a/compiler/src/dmd/dinterpret.d b/compiler/src/dmd/dinterpret.d index c021b184c6..c4924903f2 100644 --- a/compiler/src/dmd/dinterpret.d +++ b/compiler/src/dmd/dinterpret.d @@ -3787,7 +3787,7 @@ public: if (v is v2 || !v.isOverlappedWith(v2)) continue; auto e = (*sle.elements)[i]; - if (e.op != EXP.void_) + if (e !is null && e.op != EXP.void_) (*sle.elements)[i] = voidInitLiteral(e.type, v).copy(); } } diff --git a/compiler/src/dmd/dmodule.d b/compiler/src/dmd/dmodule.d index a77e4f303c..58bf3fd075 100644 --- a/compiler/src/dmd/dmodule.d +++ b/compiler/src/dmd/dmodule.d @@ -1394,6 +1394,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) { enum SourceEncoding { utf16, utf32} enum Endian { little, big} + immutable loc = mod.getLoc(); /* * Convert a buffer from UTF32 to UTF8 @@ -1413,7 +1414,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) if (buf.length & 3) { - .error(mod.loc, "%s `%s` odd length of UTF-32 char source %llu", + .error(loc, "%s `%s` odd length of UTF-32 char source %llu", mod.kind, mod.toPrettyChars, cast(ulong) buf.length); return null; } @@ -1430,7 +1431,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) { if (u > 0x10FFFF) { - .error(mod.loc, "%s `%s` UTF-32 value %08x greater than 0x10FFFF", mod.kind, mod.toPrettyChars, u); + .error(loc, "%s `%s` UTF-32 value %08x greater than 0x10FFFF", mod.kind, mod.toPrettyChars, u); return null; } dbuf.writeUTF8(u); @@ -1460,7 +1461,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) if (buf.length & 1) { - .error(mod.loc, "%s `%s` odd length of UTF-16 char source %llu", mod.kind, mod.toPrettyChars, cast(ulong) buf.length); + .error(loc, "%s `%s` odd length of UTF-16 char source %llu", mod.kind, mod.toPrettyChars, cast(ulong) buf.length); return null; } @@ -1480,13 +1481,13 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) i++; if (i >= eBuf.length) { - .error(mod.loc, "%s `%s` surrogate UTF-16 high value %04x at end of file", mod.kind, mod.toPrettyChars, u); + .error(loc, "%s `%s` surrogate UTF-16 high value %04x at end of file", mod.kind, mod.toPrettyChars, u); return null; } const u2 = readNext(&eBuf[i]); if (u2 < 0xDC00 || 0xE000 <= u2) { - .error(mod.loc, "%s `%s` surrogate UTF-16 low value %04x out of range", mod.kind, mod.toPrettyChars, u2); + .error(loc, "%s `%s` surrogate UTF-16 low value %04x out of range", mod.kind, mod.toPrettyChars, u2); return null; } u = (u - 0xD7C0) << 10; @@ -1494,12 +1495,12 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) } else if (u >= 0xDC00 && u <= 0xDFFF) { - .error(mod.loc, "%s `%s` unpaired surrogate UTF-16 value %04x", mod.kind, mod.toPrettyChars, u); + .error(loc, "%s `%s` unpaired surrogate UTF-16 value %04x", mod.kind, mod.toPrettyChars, u); return null; } else if (u == 0xFFFE || u == 0xFFFF) { - .error(mod.loc, "%s `%s` illegal UTF-16 value %04x", mod.kind, mod.toPrettyChars, u); + .error(loc, "%s `%s` illegal UTF-16 value %04x", mod.kind, mod.toPrettyChars, u); return null; } dbuf.writeUTF8(u); @@ -1558,7 +1559,6 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod) // It's UTF-8 if (buf[0] >= 0x80) { - auto loc = mod.getLoc(); .error(loc, "%s `%s` source file must start with BOM or ASCII character, not \\x%02X", mod.kind, mod.toPrettyChars, buf[0]); return null; } diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index b4d5274e7c..db40ae01de 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -12357,8 +12357,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return result; } - void handleCatArgument(Expressions *arguments, Expression e) + void handleCatArgument(Expressions *arguments, Expression e, Type catType, bool isRightArg) { + auto tb = e.type.toBasetype(); + + if ((isRightArg && e.parens) || (!isRightArg && !tb.equals(catType))) + { + arguments.push(e); + return; + } + if (auto ce = e.isCatExp()) { Expression lowering = ce.lowering; @@ -12388,8 +12396,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor arguments.push(new StringExp(exp.loc, funcname.toDString())); } - handleCatArgument(arguments, exp.e1); - handleCatArgument(arguments, exp.e2); + handleCatArgument(arguments, exp.e1, exp.type.toBasetype(), false); + handleCatArgument(arguments, exp.e2, exp.type.toBasetype(), true); Expression id = new IdentifierExp(exp.loc, Id.empty); id = new DotIdExp(exp.loc, id, Id.object); diff --git a/compiler/src/dmd/objc_glue.d b/compiler/src/dmd/objc_glue.d index 1812470675..db17af93d6 100644 --- a/compiler/src/dmd/objc_glue.d +++ b/compiler/src/dmd/objc_glue.d @@ -338,7 +338,7 @@ struct Segments immutable(char*) sectionName; immutable(char*) segmentName; immutable int flags; - immutable int alignment; + immutable int p2align; this(typeof(this.tupleof) tuple) @safe { @@ -388,7 +388,7 @@ struct Segments return segments[id] = Obj.getsegment( seg.sectionName, seg.segmentName, - seg.alignment, + seg.p2align, seg.flags ); } @@ -1159,7 +1159,7 @@ private: const symbolName = prefix ~ classDeclaration.objc.identifier.toString(); auto symbol = Symbols.getStatic(symbolName); symbol.Sseg = Segments[Segments.Id.const_]; - symbol.Salignment = 3; + symbol.Salignment = 8; symbol.Sdt = dtb.finish(); return symbol; @@ -1311,7 +1311,7 @@ struct ProtocolDeclaration symbol.Sseg = Segments[Segments.Id.protolist]; symbol.Sclass = SC.comdat; symbol.Sflags |= SFLhidden; - symbol.Salignment = 3; + symbol.Salignment = 8; auto dtb = DtBuilder(0); dtb.xoff(protocol, 0); @@ -1326,7 +1326,7 @@ struct ProtocolDeclaration symbol.Sseg = Segments[Segments.Id.data]; symbol.Sclass = SC.comdat; symbol.Sflags |= SFLhidden; - symbol.Salignment = 3; + symbol.Salignment = 8; auto dtb = DtBuilder(0); toDt(dtb); @@ -1478,7 +1478,7 @@ private: symbol.Sdt = dtb.finish(); symbol.Sseg = Segments[Segments.Id.const_]; - symbol.Salignment = 3; + symbol.Salignment = 8; return symbol; } @@ -1512,7 +1512,7 @@ private: symbol.Sdt = dtb.finish(); symbol.Sseg = Segments[Segments.Id.const_]; - symbol.Salignment = 3; + symbol.Salignment = 8; outdata(symbol); @@ -1546,7 +1546,7 @@ private: symbol.Sdt = dtb.finish(); symbol.Sseg = Segments[Segments.Id.const_]; - symbol.Salignment = 3; + symbol.Salignment = 8; outdata(symbol); diff --git a/compiler/src/dmd/todt.d b/compiler/src/dmd/todt.d index 10df5c782d..a614fcdfd0 100644 --- a/compiler/src/dmd/todt.d +++ b/compiler/src/dmd/todt.d @@ -92,6 +92,11 @@ void Initializer_toDt(Initializer init, ref DtBuilder dtb, bool isCfile) if (tb.ty == Tvector) tb = (cast(TypeVector)tb).basetype; + if (ai.dim == 0 && tb.isZeroInit(ai.loc)) + { + dtb.nzeros(cast(uint)ai.type.size()); + return; + } Type tn = tb.nextOf().toBasetype(); //printf("\tdim = %d\n", ai.dim); diff --git a/compiler/test/compilable/issue24399.d b/compiler/test/compilable/issue24399.d new file mode 100644 index 0000000000..ae3e7442f5 --- /dev/null +++ b/compiler/test/compilable/issue24399.d @@ -0,0 +1,9 @@ +// REQUIRED_ARGS: -main +// LINK: +template rt_options() +{ + __gshared string[] rt_options = []; + string[] rt_options_tls = []; +} + +alias _ = rt_options!(); diff --git a/compiler/test/compilable/issue24409.d b/compiler/test/compilable/issue24409.d new file mode 100644 index 0000000000..5d298df211 --- /dev/null +++ b/compiler/test/compilable/issue24409.d @@ -0,0 +1,17 @@ +static struct S +{ + union + { + int i; + long l; + } +} + +int f() +{ + S* r = new S(); + r.i = 5; + return r.i; +} + +enum X = f(); diff --git a/compiler/test/fail_compilation/fail24422.c b/compiler/test/fail_compilation/fail24422.c new file mode 100644 index 0000000000..d148b492c3 --- /dev/null +++ b/compiler/test/fail_compilation/fail24422.c @@ -0,0 +1,7 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail24422.c(7): Error: type-specifier missing for declaration of `a` +--- +*/ +void f24422(a) a; { } diff --git a/compiler/test/runnable/debug_info.d b/compiler/test/runnable/debug_info.d deleted file mode 100644 index 7853d9a3d9..0000000000 --- a/compiler/test/runnable/debug_info.d +++ /dev/null @@ -1,50 +0,0 @@ -// REQUIRED_ARGS: -g - -void main() -{ - version(OSX) testDebugLineMacOS(); -} - -version (OSX): - -struct mach_header; -struct mach_header_64; -struct section; -struct section_64; - -version (D_LP64) -{ - alias MachHeader = mach_header_64; - alias Section = section_64; -} - -else -{ - alias MachHeader = mach_header; - alias Section = section; -} - -extern (C) -{ - MachHeader* _dyld_get_image_header(uint image_index); - const(section)* getsectbynamefromheader(scope const mach_header* mhp, scope const char* segname, scope const char* sectname); - const(section_64)* getsectbynamefromheader_64(scope const mach_header_64* mhp, scope const char* segname, scope const char* sectname); -} - -const(Section)* getSectByNameFromHeader(MachHeader* mhp, in char* segname, in char* sectname) -{ - version (D_LP64) - return getsectbynamefromheader_64(mhp, segname, sectname); - else - return getsectbynamefromheader(mhp, segname, sectname); -} - -void testDebugLineMacOS() -{ - auto header = _dyld_get_image_header(0); - assert(header); - - auto section = getSectByNameFromHeader(header, "__DWARF", "__debug_line"); - // verify that the __debug_line section is present in the final executable - assert(section); -} diff --git a/compiler/test/runnable/extra-files/link20802a.d b/compiler/test/runnable/extra-files/link20802a.d new file mode 100644 index 0000000000..3c52258ca4 --- /dev/null +++ b/compiler/test/runnable/extra-files/link20802a.d @@ -0,0 +1,8 @@ +import link20802b; +void main() +{ + // First test from https://issues.dlang.org/show_bug.cgi?id=20802#c3 + CodepointSet('a', 'z'); + dstring s; + decodeGrapheme(s); +} diff --git a/compiler/test/runnable/extra-files/link20802b.d b/compiler/test/runnable/extra-files/link20802b.d new file mode 100644 index 0000000000..333e8a29fc --- /dev/null +++ b/compiler/test/runnable/extra-files/link20802b.d @@ -0,0 +1,30 @@ +module link20802b; + +// First test from https://issues.dlang.org/show_bug.cgi?id=20802#c3 + +enum TransformRes { goOn } + +void writeAligned()() +{ + final switch (TransformRes.goOn) { case TransformRes.goOn: break; } +} + +struct GcPolicy {} +alias CodepointSet = InversionList!GcPolicy; +struct InversionList(SP=GcPolicy) +{ + this()(uint[] intervals...) + { + sanitize(); + } + + void sanitize() + { + writeAligned(); + } +} + +void decodeGrapheme(Input)(ref Input inp) +{ + final switch (TransformRes.goOn) { case TransformRes.goOn: break; } +} diff --git a/compiler/test/runnable/issue24401.d b/compiler/test/runnable/issue24401.d new file mode 100644 index 0000000000..109d543a0b --- /dev/null +++ b/compiler/test/runnable/issue24401.d @@ -0,0 +1,6 @@ +// PERMUTE_ARGS: +// https://issues.dlang.org/show_bug.cgi?id=24401 +int main() +{ + return (() @trusted => 0)(); +} diff --git a/compiler/test/runnable/link20802.sh b/compiler/test/runnable/link20802.sh new file mode 100755 index 0000000000..f0a6674fbf --- /dev/null +++ b/compiler/test/runnable/link20802.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + + +dir=${RESULTS_DIR}${SEP}runnable + +libname=${OUTPUT_BASE}${LIBEXT} +exename=${OUTPUT_BASE}${EXE} + +$DMD -m${MODEL} -I${EXTRA_FILES} -lib -release -of${libname} ${EXTRA_FILES}${SEP}link20802b.d +$DMD -m${MODEL} -I${EXTRA_FILES} -of${exename} ${EXTRA_FILES}${SEP}link20802a.d ${libname} + +${exename} + +rm_retry ${OUTPUT_BASE}{${LIBEXT},${EXE},${OBJ}} diff --git a/compiler/test/runnable/test24371.d b/compiler/test/runnable/test24371.d new file mode 100644 index 0000000000..885f9b8648 --- /dev/null +++ b/compiler/test/runnable/test24371.d @@ -0,0 +1,15 @@ +// https://issues.dlang.org/show_bug.cgi?id=24371 + +void main() +{ + assert("b" ~ "c" == "bc"); + assert(["a"] ~ "b" == ["a", "b"]); + assert(["a"] ~ ("b" ~ "c") == ["a", "bc"]); + + auto strArr = ["a"]; + assert(strArr ~ ("b" ~ "c") == ["a", "bc"]); + auto str = "c"; + assert(["a"] ~ ("b" ~ str) == ["a", "bc"]); + + assert(strArr ~ ("b" ~ str) == ["a", "bc"]); +} diff --git a/compiler/test/runnable_cxx/test7925.d b/compiler/test/runnable_cxx/test7925.d index f05aac916e..2d0b023fe5 100644 --- a/compiler/test/runnable_cxx/test7925.d +++ b/compiler/test/runnable_cxx/test7925.d @@ -1,12 +1,5 @@ // EXTRA_CPP_SOURCES: cpp7925.cpp -/* -Exclude -O/-inline due to a codegen bug on OSX: -https://issues.dlang.org/show_bug.cgi?id=22556 - -PERMUTE_ARGS(osx): -release -g -*/ - import core.vararg; extern(C++) class C1 diff --git a/druntime/src/core/exception.d b/druntime/src/core/exception.d index 959ce83f02..c7b302c452 100644 --- a/druntime/src/core/exception.d +++ b/druntime/src/core/exception.d @@ -19,6 +19,19 @@ void __switch_errorT()(string file = __FILE__, size_t line = __LINE__) @trusted assert(0, "No appropriate switch clause found"); } +/* + * Make sure template __switch_errorT is always instantiated when building + * druntime. This works around https://issues.dlang.org/show_bug.cgi?id=20802. + * When druntime and phobos are compiled with -release, the instance for + * __switch_errorT is not needed. An application compiled with -release + * could need the instance for __switch_errorT, but the compiler would + * not generate code for it, because it assumes, that it was already + * generated for druntime. Always including the instance in a compiled + * druntime allows to use an application without -release with druntime + * with -release. + */ +private alias dummy__switch_errorT = __switch_errorT!(); + /** * Thrown on a range error. */ diff --git a/druntime/test/exceptions/Makefile b/druntime/test/exceptions/Makefile index fd975327d9..230013cc65 100644 --- a/druntime/test/exceptions/Makefile +++ b/druntime/test/exceptions/Makefile @@ -20,7 +20,7 @@ ifeq ($(OS)-$(BUILD),dragonflybsd-debug) LINE_TRACE_DFLAGS:=-L--export-dynamic endif ifeq ($(OS)-$(BUILD),osx-debug) - TESTS+=line_trace line_trace_21656 long_backtrace_trunc cpp_demangle + TESTS+=line_trace line_trace_21656 cpp_demangle LINE_TRACE_DFLAGS:= endif ifeq ($(OS)-$(BUILD),windows-debug) @@ -42,7 +42,7 @@ $(ROOT)/line_trace.done: $(ROOT)/line_trace$(DOTEXE) @echo Testing line_trace $(QUIET)$(TIMELIMIT)$(ROOT)/line_trace $(RUN_ARGS) > $(ROOT)/line_trace.output # Use sed to canonicalize line_trace.output and compare against expected output in line_trace.exp - $(QUIET)$(SED) "s/\[0x[0-9a-f]*\]/\[ADDR\]/g; s/scope //g; s/Nl//g" $(ROOT)/line_trace.output | $(DIFF) line_trace.exp - + $(QUIET)$(SED) "s|^.*/src/|src/|g; s/\[0x[0-9a-f]*\]/\[ADDR\]/g; s/scope //g; s/Nl//g" $(ROOT)/line_trace.output | $(DIFF) line_trace.exp - @rm -f $(ROOT)/line_trace.output @touch $@ @@ -52,7 +52,7 @@ $(ROOT)/line_trace_21656.done: $(ROOT)/line_trace$(DOTEXE) @mkdir -p $(ROOT)/line_trace_21656 @touch $(ROOT)/line_trace_21656/line_trace $(QUIET)cd $(ROOT)/line_trace_21656 && PATH="..:$$PATH" $(TIMELIMIT)line_trace $(RUN_ARGS) > line_trace.output - $(QUIET)$(SED) "s/\[0x[0-9a-f]*\]/\[ADDR\]/g; s/scope //g; s/Nl//g" $(ROOT)/line_trace_21656/line_trace.output | $(DIFF) line_trace.exp - + $(QUIET)$(SED) "s|^.*/src/|src/|g; s/\[0x[0-9a-f]*\]/\[ADDR\]/g; s/scope //g; s/Nl//g" $(ROOT)/line_trace_21656/line_trace.output | $(DIFF) line_trace.exp - @rm -rf $(ROOT)/line_trace_21656 @touch $@ @@ -60,7 +60,7 @@ $(ROOT)/long_backtrace_trunc.done: $(ROOT)/long_backtrace_trunc$(DOTEXE) @echo Testing long_backtrace_trunc $(QUIET)$(TIMELIMIT)$(ROOT)/long_backtrace_trunc $(RUN_ARGS) > $(ROOT)/long_backtrace_trunc.output # Use sed to canonicalize long_backtrace_trunc.output and compare against expected output in long_backtrace_trunc.exp - $(QUIET)$(SED) "s/\[0x[0-9a-f]*\]/\[ADDR\]/g; s/scope //g; s/Nl//g" $(ROOT)/long_backtrace_trunc.output | $(DIFF) long_backtrace_trunc.exp - + $(QUIET)$(SED) "s|^.*/src/|src/|g; s/\[0x[0-9a-f]*\]/\[ADDR\]/g; s/scope //g; s/Nl//g" $(ROOT)/long_backtrace_trunc.output | $(DIFF) long_backtrace_trunc.exp - @rm -f $(ROOT)/long_backtrace_trunc.output @touch $@