diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index c2e66d0a29c..1ede1951c39 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -62,11 +62,11 @@ jobs: os: windows-2022 arch: x86 bootstrap_cmake_flags: -DBUILD_LTO_LIBS=ON - # Undefined symbol errors with FullLTO; ThinLTO works. extra_cmake_flags: >- -DBUILD_LTO_LIBS=ON - "-DD_COMPILER_FLAGS=-O -flto=thin -defaultlib=phobos2-ldc-lto,druntime-ldc-lto" - -DEXTRA_CXXFLAGS=-flto=thin + # Undefined symbol errors with FullLTO; ThinLTO used to work, but apparently miscompiles a lexer.d:130 assertion since v1.33. + # "-DD_COMPILER_FLAGS=-O -flto=thin -defaultlib=phobos2-ldc-lto,druntime-ldc-lto" + # -DEXTRA_CXXFLAGS=-flto=thin with_pgo: true name: ${{ matrix.job_name }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c725ff70f9..1d2896019c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # LDC master #### Big news +- Frontend, druntime and Phobos are at version [2.103.1](https://dlang.org/changelog/2.103.0.html), incl. new command-line option `-verror-supplements`. (#4345) #### Platform support diff --git a/CMakeLists.txt b/CMakeLists.txt index 64eca1722c1..e0ebfd8d9c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,10 +111,10 @@ include(GetLinuxDistribution) # # Version information -set(LDC_VERSION "1.32.0") # May be overridden by git hash tag +set(LDC_VERSION "1.33.0") # May be overridden by git hash tag set(DMDFE_MAJOR_VERSION 2) -set(DMDFE_MINOR_VERSION 102) -set(DMDFE_PATCH_VERSION 2) +set(DMDFE_MINOR_VERSION 103) +set(DMDFE_PATCH_VERSION 1) set(DMD_VERSION ${DMDFE_MAJOR_VERSION}.${DMDFE_MINOR_VERSION}.${DMDFE_PATCH_VERSION}) diff --git a/dmd/README.md b/dmd/README.md index 43eb187c735..cecd008e608 100644 --- a/dmd/README.md +++ b/dmd/README.md @@ -38,7 +38,8 @@ Note that these groups have no strict meaning, the category assignments are a bi | [dinifile.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dinifile.d) | Parse settings from .ini file (`sc.ini` / `dmd.conf`) | | [vsoptions.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/vsoptions.d) | Detect the Microsoft Visual Studio toolchain for linking | | [frontend.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/frontend.d) | An interface for using DMD as a library | -| [errors.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errors.d) | Error reporting functionality | +| [errors.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errors.d) | Error reporting implementation | +| [errorsink.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errorsink.d) | Error reporting interface | | [target.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/target.d) | Manage target-specific parameters for cross-compiling (for LDC/GDC) | | [compiler.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/compiler.d) | Describe a back-end compiler and implements compiler-specific actions | diff --git a/dmd/aggregate.h b/dmd/aggregate.h index 1c22b717487..ac086679ddb 100644 --- a/dmd/aggregate.h +++ b/dmd/aggregate.h @@ -310,7 +310,6 @@ class ClassDeclaration : public AggregateDeclaration virtual int vtblOffset() const; const char *kind() const override; - void addLocalClass(ClassDeclarations *) override final; void addObjcSymbols(ClassDeclarations *classes, ClassDeclarations *categories) override final; // Back end diff --git a/dmd/apply.d b/dmd/apply.d index f5855c4758a..59ba9f5ecd6 100644 --- a/dmd/apply.d +++ b/dmd/apply.d @@ -75,7 +75,7 @@ private extern (C++) final class PostorderExpressionVisitor : StoppableVisitor public: StoppableVisitor v; - extern (D) this(StoppableVisitor v) + extern (D) this(StoppableVisitor v) scope { this.v = v; } diff --git a/dmd/argtypes_sysv_x64.d b/dmd/argtypes_sysv_x64.d index da8bc8d22cf..835544d2c46 100644 --- a/dmd/argtypes_sysv_x64.d +++ b/dmd/argtypes_sysv_x64.d @@ -156,7 +156,7 @@ extern (C++) final class ToClassesVisitor : Visitor int numEightbytes; Class[4] result = Class.noClass; - this(size_t size) + this(size_t size) scope { assert(size > 0); this.size = size; diff --git a/dmd/arrayop.d b/dmd/arrayop.d index da2f8000fc1..908855e271c 100644 --- a/dmd/arrayop.d +++ b/dmd/arrayop.d @@ -149,7 +149,7 @@ Expression arrayOp(BinExp e, Scope* sc) ObjectNotFound(idArrayOp); // fatal error } - auto fd = resolveFuncCall(e.loc, sc, arrayOp, tiargs, null, args, FuncResolveFlag.standard); + auto fd = resolveFuncCall(e.loc, sc, arrayOp, tiargs, null, ArgumentList(args), FuncResolveFlag.standard); if (!fd || fd.errors) return ErrorExp.get(); return new CallExp(e.loc, new VarExp(e.loc, fd, false), args).expressionSemantic(sc); @@ -194,7 +194,7 @@ private Expressions* buildArrayOp(Scope* sc, Expression e, Objects* tiargs) Expressions* args; public: - extern (D) this(Scope* sc, Objects* tiargs) + extern (D) this(Scope* sc, Objects* tiargs) scope { this.sc = sc; this.tiargs = tiargs; diff --git a/dmd/attrib.d b/dmd/attrib.d index 8993dc3e4da..a73119078ec 100644 --- a/dmd/attrib.d +++ b/dmd/attrib.d @@ -197,17 +197,12 @@ extern (C++) abstract class AttribDeclaration : Dsymbol /**************************************** */ - override final void addLocalClass(ClassDeclarations* aclasses) - { - include(null).foreachDsymbol( s => s.addLocalClass(aclasses) ); - } - override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories) { objc.addSymbols(this, classes, categories); } - override final inout(AttribDeclaration) isAttribDeclaration() inout pure @safe + override inout(AttribDeclaration) isAttribDeclaration() inout pure @safe { return this; } @@ -1101,6 +1096,11 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration return "static if"; } + override inout(StaticIfDeclaration) isStaticIfDeclaration() inout pure @safe + { + return this; + } + override void accept(Visitor v) { v.visit(this); diff --git a/dmd/attrib.h b/dmd/attrib.h index 96c46e8f718..44ceb12e0d0 100644 --- a/dmd/attrib.h +++ b/dmd/attrib.h @@ -36,8 +36,7 @@ class AttribDeclaration : public Dsymbol bool hasPointers() override final; bool hasStaticCtorOrDtor() override final; void checkCtorConstInit() override final; - void addLocalClass(ClassDeclarations *) override final; - AttribDeclaration *isAttribDeclaration() override final { return this; } + AttribDeclaration *isAttribDeclaration() override { return this; } void accept(Visitor *v) override { v->visit(this); } }; @@ -184,6 +183,7 @@ class StaticIfDeclaration final : public ConditionalDeclaration void addMember(Scope *sc, ScopeDsymbol *sds) override; void setScope(Scope *sc) override; void importAll(Scope *sc) override; + StaticIfDeclaration *isStaticIfDeclaration() override { return this; } const char *kind() const override; void accept(Visitor *v) override { v->visit(this); } }; diff --git a/dmd/blockexit.d b/dmd/blockexit.d index 6369b5ab04b..bd5b78e92dc 100644 --- a/dmd/blockexit.d +++ b/dmd/blockexit.d @@ -71,7 +71,7 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow) bool mustNotThrow; int result; - extern (D) this(FuncDeclaration func, bool mustNotThrow) + extern (D) this(FuncDeclaration func, bool mustNotThrow) scope { this.func = func; this.mustNotThrow = mustNotThrow; diff --git a/dmd/canthrow.d b/dmd/canthrow.d index 7c18040eb02..0c237e6da56 100644 --- a/dmd/canthrow.d +++ b/dmd/canthrow.d @@ -63,7 +63,7 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN CT result; public: - extern (D) this(FuncDeclaration func, bool mustNotThrow) + extern (D) this(FuncDeclaration func, bool mustNotThrow) scope { this.func = func; this.mustNotThrow = mustNotThrow; diff --git a/dmd/cli.d b/dmd/cli.d index 757f24e6560..68f92c16c85 100644 --- a/dmd/cli.d +++ b/dmd/cli.d @@ -774,6 +774,9 @@ dmd -cov -unittest myprog.d $(DT gnu)$(DD 'file:line[:column]: message', conforming to the GNU standard used by gcc and clang.) )`, ), + Option("verror-supplements=", + "limit the number of supplemental messages for each error (0 means unlimited)" + ), Option("verrors=", "limit the number of error messages (0 means unlimited)" ), @@ -855,7 +858,7 @@ dmd -cov -unittest myprog.d /// Returns all available reverts static immutable reverts = [ - Feature("dip25", "useDIP25", "revert DIP25 changes https://github.com/dlang/DIPs/blob/master/DIPs/archive/DIP25.md"), + Feature("dip25", "useDIP25", "revert DIP25 changes https://github.com/dlang/DIPs/blob/master/DIPs/archive/DIP25.md", true, true), Feature("dip1000", "useDIP1000", "revert DIP1000 changes https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1000.md (Scoped Pointers)"), Feature("intpromote", "fix16997", "revert integral promotions for unary + - ~ operators"), @@ -865,7 +868,7 @@ dmd -cov -unittest myprog.d /// Returns all available previews static immutable previews = [ Feature("dip25", "useDIP25", - "implement https://github.com/dlang/DIPs/blob/master/DIPs/archive/DIP25.md (Sealed references)"), + "implement https://github.com/dlang/DIPs/blob/master/DIPs/archive/DIP25.md (Sealed references)", true, true), Feature("dip1000", "useDIP1000", "implement https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1000.md (Scoped Pointers)"), Feature("dip1008", "ehnogc", diff --git a/dmd/clone.d b/dmd/clone.d index ef5464d75e0..19bf83e4ec3 100644 --- a/dmd/clone.d +++ b/dmd/clone.d @@ -113,11 +113,11 @@ FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* sc) sc.minst = null; a[0] = er; - auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, &a, FuncResolveFlag.quiet); + auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(&a), FuncResolveFlag.quiet); if (!f) { a[0] = el; - f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, &a, FuncResolveFlag.quiet); + f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(&a), FuncResolveFlag.quiet); } sc = sc.pop(); @@ -478,7 +478,7 @@ private FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* sc) { a[0] = e; a[0].type = tthis; - return resolveFuncCall(ad.loc, sc, eq, null, tthis, &a, FuncResolveFlag.quiet); + return resolveFuncCall(ad.loc, sc, eq, null, tthis, ArgumentList(&a), FuncResolveFlag.quiet); } f = rfc(er); @@ -1065,7 +1065,7 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara { auto cldec = ad.isClassDeclaration(); if (!cldec || cldec.cppDtorVtblIndex == -1) // scalar deleting dtor not built for non-virtual dtors - return dtor; + return dtor; // perhaps also do this if STC.scope_ is set // generate deleting C++ destructor corresponding to: // void* C::~C(int del) @@ -1077,8 +1077,9 @@ private DtorDeclaration buildWindowsCppDtor(AggregateDeclaration ad, DtorDeclara Parameter delparam = new Parameter(STC.undefined_, Type.tuns32, Identifier.idPool("del"), new IntegerExp(dtor.loc, 0, Type.tuns32), null); Parameters* params = new Parameters; params.push(delparam); - auto ftype = new TypeFunction(ParameterList(params), Type.tvoidptr, LINK.cpp, dtor.storage_class); - auto func = new DtorDeclaration(dtor.loc, dtor.loc, dtor.storage_class, Id.cppdtor); + const stc = dtor.storage_class & ~STC.scope_; // because we add the `return this;` later + auto ftype = new TypeFunction(ParameterList(params), Type.tvoidptr, LINK.cpp, stc); + auto func = new DtorDeclaration(dtor.loc, dtor.loc, stc, Id.cppdtor); func.type = ftype; // Always generate the function with body, because it is not exported from DLLs. diff --git a/dmd/common/outbuffer.d b/dmd/common/outbuffer.d index 276928a6bd8..007d301359c 100644 --- a/dmd/common/outbuffer.d +++ b/dmd/common/outbuffer.d @@ -338,9 +338,12 @@ struct OutBuffer offset += len; } - /// write newline + /// strip trailing tabs or spaces, write newline extern (C++) void writenl() pure nothrow @safe { + while (offset > 0 && (data[offset - 1] == ' ' || data[offset - 1] == '\t')) + offset--; + version (Windows) { writeword(0x0A0D); // newline is CR,LF on Microsoft OS's @@ -919,3 +922,18 @@ unittest buf.setsize(4); assert(buf.length == 4); } + +unittest +{ + OutBuffer buf; + + buf.writenl(); + buf.writestring("abc \t "); + buf.writenl(); // strips trailing whitespace + buf.writenl(); // doesn't strip previous newline + + version(Windows) + assert(buf[] == "\r\nabc\r\n\r\n"); + else + assert(buf[] == "\nabc\n\n"); +} diff --git a/dmd/compiler.d b/dmd/compiler.d index 65adf24bcbf..11b2eaf1459 100644 --- a/dmd/compiler.d +++ b/dmd/compiler.d @@ -11,6 +11,8 @@ module dmd.compiler; +import core.stdc.string; + import dmd.astcodegen; import dmd.astenums; import dmd.arraytypes; @@ -142,7 +144,7 @@ extern (C++) struct Compiler */ extern(C++) static bool onImport(Module m) { - if (includeImports) + if (includeImports && m.filetype == FileType.d) { if (includeImportedModuleCheck(ModuleComponentRange( m.md ? m.md.packages : [], m.ident, m.isPackageFile))) @@ -305,7 +307,7 @@ private void createMatchNodes() { foreach (modulePattern; includeModulePatterns) { - auto depth = parseModulePatternDepth(modulePattern); + auto depth = parseModulePatternDepth(modulePattern[0 .. strlen(modulePattern)]); auto entryIndex = findSortedIndexToAddForDepth(depth); matchNodes.split(entryIndex, depth + 1); parseModulePattern(modulePattern, &matchNodes[entryIndex], depth); @@ -343,24 +345,20 @@ private void createMatchNodes() * Returns: * The component depth of the given module pattern. */ -private ushort parseModulePatternDepth(const(char)* modulePattern) +pure @safe +private ushort parseModulePatternDepth(const char[] modulePattern) { - if (modulePattern[0] == '-') - modulePattern++; + const length = modulePattern.length; + size_t i = (length && modulePattern[0] == '-'); // skip past leading '-' // handle special case - if (modulePattern[0] == '.' && modulePattern[1] == '\0') + if (i + 1 == length && modulePattern[i] == '.') return 0; - ushort depth = 1; - for (;; modulePattern++) - { - auto c = *modulePattern; - if (c == '.') - depth++; - if (c == '\0') - return depth; - } + int depth = 1; + foreach (c; modulePattern[i .. length]) + depth += c == '.'; + return cast(ushort)depth; } unittest { diff --git a/dmd/cond.d b/dmd/cond.d index c0c4cf1ce82..c40936c78d1 100644 --- a/dmd/cond.d +++ b/dmd/cond.d @@ -935,9 +935,6 @@ extern (C++) final class StaticIfCondition : Condition import dmd.staticcond; bool errors; - if (!exp) - return errorReturn(); - bool result = evalStaticCondition(sc, exp, exp, errors); // Prevent repeated condition evaluation. diff --git a/dmd/constfold.d b/dmd/constfold.d index 74992480058..4ece94496f6 100644 --- a/dmd/constfold.d +++ b/dmd/constfold.d @@ -858,20 +858,8 @@ UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expressio } else { - if (e1.type.isreal()) - { - cmp = CTFloat.isIdentical(e1.toReal(), e2.toReal()); - } - else if (e1.type.isimaginary()) - { - cmp = RealIdentical(e1.toImaginary(), e2.toImaginary()); - } - else if (e1.type.iscomplex()) - { - complex_t v1 = e1.toComplex(); - complex_t v2 = e2.toComplex(); - cmp = RealIdentical(creall(v1), creall(v2)) && RealIdentical(cimagl(v1), cimagl(v1)); - } + if (e1.type.isfloating()) + cmp = e1.isIdentical(e2); else { ue = Equal((op == EXP.identity) ? EXP.equal : EXP.notEqual, loc, type, e1, e2); diff --git a/dmd/cparse.d b/dmd/cparse.d index 47f37d59c61..a39fa1d3491 100644 --- a/dmd/cparse.d +++ b/dmd/cparse.d @@ -16,6 +16,7 @@ module dmd.cparse; import core.stdc.stdio; import core.stdc.string; import dmd.astenums; +import dmd.errorsink; import dmd.globals; import dmd.id; import dmd.identifier; @@ -72,9 +73,10 @@ final class CParser(AST) : Parser!AST OutBuffer* defines; extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment, - const ref TARGET target, OutBuffer* defines) + ErrorSink errorSink, + const ref TARGET target, OutBuffer* defines) scope { - super(_module, input, doDocComment); + super(_module, input, doDocComment, errorSink); //printf("CParser.this()\n"); mod = _module; @@ -271,11 +273,12 @@ final class CParser(AST) : Parser!AST case TOK.minusMinus: case TOK.sizeof_: case TOK._Generic: + case TOK._assert: Lexp: auto exp = cparseExpression(); if (token.value == TOK.identifier && exp.op == EXP.identifier) { - error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars()); + error(token.loc, "found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars()); nextToken(); } else @@ -289,6 +292,7 @@ final class CParser(AST) : Parser!AST case TOK.int16: case TOK.int32: case TOK.int64: + case TOK.__int128: case TOK.float32: case TOK.float64: case TOK.signed: @@ -755,7 +759,7 @@ final class CParser(AST) : Parser!AST if (token.postfix) { if (token.postfix != postfix) - error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix); + error(token.loc, "mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix); postfix = token.postfix; } @@ -784,6 +788,14 @@ final class CParser(AST) : Parser!AST e = cparseGenericSelection(); break; + case TOK._assert: // __check(assign-exp) extension + nextToken(); + check(TOK.leftParenthesis, "`__check`"); + e = parseAssignExp(); + check(TOK.rightParenthesis); + e = new AST.AssertExp(loc, e, null); + break; + default: error("expression expected, not `%s`", token.toChars()); // Anything for e, as long as it's not NULL @@ -1643,6 +1655,23 @@ final class CParser(AST) : Parser!AST specifier.packalign = this.packalign; auto tspec = cparseDeclarationSpecifiers(level, specifier); + AST.Dsymbol declareTag(AST.TypeTag tt, ref Specifier specifier) + { + /* `struct tag;` and `struct tag { ... };` + * always result in a declaration in the current scope + */ + auto stag = (tt.tok == TOK.struct_) ? new AST.StructDeclaration(tt.loc, tt.id, false) : + (tt.tok == TOK.union_) ? new AST.UnionDeclaration(tt.loc, tt.id) : + new AST.EnumDeclaration(tt.loc, tt.id, tt.base); + stag.members = tt.members; + tt.members = null; + if (!symbols) + symbols = new AST.Dsymbols(); + auto stags = applySpecifier(stag, specifier); + symbols.push(stags); + return stags; + } + /* If a declarator does not follow, it is unnamed */ if (token.value == TOK.semicolon) @@ -1667,22 +1696,12 @@ final class CParser(AST) : Parser!AST !tt.id && (tt.tok == TOK.struct_ || tt.tok == TOK.union_)) return; // legal but meaningless empty declaration, ignore it - /* `struct tag;` and `struct tag { ... };` - * always result in a declaration in the current scope - */ - auto stag = (tt.tok == TOK.struct_) ? new AST.StructDeclaration(tt.loc, tt.id, false) : - (tt.tok == TOK.union_) ? new AST.UnionDeclaration(tt.loc, tt.id) : - new AST.EnumDeclaration(tt.loc, tt.id, tt.base); - stag.members = tt.members; - if (!symbols) - symbols = new AST.Dsymbols(); - auto stags = applySpecifier(stag, specifier); - symbols.push(stags); + auto stags = declareTag(tt, specifier); if (0 && tt.tok == TOK.enum_) // C11 proscribes enums with no members, but we allow it { if (!tt.members) - error(tt.loc, "`enum %s` has no members", stag.toChars()); + error(tt.loc, "`enum %s` has no members", stags.toChars()); } return; } @@ -1828,17 +1847,8 @@ final class CParser(AST) : Parser!AST { if (!tt.id && id) tt.id = id; - /* `struct tag;` and `struct tag { ... };` - * always result in a declaration in the current scope - */ - auto stag = (tt.tok == TOK.struct_) ? new AST.StructDeclaration(tt.loc, tt.id, false) : - (tt.tok == TOK.union_) ? new AST.UnionDeclaration(tt.loc, tt.id) : - new AST.EnumDeclaration(tt.loc, tt.id, tt.base); - stag.members = tt.members; - tt.members = null; - if (!symbols) - symbols = new AST.Dsymbols(); - symbols.push(stag); + Specifier spec; + auto stag = declareTag(tt, spec); if (tt.tok == TOK.enum_) { isalias = false; @@ -1852,6 +1862,15 @@ final class CParser(AST) : Parser!AST } else if (id) { + if (auto tt = dt.isTypeTag()) + { + if (tt.members && (tt.id || tt.tok == TOK.enum_)) + { + Specifier spec; + declareTag(tt, spec); + } + } + if (level == LVL.prototype) break; // declared later as Parameter, not VarDeclaration @@ -1934,7 +1953,7 @@ final class CParser(AST) : Parser!AST case TOK.identifier: if (s) { - error("missing comma or semicolon after declaration of `%s`, found `%s` instead", s.toChars(), token.toChars()); + error(token.loc, "missing comma or semicolon after declaration of `%s`, found `%s` instead", s.toChars(), token.toChars()); goto Lend; } goto default; @@ -2000,7 +2019,7 @@ final class CParser(AST) : Parser!AST importBuiltins = true; // will need __va_list_tag auto plLength = pl.length; if (symbols.length != plLength) - error("%d identifiers does not match %d declarations", cast(int)plLength, cast(int)symbols.length); + 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[] */ @@ -2188,6 +2207,7 @@ final class CParser(AST) : Parser!AST ximaginary = 0x8000, xcomplex = 0x10000, x_Atomic = 0x20000, + xint128 = 0x40000, } AST.Type t; @@ -2232,6 +2252,7 @@ final class CParser(AST) : Parser!AST case TOK.int16: tkwx = TKW.xshort; break; case TOK.int32: tkwx = TKW.xint; break; case TOK.int64: tkwx = TKW.xlong; break; + case TOK.__int128: tkwx = TKW.xint128; break; case TOK.float32: tkwx = TKW.xfloat; break; case TOK.float64: tkwx = TKW.xdouble; break; case TOK.void_: tkwx = TKW.xvoid; break; @@ -2510,6 +2531,11 @@ final class CParser(AST) : Parser!AST case TKW.xunsigned | TKW.xllong | TKW.xint: case TKW.xunsigned | TKW.xllong: t = unsignedTypeForSize(long_longsize); break; + case TKW.xint128: + case TKW.xsigned | TKW.xint128: t = integerTypeForSize(16); break; + + case TKW.xunsigned | TKW.xint128: t = unsignedTypeForSize(16); break; + case TKW.xvoid: t = AST.Type.tvoid; break; case TKW.xbool: t = boolsize == 1 ? AST.Type.tbool : integerTypeForSize(boolsize); break; @@ -3275,6 +3301,7 @@ final class CParser(AST) : Parser!AST case TOK._Complex: case TOK._Thread_local: case TOK.int32: + case TOK.__int128: case TOK.char_: case TOK.float32: case TOK.float64: @@ -3945,6 +3972,7 @@ final class CParser(AST) : Parser!AST case TOK.int16: case TOK.int32: case TOK.int64: + case TOK.__int128: case TOK.float32: case TOK.float64: case TOK.signed: @@ -4309,6 +4337,7 @@ final class CParser(AST) : Parser!AST case TOK.int16: case TOK.int32: case TOK.int64: + case TOK.__int128: case TOK.float32: case TOK.float64: case TOK.void_: @@ -4707,6 +4736,11 @@ final class CParser(AST) : Parser!AST return AST.Type.tint32; if (size <= 8) return AST.Type.tint64; + if (size == 16) + { + error("__int128 not supported"); + return AST.Type.terror; + } error("unsupported integer type"); return AST.Type.terror; } @@ -4728,6 +4762,11 @@ final class CParser(AST) : Parser!AST return AST.Type.tuns32; if (size <= 8) return AST.Type.tuns64; + if (size == 16) + { + error("unsigned __int128 not supported"); + return AST.Type.terror; + } error("unsupported integer type"); return AST.Type.terror; } @@ -5130,9 +5169,9 @@ final class CParser(AST) : Parser!AST if (n.value == TOK.identifier && n.ident == Id.show) { if (packalign.isDefault()) - warning(startloc, "current pack attribute is default"); + eSink.warning(startloc, "current pack attribute is default"); else - warning(startloc, "current pack attribute is %d", packalign.get()); + eSink.warning(startloc, "current pack attribute is %d", packalign.get()); scan(&n); return closingParen(); } @@ -5293,6 +5332,8 @@ final class CParser(AST) : Parser!AST void addVar(AST.VarDeclaration v) { + //printf("addVar() %s\n", v.toChars()); + v.isCmacro(true); // mark it as coming from a C #define /* If it's already defined, replace the earlier * definition */ diff --git a/dmd/cppmangle.d b/dmd/cppmangle.d index d3effa99ddd..32b38518953 100644 --- a/dmd/cppmangle.d +++ b/dmd/cppmangle.d @@ -173,7 +173,7 @@ private final class CppMangleVisitor : Visitor * buf = `OutBuffer` to write the mangling to * loc = `Loc` of the symbol being mangled */ - this(OutBuffer* buf, Loc loc) + this(OutBuffer* buf, Loc loc) scope { this.buf = buf; this.loc = loc; @@ -213,6 +213,11 @@ private final class CppMangleVisitor : Visitor { auto tf = cast(TypeFunction)this.context.res.asFuncDecl().type; Type rt = preSemantic.nextOf(); + // https://issues.dlang.org/show_bug.cgi?id=22739 + // auto return type means that rt is null. + // if so, just pick up the type from the instance + if (!rt) + rt = tf.nextOf(); if (tf.isref) rt = rt.referenceTo(); auto prev = this.context.push(tf.nextOf()); @@ -560,7 +565,11 @@ private final class CppMangleVisitor : Visitor foreach (j; i .. (*ti.tiargs).length) { Type t = isType((*ti.tiargs)[j]); - assert(t); + if (t is null) + { + ti.error("internal compiler error: C++ `%s` template value parameter is not supported", (*ti.tiargs)[j].toChars()); + fatal(); + } t.accept(this); } diff --git a/dmd/cppmanglewin.d b/dmd/cppmanglewin.d index 1ae53c0a5f7..c59a9a6de1a 100644 --- a/dmd/cppmanglewin.d +++ b/dmd/cppmanglewin.d @@ -135,7 +135,7 @@ private final class VisualCPPMangler : Visitor int flags; OutBuffer buf; - extern (D) this(VisualCPPMangler rvl) + extern (D) this(VisualCPPMangler rvl) scope { flags |= (rvl.flags & IS_DMC); saved_idents[] = rvl.saved_idents[]; @@ -144,7 +144,7 @@ private final class VisualCPPMangler : Visitor } public: - extern (D) this(bool isdmc, Loc loc) + extern (D) this(bool isdmc, Loc loc) scope { if (isdmc) { @@ -1022,9 +1022,14 @@ extern(D): { tmp.mangleTemplateValue(o, tv, actualti, is_dmc_template); } - else - if (!tp || tp.isTemplateTypeParameter()) + else if (!tp || tp.isTemplateTypeParameter()) { + Type t = isType(o); + if (t is null) + { + actualti.error("internal compiler error: C++ `%s` template value parameter is not supported", o.toChars()); + fatal(); + } tmp.mangleTemplateType(o); } else if (tp.isTemplateAliasParameter()) diff --git a/dmd/ctfeexpr.d b/dmd/ctfeexpr.d index c902149e2b5..8109e12d43d 100644 --- a/dmd/ctfeexpr.d +++ b/dmd/ctfeexpr.d @@ -1281,12 +1281,12 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide { return e1.toInteger() != e2.toInteger(); } + if (identity && e1.type.isfloating()) + return !e1.isIdentical(e2); if (e1.type.isreal() || e1.type.isimaginary()) { real_t r1 = e1.type.isreal() ? e1.toReal() : e1.toImaginary(); real_t r2 = e1.type.isreal() ? e2.toReal() : e2.toImaginary(); - if (identity) - return !CTFloat.isIdentical(r1, r2); if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered { return 1; // they are not equal @@ -1298,13 +1298,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide } else if (e1.type.iscomplex()) { - auto c1 = e1.toComplex(); - auto c2 = e2.toComplex(); - if (identity) - { - return !RealIdentical(c1.re, c2.re) && !RealIdentical(c1.im, c2.im); - } - return c1 != c2; + return e1.toComplex() != e2.toComplex(); } if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral) { @@ -1415,16 +1409,8 @@ bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2) SymOffExp es2 = e2.isSymOffExp(); cmp = (es1.var == es2.var && es1.offset == es2.offset); } - else if (e1.type.isreal()) - cmp = CTFloat.isIdentical(e1.toReal(), e2.toReal()); - else if (e1.type.isimaginary()) - cmp = RealIdentical(e1.toImaginary(), e2.toImaginary()); - else if (e1.type.iscomplex()) - { - complex_t v1 = e1.toComplex(); - complex_t v2 = e2.toComplex(); - cmp = RealIdentical(creall(v1), creall(v2)) && RealIdentical(cimagl(v1), cimagl(v1)); - } + else if (e1.type.isfloating()) + cmp = e1.isIdentical(e2); else { cmp = !ctfeRawCmp(loc, e1, e2, true); diff --git a/dmd/dclass.d b/dmd/dclass.d index 82aed53f5e2..ec893cd5973 100644 --- a/dmd/dclass.d +++ b/dmd/dclass.d @@ -966,12 +966,6 @@ version (IN_LLVM) {} else /**************************************** */ - override final void addLocalClass(ClassDeclarations* aclasses) - { - if (classKind != ClassKind.objc) - aclasses.push(this); - } - override final void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories) { .objc.addSymbols(this, classes, categories); diff --git a/dmd/declaration.d b/dmd/declaration.d index f365908b91a..e87bd3baa53 100644 --- a/dmd/declaration.d +++ b/dmd/declaration.d @@ -1120,7 +1120,7 @@ extern (C++) class VarDeclaration : Declaration { Initializer _init; FuncDeclarations nestedrefs; // referenced by these lexically nested functions - Dsymbol aliassym; // if redone as alias to another symbol + TupleDeclaration aliasTuple; // when `this` is really a tuple of declarations VarDeclaration lastVar; // Linked list of variables for goto-skips-init detection Expression edtor; // if !=null, does the destruction of the variable IntRange* range; // if !=null, the variable is known to be within the range @@ -1161,6 +1161,12 @@ version (IN_LLVM) bool doNotInferReturn; /// do not infer 'return' for this variable bool isArgDtorVar; /// temporary created to handle scope destruction of a function argument + bool isCmacro; /// it is a C macro turned into a C declaration + version (MARS) + { + bool inClosure; /// is inserted into a GC allocated closure + bool inAlignSection; /// is inserted into an aligned section on stack + } } import dmd.common.bitfields : generateBitFields; @@ -1212,12 +1218,10 @@ version (IN_LLVM) { //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars()); - if (aliassym) + if (aliasTuple) { // If this variable was really a tuple, set the offsets for the tuple fields - TupleDeclaration v2 = aliassym.isTupleDeclaration(); - assert(v2); - v2.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); }); + aliasTuple.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); }); return; } @@ -1328,9 +1332,17 @@ version (IN_LLVM) override final bool isImportedSymbol() const { - if (visibility.kind == Visibility.Kind.export_ && !_init && (storage_class & STC.static_ || parent.isModule())) - return true; - return false; + /* If global variable has `export` and `extern` then it is imported + * export int sym1; // definition: exported + * export extern int sym2; // declaration: imported + * export extern int sym3 = 0; // error, extern cannot have initializer + */ + bool result = + visibility.kind == Visibility.Kind.export_ && + storage_class & STC.extern_ && + (storage_class & STC.static_ || parent.isModule()); + //printf("isImportedSymbol() %s %d\n", toChars(), result); + return result; } final bool isCtorinit() const pure nothrow @nogc @safe @@ -1672,8 +1684,7 @@ version (IN_LLVM) // Add this VarDeclaration to fdv.closureVars[] if not already there if (!sc.intypeof && !(sc.flags & SCOPE.compile) && // https://issues.dlang.org/show_bug.cgi?id=17605 - (fdv.isCompileTimeOnly || !fdthis.isCompileTimeOnly) - ) + (fdv.skipCodegen || !fdthis.skipCodegen)) { if (!fdv.closureVars.contains(this)) fdv.closureVars.push(this); @@ -1710,8 +1721,8 @@ version (IN_LLVM) if ((!type || !type.deco) && _scope) dsymbolSemantic(this, _scope); - assert(this != aliassym); - Dsymbol s = aliassym ? aliassym.toAlias() : this; + assert(this != aliasTuple); + Dsymbol s = aliasTuple ? aliasTuple.toAlias() : this; return s; } diff --git a/dmd/declaration.h b/dmd/declaration.h index 05072645637..b4b78af9ce8 100644 --- a/dmd/declaration.h +++ b/dmd/declaration.h @@ -235,7 +235,7 @@ class VarDeclaration : public Declaration public: Initializer *_init; FuncDeclarations nestedrefs; // referenced by these lexically nested functions - Dsymbol *aliassym; // if redone as alias to another symbol + TupleDeclaration *aliasTuple; // if `this` is really a tuple of declarations VarDeclaration *lastVar; // Linked list of variables for goto-skips-init detection Expression *edtor; // if !=NULL, does the destruction of the variable IntRange *range; // if !NULL, the variable is known to be within the range @@ -280,6 +280,14 @@ class VarDeclaration : public Declaration bool doNotInferReturn(bool v); bool isArgDtorVar() const; // temporary created to handle scope destruction of a function argument bool isArgDtorVar(bool v); + bool isCmacro() const; // if a C macro turned into a C variable + bool isCmacro(bool v); +#if MARS + bool inClosure() const; // is inserted into a GC allocated closure + bool inClosure(bool v); + bool inAlignSection() const; // is inserted into aligned section on stack + bool inAlignSection(bool v); +#endif static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined); VarDeclaration *syntaxCopy(Dsymbol *) override; void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override final; @@ -664,8 +672,8 @@ class FuncDeclaration : public Declaration bool inferScope(bool v); bool hasCatches() const; bool hasCatches(bool v); - bool isCompileTimeOnly() const; - bool isCompileTimeOnly(bool v); + bool skipCodegen() const; + bool skipCodegen(bool v); bool printf() const; bool printf(bool v); bool scanf() const; @@ -710,7 +718,7 @@ class FuncDeclaration : public Declaration BaseClass *overrideInterface(); bool overloadInsert(Dsymbol *s) override; bool inUnittest(); - MATCH leastAsSpecialized(FuncDeclaration *g); + MATCH leastAsSpecialized(FuncDeclaration *g, Identifiers *names); LabelDsymbol *searchLabel(Identifier *ident, const Loc &loc); int getLevel(FuncDeclaration *fd, int intypeof); // lexical nesting level difference int getLevelAndCheck(const Loc &loc, Scope *sc, FuncDeclaration *fd); diff --git a/dmd/delegatize.d b/dmd/delegatize.d index 3f982b3faf7..fd9569105b5 100644 --- a/dmd/delegatize.d +++ b/dmd/delegatize.d @@ -109,7 +109,7 @@ private void lambdaSetParent(Expression e, FuncDeclaration fd) } public: - extern (D) this(FuncDeclaration fd) + extern (D) this(FuncDeclaration fd) scope { this.fd = fd; } @@ -205,7 +205,7 @@ bool lambdaCheckForNestedRef(Expression e, Scope* sc) Scope* sc; bool result; - extern (D) this(Scope* sc) + extern (D) this(Scope* sc) scope { this.sc = sc; } diff --git a/dmd/dinterpret.d b/dmd/dinterpret.d index ff0957e6b86..ff406296343 100644 --- a/dmd/dinterpret.d +++ b/dmd/dinterpret.d @@ -778,7 +778,7 @@ public: Expression result; UnionExp* pue; // storage for `result` - extern (D) this(UnionExp* pue, InterState* istate, CTFEGoal goal) + extern (D) this(UnionExp* pue, InterState* istate, CTFEGoal goal) scope { this.pue = pue; this.istate = istate; @@ -2067,7 +2067,7 @@ public: } auto er = interpret(e.e1, istate, CTFEGoal.LValue); if (auto ve = er.isVarExp()) - if (ve.var == istate.fd.vthis) + if (istate && ve.var == istate.fd.vthis) er = interpret(er, istate); if (exceptionOrCant(er)) @@ -2148,6 +2148,16 @@ public: return CTFEExp.cantexp; assert(e.type); + // There's a terrible hack in `dmd.dsymbolsem` that special case + // a struct with all zeros to an `ExpInitializer(BlitExp(IntegerExp(0)))` + // There's matching code for it in e2ir (toElem's visitAssignExp), + // so we need the same hack here. + // This does not trigger for global as they get a normal initializer. + if (auto ts = e.type.isTypeStruct()) + if (auto ae = e.isBlitExp()) + if (ae.e2.op == EXP.int64) + e = ts.defaultInitLiteral(loc); + if (e.op == EXP.construct || e.op == EXP.blit) { AssignExp ae = cast(AssignExp)e; diff --git a/dmd/dmangle.d b/dmd/dmangle.d index 867d3cacb2f..72a44765787 100644 --- a/dmd/dmangle.d +++ b/dmd/dmangle.d @@ -14,17 +14,18 @@ module dmd.dmangle; -import dmd.astenums; /****************************************************************************** * Returns exact mangled name of function. */ extern (C++) const(char)* mangleExact(FuncDeclaration fd) { + //printf("mangleExact()\n"); if (!fd.mangleString) { OutBuffer buf; - scope Mangler v = new Mangler(&buf); + auto backref = Backref(null); + scope Mangler v = new Mangler(&buf, &backref); v.mangleExact(fd); fd.mangleString = buf.extractChars(); } @@ -33,30 +34,38 @@ extern (C++) const(char)* mangleExact(FuncDeclaration fd) extern (C++) void mangleToBuffer(Type t, OutBuffer* buf) { + //printf("mangleToBuffer t()\n"); if (t.deco) buf.writestring(t.deco); else { - scope Mangler v = new Mangler(buf, t); - v.visitWithMask(t, 0); + auto backref = Backref(t); + mangleType(t, 0, buf, backref); + //printf("%s\n", buf.peekChars()); } } extern (C++) void mangleToBuffer(Expression e, OutBuffer* buf) { - scope Mangler v = new Mangler(buf); + //printf("mangleToBuffer e()\n"); + auto backref = Backref(null); + scope Mangler v = new Mangler(buf, &backref); e.accept(v); } extern (C++) void mangleToBuffer(Dsymbol s, OutBuffer* buf) { - scope Mangler v = new Mangler(buf); + //printf("mangleToBuffer s(%s)\n", s.toChars()); + auto backref = Backref(null); + scope Mangler v = new Mangler(buf, &backref); s.accept(v); } extern (C++) void mangleToBuffer(TemplateInstance ti, OutBuffer* buf) { - scope Mangler v = new Mangler(buf); + //printf("mangleToBuffer ti()\n"); + auto backref = Backref(null); + scope Mangler v = new Mangler(buf, &backref); v.mangleTemplateInstance(ti); } @@ -127,6 +136,7 @@ import core.stdc.string; import dmd.aggregate; import dmd.arraytypes; +import dmd.astenums; import dmd.dclass; import dmd.declaration; import dmd.dmodule; @@ -231,233 +241,344 @@ unittest } } -private extern (C++) final class Mangler : Visitor +/************************************************ + * Append the mangling of type `t` to `buf`. + * Params: + * t = type to mangle + * modMask = mod bits currently applying to t + * buf = buffer to append mangling to + * backref = state of back references (updated) + */ +void mangleType(Type t, ubyte modMask, OutBuffer* buf, ref Backref backref) { - alias visit = Visitor.visit; -public: - static assert(Key.sizeof == size_t.sizeof); - - OutBuffer* buf; - Backref backref; - - extern (D) this(OutBuffer* buf, Type rootType = null) - { - this.buf = buf; - this.backref = Backref(rootType); - } - - void mangleSymbol(Dsymbol s) - { - s.accept(this); - } - - void mangleType(Type t) + void visitWithMask(Type t, ubyte modMask) { - if (!backref.addRefToType(buf, t)) - t.accept(this); - } + void mangleSymbol(Dsymbol s) + { + scope Mangler v = new Mangler(buf, &backref); + v.mangleSymbol(s); + } - void mangleIdentifier(Identifier id, Dsymbol s) - { - if (!backref.addRefToIdentifier(buf, id)) - toBuffer(buf, id.toString(), s); - } + void visitType(Type t) + { + tyToDecoBuffer(buf, t.ty); + } - //////////////////////////////////////////////////////////////////////////// - /************************************************** - * Type mangling - */ - void visitWithMask(Type t, ubyte modMask) - { - if (modMask != t.mod) + void visitTypeNext(TypeNext t) { - MODtoDecoBuffer(buf, t.mod); + visitType(t); + visitWithMask(t.next, t.mod); } - mangleType(t); - } - override void visit(Type t) - { - tyToDecoBuffer(buf, t.ty); - } + void visitTypeVector(TypeVector t) + { + buf.writestring("Nh"); + visitWithMask(t.basetype, t.mod); + } - override void visit(TypeNext t) - { - visit(cast(Type)t); - visitWithMask(t.next, t.mod); - } + void visitTypeSArray(TypeSArray t) + { + visitType(t); + if (t.dim) + buf.print(t.dim.toInteger()); + if (t.next) + visitWithMask(t.next, t.mod); + } - override void visit(TypeVector t) - { - buf.writestring("Nh"); - visitWithMask(t.basetype, t.mod); - } + void visitTypeDArray(TypeDArray t) + { + visitType(t); + if (t.next) + visitWithMask(t.next, t.mod); + } - override void visit(TypeSArray t) - { - visit(cast(Type)t); - if (t.dim) - buf.print(t.dim.toInteger()); - if (t.next) + void visitTypeAArray(TypeAArray t) + { + visitType(t); + visitWithMask(t.index, 0); visitWithMask(t.next, t.mod); - } + } - override void visit(TypeDArray t) - { - visit(cast(Type)t); - if (t.next) - visitWithMask(t.next, t.mod); - } + void visitTypeFunction(TypeFunction t) + { + //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars()); + //static int nest; if (++nest == 50) *(char*)0=0; + mangleFuncType(t, t, t.mod, t.next, buf, backref); + } - override void visit(TypeAArray t) - { - visit(cast(Type)t); - visitWithMask(t.index, 0); - visitWithMask(t.next, t.mod); - } + void visitTypeIdentifier(TypeIdentifier t) + { + visitType(t); + auto name = t.ident.toString(); + buf.print(cast(int)name.length); + buf.writestring(name); + } - override void visit(TypeFunction t) - { - //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars()); - //static int nest; if (++nest == 50) *(char*)0=0; - mangleFuncType(t, t, t.mod, t.next); - } + void visitTypeEnum(TypeEnum t) + { + visitType(t); + mangleSymbol(t.sym); + } - void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret) - { - //printf("mangleFuncType() %s\n", t.toChars()); - if (t.inuse && tret) + void visitTypeStruct(TypeStruct t) { - // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars()); - t.inuse = 2; // flag error to caller - return; + //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name); + visitType(t); + mangleSymbol(t.sym); } - t.inuse++; - if (modMask != t.mod) - MODtoDecoBuffer(buf, t.mod); - char mc; - final switch (t.linkage) + void visitTypeClass(TypeClass t) { - case LINK.default_: - case LINK.d: - mc = 'F'; - break; - case LINK.c: - mc = 'U'; - break; - case LINK.windows: - mc = 'W'; - break; - case LINK.cpp: - mc = 'R'; - break; - case LINK.objc: - mc = 'Y'; - break; - case LINK.system: - assert(0); + //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name); + visitType(t); + mangleSymbol(t.sym); } - buf.writeByte(mc); - - if (ta.purity) - buf.writestring("Na"); - if (ta.isnothrow) - buf.writestring("Nb"); - if (ta.isref) - buf.writestring("Nc"); - if (ta.isproperty) - buf.writestring("Nd"); - if (ta.isnogc) - buf.writestring("Ni"); - - // `return scope` must be in that order - if (ta.isreturnscope && !ta.isreturninferred) + + void visitTypeTuple(TypeTuple t) { - buf.writestring("NjNl"); + //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars()); + visitType(t); + Parameter._foreach(t.arguments, (idx, param) { + mangleParameter(param, buf, backref); + return 0; + }); + buf.writeByte('Z'); } - else + + void visitTypeNull(TypeNull t) { - // when return ref, the order is `scope return` - if (ta.isScopeQual && !ta.isscopeinferred) - buf.writestring("Nl"); + visitType(t); + } - if (ta.isreturn && !ta.isreturninferred) - buf.writestring("Nj"); + void visitTypeNoreturn(TypeNoreturn t) + { + buf.writestring("Nn"); } - if (ta.islive) - buf.writestring("Nm"); + if (modMask != t.mod) + { + MODtoDecoBuffer(buf, t.mod); + } + if (backref.addRefToType(buf, t)) + return; - switch (ta.trust) + switch (t.ty) { - case TRUST.trusted: - buf.writestring("Ne"); - break; - case TRUST.safe: - buf.writestring("Nf"); - break; - default: - break; + case Tpointer: + case Treference: + case Tdelegate: + case Tslice: visitTypeNext (cast(TypeNext)t); break; + + case Tarray: visitTypeDArray (t.isTypeDArray()); break; + case Tsarray: visitTypeSArray (t.isTypeSArray()); break; + case Taarray: visitTypeAArray (t.isTypeAArray()); break; + case Tfunction: visitTypeFunction (t.isTypeFunction()); break; + case Tident: visitTypeIdentifier(t.isTypeIdentifier()); break; + case Tclass: visitTypeClass (t.isTypeClass()); break; + case Tstruct: visitTypeStruct (t.isTypeStruct()); break; + case Tenum: visitTypeEnum (t.isTypeEnum()); break; + case Ttuple: visitTypeTuple (t.isTypeTuple()); break; + case Tnull: visitTypeNull (t.isTypeNull()); break; + case Tvector: visitTypeVector (t.isTypeVector()); break; + case Tnoreturn: visitTypeNoreturn (t.isTypeNoreturn); break; + + case Terror: + break; // ignore errors + + default: visitType(t); break; } + } - // Write argument types - foreach (idx, param; t.parameterList) - mangleParameter(param); - //if (buf.data[buf.length - 1] == '@') assert(0); - buf.writeByte('Z' - t.parameterList.varargs); // mark end of arg list - if (tret !is null) - visitWithMask(tret, 0); - t.inuse--; + visitWithMask(t, modMask); +} + + +/************************************************************* + */ +void mangleFuncType(TypeFunction t, TypeFunction ta, ubyte modMask, Type tret, OutBuffer* buf, ref Backref backref) +{ + //printf("mangleFuncType() %s\n", t.toChars()); + if (t.inuse && tret) + { + // printf("TypeFunction.mangleFuncType() t = %s inuse\n", t.toChars()); + t.inuse = 2; // flag error to caller + return; } + t.inuse++; + if (modMask != t.mod) + MODtoDecoBuffer(buf, t.mod); - override void visit(TypeIdentifier t) + char mc; + final switch (t.linkage) + { + case LINK.default_: + case LINK.d: + mc = 'F'; + break; + case LINK.c: + mc = 'U'; + break; + case LINK.windows: + mc = 'W'; + break; + case LINK.cpp: + mc = 'R'; + break; + case LINK.objc: + mc = 'Y'; + break; + case LINK.system: + assert(0); + } + buf.writeByte(mc); + + if (ta.purity) + buf.writestring("Na"); + if (ta.isnothrow) + buf.writestring("Nb"); + if (ta.isref) + buf.writestring("Nc"); + if (ta.isproperty) + buf.writestring("Nd"); + if (ta.isnogc) + buf.writestring("Ni"); + + // `return scope` must be in that order + if (ta.isreturnscope && !ta.isreturninferred) + { + buf.writestring("NjNl"); + } + else { - visit(cast(Type)t); - auto name = t.ident.toString(); - buf.print(cast(int)name.length); - buf.writestring(name); + // when return ref, the order is `scope return` + if (ta.isScopeQual && !ta.isscopeinferred) + buf.writestring("Nl"); + + if (ta.isreturn && !ta.isreturninferred) + buf.writestring("Nj"); } - override void visit(TypeEnum t) + if (ta.islive) + buf.writestring("Nm"); + + switch (ta.trust) { - visit(cast(Type)t); - mangleSymbol(t.sym); + case TRUST.trusted: + buf.writestring("Ne"); + break; + case TRUST.safe: + buf.writestring("Nf"); + break; + default: + break; } - override void visit(TypeStruct t) + // Write argument types + foreach (idx, param; t.parameterList) + mangleParameter(param, buf, backref); + //if (buf.data[buf.length - 1] == '@') assert(0); + buf.writeByte('Z' - t.parameterList.varargs); // mark end of arg list + if (tret !is null) + mangleType(tret, 0, buf, backref); + t.inuse--; +} + +/************************************************************* + */ +void mangleParameter(Parameter p, OutBuffer* buf, ref Backref backref) +{ + // https://dlang.org/spec/abi.html#Parameter + + auto stc = p.storageClass; + + // Inferred storage classes don't get mangled in + if (stc & STC.scopeinferred) + stc &= ~(STC.scope_ | STC.scopeinferred); + if (stc & STC.returninferred) + stc &= ~(STC.return_ | STC.returninferred); + + // much like hdrgen.stcToBuffer() + string rrs; + const isout = (stc & STC.out_) != 0; + final switch (buildScopeRef(stc)) { - //printf("TypeStruct.toDecoBuffer('%s') = '%s'\n", t.toChars(), name); - visit(cast(Type)t); - mangleSymbol(t.sym); + case ScopeRef.None: + case ScopeRef.Scope: + case ScopeRef.Ref: + case ScopeRef.Return: + case ScopeRef.RefScope: + break; + + case ScopeRef.ReturnScope: rrs = "NkM"; goto L1; // return scope + case ScopeRef.ReturnRef: rrs = isout ? "NkJ" : "NkK"; goto L1; // return ref + case ScopeRef.ReturnRef_Scope: rrs = isout ? "MNkJ" : "MNkK"; goto L1; // scope return ref + case ScopeRef.Ref_ReturnScope: rrs = isout ? "NkMJ" : "NkMK"; goto L1; // return scope ref + L1: + buf.writestring(rrs); + stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_); + break; } - override void visit(TypeClass t) + if (stc & STC.scope_) + buf.writeByte('M'); // scope + + if (stc & STC.return_) + buf.writestring("Nk"); // return + + switch (stc & (STC.IOR | STC.lazy_)) { - //printf("TypeClass.toDecoBuffer('%s' mod=%x) = '%s'\n", t.toChars(), mod, name); - visit(cast(Type)t); - mangleSymbol(t.sym); + case 0: + break; + case STC.in_: + buf.writeByte('I'); + break; + case STC.in_ | STC.ref_: + buf.writestring("IK"); + break; + case STC.out_: + buf.writeByte('J'); + break; + case STC.ref_: + buf.writeByte('K'); + break; + case STC.lazy_: + buf.writeByte('L'); + break; + default: + debug + { + printf("storageClass = x%llx\n", stc & (STC.IOR | STC.lazy_)); + } + assert(0); } + mangleType(p.type, (stc & STC.in_) ? MODFlags.const_ : 0, buf, backref); +} + + +private extern (C++) final class Mangler : Visitor +{ + alias visit = Visitor.visit; +public: + static assert(Key.sizeof == size_t.sizeof); - override void visit(TypeTuple t) + OutBuffer* buf; + Backref* backref; + + extern (D) this(OutBuffer* buf, Backref* backref) { - //printf("TypeTuple.toDecoBuffer() t = %p, %s\n", t, t.toChars()); - visit(cast(Type)t); - Parameter._foreach(t.arguments, (idx, param) { - mangleParameter(param); - return 0; - }); - buf.writeByte('Z'); + this.buf = buf; + this.backref = backref; } - override void visit(TypeNull t) + void mangleSymbol(Dsymbol s) { - visit(cast(Type)t); + s.accept(this); } - override void visit(TypeNoreturn t) + void mangleIdentifier(Identifier id, Dsymbol s) { - buf.writestring("Nn"); + if (!backref.addRefToIdentifier(buf, id)) + toBuffer(buf, id.toString(), s); } //////////////////////////////////////////////////////////////////////////// @@ -472,7 +593,7 @@ public: } else if (sthis.type) { - visitWithMask(sthis.type, 0); + mangleType(sthis.type, 0, buf, *backref); } else assert(0); @@ -530,11 +651,11 @@ public: { TypeFunction tf = fd.type.isTypeFunction(); TypeFunction tfo = fd.originalType.isTypeFunction(); - mangleFuncType(tf, tfo, 0, null); + mangleFuncType(tf, tfo, 0, null, buf, *backref); } else { - visitWithMask(fd.type, 0); + mangleType(fd.type, 0, buf, *backref); } } @@ -735,7 +856,7 @@ public: if (ta) { buf.writeByte('T'); - visitWithMask(ta, 0); + mangleType(ta, 0, buf, *backref); } else if (ea) { @@ -778,7 +899,7 @@ public: /* Use type mangling that matches what it would be for a function parameter */ - visitWithMask(ea.type, 0); + mangleType(ea.type, 0, buf, *backref); ea.accept(this); } else if (sa) @@ -1004,77 +1125,6 @@ public: else mangleSymbol(e.fd); } - - //////////////////////////////////////////////////////////////////////////// - - void mangleParameter(Parameter p) - { - // https://dlang.org/spec/abi.html#Parameter - - auto stc = p.storageClass; - - // Inferred storage classes don't get mangled in - if (stc & STC.scopeinferred) - stc &= ~(STC.scope_ | STC.scopeinferred); - if (stc & STC.returninferred) - stc &= ~(STC.return_ | STC.returninferred); - - // much like hdrgen.stcToBuffer() - string rrs; - const isout = (stc & STC.out_) != 0; - final switch (buildScopeRef(stc)) - { - case ScopeRef.None: - case ScopeRef.Scope: - case ScopeRef.Ref: - case ScopeRef.Return: - case ScopeRef.RefScope: - break; - - case ScopeRef.ReturnScope: rrs = "NkM"; goto L1; // return scope - case ScopeRef.ReturnRef: rrs = isout ? "NkJ" : "NkK"; goto L1; // return ref - case ScopeRef.ReturnRef_Scope: rrs = isout ? "MNkJ" : "MNkK"; goto L1; // scope return ref - case ScopeRef.Ref_ReturnScope: rrs = isout ? "NkMJ" : "NkMK"; goto L1; // return scope ref - L1: - buf.writestring(rrs); - stc &= ~(STC.out_ | STC.scope_ | STC.ref_ | STC.return_); - break; - } - - if (stc & STC.scope_) - buf.writeByte('M'); // scope - - if (stc & STC.return_) - buf.writestring("Nk"); // return - - switch (stc & (STC.IOR | STC.lazy_)) - { - case 0: - break; - case STC.in_: - buf.writeByte('I'); - break; - case STC.in_ | STC.ref_: - buf.writestring("IK"); - break; - case STC.out_: - buf.writeByte('J'); - break; - case STC.ref_: - buf.writeByte('K'); - break; - case STC.lazy_: - buf.writeByte('L'); - break; - default: - debug - { - printf("storageClass = x%llx\n", stc & (STC.IOR | STC.lazy_)); - } - assert(0); - } - visitWithMask(p.type, (stc & STC.in_) ? MODFlags.const_ : 0); - } } /*************************************** @@ -1322,7 +1372,7 @@ void realToMangleBuffer(OutBuffer* buf, real_t value) char[36] buffer = void; // 'A' format yields [-]0xh.hhhhp+-d - const n = CTFloat.sprint(buffer.ptr, 'A', value); + const n = CTFloat.sprint(buffer.ptr, buffer.length, 'A', value); assert(n < buffer.length); foreach (const c; buffer[2 .. n]) { diff --git a/dmd/dmodule.d b/dmd/dmodule.d index 77d54c7992d..4bd20cf1101 100644 --- a/dmd/dmodule.d +++ b/dmd/dmodule.d @@ -29,6 +29,7 @@ import dmd.dscope; import dmd.dsymbol; import dmd.dsymbolsem; import dmd.errors; +import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.file_manager; @@ -827,7 +828,7 @@ else { filetype = FileType.c; - scope p = new CParser!AST(this, buf, cast(bool) docfile, target.c, &defines); + scope p = new CParser!AST(this, buf, cast(bool) docfile, global.errorSink, target.c, &defines); p.nextToken(); checkCompiledImport(); members = p.parseModule(); @@ -836,7 +837,7 @@ else } else { - scope p = new Parser!AST(this, buf, cast(bool) docfile); + scope p = new Parser!AST(this, buf, cast(bool) docfile, global.errorSink); p.nextToken(); p.parseModuleDeclaration(); md = p.md; @@ -1462,6 +1463,37 @@ extern (C++) struct ModuleDeclaration } } +/**************************************** + * Create array of the local classes in the Module, suitable + * for inclusion in ModuleInfo + * Params: + * mod = the Module + * aclasses = array to fill in + * Returns: array of local classes + */ +extern (C++) void getLocalClasses(Module mod, ref ClassDeclarations aclasses) +{ + //printf("members.length = %d\n", mod.members.length); + int pushAddClassDg(size_t n, Dsymbol sm) + { + if (!sm) + return 0; + + if (auto cd = sm.isClassDeclaration()) + { + // compatibility with previous algorithm + if (cd.parent && cd.parent.isTemplateMixin()) + return 0; + + if (cd.classKind != ClassKind.objc) + aclasses.push(cd); + } + return 0; + } + + ScopeDsymbol._foreach(null, mod.members, &pushAddClassDg); +} + /** * Process the content of a source file * diff --git a/dmd/doc.d b/dmd/doc.d index 478e813372e..65c917909f2 100644 --- a/dmd/doc.d +++ b/dmd/doc.d @@ -955,7 +955,7 @@ private void emitComment(Dsymbol s, ref OutBuffer buf, Scope* sc) OutBuffer* buf; Scope* sc; - extern (D) this(ref OutBuffer buf, Scope* sc) + extern (D) this(ref OutBuffer buf, Scope* sc) scope { this.buf = &buf; this.sc = sc; @@ -1239,7 +1239,7 @@ private void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc) OutBuffer* buf; Scope* sc; - extern (D) this(ref OutBuffer buf, Scope* sc) + extern (D) this(ref OutBuffer buf, Scope* sc) scope { this.buf = &buf; this.sc = sc; @@ -5187,6 +5187,7 @@ private void highlightCode2(Scope* sc, Dsymbols* a, ref OutBuffer buf, size_t of uint errorsave = global.startGagging(); scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1, + global.errorSink, global.vendor, global.versionNumber()); OutBuffer res; const(char)* lastp = cast(char*)buf[].ptr; diff --git a/dmd/dscope.d b/dmd/dscope.d index e659448af83..a0a80b27264 100644 --- a/dmd/dscope.d +++ b/dmd/dscope.d @@ -64,13 +64,14 @@ enum SCOPE free = 0x8000, /// is on free list fullinst = 0x10000, /// fully instantiate templates + ctfeBlock = 0x20000, /// inside a `if (__ctfe)` block } /// Flags that are carried along with a scope push() private enum PersistentFlags = SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint | SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility | - SCOPE.Cfile; + SCOPE.Cfile | SCOPE.ctfeBlock; extern (C++) struct Scope { @@ -277,6 +278,10 @@ version (IN_LLVM) * // To call x.toString in runtime, compiler should unspeculative S!int. * assert(x.toString() == "instantiated"); * } + * + * This results in an undefined reference to `RTInfoImpl`: + * class C { int a,b,c; int* p,q; } + * void test() { C c = new C(); } */ // If a template is instantiated from CT evaluated expression, // compiler can elide its code generation. diff --git a/dmd/dstruct.d b/dmd/dstruct.d index 895aea8c48b..bb5ecbbdff6 100644 --- a/dmd/dstruct.d +++ b/dmd/dstruct.d @@ -75,7 +75,7 @@ extern (C++) void semanticTypeInfo(Scope* sc, Type t) { if (sc.intypeof) return; - if (sc.flags & (SCOPE.ctfe | SCOPE.compile)) + if (sc.flags & (SCOPE.ctfe | SCOPE.compile | SCOPE.ctfeBlock)) return; } @@ -489,6 +489,16 @@ version (IN_LLVM) {} else return (ispod == ThreeState.yes); } + /*************************************** + * Determine if struct has copy construction (copy constructor or postblit) + * Returns: + * true if struct has copy construction + */ + final bool hasCopyConstruction() + { + return postblit || hasCopyCtor; + } + override final inout(StructDeclaration) isStructDeclaration() inout @nogc nothrow pure @safe { return this; diff --git a/dmd/dsymbol.d b/dmd/dsymbol.d index 90cac64bd73..a9239be6d0c 100644 --- a/dmd/dsymbol.d +++ b/dmd/dsymbol.d @@ -1275,10 +1275,6 @@ version (IN_LLVM) return false; } - void addLocalClass(ClassDeclarations*) - { - } - void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories) { } @@ -1449,6 +1445,7 @@ version (IN_LLVM) inout(OverloadSet) isOverloadSet() inout { return null; } inout(CompileDeclaration) isCompileDeclaration() inout { return null; } inout(StaticAssert) isStaticAssert() inout { return null; } + inout(StaticIfDeclaration) isStaticIfDeclaration() inout { return null; } } /*********************************************************** @@ -2201,10 +2198,23 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol * or a variable (in which case an expression is created in * toir.c). */ - auto e = new VoidInitializer(Loc.initial); - e.type = Type.tsize_t; - v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e); - v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable + + // https://issues.dlang.org/show_bug.cgi?id=16213 + // For static arrays $ is known at compile time, + // so declare it as a manifest constant. + auto tsa = ce.type ? ce.type.isTypeSArray() : null; + if (tsa) + { + auto e = new ExpInitializer(loc, tsa.dim); + v = new VarDeclaration(loc, tsa.dim.type, Id.dollar, e, STC.manifest); + } + else + { + auto e = new VoidInitializer(Loc.initial); + e.type = Type.tsize_t; + v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e); + v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable + } } *pvar = v; } @@ -2653,6 +2663,12 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy auto vd = s.isVarDeclaration(); // new declaration auto vd2 = s2.isVarDeclaration(); // existing declaration + + if (vd && vd.isCmacro()) + return vd2; + + assert(!(vd2 && vd2.isCmacro())); + if (vd && vd2) { /* if one is `static` and the other isn't, the result is undefined diff --git a/dmd/dsymbol.h b/dmd/dsymbol.h index f07a11e6a52..0e6bb72b439 100644 --- a/dmd/dsymbol.h +++ b/dmd/dsymbol.h @@ -72,6 +72,7 @@ class ExpressionDsymbol; class AliasAssign; class OverloadSet; class StaticAssert; +class StaticIfDeclaration; struct AA; #ifdef IN_GCC typedef union tree_node Symbol; @@ -264,7 +265,6 @@ class Dsymbol : public ASTNode virtual void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion); virtual bool hasPointers(); virtual bool hasStaticCtorOrDtor(); - virtual void addLocalClass(ClassDeclarations *) { } virtual void addObjcSymbols(ClassDeclarations *, ClassDeclarations *) { } virtual void checkCtorConstInit() { } @@ -330,6 +330,7 @@ class Dsymbol : public ASTNode virtual OverloadSet *isOverloadSet() { return NULL; } virtual CompileDeclaration *isCompileDeclaration() { return NULL; } virtual StaticAssert *isStaticAssert() { return NULL; } + virtual StaticIfDeclaration *isStaticIfDeclaration() { return NULL; } void accept(Visitor *v) override { v->visit(this); } }; diff --git a/dmd/dsymbolsem.d b/dmd/dsymbolsem.d index 359cfcc0715..dd92286c88c 100644 --- a/dmd/dsymbolsem.d +++ b/dmd/dsymbolsem.d @@ -281,7 +281,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor alias visit = Visitor.visit; Scope* sc; - this(Scope* sc) + this(Scope* sc) scope { this.sc = sc; } @@ -327,6 +327,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor return; } + // @@@DEPRECATED_2.121@@@ + // Deprecated in 2.101 - Can be removed in 2.121 + if (ad.isClassDeclaration() || ad.isInterfaceDeclaration()) + deprecation(dsym.loc, "alias this for classes/interfaces is deprecated"); + assert(ad.members); Dsymbol s = ad.search(dsym.loc, dsym.ident); if (!s) @@ -384,6 +389,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor return; assert(dsym.semanticRun <= PASS.semantic); + if (!sc) + return; + + dsym.semanticRun = PASS.semantic; + dsym.storage_class |= sc.stc & STC.deprecated_; dsym.visibility = sc.visibility; dsym.userAttribDecl = sc.userAttribDecl; @@ -555,10 +565,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { if (inferred) { - dsym.error("type `%s` is inferred from initializer `%s`, and variables cannot be of type `void`", dsym.type.toChars(), dsym._init.toChars()); + dsym.error("- type `%s` is inferred from initializer `%s`, and variables cannot be of type `void`", dsym.type.toChars(), dsym._init.toChars()); } else - dsym.error("variables cannot be of type `void`"); + dsym.error("- variables cannot be of type `void`"); dsym.type = Type.terror; tb = dsym.type; } @@ -574,7 +584,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // or when the variable is defined externally if (!ts.sym.members && !(dsym.storage_class & (STC.ref_ | STC.extern_))) { - dsym.error("no definition of struct `%s`", ts.toChars()); + dsym.error("- no definition of struct `%s`", ts.toChars()); // Explain why the definition is required when it's part of another type if (!dsym.type.isTypeStruct()) @@ -590,7 +600,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } } if ((dsym.storage_class & STC.auto_) && !inferred) - dsym.error("storage class `auto` has no effect if type is not inferred, did you mean `scope`?"); + dsym.error("- storage class `auto` has no effect if type is not inferred, did you mean `scope`?"); if (auto tt = tb.isTypeTuple()) { @@ -735,7 +745,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor auto v2 = new TupleDeclaration(dsym.loc, dsym.ident, exps); v2.parent = dsym.parent; v2.isexp = true; - dsym.aliassym = v2; + dsym.aliasTuple = v2; dsym.semanticRun = PASS.semanticdone; return; } @@ -788,7 +798,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } else if (dsym.isMember()) { - dsym.error("field cannot be `scope`"); + error(dsym.loc, "field `%s` cannot be `scope`", dsym.toChars()); } else if (!dsym.type.hasPointers()) { @@ -826,11 +836,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor InterfaceDeclaration id = parent.isInterfaceDeclaration(); if (id) { - dsym.error("field not allowed in interface"); + error(dsym.loc, "field `%s` not allowed in interface", dsym.toChars()); } else if (aad && aad.sizeok == Sizeok.done) { - dsym.error("cannot be further field because it will change the determined %s size", aad.toChars()); + error(dsym.loc, "cannot declare field `%s` because it will change the determined size of `%s`", dsym.toChars(), aad.toChars()); } /* Templates cannot add fields to aggregates @@ -850,21 +860,37 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor AggregateDeclaration ad2 = ti.tempdecl.isMember(); if (ad2 && dsym.storage_class != STC.undefined_) { - dsym.error("cannot use template to add field to aggregate `%s`", ad2.toChars()); + dsym.error("- cannot use template to add field to aggregate `%s`", ad2.toChars()); } } } + /* If the alignment of a stack local is greater than the stack alignment, + * note it in the enclosing function's alignSectionVars + */ + version (MARS) + { + if (!dsym.alignment.isDefault() && sc.func && + dsym.alignment.get() > target.stackAlign() && + sc.func && !dsym.isDataseg() && !dsym.isParameter() && !dsym.isField()) + { + auto fd = sc.func; + if (!fd.alignSectionVars) + fd.alignSectionVars = new VarDeclarations(); + fd.alignSectionVars.push(dsym); + } + } + if ((dsym.storage_class & (STC.ref_ | STC.parameter | STC.foreach_ | STC.temp | STC.result)) == STC.ref_ && dsym.ident != Id.This) { - dsym.error("only parameters or `foreach` declarations can be `ref`"); + dsym.error("- only parameters, functions and `foreach` declarations can be `ref`"); } if (dsym.type.hasWild()) { if (dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field) || dsym.isDataseg()) { - dsym.error("only parameters or stack based variables can be `inout`"); + dsym.error("- only parameters or stack-based variables can be `inout`"); } FuncDeclaration func = sc.func; if (func) @@ -882,7 +908,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } if (!isWild) { - dsym.error("`inout` variables can only be declared inside `inout` functions"); + dsym.error("- `inout` variables can only be declared inside `inout` functions"); } } } @@ -902,7 +928,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { } else - dsym.error("default construction is disabled for type `%s`", dsym.type.toChars()); + dsym.error("- default construction is disabled for type `%s`", dsym.type.toChars()); } } @@ -957,7 +983,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (dsym._init) { } // remember we had an explicit initializer else if (dsym.storage_class & STC.manifest) - dsym.error("manifest constants must have initializers"); + dsym.error("- manifest constants must have initializers"); // Don't allow non-extern, non-__gshared variables to be interfaced with C++ if (dsym._linkage == LINK.cpp && !(dsym.storage_class & (STC.ctfe | STC.extern_ | STC.gshared)) && dsym.isDataseg()) @@ -985,7 +1011,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor //printf("Providing default initializer for '%s'\n", dsym.toChars()); if (sz == SIZE_INVALID && dsym.type.ty != Terror) - dsym.error("size of type `%s` is invalid", dsym.type.toChars()); + dsym.error("- size of type `%s` is invalid", dsym.type.toChars()); Type tv = dsym.type; while (tv.ty == Tsarray) // Don't skip Tenum @@ -1020,7 +1046,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } if (dsym.type.baseElemOf().ty == Tvoid) { - dsym.error("`%s` does not have a default initializer", dsym.type.toChars()); + dsym.error("of type `%s` does not have a default initializer", dsym.type.toChars()); } else if (auto e = dsym.type.defaultInit(dsym.loc)) { @@ -1041,7 +1067,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor dsym._init.isVoidInitializer() && !(dsym.storage_class & STC.field)) { - dsym.error("incomplete array type must have initializer"); + dsym.error("- incomplete array type must have initializer"); } ExpInitializer ei = dsym._init.isExpInitializer(); @@ -1095,9 +1121,26 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor ex = (cast(AssignExp)ex).e2; if (auto ne = ex.isNewExp()) { - // See if initializer is a NewExp that can be allocated on the stack + /* See if initializer is a NewExp that can be allocated on the stack. + */ if (dsym.type.toBasetype().ty == Tclass) { + /* Unsafe to allocate on stack if constructor is not `scope` because the `this` can leak. + * https://issues.dlang.org/show_bug.cgi?id=23145 + */ + if (ne.member && !(ne.member.storage_class & STC.scope_)) + { + if (sc.func.isSafe()) + { + // @@@DEPRECATED_2.112@@@ + deprecation(dsym.loc, + "`scope` allocation of `%s` requires that constructor be annotated with `scope`", + dsym.toChars()); + deprecationSupplemental(ne.member.loc, "is the location of the constructor"); + } + else + sc.func.setUnsafe(); + } ne.onstack = 1; dsym.onstack = true; version (IN_LLVM) @@ -1304,7 +1347,7 @@ version (IN_LLVM) if (!dsym.parent.isStructDeclaration() && !dsym.parent.isClassDeclaration()) { - dsym.error("bit-field must be member of struct, union, or class"); + dsym.error("- bit-field must be member of struct, union, or class"); } sc = sc.startCTFE(); @@ -1364,10 +1407,14 @@ version (IN_LLVM) imp.semanticRun = PASS.semantic; // Load if not already done so - bool loadErrored = false; if (!imp.mod) { - loadErrored = imp.load(sc); + // https://issues.dlang.org/show_bug.cgi?id=22857 + // if parser errors occur when loading a module + // we should just stop compilation + if (imp.load(sc)) + return; + if (imp.mod) { imp.mod.importAll(null); @@ -1408,10 +1455,7 @@ version (IN_LLVM) imp.addPackageAccess(scopesym); } - if (!loadErrored) - { - imp.mod.dsymbolSemantic(null); - } + imp.mod.dsymbolSemantic(null); if (imp.mod.needmoduleinfo) { @@ -1602,12 +1646,12 @@ version (IN_LLVM) e = se; if (!se.len) { - pd.error("zero-length string not allowed for mangled name"); + pd.error("- zero-length string not allowed for mangled name"); return null; } if (se.sz != 1) { - pd.error("mangled name characters can only be of type `char`"); + pd.error("- mangled name characters can only be of type `char`"); return null; } version (all) @@ -1845,7 +1889,7 @@ else // !IN_LLVM pd.args = new Expressions(); if (pd.args.length == 0 || pd.args.length > 2) { - pd.error(pd.args.length == 0 ? "string expected for mangled name" + pd.error(pd.args.length == 0 ? "- string expected for mangled name" : "expected 1 or 2 arguments"); pd.args.setDim(1); (*pd.args)[0] = ErrorExp.get(); // error recovery @@ -1961,7 +2005,7 @@ else // !IN_LLVM const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - scope p = new Parser!ASTCodegen(cd.loc, sc._module, str, false); + scope p = new Parser!ASTCodegen(cd.loc, sc._module, str, false, global.errorSink); p.nextToken(); auto d = p.parseDeclDefs(0); @@ -2765,7 +2809,7 @@ else // !IN_LLVM override void visit(TemplateInstance ti) { - templateInstanceSemantic(ti, sc, null); + templateInstanceSemantic(ti, sc, ArgumentList()); } override void visit(TemplateMixin tm) @@ -2803,7 +2847,7 @@ else // !IN_LLVM /* Run semantic on each argument, place results in tiargs[], * then find best match template with tiargs */ - if (!tm.findTempDecl(sc) || !tm.semanticTiargs(sc) || !tm.findBestMatch(sc, null)) + if (!tm.findTempDecl(sc) || !tm.semanticTiargs(sc) || !tm.findBestMatch(sc, ArgumentList())) { if (tm.semanticRun == PASS.initial) // forward reference had occurred { @@ -3163,7 +3207,7 @@ else // !IN_LLVM //printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration.isFinal()); if (sc.flags & SCOPE.compile) - funcdecl.isCompileTimeOnly = true; // don't emit code for this function + funcdecl.skipCodegen = true; funcdecl._linkage = sc.linkage; if (auto fld = funcdecl.isFuncLiteralDeclaration()) @@ -4218,9 +4262,8 @@ version (IN_LLVM) else if (dim == 0 && tf.parameterList.varargs != VarArg.none) // allow varargs only ctor { } - else if (dim && tf.parameterList[0].defaultArg) + else if (dim && !tf.parameterList.hasArgsWithoutDefault) { - // if the first parameter has a default argument, then the rest does as well if (ctd.storage_class & STC.disable) { ctd.error("is marked `@disable`, so it cannot have default "~ @@ -4288,8 +4331,8 @@ version (IN_LLVM) override void visit(DtorDeclaration dd) { - //printf("DtorDeclaration::semantic() %s\n", toChars()); - //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id.dtor.toChars(), ident, Id.dtor); + //printf("DtorDeclaration::semantic() %s\n", dd.toChars()); + //printf("ident: %s, %s, %p, %p\n", dd.ident.toChars(), Id.dtor.toChars(), dd.ident, Id.dtor); if (dd.semanticRun >= PASS.semanticdone) return; if (dd._scope) @@ -4651,7 +4694,8 @@ version (IN_LLVM) override void visit(StructDeclaration sd) { - //printf("StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok); + enum log = false; + if (log) printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok); //static int count; if (++count == 20) assert(0); @@ -4721,6 +4765,7 @@ version (IN_LLVM) if (!sd.members) // if opaque declaration { + if (log) printf("\topaque declaration %s\n", sd.toChars()); sd.semanticRun = PASS.semanticdone; return; } @@ -4772,7 +4817,7 @@ version (IN_LLVM) sc2.pop(); - //printf("\tdeferring %s\n", toChars()); + if (log) printf("\tdeferring %s\n", sd.toChars()); return deferDsymbolSemantic(sd, scx); } @@ -4802,7 +4847,7 @@ version (IN_LLVM) sd.inv = buildInv(sd, sc2); sd.semanticRun = PASS.semanticdone; - //printf("-StructDeclaration::semantic(this=%p, '%s')\n", sd, sd.toChars()); + if (log) printf("-StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok); sc2.pop(); @@ -4815,7 +4860,7 @@ version (IN_LLVM) sc = sc.push(); sc.tinst = null; sc.minst = null; - auto fcall = resolveFuncCall(sd.loc, sc, scall, null, null, null, FuncResolveFlag.quiet); + auto fcall = resolveFuncCall(sd.loc, sc, scall, null, null, ArgumentList(), FuncResolveFlag.quiet); sc = sc.pop(); global.endGagging(xerrors); @@ -4869,6 +4914,7 @@ version (IN_LLVM) // Make an error in 2.110 if (sd.storage_class & STC.scope_) deprecation(sd.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + //printf("-StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok); } void interfaceSemantic(ClassDeclaration cd) @@ -5414,9 +5460,9 @@ version (IN_LLVM) // this() { } if (!cldec.ctor && cldec.baseClass && cldec.baseClass.ctor) { - auto fd = resolveFuncCall(cldec.loc, sc2, cldec.baseClass.ctor, null, cldec.type, null, FuncResolveFlag.quiet); + auto fd = resolveFuncCall(cldec.loc, sc2, cldec.baseClass.ctor, null, cldec.type, ArgumentList(), FuncResolveFlag.quiet); if (!fd) // try shared base ctor instead - fd = resolveFuncCall(cldec.loc, sc2, cldec.baseClass.ctor, null, cldec.type.sharedOf, null, FuncResolveFlag.quiet); + fd = resolveFuncCall(cldec.loc, sc2, cldec.baseClass.ctor, null, cldec.type.sharedOf, ArgumentList(), FuncResolveFlag.quiet); if (fd && !fd.errors) { //printf("Creating default this(){} for class %s\n", toChars()); @@ -5428,7 +5474,7 @@ version (IN_LLVM) // is less strict (e.g. `preview=dtorfields` might introduce a call to a less qualified dtor) auto ctor = new CtorDeclaration(cldec.loc, Loc.initial, 0, tf); - ctor.storage_class |= STC.inference; + ctor.storage_class |= STC.inference | (fd.storage_class & STC.scope_); ctor.isGenerated = true; ctor.fbody = new CompoundStatement(Loc.initial, new Statements()); @@ -5893,7 +5939,7 @@ void addEnumMembers(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds) }); } -void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* fargs) +void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList argumentList) { //printf("[%s] TemplateInstance.dsymbolSemantic('%s', this=%p, gag = %d, sc = %p)\n", tempinst.loc.toChars(), tempinst.toChars(), tempinst, global.gag, sc); version (none) @@ -5965,7 +6011,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* * then run semantic on each argument (place results in tiargs[]), * last find most specialized template from overload list/set. */ - if (!tempinst.findTempDecl(sc, null) || !tempinst.semanticTiargs(sc) || !tempinst.findBestMatch(sc, fargs)) + if (!tempinst.findTempDecl(sc, null) || !tempinst.semanticTiargs(sc) || !tempinst.findBestMatch(sc, argumentList)) { Lerror: if (tempinst.gagged) @@ -6018,6 +6064,8 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* return aliasInstanceSemantic(tempinst, sc, tempdecl); } + Expressions* fargs = argumentList.arguments; // TODO: resolve named args + /* See if there is an existing TemplateInstantiation that already * implements the typeargs. If so, just refer to that one instead. */ @@ -6108,7 +6156,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* alias visit = Visitor.visit; TemplateInstance inst; - extern (D) this(TemplateInstance inst) + extern (D) this(TemplateInstance inst) scope { this.inst = inst; } @@ -6271,7 +6319,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* Dsymbol s; if (Dsymbol.oneMembers(tempinst.members, &s, tempdecl.ident) && s) { - //printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars()); + //printf("tempdecl.ident = %s, s = `%s %s`\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars()); //printf("setting aliasdecl\n"); tempinst.aliasdecl = s; version (IN_LLVM) @@ -6328,7 +6376,7 @@ version (IN_LLVM) { if (!tempinst.aliasdecl || tempinst.aliasdecl != s) { - //printf("tempdecl.ident = %s, s = '%s'\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars()); + //printf("tempdecl.ident = %s, s = `%s %s`\n", tempdecl.ident.toChars(), s.kind(), s.toPrettyChars()); //printf("setting aliasdecl 2\n"); tempinst.aliasdecl = s; } @@ -7161,12 +7209,10 @@ bool determineFields(AggregateDeclaration ad) if (ad.sizeok != Sizeok.none) return 1; - if (v.aliassym) + if (v.aliasTuple) { // If this variable was really a tuple, process each element. - if (auto tup = v.aliassym.isTupleDeclaration()) - return tup.foreachVar(tv => tv.apply(&func, ad)); - return 0; + return v.aliasTuple.foreachVar(tv => tv.apply(&func, ad)); } if (v.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.ctfe | STC.templateparameter)) diff --git a/dmd/dtemplate.d b/dmd/dtemplate.d index d1c8c597efd..8d173673cf4 100644 --- a/dmd/dtemplate.d +++ b/dmd/dtemplate.d @@ -45,6 +45,7 @@ import dmd.aliasthis; import dmd.arraytypes; import dmd.astenums; import dmd.ast_node; +import dmd.attrib; import dmd.dcast; import dmd.dclass; import dmd.declaration; @@ -1066,7 +1067,7 @@ else * dedtypes deduced arguments * Return match level. */ - extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, Expressions* fargs, int flag) + extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, ArgumentList argumentList, int flag) { enum LOGM = 0; static if (LOGM) @@ -1184,6 +1185,12 @@ else if (fd) { TypeFunction tf = fd.type.isTypeFunction().syntaxCopy(); + if (argumentList.hasNames) + return nomatch(); + Expressions* fargs = argumentList.arguments; + // TODO: Expressions* fargs = tf.resolveNamedArgs(argumentList, null); + // if (!fargs) + // return nomatch(); fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf); fd.parent = ti; @@ -1242,7 +1249,7 @@ else paramscope.pop(); static if (LOGM) { - printf("-TemplateDeclaration.matchWithInstance(this = %p, ti = %p) = %d\n", this, ti, m); + printf("-TemplateDeclaration.matchWithInstance(this = %s, ti = %s) = %d\n", toChars(), ti.toChars(), m); } return m; } @@ -1253,7 +1260,7 @@ else * match this is at least as specialized as td2 * 0 td2 is more specialized than this */ - MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td2, Expressions* fargs) + MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration td2, ArgumentList argumentList) { enum LOG_LEASTAS = 0; static if (LOG_LEASTAS) @@ -1288,7 +1295,7 @@ else Objects dedtypes = Objects(td2.parameters.length); // Attempt a type deduction - MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, fargs, 1); + MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, argumentList, 1); if (m > MATCH.nomatch) { /* A non-variadic template is more specialized than a @@ -1319,14 +1326,14 @@ else * sc instantiation scope * fd * tthis 'this' argument if !NULL - * fargs arguments to function + * argumentList arguments to function * Output: * fd Partially instantiated function declaration * ti.tdtypes Expression/Type deduced template arguments * Returns: * match pair of initial and inferred template arguments */ - extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, Expressions* fargs) + extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateInstance ti, Scope* sc, ref FuncDeclaration fd, Type tthis, ArgumentList argumentList) { size_t nfparams; size_t nfargs; @@ -1350,7 +1357,7 @@ else for (size_t i = 0; i < (fargs ? fargs.length : 0); i++) { Expression e = (*fargs)[i]; - printf("\tfarg[%d] is %s, type is %s\n", i, e.toChars(), e.type.toChars()); + printf("\tfarg[%d] is %s, type is %s\n", cast(int) i, e.toChars(), e.type.toChars()); } printf("fd = %s\n", fd.toChars()); printf("fd.type = %s\n", fd.type.toChars()); @@ -1474,7 +1481,10 @@ else fparameters = fd.getParameterList(); nfparams = fparameters.length; // number of function parameters - nfargs = fargs ? fargs.length : 0; // number of function arguments + nfargs = argumentList.length; // number of function arguments + if (argumentList.hasNames) + return matcherror(); // TODO: resolve named args + Expressions* fargs = argumentList.arguments; // TODO: resolve named args /* Check for match of function arguments with variadic template * parameter, such as: @@ -2609,13 +2619,12 @@ extern (C++) final class TypeDeduced : Type * sc = instantiation scope * tiargs = initial list of template arguments * tthis = if !NULL, the 'this' pointer argument - * fargs = arguments to function + * argumentList= arguments to function * pMessage = address to store error message, or null */ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs, - Type tthis, Expressions* fargs, const(char)** pMessage = null) + Type tthis, ArgumentList argumentList, const(char)** pMessage = null) { - Expression[] fargs_ = fargs.peekSlice(); version (none) { printf("functionResolve() dstart = %s\n", dstart.toChars()); @@ -2720,7 +2729,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, else if (shared_this && !shared_dtor && tthis_fd !is null) tf.mod = tthis_fd.mod; } - MATCH mfa = tf.callMatch(tthis_fd, fargs_, 0, pMessage, sc); + MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, pMessage, sc); //printf("test1: mfa = %d\n", mfa); if (mfa == MATCH.nomatch) return 0; @@ -2753,8 +2762,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, * This is because f() is "more specialized." */ { - MATCH c1 = fd.leastAsSpecialized(m.lastf); - MATCH c2 = m.lastf.leastAsSpecialized(fd); + MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names); + MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names); //printf("c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) return firstIsBetter(); if (c1 < c2) return 0; @@ -2846,6 +2855,11 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, } //printf("td = %s\n", td.toChars()); + if (argumentList.hasNames) + { + .error(loc, "named arguments with Implicit Function Template Instantiation are not supported yet"); + goto Lerror; + } auto f = td.onemember ? td.onemember.isFuncDeclaration() : null; if (!f) { @@ -2854,12 +2868,12 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, auto ti = new TemplateInstance(loc, td, tiargs); Objects dedtypes = Objects(td.parameters.length); assert(td.semanticRun != PASS.initial); - MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, fargs, 0); + MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, argumentList, 0); //printf("matchWithInstance = %d\n", mta); if (mta == MATCH.nomatch || mta < ta_last) // no match or less match return 0; - ti.templateInstanceSemantic(sc, fargs); + ti.templateInstanceSemantic(sc, argumentList); if (!ti.inst) // if template failed to expand return 0; @@ -2898,13 +2912,13 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, pr.dedargs = &dedtypesX; tdx.previous = ≺ // add this to threaded list - fd = resolveFuncCall(loc, sc, s, null, tthis, fargs, FuncResolveFlag.quiet); + fd = resolveFuncCall(loc, sc, s, null, tthis, argumentList, FuncResolveFlag.quiet); tdx.previous = pr.prev; // unlink from threaded list } else if (s.isFuncDeclaration()) { - fd = resolveFuncCall(loc, sc, s, null, tthis, fargs, FuncResolveFlag.quiet); + fd = resolveFuncCall(loc, sc, s, null, tthis, argumentList, FuncResolveFlag.quiet); } else goto Lerror; @@ -2923,7 +2937,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null; auto tf = cast(TypeFunction)fd.type; - MATCH mfa = tf.callMatch(tthis_fd, fargs_, 0, null, sc); + MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, null, sc); if (mfa < m.last) return 0; @@ -2970,7 +2984,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, ti.parent = td.parent; // Maybe calculating valid 'enclosing' is unnecessary. auto fd = f; - MATCHpair x = td.deduceFunctionTemplateMatch(ti, sc, fd, tthis, fargs); + MATCHpair x = td.deduceFunctionTemplateMatch(ti, sc, fd, tthis, argumentList); MATCH mta = x.mta; MATCH mfa = x.mfa; //printf("match:t/f = %d/%d\n", mta, mfa); @@ -3014,8 +3028,8 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, if (td_best) { // Disambiguate by picking the most specialized TemplateDeclaration - MATCH c1 = td.leastAsSpecialized(sc, td_best, fargs); - MATCH c2 = td_best.leastAsSpecialized(sc, td, fargs); + MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList); + MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList); //printf("1: c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; @@ -3025,16 +3039,16 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, // Disambiguate by tf.callMatch auto tf1 = fd.type.isTypeFunction(); auto tf2 = m.lastf.type.isTypeFunction(); - MATCH c1 = tf1.callMatch(tthis_fd, fargs_, 0, null, sc); - MATCH c2 = tf2.callMatch(tthis_best, fargs_, 0, null, sc); + MATCH c1 = tf1.callMatch(tthis_fd, argumentList, 0, null, sc); + MATCH c2 = tf2.callMatch(tthis_best, argumentList, 0, null, sc); //printf("2: c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; } { // Disambiguate by picking the most specialized FunctionDeclaration - MATCH c1 = fd.leastAsSpecialized(m.lastf); - MATCH c2 = m.lastf.leastAsSpecialized(fd); + MATCH c1 = fd.leastAsSpecialized(m.lastf, argumentList.names); + MATCH c2 = m.lastf.leastAsSpecialized(fd, argumentList.names); //printf("3: c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; @@ -3101,7 +3115,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, sc = td_best._scope; // workaround for Type.aliasthisOf auto ti = new TemplateInstance(loc, td_best, ti_best.tiargs); - ti.templateInstanceSemantic(sc, fargs); + ti.templateInstanceSemantic(sc, argumentList); m.lastf = ti.toAlias().isFuncDeclaration(); if (!m.lastf) @@ -3129,7 +3143,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, if (m.lastf.type.ty == Terror) goto Lerror; auto tf = m.lastf.type.isTypeFunction(); - if (!tf.callMatch(tthis_best, fargs_, 0, null, sc)) + if (!tf.callMatch(tthis_best, argumentList, 0, null, sc)) goto Lnomatch; /* As https://issues.dlang.org/show_bug.cgi?id=3682 shows, @@ -5912,7 +5926,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol } } - extern (D) this(const ref Loc loc, Identifier ident, Objects* tiargs) + extern (D) this(const ref Loc loc, Identifier ident, Objects* tiargs) scope { super(loc, null); static if (LOG) @@ -5927,7 +5941,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol * This constructor is only called when we figured out which function * template to instantiate. */ - extern (D) this(const ref Loc loc, TemplateDeclaration td, Objects* tiargs) + extern (D) this(const ref Loc loc, TemplateDeclaration td, Objects* tiargs) scope { super(loc, null); static if (LOG) @@ -6035,7 +6049,10 @@ extern (C++) class TemplateInstance : ScopeDsymbol return; // Print full trace for verbose mode, otherwise only short traces - const(uint) max_shown = !global.params.verbose ? 6 : uint.max; + const(uint) max_shown = !global.params.verbose ? + (global.params.errorSupplementLimit ? global.params.errorSupplementLimit : uint.max) + : uint.max; + const(char)* format = "instantiated from here: `%s`"; // This returns a function pointer @@ -6277,13 +6294,14 @@ version (IN_LLVM) assert(global.params.linkonceTemplates != LinkonceTemplates.aggressive); } + //printf("needsCodegen() %s\n", toChars()); + // minst is finalized after the 1st invocation. - // tnext and tinst are only needed for the 1st invocation and + // tnext is only needed for the 1st invocation and // cleared for further invocations. TemplateInstance tnext = this.tnext; TemplateInstance tinst = this.tinst; this.tnext = null; - this.tinst = null; // Don't do codegen if the instance has errors, // is a dummy instance (see evaluateConstraint), @@ -6619,7 +6637,17 @@ version (IN_LLVM) } TemplateInstance ti = s.parent ? s.parent.isTemplateInstance() : null; - if (ti && (ti.name == s.ident || ti.toAlias().ident == s.ident) && ti.tempdecl) + + /* This avoids the VarDeclaration.toAlias() which runs semantic() too soon + */ + static bool matchId(TemplateInstance ti, Identifier id) + { + if (ti.aliasdecl && ti.aliasdecl.isVarDeclaration()) + return ti.aliasdecl.isVarDeclaration().ident == id; + return ti.toAlias().ident == id; + } + + if (ti && (ti.name == s.ident || matchId(ti, s.ident)) && ti.tempdecl) { /* This is so that one can refer to the enclosing * template, even if it has the same name as a member @@ -6938,12 +6966,12 @@ version (IN_LLVM) * * Params: * sc = the scope this TemplateInstance resides in - * fargs = function arguments in case of a template function, null otherwise + * argumentList = function arguments in case of a template function * * Returns: * `true` if a match was found, `false` otherwise */ - extern (D) final bool findBestMatch(Scope* sc, Expressions* fargs) + extern (D) final bool findBestMatch(Scope* sc, ArgumentList argumentList) { if (havetempdecl) { @@ -6952,7 +6980,7 @@ version (IN_LLVM) assert(tempdecl._scope); // Deduce tdtypes tdtypes.setDim(tempdecl.parameters.length); - if (!tempdecl.matchWithInstance(sc, this, &tdtypes, fargs, 2)) + if (!tempdecl.matchWithInstance(sc, this, &tdtypes, argumentList, 2)) { error("incompatible arguments for template instantiation"); return false; @@ -7002,7 +7030,7 @@ version (IN_LLVM) dedtypes.zero(); assert(td.semanticRun != PASS.initial); - MATCH m = td.matchWithInstance(sc, this, &dedtypes, fargs, 0); + MATCH m = td.matchWithInstance(sc, this, &dedtypes, argumentList, 0); //printf("matchWithInstance = %d\n", m); if (m == MATCH.nomatch) // no match at all return 0; @@ -7011,8 +7039,8 @@ version (IN_LLVM) // Disambiguate by picking the most specialized TemplateDeclaration { - MATCH c1 = td.leastAsSpecialized(sc, td_best, fargs); - MATCH c2 = td_best.leastAsSpecialized(sc, td, fargs); + MATCH c1 = td.leastAsSpecialized(sc, td_best, argumentList); + MATCH c2 = td_best.leastAsSpecialized(sc, td, argumentList); //printf("c1 = %d, c2 = %d\n", c1, c2); if (c1 > c2) goto Ltd; if (c1 < c2) goto Ltd_best; @@ -7278,7 +7306,7 @@ version (IN_LLVM) return 1; } } - MATCH m = td.matchWithInstance(sc, this, &dedtypes, null, 0); + MATCH m = td.matchWithInstance(sc, this, &dedtypes, ArgumentList(), 0); if (m == MATCH.nomatch) return 0; } @@ -7554,6 +7582,43 @@ version (IN_LLVM) members.foreachDsymbol( (s) { s.importAll(sc2); } ); + if (!aliasdecl) + { + /* static if's are crucial to evaluating aliasdecl correctly. But + * evaluating the if/else bodies may require aliasdecl. + * So, evaluate the condition for static if's, but not their if/else bodies. + * Then try to set aliasdecl. + * Later do the if/else bodies. + * https://issues.dlang.org/show_bug.cgi?id=23598 + * It might be better to do this by attaching a lambda to the StaticIfDeclaration + * to do the oneMembers call after the sid.include(sc2) is run as part of dsymbolSemantic(). + */ + bool done; + void staticIfDg(Dsymbol s) + { + if (done || aliasdecl) + return; + //printf("\t staticIfDg on '%s %s' in '%s'\n", s.kind(), s.toChars(), this.toChars()); + if (!s.isStaticIfDeclaration()) + { + //s.dsymbolSemantic(sc2); + done = true; + return; + } + auto sid = s.isStaticIfDeclaration(); + sid.include(sc2); + if (members.length) + { + Dsymbol sa; + if (Dsymbol.oneMembers(members, &sa, tempdecl.ident) && sa) + aliasdecl = sa; + } + done = true; + } + + members.foreachDsymbol(&staticIfDg); + } + void symbolDg(Dsymbol s) { //printf("\t semantic on '%s' %p kind %s in '%s'\n", s.toChars(), s, s.kind(), this.toChars()); diff --git a/dmd/dtoh.d b/dmd/dtoh.d index 30ca3d1f8c6..7c3ff4bccc2 100644 --- a/dmd/dtoh.d +++ b/dmd/dtoh.d @@ -291,9 +291,23 @@ public: /// Informations about the current context in the AST Context context; - alias context this; - this(OutBuffer* fwdbuf, OutBuffer* donebuf, OutBuffer* buf) + // Generates getter-setter methods to replace the use of alias this + // This should be replaced by a `static foreach` once the gdc tester + // gets upgraded to version 10 (to support `static foreach`). + private extern(D) static string generateMembers() + { + string result = ""; + foreach(member; __traits(allMembers, Context)) + { + result ~= "ref auto " ~ member ~ "() { return context." ~ member ~ "; }\n"; + } + return result; + } + + mixin(generateMembers()); + + this(OutBuffer* fwdbuf, OutBuffer* donebuf, OutBuffer* buf) scope { this.fwdbuf = fwdbuf; this.donebuf = donebuf; @@ -875,7 +889,7 @@ public: // (we'll visit them later) if (vd.type && vd.type.isTypeTuple()) { - assert(vd.aliassym); + assert(vd.aliasTuple); vd.toAlias().accept(this); return; } diff --git a/dmd/errors.d b/dmd/errors.d index 9265ded030b..05b884c280e 100644 --- a/dmd/errors.d +++ b/dmd/errors.d @@ -15,6 +15,7 @@ import core.stdc.stdarg; import core.stdc.stdio; import core.stdc.stdlib; import core.stdc.string; +import dmd.errorsink; import dmd.globals; import dmd.location; import dmd.common.outbuffer; @@ -24,6 +25,57 @@ import dmd.console; nothrow: +/*************************** + * Error message sink for D compiler. + */ +class ErrorSinkCompiler : ErrorSink +{ + nothrow: + extern (C++): + override: + + void error(const ref Loc loc, const(char)* format, ...) + { + va_list ap; + va_start(ap, format); + verror(loc, format, ap); + va_end(ap); + } + + void errorSupplemental(const ref Loc loc, const(char)* format, ...) + { + va_list ap; + va_start(ap, format); + verrorSupplemental(loc, format, ap); + va_end(ap); + } + + void warning(const ref Loc loc, const(char)* format, ...) + { + va_list ap; + va_start(ap, format); + vwarning(loc, format, ap); + va_end(ap); + } + + void deprecation(const ref Loc loc, const(char)* format, ...) + { + va_list ap; + va_start(ap, format); + vdeprecation(loc, format, ap); + va_end(ap); + } + + void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) + { + va_list ap; + va_start(ap, format); + vdeprecationSupplemental(loc, format, ap); + va_end(ap); + } +} + + /** * Color highlighting to classify messages */ @@ -381,7 +433,7 @@ private void verrorPrint(const ref Loc loc, Color headerColor, const(char)* head fputs(tmp.peekChars(), stderr); fputc('\n', stderr); - static Loc old_loc; + __gshared Loc old_loc; if (global.params.printErrorContext && // ignore supplemental messages with same loc (loc != old_loc || strchr(header, ':')) && @@ -768,7 +820,7 @@ private void colorHighlightCode(ref OutBuffer buf) ++nested; auto gaggedErrorsSave = global.startGagging(); - scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1, global.vendor, global.versionNumber()); + scope Lexer lex = new Lexer(null, cast(char*)buf[].ptr, 0, buf.length - 1, 0, 1, global.errorSink, global.vendor, global.versionNumber()); OutBuffer res; const(char)* lastp = cast(char*)buf[].ptr; //printf("colorHighlightCode('%.*s')\n", cast(int)(buf.length - 1), buf[].ptr); diff --git a/dmd/errorsink.d b/dmd/errorsink.d new file mode 100644 index 00000000000..b519db7e9bc --- /dev/null +++ b/dmd/errorsink.d @@ -0,0 +1,121 @@ +/** + * Provides an abstraction for what to do with error messages. + * + * Copyright: Copyright (C) 2023 by The D Language Foundation, All Rights Reserved + * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) + * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/errorsink.d, _errorsink.d) + * Documentation: https://dlang.org/phobos/dmd_errorsink.html + * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/errorsink.d + */ + +module dmd.errorsink; + +import dmd.location; + +/*************************************** + * Where error/warning/deprecation messages go. + */ +abstract class ErrorSink +{ + nothrow: + extern (C++): + + void error(const ref Loc loc, const(char)* format, ...); + + void errorSupplemental(const ref Loc loc, const(char)* format, ...); + + void warning(const ref Loc loc, const(char)* format, ...); + + void deprecation(const ref Loc loc, const(char)* format, ...); + + void deprecationSupplemental(const ref Loc loc, const(char)* format, ...); +} + +/***************************************** + * Just ignores the messages. + */ +class ErrorSinkNull : ErrorSink +{ + nothrow: + extern (C++): + override: + + void error(const ref Loc loc, const(char)* format, ...) { } + + void errorSupplemental(const ref Loc loc, const(char)* format, ...) { } + + void warning(const ref Loc loc, const(char)* format, ...) { } + + void deprecation(const ref Loc loc, const(char)* format, ...) { } + + void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { } +} + +/***************************************** + * Simplest implementation, just sends messages to stderr. + */ +class ErrorSinkStderr : ErrorSink +{ + import core.stdc.stdio; + import core.stdc.stdarg; + + nothrow: + extern (C++): + override: + + void error(const ref Loc loc, const(char)* format, ...) + { + fputs("Error: ", stderr); + const p = loc.toChars(); + if (*p) + { + fprintf(stderr, "%s: ", p); + //mem.xfree(cast(void*)p); // loc should provide the free() + } + + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + fputc('\n', stderr); + va_end(ap); + } + + void errorSupplemental(const ref Loc loc, const(char)* format, ...) { } + + void warning(const ref Loc loc, const(char)* format, ...) + { + fputs("Warning: ", stderr); + const p = loc.toChars(); + if (*p) + { + fprintf(stderr, "%s: ", p); + //mem.xfree(cast(void*)p); // loc should provide the free() + } + + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + fputc('\n', stderr); + va_end(ap); + } + + void deprecation(const ref Loc loc, const(char)* format, ...) + { + fputs("Deprecation: ", stderr); + const p = loc.toChars(); + if (*p) + { + fprintf(stderr, "%s: ", p); + //mem.xfree(cast(void*)p); // loc should provide the free() + } + + va_list ap; + va_start(ap, format); + vfprintf(stderr, format, ap); + fputc('\n', stderr); + va_end(ap); + } + + void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { } +} diff --git a/dmd/escape.d b/dmd/escape.d index 7bc018e1e32..420fa7f80bb 100644 --- a/dmd/escape.d +++ b/dmd/escape.d @@ -181,7 +181,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf, if (!(eb.isMutable || eb2.isMutable)) return; - if (!(global.params.useDIP1000 == FeatureState.enabled && sc.setUnsafe())) + if (!tf.islive && !(global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe())) return; if (!gag) @@ -558,6 +558,46 @@ bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag) return false; } +/// How a `return` parameter escapes its pointer value +enum ReturnParamDest +{ + returnVal, /// through return statement: `return x` + this_, /// assigned to a struct instance: `this.x = x` + firstArg, /// assigned to first argument: `firstArg = x` +} + +/**************************************** + * Find out if instead of returning a `return` parameter via a return statement, + * it is returned via assignment to either `this` or the first parameter. + * + * This works the same as returning the value via a return statement. + * Although the first argument must be `ref`, it is not regarded as returning by `ref`. + * + * See_Also: https://dlang.org.spec/function.html#return-ref-parameters + * + * Params: + * tf = function type + * tthis = type of `this` parameter, or `null` if none + * Returns: What a `return` parameter should transfer the lifetime of the argument to + */ +ReturnParamDest returnParamDest(TypeFunction tf, Type tthis) +{ + assert(tf); + if (tf.isctor) + return ReturnParamDest.this_; + + if (!tf.nextOf() || (tf.nextOf().ty != Tvoid)) + return ReturnParamDest.returnVal; + + if (tthis && tthis.toBasetype().ty == Tstruct) // class `this` is passed by value + return ReturnParamDest.this_; + + if (tf.parameterList.length > 0 && tf.parameterList[0].isReference) + return ReturnParamDest.firstArg; + + return ReturnParamDest.returnVal; +} + /**************************************** * Given an `AssignExp`, determine if the lvalue will cause * the contents of the rvalue to escape. @@ -608,6 +648,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) if (e1.isStructLiteralExp()) return false; + VarDeclaration va = expToVariable(e1); EscapeByResults er; if (byRef) @@ -618,7 +659,6 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) if (!er.byref.length && !er.byvalue.length && !er.byfunc.length && !er.byexp.length) return false; - VarDeclaration va = expToVariable(e1); if (va && e.op == EXP.concatenateElemAssign) { @@ -653,30 +693,23 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef) const bool vaIsRef = va && va.isParameter() && va.isReference(); if (log && vaIsRef) printf("va is ref `%s`\n", va.toChars()); - /* Determine if va is the first parameter, through which other 'return' parameters - * can be assigned. - * This works the same as returning the value via a return statement. - * Although va is marked as `ref`, it is not regarded as returning by `ref`. - * https://dlang.org.spec/function.html#return-ref-parameters - */ - bool isFirstRef() + // Determine if va is the first parameter, through which other 'return' parameters + // can be assigned. + bool vaIsFirstRef = false; + if (fd && fd.type) { - if (!vaIsRef) - return false; - Dsymbol p = va.toParent2(); - if (p == fd && fd.type && fd.type.isTypeFunction()) + final switch (returnParamDest(fd.type.isTypeFunction(), fd.vthis ? fd.vthis.type : null)) { - TypeFunction tf = fd.type.isTypeFunction(); - if (!tf.nextOf() || (tf.nextOf().ty != Tvoid && !fd.isCtorDeclaration())) - return false; - if (va == fd.vthis) // `this` of a non-static member function is considered to be the first parameter - return true; - if (!fd.vthis && fd.parameters && fd.parameters.length && (*fd.parameters)[0] == va) // va is first parameter - return true; + case ReturnParamDest.this_: + vaIsFirstRef = va == fd.vthis; + break; + case ReturnParamDest.firstArg: + vaIsFirstRef = (*fd.parameters)[0] == va; + break; + case ReturnParamDest.returnVal: + break; } - return false; } - const bool vaIsFirstRef = isFirstRef(); if (log && vaIsFirstRef) printf("va is first ref `%s`\n", va.toChars()); bool result = false; @@ -1745,7 +1778,25 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re const stc = tf.parameterStorageClass(null, p); ScopeRef psr = buildScopeRef(stc); if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) - escapeByValue(arg, er, live, retRefTransition); + { + if (tf.isref) + { + /* ignore `ref` on struct constructor return because + * struct S { this(return scope int* q) { this.p = q; } int* p; } + * is different from: + * ref char* front(return scope char** q) { return *q; } + * https://github.com/dlang/dmd/pull/14869 + */ + if (auto dve = e.e1.isDotVarExp()) + if (auto fd = dve.var.isFuncDeclaration()) + if (fd.isCtorDeclaration() && tf.next.toBasetype().isTypeStruct()) + { + escapeByValue(arg, er, live, retRefTransition); + } + } + else + escapeByValue(arg, er, live, retRefTransition); + } else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) { if (tf.isref) @@ -1768,68 +1819,55 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re { DotVarExp dve = e.e1.isDotVarExp(); FuncDeclaration fd = dve.var.isFuncDeclaration(); - if (1) + if (fd && fd.isThis()) { - if (fd && fd.isThis()) + /* Calling a non-static member function dve.var, which is returning `this`, and with dve.e1 representing `this` + */ + + /***************************** + * Concoct storage class for member function's implicit `this` parameter. + * Params: + * fd = member function + * Returns: + * storage class for fd's `this` + */ + StorageClass getThisStorageClass(FuncDeclaration fd) { - /* Calling a non-static member function dve.var, which is returning `this`, and with dve.e1 representing `this` - */ - - /***************************** - * Concoct storage class for member function's implicit `this` parameter. - * Params: - * fd = member function - * Returns: - * storage class for fd's `this` - */ - StorageClass getThisStorageClass(FuncDeclaration fd) - { - StorageClass stc; - auto tf = fd.type.toBasetype().isTypeFunction(); - if (tf.isreturn) - stc |= STC.return_; - if (tf.isreturnscope) - stc |= STC.returnScope | STC.scope_; - auto ad = fd.isThis(); - if (ad.isClassDeclaration() || tf.isScopeQual) - stc |= STC.scope_; - if (ad.isStructDeclaration()) - stc |= STC.ref_; // `this` for a struct member function is passed by `ref` - return stc; - } + StorageClass stc; + auto tf = fd.type.toBasetype().isTypeFunction(); + if (tf.isreturn) + stc |= STC.return_; + if (tf.isreturnscope) + stc |= STC.returnScope | STC.scope_; + auto ad = fd.isThis(); + if (ad.isClassDeclaration() || tf.isScopeQual) + stc |= STC.scope_; + if (ad.isStructDeclaration()) + stc |= STC.ref_; // `this` for a struct member function is passed by `ref` + return stc; + } - const psr = buildScopeRef(getThisStorageClass(fd)); - if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) + const psr = buildScopeRef(getThisStorageClass(fd)); + if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) + { + if (!tf.isref || tf.isctor) escapeByValue(dve.e1, er, live, retRefTransition); - else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) + } + else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) + { + if (tf.isref) { - if (tf.isref) - { - /* Treat calling: - * struct S { ref S foo() return; } - * as: - * this; - */ - escapeByValue(dve.e1, er, live, retRefTransition); - } - else - escapeByRef(dve.e1, er, live, psr == ScopeRef.ReturnRef_Scope); + /* Treat calling: + * struct S { ref S foo() return; } + * as: + * this; + */ + escapeByValue(dve.e1, er, live, retRefTransition); } + else + escapeByRef(dve.e1, er, live, psr == ScopeRef.ReturnRef_Scope); } } - else - { - // Calling member function before dip1000 - StorageClass stc = dve.var.storage_class & (STC.return_ | STC.scope_ | STC.ref_); - if (tf.isreturn) - stc |= STC.return_; - - const psr = buildScopeRef(stc); - if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) - escapeByValue(dve.e1, er, live, retRefTransition); - else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) - escapeByRef(dve.e1, er, live, retRefTransition); - } // If it's also a nested function that is 'return scope' if (fd && fd.isNested()) diff --git a/dmd/expression.d b/dmd/expression.d index e0c4493ac0c..b27afc7f42b 100644 --- a/dmd/expression.d +++ b/dmd/expression.d @@ -249,18 +249,55 @@ bool isDotOpDispatch(Expression e) } /**************************************** - * Expand tuples. - * Input: - * exps aray of Expressions - * Output: - * exps rewritten in place + * Expand tuples in-place. + * + * Example: + * When there's a call `f(10, pair: AliasSeq!(20, 30), single: 40)`, the input is: + * `exps = [10, (20, 30), 40]` + * `names = [null, "pair", "single"]` + * The arrays will be modified to: + * `exps = [10, 20, 30, 40]` + * `names = [null, "pair", null, "single"]` + * + * Params: + * exps = array of Expressions + * names = optional array of names corresponding to Expressions */ -extern (C++) void expandTuples(Expressions* exps) +extern (C++) void expandTuples(Expressions* exps, Identifiers* names = null) { //printf("expandTuples()\n"); if (exps is null) return; + if (names) + { + if (exps.length != names.length) + { + printf("exps.length = %d, names.length = %d\n", cast(int) exps.length, cast(int) names.length); + printf("exps = %s, names = %s\n", exps.toChars(), names.toChars()); + if (exps.length > 0) + printf("%s\n", (*exps)[0].loc.toChars()); + assert(0); + } + } + + // At `index`, a tuple of length `length` is expanded. Insert corresponding nulls in `names`. + void expandNames(size_t index, size_t length) + { + if (names) + { + if (length == 0) + { + names.remove(index); + return; + } + foreach (i; 1 .. length) + { + names.insert(index + i, cast(Identifier) null); + } + } + } + for (size_t i = 0; i < exps.length; i++) { Expression arg = (*exps)[i]; @@ -275,6 +312,7 @@ extern (C++) void expandTuples(Expressions* exps) if (!tt.arguments || tt.arguments.length == 0) { exps.remove(i); + expandNames(i, 0); if (i == exps.length) return; } @@ -285,6 +323,7 @@ extern (C++) void expandTuples(Expressions* exps) foreach (j, a; *tt.arguments) (*texps)[j] = new TypeExp(e.loc, a.type); exps.insert(i, texps); + expandNames(i, texps.length); } i--; continue; @@ -297,6 +336,7 @@ extern (C++) void expandTuples(Expressions* exps) TupleExp te = cast(TupleExp)arg; exps.remove(i); // remove arg exps.insert(i, te.exps); // replace with tuple contents + expandNames(i, te.exps.length); if (i == exps.length) return; // empty tuple, no more arguments (*exps)[i] = Expression.combine(te.e0, (*exps)[i]); @@ -683,11 +723,11 @@ extern (C++) /* IN_LLVM abstract */ class Expression : ASTNode { const EXP op; // to minimize use of dynamic_cast ubyte size; // # of bytes in Expression so we can copy() it - ubyte parens; // if this is a parenthesized expression + bool parens; // if this is a parenthesized expression Type type; // !=null means that semantic() has been run Loc loc; // file location - extern (D) this(const ref Loc loc, EXP op, int size) + extern (D) this(const ref Loc loc, EXP op, int size) scope { //printf("Expression::Expression(op = %d) this = %p\n", op, this); this.loc = loc; @@ -1394,7 +1434,7 @@ extern (C++) /* IN_LLVM abstract */ class Expression : ASTNode */ private static bool checkImpure(Scope* sc) { - return sc.func && (sc.flags & SCOPE.compile + return sc.func && (isRootTraitsCompilesScope(sc) ? sc.func.isPureBypassingInference() >= PURE.weak : sc.func.setImpure()); } @@ -1436,7 +1476,7 @@ extern (C++) /* IN_LLVM abstract */ class Expression : ASTNode if (!f.isSafe() && !f.isTrusted()) { - if (sc.flags & SCOPE.compile ? sc.func.isSafeBypassingInference() : sc.func.setUnsafeCall(f)) + if (isRootTraitsCompilesScope(sc) ? sc.func.isSafeBypassingInference() : sc.func.setUnsafeCall(f)) { if (!loc.isValid()) // e.g. implicitly generated dtor loc = sc.func.loc; @@ -1489,7 +1529,7 @@ extern (C++) /* IN_LLVM abstract */ class Expression : ASTNode if (!f.isNogc()) { - if (sc.flags & SCOPE.compile ? sc.func.isNogcBypassingInference() : sc.func.setGC()) + if (isRootTraitsCompilesScope(sc) ? sc.func.isNogcBypassingInference() : sc.func.setGC()) { if (loc.linnum == 0) // e.g. implicitly generated dtor loc = sc.func.loc; @@ -1497,7 +1537,8 @@ extern (C++) /* IN_LLVM abstract */ class Expression : ASTNode // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)), // so don't print anything to avoid double error messages. if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT - || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX)) + || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX + || f.ident == Id._d_newclassT)) error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`", sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars()); @@ -1648,6 +1689,15 @@ extern (C++) /* IN_LLVM abstract */ class Expression : ASTNode return .isConst(this); } + /****** + * Identical, not just equal. I.e. NaNs with different bit patterns are not identical + */ + bool isIdentical(const Expression e) const + { + return equals(e); + } + + /// Statically evaluate this expression to a `bool` if possible /// Returns: an optional thath either contains the value or is empty Optional!bool toBool() @@ -2138,6 +2188,13 @@ extern (C++) final class RealExp : Expression return false; } + override bool isIdentical(const Expression e) const + { + if (!equals(e)) + return false; + return CTFloat.isIdentical(value, e.isRealExp().value); + } + override dinteger_t toInteger() { return cast(sinteger_t)toReal(); @@ -2214,6 +2271,16 @@ extern (C++) final class ComplexExp : Expression return false; } + override bool isIdentical(const Expression e) const + { + if (!equals(e)) + return false; + // equals() regards different NaN values as 'equals' + auto c = e.isComplexExp(); + return CTFloat.isIdentical(creall(value), creall(c.value)) && + CTFloat.isIdentical(cimagl(value), cimagl(c.value)); + } + override dinteger_t toInteger() { return cast(sinteger_t)toReal(); @@ -2262,7 +2329,7 @@ extern (C++) class IdentifierExp : Expression { Identifier ident; - extern (D) this(const ref Loc loc, Identifier ident) + extern (D) this(const ref Loc loc, Identifier ident) scope { super(loc, EXP.identifier, __traits(classInstanceSize, IdentifierExp)); this.ident = ident; @@ -2417,7 +2484,7 @@ extern (C++) final class SuperExp : ThisExp */ extern (C++) final class NullExp : Expression { - extern (D) this(const ref Loc loc, Type type = null) + extern (D) this(const ref Loc loc, Type type = null) scope { super(loc, EXP.null_, __traits(classInstanceSize, NullExp)); this.type = type; @@ -2476,7 +2543,7 @@ extern (C++) final class StringExp : Expression char postfix = NoPostfix; // 'c', 'w', 'd' OwnedBy ownedByCtfe = OwnedBy.code; - extern (D) this(const ref Loc loc, const(void)[] string) + extern (D) this(const ref Loc loc, const(void)[] string) scope { super(loc, EXP.string_, __traits(classInstanceSize, StringExp)); this.string = cast(char*)string.ptr; // note that this.string should be const @@ -2484,7 +2551,7 @@ extern (C++) final class StringExp : Expression this.sz = 1; // work around LDC bug #1286 } - extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix) + extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix) scope { super(loc, EXP.string_, __traits(classInstanceSize, StringExp)); this.string = cast(char*)string.ptr; // note that this.string should be const @@ -3581,18 +3648,26 @@ 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 Expression argprefix; // expression to be evaluated just before arguments[] CtorDeclaration member; // constructor function bool onstack; // allocate on stack bool thrownew; // this NewExp is the expression of a ThrowStatement - extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments) + Expression lowering; // lowered druntime hook: `_d_newclass` + + /// 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(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments, Identifiers* names = null) { super(loc, EXP.new_, __traits(classInstanceSize, NewExp)); this.thisexp = thisexp; this.newtype = newtype; this.arguments = arguments; + this.names = names; } static NewExp create(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments) @@ -3605,7 +3680,8 @@ extern (C++) final class NewExp : Expression return new NewExp(loc, thisexp ? thisexp.syntaxCopy() : null, newtype.syntaxCopy(), - arraySyntaxCopy(arguments)); + arraySyntaxCopy(arguments), + names ? names.copy() : null); } override void accept(Visitor v) @@ -3989,6 +4065,7 @@ extern (C++) final class FuncExp : Expression Type t = pto.type; if (t.ty == Terror) return cannotInfer(this, to, flag); + tf.parameterList[u].storageClass = tof.parameterList[u].storageClass; tiargs.push(t); } @@ -4237,7 +4314,7 @@ extern (C++) final class IsExp : Expression TOK tok; // ':' or '==' TOK tok2; // 'struct', 'union', etc. - extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters) + extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters) scope { super(loc, EXP.is_, __traits(classInstanceSize, IsExp)); this.targ = targ; @@ -4277,7 +4354,7 @@ extern (C++) abstract class UnaExp : Expression Expression e1; Type att1; // Save alias this type to detect recursion - extern (D) this(const ref Loc loc, EXP op, int size, Expression e1) + extern (D) this(const ref Loc loc, EXP op, int size, Expression e1) scope { super(loc, op, size); this.e1 = e1; @@ -4350,7 +4427,7 @@ extern (C++) abstract class BinExp : Expression Type att1; // Save alias this type to detect recursion Type att2; // Save alias this type to detect recursion - extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2) + extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2) scope { super(loc, op, size); this.e1 = e1; @@ -4641,7 +4718,7 @@ extern (C++) abstract class BinExp : Expression */ extern (C++) class BinAssignExp : BinExp { - extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2) + extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2) scope { super(loc, op, size, e1, e2); } @@ -5068,21 +5145,53 @@ extern (C++) final class DotTypeExp : UnaExp } } +/** + * The arguments of a function call + * + * Contains a list of expressions. If it is a named argument, the `names` + * list has a non-null entry at the same index. + */ +struct ArgumentList +{ + Expressions* arguments; // function arguments + Identifiers* names; // named argument identifiers + + 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 + { + if (names is null) + return false; + foreach (name; *names) + if (name !is null) + return true; + + return false; + } +} + /*********************************************************** */ extern (C++) final class CallExp : UnaExp { Expressions* arguments; // function arguments + Identifiers* names; // named argument identifiers FuncDeclaration f; // symbol to call bool directcall; // true if a virtual call is devirtualized bool inDebugStatement; /// true if this was in a debug statement bool ignoreAttributes; /// don't enforce attributes (e.g. call @gc function in @nogc code) VarDeclaration vthis2; // container for multi-context - extern (D) this(const ref Loc loc, Expression e, Expressions* exps) + /// 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(const ref Loc loc, Expression e, Expressions* exps, Identifiers* names = null) { super(loc, EXP.call, __traits(classInstanceSize, CallExp), e); this.arguments = exps; + this.names = names; } extern (D) this(const ref Loc loc, Expression e) @@ -5149,7 +5258,7 @@ extern (C++) final class CallExp : UnaExp override CallExp syntaxCopy() { - return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments)); + return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments), names ? names.copy() : null); } override bool isLvalue() @@ -5345,7 +5454,7 @@ extern (C++) final class NegExp : UnaExp */ extern (C++) final class UAddExp : UnaExp { - extern (D) this(const ref Loc loc, Expression e) + extern (D) this(const ref Loc loc, Expression e) scope { super(loc, EXP.uadd, __traits(classInstanceSize, UAddExp), e); } @@ -6407,7 +6516,7 @@ extern (C++) final class MinExp : BinExp */ extern (C++) final class CatExp : BinExp { - extern (D) this(const ref Loc loc, Expression e1, Expression e2) + extern (D) this(const ref Loc loc, Expression e1, Expression e2) scope { super(loc, EXP.concatenate, __traits(classInstanceSize, CatExp), e1, e2); } @@ -6737,7 +6846,7 @@ extern (C++) final class CondExp : BinExp { Expression econd; - extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2) + extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2) scope { super(loc, EXP.question, __traits(classInstanceSize, CondExp), e1, e2); this.econd = econd; diff --git a/dmd/expression.h b/dmd/expression.h index 89a3980b222..b4dc9988db0 100644 --- a/dmd/expression.h +++ b/dmd/expression.h @@ -56,7 +56,7 @@ Expression *expressionSemantic(Expression *e, Scope *sc); Expression *defaultInit(Type *mt, const Loc &loc, const bool isCfile = false); #endif -void expandTuples(Expressions *exps); +void expandTuples(Expressions *exps, Identifiers *names = nullptr); bool isTrivialExp(Expression *e); bool hasSideEffect(Expression *e, bool assumeImpureCalls = false); @@ -97,7 +97,7 @@ class Expression : public ASTNode public: EXP op; // to minimize use of dynamic_cast unsigned char size; // # of bytes in Expression so we can copy() it - unsigned char parens; // if this is a parenthesized expression + bool parens; // if this is a parenthesized expression Type *type; // !=NULL means that semantic() has been run Loc loc; // file location @@ -139,6 +139,7 @@ class Expression : public ASTNode // A compile-time result is required. Give an error if not possible Expression *ctfeInterpret(); int isConst(); + virtual bool isIdentical(const Expression *e) const; virtual Optional toBool(); virtual bool hasCode() { @@ -297,6 +298,7 @@ class RealExp final : public Expression static RealExp *create(const Loc &loc, real_t value, Type *type); static void emplace(UnionExp *pue, const Loc &loc, real_t value, Type *type); bool equals(const RootObject * const o) const override; + bool isIdentical(const Expression *e) const override; dinteger_t toInteger() override; uinteger_t toUInteger() override; real_t toReal() override; @@ -314,6 +316,7 @@ class ComplexExp final : public Expression static ComplexExp *create(const Loc &loc, complex_t value, Type *type); static void emplace(UnionExp *pue, const Loc &loc, complex_t value, Type *type); bool equals(const RootObject * const o) const override; + bool isIdentical(const Expression *e) const override; dinteger_t toInteger() override; uinteger_t toUInteger() override; real_t toReal() override; @@ -565,6 +568,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 Expression *argprefix; // expression to be evaluated just before arguments[] @@ -572,6 +576,8 @@ class NewExp final : public Expression bool onstack; // allocate on stack bool thrownew; // this NewExp is the expression of a ThrowStatement + Expression *lowering; // lowered druntime hook: `_d_newclass` + static NewExp *create(const Loc &loc, Expression *thisexp, Type *newtype, Expressions *arguments); NewExp *syntaxCopy() override; @@ -859,6 +865,7 @@ class CallExp final : public UnaExp { public: Expressions *arguments; // function arguments + Identifiers *names; FuncDeclaration *f; // symbol to call bool directcall; // true if a virtual call is devirtualized bool inDebugStatement; // true if this was in a debug statement diff --git a/dmd/expressionsem.d b/dmd/expressionsem.d index 536ec2531d3..f662f49c93f 100644 --- a/dmd/expressionsem.d +++ b/dmd/expressionsem.d @@ -105,6 +105,8 @@ bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps) if (!ex) continue; auto sc2 = sc.startCTFE(); + sc2.tinst = null; + sc2.minst = null; // prevents emission of any instantiated templates to object file auto e2 = ex.expressionSemantic(sc2); auto e3 = resolveProperties(sc2, e2); sc2.endCTFE(); @@ -260,7 +262,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0) uint xerrors = global.startGagging(); sc = sc.push(); - FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, fargs, FuncResolveFlag.quiet); + FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, ArgumentList(fargs), FuncResolveFlag.quiet); sc = sc.pop(); global.endGagging(xerrors); if (!fslice) @@ -649,6 +651,9 @@ private Expression resolveUFCS(Scope* sc, CallExp ce) if (!ce.arguments) ce.arguments = new Expressions(); ce.arguments.shift(eleft); + if (!ce.names) + ce.names = new Identifiers(); + ce.names.shift(null); return null; } @@ -1150,6 +1155,69 @@ L1: return e1; } +/* + * Check whether `outerFunc` and `calledFunc` have the same `this`. + * If `calledFunc` is the member of a base class of the class that contains + * `outerFunc` we consider that they have the same this. + * + * This function is used to test whether `this` needs to be prepended to + * a function call or function symbol. For example: + * + * struct X + * { + * void gun() {} + * } + * struct A + * { + * void fun() {} + * void sun() + * { + * fun(); + * X.gun(); // error + * } + * } + * + * When `fun` is called, `outerfunc` = `sun` and `calledFunc = `fun`. + * `sun` is a member of `A` and `fun` is also a member of `A`, therefore + * `this` can be prepended to `fun`. When `gun` is called (it will result + * in an error, but that is not relevant here), which is a member of `X`, + * no `this` is needed because the outer function does not have the same + * `this` as `gun`. + * + * Returns: + * `true` if outerFunc and calledFunc may use the same `this` pointer. + * `false` otherwise. + */ +private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc) +{ + auto thisAd = outerFunc.isMemberLocal(); + if (!thisAd) + return false; + + auto requiredAd = calledFunc.isMemberLocal(); + if (!requiredAd) + return false; + + if (thisAd == requiredAd) + return true; + + // outerfunc is the member of a base class that contains calledFunc, + // then we consider that they have the same this. + auto cd = requiredAd.isClassDeclaration(); + if (!cd) + return false; + + if (cd.isBaseOf2(thisAd.isClassDeclaration())) + return true; + + // if outerfunc is the member of a nested aggregate, then let + // getRightThis take care of this. + if (thisAd.isNested()) + return true; + + return false; +} + /*************************************** * Pull out any properties. */ @@ -1192,7 +1260,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = for (size_t i = 0; i < os.a.length; i++) { - if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, &a, FuncResolveFlag.quiet)) + if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(&a), FuncResolveFlag.quiet)) { if (f.errors) return ErrorExp.get(); @@ -1209,7 +1277,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = { for (size_t i = 0; i < os.a.length; i++) { - if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, null, FuncResolveFlag.quiet)) + if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet)) { if (f.errors) return ErrorExp.get(); @@ -1307,7 +1375,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = Expressions a; a.push(e2); - FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, &a, FuncResolveFlag.quiet); + FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(&a), FuncResolveFlag.quiet); if (fd && fd.type) { if (fd.errors) @@ -1327,7 +1395,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = } } { - FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, null, FuncResolveFlag.quiet); + FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet); if (fd && fd.type) { if (fd.errors) @@ -1586,29 +1654,22 @@ private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expres /********************* * Rewrite: * array.length op= e2 - * as: - * array.length = array.length op e2 - * or: - * auto tmp = &array; - * (*tmp).length = (*tmp).length op e2 */ private Expression rewriteOpAssign(BinExp exp) { ArrayLengthExp ale = exp.e1.isArrayLengthExp(); if (ale.e1.isVarExp()) { + // array.length = array.length op e2 Expression e = opAssignToOp(exp.loc, exp.op, ale, exp.e2); e = new AssignExp(exp.loc, ale.syntaxCopy(), e); return e; } else { - /* auto tmp = &array; - * (*tmp).length = (*tmp).length op e2 - */ - auto tmp = copyToTemp(0, "__arraylength", new AddrExp(ale.loc, ale.e1)); - - Expression e1 = new ArrayLengthExp(ale.loc, new PtrExp(ale.loc, new VarExp(ale.loc, tmp))); + // (ref tmp = array;), tmp.length = tmp.length op e2 + auto tmp = copyToTemp(STC.ref_, "__arraylength", ale.e1); + Expression e1 = new ArrayLengthExp(ale.loc, new VarExp(ale.loc, tmp)); Expression elvalue = e1.syntaxCopy(); Expression e = opAssignToOp(exp.loc, exp.op, e1, exp.e2); e = new AssignExp(exp.loc, elvalue, e); @@ -1619,20 +1680,24 @@ private Expression rewriteOpAssign(BinExp exp) /**************************************** * Preprocess arguments to function. - * Input: - * reportErrors whether or not to report errors here. Some callers are not + * + * Tuples in argumentList get expanded, properties resolved, rewritten in place + * + * Params: + * sc = scope + * argumentList = arguments to function + * reportErrors = whether or not to report errors here. Some callers are not * checking actual function params, so they'll do their own error reporting - * Output: - * exps[] tuples expanded, properties resolved, rewritten in place * Returns: - * true a semantic error occurred + * `true` when a semantic error occurred */ -private bool preFunctionParameters(Scope* sc, Expressions* exps, const bool reportErrors = true) +private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, const bool reportErrors = true) { + Expressions* exps = argumentList.arguments; bool err = false; if (exps) { - expandTuples(exps); + expandTuples(exps, argumentList.names); for (size_t i = 0; i < exps.length; i++) { @@ -1708,7 +1773,7 @@ private bool checkDefCtor(Loc loc, Type t) * tf = type of the function * ethis = `this` argument, `null` if none or not known * tthis = type of `this` argument, `null` if no `this` argument - * arguments = array of actual arguments to function call + * argumentsList = array of actual arguments to function call * fd = the function being called, `null` if called indirectly * prettype = set to return type of function * peprefix = set to expression to execute before `arguments[]` are evaluated, `null` if none @@ -1716,20 +1781,38 @@ private bool checkDefCtor(Loc loc, Type t) * true errors happened */ private bool functionParameters(const ref Loc loc, Scope* sc, - TypeFunction tf, Expression ethis, Type tthis, Expressions* arguments, FuncDeclaration fd, + TypeFunction tf, Expression ethis, Type tthis, ArgumentList argumentList, FuncDeclaration fd, Type* prettype, Expression* peprefix) { + Expressions* arguments = argumentList.arguments; //printf("functionParameters() %s\n", fd ? fd.toChars() : ""); assert(arguments); assert(fd || tf.next); - size_t nargs = arguments ? arguments.length : 0; const size_t nparams = tf.parameterList.length; const olderrors = global.errors; bool err = false; - *prettype = Type.terror; Expression eprefix = null; *peprefix = null; + if (argumentList.names) + { + const(char)* msg = null; + auto resolvedArgs = tf.resolveNamedArgs(argumentList, &msg); + if (!resolvedArgs) + { + // while errors are usually already caught by `tf.callMatch`, + // this can happen when calling `typeof(freefunc)` + if (msg) + error(loc, "%s", msg); + return true; + } + // note: the argument list should be mutated with named arguments / default arguments, + // so we can't simply change the pointer like `arguments = resolvedArgs;` + arguments.setDim(0); + arguments.pushSlice((*resolvedArgs)[]); + } + size_t nargs = arguments ? arguments.length : 0; + if (nargs > nparams && tf.parameterList.varargs == VarArg.none) { error(loc, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams, cast(ulong)nargs, tf.toChars()); @@ -1796,11 +1879,18 @@ private bool functionParameters(const ref Loc loc, Scope* sc, return errorArgs(); } arg = p.defaultArg; + if (!arg.type) + arg = arg.expressionSemantic(sc); arg = inlineCopy(arg, sc); // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__ arg = arg.resolveLoc(loc, sc); - arguments.push(arg); - nargs++; + if (i >= nargs) + { + arguments.push(arg); + nargs++; + } + else + (*arguments)[i] = arg; } else { @@ -1978,11 +2068,18 @@ private bool functionParameters(const ref Loc loc, Scope* sc, return errorInout(wildmatch); } - Expression firstArg = ((tf.next && tf.next.ty == Tvoid || isCtorCall) && - tthis && - tthis.isMutable() && tthis.toBasetype().ty == Tstruct && - tthis.hasPointers()) - ? ethis : null; + Expression firstArg = null; + final switch (returnParamDest(tf, tthis)) + { + case ReturnParamDest.returnVal: + break; + case ReturnParamDest.firstArg: + firstArg = nargs > 0 ? (*arguments)[0] : null; + break; + case ReturnParamDest.this_: + firstArg = ethis; + break; + } assert(nargs >= nparams); foreach (const i, arg; (*arguments)[0 .. nargs]) @@ -2145,19 +2242,6 @@ private bool functionParameters(const ref Loc loc, Scope* sc, err |= arg.checkSharedAccess(sc); arg = arg.optimize(WANTvalue, p.isReference()); - - /* Determine if this parameter is the "first reference" parameter through which - * later "return" arguments can be stored. - */ - if (i == 0 && !tthis && p.isReference() && p.type && - (tf.next && tf.next.ty == Tvoid || isCtorCall)) - { - Type tb = p.type.baseElemOf(); - if (tb.isMutable() && tb.hasPointers()) - { - firstArg = arg; - } - } } else { @@ -2448,10 +2532,10 @@ private bool functionParameters(const ref Loc loc, Scope* sc, } //if (eprefix) printf("eprefix: %s\n", eprefix.toChars()); - /* Test compliance with DIP1021 + /* Test compliance with DIP1021 Argument Ownership and Function Calls */ - if (global.params.useDIP1021 && - tf.trust != TRUST.system && tf.trust != TRUST.trusted) + if (global.params.useDIP1021 && (tf.trust == TRUST.safe || tf.trust == TRUST.default_) || + tf.islive) err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false); // If D linkage and variadic, add _arguments[] as first argument @@ -2550,7 +2634,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Scope* sc; Expression result; - this(Scope* sc) + this(Scope* sc) scope { this.sc = sc; } @@ -3552,7 +3636,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { return setError(); } - if (preFunctionParameters(sc, exp.arguments)) + if (preFunctionParameters(sc, exp.argumentList)) { return setError(); } @@ -3711,7 +3795,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (cd.ctor) { - FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard); + FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard); if (!f || f.errors) return setError(); @@ -3721,7 +3805,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor TypeFunction tf = f.type.isTypeFunction(); if (!exp.arguments) exp.arguments = new Expressions(); - if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix)) + if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix)) return setError(); exp.member = f.isCtorDeclaration(); @@ -3781,6 +3865,33 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = id.expressionSemantic(sc); return; } + // LDC: not using the `_d_newclassT` lowering yet + else if (!IN_LLVM && !exp.onstack && !exp.type.isscope()) + { + auto hook = global.params.tracegc ? Id._d_newclassTTrace : Id._d_newclassT; + if (!verifyHookExist(exp.loc, *sc, hook, "new class")) + return setError(); + + Expression id = new IdentifierExp(exp.loc, Id.empty); + id = new DotIdExp(exp.loc, id, Id.object); + + auto tiargs = new Objects(); + auto t = exp.newtype.unqualify(MODFlags.wild); // remove `inout` + tiargs.push(t); + id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs); + auto arguments = new Expressions(); + if (global.params.tracegc) + { + auto funcname = (sc.callsc && sc.callsc.func) ? + sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars(); + arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString())); + arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32)); + arguments.push(new StringExp(exp.loc, funcname.toDString())); + } + id = new CallExp(exp.loc, id, arguments); + + exp.lowering = id.expressionSemantic(sc); + } } else if (auto ts = tb.isTypeStruct()) { @@ -3810,7 +3921,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // is the same type as the struct if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf()))) { - FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard); + FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard); if (!f || f.errors) return setError(); @@ -3820,7 +3931,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor TypeFunction tf = f.type.isTypeFunction(); if (!exp.arguments) exp.arguments = new Expressions(); - if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix)) + if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix)) return setError(); exp.member = f.isCtorDeclaration(); @@ -3831,8 +3942,20 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else { - if (!exp.arguments) + if (exp.names) + { + exp.arguments = resolveStructLiteralNamedArgs(sd, exp.type, sc, exp.loc, + exp.names ? (*exp.names)[] : null, + (size_t i, Type t) => (*exp.arguments)[i], + i => (*exp.arguments)[i].loc + ); + if (!exp.arguments) + return setError(); + } + else if (!exp.arguments) + { exp.arguments = new Expressions(); + } if (!sd.fit(exp.loc, sc, exp.arguments, tb)) return setError(); @@ -3881,6 +4004,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } Expression arg = (*exp.arguments)[i]; + if (exp.names && (*exp.names)[i]) + { + exp.error("no named argument `%s` allowed for array dimension", (*exp.names)[i].toChars()); + return setError(); + } + arg = resolveProperties(sc, arg); arg = arg.implicitCastTo(sc, Type.tsize_t); if (arg.op == EXP.error) @@ -3902,6 +4031,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else if (nargs == 1) { + if (exp.names && (*exp.names)[0]) + { + exp.error("no named argument `%s` allowed for scalar", (*exp.names)[0].toChars()); + return setError(); + } Expression e = (*exp.arguments)[0]; e = e.implicitCastTo(sc, tb); (*exp.arguments)[0] = e; @@ -4290,7 +4424,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (FuncExp fe = exp.e1.isFuncExp()) { if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) || - preFunctionParameters(sc, exp.arguments)) + preFunctionParameters(sc, exp.argumentList)) return setError(); // Run e1 semantic even if arguments have any errors @@ -4529,7 +4663,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) || - preFunctionParameters(sc, exp.arguments)) + preFunctionParameters(sc, exp.argumentList)) return setError(); // Check for call operator overload @@ -4627,7 +4761,22 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor /* It's a struct literal */ Lx: - Expression e = new StructLiteralExp(exp.loc, sd, exp.arguments, exp.e1.type); + Expressions* resolvedArgs = exp.arguments; + if (exp.names) + { + resolvedArgs = resolveStructLiteralNamedArgs(sd, exp.e1.type, sc, exp.loc, + (*exp.names)[], + (size_t i, Type t) => (*exp.arguments)[i], + i => (*exp.arguments)[i].loc + ); + if (!resolvedArgs) + { + result = ErrorExp.get(); + return; + } + } + + Expression e = new StructLiteralExp(exp.loc, sd, resolvedArgs, exp.e1.type); e = e.expressionSemantic(sc); result = e; return; @@ -4637,7 +4786,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor L1: // Rewrite as e1.call(arguments) Expression e = new DotIdExp(exp.loc, exp.e1, Id.call); - e = new CallExp(exp.loc, e, exp.arguments); + e = new CallExp(exp.loc, e, exp.arguments, exp.names); e = e.expressionSemantic(sc); result = e; return; @@ -4676,14 +4825,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc, - OverloadSet os, Objects* tiargs, Type tthis, Expressions* arguments) + OverloadSet os, Objects* tiargs, Type tthis, ArgumentList argumentList) { FuncDeclaration f = null; foreach (s; os.a) { if (tiargs && s.isFuncDeclaration()) continue; - if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, arguments, FuncResolveFlag.quiet)) + if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, argumentList, FuncResolveFlag.quiet)) { if (f2.errors) return null; @@ -4743,7 +4892,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } // Do overload resolution - exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.arguments, FuncResolveFlag.standard); + exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.argumentList, FuncResolveFlag.standard); if (!exp.f || exp.f.errors || exp.f.type.ty == Terror) return setError(); @@ -4906,9 +5055,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor tthis = ad.type.addMod(sc.func.type.mod); auto ctor = isSuper ? cd.baseClass.ctor : ad.ctor; if (auto os = ctor.isOverloadSet()) - exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.arguments); + exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.argumentList); else - exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.arguments, FuncResolveFlag.standard); + exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.argumentList, FuncResolveFlag.standard); if (!exp.f || exp.f.errors) return setError(); @@ -4933,7 +5082,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } else if (auto oe = exp.e1.isOverExp()) { - exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.arguments); + exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.argumentList); if (!exp.f) return setError(); if (ethis) @@ -4980,7 +5129,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else if (exp.e1.op == EXP.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration()) { DotVarExp dve = cast(DotVarExp)exp.e1; - exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.arguments, FuncResolveFlag.overloadOnly); + exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.argumentList, FuncResolveFlag.overloadOnly); if (!exp.f) return setError(); if (exp.f.needThis()) @@ -5004,7 +5153,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { s = (cast(TemplateExp)exp.e1).td; L2: - exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.arguments, FuncResolveFlag.standard); + exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.argumentList, FuncResolveFlag.standard); if (!exp.f || exp.f.errors) return setError(); if (exp.f.needThis()) @@ -5032,8 +5181,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } const(char)* failMessage; - Expression[] fargs = exp.arguments ? (*exp.arguments)[] : null; - if (!tf.callMatch(null, fargs, 0, &failMessage, sc)) + if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc)) { OutBuffer buf; buf.writeByte('('); @@ -5100,14 +5248,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor tiargs = null; if (exp.f.overnext) - exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.arguments, FuncResolveFlag.overloadOnly); + exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.overloadOnly); else { exp.f = exp.f.toAliasFunc(); TypeFunction tf = cast(TypeFunction)exp.f.type; const(char)* failMessage; - Expression[] fargs = exp.arguments ? (*exp.arguments)[] : null; - if (!tf.callMatch(null, fargs, 0, &failMessage, sc)) + if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc)) { OutBuffer buf; buf.writeByte('('); @@ -5131,7 +5278,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.f.checkNestedReference(sc, exp.loc)) return setError(); - if (hasThis(sc)) + auto memberFunc = hasThis(sc); + if (memberFunc && haveSameThis(memberFunc, exp.f)) { // Supply an implicit 'this', as in // this.ident @@ -5149,7 +5297,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // // https://issues.dlang.org/show_bug.cgi?id=22157 if (exp.f.overnext) - exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.arguments, FuncResolveFlag.standard); + exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.standard); if (!exp.f || exp.f.errors) return setError(); @@ -5181,7 +5329,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Expression argprefix; if (!exp.arguments) exp.arguments = new Expressions(); - if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.arguments, exp.f, &exp.type, &argprefix)) + if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.argumentList, exp.f, &exp.type, &argprefix)) return setError(); if (!exp.type) @@ -5504,8 +5652,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { // Handle this in the glue layer e = new TypeidExp(exp.loc, ta); - e.type = getTypeInfoType(exp.loc, ta, sc); + bool genObjCode = true; + + // https://issues.dlang.org/show_bug.cgi?id=23650 + // We generate object code for typeinfo, required + // by typeid, only if in non-speculative context + if (sc.flags & SCOPE.compile) + { + genObjCode = false; + } + + e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode); semanticTypeInfo(sc, ta); if (ea) @@ -6014,7 +6172,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor uint errors = global.errors; const len = buf.length; const str = buf.extractChars()[0 .. len]; - scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false); + scope p = new Parser!ASTCodegen(exp.loc, sc._module, str, false, global.errorSink); p.nextToken(); //printf("p.loc.linnum = %d\n", p.loc.linnum); @@ -6804,8 +6962,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor AggregateDeclaration ad = f.isMemberLocal(); if (f.needThis()) e.e1 = getRightThis(e.loc, sc, ad, e.e1, f); - if (e.e1.op == EXP.error) - return setError(); if (f.type.ty == Tfunction) { @@ -7129,7 +7285,8 @@ version (IN_LLVM) } if (f.needThis()) { - if (hasThis(sc)) + auto memberFunc = hasThis(sc); + if (memberFunc && haveSameThis(memberFunc, f)) { /* Should probably supply 'this' after overload resolution, * not before. @@ -7231,6 +7388,14 @@ version (IN_LLVM) goto case Terror; } + if (sc.flags & SCOPE.Cfile && exp.type && exp.type.toBasetype().ty == Tvoid) + { + // https://issues.dlang.org/show_bug.cgi?id=23752 + // `&*((void*)(0))` is allowed in C + result = exp; + return; + } + if (exp.checkValue()) return setError(); @@ -12009,6 +12174,9 @@ version (IN_LLVM) if (!needsArrayLowering) { + // https://issues.dlang.org/show_bug.cgi?id=23783 + if (exp.e1.checkSharedAccess(sc) || exp.e2.checkSharedAccess(sc)) + return setError(); if (auto e = typeCombine(exp, sc)) { result = e; @@ -12233,6 +12401,29 @@ version (IN_LLVM) Type t1 = exp.e1.type; Type t2 = exp.e2.type; + + // https://issues.dlang.org/show_bug.cgi?id=23767 + // `cast(void*) 0` should be treated as `null` so the ternary expression + // gets the pointer type of the other branch + if (sc.flags & SCOPE.Cfile) + { + static void rewriteCNull(ref Expression e, ref Type t) + { + if (!t.isTypePointer()) + return; + if (auto ie = e.optimize(WANTvalue).isIntegerExp()) + { + if (ie.getInteger() == 0) + { + e = new NullExp(e.loc, Type.tnull); + t = Type.tnull; + } + } + } + rewriteCNull(exp.e1, t1); + rewriteCNull(exp.e2, t2); + } + if (t1.ty == Tnoreturn) { exp.type = t2; @@ -13184,7 +13375,9 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) // Error by default bool visit(Expression e) { - if (e.type.isShared()) + // https://issues.dlang.org/show_bug.cgi?id=23639 + // Should be able to cast(shared) + if (!e.isCastExp() && e.type.isShared()) return sharedError(e); return false; } @@ -13198,6 +13391,12 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) bool visitVar(VarExp e) { + // https://issues.dlang.org/show_bug.cgi?id=20908 + // direct access to init symbols is ok as they + // cannot be modified. + if (e.var.isSymbolDeclaration()) + return false; + // https://issues.dlang.org/show_bug.cgi?id=22626 // Synchronized functions don't need to use core.atomic // when accessing `this`. @@ -13235,9 +13434,16 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) //printf("dotvarexp = %s\n", e.toChars()); if (e.type.isShared()) { - // / https://issues.dlang.org/show_bug.cgi?id=22626 - if (e.e1.isThisExp() && sc.func && sc.func.isSynchronized()) - return false; + if (e.e1.isThisExp()) + { + // https://issues.dlang.org/show_bug.cgi?id=22626 + if (sc.func && sc.func.isSynchronized()) + return false; + + // https://issues.dlang.org/show_bug.cgi?id=23790 + if (e.e1.type.isTypeStruct()) + return false; + } auto fd = e.var.isFuncDeclaration(); const sharedFunc = fd && fd.type.isShared; diff --git a/dmd/foreachvar.d b/dmd/foreachvar.d index 7c4df0deca8..ba2825a3098 100644 --- a/dmd/foreachvar.d +++ b/dmd/foreachvar.d @@ -56,7 +56,7 @@ void foreachVar(Expression e, void delegate(VarDeclaration) dgVar) alias visit = typeof(super).visit; extern (D) void delegate(VarDeclaration) dgVar; - extern (D) this(void delegate(VarDeclaration) dgVar) + extern (D) this(void delegate(VarDeclaration) dgVar) scope { this.dgVar = dgVar; } diff --git a/dmd/frontend.h b/dmd/frontend.h index 1dd67beb72a..480b91922c2 100644 --- a/dmd/frontend.h +++ b/dmd/frontend.h @@ -102,6 +102,7 @@ class VisibilityDeclaration; class OverloadSet; class CompileDeclaration; class StaticAssert; +class StaticIfDeclaration; class DsymbolTable; struct MangleOverride; class AliasThis; @@ -306,6 +307,7 @@ class ArrayInitializer; class ExpInitializer; class CInitializer; class FileManager; +class ErrorSink; class ErrorStatement; class ExpStatement; class ConditionalStatement; @@ -507,7 +509,6 @@ class Dsymbol : public ASTNode virtual void setFieldOffset(AggregateDeclaration* ad, FieldState& fieldState, bool isunion); virtual bool hasPointers(); virtual bool hasStaticCtorOrDtor(); - virtual void addLocalClass(Array* _param_0); virtual void addObjcSymbols(Array* classes, Array* categories); virtual void checkCtorConstInit(); virtual void addComment(const char* comment); @@ -571,6 +572,7 @@ class Dsymbol : public ASTNode virtual OverloadSet* isOverloadSet(); virtual CompileDeclaration* isCompileDeclaration(); virtual StaticAssert* isStaticAssert(); + virtual StaticIfDeclaration* isStaticIfDeclaration(); }; typedef uint64_t size_t; @@ -784,6 +786,7 @@ struct FileName final private: _d_dynamicArray< const char > str; public: + static FileName create(const char* name); static bool equals(const char* name1, const char* name2); static bool absolute(const char* name); static const char* toAbsolute(const char* name, const char* base = nullptr); @@ -991,7 +994,7 @@ class Expression : public ASTNode public: const EXP op; uint8_t size; - uint8_t parens; + bool parens; Type* type; Loc loc; static void _init(); @@ -1026,6 +1029,7 @@ class Expression : public ASTNode Expression* optimize(int32_t result, bool keepLvalue = false); Expression* ctfeInterpret(); int32_t isConst(); + virtual bool isIdentical(const Expression* const e) const; virtual Optional toBool(); virtual bool hasCode(); IntegerExp* isIntegerExp(); @@ -1297,6 +1301,21 @@ struct AssocArray final } }; +struct ArgumentList final +{ + Array* arguments; + Array* names; + ArgumentList() : + arguments(), + names() + { + } + ArgumentList(Array* arguments, Array* names = nullptr) : + arguments(arguments), + names(names) + {} +}; + enum class TY : uint8_t { Tarray = 0u, @@ -1811,12 +1830,14 @@ enum class TOK : uint8_t _Noreturn = 212u, _Static_assert = 213u, _Thread_local = 214u, - _import = 215u, - __cdecl_ = 216u, - __declspec_ = 217u, - __stdcall_ = 218u, - __pragma_ = 219u, - __attribute___ = 220u, + _assert = 215u, + _import = 216u, + __cdecl_ = 217u, + __declspec_ = 218u, + __stdcall_ = 219u, + __pragma_ = 220u, + __int128_ = 221u, + __attribute___ = 222u, }; enum class MemorySet @@ -2468,6 +2489,8 @@ class FuncDeclaration : public Declaration Symbol* shidden; Array* returns; Array* gotos; + Array* alignSectionVars; + Symbol* salignSection; BUILTIN builtin; int32_t tookAddressOf; bool requiresClosure; @@ -2492,8 +2515,8 @@ class FuncDeclaration : public Declaration bool inferScope(bool v); bool hasCatches() const; bool hasCatches(bool v); - bool isCompileTimeOnly() const; - bool isCompileTimeOnly(bool v); + bool skipCodegen() const; + bool skipCodegen(bool v); bool printf() const; bool printf(bool v); bool scanf() const; @@ -2522,6 +2545,10 @@ class FuncDeclaration : public Declaration bool isCrtCtor(bool v); bool isCrtDtor() const; bool isCrtDtor(bool v); + bool hasEscapingSiblings() const; + bool hasEscapingSiblings(bool v); + bool computedEscapingSiblings() const; + bool computedEscapingSiblings(bool v); private: uint32_t bitFields; public: @@ -2536,7 +2563,7 @@ class FuncDeclaration : public Declaration BaseClass* overrideInterface(); bool overloadInsert(Dsymbol* s) override; bool inUnittest(); - MATCH leastAsSpecialized(FuncDeclaration* g); + MATCH leastAsSpecialized(FuncDeclaration* g, Array* names); LabelDsymbol* searchLabel(Identifier* ident, const Loc& loc = Loc::initial); int32_t getLevel(FuncDeclaration* fd, int32_t intypeof); int32_t getLevelAndCheck(const Loc& loc, Scope* sc, FuncDeclaration* fd, Declaration* decl); @@ -2808,6 +2835,7 @@ struct HdrGenState final int32_t autoMember; int32_t forStmtInit; int32_t insideFuncBody; + int32_t insideAggregate; bool declstring; EnumDeclaration* inEnumDecl; HdrGenState() : @@ -2819,11 +2847,12 @@ struct HdrGenState final autoMember(), forStmtInit(), insideFuncBody(), + insideAggregate(), declstring(), inEnumDecl() { } - HdrGenState(bool hdrgen, bool ddoc = false, bool fullDump = false, bool fullQual = false, int32_t tpltMember = 0, int32_t autoMember = 0, int32_t forStmtInit = 0, int32_t insideFuncBody = 0, bool declstring = false, EnumDeclaration* inEnumDecl = nullptr) : + HdrGenState(bool hdrgen, bool ddoc = false, bool fullDump = false, bool fullQual = false, int32_t tpltMember = 0, int32_t autoMember = 0, int32_t forStmtInit = 0, int32_t insideFuncBody = 0, int32_t insideAggregate = 0, bool declstring = false, EnumDeclaration* inEnumDecl = nullptr) : hdrgen(hdrgen), ddoc(ddoc), fullDump(fullDump), @@ -2832,6 +2861,7 @@ struct HdrGenState final autoMember(autoMember), forStmtInit(forStmtInit), insideFuncBody(insideFuncBody), + insideAggregate(insideAggregate), declstring(declstring), inEnumDecl(inEnumDecl) {} @@ -3093,6 +3123,7 @@ struct Param final CHECKENABLE boundscheck; CHECKACTION checkAction; uint32_t errorLimit; + uint32_t errorSupplementLimit; _d_dynamicArray< const char > argv0; Array modFileAliasStrings; Array* imppath; @@ -3172,6 +3203,7 @@ struct Param final externStdUsage(), hcUsage(), logo(), + useDIP25((FeatureState)1), ehnogc(), useDIP1021(), fieldwise(), @@ -3190,6 +3222,7 @@ struct Param final boundscheck((CHECKENABLE)0u), checkAction((CHECKACTION)0u), errorLimit(20u), + errorSupplementLimit(6u), argv0(), modFileAliasStrings(), imppath(), @@ -3223,7 +3256,7 @@ struct Param final mapfile() { } - Param(bool obj, bool multiobj = false, bool trace = false, bool tracegc = false, bool verbose = false, bool vcg_ast = false, bool showColumns = false, bool vtls = false, bool vtemplates = false, bool vtemplatesListInstances = false, bool vgc = false, bool vfield = false, bool vcomplex = true, bool vin = false, DiagnosticReporting useDeprecated = (DiagnosticReporting)1u, bool useUnitTests = false, bool useInline = false, bool release = false, bool preservePaths = false, DiagnosticReporting warnings = (DiagnosticReporting)2u, bool color = false, bool cov = false, uint8_t covPercent = 0u, bool ctfe_cov = false, bool ignoreUnsupportedPragmas = false, bool useModuleInfo = true, bool useTypeInfo = true, bool useExceptions = true, bool betterC = false, bool addMain = false, bool allInst = false, bool bitfields = false, CppStdRevision cplusplus = (CppStdRevision)201103u, bool showGaggedErrors = false, bool printErrorContext = false, bool manual = false, bool usage = false, bool mcpuUsage = false, bool transitionUsage = false, bool checkUsage = false, bool checkActionUsage = false, bool revertUsage = false, bool previewUsage = false, bool externStdUsage = false, bool hcUsage = false, bool logo = false, FeatureState useDIP25 = (FeatureState)-1, FeatureState useDIP1000 = (FeatureState)-1, bool ehnogc = false, bool useDIP1021 = false, bool fieldwise = false, bool fixAliasThis = false, FeatureState rvalueRefParam = (FeatureState)-1, FeatureState noSharedAccess = (FeatureState)-1, bool previewIn = false, bool inclusiveInContracts = false, bool shortenedMethods = true, bool fixImmutableConv = false, bool fix16997 = true, FeatureState dtorFields = (FeatureState)-1, FeatureState systemVariables = (FeatureState)-1, CHECKENABLE useInvariants = (CHECKENABLE)0u, CHECKENABLE useIn = (CHECKENABLE)0u, CHECKENABLE useOut = (CHECKENABLE)0u, CHECKENABLE useArrayBounds = (CHECKENABLE)0u, CHECKENABLE useAssert = (CHECKENABLE)0u, CHECKENABLE useSwitchError = (CHECKENABLE)0u, CHECKENABLE boundscheck = (CHECKENABLE)0u, CHECKACTION checkAction = (CHECKACTION)0u, uint32_t errorLimit = 20u, _d_dynamicArray< const char > argv0 = {}, Array modFileAliasStrings = Array(), Array* imppath = nullptr, Array* fileImppath = nullptr, _d_dynamicArray< const char > objdir = {}, _d_dynamicArray< const char > objname = {}, _d_dynamicArray< const char > libname = {}, Output ddoc = Output(), Output dihdr = Output(), Output cxxhdr = Output(), Output json = Output(), JsonFieldFlags jsonFieldFlags = (JsonFieldFlags)0u, Output makeDeps = Output(), Output mixinOut = Output(), Output moduleDeps = Output(), uint32_t debuglevel = 0u, Array* debugids = nullptr, uint32_t versionlevel = 0u, Array* versionids = nullptr, MessageStyle messageStyle = (MessageStyle)0u, bool run = false, Array runargs = Array(), Array cppswitches = Array(), Array objfiles = Array(), Array linkswitches = Array(), Array linkswitchIsForCC = Array(), Array libfiles = Array(), Array dllfiles = Array(), _d_dynamicArray< const char > deffile = {}, _d_dynamicArray< const char > resfile = {}, _d_dynamicArray< const char > exefile = {}, _d_dynamicArray< const char > mapfile = {}) : + Param(bool obj, bool multiobj = false, bool trace = false, bool tracegc = false, bool verbose = false, bool vcg_ast = false, bool showColumns = false, bool vtls = false, bool vtemplates = false, bool vtemplatesListInstances = false, bool vgc = false, bool vfield = false, bool vcomplex = true, bool vin = false, DiagnosticReporting useDeprecated = (DiagnosticReporting)1u, bool useUnitTests = false, bool useInline = false, bool release = false, bool preservePaths = false, DiagnosticReporting warnings = (DiagnosticReporting)2u, bool color = false, bool cov = false, uint8_t covPercent = 0u, bool ctfe_cov = false, bool ignoreUnsupportedPragmas = false, bool useModuleInfo = true, bool useTypeInfo = true, bool useExceptions = true, bool betterC = false, bool addMain = false, bool allInst = false, bool bitfields = false, CppStdRevision cplusplus = (CppStdRevision)201103u, bool showGaggedErrors = false, bool printErrorContext = false, bool manual = false, bool usage = false, bool mcpuUsage = false, bool transitionUsage = false, bool checkUsage = false, bool checkActionUsage = false, bool revertUsage = false, bool previewUsage = false, bool externStdUsage = false, bool hcUsage = false, bool logo = false, FeatureState useDIP25 = (FeatureState)1, FeatureState useDIP1000 = (FeatureState)-1, bool ehnogc = false, bool useDIP1021 = false, bool fieldwise = false, bool fixAliasThis = false, FeatureState rvalueRefParam = (FeatureState)-1, FeatureState noSharedAccess = (FeatureState)-1, bool previewIn = false, bool inclusiveInContracts = false, bool shortenedMethods = true, bool fixImmutableConv = false, bool fix16997 = true, FeatureState dtorFields = (FeatureState)-1, FeatureState systemVariables = (FeatureState)-1, CHECKENABLE useInvariants = (CHECKENABLE)0u, CHECKENABLE useIn = (CHECKENABLE)0u, CHECKENABLE useOut = (CHECKENABLE)0u, CHECKENABLE useArrayBounds = (CHECKENABLE)0u, CHECKENABLE useAssert = (CHECKENABLE)0u, CHECKENABLE useSwitchError = (CHECKENABLE)0u, CHECKENABLE boundscheck = (CHECKENABLE)0u, CHECKACTION checkAction = (CHECKACTION)0u, uint32_t errorLimit = 20u, uint32_t errorSupplementLimit = 6u, _d_dynamicArray< const char > argv0 = {}, Array modFileAliasStrings = Array(), Array* imppath = nullptr, Array* fileImppath = nullptr, _d_dynamicArray< const char > objdir = {}, _d_dynamicArray< const char > objname = {}, _d_dynamicArray< const char > libname = {}, Output ddoc = Output(), Output dihdr = Output(), Output cxxhdr = Output(), Output json = Output(), JsonFieldFlags jsonFieldFlags = (JsonFieldFlags)0u, Output makeDeps = Output(), Output mixinOut = Output(), Output moduleDeps = Output(), uint32_t debuglevel = 0u, Array* debugids = nullptr, uint32_t versionlevel = 0u, Array* versionids = nullptr, MessageStyle messageStyle = (MessageStyle)0u, bool run = false, Array runargs = Array(), Array cppswitches = Array(), Array objfiles = Array(), Array linkswitches = Array(), Array linkswitchIsForCC = Array(), Array libfiles = Array(), Array dllfiles = Array(), _d_dynamicArray< const char > deffile = {}, _d_dynamicArray< const char > resfile = {}, _d_dynamicArray< const char > exefile = {}, _d_dynamicArray< const char > mapfile = {}) : obj(obj), multiobj(multiobj), trace(trace), @@ -3294,6 +3327,7 @@ struct Param final boundscheck(boundscheck), checkAction(checkAction), errorLimit(errorLimit), + errorSupplementLimit(errorSupplementLimit), argv0(argv0), modFileAliasStrings(modFileAliasStrings), imppath(imppath), @@ -3351,6 +3385,7 @@ struct Global final FileManager* fileManager; enum : int32_t { recursionLimit = 500 }; + ErrorSink* errorSink; FileName(*preprocess)(FileName , const Loc& , bool& , OutBuffer* ); uint32_t startGagging(); bool endGagging(uint32_t oldGagged); @@ -3377,10 +3412,11 @@ struct Global final hasMainFunction(), varSequenceNumber(1u), fileManager(), + errorSink(), preprocess() { } - Global(_d_dynamicArray< const char > inifilename, _d_dynamicArray< const char > copyright = { 73, "Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved" }, _d_dynamicArray< const char > written = { 24, "written by Walter Bright" }, Array* path = nullptr, Array* filePath = nullptr, _d_dynamicArray< const char > vendor = {}, Param params = Param(), uint32_t errors = 0u, uint32_t warnings = 0u, uint32_t gag = 0u, uint32_t gaggedErrors = 0u, uint32_t gaggedWarnings = 0u, void* console = nullptr, Array* versionids = nullptr, Array* debugids = nullptr, bool hasMainFunction = false, uint32_t varSequenceNumber = 1u, FileManager* fileManager = nullptr, FileName(*preprocess)(FileName , const Loc& , bool& , OutBuffer* ) = nullptr) : + Global(_d_dynamicArray< const char > inifilename, _d_dynamicArray< const char > copyright = { 73, "Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved" }, _d_dynamicArray< const char > written = { 24, "written by Walter Bright" }, Array* path = nullptr, Array* filePath = nullptr, _d_dynamicArray< const char > vendor = {}, Param params = Param(), uint32_t errors = 0u, uint32_t warnings = 0u, uint32_t gag = 0u, uint32_t gaggedErrors = 0u, uint32_t gaggedWarnings = 0u, void* console = nullptr, Array* versionids = nullptr, Array* debugids = nullptr, bool hasMainFunction = false, uint32_t varSequenceNumber = 1u, FileManager* fileManager = nullptr, ErrorSink* errorSink = nullptr, FileName(*preprocess)(FileName , const Loc& , bool& , OutBuffer* ) = nullptr) : inifilename(inifilename), copyright(copyright), written(written), @@ -3399,6 +3435,7 @@ struct Global final hasMainFunction(hasMainFunction), varSequenceNumber(varSequenceNumber), fileManager(fileManager), + errorSink(errorSink), preprocess(preprocess) {} }; @@ -4373,6 +4410,7 @@ class GotoStatement final : public Statement TryFinallyStatement* tf; ScopeGuardStatement* os; VarDeclaration* lastVar; + bool inCtfeBlock; GotoStatement* syntaxCopy() override; void accept(Visitor* v) override; }; @@ -4388,6 +4426,7 @@ class IfStatement final : public Statement Loc endloc; IfStatement* syntaxCopy() override; void accept(Visitor* v) override; + bool isIfCtfeBlock(); }; class ImportStatement final : public Statement @@ -4433,6 +4472,7 @@ class LabelStatement final : public Statement Statement* gotoTarget; void* extra; bool breaks; + bool inCtfeBlock; LabelStatement* syntaxCopy() override; void accept(Visitor* v) override; }; @@ -4831,6 +4871,7 @@ struct ASTCodegen final using AddrExp = ::AddrExp; using AndAssignExp = ::AndAssignExp; using AndExp = ::AndExp; + using ArgumentList = ::ArgumentList; using ArrayExp = ::ArrayExp; using ArrayLengthExp = ::ArrayLengthExp; using ArrayLiteralExp = ::ArrayLiteralExp; @@ -5378,9 +5419,8 @@ class AttribDeclaration : public Dsymbol bool hasPointers() final override; bool hasStaticCtorOrDtor() final override; void checkCtorConstInit() final override; - void addLocalClass(Array* aclasses) final override; void addObjcSymbols(Array* classes, Array* categories) final override; - AttribDeclaration* isAttribDeclaration() final override; + AttribDeclaration* isAttribDeclaration() override; void accept(Visitor* v) override; }; @@ -5517,6 +5557,7 @@ class StaticIfDeclaration final : public ConditionalDeclaration void setScope(Scope* sc) override; void importAll(Scope* sc) override; const char* kind() const override; + StaticIfDeclaration* isStaticIfDeclaration() override; void accept(Visitor* v) override; }; @@ -5776,7 +5817,6 @@ class ClassDeclaration : public AggregateDeclaration bool isAbstract(); virtual int32_t vtblOffset() const; const char* kind() const override; - void addLocalClass(Array* aclasses) final override; void addObjcSymbols(Array* classes, Array* categories) final override; Dsymbol* vtblsym; Dsymbol* vtblSymbol(); @@ -5905,7 +5945,7 @@ class VarDeclaration : public Declaration public: Initializer* _init; Array nestedrefs; - Dsymbol* aliassym; + TupleDeclaration* aliasTuple; VarDeclaration* lastVar; Expression* edtor; IntRange* range; @@ -5939,6 +5979,12 @@ class VarDeclaration : public Declaration bool doNotInferReturn(bool v); bool isArgDtorVar() const; bool isArgDtorVar(bool v); + bool isCmacro() const; + bool isCmacro(bool v); + bool inClosure() const; + bool inClosure(bool v); + bool inAlignSection() const; + bool inAlignSection(bool v); private: uint16_t bitFields; public: @@ -6343,6 +6389,8 @@ struct ModuleDeclaration final } }; +extern void getLocalClasses(Module* mod, Array& aclasses); + extern void gendocfile(Module* m); struct Scope final @@ -6518,6 +6566,7 @@ class StructDeclaration : public AggregateDeclaration const char* kind() const override; void finalizeSize() final override; bool isPOD(); + bool hasCopyConstruction(); StructDeclaration* isStructDeclaration() final override; void accept(Visitor* v) override; uint32_t numArgTypes() const; @@ -6663,7 +6712,7 @@ class TemplateDeclaration final : public ScopeDsymbol Visibility visible() override; const char* getConstraintEvalError(const char*& tip); Scope* scopeForTemplateParameters(TemplateInstance* ti, Scope* sc); - MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration* td2, Array* fargs); + MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration* td2, ArgumentList argumentList); RootObject* declareParameter(Scope* sc, TemplateParameter* tp, RootObject* o); TemplateDeclaration* isTemplateDeclaration() override; TemplateTupleParameter* isVariadic(); @@ -6868,7 +6917,7 @@ class VersionSymbol final : public Dsymbol void accept(Visitor* v) override; }; -extern void expandTuples(Array* exps); +extern void expandTuples(Array* exps, Array* names = nullptr); struct UnionExp final { @@ -6951,6 +7000,7 @@ class RealExp final : public Expression static RealExp* create(const Loc& loc, _d_real value, Type* type); static void emplace(UnionExp* pue, const Loc& loc, _d_real value, Type* type); bool equals(const RootObject* const o) const override; + bool isIdentical(const Expression* const e) const override; dinteger_t toInteger() override; uinteger_t toUInteger() override; _d_real toReal() override; @@ -6967,6 +7017,7 @@ class ComplexExp final : public Expression static ComplexExp* create(const Loc& loc, complex_t value, Type* type); static void emplace(UnionExp* pue, const Loc& loc, complex_t value, Type* type); bool equals(const RootObject* const o) const override; + bool isIdentical(const Expression* const e) const override; dinteger_t toInteger() override; uinteger_t toUInteger() override; _d_real toReal() override; @@ -7171,10 +7222,12 @@ class NewExp final : public Expression Expression* thisexp; Type* newtype; Array* arguments; + Array* names; Expression* argprefix; CtorDeclaration* member; bool onstack; bool thrownew; + Expression* lowering; static NewExp* create(const Loc& loc, Expression* thisexp, Type* newtype, Array* arguments); NewExp* syntaxCopy() override; void accept(Visitor* v) override; @@ -7414,6 +7467,7 @@ class CallExp final : public UnaExp { public: Array* arguments; + Array* names; FuncDeclaration* f; bool directcall; bool inDebugStatement; @@ -7925,6 +7979,7 @@ class NOGCVisitor final : public StoppableVisitor public: using StoppableVisitor::visit; FuncDeclaration* f; + bool checkOnly; bool err; void doCond(Expression* exp); void visit(Expression* e) override; @@ -8143,9 +8198,9 @@ extern Target target; extern bool tpsemantic(TemplateParameter* tp, Scope* sc, Array* parameters); -extern void genTypeInfo(Expression* e, const Loc& loc, Type* torig, Scope* sc); +extern void genTypeInfo(Expression* e, const Loc& loc, Type* torig, Scope* sc, bool genObjCode = true); -extern Type* getTypeInfoType(const Loc& loc, Type* t, Scope* sc); +extern Type* getTypeInfoType(const Loc& loc, Type* t, Scope* sc, bool genObjCode = true); extern bool builtinTypeInfo(Type* t); @@ -8563,6 +8618,8 @@ struct Id final static Identifier* criticalexit; static Identifier* _d_delThrowable; static Identifier* _d_newThrowable; + static Identifier* _d_newclassT; + static Identifier* _d_newclassTTrace; static Identifier* _d_assert_fail; static Identifier* dup; static Identifier* _aaApply; @@ -8682,6 +8739,7 @@ struct Id final static Identifier* isLazy; static Identifier* hasMember; static Identifier* identifier; + static Identifier* fullyQualifiedName; static Identifier* getProtection; static Identifier* getVisibility; static Identifier* parent; @@ -8849,7 +8907,7 @@ struct CTFloat final static bool isSNaN(_d_real r); static bool isInfinity(_d_real r); static _d_real parse(const char* literal, bool& isOutOfRange); - static int32_t sprint(char* str, char fmt, _d_real x); + static int32_t sprint(char* str, size_t size, char fmt, _d_real x); static _d_real zero; static _d_real one; static _d_real minusone; diff --git a/dmd/func.d b/dmd/func.d index e54a2fb79f7..693005087ff 100644 --- a/dmd/func.d +++ b/dmd/func.d @@ -228,7 +228,7 @@ private struct FUNCFLAG bool inlineScanned; /// function has been scanned for inline possibilities bool inferScope; /// infer 'scope' for parameters bool hasCatches; /// function has try-catch statements - bool isCompileTimeOnly; /// is a compile time only function; no code will be generated for it + bool skipCodegen; /// do not generate code for this function. bool printf; /// is a printf-like function bool scanf; /// is a scanf-like function bool noreturn; /// the function does not return @@ -243,6 +243,8 @@ private struct FUNCFLAG bool hasAlwaysInlines; /// Contains references to functions that must be inlined bool isCrtCtor; /// Has attribute pragma(crt_constructor) bool isCrtDtor; /// Has attribute pragma(crt_destructor) + bool hasEscapingSiblings;/// Has sibling functions that escape + bool computedEscapingSiblings; /// `hasEscapingSiblings` has been computed } /*********************************************************** @@ -367,6 +369,12 @@ version (IN_LLVM) {} else GotoStatements* gotos; /// Gotos with forward references + version (MARS) + { + VarDeclarations* alignSectionVars; /// local variables with alignment needs larger than stackAlign + Symbol* salignSection; /// pointer to aligned section, if any + } + /// set if this is a known, builtin function we can evaluate at compile time BUILTIN builtin = BUILTIN.unknown; @@ -1088,12 +1096,13 @@ version (IN_LLVM) * match 'this' is at least as specialized as g * 0 g is more specialized than 'this' */ - final MATCH leastAsSpecialized(FuncDeclaration g) + final MATCH leastAsSpecialized(FuncDeclaration g, Identifiers* names) { enum LOG_LEASTAS = 0; static if (LOG_LEASTAS) { - printf("%s.leastAsSpecialized(%s)\n", toChars(), g.toChars()); + import core.stdc.stdio : printf; + printf("%s.leastAsSpecialized(%s, %s)\n", toChars(), g.toChars(), names ? names.toChars() : "null"); printf("%s, %s\n", type.toChars(), g.type.toChars()); } @@ -1138,7 +1147,7 @@ version (IN_LLVM) args.push(e); } - MATCH m = tg.callMatch(null, args[], 1); + MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1); if (m > MATCH.nomatch) { /* A variadic parameter list is less specialized than a @@ -2028,6 +2037,7 @@ version (IN_LLVM) if (!sc.intypeof && !(sc.flags & SCOPE.compile)) { siblingCallers.push(fdthis); + computedEscapingSiblings = false; } } } @@ -2077,8 +2087,7 @@ version (IN_LLVM) * is already set to `true` upon entering this function when the * struct/class refers to a local variable and a closure is needed. */ - - //printf("FuncDeclaration::needsClosure() %s\n", toChars()); + //printf("FuncDeclaration::needsClosure() %s\n", toPrettyChars()); if (requiresClosure) goto Lyes; @@ -2155,7 +2164,7 @@ version (IN_LLVM) */ extern (C++) final bool checkClosure() { - //printf("checkClosure() %s\n", toChars()); + //printf("checkClosure() %s\n", toPrettyChars()); if (!needsClosure()) return false; @@ -2369,6 +2378,7 @@ version (IN_LLVM) * base.in(); * assert(false, "Logic error: " ~ thr.msg); * } + * } */ foreach (fdv; foverrides) @@ -2876,6 +2886,12 @@ version (IN_LLVM) return false; if (v.nestedrefs.length && needsClosure()) return false; + // don't know if the return storage is aligned + version (MARS) + { + if (alignSectionVars && (*alignSectionVars).contains(v)) + return false; + } // The variable type needs to be equivalent to the return type. if (!v.type.equivalent(tf.next)) return false; @@ -3176,14 +3192,15 @@ enum FuncResolveFlag : ubyte * s = instantiation symbol * tiargs = initial list of template arguments * tthis = if !NULL, the `this` argument type - * fargs = arguments to function + * argumentList = arguments to function * flags = see $(LREF FuncResolveFlag). * Returns: * if match is found, then function symbol, else null */ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, - Objects* tiargs, Type tthis, Expressions* fargs, FuncResolveFlag flags) + Objects* tiargs, Type tthis, ArgumentList argumentList, FuncResolveFlag flags) { + auto fargs = argumentList.arguments; if (!s) return null; // no match @@ -3201,6 +3218,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, printf("\t%s: %s\n", arg.toChars(), arg.type.toChars()); } } + printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null"); } if (tiargs && arrayObjectIsError(tiargs)) @@ -3211,7 +3229,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, return null; MatchAccumulator m; - functionResolve(m, s, loc, sc, tiargs, tthis, fargs, null); + functionResolve(m, s, loc, sc, tiargs, tthis, argumentList); auto orig_s = s; if (m.last > MATCH.nomatch && m.lastf) @@ -3334,7 +3352,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, } const(char)* failMessage; - functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage); + functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage); if (failMessage) { .error(loc, "%s `%s%s%s` is not callable using argument types `%s`", @@ -3380,7 +3398,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, if (auto baseFunction = baseClass.search(baseClass.loc, fd.ident)) { MatchAccumulator mErr; - functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, fargs, null); + functionResolve(mErr, baseFunction, loc, sc, tiargs, baseClass.type, argumentList); if (mErr.last > MATCH.nomatch && mErr.lastf) { errorSupplemental(loc, "%s `%s` hides base class function `%s`", @@ -3394,7 +3412,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, } } const(char)* failMessage; - functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage); + functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage); if (failMessage) errorSupplemental(loc, failMessage); } @@ -3411,8 +3429,10 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s, private void printCandidates(Decl)(const ref Loc loc, Decl declaration, bool showDeprecated) if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration)) { - // max num of overloads to print (-v overrides this). - enum int DisplayLimit = 5; + // max num of overloads to print (-v or -verror-supplements overrides this). + const int DisplayLimit = !global.params.verbose ? + (global.params.errorSupplementLimit ? global.params.errorSupplementLimit : int.max) + : int.max; const(char)* constraintsTip; // determine if the first candidate was printed int printed; @@ -3668,6 +3688,9 @@ private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, FuncDeclaration f; } + if (f.computedEscapingSiblings) + return f.hasEscapingSiblings; + PrevSibling ps; ps.p = cast(PrevSibling*)p; ps.f = f; @@ -3709,6 +3732,8 @@ private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, prev = prev.p; } } + f.hasEscapingSiblings = bAnyClosures; + f.computedEscapingSiblings = true; //printf("\t%d\n", bAnyClosures); return bAnyClosures; } @@ -3908,7 +3933,7 @@ extern (C++) final class CtorDeclaration : FuncDeclaration { super(loc, endloc, Id.ctor, stc, type); this.isCpCtor = isCpCtor; - //printf("CtorDeclaration(loc = %s) %s\n", loc.toChars(), toChars()); + //printf("CtorDeclaration(loc = %s) %s %p\n", loc.toChars(), toChars(), this); } override CtorDeclaration syntaxCopy(Dsymbol s) @@ -4399,6 +4424,26 @@ extern (C++) final class NewDeclaration : FuncDeclaration } } +/************************************** + * When a traits(compiles) is used on a function literal call + * we need to take into account if the body of the function + * violates any attributes, however, we must not affect the + * attribute inference on the outer function. The attributes + * of the function literal still need to be inferred, therefore + * we need a way to check for the scope that the traits compiles + * introduces. + * + * Params: + * sc = scope to be checked for + * + * Returns: `true` if the provided scope is the root + * of the traits compiles list of scopes. + */ +bool isRootTraitsCompilesScope(Scope* sc) +{ + return (sc.flags & SCOPE.compile) && !(sc.func.flags & SCOPE.compile); +} + /************************************** * A statement / expression in this scope is not `@safe`, * so mark the enclosing function as `@system` @@ -4441,7 +4486,7 @@ bool setUnsafe(Scope* sc, } - if (sc.flags & SCOPE.compile) // __traits(compiles, x) + if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x) { if (sc.func.isSafeBypassingInference()) { diff --git a/dmd/globals.d b/dmd/globals.d index edc713f43e7..7c7a7d89d28 100644 --- a/dmd/globals.d +++ b/dmd/globals.d @@ -15,6 +15,8 @@ import core.stdc.stdint; import dmd.root.array; import dmd.root.filename; import dmd.common.outbuffer; +import dmd.errorsink; +import dmd.errors; import dmd.file_manager; import dmd.identifier; import dmd.location; @@ -177,7 +179,7 @@ extern (C++) struct Param bool logo; // print compiler logo // Options for `-preview=/-revert=` - FeatureState useDIP25; // implement https://wiki.dlang.org/DIP25 + FeatureState useDIP25 = FeatureState.enabled; // implement https://wiki.dlang.org/DIP25 FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params bool ehnogc; // use @nogc exception handling bool useDIP1021; // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md @@ -210,6 +212,7 @@ extern (C++) struct Param CHECKACTION checkAction = CHECKACTION.D; // action to take when bounds, asserts or switch defaults are violated uint errorLimit = 20; + uint errorSupplementLimit = 6; // Limit the number of supplemental messages for each error (0 means unlimited) const(char)[] argv0; // program name Array!(const(char)*) modFileAliasStrings; // array of char*'s of -I module filename alias strings @@ -383,6 +386,8 @@ version (IN_LLVM) {} else /// Cache files read from disk FileManager fileManager; + ErrorSink errorSink; /// where the error messages go + version (IN_LLVM) { const(char)[] ldc_version; @@ -451,6 +456,8 @@ else extern (C++) void _init() { + global.errorSink = new ErrorSinkCompiler; + this.fileManager = new FileManager(); version (MARS) { diff --git a/dmd/globals.h b/dmd/globals.h index f69a51fcdbb..8019a59d769 100644 --- a/dmd/globals.h +++ b/dmd/globals.h @@ -30,6 +30,7 @@ enum OUTPUTFLAG // Can't include arraytypes.h here, need to declare these directly. template struct Array; +class ErrorSink; class FileManager; struct Loc; @@ -206,6 +207,7 @@ struct Param CHECKACTION checkAction; // action to take when bounds, asserts or switch defaults are violated unsigned errorLimit; + unsigned errorSupplementLimit; // Limit the number of supplemental messages for each error (0 means unlimited) DString argv0; // program name Array modFileAliasStrings; // array of char*'s of -I module filename alias strings @@ -355,6 +357,7 @@ struct Global unsigned varSequenceNumber; FileManager* fileManager; + ErrorSink* errorSink; // where the error messages go #if IN_LLVM DString ldc_version; diff --git a/dmd/gluelayer.d b/dmd/gluelayer.d index 4a87ae52076..efe58a475d6 100644 --- a/dmd/gluelayer.d +++ b/dmd/gluelayer.d @@ -93,6 +93,7 @@ else version (IN_GCC) extern (C++) { Statement asmSemantic(AsmStatement s, Scope* sc); + void toObjFile(Dsymbol ds, bool multiobj); } // stubs diff --git a/dmd/hdrgen.d b/dmd/hdrgen.d index d931581610f..d63b4ff3689 100644 --- a/dmd/hdrgen.d +++ b/dmd/hdrgen.d @@ -65,6 +65,7 @@ struct HdrGenState int autoMember; int forStmtInit; int insideFuncBody; + int insideAggregate; bool declstring; // set while declaring alias for string,wstring or dstring EnumDeclaration inEnumDecl; @@ -149,7 +150,7 @@ public: OutBuffer* buf; HdrGenState* hgs; - extern (D) this(OutBuffer* buf, HdrGenState* hgs) + extern (D) this(OutBuffer* buf, HdrGenState* hgs) scope { this.buf = buf; this.hgs = hgs; @@ -810,7 +811,7 @@ public: OutBuffer* buf; HdrGenState* hgs; - extern (D) this(OutBuffer* buf, HdrGenState* hgs) + extern (D) this(OutBuffer* buf, HdrGenState* hgs) scope { this.buf = buf; this.hgs = hgs; @@ -1411,8 +1412,10 @@ public: buf.writeByte('{'); buf.writenl(); buf.level++; + hgs.insideAggregate++; foreach (s; *d.members) s.accept(this); + hgs.insideAggregate--; buf.level--; buf.writeByte('}'); buf.writenl(); @@ -1433,8 +1436,10 @@ public: buf.writeByte('{'); buf.writenl(); buf.level++; + hgs.insideAggregate++; foreach (s; *d.members) s.accept(this); + hgs.insideAggregate--; buf.level--; buf.writeByte('}'); } @@ -1526,6 +1531,21 @@ public: void visitVarDecl(VarDeclaration v, bool anywritten) { + const bool isextern = hgs.hdrgen && + !hgs.insideFuncBody && + !hgs.tpltMember && + !hgs.insideAggregate && + !(v.storage_class & STC.manifest); + + void vinit(VarDeclaration v) + { + auto ie = v._init.isExpInitializer(); + if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) + (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); + else + v._init.initializerToBuffer(buf, hgs); + } + if (anywritten) { buf.writestring(", "); @@ -1533,21 +1553,30 @@ public: } else { - if (stcToBuffer(buf, v.storage_class)) + const bool useTypeof = isextern && v._init && !v.type; + auto stc = v.storage_class; + if (isextern) + stc |= STC.extern_; + if (useTypeof) + stc &= ~STC.auto_; + if (stcToBuffer(buf, stc)) buf.writeByte(' '); if (v.type) typeToBuffer(v.type, v.ident, buf, hgs); + else if (useTypeof) + { + buf.writestring("typeof("); + vinit(v); + buf.writestring(") "); + buf.writestring(v.ident.toString()); + } else buf.writestring(v.ident.toString()); } - if (v._init) + if (v._init && !isextern) { buf.writestring(" = "); - auto ie = v._init.isExpInitializer(); - if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit)) - (cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs); - else - v._init.initializerToBuffer(buf, hgs); + vinit(v); } } @@ -1562,7 +1591,10 @@ public: if (hgs.hdrgen) { // if the return type is missing (e.g. ref functions or auto) - if (!tf.next || f.storage_class & STC.auto_) + // https://issues.dlang.org/show_bug.cgi?id=20090 + // constructors are an exception: they don't have an explicit return + // type but we still don't output the body. + if ((!f.isCtorDeclaration() && !tf.next) || f.storage_class & STC.auto_) { hgs.autoMember++; bodyToBuffer(f); @@ -2141,7 +2173,7 @@ private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hg if (e.arguments && e.arguments.length) { buf.writeByte('('); - argsToBuffer(e.arguments, buf, hgs); + argsToBuffer(e.arguments, buf, hgs, null, e.names); buf.writeByte(')'); } } @@ -2445,7 +2477,7 @@ private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hg else expToBuffer(e.e1, precedence[e.op], buf, hgs); buf.writeByte('('); - argsToBuffer(e.arguments, buf, hgs); + argsToBuffer(e.arguments, buf, hgs, null, e.names); buf.writeByte(')'); } @@ -2688,7 +2720,7 @@ void floatToBuffer(Type type, const real_t value, OutBuffer* buf, const bool all Plus one for rounding. */ const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1; char[BUFFER_LEN] buffer = void; - CTFloat.sprint(buffer.ptr, 'g', value); + CTFloat.sprint(buffer.ptr, BUFFER_LEN, 'g', value); assert(strlen(buffer.ptr) < BUFFER_LEN); if (allowHex) { @@ -2696,7 +2728,7 @@ void floatToBuffer(Type type, const real_t value, OutBuffer* buf, const bool all real_t r = CTFloat.parse(buffer.ptr, isOutOfRange); //assert(!isOutOfRange); // test/compilable/test22725.c asserts here if (r != value) // if exact duplication - CTFloat.sprint(buffer.ptr, 'a', value); + CTFloat.sprint(buffer.ptr, BUFFER_LEN, 'a', value); } buf.writestring(buffer.ptr); if (buffer.ptr[strlen(buffer.ptr) - 1] == '.') @@ -2738,7 +2770,7 @@ public: OutBuffer* buf; HdrGenState* hgs; - extern (D) this(OutBuffer* buf, HdrGenState* hgs) + extern (D) this(OutBuffer* buf, HdrGenState* hgs) scope { this.buf = buf; this.hgs = hgs; @@ -2819,7 +2851,7 @@ public: OutBuffer* buf; HdrGenState* hgs; - extern (D) this(OutBuffer* buf, HdrGenState* hgs) + extern (D) this(OutBuffer* buf, HdrGenState* hgs) scope { this.buf = buf; this.hgs = hgs; @@ -3286,8 +3318,14 @@ private void parameterToBuffer(Parameter p, OutBuffer* buf, HdrGenState* hgs) /************************************************** * Write out argument list to buf. + * Params: + * expressions = argument list + * 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 */ -private void argsToBuffer(Expressions* expressions, OutBuffer* buf, HdrGenState* hgs, Expression basis = null) +private void argsToBuffer(Expressions* expressions, OutBuffer* buf, HdrGenState* hgs, Expression basis = null, Identifiers* names = null) { if (!expressions || !expressions.length) return; @@ -3297,6 +3335,12 @@ private void argsToBuffer(Expressions* expressions, OutBuffer* buf, HdrGenState* { if (i) buf.writestring(", "); + + if (names && i < names.length && (*names)[i]) + { + buf.writestring((*names)[i].toString()); + buf.writestring(": "); + } if (!el) el = basis; if (el) diff --git a/dmd/iasmgcc.d b/dmd/iasmgcc.d index baf6b14b97d..f8c88ab536e 100644 --- a/dmd/iasmgcc.d +++ b/dmd/iasmgcc.d @@ -17,6 +17,7 @@ import dmd.arraytypes; import dmd.astcodegen; import dmd.dscope; import dmd.errors; +import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.identifier; @@ -72,7 +73,7 @@ int parseExtAsmOperands(Parser)(Parser p, GccAsmStatement s) } else { - p.error(s.loc, "expected identifier after `[`"); + p.eSink.error(s.loc, "expected identifier after `[`"); goto Lerror; } // Look for closing `]` @@ -116,7 +117,7 @@ int parseExtAsmOperands(Parser)(Parser p, GccAsmStatement s) break; default: - p.error("expected constant string constraint for operand, not `%s`", + p.eSink.error(p.token.loc, "expected constant string constraint for operand, not `%s`", p.token.toChars()); goto Lerror; } @@ -167,7 +168,7 @@ Expressions *parseExtAsmClobbers(Parser)(Parser p) break; default: - p.error("expected constant string constraint for clobber name, not `%s`", + p.eSink.error(p.token.loc, "expected constant string constraint for clobber name, not `%s`", p.token.toChars()); goto Lerror; } @@ -214,7 +215,7 @@ Identifiers *parseExtAsmGotoLabels(Parser)(Parser p) break; default: - p.error("expected identifier for goto label name, not `%s`", + p.eSink.error(p.token.loc, "expected identifier for goto label name, not `%s`", p.token.toChars()); goto Lerror; } @@ -301,7 +302,7 @@ Ldone: extern (C++) public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc) { //printf("GccAsmStatement.semantic()\n"); - scope p = new Parser!ASTCodegen(sc._module, ";", false); + scope p = new Parser!ASTCodegen(sc._module, ";", false, global.errorSink); // Make a safe copy of the token list before parsing. Token *toklist = null; @@ -384,6 +385,9 @@ unittest { import dmd.mtype : TypeBasic; + if (!global.errorSink) + global.errorSink = new ErrorSinkCompiler; + uint errors = global.startGagging(); scope(exit) global.endGagging(errors); @@ -406,7 +410,7 @@ unittest { const errors = global.errors; scope gas = new GccAsmStatement(Loc.initial, tokens); - scope p = new Parser!ASTCodegen(null, ";", false); + scope p = new Parser!ASTCodegen(null, ";", false, global.errorSink); p.token = *tokens; p.parseGccAsm(gas); return global.errors - errors; @@ -416,7 +420,7 @@ unittest static void parseAsm(string input, bool expectError) { // Generate tokens from input test. - scope p = new Parser!ASTCodegen(null, input, false); + scope p = new Parser!ASTCodegen(null, input, false, global.errorSink); p.nextToken(); Token* toklist = null; diff --git a/dmd/id.d b/dmd/id.d index d0c897e9e73..fd60a569ac5 100644 --- a/dmd/id.d +++ b/dmd/id.d @@ -313,6 +313,8 @@ immutable Msgtable[] msgtable = { "__ArrayDtor" }, { "_d_delThrowable" }, { "_d_newThrowable" }, + { "_d_newclassT" }, + { "_d_newclassTTrace" }, { "_d_assert_fail" }, { "dup" }, { "_aaApply" }, @@ -455,6 +457,7 @@ immutable Msgtable[] msgtable = { "isLazy" }, { "hasMember" }, { "identifier" }, + { "fullyQualifiedName" }, { "getProtection" }, { "getVisibility" }, { "parent" }, diff --git a/dmd/initsem.d b/dmd/initsem.d index 572753b2dd8..18b10b41a2d 100644 --- a/dmd/initsem.d +++ b/dmd/initsem.d @@ -135,111 +135,19 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ sd.size(i.loc); if (sd.sizeok != Sizeok.done) return err(); - const nfields = sd.nonHiddenFields(); - //expandTuples for non-identity arguments? - auto elements = new Expressions(nfields); - auto elems = (*elements)[]; - foreach (ref elem; elems) - elem = null; - - // Run semantic for explicitly given initializers - // TODO: this part is slightly different from StructLiteralExp::semantic. - bool errors = false; - size_t fieldi = 0; - foreach (j, id; i.field[]) - { - if (id) - { - /* Determine `fieldi` that `id` matches - */ - Dsymbol s = sd.search(i.loc, id); - if (!s) - { - s = sd.search_correct(id); - const initLoc = i.value[j].loc; - if (s) - error(initLoc, "`%s` is not a member of `%s`, did you mean %s `%s`?", id.toChars(), sd.toChars(), s.kind(), s.toChars()); - else - error(initLoc, "`%s` is not a member of `%s`", id.toChars(), sd.toChars()); - return err(); - } - s.checkDeprecated(i.loc, sc); - s = s.toAlias(); - - // Find out which field index `s` is - for (fieldi = 0; 1; fieldi++) - { - if (fieldi >= nfields) - { - error(i.loc, "`%s.%s` is not a per-instance initializable field", sd.toChars(), s.toChars()); - return err(); - } - if (s == sd.fields[fieldi]) - break; - } - } - if (j >= nfields) - { - error(i.value[j].loc, "too many initializers for `%s`", sd.toChars()); - return err(); - } - - VarDeclaration vd = sd.fields[fieldi]; - if (elems[fieldi]) - { - error(i.value[j].loc, "duplicate initializer for field `%s`", vd.toChars()); - errors = true; - elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors - ++fieldi; - continue; - } - - // Check for @safe violations - if (vd.type.hasPointers) - { - if ((!t.alignment.isDefault() && t.alignment.get() < target.ptrsize || - (vd.offset & (target.ptrsize - 1)))) - { - if (sc.setUnsafe(false, i.value[j].loc, - "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, vd)) - { - errors = true; - elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors - ++fieldi; - continue; - } - } - } - - // Check for overlapping initializations (can happen with unions) - foreach (k, v2; sd.fields[0 .. nfields]) - { - if (vd.isOverlappedWith(v2) && elems[k]) - { - error(elems[k].loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars()); - errors = true; - continue; - } - } - - // Convert initializer to Expression `ex` - assert(sc); - auto tm = vd.type.addMod(t.mod); - auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret); - auto ex = iz.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0); - if (ex.op == EXP.error) - { - errors = true; - elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors - ++fieldi; - continue; - } + Expression getExp(size_t j, Type fieldType) + { + // Convert initializer to Expression `ex` + auto tm = fieldType.addMod(t.mod); + auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret); + auto ex = iz.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0); + if (ex.op != EXP.error) i.value[j] = iz; - elems[fieldi] = doCopyOrMove(sc, ex); - ++fieldi; - } - if (errors) + return ex; + } + auto elements = resolveStructLiteralNamedArgs(sd, t, sc, i.loc, i.field[], &getExp, (size_t j) => i.value[j].loc); + if (!elements) return err(); // Make a StructLiteralExp out of elements[] @@ -1514,3 +1422,141 @@ private bool hasNonConstPointers(Expression e) } return false; } + +/** +Given the names and values of a `StructInitializer` or `CallExp`, +resolve it to a list of expressions to construct a `StructLiteralExp`. + +Params: + sd = struct + 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 + +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 +) +{ + //expandTuples for non-identity arguments? + const nfields = sd.nonHiddenFields(); + auto elements = new Expressions(nfields); + auto elems = (*elements)[]; + foreach (ref elem; elems) + elem = null; + + // Run semantic for explicitly given initializers + // TODO: this part is slightly different from StructLiteralExp::semantic. + bool errors = false; + size_t fieldi = 0; + foreach (j, id; names) + { + const argLoc = getLoc(j); + if (id) + { + // Determine `fieldi` that `id` matches + Dsymbol s = sd.search(iloc, id); + if (!s) + { + 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()); + else + error(argLoc, "`%s` is not a member of `%s`", id.toChars(), sd.toChars()); + return null; + } + s.checkDeprecated(iloc, sc); + s = s.toAlias(); + + // Find out which field index `s` is + for (fieldi = 0; 1; fieldi++) + { + if (fieldi >= nfields) + { + error(iloc, "`%s.%s` is not a per-instance initializable field", sd.toChars(), s.toChars()); + return null; + } + if (s == sd.fields[fieldi]) + break; + } + } + if (nfields == 0) + { + error(argLoc, "initializer provided for struct `%s` with no fields", sd.toChars()); + return null; + } + if (j >= nfields) + { + error(argLoc, "too many initializers for `%s` with %d field%s", sd.toChars(), + cast(int) nfields, nfields != 1 ? "s".ptr : "".ptr); + return null; + } + + VarDeclaration vd = sd.fields[fieldi]; + if (elems[fieldi]) + { + error(argLoc, "duplicate initializer for field `%s`", vd.toChars()); + errors = true; + elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors + ++fieldi; + continue; + } + + // Check for @safe violations + if (vd.type.hasPointers) + { + if ((!t.alignment.isDefault() && t.alignment.get() < target.ptrsize || + (vd.offset & (target.ptrsize - 1)))) + { + if (sc.setUnsafe(false, argLoc, + "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, vd)) + { + errors = true; + elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors + ++fieldi; + continue; + } + } + } + + // Check for overlapping initializations (can happen with unions) + foreach (k, v2; sd.fields[0 .. nfields]) + { + if (vd.isOverlappedWith(v2) && elems[k]) + { + error(elems[k].loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars()); + enum errorMsg = "`struct` initializers that contain anonymous unions" ~ + " must initialize only the first member of a `union`. All subsequent" ~ + " non-overlapping fields are default initialized"; + if (!sd.isUnionDeclaration()) + .errorSupplemental(elems[k].loc, errorMsg); + errors = true; + continue; + } + } + + assert(sc); + + auto ex = getExp(j, vd.type); + + if (ex.op == EXP.error) + { + errors = true; + elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors + ++fieldi; + continue; + } + + elems[fieldi] = doCopyOrMove(sc, ex); + ++fieldi; + } + if (errors) + return null; + + return elements; +} diff --git a/dmd/inline.d b/dmd/inline.d index 4a5cb53278d..0a94d4669fe 100644 --- a/dmd/inline.d +++ b/dmd/inline.d @@ -142,7 +142,7 @@ private final class InlineDoState // inline result bool foundReturn; - this(Dsymbol parent, FuncDeclaration fd) + this(Dsymbol parent, FuncDeclaration fd) scope { this.parent = parent; this.fd = fd; @@ -167,7 +167,7 @@ public: enum asStatements = is(Result == Statement); - extern (D) this(InlineDoState ids) + extern (D) this(InlineDoState ids) scope { this.ids = ids; } @@ -952,7 +952,7 @@ public: Expression eresult; bool again; - extern (D) this() + extern (D) this() scope { } @@ -1670,6 +1670,9 @@ private bool canInline(FuncDeclaration fd, bool hasthis, bool hdrscan, bool stat assert(fd.semanticRun >= PASS.semantic3done); } + if (fd.skipCodegen) + return false; + final switch (statementsToo ? fd.inlineStatusStmt : fd.inlineStatusExp) { case ILS.yes: @@ -2304,7 +2307,7 @@ private bool expNeedsDtor(Expression exp) Expression exp; public: - extern (D) this(Expression exp) + extern (D) this(Expression exp) scope { this.exp = exp; } diff --git a/dmd/inlinecost.d b/dmd/inlinecost.d index 155196348af..f7c5565f97f 100644 --- a/dmd/inlinecost.d +++ b/dmd/inlinecost.d @@ -156,11 +156,11 @@ public: FuncDeclaration fd; int cost; // zero start for subsequent AST - extern (D) this() + extern (D) this() scope { } - extern (D) this(bool hasthis, bool hdrscan, bool allowAlloca, FuncDeclaration fd) + extern (D) this(bool hasthis, bool hdrscan, bool allowAlloca, FuncDeclaration fd) scope { this.hasthis = hasthis; this.hdrscan = hdrscan; @@ -168,7 +168,7 @@ public: this.fd = fd; } - extern (D) this(InlineCostVisitor icv) + extern (D) this(InlineCostVisitor icv) scope { nested = icv.nested; hasthis = icv.hasthis; @@ -264,6 +264,13 @@ public: return; } expressionInlineCost(s.condition); + + if (s.isIfCtfeBlock()) + { + cost = COST_MAX; + return; + } + /* Specifically allow: * if (condition) * return exp1; diff --git a/dmd/json.d b/dmd/json.d index 38e03e7d20d..2af7faec354 100644 --- a/dmd/json.d +++ b/dmd/json.d @@ -54,7 +54,7 @@ public: int indentLevel; const(char)[] filename; - extern (D) this(OutBuffer* buf) + extern (D) this(OutBuffer* buf) scope { this.buf = buf; } diff --git a/dmd/lambdacomp.d b/dmd/lambdacomp.d index c800273e2d4..885a27af905 100644 --- a/dmd/lambdacomp.d +++ b/dmd/lambdacomp.d @@ -120,7 +120,7 @@ public: OutBuffer buf; alias visit = SemanticTimeTransitiveVisitor.visit; - this(Scope* sc) + this(Scope* sc) scope { this.sc = sc; } diff --git a/dmd/lexer.d b/dmd/lexer.d index bd53433d6c8..f0f7872c2b2 100644 --- a/dmd/lexer.d +++ b/dmd/lexer.d @@ -22,8 +22,7 @@ import core.stdc.string; import core.stdc.time; import dmd.entity; -import dmd.errors; -import dmd.globals; +import dmd.errorsink; import dmd.id; import dmd.identifier; import dmd.location; @@ -69,6 +68,8 @@ class Lexer ubyte long_doublesize; /// size of C long double, 8 or D real.sizeof ubyte wchar_tsize; /// size of C wchar_t, 2 or 4 + ErrorSink eSink; /// send error messages through this interface + private { const(char)* base; // pointer to start of buffer @@ -103,12 +104,14 @@ class Lexer * endoffset = the last offset to read into base[] * doDocComment = handle documentation comments * commentToken = comments become TOK.comment's + * errorSink = where error messages go, must not be null * vendor = name of the vendor * versionNumber = version of the caller */ this(const(char)* filename, const(char)* base, size_t begoffset, size_t endoffset, bool doDocComment, bool commentToken, - const(char)[] vendor = "DLF", uint versionNumber = 1) pure + ErrorSink errorSink, + const(char)[] vendor = "DLF", uint versionNumber = 1) pure scope { scanloc = Loc(filename, 1, 1); // debug printf("Lexer::Lexer(%p)\n", base); @@ -123,6 +126,8 @@ class Lexer this.tokenizeNewlines = false; this.inTokenStringConstant = 0; this.lastDocLine = 0; + this.eSink = errorSink; + assert(errorSink); this.versionNumber = versionNumber; this.vendor = vendor; //initKeywords(); @@ -163,16 +168,18 @@ class Lexer * Alternative entry point for DMDLIB, adds `whitespaceToken` */ this(const(char)* filename, const(char)* base, size_t begoffset, size_t endoffset, - bool doDocComment, bool commentToken, bool whitespaceToken) + bool doDocComment, bool commentToken, bool whitespaceToken, + ErrorSink errorSink + ) { - this(filename, base, begoffset, endoffset, doDocComment, commentToken); + this(filename, base, begoffset, endoffset, doDocComment, commentToken, errorSink); this.whitespaceToken = whitespaceToken; } /****************** * Used for unittests for a mock Lexer */ - this() { } + this(ErrorSink errorSink) scope { assert(errorSink); this.eSink = errorSink; } /************************************** * Reset lexer to lex #define's @@ -565,7 +572,7 @@ class Lexer else if (*t.ptr == '_') // if special identifier token { // Lazy initialization - TimeStampInfo.initialize(t.loc); + TimeStampInfo.initialize(t.loc, eSink); if (id == Id.DATE) { @@ -1616,7 +1623,7 @@ class Lexer else if (isspace(delimright)) error("delimited string must end in `\"`"); else - error("delimited string must end in `%c\"`", delimright); + error(token.loc, "delimited string must end in `%c\"`", delimright); result.setString(stringbuffer); stringPostfix(result); } @@ -1909,10 +1916,10 @@ class Lexer if (idx < n && !msg) msg = utf_decodeChar(str, idx, d2); if (msg) - error(loc, "%s", msg); + error(loc, "%.*s", cast(int)msg.length, msg.ptr); else if (idx < n) error(loc, "max number of chars in 16 bit character literal is 2, had %d", - (n + 1) >> 1); + cast(int)((n + 1) >> 1)); else if (d1 > 0x1_0000) error(loc, "%d does not fit in 16 bits", d1); else if (d2 > 0x1_0000) @@ -1927,10 +1934,10 @@ class Lexer size_t idx; auto msg = utf_decodeChar(str, idx, d); if (msg) - error(loc, "%s", msg); + error(loc, "%.*s", cast(int)msg.length, msg.ptr); else if (idx < n) error(loc, "max number of chars in 32 bit character literal is 1, had %d", - (n + 3) >> 2); + cast(int)((n + 3) >> 2)); u = d; break; @@ -2137,7 +2144,7 @@ class Lexer Ldone: if (errorDigit) { - error("%s digit expected, not `%c`", base == 2 ? "binary".ptr : + error(token.loc, "%s digit expected, not `%c`", base == 2 ? "binary".ptr : base == 8 ? "octal".ptr : "decimal".ptr, errorDigit); err = true; @@ -2149,7 +2156,7 @@ class Lexer } if ((base == 2 && !anyBinaryDigitsNoSingleUS) || (base == 16 && !anyHexDigitsNoSingleUS)) - error("`%.*s` isn't a valid integer literal, use `%.*s0` instead", cast(int)(p - start), start, 2, start); + error(token.loc, "`%.*s` isn't a valid integer literal, use `%.*s0` instead", cast(int)(p - start), start, 2, start); t.unsvalue = n; @@ -2202,7 +2209,7 @@ class Lexer // can't translate invalid octal value, just show a generic message error("octal literals larger than 7 are no longer supported"); else - error("octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!\"%llo%.*s\"` instead", + error(token.loc, "octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!\"%llo%.*s\"` instead", n, cast(int)(p - psuffix), psuffix, n, cast(int)(p - psuffix), psuffix); } TOK result; @@ -2619,7 +2626,7 @@ class Lexer TOK.float80Literal: "`real` for the current target".ptr][result]; error(scanloc, "number `%s%s` is not representable as a %s", sbufptr, suffix, type); const char* extra = result == TOK.float64Literal ? "`real` literals can be written using the `L` suffix. " : ""; - errorSupplemental(scanloc, "%shttps://dlang.org/spec/lex.html#floatliteral", extra); + eSink.errorSupplemental(scanloc, "%shttps://dlang.org/spec/lex.html#floatliteral", extra); } debug { @@ -2647,28 +2654,29 @@ class Lexer return scanloc; } - final void error(const(char)* format, ...) + void error(T...)(const(char)* format, T args) + { + eSink.error(token.loc, format, args); + } + + void error(T...)(const ref Loc loc, const(char)* format, T args) + { + eSink.error(loc, format, args); + } + + void deprecation(T...)(const ref Loc loc, const(char)* format, T args) { - va_list args; - va_start(args, format); - .verror(token.loc, format, args); - va_end(args); + eSink.deprecation(loc, format, args); } - final void error(const ref Loc loc, const(char)* format, ...) + void deprecation(T...)(const(char)* format, T args) { - va_list args; - va_start(args, format); - .verror(loc, format, args); - va_end(args); + eSink.deprecation(token.loc, format, args); } - final void deprecation(const(char)* format, ...) + void deprecationSupplemental(T...)(const(char)* format, T args) { - va_list args; - va_start(args, format); - .vdeprecation(token.loc, format, args); - va_end(args); + eSink.deprecationSupplemental(token.loc, format, args); } /*************************************** @@ -2692,12 +2700,21 @@ class Lexer else { const locx = loc(); - warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars()); + // @@@DEPRECATED_2.103@@@ + // Turn into an error in 2.113 + if (inTokenStringConstant) + deprecation(locx, "token string requires valid D tokens, not `#%s`", n.ident.toChars()); + else + error(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars()); } } else if (n.value == TOK.if_) { - error("C preprocessor directive `#if` is not supported, use `version` or `static if`"); + const locx = loc(); + if (inTokenStringConstant) + error(locx, "token string requires valid D tokens, not `#if`"); + else + error(locx, "C preprocessor directive `#if` is not supported, use `version` or `static if`"); } return false; } @@ -2853,7 +2870,7 @@ class Lexer auto result = decodeUTFpure(msg); if (msg) - error("%.*s", cast(int)msg.length, msg.ptr); + error(token.loc, "%.*s", cast(int)msg.length, msg.ptr); return result; } @@ -3077,7 +3094,7 @@ private struct TimeStampInfo __gshared char[8 + 1] time; __gshared char[24 + 1] timestamp; - public static void initialize(const ref Loc loc) nothrow + public static void initialize(const ref Loc loc, ErrorSink eSink) nothrow { if (initdone) return; @@ -3088,15 +3105,15 @@ private struct TimeStampInfo if (auto p = getenv("SOURCE_DATE_EPOCH")) { if (!ct.parseDigits(p.toDString())) - error(loc, "value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p); + eSink.error(loc, "value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p); } else .time(&ct); const p = ctime(&ct); assert(p); - sprintf(&date[0], "%.6s %.4s", p + 4, p + 20); - sprintf(&time[0], "%.8s", p + 11); - sprintf(×tamp[0], "%.24s", p); + snprintf(&date[0], date.length, "%.6s %.4s", p + 4, p + 20); + snprintf(&time[0], time.length, "%.8s", p + 11); + snprintf(×tamp[0], timestamp.length, "%.24s", p); } } @@ -3217,19 +3234,15 @@ private bool c_isalnum(const int c) pure @nogc @safe unittest { - import dmd.console; - nothrow bool assertDiagnosticHandler(const ref Loc loc, Color headerColor, const(char)* header, - const(char)* format, va_list ap, const(char)* p1, const(char)* p2) - { - assert(0); - } - diagnosticHandler = &assertDiagnosticHandler; + fprintf(stderr, "Lexer.unittest %d\n", __LINE__); + + ErrorSink errorSink = new ErrorSinkStderr; - static void test(T)(string sequence, T expected, bool Ccompile = false) + void test(T)(string sequence, T expected, bool Ccompile = false) { auto p = cast(const(char)*)sequence.ptr; dchar c2; - Lexer lexer = new Lexer(); + Lexer lexer = new Lexer(errorSink); assert(expected == lexer.escapeSequence(Loc.initial, p, Ccompile, c2)); assert(p == sequence.ptr + sequence.length); } @@ -3266,45 +3279,51 @@ unittest test(`"`, '"'); test(`<`, '<'); test(`>`, '>'); - - diagnosticHandler = null; } unittest { - import dmd.console; - string expected; - bool gotError; + fprintf(stderr, "Lexer.unittest %d\n", __LINE__); - nothrow bool expectDiagnosticHandler(const ref Loc loc, Color headerColor, const(char)* header, - const(char)* format, va_list ap, const(char)* p1, const(char)* p2) + static class ErrorSinkTest : ErrorSinkNull { - assert(cast(Classification)headerColor == Classification.error); + nothrow: + extern (C++): + override: + + import core.stdc.stdio; + import core.stdc.stdarg; + + string expected; + bool gotError; - gotError = true; - char[100] buffer = void; - auto actual = buffer[0 .. vsprintf(buffer.ptr, format, ap)]; - assert(expected == actual); - return true; + void error(const ref Loc loc, const(char)* format, ...) + { + gotError = true; + char[100] buffer = void; + va_list ap; + va_start(ap, format); + auto actual = buffer[0 .. vsnprintf(buffer.ptr, buffer.length, format, ap)]; + va_end(ap); + assert(expected == actual); + } } - diagnosticHandler = &expectDiagnosticHandler; + ErrorSinkTest errorSink = new ErrorSinkTest; void test(string sequence, string expectedError, dchar expectedReturnValue, uint expectedScanLength, bool Ccompile = false) { - uint errors = global.errors; - gotError = false; - expected = expectedError; + errorSink.expected = expectedError; + errorSink.gotError = false; auto p = cast(const(char)*)sequence.ptr; - Lexer lexer = new Lexer(); + Lexer lexer = new Lexer(errorSink); dchar c2; auto actualReturnValue = lexer.escapeSequence(Loc.initial, p, Ccompile, c2); - assert(gotError); + assert(errorSink.gotError); assert(expectedReturnValue == actualReturnValue); auto actualScanLength = p - sequence.ptr; assert(expectedScanLength == actualScanLength); - global.errors = errors; } test("c", `undefined escape sequence \c`, 'c', 1); @@ -3338,17 +3357,16 @@ unittest test(""", `unterminated named entity "`, '?', 5); test("400", `escape octal sequence \400 is larger than \377`, 0x100, 3); - - diagnosticHandler = null; } unittest { - //printf("lexer.unittest\n"); + fprintf(stderr, "Lexer.unittest %d\n", __LINE__); /* Not much here, just trying things out. */ string text = "int"; // We rely on the implicit null-terminator - scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, 0, 0); + ErrorSink errorSink = new ErrorSinkStderr; + scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, false, false, errorSink); TOK tok; tok = lex1.nextToken(); //printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOK.int32); @@ -3363,9 +3381,10 @@ unittest unittest { + fprintf(stderr, "Lexer.unittest %d\n", __LINE__); + // We don't want to see Lexer error output during these tests. - uint errors = global.startGagging(); - scope(exit) global.endGagging(errors); + ErrorSink errorSink = new ErrorSinkNull; // Test malformed input: even malformed input should end in a TOK.endOfFile. static immutable char[][] testcases = @@ -3383,7 +3402,7 @@ unittest foreach (testcase; testcases) { - scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, 0, 0); + scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, false, false, errorSink); TOK tok = lex2.nextToken(); size_t iterations = 1; while ((tok != TOK.endOfFile) && (iterations++ < testcase.length)) diff --git a/dmd/mars.d b/dmd/mars.d index a6936de4216..49561188675 100644 --- a/dmd/mars.d +++ b/dmd/mars.d @@ -886,7 +886,7 @@ bool parseCommandlineAndConfig(size_t argc, const(char)** argv, ref Param params // read from DFLAGS in [Environment{arch}] section char[80] envsection = void; - sprintf(envsection.ptr, "Environment%.*s", cast(int) arch.length, arch.ptr); + snprintf(envsection.ptr, envsection.length, "Environment%.*s", cast(int) arch.length, arch.ptr); sections.push(envsection.ptr); parseConfFile(environment, global.inifilename, inifilepath, inifileBuffer, §ions); getenv_setargv(readFromEnv(environment, "DFLAGS"), &arguments); @@ -2161,6 +2161,14 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param return true; } } + else if (startsWith(p + 1, "verror-supplements")) + { + if (!params.errorSupplementLimit.parseDigits(p.toDString()[20 .. $])) + { + errorInvalidSwitch(p, "Only a number is allowed for `-verror-supplements`"); + return true; + } + } else if (startsWith(p + 1, "verror-style=")) { const(char)[] style = arg["verror-style=".length + 1 .. $]; @@ -2570,7 +2578,11 @@ bool parseCommandLine(const ref Strings arguments, const size_t argc, ref Param } } else if (arg == "-dip25") // https://dlang.org/dmd.html#switch-dip25 + { + // @@@ DEPRECATION 2.112 @@@ + deprecation(Loc.initial, "`-dip25` no longer has any effect"); params.useDIP25 = FeatureState.enabled; + } else if (arg == "-dip1000") { params.useDIP25 = FeatureState.enabled; diff --git a/dmd/module.h b/dmd/module.h index 933a7f147ad..6dbab15933f 100644 --- a/dmd/module.h +++ b/dmd/module.h @@ -194,3 +194,5 @@ struct ModuleDeclaration const char *toChars() const; }; + +extern void getLocalClasses(Module* mod, Array& aclasses); diff --git a/dmd/mtype.d b/dmd/mtype.d index 9e6f4f9b49e..1858553645c 100644 --- a/dmd/mtype.d +++ b/dmd/mtype.d @@ -460,7 +460,7 @@ version (IN_LLVM) return sizeTy; }(); - final extern (D) this(TY ty) + final extern (D) this(TY ty) scope { this.ty = ty; } @@ -2050,7 +2050,7 @@ version (IN_LLVM) } if (auto fd = s.isFuncDeclaration()) { - fd = resolveFuncCall(Loc.initial, null, fd, null, this, null, FuncResolveFlag.quiet); + fd = resolveFuncCall(Loc.initial, null, fd, null, this, ArgumentList(), FuncResolveFlag.quiet); if (!fd || fd.errors || !fd.functionSemantic()) return Type.terror; @@ -2072,7 +2072,7 @@ version (IN_LLVM) if (auto td = s.isTemplateDeclaration()) { assert(td._scope); - auto fd = resolveFuncCall(Loc.initial, null, td, null, this, null, FuncResolveFlag.quiet); + auto fd = resolveFuncCall(Loc.initial, null, td, null, this, ArgumentList(), FuncResolveFlag.quiet); if (!fd || fd.errors || !fd.functionSemantic()) return Type.terror; @@ -2459,7 +2459,7 @@ version (IN_LLVM) auto hashedname = toHexString(md5hash); static assert(hashedname.length < namebuf.length-30); name = namebuf.ptr; - length = sprintf(name, "_D%lluTypeInfo_%.*s6__initZ", + length = snprintf(name, namebuf.length, "_D%lluTypeInfo_%.*s6__initZ", 9LU + hashedname.length, cast(int) hashedname.length, hashedname.ptr); } else @@ -2469,7 +2469,7 @@ version (IN_LLVM) const namelen = 19 + size_t.sizeof * 3 + slice.length + 1; name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen)); - length = sprintf(name, "_D%lluTypeInfo_%.*s6__initZ", + length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ", cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr); //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name); assert(0 < length && length < namelen); // don't overflow the buffer @@ -3144,7 +3144,7 @@ extern (C++) final class TypeBasic : Type const(char)* dstring; uint flags; - extern (D) this(TY ty) + extern (D) this(TY ty) scope { super(ty); const(char)* d; @@ -4650,14 +4650,14 @@ extern (C++) final class TypeFunction : TypeNext * Determine match level. * Params: * tthis = type of `this` pointer, null if not member function - * args = array of function arguments + * argumentList = arguments to function call * flag = 1: performing a partial ordering match * pMessage = address to store error message, or null * sc = context * Returns: * MATCHxxxx */ - extern (D) MATCH callMatch(Type tthis, Expression[] args, int flag = 0, const(char)** pMessage = null, Scope* sc = null) + extern (D) MATCH callMatch(Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null) { //printf("TypeFunction::callMatch() %s\n", toChars()); MATCH match = MATCH.exact; // assume exact match @@ -4693,8 +4693,7 @@ extern (C++) final class TypeFunction : TypeNext } const nparams = parameterList.length; - const nargs = args.length; - if (nargs > nparams) + if (argumentList.length > nparams) { if (parameterList.varargs == VarArg.none) { @@ -4708,22 +4707,39 @@ extern (C++) final class TypeFunction : TypeNext } // https://issues.dlang.org/show_bug.cgi?id=22997 - if (parameterList.varargs == VarArg.none && nparams > nargs && !parameterList[nargs].defaultArg) + if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs) { OutBuffer buf; - buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)nargs); + buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length); if (pMessage) *pMessage = buf.extractChars(); return MATCH.nomatch; } + auto resolvedArgs = resolveNamedArgs(argumentList, pMessage); + Expression[] args; + if (!resolvedArgs) + { + if (!pMessage || *pMessage) + return MATCH.nomatch; + + // if no message was provided, it was because of overflow which will be diagnosed below + match = MATCH.nomatch; + args = argumentList.arguments ? (*argumentList.arguments)[] : null; + } + else + { + args = (*resolvedArgs)[]; + } foreach (u, p; parameterList) { - if (u == nargs) + if (u >= args.length) break; Expression arg = args[u]; - assert(arg); + if (!arg) + continue; // default argument + Type tprm = p.type; Type targ = arg.type; @@ -4757,10 +4773,11 @@ extern (C++) final class TypeFunction : TypeNext assert(p); // One or more arguments remain - if (u < nargs) + if (u < args.length) { Expression arg = args[u]; - assert(arg); + if (!arg) + continue; // default argument m = argumentMatchParameter(this, p, arg, wildmatch, flag, sc, pMessage); } else if (p.defaultArg) @@ -4769,7 +4786,7 @@ extern (C++) final class TypeFunction : TypeNext /* prefer matching the element type rather than the array * type when more arguments are present with T[]... */ - if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && nargs > nparams) + if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams) goto L1; //printf("\tm = %d\n", m); @@ -4784,7 +4801,7 @@ extern (C++) final class TypeFunction : TypeNext // Error message was already generated in `matchTypeSafeVarArgs` return MATCH.nomatch; } - if (pMessage && u >= nargs) + if (pMessage && u >= args.length) *pMessage = getMatchError("missing argument for parameter #%d: `%s`", u + 1, parameterToChars(p, this, false)); // If an error happened previously, `pMessage` was already filled @@ -4797,16 +4814,97 @@ extern (C++) final class TypeFunction : TypeNext match = m; // pick worst match } - if (pMessage && !parameterList.varargs && nargs > nparams) + if (pMessage && !parameterList.varargs && args.length > nparams) { // all parameters had a match, but there are surplus args - *pMessage = getMatchError("expected %d argument(s), not %d", nparams, nargs); + *pMessage = getMatchError("expected %d argument(s), not %d", nparams, args.length); return MATCH.nomatch; } //printf("match = %d\n", match); return match; } + /******************************** + * Convert an `argumentList`, which may contain named arguments, into + * a list of arguments in the order of the parameter list. + * + * Params: + * argumentList = array of function arguments + * pMessage = address to store error message, or `null` + * Returns: re-ordered argument list, or `null` on error + */ + extern(D) Expressions* resolveNamedArgs(ArgumentList argumentList, const(char)** pMessage) + { + Expression[] args = argumentList.arguments ? (*argumentList.arguments)[] : null; + Identifier[] names = argumentList.names ? (*argumentList.names)[] : null; + auto newArgs = new Expressions(parameterList.length); + newArgs.zero(); + size_t ci = 0; + bool hasNamedArgs = false; + foreach (i, arg; args) + { + if (!arg) + { + ci++; + continue; + } + auto name = i < names.length ? names[i] : null; + if (name) + { + hasNamedArgs = true; + const pi = findParameterIndex(name); + if (pi == -1) + { + if (pMessage) + *pMessage = getMatchError("no parameter named `%s`", name.toChars()); + return null; + } + ci = pi; + } + if (ci >= newArgs.length) + { + if (!parameterList.varargs) + { + // Without named args, let the caller diagnose argument overflow + if (hasNamedArgs && pMessage) + *pMessage = getMatchError("argument `%s` goes past end of parameter list", arg.toChars()); + return null; + } + while (ci >= newArgs.length) + newArgs.push(null); + } + + if ((*newArgs)[ci]) + { + if (pMessage) + *pMessage = getMatchError("parameter `%s` assigned twice", parameterList[ci].toChars()); + return null; + } + (*newArgs)[ci++] = arg; + } + foreach (i, arg; (*newArgs)[]) + { + if (arg || parameterList[i].defaultArg) + continue; + + if (parameterList.varargs != VarArg.none && i + 1 == newArgs.length) + continue; + + if (pMessage) + *pMessage = getMatchError("missing argument for parameter #%d: `%s`", + i + 1, parameterToChars(parameterList[i], this, false)); + return null; + } + // strip trailing nulls from default arguments + size_t e = newArgs.length; + while (e > 0 && (*newArgs)[e - 1] is null) + { + --e; + } + newArgs.setDim(e); + return newArgs; + } + /+ + Checks whether this function type is convertible to ` to` + when used in a function pointer / delegate. @@ -4852,7 +4950,7 @@ extern (C++) final class TypeFunction : TypeNext override MATCH constConv(Type to) { // Attributes need to match exactly, otherwise it's an implicit conversion - if (this.ty != to.ty || !this.attributesEqual(cast(TypeFunction) to, true)) + if (this.ty != to.ty || !this.attributesEqual(cast(TypeFunction) to)) return MATCH.nomatch; return super.constConv(to); @@ -4895,7 +4993,7 @@ extern (C++) final class TypeFunction : TypeNext } /// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other` - extern (D) bool attributesEqual(const scope TypeFunction other, bool trustSystemEqualsDefault = false) const pure nothrow @safe @nogc + extern (D) bool attributesEqual(const scope TypeFunction other, bool trustSystemEqualsDefault = true) const pure nothrow @safe @nogc { // @@@DEPRECATED_2.112@@@ // See semantic2.d Semantic2Visitor.visit(FuncDeclaration): @@ -4917,6 +5015,23 @@ extern (C++) final class TypeFunction : TypeNext { v.visit(this); } + + /** + * Look for the index of parameter `ident` in the parameter list + * + * Params: + * ident = identifier of parameter to search for + * Returns: index of parameter with name `ident` or -1 if not found + */ + private extern(D) ptrdiff_t findParameterIndex(Identifier ident) + { + foreach (i, p; this.parameterList) + { + if (p.ident == ident) + return i; + } + return -1; + } } /*********************************************************** @@ -6540,6 +6655,28 @@ extern (C++) struct ParameterList // Ensure no remaining parameters in `other` return !diff && other[idx] is null; } + + /// Returns: `true` if any parameter has a default argument + extern(D) bool hasDefaultArgs() + { + foreach (oidx, oparam, eidx, eparam; this) + { + if (eparam.defaultArg) + return true; + } + return false; + } + + // Returns: `true` if any parameter doesn't have a default argument + extern(D) bool hasArgsWithoutDefault() + { + foreach (oidx, oparam, eidx, eparam; this) + { + if (!eparam.defaultArg) + return true; + } + return false; + } } @@ -7008,7 +7145,7 @@ bool isCopyable(Type t) el.type = cast() ts; Expressions args; args.push(el); - FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, &args, FuncResolveFlag.quiet); + FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(&args), FuncResolveFlag.quiet); if (!f || f.storage_class & STC.disable) return false; } diff --git a/dmd/nogc.d b/dmd/nogc.d index 370e3b81d20..201f168527c 100644 --- a/dmd/nogc.d +++ b/dmd/nogc.d @@ -13,11 +13,14 @@ module dmd.nogc; +import core.stdc.stdio; + import dmd.aggregate; import dmd.apply; import dmd.astenums; import dmd.declaration; import dmd.dscope; +import dmd.errors; import dmd.expression; import dmd.func; import dmd.globals; @@ -34,9 +37,10 @@ extern (C++) final class NOGCVisitor : StoppableVisitor alias visit = typeof(super).visit; public: FuncDeclaration f; + bool checkOnly; // don't print errors bool err; - extern (D) this(FuncDeclaration f) + extern (D) this(FuncDeclaration f) scope { this.f = f; } @@ -64,6 +68,30 @@ public: } } + /** + * Register that expression `e` requires the GC + * Params: + * e = expression that uses GC + * format = error message when `e` is used in a `@nogc` function. + * Must contain format strings "`@nogc` %s `%s`" referring to the function. + * Returns: `true` if `err` was set, `false` if it's not in a `@nogc` and not checkonly (-betterC) + */ + private bool setGC(Expression e, const(char)* format) + { + if (checkOnly) + { + err = true; + return true; + } + if (f.setGC()) + { + e.error(format, f.kind(), f.toPrettyChars()); + err = true; + return true; + } + return false; + } + override void visit(CallExp e) { import dmd.id : Id; @@ -75,24 +103,14 @@ public: auto fd = stripHookTraceImpl(e.f); if (fd.ident == Id._d_arraysetlengthT) { - if (f.setGC()) - { - e.error("setting `length` in `@nogc` %s `%s` may cause a GC allocation", - f.kind(), f.toPrettyChars()); - err = true; + if (setGC(e, "setting `length` in `@nogc` %s `%s` may cause a GC allocation")) return; - } f.printGCUsage(e.loc, "setting `length` may cause a GC allocation"); } else if (fd.ident == Id._d_arrayappendT || fd.ident == Id._d_arrayappendcTX) { - if (f.setGC()) - { - e.error("cannot use operator `~=` in `@nogc` %s `%s`", - f.kind(), f.toPrettyChars()); - err = true; + if (setGC(e, "cannot use operator `~=` in `@nogc` %s `%s`")) return; - } f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation"); } } @@ -101,13 +119,8 @@ public: { if (e.type.ty != Tarray || !e.elements || !e.elements.length || e.onstack) return; - if (f.setGC()) - { - e.error("array literal in `@nogc` %s `%s` may cause a GC allocation", - f.kind(), f.toPrettyChars()); - err = true; + if (setGC(e, "array literal in `@nogc` %s `%s` may cause a GC allocation")) return; - } f.printGCUsage(e.loc, "array literal may cause a GC allocation"); } @@ -115,13 +128,8 @@ public: { if (!e.keys.length) return; - if (f.setGC()) - { - e.error("associative array literal in `@nogc` %s `%s` may cause a GC allocation", - f.kind(), f.toPrettyChars()); - err = true; + if (setGC(e, "associative array literal in `@nogc` %s `%s` may cause a GC allocation")) return; - } f.printGCUsage(e.loc, "associative array literal may cause a GC allocation"); } @@ -136,13 +144,9 @@ public: return; if (global.params.ehnogc && e.thrownew) return; // separate allocator is called for this, not the GC - if (f.setGC()) - { - e.error("cannot use `new` in `@nogc` %s `%s`", - f.kind(), f.toPrettyChars()); - err = true; + + if (setGC(e, "cannot use `new` in `@nogc` %s `%s`")) return; - } f.printGCUsage(e.loc, "`new` causes a GC allocation"); } @@ -164,13 +168,8 @@ public: Type t1b = e.e1.type.toBasetype(); if (e.modifiable && t1b.ty == Taarray) { - if (f.setGC()) - { - e.error("assigning an associative array element in `@nogc` %s `%s` may cause a GC allocation", - f.kind(), f.toPrettyChars()); - err = true; + if (setGC(e, "assigning an associative array element in `@nogc` %s `%s` may cause a GC allocation")) return; - } f.printGCUsage(e.loc, "assigning an associative array element may cause a GC allocation"); } } @@ -179,13 +178,8 @@ public: { if (e.e1.op == EXP.arrayLength) { - if (f.setGC()) - { - e.error("setting `length` in `@nogc` %s `%s` may cause a GC allocation", - f.kind(), f.toPrettyChars()); - err = true; + if (setGC(e, "setting `length` in `@nogc` %s `%s` may cause a GC allocation")) return; - } f.printGCUsage(e.loc, "setting `length` may cause a GC allocation"); } } @@ -196,6 +190,11 @@ public: * The other branch will be `_d_arrayappendcTX(e1, 1), e1[$-1]=e2` which will generate the warning about * GC usage. See visit(CallExp). */ + if (checkOnly) + { + err = true; + return; + } if (f.setGC()) { err = true; @@ -205,29 +204,43 @@ public: override void visit(CatExp e) { - if (f.setGC()) - { - e.error("cannot use operator `~` in `@nogc` %s `%s`", - f.kind(), f.toPrettyChars()); - err = true; + if (setGC(e, "cannot use operator `~` in `@nogc` %s `%s`")) return; - } f.printGCUsage(e.loc, "operator `~` may cause a GC allocation"); } } Expression checkGC(Scope* sc, Expression e) { + if (sc.flags & SCOPE.ctfeBlock) // ignore GC in ctfe blocks + return e; + + /* If betterC, allow GC to happen in non-CTFE code. + * Just don't generate code for it. + * Detect non-CTFE use of the GC in betterC code. + */ + const betterC = global.params.betterC; FuncDeclaration f = sc.func; - if (e && e.op != EXP.error && f && sc.intypeof != 1 && !(sc.flags & SCOPE.ctfe) && + if (e && e.op != EXP.error && f && sc.intypeof != 1 && + (!(sc.flags & SCOPE.ctfe) || betterC) && (f.type.ty == Tfunction && (cast(TypeFunction)f.type).isnogc || f.nogcInprocess || global.params.vgc) && !(sc.flags & SCOPE.debug_)) { scope NOGCVisitor gcv = new NOGCVisitor(f); + gcv.checkOnly = betterC; walkPostorder(e, gcv); if (gcv.err) - return ErrorExp.get(); + { + if (betterC) + { + /* Allow ctfe to use the gc code, but don't let it into the runtime + */ + f.skipCodegen = true; + } + else + return ErrorExp.get(); + } } return e; } diff --git a/dmd/ob.d b/dmd/ob.d index 31e93a7637f..9cff76b84aa 100644 --- a/dmd/ob.d +++ b/dmd/ob.d @@ -115,7 +115,7 @@ struct ObNode PtrVarState[] input; /// variable states on entry to exp PtrVarState[] output; /// variable states on exit to exp - this(ObNode* tryBlock) + this(ObNode* tryBlock) scope { this.tryBlock = tryBlock; } @@ -1353,7 +1353,7 @@ void genKill(ref ObState obstate, ObNode* ob) extern (D) this(void delegate(ObNode*, VarDeclaration, Expression, bool) dgWriteVar, void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable) dgReadVar, - ObNode* ob, ref ObState obstate) + ObNode* ob, ref ObState obstate) scope { this.dgWriteVar = dgWriteVar; this.dgReadVar = dgReadVar; @@ -2058,7 +2058,7 @@ void checkObErrors(ref ObState obstate) extern (D) this(void delegate(const ref Loc loc, ObNode* ob, VarDeclaration v, bool mutable, PtrVarState[]) dgReadVar, void delegate(ObNode*, PtrVarState[], VarDeclaration, Expression) dgWriteVar, - PtrVarState[] cpvs, ObNode* ob, ref ObState obstate) + PtrVarState[] cpvs, ObNode* ob, ref ObState obstate) scope { this.dgReadVar = dgReadVar; this.dgWriteVar = dgWriteVar; @@ -2569,7 +2569,7 @@ void checkObErrors(ref ObState obstate) { auto v = obstate.vars[i]; if (v.type.hasPointers()) - v.error(v.loc, "is left dangling at return"); + v.error(v.loc, "is not disposed of before return"); } } } diff --git a/dmd/opover.d b/dmd/opover.d index 4d7fe9fcea3..3c80e5e1d0e 100644 --- a/dmd/opover.d +++ b/dmd/opover.d @@ -711,7 +711,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) MatchAccumulator m; if (s) { - functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2); + functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); @@ -720,7 +720,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) FuncDeclaration lastf = m.lastf; if (s_r) { - functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1); + functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(&args1)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); @@ -793,7 +793,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) MatchAccumulator m; if (s_r) { - functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, &args2); + functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); @@ -802,7 +802,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) FuncDeclaration lastf = m.lastf; if (s) { - functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, &args1); + functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, ArgumentList(&args1)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); @@ -1254,7 +1254,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) args2[0] = e.e2; expandTuples(&args2); MatchAccumulator m; - functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2); + functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) { return ErrorExp.get(); @@ -1347,7 +1347,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop } if (s) { - functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2); + functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, ArgumentList(&args2)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) return ErrorExp.get(); } @@ -1355,7 +1355,7 @@ private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop int count = m.count; if (s_r) { - functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1); + functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, ArgumentList(&args1)); if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors())) return ErrorExp.get(); } @@ -1746,7 +1746,10 @@ private FuncDeclaration findBestOpApplyMatch(Expression ethis, FuncDeclaration f // Found another overload with different attributes? // e.g. @system vs. @safe opApply - bool ambig = tf.attributesEqual(bestTf); + // @@@DEPRECATED_2.112@@@ + // See semantic2.d Semantic2Visitor.visit(FuncDeclaration): + // Remove `false` after deprecation period is over. + bool ambig = tf.attributesEqual(bestTf, false); // opApplies with identical attributes could still accept // different function bodies as delegate diff --git a/dmd/parse.d b/dmd/parse.d index 2cac26ae7aa..36a76f50da2 100644 --- a/dmd/parse.d +++ b/dmd/parse.d @@ -16,6 +16,7 @@ module dmd.parse; import core.stdc.stdio; import core.stdc.string; import dmd.astenums; +import dmd.errorsink; import dmd.globals; import dmd.id; import dmd.identifier; @@ -51,9 +52,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer * Input: * loc location in source file of mixin */ - extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, bool doDocComment) + extern (D) this(const ref Loc loc, AST.Module _module, const(char)[] input, bool doDocComment, + ErrorSink errorSink) scope { super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false, + errorSink, global.vendor, global.versionNumber()); //printf("Parser::Parser()\n"); @@ -64,8 +67,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer /* Create a pseudo-filename for the mixin string, as it may not even exist * in the source file. */ - char* filename = cast(char*)mem.xmalloc(strlen(loc.filename) + 7 + (loc.linnum).sizeof * 3 + 1); - sprintf(filename, "%s-mixin-%d", loc.filename, cast(int)loc.linnum); + auto len = strlen(loc.filename) + 7 + (loc.linnum).sizeof * 3 + 1; + char* filename = cast(char*)mem.xmalloc(len); + snprintf(filename, len, "%s-mixin-%d", loc.filename, cast(int)loc.linnum); scanloc.filename = filename; } @@ -74,9 +78,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer //nextToken(); // start up the scanner } - extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment) + extern (D) this(AST.Module _module, const(char)[] input, bool doDocComment, ErrorSink errorSink) scope { super(_module ? _module.srcfile.toChars() : null, input.ptr, 0, input.length, doDocComment, false, + errorSink, global.vendor, global.versionNumber()); //printf("Parser::Parser()\n"); @@ -167,13 +172,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.rightCurly) { - error(token.loc, "unmatched closing brace"); + error("unmatched closing brace"); return errorReturn(); } if (token.value != TOK.endOfFile) { - error(token.loc, "unrecognized declaration"); + error("unrecognized declaration"); return errorReturn(); } return decldefs; @@ -286,7 +291,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer check(TOK.rightParenthesis); if (msg) { - error("conflicting storage class `deprecated(%s)` and `deprecated(%s)`", msg.toChars(), e.toChars()); + error(token.loc, "conflicting storage class `deprecated(%s)` and `deprecated(%s)`", msg.toChars(), e.toChars()); } msg = e; return true; @@ -799,7 +804,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { if (pAttrs.link != res.link) { - error("conflicting linkage `extern (%s)` and `extern (%s)`", AST.linkageToChars(pAttrs.link), AST.linkageToChars(res.link)); + error(token.loc, "conflicting linkage `extern (%s)` and `extern (%s)`", AST.linkageToChars(pAttrs.link), AST.linkageToChars(res.link)); } else if (res.idents || res.identExps || res.cppmangle != CPPMANGLE.def) { @@ -887,7 +892,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (pAttrs.visibility.kind != AST.Visibility.Kind.undefined) { if (pAttrs.visibility.kind != prot) - error("conflicting visibility attribute `%s` and `%s`", AST.visibilityToChars(pAttrs.visibility.kind), AST.visibilityToChars(prot)); + error(token.loc, "conflicting visibility attribute `%s` and `%s`", AST.visibilityToChars(pAttrs.visibility.kind), AST.visibilityToChars(prot)); else error("redundant visibility attribute `%s`", AST.visibilityToChars(prot)); } @@ -1240,7 +1245,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { // Windows `printf` does not support `%1$s` const(char*) stc_str = (orig & STC.scope_) ? "scope".ptr : "ref".ptr; - error("attribute `in` cannot be added after `%s`: remove `%s`", + error(token.loc, "attribute `in` cannot be added after `%s`: remove `%s`", stc_str, stc_str); } else @@ -1285,7 +1290,10 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.leftParenthesis) { const loc = token.loc; - exp = new AST.CallExp(loc, exp, parseArguments()); + AST.Expressions* args = new AST.Expressions(); + AST.Identifiers* names = new AST.Identifiers(); + parseNamedArguments(args, names); + exp = new AST.CallExp(loc, exp, args, names); } if (udas is null) @@ -2170,7 +2178,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); if (token.value != TOK.identifier) { - error("`%s` expected as dot-separated identifiers, got `%s`", entity, token.toChars()); + error(token.loc, "`%s` expected as dot-separated identifiers, got `%s`", entity, token.toChars()); return qualified; } @@ -2879,43 +2887,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer storageClass = appendStorageClass(storageClass, stc); continue; - version (none) - { - case TOK.static_: - stc = STC.static_; - goto L2; - - case TOK.auto_: - storageClass = STC.auto_; - goto L4; - - case TOK.alias_: - storageClass = STC.alias_; - goto L4; - L4: - nextToken(); - ai = null; - if (token.value == TOK.identifier) - { - ai = token.ident; - nextToken(); - } - - at = null; // no type - ae = null; // no default argument - if (token.value == TOK.assign) // = defaultArg - { - nextToken(); - ae = parseDefaultInitExp(); - hasdefault = 1; - } - else - { - if (hasdefault) - error("default argument expected for `alias %s`", ai ? ai.toChars() : ""); - } - goto L3; - } default: { stc = storageClass & (STC.IOR | STC.lazy_); @@ -3270,7 +3241,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value != TOK.rightCurly) { /* { */ - error("`}` expected following members in `%s` declaration at %s", + error(token.loc, "`}` expected following members in `%s` declaration at %s", Token.toChars(tok), loc.toChars()); } nextToken(); @@ -3283,7 +3254,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer } else { - error("{ } expected following `%s` declaration", Token.toChars(tok)); + error(token.loc, "{ } expected following `%s` declaration", Token.toChars(tok)); } AST.AggregateDeclaration a; @@ -3670,7 +3641,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer loc = token.loc; nextToken(); if (token.value != TOK.leftParenthesis) - error("found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis)); + error(token.loc, "found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis)); auto exps = parseArguments(); t = new AST.TypeMixin(loc, exps); break; @@ -3734,7 +3705,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer default: error("basic type expected, not `%s`", token.toChars()); if (token.value == TOK.else_) - errorSupplemental(token.loc, "There's no `static else`, use `else` instead."); + eSink.errorSupplemental(token.loc, "There's no `static else`, use `else` instead."); t = AST.Type.terror; break; } @@ -4482,7 +4453,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (!tfirst) tfirst = t; else if (t != tfirst) - error("multiple declarations must have the same type, not `%s` and `%s`", tfirst.toChars(), t.toChars()); + error(token.loc, "multiple declarations must have the same type, not `%s` and `%s`", tfirst.toChars(), t.toChars()); if (token.value == TOK.colon && !ident && t.ty != Tfunction) { @@ -4519,7 +4490,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (_init) { if (isThis) - error("cannot use syntax `alias this = %s`, use `alias %s this` instead", _init.toChars(), _init.toChars()); + error(token.loc, "cannot use syntax `alias this = %s`, use `alias %s this` instead", _init.toChars(), _init.toChars()); else error("alias cannot have initializer"); } @@ -4558,7 +4529,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer continue; default: - error("semicolon expected to close `alias` declaration"); + error("semicolon expected to close `alias` declaration, not `%s`", token.toChars()); break; } } @@ -4697,12 +4668,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer default: if (loc.linnum != token.loc.linnum) { - error("semicolon needed to end declaration of `%s`, instead of `%s`", s.toChars(), token.toChars()); - errorSupplemental(loc, "`%s` declared here", s.toChars()); + error(token.loc, "semicolon needed to end declaration of `%s`, instead of `%s`", s.toChars(), token.toChars()); + eSink.errorSupplemental(loc, "`%s` declared here", s.toChars()); } else { - error("semicolon needed to end declaration of `%s` instead of `%s`", s.toChars(), token.toChars()); + error(token.loc, "semicolon needed to end declaration of `%s` instead of `%s`", s.toChars(), token.toChars()); } break; } @@ -4720,7 +4691,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer // A common mistake is to use a reserved keyword as an identifier, e.g. `in` or `out` if (token.isKeyword) { - errorSupplemental(token.loc, "`%s` is a keyword, perhaps append `_` to make it an identifier", token.toChars()); + eSink.errorSupplemental(token.loc, "`%s` is a keyword, perhaps append `_` to make it an identifier", token.toChars()); nextToken(); } } @@ -4940,7 +4911,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer AST.stcToBuffer(&buf, remStc); // @@@DEPRECATED_2.103@@@ // Deprecated in 2020-07, can be made an error in 2.103 - deprecation("storage class `%s` has no effect in type aliases", buf.peekChars()); + eSink.deprecation(token.loc, "storage class `%s` has no effect in type aliases", buf.peekChars()); } } @@ -4990,7 +4961,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer continue; default: - error("semicolon expected to close `alias` declaration"); + error("semicolon expected to close `alias` declaration, not `%s`", token.toChars()); break; } break; @@ -5132,7 +5103,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer if (token.value == TOK.leftCurly) { deprecation("using `(args) => { ... }` to create a delegate that returns a delegate is error-prone."); - deprecationSupplemental(token.loc, "Use `(args) { ... }` for a multi-statement function literal or use `(args) => () { }` if you intended for the lambda to return a delegate."); + deprecationSupplemental("Use `(args) { ... }` for a multi-statement function literal or use `(args) => () { }` if you intended for the lambda to return a delegate."); } const returnloc = token.loc; AST.Expression ae = parseAssignExp(); @@ -5357,7 +5328,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer { if (token.value != TOK.else_ && token.value != TOK.catch_ && token.value != TOK.finally_ && lookingForElse.linnum != 0) { - warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars()); + eSink.warning(elseloc, "else is dangling, add { } after condition at %s", lookingForElse.toChars()); } } @@ -5400,7 +5371,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); } if (format) - error(format.ptr, start.ptr, param ? "declaration".ptr : condition.toChars()); + error(token.loc, format.ptr, start.ptr, param ? "declaration".ptr : condition.toChars()); } /***************************************** @@ -5535,7 +5506,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer nextToken(); if (lastai && parameters.length >= 2) { - errorSupplemental(loc, "perhaps the `;` goes before `%s`", lastai.toChars()); + eSink.errorSupplemental(loc, "perhaps the `;` goes before `%s`", lastai.toChars()); } return null; } @@ -5808,7 +5779,7 @@ LagainStc: */ if (token.value == TOK.identifier && exp.op == EXP.identifier) { - error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars()); + error(token.loc, "found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars()); nextToken(); } else @@ -6511,7 +6482,7 @@ LagainStc: if (token.value != TOK.leftParenthesis) { deprecation("`catch` statement without an exception specification is deprecated"); - deprecationSupplemental(token.loc, "use `catch(Throwable)` for old behavior"); + deprecationSupplemental("use `catch(Throwable)` for old behavior"); t = null; id = null; } @@ -7070,7 +7041,7 @@ LagainStc: void check(TOK value, const(char)* string) { if (token.value != value) - error("found `%s` when expecting `%s` following %s", token.toChars(), Token.toChars(value), string); + error(token.loc, "found `%s` when expecting `%s` following %s", token.toChars(), Token.toChars(value), string); nextToken(); } @@ -7340,7 +7311,7 @@ LagainStc: { // This code parallels parseDeclarator() Token* t = *pt; - int parens; + bool parens; //printf("Parser::isDeclarator() %s\n", t.toChars()); if (t.value == TOK.assign) @@ -7635,24 +7606,6 @@ LagainStc: } goto L1; - version (none) - { - case TOK.static_: - continue; - case TOK.auto_: - case TOK.alias_: - t = peek(t); - if (t.value == TOK.identifier) - t = peek(t); - if (t.value == TOK.assign) - { - t = peek(t); - if (!isExpression(&t)) - return false; - } - goto L3; - } - default: { if (!isBasicType(&t)) @@ -8154,12 +8107,12 @@ LagainStc: if (token.postfix) { if (token.postfix != postfix) - error("mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix); + error(token.loc, "mismatched string literal postfixes `'%c'` and `'%c'`", postfix, token.postfix); postfix = token.postfix; } error("implicit string concatenation is error-prone and disallowed in D"); - errorSupplemental(token.loc, "Use the explicit syntax instead " ~ + eSink.errorSupplemental(token.loc, "Use the explicit syntax instead " ~ "(concatenating literals is `@nogc`): %s ~ %s", prev.toChars(), token.toChars()); @@ -8290,7 +8243,7 @@ LagainStc: check(TOK.dot); if (token.value != TOK.identifier) { - error("found `%s` when expecting identifier following `%s`.", token.toChars(), t.toChars()); + error(token.loc, "found `%s` when expecting identifier following `%s`.", token.toChars(), t.toChars()); goto Lerr; } e = new AST.DotIdExp(loc, new AST.TypeExp(loc, t), token.ident); @@ -8435,7 +8388,7 @@ LagainStc: // https://dlang.org/spec/expression.html#mixin_expressions nextToken(); if (token.value != TOK.leftParenthesis) - error("found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis)); + error(token.loc, "found `%s` when expecting `%s` following `mixin`", token.toChars(), Token.toChars(TOK.leftParenthesis)); auto exps = parseArguments(); e = new AST.MixinExp(loc, exps); break; @@ -8498,7 +8451,7 @@ LagainStc: // ( expression ) nextToken(); e = parseExpression(); - e.parens = 1; + e.parens = true; check(loc, TOK.rightParenthesis); break; } @@ -8768,14 +8721,6 @@ LagainStc: case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: - version (none) - { - case TOK.tilde: - case TOK.and: - case TOK.mul: - case TOK.min: - case TOK.add: - } case TOK.function_: case TOK.delegate_: case TOK.typeof_: @@ -8917,7 +8862,10 @@ LagainStc: break; case TOK.leftParenthesis: - e = new AST.CallExp(loc, e, parseArguments()); + AST.Expressions* args = new AST.Expressions(); + AST.Identifiers* names = new AST.Identifiers(); + parseNamedArguments(args, names); + e = new AST.CallExp(loc, e, args, names); continue; case TOK.leftBracket: @@ -9352,26 +9300,52 @@ LagainStc: private AST.Expressions* parseArguments() { // function call - AST.Expressions* arguments; + AST.Expressions* arguments = new AST.Expressions(); + parseNamedArguments(arguments, null); + return arguments; + } + + /************************* + * Collect argument list. + * Assume current token is ',', '$(LPAREN)' or '['. + */ + private void parseNamedArguments(AST.Expressions* arguments, AST.Identifiers* names) + { + assert(arguments); - arguments = new AST.Expressions(); const endtok = token.value == TOK.leftBracket ? TOK.rightBracket : TOK.rightParenthesis; nextToken(); while (token.value != endtok && token.value != TOK.endOfFile) { + if (peekNext() == TOK.colon) + { + // Named argument `name: exp` + auto loc = token.loc; + auto ident = token.ident; + check(TOK.identifier); + check(TOK.colon); + if (names) + names.push(ident); + else + error(loc, "named arguments not allowed here"); + } + else + { + if (names) + names.push(null); + } + auto arg = parseAssignExp(); arguments.push(arg); + if (token.value != TOK.comma) break; nextToken(); //comma } - check(endtok); - - return arguments; } /******************************************* @@ -9382,13 +9356,18 @@ LagainStc: nextToken(); AST.Expressions* arguments = null; + AST.Identifiers* names = null; // An anonymous nested class starts with "class" if (token.value == TOK.class_) { nextToken(); if (token.value == TOK.leftParenthesis) - arguments = parseArguments(); + { + arguments = new AST.Expressions(); + names = new AST.Identifiers(); + parseNamedArguments(arguments, names); + } AST.BaseClasses* baseclasses = null; if (token.value != TOK.leftCurly) @@ -9430,10 +9409,12 @@ LagainStc: } else if (token.value == TOK.leftParenthesis && t.ty != Tsarray) { - arguments = parseArguments(); + arguments = new AST.Expressions(); + names = new AST.Identifiers(); + parseNamedArguments(arguments, names); } - auto e = new AST.NewExp(loc, thisexp, t, arguments); + auto e = new AST.NewExp(loc, thisexp, t, arguments, names); return e; } diff --git a/dmd/printast.d b/dmd/printast.d index 00a54578639..d85105d6f20 100644 --- a/dmd/printast.d +++ b/dmd/printast.d @@ -39,7 +39,7 @@ extern (C++) final class PrintASTVisitor : Visitor int indent; - extern (D) this(int indent) + extern (D) this(int indent) scope { this.indent = indent; } diff --git a/dmd/root/aav.d b/dmd/root/aav.d index 42d13994126..1d450505a4d 100644 --- a/dmd/root/aav.d +++ b/dmd/root/aav.d @@ -149,7 +149,7 @@ private struct AARange(K,V) size_t bIndex; aaA* current; - this(AA* aa) pure nothrow @nogc + this(AA* aa) pure nothrow @nogc scope { if (aa) { diff --git a/dmd/root/array.d b/dmd/root/array.d index e352c61ce6b..541a12d9e1d 100644 --- a/dmd/root/array.d +++ b/dmd/root/array.d @@ -41,7 +41,7 @@ public: * Params: * dim = initial length of array */ - this(size_t dim) pure nothrow + this(size_t dim) pure nothrow scope { reserve(dim); this.length = dim; @@ -69,7 +69,18 @@ public: { foreach (u; 0 .. a.length) { - buf[u] = toStringFunc(a.data[u]); + static if (is(typeof(a.data[u] is null))) + { + if (a.data[u] is null) + buf[u] = "null"; + else + buf[u] = toStringFunc(a.data[u]); + } + else + { + buf[u] = toStringFunc(a.data[u]); + } + len += buf[u].length + seplen; } } @@ -381,6 +392,19 @@ unittest assert(str == `["hello","world"]`); // Test presence of null terminator. assert(str.ptr[str.length] == '\0'); + + // Test printing an array of classes, which can be null + static class C + { + override string toString() const + { + return "x"; + } + } + auto nullarray = Array!C(2); + nullarray[0] = new C(); + nullarray[1] = null; + assert(nullarray.toString() == `[x,null]`); } unittest diff --git a/dmd/root/ctfloat.d b/dmd/root/ctfloat.d index d3b74c2b7dd..fa56200c81e 100644 --- a/dmd/root/ctfloat.d +++ b/dmd/root/ctfloat.d @@ -207,9 +207,7 @@ extern (C++) struct CTFloat @system static real_t parse(const(char)* literal, out bool isOutOfRange); @system - static int sprint(char* str, char fmt, real_t x); - @system - static int snprint(char* str, size_t str_buf_length, char fmt, real_t x); + static int sprint(char* str, size_t size, char fmt, real_t x); } else { @@ -234,17 +232,17 @@ extern (C++) struct CTFloat } @system - static int sprint(char* str, char fmt, real_t x) + static int sprint(char* str, size_t size, char fmt, real_t x) { version(CRuntime_Microsoft) { - auto len = cast(int) ld_sprint(str, fmt, longdouble_soft(x)); + auto len = cast(int) ld_sprint(str, size, fmt, longdouble_soft(x)); } else { char[4] sfmt = "%Lg\0"; sfmt[2] = fmt; - auto len = sprintf(str, sfmt.ptr, x); + auto len = snprintf(str, size, sfmt.ptr, x); } if (fmt != 'a' && fmt != 'A') @@ -320,7 +318,7 @@ version (IN_LLVM) static void printAndCheck(char format, real_t x, string expected) nothrow { char[32] buffer = void; - const length = CTFloat.sprint(buffer.ptr, format, x); + const length = CTFloat.sprint(buffer.ptr, buffer.length, format, x); assert(length < buffer.length); printf("'%s', expected '%.*s'\n", buffer.ptr, cast(int) expected.length, expected.ptr); assert(buffer[0 .. length] == expected); diff --git a/dmd/root/ctfloat.h b/dmd/root/ctfloat.h index 6670a8079bf..6e8e8808b0f 100644 --- a/dmd/root/ctfloat.h +++ b/dmd/root/ctfloat.h @@ -9,6 +9,7 @@ #pragma once +#include "dcompat.h" #include "longdouble.h" // Type used by the front-end for compile-time reals @@ -69,10 +70,7 @@ struct CTFloat static bool isInfinity(real_t r); static real_t parse(const char *literal, bool& isOutOfRange); - static int sprint(char *str, char fmt, real_t x); -#if IN_LLVM - static int snprint(char *str, size_t str_buf_length, char fmt, real_t x); -#endif + static int sprint(char *str, d_size_t size, char fmt, real_t x); static size_t hash(real_t a); diff --git a/dmd/root/filename.d b/dmd/root/filename.d index 17c8835f753..14cffd265e2 100644 --- a/dmd/root/filename.d +++ b/dmd/root/filename.d @@ -92,6 +92,12 @@ nothrow: this.str = str.xarraydup; } + /// + extern (C++) static FileName create(const(char)* name) pure + { + return FileName(name.toDString); + } + /// Compare two name according to the platform's rules (case sensitive or not) extern (C++) static bool equals(const(char)* name1, const(char)* name2) pure @nogc { diff --git a/dmd/root/filename.h b/dmd/root/filename.h index f87a8d3bde0..7185c166d40 100644 --- a/dmd/root/filename.h +++ b/dmd/root/filename.h @@ -19,6 +19,7 @@ struct FileName private: DString str; public: + static FileName create(const char *name); static bool equals(const char *name1, const char *name2); static bool absolute(const char *name); static const char *toAbsolute(const char *name, const char *base = NULL); diff --git a/dmd/root/longdouble.d b/dmd/root/longdouble.d index 64ad1c98b6a..f26a1a8d989 100644 --- a/dmd/root/longdouble.d +++ b/dmd/root/longdouble.d @@ -732,19 +732,19 @@ int ld_type(longdouble_soft x) return LD_TYPE_QNAN; // qnan, indefinite, pseudo-nan } -// consider sprintf pure -private extern(C) int sprintf(scope char* s, scope const char* format, ...) pure @nogc nothrow; +// consider snprintf pure +private extern(C) int snprintf(scope char* s, size_t size, scope const char* format, ...) pure @nogc nothrow; -size_t ld_sprint(char* str, int fmt, longdouble_soft x) @system +size_t ld_sprint(char* str, size_t size, int fmt, longdouble_soft x) @system { // ensure dmc compatible strings for nan and inf switch(ld_type(x)) { case LD_TYPE_QNAN: case LD_TYPE_SNAN: - return sprintf(str, "nan"); + return snprintf(str, size, "nan"); case LD_TYPE_INFINITE: - return sprintf(str, x.sign ? "-inf" : "inf"); + return snprintf(str, size, x.sign ? "-inf" : "inf"); default: break; } @@ -753,14 +753,14 @@ size_t ld_sprint(char* str, int fmt, longdouble_soft x) @system if(fmt != 'a' && fmt != 'A') { char[3] format = ['%', cast(char)fmt, 0]; - return sprintf(str, format.ptr, ld_read(&x)); + return snprintf(str, size, format.ptr, ld_read(&x)); } ushort exp = x.exponent; ulong mantissa = x.mantissa; if(ld_type(x) == LD_TYPE_ZERO) - return sprintf(str, fmt == 'a' ? "0x0.0L" : "0X0.0L"); + return snprintf(str, size, fmt == 'a' ? "0x0.0L" : "0X0.0L"); size_t len = 0; if(x.sign) @@ -806,20 +806,21 @@ size_t ld_sprint(char* str, int fmt, longdouble_soft x) @system import core.stdc.string; import core.stdc.stdio; - char[32] buffer; - ld_sprint(buffer.ptr, 'a', ld_pi); + const bufflen = 32; + char[bufflen] buffer; + ld_sprint(buffer.ptr, bufflen, 'a', ld_pi); assert(strcmp(buffer.ptr, "0x1.921fb54442d1846ap+1") == 0); - auto len = ld_sprint(buffer.ptr, 'g', longdouble_soft(2.0)); + auto len = ld_sprint(buffer.ptr, bufflen, 'g', longdouble_soft(2.0)); assert(buffer[0 .. len] == "2.00000" || buffer[0 .. len] == "2"); // Win10 - 64bit - ld_sprint(buffer.ptr, 'g', longdouble_soft(1_234_567.89)); + ld_sprint(buffer.ptr, bufflen, 'g', longdouble_soft(1_234_567.89)); assert(strcmp(buffer.ptr, "1.23457e+06") == 0); - ld_sprint(buffer.ptr, 'g', ld_inf); + ld_sprint(buffer.ptr, bufflen, 'g', ld_inf); assert(strcmp(buffer.ptr, "inf") == 0); - ld_sprint(buffer.ptr, 'g', ld_qnan); + ld_sprint(buffer.ptr, bufflen, 'g', ld_qnan); assert(strcmp(buffer.ptr, "nan") == 0); longdouble_soft ldb = longdouble_soft(0.4); diff --git a/dmd/root/longdouble.h b/dmd/root/longdouble.h index bd7e146cc94..2c8a6fee793 100644 --- a/dmd/root/longdouble.h +++ b/dmd/root/longdouble.h @@ -23,11 +23,10 @@ typedef volatile long double volatile_longdouble; #if __MINGW32__ // MinGW supports 80 bit reals, but the formatting functions map to versions // from the MSVC runtime by default which don't. -#define sprintf __mingw_sprintf +#define snprintf __mingw_snprintf #endif -#if !IN_LLVM // warning: 'sprintf' is deprecated: This function is provided for compatibility reasons only. Due to security concerns inherent in the design of sprintf(3), it is highly recommended that you use snprintf(3) instead. -inline size_t ld_sprint(char* str, int fmt, longdouble x) +inline size_t ld_sprint(char* str, size_t size, int fmt, longdouble x) { if (((longdouble)(unsigned long long)x) == x) { // ((1.5 -> 1 -> 1.0) == 1.5) is false @@ -35,19 +34,18 @@ inline size_t ld_sprint(char* str, int fmt, longdouble x) // see https://en.cppreference.com/w/cpp/io/c/fprintf char sfmt[5] = "%#Lg"; sfmt[3] = fmt; - return sprintf(str, sfmt, x); + return snprintf(str, size, sfmt, x); } else { char sfmt[4] = "%Lg"; sfmt[2] = fmt; - return sprintf(str, sfmt, x); + return snprintf(str, size, sfmt, x); } } -#endif #if __MINGW32__ -#undef sprintf +#undef snprintf #endif #else @@ -255,7 +253,7 @@ extern const longdouble_soft ld_pi2; extern const longdouble_soft ld_piOver2; extern const longdouble_soft ld_piOver4; -size_t ld_sprint(char* str, int fmt, longdouble_soft x); +size_t ld_sprint(char* str, size_t size, int fmt, longdouble_soft x); ////////////////////////////////////////////// typedef longdouble_soft longdouble; diff --git a/dmd/root/rootobject.d b/dmd/root/rootobject.d index 4437d1622e4..7138841caa0 100644 --- a/dmd/root/rootobject.d +++ b/dmd/root/rootobject.d @@ -38,7 +38,7 @@ enum DYNCAST : int extern (C++) class RootObject { - this() nothrow pure @nogc @safe + this() nothrow pure @nogc @safe scope { } diff --git a/dmd/sapply.d b/dmd/sapply.d index 848602897b9..ef0151656b1 100644 --- a/dmd/sapply.d +++ b/dmd/sapply.d @@ -37,7 +37,7 @@ private extern (C++) final class PostorderStatementVisitor : StoppableVisitor public: StoppableVisitor v; - extern (D) this(StoppableVisitor v) + extern (D) this(StoppableVisitor v) scope { this.v = v; } diff --git a/dmd/semantic2.d b/dmd/semantic2.d index 0ae21f2110d..c55674b3d73 100644 --- a/dmd/semantic2.d +++ b/dmd/semantic2.d @@ -93,7 +93,7 @@ private extern(C++) final class Semantic2Visitor : Visitor { alias visit = Visitor.visit; Scope* sc; - this(Scope* sc) + this(Scope* sc) scope { this.sc = sc; } @@ -258,9 +258,9 @@ private extern(C++) final class Semantic2Visitor : Visitor sc.varDecl = vd; scope(exit) sc.varDecl = null; - if (vd.aliassym) // if it's a tuple + if (vd.aliasTuple) // if it's a tuple { - vd.aliassym.accept(this); + vd.aliasTuple.accept(this); vd.semanticRun = PASS.semantic2done; return; } @@ -449,7 +449,11 @@ private extern(C++) final class Semantic2Visitor : Visitor if (tf1.mod != tf2.mod || ((f1.storage_class ^ f2.storage_class) & STC.static_)) return 0; - const sameAttr = tf1.attributesEqual(tf2); + // @@@DEPRECATED_2.112@@@ + // This test doesn't catch identical functions that differ only + // in explicit/implicit `@system` - a deprecation has now been + // added below, remove `false` after deprecation period is over. + const sameAttr = tf1.attributesEqual(tf2, false); const sameParams = tf1.parameterList == tf2.parameterList; // Allow the hack to declare overloads with different parameters/STC's @@ -477,7 +481,7 @@ private extern(C++) final class Semantic2Visitor : Visitor // Same as 2.104 deprecation, but also catching explicit/implicit `@system` // At the end of deprecation period, fix Type.attributesEqual and remove // this condition, as well as the error for extern(C) functions above. - if (sameAttr != tf1.attributesEqual(tf2, true)) + if (sameAttr != tf1.attributesEqual(tf2)) { f2.deprecation("cannot overload `extern(%s)` function at %s", linkageToChars(f1._linkage), diff --git a/dmd/semantic3.d b/dmd/semantic3.d index fc19b6089cd..19d53507db2 100644 --- a/dmd/semantic3.d +++ b/dmd/semantic3.d @@ -98,7 +98,7 @@ private extern(C++) final class Semantic3Visitor : Visitor alias visit = Visitor.visit; Scope* sc; - this(Scope* sc) + this(Scope* sc) scope { this.sc = sc; } @@ -352,7 +352,6 @@ private extern(C++) final class Semantic3Visitor : Visitor sc2.aligndecl = null; if (funcdecl.ident != Id.require && funcdecl.ident != Id.ensure) sc2.flags = sc.flags & ~SCOPE.contract; - sc2.flags &= ~SCOPE.compile; sc2.tf = null; sc2.os = null; sc2.inLoop = false; @@ -722,7 +721,7 @@ private extern(C++) final class Semantic3Visitor : Visitor // Insert implicit super() at start of fbody Type tthis = ad2.type.addMod(funcdecl.vthis.type.mod); - FuncDeclaration fd = resolveFuncCall(Loc.initial, sc2, cd.baseClass.ctor, null, tthis, null, FuncResolveFlag.quiet); + FuncDeclaration fd = resolveFuncCall(Loc.initial, sc2, cd.baseClass.ctor, null, tthis, ArgumentList(), FuncResolveFlag.quiet); if (!fd) { funcdecl.error("no match for implicit `super()` call in constructor"); @@ -1632,7 +1631,7 @@ private struct FuncDeclSem3 // Scope of analysis Scope* sc; - this(FuncDeclaration fd,Scope* s) + this(FuncDeclaration fd,Scope* s) scope { funcdecl = fd; sc = s; diff --git a/dmd/sideeffect.d b/dmd/sideeffect.d index ed938762bab..60a74cc2812 100644 --- a/dmd/sideeffect.d +++ b/dmd/sideeffect.d @@ -37,7 +37,7 @@ extern (C++) bool isTrivialExp(Expression e) { alias visit = typeof(super).visit; public: - extern (D) this() + extern (D) this() scope { } @@ -75,7 +75,7 @@ extern (C++) bool hasSideEffect(Expression e, bool assumeImpureCalls = false) { alias visit = typeof(super).visit; public: - extern (D) this() + extern (D) this() scope { } diff --git a/dmd/statement.d b/dmd/statement.d index 98a4b69f544..ba0959692e1 100644 --- a/dmd/statement.d +++ b/dmd/statement.d @@ -1084,6 +1084,16 @@ extern (C++) final class IfStatement : Statement { v.visit(this); } + + /****** + * Returns: true if `if (__ctfe)` + */ + bool isIfCtfeBlock() + { + if (auto cv = condition.isVarExp()) + return cv.var.ident == Id.ctfe; + return false; + } } /*********************************************************** @@ -1816,6 +1826,7 @@ extern (C++) final class GotoStatement : Statement TryFinallyStatement tf; ScopeGuardStatement os; VarDeclaration lastVar; + bool inCtfeBlock; /// set if goto is inside an `if (__ctfe)` block extern (D) this(const ref Loc loc, Identifier ident) { @@ -1858,6 +1869,12 @@ extern (C++) final class GotoStatement : Statement return true; } + if (label.statement.inCtfeBlock && !inCtfeBlock) + { + error("cannot `goto` into `if (__ctfe)` block"); + return true; + } + Statement stbnext; for (auto stb = tryBody; stb != label.statement.tryBody; stb = stbnext) { @@ -1924,6 +1941,7 @@ extern (C++) final class LabelStatement : Statement Statement gotoTarget; // interpret void* extra; // used by Statement_toIR() bool breaks; // someone did a 'break ident' + bool inCtfeBlock; // inside a block dominated by `if (__ctfe)` extern (D) this(const ref Loc loc, Identifier ident, Statement statement) { diff --git a/dmd/statement.h b/dmd/statement.h index 082546f0f12..e844636f9ab 100644 --- a/dmd/statement.h +++ b/dmd/statement.h @@ -398,6 +398,7 @@ class IfStatement final : public Statement IfStatement *syntaxCopy() override; void accept(Visitor *v) override { v->visit(this); } + bool isIfCtfeBlock(); }; class ConditionalStatement final : public Statement @@ -710,7 +711,7 @@ class GotoStatement final : public Statement TryFinallyStatement *tf; ScopeGuardStatement *os; VarDeclaration *lastVar; - + bool inCtfeBlock; GotoStatement *syntaxCopy() override; void accept(Visitor *v) override { v->visit(this); } @@ -728,7 +729,7 @@ class LabelStatement final : public Statement Statement *gotoTarget; // interpret void* extra; // used by Statement_toIR() bool breaks; // someone did a 'break ident' - + bool inCtfeBlock; LabelStatement *syntaxCopy() override; void accept(Visitor *v) override { v->visit(this); } diff --git a/dmd/statementsem.d b/dmd/statementsem.d index ef387ac5640..300b26948cf 100644 --- a/dmd/statementsem.d +++ b/dmd/statementsem.d @@ -39,6 +39,7 @@ import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; +import dmd.errorsink; import dmd.escape; import dmd.expression; import dmd.expressionsem; @@ -160,7 +161,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor Statement result; Scope* sc; - this(Scope* sc) + this(Scope* sc) scope { this.sc = sc; } @@ -1277,7 +1278,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor else if (auto td = sfront.isTemplateDeclaration()) { Expressions a; - if (auto f = resolveFuncCall(loc, sc, td, null, tab, &a, FuncResolveFlag.quiet)) + if (auto f = resolveFuncCall(loc, sc, td, null, tab, ArgumentList(&a), FuncResolveFlag.quiet)) tfront = f.type; } else if (auto d = sfront.toAlias().isDeclaration()) @@ -1492,7 +1493,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor assert(0); } const(char)* r = (fs.op == TOK.foreach_reverse_) ? "R" : ""; - int j = sprintf(fdname.ptr, "_aApply%s%.*s%llu", r, 2, fntab[flag].ptr, cast(ulong)dim); + int j = snprintf(fdname.ptr, BUFFER_LEN, "_aApply%s%.*s%llu", r, 2, fntab[flag].ptr, cast(ulong)dim); assert(j < BUFFER_LEN); FuncDeclaration fdapply; @@ -1971,7 +1972,6 @@ else } if (checkNonAssignmentArrayOp(ifs.condition)) ifs.condition = ErrorExp.get(); - ifs.condition = checkGC(scd, ifs.condition); // Convert to boolean after declaring prm so this works: // if (S prm = S()) {} @@ -1983,10 +1983,24 @@ else // This feature allows a limited form of conditional compilation. ifs.condition = ifs.condition.optimize(WANTvalue); + // checkGC after optimizing the condition so that + // compile time constants are reduced. + ifs.condition = checkGC(scd, ifs.condition); + // Save 'root' of two branches (then and else) at the point where it forks CtorFlow ctorflow_root = scd.ctorflow.clone(); - ifs.ifbody = ifs.ifbody.semanticNoScope(scd); + /* Detect `if (__ctfe)` + */ + if (ifs.isIfCtfeBlock()) + { + Scope* scd2 = scd.push(); + scd2.flags |= SCOPE.ctfeBlock; + ifs.ifbody = ifs.ifbody.semanticNoScope(scd2); + scd2.pop(); + } + else + ifs.ifbody = ifs.ifbody.semanticNoScope(scd); scd.pop(); CtorFlow ctorflow_then = sc.ctorflow; // move flow results @@ -2289,7 +2303,9 @@ version (IN_LLVM) if (ed && ss.cases.length < ed.members.length) { int missingMembers = 0; - const maxShown = !global.params.verbose ? 6 : int.max; + const maxShown = !global.params.verbose ? + (global.params.errorSupplementLimit ? global.params.errorSupplementLimit : int.max) + : int.max; Lmembers: foreach (es; *ed.members) { @@ -2323,7 +2339,7 @@ version (IN_LLVM) } if (!sc.sw.sdefault && - (!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on)) + (!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on || sc.func.isSafe)) { ss.hasNoDefault = 1; @@ -2564,7 +2580,7 @@ version (IN_LLVM) cs.exp = se; else if (!cs.exp.isIntegerExp() && !cs.exp.isErrorExp()) { - cs.error("`case` must be a `string` or an integral constant, not `%s`", cs.exp.toChars()); + cs.error("`case` expression must be a compile-time `string` or an integral constant, not `%s`", cs.exp.toChars()); errors = true; } @@ -3896,6 +3912,7 @@ version (IN_LLVM) gs.tf = sc.tf; gs.os = sc.os; gs.lastVar = sc.lastVar; + gs.inCtfeBlock = (sc.flags & SCOPE.ctfeBlock) != 0; if (!gs.label.statement && sc.fes) { @@ -3935,6 +3952,7 @@ version (IN_LLVM) ls.tf = sc.tf; ls.os = sc.os; ls.lastVar = sc.lastVar; + ls.inCtfeBlock = (sc.flags & SCOPE.ctfeBlock) != 0; LabelDsymbol ls2 = fd.searchLabel(ls.ident, ls.loc); if (ls2.statement) @@ -4608,8 +4626,7 @@ public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachState decls.append(Dsymbol.arraySyntaxCopy(dbody)); else { - if (fs._body) // https://issues.dlang.org/show_bug.cgi?id=17646 - stmts.push(fs._body.syntaxCopy()); + stmts.push(fs._body.syntaxCopy()); s = new CompoundStatement(loc, stmts); } @@ -4828,7 +4845,7 @@ private Statements* flatten(Statement statement, Scope* sc) const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - scope p = new Parser!ASTCodegen(cs.loc, sc._module, str, false); + scope p = new Parser!ASTCodegen(cs.loc, sc._module, str, false, global.errorSink); p.nextToken(); auto a = new Statements(); diff --git a/dmd/target.d b/dmd/target.d index 723339c98f7..e08cfd27a81 100644 --- a/dmd/target.d +++ b/dmd/target.d @@ -1243,6 +1243,15 @@ else // !IN_LLVM { return (os & Target.OS.Posix) != 0; } + + /********************* + * Returns: + * alignment of the stack + */ + extern (D) uint stackAlign() + { + return isXmmSupported() ? 16 : (is64bit ? 8 : 4); + } } // !IN_LLVM } diff --git a/dmd/template.h b/dmd/template.h index c6072b09671..09db40fd126 100644 --- a/dmd/template.h +++ b/dmd/template.h @@ -46,6 +46,21 @@ struct TemplatePrevious Objects *dedargs; }; +struct ArgumentList final +{ + Expressions* arguments; + Identifiers* names; + ArgumentList() : + arguments(), + names() + { + } + ArgumentList(Expressions* arguments, Identifiers* names = nullptr) : + arguments(arguments), + names(names) + {} +}; + class TemplateDeclaration final : public ScopeDsymbol { public: @@ -85,7 +100,7 @@ class TemplateDeclaration final : public ScopeDsymbol Visibility visible() override; - MATCH leastAsSpecialized(Scope *sc, TemplateDeclaration *td2, Expressions *fargs); + MATCH leastAsSpecialized(Scope* sc, TemplateDeclaration* td2, ArgumentList argumentList); RootObject *declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o); TemplateDeclaration *isTemplateDeclaration() override { return this; } diff --git a/dmd/templateparamsem.d b/dmd/templateparamsem.d index 432daeea5c7..1a9d2520c84 100644 --- a/dmd/templateparamsem.d +++ b/dmd/templateparamsem.d @@ -50,7 +50,7 @@ private extern (C++) final class TemplateParameterSemanticVisitor : Visitor TemplateParameters* parameters; bool result; - this(Scope* sc, TemplateParameters* parameters) + this(Scope* sc, TemplateParameters* parameters) scope { this.sc = sc; this.parameters = parameters; diff --git a/dmd/tokens.d b/dmd/tokens.d index b3cd2d3c403..aec3a77dee8 100644 --- a/dmd/tokens.d +++ b/dmd/tokens.d @@ -269,11 +269,13 @@ enum TOK : ubyte _Thread_local, // C only extended keywords + _assert, _import, __cdecl, __declspec, __stdcall, __pragma, + __int128, __attribute__, } @@ -579,11 +581,13 @@ private immutable TOK[] keywords = TOK._Thread_local, // C only extended keywords + TOK._assert, TOK._import, TOK.__cdecl, TOK.__declspec, TOK.__stdcall, TOK.__pragma, + TOK.__int128, TOK.__attribute__, ]; @@ -612,7 +616,9 @@ static immutable TOK[TOK.max + 1] Ckeywords = restrict, return_, int16, signed, sizeof_, static_, struct_, switch_, typedef_, union_, unsigned, void_, volatile, while_, asm_, typeof_, _Alignas, _Alignof, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn, - _Static_assert, _Thread_local, _import, __cdecl, __declspec, __stdcall, __pragma, __attribute__ ]; + _Static_assert, _Thread_local, + _import, __cdecl, __declspec, __stdcall, __pragma, __int128, __attribute__, + _assert ]; foreach (kw; Ckwds) tab[kw] = cast(TOK) kw; @@ -878,11 +884,13 @@ extern (C++) struct Token TOK._Thread_local : "_Thread_local", // C only extended keywords + TOK._assert : "__check", TOK._import : "__import", TOK.__cdecl : "__cdecl", TOK.__declspec : "__declspec", TOK.__stdcall : "__stdcall", TOK.__pragma : "__pragma", + TOK.__int128 : "__int128", TOK.__attribute__ : "__attribute__", ]; @@ -942,16 +950,17 @@ nothrow: extern (C++) const(char)* toChars() const { - __gshared char[3 + 3 * floatvalue.sizeof + 1] buffer; + const bufflen = 3 + 3 * floatvalue.sizeof + 1; + __gshared char[bufflen] buffer; const(char)* p = &buffer[0]; switch (value) { case TOK.int32Literal: - sprintf(&buffer[0], "%d", cast(int)intvalue); + snprintf(&buffer[0], bufflen, "%d", cast(int)intvalue); break; case TOK.uns32Literal: case TOK.wchar_tLiteral: - sprintf(&buffer[0], "%uU", cast(uint)unsvalue); + snprintf(&buffer[0], bufflen, "%uU", cast(uint)unsvalue); break; case TOK.wcharLiteral: case TOK.dcharLiteral: @@ -960,36 +969,36 @@ nothrow: OutBuffer buf; buf.writeSingleCharLiteral(cast(dchar) intvalue); buf.writeByte('\0'); - p = buf.extractSlice().ptr; + p = buf.extractChars(); } break; case TOK.int64Literal: - sprintf(&buffer[0], "%lldL", cast(long)intvalue); + snprintf(&buffer[0], bufflen, "%lldL", cast(long)intvalue); break; case TOK.uns64Literal: - sprintf(&buffer[0], "%lluUL", cast(ulong)unsvalue); + snprintf(&buffer[0], bufflen, "%lluUL", cast(ulong)unsvalue); break; case TOK.float32Literal: - CTFloat.sprint(&buffer[0], 'g', floatvalue); + CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); strcat(&buffer[0], "f"); break; case TOK.float64Literal: - CTFloat.sprint(&buffer[0], 'g', floatvalue); + CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); break; case TOK.float80Literal: - CTFloat.sprint(&buffer[0], 'g', floatvalue); + CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); strcat(&buffer[0], "L"); break; case TOK.imaginary32Literal: - CTFloat.sprint(&buffer[0], 'g', floatvalue); + CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); strcat(&buffer[0], "fi"); break; case TOK.imaginary64Literal: - CTFloat.sprint(&buffer[0], 'g', floatvalue); + CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); strcat(&buffer[0], "i"); break; case TOK.imaginary80Literal: - CTFloat.sprint(&buffer[0], 'g', floatvalue); + CTFloat.sprint(&buffer[0], bufflen, 'g', floatvalue); strcat(&buffer[0], "Li"); break; case TOK.string_: @@ -1006,7 +1015,7 @@ nothrow: if (postfix) buf.writeByte(postfix); buf.writeByte(0); - p = buf.extractSlice().ptr; + p = buf.extractChars(); } break; case TOK.identifier: @@ -1116,7 +1125,7 @@ unittest { writeCharLiteral(buf, d); } - assert(buf.extractSlice() == `a\n\r\t\b\f\0\x11\u7233\U00017233`); + assert(buf[] == `a\n\r\t\b\f\0\x11\u7233\U00017233`); } /** @@ -1147,11 +1156,11 @@ unittest { OutBuffer buf; writeSingleCharLiteral(buf, '\''); - assert(buf.extractSlice() == `'\''`); + assert(buf[] == `'\''`); buf.reset(); writeSingleCharLiteral(buf, '"'); - assert(buf.extractSlice() == `'"'`); + assert(buf[] == `'"'`); buf.reset(); writeSingleCharLiteral(buf, '\n'); - assert(buf.extractSlice() == `'\n'`); + assert(buf[] == `'\n'`); } diff --git a/dmd/tokens.h b/dmd/tokens.h index 32ae5f437c4..87361f327a4 100644 --- a/dmd/tokens.h +++ b/dmd/tokens.h @@ -278,11 +278,13 @@ enum class TOK : unsigned char _Thread_local_, // C only extended keywords + _assert, _import, cdecl_, declspec, stdcall, pragma, + int128_, attribute__, MAX, diff --git a/dmd/traits.d b/dmd/traits.d index 5fcf19e6b01..989e978b8e9 100644 --- a/dmd/traits.d +++ b/dmd/traits.d @@ -122,7 +122,7 @@ ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data) { alias visit = Visitor.visit; public: - extern (D) this(Array!(ulong)* _data, ulong _sz_size_t) + extern (D) this(Array!(ulong)* _data, ulong _sz_size_t) scope { this.data = _data; this.sz_size_t = _sz_size_t; @@ -634,6 +634,10 @@ Expression semanticTraits(TraitsExp e, Scope* sc) } if (e.ident == Id.isVirtualFunction) { + // @@@DEPRECATED2.121@@@ + // Deprecated in 2.101 - Can be removed from 2.121 + e.deprecation("`traits(isVirtualFunction)` is deprecated. Use `traits(isVirtualMethod)` instead"); + if (dim != 1) return dimError(1); @@ -739,6 +743,42 @@ Expression semanticTraits(TraitsExp e, Scope* sc) auto se = new StringExp(e.loc, id.toString()); return se.expressionSemantic(sc); } + if (e.ident == Id.fullyQualifiedName) // https://dlang.org/spec/traits.html#fullyQualifiedName + { + if (dim != 1) + return dimError(1); + + Scope* sc2 = sc.push(); + sc2.flags = sc.flags | SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility; + bool ok = TemplateInstance.semanticTiargs(e.loc, sc2, e.args, 1); + sc2.pop(); + if (!ok) + return ErrorExp.get(); + + const(char)[] fqn; + auto o = (*e.args)[0]; + if (auto s = getDsymbolWithoutExpCtx(o)) + { + if (s.semanticRun == PASS.initial) + s.dsymbolSemantic(null); + + fqn = s.toPrettyChars().toDString(); + } + else if (auto t = getType(o)) + { + fqn = t.toPrettyChars(true).toDString(); + } + else + { + if (!isError(o)) + e.error("argument `%s` has no identifier", o.toChars()); + return ErrorExp.get(); + } + assert(fqn); + auto se = new StringExp(e.loc, fqn); + return se.expressionSemantic(sc); + + } if (e.ident == Id.getProtection || e.ident == Id.getVisibility) { if (dim != 1) @@ -995,6 +1035,13 @@ Expression semanticTraits(TraitsExp e, Scope* sc) if (errors < global.errors) e.error("`%s` cannot be resolved", eorig.toChars()); + if (e.ident == Id.getVirtualFunctions) + { + // @@@DEPRECATED2.121@@@ + // Deprecated in 2.101 - Can be removed from 2.121 + e.deprecation("`traits(getVirtualFunctions)` is deprecated. Use `traits(getVirtualMethods)` instead"); + } + /* Create tuple of functions of ex */ auto exps = new Expressions(); @@ -1676,7 +1723,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc) uint errors = global.startGagging(); Scope* sc2 = sc.push(); sc2.tinst = null; - sc2.minst = null; + sc2.minst = null; // this is why code for these are not emitted to object file sc2.flags = (sc.flags & ~(SCOPE.ctfe | SCOPE.condition)) | SCOPE.compile | SCOPE.fullinst; bool err = false; @@ -2205,7 +2252,7 @@ private void traitNotFound(TraitsExp e) initialized = true; // lazy initialization // All possible traits - __gshared Identifier*[58] idents = + __gshared Identifier*[59] idents = [ &Id.isAbstractClass, &Id.isArithmetic, @@ -2235,6 +2282,7 @@ private void traitNotFound(TraitsExp e) &Id.isReturnOnStack, &Id.hasMember, &Id.identifier, + &Id.fullyQualifiedName, &Id.getProtection, &Id.getVisibility, &Id.parent, diff --git a/dmd/typesem.d b/dmd/typesem.d index b6d460ba43f..c668199e5f7 100644 --- a/dmd/typesem.d +++ b/dmd/typesem.d @@ -35,6 +35,7 @@ import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.errors; +import dmd.errorsink; import dmd.expression; import dmd.expressionsem; import dmd.func; @@ -1242,20 +1243,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) if (fparam.storageClass & STC.return_) { - if (fparam.isReference()) - { - // Disabled for the moment awaiting improvement to allow return by ref - // to be transformed into return by scope. - if (0 && !tf.isref) - { - auto stc = fparam.storageClass & (STC.ref_ | STC.out_); - .error(loc, "parameter `%s` is `return %s` but function does not return by `ref`", - fparam.ident ? fparam.ident.toChars() : "", - stcToString(stc).ptr); - errors = true; - } - } - else + if (!fparam.isReference()) { if (!(fparam.storageClass & STC.scope_)) fparam.storageClass |= STC.scope_ | STC.scopeinferred; // 'return' implies 'scope' @@ -1346,7 +1334,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) // extended index), as we need to run semantic when `oidx` changes. size_t tupleOrigIdx = size_t.max; size_t tupleExtIdx = size_t.max; - bool hasDefault; foreach (oidx, oparam, eidx, eparam; tf.parameterList) { // oparam (original param) will always have the default arg @@ -1355,7 +1342,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) // position to get the offset in it later on. if (oparam.defaultArg) { - hasDefault = true; // Get the obvious case out of the way if (oparam is eparam) errors |= !defaultArgSemantic(eparam, argsc); @@ -1382,11 +1368,6 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) eparam.defaultArg = (*te.exps)[eidx - tupleExtIdx]; } } - else if (hasDefault) - { - .error(loc, "default argument expected for `%s`", oparam.toChars()); - errors = true; - } // We need to know the default argument to resolve `auto ref`, // hence why this has to take place as the very last step. @@ -3869,8 +3850,15 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) { /* Rewrite as: * this.d + * + * only if the scope in which we are + * has a `this` that matches the type + * of the lhs of the dot expression. + * + * https://issues.dlang.org/show_bug.cgi?id=23617 */ - if (hasThis(sc)) + auto fd = hasThis(sc); + if (fd && fd.isThis() == mt.sym) { e = new DotVarExp(e.loc, new ThisExp(e.loc), d); return e.expressionSemantic(sc); @@ -4188,6 +4176,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) } if (v.type.ty == Terror) { + e.error("type of variable `%s` has errors", v.toPrettyChars); return ErrorExp.get(); } @@ -4930,7 +4919,7 @@ RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc) const len = buf.length; buf.writeByte(0); const str = buf.extractSlice()[0 .. len]; - scope p = new Parser!ASTCodegen(loc, sc._module, str, false); + scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink); p.nextToken(); //printf("p.loc.linnum = %d\n", p.loc.linnum); diff --git a/dmd/typinf.d b/dmd/typinf.d index 06e28093863..f993262e607 100644 --- a/dmd/typinf.d +++ b/dmd/typinf.d @@ -34,8 +34,9 @@ import core.stdc.stdio; * loc = the location for reporting line numbers in errors * torig = the type to generate the `TypeInfo` object for * sc = the scope + * genObjCode = if true, object code will be generated for the obtained TypeInfo */ -extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc) +extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc, bool genObjCode = true) { // printf("genTypeInfo() %s\n", torig.toChars()); @@ -86,7 +87,7 @@ else // generate a COMDAT for other TypeInfos not available as builtins in // druntime - if (!isUnqualifiedClassInfo && !builtinTypeInfo(t)) + if (!isUnqualifiedClassInfo && !builtinTypeInfo(t) && genObjCode) { if (sc) // if in semantic() pass { @@ -112,13 +113,14 @@ else * loc = the location for reporting line nunbers in errors * t = the type to get the type of the `TypeInfo` object for * sc = the scope + * genObjCode = if true, object code will be generated for the obtained TypeInfo * Returns: * The type of the `TypeInfo` object associated with `t` */ -extern (C++) Type getTypeInfoType(const ref Loc loc, Type t, Scope* sc) +extern (C++) Type getTypeInfoType(const ref Loc loc, Type t, Scope* sc, bool genObjCode = true) { assert(t.ty != Terror); - genTypeInfo(null, loc, t, sc); + genTypeInfo(null, loc, t, sc, genObjCode); return t.vtinfo.type; } diff --git a/dmd/visitor.d b/dmd/visitor.d index e4c2a91e7f7..8990ce49a2a 100644 --- a/dmd/visitor.d +++ b/dmd/visitor.d @@ -248,7 +248,7 @@ extern (C++) class StoppableVisitor : Visitor public: bool stop; - final extern (D) this() + final extern (D) this() scope { } } diff --git a/driver/cl_options.cpp b/driver/cl_options.cpp index c9d4e10239f..6c308675de8 100644 --- a/driver/cl_options.cpp +++ b/driver/cl_options.cpp @@ -163,6 +163,12 @@ static cl::opt verrorStyle( "standard used by gcc and clang")), cl::init(MessageStyle::digitalmars)); +static cl::opt + verrorSupplements("verror-supplements", cl::ZeroOrMore, + cl::location(global.params.errorSupplementLimit), + cl::desc("Limit the number of supplemental messages for " + "each error (0 means unlimited)")); + static cl::opt warnings( cl::desc("Warnings:"), cl::ZeroOrMore, cl::location(global.params.warnings), cl::values( diff --git a/driver/ldmd.cpp b/driver/ldmd.cpp index 2b71e8a28d2..4a9aaf63694 100644 --- a/driver/ldmd.cpp +++ b/driver/ldmd.cpp @@ -259,6 +259,8 @@ Where:\n\ -vdmd print the underlying LDC command line\n\ -verror-style=[digitalmars|gnu]\n\ set the style for file/line number annotations on compiler messages\n\ + -verror-supplements=\n\ + limit the number of supplemental messages for each error (0 means unlimited)\n\ -verrors= limit the number of error messages (0 means unlimited)\n\ -verrors=context show error messages with the context of the erroring source line\n\ -verrors=spec show errors from speculative compiles such as __traits(compiles,...)\n\ @@ -292,7 +294,6 @@ void appendEnvVar(const char *envVarName, std::vector &args) { char *env = strdup(envVar.c_str()); // create forever-living copy - size_t j = 1; // leave argv[0] alone while (1) { switch (*env) { case ' ': @@ -305,7 +306,6 @@ void appendEnvVar(const char *envVarName, std::vector &args) { default: args.push_back(env); // append - j++; char *p = env; int slash = 0; int instring = 0; @@ -563,7 +563,8 @@ void translateArgs(const llvm::SmallVectorImpl &ldmdArgs, goto Lerror; } } - /* -verror-style + /* -verror-supplements + * -verror-style */ else if (startsWith(p + 1, "target=")) { ldcArgs.push_back(concat("-mtriple=", p + 8)); diff --git a/driver/main.cpp b/driver/main.cpp index bdcfd764e17..6d1c3441eb0 100644 --- a/driver/main.cpp +++ b/driver/main.cpp @@ -439,10 +439,8 @@ void parseCommandLine(Strings &sourceFiles) { if (global.params.useDIP1000 == FeatureState::enabled) // DIP1000 implies DIP25 global.params.useDIP25 = FeatureState::enabled; // legacy -dip25 option - if (global.params.useDIP25 == FeatureState::default_ && - opts::useDIP25.getNumOccurrences()) { - global.params.useDIP25 = - opts::useDIP25 ? FeatureState::enabled : FeatureState::disabled; + if (opts::useDIP25.getNumOccurrences()) { + deprecation(Loc(), "`-dip25` no longer has any effect"); } global.params.output_o = diff --git a/gen/ctfloat.cpp b/gen/ctfloat.cpp index 394d2bb7ab5..0ba8a5e838c 100644 --- a/gen/ctfloat.cpp +++ b/gen/ctfloat.cpp @@ -128,14 +128,7 @@ bool CTFloat::isFloat64LiteralOutOfRange(const char *literal) { //////////////////////////////////////////////////////////////////////////////// -// TODO: remove this function when no longer used, it's there because frontend D -// code still uses it. It simply forwards to snprintf with a very large assumed -// buffer length = no memory safety checking. -int CTFloat::sprint(char *str, char fmt, real_t x) { - return CTFloat::snprint(str, 1000, fmt, x); -} - -int CTFloat::snprint(char *str, size_t str_buf_length, char fmt, real_t x) { +int CTFloat::sprint(char *str, size_t str_buf_length, char fmt, real_t x) { assert(fmt == 'g' || fmt == 'a' || fmt == 'A'); const bool uppercase = fmt == 'A'; diff --git a/gen/declarations.cpp b/gen/declarations.cpp index a5fe715c556..040bb862e58 100644 --- a/gen/declarations.cpp +++ b/gen/declarations.cpp @@ -250,8 +250,8 @@ class CodegenVisitor : public Visitor { decl->ir->setDefined(); // just forward aliases - if (decl->aliassym) { - Logger::println("alias sym"); + if (decl->aliasTuple) { + Logger::println("aliasTuple"); decl->toAlias()->accept(this); return; } @@ -284,7 +284,7 @@ class CodegenVisitor : public Visitor { void visit(FuncDeclaration *decl) override { // don't touch function aliases, they don't contribute any new symbols - if (!decl->isFuncAliasDeclaration()) { + if (!decl->skipCodegen() && !decl->isFuncAliasDeclaration()) { DtoDefineFunction(decl); } } diff --git a/gen/dibuilder.cpp b/gen/dibuilder.cpp index e6cf0bcc9f3..1e817ee3f4a 100644 --- a/gen/dibuilder.cpp +++ b/gen/dibuilder.cpp @@ -515,19 +515,17 @@ void DIBuilder::AddStaticMembers(AggregateDeclaration *ad, DIFile file, visitMembers(tmixin->members); } else if (auto vd = s->isVarDeclaration()) { if (vd->isDataseg()) { - if (vd->aliassym) { // ugly kludge for tuples - if (auto td = vd->aliassym->isTupleDeclaration()) { - if (td->isexp && td->objects) { - Dsymbols tupleVars; - for (auto o : *td->objects) { - if (auto e = isExpression(o)) - if (auto ve = e->isVarExp()) - if (auto vd2 = ve->var->isVarDeclaration()) - if (vd2->isDataseg()) - tupleVars.push(vd2); - } - visitMembers(&tupleVars); + if (auto td = vd->aliasTuple) { // ugly kludge for tuples + if (td->isexp && td->objects) { + Dsymbols tupleVars; + for (auto o : *td->objects) { + if (auto e = isExpression(o)) + if (auto ve = e->isVarExp()) + if (auto vd2 = ve->var->isVarDeclaration()) + if (vd2->isDataseg()) + tupleVars.push(vd2); } + visitMembers(&tupleVars); } } else if (!vd->type->toBasetype()->isTypeNoreturn()) { llvm::MDNode *elem = diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp index 28dd43b6b16..2a4a550ee4a 100644 --- a/gen/llvmhelpers.cpp +++ b/gen/llvmhelpers.cpp @@ -844,9 +844,9 @@ void DtoResolveVariable(VarDeclaration *vd) { // just forward aliases // TODO: Is this required here or is the check in VarDeclaration::codegen // sufficient? - if (vd->aliassym) { - Logger::println("alias sym"); - DtoResolveDsymbol(vd->aliassym); + if (vd->aliasTuple) { + Logger::println("aliasTuple"); + DtoResolveDsymbol(vd->aliasTuple); return; } @@ -880,7 +880,7 @@ void DtoResolveVariable(VarDeclaration *vd) { void DtoVarDeclaration(VarDeclaration *vd) { assert(!vd->isDataseg() && "Statics/globals are handled in DtoDeclarationExp."); - assert(!vd->aliassym && "Aliases are handled in DtoDeclarationExp."); + assert(!vd->aliasTuple && "Aliases are handled in DtoDeclarationExp."); IF_LOG Logger::println("DtoVarDeclaration(vdtype = %s)", vd->type->toChars()); LOG_SCOPE @@ -953,11 +953,11 @@ DValue *DtoDeclarationExp(Dsymbol *declaration) { if (VarDeclaration *vd = declaration->isVarDeclaration()) { Logger::println("VarDeclaration"); - // if aliassym is set, this VarDecl is redone as an alias to another symbol + // if aliasTuple is set, this VarDecl is redone as an alias to another symbol // this seems to be done to rewrite Tuple!(...) v; // as a TupleDecl that contains a bunch of individual VarDecls - if (vd->aliassym) { - return DtoDeclarationExp(vd->aliassym); + if (vd->aliasTuple) { + return DtoDeclarationExp(vd->aliasTuple); } if (vd->storage_class & STCmanifest) { @@ -1021,7 +1021,7 @@ LLValue *DtoRawVarDeclaration(VarDeclaration *var, LLValue *addr) { assert(!var->isDataseg()); // we don't handle aliases either - assert(!var->aliassym); + assert(!var->aliasTuple); IrLocal *irLocal = isIrLocalCreated(var) ? getIrLocal(var) : nullptr; diff --git a/gen/moduleinfo.cpp b/gen/moduleinfo.cpp index 37400cde863..853f68b0760 100644 --- a/gen/moduleinfo.cpp +++ b/gen/moduleinfo.cpp @@ -162,9 +162,7 @@ llvm::Constant *buildLocalClasses(Module *m, size_t &count) { const auto classinfoTy = DtoType(getClassInfoType()); ClassDeclarations aclasses; - for (auto s : *m->members) { - s->addLocalClass(&aclasses); - } + getLocalClasses(m, aclasses); std::vector classInfoRefs; for (auto cd : aclasses) { diff --git a/gen/toir.cpp b/gen/toir.cpp index 6a2c00052e0..265a12a35bf 100644 --- a/gen/toir.cpp +++ b/gen/toir.cpp @@ -1754,7 +1754,8 @@ class ToElemVisitor : public Visitor { */ DValue *msg = e->msg ? toElemDtor(e->msg) : nullptr; Module *module = p->func()->decl->getModule(); - if (global.params.checkAction == CHECKACTION_C) { + if (global.params.checkAction == CHECKACTION_C || + module->filetype == FileType::c) { LLValue *cMsg = msg ? DtoArrayPtr( msg) // assuming `msg` is null-terminated, like DMD diff --git a/gen/typinf.cpp b/gen/typinf.cpp index ff1cb60052c..6abc0ea5f42 100644 --- a/gen/typinf.cpp +++ b/gen/typinf.cpp @@ -58,14 +58,15 @@ #include // in dmd/typinf.d: -void genTypeInfo(Expression *e, const Loc &loc, Type *torig, Scope *sc); +void genTypeInfo(Expression *e, const Loc &loc, Type *torig, Scope *sc, bool genObjCode = true); TypeInfoDeclaration *getOrCreateTypeInfoDeclaration(const Loc &loc, Type *forType) { IF_LOG Logger::println("getOrCreateTypeInfoDeclaration(): %s", forType->toChars()); LOG_SCOPE - genTypeInfo(nullptr, loc, forType, nullptr); + // the `genObjCode` parameter is unused by LDC + genTypeInfo(nullptr, loc, forType, nullptr, false); return forType->vtinfo; } diff --git a/ir/irclass.cpp b/ir/irclass.cpp index 6eda5106614..88e54d089db 100644 --- a/ir/irclass.cpp +++ b/ir/irclass.cpp @@ -246,8 +246,8 @@ LLConstant *IrClass::getVtblInit() { if (fd2->isFuture()) { continue; } - if (fd->leastAsSpecialized(fd2) != MATCH::nomatch || - fd2->leastAsSpecialized(fd) != MATCH::nomatch) { + if (fd->leastAsSpecialized(fd2, nullptr) != MATCH::nomatch || + fd2->leastAsSpecialized(fd, nullptr) != MATCH::nomatch) { TypeFunction *tf = static_cast(fd->type); if (tf->ty == TY::Tfunction) { cd->error("use of `%s%s` is hidden by `%s`; use `alias %s = " diff --git a/packaging/dlang-tools_version b/packaging/dlang-tools_version index b87e57a249c..4ac687073e6 100644 --- a/packaging/dlang-tools_version +++ b/packaging/dlang-tools_version @@ -1 +1 @@ -v2.102.2 \ No newline at end of file +v2.103.1 \ No newline at end of file diff --git a/packaging/dub_version b/packaging/dub_version index 6f986544fec..4beef39c0b7 100644 --- a/packaging/dub_version +++ b/packaging/dub_version @@ -1 +1 @@ -v1.31.1 \ No newline at end of file +v1.32.1 \ No newline at end of file diff --git a/packaging/reggae_version b/packaging/reggae_version index 3c41a9d487a..ceb52eaf4dd 100644 --- a/packaging/reggae_version +++ b/packaging/reggae_version @@ -1 +1 @@ -087b629e559d15d3372fefaceecb740ef5379316 \ No newline at end of file +fb18f3eb6cb0cd82ea401750f4e200fa82d91e39 \ No newline at end of file diff --git a/runtime/CMakeLists.txt b/runtime/CMakeLists.txt index c0978274756..d595144737b 100644 --- a/runtime/CMakeLists.txt +++ b/runtime/CMakeLists.txt @@ -452,6 +452,15 @@ macro(dc src_files src_basedir d_flags output_basedir emit_bc all_at_once single list(APPEND dc_flags -of=${new_o}) endif() + # Use a response file on Windows, in order not to exceed the max command-line length. + if(WIN32) + set(first_obj "") + list(GET new_o 0 first_obj) + string(REPLACE ";" " " relative_src_files "${relative_src_files}") + file(WRITE ${first_obj}.rsp ${relative_src_files}) + set(relative_src_files "@${first_obj}.rsp") + endif() + add_custom_command( OUTPUT ${new_o} ${new_bc} COMMAND ${LDC_EXE_FULL} ${dc_flags} ${relative_src_files} diff --git a/runtime/druntime/src/core/attribute.d b/runtime/druntime/src/core/attribute.d index 8a1dc8add89..c2a7c334eb7 100644 --- a/runtime/druntime/src/core/attribute.d +++ b/runtime/druntime/src/core/attribute.d @@ -236,9 +236,9 @@ version (UdaGNUAbiTag) struct gnuAbiTag { string[] tags; - this(string[] tags...) + this(string[] tags...) @safe pure nothrow { - this.tags = tags; + this.tags = tags.dup; } } diff --git a/runtime/druntime/src/core/cpuid.d b/runtime/druntime/src/core/cpuid.d index 1c2ac067704..b79bd1df9c4 100644 --- a/runtime/druntime/src/core/cpuid.d +++ b/runtime/druntime/src/core/cpuid.d @@ -1080,7 +1080,7 @@ void cpuidSparc() } */ -shared static this() +pragma(crt_constructor) void cpuid_initialization() { auto cf = getCpuFeatures(); diff --git a/runtime/druntime/src/core/demangle.d b/runtime/druntime/src/core/demangle.d index 4922c317670..c7ab6a9b489 100644 --- a/runtime/druntime/src/core/demangle.d +++ b/runtime/druntime/src/core/demangle.d @@ -801,7 +801,7 @@ pure @safe: TypeTuple: B Number Arguments */ - char[] parseType( char[] name = null ) return scope + char[] parseType() return scope { static immutable string[23] primitives = [ "char", // a @@ -830,7 +830,7 @@ pure @safe: ]; static if (__traits(hasMember, Hooks, "parseType")) - if (auto n = hooks.parseType(this, name)) + if (auto n = hooks.parseType(this, null)) return n; debug(trace) printf( "parseType+\n" ); @@ -861,27 +861,24 @@ pure @safe: switch ( t ) { case 'Q': // Type back reference - return parseBackrefType( () => parseType( name ) ); + return parseBackrefType(() => parseType()); case 'O': // Shared (O Type) popFront(); put( "shared(" ); parseType(); put( ')' ); - pad( name ); return dst[beg .. len]; case 'x': // Const (x Type) popFront(); put( "const(" ); parseType(); put( ')' ); - pad( name ); return dst[beg .. len]; case 'y': // Immutable (y Type) popFront(); put( "immutable(" ); parseType(); put( ')' ); - pad( name ); return dst[beg .. len]; case 'N': popFront(); @@ -912,7 +909,6 @@ pure @safe: popFront(); parseType(); put( "[]" ); - pad( name ); return dst[beg .. len]; case 'G': // TypeStaticArray (G Number Type) popFront(); @@ -921,7 +917,6 @@ pure @safe: put( '[' ); put( num ); put( ']' ); - pad( name ); return dst[beg .. len]; case 'H': // TypeAssocArray (H Type Type) popFront(); @@ -931,31 +926,28 @@ pure @safe: put( '[' ); put( tx ); put( ']' ); - pad( name ); return dst[beg .. len]; case 'P': // TypePointer (P Type) popFront(); parseType(); put( '*' ); - pad( name ); return dst[beg .. len]; case 'F': case 'U': case 'W': case 'V': case 'R': // TypeFunction - return parseTypeFunction( name ); + return parseTypeFunction(); case 'C': // TypeClass (C LName) case 'S': // TypeStruct (S LName) case 'E': // TypeEnum (E LName) case 'T': // TypeTypedef (T LName) popFront(); parseQualifiedName(); - pad( name ); return dst[beg .. len]; case 'D': // TypeDelegate (D TypeFunction) popFront(); auto modifiers = parseModifier(); if ( front == 'Q' ) - parseBackrefType( () => parseTypeFunction( name, IsDelegate.yes ) ); + parseBackrefType(() => parseTypeFunction(IsDelegate.yes)); else - parseTypeFunction( name, IsDelegate.yes ); + parseTypeFunction(IsDelegate.yes); if (modifiers) { // write modifiers behind the function arguments @@ -989,7 +981,6 @@ pure @safe: { popFront(); put( primitives[cast(size_t)(t - 'a')] ); - pad( name ); return dst[beg .. len]; } else if (t == 'z') @@ -1000,12 +991,10 @@ pure @safe: case 'i': popFront(); put( "cent" ); - pad( name ); return dst[beg .. len]; case 'k': popFront(); put( "ucent" ); - pad( name ); return dst[beg .. len]; default: error(); @@ -1358,7 +1347,7 @@ pure @safe: TypeFunction: CallConvention FuncAttrs Arguments ArgClose Type */ - char[] parseTypeFunction( char[] name = null, IsDelegate isdg = IsDelegate.no ) return scope + char[] parseTypeFunction(IsDelegate isdg = IsDelegate.no) return scope { debug(trace) printf( "parseTypeFunction+\n" ); debug(trace) scope(success) printf( "parseTypeFunction-\n" ); @@ -1383,18 +1372,8 @@ pure @safe: auto retbeg = len; parseType(); put( ' ' ); - // append name/delegate/function - if ( name.length ) - { - if ( !contains( dst[0 .. len], name ) ) - put( name ); - else if ( shift( name ).ptr != name.ptr ) - { - argbeg -= name.length; - retbeg -= name.length; - } - } - else if ( IsDelegate.yes == isdg ) + // append delegate/function + if (IsDelegate.yes == isdg) put( "delegate" ); else put( "function" ); diff --git a/runtime/druntime/src/core/factory.d b/runtime/druntime/src/core/factory.d new file mode 100644 index 00000000000..f45a04ea91f --- /dev/null +++ b/runtime/druntime/src/core/factory.d @@ -0,0 +1,68 @@ +/* Create classes from their modules and names. + * + * Copyright: Copyright (C) D Language Foundation 2023 + * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) + * Authors: Walter Bright, Steven Schveighoffer + * Source: $(DRUNTIMESRC core/_factory.d) + */ + +module core.factory; + +/** + * Create instance of class specified by the module symbol and a string + * representing the name of the class. + * The class must either have no constructors or have + * a default constructor. + * Params: + * mod = symbol representing the module that the class is in + * classname = string representing the name of the class + * Returns: + * null if failed + * Example: + * --- + * module foo.bar; + * + * class C + * { + * this() { x = 10; } + * int x; + * } + * + * void main() + * { + * auto c = cast(C)factory!(foo.bar)("C"); + * assert(c !is null && c.x == 10); + * } + * --- + */ +Object factory(alias mod)(string classname) +{ + foreach(cl; _getModuleClasses!mod) + { + if (cl.stringof == classname) + return cl.classinfo.create(); + } + return null; +} + +@system unittest +{ + Object valid_obj = factory!object("Object"); + Object invalid_obj = factory!object("__this_class_doesnt_exist__"); + + assert(valid_obj !is null); + assert(invalid_obj is null); +} + +/************************************** + * Retrieve as a tuple all the types of the top level classes in the module mod. + */ +private template _getModuleClasses(alias mod) { + alias result = _AliasSeq!(); + static foreach(m; __traits(allMembers, mod)) + static if(is(__traits(getMember, mod, m) == class)) + result = _AliasSeq!(result, __traits(getMember, mod, m)); + alias _getModuleClasses = result; +} + +private template _AliasSeq(TList...) { alias _AliasSeq = TList; } diff --git a/runtime/druntime/src/core/int128.d b/runtime/druntime/src/core/int128.d index dc5440774cf..681fe93661f 100644 --- a/runtime/druntime/src/core/int128.d +++ b/runtime/druntime/src/core/int128.d @@ -18,12 +18,27 @@ alias I = long; alias U = ulong; enum Ubits = uint(U.sizeof * 8); -version (LDC) version (X86) version = LDC_X86; +version (DigitalMars) +{ + /* The alignment should follow target.stackAlign(), + * which is `isXmmSupported() ? 16 : (is64bit ? 8 : 4) + */ + version (D_SIMD) + private enum Cent_alignment = 16; + else version (X86_64) + private enum Cent_alignment = 8; + else + private enum Cent_alignment = 4; +} +else +{ + version (LDC) version (X86) version = LDC_X86; -version (X86_64) private enum Cent_alignment = 16; -// 32-bit x86: need default alignment due to https://github.com/ldc-developers/ldc/issues/1356 -else version (LDC_X86) private enum Cent_alignment = U.alignof; -else private enum Cent_alignment = (size_t.sizeof * 2); + version (X86_64) private enum Cent_alignment = 16; + // 32-bit x86: need default alignment due to https://github.com/ldc-developers/ldc/issues/1356 + else version (LDC_X86) private enum Cent_alignment = U.alignof; + else private enum Cent_alignment = (size_t.sizeof * 2); +} align(Cent_alignment) struct Cent { diff --git a/runtime/druntime/src/core/internal/traits.d b/runtime/druntime/src/core/internal/traits.d index 0b4890cbfa9..966839f176a 100644 --- a/runtime/druntime/src/core/internal/traits.d +++ b/runtime/druntime/src/core/internal/traits.d @@ -654,7 +654,7 @@ if (func.length == 1 /*&& isCallable!func*/) int test(int); int test() @property; } - alias ov = __traits(getVirtualFunctions, Overloads, "test"); + alias ov = __traits(getVirtualMethods, Overloads, "test"); alias F_ov0 = FunctionTypeOf!(ov[0]); alias F_ov1 = FunctionTypeOf!(ov[1]); alias F_ov2 = FunctionTypeOf!(ov[2]); diff --git a/runtime/druntime/src/core/lifetime.d b/runtime/druntime/src/core/lifetime.d index 54493ceba95..5e339c041d1 100644 --- a/runtime/druntime/src/core/lifetime.d +++ b/runtime/druntime/src/core/lifetime.d @@ -2712,3 +2712,108 @@ T _d_newThrowable(T)() @trusted assert(exc.refcount() == 1); assert(e.refcount() == 1); } + +/** + * Create a new class instance. + * Allocates memory and sets fields to their initial value, but does not call a + * constructor. + * --- + * new C() // _d_newclass!(C)() + * --- + * Returns: newly created object + */ +T _d_newclassT(T)() @trusted +if (is(T == class)) +{ + import core.internal.traits : hasIndirections; + import core.exception : onOutOfMemoryError; + import core.memory : GC, pureMalloc; + + alias BlkAttr = GC.BlkAttr; + + auto init = __traits(initSymbol, T); + void* p; + + static if (__traits(getLinkage, T) == "Windows") + { + p = pureMalloc(init.length); + if (!p) + onOutOfMemoryError(); + } + else + { + BlkAttr attr = BlkAttr.NONE; + + /* `extern(C++)`` classes don't have a classinfo pointer in their vtable, + * so the GC can't finalize them. + */ + static if (__traits(hasMember, T, "__dtor") && __traits(getLinkage, T) != "C++") + attr |= BlkAttr.FINALIZE; + static if (!hasIndirections!T) + attr |= BlkAttr.NO_SCAN; + + p = GC.malloc(init.length, attr, typeid(T)); + debug(PRINTF) printf(" p = %p\n", p); + } + + debug(PRINTF) + { + printf("p = %p\n", p); + printf("init.ptr = %p, len = %llu\n", init.ptr, cast(ulong)init.length); + printf("vptr = %p\n", *cast(void**) init); + printf("vtbl[0] = %p\n", (*cast(void***) init)[0]); + printf("vtbl[1] = %p\n", (*cast(void***) init)[1]); + printf("init[0] = %x\n", (cast(uint*) init)[0]); + printf("init[1] = %x\n", (cast(uint*) init)[1]); + printf("init[2] = %x\n", (cast(uint*) init)[2]); + printf("init[3] = %x\n", (cast(uint*) init)[3]); + printf("init[4] = %x\n", (cast(uint*) init)[4]); + } + + // initialize it + p[0 .. init.length] = init[]; + + debug(PRINTF) printf("initialization done\n"); + return cast(T) p; +} + +// Test allocation +@safe unittest +{ + class C { } + C c = _d_newclassT!C(); + + assert(c !is null); +} + +// Test initializers +@safe unittest +{ + { + class C { int x, y; } + C c = _d_newclassT!C(); + + assert(c.x == 0); + assert(c.y == 0); + } + { + class C { int x = 2, y = 3; } + C c = _d_newclassT!C(); + + assert(c.x == 2); + assert(c.y == 3); + } +} + +T _d_newclassTTrace(T)(string file, int line, string funcname) @trusted +{ + version (D_TypeInfo) + { + import core.internal.array.utils: TraceHook, gcStatsPure, accumulatePure; + mixin(TraceHook!(T.stringof, "_d_newclassT")); + + return _d_newclassT!T(); + } + else + assert(0, "Cannot create new class if compiling without support for runtime type information!"); +} diff --git a/runtime/druntime/src/core/memory.d b/runtime/druntime/src/core/memory.d index 5186dda14a8..fe8978b59fb 100644 --- a/runtime/druntime/src/core/memory.d +++ b/runtime/druntime/src/core/memory.d @@ -202,8 +202,8 @@ unittest // make it more difficult to call the function again, manually. private void initialize(); pragma(crt_constructor) -pragma(mangle, `_D` ~ initialize.mangleof) -private extern (C) void initialize() @system +pragma(mangle, initialize.mangleof) +private extern (C) void _initialize() @system { version (Posix) { diff --git a/runtime/druntime/src/core/sys/freebsd/config.d b/runtime/druntime/src/core/sys/freebsd/config.d index 5e3129e2422..9d502e52e32 100644 --- a/runtime/druntime/src/core/sys/freebsd/config.d +++ b/runtime/druntime/src/core/sys/freebsd/config.d @@ -14,8 +14,9 @@ public import core.sys.posix.config; // NOTE: When adding newer versions of FreeBSD, verify all current versioned // bindings are still compatible with the release. - version (FreeBSD_13) enum __FreeBSD_version = 1300000; -else version (FreeBSD_12) enum __FreeBSD_version = 1202000; + version (FreeBSD_14) enum __FreeBSD_version = 1400000; +else version (FreeBSD_13) enum __FreeBSD_version = 1301000; +else version (FreeBSD_12) enum __FreeBSD_version = 1203000; else version (FreeBSD_11) enum __FreeBSD_version = 1104000; else version (FreeBSD_10) enum __FreeBSD_version = 1004000; else version (FreeBSD_9) enum __FreeBSD_version = 903000; diff --git a/runtime/druntime/src/core/sys/posix/netinet/in_.d b/runtime/druntime/src/core/sys/posix/netinet/in_.d index a58fa850d5d..5818ee6e22b 100644 --- a/runtime/druntime/src/core/sys/posix/netinet/in_.d +++ b/runtime/druntime/src/core/sys/posix/netinet/in_.d @@ -547,7 +547,7 @@ version (CRuntime_Glibc) } // macros - extern (D) int IN6_IS_ADDR_UNSPECIFIED( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_UNSPECIFIED( const scope in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && @@ -555,7 +555,7 @@ version (CRuntime_Glibc) (cast(uint32_t*) addr)[3] == 0; } - extern (D) int IN6_IS_ADDR_LOOPBACK( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_LOOPBACK( const scope in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && @@ -563,29 +563,29 @@ version (CRuntime_Glibc) (cast(uint32_t*) addr)[3] == htonl( 1 ); } - extern (D) int IN6_IS_ADDR_MULTICAST( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_MULTICAST( const scope in6_addr* addr ) pure { return (cast(uint8_t*) addr)[0] == 0xff; } - extern (D) int IN6_IS_ADDR_LINKLOCAL( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_LINKLOCAL( const scope in6_addr* addr ) pure { return ((cast(uint32_t*) addr)[0] & htonl( 0xffc00000 )) == htonl( 0xfe800000 ); } - extern (D) int IN6_IS_ADDR_SITELOCAL( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_SITELOCAL( const scope in6_addr* addr ) pure { return ((cast(uint32_t*) addr)[0] & htonl( 0xffc00000 )) == htonl( 0xfec00000 ); } - extern (D) int IN6_IS_ADDR_V4MAPPED( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_V4MAPPED( const scope in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && (cast(uint32_t*) addr)[2] == htonl( 0xffff ); } - extern (D) int IN6_IS_ADDR_V4COMPAT( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_V4COMPAT( const scope in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && @@ -593,31 +593,31 @@ version (CRuntime_Glibc) ntohl( (cast(uint32_t*) addr)[3] ) > 1; } - extern (D) int IN6_IS_ADDR_MC_NODELOCAL( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_MC_NODELOCAL( const scope in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr ) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x1; } - extern (D) int IN6_IS_ADDR_MC_LINKLOCAL( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_MC_LINKLOCAL( const scope in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr ) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x2; } - extern (D) int IN6_IS_ADDR_MC_SITELOCAL( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_MC_SITELOCAL( const scope in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST(addr) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x5; } - extern (D) int IN6_IS_ADDR_MC_ORGLOCAL( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_MC_ORGLOCAL( const scope in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x8; } - extern (D) int IN6_IS_ADDR_MC_GLOBAL( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_MC_GLOBAL( const scope in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr ) && ((cast(uint8_t*) addr)[1] & 0xf) == 0xe; @@ -670,7 +670,7 @@ else version (Darwin) } // macros - extern (D) int IN6_IS_ADDR_UNSPECIFIED( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_UNSPECIFIED( const scope in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && @@ -678,7 +678,7 @@ else version (Darwin) (cast(uint32_t*) addr)[3] == 0; } - extern (D) int IN6_IS_ADDR_LOOPBACK( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_LOOPBACK( const scope in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && @@ -686,29 +686,29 @@ else version (Darwin) (cast(uint32_t*) addr)[3] == ntohl( 1 ); } - extern (D) int IN6_IS_ADDR_MULTICAST( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_MULTICAST( const scope in6_addr* addr ) pure { return addr.s6_addr[0] == 0xff; } - extern (D) int IN6_IS_ADDR_LINKLOCAL( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_LINKLOCAL( const scope in6_addr* addr ) pure { return addr.s6_addr[0] == 0xfe && (addr.s6_addr[1] & 0xc0) == 0x80; } - extern (D) int IN6_IS_ADDR_SITELOCAL( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_SITELOCAL( const scope in6_addr* addr ) pure { return addr.s6_addr[0] == 0xfe && (addr.s6_addr[1] & 0xc0) == 0xc0; } - extern (D) int IN6_IS_ADDR_V4MAPPED( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_V4MAPPED( const scope in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && (cast(uint32_t*) addr)[2] == ntohl( 0x0000ffff ); } - extern (D) int IN6_IS_ADDR_V4COMPAT( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_V4COMPAT( const scope in6_addr* addr ) pure { return (cast(uint32_t*) addr)[0] == 0 && (cast(uint32_t*) addr)[1] == 0 && @@ -717,31 +717,31 @@ else version (Darwin) (cast(uint32_t*) addr)[3] != ntohl( 1 ); } - extern (D) int IN6_IS_ADDR_MC_NODELOCAL( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_MC_NODELOCAL( const scope in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr ) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x1; } - extern (D) int IN6_IS_ADDR_MC_LINKLOCAL( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_MC_LINKLOCAL( const scope in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr ) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x2; } - extern (D) int IN6_IS_ADDR_MC_SITELOCAL( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_MC_SITELOCAL( const scope in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST(addr) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x5; } - extern (D) int IN6_IS_ADDR_MC_ORGLOCAL( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_MC_ORGLOCAL( const scope in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr) && ((cast(uint8_t*) addr)[1] & 0xf) == 0x8; } - extern (D) int IN6_IS_ADDR_MC_GLOBAL( in6_addr* addr ) pure + extern (D) int IN6_IS_ADDR_MC_GLOBAL( const scope in6_addr* addr ) pure { return IN6_IS_ADDR_MULTICAST( addr ) && ((cast(uint8_t*) addr)[1] & 0xf) == 0xe; diff --git a/runtime/druntime/src/core/sys/posix/sys/stat.d b/runtime/druntime/src/core/sys/posix/sys/stat.d index 4bcba2a6116..ee9e5da2feb 100644 --- a/runtime/druntime/src/core/sys/posix/sys/stat.d +++ b/runtime/druntime/src/core/sys/posix/sys/stat.d @@ -1656,7 +1656,6 @@ else version (CRuntime_Bionic) } else version (CRuntime_Musl) { - alias __mode_t = uint; enum { S_IRUSR = 0x100, // octal 0400 S_IWUSR = 0x080, // octal 0200 diff --git a/runtime/druntime/src/core/sys/windows/stacktrace.d b/runtime/druntime/src/core/sys/windows/stacktrace.d index eba26e346f2..0608dbbbd7e 100644 --- a/runtime/druntime/src/core/sys/windows/stacktrace.d +++ b/runtime/druntime/src/core/sys/windows/stacktrace.d @@ -70,7 +70,7 @@ public: m_trace = trace(tracebuf[], skip, context); } - int opApply( scope int delegate(ref const(char[])) dg ) const + override int opApply( scope int delegate(ref const(char[])) dg ) const { return opApply( (ref size_t, ref const(char[]) buf) { @@ -79,7 +79,7 @@ public: } - int opApply( scope int delegate(ref size_t, ref const(char[])) dg ) const + override int opApply( scope int delegate(ref size_t, ref const(char[])) dg ) const { int result; foreach ( i, e; resolve(m_trace) ) @@ -241,6 +241,8 @@ private: if (frameNum >= skip) { buffer[nframes++] = stackframe.AddrPC.Offset; + if (nframes >= buffer.length) + break; } frameNum++; } diff --git a/runtime/druntime/src/core/sys/windows/winbase.d b/runtime/druntime/src/core/sys/windows/winbase.d index 3b571ad57da..bbb6e9a7b41 100644 --- a/runtime/druntime/src/core/sys/windows/winbase.d +++ b/runtime/druntime/src/core/sys/windows/winbase.d @@ -38,6 +38,7 @@ import core.sys.windows.basetyps, core.sys.windows.w32api, core.sys.windows.winn // FIXME: //alias void va_list; import core.stdc.stdarg : va_list; +import core.stdc.string : memset, memcpy, memmove; // COMMPROP structure, used by GetCommProperties() @@ -1713,23 +1714,15 @@ extern (Windows) nothrow @nogc { BOOL CopyFileExA(LPCSTR, LPCSTR, LPPROGRESS_ROUTINE, LPVOID, LPBOOL, DWORD); BOOL CopyFileExW(LPCWSTR, LPCWSTR, LPPROGRESS_ROUTINE, LPVOID, LPBOOL, DWORD); - /+ FIXME - alias memmove RtlMoveMemory; - alias memcpy RtlCopyMemory; + alias RtlMoveMemory = memmove; + alias RtlCopyMemory = memcpy; + pragma(inline, true) void RtlFillMemory(PVOID Destination, SIZE_T Length, BYTE Fill) { memset(Destination, Fill, Length); } + pragma(inline, true) void RtlZeroMemory(PVOID Destination, SIZE_T Length) { memset(Destination, 0, Length); } + alias MoveMemory = RtlMoveMemory; + alias CopyMemory = RtlCopyMemory; + alias FillMemory = RtlFillMemory; + alias ZeroMemory = RtlZeroMemory; - void RtlFillMemory(PVOID dest, SIZE_T len, BYTE fill) { - memset(dest, fill, len); - } - - void RtlZeroMemory(PVOID dest, SIZE_T len) { - RtlFillMemory(dest, len, 0); - } - - alias RtlMoveMemory MoveMemory; - alias RtlCopyMemory CopyMemory; - alias RtlFillMemory FillMemory; - alias RtlZeroMemory ZeroMemory; - +/ BOOL CreateDirectoryA(LPCSTR, LPSECURITY_ATTRIBUTES); BOOL CreateDirectoryW(LPCWSTR, LPSECURITY_ATTRIBUTES); BOOL CreateDirectoryExA(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES); diff --git a/runtime/druntime/src/core/thread/fiber.d b/runtime/druntime/src/core/thread/fiber.d index 6e7e6ae300e..161e2ff766c 100644 --- a/runtime/druntime/src/core/thread/fiber.d +++ b/runtime/druntime/src/core/thread/fiber.d @@ -16,6 +16,8 @@ import core.thread.threadgroup; import core.thread.types; import core.thread.context; +import core.memory : pageSize; + version (OSX) version = Darwin; else version (iOS) @@ -784,7 +786,7 @@ class Fiber version (X86_64) // libunwind on macOS 11 now requires more stack space than 16k, so // default to a larger stack size. This is only applied to X86 as - // the PAGESIZE is still 4k, however on AArch64 it is 16k. + // the pageSize is still 4k, however on AArch64 it is 16k. enum defaultStackPages = 8; else enum defaultStackPages = 4; @@ -807,8 +809,8 @@ class Fiber * In: * fn must not be null. */ - this( void function() fn, size_t sz = PAGESIZE * defaultStackPages, - size_t guardPageSize = PAGESIZE ) nothrow + this( void function() fn, size_t sz = pageSize * defaultStackPages, + size_t guardPageSize = pageSize ) nothrow in { assert( fn ); @@ -835,8 +837,8 @@ class Fiber * In: * dg must not be null. */ - this( void delegate() dg, size_t sz = PAGESIZE * defaultStackPages, - size_t guardPageSize = PAGESIZE ) nothrow + this( void delegate() dg, size_t sz = pageSize * defaultStackPages, + size_t guardPageSize = pageSize ) nothrow { allocStack( sz, guardPageSize ); reset( cast(void delegate() const) dg ); @@ -1190,9 +1192,9 @@ private: } do { - // adjust alloc size to a multiple of PAGESIZE - sz += PAGESIZE - 1; - sz -= sz % PAGESIZE; + // adjust alloc size to a multiple of pageSize + sz += pageSize - 1; + sz -= sz % pageSize; // NOTE: This instance of Thread.Context is dynamic so Fiber objects // can be collected by the GC so long as no user level references diff --git a/runtime/druntime/src/core/thread/osthread.d b/runtime/druntime/src/core/thread/osthread.d index d54f4716b80..bc47c17e890 100644 --- a/runtime/druntime/src/core/thread/osthread.d +++ b/runtime/druntime/src/core/thread/osthread.d @@ -16,7 +16,7 @@ import core.thread.threadbase; import core.thread.context; import core.thread.types; import core.atomic; -import core.memory : GC; +import core.memory : GC, pageSize; import core.time; import core.exception : onOutOfMemoryError; import core.internal.traits : externDFunc; @@ -1119,7 +1119,7 @@ unittest unittest { - // use >PAGESIZE to avoid stack overflow (e.g. in an syscall) + // use >pageSize to avoid stack overflow (e.g. in an syscall) auto thr = new Thread(function{}, 4096 + 1).start(); thr.join(); } @@ -2968,8 +2968,8 @@ private size_t adjustStackSize(size_t sz) nothrow @nogc size_t function() @nogc nothrow)(); } - // stack size must be a multiple of PAGESIZE - sz = ((sz + PAGESIZE - 1) & ~(PAGESIZE - 1)); + // stack size must be a multiple of pageSize + sz = ((sz + pageSize - 1) & ~(pageSize - 1)); return sz; } diff --git a/runtime/druntime/src/core/thread/types.d b/runtime/druntime/src/core/thread/types.d index e50399a59d9..eb84ad74b48 100644 --- a/runtime/druntime/src/core/thread/types.d +++ b/runtime/druntime/src/core/thread/types.d @@ -47,31 +47,15 @@ else package { - static immutable size_t PAGESIZE; version (Posix) static immutable size_t PTHREAD_STACK_MIN; } shared static this() { - version (Windows) - { - import core.sys.windows.winbase; - - SYSTEM_INFO info; - GetSystemInfo(&info); - - PAGESIZE = info.dwPageSize; - assert(PAGESIZE < int.max); - } - else version (Posix) + version (Posix) { import core.sys.posix.unistd; - PAGESIZE = cast(size_t)sysconf(_SC_PAGESIZE); PTHREAD_STACK_MIN = cast(size_t)sysconf(_SC_THREAD_STACK_MIN); } - else - { - static assert(0, "unimplemented"); - } } diff --git a/runtime/druntime/src/importc.h b/runtime/druntime/src/importc.h index c9e54646b60..5d50e541969 100644 --- a/runtime/druntime/src/importc.h +++ b/runtime/druntime/src/importc.h @@ -43,6 +43,13 @@ */ #define __fastcall +#define __forceinline +#undef _Check_return_ +//#define _Check_return_ +#define __pragma(x) + +#undef _GLIBCXX_USE_FLOAT128 + /* Microsoft builtin types */ #define __int8 char #define __int16 short @@ -66,21 +73,58 @@ */ #define __extension__ /* ignore it, as ImportC doesn't do warnings */ +/******************************** + * __has_extension is a clang thing: + * https://clang.llvm.org/docs/LanguageExtensions.html + * ImportC no has extensions. + */ +#undef __has_feature +#define __has_feature(x) 0 + +#undef __has_extension +#define __has_extension(x) 0 + +/************************************* + * OS-specific macros + */ +#if __APPLE__ +#define __builtin___memmove_chk(dest, src, len, x) memmove(dest,src,len) // put it back to memmove() +#define __builtin___memcpy_chk(dest, src, len, x) memcpy(dest,src,len) +#define __builtin___memset_chk(dest, val, len, x) memset(dest,val,len) +#define __builtin___stpcpy_chk(dest, src, x) stpcpy(dest,src) +#define __builtin___stpncpy_chk(dest, src, len, x) stpncpy(dest,src,len) +#define __builtin___strcat_chk(dest, src, x) strcat(dest,src) +#define __builtin___strcpy_chk(dest, src, x) strcpy(dest,src) +#define __builtin___strncat_chk(dest, src, len, x) strncat(dest,src,len) +#define __builtin___strncpy_chk(dest, src, len, x) strncpy(dest,src,len) +#endif + +#if __FreeBSD__ +#endif + +#if _MSC_VER +//#undef _Post_writable_size +//#define _Post_writable_size(x) // consider #include +#endif + /**************************** * Define it to do what other C compilers do. */ #define __builtin_offsetof(t,i) ((typeof(sizeof(0)))((char *)&((t *)0)->i - (char *)0)) +#define __builtin_bit_cast(t,e) (*(t*)(void*)&(e)) + /*************************** * C11 6.10.8.3 Conditional feature macros */ #define __STDC_NO_VLA__ 1 -/************************* - * Ubuntu's assert.h uses this - */ #if linux // Microsoft won't allow the following macro +// Ubuntu's assert.h uses this #define __PRETTY_FUNCTION__ __func__ + +#define _Float128 long double +#define __float128 long double #endif #if __APPLE__ diff --git a/runtime/druntime/src/object.d b/runtime/druntime/src/object.d index dafc4d2dbb9..c24effd58d4 100644 --- a/runtime/druntime/src/object.d +++ b/runtime/druntime/src/object.d @@ -275,7 +275,7 @@ class Object * } * --- */ - deprecated static Object factory(string classname) + static Object factory(string classname) { auto ci = TypeInfo_Class.find(classname); if (ci) @@ -285,7 +285,7 @@ class Object return null; } - deprecated @system unittest + @system unittest { Object valid_obj = Object.factory("object.Object"); Object invalid_obj = Object.factory("object.__this_class_doesnt_exist__"); @@ -1465,7 +1465,7 @@ class TypeInfo_Function : TypeInfo int func(int a, int b); } - alias functionTypes = typeof(__traits(getVirtualFunctions, C, "func")); + alias functionTypes = typeof(__traits(getVirtualMethods, C, "func")); assert(typeid(functionTypes[0]).toString() == "void function()"); assert(typeid(functionTypes[1]).toString() == "void function(int)"); assert(typeid(functionTypes[2]).toString() == "int function(int, int)"); @@ -1479,7 +1479,7 @@ class TypeInfo_Function : TypeInfo void func(int a); } - alias functionTypes = typeof(__traits(getVirtualFunctions, C, "func")); + alias functionTypes = typeof(__traits(getVirtualMethods, C, "func")); Object obj = typeid(functionTypes[0]); assert(obj.opEquals(typeid(functionTypes[0]))); @@ -2986,25 +2986,6 @@ void clear(Value, Key)(Value[Key]* aa) assert("k1" !in aa); } -// Issue 20559 -@system unittest -{ - static class Foo - { - int[string] aa; - alias aa this; - } - - auto v = new Foo(); - v["Hello World"] = 42; - v.clear; - assert("Hello World" !in v); - - // Test for T* - static assert(!__traits(compiles, (&v).clear)); - static assert( __traits(compiles, (*(&v)).clear)); -} - /*********************************** * Reorganizes the associative array in place so that lookups are more * efficient. @@ -4337,44 +4318,6 @@ void destroy(bool initialize = true, T)(T obj) if (is(T == interface)) destroy!true(new C()); } -@system unittest -{ - // class with an `alias this` - class A - { - static int dtorCount; - ~this() - { - dtorCount++; - } - } - - class B - { - A a; - alias a this; - this() - { - a = new A; - } - static int dtorCount; - ~this() - { - dtorCount++; - } - } - auto b = new B; - assert(A.dtorCount == 0); - assert(B.dtorCount == 0); - destroy(b); - assert(A.dtorCount == 0); - assert(B.dtorCount == 1); - - auto a = new A; - destroy(a); - assert(A.dtorCount == 1); -} - @system unittest { interface I { } @@ -4588,43 +4531,6 @@ if (__traits(isStaticArray, T)) } } -// https://issues.dlang.org/show_bug.cgi?id=19218 -@system unittest -{ - static struct S - { - static dtorCount = 0; - ~this() { ++dtorCount; } - } - - static interface I - { - ref S[3] getArray(); - alias getArray this; - } - - static class C : I - { - static dtorCount = 0; - ~this() { ++dtorCount; } - - S[3] a; - alias a this; - - ref S[3] getArray() { return a; } - } - - C c = new C(); - destroy(c); - assert(S.dtorCount == 3); - assert(C.dtorCount == 1); - - I i = new C(); - destroy(i); - assert(S.dtorCount == 6); - assert(C.dtorCount == 2); -} - /// ditto void destroy(bool initialize = true, T)(ref T obj) if (!is(T == struct) && !is(T == interface) && !is(T == class) && !__traits(isStaticArray, T)) @@ -4708,6 +4614,8 @@ public import core.internal.switch_: __switch_error; public import core.lifetime : _d_delstructImpl; public import core.lifetime : _d_newThrowable; +public import core.lifetime : _d_newclassT; +public import core.lifetime : _d_newclassTTrace; public @trusted @nogc nothrow pure extern (C) void _d_delThrowable(scope Throwable); diff --git a/runtime/druntime/src/rt/tracegc.d b/runtime/druntime/src/rt/tracegc.d index 2575a50dab9..29b61468056 100644 --- a/runtime/druntime/src/rt/tracegc.d +++ b/runtime/druntime/src/rt/tracegc.d @@ -17,7 +17,6 @@ module rt.tracegc; // version = tracegc; -extern (C) Object _d_newclass(const ClassInfo ci); extern (C) void[] _d_newarrayT(const TypeInfo ti, size_t length); extern (C) void[] _d_newarrayU(const scope TypeInfo ti, size_t length); extern (C) void[] _d_newarrayiT(const TypeInfo ti, size_t length); diff --git a/runtime/druntime/test/exceptions/Makefile b/runtime/druntime/test/exceptions/Makefile index 76685d01e4b..ba81a49fe21 100644 --- a/runtime/druntime/test/exceptions/Makefile +++ b/runtime/druntime/test/exceptions/Makefile @@ -110,7 +110,7 @@ $(ROOT)/rt_trap_exceptions_drt_gdb.done: $(ROOT)/rt_trap_exceptions_drt $(QUIET)$(TIMELIMIT) $(GDB) -n -ex 'set confirm off' -ex run -ex 'bt full' -ex q --args $< --DRT-trapExceptions=0 \ > $(ROOT)/rt_trap_exceptions_drt_gdb.output 2>&1 || true cat $(ROOT)/rt_trap_exceptions_drt_gdb.output - grep "D main (args=...) at .*rt_trap_exceptions_drt.d:9" > /dev/null < $(ROOT)/rt_trap_exceptions_drt_gdb.output + grep "\(D main\|_Dmain\) (args=...) at .*rt_trap_exceptions_drt.d:9" > /dev/null < $(ROOT)/rt_trap_exceptions_drt_gdb.output grep 'myLocal' > /dev/null < $(ROOT)/rt_trap_exceptions_drt_gdb.output ! grep "No stack." > /dev/null < $(ROOT)/rt_trap_exceptions_drt_gdb.output @touch $@ diff --git a/runtime/druntime/test/exceptions/src/winstack.d b/runtime/druntime/test/exceptions/src/winstack.d index fcade2893ca..0577a2d04a4 100644 --- a/runtime/druntime/test/exceptions/src/winstack.d +++ b/runtime/druntime/test/exceptions/src/winstack.d @@ -49,6 +49,15 @@ void main() assert(checkStack(ex), "Bad stack"); } } + + // see https://issues.dlang.org/show_bug.cgi?id=23859 + try + { + recurseThrow(200); + } + catch(Exception e) + { + } } void regular() @@ -66,3 +75,10 @@ void recursion(int i) f(); } } + +void* recurseThrow(int n) +{ + if (n > 0) + return recurseThrow(n - 1) + 1; // avoid tail call optimization + throw new Exception("cancel"); +} diff --git a/runtime/druntime/test/profile/myprofilegc.log.freebsd.32.exp b/runtime/druntime/test/profile/myprofilegc.log.freebsd.32.exp index 7e1a05881c6..15b5e41fd7c 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.freebsd.32.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.freebsd.32.exp @@ -6,6 +6,7 @@ bytes allocated, allocations, type, function, file:line 48 1 float[] D main src/profilegc.d:42 48 1 int[] D main src/profilegc.d:41 32 1 void[] profilegc.main src/profilegc.d:55 + 16 1 C D main src/profilegc.d:12 16 1 char[] D main src/profilegc.d:34 16 1 char[] D main src/profilegc.d:36 16 1 closure profilegc.main.foo src/profilegc.d:45 @@ -15,5 +16,5 @@ bytes allocated, allocations, type, function, file:line 16 1 int[] D main src/profilegc.d:14 16 1 int[] D main src/profilegc.d:22 16 1 int[] D main src/profilegc.d:37 - 16 1 profilegc.main.C D main src/profilegc.d:12 + 16 1 profilegc.main.C core.lifetime._d_newclassT!(C)._d_newclassT ../../src/core/lifetime.d:2755 16 1 wchar[] D main src/profilegc.d:35 diff --git a/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp b/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp index a3e18492074..79c86edcfb3 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.freebsd.64.exp @@ -5,7 +5,8 @@ bytes allocated, allocations, type, function, file:line 64 1 double[] profilegc.main src/profilegc.d:56 48 1 float[] D main src/profilegc.d:42 48 1 int[] D main src/profilegc.d:41 - 32 1 profilegc.main.C D main src/profilegc.d:12 + 32 1 C D main src/profilegc.d:12 + 32 1 profilegc.main.C core.lifetime._d_newclassT!(C)._d_newclassT ../../src/core/lifetime.d:2755 32 1 void[] profilegc.main src/profilegc.d:55 16 1 char[] D main src/profilegc.d:34 16 1 char[] D main src/profilegc.d:36 diff --git a/runtime/druntime/test/profile/myprofilegc.log.linux.32.exp b/runtime/druntime/test/profile/myprofilegc.log.linux.32.exp index 7e1a05881c6..15b5e41fd7c 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.linux.32.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.linux.32.exp @@ -6,6 +6,7 @@ bytes allocated, allocations, type, function, file:line 48 1 float[] D main src/profilegc.d:42 48 1 int[] D main src/profilegc.d:41 32 1 void[] profilegc.main src/profilegc.d:55 + 16 1 C D main src/profilegc.d:12 16 1 char[] D main src/profilegc.d:34 16 1 char[] D main src/profilegc.d:36 16 1 closure profilegc.main.foo src/profilegc.d:45 @@ -15,5 +16,5 @@ bytes allocated, allocations, type, function, file:line 16 1 int[] D main src/profilegc.d:14 16 1 int[] D main src/profilegc.d:22 16 1 int[] D main src/profilegc.d:37 - 16 1 profilegc.main.C D main src/profilegc.d:12 + 16 1 profilegc.main.C core.lifetime._d_newclassT!(C)._d_newclassT ../../src/core/lifetime.d:2755 16 1 wchar[] D main src/profilegc.d:35 diff --git a/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp b/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp index a3e18492074..79c86edcfb3 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.linux.64.exp @@ -5,7 +5,8 @@ bytes allocated, allocations, type, function, file:line 64 1 double[] profilegc.main src/profilegc.d:56 48 1 float[] D main src/profilegc.d:42 48 1 int[] D main src/profilegc.d:41 - 32 1 profilegc.main.C D main src/profilegc.d:12 + 32 1 C D main src/profilegc.d:12 + 32 1 profilegc.main.C core.lifetime._d_newclassT!(C)._d_newclassT ../../src/core/lifetime.d:2755 32 1 void[] profilegc.main src/profilegc.d:55 16 1 char[] D main src/profilegc.d:34 16 1 char[] D main src/profilegc.d:36 diff --git a/runtime/druntime/test/profile/myprofilegc.log.osx.32.exp b/runtime/druntime/test/profile/myprofilegc.log.osx.32.exp index a099944c288..4faa76ae777 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.osx.32.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.osx.32.exp @@ -6,6 +6,7 @@ bytes allocated, allocations, type, function, file:line 64 1 int[] D main src/profilegc.d:41 64 1 double[] profilegc.main src/profilegc.d:56 32 1 void[] profilegc.main src/profilegc.d:55 + 16 1 C D main src/profilegc.d:12 16 1 char[] D main src/profilegc.d:34 16 1 char[] D main src/profilegc.d:36 16 1 closure profilegc.main.foo src/profilegc.d:45 @@ -15,5 +16,5 @@ bytes allocated, allocations, type, function, file:line 16 1 int[] D main src/profilegc.d:14 16 1 int[] D main src/profilegc.d:22 16 1 int[] D main src/profilegc.d:37 - 16 1 profilegc.main.C D main src/profilegc.d:12 + 16 1 profilegc.main.C core.lifetime._d_newclassT!(C)._d_newclassT ../../src/core/lifetime.d:2755 16 1 wchar[] D main src/profilegc.d:35 diff --git a/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp b/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp index a3e18492074..79c86edcfb3 100644 --- a/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp +++ b/runtime/druntime/test/profile/myprofilegc.log.osx.64.exp @@ -5,7 +5,8 @@ bytes allocated, allocations, type, function, file:line 64 1 double[] profilegc.main src/profilegc.d:56 48 1 float[] D main src/profilegc.d:42 48 1 int[] D main src/profilegc.d:41 - 32 1 profilegc.main.C D main src/profilegc.d:12 + 32 1 C D main src/profilegc.d:12 + 32 1 profilegc.main.C core.lifetime._d_newclassT!(C)._d_newclassT ../../src/core/lifetime.d:2755 32 1 void[] profilegc.main src/profilegc.d:55 16 1 char[] D main src/profilegc.d:34 16 1 char[] D main src/profilegc.d:36 diff --git a/runtime/phobos b/runtime/phobos index 28bf63ab130..6c83b490f7d 160000 --- a/runtime/phobos +++ b/runtime/phobos @@ -1 +1 @@ -Subproject commit 28bf63ab1302f04694f1fc00a68df09b856bbd7a +Subproject commit 6c83b490f7d6c66bf430e5249dae608848d3ac2c diff --git a/tests/codegen/const_struct_export.d b/tests/codegen/const_struct_export.d index 6cfb48620b8..d5c68f2847a 100644 --- a/tests/codegen/const_struct_export.d +++ b/tests/codegen/const_struct_export.d @@ -8,7 +8,7 @@ export void exportedFunction() {} export void importedFunction(); export immutable int exportedVariable = 1; -export immutable int importedVariable; +export extern immutable int importedVariable; void foo () { immutable auto exportedFuncs = [ &exportedFunction, &exportedFunction ]; diff --git a/tests/dmd/compilable/ctests2.c b/tests/dmd/compilable/ctests2.c index 8b8ca96285a..16da88ba378 100644 --- a/tests/dmd/compilable/ctests2.c +++ b/tests/dmd/compilable/ctests2.c @@ -190,3 +190,19 @@ const typeof(testTypeofA) testTypeofB = 0; _Static_assert(sizeof(testTypeofB) == sizeof(short), "17"); /*************************************************/ + +// https://issues.dlang.org/show_bug.cgi?id=23752 +void *c23752 = &*((void*)(0)); + +/*************************************************/ + +// https://issues.dlang.org/show_bug.cgi?id=23767 +const int arr23767[4]; +void f23767(void) +{ + int x = *(0 ? (void*)0 : arr23767); + int y = *(1 ? arr23767 : (void*)(3-3)); + int* p = (1 ? (void*)0 : (void*)0); +} + +/*************************************************/ diff --git a/tests/dmd/compilable/extra-files/header1.di b/tests/dmd/compilable/extra-files/header1.di index fa4eb937715..ef298a3878a 100644 --- a/tests/dmd/compilable/extra-files/header1.di +++ b/tests/dmd/compilable/extra-files/header1.di @@ -215,15 +215,11 @@ class xFoo2 : iFoo, iFoo2 } class Foo3 { - this(int a, ...) - { - } - this(int* a) - { - } + this(int a, ...); + this(int* a); } alias myint = int; -static notquit = 1; +static extern typeof(1) notquit; class Test { void a(); @@ -277,7 +273,7 @@ void templ(T)(T val) { pragma (msg, "Invalid destination type."); } -static char[] charArray = ['"', '\'']; +static extern char[] charArray; class Point { auto x = 10; @@ -368,12 +364,8 @@ struct S6360 } struct S12 { - nothrow this(int n) - { - } - nothrow this(string s) - { - } + nothrow this(int n); + nothrow this(string s); } struct T12 { @@ -482,11 +474,7 @@ class TestClass int aa; int b1; int b2; - this(int b1, int b2) - { - this.b1 = b1; - this.b2 = b2; - } + this(int b1, int b2); ref foo() { return aa; @@ -514,9 +502,7 @@ size_t magic(); class Foo2A { immutable(FooA) Dummy = new immutable(FooA); - private immutable pure nothrow @nogc @safe this() - { - } + private immutable pure nothrow @nogc @safe this(); } struct Foo3A(T) { @@ -573,4 +559,4 @@ interface I12344 assert(result > 0); } ; -} +} \ No newline at end of file diff --git a/tests/dmd/compilable/extra-files/header18365.d b/tests/dmd/compilable/extra-files/header18365.d index 64d8ad073cf..a0fb8333d1b 100644 --- a/tests/dmd/compilable/extra-files/header18365.d +++ b/tests/dmd/compilable/extra-files/header18365.d @@ -1,5 +1,5 @@ module foo.bar.ba; -nothrow pure @nogc @safe package(foo) +nothrow pure @nogc @safe package(foo) { void foo(); nothrow pure @nogc @safe package(foo.bar) void foo2(); diff --git a/tests/dmd/compilable/extra-files/header1i.di b/tests/dmd/compilable/extra-files/header1i.di index f1b371304f5..61125ef5c95 100644 --- a/tests/dmd/compilable/extra-files/header1i.di +++ b/tests/dmd/compilable/extra-files/header1i.di @@ -241,7 +241,7 @@ class Foo3 } } alias myint = int; -static notquit = 1; +static extern typeof(1) notquit; class Test { void a() @@ -357,7 +357,7 @@ void templ(T)(T val) { pragma (msg, "Invalid destination type."); } -static char[] charArray = ['"', '\'']; +static extern char[] charArray; class Point { auto x = 10; diff --git a/tests/dmd/compilable/extra-files/header2.di b/tests/dmd/compilable/extra-files/header2.di index b78abdcc2dd..7a2cff9de31 100644 --- a/tests/dmd/compilable/extra-files/header2.di +++ b/tests/dmd/compilable/extra-files/header2.di @@ -76,7 +76,7 @@ template templateVariableBar(T) if (is(T == int)) { enum int templateVariableBar = T.stringof.length; } -auto flit = 3 / 2.0; +extern typeof(3 / 2.0) flit; void foo11217()(const int[] arr) { } @@ -162,18 +162,12 @@ interface LeInterface } class LeClass { - this() - { - auto foo = new class LeInterface - { - } - ; - } + this(); } -const levar = new class LeClass, LeInterface +extern const typeof(new class LeClass, LeInterface { } -; +) levar; class CC { @safe void fun()() @@ -186,4 +180,4 @@ class CC } private struct Export { -} +} \ No newline at end of file diff --git a/tests/dmd/compilable/extra-files/header2i.di b/tests/dmd/compilable/extra-files/header2i.di index 3a563958c4f..9c57de106e7 100644 --- a/tests/dmd/compilable/extra-files/header2i.di +++ b/tests/dmd/compilable/extra-files/header2i.di @@ -89,7 +89,7 @@ template templateVariableBar(T) if (is(T == int)) { enum int templateVariableBar = T.stringof.length; } -auto flit = 3 / 2.0; +extern typeof(3 / 2.0) flit; void foo11217()(const int[] arr) { } @@ -272,10 +272,10 @@ class LeClass ; } } -const levar = new class LeClass, LeInterface +extern const typeof(new class LeClass, LeInterface { } -; +) levar; class CC { @safe void fun()() diff --git a/tests/dmd/compilable/extra-files/imp9057.d b/tests/dmd/compilable/extra-files/imp9057.d index 54598dd7769..74f035e40d3 100644 --- a/tests/dmd/compilable/extra-files/imp9057.d +++ b/tests/dmd/compilable/extra-files/imp9057.d @@ -1,5 +1,5 @@ struct BugInt { - uint[] data = ZEROX; + uint[] data = ZEROX; } enum uint [] ZEROX = [0]; diff --git a/tests/dmd/compilable/extra-files/test23626a.d b/tests/dmd/compilable/extra-files/test23626a.d index d3608f407fa..a1345929e14 100644 --- a/tests/dmd/compilable/extra-files/test23626a.d +++ b/tests/dmd/compilable/extra-files/test23626a.d @@ -1,5 +1,5 @@ template fullyQualifiedName(T...) -{ +{ enum fullyQualifiedName = !T[0]; } diff --git a/tests/dmd/compilable/extra-files/vcg-ast.d.cg b/tests/dmd/compilable/extra-files/vcg-ast.d.cg index 8fc8ac970a5..cdafdb9d7a2 100644 --- a/tests/dmd/compilable/extra-files/vcg-ast.d.cg +++ b/tests/dmd/compilable/extra-files/vcg-ast.d.cg @@ -109,7 +109,7 @@ R!int } mixin _d_cmain!(); { - extern (C) + extern (C) { extern (C) int _Dmain(char[][] args); version (Windows) diff --git a/tests/dmd/compilable/ice13920.d b/tests/dmd/compilable/ice13920.d index 466b2e0449f..a4540d1eac8 100644 --- a/tests/dmd/compilable/ice13920.d +++ b/tests/dmd/compilable/ice13920.d @@ -14,11 +14,6 @@ class Foo { auto dg = &f; } - - foreach (f; __traits(getVirtualFunctions, typeof(this), "bar")) - { - auto dg = &f; - } } uint bar() { return 0; } diff --git a/tests/dmd/compilable/imports/test23597.di b/tests/dmd/compilable/imports/test23597.di new file mode 100644 index 00000000000..d21a0f76491 --- /dev/null +++ b/tests/dmd/compilable/imports/test23597.di @@ -0,0 +1,3 @@ +module imports.test23597; + +void fun()() {} diff --git a/tests/dmd/compilable/infer_stc.d b/tests/dmd/compilable/infer_stc.d new file mode 100644 index 00000000000..50140e73d2b --- /dev/null +++ b/tests/dmd/compilable/infer_stc.d @@ -0,0 +1,51 @@ +/// Test storage class inference on delegate parameters + +alias FPT = void function (in string, ref string, out string, scope string); +alias DGT = void delegate (in string, ref string, out string, scope string); + +void f1 (FPT func) +{ + string ro = "Hello World"; + string ref_ = ro, out_ = ro; + func(ro, ref_, out_, ro); +} + +void f2 (DGT func) +{ + string ro = "Hello World"; + string ref_ = ro, out_ = ro; + func(ro, ref_, out_, ro); +} + +void test () +{ + f1((in_, ref_, out_, scope_) { + assert(in_ == "Hello World"); + assert(in_ == scope_); + assert(in_ == ref_); + assert(out_ is null); + }); + + f2((in_, ref_, out_, scope_) { + assert(in_ == "Hello World"); + assert(in_ == scope_); + assert(in_ == ref_); + assert(out_ is null); + }); +} + +// https://issues.dlang.org/show_bug.cgi?id=11316 +void issue11316() { + void delegate(const int x) F0; + F0 = (const int x) {}; // OK + F0 = (x) {}; // OK + void delegate(in int x) F1; + F1 = (in int x) {}; // OK + F1 = (x) {}; // OK + void delegate(ref int x) F2; + F2 = (ref int x) {}; // OK + F2 = (x) {}; // Error + void delegate(out int x) F3; + F3 = (out int x) {}; // OK + F3 = (x) {}; // Error +} diff --git a/tests/dmd/compilable/issue23597.d b/tests/dmd/compilable/issue23597.d new file mode 100644 index 00000000000..9299d744cea --- /dev/null +++ b/tests/dmd/compilable/issue23597.d @@ -0,0 +1,7 @@ +/** +PERMUTE_ARGS: -i +LINK: +**/ +import imports.test23597; + +void main() { fun(); } diff --git a/tests/dmd/compilable/named_argumens_struct.d b/tests/dmd/compilable/named_argumens_struct.d new file mode 100644 index 00000000000..0c60509dda8 --- /dev/null +++ b/tests/dmd/compilable/named_argumens_struct.d @@ -0,0 +1,24 @@ + +struct S +{ + string name; + int x; + int y; +} + + +immutable S s = S(x: 2, 3, name: "boo"); + +static assert(s.x == 2); +static assert(s.y == 3); +static assert(s.name == "boo"); + +union U +{ + float f; + int i; +} + +immutable U u = U(i: 2); + +static assert(u.i == 2); diff --git a/tests/dmd/compilable/named_arguments.d b/tests/dmd/compilable/named_arguments.d new file mode 100644 index 00000000000..f287ccdea95 --- /dev/null +++ b/tests/dmd/compilable/named_arguments.d @@ -0,0 +1,74 @@ + +string fun(string x, string y, string z = "Z", string w = "W") +{ + return x ~ y ~ z ~ w; +} + +static assert(fun( "x", "y") == "xyZW"); +static assert(fun( "x", "y", "z", "w") == "xyzw"); +static assert(fun(x: "x", y: "y", z: "z", w: "w") == "xyzw"); +static assert(fun(w: "w", z: "z", y: "y", x: "x") == "xyzw"); +static assert(fun(y: "y", "z", x: "x") == "xyzW"); +static assert(fun( "x", "y", w: "w") == "xyZw"); +static assert(fun(x: "x", "y", z: "z") == "xyzW"); + +// Default arguments need not all be at the end anymore +string fun2(string x = "x", string y, string z = "z") +{ + return x ~ y ~ z; +} + +static assert(fun2(y: "y") == "xyz"); + +// The assumption that first parameter having a default implies all parameters have a default is no longer valid, +// so this struct constructor shouldn't be mistaken for a default constructor. +struct SD { this(int x = 1, int y) { } } + +// UFCS +static assert("x".fun("y", w: "w") == "xyZw"); + +// tuples +alias AliasSeq(T...) = T; + +static assert("x".fun(x: AliasSeq!(), "y", w: "w") == "xyZw"); +static assert(AliasSeq!("x", "y").fun(w: "w", z: AliasSeq!()) == "xyZw"); +static assert(fun(y: AliasSeq!("y", "z", "w"), x: "x") == "xyzw"); + +// `new` expressions +class C +{ + int x, y; + + this(int x, int y) + { + this.x = x; + this.y = y; + } + + static C opCall(int x, int y) { return new C(x, y); } +} + +struct S +{ + int x, y; +} + +static assert(new C(y: 3, x: 2).x == 2); +static assert( C(y: 3, x: 2).x == 2); +static assert(new S(y: 3, x: 2).x == 2); +static assert( S(y: 3, x: 2).x == 2); + +// opCall +struct Div +{ + static int opCall(int numer, int denom) { return numer / denom; } +} +static assert(Div(denom: 3, numer: 6) == 2); + +struct Concat +{ + string s = "s"; + string opCall(string st0, string st1) { return s ~ st0 ~ st1; } +} + +static assert(Concat.init("t0", "t1") == "st0t1"); diff --git a/tests/dmd/compilable/previewhelp.d b/tests/dmd/compilable/previewhelp.d index f4753eeeb2a..f71a3dd72ec 100644 --- a/tests/dmd/compilable/previewhelp.d +++ b/tests/dmd/compilable/previewhelp.d @@ -5,7 +5,7 @@ TEST_OUTPUT: ---- Upcoming language changes listed by -preview=name: =all Enables all available upcoming language changes - =dip25 implement https://github.com/dlang/DIPs/blob/master/DIPs/archive/DIP25.md (Sealed references) + =dip25 implement https://github.com/dlang/DIPs/blob/master/DIPs/archive/DIP25.md (Sealed references) [DEPRECATED] =dip1000 implement https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1000.md (Scoped Pointers) =dip1008 implement https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1008.md (@nogc Throwable) =dip1021 implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md (Mutable function arguments) diff --git a/tests/dmd/compilable/reverthelp.d b/tests/dmd/compilable/reverthelp.d index 96ff760ba75..127baef5544 100644 --- a/tests/dmd/compilable/reverthelp.d +++ b/tests/dmd/compilable/reverthelp.d @@ -5,7 +5,7 @@ TEST_OUTPUT: ---- Revertable language changes listed by -revert=name: =all Enables all available revertable language changes - =dip25 revert DIP25 changes https://github.com/dlang/DIPs/blob/master/DIPs/archive/DIP25.md + =dip25 revert DIP25 changes https://github.com/dlang/DIPs/blob/master/DIPs/archive/DIP25.md [DEPRECATED] =dip1000 revert DIP1000 changes https://github.com/dlang/DIPs/blob/master/DIPs/other/DIP1000.md (Scoped Pointers) =intpromote revert integral promotions for unary + - ~ operators =dtorfields don't destruct fields of partially constructed objects diff --git a/tests/dmd/compilable/scope.d b/tests/dmd/compilable/scope.d index 95c784627fa..44f54f7468a 100644 --- a/tests/dmd/compilable/scope.d +++ b/tests/dmd/compilable/scope.d @@ -253,3 +253,12 @@ void main21209() testForeach(cs); testForeach(fs); } + +struct S23669 +{ + string[] a; + @safe void reserve() scope + { + a.length += 1; + } +} diff --git a/tests/dmd/compilable/shared.d b/tests/dmd/compilable/shared.d index 695083a5476..647910ecf16 100644 --- a/tests/dmd/compilable/shared.d +++ b/tests/dmd/compilable/shared.d @@ -11,34 +11,48 @@ ref shared(int) f(return shared ref int y) } // https://issues.dlang.org/show_bug.cgi?id=20908 +struct S +{ + int i = 2; +} + +union U +{ + int i = 1; + bool b; +} + void test20908() { - // shared locals (or struct members) should be able to be initialised: - shared int x; + // shared locals (or struct members) should be able to be initialised: + shared int x; - ref shared(int) fun() - { - static shared(int) val; + ref shared(int) fun() + { + static shared(int) val; - // return by reference - return val; - } + // return by reference + return val; + } - ref shared(int) fun2() - { - static shared(int)* val; + ref shared(int) fun2() + { + static shared(int)* val; - // transfer pointer to reference - return *val; - } + // transfer pointer to reference + return *val; + } - ref shared(int) fun3() - { - static shared(int)*** val; + ref shared(int) fun3() + { + static shared(int)*** val; + + // Multiple indirections + return ***val; + } - // Multiple indirections - return ***val; - } + shared S s; + shared U u; } // Simple tests for `DotVarExp` @@ -130,3 +144,15 @@ void main() { auto b = new shared Class(); } + +// https://issues.dlang.org/show_bug.cgi?id=23790 +bool cas(shared bool*, bool, bool) { return true; } + +struct Argh +{ + bool locked; + void lock() shared + { + while(!cas(&locked, false, true)) {} + } +} diff --git a/tests/dmd/compilable/stdcheaders.c b/tests/dmd/compilable/stdcheaders.c new file mode 100644 index 00000000000..5fef0eeff78 --- /dev/null +++ b/tests/dmd/compilable/stdcheaders.c @@ -0,0 +1,104 @@ +/* Do a smoke test of the C Standard headers. + * Many platforms do not support all the C Standard headers. + * DISABLED: LDC // FIXME: needs preprocessor + */ + +#include + +#ifndef __DMC__ // D:\a\1\s\tools\dm\include\complex.h(105): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead +#ifndef __FreeBSD__ // defines _COMPLEX_I with use of `i` postfix +#include +#endif +#endif + +#include +#include + +#ifndef _MSC_VER // C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt\fenv.h(68): Error: variable `stdcheaders._Fenv1` extern symbols cannot have initializers +#ifndef __FreeBSD__ // cannot turn off __GNUCLIKE_ASM in machine/ieeefp.h +#include +#endif +#endif + +#include +#include +#include +#include +#include + +#ifndef __APPLE__ // /Applications/Xcode-14.2.0.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/tgmath.h(39): Error: named parameter required before `...` +#include +#endif + +#ifndef _MSC_VER // setjmp.h(51): Error: missing tag `identifier` after `struct +#include +#endif + +#include + +#ifndef __DMC__ // no stdalign.h +#include +#endif + +#include + +#ifndef __DMC__ // no stdatomic.h +#ifndef __linux__ +#ifndef _MSC_VER +#ifndef __APPLE__ // /Applications/Xcode-14.2.0.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.0/include/stdatomic.h(80): Error: type-specifier is missing +#ifndef __FreeBSD__ // /stdatomic.h(162): Error: found `volatile` when expecting `{` +#include +#endif +#endif +#endif +#endif +#endif + +#include +#include +#include +#include + +#ifndef _MSC_VER // ucrt\corecrt_malloc.h(58): Error: extended-decl-modifier expected +#include +#endif + +#ifndef __DMC__ // no stdnoreturn.h +#include +#endif + +#include + +#ifndef __DMC__ // no tgmath.h +#ifndef _MSC_VER // C:\Program Files (x86)\Windows Kits\10\include\10.0.22621.0\ucrt\tgmath.h(33): Error: no type for declarator before `)` +#ifndef __APPLE__ // /Applications/Xcode-14.2.0.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/tgmath.h(39): Error: named parameter required before `...` +#ifndef __FreeBSD__ // #includes complex.h +#include +#endif +#endif +#endif +#endif + +#ifndef __DMC__ +#ifndef __linux__ +#ifndef __APPLE__ +#ifndef _MSC_VER +#include +#endif +#endif +#endif +#endif + +#include + +#ifndef __DMC__ // no uchar.h +#ifndef __APPLE__ // no uchar.h +#include +#endif +#endif + +#include + +#ifndef __DMC__ // wctype.h(102): Error: unterminated string constant starting at #defines(780) +#include +#endif diff --git a/tests/dmd/compilable/test16213.d b/tests/dmd/compilable/test16213.d new file mode 100644 index 00000000000..ccf77c6c948 --- /dev/null +++ b/tests/dmd/compilable/test16213.d @@ -0,0 +1,8 @@ +// https://issues.dlang.org/show_bug.cgi?id=16213 + +enum Id(size_t i) = i; +void main() +{ + int[5] y; + y[ Id!($) - 1 ] = 3; +} diff --git a/tests/dmd/compilable/test16495.d b/tests/dmd/compilable/test16495.d new file mode 100644 index 00000000000..70f11be49b8 --- /dev/null +++ b/tests/dmd/compilable/test16495.d @@ -0,0 +1,117 @@ +// https://issues.dlang.org/show_bug.cgi?id=16495 + +void types() +{ + static assert(__traits(fullyQualifiedName, string) == "string"); + static assert(__traits(fullyQualifiedName, wstring) == "wstring"); + static assert(__traits(fullyQualifiedName, dstring) == "dstring"); + static assert(__traits(fullyQualifiedName, typeof(null)) == "typeof(null)"); + static assert(__traits(fullyQualifiedName, void) == "void"); + static assert(__traits(fullyQualifiedName, const(void)) == "const(void)"); + static assert(__traits(fullyQualifiedName, shared(void)) == "shared(void)"); + static assert(__traits(fullyQualifiedName, shared const(void)) == "shared(const(void))"); + static assert(__traits(fullyQualifiedName, shared inout(void)) == "shared(inout(void))"); + static assert(__traits(fullyQualifiedName, shared inout const(void)) == "shared(inout(const(void)))"); + static assert(__traits(fullyQualifiedName, inout(void)) == "inout(void)"); + static assert(__traits(fullyQualifiedName, inout const(void)) == "inout(const(void))"); + static assert(__traits(fullyQualifiedName, immutable(void)) == "immutable(void)"); +} + +struct QualifiedNameTests +{ + struct Inner + { + bool value; + } + + ref const(Inner[string]) func( ref Inner var1, lazy scope string var2 ); + ref const(Inner[string]) retfunc( return ref Inner var1 ); + Inner inoutFunc(inout Inner) inout; + shared(const(Inner[string])[]) data; + const Inner delegate(double, string) @safe nothrow deleg; + inout(int) delegate(inout int) inout inoutDeleg; + Inner function(out double, string) funcPtr; + extern(C) Inner function(double, string) cFuncPtr; + + extern(C) void cVarArg(int, ...); + void dVarArg(...); + void dVarArg2(int, ...); + void typesafeVarArg(int[] ...); + + Inner[] array; + Inner[16] sarray; + Inner[Inner] aarray; + const(Inner[const(Inner)]) qualAarray; + + shared(immutable(Inner) delegate(ref double, scope string) const shared @trusted nothrow) attrDeleg; + + struct Data(T) { int x; } + void tfunc(T...)(T args) {} + + template Inst(alias A) { int x; } + + class Test12309(T, int x, string s) {} +} + +void symbols() +{ + alias qnTests = QualifiedNameTests; + enum prefix = "test16495.QualifiedNameTests."; + static assert(__traits(fullyQualifiedName, qnTests.Inner) == prefix ~ "Inner"); + static assert(__traits(fullyQualifiedName, qnTests.func) == prefix ~ "func"); + + static assert(__traits(fullyQualifiedName, qnTests.Data!int) == prefix ~ "Data!int.Data"); + static assert(__traits(fullyQualifiedName, qnTests.Data!int.x) == prefix ~ "Data!int.Data.x"); + static assert(__traits(fullyQualifiedName, qnTests.tfunc!(int[])) == prefix ~ "tfunc!(int[]).tfunc"); + static assert(__traits(fullyQualifiedName, qnTests.Inst!(Object)) == prefix ~ "Inst!(Object)"); + static assert(__traits(fullyQualifiedName, qnTests.Inst!(Object).x) == prefix ~ "Inst!(Object).x"); + static assert(__traits(fullyQualifiedName, qnTests.Test12309!(int, 10, "str")) + == prefix ~ "Test12309!(int, 10, \"str\").Test12309"); +} + +void names() +{ + enum prefix = "test16495.QualifiedNameTests"; + enum xx = prefix ~ ".Inner"; + with (QualifiedNameTests) + { + // Basic qualified name + static assert(__traits(fullyQualifiedName, Inner) == xx); + + // Array types + static assert(__traits(fullyQualifiedName, typeof(array)) == xx ~ "[]"); + static assert(__traits(fullyQualifiedName, typeof(sarray)) == xx ~ "[16]"); + static assert(__traits(fullyQualifiedName, typeof(aarray)) == xx ~ "[" ~ xx ~ "]"); + + // qualified key for AA + static assert(__traits(fullyQualifiedName, typeof(qualAarray)) == "const(" ~ xx ~ "[const(" ~ xx ~ ")])"); + + // Qualified composed data types + static assert(__traits(fullyQualifiedName, typeof(data)) == "shared(const(" ~ xx ~ "[string])[])"); + + // Function types + function attributes + static assert(__traits(fullyQualifiedName, typeof(func)) == "ref const(" ~ xx ~ "[string])(ref " ~ xx ~ ", lazy scope string)"); + static assert(__traits(fullyQualifiedName, typeof(retfunc)) == "ref const(" ~ xx ~ "[string])(return ref " ~ xx ~ ")"); + static assert(__traits(fullyQualifiedName, typeof(inoutFunc)) == "inout "~xx~"(inout("~xx~"))"); + static assert(__traits(fullyQualifiedName, typeof(deleg)) == "const(" ~ xx ~ " delegate(double, string) nothrow @safe)"); + static assert(__traits(fullyQualifiedName, typeof(inoutDeleg)) == "inout(int) delegate(inout(int)) inout"); + static assert(__traits(fullyQualifiedName, typeof(funcPtr)) == "" ~ xx ~ " function(out double, string)"); + static assert(__traits(fullyQualifiedName, typeof(cFuncPtr)) == "extern (C) " ~ xx ~ " function(double, string)"); + + // Delegate type with qualified function type + static assert(__traits(fullyQualifiedName, typeof(attrDeleg)) == "shared(immutable(" ~ xx ~ ") "~ + "delegate(ref double, scope string) shared const nothrow @trusted)"); + + // Variable argument function types + static assert(__traits(fullyQualifiedName, typeof(cVarArg)) == "extern (C) void(int, ...)"); + static assert(__traits(fullyQualifiedName, typeof(dVarArg)) == "void(...)"); + static assert(__traits(fullyQualifiedName, typeof(dVarArg2)) == "void(int, ...)"); + static assert(__traits(fullyQualifiedName, typeof(typesafeVarArg)) == "void(int[]...)"); + + // SIMD vector + static if (is(__vector(float[4]))) + { + static assert(__traits(fullyQualifiedName, __vector(float[4])) == "__vector(float[4])"); + } + } +} diff --git a/tests/dmd/compilable/test17351.d b/tests/dmd/compilable/test17351.d index fffe92c4d58..a04ade12476 100644 --- a/tests/dmd/compilable/test17351.d +++ b/tests/dmd/compilable/test17351.d @@ -1,3 +1,4 @@ +// PERMUTE_ARGS: -preview=in bool fun(S)(ref S[3] a) { assert(a == [42, 84, 169]); return true; } bool fun2(S)(ref S a) { return true; } void main() @@ -14,4 +15,12 @@ void test2() { static immutable int[2] P = [ 0, 1 ]; static assert(f2(P) == 1); + immutable BigInt a, b; + static assert(glob1.twice == b.twice); + static assert(a.twice == b.twice); } + +struct BigInt { int[64] big; } +BigInt twice (in BigInt v) @safe pure nothrow @nogc { return v; } + +immutable BigInt glob1 = BigInt.init; diff --git a/tests/dmd/compilable/test19295.d b/tests/dmd/compilable/test19295.d new file mode 100644 index 00000000000..a32a317c08e --- /dev/null +++ b/tests/dmd/compilable/test19295.d @@ -0,0 +1,10 @@ +struct S1(T...) { + auto fun() { + static assert(__traits(compiles, &T[0])); + } +} + +struct S2 { + void gun() {} + S1!gun overloaded; +} diff --git a/tests/dmd/compilable/test20201.d b/tests/dmd/compilable/test20201.d new file mode 100644 index 00000000000..b0419d6a345 --- /dev/null +++ b/tests/dmd/compilable/test20201.d @@ -0,0 +1,16 @@ +/* REQUIRED_ARGS: -betterC + */ + +// https://issues.dlang.org/show_bug.cgi?id=20101 + +public string ctfeHelper()(string a) +{ + return "int " ~ a ~ " = 42;"; +} + +extern(C) int main() +{ + int b = __traits(compiles, ctfeHelper("a")); + mixin(ctfeHelper("a")); + return !(a + b); +} diff --git a/tests/dmd/compilable/test21073.d b/tests/dmd/compilable/test21073.d deleted file mode 100644 index 47d788128b3..00000000000 --- a/tests/dmd/compilable/test21073.d +++ /dev/null @@ -1,16 +0,0 @@ -// https://issues.dlang.org/show_bug.cgi?id=21073 - -class C -{ - auto internal() const - { - return 5; - } - alias internal this; -} - -void main() pure -{ - const c = new C; - auto r = cast(C)c; -} diff --git a/tests/dmd/compilable/test21543.d b/tests/dmd/compilable/test21543.d deleted file mode 100644 index 4914264aaf9..00000000000 --- a/tests/dmd/compilable/test21543.d +++ /dev/null @@ -1,116 +0,0 @@ -// https://issues.dlang.org/show_bug.cgi?id=21543 - -class B -{ - Nullable!B data; - alias data this; -} - -void test1() -{ - B b; - Nullable!B n; -} - -struct Nullable(T) -{ - T payload; - - void opAssign()(T) - { - move(payload); - } - - inout(T) get_() inout - { - return payload; - } - - alias get_ this; -} - -// another version with chain of 3 alias this - -struct C -{ - Nullable2 data; - alias data this; -} - -void test2() -{ - C c; - Nullable2 n2 = &c; - Nullable3 n3 = &c; - - // these are to check a sane -vcg-ast output - fn1(c); - fn1(n2); - fn1(n3); - fn2(c); - fn2(n2); - fn2(n3); - fn3(c); - fn3(n2); - fn3(n3); -} - -void fn1(C x) {} - -void fn2(Nullable2 x) {} - -void fn3(Nullable3 x) {} - -struct Nullable2 -{ - Nullable3 payload; - - this(C* c) - { - payload = Nullable3(c); - } - - void opAssign()(Nullable3) - { - move(payload); - } - - inout(Nullable3) get_() inout - { - return payload; - } - - alias get_ this; -} - -struct Nullable3 -{ - C* payload; - - this(C* c) - { - payload = c; - } - - void opAssign()(C) - { - move(payload); - } - - inout(C) get_() inout - { - return *payload; - } - - alias get_ this; -} - -T move(T)(ref T source) -{ - return source; -} - -T move(T)(T source) -{ - return source; -} diff --git a/tests/dmd/compilable/test22674.d b/tests/dmd/compilable/test22674.d index c9076fae14d..00750b0108f 100644 --- a/tests/dmd/compilable/test22674.d +++ b/tests/dmd/compilable/test22674.d @@ -1,4 +1,5 @@ // https://issues.dlang.org/show_bug.cgi?id=22674 +// EXTRA_FILES: imports/cimports2a.i imports/cimports2b.i import imports.cimports2a; import imports.cimports2b; diff --git a/tests/dmd/compilable/test22739.d b/tests/dmd/compilable/test22739.d new file mode 100644 index 00000000000..6aeb5d60fd7 --- /dev/null +++ b/tests/dmd/compilable/test22739.d @@ -0,0 +1,10 @@ +// https://issues.dlang.org/show_bug.cgi?id=22739 + +extern(C++) auto f(T)() +{ + return T.init; +} +void main() +{ + f!int; +} diff --git a/tests/dmd/compilable/test22809.c b/tests/dmd/compilable/test22809.c index 1f41da0dad6..fcf3fbf4c4b 100644 --- a/tests/dmd/compilable/test22809.c +++ b/tests/dmd/compilable/test22809.c @@ -13,3 +13,19 @@ struct Foo { int y = ((size_t)((char *)&((struct Foo *)1)->x - (char *)1)); _Static_assert(((size_t)((char *)&((struct Foo *)0)->y - (char *)0))==4, ""); + + +/* LDC FIXME: needs preprocessor (for including importc.h) +// https://issues.dlang.org/show_bug.cgi?id=23584 + +int foo(float bar) +{ + return __builtin_bit_cast(unsigned int, bar); +} + +void test23584() +{ + int i = foo(3.5); + _Static_assert(foo(3.5) == 0x40600000, "1"); +} +*/ diff --git a/tests/dmd/compilable/test22916.d b/tests/dmd/compilable/test22916.d new file mode 100644 index 00000000000..9f779fd07da --- /dev/null +++ b/tests/dmd/compilable/test22916.d @@ -0,0 +1,42 @@ +// REQUIRED_ARGS: -preview=dip1000 + +// https://issues.dlang.org/show_bug.cgi?id=22916 +// Issue 22916 - [dip1000] copy of ref return still treated as scope variable (edit) + +@safe: +struct Arr +{ + int** ptr; + ref int* index() return scope { return *ptr; } + void assign(int* p) scope { *ptr = p; } +} + +void main0() +{ + scope Arr a; + a.assign(a.index()); +} + +// https://issues.dlang.org/show_bug.cgi?id=23682 +ref char* front_p(ref return scope char** p) { return *p; } +ref char* front_r( return scope char** p) { return *p; } + +char* g; + +void test23862() +{ + scope char** _errors; + g = front_p(_errors); // should pass + g = front_r(_errors); // should pass +} + +// Test case reduced from druntime +ref int* monitor(return scope Object h) pure nothrow @nogc @trusted +{ + return *cast(int**)&h.__monitor; +} + +int* getMonitor(Object h) pure @nogc +{ + return monitor(h); // should pass +} diff --git a/tests/dmd/compilable/test23145.d b/tests/dmd/compilable/test23145.d new file mode 100644 index 00000000000..45235dc5284 --- /dev/null +++ b/tests/dmd/compilable/test23145.d @@ -0,0 +1,39 @@ +/* TEST_OUTPUT: +--- +compilable/test23145.d(117): Deprecation: `scope` allocation of `c` requires that constructor be annotated with `scope` +compilable/test23145.d(111): is the location of the constructor +compilable/test23145.d(124): Deprecation: `scope` allocation of `c` requires that constructor be annotated with `scope` +compilable/test23145.d(111): is the location of the constructor +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=23145 + +#line 100 + +class D +{ + C c; +} + +class C +{ + D d; + int x=3; + this(int i) scope @safe @nogc; + this(D d) @safe @nogc; +} + +C foo(D d)@nogc @safe +{ + scope e = new C(1); // ok + scope c = new C(d); // deprecation + return c.d.c; +} + +C bax(D d) @safe +{ + scope e = new C(1); // ok + scope c = new C(d); // deprecation + return c.d.c; +} diff --git a/tests/dmd/compilable/test23407.i b/tests/dmd/compilable/test23407.i new file mode 100644 index 00000000000..538c9588142 --- /dev/null +++ b/tests/dmd/compilable/test23407.i @@ -0,0 +1,22 @@ +// https://issues.dlang.org/show_bug.cgi?id=23407 + +struct Foo { int x; }; +_Static_assert(sizeof(struct Foo) == sizeof(int), ""); + +void one(void){ + struct Foo { + int y, z; + }; + struct Foo f = {0}; + _Static_assert(sizeof(struct Foo) == 2*sizeof(int), ""); +} + +void two(void){ + struct Foo { + int y, z; + } + f + ; + _Static_assert(sizeof(f) == 2*sizeof(int), ""); + _Static_assert(sizeof(struct Foo) == 2*sizeof(int), ""); // fails +} diff --git a/tests/dmd/compilable/test23431_minimal.d b/tests/dmd/compilable/test23431_minimal.d index e09dbb91b9e..49f1b45825a 100644 --- a/tests/dmd/compilable/test23431_minimal.d +++ b/tests/dmd/compilable/test23431_minimal.d @@ -19,6 +19,13 @@ class Exception : Throwable class Error { } +// Needed to lower `new Exception("ice")` to it. +T _d_newclassT(T)() +if (is(T == class)) +{ + return null; +} + void test23431() { int a; diff --git a/tests/dmd/compilable/test23433.d b/tests/dmd/compilable/test23433.d index 056f857aa52..956b0ed6c16 100644 --- a/tests/dmd/compilable/test23433.d +++ b/tests/dmd/compilable/test23433.d @@ -10,6 +10,13 @@ version (LDC) // more thorough checks class Throwable { } class Exception : Throwable { this(immutable(char)[]) { } } +// Needed to lower `new Exception("ice")` to it. +T _d_newclassT(T)() +if (is(T == class)) +{ + return null; +} + void test23433() { try diff --git a/tests/dmd/compilable/test23583.c b/tests/dmd/compilable/test23583.c new file mode 100644 index 00000000000..60ca47cab94 --- /dev/null +++ b/tests/dmd/compilable/test23583.c @@ -0,0 +1,22 @@ +// DISABLED: LDC // FIXME: needs preprocessor +// https://issues.dlang.org/show_bug.cgi?id=23580 +// https://issues.dlang.org/show_bug.cgi?id=23581 +// https://issues.dlang.org/show_bug.cgi?id=23582 +// https://issues.dlang.org/show_bug.cgi?id=23583 + +#include + +void foo() +{ + memmove(0, 0, 0); + memcpy(0, 0, 0); + memset(0, 0, 0); +#if __APPLE__ + stpcpy(0, 0); + stpncpy(0, 0, 0); +#endif + strcat(0, 0); + strcpy(0, 0); + strncat(0, 0, 0); + strncpy(0, 0, 0); +} diff --git a/tests/dmd/compilable/test23598.d b/tests/dmd/compilable/test23598.d new file mode 100644 index 00000000000..cdcb5a801d4 --- /dev/null +++ b/tests/dmd/compilable/test23598.d @@ -0,0 +1,87 @@ +// https://issues.dlang.org/show_bug.cgi?id=23598 + +alias AliasSeq(a...) = a; + +static if (1) +{ + +template sort(alias f, a...) +{ + static if (a.length > 0) + { + alias x = f!(a[0]); + alias sort = a; + } + else + alias sort = a; +} + +alias SortedItems = sort!(isDependencyOf, String); + +enum isDependencyOf(Item) = Item.DirectDependencies.length == 0; + +struct String +{ + alias DirectDependencies = AliasSeq!(); + + enum l = SortedItems.length; // (3) +} + +} + +/*****************************************************/ + +static if (1) +{ +enum x = 1; +enum y = 2; + +template f(T) +{ + alias b = int; + static if (x) + { + alias c = x; + } + else + { + alias c = y; + } + + static if (is(typeof(c))) + { + } + else + { + static assert(0); + } +} + +void g() +{ + int x = f!int.c; +} +} + +/*****************************************************/ + +template forward(args...) +{ + template fwd(alias arg) + { + alias fwd = arg; + } + + alias Result = AliasSeq!(); + static foreach (arg; args) + Result = AliasSeq!(Result, fwd!arg); + static if (Result.length == 1) + alias forward = Result[0]; + else + alias forward = Result; +} + +void func(int i, int j) +{ + func(forward!(i, j)); +} diff --git a/tests/dmd/compilable/test23606.d b/tests/dmd/compilable/test23606.d new file mode 100644 index 00000000000..4d8ab2472ba --- /dev/null +++ b/tests/dmd/compilable/test23606.d @@ -0,0 +1,12 @@ +/* REQUIRED_ARGS: -betterC + */ + +// https://issues.dlang.org/show_bug.cgi?id=23606 + +string foo()() +{ + string a, b; + return a ~ b; +} + +enum s = foo(); diff --git a/tests/dmd/compilable/test23616.c b/tests/dmd/compilable/test23616.c new file mode 100644 index 00000000000..019cea90afc --- /dev/null +++ b/tests/dmd/compilable/test23616.c @@ -0,0 +1,9 @@ +// DISABLED: LDC // FIXME: needs preprocessor +// https://issues.dlang.org/show_bug.cgi?id=23616 + +#if __has_extension(gnu_asm) +void _hreset(int __eax) +{ + __asm__ ("hreset $0" :: "a"(__eax)); +} +#endif diff --git a/tests/dmd/compilable/test23617.d b/tests/dmd/compilable/test23617.d new file mode 100644 index 00000000000..2d03ee7fae9 --- /dev/null +++ b/tests/dmd/compilable/test23617.d @@ -0,0 +1,23 @@ +// https://issues.dlang.org/show_bug.cgi?id=23617 + +struct S +{ + void foo() {} +} + +struct Wrapper +{ + size_t currentIndex; + S[] arrayOfS; + + auto opDispatch(string name, T ...)(T t) + { + return __traits(child, arrayOfS[this.currentIndex], __traits(getMember, S, name))(t); + } +} + +void main() +{ + Wrapper w; + w.opDispatch!"foo"(); +} diff --git a/tests/dmd/compilable/test23622.c b/tests/dmd/compilable/test23622.c new file mode 100644 index 00000000000..009da1484ba --- /dev/null +++ b/tests/dmd/compilable/test23622.c @@ -0,0 +1,7 @@ +// https://issues.dlang.org/show_bug.cgi?id=23622 + +int FP_NAN = 0; +#define FP_NAN 0 + +enum E { ENUM = 0 }; +#define ENUM 0 diff --git a/tests/dmd/compilable/test23639.d b/tests/dmd/compilable/test23639.d new file mode 100644 index 00000000000..e2ec002c848 --- /dev/null +++ b/tests/dmd/compilable/test23639.d @@ -0,0 +1,12 @@ +// https://issues.dlang.org/show_bug.cgi?id=23639 + +// REQUIRED_ARGS: -preview=nosharedaccess + +class T {} + +shared(T) allocClassMem() +{ + void *p; + // assume p is allocated here + return cast(shared(T))p; +} diff --git a/tests/dmd/compilable/test23651.d b/tests/dmd/compilable/test23651.d new file mode 100644 index 00000000000..8c477b0c0b6 --- /dev/null +++ b/tests/dmd/compilable/test23651.d @@ -0,0 +1,34 @@ +// https://issues.dlang.org/show_bug.cgi?id=23651 + +template isCallable(alias callable) +{ + static if (is(typeof(&callable!()))) + enum bool isCallable = isCallable!(typeof(&callable!())); + else + enum bool isCallable = true; +} + +string foo(); + +template FunctionTypeOf(alias func) +if (isCallable!func) +{ + alias FunctionTypeOf = typeof(foo); +} + +template ReturnType(alias func) +{ + static if (is(FunctionTypeOf!func R == return)) + alias ReturnType = R; +} + +template isAttrRange() +{ + alias NameType = ReturnType!((string r) => r); + //pragma(msg, "isAttrRange ", NameType, " ", string); + static assert(is(NameType == string)); + + enum isAttrRange = is(NameType == string); +} + +static assert(isAttrRange!()); diff --git a/tests/dmd/compilable/test23676.d b/tests/dmd/compilable/test23676.d new file mode 100644 index 00000000000..91a73b9de82 --- /dev/null +++ b/tests/dmd/compilable/test23676.d @@ -0,0 +1,16 @@ +// Issue 23676 - Static foreach hangs compilation for some time +// https://issues.dlang.org/show_bug.cgi?id=23676 + +void f() +{ + int i; + void g(int I)() + { + static foreach(j; 0..11) + { + i++; + g!j(); + } + } + g!0; +} diff --git a/tests/dmd/compilable/test23799.d b/tests/dmd/compilable/test23799.d new file mode 100644 index 00000000000..007351602a3 --- /dev/null +++ b/tests/dmd/compilable/test23799.d @@ -0,0 +1,37 @@ +// https://issues.dlang.org/show_bug.cgi?id=23799 + +// REQUIRED_ARGS: -betterC + +struct Data +{ + Data[] range; + string test; +} + +Data[] foo() +{ + Data[] ret; + if (__ctfe) + { + Data tmp; + tmp.range ~= Data.init; + ret ~= tmp; + } + return ret; +} + +void func(Data dat)() +{ +} + +void bar(Data dat)() +{ + if (dat.test.length) + func!(dat.range[0])(); +} + +extern (C) void main() +{ + static immutable data = foo(); + bar!(data[0])(); +} diff --git a/tests/dmd/compilable/test5973.d b/tests/dmd/compilable/test5973.d deleted file mode 100644 index a54b0ae173a..00000000000 --- a/tests/dmd/compilable/test5973.d +++ /dev/null @@ -1,41 +0,0 @@ -// https://issues.dlang.org/show_bug.cgi?id=5973 - -class A { int a = 1; } -class B { int b = 2; } -class C : A -{ - B obj; - alias obj this; - this(){ obj = new B(); } -} -class X : C {} - -class D -{ - int i; -} - -class E -{ - D x; - alias x this; -} - -class F : E -{ - void test() - { - i = 5; - } -} - -void main() -{ - auto c = new C(); - assert(c.a == 1); // lookup C -> A, OK - assert(c.b == 2); // lookup C => B, OK - - auto x = new X(); - assert(x.a == 1); // lookup X -> C -> A, OK - assert(x.b == 2); // lookup X -> C => B, NG (Line 17) -} diff --git a/tests/dmd/compilable/test6777.d b/tests/dmd/compilable/test6777.d deleted file mode 100644 index 161a94a179d..00000000000 --- a/tests/dmd/compilable/test6777.d +++ /dev/null @@ -1,11 +0,0 @@ -struct S {} - -class C { - S s; - alias s this; -} - -void main() { - auto c = new C; - auto p = cast(void*) c; -} diff --git a/tests/dmd/compilable/testcorrectthis.d b/tests/dmd/compilable/testcorrectthis.d new file mode 100644 index 00000000000..3adc0628236 --- /dev/null +++ b/tests/dmd/compilable/testcorrectthis.d @@ -0,0 +1,37 @@ +// https://issues.dlang.org/show_bug.cgi?id=10886 + +struct A +{ + @property int foo() { return 0; } + int bar() { return 0; } +} + +struct B +{ + void bar() + { + alias f = typeof(A.foo); // NG + alias b = typeof(A.bar); // ok + } +} + +// https://issues.dlang.org/show_bug.cgi?id=21288 + +struct XA +{ + int p; +} + +struct XB +{ + XA a() { return XA.init; } + alias a this; +} + +struct XC +{ + void foo() + { + static assert(XB.p.stringof == "p"); // Error: this for s needs to be type B not type C + } +} diff --git a/tests/dmd/compilable/testcstuff1.c b/tests/dmd/compilable/testcstuff1.c index bd18f3ff2b5..2067e72b0c3 100644 --- a/tests/dmd/compilable/testcstuff1.c +++ b/tests/dmd/compilable/testcstuff1.c @@ -60,7 +60,7 @@ _Static_assert(sizeof(float) == 4, "ok"); _Static_assert(sizeof(double) == 8, "ok"); //_Static_assert(sizeof(long double) == 8 || sizeof(long double) == 10 || sizeof(long double) == 16, "ok"); -_Static_assert(sizeof(const restrict volatile char volatile restrict const) == 1, "ok"); +_Static_assert(sizeof(const volatile char volatile const) == 1, "ok"); _Static_assert(sizeof(int*) == 8 || 4 == sizeof(char*), "ok"); @@ -259,7 +259,7 @@ void test2() int; int (*xi); int (*fp)(void); - int (* const volatile restrict fp2)(void); + int (* const volatile fp2)(void); void* pv; char c, d; short sh; @@ -277,7 +277,7 @@ void test2() register int reg; const int ci; volatile int vi; - restrict int ri; + int* restrict ri; // _Atomic(int) ai; // _Alignas(c) ac; diff --git a/tests/dmd/dshell/dll.d b/tests/dmd/dshell/dll.d index 713b052223c..f30e49a5394 100644 --- a/tests/dmd/dshell/dll.d +++ b/tests/dmd/dshell/dll.d @@ -11,8 +11,11 @@ int main() return DISABLED; version (DigitalMars) - version (OSX) // Shared libraries are not yet supported on OSX + { +// Disable DM Dlls for now, need to redesign it +// version (OSX) // Shared libraries are not yet supported on OSX return DISABLED; + } Vars.set(`SRC`, `$EXTRA_FILES/dll`); Vars.set(`EXE_NAME`, `$OUTPUT_BASE/testdll$EXE`); diff --git a/tests/dmd/fail_compilation/biterrors2.d b/tests/dmd/fail_compilation/biterrors2.d index c8390ba7dc3..77671eb853f 100644 --- a/tests/dmd/fail_compilation/biterrors2.d +++ b/tests/dmd/fail_compilation/biterrors2.d @@ -1,7 +1,7 @@ /* REQUIRED_ARGS: -preview=bitfields * TEST_OUTPUT: --- -fail_compilation/biterrors2.d(100): Error: variable `biterrors2.a` bit-field must be member of struct, union, or class +fail_compilation/biterrors2.d(100): Error: variable `biterrors2.a` - bit-field must be member of struct, union, or class fail_compilation/biterrors2.d(104): Error: bit-field `b` has zero width fail_compilation/biterrors2.d(105): Error: bit-field type `float` is not an integer type --- diff --git a/tests/dmd/fail_compilation/bug9631.d b/tests/dmd/fail_compilation/bug9631.d index f456454fe87..c980d76a73d 100644 --- a/tests/dmd/fail_compilation/bug9631.d +++ b/tests/dmd/fail_compilation/bug9631.d @@ -4,7 +4,7 @@ TEST_OUTPUT: fail_compilation/bug9631.d(20): Error: cannot implicitly convert expression `F()` of type `bug9631.T1!().F` to `bug9631.T2!().F` --- */ - +// DISABLED: win32 template T1() { struct F { } diff --git a/tests/dmd/fail_compilation/call_function_type.d b/tests/dmd/fail_compilation/call_function_type.d new file mode 100644 index 00000000000..da60092c849 --- /dev/null +++ b/tests/dmd/fail_compilation/call_function_type.d @@ -0,0 +1,20 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/call_function_type.d(18): Error: missing argument for parameter #1: `int` +fail_compilation/call_function_type.d(19): Error: cannot call `int(int)(3)` at compile time +--- +*/ + +// This is a rare case where `dmd.expressionsem.functionParameters` catches a missing argument error, +// which is usually caught earlier by `TypeFunction.callMatch`, and had no test coverage yet. +// This was found while implementing named arguments and reduced from `vibe.internal.meta.traits`. + +int f(int); + +void m() +{ + alias FT = typeof(f); + enum X0 = FT(); + enum X1 = FT(3); +} diff --git a/tests/dmd/fail_compilation/cerrors.d b/tests/dmd/fail_compilation/cerrors.d index 3d69d415e2b..db306c1f213 100644 --- a/tests/dmd/fail_compilation/cerrors.d +++ b/tests/dmd/fail_compilation/cerrors.d @@ -1,10 +1,12 @@ /* REQUIRED_ARGS: -wi TEST_OUTPUT: --- -fail_compilation/cerrors.d(11): Error: C preprocessor directive `#if` is not supported, use `version` or `static if` -fail_compilation/cerrors.d(11): Error: declaration expected, not `#` -fail_compilation/cerrors.d(15): Warning: C preprocessor directive `#endif` is not supported -fail_compilation/cerrors.d(15): Error: declaration expected, not `#` +fail_compilation/cerrors.d(13): Error: C preprocessor directive `#if` is not supported, use `version` or `static if` +fail_compilation/cerrors.d(13): Error: declaration expected, not `#` +fail_compilation/cerrors.d(17): Error: C preprocessor directive `#endif` is not supported +fail_compilation/cerrors.d(17): Error: declaration expected, not `#` +fail_compilation/cerrors.d(21): Error: token string requires valid D tokens, not `#if` +fail_compilation/cerrors.d(22): Deprecation: token string requires valid D tokens, not `#include` --- */ @@ -13,3 +15,9 @@ fail_compilation/cerrors.d(15): Error: declaration expected, not `#` void test(wchar_t u); #endif + +// https://issues.dlang.org/show_bug.cgi?id=23792 +enum s1 = q{ +#if 1 +#include +}; diff --git a/tests/dmd/fail_compilation/ctfeblock.d b/tests/dmd/fail_compilation/ctfeblock.d new file mode 100644 index 00000000000..2d8bf7a0fef --- /dev/null +++ b/tests/dmd/fail_compilation/ctfeblock.d @@ -0,0 +1,33 @@ +/* TEST_OUTPUT: +--- +fail_compilation/ctfeblock.d(112): Error: cannot `goto` into `if (__ctfe)` block +--- +*/ + +/*******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=18472 +// https://github.com/dlang/dmd/pull/14676 + +#line 100 + +struct T { } + +@nogc void test1() +{ + int a; + if (__ctfe) + { +L1: + new T(); + a = 3; + } + goto L1; +} + +@nogc void test2() +{ + if (__ctfe) + { + new T(); + } +} diff --git a/tests/dmd/fail_compilation/deprecate_getVirtualFunctions.d b/tests/dmd/fail_compilation/deprecate_getVirtualFunctions.d new file mode 100644 index 00000000000..137482f98ac --- /dev/null +++ b/tests/dmd/fail_compilation/deprecate_getVirtualFunctions.d @@ -0,0 +1,20 @@ +// REQUIRED_ARGS: -de + +/* +TEST_OUTPUT: +--- +fail_compilation/deprecate_getVirtualFunctions.d(18): Deprecation: `traits(isVirtualFunction)` is deprecated. Use `traits(isVirtualMethod)` instead +fail_compilation/deprecate_getVirtualFunctions.d(19): Deprecation: `traits(getVirtualFunctions)` is deprecated. Use `traits(getVirtualMethods)` instead +--- +*/ + +class A +{ + void fun() {} +} + +void main() +{ + auto a = __traits(isVirtualFunction, A.fun); + foreach(f; __traits(getVirtualFunctions, A, "fun")) {} +} diff --git a/tests/dmd/fail_compilation/diag10099.d b/tests/dmd/fail_compilation/diag10099.d index cf1b6459436..46109247fb6 100644 --- a/tests/dmd/fail_compilation/diag10099.d +++ b/tests/dmd/fail_compilation/diag10099.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/diag10099.d(15): Error: variable `diag10099.main.s` default construction is disabled for type `S` +fail_compilation/diag10099.d(15): Error: variable `diag10099.main.s` - default construction is disabled for type `S` --- */ diff --git a/tests/dmd/fail_compilation/diag11132.d b/tests/dmd/fail_compilation/diag11132.d index 64db64d1e97..0bdfe50ca74 100644 --- a/tests/dmd/fail_compilation/diag11132.d +++ b/tests/dmd/fail_compilation/diag11132.d @@ -1,7 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/diag11132.d(22): Error: overlapping initialization for field `a` and `b` +fail_compilation/diag11132.d(23): Error: overlapping initialization for field `a` and `b` +fail_compilation/diag11132.d(23): `struct` initializers that contain anonymous unions must initialize only the first member of a `union`. All subsequent non-overlapping fields are default initialized --- */ diff --git a/tests/dmd/fail_compilation/diag12312.d b/tests/dmd/fail_compilation/diag12312.d index e015cfea7ac..307c6be1d09 100644 --- a/tests/dmd/fail_compilation/diag12312.d +++ b/tests/dmd/fail_compilation/diag12312.d @@ -1,11 +1,16 @@ /* TEST_OUTPUT: --- -fail_compilation/diag12312.d(10): Error: variable `diag12312.main.arr` `void[16]` does not have a default initializer +fail_compilation/diag12312.d(10): Error: variable `diag12312.main.arr` of type `void[16]` does not have a default initializer +fail_compilation/diag12312.d(15): Error: variable `diag12312.bug1176.v` of type `void[1]` does not have a default initializer --- */ - void main() { void[16] arr; } + +void bug1176() +{ + void[1] v; +} diff --git a/tests/dmd/fail_compilation/diag3438.d b/tests/dmd/fail_compilation/diag3438.d index c4cbc721d86..0e4fb8b076f 100644 --- a/tests/dmd/fail_compilation/diag3438.d +++ b/tests/dmd/fail_compilation/diag3438.d @@ -7,7 +7,7 @@ fail_compilation/diag3438.d(20): Error: constructor `diag3438.F5.this` is marked fail_compilation/diag3438.d(20): Use `@disable this();` if you want to disable default initialization. fail_compilation/diag3438.d(21): Error: constructor `diag3438.F6.this` is marked `@disable`, so it cannot have default arguments for all parameters. fail_compilation/diag3438.d(21): Use `@disable this();` if you want to disable default initialization. -fail_compilation/diag3438.d(24): Error: default argument expected for `y` +fail_compilation/diag3438.d(22): Error: constructor `diag3438.F7.this` all parameters have default arguments, but structs cannot have default constructors. --- */ @@ -19,6 +19,4 @@ struct F3 { this(...) { } } // ok struct F4 { this(int[] x...) { } } // ok struct F5 { @disable this(int x = 1); } struct F6 { @disable this(int x = 1) { } } - -// Make sure the deprecation doesn't interfere w/ the check for default arguments -struct S { this(int x = 1, int y) { } } +struct F7 { this(int x = 1, int y = 2) { } } diff --git a/tests/dmd/fail_compilation/diag8101.d b/tests/dmd/fail_compilation/diag8101.d index 9644fdd2242..ddc74e28131 100644 --- a/tests/dmd/fail_compilation/diag8101.d +++ b/tests/dmd/fail_compilation/diag8101.d @@ -1,30 +1,32 @@ /* TEST_OUTPUT: --- -fail_compilation/diag8101.d(57): Error: function `diag8101.f_0(int)` is not callable using argument types `()` -fail_compilation/diag8101.d(57): too few arguments, expected 1, got 0 -fail_compilation/diag8101.d(58): Error: none of the overloads of `f_1` are callable using argument types `()` -fail_compilation/diag8101.d(33): Candidates are: `diag8101.f_1(int)` -fail_compilation/diag8101.d(34): `diag8101.f_1(int, int)` -fail_compilation/diag8101.d(59): Error: none of the overloads of `f_2` are callable using argument types `()` -fail_compilation/diag8101.d(36): Candidates are: `diag8101.f_2(int)` -fail_compilation/diag8101.d(37): `diag8101.f_2(int, int)` -fail_compilation/diag8101.d(38): `diag8101.f_2(int, int, int)` -fail_compilation/diag8101.d(39): `diag8101.f_2(int, int, int, int)` -fail_compilation/diag8101.d(40): `diag8101.f_2(int, int, int, int, int)` -fail_compilation/diag8101.d(59): ... (1 more, -v to show) ... -fail_compilation/diag8101.d(61): Error: none of the overloads of template `diag8101.t_0` are callable using argument types `!()()` -fail_compilation/diag8101.d(43): Candidate is: `t_0(T1)()` -fail_compilation/diag8101.d(62): Error: none of the overloads of template `diag8101.t_1` are callable using argument types `!()()` -fail_compilation/diag8101.d(45): Candidates are: `t_1(T1)()` -fail_compilation/diag8101.d(46): `t_1(T1, T2)()` -fail_compilation/diag8101.d(63): Error: none of the overloads of template `diag8101.t_2` are callable using argument types `!()()` -fail_compilation/diag8101.d(48): Candidates are: `t_2(T1)()` -fail_compilation/diag8101.d(49): `t_2(T1, T2)()` -fail_compilation/diag8101.d(50): `t_2(T1, T2, T3)()` -fail_compilation/diag8101.d(51): `t_2(T1, T2, T3, T4)()` -fail_compilation/diag8101.d(52): `t_2(T1, T2, T3, T4, T5)()` +fail_compilation/diag8101.d(61): Error: function `diag8101.f_0(int)` is not callable using argument types `()` +fail_compilation/diag8101.d(61): too few arguments, expected 1, got 0 +fail_compilation/diag8101.d(62): Error: none of the overloads of `f_1` are callable using argument types `()` +fail_compilation/diag8101.d(35): Candidates are: `diag8101.f_1(int)` +fail_compilation/diag8101.d(36): `diag8101.f_1(int, int)` +fail_compilation/diag8101.d(63): Error: none of the overloads of `f_2` are callable using argument types `()` +fail_compilation/diag8101.d(38): Candidates are: `diag8101.f_2(int)` +fail_compilation/diag8101.d(39): `diag8101.f_2(int, int)` +fail_compilation/diag8101.d(40): `diag8101.f_2(int, int, int)` +fail_compilation/diag8101.d(41): `diag8101.f_2(int, int, int, int)` +fail_compilation/diag8101.d(42): `diag8101.f_2(int, int, int, int, int)` +fail_compilation/diag8101.d(43): `diag8101.f_2(int, int, int, int, int, int)` fail_compilation/diag8101.d(63): ... (1 more, -v to show) ... +fail_compilation/diag8101.d(65): Error: none of the overloads of template `diag8101.t_0` are callable using argument types `!()()` +fail_compilation/diag8101.d(46): Candidate is: `t_0(T1)()` +fail_compilation/diag8101.d(66): Error: none of the overloads of template `diag8101.t_1` are callable using argument types `!()()` +fail_compilation/diag8101.d(48): Candidates are: `t_1(T1)()` +fail_compilation/diag8101.d(49): `t_1(T1, T2)()` +fail_compilation/diag8101.d(67): Error: none of the overloads of template `diag8101.t_2` are callable using argument types `!()()` +fail_compilation/diag8101.d(51): Candidates are: `t_2(T1)()` +fail_compilation/diag8101.d(52): `t_2(T1, T2)()` +fail_compilation/diag8101.d(53): `t_2(T1, T2, T3)()` +fail_compilation/diag8101.d(54): `t_2(T1, T2, T3, T4)()` +fail_compilation/diag8101.d(55): `t_2(T1, T2, T3, T4, T5)()` +fail_compilation/diag8101.d(56): `t_2(T1, T2, T3, T4, T5, T6)()` +fail_compilation/diag8101.d(67): ... (1 more, -v to show) ... --- */ @@ -39,6 +41,7 @@ void f_2(int, int, int); void f_2(int, int, int, int); void f_2(int, int, int, int, int); void f_2(int, int, int, int, int, int); +void f_2(int, int, int, int, int, int, int); void t_0(T1)(); @@ -51,6 +54,7 @@ void t_2(T1, T2, T3)(); void t_2(T1, T2, T3, T4)(); void t_2(T1, T2, T3, T4, T5)(); void t_2(T1, T2, T3, T4, T5, T6)(); +void t_2(T1, T2, T3, T4, T5, T6, T7)(); void main() { diff --git a/tests/dmd/fail_compilation/diag9358.d b/tests/dmd/fail_compilation/diag9358.d index 5aea6b5f9c1..58dd495ab8e 100644 --- a/tests/dmd/fail_compilation/diag9358.d +++ b/tests/dmd/fail_compilation/diag9358.d @@ -1,9 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/diag9358.d(12): Error: `x` must be of integral or string type, it is a `double` -fail_compilation/diag9358.d(14): Error: `case` must be a `string` or an integral constant, not `1.1` -fail_compilation/diag9358.d(15): Error: `case` must be a `string` or an integral constant, not `2.1` +fail_compilation/diag9358.d(13): Error: `x` must be of integral or string type, it is a `double` +fail_compilation/diag9358.d(15): Error: `case` expression must be a compile-time `string` or an integral constant, not `1.1` +fail_compilation/diag9358.d(16): Error: `case` expression must be a compile-time `string` or an integral constant, not `2.1` +fail_compilation/diag9358.d(26): Error: `case` expression must be a compile-time `string` or an integral constant, not `z` --- */ void main() @@ -16,3 +17,13 @@ void main() default: } } + +void f(immutable string y) +{ + auto z = y[0..2]; + switch (y) + { + case z: break; + default: + } +} diff --git a/tests/dmd/fail_compilation/diag9679.d b/tests/dmd/fail_compilation/diag9679.d index 4496f0c8920..85923b7189e 100644 --- a/tests/dmd/fail_compilation/diag9679.d +++ b/tests/dmd/fail_compilation/diag9679.d @@ -1,8 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/diag9679.d(11): Error: variable `diag9679.main.n` only parameters or `foreach` declarations can be `ref` -fail_compilation/diag9679.d(12): Error: variable `diag9679.main.n` storage class `auto` has no effect if type is not inferred, did you mean `scope`? +fail_compilation/diag9679.d(11): Error: variable `diag9679.main.n` - only parameters, functions and `foreach` declarations can be `ref` +fail_compilation/diag9679.d(12): Error: variable `diag9679.main.n` - storage class `auto` has no effect if type is not inferred, did you mean `scope`? --- */ diff --git a/tests/dmd/fail_compilation/dip25.d b/tests/dmd/fail_compilation/dip25.d index 02f31407754..f43a6e9ef8d 100644 --- a/tests/dmd/fail_compilation/dip25.d +++ b/tests/dmd/fail_compilation/dip25.d @@ -1,11 +1,11 @@ /* -REQUIRED_ARGS: -de +REQUIRED_ARGS: TEST_OUTPUT: --- -fail_compilation/dip25.d(17): Deprecation: returning `this.buffer[]` escapes a reference to parameter `this` +fail_compilation/dip25.d(17): Error: returning `this.buffer[]` escapes a reference to parameter `this` fail_compilation/dip25.d(15): perhaps annotate the function with `return` fail_compilation/dip25.d(22): Error: returning `identity(x)` escapes a reference to parameter `x` -fail_compilation/dip25.d(23): Deprecation: returning `identity(x)` escapes a reference to parameter `x` +fail_compilation/dip25.d(23): Error: returning `identity(x)` escapes a reference to parameter `x` fail_compilation/dip25.d(23): perhaps annotate the parameter with `return` --- */ diff --git a/tests/dmd/fail_compilation/dip25flag.d b/tests/dmd/fail_compilation/dip25flag.d new file mode 100644 index 00000000000..d75ceace611 --- /dev/null +++ b/tests/dmd/fail_compilation/dip25flag.d @@ -0,0 +1,7 @@ +/* +REQUIRED_ARGS: -de -dip25 +TEST_OUTPUT: +--- +Deprecation: `-dip25` no longer has any effect +--- +*/ diff --git a/tests/dmd/fail_compilation/e15876_5.d b/tests/dmd/fail_compilation/e15876_5.d index 5b65b1b345a..96b23e278cd 100644 --- a/tests/dmd/fail_compilation/e15876_5.d +++ b/tests/dmd/fail_compilation/e15876_5.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/e15876_5.d(16): Error: basic type expected, not `End of File` -fail_compilation/e15876_5.d(16): Error: semicolon expected to close `alias` declaration +fail_compilation/e15876_5.d(16): Error: semicolon expected to close `alias` declaration, not `End of File` fail_compilation/e15876_5.d(16): Error: found `End of File` when expecting `}` following compound statement fail_compilation/e15876_5.d(16): Error: found `End of File` when expecting `]` fail_compilation/e15876_5.d(16): Error: no identifier for declarator `p[() diff --git a/tests/dmd/fail_compilation/enum9921.d b/tests/dmd/fail_compilation/enum9921.d index 90d8802d6d8..51c8b1a6653 100644 --- a/tests/dmd/fail_compilation/enum9921.d +++ b/tests/dmd/fail_compilation/enum9921.d @@ -3,9 +3,11 @@ TEST_OUTPUT: --- fail_compilation/enum9921.d(9): Error: enum `enum9921.X` base type must not be `void` fail_compilation/enum9921.d(11): Error: enum `enum9921.Z` base type must not be `void` +fail_compilation/enum9921.d(13): Error: variable `enum9921.x` - manifest constants must have initializers --- */ - enum X : void; enum Z : void { Y }; + +enum int x; diff --git a/tests/dmd/fail_compilation/enum_init.d b/tests/dmd/fail_compilation/enum_init.d index ab6ba308550..8344a4701c7 100644 --- a/tests/dmd/fail_compilation/enum_init.d +++ b/tests/dmd/fail_compilation/enum_init.d @@ -56,7 +56,7 @@ https://issues.dlang.org/show_bug.cgi?id=21785 TEST_OUTPUT: --- -fail_compilation/enum_init.d(306): Error: variable `enum_init.fooOB.ob` no definition of struct `S` +fail_compilation/enum_init.d(306): Error: variable `enum_init.fooOB.ob` - no definition of struct `S` fail_compilation/enum_init.d(302): required by type `OpaqueBase` --- */ diff --git a/tests/dmd/fail_compilation/fail10102.d b/tests/dmd/fail_compilation/fail10102.d index 4847413ffea..17577ec84f4 100644 --- a/tests/dmd/fail_compilation/fail10102.d +++ b/tests/dmd/fail_compilation/fail10102.d @@ -1,8 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail10102.d(48): Error: variable `fail10102.main.m` default construction is disabled for type `NotNull!(int*)` -fail_compilation/fail10102.d(49): Error: variable `fail10102.main.a` default construction is disabled for type `NotNull!(int*)[3]` +fail_compilation/fail10102.d(48): Error: variable `fail10102.main.m` - default construction is disabled for type `NotNull!(int*)` +fail_compilation/fail10102.d(49): Error: variable `fail10102.main.a` - default construction is disabled for type `NotNull!(int*)[3]` fail_compilation/fail10102.d(50): Error: default construction is disabled for type `NotNull!(int*)` fail_compilation/fail10102.d(51): Error: field `S.m` must be initialized because it has no default constructor --- diff --git a/tests/dmd/fail_compilation/fail14406.d b/tests/dmd/fail_compilation/fail14406.d index 3725a913c5b..f6c8fbb6804 100644 --- a/tests/dmd/fail_compilation/fail14406.d +++ b/tests/dmd/fail_compilation/fail14406.d @@ -1,8 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail14406.d-mixin-20(20): Error: variable `fail14406.CFrop.bar_obj` cannot be further field because it will change the determined CFrop size -fail_compilation/fail14406.d-mixin-25(25): Error: variable `fail14406.IFrop.bar_obj` field not allowed in interface +fail_compilation/fail14406.d-mixin-20(20): Error: cannot declare field `bar_obj` because it will change the determined size of `CFrop` +fail_compilation/fail14406.d-mixin-25(25): Error: field `bar_obj` not allowed in interface --- */ diff --git a/tests/dmd/fail_compilation/fail155.d b/tests/dmd/fail_compilation/fail155.d index 6d8f184c9ea..5f73f9a0ea5 100644 --- a/tests/dmd/fail_compilation/fail155.d +++ b/tests/dmd/fail_compilation/fail155.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail155.d(20): Error: overlapping initialization for `y` +fail_compilation/fail155.d(20): Error: overlapping initialization for field `x` and `y` fail_compilation/fail155.d(20): `struct` initializers that contain anonymous unions must initialize only the first member of a `union`. All subsequent non-overlapping fields are default initialized --- */ diff --git a/tests/dmd/fail_compilation/fail156.d b/tests/dmd/fail_compilation/fail156.d index bfc2383b590..ccb325415b2 100644 --- a/tests/dmd/fail_compilation/fail156.d +++ b/tests/dmd/fail_compilation/fail156.d @@ -2,9 +2,9 @@ /* TEST_OUTPUT: --- -fail_compilation/fail156.d(35): Error: overlapping initialization for `y` +fail_compilation/fail156.d(35): Error: overlapping initialization for field `x` and `y` fail_compilation/fail156.d(35): `struct` initializers that contain anonymous unions must initialize only the first member of a `union`. All subsequent non-overlapping fields are default initialized -fail_compilation/fail156.d(42): Error: overlapping initialization for `y` +fail_compilation/fail156.d(42): Error: overlapping initialization for field `x` and `y` fail_compilation/fail156.d(42): `struct` initializers that contain anonymous unions must initialize only the first member of a `union`. All subsequent non-overlapping fields are default initialized --- */ diff --git a/tests/dmd/fail_compilation/fail15616a.d b/tests/dmd/fail_compilation/fail15616a.d index e047365fbe3..042eee12299 100644 --- a/tests/dmd/fail_compilation/fail15616a.d +++ b/tests/dmd/fail_compilation/fail15616a.d @@ -7,10 +7,11 @@ fail_compilation/fail15616a.d(17): `fail15616a.foo(int a, fail_compilation/fail15616a.d(26): `fail15616a.foo(int a, int b, int c)` fail_compilation/fail15616a.d(29): `fail15616a.foo(string a)` fail_compilation/fail15616a.d(32): `fail15616a.foo(string a, string b)` -fail_compilation/fail15616a.d(41): ... (3 more, -v to show) ... +fail_compilation\fail15616a.d(35): `fail15616a.foo(string a, string b, string c)` +fail_compilation/fail15616a.d(41): ... (2 more, -v to show) ... --- */ - +#line 14 void foo(int a) {} diff --git a/tests/dmd/fail_compilation/fail15616c.d b/tests/dmd/fail_compilation/fail15616c.d new file mode 100644 index 00000000000..092590eff1a --- /dev/null +++ b/tests/dmd/fail_compilation/fail15616c.d @@ -0,0 +1,52 @@ +/* +REQUIRED_ARGS: -verror-supplements=0 +TEST_OUTPUT: +--- +fail_compilation/fail15616c.d(44): Error: none of the overloads of `foo` are callable using argument types `(double)` +fail_compilation/fail15616c.d(17): Candidates are: `fail15616c.foo(int a)` +fail_compilation/fail15616c.d(20): `fail15616c.foo(int a, int b)` +fail_compilation/fail15616c.d(29): `fail15616c.foo(int a, int b, int c)` +fail_compilation/fail15616c.d(32): `fail15616c.foo(string a)` +fail_compilation/fail15616c.d(35): `fail15616c.foo(string a, string b)` +fail_compilation/fail15616c.d(38): `fail15616c.foo(string a, string b, string c)` +fail_compilation/fail15616c.d(23): `foo(T)(T a)` + with `T = double` + must satisfy the following constraint: +` is(T == float)` +fail_compilation/fail15616c.d(26): `foo(T)(T a)` + with `T = double` + must satisfy the following constraint: +` is(T == char)` +--- +*/ + +#line 17 +void foo(int a) +{} + +void foo(int a, int b) +{} + +void foo(T)(T a) if (is(T == float)) +{} + +void foo(T)(T a) if (is(T == char)) +{} + +void foo(int a, int b, int c) +{} + +void foo(string a) +{} + +void foo(string a, string b) +{} + +void foo(string a, string b, string c) +{} + + +void main() +{ + foo(3.14); +} diff --git a/tests/dmd/fail_compilation/fail15616d.d b/tests/dmd/fail_compilation/fail15616d.d new file mode 100644 index 00000000000..a0f85a1df9c --- /dev/null +++ b/tests/dmd/fail_compilation/fail15616d.d @@ -0,0 +1,41 @@ +/* +REQUIRED_ARGS: -verror-supplements=2 +TEST_OUTPUT: +--- +fail_compilation/fail15616d.d(44): Error: none of the overloads of `foo` are callable using argument types `(double)` +fail_compilation/fail15616d.d(17): Candidates are: `fail15616d.foo(int a)` +fail_compilation/fail15616d.d(20): `fail15616d.foo(int a, int b)` +fail_compilation/fail15616d.d(44): ... (6 more, -v to show) ... +--- +*/ + +#line 17 +void foo(int a) +{} + +void foo(int a, int b) +{} + +void foo(T)(T a) if (is(T == float)) +{} + +void foo(T)(T a) if (is(T == char)) +{} + +void foo(int a, int b, int c) +{} + +void foo(string a) +{} + +void foo(string a, string b) +{} + +void foo(string a, string b, string c) +{} + + +void main() +{ + foo(3.14); +} diff --git a/tests/dmd/fail_compilation/fail158.d b/tests/dmd/fail_compilation/fail158.d index 6f09f658487..3253d167162 100644 --- a/tests/dmd/fail_compilation/fail158.d +++ b/tests/dmd/fail_compilation/fail158.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail158.d(17): Error: more initializers than fields (2) of `S` +fail_compilation/fail158.d(17): Error: too many initializers for `S` with 2 fields --- */ diff --git a/tests/dmd/fail_compilation/fail17646.d b/tests/dmd/fail_compilation/fail17646.d index 39e7cb9eb73..2074b472a1e 100644 --- a/tests/dmd/fail_compilation/fail17646.d +++ b/tests/dmd/fail_compilation/fail17646.d @@ -4,7 +4,7 @@ EXTRA_FILES: imports/fail17646.d TEST_OUTPUT: --- fail_compilation/imports/fail17646.d(10): Error: found `}` instead of statement -fail_compilation/fail17646.d(11): Error: function `fail17646.runTests!"".runTests` has no `return` statement, but is expected to return a value of type `int` +fail_compilation/fail17646.d(15): Error: template instance `allTestData!Modules` template `allTestData` is not defined fail_compilation/fail17646.d(18): Error: template instance `fail17646.runTests!""` error instantiating --- */ diff --git a/tests/dmd/fail_compilation/fail17955.d b/tests/dmd/fail_compilation/fail17955.d index f33149ea94d..95eb5cc8c1f 100644 --- a/tests/dmd/fail_compilation/fail17955.d +++ b/tests/dmd/fail_compilation/fail17955.d @@ -13,7 +13,7 @@ fail_compilation/fail17955.d(32): instantiated from here: `indicesOf!(isR fail_compilation/fail17955.d(67): instantiated from here: `RedisStripped!(User, true)` fail_compilation/fail17955.d(93): Error: need `this` for `fromISOExtString` of type `pure nothrow @nogc @safe immutable(SimpleTimeZone)(dstring _param_0)` fail_compilation/fail17955.d(95): Error: undefined identifier `DateTimeException` -fail_compilation/fail17955.d(25): Error: variable `fail17955.isISOExtStringSerializable!(SysTime).isISOExtStringSerializable` type `void` is inferred from initializer `fromISOExtString("")`, and variables cannot be of type `void` +fail_compilation/fail17955.d(25): Error: variable `fail17955.isISOExtStringSerializable!(SysTime).isISOExtStringSerializable` - type `void` is inferred from initializer `fromISOExtString("")`, and variables cannot be of type `void` fail_compilation/fail17955.d(54): Error: function `fail17955.toRedis!(SysTime).toRedis` has no `return` statement, but is expected to return a value of type `string` --- */ diff --git a/tests/dmd/fail_compilation/fail19076.d b/tests/dmd/fail_compilation/fail19076.d index 9bfc0a564eb..2441d6f3cae 100644 --- a/tests/dmd/fail_compilation/fail19076.d +++ b/tests/dmd/fail_compilation/fail19076.d @@ -8,4 +8,4 @@ fail_compilation/fail19076.d(11): Error: `(I).V` cannot be resolved interface P { } interface I : P { } -auto F = __traits(getVirtualFunctions, I, "V"); +auto F = __traits(getVirtualMethods, I, "V"); diff --git a/tests/dmd/fail_compilation/fail19948.d b/tests/dmd/fail_compilation/fail19948.d index 6122e418339..e8a9e777904 100644 --- a/tests/dmd/fail_compilation/fail19948.d +++ b/tests/dmd/fail_compilation/fail19948.d @@ -7,7 +7,7 @@ fail_compilation/fail19948.d(15): Error: function `fail19948.func(const(X))` is fail_compilation/fail19948.d(15): cannot pass argument `X()` of type `fail19948.main.X` to parameter `const(fail19948.X)` --- */ - +// DISABLED: win32 struct X {} void main() { diff --git a/tests/dmd/fail_compilation/fail21243.d b/tests/dmd/fail_compilation/fail21243.d index 25df235e9cb..2e170d096c5 100644 --- a/tests/dmd/fail_compilation/fail21243.d +++ b/tests/dmd/fail_compilation/fail21243.d @@ -8,7 +8,7 @@ fail_compilation/fail21243.d(17): Error: `auto` can only be used as part of `aut fail_compilation/fail21243.d(18): Error: basic type expected, not `(` fail_compilation/fail21243.d(18): Error: function declaration without return type. (Note that constructors are always named `this`) fail_compilation/fail21243.d(18): Deprecation: storage class `auto` has no effect in type aliases -fail_compilation/fail21243.d(18): Error: semicolon expected to close `alias` declaration +fail_compilation/fail21243.d(18): Error: semicolon expected to close `alias` declaration, not `=>` fail_compilation/fail21243.d(18): Error: declaration expected, not `=>` fail_compilation/fail21243.d(19): Error: `auto` can only be used as part of `auto ref` for function literal return values --- diff --git a/tests/dmd/fail_compilation/fail22039.d b/tests/dmd/fail_compilation/fail22039.d new file mode 100644 index 00000000000..3df834f7ad0 --- /dev/null +++ b/tests/dmd/fail_compilation/fail22039.d @@ -0,0 +1,14 @@ +// https://issues.dlang.org/show_bug.cgi?id=22039 + +/* +TEST_OUTPUT: +--- +fail_compilation/fail22039.d(11): Error: recursive evaluation of `func()` +fail_compilation/fail22039.d(14): Error: recursive evaluation of `gun(func2())` +--- +*/ + +int func(int x = func()) { return x; } + +int gun() { return 2; } +int func2(int x = gun(func2())) { return x; } diff --git a/tests/dmd/fail_compilation/fail22570.d b/tests/dmd/fail_compilation/fail22570.d index cb8c286650d..e937a480b45 100644 --- a/tests/dmd/fail_compilation/fail22570.d +++ b/tests/dmd/fail_compilation/fail22570.d @@ -3,8 +3,8 @@ /* TEST_OUTPUT: --- -fail_compilation/fail22570.d(19): Error: more initializers than fields (1) of `S` -fail_compilation/fail22570.d(20): Error: more initializers than fields (1) of `S` +fail_compilation/fail22570.d(19): Error: too many initializers for `S` with 1 field +fail_compilation/fail22570.d(20): Error: too many initializers for `S` with 1 field --- */ diff --git a/tests/dmd/fail_compilation/fail22857.d b/tests/dmd/fail_compilation/fail22857.d new file mode 100644 index 00000000000..061eb62d49e --- /dev/null +++ b/tests/dmd/fail_compilation/fail22857.d @@ -0,0 +1,18 @@ +// https://issues.dlang.org/show_bug.cgi?id=22857 +// EXTRA_FILES: imports/import22857.d + +/* +TEST_OUTPUT: +--- +fail_compilation/imports/import22857.d(4): Error: (expression) expected following `static if` +fail_compilation/imports/import22857.d(4): Error: declaration expected, not `}` +fail_compilation/fail22857.d(17): Error: template instance `unaryFun!()` template `unaryFun` is not defined +--- +*/ + +void isPrettyPropertyName() +{ + import imports.import22857; + + unaryFun!(); +} diff --git a/tests/dmd/fail_compilation/fail233.d b/tests/dmd/fail_compilation/fail233.d deleted file mode 100644 index 7d4d97892dd..00000000000 --- a/tests/dmd/fail_compilation/fail233.d +++ /dev/null @@ -1,12 +0,0 @@ -// REQUIRED_ARGS: -o- -/* -TEST_OUTPUT: ---- -fail_compilation/fail233.d(11): Error: variable `fail233.bug1176.v` `void[1]` does not have a default initializer ---- -*/ - -void bug1176() -{ - void[1] v; -} diff --git a/tests/dmd/fail_compilation/fail23760.d b/tests/dmd/fail_compilation/fail23760.d new file mode 100644 index 00000000000..fbca6ecd797 --- /dev/null +++ b/tests/dmd/fail_compilation/fail23760.d @@ -0,0 +1,27 @@ +// https://issues.dlang.org/show_bug.cgi?id=23760 + +/* +TEST_OUTPUT: +--- +fail_compilation/fail23760.d(16): Error: type of variable `fail23760.A.state` has errors +fail_compilation/fail23760.d(16): Error: `(A).state` cannot be resolved +fail_compilation/fail23760.d(21): Error: template instance `fail23760.JavaBridge!(A)` error instantiating +fail_compilation/fail23760.d(24): instantiated from here: `JavaClass!(A)` +--- +*/ + +class JavaBridge(Class) +{ + static if(is(typeof(__traits(getMember, Class, "state")))) {} + alias T = __traits(getOverloads, Class, "state"); +} + +class JavaClass(CRTP) +{ + JavaBridge!(CRTP) _javaDBridge; +} + +class A : JavaClass!A +{ + State* state; +} diff --git a/tests/dmd/fail_compilation/fail23816.d b/tests/dmd/fail_compilation/fail23816.d new file mode 100644 index 00000000000..b8536219381 --- /dev/null +++ b/tests/dmd/fail_compilation/fail23816.d @@ -0,0 +1,16 @@ +// https://issues.dlang.org/show_bug.cgi?id=23816 +// DISABLED: LDC_not_x86 +/* +TEST_OUTPUT: +--- +fail_compilation/fail23816.d(14): Error: unknown opcode `NOP` +--- +*/ + +void main() +{ + asm + { + NOP; + } +} diff --git a/tests/dmd/fail_compilation/fail253.d b/tests/dmd/fail_compilation/fail253.d index bee7e31eb3d..e6bfbedc7a3 100644 --- a/tests/dmd/fail_compilation/fail253.d +++ b/tests/dmd/fail_compilation/fail253.d @@ -1,11 +1,11 @@ /* TEST_OUTPUT: --- -fail_compilation/fail253.d(13): Error: variable `fail253.main.x` `inout` variables can only be declared inside `inout` functions +fail_compilation/fail253.d(13): Error: variable `fail253.main.x` - `inout` variables can only be declared inside `inout` functions fail_compilation/fail253.d(16): Error: cannot modify `inout` expression `x` +fail_compilation/fail253.d(19): Error: variable `fail253.main.err11` - `inout` variables can only be declared inside `inout` functions --- */ - void main() { foreach (i; 0 .. 2) @@ -16,4 +16,5 @@ void main() x = '?'; } } + inout(int)* err11; } diff --git a/tests/dmd/fail_compilation/fail299.d b/tests/dmd/fail_compilation/fail299.d index ffe50679282..832a9a8d193 100644 --- a/tests/dmd/fail_compilation/fail299.d +++ b/tests/dmd/fail_compilation/fail299.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail299.d(14): Error: more initializers than fields (0) of `Foo` +fail_compilation/fail299.d(14): Error: initializer provided for struct `Foo` with no fields --- */ diff --git a/tests/dmd/fail_compilation/fail308.d b/tests/dmd/fail_compilation/fail308.d index d885b3ef3ee..603fe51db7b 100644 --- a/tests/dmd/fail_compilation/fail308.d +++ b/tests/dmd/fail_compilation/fail308.d @@ -16,6 +16,6 @@ class MinHeap(NodeType) unittest { struct TestType {} - MinHeap!(TestType) foo = new MinHeap!(TestType)(); + MinHeap!(TestType) foo; } } diff --git a/tests/dmd/fail_compilation/fail346.d b/tests/dmd/fail_compilation/fail346.d index 77042cc111b..5b51f54498f 100644 --- a/tests/dmd/fail_compilation/fail346.d +++ b/tests/dmd/fail_compilation/fail346.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/fail346.d(15): Error: undefined identifier `P` -fail_compilation/fail346.d(15): Error: variable `fail346.S.T!0.T` cannot use template to add field to aggregate `S` +fail_compilation/fail346.d(15): Error: variable `fail346.S.T!0.T` - cannot use template to add field to aggregate `S` fail_compilation/fail346.d(20): Error: template instance `fail346.S.T!0` error instantiating fail_compilation/fail346.d(23): instantiated from here: `V!(S, 0)` --- diff --git a/tests/dmd/fail_compilation/fail4269a.d b/tests/dmd/fail_compilation/fail4269a.d index be59e1f72b0..1ce98065882 100644 --- a/tests/dmd/fail_compilation/fail4269a.d +++ b/tests/dmd/fail_compilation/fail4269a.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/fail4269a.d(12): Error: undefined identifier `B` -fail_compilation/fail4269a.d(12): Error: variable `fail4269a.A.blah` field not allowed in interface +fail_compilation/fail4269a.d(12): Error: field `blah` not allowed in interface fail_compilation/fail4269a.d(13): Error: undefined identifier `B` --- */ diff --git a/tests/dmd/fail_compilation/fail5851.d b/tests/dmd/fail_compilation/fail5851.d deleted file mode 100644 index 236a956de92..00000000000 --- a/tests/dmd/fail_compilation/fail5851.d +++ /dev/null @@ -1,16 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/fail5851.d(11): Error: alias this is not reachable as `Foo` already converts to `object.Object` ---- -*/ - -class Foo -{ - Object o; - alias o this; -} - -void main() -{ -} diff --git a/tests/dmd/fail_compilation/fail61.d b/tests/dmd/fail_compilation/fail61.d index 90c3b39977d..1386bd664a3 100644 --- a/tests/dmd/fail_compilation/fail61.d +++ b/tests/dmd/fail_compilation/fail61.d @@ -4,7 +4,7 @@ TEST_OUTPUT: fail_compilation/fail61.d(22): Error: no property `B` for type `fail61.A.B` fail_compilation/fail61.d(23): Error: no property `B` for type `fail61.A.B` fail_compilation/fail61.d(32): Error: no property `A2` for type `fail61.B2` -fail_compilation/fail61.d(41): Error: `this` for `foo` needs to be type `B3` not type `fail61.C3` +fail_compilation/fail61.d(41): Error: need `this` for `foo` of type `void()` --- */ diff --git a/tests/dmd/fail_compilation/fail_circular.d b/tests/dmd/fail_compilation/fail_circular.d index 186444e459a..e67fabce91d 100644 --- a/tests/dmd/fail_compilation/fail_circular.d +++ b/tests/dmd/fail_compilation/fail_circular.d @@ -110,12 +110,15 @@ struct S6 /* TEST_OUTPUT: --- -fail_compilation/fail_circular.d(123): Error: circular reference to variable `fail_circular.C.a1` -fail_compilation/fail_circular.d(125): Error: circular reference to variable `fail_circular.C.b1` -fail_compilation/fail_circular.d(127): Error: circular reference to variable `fail_circular.C.c1` -fail_compilation/fail_circular.d(130): Error: circular reference to variable `fail_circular.C.a1a` -fail_compilation/fail_circular.d(133): Error: circular reference to variable `fail_circular.C.b1a` -fail_compilation/fail_circular.d(136): Error: circular reference to variable `fail_circular.C.c1a` +fail_compilation/fail_circular.d(126): Error: circular reference to variable `fail_circular.C.a1` +fail_compilation/fail_circular.d(128): Error: circular reference to variable `fail_circular.C.b1` +fail_compilation/fail_circular.d(130): Error: circular reference to variable `fail_circular.C.c1` +fail_compilation/fail_circular.d(133): Error: circular reference to variable `fail_circular.C.a1a` +fail_compilation/fail_circular.d(132): Error: type of variable `fail_circular.C.a1b` has errors +fail_compilation/fail_circular.d(136): Error: circular reference to variable `fail_circular.C.b1a` +fail_compilation/fail_circular.d(135): Error: type of variable `fail_circular.C.b1b` has errors +fail_compilation/fail_circular.d(139): Error: circular reference to variable `fail_circular.C.c1a` +fail_compilation/fail_circular.d(138): Error: type of variable `fail_circular.C.c1b` has errors --- */ class C diff --git a/tests/dmd/fail_compilation/fail_scope.d b/tests/dmd/fail_compilation/fail_scope.d index 3fac1678e69..f2095921968 100644 --- a/tests/dmd/fail_compilation/fail_scope.d +++ b/tests/dmd/fail_compilation/fail_scope.d @@ -15,7 +15,7 @@ fail_compilation/fail_scope.d(69): `fail_scope.foo8(return ref int x)` fail_compilation/fail_scope.d(82): Error: returning `& string` escapes a reference to local variable `string` fail_compilation/fail_scope.d(92): Error: returning `cast(int[])a` escapes a reference to local variable `a` fail_compilation/fail_scope.d(100): Error: returning `cast(int[])a` escapes a reference to local variable `a` -fail_compilation/fail_scope.d(108): Deprecation: escaping reference to outer local variable `x` +fail_compilation/fail_scope.d(108): Error: escaping reference to outer local variable `x` fail_compilation/fail_scope.d(127): Deprecation: returning `s.bar()` escapes a reference to local variable `s` fail_compilation/fail_scope.d(137): Error: returning `foo16226(i)` escapes a reference to local variable `i` --- diff --git a/tests/dmd/fail_compilation/failcstuff4.c b/tests/dmd/fail_compilation/failcstuff4.c index 664680ebdbb..41f9ab5556b 100644 --- a/tests/dmd/fail_compilation/failcstuff4.c +++ b/tests/dmd/fail_compilation/failcstuff4.c @@ -2,7 +2,7 @@ /* TEST_OUTPUT: --- fail_compilation/failcstuff4.c(100): Error: can only `*` a pointer, not a `int` -fail_compilation/failcstuff4.c(157): Error: variable `failcstuff4.T22106.f1` no definition of struct `S22106_t` +fail_compilation/failcstuff4.c(157): Error: variable `failcstuff4.T22106.f1` - no definition of struct `S22106_t` --- */ diff --git a/tests/dmd/fail_compilation/failinout2.d b/tests/dmd/fail_compilation/failinout2.d index e1553636ab7..6fe86434e29 100644 --- a/tests/dmd/fail_compilation/failinout2.d +++ b/tests/dmd/fail_compilation/failinout2.d @@ -1,7 +1,13 @@ /* TEST_OUTPUT: --- -fail_compilation/failinout2.d(7): Error: variable `failinout2.x` only parameters or stack based variables can be `inout` +fail_compilation/failinout2.d(8): Error: variable `failinout2.x` - only parameters or stack-based variables can be `inout` +fail_compilation/failinout2.d(12): Error: variable `failinout2.S3748.err8` - only parameters or stack-based variables can be `inout` --- */ inout int x; + +struct S3748 +{ + inout(int) err8; +} diff --git a/tests/dmd/fail_compilation/failinout3748a.d b/tests/dmd/fail_compilation/failinout3748a.d deleted file mode 100644 index 77edb7e523d..00000000000 --- a/tests/dmd/fail_compilation/failinout3748a.d +++ /dev/null @@ -1,10 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/failinout3748a.d(9): Error: variable `failinout3748a.S3748.err8` only parameters or stack based variables can be `inout` ---- -*/ -struct S3748 -{ - inout(int) err8; -} diff --git a/tests/dmd/fail_compilation/failinout3748b.d b/tests/dmd/fail_compilation/failinout3748b.d deleted file mode 100644 index b6dddd879ca..00000000000 --- a/tests/dmd/fail_compilation/failinout3748b.d +++ /dev/null @@ -1,10 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/failinout3748b.d(9): Error: variable `failinout3748b.main.err11` `inout` variables can only be declared inside `inout` functions ---- -*/ -void main() -{ - inout(int)* err11; -} diff --git a/tests/dmd/fail_compilation/failob1.d b/tests/dmd/fail_compilation/failob1.d index 7fe73d3d179..377125d569b 100644 --- a/tests/dmd/fail_compilation/failob1.d +++ b/tests/dmd/fail_compilation/failob1.d @@ -2,11 +2,11 @@ REQUIRED_ARGS:-preview=dip1021 TEST_OUTPUT: --- -fail_compilation/failob1.d(104): Error: variable `failob1.test1.a1` is left dangling at return -fail_compilation/failob1.d(105): Error: variable `failob1.test2.a2` is left dangling at return -fail_compilation/failob1.d(107): Error: variable `failob1.test4.s4` is left dangling at return -fail_compilation/failob1.d(108): Error: variable `failob1.test5.dg5` is left dangling at return -fail_compilation/failob1.d(115): Error: variable `failob1.test12.p12` is left dangling at return +fail_compilation/failob1.d(104): Error: variable `failob1.test1.a1` is not disposed of before return +fail_compilation/failob1.d(105): Error: variable `failob1.test2.a2` is not disposed of before return +fail_compilation/failob1.d(107): Error: variable `failob1.test4.s4` is not disposed of before return +fail_compilation/failob1.d(108): Error: variable `failob1.test5.dg5` is not disposed of before return +fail_compilation/failob1.d(115): Error: variable `failob1.test12.p12` is not disposed of before return --- */ diff --git a/tests/dmd/fail_compilation/failob2.d b/tests/dmd/fail_compilation/failob2.d index bd526485409..c8a4c4d93d4 100644 --- a/tests/dmd/fail_compilation/failob2.d +++ b/tests/dmd/fail_compilation/failob2.d @@ -48,7 +48,7 @@ void test1() { /* TEST_OUTPUT: --- -fail_compilation/failob2.d(205): Error: variable `failob2.foo4!int.foo4.p` is left dangling at return +fail_compilation/failob2.d(205): Error: variable `failob2.foo4!int.foo4.p` is not disposed of before return fail_compilation/failob2.d(209): Error: template instance `failob2.foo4!int` error instantiating --- */ diff --git a/tests/dmd/fail_compilation/fix22104.c b/tests/dmd/fail_compilation/fix22104.c index 845ec804ec4..e8079f54df2 100644 --- a/tests/dmd/fail_compilation/fix22104.c +++ b/tests/dmd/fail_compilation/fix22104.c @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fix22104.c(103): Error: variable `fix22104.test1.array1` incomplete array type must have initializer -fail_compilation/fix22104.c(108): Error: variable `fix22104.test2.array2` incomplete array type must have initializer +fail_compilation/fix22104.c(103): Error: variable `fix22104.test1.array1` - incomplete array type must have initializer +fail_compilation/fix22104.c(108): Error: variable `fix22104.test2.array2` - incomplete array type must have initializer --- */ diff --git a/tests/dmd/fail_compilation/fob1.d b/tests/dmd/fail_compilation/fob1.d index 9dfcc4da7df..d11a7a69916 100644 --- a/tests/dmd/fail_compilation/fob1.d +++ b/tests/dmd/fail_compilation/fob1.d @@ -18,7 +18,7 @@ fail_compilation/fob1.d(104): Error: variable `fob1.foo1.p` is returned but is U /* TEST_OUTPUT: --- fail_compilation/fob1.d(204): Error: variable `fob1.foo2.p` assigning to Owner without disposing of owned value -fail_compilation/fob1.d(203): Error: variable `fob1.foo2.p` is left dangling at return +fail_compilation/fob1.d(203): Error: variable `fob1.foo2.p` is not disposed of before return --- */ @@ -35,7 +35,7 @@ fail_compilation/fob1.d(203): Error: variable `fob1.foo2.p` is left dangling at --- fail_compilation/fob1.d(304): Error: variable `fob1.foo3.p` has undefined state and cannot be read fail_compilation/fob1.d(304): Error: variable `fob1.foo3.p` is returned but is Undefined -fail_compilation/fob1.d(303): Error: variable `fob1.foo3.q` is left dangling at return +fail_compilation/fob1.d(303): Error: variable `fob1.foo3.q` is not disposed of before return --- */ @@ -62,3 +62,20 @@ fail_compilation/fob1.d(405): Error: variable `fob1.foo4.bq` has undefined state *bq = 1; return p; } + +/* TEST_OUTPUT: +--- +fail_compilation/fob1.d(503): Error: more than one mutable reference to `a` in arguments to `fob1.foo5()` +--- +*/ + +// https://issues.dlang.org/show_bug.cgi?id=20781 + +#line 500 + +void test5() { + int a; + foo5(a, a); +} + +@live void foo5(ref int, ref int); diff --git a/tests/dmd/fail_compilation/fob2.d b/tests/dmd/fail_compilation/fob2.d index 6f100ee5124..e9179da7405 100644 --- a/tests/dmd/fail_compilation/fob2.d +++ b/tests/dmd/fail_compilation/fob2.d @@ -8,7 +8,7 @@ void free(int*); /* TEST_OUTPUT: --- fail_compilation/fob2.d(110): Error: variable `fob2.foo1.b1` has undefined state and cannot be read -fail_compilation/fob2.d(103): Error: variable `fob2.foo1.p` is left dangling at return +fail_compilation/fob2.d(103): Error: variable `fob2.foo1.p` is not disposed of before return --- */ @@ -28,11 +28,13 @@ fail_compilation/fob2.d(103): Error: variable `fob2.foo1.p` is left dangling at /* TEST_OUTPUT: --- -fail_compilation/fob2.d(203): Error: variable `fob2.zoo2.p` is passed as Owner more than once -fail_compilation/fob2.d(202): Error: variable `fob2.zoo2.p` is left dangling at return +fail_compilation/fob2.d(203): Error: more than one mutable reference of `p` in arguments to `fob2.foo2()` --- */ +//fail_compilation/fob2.d(203): Error: variable `fob2.zoo2.p` is passed as Owner more than once +//fail_compilation/fob2.d(202): Error: variable `fob2.zoo2.p` is left dangling at return + #line 200 @live void zoo2() { @@ -44,7 +46,7 @@ fail_compilation/fob2.d(202): Error: variable `fob2.zoo2.p` is left dangling at /* TEST_OUTPUT: --- -fail_compilation/fob2.d(303): Error: variable `fob2.foo3.b` is left dangling at return +fail_compilation/fob2.d(303): Error: variable `fob2.foo3.b` is not disposed of before return --- */ @@ -140,7 +142,8 @@ fail_compilation/fob2.d(515): Error: variable `fob2.test52.p` has undefined stat /* TEST_OUTPUT: --- -fail_compilation/fob2.d(603): Error: variable `fob2.test6.p` is left dangling at return +fail_compilation/fob2.d(603): Error: variable `fob2.test6.p` is not disposed of before return +fail_compilation/fob2.d(612): Error: more than one mutable reference of `p` in arguments to `fob2.foo6b()` --- */ diff --git a/tests/dmd/fail_compilation/gag4269f.d b/tests/dmd/fail_compilation/gag4269f.d index 84d39ebae50..b571059eb45 100644 --- a/tests/dmd/fail_compilation/gag4269f.d +++ b/tests/dmd/fail_compilation/gag4269f.d @@ -3,7 +3,7 @@ TEST_OUTPUT: --- fail_compilation/gag4269f.d(11): Error: undefined identifier `Y9`, did you mean interface `X9`? -fail_compilation/gag4269f.d(11): Error: variable `gag4269f.X9.y` field not allowed in interface +fail_compilation/gag4269f.d(11): Error: field `y` not allowed in interface --- */ diff --git a/tests/dmd/fail_compilation/ice12727.d b/tests/dmd/fail_compilation/ice12727.d index bf6af7b404f..13eb8e09ed8 100644 --- a/tests/dmd/fail_compilation/ice12727.d +++ b/tests/dmd/fail_compilation/ice12727.d @@ -1,13 +1,13 @@ /* TEST_OUTPUT: ---- +fail_compilation/ice12727.d(16): Error: template instance `IndexTuple!(1, 0)` recursive template expansion fail_compilation/ice12727.d(16): Error: alias `ice12727.IndexTuple!(1, 0).IndexTuple` recursive alias declaration fail_compilation/ice12727.d(23): Error: template instance `ice12727.IndexTuple!(1, 0)` error instantiating fail_compilation/ice12727.d(27): instantiated from here: `Matrix!(float, 3)` fail_compilation/ice12727.d(28): instantiated from here: `Vector!(float, 3)` ---- */ - template IndexTuple(int e, int s = 0, T...) { static if (s == e) diff --git a/tests/dmd/fail_compilation/ice12902.d b/tests/dmd/fail_compilation/ice12902.d index ac430120d49..03763f7c18a 100644 --- a/tests/dmd/fail_compilation/ice12902.d +++ b/tests/dmd/fail_compilation/ice12902.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice12902.d(20): Error: variable `ice12902.main.__dollar` type `void` is inferred from initializer `s.opDollar()`, and variables cannot be of type `void` +fail_compilation/ice12902.d(20): Error: variable `ice12902.main.__dollar` - type `void` is inferred from initializer `s.opDollar()`, and variables cannot be of type `void` fail_compilation/ice12902.d(20): Error: expression `s.opDollar()` is `void` and has no value --- */ diff --git a/tests/dmd/fail_compilation/ice13788.d b/tests/dmd/fail_compilation/ice13788.d index 99f3c4a6c35..3e3989bc290 100644 --- a/tests/dmd/fail_compilation/ice13788.d +++ b/tests/dmd/fail_compilation/ice13788.d @@ -1,10 +1,10 @@ /* TEST_OUTPUT: --- -fail_compilation/ice13788.d(11): Error: pragma `mangle` string expected for mangled name +fail_compilation/ice13788.d(11): Error: pragma `mangle` - string expected for mangled name fail_compilation/ice13788.d(12): Error: `string` expected for mangled name, not `(1)` of type `int` -fail_compilation/ice13788.d(13): Error: pragma `mangle` zero-length string not allowed for mangled name -fail_compilation/ice13788.d(14): Error: pragma `mangle` mangled name characters can only be of type `char` +fail_compilation/ice13788.d(13): Error: pragma `mangle` - zero-length string not allowed for mangled name +fail_compilation/ice13788.d(14): Error: pragma `mangle` - mangled name characters can only be of type `char` --- */ diff --git a/tests/dmd/fail_compilation/ice13816.d b/tests/dmd/fail_compilation/ice13816.d index e683e339e61..aefe273da0c 100644 --- a/tests/dmd/fail_compilation/ice13816.d +++ b/tests/dmd/fail_compilation/ice13816.d @@ -1,11 +1,13 @@ /* TEST_OUTPUT: --- -fail_compilation/ice13816.d(15): Error: alias `ice13816.ItemProperty!().ItemProperty` recursive alias declaration -fail_compilation/ice13816.d(20): Error: template instance `ice13816.ItemProperty!()` error instantiating +fail_compilation/ice13816.d(17): Error: template instance `TypeTuple!(ItemProperty!())` recursive template expansion +fail_compilation/ice13816.d(17): Error: alias `ice13816.ItemProperty!().ItemProperty` recursive alias declaration +fail_compilation/ice13816.d(22): Error: template instance `ice13816.ItemProperty!()` error instantiating --- */ + alias TypeTuple(T...) = T; template ItemProperty() diff --git a/tests/dmd/fail_compilation/ice18753.d b/tests/dmd/fail_compilation/ice18753.d index 253025cdc7a..f41ab3e754f 100644 --- a/tests/dmd/fail_compilation/ice18753.d +++ b/tests/dmd/fail_compilation/ice18753.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/ice18753.d(21): Error: variable `ice18753.isInputRange!(Group).isInputRange` type `void` is inferred from initializer `ReturnType(func...)`, and variables cannot be of type `void` +fail_compilation/ice18753.d(21): Error: variable `ice18753.isInputRange!(Group).isInputRange` - type `void` is inferred from initializer `ReturnType(func...)`, and variables cannot be of type `void` fail_compilation/ice18753.d(23): Error: template instance `ice18753.isInputRange!(Group)` error instantiating fail_compilation/ice18753.d(18): instantiated from here: `isForwardRange!(Group)` fail_compilation/ice18753.d(18): while evaluating: `static assert(isForwardRange!(Group))` diff --git a/tests/dmd/fail_compilation/ice19295.d b/tests/dmd/fail_compilation/ice19295.d deleted file mode 100644 index a92f5f8384c..00000000000 --- a/tests/dmd/fail_compilation/ice19295.d +++ /dev/null @@ -1,18 +0,0 @@ -/* -TEST_OUTPUT: ---- -fail_compilation/ice19295.d(11): Error: `this` for `gun` needs to be type `S2` not type `S1!(gun)` -fail_compilation/ice19295.d(11): while evaluating `pragma(msg, &gun)` -fail_compilation/ice19295.d(17): Error: template instance `ice19295.S1!(gun)` error instantiating ---- -*/ -struct S1(T...) { - auto fun() { - pragma(msg, &T[0]); - } -} - -struct S2 { - void gun() {} - S1!gun overloaded; -} diff --git a/tests/dmd/fail_compilation/ice23569.d b/tests/dmd/fail_compilation/ice23569.d index 277814f76cf..6fdb71a3976 100644 --- a/tests/dmd/fail_compilation/ice23569.d +++ b/tests/dmd/fail_compilation/ice23569.d @@ -2,11 +2,17 @@ /* TEST_OUTPUT: --- -fail_compilation/ice23569.d(18): Error: cannot compare classes for equality because `object.Object` was not declared +fail_compilation/ice23569.d(24): Error: cannot compare classes for equality because `object.Object` was not declared --- */ module object; +T _d_newclassT(T)() +if (is(T == class)) +{ + return null; +} + @safe unittest1() { class F diff --git a/tests/dmd/fail_compilation/ice23781.d b/tests/dmd/fail_compilation/ice23781.d new file mode 100644 index 00000000000..7adc11607db --- /dev/null +++ b/tests/dmd/fail_compilation/ice23781.d @@ -0,0 +1,10 @@ +/** +TEST_OUTPUT: +--- +fail_compilation/ice23781.d(10): Error: variable `b` cannot be read at compile time +--- +**/ +struct Bar { int i; } +ref const(Bar) func1 (const return ref Bar b) { return b; } +immutable E1 = Bar(); +enum E2 = &E1.func1(); diff --git a/tests/dmd/fail_compilation/ice9439.d b/tests/dmd/fail_compilation/ice9439.d index a9e70083802..5b2a8b12031 100644 --- a/tests/dmd/fail_compilation/ice9439.d +++ b/tests/dmd/fail_compilation/ice9439.d @@ -1,8 +1,8 @@ /* TEST_OUTPUT: --- -fail_compilation/ice9439.d(12): Error: `this` for `foo` needs to be type `Derived` not type `ice9439.Base` -fail_compilation/ice9439.d(12): while evaluating: `static assert((__error).foo())` +fail_compilation/ice9439.d(12): Error: need `this` for `foo` of type `int()` +fail_compilation/ice9439.d(12): while evaluating: `static assert(foo())` fail_compilation/ice9439.d(19): Error: template instance `ice9439.Base.boo!(foo)` error instantiating --- */ diff --git a/tests/dmd/fail_compilation/imports/import22857.d b/tests/dmd/fail_compilation/imports/import22857.d new file mode 100644 index 00000000000..280c2eb10ff --- /dev/null +++ b/tests/dmd/fail_compilation/imports/import22857.d @@ -0,0 +1,4 @@ +template unaryFun() +{ + static if +} diff --git a/tests/dmd/fail_compilation/issue16020.d b/tests/dmd/fail_compilation/issue16020.d index 75e3b9f0b81..fe4ad78f1ac 100644 --- a/tests/dmd/fail_compilation/issue16020.d +++ b/tests/dmd/fail_compilation/issue16020.d @@ -2,7 +2,7 @@ TEST_OUTPUT: --- fail_compilation/issue16020.d(12): Error: user-defined attributes not allowed for `alias` declarations -fail_compilation/issue16020.d(13): Error: semicolon expected to close `alias` declaration +fail_compilation/issue16020.d(13): Error: semicolon expected to close `alias` declaration, not `(` fail_compilation/issue16020.d(13): Error: declaration expected, not `(` --- */ diff --git a/tests/dmd/fail_compilation/named_arguments_error.d b/tests/dmd/fail_compilation/named_arguments_error.d new file mode 100644 index 00000000000..0900e6010d1 --- /dev/null +++ b/tests/dmd/fail_compilation/named_arguments_error.d @@ -0,0 +1,48 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/named_arguments_error.d(32): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(32): parameter `x` assigned twice +fail_compilation/named_arguments_error.d(33): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(33): argument `4` goes past end of parameter list +fail_compilation/named_arguments_error.d(34): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(34): parameter `y` assigned twice +fail_compilation/named_arguments_error.d(35): Error: function `named_arguments_error.f(int x, int y, int z)` is not callable using argument types `(int, int, int)` +fail_compilation/named_arguments_error.d(35): no parameter named `a` +fail_compilation/named_arguments_error.d(36): Error: function `named_arguments_error.g(int x, int y, int z = 3)` is not callable using argument types `(int, int)` +fail_compilation/named_arguments_error.d(36): missing argument for parameter #1: `int x` +fail_compilation/named_arguments_error.d(38): Error: no named argument `element` allowed for array dimension +fail_compilation/named_arguments_error.d(39): Error: no named argument `number` allowed for scalar +fail_compilation/named_arguments_error.d(40): Error: cannot implicitly convert expression `g(x: 3, y: 4, z: 5)` of type `int` to `string` +fail_compilation/named_arguments_error.d(41): Error: named arguments with Implicit Function Template Instantiation are not supported yet +fail_compilation/named_arguments_error.d(41): Error: none of the overloads of template `named_arguments_error.tempfun` are callable using argument types `!()(string, int)` +fail_compilation/named_arguments_error.d(45): Candidate is: `tempfun(T, U)(T t, U u)` +--- +*/ + + + + +void f(int x, int y, int z); + +int g(int x, int y, int z = 3); + +void main() +{ + f(x: 3, x: 3, 5); + f(z: 3, 4, 5); + f(y: 3, x: 4, 5); + f(a: 3, b: 4, 5); + g(y: 4, z: 3); + + auto g0 = new int[](element: 3); + auto g1 = new int(number: 3); + string s = g(x: 3, y: 4, z: 5); + enum x = tempfun(u: "u", t: 0); +} + +// template arguments +int tempfun(T, U)(T t, U u) +{ + return 3; +} diff --git a/tests/dmd/fail_compilation/named_arguments_overload.d b/tests/dmd/fail_compilation/named_arguments_overload.d new file mode 100644 index 00000000000..a9704464605 --- /dev/null +++ b/tests/dmd/fail_compilation/named_arguments_overload.d @@ -0,0 +1,35 @@ +/** +TEST_OUTPUT: +--- +fail_compilation/named_arguments_overload.d(33): Error: none of the overloads of `snoopy` are callable using argument types `(immutable(S), immutable(T))` +fail_compilation/named_arguments_overload.d(17): Candidates are: `named_arguments_overload.snoopy(S s, int i = 0, T t = T())` +fail_compilation/named_arguments_overload.d(18): `named_arguments_overload.snoopy(T t, int i, S s)` +fail_compilation/named_arguments_overload.d(34): Error: none of the overloads of `snoopy` are callable using argument types `(immutable(T), immutable(S))` +fail_compilation/named_arguments_overload.d(17): Candidates are: `named_arguments_overload.snoopy(S s, int i = 0, T t = T())` +fail_compilation/named_arguments_overload.d(18): `named_arguments_overload.snoopy(T t, int i, S s)` +fail_compilation/named_arguments_overload.d(35): Error: `named_arguments_overload.snoopy` called with argument types `(immutable(S), immutable(T), immutable(int))` matches both: +fail_compilation/named_arguments_overload.d(17): `named_arguments_overload.snoopy(S s, int i = 0, T t = T())` +and: +fail_compilation/named_arguments_overload.d(18): `named_arguments_overload.snoopy(T t, int i, S s)` +--- +*/ + +char snoopy(S s, int i = 0, T t = T.init) { return 'B'; } +char snoopy(T t, int i, S s) { return 'A'; } + +struct S { } +struct T { } +immutable S s = S.init; +immutable T t = T.init; +immutable int i = 0; + +static assert(snoopy(t, i, s ) == 'A'); +static assert(snoopy(s, i, t ) == 'B'); +static assert(snoopy(s:s, t:t ) == 'B'); +static assert(snoopy(t:t, s:s ) == 'B'); +static assert(snoopy(t:t, i, s:s) == 'A'); +static assert(snoopy(s:s, t:t, i ) == 'A'); + +immutable err0 = snoopy(s, t); // error, neither A nor B match +immutable err1 = snoopy(t, s); // error, neither A nor B match +immutable err2 = snoopy(s:s, t:t, i:i); // error, ambiguous diff --git a/tests/dmd/fail_compilation/named_arguments_parse.d b/tests/dmd/fail_compilation/named_arguments_parse.d new file mode 100644 index 00000000000..19e230ee519 --- /dev/null +++ b/tests/dmd/fail_compilation/named_arguments_parse.d @@ -0,0 +1,15 @@ +/** +TEST_OUTPUT: +--- +fail_compilation/named_arguments_parse.d(10): Error: named arguments not allowed here +fail_compilation/named_arguments_parse.d(13): Error: named arguments not allowed here +fail_compilation/named_arguments_parse.d(14): Error: named arguments not allowed here +--- +*/ + +@(attribute: 3) +void main() +{ + mixin(thecode: "{}"); + pragma(msg, themsg: "hello"); +} diff --git a/tests/dmd/fail_compilation/retscope6.d b/tests/dmd/fail_compilation/retscope6.d index 9736d37e949..5c581d1db71 100644 --- a/tests/dmd/fail_compilation/retscope6.d +++ b/tests/dmd/fail_compilation/retscope6.d @@ -141,13 +141,14 @@ void testarchie() /* TEST_OUTPUT: --- -fail_compilation/retscope6.d(9022): Error: returning `fred(& i)` escapes a reference to local variable `i` +fail_compilation/retscope6.d(9023): Error: returning `fred(& i)` escapes a reference to local variable `i` --- */ #line 9000 -@safe: +@safe +{ alias T9 = S9!(); struct S9() { @@ -199,6 +200,7 @@ void hmac(scope ubyte[] secret) ubyte[10] buffer; secret = buffer[]; } +} /* TEST_OUTPUT: --- @@ -289,3 +291,5 @@ ref int escape23021() @safe // ensure we do not infer return ref return infer23021(nonScopePtr); // no error } + +/******************************/ diff --git a/tests/dmd/fail_compilation/shared.d b/tests/dmd/fail_compilation/shared.d index 5b08b36b7ea..8b94a7981a1 100644 --- a/tests/dmd/fail_compilation/shared.d +++ b/tests/dmd/fail_compilation/shared.d @@ -236,3 +236,45 @@ struct BitRange this.bits++; } } + +/* +TEST_OUTPUT: +--- +fail_compilation/shared.d(3004): Error: cast from `void*` to `shared(int*)` not allowed in safe code +fail_compilation/shared.d(3005): Error: cast from `void*` to `shared(const(int*))` not allowed in safe code +fail_compilation/shared.d(3008): Error: cast from `shared(void*)` to `int*` not allowed in safe code +fail_compilation/shared.d(3009): Error: cast from `shared(void*)` to `shared(const(int*))` not allowed in safe code +--- +*/ + +#line 3000 + +void test_casting_safe() @safe +{ + void *p; + auto t1 = cast(shared(int*))p; + auto t2 = cast(const(shared(int*)))p; + + shared void* s; + auto x1 = cast(int*)s; + auto x2 = cast(const(shared(int*)))s; +} + +#line 3100 + +// https://issues.dlang.org/show_bug.cgi?id=23783 + +/* +TEST_OUTPUT: +--- +fail_compilation/shared.d(3114): Error: direct access to shared `x` is not allowed, see `core.atomic` +fail_compilation/shared.d(3115): Error: direct access to shared `x` is not allowed, see `core.atomic` +--- +*/ + +void test23783() +{ + shared int x = 3; + assert(x == 3); + bool b = x == 3; +} diff --git a/tests/dmd/fail_compilation/test128.i b/tests/dmd/fail_compilation/test128.i new file mode 100644 index 00000000000..fbbd5e7d758 --- /dev/null +++ b/tests/dmd/fail_compilation/test128.i @@ -0,0 +1,15 @@ +/* TEST_OUTPUT: +--- +fail_compilation/test128.i(12): Error: unsigned __int128 not supported +fail_compilation/test128.i(12): Error: __int128 not supported +--- + */ + +// https://issues.dlang.org/show_bug.cgi?id=23614 + +unsigned long long _mulx_u64(unsigned long long __X, unsigned long long __Y, unsigned long long *__P) +{ + unsigned __int128 __res = (__int128) __X * __Y; + *__P = (unsigned long long) (__res >> 64); + return (unsigned long long) __res; +} diff --git a/tests/dmd/fail_compilation/test16495.d b/tests/dmd/fail_compilation/test16495.d new file mode 100644 index 00000000000..667d4c2feb7 --- /dev/null +++ b/tests/dmd/fail_compilation/test16495.d @@ -0,0 +1,18 @@ +/* TEST_OUTPUT: +--- +fail_compilation/test16495.d(12): Error: undefined identifier `q` +fail_compilation/test16495.d(17): Error: expected 1 arguments for `fullyQualifiedName` but had 0 +--- + */ + +// https://issues.dlang.org/show_bug.cgi?id=16495 + +void test1() +{ + auto m = __traits(fullyQualifiedName, q); +} + +void test2() +{ + auto n = __traits(fullyQualifiedName); +} diff --git a/tests/dmd/fail_compilation/test17096.d b/tests/dmd/fail_compilation/test17096.d index e421419ae2d..2c431a3849b 100644 --- a/tests/dmd/fail_compilation/test17096.d +++ b/tests/dmd/fail_compilation/test17096.d @@ -1,28 +1,29 @@ /* TEST_OUTPUT: --- -fail_compilation/test17096.d(28): Error: expected 1 arguments for `isPOD` but had 2 -fail_compilation/test17096.d(29): Error: expected 1 arguments for `isNested` but had 2 -fail_compilation/test17096.d(30): Error: expected 1 arguments for `isVirtualFunction` but had 2 -fail_compilation/test17096.d(31): Error: expected 1 arguments for `isVirtualMethod` but had 2 -fail_compilation/test17096.d(32): Error: expected 1 arguments for `isAbstractFunction` but had 2 -fail_compilation/test17096.d(33): Error: expected 1 arguments for `isFinalFunction` but had 2 -fail_compilation/test17096.d(34): Error: expected 1 arguments for `isOverrideFunction` but had 2 -fail_compilation/test17096.d(35): Error: expected 1 arguments for `isStaticFunction` but had 2 -fail_compilation/test17096.d(36): Error: expected 1 arguments for `isRef` but had 2 -fail_compilation/test17096.d(37): Error: expected 1 arguments for `isOut` but had 2 -fail_compilation/test17096.d(38): Error: expected 1 arguments for `isLazy` but had 2 -fail_compilation/test17096.d(39): Error: expected 1 arguments for `identifier` but had 2 -fail_compilation/test17096.d(40): Error: expected 1 arguments for `getProtection` but had 2 -fail_compilation/test17096.d(41): Error: expected 1 arguments for `parent` but had 2 -fail_compilation/test17096.d(42): Error: expected 1 arguments for `classInstanceSize` but had 2 -fail_compilation/test17096.d(43): Error: expected 1 arguments for `allMembers` but had 2 -fail_compilation/test17096.d(44): Error: expected 1 arguments for `derivedMembers` but had 2 -fail_compilation/test17096.d(45): Error: expected 1 arguments for `getAliasThis` but had 2 -fail_compilation/test17096.d(46): Error: expected 1 arguments for `getAttributes` but had 2 -fail_compilation/test17096.d(47): Error: expected 1 arguments for `getFunctionAttributes` but had 2 -fail_compilation/test17096.d(48): Error: expected 1 arguments for `getUnitTests` but had 2 -fail_compilation/test17096.d(49): Error: expected 1 arguments for `getVirtualIndex` but had 2 -fail_compilation/test17096.d(50): Error: a single type expected for trait pointerBitmap +fail_compilation/test17096.d(29): Error: expected 1 arguments for `isPOD` but had 2 +fail_compilation/test17096.d(30): Error: expected 1 arguments for `isNested` but had 2 +fail_compilation/test17096.d(31): Deprecation: `traits(isVirtualFunction)` is deprecated. Use `traits(isVirtualMethod)` instead +fail_compilation/test17096.d(31): Error: expected 1 arguments for `isVirtualFunction` but had 2 +fail_compilation/test17096.d(32): Error: expected 1 arguments for `isVirtualMethod` but had 2 +fail_compilation/test17096.d(33): Error: expected 1 arguments for `isAbstractFunction` but had 2 +fail_compilation/test17096.d(34): Error: expected 1 arguments for `isFinalFunction` but had 2 +fail_compilation/test17096.d(35): Error: expected 1 arguments for `isOverrideFunction` but had 2 +fail_compilation/test17096.d(36): Error: expected 1 arguments for `isStaticFunction` but had 2 +fail_compilation/test17096.d(37): Error: expected 1 arguments for `isRef` but had 2 +fail_compilation/test17096.d(38): Error: expected 1 arguments for `isOut` but had 2 +fail_compilation/test17096.d(39): Error: expected 1 arguments for `isLazy` but had 2 +fail_compilation/test17096.d(40): Error: expected 1 arguments for `identifier` but had 2 +fail_compilation/test17096.d(41): Error: expected 1 arguments for `getProtection` but had 2 +fail_compilation/test17096.d(42): Error: expected 1 arguments for `parent` but had 2 +fail_compilation/test17096.d(43): Error: expected 1 arguments for `classInstanceSize` but had 2 +fail_compilation/test17096.d(44): Error: expected 1 arguments for `allMembers` but had 2 +fail_compilation/test17096.d(45): Error: expected 1 arguments for `derivedMembers` but had 2 +fail_compilation/test17096.d(46): Error: expected 1 arguments for `getAliasThis` but had 2 +fail_compilation/test17096.d(47): Error: expected 1 arguments for `getAttributes` but had 2 +fail_compilation/test17096.d(48): Error: expected 1 arguments for `getFunctionAttributes` but had 2 +fail_compilation/test17096.d(49): Error: expected 1 arguments for `getUnitTests` but had 2 +fail_compilation/test17096.d(50): Error: expected 1 arguments for `getVirtualIndex` but had 2 +fail_compilation/test17096.d(51): Error: a single type expected for trait pointerBitmap --- */ enum b03 = __traits(isPOD, 1, 2); diff --git a/tests/dmd/fail_compilation/test17451.d b/tests/dmd/fail_compilation/test17451.d index a7ef88a0dba..b0cda2105a2 100644 --- a/tests/dmd/fail_compilation/test17451.d +++ b/tests/dmd/fail_compilation/test17451.d @@ -2,7 +2,7 @@ --- fail_compilation/test17451.d(22): Error: undefined identifier `allocator` fail_compilation/test17451.d(23): Error: `false` has no effect -fail_compilation/test17451.d(30): Error: variable `test17451.HashMap!(ThreadSlot).HashMap.__lambda2.v` size of type `ThreadSlot` is invalid +fail_compilation/test17451.d(30): Error: variable `test17451.HashMap!(ThreadSlot).HashMap.__lambda2.v` - size of type `ThreadSlot` is invalid fail_compilation/test17451.d(44): Error: template instance `test17451.HashMap!(ThreadSlot)` error instantiating --- */ diff --git a/tests/dmd/fail_compilation/test20549.d b/tests/dmd/fail_compilation/test20549.d index 2cafc1be9e2..dc95da10eb5 100644 --- a/tests/dmd/fail_compilation/test20549.d +++ b/tests/dmd/fail_compilation/test20549.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: ---- -fail_compilation/test20549.d(12): Error: variable `test.__a_field_0` variables cannot be of type `void` +fail_compilation/test20549.d(12): Error: variable `test.__a_field_0` - variables cannot be of type `void` ---- */ diff --git a/tests/dmd/fail_compilation/test20719.d b/tests/dmd/fail_compilation/test20719.d index 44d3d5a36a3..b9305f20f80 100644 --- a/tests/dmd/fail_compilation/test20719.d +++ b/tests/dmd/fail_compilation/test20719.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- fail_compilation/test20719.d(13): Error: struct `test20719.SumType` no size because of forward reference -fail_compilation/test20719.d(32): Error: variable `test20719.isCopyable!(SumType).__lambda2.foo` size of type `SumType` is invalid +fail_compilation/test20719.d(32): Error: variable `test20719.isCopyable!(SumType).__lambda2.foo` - size of type `SumType` is invalid fail_compilation/test20719.d(18): Error: template instance `test20719.isCopyable!(SumType)` error instantiating --- */ diff --git a/tests/dmd/fail_compilation/test20809.d b/tests/dmd/fail_compilation/test20809.d index 44728c5c2ff..0b452774245 100644 --- a/tests/dmd/fail_compilation/test20809.d +++ b/tests/dmd/fail_compilation/test20809.d @@ -1,8 +1,8 @@ /* -REQUIRED_ARGS: -de +REQUIRED_ARGS: TEST_OUTPUT: --- -fail_compilation/test20809.d(114): Deprecation: returning `this.a` escapes a reference to parameter `this` +fail_compilation/test20809.d(114): Error: returning `this.a` escapes a reference to parameter `this` fail_compilation/test20809.d(112): perhaps annotate the function with `return` --- */ diff --git a/tests/dmd/fail_compilation/test20998.d b/tests/dmd/fail_compilation/test20998.d index 16eb02622d8..2e137ab7631 100644 --- a/tests/dmd/fail_compilation/test20998.d +++ b/tests/dmd/fail_compilation/test20998.d @@ -6,7 +6,7 @@ TEST_OUTPUT: fail_compilation/test20998.d(76): Error: undefined identifier `invalid` X x = { invalid, 2, "asd" }; ^ -fail_compilation/test20998.d(76): Error: too many initializers for `X` +fail_compilation/test20998.d(76): Error: too many initializers for `X` with 2 fields X x = { invalid, 2, "asd" }; ^ fail_compilation/test20998.d(83): Error: cannot implicitly convert expression `"a"` of type `string` to `int` @@ -15,7 +15,7 @@ X2 x2 = { ptr: null, "a", ptr: 2, 444 }; fail_compilation/test20998.d(83): Error: duplicate initializer for field `ptr` X2 x2 = { ptr: null, "a", ptr: 2, 444 }; ^ -fail_compilation/test20998.d(83): Error: too many initializers for `X2` +fail_compilation/test20998.d(83): Error: too many initializers for `X2` with 3 fields X2 x2 = { ptr: null, "a", ptr: 2, 444 }; ^ fail_compilation/test20998.d(90): Error: overlapping initialization for field `ptr` and `x` @@ -27,7 +27,7 @@ X3 x3 = { ptr: null, "a", ptr: 2, 444 }; fail_compilation/test20998.d(90): Error: duplicate initializer for field `ptr` X3 x3 = { ptr: null, "a", ptr: 2, 444 }; ^ -fail_compilation/test20998.d(90): Error: too many initializers for `X3` +fail_compilation/test20998.d(90): Error: too many initializers for `X3` with 3 fields X3 x3 = { ptr: null, "a", ptr: 2, 444 }; ^ fail_compilation/test20998.d(98): Error: field `X4.ptr` cannot assign to misaligned pointers in `@safe` code @@ -36,7 +36,7 @@ fail_compilation/test20998.d(98): Error: field `X4.ptr` cannot assign to misalig fail_compilation/test20998.d(98): Error: cannot implicitly convert expression `"a"` of type `string` to `int` X4 x4 = { ptr: null, "a", 444, ptr: 2, true }; ^ -fail_compilation/test20998.d(98): Error: too many initializers for `X4` +fail_compilation/test20998.d(98): Error: too many initializers for `X4` with 2 fields X4 x4 = { ptr: null, "a", 444, ptr: 2, true }; ^ fail_compilation/test20998.d(102): called from here: `test()` @@ -51,16 +51,16 @@ X2 a5 = { ptr: 1, ptr: 2, ptr: 444, ptr: 555 }; fail_compilation/test20998.d(104): Error: duplicate initializer for field `ptr` X2 a5 = { ptr: 1, ptr: 2, ptr: 444, ptr: 555 }; ^ -fail_compilation/test20998.d(104): Error: too many initializers for `X2` +fail_compilation/test20998.d(104): Error: too many initializers for `X2` with 3 fields X2 a5 = { ptr: 1, ptr: 2, ptr: 444, ptr: 555 }; ^ -fail_compilation/test20998.d(107): Error: too many initializers for `X2` +fail_compilation/test20998.d(107): Error: too many initializers for `X2` with 3 fields X2 c6 = { null, 2, true, null }; ^ fail_compilation/test20998.d(116): Error: cannot implicitly convert expression `1` of type `int` to `immutable(char*)` immutable Struct iStruct = {1, &ch}; ^ -fail_compilation/test20998.d(116): Error: too many initializers for `Struct` +fail_compilation/test20998.d(116): Error: too many initializers for `Struct` with 1 field immutable Struct iStruct = {1, &ch}; ^ fail_compilation/test20998.d(120): called from here: `test2()` diff --git a/tests/dmd/fail_compilation/test21164.d b/tests/dmd/fail_compilation/test21164.d index f42c4bc9d15..a12002488ed 100644 --- a/tests/dmd/fail_compilation/test21164.d +++ b/tests/dmd/fail_compilation/test21164.d @@ -3,7 +3,8 @@ TEST_OUTPUT: --- fail_compilation/imports/test21164d.d(3): Error: (expression) expected following `static if` fail_compilation/imports/test21164d.d(3): Error: found `}` instead of statement -fail_compilation/test21164.d(11): Error: template instance `test21164a.D!(R!(O(), 1))` error instantiating +fail_compilation/imports/test21164a.d(5): Error: undefined identifier `I` +fail_compilation/test21164.d(12): Error: template instance `test21164a.D!(R!(O(), 1))` error instantiating --- */ import imports.test21164a; diff --git a/tests/dmd/fail_compilation/test22765.d b/tests/dmd/fail_compilation/test22765.d new file mode 100644 index 00000000000..0d1b582d517 --- /dev/null +++ b/tests/dmd/fail_compilation/test22765.d @@ -0,0 +1,14 @@ +// https://issues.dlang.org/show_bug.cgi?id=22765 + +/* +TEST_OUTPUT: +--- +fail_compilation/test22765.d(14): Error: template instance `test22765.Template!null` internal compiler error: C++ `null` template value parameter is not supported +--- +*/ + +template Template(T...) +{ + extern(C++) const __gshared int Template = 0; +} +auto x = Template!(null); diff --git a/tests/dmd/fail_compilation/test23710.d b/tests/dmd/fail_compilation/test23710.d new file mode 100644 index 00000000000..e834b78f7d5 --- /dev/null +++ b/tests/dmd/fail_compilation/test23710.d @@ -0,0 +1,32 @@ +/* REQUIRED_ARGS: -betterC +TEST_OUTPUT: +--- +fail_compilation/test23710.d(111): Error: array concatenation of expression `foo ~ [1, 2, 3]` requires the GC which is not available with -betterC +--- + */ +// https://issues.dlang.org/show_bug.cgi?id=23710 + +#line 100 + +int test(int i) +{ + int j; + int[] foo; + if (0) + { + for (;;) + { + import core.stdc.stdio; + printf("start body\n"); + foo = foo ~ [1,2,3]; +L1: + printf("foo.length = %zu\n", foo.length); + j += foo.length; + i += 2; + if (i > 5) + return j; + printf("end body\n"); + } + } + goto L1; +} diff --git a/tests/dmd/fail_compilation/test_switch_error.d b/tests/dmd/fail_compilation/test_switch_error.d index bfd8803d2f2..41b6e52545e 100644 --- a/tests/dmd/fail_compilation/test_switch_error.d +++ b/tests/dmd/fail_compilation/test_switch_error.d @@ -104,7 +104,7 @@ void test5(int i) TEST_OUTPUT: --- fail_compilation/test_switch_error.d(513): Error: undefined identifier `undefinedFunc` -fail_compilation/test_switch_error.d(517): Error: `case` must be a `string` or an integral constant, not `Strukt(1)` +fail_compilation/test_switch_error.d(517): Error: `case` expression must be a compile-time `string` or an integral constant, not `Strukt(1)` fail_compilation/test_switch_error.d(518): Error: `case` variables have to be `const` or `immutable` fail_compilation/test_switch_error.d(518): Error: `case` variables not allowed in `final switch` statements fail_compilation/test_switch_error.d(519): Error: `case` variables not allowed in `final switch` statements @@ -144,8 +144,8 @@ void errorsWithErrors(int param, immutable int constant) TEST_OUTPUT: --- fail_compilation/test_switch_error.d(622): Error: undefined identifier `undefinedFunc` -fail_compilation/test_switch_error.d(624): Error: `case` must be a `string` or an integral constant, not `SubtypeOfInt(2)` -fail_compilation/test_switch_error.d(625): Error: `case` must be a `string` or an integral constant, not `SubtypeOfIntMethod()` +fail_compilation/test_switch_error.d(624): Error: `case` expression must be a compile-time `string` or an integral constant, not `SubtypeOfInt(2)` +fail_compilation/test_switch_error.d(625): Error: `case` expression must be a compile-time `string` or an integral constant, not `SubtypeOfIntMethod()` --- ++/ #line 600 diff --git a/tests/dmd/fail_compilation/testscopestatic.d b/tests/dmd/fail_compilation/testscopestatic.d index 86c6328e9e4..cc7b0125953 100644 --- a/tests/dmd/fail_compilation/testscopestatic.d +++ b/tests/dmd/fail_compilation/testscopestatic.d @@ -4,7 +4,7 @@ fail_compilation/testscopestatic.d(15): Error: variable `testscopestatic.foo.p` cannot be `scope` and `static` fail_compilation/testscopestatic.d(16): Error: variable `testscopestatic.foo.b` cannot be `scope` and `extern` fail_compilation/testscopestatic.d(17): Error: variable `testscopestatic.foo.c` cannot be `scope` and `__gshared` -fail_compilation/testscopestatic.d(21): Error: variable `testscopestatic.foo.S.x` field cannot be `scope` +fail_compilation/testscopestatic.d(21): Error: field `x` cannot be `scope` --- */ diff --git a/tests/dmd/fail_compilation/udaparams.d b/tests/dmd/fail_compilation/udaparams.d index ec4796789ac..453ebba4e09 100644 --- a/tests/dmd/fail_compilation/udaparams.d +++ b/tests/dmd/fail_compilation/udaparams.d @@ -14,9 +14,9 @@ fail_compilation/udaparams.d(44): Error: `@trusted` attribute for function param fail_compilation/udaparams.d(45): Error: `@nogc` attribute for function parameter is not supported fail_compilation/udaparams.d(51): Error: cannot put a storage-class in an `alias` declaration. fail_compilation/udaparams.d(52): Error: cannot put a storage-class in an `alias` declaration. -fail_compilation/udaparams.d(53): Error: semicolon expected to close `alias` declaration +fail_compilation/udaparams.d(53): Error: semicolon expected to close `alias` declaration, not `=>` fail_compilation/udaparams.d(53): Error: declaration expected, not `=>` -fail_compilation/udaparams.d(54): Error: semicolon expected to close `alias` declaration +fail_compilation/udaparams.d(54): Error: semicolon expected to close `alias` declaration, not `=>` fail_compilation/udaparams.d(54): Error: declaration expected, not `=>` fail_compilation/udaparams.d(57): Error: basic type expected, not `@` fail_compilation/udaparams.d(57): Error: identifier expected for template value parameter diff --git a/tests/dmd/run.d b/tests/dmd/run.d index b931e6f8a11..978ba898b61 100755 --- a/tests/dmd/run.d +++ b/tests/dmd/run.d @@ -197,7 +197,7 @@ Options: if (targets.length > 0) { - string[] failedTargets; + shared string[] failedTargets; foreach (target; parallel(targets, 1)) { log("run: %-(%s %)", target.args); @@ -209,7 +209,7 @@ Options: : "`unit` tests"; writeln(">>> TARGET FAILED: ", name); - failedTargets ~= name; + synchronized failedTargets ~= name; } } if (failedTargets.length > 0) diff --git a/tests/dmd/runnable/aliasthis.d b/tests/dmd/runnable/aliasthis.d index db5913c8389..50e5c4db64b 100644 --- a/tests/dmd/runnable/aliasthis.d +++ b/tests/dmd/runnable/aliasthis.d @@ -1,7 +1,16 @@ /* TEST_OUTPUT: --- +runnable/aliasthis.d(103): Deprecation: alias this for classes/interfaces is deprecated +runnable/aliasthis.d(291): Deprecation: alias this for classes/interfaces is deprecated +runnable/aliasthis.d(292): Deprecation: alias this for classes/interfaces is deprecated +runnable/aliasthis.d(294): Deprecation: alias this for classes/interfaces is deprecated +runnable/aliasthis.d(465): Deprecation: alias this for classes/interfaces is deprecated +runnable/aliasthis.d(466): Deprecation: alias this for classes/interfaces is deprecated +runnable/aliasthis.d(477): Deprecation: alias this for classes/interfaces is deprecated +runnable/aliasthis.d(1013): Deprecation: alias this for classes/interfaces is deprecated false +runnable/aliasthis.d(2100): Deprecation: alias this for classes/interfaces is deprecated [] = int [] = string [0] = int @@ -10,6 +19,7 @@ false [] = int [1] = string [0] = int +runnable/aliasthis.d(741): Deprecation: alias this for classes/interfaces is deprecated --- RUN_OUTPUT: diff --git a/tests/dmd/runnable/auto1.d b/tests/dmd/runnable/auto1.d index 6ee075089d1..af95545ccc9 100644 --- a/tests/dmd/runnable/auto1.d +++ b/tests/dmd/runnable/auto1.d @@ -67,13 +67,13 @@ int ax; class A2 { - this() + this() scope { printf("A2.this()\n"); ax += 1; } - ~this() + ~this() scope { printf("A2.~this()\n"); ax += 1000; @@ -102,12 +102,12 @@ class Parent3 class Child3 : Parent3 { - this(){ + this() scope { assert(status3==0); status3=1; } - ~this(){ + ~this() scope { assert(status3==1); status3=2; } diff --git a/tests/dmd/runnable/bitfields.c b/tests/dmd/runnable/bitfields.c index 7e986b5f5f7..8946c832571 100644 --- a/tests/dmd/runnable/bitfields.c +++ b/tests/dmd/runnable/bitfields.c @@ -189,7 +189,7 @@ struct S6 int boo6() { - S s; + struct S6 s; s.a = 3; s.b = 1; s.a += 2; diff --git a/tests/dmd/runnable/complex3.d b/tests/dmd/runnable/complex3.d new file mode 100644 index 00000000000..7167b0b6ff8 --- /dev/null +++ b/tests/dmd/runnable/complex3.d @@ -0,0 +1,31 @@ +// https://issues.dlang.org/show_bug.cgi?id=23778 + + +enum __c_long_double : double; + +alias __c_long_double c_long_double; + +struct _Complex +{ + c_long_double re; + c_long_double im; +} + +version (all) // bug to test +{ + enum __c_complex_real : _Complex; + alias c_complex_real = __c_complex_real; +} +else // works + enum c_complex_real : _Complex; + +c_complex_real toNative2(real re, real im) +{ + return c_complex_real(re, im); +} + +void main() +{ + c_complex_real n = toNative2(123, 456); + assert(123 == n.re && 456 == n.im); +} diff --git a/tests/dmd/runnable/cppdtor.d b/tests/dmd/runnable/cppdtor.d index 0592d448b1f..711f309b7a2 100644 --- a/tests/dmd/runnable/cppdtor.d +++ b/tests/dmd/runnable/cppdtor.d @@ -38,12 +38,12 @@ extern (C) int printf(scope const char*, ...); extern (C++) class CppA { int num; - this(int num) + this(int num) scope { this.num = num; } - ~this() + ~this() scope { printf("%d: CppA.~this\n", num); } @@ -51,12 +51,12 @@ extern (C++) class CppA extern (C++) class CppB : CppA { - this(int num) + this(int num) scope { super(num); } - ~this() + ~this() scope { printf("%d: CppB.~this\n", num); } @@ -64,12 +64,12 @@ extern (C++) class CppB : CppA extern (C++) class CppC : CppB { - this(int num) + this(int num) scope { super(num); } - ~this() + ~this() scope { printf("%d: CppC.~this\n", num); } @@ -78,12 +78,12 @@ extern (C++) class CppC : CppB extern (D) class DA { int num; - this(int num) + this(int num) scope { this.num = num; } - ~this() + ~this() scope { printf("%d: DA.~this\n", num); } @@ -91,12 +91,12 @@ extern (D) class DA extern (D) class DB : DA { - this(int num) + this(int num) scope { super(num); } - ~this() + ~this() scope { printf("%d: DB.~this\n", num); } @@ -104,12 +104,12 @@ extern (D) class DB : DA extern (D) class DC : DB { - this(int num) + this(int num) scope { super(num); } - ~this() + ~this() scope { printf("%d: DC.~this\n", num); } @@ -118,7 +118,7 @@ extern (D) class DC : DB extern (C++) class CppNoDestruct { int num; - this(int num) + this(int num) scope { this.num = num; } diff --git a/tests/dmd/runnable/e7804.d b/tests/dmd/runnable/e7804.d index d32531055f5..ff66310ff2b 100644 --- a/tests/dmd/runnable/e7804.d +++ b/tests/dmd/runnable/e7804.d @@ -63,8 +63,6 @@ TmpPrm!(__traits(getMember, Foo, "MyInt")) tpt = TmpPrm!(__traits(getMember, Foo int virtual(int p){return p;} void test(this T)() { - alias vf = __traits(getVirtualFunctions, Class, "virtual"); - assert(vf.length == 2); alias vm = __traits(getVirtualMethods, Class, "virtual"); assert(vm.length == 1); assert(vm[0](42) == 42); diff --git a/tests/dmd/runnable/extra-files/paranoia.d b/tests/dmd/runnable/extra-files/paranoia.d index 986fe75387a..9aed89b457d 100644 --- a/tests/dmd/runnable/extra-files/paranoia.d +++ b/tests/dmd/runnable/extra-files/paranoia.d @@ -302,7 +302,7 @@ void printExtended(const(char) *fmt, FLOAT f) printf("%lg", cast(double)f); else { - ld_sprint(str.ptr, 'A', longdouble_soft(f)); + ld_sprint(str.ptr, str.length, 'A', longdouble_soft(f)); printf("%s", str.ptr); } } diff --git a/tests/dmd/runnable/extra-files/test11051.d b/tests/dmd/runnable/extra-files/test11051.d new file mode 100644 index 00000000000..c8bfdc278bd --- /dev/null +++ b/tests/dmd/runnable/extra-files/test11051.d @@ -0,0 +1,30 @@ +module test11051; + +version (Safe) +{ + void main() @safe + { + enum E { A, B } + E e = cast(E)-1; + + final switch (e) + { + case E.A: break; + case E.B: break; + } + } +} +else +{ + void main() + { + enum E { A, B } + E e = cast(E)-1; + + final switch (e) + { + case E.A: break; + case E.B: break; + } + } +} diff --git a/tests/dmd/runnable/extra-files/test39.d b/tests/dmd/runnable/extra-files/test39.d index dd05b1b3529..a8f512d5a0b 100644 --- a/tests/dmd/runnable/extra-files/test39.d +++ b/tests/dmd/runnable/extra-files/test39.d @@ -7,4 +7,4 @@ void main() { auto t = new Test!(char); t.show ("hello"); -} +} diff --git a/tests/dmd/runnable/extra-files/untag.html b/tests/dmd/runnable/extra-files/untag.html deleted file mode 100644 index cec0c87a114..00000000000 --- a/tests/dmd/runnable/extra-files/untag.html +++ /dev/null @@ -1,555 +0,0 @@ - - - - - - - Abbott and Costello Meet Frankenstein - Wikipedia, the free encyclopedia - - - - - - - - - - - - -
-
-
- -

Abbott and Costello Meet Frankenstein

-
-

From Wikipedia, the free encyclopedia

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Abbott and Costello Meet Frankenstein

-Abbott and Costello Meet Frankenstein Theatrical Poster
Directed byCharles Barton
Produced byRobert Arthur
Written byRobert Lees
-Frederic I. Rinaldo
-John Grant
StarringBud Abbott
-Lou Costello
-Lon Chaney, Jr.
-Bela Lugosi
-Glenn Strange
Music byFrank Skinner
Editing byFrank Gross
Distributed byUniversal International
Release date(s)June 15, 1948 (U.S. release)
Running time83 min.
LanguageEnglish
Budget$760,000
Preceded byHouse of Dracula (1945)
-The Invisible Man's Revenge (1944)
-The Noose Hangs High (1948)
Followed byMexican Hayride (1948)
-Abbott and Costello Meet the Invisible Man (1951)
-

Abbott and Costello Meet Frankenstein (onscreen title: Bud Abbott Lou Costello Meet Frankenstein) is a 1948 comedy/horror film directed by Charles Barton and starring the comedy team of Abbott and Costello.

-

This is the first of several films where the comedy duo meets classic characters from Universal's film stable. In the film, they encounter Dracula, Frankenstein's monster, and the Wolf Man. Subsequent films pair the duo with the Mummy, the Keystone Kops, and the Invisible Man. On a TV special in the early 1950s, the comedy duo did a sketch where they interacted with the latest original Universal Studios monster being promoted at the time, the Creature from the Black Lagoon.

-

The film is considered the swan song for the "Big Three" Universal horror monsters – Dracula, the Wolf Man and Frankenstein's monster – although it does not appear to fit within the loose continuity of the earlier films.

-

The film was re-released in 1956 along with Abbott and Costello Meet the Killer, Boris Karloff.

-

In 2001, the United States Library of Congress deemed this film "culturally, historically, or aesthetically significant" and selected it for preservation in the National Film Registry.

-

In September 2007, Reader’s Digest selected the movie as one of the top 100 funniest films of all time.

- - - - -
-
-

Contents

-
- -
- -

-

[edit] Plot

-

Chick Young (Bud Abbott) and Wilbur Grey (Lou Costello) work as baggage clerks in LaMirada, Florida. When Wilbur mishandles two crates belonging to 'MacDougal's House of Horrors' museum, Mr. MacDougal (Frank Ferguson) demands that they deliver them in person so that they can be inspected by an insurance agent. MacDougal boasts to Wilbur's girlfriend, Dr. Sandra Mornay (Lénore Aubert), that the crates contain "the remains of the original Count Dracula" (Bela Lugosi) and "the body of the Frankenstein Monster" (Glenn Strange).

-

Dracula awakens, hypnotizes Wilbur, and spirits away his own coffin (and the revived Monster) before anyone else sees them. MacDougal then arrives with the insurance agent. Finding the storage crates empty, he accuses the boys of theft and has them arrested.

-

Mornay receives Dracula and the Monster at her island castle. Sandra is a gifted surgeon who has studied Dr. Frankenstein's notebooks, and has been posing as Wilbur's girlfriend as part of Dracula's scheme to replace the Monster's brutish brain with one more pliable — Wilbur's.

-

Wilbur and Chick are bailed out of jail and mistakenly believe Sandra to be their benefactor. Actually Joan Raymond (Jane Randolph), who also seems to like Wilbur, is responsible for the good deed. Joan is secretly working for the company that is processing MacDougal's insurance claim, and hopes Wilbur will lead her to the missing 'exhibits'.

-

Meanwhile, Larry Talbot (Lon Chaney, Jr.) has taken the apartment across the hall from Wilbur and Chick. He has tracked Dracula and the Monster from Europe, and knows them to be alive. Talbot asks the boys to help him find and destroy the villains. Wilbur is amenable to the plan, but Chick thinks both of them are crazy. Talbot's desperate insistence that he be locked in his room before moonrise impresses Chick even less.

-

The following night, Wilbur, Chick and Joan go to Sandra's castle to pick her up for a costume ball. Sandra has told Wilbur to come alone, and receives the extra guests rather icily.

-

While the ladies powder their noses, Wilbur answers a telephone call from someone wanting to speak to a 'Dr Lejos'. It is Talbot, who informs them that they are in the "house of Dracula". Wilbur reluctantly agrees to search the castle with Chick, and soon stumbles upon an underground passageway, complete with boat and dock. Behind a secret revolving wall, Wilbur again encounters Dracula and the Monster, but escapes. Wilbur's every attempt to get Chick to witness the villains fails - thanks to the revolving wall. Meanwhile, Joan has discovered Dr Frankenstein's notebook in Sandra's bureau, while Sandra has discovered Joan's employee I.D. in her bag.

-

Suavely reattired, Dracula (a.k.a. Dr. Lejos) is introduced by Sandra to Joan and the boys. He commends Sandra on her 'choice', expertly massaging the ego of Wilbur, who does not realize the true context of the remark. Also working at the castle is the naive Dr. Stevens (Charles Bradstreet), who questions some of the specialized equipment that has arrived. Dracula manages to deflect Dr. Stevens' questions by pairing him with Joan and shooing off the 'young people' to their ball. Sandra claims to have a sudden splitting headache and will not be able to attend the event. When Dracula consults Sandra in private, she admits that Dr. Stevens' questions, Joan's insurance credentials and Wilbur's inquiries have made her nervous, and wants to postpone the experiments. Impatient, Dracula asserts his will by hypnotizing her, and biting her in the throat.

-

At the ball, the boys encounter Talbot and MacDougal. Dracula arrives unexpectedly with Sandra, now under his spell. Dracula easily deflects Talbot's accusations, making the man appear disturbed. Dracula takes Joan for a dance while Sandra lures Wilbur to a quiet spot. Just before she can bite Wilbur's neck, Chick and Larry approach looking for Joan, and Sandra flees. As they search the grounds, Talbot transforms into the Wolf Man. Wilbur escapes, but the Wolf Man finds and injures MacDougal. Later noting that Chick is costumed as a werewolf, MacDougal concludes that Chick attacked him for revenge. (The fact that Chick is dressed like Talbot certainly does not help the situation). Chick manages to slip away, only to witness Dracula hypnotizing Wilbur. Chick becomes somewhat hypnotized himself, while Wilbur and an entranced Joan are brought back to the castle by Dracula and Sandra. The next morning, Chick is still on the lam when he finds Larry, who confesses that he was MacDougal's attacker. Now finally convinced, Chick agrees to help Larry rescue Wilbur and Joan.

-

While Wilbur is being held in a pillory, Sandra finally explains to him the plan to transplant his brain into the Monster. She and Dracula leave him to prepare the Monster for the operation. Chick and Talbot arrive, free Wilbur, and head off to save Joan. Wilbur, meanwhile, is lured back to the castle by Dracula, who easily overpowers his mind.

-

While the Monster receives an electrical boost in the lab, Sandra is about to open Wilbur's skull when Talbot storms in and casts her aside. Chick fends off Dracula with a chair, lifting it over his head to swing it at the vampire and inadvertently knocking out Sandra in the process. But just as Talbot is about to untie Wilbur, he once again transforms into the Wolf Man.

-

Dracula returns to the scene, only to have a tug-of-war with the Wolf Man over Wilbur's gurney. Dracula flees, with the Wolf Man giving chase. Chick arrives to untie Wilbur just as the Monster, now fully recovered, breaks his own restraints and rises from his stretcher. Sandra attempts to order him back as Dracula does, but the Monster defiantly tosses her out a window.

-

Dr. Stevens, meanwhile, has managed to find Joan and gets her to the boat. Dracula, in an attempt to escape, transforms into a bat, but the Wolf Man snares him and both fall over a balcony and into the rocky seas below. Joan abruptly wakes from her trance, while the boys escape the castle and head to the pier, with the Monster in pursuit. Once again Chick and Wilbur encounter Mr. MacDougal, who still insists that he wants his exhibits. They loudly reply, "..here comes one of them now!" When the Monster appears, MacDougal and his partner jump off the pier. Chick and Wilbur attempt to escape in a rowboat that is securely tied to the pier. The Monster throws barrels at them, in a series of near misses. Wilbur finally unties the boat, while Stevens and Joan arrive and set the pier ablaze. The Monster turns around and marches into the flames, slowing and succumbing as the pier collapses into the water.

-

Just as Chick and Wilbur relax, they hear a disembodied voice (Vincent Price) and see a cigarette floating in the air: "Allow me to introduce myself, I'm the Invisible Man!" The boys jump off the boat and swim away as the Invisible Man lights his cigarette and laughs. (This scene presaged 1951's Abbott and Costello Meet the Invisible Man, though Price did not star, and all characters were different.

-

-

[edit] Cast

- -

-

[edit] Production

-

The film was originally intended to be titled The Brain of Frankenstein, but its name was changed prior to the filming schedule, which ran from February 5 through March 20, 1948.

-

Walter Lantz, noted for the creation of Woody Woodpecker, provided the animation for Dracula's transformations.

-

In a 1996 documentary, 100 Years of Horror, hosted by Christopher Lee, it was revealed that the studio hired two additional comedians to add laughs between takes on the set.

-

Costello hated the script for Abbott and Costello Meet Frankenstein.[2] He said that his five-year-old daughter could have written something better, but later warmed to the film during production.

-

During the filming of Abbott and Costello Meet Frankenstein, Glenn Strange found Costello so funny he would often break up laughing, necessitating many retakes. There were several pie fights between takes as well, but Abbott and Costello respected the three monsters (Chaney as the Wolfman, Lugosi as Dracula and Strange as the Monster) and made sure no pies were flung at the heavily made-up actors.

-

Boris Karloff was originally approached to play the monster once again, but declined. He did, however, help promote the movie and can be seen in several publicity photos, including one where he is buying a ticket, even though he refused to actually see the film (considering it an insult).

-

The Australian film board required that almost every scene involving a monster should be removed before release.[3]

-

-

[edit] Film mistakes

-

At one point in the film, where Abbott and Costello's characters are going through the revolving panel, Costello calls Abbott by his real name instead of his character's name. In addition, although the film is titled Abbott and Costello Meet Frankenstein, there is no character named Frankenstein in this movie. He is referenced for his work in bringing his creature to life, but the character himself does not appear. In addition, Dracula's reflection can be seen in the mirror when he makes the nurse his next victim. The studio intended to remove the reflection, but failed to do before the theatrical release, and to this day can still be seen in the movie.

-

-

[edit] Cultural references

- - - - - - -
    -
  • In a 2006 episode of Iconoclasts on the Sundance Channel, Quentin Tarantino cited the film as his favorite childhood movie because "when it was supposed to be funny, it was really funny, and when it was supposed to be scary, it was really scary."
  • -
  • The film was unofficially remade in Mexico as Frankenstein, el Vampiro y Compañía (1962) and in Egypt as Haram Alek (1953).[4]
  • -
  • In the Star Trek: Enterprise episode "Horizon", Trip Tucker wanted to show the film.
  • -
  • In an episode of Home Improvement in which Mark is putting together a project for film class, after Tim tells his other sons that film was something he himself appreciated in school, Randy sarcastically quips back that his favorite movie was Abbott and Costello Meet Frankenstein.[citation needed]
  • -
  • In 1954, an Egyptian film studio created Ismil and Abdel Meet Frankenstein, a scene-for-scene remake of the 1948 classic. This version is not commercially available on DVD, but is scheduled for a public film showing at the Mid-Atlantic Nostalgia Convention in September 2008.
  • -
-

-

[edit] Routines

-

The Moving Candle routine previously used in Hold That Ghost was utilized again in this film.

-

-

[edit] DVD releases

- - - - - - -

-

[edit] Notes

-
-
    -
  1. ^ The monster is actually played by two actors. Glenn Strange plays him for most of the film, but when he broke his foot during production, Lon Chaney, Jr. (who previously played the monster in The Ghost of Frankenstein), took over the role for a portion of the laboratory battle sequence.
  2. -
  3. ^ Furmanek, Bob and Ron Palumbo (1991). Abbott and Costello in Hollywood. New York: Perigee Books. ISBN 0-399-51605-0
  4. -
  5. ^ Furmanek, Bob and Ron Palumbo (1991). Abbott and Costello in Hollywood. New York: Perigee Books. ISBN 0-399-51605-0
  6. -
  7. ^ Frankensteinia: The Frankenstein Blog: Frankenstein Gets Knocked-Off
  8. -
-
-

-

[edit] External links

- - - - - - - - - - - - - - - - - - - -
-
- -
-
-
-
-
- - - -
-
Navigation
- -
- - -
-
Languages
-
- -
-
-
-
- -
- - diff --git a/tests/dmd/runnable/funclit.d b/tests/dmd/runnable/funclit.d index 25b4e6e512c..e6e4fec1c54 100644 --- a/tests/dmd/runnable/funclit.d +++ b/tests/dmd/runnable/funclit.d @@ -520,7 +520,6 @@ void test7705() { void foo1(void delegate(ref int ) dg){ int x=10; dg(x); } foo1((ref x){ pragma(msg, typeof(x)); assert(x == 10); }); - static assert(!__traits(compiles, foo1((x){}) )); void foo2(void delegate(int, ...) dg){ dg(20, 3.14); } foo2((x,...){ pragma(msg, typeof(x)); assert(x == 20); }); diff --git a/tests/dmd/runnable/imports/freer.i b/tests/dmd/runnable/imports/freer.i new file mode 100644 index 00000000000..57e8792bd8a --- /dev/null +++ b/tests/dmd/runnable/imports/freer.i @@ -0,0 +1,5 @@ +typedef struct Foo *FooRef; +struct Foo { + int x; +}; +void free_foo(FooRef foo) { } diff --git a/tests/dmd/runnable/imports/maker.i b/tests/dmd/runnable/imports/maker.i new file mode 100644 index 00000000000..d3a7d943834 --- /dev/null +++ b/tests/dmd/runnable/imports/maker.i @@ -0,0 +1,5 @@ +typedef struct Foo *FooRef; +struct Foo { + int x; +}; +FooRef make_foo(void) { return 0; } diff --git a/tests/dmd/runnable/interpret.d b/tests/dmd/runnable/interpret.d index 16d4c5570a4..f9972f235e2 100644 --- a/tests/dmd/runnable/interpret.d +++ b/tests/dmd/runnable/interpret.d @@ -4,6 +4,7 @@ TEST_OUTPUT: true g &Test109S(&Test109S()) +runnable/interpret.d(3742): Deprecation: alias this for classes/interfaces is deprecated tfoo tfoo Crash! diff --git a/tests/dmd/runnable/mixin2.d b/tests/dmd/runnable/mixin2.d index 7679bbe5b34..70bf051a46f 100644 --- a/tests/dmd/runnable/mixin2.d +++ b/tests/dmd/runnable/mixin2.d @@ -82,13 +82,13 @@ int x5; class Foo5 { - this () + this () scope { printf ("Constructor\n"); assert(x5 == 0); x5++; } - ~this () + ~this () scope { printf ("Destructor\n"); assert(x5 == 2); diff --git a/tests/dmd/runnable/test15985.d b/tests/dmd/runnable/test15985.d new file mode 100644 index 00000000000..dbf4f4b9817 --- /dev/null +++ b/tests/dmd/runnable/test15985.d @@ -0,0 +1,18 @@ +/* PERMUTE_ARGS: -allinst + */ + +// https://issues.dlang.org/show_bug.cgi?id=15985 + +void ff()() +{ + gg!()(); + hh!()(); +} + +void gg()() { ff!()(); } +void hh()() { ff!()(); } + +enum x = is(typeof(ff!()())); +alias my_g = gg!(); + +int main() { return 0; } diff --git a/tests/dmd/runnable/test16098.d b/tests/dmd/runnable/test16098.d index 16b34f1894c..a5af2d56448 100644 --- a/tests/dmd/runnable/test16098.d +++ b/tests/dmd/runnable/test16098.d @@ -1,14 +1,73 @@ // https://issues.dlang.org/show_bug.cgi?id=16098 -void main() { +/*********************************************/ + +void testDynamicClosure() +{ byte a; align(128) byte b; assert((cast(size_t) &b) % 128 == 0); + b = 37; byte foo() { return b; } dg = &foo; - assert(dg() == false); + assert(dg() == 37); } __gshared byte delegate() dg; + +/*********************************************/ + +void testStaticClosure() +{ + byte aa; + align(128) byte b; + assert((cast(size_t) &b) % 128 == 0); + b = 73; + + byte foo() { return b; } + assert(foo() == 73); +} + +/*********************************************/ + +void test3() +{ + struct S + { + align(32) int b; + } +} + +/*********************************************/ + +align(16) +struct Cent +{ + ulong lo; // low 64 bits + ulong hi; // high 64 bits +} + +enum Cent One = { 1 }; + +Cent inc(Cent c) { return add(c, One); } + +Cent add(Cent c1, Cent c2) { const Cent ret = { 3, 2 }; return ret; } + +void test4() +{ + const Cent C10_0 = { 0, 10 }; + const Cent Cm10_0 = inc(C10_0); +} + +/*********************************************/ + +int main() +{ + testDynamicClosure(); + testStaticClosure(); + test3(); + test4(); + return 0; +} diff --git a/tests/dmd/runnable/test17684.d b/tests/dmd/runnable/test17684.d index efdce0847ba..e10265558e8 100644 --- a/tests/dmd/runnable/test17684.d +++ b/tests/dmd/runnable/test17684.d @@ -1,3 +1,13 @@ +/* +TEST_OUTPUT: +--- +runnable/test17684.d(37): Deprecation: alias this for classes/interfaces is deprecated +runnable/test17684.d(54): Deprecation: alias this for classes/interfaces is deprecated +runnable/test17684.d(54): Deprecation: alias this for classes/interfaces is deprecated +runnable/test17684.d(37): Deprecation: alias this for classes/interfaces is deprecated +--- +*/ + struct StructField(T) { static T Field; diff --git a/tests/dmd/runnable/test18472.d b/tests/dmd/runnable/test18472.d new file mode 100644 index 00000000000..a571b08cfd2 --- /dev/null +++ b/tests/dmd/runnable/test18472.d @@ -0,0 +1,53 @@ +/* REQUIRED_ARGS: -betterC +*/ + +/*******************************************/ +// https://issues.dlang.org/show_bug.cgi?id=18472 +// https://github.com/dlang/dmd/pull/14676 + +@nogc nothrow pure: +immutable(Char)[] format(Char, Args...)(in Char[] fmt, Args args) +{ + + if (__ctfe) + { + auto data2 = new char[5]; + auto data = new Data2; + { + auto data3 = new Data2; + } + data2 = cast(char[]) "test2"; + return data2; + } + else + { + return "test"; + } +} + +extern(C) void main() +{ + static assert(getData() == "test"); + static assert("%s %s".format("test", "test") == "test2", "Not working"); + assert("%s %s".format("test", "test") == "test", "%s %s".format("test", "test")); + assert(getData() == "test2", getData()); +} + +string getData() +{ + if (__ctfe) + { + auto data2 = new ubyte[5]; + auto data = new Data2; + return "test"; + } + else + { + return "test2"; + } +} + +private struct Data2 +{ + size_t capacity; +} diff --git a/tests/dmd/runnable/test19782.d b/tests/dmd/runnable/test19782.d index a24d84173ec..61a168bf918 100644 --- a/tests/dmd/runnable/test19782.d +++ b/tests/dmd/runnable/test19782.d @@ -1,4 +1,12 @@ // https://issues.dlang.org/show_bug.cgi?id=19782 + +/* +TEST_OUTPUT: +--- +runnable/test19782.d(17): Deprecation: alias this for classes/interfaces is deprecated +--- +*/ + class Inner { int a; diff --git a/tests/dmd/runnable/test19946.d b/tests/dmd/runnable/test19946.d new file mode 100644 index 00000000000..9f9d3bc9824 --- /dev/null +++ b/tests/dmd/runnable/test19946.d @@ -0,0 +1,37 @@ +// https://issues.dlang.org/show_bug.cgi?id=19946 + +import core.stdc.stdio; + +template Tests(TY) +{ + void test1() + { + TY[24] ba; + ba[0..23] = 0x40; + check1(ba[]); + } + + void check1(TY[] ba) + { + foreach (i; 0 .. 23) + { + //printf("ba[%d] = 0x%02x\n", i, ba[i]); + assert(ba[i] == 0x40); + } + assert(ba[23] == 0); + } +} + +int main() +{ + Tests!byte.test1(); + Tests!short.test1(); + Tests!int.test1(); + Tests!long.test1(); + + Tests!ubyte.test1(); + Tests!ushort.test1(); + Tests!uint.test1(); + Tests!ulong.test1(); + return 0; +} diff --git a/tests/dmd/runnable/test20855.d b/tests/dmd/runnable/test20855.d index 30152fe3914..1d2ae50919a 100644 --- a/tests/dmd/runnable/test20855.d +++ b/tests/dmd/runnable/test20855.d @@ -4,7 +4,7 @@ string exp() { string s = "a = b + c * d + a;"; - foreach (i; 0 .. 9) + foreach (i; 0 .. 8) s = s ~ s; return s; } @@ -22,6 +22,6 @@ int main() { int a = test(); printf("a = %d\n", a); - assert(test() == 7169); + assert(test() == 3585); return 0; } diff --git a/tests/dmd/runnable/test21039.d b/tests/dmd/runnable/test21039.d index c58600f8da0..f32267ab59e 100644 --- a/tests/dmd/runnable/test21039.d +++ b/tests/dmd/runnable/test21039.d @@ -1,5 +1,12 @@ // https://issues.dlang.org/show_bug.cgi?id=21039 +/* +TEST_OUTPUT: +--- +runnable/test21039.d(14): Deprecation: alias this for classes/interfaces is deprecated +--- +*/ + class Inner {} class Outer { diff --git a/tests/dmd/runnable/test21772.d b/tests/dmd/runnable/test21772.d new file mode 100644 index 00000000000..dcb7b8088db --- /dev/null +++ b/tests/dmd/runnable/test21772.d @@ -0,0 +1,14 @@ +// https://issues.dlang.org/show_bug.cgi?id=21772 + +import core.stdc.string; + +int main() +{ + //import std.stdio : writeln; + + double[] a = [-double.nan, double.nan, double.nan, + 1.0, double.nan, -double.nan]; + //writeln(a); // Writes "[-nan, -nan, -nan, 1, nan, nan]" (Uh-oh!) + assert(memcmp(&a[0], &a[1], double.sizeof) != 0); + return 0; +} diff --git a/tests/dmd/runnable/test21821.d b/tests/dmd/runnable/test21821.d new file mode 100644 index 00000000000..d16331d1897 --- /dev/null +++ b/tests/dmd/runnable/test21821.d @@ -0,0 +1,32 @@ +// REQUIRED_ARGS: -preview=fieldwise -O +// https://issues.dlang.org/show_bug.cgi?id=21821 + +// test case comes from unittests in core.lifetime + +void test() +{ + alias T = immutable(S); + T source; + T target; + copyEmplacex(source, target); + T expectedCopy = source; + assert(target == expectedCopy); +} + +struct S +{ + int x = 42; + this(this) { x += 10; } +} + +void copyEmplacex(ref immutable(S) source, ref immutable(S) target) @system +{ + import core.stdc.string : memcpy; + memcpy(cast(S*) &target, cast(S*) &source, S.sizeof); + (cast() target).__xpostblit(); // casting away immutable +} + +void main() +{ + test(); +} diff --git a/tests/dmd/runnable/test23.d b/tests/dmd/runnable/test23.d index f1fd4a6c2bc..cb951c17faa 100644 --- a/tests/dmd/runnable/test23.d +++ b/tests/dmd/runnable/test23.d @@ -1322,22 +1322,22 @@ void test70() class C71 { static int cnt; - this() { printf("C()\n"); cnt++; } - ~this() { printf("~C()\n"); cnt--; } + this() scope { printf("C()\n"); cnt++; } + ~this() scope { printf("~C()\n"); cnt--; } } class D71 { static int cnt; - this() { printf("D()\n"); cnt++; } - ~this() { printf("~D()\n"); cnt--; } + this() scope { printf("D()\n"); cnt++; } + ~this() scope { printf("~D()\n"); cnt--; } } class E71 { static int cnt; - this() { printf("E()\n"); cnt++; } - ~this() { printf("~E()\n"); cnt--; } + this() scope { printf("E()\n"); cnt++; } + ~this() scope { printf("~E()\n"); cnt--; } } void test71() diff --git a/tests/dmd/runnable/test23234.d b/tests/dmd/runnable/test23234.d index 7872aa76dfe..f97486404b3 100644 --- a/tests/dmd/runnable/test23234.d +++ b/tests/dmd/runnable/test23234.d @@ -1,5 +1,12 @@ // https://issues.dlang.org/show_bug.cgi?id=23234 +/* +TEST_OUTPUT: +--- +runnable/test23234.d(17): Deprecation: alias this for classes/interfaces is deprecated +--- +*/ + class Bar { } diff --git a/tests/dmd/runnable/test23387.d b/tests/dmd/runnable/test23387.d new file mode 100644 index 00000000000..4419cf1200e --- /dev/null +++ b/tests/dmd/runnable/test23387.d @@ -0,0 +1,30 @@ +/* COMPILE_SEPARATELY: + * EXTRA_SOURCES: imports/maker.i imports/freer.i + */ + +// https://issues.dlang.org/show_bug.cgi?id=23387 + +/+ maker.i +typedef struct Foo *FooRef; +struct Foo { + int x; +}; +FooRef make_foo(void); ++/ +import imports.maker; + + +/+ freer.i +typedef struct Foo *FooRef; +struct Foo { + int x; +}; +void free_foo(FooRef foo); ++/ +import imports.freer; + +int main(){ + FooRef f = make_foo(); + free_foo(f); + return 0; +} diff --git a/tests/dmd/runnable/test23650.d b/tests/dmd/runnable/test23650.d new file mode 100644 index 00000000000..3ce8f5f0759 --- /dev/null +++ b/tests/dmd/runnable/test23650.d @@ -0,0 +1,13 @@ +// https://issues.dlang.org/show_bug.cgi?id=23650 + +__gshared int x; + +void main() +{ + + static assert(__traits(compiles, + { + struct S { int *p = &x; } + auto t = typeid(S); + })); +} diff --git a/tests/dmd/runnable/test23710.d b/tests/dmd/runnable/test23710.d new file mode 100644 index 00000000000..05ab1e43256 --- /dev/null +++ b/tests/dmd/runnable/test23710.d @@ -0,0 +1,30 @@ +// https://issues.dlang.org/show_bug.cgi?id=23710 + +int test(int i) +{ + int j; + int[] foo; + if (0) + { + for (;;) + { + import core.stdc.stdio; + printf("start body\n"); + foo = foo ~ [1,2,3]; +L1: + printf("foo.length = %zu\n", foo.length); + j += foo.length; + i += 2; + if (i > 5) + return j; + printf("end body\n"); + } + } + goto L1; +} + +int main() +{ + assert(test(1) == 0 + 3 + 6); + return 0; +} diff --git a/tests/dmd/runnable/test34.d b/tests/dmd/runnable/test34.d index 11543f1ae85..df461370066 100644 --- a/tests/dmd/runnable/test34.d +++ b/tests/dmd/runnable/test34.d @@ -1,5 +1,3 @@ -// REQUIRED_ARGS: -d - module test34; import core.exception; diff --git a/tests/dmd/runnable/test8.d b/tests/dmd/runnable/test8.d index d65ba0eb7ad..f10076223d5 100644 --- a/tests/dmd/runnable/test8.d +++ b/tests/dmd/runnable/test8.d @@ -786,8 +786,8 @@ void test42() int x44; class A44 { - this() { printf("A44 ctor\n"); x44 += 1; } - ~this() { printf("A44 dtor\n"); x44 += 0x100; } + this() scope { printf("A44 ctor\n"); x44 += 1; } + ~this() scope { printf("A44 dtor\n"); x44 += 0x100; } } class B44 : A44 { } diff --git a/tests/dmd/runnable/test_safe_final_switch.sh b/tests/dmd/runnable/test_safe_final_switch.sh new file mode 100755 index 00000000000..ae0312009d5 --- /dev/null +++ b/tests/dmd/runnable/test_safe_final_switch.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +# tests various @safe behavior for final switches in +# -release and non-release builds + +src_file=runnable/extra-files/test11051.d + +die() +{ + echo "test_safe_final_switch.sh error: test #$1 failed" + exit 1 +} + +# some tests cause a core dump rather than throwing an Error +ulimit -c 0 + +# returns 1 (failure) +$DMD -run ${src_file} 2> /dev/null && die 1 + +# returns 1 (failure) +$DMD -release -run ${src_file} 2> /dev/null && die 2 + +# returns 1 (failure) +$DMD -version=Safe -run ${src_file} 2> /dev/null && die 3 + +# returns 1 (failure) +$DMD -release -version=Safe -run ${src_file} 2> /dev/null && die 4 + +exit 0 diff --git a/tests/dmd/runnable/testaliascast.d b/tests/dmd/runnable/testaliascast.d index c55f8203499..ed5091dff01 100644 --- a/tests/dmd/runnable/testaliascast.d +++ b/tests/dmd/runnable/testaliascast.d @@ -1,5 +1,13 @@ // https://issues.dlang.org/show_bug.cgi?id=11294 +/* +TEST_OUTPUT: +--- +runnable/testaliascast.d(29): Deprecation: alias this for classes/interfaces is deprecated +runnable/testaliascast.d(58): Deprecation: alias this for classes/interfaces is deprecated +--- +*/ + string result; extern(C) void rt_finalize(void *ptr, bool det=true); diff --git a/tests/dmd/runnable/testassign.d b/tests/dmd/runnable/testassign.d index 586aea80cce..79a4c57cf3b 100644 --- a/tests/dmd/runnable/testassign.d +++ b/tests/dmd/runnable/testassign.d @@ -2,6 +2,8 @@ REQUIRED_ARGS: -preview=rvaluerefparam TEST_OUTPUT: --- +runnable/testassign.d(802): Deprecation: alias this for classes/interfaces is deprecated +runnable/testassign.d(808): Deprecation: alias this for classes/interfaces is deprecated \ S1 S2a S2b S3a S3b S4a S4b - true true true true true true true Xa true true true true true true true diff --git a/tests/dmd/runnable/testcheck.c b/tests/dmd/runnable/testcheck.c new file mode 100644 index 00000000000..3fcf0e58414 --- /dev/null +++ b/tests/dmd/runnable/testcheck.c @@ -0,0 +1,7 @@ + +int main() +{ + int i = 3; + __check(i == 3); + return 0; +} diff --git a/tests/dmd/runnable/testdstress.d b/tests/dmd/runnable/testdstress.d index 03af20710f2..269949fb0c0 100644 --- a/tests/dmd/runnable/testdstress.d +++ b/tests/dmd/runnable/testdstress.d @@ -494,7 +494,7 @@ void test23() int status24; class C24{ - this(){ + this() scope { assert(status24==0); status24+=2; } diff --git a/tests/dmd/runnable/traits.d b/tests/dmd/runnable/traits.d index ddd505919d2..5186987deae 100644 --- a/tests/dmd/runnable/traits.d +++ b/tests/dmd/runnable/traits.d @@ -312,14 +312,6 @@ void test9() /********************************************************/ -void test10() -{ - assert(__traits(isVirtualFunction, C.bar) == true); - assert(__traits(isVirtualFunction, S.bar) == false); -} - -/********************************************************/ - void test11() { assert(__traits(isAbstractFunction, C.bar) == false); @@ -403,24 +395,6 @@ class D15 int foo(int) { return 2; } } -void test15() -{ - D15 d = new D15(); - - assert(__traits(getVirtualFunctions, D15, "foo").length == 2); - assert(typeid(typeof(__traits(getVirtualFunctions, D15, "foo")[0])).toString() - == "void function()"); - assert(typeid(typeof(__traits(getVirtualFunctions, D15, "foo")[1])).toString() - == "int function(int)"); - - alias typeof(__traits(getVirtualFunctions, D15, "foo")) b; - assert(typeid(b[0]).toString() == "void function()"); - assert(typeid(b[1]).toString() == "int function(int)"); - - auto i = __traits(getVirtualFunctions, d, "foo")[1](1); - assert(i == 2); -} - /********************************************************/ struct S16 { } @@ -714,14 +688,6 @@ interface AA int YYY(); } -class CC : AA -{ - final int YYY() { return 4; } -} - -static assert(__traits(isVirtualMethod, CC.YYY)); -static assert(__traits(getVirtualMethods, CC, "YYY").length == 1); - class DD { final int YYY() { return 4; } @@ -790,8 +756,6 @@ void test7858() static assert(__traits(isFinalFunction, C.ffunc) == __traits(isFinalFunction, __traits(getOverloads, C, "ffunc")[0])); // NG - static assert(__traits(isVirtualFunction, C.vfunc) == - __traits(isVirtualFunction, __traits(getOverloads, C, "vfunc")[0])); // NG static assert(__traits(isVirtualMethod, C.vfunc) == __traits(isVirtualMethod, __traits(getOverloads, C, "vfunc")[0])); // NG static assert(__traits(isAbstractFunction, C.afunc) == @@ -1456,13 +1420,11 @@ int main() test7(); test8(); test9(); - test10(); test11(); test12(); test13(); test7123(); test14(); - test15(); test16(); test17(); test18(); diff --git a/tests/dmd/runnable/traits_getPointerBitmap.d b/tests/dmd/runnable/traits_getPointerBitmap.d index 8996c9ebb8f..ffa0b803ade 100644 --- a/tests/dmd/runnable/traits_getPointerBitmap.d +++ b/tests/dmd/runnable/traits_getPointerBitmap.d @@ -1,4 +1,3 @@ - module traits_getPointerBitmap; import core.stdc.stdio; @@ -76,19 +75,6 @@ template pOff(T) enum pOff = T.p.offsetof / bytesPerPtr; } -class C(T, aliasTo = void) -{ - static if(!is(aliasTo == void)) - { - aliasTo a; - alias a this; - } - - size_t x; - T t = void; - void* p; -} - /////////////////////////////////////// void _testType(T)(size_t[] expected) @@ -118,21 +104,6 @@ void testType(T)(size_t[] expected) // prepend string sexp[0] = (expected[0] << tOff!(S!(T, string))) | (1 << pOff!(S!(T, string))) | 2; // arr ptr _testType!(S!(T, string))(sexp); - - // generate bit pattern for C!T - C!T ct = null; - size_t mutexBit = (RTInfoMark__Monitor ? 2 : 0); - size_t ctpOff = ct.p.offsetof / bytesPerPtr; - size_t cttOff = ct.t.offsetof / bytesPerPtr; - sexp[0] = (expected[0] << cttOff) | (1 << ctpOff) | mutexBit; - _testType!(C!(T))(sexp); - - C!(T, string) cts = null; - size_t ctspOff = cts.p.offsetof / bytesPerPtr; - size_t ctstOff = cts.t.offsetof / bytesPerPtr; - // generate bit pattern for C!T - sexp[0] = (expected[0] << ctstOff) | (1 << ctspOff) | mutexBit | 0b1000; // arr ptr - _testType!(C!(T, string))(sexp); } /////////////////////////////////////// diff --git a/tests/dmd/runnable/untag.d b/tests/dmd/runnable/untag.d deleted file mode 100644 index 7aaa58cf87d..00000000000 --- a/tests/dmd/runnable/untag.d +++ /dev/null @@ -1,187 +0,0 @@ -// PERMUTE_ARGS: - -import std.algorithm, std.ascii, std.conv, std.exception, - std.file, std.getopt, std.path, std.range, - std.string, std.traits; - -auto binaryFun(string pred, T, U)(T a, U b) -{ - return(mixin(pred)); -} - -/** -If $(D startsWith(r1, r2)), consume the corresponding elements off $(D -r1) and return $(D true). Otherwise, leave $(D r1) unchanged and -return $(D false). -*/ -bool startsWithConsume(alias pred = "a == b", R1, R2)(ref R1 r1, R2 r2) -{ - auto r = r1; // .save(); - while (!r2.empty && !r.empty && binaryFun!pred(r.front, r2.front)) - { - r.popFront(); - r2.popFront(); - } - return r2.empty ? (){ r1 = r; return true;}() : false; -} - - -uint bug = 1; - -int main(string[] args) { - getopt(args, "bug", &bug); - enforce(bug <= 2); - auto txt = readText("runnable/extra-files/untag.html"); - untag(txt, "runnable/extra-files/untag.html"); - return 0; -} - -void untag(string txt, string filename) { - string currentParagraph; - string origtxt = txt; - string origtxtcopy = txt.idup; - - // Find beginning of content - txt = std.algorithm.find(txt, "\n"); - - // Ancillary function that commits the current paragraph for - // writing - void commit() { - writeParagraph(strip(currentParagraph)); - } - - void writeChar(dchar c) { - immutable lastWritten = currentParagraph.length - ? currentParagraph.back - : dchar.init; - if (lastWritten == ' ' && c == ' ') { - // Two consecutive spaces fused - } else { - // Normal case - currentParagraph ~= c; - } - } - - void writeWords(string s) { - if (bug == 0) { - foreach (dchar c; s) { - currentParagraph ~= c; - } - } else if (bug == 1) { - reserve(currentParagraph, currentParagraph.length + s.length); - currentParagraph ~= s; - } else { - currentParagraph = currentParagraph ~ s; - } - } - - // Parse the content - while (!txt.empty) { - size_t i = 0; - while (i < txt.length && txt[i] != '<' && txt[i] != '&') { - ++i; - } - writeWords(txt[0 .. i]); - if (i == txt.length) { - commit(); - return; - } - txt = txt[i .. $]; - auto c = txt[0]; - txt = txt[1 .. $]; - if (c == '<') { // This is a tag - if (startsWithConsume(txt, `/p>`) || - startsWithConsume(txt, `/li>`)) { - // End of paragraph - commit(); - } else { - // This is an uninteresting tag - enforce(findConsume(txt, '>'), - "Could not find closing tag: "~txt); - } - } else { - auto app = appender!string(); - findConsume(txt, ';', app); - switch (app.data) { - case "#160;": case "#32;": case "reg;": case "nbsp;": - writeChar(' '); - break; - case "amp;": - writeChar('&'); - break; - case "gt;": - writeChar('>'); - break; - case "lt;": - writeChar('<'); - break; - case "quot;": - writeChar('"'); - break; - default: - throw new Exception(text("Unknown code: &", app.data)); - break; - } - } - } -} - -void writeParagraph(string sentence) { - static bool isSeparator(dchar a) { - return !(isAlpha(a) /*|| a == '.'*/); - } - - foreach (string cand; std.algorithm.splitter(sentence, ' ')) { - cand = toLower(cand); - } -} - -/** -If $(D r2) can not be found in $(D r1), leave $(D r1) unchanged and -return $(D false). Otherwise, consume elements in $(D r1) until $(D -startsWithConsume(r1, r2)), and return $(D true). Effectively -positions $(D r1) right after $(D r2). - */ -bool findConsume(R1, R2)(ref R1 r1, R2 r2) if (isForwardRange!R2) { - auto r = r1; // .save(); - while (!r.empty) { - if (startsWithConsume(r, r2)) { - r1 = r; - return true; - } - r.popFront(); - } - return false; -} - -/** -If $(D r2) can not be found in $(D r1), leave $(D r1) unchanged and -return $(D false). Otherwise, consume elements in $(D r1) until $(D -startsWith(r1, r2)), and return $(D true). - */ -bool findConsume(R, E)(ref R r, E e) if (is(typeof(r.front == e))) { - auto r1 = std.algorithm.find(r, e); - if (r1.empty) return false; - r = r1; - r.popFront(); - return true; -} - -/** -If $(D r2) can not be found in $(D r1), leave $(D r1) unchanged and -return $(D false). Otherwise, consume elements in $(D r1) until $(D -startsWith(r1, r2)), and return $(D true). - */ -bool findConsume(R1, E, R2)(ref R1 r1, E e, R2 r2) if (is(typeof(r1.front == e))) { - auto r = r1; - while (!r.empty) { - r2.put(r.front); - if (r.front == e) { - r.popFront(); - r1 = r; - return true; - } - r.popFront(); - } - return false; -} diff --git a/tests/dmd/runnable/xtest46.d b/tests/dmd/runnable/xtest46.d index f6a41b6c911..e57f52f6578 100644 --- a/tests/dmd/runnable/xtest46.d +++ b/tests/dmd/runnable/xtest46.d @@ -1,12 +1,15 @@ -// REQUIRED_ARGS: -d -preview=rvaluerefparam +// REQUIRED_ARGS: -preview=rvaluerefparam // /* TEST_OUTPUT: --- +runnable/xtest46.d(165): Deprecation: alias this for classes/interfaces is deprecated Boo!double Boo!int true int !! immutable(int)[] +runnable/xtest46.d(2932): Deprecation: alias this for classes/interfaces is deprecated +runnable/xtest46.d(2964): Deprecation: alias this for classes/interfaces is deprecated int(int i, long j = 7L) long C10390(C10390(C10390())) @@ -19,6 +22,7 @@ string[] double[] double[] {} +runnable/xtest46.d(4670): Deprecation: alias this for classes/interfaces is deprecated tuple("m") true TFunction1: extern (C) void function() @@ -3116,14 +3120,12 @@ template map(fun...) void test139() { - /* LDC: FIXME - https://github.com/ldc-developers/ldc/issues/2361 double[] x; alias typeof(map!"a"(x)) T; T a = void; auto b = map!"a"(x); auto c = [map!"a"(x)]; T[3] d = void; - */ } diff --git a/tests/dmd/runnable/xtest46_gc.d b/tests/dmd/runnable/xtest46_gc.d index b0288a25e08..224625c65ec 100644 --- a/tests/dmd/runnable/xtest46_gc.d +++ b/tests/dmd/runnable/xtest46_gc.d @@ -1,13 +1,16 @@ /* -REQUIRED_ARGS: -d -lowmem -Jrunnable -preview=rvaluerefparam +REQUIRED_ARGS: -lowmem -Jrunnable -preview=rvaluerefparam EXTRA_FILES: xtest46.d TEST_OUTPUT: --- +runnable/xtest46_gc.d-mixin-33(197): Deprecation: alias this for classes/interfaces is deprecated Boo!double Boo!int true int !! immutable(int)[] +runnable/xtest46_gc.d-mixin-33(2964): Deprecation: alias this for classes/interfaces is deprecated +runnable/xtest46_gc.d-mixin-33(2996): Deprecation: alias this for classes/interfaces is deprecated int(int i, long j = 7L) long C10390(C10390()) @@ -20,6 +23,7 @@ string[] double[] double[] {} +runnable/xtest46_gc.d-mixin-33(4702): Deprecation: alias this for classes/interfaces is deprecated tuple("m") true TFunction1: extern (C) void function() diff --git a/tests/dmd/runnable_cxx/cpp_abi_tests.d b/tests/dmd/runnable_cxx/cpp_abi_tests.d index c677d6e0be8..c0f4e6dd780 100644 --- a/tests/dmd/runnable_cxx/cpp_abi_tests.d +++ b/tests/dmd/runnable_cxx/cpp_abi_tests.d @@ -207,6 +207,8 @@ extern(C++, `ns1`) extern(C++) { + // https://issues.dlang.org/show_bug.cgi?id=19563 + struct SmallStruct { int i; @@ -220,6 +222,50 @@ extern(C++) } } +/*********************************************/ +// https://issues.dlang.org/show_bug.cgi?id=23195 + +extern (C++) +{ + struct FF + { + float x, y; + + ~this() { } + } + + float draw(FF min, FF max); + + void test23195() + { + FF a = { 1, 2 }; + FF b = { 3, 4 }; + float f = draw(a, b); + assert(f == 1234); + } + + /*********************/ + + struct FF2 + { + float x, y; + + this(int i) { } + } + + float draw2(FF2 min, FF2 max); + + void test23195_2() + { + FF2 a; a.x = 1; a.y = 2; + FF2 b; b.x = 3; b.y = 4; + float f = draw2(a, b); + assert(f == 1234); + } +} + +/*********************************************/ + void main() { foreach(bool val; values!bool()) check(val); @@ -268,4 +314,6 @@ else doConsume2(sd); assert(Sdtor.counter == 2); } + test23195(); + test23195_2(); } diff --git a/tests/dmd/runnable_cxx/cppa.d b/tests/dmd/runnable_cxx/cppa.d index ae030b16128..a040939cedb 100644 --- a/tests/dmd/runnable_cxx/cppa.d +++ b/tests/dmd/runnable_cxx/cppa.d @@ -5,8 +5,6 @@ // CXXFLAGS(linux freebsd osx netbsd dragonflybsd): -std=c++11 // druntime isn't linked, this prevents missing symbols '_d_arraybounds_slicep': // REQUIRED_ARGS: -checkaction=C -// Filter a spurious warning on Semaphore: -// TRANSFORM_OUTPUT: remove_lines("warning: relocation refers to discarded section") // N.B MSVC doesn't have a C++11 switch, but it defaults to the latest fully-supported standard @@ -444,57 +442,10 @@ void test13161() /****************************************/ -version (linux) -{ - static if (__traits(getTargetInfo, "cppStd") < 201703) - { - // See note on std::allocator below. - extern(C++, __gnu_cxx) - { - struct new_allocator(T) - { - alias size_type = size_t; - static if (is(T : char)) - void deallocate(T*, size_type) { } - else - void deallocate(T*, size_type); - } - } - } -} - extern (C++, std) { - version (linux) - { - static if (__traits(getTargetInfo, "cppStd") >= 201703) - { - // std::allocator no longer derives from __gnu_cxx::new_allocator, - // it derives from std::__new_allocator instead. - struct __new_allocator(T) - { - alias size_type = size_t; - static if (is(T : char)) - void deallocate(T*, size_type) { } - else - void deallocate(T*, size_type); - } - } - } - extern (C++, class) struct allocator(T) { - version (linux) - { - alias size_type = size_t; - void deallocate(T* p, size_type sz) - { - static if (__traits(getTargetInfo, "cppStd") >= 201703) - (cast(std.__new_allocator!T*)&this).deallocate(p, sz); - else - (cast(__gnu_cxx.new_allocator!T*)&this).deallocate(p, sz); - } - } } class vector(T, A = allocator!T) @@ -586,11 +537,6 @@ void test14() version (linux) { - void test14a(std.allocator!int * pa) - { - pa.deallocate(null, 0); - } - void gun(std.vector!int pa) { int x = 42; @@ -1132,83 +1078,99 @@ void test15576() /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=15579 -extern (C++) +version (DigitalMars) { - class Base + version (linux) { - //~this() {} - void based() { } - ubyte x = 4; + // Test removed for DMD/linux-only. + // https://issues.dlang.org/show_bug.cgi?id=23660 } + else + version = TEST15579; +} +else + version = TEST15579; - interface Interface +version (TEST15579) +{ + extern (C++) { - int MethodCPP(); - int MethodD(); - } + class Base + { + //~this() {} + void based() { } + ubyte x = 4; + } - class Derived : Base, Interface - { - short y = 5; - int MethodCPP(); - int MethodD() { - printf("Derived.MethodD(): this = %p, x = %d, y = %d\n", this, x, y); - Derived p = this; - //p = cast(Derived)(cast(void*)p - 16); - assert(p.x == 4 || p.x == 7); - assert(p.y == 5 || p.y == 8); - return 3; + interface Interface + { + int MethodCPP(); + int MethodD(); } - int Method() { return 6; } + + class Derived : Base, Interface + { + short y = 5; + int MethodCPP(); + int MethodD() { + printf("Derived.MethodD(): this = %p, x = %d, y = %d\n", this, x, y); + Derived p = this; + //p = cast(Derived)(cast(void*)p - 16); + assert(p.x == 4 || p.x == 7); + assert(p.y == 5 || p.y == 8); + return 3; + } + int Method() { return 6; } + } + + Derived cppfoo(Derived); + Interface cppfooi(Interface); } - Derived cppfoo(Derived); - Interface cppfooi(Interface); -} - -void test15579() -{ - Derived d = new Derived(); - printf("d = %p\n", d); - assert(d.x == 4); - assert(d.y == 5); - assert((cast(Interface)d).MethodCPP() == 30); - assert((cast(Interface)d).MethodD() == 3); - assert(d.MethodCPP() == 30); - assert(d.MethodD() == 3); - assert(d.Method() == 6); - - d = cppfoo(d); - assert(d.x == 7); - assert(d.y == 8); - - printf("d2 = %p\n", d); - - /* Casting to an interface involves thunks in the vtbl[]. - * g++ puts the thunks for MethodD in the same COMDAT as MethodD. - * But D doesn't, so when the linker "picks one" of the D generated MethodD - * or the g++ generated MethodD, it may wind up with a messed up thunk, - * resulting in a seg fault. The solution is to not expect objects of the same - * type to be constructed on both sides of the D/C++ divide if the same member - * function (in this case, MethodD) is also defined on both sides. - */ - version (Windows) + void test15579() { + Derived d = new Derived(); + printf("d = %p\n", d); + assert(d.x == 4); + assert(d.y == 5); + assert((cast(Interface)d).MethodCPP() == 30); assert((cast(Interface)d).MethodD() == 3); - } - assert((cast(Interface)d).MethodCPP() == 30); + assert(d.MethodCPP() == 30); + assert(d.MethodD() == 3); + assert(d.Method() == 6); + + d = cppfoo(d); + assert(d.x == 7); + assert(d.y == 8); + + printf("d2 = %p\n", d); + + /* Casting to an interface involves thunks in the vtbl[]. + * g++ puts the thunks for MethodD in the same COMDAT as MethodD. + * But D doesn't, so when the linker "picks one" of the D generated MethodD + * or the g++ generated MethodD, it may wind up with a messed up thunk, + * resulting in a seg fault. The solution is to not expect objects of the same + * type to be constructed on both sides of the D/C++ divide if the same member + * function (in this case, MethodD) is also defined on both sides. + */ + version (Windows) + { + assert((cast(Interface)d).MethodD() == 3); + } + assert((cast(Interface)d).MethodCPP() == 30); - assert(d.Method() == 6); + assert(d.Method() == 6); - printf("d = %p, i = %p\n", d, cast(Interface)d); - version (Windows) - { - Interface i = cppfooi(d); - printf("i2: %p\n", i); - assert(i.MethodD() == 3); - assert(i.MethodCPP() == 30); + printf("d = %p, i = %p\n", d, cast(Interface)d); + version (Windows) + { + Interface i = cppfooi(d); + printf("i2: %p\n", i); + assert(i.MethodD() == 3); + assert(i.MethodCPP() == 30); + } + printf("test15579() done\n"); } - printf("test15579() done\n"); } /****************************************/ @@ -1379,7 +1341,7 @@ extern(C++) class Cpp15589Derived : Cpp15589Base { public: - this(); + this() scope; final ~this(); int b; } @@ -1389,7 +1351,7 @@ extern(C++) public: void beforeDtor(); - this(); + this() scope; ~this(); void afterDtor(); @@ -1399,7 +1361,7 @@ extern(C++) class Cpp15589DerivedVirtual : Cpp15589BaseVirtual { public: - this(); + this() scope; ~this(); override void afterDtor(); @@ -1410,7 +1372,7 @@ extern(C++) class Cpp15589IntroducingVirtual : Cpp15589Base { public: - this(); + this() scope; void beforeIntroducedVirtual(); ~this(); void afterIntroducedVirtual(int); @@ -1710,7 +1672,7 @@ void main() testeh2(); testeh3(); test15576(); - test15579(); + version (TEST15579) test15579(); test15610(); test15455(); test15372(); diff --git a/tests/dmd/runnable_cxx/extra-files/cpp_abi_tests.cpp b/tests/dmd/runnable_cxx/extra-files/cpp_abi_tests.cpp index 8ba613920a4..e1dcc28b8b1 100644 --- a/tests/dmd/runnable_cxx/extra-files/cpp_abi_tests.cpp +++ b/tests/dmd/runnable_cxx/extra-files/cpp_abi_tests.cpp @@ -161,3 +161,29 @@ void doConsume2(Sdtor& value) // fn0 passthrough_fn0 (fn0 value) { return value; } // typedef int (*fn1)(int); // fn1 passthrough_fn1 (fn1 value) { return value; } + +/******************************/ + +struct FF +{ + float x, y; + ~FF(); +}; + +float draw(FF min, FF max) +{ + return min.x * 1000 + min.y * 100 + max.x * 10 + max.y; +} + +/******************************/ + +struct FF2 +{ + float x, y; + FF2(int i) { } +}; + +float draw2(FF2 min, FF2 max) +{ + return min.x * 1000 + min.y * 100 + max.x * 10 + max.y; +} diff --git a/tests/dmd/tools/d_do_test.d b/tests/dmd/tools/d_do_test.d index 6517350dea3..04ac9eae59f 100755 --- a/tests/dmd/tools/d_do_test.d +++ b/tests/dmd/tools/d_do_test.d @@ -1815,7 +1815,7 @@ int tryMain(string[] args) { foreach (filename; testArgs.sources ~ (autoCompileImports ? null : testArgs.compiledImports)) { - string newo = output_dir ~ envData.sep ~ replace(filename.baseName(), ".d", envData.obj); + string newo = output_dir ~ envData.sep ~ filename.baseName().setExtension(envData.obj); toCleanup ~= newo; command = format("%s -conf= -m%s -I%s %s %s -od%s -c %s %s", envData.dmd, envData.model, input_dir, diff --git a/tests/dmd/unit/frontend.d b/tests/dmd/unit/frontend.d index fd3556d6327..59275132709 100644 --- a/tests/dmd/unit/frontend.d +++ b/tests/dmd/unit/frontend.d @@ -56,7 +56,7 @@ unittest initDMD(); defaultImportPaths.each!addImport; - auto t = parseModule!AST("test.d", q{ + auto t = parseModule!AST("frontendcustomASTfamily.d", q{ interface Foo {} }); @@ -174,7 +174,7 @@ unittest initDMD(); defaultImportPaths.each!addImport; - auto t = parseModule("test.d", q{ + auto t = parseModule("frontendcontractchecking.d", q{ int foo(int a) in(a == 3) out(result; result == 0) @@ -219,7 +219,7 @@ unittest initDMD(null, null, ["Foo"]); defaultImportPaths.each!addImport; - auto t = parseModule("test.d", q{ + auto t = parseModule("frontendversionidentifiers.d", q{ version (Foo) enum a = 1; else @@ -263,7 +263,7 @@ unittest initDMD(&diagnosticHandler); defaultImportPaths.each!addImport; - parseModule("test.d", q{ + parseModule("frontendcustomdiagnostichandling.d", q{ void foo(){ auto temp == 7.8; foreach(i; 0..5){ @@ -287,7 +287,7 @@ unittest defaultImportPaths.each!addImport; addStringImport(__FILE_FULL_PATH__.dirName.buildPath("support", "data")); - auto t = parseModule("test.d", q{ + auto t = parseModule("frontendaddStringImport.d", q{ enum a = import("foo.txt"); }); @@ -310,7 +310,7 @@ unittest initDMD(); defaultImportPaths.each!addImport; - auto t = parseModule("test.d", q{ + auto t = parseModule("frontendfloatingpoint.d", q{ static assert((2.0i).re == 0); }); @@ -333,7 +333,7 @@ unittest initDMD(); defaultImportPaths.each!addImport; - auto t = parseModule("test.d", q{ + auto t = parseModule("frontendinlineassembly.d", q{ void foo() { asm @@ -380,7 +380,7 @@ unittest initDMD(&diagnosticHandler); defaultImportPaths.each!addImport; - auto t = parseModule("test.dd", q{Ddoc}); + auto t = parseModule("frontendddoc.dd", q{Ddoc}); assert(!t.diagnostics.hasErrors); assert(!t.diagnostics.hasWarnings); diff --git a/tests/dmd/unit/lexer/diagnostic_reporter.d b/tests/dmd/unit/lexer/diagnostic_reporter.d index 314c7a80f34..e707e99bb76 100644 --- a/tests/dmd/unit/lexer/diagnostic_reporter.d +++ b/tests/dmd/unit/lexer/diagnostic_reporter.d @@ -6,6 +6,7 @@ import core.stdc.stdarg; import dmd.globals : global, DiagnosticReporting; import dmd.location; +import dmd.errors; import support : afterEach, NoopDiagnosticReporter; @@ -35,33 +36,14 @@ unittest assert(reporter.errorCount == 1); } -@("warnings: C preprocessor directive") -unittest -{ - static final class WarningCountingDiagnosticReporter : NoopDiagnosticReporter - { - int warningCount; - - override bool warning(const ref Loc, const(char)*, va_list, const(char)*, const(char)*) - { - warningCount++; - return true; - } - } - - global.params.warnings = DiagnosticReporting.inform; - scope reporter = new WarningCountingDiagnosticReporter; - lexUntilEndOfFile(`#foo`); - - assert(reporter.warningCount == 1); -} - private void lexUntilEndOfFile(string code) { import dmd.lexer : Lexer; import dmd.tokens : TOK; - scope lexer = new Lexer("test", code.ptr, 0, code.length, 0, 0); + if (!global.errorSink) + global.errorSink = new ErrorSinkCompiler; + scope lexer = new Lexer("test", code.ptr, 0, code.length, 0, 0, global.errorSink); lexer.nextToken; while (lexer.nextToken != TOK.endOfFile) {} diff --git a/tests/dmd/unit/lexer/lexer_dmdlib.d b/tests/dmd/unit/lexer/lexer_dmdlib.d index 589abce0e45..4b53bafc9ac 100644 --- a/tests/dmd/unit/lexer/lexer_dmdlib.d +++ b/tests/dmd/unit/lexer/lexer_dmdlib.d @@ -2,6 +2,19 @@ module lexer.lexer_dmdlib; import dmd.lexer : Lexer; import dmd.tokens : TOK; +import dmd.errorsink; + +/// Test that lexing `code` generates the `expected` tokens +private void test(string code, const TOK[] expected, bool keepComments = false, bool keepWhitespace = false) +{ + Lexer lexer = new Lexer(null, code.ptr, 0, code.length, /*doDocComment*/ false, keepComments, keepWhitespace, new ErrorSinkStderr); + TOK[] result; + + while (lexer.nextToken != TOK.endOfFile) + result ~= lexer.token.value; + + assert(result == expected); +} unittest { @@ -16,13 +29,7 @@ unittest TOK.rightCurly, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, false, false); - TOK[] result; - - while (lexer.nextToken != TOK.endOfFile) - result ~= lexer.token.value; - - assert(result == expected); + test(code, expected, false, false); } unittest @@ -39,13 +46,7 @@ unittest TOK.comment, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, false); - TOK[] result; - - while (lexer.nextToken != TOK.endOfFile) - result ~= lexer.token.value; - - assert(result == expected); + test(code, expected, true, false); } unittest @@ -65,13 +66,7 @@ unittest TOK.comment, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, true); - TOK[] result; - - while (lexer.nextToken != TOK.endOfFile) - result ~= lexer.token.value; - - assert(result == expected); + test(code, expected, true, true); } unittest @@ -92,13 +87,7 @@ unittest TOK.whitespace, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, true); - TOK[] result; - - while (lexer.nextToken != TOK.endOfFile) - result ~= lexer.token.value; - - assert(result == expected); + test(code, expected, true, true); } unittest @@ -136,13 +125,7 @@ unittest TOK.whitespace, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, true); - TOK[] result; - - while (lexer.nextToken != TOK.endOfFile) - result ~= lexer.token.value; - - assert(result == expected); + test(code, expected, true, true); } unittest @@ -171,13 +154,7 @@ unittest TOK.whitespace, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, true); - TOK[] result; - - while (lexer.nextToken != TOK.endOfFile) - result ~= lexer.token.value; - - assert(result == expected); + test(code, expected, true, true); } unittest @@ -193,7 +170,7 @@ unittest TOK.rightCurly, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, false); + Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, false, new ErrorSinkStderr); lexer.nextToken; TOK[] result; @@ -214,7 +191,7 @@ unittest TOK.comment, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true); + Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, true, new ErrorSinkStderr); lexer.nextToken; TOK[] result; @@ -240,7 +217,7 @@ unittest TOK.reserved, ]; - Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, false); + Lexer lexer = new Lexer(null, code.ptr, 0, code.length, false, false, new ErrorSinkStderr); TOK[] result; @@ -265,6 +242,7 @@ unittest import dmd.location; import dmd.common.outbuffer; import dmd.console : Color; + import dmd.errors; const(char)[][2][] diagnosticMessages; nothrow bool diagnosticHandler(const ref Loc loc, Color headerColor, const(char)* header, @@ -288,7 +266,7 @@ unittest foreach (codeNum, code; codes) { auto fileName = text("file", codeNum, '\0'); - Lexer lexer = new Lexer(fileName.ptr, code.ptr, 0, code.length, false, false); + Lexer lexer = new Lexer(fileName.ptr, code.ptr, 0, code.length, false, false, new ErrorSinkCompiler); // Generate the errors foreach(unused; lexer){} } diff --git a/tests/dmd/unit/lexer/location_offset.d b/tests/dmd/unit/lexer/location_offset.d index 9eaa7eb38eb..c52de839dbe 100644 --- a/tests/dmd/unit/lexer/location_offset.d +++ b/tests/dmd/unit/lexer/location_offset.d @@ -2,6 +2,7 @@ module lexer.location_offset; import dmd.lexer : Lexer; import dmd.tokens : TOK; +import dmd.errorsink; import support : afterEach; @@ -16,7 +17,7 @@ unittest { enum code = "token"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; @@ -28,7 +29,7 @@ unittest { enum code = "ignored_token token"; - scope lexer = new Lexer("test.d", code.ptr, 13, code.length - 14, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 13, code.length - 14, 0, 0, new ErrorSinkStderr); lexer.nextToken; @@ -40,7 +41,7 @@ unittest { enum code = "token1 token2 3"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken; @@ -54,7 +55,7 @@ unittest { enum code = "token"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken; @@ -67,7 +68,7 @@ unittest { enum code = "/* comment */"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, true); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, true, new ErrorSinkStderr); lexer.nextToken; @@ -80,7 +81,7 @@ unittest { enum code = "// comment"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, true); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, true, new ErrorSinkStderr); lexer.nextToken; @@ -93,7 +94,7 @@ unittest { enum code = "/+ comment +/"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, true); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, true, new ErrorSinkStderr); lexer.nextToken; @@ -106,7 +107,7 @@ unittest { enum code = "/* comment */ token"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; @@ -118,7 +119,7 @@ unittest { enum code = "// comment\ntoken"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; @@ -130,7 +131,7 @@ unittest { enum code = "/+ comment +/ token"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; @@ -142,7 +143,7 @@ unittest { enum code = "line\ntoken"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken; @@ -155,7 +156,7 @@ unittest { enum code = "line\r\ntoken"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken; @@ -168,7 +169,7 @@ unittest { enum code = "line\rtoken"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken; @@ -181,7 +182,7 @@ unittest { enum code = "'🍺'"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; @@ -193,7 +194,7 @@ unittest { enum code = `"🍺🍺"`; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; @@ -205,7 +206,7 @@ unittest { enum code = "'🍺' token"; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken; @@ -218,7 +219,7 @@ unittest { enum code = `"🍺🍺" token`; - scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0); + scope lexer = new Lexer("test.d", code.ptr, 0, code.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken; @@ -536,11 +537,13 @@ enum ignoreTokens _Static_assert, _Thread_local, + _assert, _import, __cdecl, __declspec, __stdcall, __pragma, + __int128, __attribute__, max_, @@ -555,7 +558,7 @@ static foreach (tok; __traits(allMembers, TOK)) { const newCode = "first_token " ~ tests[tok].code; - scope lexer = new Lexer("test.d", newCode.ptr, 0, newCode.length, 0, 0); + scope lexer = new Lexer("test.d", newCode.ptr, 0, newCode.length, 0, 0, new ErrorSinkStderr); lexer.nextToken; lexer.nextToken;