diff --git a/CHANGELOG.md b/CHANGELOG.md index d461fb54c2..343a3e45fa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,7 @@ # LDC master #### Big news -- Frontend, druntime and Phobos are at version [2.111.0+](https://dlang.org/changelog/2.111.0.html). (#4877, #4910) +- Frontend, druntime and Phobos are at version [2.111.0+](https://dlang.org/changelog/2.111.0.html). (#4877, #4910, #4918) - Keep frame pointers by default with `-O` for some targets, notably AArch64 (except Windows), x86_64 (except Windows and glibc Linux), Windows x86, and Android. This fixes druntime backtraces with optimized code (incl. prebuilt druntime/Phobos). (#4889) - The prebuilt (non-musl) Linux packages are now generated on Ubuntu 22.04; the minimum glibc version has accordingly been raised from v2.31 to v2.35. (#4893) - ldc2.conf: Arrays can now be appended to via the `~=` operator. (#4848, #4856) diff --git a/dmd/arraytypes.d b/dmd/arraytypes.d index 2cd446ea5e..bed684b3a4 100644 --- a/dmd/arraytypes.d +++ b/dmd/arraytypes.d @@ -29,6 +29,7 @@ alias Strings = Array!(const(char)*); alias Identifiers = Array!(Identifier); alias TemplateParameters = Array!(TemplateParameter); alias Expressions = Array!(Expression); +alias ArgumentLabels = Array!(ArgumentLabel); alias Statements = Array!(Statement); alias BaseClasses = Array!(BaseClass*); alias ClassDeclarations = Array!(ClassDeclaration); diff --git a/dmd/arraytypes.h b/dmd/arraytypes.h index 28165f3ed8..a06144332d 100644 --- a/dmd/arraytypes.h +++ b/dmd/arraytypes.h @@ -17,6 +17,8 @@ typedef Array TemplateParameters; typedef Array Expressions; +typedef Array ArgumentLabels; + typedef Array Statements; typedef Array BaseClasses; diff --git a/dmd/cparse.d b/dmd/cparse.d index 7b27eff957..100cf6bf65 100644 --- a/dmd/cparse.d +++ b/dmd/cparse.d @@ -1870,7 +1870,7 @@ final class CParser(AST) : Parser!AST { Identifier id; AST.StringExp asmName; - auto dt = cparseDeclarator(DTR.xdirect, tspec, id, specifier); + auto dt = cparseDeclarator(DTR.xdirect_fd, tspec, id, specifier); if (!dt) { panic(); @@ -2842,6 +2842,18 @@ final class CParser(AST) : Parser!AST //printf("cparseDeclarator(%d, %s)\n", declarator, tbase.toChars()); AST.Types constTypes; // all the Types that will need `const` applied to them + // this.symbols can get changed to the symbol table for the + // parameter-type-list if we parse a function type. + // Callers are only ready to handle this if they pass DTR.xdirect_fd, + // so remember to restore this.symbols. + bool restore_symbols = true; + if (declarator == DTR.xdirect_fd) + { + declarator = DTR.xdirect; + restore_symbols = false; + } + + /* Insert tx -> t into * ts -> ... -> t * so that @@ -3033,7 +3045,7 @@ final class CParser(AST) : Parser!AST //tf = tf.addSTC(storageClass); // TODO insertTx(ts, tf, t); // ts -> ... -> tf -> t - if (ts != tf) + if (ts != tf || restore_symbols) this.symbols = symbolsSave; break; } @@ -5107,6 +5119,7 @@ final class CParser(AST) : Parser!AST /// Types of declarator to parse enum DTR { + xdirect_fd = 0, /// C11 6.7.6 direct-declarator, allow to start function definition xdirect = 1, /// C11 6.7.6 direct-declarator xabstract = 2, /// C11 6.7.7 abstract-declarator xparameter = 3, /// parameter declarator may be either direct or abstract diff --git a/dmd/cxxfrontend.d b/dmd/cxxfrontend.d index 05f2d21e29..59fc6ba0e7 100644 --- a/dmd/cxxfrontend.d +++ b/dmd/cxxfrontend.d @@ -257,7 +257,7 @@ Expression getDefaultValue(EnumDeclaration ed, Loc loc) /*********************************************************** * expression.d */ -void expandTuples(Expressions* exps, Identifiers* names = null) +void expandTuples(Expressions* exps, ArgumentLabels* names = null) { return dmd.expression.expandTuples(exps, names); } @@ -306,7 +306,7 @@ bool functionSemantic3(FuncDeclaration fd) return dmd.funcsem.functionSemantic3(fd); } -MATCH leastAsSpecialized(FuncDeclaration fd, FuncDeclaration g, Identifiers* names) +MATCH leastAsSpecialized(FuncDeclaration fd, FuncDeclaration g, ArgumentLabels* names) { import dmd.funcsem; return dmd.funcsem.leastAsSpecialized(fd, g, names); diff --git a/dmd/declaration.h b/dmd/declaration.h index 2f91fb6b50..e336dff302 100644 --- a/dmd/declaration.h +++ b/dmd/declaration.h @@ -35,7 +35,7 @@ namespace dmd bool functionSemantic(FuncDeclaration* fd); bool functionSemantic3(FuncDeclaration* fd); bool checkClosure(FuncDeclaration* fd); - MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, Identifiers *names); + MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, ArgumentLabels *names); PURE isPure(FuncDeclaration *f); FuncDeclaration *genCfunc(Parameters *args, Type *treturn, const char *name, StorageClass stc=0); FuncDeclaration *genCfunc(Parameters *args, Type *treturn, Identifier *id, StorageClass stc=0); diff --git a/dmd/dtemplate.d b/dmd/dtemplate.d index bc6ecfd7be..4de1914675 100644 --- a/dmd/dtemplate.d +++ b/dmd/dtemplate.d @@ -3677,11 +3677,11 @@ extern (C++) class TemplateInstance : ScopeDsymbol ScopeDsymbol argsym; // argument symbol table size_t hash; // cached result of toHash() - /// For function template, these are the function names and arguments + /// For function template, these are the function fnames(name and loc of it) and arguments /// Relevant because different resolutions of `auto ref` parameters /// create different template instances even with the same template arguments Expressions* fargs; - Identifiers* fnames; + ArgumentLabels* fnames; TemplateInstances* deferred; diff --git a/dmd/enumsem.d b/dmd/enumsem.d index 4f0d4e5f53..566a0637a1 100644 --- a/dmd/enumsem.d +++ b/dmd/enumsem.d @@ -158,9 +158,10 @@ void enumSemantic(Scope* sc, EnumDeclaration ed) ed.semanticRun = PASS.initial; return; } - else - // Ensure that semantic is run to detect. e.g. invalid forward references - sym.dsymbolSemantic(sc); + // Ensure that semantic is run to detect. e.g. invalid forward references + sym.dsymbolSemantic(sc); + if (ed.errors) + ed.memtype = Type.terror; // avoid infinite recursion in toBaseType } if (ed.memtype.ty == Tvoid) { @@ -175,6 +176,8 @@ void enumSemantic(Scope* sc, EnumDeclaration ed) ed.semanticRun = PASS.semanticdone; return; } + if (global.params.useTypeInfo && Type.dtypeinfo && !ed.inNonRoot()) + semanticTypeInfo(sc, ed.memtype); } if (!ed.members) // enum ident : memtype; @@ -341,6 +344,9 @@ void enumSemantic(Scope* sc, EnumDeclaration ed) if (EnumMember em = s.isEnumMember()) em.dsymbolSemantic(em._scope); }); + + if (global.params.useTypeInfo && Type.dtypeinfo && !ed.inNonRoot()) + semanticTypeInfo(sc, ed.memtype); //printf("ed.defaultval = %lld\n", ed.defaultval); //if (ed.defaultval) printf("ed.defaultval: %s %s\n", ed.defaultval.toChars(), ed.defaultval.type.toChars()); diff --git a/dmd/expression.d b/dmd/expression.d index 6edca1cb22..b457f7d503 100644 --- a/dmd/expression.d +++ b/dmd/expression.d @@ -86,7 +86,7 @@ inout(Expression) lastComma(inout Expression e) * exps = array of Expressions * names = optional array of names corresponding to Expressions */ -void expandTuples(Expressions* exps, Identifiers* names = null) +void expandTuples(Expressions* exps, ArgumentLabels* names = null) { //printf("expandTuples()\n"); if (exps is null) @@ -116,7 +116,7 @@ void expandTuples(Expressions* exps, Identifiers* names = null) } foreach (i; 1 .. length) { - names.insert(index + i, cast(Identifier) null); + names.insert(index + i, ArgumentLabel(cast(Identifier) null, Loc.init)); } } } @@ -2469,7 +2469,7 @@ extern (C++) final class NewExp : Expression Expression thisexp; // if !=null, 'this' for class being allocated Type newtype; Expressions* arguments; // Array of Expression's - Identifiers* names; // Array of names corresponding to expressions + ArgumentLabels* names; // Array of names(name and location of name) corresponding to expressions Expression placement; // if !=null, then PlacementExpression Expression argprefix; // expression to be evaluated just before arguments[] @@ -2481,9 +2481,10 @@ extern (C++) final class NewExp : Expression /// Puts the `arguments` and `names` into an `ArgumentList` for easily passing them around. /// The fields are still separate for backwards compatibility + extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); } - extern (D) this(Loc loc, Expression placement, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null) @safe + extern (D) this(Loc loc, Expression placement, Expression thisexp, Type newtype, Expressions* arguments, ArgumentLabels* names = null) @safe { super(loc, EXP.new_); this.placement = placement; @@ -3304,29 +3305,36 @@ extern (C++) final class DotTypeExp : UnaExp struct ArgumentList { Expressions* arguments; // function arguments - Identifiers* names; // named argument identifiers + ArgumentLabels* names; // named argument labels size_t length() const @nogc nothrow pure @safe { return arguments ? arguments.length : 0; } /// Returns: whether this argument list contains any named arguments - bool hasNames() const @nogc nothrow pure @safe + bool hasArgNames() const @nogc nothrow pure @safe { if (names is null) return false; - foreach (name; *names) - if (name !is null) + foreach (argLabel; *names) + if (argLabel.name !is null) return true; return false; } } +// Contains both `name` and `location of the name` for an expression. +struct ArgumentLabel +{ + Identifier name; // name of the argument + Loc loc; // location of the name + } + /*********************************************************** */ extern (C++) final class CallExp : UnaExp { Expressions* arguments; // function arguments - Identifiers* names; // named argument identifiers + ArgumentLabels *names; // named argument labels FuncDeclaration f; // symbol to call bool directcall; // true if a virtual call is devirtualized bool inDebugStatement; /// true if this was in a debug statement @@ -3338,7 +3346,7 @@ extern (C++) final class CallExp : UnaExp /// The fields are still separate for backwards compatibility extern (D) ArgumentList argumentList() { return ArgumentList(arguments, names); } - extern (D) this(Loc loc, Expression e, Expressions* exps, Identifiers* names = null) @safe + extern (D) this(Loc loc, Expression e, Expressions* exps, ArgumentLabels *names = null) @safe { super(loc, EXP.call, e); this.arguments = exps; diff --git a/dmd/expression.h b/dmd/expression.h index 5f637b4c2e..336da1db32 100644 --- a/dmd/expression.h +++ b/dmd/expression.h @@ -60,7 +60,7 @@ namespace dmd // Entry point for CTFE. // A compile-time result is required. Give an error if not possible Expression *ctfeInterpret(Expression *e); - void expandTuples(Expressions *exps, Identifiers *names = nullptr); + void expandTuples(Expressions *exps, ArgumentLabels *names = nullptr); Expression *optimize(Expression *exp, int result, bool keepLvalue = false); } @@ -540,7 +540,7 @@ class NewExp final : public Expression Expression *thisexp; // if !NULL, 'this' for class being allocated Type *newtype; Expressions *arguments; // Array of Expression's - Identifiers *names; // Array of names corresponding to expressions + ArgumentLabels *names; // Array of argument Labels (name and location of name) corresponding to expressions Expression *placement; // if !NULL, placement expression Expression *argprefix; // expression to be evaluated just before arguments[] @@ -817,23 +817,38 @@ class DotTypeExp final : public UnaExp struct ArgumentList final { Expressions* arguments; - Identifiers* names; + ArgumentLabels* names; ArgumentList() : arguments(), names() { } - ArgumentList(Expressions* arguments, Identifiers* names = nullptr) : + ArgumentList(Expressions* arguments, ArgumentLabels* names = nullptr) : arguments(arguments), names(names) {} }; +struct ArgumentLabel final +{ + Identifier* name; + Loc loc; + ArgumentLabel() : + name(), + loc() + { + } + ArgumentLabel(Identifier* name, Loc loc = Loc()) : + name(name), + loc(loc) + {} +}; + class CallExp final : public UnaExp { public: Expressions *arguments; // function arguments - Identifiers *names; + ArgumentLabels* names; // function argument Labels (name + location of name) FuncDeclaration *f; // symbol to call d_bool directcall; // true if a virtual call is devirtualized d_bool inDebugStatement; // true if this was in a debug statement diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index d3dc481510..239167a0c3 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -1334,8 +1334,8 @@ private Expression resolveUFCS(Scope* sc, CallExp ce) ce.arguments = new Expressions(); ce.arguments.shift(eleft); if (!ce.names) - ce.names = new Identifiers(); - ce.names.shift(null); + ce.names = new ArgumentLabels(); + ce.names.shift(ArgumentLabel(cast(Identifier) null, Loc.init)); ce.isUfcsRewrite = true; return null; } @@ -4556,7 +4556,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars()); } - + if (e.type) + { + // already done, but we might have missed generating type info + semanticTypeInfo(sc, e.type); + result = e; + return; + } // Run semantic() on each element bool err_keys = arrayExpressionSemantic(e.keys.peekSlice(), sc); bool err_vals = arrayExpressionSemantic(e.values.peekSlice(), sc); @@ -5300,10 +5306,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { if (exp.names) { - exp.arguments = resolveStructLiteralNamedArgs(sd, exp.type, sc, exp.loc, - exp.names ? (*exp.names)[] : null, + exp.arguments = resolveStructLiteralNamedArgs(sd, exp.type, sc, exp.loc, exp.names.length, + i => (*exp.names)[i].name, (size_t i, Type t) => (*exp.arguments)[i], - i => (*exp.arguments)[i].loc + i => (*exp.arguments)[i].loc, + i => (*exp.names)[i].loc ); if (!exp.arguments) return setError(); @@ -5367,9 +5374,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } Expression arg = (*exp.arguments)[i]; - if (exp.names && (*exp.names)[i]) + if (exp.names && (*exp.names)[i].name) { - error(exp.loc, "no named argument `%s` allowed for array dimension", (*exp.names)[i].toChars()); + error(exp.loc, "no named argument `%s` allowed for array dimension", (*exp.names)[i].name.toChars()); return setError(); } @@ -5483,9 +5490,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else if (nargs == 1) { - if (exp.names && (*exp.names)[0]) + if (exp.names && (*exp.names)[0].name) { - error(exp.loc, "no named argument `%s` allowed for scalar", (*exp.names)[0].toChars()); + error(exp.loc, "no named argument `%s` allowed for scalar", (*exp.names)[0].name.toChars()); return setError(); } Expression e = (*exp.arguments)[0]; @@ -5665,6 +5672,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor s = "__funcliteral"; DsymbolTable symtab; + string parentMangle; if (FuncDeclaration func = sc.parent.isFuncDeclaration()) { if (func.localsymtab is null) @@ -5674,6 +5682,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor func.localsymtab = new DsymbolTable(); } symtab = func.localsymtab; + parentMangle = cast(string) mangleExact(func).toDString(); } else { @@ -5686,9 +5695,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor sds.symtab = new DsymbolTable(); } symtab = sds.symtab; + + OutBuffer buf; + mangleToBuffer(sds, buf); + parentMangle = buf.extractSlice(); } assert(symtab); - Identifier id = Identifier.generateIdWithLoc(s, exp.loc, cast(string) toDString(sc.parent.toPrettyChars())); + Identifier id = Identifier.generateIdWithLoc(s, exp.loc, parentMangle); exp.fd.ident = id; if (exp.td) exp.td.ident = id; @@ -6275,10 +6288,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Expressions* resolvedArgs = exp.arguments; if (exp.names) { - resolvedArgs = resolveStructLiteralNamedArgs(sd, exp.e1.type, sc, exp.loc, - (*exp.names)[], + resolvedArgs = resolveStructLiteralNamedArgs(sd, exp.e1.type, sc, exp.loc, exp.names.length, + i => (*exp.names)[i].name, (size_t i, Type t) => (*exp.arguments)[i], - i => (*exp.arguments)[i].loc + i => (*exp.arguments)[i].loc, + i => (*exp.names)[i].loc ); if (!resolvedArgs) { @@ -13890,6 +13904,7 @@ private bool expressionSemanticDone(Expression e) || e.isTypeExp() // stores its type in the Expression.type field || e.isCompoundLiteralExp() // stores its `(type) {}` in type field, gets rewritten to struct literal || e.isVarExp() // type sometimes gets set already before semantic + || (e.isAssocArrayLiteralExp() && !e.type.vtinfo) // semanticTypeInfo not run during initialization ); } diff --git a/dmd/frontend.h b/dmd/frontend.h index 910dd0d037..b41539e130 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -1485,6 +1485,23 @@ struct MangleOverride final typedef Array AliasDeclarations; +struct ArgumentLabel final +{ + Identifier* name; + Loc loc; + ArgumentLabel() : + name(), + loc() + { + } + ArgumentLabel(Identifier* name, Loc loc = Loc()) : + name(name), + loc(loc) + {} +}; + +typedef Array ArgumentLabels; + typedef Array BaseClasses; typedef Array CaseStatements; @@ -1778,7 +1795,7 @@ class TemplateInstance : public ScopeDsymbol ScopeDsymbol* argsym; size_t hash; Array* fargs; - Array* fnames; + Array* fnames; Array* deferred; Module* memberOf; TemplateInstance* tinst; @@ -2585,13 +2602,13 @@ class AndExp final : public BinExp struct ArgumentList final { Array* arguments; - Array* names; + Array* names; ArgumentList() : arguments(), names() { } - ArgumentList(Array* arguments, Array* names = nullptr) : + ArgumentList(Array* arguments, Array* names = nullptr) : arguments(arguments), names(names) {} @@ -2688,7 +2705,7 @@ class CallExp final : public UnaExp { public: Array* arguments; - Array* names; + Array* names; FuncDeclaration* f; bool directcall; bool inDebugStatement; @@ -3401,7 +3418,7 @@ class NewExp final : public Expression Expression* thisexp; Type* newtype; Array* arguments; - Array* names; + Array* names; Expression* placement; Expression* argprefix; CtorDeclaration* member; @@ -5586,6 +5603,7 @@ struct ASTCodegen final using MangleOverride = ::MangleOverride; using AliasThis = ::AliasThis; using AliasDeclarations = ::AliasDeclarations; + using ArgumentLabels = ::ArgumentLabels; using BaseClasses = ::BaseClasses; using CaseStatements = ::CaseStatements; using Catches = ::Catches; @@ -5716,6 +5734,7 @@ struct ASTCodegen final using AddrExp = ::AddrExp; using AndAssignExp = ::AndAssignExp; using AndExp = ::AndExp; + using ArgumentLabel = ::ArgumentLabel; using ArgumentList = ::ArgumentList; using ArrayExp = ::ArrayExp; using ArrayLengthExp = ::ArrayLengthExp; diff --git a/dmd/funcsem.d b/dmd/funcsem.d index b3cb79b74e..d51cfcbdd1 100644 --- a/dmd/funcsem.d +++ b/dmd/funcsem.d @@ -2057,16 +2057,17 @@ int overrides(FuncDeclaration fd1, FuncDeclaration fd2) * Params: * f = first function * g = second function - * names = names of parameters + * names = argument Labels of parameters(name and location of the name) * 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) +MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, ArgumentLabels* names) { enum LOG_LEASTAS = 0; static if (LOG_LEASTAS) { + Identifiers *names = extractNames(names); 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()); diff --git a/dmd/hdrgen.d b/dmd/hdrgen.d index bb9632ba87..faedec478a 100644 --- a/dmd/hdrgen.d +++ b/dmd/hdrgen.d @@ -3701,9 +3701,9 @@ private void parameterToBuffer(Parameter p, ref OutBuffer buf, ref HdrGenState h * buf = buffer to write to * hgs = context * basis = replace `null`s in argument list with this expression (for sparse array literals) - * names = if non-null, use these as the names for the arguments + * names = if non-null, use these as the argument Labels for the arguments */ -private void argsToBuffer(Expressions* expressions, ref OutBuffer buf, ref HdrGenState hgs, Expression basis = null, Identifiers* names = null) +private void argsToBuffer(Expressions* expressions, ref OutBuffer buf, ref HdrGenState hgs, Expression basis = null, ArgumentLabels* names = null) { if (!expressions || !expressions.length) return; @@ -3714,9 +3714,9 @@ private void argsToBuffer(Expressions* expressions, ref OutBuffer buf, ref HdrGe if (i) buf.writestring(", "); - if (names && i < names.length && (*names)[i]) + if (names && i < names.length && (*names)[i].name) { - buf.writestring((*names)[i].toString()); + buf.writestring((*names)[i].name.toString()); buf.writestring(": "); } if (!el) diff --git a/dmd/identifier.d b/dmd/identifier.d index c213597eb0..6c021d72e4 100644 --- a/dmd/identifier.d +++ b/dmd/identifier.d @@ -221,7 +221,7 @@ nothrow: * Identifier (inside Identifier.idPool) with deterministic name based * on the source location. */ - extern (D) static Identifier generateIdWithLoc(string prefix, Loc loc, string parent = "") + extern (D) static Identifier generateIdWithLoc(string prefix, Loc loc, string parent = null) { // generate `_L_C` auto sl = SourceLoc(loc); @@ -251,11 +251,12 @@ nothrow: static struct Key { string locKey; string prefix; string parent; } __gshared uint[Key] counters; - string locKey = cast(string) (sl.filename ~ idBuf[]); + const locKey = cast(string) (sl.filename ~ idBuf[]); + const key = Key(locKey, prefix, parent); static if (__traits(compiles, counters.update(Key.init, () => 0u, (ref uint a) => 0u))) { // 2.082+ - counters.update(Key(locKey, prefix, parent), + counters.update(key, () => 1u, // insertion (ref uint counter) // update { @@ -267,7 +268,6 @@ nothrow: } else { - const key = Key(locKey, prefix, parent); if (auto pCounter = key in counters) { idBuf.writestring("_"); diff --git a/dmd/initsem.d b/dmd/initsem.d index 1ebccf77ee..94aff2ac5e 100644 --- a/dmd/initsem.d +++ b/dmd/initsem.d @@ -171,7 +171,8 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn return ex; } - auto elements = resolveStructLiteralNamedArgs(sd, t, sc, i.loc, i.field[], &getExp, (size_t j) => i.value[j].loc); + auto elements = resolveStructLiteralNamedArgs(sd, t, sc, i.loc, i.field.length, (size_t j) => i.field[j], &getExp, (size_t j) => i.value[j].loc, (size_t j) => i.value[j].loc); + //Keeping both the getArgLoc and getNameLoc same as i.field doesn't have a .loc value here. if (!elements) return err(); @@ -240,6 +241,9 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn goto default; break; + case Terror: + return err(); + default: error(i.loc, "cannot use array to initialize `%s`", t.toChars()); return err(); @@ -1505,15 +1509,18 @@ Params: t = type of struct (potentially including qualifiers such as `const` or `immutable`) sc = scope of the expression initializing the struct iloc = location of expression initializing the struct - names = identifiers passed in argument list, `null` entries for positional arguments - getExp = function that, given an index into `names` and destination type, returns the initializing expression - getLoc = function that, given an index into `names`, returns a location for error messages + argCount = count of argumnet present + getExp = function that, given an index into `argNames` and destination type, returns the initializing expression + getArgName = function that, given an index into `argNames`, returns the name of argument for error messages + getArgLoc = function that, given an index into `argNames`, returns a location of argument for error messages + getNameLoc = function that, given an index into `argNames`, returns a location of that `name` for error messages Returns: list of expressions ordered to the struct's fields, or `null` on error */ Expressions* resolveStructLiteralNamedArgs(StructDeclaration sd, Type t, Scope* sc, - Loc iloc, Identifier[] names, scope Expression delegate(size_t i, Type fieldType) getExp, - scope Loc delegate(size_t i) getLoc + Loc iloc, size_t argCount, scope Identifier delegate(size_t i) getArgName, scope Expression delegate(size_t i, Type fieldType) getExp, + scope Loc delegate(size_t i) getArgLoc, + scope Loc delegate(size_t i) getNameLoc ) { //expandTuples for non-identity arguments? @@ -1527,9 +1534,11 @@ Expressions* resolveStructLiteralNamedArgs(StructDeclaration sd, Type t, Scope* // TODO: this part is slightly different from StructLiteralExp::semantic. bool errors = false; size_t fieldi = 0; - foreach (j, id; names) + foreach (j; 0 .. argCount) { - const argLoc = getLoc(j); + const argLoc = getArgLoc(j); + const nameLoc = getNameLoc(j); + Identifier id = getArgName(j); if (id) { // Determine `fieldi` that `id` matches @@ -1538,9 +1547,9 @@ Expressions* resolveStructLiteralNamedArgs(StructDeclaration sd, Type t, Scope* { s = sd.search_correct(id); if (s) - error(argLoc, "`%s` is not a member of `%s`, did you mean %s `%s`?", id.toChars(), sd.toChars(), s.kind(), s.toChars()); + error(nameLoc, "`%s` is not a member of `%s`, did you mean %s `%s`?", id.toChars(), sd.toChars(), s.kind(), s.toChars()); else - error(argLoc, "`%s` is not a member of `%s`", id.toChars(), sd.toChars()); + error(nameLoc, "`%s` is not a member of `%s`", id.toChars(), sd.toChars()); return null; } s.checkDeprecated(iloc, sc); diff --git a/dmd/mtype.d b/dmd/mtype.d index fed8ebdaf3..e1d11484a5 100644 --- a/dmd/mtype.d +++ b/dmd/mtype.d @@ -2635,7 +2635,7 @@ extern (C++) final class TypeFunction : TypeNext extern(D) Expressions* resolveNamedArgs(ArgumentList argumentList, OutBuffer* buf) { Expression[] args = argumentList.arguments ? (*argumentList.arguments)[] : null; - Identifier[] names = argumentList.names ? (*argumentList.names)[] : null; + ArgumentLabel[] names = argumentList.names ? (*argumentList.names)[] : null; const nParams = parameterList.length(); // cached because O(n) auto newArgs = new Expressions(nParams); newArgs.zero(); @@ -2649,7 +2649,7 @@ extern (C++) final class TypeFunction : TypeNext ci++; continue; } - auto name = i < names.length ? names[i] : null; + auto name = i < names.length ? names[i].name : null; if (name) { hasNamedArgs = true; diff --git a/dmd/parse.d b/dmd/parse.d index e68017c87e..f7ac4b564e 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -28,6 +28,7 @@ import dmd.root.rmem; import dmd.rootobject; import dmd.root.string; import dmd.tokens; +import dmd.expression; alias CompileEnv = dmd.lexer.CompileEnv; @@ -1324,7 +1325,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { const loc = token.loc; AST.Expressions* args = new AST.Expressions(); - AST.Identifiers* names = new AST.Identifiers(); + AST.ArgumentLabels* names = new AST.ArgumentLabels(); parseNamedArguments(args, names); exp = new AST.CallExp(loc, exp, args, names); } @@ -9006,7 +9007,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer case TOK.leftParenthesis: AST.Expressions* args = new AST.Expressions(); - AST.Identifiers* names = new AST.Identifiers(); + AST.ArgumentLabels* names = new AST.ArgumentLabels(); parseNamedArguments(args, names); e = new AST.CallExp(loc, e, args, names); continue; @@ -9452,7 +9453,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer * Collect argument list. * Assume current token is ',', '$(LPAREN)' or '['. */ - private void parseNamedArguments(AST.Expressions* arguments, AST.Identifiers* names) + private void parseNamedArguments(AST.Expressions* arguments, AST.ArgumentLabels* names) { assert(arguments); @@ -9470,14 +9471,14 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer check(TOK.identifier); check(TOK.colon); if (names) - names.push(ident); + names.push(ArgumentLabel(ident, loc)); else error(loc, "named arguments not allowed here"); } else { if (names) - names.push(null); + names.push(ArgumentLabel(null, Loc.init)); } auto arg = parseAssignExp(); @@ -9518,7 +9519,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } AST.Expressions* arguments = null; - AST.Identifiers* names = null; + AST.ArgumentLabels* names = null; // An anonymous nested class starts with "class" if (token.value == TOK.class_) @@ -9527,7 +9528,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.leftParenthesis) { arguments = new AST.Expressions(); - names = new AST.Identifiers(); + names = new AST.ArgumentLabels(); parseNamedArguments(arguments, names); } @@ -9572,7 +9573,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer else if (token.value == TOK.leftParenthesis && t.ty != Tsarray) { arguments = new AST.Expressions(); - names = new AST.Identifiers(); + names = new AST.ArgumentLabels(); parseNamedArguments(arguments, names); } diff --git a/dmd/templatesem.d b/dmd/templatesem.d index 1e71cd5e8b..ac38b3d2ae 100644 --- a/dmd/templatesem.d +++ b/dmd/templatesem.d @@ -950,7 +950,7 @@ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat size_t nfargs2 = argumentList.length; // total number of arguments including applied defaultArgs uint inoutMatch = 0; // for debugging only Expression[] fargs = argumentList.arguments ? (*argumentList.arguments)[] : null; - Identifier[] fnames = argumentList.names ? (*argumentList.names)[] : null; + ArgumentLabel[] fnames = argumentList.names ? (*argumentList.names)[] : null; for (size_t parami = 0; parami < nfparams; parami++) { @@ -960,16 +960,17 @@ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat Type prmtype = fparam.type.addStorageClass(fparam.storageClass); Expression farg; - Identifier fname = argi < fnames.length ? fnames[argi] : null; + Identifier fname = argi < fnames.length ? fnames[argi].name : null; bool foundName = false; if (fparam.ident) { foreach (i; 0 .. fnames.length) { - if (fparam.ident == fnames[i]) + if (fparam.ident == fnames[i].name) { argi = i; foundName = true; + break; //Exits the loop after a match } } } @@ -1004,9 +1005,9 @@ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat { break; } - foreach(name; fnames) + foreach(argLabel; fnames) { - if (p.ident == name) + if (p.ident == argLabel.name) break; } if (!reliesOnTemplateParameters(p.type, (*td.parameters)[inferStart .. td.parameters.length])) diff --git a/dmd/typesem.d b/dmd/typesem.d index d4c7a5865d..217a442aac 100644 --- a/dmd/typesem.d +++ b/dmd/typesem.d @@ -3288,6 +3288,11 @@ Type merge(Type type) return type; goto default; + case Tfunction: + if (!type.nextOf()) + return type; + goto default; + default: if (type.nextOf() && !type.nextOf().deco) return type; diff --git a/gen/arrays.cpp b/gen/arrays.cpp index bf701c696b..36aa43e0f0 100644 --- a/gen/arrays.cpp +++ b/gen/arrays.cpp @@ -308,8 +308,8 @@ static void DtoSetArray(DValue *array, DValue *rhs) { LLConstant *DtoConstArrayInitializer(ArrayInitializer *arrinit, Type *targetType, const bool isCfile) { - IF_LOG Logger::println("DtoConstArrayInitializer: %s | %s", - arrinit->toChars(), targetType->toChars()); + IF_LOG Logger::println("DtoConstArrayInitializer | %s", + targetType->toChars()); LOG_SCOPE; assert(arrinit->value.length == arrinit->index.length); diff --git a/runtime/phobos b/runtime/phobos index 39f1725829..983294523d 160000 --- a/runtime/phobos +++ b/runtime/phobos @@ -1 +1 @@ -Subproject commit 39f17258290770b97ef332d1707ce3739e8104cf +Subproject commit 983294523d02c9b48130902c805bce7af085de70 diff --git a/tests/dmd/compilable/test21244.c b/tests/dmd/compilable/test21244.c new file mode 100644 index 0000000000..b3564a756c --- /dev/null +++ b/tests/dmd/compilable/test21244.c @@ -0,0 +1,2 @@ +// https://github.com/dlang/dmd/issues/21244 +int z = _Generic(1, int()(int): 3, int: 3); diff --git a/tests/dmd/compilable/test21246.c b/tests/dmd/compilable/test21246.c new file mode 100644 index 0000000000..944b547546 --- /dev/null +++ b/tests/dmd/compilable/test21246.c @@ -0,0 +1,4 @@ +// https://github.com/dlang/dmd/issues/21246 +#define M1(x) _Generic(x, ( +#define M2(a,b) _Generic(val, int(int) a +#define M3(str,val) _Generic(val, M(F) struct{int foo;}: 0)(__FILE__, __func__, __LINE__, str, val) diff --git a/tests/dmd/fail_compilation/test21215.d b/tests/dmd/fail_compilation/test21215.d new file mode 100644 index 0000000000..5efa315723 --- /dev/null +++ b/tests/dmd/fail_compilation/test21215.d @@ -0,0 +1,35 @@ +/* TEST_OUTPUT: +--- +fail_compilation/test21215.d(13): Error: `y` is not a member of `S` +fail_compilation/test21215.d(18): Error: `xhs` is not a member of `S`, did you mean variable `xsh`? +fail_compilation/test21215.d(28): Error: `y` is not a member of `S` +fail_compilation/test21215.d(32): Error: `yashu` is not a member of `S` +--- +*/ +struct S { int xsh; } + +void test() { + auto s1 = S( + y: + 1 + ); + + auto s2 = S( + xhs: + 1 + ); + + auto s3 = S( + xsh: 1 + ); + + auto s4 = S( + xsh: 1, + y: 2 + ); + + auto s5 = S( + yashu: + 2 + ); +} diff --git a/tests/dmd/fail_compilation/test21244.c b/tests/dmd/fail_compilation/test21244.c new file mode 100644 index 0000000000..d57a46f879 --- /dev/null +++ b/tests/dmd/fail_compilation/test21244.c @@ -0,0 +1,9 @@ +// https://github.com/dlang/dmd/issues/21244 +// This used to segfault the compiler. The below error message can change. +/* +* TEST_OUTPUT: +--- +fail_compilation/test21244.c(9): Error: no size for type `extern (C) int(int)` +--- + */ +int x = sizeof(int()(int)); diff --git a/tests/dmd/fail_compilation/test21304.d b/tests/dmd/fail_compilation/test21304.d new file mode 100644 index 0000000000..9789e2b9c9 --- /dev/null +++ b/tests/dmd/fail_compilation/test21304.d @@ -0,0 +1,6 @@ +/* TEST_OUTPUT: +--- +fail_compilation/test21304.d(6): Error: undefined identifier `unknown` +--- +*/ +int[unknown] values = [1, 2, 3]; diff --git a/tests/dmd/runnable/testaa2.d b/tests/dmd/runnable/testaa2.d index e1abcb4418..3d199d9841 100644 --- a/tests/dmd/runnable/testaa2.d +++ b/tests/dmd/runnable/testaa2.d @@ -307,6 +307,26 @@ void testinenum() assert("one" in aa); } +// https://github.com/dlang/dmd/issues/21258 +void test21258() +{ + alias AliasSeq(TList...) = TList; + + struct S { int x; } // use a local type to not generate required TypeInfo elsewhere + foreach (T; AliasSeq!(S[int])) + enum E { a = T.init, } // bug report uses bad syntax here, but this crashed, too +} + +// https://github.com/dlang/dmd/issues/21207 +void test21207() +{ + struct S { int x; } // use a local type to not generate required TypeInfo elsewhere + enum aa = ["baz": S(7)]; + + void foo(S[string] x = aa) { } + foo(); +} + /************************************************/ int main() @@ -318,6 +338,7 @@ int main() test3825x(); testinout(); testinenum(); + test21258(); printf("Success\n"); return 0;