From 57c5b071afcfea4fcdd280d4592d5aebb0116875 Mon Sep 17 00:00:00 2001 From: Nicholas Wilson Date: Mon, 7 Oct 2024 17:00:14 +0800 Subject: [PATCH] Rebase stable6 (#16967) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Document template instance duplication status as part of its field documentation. (#16643) * Fix Bugzilla 24599 - Wrongly elided TypeInfo emission (#15868) Reverting #14844, which caused such missing TypeInfos, *and* making sure the special TypeInfo members are fully analyzed and ready for codegen (otherwise hitting an assertion for the real-world project). * Reorganize backend build files to match target and make more similar per line (#16672) * Remove redundant suggestions on linker errors (#16711) * Fix bugzilla 24337 - Segfault when printing an int[] cast from a string (#16729) * Add BitFieldStyle.Gcc_Clang_ARM Required for 32-bit ARM, and non-Apple 64-bit ARM targets. The only difference to `Gcc_Clang` is that anonymous and 0-length bit-fields do contribute to the aggregate alignment. Caught by existing proper C interop tests in runnable_cxx/testbitfields.d on such targets. The hardcoded bad tests in runnable/{bitfieldsposix64.c,dbitfieldsposix64.d} however now fail after the fix, on such targets again. * [refactor to `TargetC.contributesToAggregateAlignment(BitFieldDeclaration)` hook] * Fix Bugzilla Issue 24687 - [REG2.110] Cannot cast string-imports to select overload anymore * Also make deprecationSupplemental adhere to error limit (#16779) Co-authored-by: Dennis Korpel * Fix bugzilla 24699 - [REG2.108] No short-circuit evaluation of mixing template bool argument * Fix bugzilla 24731 - IFTI cannot handle integer expressions (#16822) * Fix Bugzilla Issue 24760 - ICE on variadic after default argument * Fix bugzilla 24790 - -vcg-ast ICE on lowered assign exp (#16914) Co-authored-by: Dennis Korpel * Fix bugzilla 24764 - ICE when -vcg-ast prints imported invariant (#16917) Co-authored-by: Dennis Korpel * Fix bugzilla 24431 - dmd -vcg-ast crashes printing failed template in… (#16916) --------- Co-authored-by: Richard (Rikki) Andrew Cattermole Co-authored-by: Martin Kinkelin Co-authored-by: Dennis Co-authored-by: Martin Kinkelin Co-authored-by: Martin Kinkelin Co-authored-by: RazvanN7 Co-authored-by: Dennis Korpel Co-authored-by: Dennis Korpel --- compiler/src/build.d | 27 ++++--- compiler/src/dmd/dcast.d | 2 +- compiler/src/dmd/dsymbolsem.d | 80 ++++++++----------- compiler/src/dmd/dtemplate.d | 35 +++++++- compiler/src/dmd/errors.d | 7 +- compiler/src/dmd/expression.d | 2 +- compiler/src/dmd/expressionsem.d | 48 ++++++----- compiler/src/dmd/frontend.h | 3 +- compiler/src/dmd/hdrgen.d | 8 +- compiler/src/dmd/link.d | 16 ++-- compiler/src/dmd/parse.d | 1 + compiler/src/dmd/pragmasem.d | 29 ++----- compiler/src/dmd/statementsem.d | 2 +- compiler/src/dmd/target.d | 20 +++++ compiler/src/dmd/target.h | 3 + compiler/src/dmd/todt.d | 7 ++ compiler/src/dmd/typesem.d | 6 +- compiler/src/dmd/typinf.d | 5 +- compiler/src/dmd/typinf.h | 2 +- compiler/src/tests/cxxfrontend.cc | 2 +- compiler/test/compilable/compile1.d | 5 ++ compiler/test/compilable/deprecationlimit.d | 2 +- .../test/compilable/extra-files/vcg-ast.d.cg | 22 ++++- compiler/test/compilable/import_exp.d | 8 ++ .../test/compilable/imports/vcg_ast_import.d | 4 + compiler/test/compilable/staticforeach.d | 4 +- compiler/test/compilable/test24337.d | 11 +++ compiler/test/compilable/test24760.d | 4 + .../test/compilable/vcg-ast-arraylength.d | 5 ++ compiler/test/compilable/vcg-ast.d | 12 +++ compiler/test/compilable/vcg_ast_compilable.d | 69 ++++++++++++++++ compiler/test/runnable/ifti.d | 15 ++++ compiler/test/runnable/test13613.d | 2 +- compiler/test/runnable/test23650.d | 13 --- compiler/test/runnable/test24599.d | 24 ++++++ 35 files changed, 359 insertions(+), 146 deletions(-) create mode 100644 compiler/test/compilable/imports/vcg_ast_import.d create mode 100644 compiler/test/compilable/test24337.d create mode 100644 compiler/test/compilable/test24760.d create mode 100644 compiler/test/compilable/vcg_ast_compilable.d delete mode 100644 compiler/test/runnable/test23650.d create mode 100644 compiler/test/runnable/test24599.d diff --git a/compiler/src/build.d b/compiler/src/build.d index 8516d01e150c..e7aa0a02d1a2 100755 --- a/compiler/src/build.d +++ b/compiler/src/build.d @@ -1581,10 +1581,12 @@ auto sourceFiles() cparse.d "), backendHeaders: fileArray(env["C"], " - cc.d cdef.d cgcv.d code.d cv4.d dt.d el.d global.d - obj.d oper.d rtlsym.d x86/code_x86.d iasm.d codebuilder.d - ty.d type.d mach.d mscoff.d dwarf.d dwarf2.d x86/xmm.d - dlist.d melf.d + cc.d cdef.d cgcv.d code.d dt.d el.d global.d + obj.d oper.d rtlsym.d iasm.d codebuilder.d + ty.d type.d dlist.d + dwarf.d dwarf2.d cv4.d + melf.d mscoff.d mach.d + x86/code_x86.d x86/xmm.d "), }; foreach (member; __traits(allMembers, DmdSources)) @@ -1620,13 +1622,16 @@ auto sourceFiles() "), backend: fileArray(env["C"], " bcomplex.d evalu8.d divcoeff.d dvec.d go.d gsroa.d glocal.d gdag.d gother.d gflow.d - dout.d inliner.d - gloop.d cgelem.d cgcs.d ee.d x86/cod4.d x86/cod5.d eh.d x86/nteh.d blockopt.d mem.d cg.d x86/cgreg.d - dtype.d debugprint.d fp.d symbol.d symtab.d elem.d dcode.d cgsched.d x86/cg87.d x86/cgxmm.d x86/cgcod.d x86/cod1.d x86/cod2.d - x86/cod3.d cv8.d dcgcv.d pdata.d util2.d var.d backconfig.d drtlsym.d dwarfeh.d ptrntab.d - dvarstats.d dwarfdbginf.d cgen.d goh.d barray.d cgcse.d elpicpie.d - machobj.d elfobj.d mscoffobj.d filespec.d aarray.d x86/disasm86.d arm/disasmarm.d arm/instr.d - arm/cod1.d arm/cod2.d arm/cod3.d arm/cod4.d + dout.d inliner.d eh.d filespec.d aarray.d + gloop.d cgelem.d cgcs.d ee.d blockopt.d mem.d cg.d + dtype.d debugprint.d fp.d symbol.d symtab.d elem.d dcode.d cgsched.d + pdata.d util2.d var.d backconfig.d drtlsym.d ptrntab.d + dvarstats.d cgen.d goh.d barray.d cgcse.d elpicpie.d + dwarfeh.d dwarfdbginf.d cv8.d dcgcv.d + machobj.d elfobj.d mscoffobj.d + x86/nteh.d x86/cgreg.d x86/cg87.d x86/cgxmm.d x86/disasm86.d + x86/cgcod.d x86/cod1.d x86/cod2.d x86/cod3.d x86/cod4.d x86/cod5.d + arm/disasmarm.d arm/instr.d arm/cod1.d arm/cod2.d arm/cod3.d arm/cod4.d " ), }; diff --git a/compiler/src/dmd/dcast.d b/compiler/src/dmd/dcast.d index f54484f981ea..34b120b34125 100644 --- a/compiler/src/dmd/dcast.d +++ b/compiler/src/dmd/dcast.d @@ -705,7 +705,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; diff --git a/compiler/src/dmd/dsymbolsem.d b/compiler/src/dmd/dsymbolsem.d index 76fe6ca490b0..e7e054930cc1 100644 --- a/compiler/src/dmd/dsymbolsem.d +++ b/compiler/src/dmd/dsymbolsem.d @@ -1832,7 +1832,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { //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; @@ -7113,12 +7113,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; @@ -7129,15 +7136,13 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor else alignsize = 1; } - else - alignsize = memsize; // not memalignsize uint dummy; bfd.offset = placeField(bfd.loc, 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; @@ -7146,45 +7151,30 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor fieldState.fieldSize = memsize; } - if (style == TargetC.BitFieldStyle.Gcc_Clang) + if (ad.alignsize == 0) + ad.alignsize = 1; + if (!isMicrosoftStyle && contributesToAggregateAlignment && ad.alignsize < memalignsize) + ad.alignsize = memalignsize; + + if (bfd.fieldWidth == 0) { - if (bfd.fieldWidth == 0) + if (!isMicrosoftStyle && !isunion) { - 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; - } - - 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; } - - if (ad.alignsize == 0) - ad.alignsize = 1; - if (!anon && - ad.alignsize < memalignsize) - ad.alignsize = memalignsize; - } - else if (style == TargetC.BitFieldStyle.MS) - { - if (ad.alignsize == 0) - ad.alignsize = 1; - if (bfd.fieldWidth == 0) + else if (isMicrosoftStyle && fieldState.inFlight && !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; + // 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) @@ -7192,7 +7182,7 @@ 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 // and is at the alignment boundary, start a new field at the @@ -7217,7 +7207,7 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor } } } - else if (style == TargetC.BitFieldStyle.MS) + else { if (memsize != fieldState.fieldSize || fieldState.bitOffset + bfd.fieldWidth > fieldState.fieldSize * 8) @@ -7226,14 +7216,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; @@ -7247,8 +7237,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/compiler/src/dmd/dtemplate.d b/compiler/src/dmd/dtemplate.d index 2bf7ad17a766..15a0fea1c664 100644 --- a/compiler/src/dmd/dtemplate.d +++ b/compiler/src/dmd/dtemplate.d @@ -1695,7 +1695,9 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa edim = s ? getValue(s) : getValue(e); } } - if (tp && tp.matchArg(sc, t.dim, i, ¶meters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger()) + if ((tp && tp.matchArg(sc, t.dim, i, ¶meters, dedtypes, null)) || + (edim && edim.isIntegerExp() && edim.toInteger() == t.dim.toInteger()) + ) { result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm); return; @@ -3653,7 +3655,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() @@ -3665,7 +3682,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. @@ -4482,9 +4507,13 @@ extern (C++) class TemplateInstance : ScopeDsymbol // The arguments are not treated as part of a default argument, // because they are evaluated at compile time. + const inCondition = sc.condition; sc = sc.push(); sc.inDefaultArg = false; + // https://issues.dlang.org/show_bug.cgi?id=24699 + sc.condition = inCondition; + for (size_t j = 0; j < tiargs.length; j++) { RootObject o = (*tiargs)[j]; diff --git a/compiler/src/dmd/errors.d b/compiler/src/dmd/errors.d index 5ff9a05ff868..6c1584998772 100644 --- a/compiler/src/dmd/errors.d +++ b/compiler/src/dmd/errors.d @@ -570,8 +570,11 @@ extern (C++) void verrorReportSupplemental(const ref Loc loc, const(char)* forma goto case ErrorKind.error; else if (global.params.useDeprecated == DiagnosticReporting.inform && !global.gag) { - info.headerColor = Classification.deprecation; - verrorPrint(format, ap, info); + if (global.params.v.errorLimit == 0 || global.deprecations <= global.params.v.errorLimit) + { + info.headerColor = Classification.deprecation; + verrorPrint(format, ap, info); + } } break; diff --git a/compiler/src/dmd/expression.d b/compiler/src/dmd/expression.d index 71a9dbb71c89..3c79b02caa02 100644 --- a/compiler/src/dmd/expression.d +++ b/compiler/src/dmd/expression.d @@ -455,7 +455,7 @@ extern (C++) abstract class Expression : ASTNode dinteger_t toInteger() { //printf("Expression %s\n", EXPtoString(op).ptr); - if (!type.isTypeError()) + if (!type || !type.isTypeError()) error(loc, "integer constant expression expected instead of `%s`", toChars()); return 0; } diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index ad702dc2c6b3..3e4a2fdd4dac 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -140,16 +140,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(); @@ -162,15 +172,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(); @@ -181,9 +192,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; @@ -336,6 +349,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; } @@ -7194,17 +7208,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // Handle this in the glue layer Expression 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.traitsCompiles) - { - genObjCode = false; - } - - e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode); + e.type = getTypeInfoType(exp.loc, ta, sc); semanticTypeInfo(sc, ta); if (ea) @@ -7704,7 +7708,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; diff --git a/compiler/src/dmd/frontend.h b/compiler/src/dmd/frontend.h index 0c6b01d91b49..2654e33a54e4 100644 --- a/compiler/src/dmd/frontend.h +++ b/compiler/src/dmd/frontend.h @@ -5904,6 +5904,7 @@ struct TargetC final uint8_t wchar_tsize; Runtime runtime; BitFieldStyle bitFieldStyle; + bool contributesToAggregateAlignment(BitFieldDeclaration* bfd); TargetC() : crtDestructorsSupported(true), boolsize(), @@ -7596,7 +7597,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 { diff --git a/compiler/src/dmd/hdrgen.d b/compiler/src/dmd/hdrgen.d index e3f1dc283f70..8c4f0e4355c7 100644 --- a/compiler/src/dmd/hdrgen.d +++ b/compiler/src/dmd/hdrgen.d @@ -1720,10 +1720,10 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) //printf("FuncDeclaration::toCBuffer() '%s'\n", f.toChars()); if (stcToBuffer(buf, f.storage_class)) buf.writeByte(' '); + typeToBuffer(f.type, f.ident, buf, hgs); auto tf = f.type.isTypeFunction(); - typeToBuffer(tf, f.ident, buf, hgs); - if (hgs.hdrgen) + if (hgs.hdrgen && tf) { // if the return type is missing (e.g. ref functions or auto) // https://issues.dlang.org/show_bug.cgi?id=20090 @@ -1858,9 +1858,9 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs) if (stcToBuffer(buf, d.storage_class)) buf.writeByte(' '); buf.writestring("invariant"); - if(auto es = d.fbody.isExpStatement()) + auto es = d.fbody.isExpStatement(); + if (es && es.exp && es.exp.op == EXP.assert_) { - assert(es.exp && es.exp.op == EXP.assert_); buf.writestring(" ("); (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs); buf.writestring(");"); diff --git a/compiler/src/dmd/link.d b/compiler/src/dmd/link.d index 7ac403ba942c..0be14612365f 100644 --- a/compiler/src/dmd/link.d +++ b/compiler/src/dmd/link.d @@ -1426,8 +1426,8 @@ void parseLinkerOutput(const(char)[] linkerOutput, ErrorSink eSink) return s; } - bool missingSymbols = false; - bool missingDfunction = false; + bool missingCSymbols = false; + bool missingDsymbols = false; bool missingMain = false; void missingSymbol(const(char)[] name, const(char)[] referencedFrom) @@ -1437,11 +1437,12 @@ void parseLinkerOutput(const(char)[] linkerOutput, ErrorSink eSink) name = name[1 .. $]; // MS LINK prepends underscore to the existing one auto sym = demangle(name); - missingSymbols = true; if (sym == "main") missingMain = true; - if (sym != name) - missingDfunction = true; + else if (sym != name) + missingDsymbols = true; + else + missingCSymbols = true; eSink.error(Loc.initial, "undefined reference to `%.*s`", cast(int) sym.length, sym.ptr); if (referencedFrom.length > 0) @@ -1513,10 +1514,9 @@ void parseLinkerOutput(const(char)[] linkerOutput, ErrorSink eSink) if (missingMain) eSink.errorSupplemental(Loc.initial, "perhaps define a `void main() {}` function or use the `-main` switch"); - - if (missingDfunction) + else if (missingDsymbols) eSink.errorSupplemental(Loc.initial, "perhaps `.d` files need to be added on the command line, or use `-i` to compile imports"); - else if (missingSymbols) + else if (missingCSymbols) eSink.errorSupplemental(Loc.initial, "perhaps a library needs to be added with the `-L` flag or `pragma(lib, ...)`"); } diff --git a/compiler/src/dmd/parse.d b/compiler/src/dmd/parse.d index 4fbc3725a7dd..2285f9ae852a 100644 --- a/compiler/src/dmd/parse.d +++ b/compiler/src/dmd/parse.d @@ -9774,6 +9774,7 @@ immutable PREC[EXP.max + 1] precedence = EXP.assign : PREC.assign, EXP.construct : PREC.assign, EXP.blit : PREC.assign, + EXP.loweredAssignExp : PREC.assign, EXP.addAssign : PREC.assign, EXP.minAssign : PREC.assign, EXP.concatenateAssign : PREC.assign, diff --git a/compiler/src/dmd/pragmasem.d b/compiler/src/dmd/pragmasem.d index 679033c410da..405b7654ffa6 100644 --- a/compiler/src/dmd/pragmasem.d +++ b/compiler/src/dmd/pragmasem.d @@ -557,32 +557,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/compiler/src/dmd/statementsem.d b/compiler/src/dmd/statementsem.d index a73bd5ebdf3a..78dd105f49aa 100644 --- a/compiler/src/dmd/statementsem.d +++ b/compiler/src/dmd/statementsem.d @@ -4803,7 +4803,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/compiler/src/dmd/target.d b/compiler/src/dmd/target.d index 0495dba1a6c5..da06609cba34 100644 --- a/compiler/src/dmd/target.d +++ b/compiler/src/dmd/target.d @@ -1373,6 +1373,8 @@ extern (C++) struct Target */ struct TargetC { + import dmd.declaration : BitFieldDeclaration; + enum Runtime : ubyte { Unspecified, @@ -1462,6 +1464,24 @@ struct TargetC crtDestructorsSupported = false; } } + + /** + * 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); + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/compiler/src/dmd/target.h b/compiler/src/dmd/target.h index 2284b8322e7b..1a9837ff4c70 100644 --- a/compiler/src/dmd/target.h +++ b/compiler/src/dmd/target.h @@ -16,6 +16,7 @@ #include "globals.h" #include "tokens.h" +class BitFieldDeclaration; class ClassDeclaration; class Dsymbol; class Expression; @@ -77,6 +78,8 @@ struct TargetC uint8_t wchar_tsize; // size of a C 'wchar_t' type Runtime runtime; BitFieldStyle bitFieldStyle; // different C compilers do it differently + + bool contributesToAggregateAlignment(BitFieldDeclaration *bfd); }; struct TargetCPP diff --git a/compiler/src/dmd/todt.d b/compiler/src/dmd/todt.d index 4bfa0f1b88cc..667cd198cac5 100644 --- a/compiler/src/dmd/todt.d +++ b/compiler/src/dmd/todt.d @@ -1441,6 +1441,13 @@ private extern (C++) class TypeInfoDtVisitor : Visitor /* ti.toObjFile() won't get called. So, store these * member functions into object file in here. */ + + if (sd.semanticRun < PASS.semantic3done) + { + import dmd.semantic3 : semanticTypeInfoMembers; + semanticTypeInfoMembers(sd); + } + if (sd.xeq && sd.xeq != StructDeclaration.xerreq) toObjFile(sd.xeq, global.params.multiobj); if (sd.xcmp && sd.xcmp != StructDeclaration.xerrcmp) diff --git a/compiler/src/dmd/typesem.d b/compiler/src/dmd/typesem.d index f947dd33174e..c6306021c8cf 100644 --- a/compiler/src/dmd/typesem.d +++ b/compiler/src/dmd/typesem.d @@ -836,7 +836,9 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis L1: if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param { - auto trailingArgs = args[u .. $]; + Expression[] trailingArgs; + if (args.length >= u) + trailingArgs = args[u .. $]; if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage)) return vmatch < match ? vmatch : match; // Error message was already generated in `matchTypeSafeVarArgs` @@ -7853,7 +7855,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/compiler/src/dmd/typinf.d b/compiler/src/dmd/typinf.d index 201ea9602663..98d4287b8db5 100644 --- a/compiler/src/dmd/typinf.d +++ b/compiler/src/dmd/typinf.d @@ -100,14 +100,13 @@ bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc) * 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/compiler/src/dmd/typinf.h b/compiler/src/dmd/typinf.h index dd9572aab42f..6414ecdd36ac 100644 --- a/compiler/src/dmd/typinf.h +++ b/compiler/src/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/compiler/src/tests/cxxfrontend.cc b/compiler/src/tests/cxxfrontend.cc index 532a6297425d..eaf4a36936d3 100644 --- a/compiler/src/tests/cxxfrontend.cc +++ b/compiler/src/tests/cxxfrontend.cc @@ -1865,7 +1865,7 @@ void template_h(TemplateParameter *tp, Scope *sc, TemplateParameters *tps, void typinf_h(Expression *e, const Loc &loc, Type *t, Scope *sc) { dmd::genTypeInfo(e, loc, t, sc); - ::getTypeInfoType(loc, t, sc, false); + ::getTypeInfoType(loc, t, sc); dmd::isSpeculativeType(t); dmd::builtinTypeInfo(t); } diff --git a/compiler/test/compilable/compile1.d b/compiler/test/compilable/compile1.d index 4678eb533864..676108f68cfa 100644 --- a/compiler/test/compilable/compile1.d +++ b/compiler/test/compilable/compile1.d @@ -623,6 +623,11 @@ static assert (__traits(compiles, false && error) == false); int f11042a3()() if (__traits(compiles, true || error) == false) { return 0; } enum x11042a3 = f11042a3(); int f11042b3()() if (__traits(compiles, false && error) == false) { return 0; } enum x11042b3 = f11042b3(); +// https://issues.dlang.org/show_bug.cgi?id=24699 +enum T24699(bool cond) = cond; +enum b24699a = T24699!(true || error); +enum b24699b = T24699!(false && error); + /***************************************************/ // https://issues.dlang.org/show_bug.cgi?id=11554 diff --git a/compiler/test/compilable/deprecationlimit.d b/compiler/test/compilable/deprecationlimit.d index dcdc9e118ca5..8ee7ab650fbf 100644 --- a/compiler/test/compilable/deprecationlimit.d +++ b/compiler/test/compilable/deprecationlimit.d @@ -18,5 +18,5 @@ void main() f(); f(); f(); - f(); + static assert("1"); // also surpress deprecationSupplemental } diff --git a/compiler/test/compilable/extra-files/vcg-ast.d.cg b/compiler/test/compilable/extra-files/vcg-ast.d.cg index 9f36634bd05b..7cf31cb91264 100644 --- a/compiler/test/compilable/extra-files/vcg-ast.d.cg +++ b/compiler/test/compilable/extra-files/vcg-ast.d.cg @@ -100,6 +100,12 @@ void main() values(); return 0; } +import imports.vcg_ast_import; +template imported() +{ + import imported = imports.vcg_ast_import; +} +alias myImport = vcg_ast_import; R!int { struct _R @@ -126,6 +132,21 @@ mixin _d_cmain!(); } } } +imported!() +{ + import object; + struct O + { + invariant + { + } + invariant + { + __invariant0(); + } + } + +} RTInfo!(C) { enum immutable(void)* RTInfo = null; @@ -150,4 +171,3 @@ RTInfo!(_R) enum immutable(void)* RTInfo = null; } - diff --git a/compiler/test/compilable/import_exp.d b/compiler/test/compilable/import_exp.d index 014d0f65f6f9..d29fc67ed66e 100644 --- a/compiler/test/compilable/import_exp.d +++ b/compiler/test/compilable/import_exp.d @@ -34,3 +34,11 @@ 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/compiler/test/compilable/imports/vcg_ast_import.d b/compiler/test/compilable/imports/vcg_ast_import.d new file mode 100644 index 000000000000..a2064c0d175b --- /dev/null +++ b/compiler/test/compilable/imports/vcg_ast_import.d @@ -0,0 +1,4 @@ +struct O +{ + invariant() {} +} diff --git a/compiler/test/compilable/staticforeach.d b/compiler/test/compilable/staticforeach.d index ce9eb74a1ef0..5b23446f89b8 100644 --- a/compiler/test/compilable/staticforeach.d +++ b/compiler/test/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/compiler/test/compilable/test24337.d b/compiler/test/compilable/test24337.d new file mode 100644 index 000000000000..a31f665f3527 --- /dev/null +++ b/compiler/test/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/compiler/test/compilable/test24760.d b/compiler/test/compilable/test24760.d new file mode 100644 index 000000000000..7c84848a6fe9 --- /dev/null +++ b/compiler/test/compilable/test24760.d @@ -0,0 +1,4 @@ +// https://issues.dlang.org/show_bug.cgi?id=24760 + +long f(int e = 0, uint[] optional...) => optional.length; +long f0() => f(); // compiler segfaults diff --git a/compiler/test/compilable/vcg-ast-arraylength.d b/compiler/test/compilable/vcg-ast-arraylength.d index 8fdd7808f7b8..8c44421c6173 100644 --- a/compiler/test/compilable/vcg-ast-arraylength.d +++ b/compiler/test/compilable/vcg-ast-arraylength.d @@ -23,4 +23,9 @@ void main() static assert(is(typeof(a.length = 0) == size_t)); static assert(is(typeof(a.length = f.length = 0) == size_t)); + + // https://issues.dlang.org/show_bug.cgi?id=24790 + struct S { int[] payload; } + S s; + s.payload.length += 3; } diff --git a/compiler/test/compilable/vcg-ast.d b/compiler/test/compilable/vcg-ast.d index 4a7b8bc33c48..9197441affea 100644 --- a/compiler/test/compilable/vcg-ast.d +++ b/compiler/test/compilable/vcg-ast.d @@ -2,6 +2,7 @@ REQUIRED_ARGS: -vcg-ast -o- PERMUTE_ARGS: OUTPUT_FILES: compilable/vcg-ast.d.cg +EXTRA_FILES: imports/vcg_ast_import.d TEST_OUTPUT_FILE: extra-files/vcg-ast.d.cg */ @@ -63,3 +64,14 @@ void main() { values!wchar_t; } + +// https://issues.dlang.org/show_bug.cgi?id=24764 + +import imports.vcg_ast_import; + +template imported() +{ + import imported = imports.vcg_ast_import; +} + +alias myImport = imported!(); diff --git a/compiler/test/compilable/vcg_ast_compilable.d b/compiler/test/compilable/vcg_ast_compilable.d new file mode 100644 index 000000000000..e84846dfbe18 --- /dev/null +++ b/compiler/test/compilable/vcg_ast_compilable.d @@ -0,0 +1,69 @@ +/* +REQUIRED_ARGS: -vcg-ast -o- +OUTPUT_FILES: compilable/vcg_ast_compilable.d.cg +TEST_OUTPUT: +--- +=== compilable/vcg_ast_compilable.d.cg +import object; +auto binaryFun(E)(E b) +{ + return 'a' == b; +} +void find(Element)(Element needle) if (is(typeof(binaryFun(needle)))) +{ +} +void find()(string needle) +{ +} +void splitter() +{ + find(3); + find(""); +} +binaryFun!int +{ + auto pure nothrow @nogc @safe bool binaryFun(int b) + { + return 97 == b; + } + +} +find!int +{ + pure nothrow @nogc @safe void find(int needle) + { + } + +} +binaryFun!string +{ + auto _error_ binaryFun + { + __error__ + } + +} +find!() +{ + pure nothrow @nogc @safe void find(string needle) + { + } + +} +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=24431 +auto binaryFun(E)(E b) +{ + return 'a' == b; +} + +void find(Element)(Element needle) if (is(typeof(binaryFun(needle)))) { } +void find()(string needle) { } + +void splitter() +{ + find!int(3); + find!()(""); +} diff --git a/compiler/test/runnable/ifti.d b/compiler/test/runnable/ifti.d index 0c94946c8b36..293b8198d7fb 100644 --- a/compiler/test/runnable/ifti.d +++ b/compiler/test/runnable/ifti.d @@ -72,6 +72,20 @@ class Tst(TST, int v = 2) { class Y : Tst!(float) {} +// https://issues.dlang.org/show_bug.cgi?id=24731 +void test24731() +{ + static int solve(size_t N)(ref double[N+1][N]) + { + return N; + } + + double[3][2] m; + assert(solve(m) == 2); + assert(solve!2(m) == 2); +} + + void main() { Tst!(int) t = new Tst!(int); Y u = new Y; @@ -113,4 +127,5 @@ void main() { printf("%g\n", i); } + test24731(); } diff --git a/compiler/test/runnable/test13613.d b/compiler/test/runnable/test13613.d index ea57df4e9159..1382f00a1780 100644 --- a/compiler/test/runnable/test13613.d +++ b/compiler/test/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/compiler/test/runnable/test23650.d b/compiler/test/runnable/test23650.d deleted file mode 100644 index 3ce8f5f0759b..000000000000 --- a/compiler/test/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/compiler/test/runnable/test24599.d b/compiler/test/runnable/test24599.d new file mode 100644 index 000000000000..257773846ebf --- /dev/null +++ b/compiler/test/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() {}