diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2023-03-05 01:47:19 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2023-03-16 17:29:57 +0100 |
commit | 8da8c7d337123b28fdeb539a283d00732118712e (patch) | |
tree | 74096a23b9e2f64a7e25ec1e8d4d3b1d8934842e /gcc | |
parent | c5e2c3dd6afcf9b152df72b30e205b0180c0afd5 (diff) | |
download | gcc-8da8c7d337123b28fdeb539a283d00732118712e.zip gcc-8da8c7d337123b28fdeb539a283d00732118712e.tar.gz gcc-8da8c7d337123b28fdeb539a283d00732118712e.tar.bz2 |
d: Merge upstream dmd, druntime 4ca4140e58, phobos 454dff14d.
D front-end changes:
- Import dmd v2.103.0-beta.1.
- Using `alias this' for classes has been deprecated.
- The feature `-fpreview=dip25` is now enabled by default.
- The compile-time traits `isVirtualFunction' and
`getVirtualFunctions' have been deprecated.
D runtime changes:
- Import druntime v2.103.0-beta.1.
Phobos changes:
- Import phobos v2.103.0-beta.1.
- Updated unicode grapheme walking updated to conform to Unicode
version 15.
- Improved friendliness of error messages when instantiating
`std.algorithm.iteration.joiner' and
`std.algorithm.sorting.sort' with wrong inputs.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd 4ca4140e58.
* dmd/VERSION: Bump version to v2.103.0-beta.1.
* Make-lang.in (D_FRONTEND_OBJS): Add d/errorsink.o.
* d-ctfloat.cc (CTFloat::sprint): Update signature for new front-end
interface.
* d-frontend.cc (getTypeInfoType): Likewise.
* d-lang.cc (d_handle_option): Remove handling of -fpreview=dip25 and
-frevert=dip25.
(d_post_options): Remove enabling of sealed references language
feature when scoped pointers is enabled.
* d-tree.h (create_typeinfo): Update signature.
* decl.cc (DeclVisitor::finish_vtable): Update for new front-end
interface.
(DeclVisitor::visit (VarDeclaration *)): Likewise.
(DeclVisitor::visit (FuncDeclaration *)): Check skipCodegen to see if
front-end explicitly requested not to generate code.
* expr.cc (ExprVisitor::visit (NewExp *)): Update for new front-end
interface.
* lang.opt (fpreview=dip25): Remove.
(frevert=dip25): Remove.
* modules.cc (layout_moduleinfo_fields): Update for new front-end
interface.
(layout_moduleinfo): Likewise.
* runtime.def (NEWCLASS): Remove.
* toir.cc (IRVisitor::visit (IfStatement *)): Don't generate IR for if
statement list when condition is `__ctfe'.
* typeinfo.cc (create_typeinfo): Add generate parameter.
* types.cc (layout_aggregate_members): Update for new front-end
interface.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime 4ca4140e58.
* libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add core/factory.d.
* libdruntime/Makefile.in: Regenerate.
* src/MERGE: Merge upstream phobos 454dff14d.
* testsuite/libphobos.hash/test_hash.d: Update test.
* testsuite/libphobos.shared/finalize.d: Update test.
* libdruntime/core/factory.d: New file.
gcc/testsuite/ChangeLog:
* gdc.dg/torture/simd23084.d: New test.
* gdc.dg/torture/simd23085.d: New test.
* gdc.dg/torture/simd23218.d: New test.
Diffstat (limited to 'gcc')
248 files changed, 4653 insertions, 1988 deletions
diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in index 4feebac..1679fb8 100644 --- a/gcc/d/Make-lang.in +++ b/gcc/d/Make-lang.in @@ -124,6 +124,7 @@ D_FRONTEND_OBJS = \ d/dversion.o \ d/entity.o \ d/errors.o \ + d/errorsink.o \ d/escape.o \ d/expression.o \ d/expressionsem.o \ diff --git a/gcc/d/d-ctfloat.cc b/gcc/d/d-ctfloat.cc index a85a413..15d02b6 100644 --- a/gcc/d/d-ctfloat.cc +++ b/gcc/d/d-ctfloat.cc @@ -96,16 +96,16 @@ CTFloat::parse (const char *buffer, bool &overflow) return r; } -/* Format the real_t value R to string BUFFER as a decimal or hexadecimal, - converting the result to uppercase if FMT requests it. */ +/* Format the real_t value R to string BUFFER, bounded by BUF_SIZE, as a decimal + or hexadecimal, converting the result to uppercase if FMT requests it. */ int -CTFloat::sprint (char *buffer, char fmt, real_t r) +CTFloat::sprint (char *buffer, d_size_t buf_size, char fmt, real_t r) { if (fmt == 'a' || fmt == 'A') { /* Converting to a hexadecimal string. */ - real_to_hexadecimal (buffer, &r.rv (), 32, 0, 1); + real_to_hexadecimal (buffer, &r.rv (), buf_size, 0, 1); int buflen; switch (fmt) diff --git a/gcc/d/d-frontend.cc b/gcc/d/d-frontend.cc index f5e0496..cf20095 100644 --- a/gcc/d/d-frontend.cc +++ b/gcc/d/d-frontend.cc @@ -79,11 +79,11 @@ eval_builtin (const Loc &loc, FuncDeclaration *fd, Expressions *arguments) /* Build and return typeinfo type for TYPE. */ Type * -getTypeInfoType (const Loc &loc, Type *type, Scope *sc) +getTypeInfoType (const Loc &loc, Type *type, Scope *sc, bool genObjCode) { gcc_assert (type->ty != TY::Terror); check_typeinfo_type (loc, sc); - create_typeinfo (type, sc ? sc->_module->importedFrom : NULL); + create_typeinfo (type, sc ? sc->_module->importedFrom : NULL, genObjCode); return type->vtinfo->type; } diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 449c692..235e22a 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -558,7 +558,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, case OPT_fpreview_all: global.params.ehnogc = value; - global.params.useDIP25 = FeatureState::enabled; global.params.useDIP1000 = FeatureState::enabled; global.params.useDIP1021 = value; global.params.bitfields = value; @@ -590,10 +589,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.useDIP1021 = value; break; - case OPT_fpreview_dip25: - global.params.useDIP25 = FeatureState::enabled; - break; - case OPT_fpreview_dtorfields: global.params.dtorFields = FeatureState::enabled; break; @@ -636,7 +631,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, case OPT_frevert_all: global.params.useDIP1000 = FeatureState::disabled; - global.params.useDIP25 = FeatureState::disabled; global.params.dtorFields = FeatureState::disabled; global.params.fix16997 = !value; break; @@ -645,10 +639,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value, global.params.useDIP1000 = FeatureState::disabled; break; - case OPT_frevert_dip25: - global.params.useDIP25 = FeatureState::disabled; - break; - case OPT_frevert_dtorfields: global.params.dtorFields = FeatureState::disabled; break; @@ -911,10 +901,6 @@ d_post_options (const char ** fn) if (global.params.useDIP1021) global.params.useDIP1000 = FeatureState::enabled; - /* Enabling DIP1000 implies DIP25. */ - if (global.params.useDIP1000 == FeatureState::enabled) - global.params.useDIP25 = FeatureState::enabled; - /* Keep in sync with existing -fbounds-check flag. */ flag_bounds_check = (global.params.useArrayBounds == CHECKENABLEon); diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h index c9f5aaa..b64a6fb 100644 --- a/gcc/d/d-tree.h +++ b/gcc/d/d-tree.h @@ -689,7 +689,7 @@ extern tree get_classinfo_decl (ClassDeclaration *); extern void check_typeinfo_type (const Loc &, Scope *, Expression * = NULL); extern tree build_typeinfo (const Loc &, Type *, Expression * = NULL); extern tree build_typeinfo (Expression *, Type *); -extern void create_typeinfo (Type *, Module *); +extern void create_typeinfo (Type *, Module *, bool = true); extern void create_tinfo_types (Module *); extern void layout_cpp_typeinfo (ClassDeclaration *); extern tree get_cpp_typeinfo_decl (ClassDeclaration *); diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc index 4fbabd5..78c4ab5 100644 --- a/gcc/d/decl.cc +++ b/gcc/d/decl.cc @@ -563,8 +563,8 @@ public: if (fd2->isFuture ()) continue; - if (fd->leastAsSpecialized (fd2) != MATCH::nomatch - || fd2->leastAsSpecialized (fd) != MATCH::nomatch) + if (fd->leastAsSpecialized (fd2, NULL) != MATCH::nomatch + || fd2->leastAsSpecialized (fd, NULL) != MATCH::nomatch) { error_at (make_location_t (fd->loc), "use of %qs", fd->toPrettyChars ()); @@ -772,7 +772,7 @@ public: return; } - if (d->aliassym) + if (d->aliasTuple) { this->build_dsymbol (d->toAlias ()); return; @@ -821,7 +821,7 @@ public: DECL_INITIAL (decl) = build_expr (e, true); } } - else + else if (!d->type->isZeroInit ()) { /* Use default initializer for the type. */ if (TypeStruct *ts = d->type->isTypeStruct ()) @@ -903,6 +903,10 @@ public: if (gcc_attribute_p (d)) return; + /* Front-end decided this function doesn't require code generation. */ + if (d->skipCodegen ()) + return; + /* Not emitting unittest functions. */ if (!global.params.useUnitTests && d->isUnitTestDeclaration ()) return; diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index ac3dd12..269eebf 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -09faa4eacd4fb147107e94eeebf56b3a73fdcc05 +4ca4140e584c055a8a9bc727e56a97ebcecd61e0 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/README.md b/gcc/d/dmd/README.md index 43eb187..cecd008 100644 --- a/gcc/d/dmd/README.md +++ b/gcc/d/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/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index 177c41d..8b24f92 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.102.0-beta.1 +v2.103.0-beta.1 diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h index 9f9098f..04e5eb2 100644 --- a/gcc/d/dmd/aggregate.h +++ b/gcc/d/dmd/aggregate.h @@ -304,7 +304,6 @@ public: 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/gcc/d/dmd/apply.d b/gcc/d/dmd/apply.d index f5855c4..59ba9f5 100644 --- a/gcc/d/dmd/apply.d +++ b/gcc/d/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/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d index da2f800..908855e 100644 --- a/gcc/d/dmd/arrayop.d +++ b/gcc/d/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/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index 712099e..dbe78ef 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/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; } @@ -1080,6 +1075,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/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h index 96c46e8..44ceb12 100644 --- a/gcc/d/dmd/attrib.h +++ b/gcc/d/dmd/attrib.h @@ -36,8 +36,7 @@ public: 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 @@ public: 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/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d index 6369b5a..bd5b78e 100644 --- a/gcc/d/dmd/blockexit.d +++ b/gcc/d/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/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d index 7c18040..0c237e6 100644 --- a/gcc/d/dmd/canthrow.d +++ b/gcc/d/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/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d index ef5464d..19bf83e 100644 --- a/gcc/d/dmd/clone.d +++ b/gcc/d/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/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d index 276928a..007d301 100644 --- a/gcc/d/dmd/common/outbuffer.d +++ b/gcc/d/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/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 79bbd5d..e4be63c 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -845,20 +845,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/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index a6bc42b..a18f810 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/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; @@ -69,9 +70,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; @@ -268,11 +270,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 @@ -286,6 +289,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: @@ -752,7 +756,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; } @@ -781,6 +785,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 @@ -1640,6 +1652,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) @@ -1664,22 +1693,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; } @@ -1823,17 +1842,10 @@ final class CParser(AST) : Parser!AST { if (tt.id || tt.tok == TOK.enum_) { - /* `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); + if (!tt.id && id) + tt.id = id; + Specifier spec; + auto stag = declareTag(tt, spec); if (tt.tok == TOK.enum_) { isalias = false; @@ -1847,6 +1859,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 @@ -1929,7 +1950,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; @@ -1995,7 +2016,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[] */ @@ -2183,6 +2204,7 @@ final class CParser(AST) : Parser!AST ximaginary = 0x8000, xcomplex = 0x10000, x_Atomic = 0x20000, + xint128 = 0x40000, } AST.Type t; @@ -2227,6 +2249,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; @@ -2505,6 +2528,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; @@ -2991,11 +3019,11 @@ final class CParser(AST) : Parser!AST auto param = new AST.Parameter(specifiersToSTC(LVL.parameter, specifier), t, id, null, null); parameters.push(param); - if (token.value == TOK.rightParenthesis) + if (token.value == TOK.rightParenthesis || token.value == TOK.endOfFile) break; check(TOK.comma); } - nextToken(); + check(TOK.rightParenthesis); return finish(); } @@ -3270,6 +3298,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: @@ -3940,6 +3969,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: @@ -4304,6 +4334,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_: @@ -4702,6 +4733,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; } @@ -4723,6 +4759,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; } @@ -5115,9 +5156,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(); } @@ -5278,6 +5319,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/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d index d3effa99..b015a64 100644 --- a/gcc/d/dmd/cppmangle.d +++ b/gcc/d/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; diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index c902149..8109e12 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/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/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index b305360..2830b25 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -1520,6 +1520,8 @@ Type toStaticArrayType(SliceExp e) */ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) { + //printf("castTo(e: %s from: %s to: %s\n", e.toChars(), e.type.toChars(), t.toChars()); + Expression visit(Expression e) { //printf("Expression::castTo(this=%s, t=%s)\n", e.toChars(), t.toChars()); diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index 1fdd073..e458593 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -963,12 +963,6 @@ extern (C++) class ClassDeclaration : AggregateDeclaration /**************************************** */ - 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/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 51737ce..7cd8df19 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -1111,7 +1111,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 @@ -1148,6 +1148,12 @@ extern (C++) class VarDeclaration : Declaration 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; @@ -1199,12 +1205,10 @@ extern (C++) class VarDeclaration : Declaration { //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; } @@ -1315,9 +1319,17 @@ extern (C++) class VarDeclaration : Declaration 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 @@ -1659,8 +1671,7 @@ extern (C++) class VarDeclaration : Declaration // 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); @@ -1697,8 +1708,8 @@ extern (C++) class VarDeclaration : Declaration 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/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index 5d5c423..cd4155d 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -229,7 +229,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 @@ -270,6 +270,14 @@ public: 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; @@ -634,8 +642,8 @@ public: 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; @@ -680,7 +688,7 @@ public: 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/gcc/d/dmd/delegatize.d b/gcc/d/dmd/delegatize.d index 3f982b3..fd95691 100644 --- a/gcc/d/dmd/delegatize.d +++ b/gcc/d/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/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index 7920df7..9073b0d 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -747,7 +747,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; diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d index 867d3ca..72a4476 100644 --- a/gcc/d/dmd/dmangle.d +++ b/gcc/d/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/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index e1234e5..a5f7cd3 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/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; @@ -766,7 +767,7 @@ extern (C++) final class Module : Package { 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(); @@ -775,7 +776,7 @@ extern (C++) final class Module : Package } 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; @@ -1377,6 +1378,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/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index 732a737..88e8996 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -951,7 +951,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; @@ -1235,7 +1235,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; @@ -5183,6 +5183,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/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index 8f19626..ab422fd 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/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 { @@ -272,6 +273,10 @@ extern (C++) struct Scope * // 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/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index 6ab93d4..3268d56 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/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; } @@ -480,6 +480,16 @@ extern (C++) class StructDeclaration : AggregateDeclaration 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/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 3611e09..aa478f2 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -999,10 +999,7 @@ extern (C++) class Dsymbol : ASTNode sm = sm.toAlias(); TemplateDeclaration td = sm.isTemplateDeclaration(); if (!td) - { - .error(loc, "`%s.%s` is not a template, it is a %s", s.toPrettyChars(), ti.name.toChars(), sm.kind()); - return null; - } + return null; // error but handled later ti.tempdecl = td; if (!ti.semanticRun) ti.dsymbolSemantic(sc); @@ -1242,10 +1239,6 @@ extern (C++) class Dsymbol : ASTNode return false; } - void addLocalClass(ClassDeclarations*) - { - } - void addObjcSymbols(ClassDeclarations* classes, ClassDeclarations* categories) { } @@ -1416,6 +1409,7 @@ extern (C++) class Dsymbol : ASTNode inout(OverloadSet) isOverloadSet() inout { return null; } inout(CompileDeclaration) isCompileDeclaration() inout { return null; } inout(StaticAssert) isStaticAssert() inout { return null; } + inout(StaticIfDeclaration) isStaticIfDeclaration() inout { return null; } } /*********************************************************** @@ -2620,6 +2614,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/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index 88110e1..1cee456 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/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; @@ -257,7 +258,6 @@ public: 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() { } @@ -323,6 +323,7 @@ public: 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/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 49e1c59..6697ad6 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -230,12 +230,48 @@ package bool allowsContractWithoutBody(FuncDeclaration funcdecl) return true; } +/* +Tests whether the `ctor` that is part of `ti` is an rvalue constructor +(i.e. a constructor that receives a single parameter of the same type as +`Unqual!typeof(this)`). If that is the case and `sd` contains a copy +constructor, than an error is issued. + +Params: + sd = struct declaration that may contin both an rvalue and copy constructor + ctor = constructor that will be checked if it is an evalue constructor + ti = template instance the ctor is part of + +Return: + `false` if ctor is not an rvalue constructor or if `sd` does not contain a + copy constructor. `true` otherwise +*/ +bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, TemplateInstance ti) +{ + auto loc = ctor.loc; + auto tf = cast(TypeFunction)ctor.type; + auto dim = tf.parameterList.length; + if (sd && sd.hasCopyCtor && (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))) + { + auto param = tf.parameterList[0]; + if (!(param.storageClass & STC.ref_) && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf()) + { + .error(loc, "cannot define both an rvalue constructor and a copy constructor for `struct %s`", sd.toChars()); + .errorSupplemental(ti.loc, "Template instance `%s` creates an rvalue constructor for `struct %s`", + ti.toPrettyChars(), sd.toChars()); + + return true; + } + } + + return false; +} + private extern(C++) final class DsymbolSemanticVisitor : Visitor { alias visit = Visitor.visit; Scope* sc; - this(Scope* sc) + this(Scope* sc) scope { this.sc = sc; } @@ -281,6 +317,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) @@ -338,6 +379,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; @@ -509,10 +555,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; } @@ -528,7 +574,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()) @@ -544,7 +590,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()) { @@ -689,7 +735,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; } @@ -742,7 +788,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()) { @@ -780,11 +826,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 @@ -804,21 +850,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) @@ -836,7 +898,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"); } } } @@ -856,7 +918,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()); } } @@ -911,7 +973,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()) @@ -939,7 +1001,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 @@ -974,7 +1036,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)) { @@ -995,7 +1057,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(); @@ -1049,9 +1111,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; } @@ -1244,7 +1323,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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(); @@ -1534,12 +1613,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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) @@ -1742,7 +1821,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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 @@ -1854,7 +1933,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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); @@ -2656,7 +2735,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor override void visit(TemplateInstance ti) { - templateInstanceSemantic(ti, sc, null); + templateInstanceSemantic(ti, sc, ArgumentList()); } override void visit(TemplateMixin tm) @@ -2694,7 +2773,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor /* 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 { @@ -3054,7 +3133,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor //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()) @@ -3844,11 +3923,25 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (fd.ident == funcdecl.ident) hgs.fullQual = true; - functionToBufferFull(cast(TypeFunction)(fd.type), &buf1, - new Identifier(fd.toPrettyChars()), &hgs, null); - error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", - funcdeclToChars, buf1.peekChars()); + // https://issues.dlang.org/show_bug.cgi?id=23745 + // If the potentially overriden function contains errors, + // inform the user to fix that one first + if (fd.errors) + { + error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", + funcdecl.toChars(), fd.toPrettyChars()); + errorSupplemental(fd.loc, "Function `%s` contains errors in its declaration, therefore it cannot be correctly overriden", + fd.toPrettyChars()); + } + else + { + functionToBufferFull(cast(TypeFunction)(fd.type), &buf1, + new Identifier(fd.toPrettyChars()), &hgs, null); + + error(funcdecl.loc, "function `%s` does not override any function, did you mean to override `%s`?", + funcdeclToChars, buf1.peekChars()); + } } else { @@ -4088,9 +4181,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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 "~ @@ -4115,20 +4207,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // https://issues.dlang.org/show_bug.cgi?id=22593 else if (auto ti = ctd.parent.isTemplateInstance()) { - if (!sd || !sd.hasCopyCtor || !(dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))) - return; - - auto param = tf.parameterList[0]; - - // if the template instance introduces an rvalue constructor - // between the members of a struct declaration, we should check if a - // copy constructor exists and issue an error in that case. - if (!(param.storageClass & STC.ref_) && param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf()) - { - .error(ctd.loc, "cannot define both an rvalue constructor and a copy constructor for `struct %s`", sd.toChars); - .errorSupplemental(ti.loc, "Template instance `%s` creates a rvalue constructor for `struct %s`", - ti.toChars(), sd.toChars()); - } + checkHasBothRvalueAndCpCtor(sd, ctd, ti); } } @@ -4171,8 +4250,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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) @@ -4534,7 +4613,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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); @@ -4604,6 +4684,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor if (!sd.members) // if opaque declaration { + if (log) printf("\topaque declaration %s\n", sd.toChars()); sd.semanticRun = PASS.semanticdone; return; } @@ -4655,7 +4736,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sc2.pop(); - //printf("\tdeferring %s\n", toChars()); + if (log) printf("\tdeferring %s\n", sd.toChars()); return deferDsymbolSemantic(sd, scx); } @@ -4685,7 +4766,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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(); @@ -4698,7 +4779,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor 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); @@ -4752,6 +4833,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // 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) @@ -5297,9 +5379,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // 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()); @@ -5311,7 +5393,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor // 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()); @@ -5776,7 +5858,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) @@ -5848,7 +5930,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) @@ -5901,6 +5983,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. */ @@ -5986,7 +6070,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; } @@ -6142,7 +6226,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; } @@ -6189,7 +6273,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions* { 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; } @@ -7022,12 +7106,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/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 32799aa..ad3a6d4 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/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; @@ -1050,7 +1051,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * 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) @@ -1168,6 +1169,12 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol 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; @@ -1226,7 +1233,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol 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; } @@ -1237,7 +1244,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * 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) @@ -1272,7 +1279,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol 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 @@ -1303,14 +1310,14 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol * 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; @@ -1334,7 +1341,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol 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()); @@ -1458,7 +1465,10 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol 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: @@ -2593,13 +2603,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()); @@ -2704,7 +2713,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; @@ -2737,8 +2746,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; @@ -2806,7 +2815,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, int applyTemplate(TemplateDeclaration td) { - //printf("applyTemplate()\n"); + //printf("applyTemplate(): td = %s\n", td.toChars()); if (td == td_best) // skip duplicates return 0; @@ -2830,6 +2839,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) { @@ -2838,12 +2852,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; @@ -2882,13 +2896,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; @@ -2907,7 +2921,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; @@ -2954,7 +2968,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); @@ -2967,7 +2981,6 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, if (isCtorCall) { // Constructor call requires additional check. - auto tf = cast(TypeFunction)fd.type; assert(tf.next); if (MODimplicitConv(tf.mod, tthis_fd.mod) || @@ -2978,6 +2991,16 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, } else continue; // MATCH.nomatch + + // need to check here whether the constructor is the member of a struct + // declaration that defines a copy constructor. This is already checked + // in the semantic of CtorDeclaration, however, when matching functions, + // the template instance is not expanded. + // https://issues.dlang.org/show_bug.cgi?id=21613 + auto ad = fd.isThis(); + auto sd = ad.isStructDeclaration(); + if (checkHasBothRvalueAndCpCtor(sd, fd.isCtorDeclaration(), ti)) + continue; } if (mta < ta_last) goto Ltd_best; @@ -2989,8 +3012,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; @@ -3000,16 +3023,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; @@ -3076,7 +3099,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) @@ -3104,7 +3127,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, @@ -5887,7 +5910,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) @@ -5902,7 +5925,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) @@ -6010,7 +6033,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 @@ -6247,41 +6273,55 @@ extern (C++) class TemplateInstance : ScopeDsymbol */ final bool needsCodegen() { + //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; - if (errors || (inst && inst.isDiscardable())) + // Don't do codegen if the instance has errors, + // is a dummy instance (see evaluateConstraint), + // or is determined to be discardable. + if (errors || inst is null || inst.isDiscardable()) { minst = null; // mark as speculative return false; } + // This should only be called on the primary instantiation. + assert(this is inst); + if (global.params.allInst) { // Do codegen if there is an instantiation from a root module, to maximize link-ability. - - // Do codegen if `this` is instantiated from a root module. - if (minst && minst.isRoot()) - return true; - - // Do codegen if the ancestor needs it. - if (tinst && tinst.needsCodegen()) + static ThreeState needsCodegenAllInst(TemplateInstance tithis, TemplateInstance tinst) { - minst = tinst.minst; // cache result - assert(minst); - assert(minst.isRoot()); - return true; + // Do codegen if `this` is instantiated from a root module. + if (tithis.minst && tithis.minst.isRoot()) + return ThreeState.yes; + + // Do codegen if the ancestor needs it. + if (tinst && tinst.inst && tinst.inst.needsCodegen()) + { + tithis.minst = tinst.inst.minst; // cache result + assert(tithis.minst); + assert(tithis.minst.isRoot()); + return ThreeState.yes; + } + return ThreeState.none; } + if (const needsCodegen = needsCodegenAllInst(this, tinst)) + return needsCodegen == ThreeState.yes ? true : false; + // Do codegen if a sibling needs it. - if (tnext) + for (; tnext; tnext = tnext.tnext) { - if (tnext.needsCodegen()) + const needsCodegen = needsCodegenAllInst(tnext, tnext.tinst); + if (needsCodegen == ThreeState.yes) { minst = tnext.minst; // cache result assert(minst); @@ -6291,8 +6331,10 @@ extern (C++) class TemplateInstance : ScopeDsymbol else if (!minst && tnext.minst) { minst = tnext.minst; // cache result from non-speculative sibling - return false; + // continue searching } + else if (needsCodegen != ThreeState.none) + break; } // Elide codegen because there's no instantiation from any root modules. @@ -6317,31 +6359,39 @@ extern (C++) class TemplateInstance : ScopeDsymbol * => Elide codegen if there is at least one instantiation from a non-root module * which doesn't import any root modules. */ - - // If the ancestor isn't speculative, - // 1. do codegen if the ancestor needs it - // 2. elide codegen if the ancestor doesn't need it (non-root instantiation of ancestor incl. subtree) - if (tinst) + static ThreeState needsCodegenRootOnly(TemplateInstance tithis, TemplateInstance tinst) { - const needsCodegen = tinst.needsCodegen(); // sets tinst.minst - if (tinst.minst) // not speculative + // If the ancestor isn't speculative, + // 1. do codegen if the ancestor needs it + // 2. elide codegen if the ancestor doesn't need it (non-root instantiation of ancestor incl. subtree) + if (tinst && tinst.inst) { - minst = tinst.minst; // cache result - return needsCodegen; + tinst = tinst.inst; + const needsCodegen = tinst.needsCodegen(); // sets tinst.minst + if (tinst.minst) // not speculative + { + tithis.minst = tinst.minst; // cache result + return needsCodegen ? ThreeState.yes : ThreeState.no; + } } + + // Elide codegen if `this` doesn't need it. + if (tithis.minst && !tithis.minst.isRoot() && !tithis.minst.rootImports()) + return ThreeState.no; + + return ThreeState.none; } - // Elide codegen if `this` doesn't need it. - if (minst && !minst.isRoot() && !minst.rootImports()) - return false; + if (const needsCodegen = needsCodegenRootOnly(this, tinst)) + return needsCodegen == ThreeState.yes ? true : false; // Elide codegen if a (non-speculative) sibling doesn't need it. - if (tnext) + for (; tnext; tnext = tnext.tnext) { - const needsCodegen = tnext.needsCodegen(); // sets tnext.minst + const needsCodegen = needsCodegenRootOnly(tnext, tnext.tinst); // sets tnext.minst if (tnext.minst) // not speculative { - if (!needsCodegen) + if (needsCodegen == ThreeState.no) { minst = tnext.minst; // cache result assert(!minst.isRoot() && !minst.rootImports()); @@ -6350,8 +6400,10 @@ extern (C++) class TemplateInstance : ScopeDsymbol else if (!minst) { minst = tnext.minst; // cache result from non-speculative sibling - return true; + // continue searching } + else if (needsCodegen != ThreeState.none) + break; } } @@ -6564,7 +6616,17 @@ extern (C++) class TemplateInstance : ScopeDsymbol } 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 @@ -6883,12 +6945,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol * * 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) { @@ -6897,7 +6959,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol 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; @@ -6947,7 +7009,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol 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; @@ -6956,8 +7018,8 @@ extern (C++) class TemplateInstance : ScopeDsymbol // 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; @@ -7223,7 +7285,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol 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; } @@ -7480,6 +7542,43 @@ extern (C++) class TemplateInstance : ScopeDsymbol 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/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 30ca3d1..7c3ff4b 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/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/gcc/d/dmd/errors.d b/gcc/d/dmd/errors.d index 03c78a5..f107f7b 100644 --- a/gcc/d/dmd/errors.d +++ b/gcc/d/dmd/errors.d @@ -12,11 +12,63 @@ module dmd.errors; import core.stdc.stdarg; +import dmd.errorsink; import dmd.globals; import dmd.location; 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 */ diff --git a/gcc/d/dmd/errorsink.d b/gcc/d/dmd/errorsink.d new file mode 100644 index 0000000..b519db7 --- /dev/null +++ b/gcc/d/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/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 7bc018e..420fa7f 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/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/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index e0f258c..df5e9dd 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/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]); @@ -682,11 +722,11 @@ extern (C++) 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; @@ -1393,7 +1433,7 @@ extern (C++) 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()); } @@ -1435,7 +1475,7 @@ extern (C++) 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; @@ -1488,7 +1528,7 @@ extern (C++) 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; @@ -1496,7 +1536,8 @@ extern (C++) 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()); @@ -1647,6 +1688,15 @@ extern (C++) 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() @@ -2137,6 +2187,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(); @@ -2213,6 +2270,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(); @@ -2261,7 +2328,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; @@ -2416,7 +2483,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; @@ -2475,7 +2542,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 @@ -2483,7 +2550,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 @@ -3570,18 +3637,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) @@ -3594,7 +3669,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) @@ -3969,6 +4045,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); } @@ -4217,7 +4294,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; @@ -4257,7 +4334,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; @@ -4330,7 +4407,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; @@ -4621,7 +4698,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); } @@ -5048,21 +5125,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) @@ -5129,7 +5238,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() @@ -5325,7 +5434,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); } @@ -6387,7 +6496,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); } @@ -6717,7 +6826,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/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 7202960..e4716c8 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -45,7 +45,7 @@ typedef union tree_node Symbol; struct Symbol; // back end symbol #endif -void expandTuples(Expressions *exps); +void expandTuples(Expressions *exps, Identifiers *names = nullptr); bool isTrivialExp(Expression *e); bool hasSideEffect(Expression *e, bool assumeImpureCalls = false); @@ -81,7 +81,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 @@ -123,6 +123,7 @@ public: // 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<bool> toBool(); virtual bool hasCode() { @@ -281,6 +282,7 @@ public: 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; @@ -298,6 +300,7 @@ public: 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; @@ -529,6 +532,7 @@ public: 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[] @@ -536,6 +540,8 @@ public: 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; @@ -823,6 +829,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/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 63236cd..d186abc 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/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; } @@ -1192,7 +1197,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 +1214,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 +1312,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 +1332,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 +1591,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 +1617,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 +1710,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 +1718,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 +1816,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 +2005,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 +2179,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 { @@ -2443,10 +2464,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 @@ -2545,7 +2566,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Scope* sc; Expression result; - this(Scope* sc) + this(Scope* sc) scope { this.sc = sc; } @@ -3547,7 +3568,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { return setError(); } - if (preFunctionParameters(sc, exp.arguments)) + if (preFunctionParameters(sc, exp.argumentList)) { return setError(); } @@ -3706,7 +3727,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(); @@ -3716,7 +3737,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(); @@ -3776,6 +3797,32 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = id.expressionSemantic(sc); return; } + else if (!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()) { @@ -3805,7 +3852,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(); @@ -3815,7 +3862,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(); @@ -3826,8 +3873,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(); @@ -3876,6 +3935,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) @@ -3897,6 +3962,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; @@ -4285,7 +4355,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 @@ -4524,7 +4594,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 @@ -4622,7 +4692,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; @@ -4632,7 +4717,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; @@ -4671,14 +4756,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; @@ -4738,7 +4823,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(); @@ -4901,9 +4986,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(); @@ -4928,7 +5013,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) @@ -4975,7 +5060,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()) @@ -4999,7 +5084,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()) @@ -5027,8 +5112,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('('); @@ -5095,14 +5179,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('('); @@ -5144,7 +5227,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(); @@ -5176,7 +5259,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) @@ -5499,8 +5582,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) @@ -6009,7 +6102,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); @@ -8342,13 +8435,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Type t1b = exp.e1.type.toBasetype(); - if (t1b.ty == Tvector) + if (TypeVector tv1 = t1b.isTypeVector()) { // Convert e1 to corresponding static array - TypeVector tv1 = cast(TypeVector)t1b; t1b = tv1.basetype; t1b = t1b.castMod(tv1.mod); - exp.e1.type = t1b; + exp.e1 = exp.e1.castTo(sc, t1b); } if (t1b.ty == Tsarray || t1b.ty == Tarray) { @@ -12043,6 +12135,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor __equals = new DotIdExp(exp.loc, __equals, Id.object); __equals = new DotIdExp(exp.loc, __equals, id); + /* https://issues.dlang.org/show_bug.cgi?id=23674 + * + * Optimize before creating the call expression to the + * druntime hook as the optimizer may output errors + * that will get swallowed otherwise. + */ + exp.e1 = exp.e1.optimize(WANTvalue); + exp.e2 = exp.e2.optimize(WANTvalue); + auto arguments = new Expressions(2); (*arguments)[0] = exp.e1; (*arguments)[1] = exp.e2; @@ -13149,11 +13250,6 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef); - /* In case we don't know which expression triggered it, - * e.g. for `visit(Type)` overload - */ - Expression original = e; - bool check(Expression e, bool allowRef) { bool sharedError(Expression e) @@ -13166,7 +13262,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; } @@ -13175,10 +13273,6 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) { if (e.thisexp) check(e.thisexp, false); - // Note: This handles things like `new shared(Throwable).msg`, - // where accessing `msg` would violate `shared`. - if (e.newtype.isShared()) - return sharedError(original); return false; } @@ -13216,33 +13310,32 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) return check(e.e1, false); } - bool visitThis(ThisExp e) + bool visitDotVar(DotVarExp e) { - if (sc.func && sc.func.isSynchronized()) - return 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 (!allowRef && e.type.isShared()) - return sharedError(e); + auto fd = e.var.isFuncDeclaration(); + const sharedFunc = fd && fd.type.isShared; + if (!allowRef && !sharedFunc) + return sharedError(e); - return false; - } + // Allow using `DotVarExp` within value types + if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct()) + return check(e.e1, allowRef); - bool visitDotVar(DotVarExp e) - { - //printf("dotvarexp = %s\n", e.toChars()); - auto fd = e.var.isFuncDeclaration(); - const sharedFunc = fd && fd.type.isShared; - // Allow using `DotVarExp` within value types - if (!allowRef && e.type.isShared() && !sharedFunc && !(sc.func && sc.func.isSynchronized())) - return sharedError(e); - if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct()) - return check(e.e1, allowRef); + // If we end up with a single `VarExp`, it might be a `ref` param + // `shared ref T` param == `shared(T)*`. + if (auto ve = e.e1.isVarExp()) + { + return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_)); + } - // If we end up with a single `VarExp`, it might be a `ref` param - // `shared ref T` param == `shared(T)*`. - if (auto ve = e.e1.isVarExp()) - { - return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_)); + return sharedError(e); } return check(e.e1, false); @@ -13283,7 +13376,6 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false) case EXP.star: return visitPtr(e.isPtrExp()); case EXP.dotVariable: return visitDotVar(e.isDotVarExp()); case EXP.index: return visitIndex(e.isIndexExp()); - case EXP.this_: return visitThis(e.isThisExp()); } } diff --git a/gcc/d/dmd/foreachvar.d b/gcc/d/dmd/foreachvar.d index 7c4df0de..ba2825a 100644 --- a/gcc/d/dmd/foreachvar.d +++ b/gcc/d/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/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 3a85679..4b6b5b5 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -202,7 +202,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 @@ -217,6 +217,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 } /*********************************************************** @@ -322,6 +324,12 @@ extern (C++) class FuncDeclaration : Declaration 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; @@ -1039,12 +1047,13 @@ extern (C++) class FuncDeclaration : Declaration * 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()); } @@ -1089,7 +1098,7 @@ extern (C++) class FuncDeclaration : Declaration 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 @@ -1979,6 +1988,7 @@ extern (C++) class FuncDeclaration : Declaration if (!sc.intypeof && !(sc.flags & SCOPE.compile)) { siblingCallers.push(fdthis); + computedEscapingSiblings = false; } } } @@ -2028,8 +2038,7 @@ extern (C++) class FuncDeclaration : Declaration * 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; @@ -2106,7 +2115,7 @@ extern (C++) class FuncDeclaration : Declaration */ extern (C++) final bool checkClosure() { - //printf("checkClosure() %s\n", toChars()); + //printf("checkClosure() %s\n", toPrettyChars()); if (!needsClosure()) return false; @@ -2320,6 +2329,7 @@ extern (C++) class FuncDeclaration : Declaration * base.in(); * assert(false, "Logic error: " ~ thr.msg); * } + * } */ foreach (fdv; foverrides) @@ -2827,6 +2837,12 @@ extern (C++) class FuncDeclaration : Declaration 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; @@ -3127,14 +3143,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 @@ -3152,6 +3169,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)) @@ -3162,7 +3180,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) @@ -3285,7 +3303,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`", @@ -3331,7 +3349,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`", @@ -3345,7 +3363,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); } @@ -3362,8 +3380,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; @@ -3619,6 +3639,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; @@ -3660,6 +3683,8 @@ private bool checkEscapingSiblings(FuncDeclaration f, FuncDeclaration outerFunc, prev = prev.p; } } + f.hasEscapingSiblings = bAnyClosures; + f.computedEscapingSiblings = true; //printf("\t%d\n", bAnyClosures); return bAnyClosures; } @@ -3859,7 +3884,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) @@ -4351,6 +4376,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` * @@ -4392,7 +4437,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/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index 80c183e..1919d9a 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/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; @@ -143,7 +145,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 @@ -176,6 +178,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 @@ -291,6 +294,8 @@ extern (C++) struct Global enum recursionLimit = 500; /// number of recursive template expansions before abort + ErrorSink errorSink; /// where the error messages go + extern (C++) FileName function(FileName, ref const Loc, out bool, OutBuffer*) preprocess; nothrow: @@ -345,6 +350,8 @@ extern (C++) struct Global extern (C++) void _init() { + global.errorSink = new ErrorSinkCompiler; + this.fileManager = new FileManager(); version (MARS) { diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index 45c5624..ec8fc32 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -19,6 +19,7 @@ // Can't include arraytypes.h here, need to declare these directly. template <typename TYPE> struct Array; +class ErrorSink; class FileManager; struct Loc; @@ -179,6 +180,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<const char *> modFileAliasStrings; // array of char*'s of -I module filename alias strings @@ -277,6 +279,7 @@ struct Global unsigned varSequenceNumber; FileManager* fileManager; + ErrorSink* errorSink; // where the error messages go FileName (*preprocess)(FileName, const Loc&, bool&, OutBuffer&); diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d index 68670d9..c7e5690 100644 --- a/gcc/d/dmd/hdrgen.d +++ b/gcc/d/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; @@ -144,7 +145,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; @@ -805,7 +806,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; @@ -1406,8 +1407,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(); @@ -1428,8 +1431,10 @@ public: buf.writeByte('{'); buf.writenl(); buf.level++; + hgs.insideAggregate++; foreach (s; *d.members) s.accept(this); + hgs.insideAggregate--; buf.level--; buf.writeByte('}'); } @@ -1521,6 +1526,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(", "); @@ -1528,21 +1548,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); } } @@ -2136,7 +2165,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(')'); } } @@ -2440,7 +2469,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(')'); } @@ -2683,7 +2712,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) { @@ -2691,7 +2720,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] == '.') @@ -2733,7 +2762,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; @@ -2814,7 +2843,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; @@ -3281,8 +3310,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; @@ -3292,6 +3327,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/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d index baf6b14..f8c88ab 100644 --- a/gcc/d/dmd/iasmgcc.d +++ b/gcc/d/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/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index 40a5c6e..ec5cb25 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/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/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index 572753b..18b10b4 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/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/gcc/d/dmd/json.d b/gcc/d/dmd/json.d index 38e03e7..2af7fae 100644 --- a/gcc/d/dmd/json.d +++ b/gcc/d/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/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d index c800273..885a27a 100644 --- a/gcc/d/dmd/lambdacomp.d +++ b/gcc/d/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/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index bd53433..c9ed35f 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/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,24 @@ 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) { - va_list args; - va_start(args, format); - .verror(token.loc, format, args); - va_end(args); + eSink.error(loc, format, args); } - final void error(const ref Loc loc, const(char)* format, ...) + final void deprecation(const(char)* format) { - va_list args; - va_start(args, format); - .verror(loc, format, args); - va_end(args); + eSink.deprecation(token.loc, format); } - final void deprecation(const(char)* format, ...) + final void deprecationSupplemental(const(char)* format) { - va_list args; - va_start(args, format); - .vdeprecation(token.loc, format, args); - va_end(args); + eSink.deprecationSupplemental(token.loc, format); } /*************************************** @@ -2692,7 +2695,7 @@ class Lexer else { const locx = loc(); - warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars()); + eSink.warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars()); } } else if (n.value == TOK.if_) @@ -2853,7 +2856,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 +3080,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 +3091,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 +3220,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 +3265,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; - gotError = true; - char[100] buffer = void; - auto actual = buffer[0 .. vsprintf(buffer.ptr, format, ap)]; - assert(expected == actual); - return true; + string expected; + bool gotError; + + 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 +3343,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 +3367,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 +3388,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/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index bc89ac4..002bb1a 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -170,3 +170,5 @@ struct ModuleDeclaration const char *toChars() const; }; + +extern void getLocalClasses(Module* mod, Array<ClassDeclaration* >& aclasses); diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 232042d..5939db5 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -456,7 +456,7 @@ extern (C++) abstract class Type : ASTNode return sizeTy; }(); - final extern (D) this(TY ty) + final extern (D) this(TY ty) scope { this.ty = ty; } @@ -2046,7 +2046,7 @@ extern (C++) abstract class Type : ASTNode } 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; @@ -2068,7 +2068,7 @@ extern (C++) abstract class Type : ASTNode 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; @@ -2447,7 +2447,7 @@ extern (C++) abstract class Type : ASTNode const namelen = 19 + size_t.sizeof * 3 + slice.length + 1; auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen)); - const length = sprintf(name, "_D%lluTypeInfo_%.*s6__initZ", + const 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 @@ -3120,7 +3120,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; @@ -4626,14 +4626,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 @@ -4669,8 +4669,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) { @@ -4684,22 +4683,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; @@ -4733,10 +4749,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) @@ -4745,7 +4762,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); @@ -4760,7 +4777,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 @@ -4773,16 +4790,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. @@ -4871,9 +4969,18 @@ extern (C++) final class TypeFunction : TypeNext } /// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other` - bool attributesEqual(const scope TypeFunction other) const pure nothrow @safe @nogc - { - return this.trust == other.trust && + 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): + // Two overloads that are identical except for one having an explicit `@system` + // attribute is currently in deprecation, and will become an error in 2.104 for + // `extern(C)`, and 2.112 for `extern(D)` code respectively. Once the deprecation + // period has passed, the trustSystemEqualsDefault=true behaviour should be made + // the default, then we can remove the `cannot overload extern(...) function` + // errors as they will become dead code as a result. + return (this.trust == other.trust || + (trustSystemEqualsDefault && this.trust <= TRUST.system && other.trust <= TRUST.system)) && this.purity == other.purity && this.isnothrow == other.isnothrow && this.isnogc == other.isnogc && @@ -4884,6 +4991,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; + } } /*********************************************************** @@ -6507,6 +6631,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; + } } @@ -6975,7 +7121,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/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d index 370e3b8..201f168 100644 --- a/gcc/d/dmd/nogc.d +++ b/gcc/d/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/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d index 31e93a7..9cff76b 100644 --- a/gcc/d/dmd/ob.d +++ b/gcc/d/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/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index 4d7fe9f..3c80e5e 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/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/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 6eb3021..36a76f5 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/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; } @@ -2420,7 +2428,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer tf = tf.addSTC(stc); auto f = new AST.CtorDeclaration(loc, Loc.initial, stc, tf); - AST.Dsymbol s = parseContracts(f); + AST.Dsymbol s = parseContracts(f, !!tpl); if (udas) { auto a = new AST.Dsymbols(); @@ -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; } } @@ -4571,7 +4542,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer pAttrs.storageClass = STC.undefined_; if (tpl) constraint = parseConstraint(); - AST.Dsymbol s = parseContracts(f); + AST.Dsymbol s = parseContracts(f, !!tpl); auto tplIdent = s.ident; if (link != linkage) @@ -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(); @@ -5157,7 +5128,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer /***************************************** * Parse contracts following function declaration. */ - private AST.FuncDeclaration parseContracts(AST.FuncDeclaration f) + private AST.FuncDeclaration parseContracts(AST.FuncDeclaration f, bool isTemplateFunction = false) { LINK linksave = linkage; @@ -5329,7 +5300,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer else if (t == TOK.at) error("attributes cannot be placed after a template constraint"); else if (t == TOK.if_) - error("cannot use function constraints for non-template functions. Use `static if` instead"); + { + if (isTemplateFunction) + error("template constraint must follow parameter lists and attributes"); + else + error("cannot use function constraints for non-template functions. Use `static if` instead"); + } else error("semicolon expected following function declaration"); } @@ -5352,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()); } } @@ -5395,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()); } /***************************************** @@ -5450,6 +5426,11 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer stc = STC.out_; goto Lagain; + case TOK.auto_: + error("cannot declare `auto` loop variable, omit `auto` to still get type inference"); + stc = STC.auto_; + goto Lagain; + case TOK.enum_: stc = STC.manifest; goto Lagain; @@ -5525,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; } @@ -5798,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 @@ -6501,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; } @@ -7060,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(); } @@ -7330,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) @@ -7625,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)) @@ -8144,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()); @@ -8280,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); @@ -8425,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; @@ -8488,7 +8451,7 @@ LagainStc: // ( expression ) nextToken(); e = parseExpression(); - e.parens = 1; + e.parens = true; check(loc, TOK.rightParenthesis); break; } @@ -8758,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_: @@ -8907,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: @@ -9342,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; } /******************************************* @@ -9372,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) @@ -9420,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/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d index 9975c9c..d85105d 100644 --- a/gcc/d/dmd/printast.d +++ b/gcc/d/dmd/printast.d @@ -14,6 +14,7 @@ module dmd.printast; import core.stdc.stdio; import dmd.expression; +import dmd.ctfeexpr; import dmd.tokens; import dmd.visitor; import dmd.hdrgen; @@ -38,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; } @@ -210,6 +211,14 @@ extern (C++) final class PrintASTVisitor : Visitor printf(".init: %s\n", e.initializer ? e.initializer.toChars() : ""); } + override void visit(ClassReferenceExp e) + { + visit(cast(Expression)e); + printIndent(indent + 2); + printf(".value: %s\n", e.value ? e.value.toChars() : ""); + printAST(e.value, indent + 2); + } + static void printIndent(int indent) { foreach (i; 0 .. indent) diff --git a/gcc/d/dmd/root/aav.d b/gcc/d/dmd/root/aav.d index 42d1399..1d45050 100644 --- a/gcc/d/dmd/root/aav.d +++ b/gcc/d/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/gcc/d/dmd/root/array.d b/gcc/d/dmd/root/array.d index e352c61..541a12d 100644 --- a/gcc/d/dmd/root/array.d +++ b/gcc/d/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/gcc/d/dmd/root/ctfloat.d b/gcc/d/dmd/root/ctfloat.d index cd336e6..aae56fa 100644 --- a/gcc/d/dmd/root/ctfloat.d +++ b/gcc/d/dmd/root/ctfloat.d @@ -50,7 +50,7 @@ extern (C++) struct CTFloat static real_t parse(const(char)* literal, out bool isOutOfRange); @system - static int sprint(char* str, char fmt, real_t x); + static int sprint(char* str, size_t size, char fmt, real_t x); // Constant real values 0, 1, -1 and 0.5. __gshared real_t zero; diff --git a/gcc/d/dmd/root/ctfloat.h b/gcc/d/dmd/root/ctfloat.h index 44bd959e..d2f795b 100644 --- a/gcc/d/dmd/root/ctfloat.h +++ b/gcc/d/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 @@ -51,7 +52,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); + static int sprint(char *str, d_size_t size, char fmt, real_t x); static size_t hash(real_t a); diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d index 33f4a7a..3873615 100644 --- a/gcc/d/dmd/root/filename.d +++ b/gcc/d/dmd/root/filename.d @@ -85,6 +85,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/gcc/d/dmd/root/filename.h b/gcc/d/dmd/root/filename.h index 8977411..6214233 100644 --- a/gcc/d/dmd/root/filename.h +++ b/gcc/d/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/gcc/d/dmd/root/rootobject.d b/gcc/d/dmd/root/rootobject.d index 4437d16..7138841 100644 --- a/gcc/d/dmd/root/rootobject.d +++ b/gcc/d/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/gcc/d/dmd/sapply.d b/gcc/d/dmd/sapply.d index 8486028..ef01516 100644 --- a/gcc/d/dmd/sapply.d +++ b/gcc/d/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/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d index c103f60..440e4cb 100644 --- a/gcc/d/dmd/semantic2.d +++ b/gcc/d/dmd/semantic2.d @@ -83,7 +83,7 @@ private extern(C++) final class Semantic2Visitor : Visitor { alias visit = Visitor.visit; Scope* sc; - this(Scope* sc) + this(Scope* sc) scope { this.sc = sc; } @@ -248,9 +248,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; } @@ -439,7 +439,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 @@ -462,7 +466,19 @@ private extern(C++) final class Semantic2Visitor : Visitor // Different attributes don't conflict in extern(D) if (!sameAttr && linkage1 == LINK.d) + { + // @@@DEPRECATED_2.112@@@ + // 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)) + { + f2.deprecation("cannot overload `extern(%s)` function at %s", + linkageToChars(f1._linkage), + f1.loc.toChars()); + } return 0; + } error(f2.loc, "%s `%s%s` conflicts with previous declaration at %s", f2.kind(), diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 78da4a1..33a4318 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -88,7 +88,7 @@ private extern(C++) final class Semantic3Visitor : Visitor alias visit = Visitor.visit; Scope* sc; - this(Scope* sc) + this(Scope* sc) scope { this.sc = sc; } @@ -342,7 +342,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; @@ -712,7 +711,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"); @@ -1600,7 +1599,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/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d index ed93876..60a74cc 100644 --- a/gcc/d/dmd/sideeffect.d +++ b/gcc/d/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/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d index 96c59ba..90728fb 100644 --- a/gcc/d/dmd/statement.d +++ b/gcc/d/dmd/statement.d @@ -1061,6 +1061,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; + } } /*********************************************************** @@ -1762,6 +1772,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) { @@ -1804,6 +1815,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) { @@ -1870,6 +1887,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/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h index 76a3991..46cc4da 100644 --- a/gcc/d/dmd/statement.h +++ b/gcc/d/dmd/statement.h @@ -381,6 +381,7 @@ public: IfStatement *syntaxCopy() override; void accept(Visitor *v) override { v->visit(this); } + bool isIfCtfeBlock(); }; class ConditionalStatement final : public Statement @@ -667,7 +668,7 @@ public: TryFinallyStatement *tf; ScopeGuardStatement *os; VarDeclaration *lastVar; - + bool inCtfeBlock; GotoStatement *syntaxCopy() override; void accept(Visitor *v) override { v->visit(this); } @@ -685,7 +686,7 @@ public: 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/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 5764efd..bbaee8e 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/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; } @@ -1276,7 +1277,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()) @@ -1491,7 +1492,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; @@ -1955,7 +1956,17 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor // 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 @@ -2222,7 +2233,9 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor 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) { @@ -2256,7 +2269,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor } 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; @@ -2485,7 +2498,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor 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; } @@ -3798,6 +3811,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor 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) { @@ -3837,6 +3851,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor 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) @@ -4730,7 +4745,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/gcc/d/dmd/template.h b/gcc/d/dmd/template.h index 8e8ba16..12b2120 100644 --- a/gcc/d/dmd/template.h +++ b/gcc/d/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: @@ -81,7 +96,7 @@ public: 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/gcc/d/dmd/templateparamsem.d b/gcc/d/dmd/templateparamsem.d index 432daee..1a9d252 100644 --- a/gcc/d/dmd/templateparamsem.d +++ b/gcc/d/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/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index b3cd2d3..aec3a77 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/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/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index 32ae5f4..87361f32 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/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/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index 048c24f..de0129b 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/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; @@ -2197,7 +2244,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, @@ -2227,6 +2274,7 @@ private void traitNotFound(TraitsExp e) &Id.isReturnOnStack, &Id.hasMember, &Id.identifier, + &Id.fullyQualifiedName, &Id.getProtection, &Id.getVisibility, &Id.parent, diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 0d64ba4..84561ac 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/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; @@ -285,54 +286,10 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb return helper3(); } } + if (!sm) - { - if (!t) - { - if (s.isDeclaration()) // var, func, or tuple declaration? - { - t = s.isDeclaration().type; - if (!t && s.isTupleDeclaration()) // expression tuple? - return helper3(); - } - else if (s.isTemplateInstance() || - s.isImport() || s.isPackage() || s.isModule()) - { - return helper3(); - } - } - if (t) - { - sm = t.toDsymbol(sc); - if (sm && id.dyncast() == DYNCAST.identifier) - { - sm = sm.search(loc, cast(Identifier)id, IgnorePrivateImports); - if (!sm) - return helper3(); - } - else - return helper3(); - } - else - { - if (id.dyncast() == DYNCAST.dsymbol) - { - // searchX already handles errors for template instances - assert(global.errors); - } - else - { - assert(id.dyncast() == DYNCAST.identifier); - sm = s.search_correct(cast(Identifier)id); - if (sm) - error(loc, "identifier `%s` of `%s` is not defined, did you mean %s `%s`?", id.toChars(), mt.toChars(), sm.kind(), sm.toChars()); - else - error(loc, "identifier `%s` of `%s` is not defined", id.toChars(), mt.toChars()); - } - pe = ErrorExp.get(); - return; - } - } + return helper3(); + s = sm.toAlias(); } @@ -580,6 +537,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) { auto errors = global.errors; mtype.dim = semanticLength(sc, tbn, mtype.dim); + mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t); if (errors != global.errors) return error(); @@ -636,7 +594,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) * run on them for the size, since they may be forward referenced. */ bool overflow = false; - if (mulu(tbn.size(loc), d2, overflow) >= target.maxStaticDataSize || overflow) + if (mulu(tbn.size(loc), d2, overflow) > target.maxStaticDataSize || overflow) return overflowError(); } } @@ -1285,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' @@ -1389,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 @@ -1398,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); @@ -1425,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. @@ -3912,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); @@ -4973,7 +4918,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/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d index b35e03d..2ca7143 100644 --- a/gcc/d/dmd/typinf.d +++ b/gcc/d/dmd/typinf.d @@ -105,10 +105,11 @@ extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope * 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); private TypeInfoDeclaration getTypeInfoDeclaration(Type t) { diff --git a/gcc/d/dmd/visitor.d b/gcc/d/dmd/visitor.d index e4c2a91..8990ce4 100644 --- a/gcc/d/dmd/visitor.d +++ b/gcc/d/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/gcc/d/expr.cc b/gcc/d/expr.cc index 4311edc..c6245ff 100644 --- a/gcc/d/expr.cc +++ b/gcc/d/expr.cc @@ -2277,8 +2277,7 @@ public: else { /* Generate: _d_newclass() */ - tree arg = build_address (get_classinfo_decl (cd)); - new_call = build_libcall (LIBCALL_NEWCLASS, tb, 1, arg); + new_call = build_expr (e->lowering); } /* Set the context pointer for nested classes. */ diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt index 25a6bce..bb0a3dc 100644 --- a/gcc/d/lang.opt +++ b/gcc/d/lang.opt @@ -360,10 +360,6 @@ fpreview=dip1021 D RejectNegative Implement DIP1021: Mutable function arguments. -fpreview=dip25 -D RejectNegative -Implement DIP25: Sealed references. - fpreview=dtorfields D RejectNegative Destruct fields of partially constructed objects. @@ -412,10 +408,6 @@ frevert=dip1000 D RejectNegative Revert DIP1000: Scoped pointers. -frevert=dip25 -D RejectNegative -Revert DIP25: Sealed references. - frevert=dtorfields D RejectNegative Don't destruct fields of partially constructed objects. diff --git a/gcc/d/modules.cc b/gcc/d/modules.cc index 84deada..f2180d3 100644 --- a/gcc/d/modules.cc +++ b/gcc/d/modules.cc @@ -530,11 +530,7 @@ layout_moduleinfo_fields (Module *decl, tree type) /* Array of local ClassInfo decls are laid out in the same way. */ ClassDeclarations aclasses; - for (size_t i = 0; i < decl->members->length; i++) - { - Dsymbol *member = (*decl->members)[i]; - member->addLocalClass (&aclasses); - } + getLocalClasses (decl, aclasses); if (aclasses.length) { @@ -564,11 +560,7 @@ layout_moduleinfo (Module *decl) ClassDeclarations aclasses; FuncDeclaration *sgetmembers; - for (size_t i = 0; i < decl->members->length; i++) - { - Dsymbol *member = (*decl->members)[i]; - member->addLocalClass (&aclasses); - } + getLocalClasses (decl, aclasses); size_t aimports_dim = decl->aimports.length; for (size_t i = 0; i < decl->aimports.length; i++) diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def index a9b2453..23f8b64 100644 --- a/gcc/d/runtime.def +++ b/gcc/d/runtime.def @@ -59,9 +59,6 @@ DEF_D_RUNTIME (ARRAYBOUNDS_SLICEP, "_d_arraybounds_slicep", RT(VOID), DEF_D_RUNTIME (ARRAYBOUNDS_INDEXP, "_d_arraybounds_indexp", RT(VOID), P4(IMMUTABLE_CHARPTR, UINT, SIZE_T, SIZE_T), ECF_NORETURN) -/* Used when calling new on a class. */ -DEF_D_RUNTIME (NEWCLASS, "_d_newclass", RT(OBJECT), P1(CONST_CLASSINFO), 0) - /* Used when calling delete on a stack-allocated class or interface. */ DEF_D_RUNTIME (CALLFINALIZER, "_d_callfinalizer", RT(VOID), P1(VOIDPTR), 0) DEF_D_RUNTIME (CALLINTERFACEFINALIZER, "_d_callinterfacefinalizer", RT(VOID), diff --git a/gcc/d/toir.cc b/gcc/d/toir.cc index e3fa0ee..8bd6eb6 100644 --- a/gcc/d/toir.cc +++ b/gcc/d/toir.cc @@ -582,8 +582,9 @@ public: tree ifbody = void_node; tree elsebody = void_node; - /* Build the `then' branch. */ - if (s->ifbody) + /* Build the `then' branch, don't do code generation when the condition + is `if (__ctfe)', as that is always false at run-time. */ + if (s->ifbody && !s->isIfCtfeBlock ()) { push_stmt_list (); this->build_stmt (s->ifbody); diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc index 08bb1bb..1c5e50c 100644 --- a/gcc/d/typeinfo.cc +++ b/gcc/d/typeinfo.cc @@ -1524,10 +1524,12 @@ get_cpp_typeinfo_decl (ClassDeclaration *decl) return decl->cpp_type_info_ptr_sym; } -/* Get the exact TypeInfo for TYPE, if it doesn't exist, create it. */ +/* Get the exact TypeInfo for TYPE, if it doesn't exist, create it. + When GENERATE is true, push the TypeInfo as a member of MOD so that it will + get code generation. */ void -create_typeinfo (Type *type, Module *mod) +create_typeinfo (Type *type, Module *mod, bool generate) { if (!Type::dtypeinfo) create_frontend_tinfo_types (); @@ -1685,7 +1687,7 @@ create_typeinfo (Type *type, Module *mod) /* If this has a custom implementation in rt/typeinfo, then do not generate a COMDAT for it. */ - if (!builtin_typeinfo_p (t)) + if (generate && !builtin_typeinfo_p (t)) { /* Find module that will go all the way to an object file. */ if (mod) diff --git a/gcc/d/types.cc b/gcc/d/types.cc index 483173d..beaf2a6 100644 --- a/gcc/d/types.cc +++ b/gcc/d/types.cc @@ -381,9 +381,9 @@ layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p) continue; /* If this variable was really a tuple, add all tuple fields. */ - if (var->aliassym) + if (var->aliasTuple) { - TupleDeclaration *td = var->aliassym->isTupleDeclaration (); + TupleDeclaration *td = var->aliasTuple; Dsymbols tmembers; /* No other way to coerce the underlying type out of the tuple. Frontend should have already validated this. */ diff --git a/gcc/testsuite/gdc.dg/torture/simd23084.d b/gcc/testsuite/gdc.dg/torture/simd23084.d new file mode 100644 index 0000000..ad18813 --- /dev/null +++ b/gcc/testsuite/gdc.dg/torture/simd23084.d @@ -0,0 +1,16 @@ +// https://issues.dlang.org/show_bug.cgi?id=23084 +// { dg-additional-options "-mavx" { target avx_runtime } } +// { dg-do compile { target { avx_runtime || vect_sizes_16B_8B } } } +// { dg-skip-if "needs gcc/config.d" { ! d_runtime } } + +__vector(int[4]) test23084a(__vector(int[4]) a) +{ + __vector(short[8]) r = cast(short)(a.array[0]); + return cast(__vector(int[4]))r; +} + +__vector(int[4]) test23084b(__vector(int[4]) a) +{ + __vector(byte[16]) r = cast(byte)(a.array[0]); + return cast(__vector(int[4]))r; +} diff --git a/gcc/testsuite/gdc.dg/torture/simd23085.d b/gcc/testsuite/gdc.dg/torture/simd23085.d new file mode 100644 index 0000000..66444ad --- /dev/null +++ b/gcc/testsuite/gdc.dg/torture/simd23085.d @@ -0,0 +1,11 @@ +// https://issues.dlang.org/show_bug.cgi?id=23085 +// { dg-additional-options "-mavx" { target avx_runtime } } +// { dg-do compile } +// { dg-skip-if "needs gcc/config.d" { ! d_runtime } } + +float test23085(float x) +{ + byte i = *cast(byte*)&x; + ++i; + return *cast(float*)&i; // this cast is not allowed in @safe code +} diff --git a/gcc/testsuite/gdc.dg/torture/simd23218.d b/gcc/testsuite/gdc.dg/torture/simd23218.d new file mode 100644 index 0000000..865fc82 --- /dev/null +++ b/gcc/testsuite/gdc.dg/torture/simd23218.d @@ -0,0 +1,15 @@ +// https://issues.dlang.org/show_bug.cgi?id=23218 +// { dg-additional-options "-mavx" { target avx_runtime } } +// { dg-do run { target { avx_runtime || vect_sizes_16B_8B } } } +// { dg-skip-if "needs gcc/config.d" { ! d_runtime } } + +__vector(int[4]) convtest(int[4] a) +{ + return cast(__vector(int[4]))a; +} + +void main() +{ + static assert(convtest([1,2,3,4])[0] == 1); + assert(convtest([1,2,3,4])[0] == 1); +} diff --git a/gcc/testsuite/gdc.test/compilable/b23620.d b/gcc/testsuite/gdc.test/compilable/b23620.d new file mode 100644 index 0000000..1eb1dcd --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/b23620.d @@ -0,0 +1,10 @@ +// https://issues.dlang.org/show_bug.cgi?id=23620 +struct Index +{ + uint value; + alias value this; +} + +enum i = Index(); +int[i] a; +static assert(a.length == 0); diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/header18365.d b/gcc/testsuite/gdc.test/compilable/extra-files/header18365.d index 64d8ad0..a0fb833 100644 --- a/gcc/testsuite/gdc.test/compilable/extra-files/header18365.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/extra-files/imp9057.d b/gcc/testsuite/gdc.test/compilable/extra-files/imp9057.d index 54598dd..74f035e 100644 --- a/gcc/testsuite/gdc.test/compilable/extra-files/imp9057.d +++ b/gcc/testsuite/gdc.test/compilable/extra-files/imp9057.d @@ -1,5 +1,5 @@ struct BugInt { - uint[] data = ZEROX; + uint[] data = ZEROX; } enum uint [] ZEROX = [0]; diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/test23626a.d b/gcc/testsuite/gdc.test/compilable/extra-files/test23626a.d new file mode 100644 index 0000000..a134592 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/test23626a.d @@ -0,0 +1,49 @@ +template fullyQualifiedName(T...) +{ + enum fullyQualifiedName = !T[0]; +} + +void __trace_maybeDumpTupleToFile(Args...)(auto ref const Args args) nothrow @nogc { } + +int getStructInfoEx(T)() { + enum Ctx = fullyQualifiedName!T; + return 0; +} + +auto as(Func)(Func) {} + +@nogc void foo() { } + +void assertOp(string OPERATION, LHS, RHS)(LHS lhs, RHS) { + as({ + try { + try as(lhs); + catch(Throwable) foo(); + } catch(Throwable) assert(false); + }); +} + +struct FixedArray(T, size_t capacity_) { + int a = getStructInfoEx!FixedArray; + + T* some_function() { + assertOp !""(1, 1); + return null; + } + alias some_function this; +} + +struct ReclamationBatch { + + FixedArray !(uint,1) dummy; + + @nogc nothrow void some_inout_func() inout { } + + void func_2(Dlg)(Dlg dlg) { + __trace_maybeDumpTupleToFile(dlg); + } + + void _reclaimBatch() { + func_2({ some_inout_func; }); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/test23626b.d b/gcc/testsuite/gdc.test/compilable/extra-files/test23626b.d new file mode 100644 index 0000000..8bb2af5 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/extra-files/test23626b.d @@ -0,0 +1,14 @@ +interface Timeline { +} + +struct Policy { + alias OldTagCallback = void delegate() @nogc nothrow; + Timeline timeline; + OldTagCallback oldTagCB; +} + +import test23626; + +struct Tiering { + StaticHashTable!(Policy) policies; +} diff --git a/gcc/testsuite/gdc.test/compilable/ice13920.d b/gcc/testsuite/gdc.test/compilable/ice13920.d index 466b2e0..a4540d1 100644 --- a/gcc/testsuite/gdc.test/compilable/ice13920.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/imports/imp23662.c b/gcc/testsuite/gdc.test/compilable/imports/imp23662.c new file mode 100644 index 0000000..1556bc9 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/imports/imp23662.c @@ -0,0 +1,6 @@ +// https://issues.dlang.org/show_bug.cgi?id=23662 +typedef enum {A} E; + +E func(E v) { + return v; +} diff --git a/gcc/testsuite/gdc.test/compilable/infer_stc.d b/gcc/testsuite/gdc.test/compilable/infer_stc.d new file mode 100644 index 0000000..50140e7 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/named_argumens_struct.d b/gcc/testsuite/gdc.test/compilable/named_argumens_struct.d new file mode 100644 index 0000000..0c60509 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/named_arguments.d b/gcc/testsuite/gdc.test/compilable/named_arguments.d new file mode 100644 index 0000000..f287ccd --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/scope.d b/gcc/testsuite/gdc.test/compilable/scope.d index 95c7846..44f54f7 100644 --- a/gcc/testsuite/gdc.test/compilable/scope.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/shared.d b/gcc/testsuite/gdc.test/compilable/shared.d index bfa8422..695083a 100644 --- a/gcc/testsuite/gdc.test/compilable/shared.d +++ b/gcc/testsuite/gdc.test/compilable/shared.d @@ -123,3 +123,10 @@ struct Parent ch = shared Child(i); } } + +// https://issues.dlang.org/show_bug.cgi?id=23732 +class Class {} +void main() +{ + auto b = new shared Class(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test16495.d b/gcc/testsuite/gdc.test/compilable/test16495.d new file mode 100644 index 0000000..70f11be --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/test18026.d b/gcc/testsuite/gdc.test/compilable/test18026.d new file mode 100644 index 0000000..97d83b4 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test18026.d @@ -0,0 +1,12 @@ +// https://issues.dlang.org/show_bug.cgi?id=18026 +bool f(T)(T x) +{ + return false; +} + +static foreach(i; 0..60000) +{ + static if(f(i)) + { + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test19268.d b/gcc/testsuite/gdc.test/compilable/test19268.d new file mode 100644 index 0000000..ff22403 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test19268.d @@ -0,0 +1,6 @@ +/* REQUIRED_ARGS: -betterC + */ + +// https://issues.dlang.org/show_bug.cgi?id=19268 + +mixin(`void foo(){}`.idup); diff --git a/gcc/testsuite/gdc.test/compilable/test20201.d b/gcc/testsuite/gdc.test/compilable/test20201.d new file mode 100644 index 0000000..b0419d6 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/test21073.d b/gcc/testsuite/gdc.test/compilable/test21073.d deleted file mode 100644 index 47d7881..0000000 --- a/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/test21543.d b/gcc/testsuite/gdc.test/compilable/test21543.d deleted file mode 100644 index 4914264..0000000 --- a/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/test22916.d b/gcc/testsuite/gdc.test/compilable/test22916.d new file mode 100644 index 0000000..9f779fd --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/test23145.d b/gcc/testsuite/gdc.test/compilable/test23145.d new file mode 100644 index 0000000..45235dc --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/test23431_minimal.d b/gcc/testsuite/gdc.test/compilable/test23431_minimal.d index 0293f12..c3ae19a2 100644 --- a/gcc/testsuite/gdc.test/compilable/test23431_minimal.d +++ b/gcc/testsuite/gdc.test/compilable/test23431_minimal.d @@ -13,6 +13,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/gcc/testsuite/gdc.test/compilable/test23433.d b/gcc/testsuite/gdc.test/compilable/test23433.d index 713267c..dfffa456 100644 --- a/gcc/testsuite/gdc.test/compilable/test23433.d +++ b/gcc/testsuite/gdc.test/compilable/test23433.d @@ -4,6 +4,13 @@ module object; 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/gcc/testsuite/gdc.test/compilable/test23598.d b/gcc/testsuite/gdc.test/compilable/test23598.d new file mode 100644 index 0000000..cdcb5a8 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/test23606.d b/gcc/testsuite/gdc.test/compilable/test23606.d new file mode 100644 index 0000000..4d8ab24 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/test23617.d b/gcc/testsuite/gdc.test/compilable/test23617.d new file mode 100644 index 0000000..2d03ee7 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/test23626.d b/gcc/testsuite/gdc.test/compilable/test23626.d new file mode 100644 index 0000000..ac19943 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23626.d @@ -0,0 +1,8 @@ +// https://issues.dlang.org/show_bug.cgi?id=23626 +// EXTRA_SOURCES: extra-files/test23626a.d extra-files/test23626b.d +module test23626; + +struct StaticHashTable(V) +{ + V v; +} diff --git a/gcc/testsuite/gdc.test/compilable/test23639.d b/gcc/testsuite/gdc.test/compilable/test23639.d new file mode 100644 index 0000000..e2ec002 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/test23651.d b/gcc/testsuite/gdc.test/compilable/test23651.d new file mode 100644 index 0000000..8c477b0 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/test23662.d b/gcc/testsuite/gdc.test/compilable/test23662.d new file mode 100644 index 0000000..884c399 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23662.d @@ -0,0 +1,8 @@ +// https://issues.dlang.org/show_bug.cgi?id=23662 +// EXTRA_FILES: imports/imp23662.c +import imports.imp23662; + +void main(string[] args) { + auto r = func(A); + assert(r == A); +} diff --git a/gcc/testsuite/gdc.test/compilable/test23676.d b/gcc/testsuite/gdc.test/compilable/test23676.d new file mode 100644 index 0000000..91a73b9 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/test23679.d b/gcc/testsuite/gdc.test/compilable/test23679.d new file mode 100644 index 0000000..9264d01 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test23679.d @@ -0,0 +1,3 @@ +// DISABLED: win32 +// https://issues.dlang.org/show_bug.cgi?id=23679 +ubyte [0x7fff_ffffU] arr; diff --git a/gcc/testsuite/gdc.test/compilable/test5973.d b/gcc/testsuite/gdc.test/compilable/test5973.d deleted file mode 100644 index a54b0ae..0000000 --- a/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/compilable/test6777.d b/gcc/testsuite/gdc.test/compilable/test6777.d deleted file mode 100644 index 161a94a..0000000 --- a/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/biterrors2.d b/gcc/testsuite/gdc.test/fail_compilation/biterrors2.d index c8390ba..77671eb 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/biterrors2.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/call_function_type.d b/gcc/testsuite/gdc.test/fail_compilation/call_function_type.d new file mode 100644 index 0000000..da60092 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/ctfeblock.d b/gcc/testsuite/gdc.test/fail_compilation/ctfeblock.d new file mode 100644 index 0000000..2d8bf7a --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/deprecate_getVirtualFunctions.d b/gcc/testsuite/gdc.test/fail_compilation/deprecate_getVirtualFunctions.d new file mode 100644 index 0000000..137482f --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/diag10099.d b/gcc/testsuite/gdc.test/fail_compilation/diag10099.d index cf1b645..4610924 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag10099.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/diag11132.d b/gcc/testsuite/gdc.test/fail_compilation/diag11132.d index 64db64d..0bdfe50 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag11132.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/diag12312.d b/gcc/testsuite/gdc.test/fail_compilation/diag12312.d index e015cfe..307c6be 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag12312.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/diag14235.d b/gcc/testsuite/gdc.test/fail_compilation/diag14235.d index 29261b4..8c563ba 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag14235.d +++ b/gcc/testsuite/gdc.test/fail_compilation/diag14235.d @@ -4,7 +4,7 @@ TEST_OUTPUT: --- fail_compilation/diag14235.d(12): Error: undefined identifier `Undefined` in module `imports.a14235` fail_compilation/diag14235.d(13): Error: undefined identifier `Something` in module `imports.a14235`, did you mean struct `SomeThing(T...)`? -fail_compilation/diag14235.d(14): Error: `imports.a14235.SomeClass` is not a template, it is a class +fail_compilation/diag14235.d(14): Error: `SomeClass` isn't a template --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag3438.d b/gcc/testsuite/gdc.test/fail_compilation/diag3438.d index c4cbc72..0e4fb8b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag3438.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/diag8101.d b/gcc/testsuite/gdc.test/fail_compilation/diag8101.d index 9644fdd..ddc74e2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag8101.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/diag9358.d b/gcc/testsuite/gdc.test/fail_compilation/diag9358.d index 5aea6b5..58dd495 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag9358.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/diag9679.d b/gcc/testsuite/gdc.test/fail_compilation/diag9679.d index 4496f0c..85923b7 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/diag9679.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/dip25.d b/gcc/testsuite/gdc.test/fail_compilation/dip25.d index 02f3140..f43a6e9e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/dip25.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/dip25flag.d b/gcc/testsuite/gdc.test/fail_compilation/dip25flag.d new file mode 100644 index 0000000..d75ceac --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/dip25flag.d @@ -0,0 +1,7 @@ +/* +REQUIRED_ARGS: -de -dip25 +TEST_OUTPUT: +--- +Deprecation: `-dip25` no longer has any effect +--- +*/ diff --git a/gcc/testsuite/gdc.test/fail_compilation/e15876_5.d b/gcc/testsuite/gdc.test/fail_compilation/e15876_5.d index 5b65b1b..96b23e2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/e15876_5.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/enum9921.d b/gcc/testsuite/gdc.test/fail_compilation/enum9921.d index 90d8802..51c8b1a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/enum9921.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/enum_init.d b/gcc/testsuite/gdc.test/fail_compilation/enum_init.d index ab6ba30..8344a47 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/enum_init.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail10102.d b/gcc/testsuite/gdc.test/fail_compilation/fail10102.d index 4847413..17577ec 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail10102.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail14406.d b/gcc/testsuite/gdc.test/fail_compilation/fail14406.d index 3725a91..f6c8fbb 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail14406.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail155.d b/gcc/testsuite/gdc.test/fail_compilation/fail155.d index 6d8f184..5f73f9a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail155.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail156.d b/gcc/testsuite/gdc.test/fail_compilation/fail156.d index bfc2383b..ccb3254 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail156.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail15616a.d b/gcc/testsuite/gdc.test/fail_compilation/fail15616a.d index e047365f..042eee1 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail15616a.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail15616c.d b/gcc/testsuite/gdc.test/fail_compilation/fail15616c.d new file mode 100644 index 0000000..092590e --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail15616d.d b/gcc/testsuite/gdc.test/fail_compilation/fail15616d.d new file mode 100644 index 0000000..a0f85a1 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail158.d b/gcc/testsuite/gdc.test/fail_compilation/fail158.d index 6f09f65..3253d16 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail158.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail17955.d b/gcc/testsuite/gdc.test/fail_compilation/fail17955.d index f33149e..95eb5cc 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail17955.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail19076.d b/gcc/testsuite/gdc.test/fail_compilation/fail19076.d index 9bfc0a5..2441d6f 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail19076.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail21243.d b/gcc/testsuite/gdc.test/fail_compilation/fail21243.d index 25df235..2e170d0 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail21243.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail22039.d b/gcc/testsuite/gdc.test/fail_compilation/fail22039.d new file mode 100644 index 0000000..3df834f --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail22570.d b/gcc/testsuite/gdc.test/fail_compilation/fail22570.d index cb8c286..e937a48 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail22570.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail233.d b/gcc/testsuite/gdc.test/fail_compilation/fail233.d deleted file mode 100644 index 7d4d978..0000000 --- a/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail23626a.d b/gcc/testsuite/gdc.test/fail_compilation/fail23626a.d new file mode 100644 index 0000000..2943f1a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23626a.d @@ -0,0 +1,16 @@ +/* TEST_OUTPUT: +--- +fail_compilation/fail23626a.d(10): Deprecation: function `fail23626a.ambig` cannot overload `extern(D)` function at fail_compilation/fail23626a.d(9) +fail_compilation/fail23626a.d(13): Deprecation: function `fail23626a.ambigC` cannot overload `extern(C)` function at fail_compilation/fail23626a.d(12) +fail_compilation/fail23626a.d(16): Error: function `fail23626a.ambigCxx(int a)` conflicts with previous declaration at fail_compilation/fail23626a.d(15) +--- +*/ + +extern(D) int ambig(int a) { return 0; } +extern(D) int ambig(int a) @system { return 1; } + +extern(C) int ambigC(int a) { return 2; } +extern(C) int ambigC(int a) @system { return 3; } + +extern(C++) int ambigCxx(int a) { return 4; } +extern(C++) int ambigCxx(int a) @system { return 5; } diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23626b.d b/gcc/testsuite/gdc.test/fail_compilation/fail23626b.d new file mode 100644 index 0000000..758a28b --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23626b.d @@ -0,0 +1,27 @@ +/* TEST_OUTPUT: +--- +fail_compilation/fail23626b.d(26): Error: `fail23626b.AmbigOpApply.opApply` called with argument types `(int delegate(int i) pure nothrow @nogc @system)` matches both: +fail_compilation/fail23626b.d(12): `fail23626b.AmbigOpApply.opApply(int delegate(int) dg)` +and: +fail_compilation/fail23626b.d(17): `fail23626b.AmbigOpApply.opApply(int delegate(int) dg)` +--- +*/ + +struct AmbigOpApply +{ + int opApply(int delegate(int) dg) + { + return 0; + } + + int opApply(int delegate(int) dg) @system + { + return 0; + } +} + +void ambigOpApply() @system +{ + AmbigOpApply sa; + foreach (int i; sa) { } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23745.d b/gcc/testsuite/gdc.test/fail_compilation/fail23745.d new file mode 100644 index 0000000..eda9e1e --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail23745.d @@ -0,0 +1,22 @@ +// https://issues.dlang.org/show_bug.cgi?id=2374 + +/* +TEST_OUTPUT: +--- +fail_compilation/fail23745.d(21): Error: undefined identifier `UndefinedType` +fail_compilation/fail23745.d(14): Error: function `fun` does not override any function, did you mean to override `fail23745.A.fun`? +fail_compilation/fail23745.d(21): Function `fail23745.A.fun` contains errors in its declaration, therefore it cannot be correctly overriden +--- +*/ + +class B : A +{ + override void fun() + { + } +} + +class A +{ + void fun(UndefinedType); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail253.d b/gcc/testsuite/gdc.test/fail_compilation/fail253.d index bee7e31..e6bfbed 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail253.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail299.d b/gcc/testsuite/gdc.test/fail_compilation/fail299.d index ffe5067..832a9a8 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail299.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail308.d b/gcc/testsuite/gdc.test/fail_compilation/fail308.d index d885b3e..603fe51 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail308.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail346.d b/gcc/testsuite/gdc.test/fail_compilation/fail346.d index 77042cc..5b51f54 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail346.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail4269a.d b/gcc/testsuite/gdc.test/fail_compilation/fail4269a.d index be59e1f..1ce9806 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail4269a.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail5851.d b/gcc/testsuite/gdc.test/fail_compilation/fail5851.d deleted file mode 100644 index 236a956..0000000 --- a/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d index 3fac167..f209592 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/failinout2.d b/gcc/testsuite/gdc.test/fail_compilation/failinout2.d index e155363..6fe8643 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/failinout2.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/failinout3748a.d b/gcc/testsuite/gdc.test/fail_compilation/failinout3748a.d deleted file mode 100644 index 77edb7e..0000000 --- a/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/failinout3748b.d b/gcc/testsuite/gdc.test/fail_compilation/failinout3748b.d deleted file mode 100644 index b6dddd8..0000000 --- a/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/failob1.d b/gcc/testsuite/gdc.test/fail_compilation/failob1.d index 7fe73d3..377125d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/failob1.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/failob2.d b/gcc/testsuite/gdc.test/fail_compilation/failob2.d index bd52648..c8a4c4d 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/failob2.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fnconstraint.d b/gcc/testsuite/gdc.test/fail_compilation/fnconstraint.d new file mode 100644 index 0000000..5862f7a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fnconstraint.d @@ -0,0 +1,25 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fnconstraint.d(13): Error: template constraint must follow parameter lists and attributes +fail_compilation/fnconstraint.d(13): Error: declaration expected, not `if` +fail_compilation/fnconstraint.d(22): Error: template constraint must follow parameter lists and attributes +fail_compilation/fnconstraint.d(22): Error: declaration expected, not `if` +fail_compilation/fnconstraint.d(26): Error: `}` expected following members in `struct` declaration at fail_compilation/fnconstraint.d(18) +--- +*/ +void foo()() +in(true) +if (true) +{} + +alias f = foo!(); + +struct S +{ + this()() + if (true) + if (true) {} +} + +S s; diff --git a/gcc/testsuite/gdc.test/fail_compilation/fob1.d b/gcc/testsuite/gdc.test/fail_compilation/fob1.d index 9dfcc4d..d11a7a6 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fob1.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/fob2.d b/gcc/testsuite/gdc.test/fail_compilation/fob2.d index 6f100ee..e9179da 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fob2.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d b/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d index 84d39eb..b571059 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/gag4269f.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/ice12727.d b/gcc/testsuite/gdc.test/fail_compilation/ice12727.d index bf6af7b..13eb8e0 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice12727.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/ice12902.d b/gcc/testsuite/gdc.test/fail_compilation/ice12902.d index ac43012..03763f7 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice12902.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/ice13788.d b/gcc/testsuite/gdc.test/fail_compilation/ice13788.d index 99f3c4a..3e3989b 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice13788.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/ice13816.d b/gcc/testsuite/gdc.test/fail_compilation/ice13816.d index e683e33..aefe273 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice13816.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/ice18753.d b/gcc/testsuite/gdc.test/fail_compilation/ice18753.d index 253025cd..f41ab3e 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice18753.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/ice23569.d b/gcc/testsuite/gdc.test/fail_compilation/ice23569.d index 277814f..6fdb71a 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/ice23569.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/issue16020.d b/gcc/testsuite/gdc.test/fail_compilation/issue16020.d index 75e3b9f..fe4ad78 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/issue16020.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/named_arguments_error.d b/gcc/testsuite/gdc.test/fail_compilation/named_arguments_error.d new file mode 100644 index 0000000..0900e60 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/named_arguments_overload.d b/gcc/testsuite/gdc.test/fail_compilation/named_arguments_overload.d new file mode 100644 index 0000000..a970446 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/named_arguments_parse.d b/gcc/testsuite/gdc.test/fail_compilation/named_arguments_parse.d new file mode 100644 index 0000000..19e230e --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/retscope6.d b/gcc/testsuite/gdc.test/fail_compilation/retscope6.d index 9736d37..5c581d1 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/retscope6.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/shared.d b/gcc/testsuite/gdc.test/fail_compilation/shared.d index 7d15b16..afdea64 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/shared.d +++ b/gcc/testsuite/gdc.test/fail_compilation/shared.d @@ -86,7 +86,7 @@ fail_compilation/shared.d(2148): Error: direct access to shared `*c` is not allo fail_compilation/shared.d(2154): Error: direct access to shared `*c.c1` is not allowed, see `core.atomic` fail_compilation/shared.d(2160): Error: direct access to shared `*c.c1.c1` is not allowed, see `core.atomic` fail_compilation/shared.d(2181): Error: direct access to shared `k` is not allowed, see `core.atomic` -fail_compilation/shared.d(2187): Error: direct access to shared `k.k2.k1` is not allowed, see `core.atomic` +fail_compilation/shared.d(2187): Error: direct access to shared `k.k2.k1.value` is not allowed, see `core.atomic` fail_compilation/shared.d(2194): Error: direct access to shared `(new shared(K2)).k1` is not allowed, see `core.atomic` fail_compilation/shared.d(2202): Error: direct access to shared `c` is not allowed, see `core.atomic` fail_compilation/shared.d(2206): Error: function `shared.test_inference_2` function returns `shared` but cannot be inferred `ref` @@ -236,3 +236,26 @@ 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; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15368.d b/gcc/testsuite/gdc.test/fail_compilation/test15368.d new file mode 100644 index 0000000..ab12e86 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test15368.d @@ -0,0 +1,14 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/test15368.d(13): Error: cannot declare `auto` loop variable, omit `auto` to still get type inference +--- +*/ + +// Issue 15368 - Improve error message for "auto" keyword inside "foreach" +// https://issues.dlang.org/show_bug.cgi?id=15368 + +void main() +{ + foreach (auto e; foo) { } +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16495.d b/gcc/testsuite/gdc.test/fail_compilation/test16495.d new file mode 100644 index 0000000..667d4c2 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/test17096.d b/gcc/testsuite/gdc.test/fail_compilation/test17096.d index e421419..2c431a3 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test17096.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/test17451.d b/gcc/testsuite/gdc.test/fail_compilation/test17451.d index a7ef88a..b0cda21 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test17451.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/test20549.d b/gcc/testsuite/gdc.test/fail_compilation/test20549.d index 2cafc1b..dc95da1 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test20549.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/test20719.d b/gcc/testsuite/gdc.test/fail_compilation/test20719.d index 44d3d5a..b9305f2 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test20719.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/test20809.d b/gcc/testsuite/gdc.test/fail_compilation/test20809.d index 44728c5..0b45277 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test20809.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/test20998.d b/gcc/testsuite/gdc.test/fail_compilation/test20998.d index 16eb026..2e137ab 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test20998.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/test22593.d b/gcc/testsuite/gdc.test/fail_compilation/test22593.d deleted file mode 100644 index a47c0fe..0000000 --- a/gcc/testsuite/gdc.test/fail_compilation/test22593.d +++ /dev/null @@ -1,23 +0,0 @@ -// https://issues.dlang.org/show_bug.cgi?id=22593 - -/* -TEST_OUTPUT: ---- -fail_compilation/test22593.d(14): Error: cannot define both an rvalue constructor and a copy constructor for `struct Foo` -fail_compilation/test22593.d(22): Template instance `__ctor!(immutable(Foo!int), immutable(Foo!int))` creates a rvalue constructor for `struct Foo` -fail_compilation/test22593.d(22): Error: template instance `test22593.Foo!int.Foo.__ctor!(immutable(Foo!int), immutable(Foo!int))` error instantiating ---- -*/ - -struct Foo(T) -{ - this(Rhs, this This)(scope Rhs rhs){} - - this(ref scope typeof(this) rhs){} -} - -void main() -{ - immutable Foo!int a; - a.__ctor(a); -} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23607.d b/gcc/testsuite/gdc.test/fail_compilation/test23607.d new file mode 100644 index 0000000..69b6f39 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test23607.d @@ -0,0 +1,16 @@ +//https://issues.dlang.org/show_bug.cgi?id=23607 +/* +TEST_OUTPUT: +--- +fail_compilation/test23607.d(15): Error: template `to(T)()` does not have property `bad` +fail_compilation/test23607.d(16): Error: template `to(T)()` does not have property `bad` +--- +*/ + +template to(T) +{ + void to(T)(){} +} + +alias comb = to!int.bad!0; +auto combe = to!int.bad!0; diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23674.d b/gcc/testsuite/gdc.test/fail_compilation/test23674.d new file mode 100644 index 0000000..0f11de9 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test23674.d @@ -0,0 +1,15 @@ +// https://issues.dlang.org/show_bug.cgi?id=23674 + +/* +TEST_OUTPUT: +--- +fail_compilation/test23674.d(14): Error: array index 2 is out of bounds `arr[0 .. 2]` +fail_compilation/test23674.d(14): Error: array index 3 is out of bounds `arr[0 .. 2]` +--- +*/ + +void main() +{ + string[2] arr; + assert(arr[2] == arr[3]); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23710.d b/gcc/testsuite/gdc.test/fail_compilation/test23710.d new file mode 100644 index 0000000..e834b78 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d b/gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d index bfd8803..41b6e52 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d b/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d new file mode 100644 index 0000000..96511f5 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d @@ -0,0 +1,47 @@ +// https://issues.dlang.org/show_bug.cgi?id=22593 + +/* +TEST_OUTPUT: +--- +fail_compilation/testrvaluecpctor.d(16): Error: cannot define both an rvalue constructor and a copy constructor for `struct Foo` +fail_compilation/testrvaluecpctor.d(24): Template instance `testrvaluecpctor.Foo!int.Foo.__ctor!(immutable(Foo!int), immutable(Foo!int))` creates an rvalue constructor for `struct Foo` +fail_compilation/testrvaluecpctor.d(24): Error: none of the overloads of `__ctor` are callable using a `immutable` object +fail_compilation/testrvaluecpctor.d(18): Candidates are: `testrvaluecpctor.Foo!int.Foo.this(ref Foo!int rhs)` +fail_compilation/testrvaluecpctor.d(16): `__ctor(Rhs, this This)(scope Rhs rhs)` +--- +*/ + +struct Foo(T) +{ + this(Rhs, this This)(scope Rhs rhs){} + + this(ref scope typeof(this) rhs){} +} + +void fail22593() +{ + immutable Foo!int a; + a.__ctor(a); +} + +// https://issues.dlang.org/show_bug.cgi?id=21613 + +/* +TEST_OUTPUT: +--- +fail_compilation/testrvaluecpctor.d(40): Error: cannot define both an rvalue constructor and a copy constructor for `struct Test` +fail_compilation/testrvaluecpctor.d(46): Template instance `testrvaluecpctor.Test.__ctor!()` creates an rvalue constructor for `struct Test` +--- +*/ + +struct Test +{ + this(ref const typeof(this) rhs){} + this()(const typeof(this) rhs){} // rvalue ctor +} + +void fail21613() +{ + const Test cb; + Test b = cb; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/testscopestatic.d b/gcc/testsuite/gdc.test/fail_compilation/testscopestatic.d index 86c6328..cc7b012 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/testscopestatic.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/fail_compilation/udaparams.d b/gcc/testsuite/gdc.test/fail_compilation/udaparams.d index ec47967..453ebba 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/udaparams.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/aliasthis.d b/gcc/testsuite/gdc.test/runnable/aliasthis.d index db5913c..50e5c4d 100644 --- a/gcc/testsuite/gdc.test/runnable/aliasthis.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/auto1.d b/gcc/testsuite/gdc.test/runnable/auto1.d index 6ee0750..af95545 100644 --- a/gcc/testsuite/gdc.test/runnable/auto1.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/cppdtor.d b/gcc/testsuite/gdc.test/runnable/cppdtor.d index 0592d44..711f309 100644 --- a/gcc/testsuite/gdc.test/runnable/cppdtor.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/e7804.d b/gcc/testsuite/gdc.test/runnable/e7804.d index d325310..ff66310 100644 --- a/gcc/testsuite/gdc.test/runnable/e7804.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/extra-files/test11051.d b/gcc/testsuite/gdc.test/runnable/extra-files/test11051.d new file mode 100644 index 0000000..c8bfdc2 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/funclit.d b/gcc/testsuite/gdc.test/runnable/funclit.d index 25b4e6e..e6e4fec1 100644 --- a/gcc/testsuite/gdc.test/runnable/funclit.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/imports/freer.i b/gcc/testsuite/gdc.test/runnable/imports/freer.i new file mode 100644 index 0000000..57e8792 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/imports/freer.i @@ -0,0 +1,5 @@ +typedef struct Foo *FooRef; +struct Foo { + int x; +}; +void free_foo(FooRef foo) { } diff --git a/gcc/testsuite/gdc.test/runnable/imports/maker.i b/gcc/testsuite/gdc.test/runnable/imports/maker.i new file mode 100644 index 0000000..d3a7d94 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/interpret.d b/gcc/testsuite/gdc.test/runnable/interpret.d index 16d4c55..f9972f2 100644 --- a/gcc/testsuite/gdc.test/runnable/interpret.d +++ b/gcc/testsuite/gdc.test/runnable/interpret.d @@ -4,6 +4,7 @@ TEST_OUTPUT: true g &Test109S(&Test109S(<recursion>)) +runnable/interpret.d(3742): Deprecation: alias this for classes/interfaces is deprecated tfoo tfoo Crash! diff --git a/gcc/testsuite/gdc.test/runnable/issue22854.d b/gcc/testsuite/gdc.test/runnable/issue22854.d index c4cae17..155144b 100644 --- a/gcc/testsuite/gdc.test/runnable/issue22854.d +++ b/gcc/testsuite/gdc.test/runnable/issue22854.d @@ -2,12 +2,12 @@ void main() { uint loops = 0; - static foreach (i; 0 .. 50) + static foreach (i; 0 .. 5) { static foreach (ch; SomeContainer().range) loops++; } - assert(loops == 50 * 50); + assert(loops == 5 * 5); } struct SomeContainer @@ -20,7 +20,7 @@ struct TypeWithDestructor { ~this() { } } struct SomeRange { - int count = 50; + int count = 5; int front() { return count; } bool empty() { return count <= 0; } void popFront() { count--; } diff --git a/gcc/testsuite/gdc.test/runnable/mars1.d b/gcc/testsuite/gdc.test/runnable/mars1.d index c981334..b24eced 100644 --- a/gcc/testsuite/gdc.test/runnable/mars1.d +++ b/gcc/testsuite/gdc.test/runnable/mars1.d @@ -617,6 +617,17 @@ void test11565() assert(cond11565(true) == size_t.max); } +// https://issues.dlang.org/show_bug.cgi?id=23743 +void test23743() +{ + ubyte[] a = [1]; + foreach (x; a) + { + ubyte v = x >= 1 ? 255 : 0; + assert(v == 255); + } +} + /////////////////////// int[3] array1 = [1:1,2,0:3]; @@ -2498,6 +2509,7 @@ int main() testdocond(); testnegcom(); test11565(); + test23743(); testoror(); testbt(); test12095(0); diff --git a/gcc/testsuite/gdc.test/runnable/mixin2.d b/gcc/testsuite/gdc.test/runnable/mixin2.d index 7679bbe..70bf051 100644 --- a/gcc/testsuite/gdc.test/runnable/mixin2.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test15985.d b/gcc/testsuite/gdc.test/runnable/test15985.d new file mode 100644 index 0000000..dbf4f4b --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test16098.d b/gcc/testsuite/gdc.test/runnable/test16098.d index 16b34f1..a5af2d5 100644 --- a/gcc/testsuite/gdc.test/runnable/test16098.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test17684.d b/gcc/testsuite/gdc.test/runnable/test17684.d index efdce08..e102655 100644 --- a/gcc/testsuite/gdc.test/runnable/test17684.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test18472.d b/gcc/testsuite/gdc.test/runnable/test18472.d new file mode 100644 index 0000000..a571b08 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test19782.d b/gcc/testsuite/gdc.test/runnable/test19782.d index a24d841..61a168b 100644 --- a/gcc/testsuite/gdc.test/runnable/test19782.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test19946.d b/gcc/testsuite/gdc.test/runnable/test19946.d new file mode 100644 index 0000000..9f9d3bc --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test20520.d b/gcc/testsuite/gdc.test/runnable/test20520.d new file mode 100644 index 0000000..dd45266 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test20520.d @@ -0,0 +1,13 @@ +// https://issues.dlang.org/show_bug.cgi?id=20520 + +class C {} + +enum Foo { + Bar = new C() +} + +void main() +{ + //pragma(msg, typeid(Foo.Bar)); // Works fine: typeid(C()) + auto t = typeid(Foo.Bar); // Segfault here +} diff --git a/gcc/testsuite/gdc.test/runnable/test20855.d b/gcc/testsuite/gdc.test/runnable/test20855.d index 30152fe..1d2ae50 100644 --- a/gcc/testsuite/gdc.test/runnable/test20855.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test21039.d b/gcc/testsuite/gdc.test/runnable/test21039.d index c58600f..f32267a 100644 --- a/gcc/testsuite/gdc.test/runnable/test21039.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test21772.d b/gcc/testsuite/gdc.test/runnable/test21772.d new file mode 100644 index 0000000..dcb7b80 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test21821.d b/gcc/testsuite/gdc.test/runnable/test21821.d new file mode 100644 index 0000000..d16331d --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test23.d b/gcc/testsuite/gdc.test/runnable/test23.d index f1fd4a6..cb951c1 100644 --- a/gcc/testsuite/gdc.test/runnable/test23.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test23234.d b/gcc/testsuite/gdc.test/runnable/test23234.d index 7872aa7..f974864 100644 --- a/gcc/testsuite/gdc.test/runnable/test23234.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test23387.d b/gcc/testsuite/gdc.test/runnable/test23387.d new file mode 100644 index 0000000..4419cf1 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test23514.d b/gcc/testsuite/gdc.test/runnable/test23514.d new file mode 100644 index 0000000..1ba7e21 --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test23514.d @@ -0,0 +1,13 @@ +// DISABLED: win64 +// https://issues.dlang.org/show_bug.cgi?id=23514 + +// Note: this test is disabled on Win64 because of an issue with the Windows +// MS-COFF backend causing it to fail. + +enum ulong offset = 0xFFFF_FFFF_0000_0000UL; + +void main() +{ + ulong voffset = offset; + assert((cast(ulong)&main + voffset) == (cast(ulong)&main + offset)); +} diff --git a/gcc/testsuite/gdc.test/runnable/test23618.d b/gcc/testsuite/gdc.test/runnable/test23618.d new file mode 100644 index 0000000..7cde3ff --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test23618.d @@ -0,0 +1,30 @@ + +// https://issues.dlang.org/show_bug.cgi?id=23618 + +import core.stdc.stdio; + +uint test1() +{ + ushort ee = 1028; + ee <<= 5U; + ee >>= 5U; + assert(ee == 1028); + //printf("%x, %d\n", ee, ee); + return ee; +} + +uint test2() +{ + ubyte ee = 4; + ee <<= 5U; + ee >>= 5U; + //printf("%x, %d\n", ee, ee); + assert(ee == 4); + return ee; +} + +void main() +{ + test1(); + test2(); +} diff --git a/gcc/testsuite/gdc.test/runnable/test23650.d b/gcc/testsuite/gdc.test/runnable/test23650.d new file mode 100644 index 0000000..3ce8f5f --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test23710.d b/gcc/testsuite/gdc.test/runnable/test23710.d new file mode 100644 index 0000000..05ab1e4 --- /dev/null +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/test34.d b/gcc/testsuite/gdc.test/runnable/test34.d index 11543f1..df46137 100644 --- a/gcc/testsuite/gdc.test/runnable/test34.d +++ b/gcc/testsuite/gdc.test/runnable/test34.d @@ -1,5 +1,3 @@ -// REQUIRED_ARGS: -d - module test34; import core.exception; diff --git a/gcc/testsuite/gdc.test/runnable/test8.d b/gcc/testsuite/gdc.test/runnable/test8.d index d65ba0e..f100762 100644 --- a/gcc/testsuite/gdc.test/runnable/test8.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/testaliascast.d b/gcc/testsuite/gdc.test/runnable/testaliascast.d index c55f820..ed5091d 100644 --- a/gcc/testsuite/gdc.test/runnable/testaliascast.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/testassign.d b/gcc/testsuite/gdc.test/runnable/testassign.d index 586aea8..79a4c57 100644 --- a/gcc/testsuite/gdc.test/runnable/testassign.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/testdstress.d b/gcc/testsuite/gdc.test/runnable/testdstress.d index 03af207..269949f 100644 --- a/gcc/testsuite/gdc.test/runnable/testdstress.d +++ b/gcc/testsuite/gdc.test/runnable/testdstress.d @@ -494,7 +494,7 @@ void test23() int status24; class C24{ - this(){ + this() scope { assert(status24==0); status24+=2; } diff --git a/gcc/testsuite/gdc.test/runnable/traits.d b/gcc/testsuite/gdc.test/runnable/traits.d index ddd5059..5186987 100644 --- a/gcc/testsuite/gdc.test/runnable/traits.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/traits_getPointerBitmap.d b/gcc/testsuite/gdc.test/runnable/traits_getPointerBitmap.d index 8996c9e..ffa0b80 100644 --- a/gcc/testsuite/gdc.test/runnable/traits_getPointerBitmap.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable/xtest46.d b/gcc/testsuite/gdc.test/runnable/xtest46.d index a0907f4..e57f52f 100644 --- a/gcc/testsuite/gdc.test/runnable/xtest46.d +++ b/gcc/testsuite/gdc.test/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(<recursion>))) @@ -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() diff --git a/gcc/testsuite/gdc.test/runnable/xtest46_gc.d b/gcc/testsuite/gdc.test/runnable/xtest46_gc.d index b0288a2..224625c 100644 --- a/gcc/testsuite/gdc.test/runnable/xtest46_gc.d +++ b/gcc/testsuite/gdc.test/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(<recursion>)) @@ -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/gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d b/gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d index c677d6e..c0f4e6d 100644 --- a/gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable_cxx/cppa.d b/gcc/testsuite/gdc.test/runnable_cxx/cppa.d index cd91dd5..cb268af 100644 --- a/gcc/testsuite/gdc.test/runnable_cxx/cppa.d +++ b/gcc/testsuite/gdc.test/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; @@ -1115,83 +1061,99 @@ void test15576() /****************************************/ // https://issues.dlang.org/show_bug.cgi?id=15579 -extern (C++) +version (DigitalMars) { - class Base - { - //~this() {} - void based() { } - ubyte x = 4; - } - - interface Interface + version (linux) { - int MethodCPP(); - int MethodD(); + // Test removed for DMD/linux-only. + // https://issues.dlang.org/show_bug.cgi?id=23660 } + else + version = TEST15579; +} +else + version = TEST15579; - class Derived : Base, Interface +version (TEST15579) +{ + extern (C++) { - 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; + class Base + { + //~this() {} + void based() { } + ubyte x = 4; } - int Method() { return 6; } - } - - 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); + interface Interface + { + int MethodCPP(); + int MethodD(); + } - d = cppfoo(d); - assert(d.x == 7); - assert(d.y == 8); + 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; } + } - printf("d2 = %p\n", d); + Derived cppfoo(Derived); + Interface cppfooi(Interface); + } - /* 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"); } /****************************************/ @@ -1362,7 +1324,7 @@ extern(C++) class Cpp15589Derived : Cpp15589Base { public: - this(); + this() scope; final ~this(); int b; } @@ -1372,7 +1334,7 @@ extern(C++) public: void beforeDtor(); - this(); + this() scope; ~this(); void afterDtor(); @@ -1382,7 +1344,7 @@ extern(C++) class Cpp15589DerivedVirtual : Cpp15589BaseVirtual { public: - this(); + this() scope; ~this(); override void afterDtor(); @@ -1393,7 +1355,7 @@ extern(C++) class Cpp15589IntroducingVirtual : Cpp15589Base { public: - this(); + this() scope; void beforeIntroducedVirtual(); ~this(); void afterIntroducedVirtual(int); @@ -1699,7 +1661,7 @@ void main() testeh2(); testeh3(); test15576(); - test15579(); + version (TEST15579) test15579(); test15610(); test15455(); test15372(); diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_abi_tests.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_abi_tests.cpp index 8ba6139..e1dcc28 100644 --- a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_abi_tests.cpp +++ b/gcc/testsuite/gdc.test/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/gcc/testsuite/gdc.test/runnable_cxx/test22898.d b/gcc/testsuite/gdc.test/runnable_cxx/test22898.d index 3250623..f6890e0 100644 --- a/gcc/testsuite/gdc.test/runnable_cxx/test22898.d +++ b/gcc/testsuite/gdc.test/runnable_cxx/test22898.d @@ -4,14 +4,26 @@ import core.stdc.config; extern(C++): -version (AArch64) version = UnsignedChar; -version (ARM) version = UnsignedChar; -version (RISCV32) version = UnsignedChar; -version (RISCV64) version = UnsignedChar; -version (PPC) version = UnsignedChar; -version (PPC64) version = UnsignedChar; -version (S390) version = UnsignedChar; -version (SystemZ) version = UnsignedChar; +version (OSX) + version = Darwin; +else version (iOS) + version = Darwin; +else version (TVOS) + version = Darwin; +else version (WatchOS) + version = Darwin; + +version (Darwin) { /* signed on ARM too */ } else +{ + version (AArch64) version = UnsignedChar; + version (ARM) version = UnsignedChar; + version (RISCV32) version = UnsignedChar; + version (RISCV64) version = UnsignedChar; + version (PPC) version = UnsignedChar; + version (PPC64) version = UnsignedChar; + version (S390) version = UnsignedChar; + version (SystemZ) version = UnsignedChar; +} version (UnsignedChar) enum __c_char : ubyte; |