From patchwork Wed Dec 15 19:02:28 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Iain Buclaw X-Patchwork-Id: 48987 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id D11093858D28 for ; Wed, 15 Dec 2021 19:04:12 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org D11093858D28 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1639595052; bh=PDqM2lk0dZg0dNOHRYQkUXsXSJaKduLA85z94i8a/T4=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:From; b=l5FN07ZBHhu42qHstxRpEMShvCPAPUM/7r5XGE9BiMevKo6N4LAOnH0qlm+nPCxye W7spfOS/V2OdAzSstiNA/BGveVw8B6+KUq+8XBLv/JSzQL8lXwix/M4GP6JuZbLvit kyr/tknkDmfp4ZcocVKaYdA+62vhEm0IFsdH+kpA= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mout-p-201.mailbox.org (mout-p-201.mailbox.org [80.241.56.171]) by sourceware.org (Postfix) with ESMTPS id EA3253858D28 for ; Wed, 15 Dec 2021 19:03:21 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org EA3253858D28 Received: from smtp2.mailbox.org (smtp2.mailbox.org [80.241.60.241]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-384) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-p-201.mailbox.org (Postfix) with ESMTPS id 4JDl5420nSzQjxM; Wed, 15 Dec 2021 20:03:20 +0100 (CET) X-Virus-Scanned: amavisd-new at heinlein-support.de To: gcc-patches@gcc.gnu.org Subject: [committed] d: Merge upstream dmd 93108bb9e, druntime 6364e010, phobos 575b67a9b. Date: Wed, 15 Dec 2021 20:02:28 +0100 Message-Id: <20211215190228.3748714-1-ibuclaw@gdcproject.org> MIME-Version: 1.0 X-Spam-Status: No, score=-14.6 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_STOCKGEN, RCVD_IN_DNSWL_LOW, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Iain Buclaw via Gcc-patches From: Iain Buclaw Reply-To: Iain Buclaw Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Hi, This patch merges the D front-end implementation with upstream dmd 93108bb9e, and the D run-time libraries with druntime 6364e010 and phobos 575b67a9b. The internal version of the language has been bumped to v2.098.1-beta.1. D front-end changes: - Import dmd v2.098.1-beta.1. - Default extern(C++) compatibility to C++17. Druntime changes: - Import druntime v2.098.1-beta.1. - Fix definition of stat_t on MIPS64 (PR103604) Phobos changes: - Import phobos v2.098.1-beta.1. Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32, and committed to mainline. Regards, Iain. --- gcc/d/ChangeLog: * d-lang.cc (d_init_options): Set default -fextern-std= to C++17. * dmd/MERGE: Merge upstream dmd 93108bb9e. * gdc.texi (Runtime Options): Document the default for -fextern-std=. libphobos/ChangeLog: PR d/103604 * configure: Regenerate. * configure.ac (libtool_VERSION): Update to 3:0:0. * libdruntime/MERGE: Merge upstream druntime 6364e010. * src/MERGE: Merge upstream phobos 575b67a9b. * testsuite/libphobos.traits/all_satisfy.d: New test. * testsuite/libphobos.traits/traits.exp: New test. --- gcc/d/d-lang.cc | 4 +- gcc/d/dmd/MERGE | 2 +- gcc/d/dmd/VERSION | 2 +- gcc/d/dmd/constfold.d | 20 +- gcc/d/dmd/cparse.d | 36 +- gcc/d/dmd/ctfeexpr.d | 11 +- gcc/d/dmd/dinterpret.d | 2 +- gcc/d/dmd/dsymbol.d | 55 ++- gcc/d/dmd/dsymbol.h | 1 + gcc/d/dmd/dsymbolsem.d | 7 +- gcc/d/dmd/dtemplate.d | 14 + gcc/d/dmd/expression.d | 2 +- gcc/d/dmd/expressionsem.d | 79 ++-- gcc/d/dmd/importc.d | 93 ++++- gcc/d/dmd/initsem.d | 13 +- gcc/d/dmd/lexer.d | 18 +- gcc/d/dmd/opover.d | 18 +- gcc/d/dmd/optimize.d | 55 +++ gcc/d/dmd/parse.d | 21 +- gcc/d/dmd/printast.d | 27 ++ gcc/d/dmd/semantic3.d | 12 + gcc/d/dmd/statementsem.d | 111 +++--- gcc/d/dmd/target.d | 2 +- gcc/d/dmd/target.h | 1 + gcc/d/dmd/tokens.d | 72 +--- gcc/d/dmd/tokens.h | 26 -- gcc/d/dmd/typesem.d | 33 +- gcc/d/gdc.texi | 11 +- gcc/testsuite/gdc.test/compilable/cppmangle.d | 371 ++++++++++-------- .../gdc.test/compilable/cppmangle3.d | 9 +- .../gdc.test/compilable/issue21203.d | 210 ++++++++++ .../gdc.test/compilable/issue21340.d | 38 ++ gcc/testsuite/gdc.test/compilable/test10028.d | 7 + gcc/testsuite/gdc.test/compilable/test20236.d | 22 ++ gcc/testsuite/gdc.test/compilable/test20860.d | 16 + gcc/testsuite/gdc.test/compilable/test21073.d | 16 + gcc/testsuite/gdc.test/compilable/test21414.d | 13 + .../gdc.test/fail_compilation/b15875.d | 2 +- .../gdc.test/fail_compilation/fail116.d | 2 +- .../gdc.test/fail_compilation/fail20616.d | 26 ++ .../gdc.test/fail_compilation/fail22529.d | 14 + .../gdc.test/fail_compilation/fail22570.d | 21 + .../gdc.test/fail_compilation/ice22516.d | 21 + .../gdc.test/fail_compilation/test22574.d | 12 + .../fail_compilation/test_switch_error.d | 101 +++++ gcc/testsuite/gdc.test/runnable/interpret.d | 23 ++ gcc/testsuite/gdc.test/runnable/test16579.d | 57 +++ gcc/testsuite/gdc.test/runnable/test18054.d | 41 ++ gcc/testsuite/gdc.test/runnable_cxx/cppa.d | 59 ++- .../runnable_cxx/extra-files/cppb.cpp | 33 -- libphobos/configure | 2 +- libphobos/configure.ac | 2 +- libphobos/libdruntime/MERGE | 2 +- libphobos/libdruntime/core/internal/traits.d | 40 +- libphobos/libdruntime/core/lifetime.d | 109 ++++- libphobos/libdruntime/core/runtime.d | 2 +- .../libdruntime/core/sys/openbsd/execinfo.d | 139 +------ .../libdruntime/core/sys/posix/sys/stat.d | 46 ++- libphobos/libdruntime/object.d | 2 +- libphobos/libdruntime/rt/monitor_.d | 36 +- libphobos/src/MERGE | 2 +- libphobos/src/std/algorithm/searching.d | 12 +- libphobos/src/std/datetime/timezone.d | 3 +- libphobos/src/std/parallelism.d | 6 +- libphobos/src/std/regex/package.d | 16 +- libphobos/src/std/traits.d | 5 + .../testsuite/libphobos.traits/all_satisfy.d | 24 ++ .../testsuite/libphobos.traits/traits.exp | 27 ++ 68 files changed, 1662 insertions(+), 675 deletions(-) create mode 100644 gcc/testsuite/gdc.test/compilable/issue21203.d create mode 100644 gcc/testsuite/gdc.test/compilable/issue21340.d create mode 100644 gcc/testsuite/gdc.test/compilable/test10028.d create mode 100644 gcc/testsuite/gdc.test/compilable/test20236.d create mode 100644 gcc/testsuite/gdc.test/compilable/test20860.d create mode 100644 gcc/testsuite/gdc.test/compilable/test21073.d create mode 100644 gcc/testsuite/gdc.test/compilable/test21414.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail20616.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail22529.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail22570.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice22516.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test22574.d create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d create mode 100644 gcc/testsuite/gdc.test/runnable/test16579.d create mode 100644 gcc/testsuite/gdc.test/runnable/test18054.d create mode 100644 libphobos/testsuite/libphobos.traits/all_satisfy.d create mode 100644 libphobos/testsuite/libphobos.traits/traits.exp diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 2c5d206a95f..d7621953b54 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -297,8 +297,8 @@ d_init_options (unsigned int, cl_decoded_option *decoded_options) global.params.argv0 = xstrdup (decoded_options[0].arg); global.params.errorLimit = flag_max_errors; - /* Default extern(C++) mangling to C++14. */ - global.params.cplusplus = CppStdRevisionCpp14; + /* Default extern(C++) mangling to C++17. */ + global.params.cplusplus = CppStdRevisionCpp17; /* Warnings and deprecations are disabled by default. */ global.params.useDeprecated = DIAGNOSTICinform; diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 4bae16c86eb..d7eff4ffd2f 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -3982604c54e8770585985a33577fbf19b9b5c9ce +93108bb9ea6216d67fa97bb4842fb59f26f6bfc7 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/VERSION b/gcc/d/dmd/VERSION index fa5940ed249..822edd4637a 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.098.0 +v2.098.1-beta.1 diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 3ca23f24d7e..3cc358e19bf 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -1054,6 +1054,12 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1) emplaceExp!(UnionExp)(&ue, ex); return ue; } + if (e1.type.toBasetype.equals(type) && type.equals(to)) + { + emplaceExp!(UnionExp)(&ue, e1); + ue.exp().type = type; + return ue; + } if (e1.type.implicitConvTo(to) >= MATCH.constant || to.implicitConvTo(e1.type) >= MATCH.constant) { goto L1; @@ -1087,7 +1093,19 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1) } else if (tb.ty == Tbool) { - emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() != 0, type); + bool val = void; + const opt = e1.toBool(); + if (opt.hasValue(true)) + val = true; + else if (opt.hasValue(false)) + val = false; + else + { + cantExp(ue); + return ue; + } + + emplaceExp!(IntegerExp)(&ue, loc, val, type); } else if (type.isintegral()) { diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index dfc45e0bc31..b1532adb6a0 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -975,12 +975,17 @@ final class CParser(AST) : Parser!AST token.value == TOK.leftParenthesis && !isCastExpression(pt)) { - /* this might actually be a function - * call that looks like `(a)(b)` or even `(a)(b,c)` + /* (t)(...)... might be a cast expression or a function call, + * with different grammars: a cast would be cparseCastExp(), + * a function call would be cparsePostfixExp(CallExp(cparseArguments())). + * We can't know until t is known. So, parse it as a function call + * and let semantic() rewrite the AST as a CastExp if it turns out + * to be a type. */ auto ie = new AST.IdentifierExp(loc, t.isTypeIdentifier().ident); - ie.parens = true; // disambiguate it from being a declaration - return new AST.CallExp(loc, ie, cparseArguments()); + ie.parens = true; // let semantic know it might be a CastExp + AST.Expression e = new AST.CallExp(loc, ie, cparseArguments()); + return cparsePostfixOperators(e); } else { @@ -1483,9 +1488,12 @@ final class CParser(AST) : Parser!AST /* If a declarator does not follow, it is unnamed */ - if (token.value == TOK.semicolon && tspec) + if (token.value == TOK.semicolon) { nextToken(); + if (!tspec) + return; // accept empty declaration as an extension + auto tt = tspec.isTypeTag(); if (!tt || !tt.id && (tt.tok == TOK.struct_ || tt.tok == TOK.union_)) @@ -1662,7 +1670,8 @@ final class CParser(AST) : Parser!AST { // Give non-extern variables an implicit void initializer // if one has not been explicitly set. - if (!hasInitializer && !(specifier.scw & SCW.xextern)) + if (!hasInitializer && + !(specifier.scw & (SCW.xextern | SCW.xstatic | SCW.x_Thread_local) || level == LVL.global)) initializer = new AST.VoidInitializer(token.loc); s = new AST.VarDeclaration(token.loc, dt, id, initializer, specifiersToSTC(level, specifier)); } @@ -2492,7 +2501,18 @@ final class CParser(AST) : Parser!AST return t; } - t = constApply(t); + if (declarator == DTR.xparameter && + t.isTypePointer()) + { + /* Because there are instances in .h files of "const pointer to mutable", + * skip applying transitive `const` + * https://issues.dlang.org/show_bug.cgi?id=22534 + */ + auto tn = cast(AST.TypeNext)t; + tn.next = constApply(tn.next); + } + else + t = constApply(t); } //printf("result: %s\n", t.toChars()); @@ -2610,6 +2630,8 @@ final class CParser(AST) : Parser!AST Identifier id; auto t = cparseDeclarator(DTR.xparameter, tspec, id, specifier); + if (token.value == TOK.__attribute__) + cparseGnuAttributes(specifier); if (specifier.mod & MOD.xconst) t = toConst(t); auto param = new AST.Parameter(STC.parameter, t, id, null, null); diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d index 9cd09bab643..baacaa6e9be 100644 --- a/gcc/d/dmd/ctfeexpr.d +++ b/gcc/d/dmd/ctfeexpr.d @@ -1574,7 +1574,7 @@ Expression ctfeIndex(UnionExp* pue, const ref Loc loc, Type type, Expression e1, assert(0); } -Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expression e) +Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expression e, bool explicitCast = false) { Expression paint() { @@ -1587,9 +1587,12 @@ Expression ctfeCast(UnionExp* pue, const ref Loc loc, Type type, Type to, Expres if (e.op == EXP.classReference) { // Disallow reinterpreting class casts. Do this by ensuring that - // the original class can implicitly convert to the target class - ClassDeclaration originalClass = (cast(ClassReferenceExp)e).originalClass(); - if (originalClass.type.implicitConvTo(to.mutableOf())) + // the original class can implicitly convert to the target class. + // Also do not check 'alias this' for explicit cast expressions. + auto tclass = (cast(ClassReferenceExp)e).originalClass().type.isTypeClass(); + auto match = explicitCast ? tclass.implicitConvToWithoutAliasThis(to.mutableOf()) + : tclass.implicitConvTo(to.mutableOf()); + if (match) return paint(); else { diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d index 891adb3c6bd..8f20c38f6f1 100644 --- a/gcc/d/dmd/dinterpret.d +++ b/gcc/d/dmd/dinterpret.d @@ -6068,7 +6068,7 @@ public: result = pue.exp(); return; } - result = ctfeCast(pue, e.loc, e.type, e.to, e1); + result = ctfeCast(pue, e.loc, e.type, e.to, e1, true); } override void visit(AssertExp e) diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index b1d1b1d8d7c..0f75157f874 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -462,6 +462,21 @@ extern (C++) class Dsymbol : ASTNode return null; } + /************************************** + * Does this Dsymbol come from a C file? + * Returns: + * true if it does + */ + final bool isCsymbol() + { + if (Module m = getModule()) + { + if (m.isCFile) + return true; + } + return false; + } + /********************************** * Determine which Module a Dsymbol is in, as far as access rights go. */ @@ -1783,7 +1798,7 @@ extern (C++) final class WithScopeSymbol : ScopeDsymbol // Acts as proxy to the with class declaration Dsymbol s = null; Expression eold = null; - for (Expression e = withstate.exp; e != eold; e = resolveAliasThis(_scope, e)) + for (Expression e = withstate.exp; e && e != eold; e = resolveAliasThis(_scope, e, true)) { if (e.op == EXP.scope_) { @@ -2426,7 +2441,9 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy auto vd2 = s2.isVarDeclaration(); // existing declaration if (vd && vd2) { - // if one is `static` and the other isn't + /* if one is `static` and the other isn't, the result is undefined + * behavior, C11 6.2.2.7 + */ if ((vd.storage_class ^ vd2.storage_class) & STC.static_) return collision(); @@ -2437,7 +2454,10 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy return collision(); // can't both have initializers if (i1) - return vd; + { + vd2._init = vd._init; + vd._init = null; + } /* BUG: the types should match, which needs semantic() to be run on it * extern int x; @@ -2454,15 +2474,38 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy auto fd2 = s2.isFuncDeclaration(); // existing declaration if (fd && fd2) { - // if one is `static` and the other isn't - if ((fd.storage_class ^ fd2.storage_class) & STC.static_) + /* if one is `static` and the other isn't, the result is undefined + * behavior, C11 6.2.2.7 + * However, match what gcc allows: + * static int sun1(); int sun1() { return 0; } + * and: + * static int sun2() { return 0; } int sun2(); + * Both produce a static function. + * + * Both of these should fail: + * int sun3(); static int sun3() { return 0; } + * and: + * int sun4() { return 0; } static int sun4(); + */ + // if adding `static` + if ( fd.storage_class & STC.static_ && + !(fd2.storage_class & STC.static_)) + { return collision(); + } if (fd.fbody && fd2.fbody) return collision(); // can't both have bodies if (fd.fbody) - return fd; + { + fd2.fbody = fd.fbody; // transfer body to existing declaration + fd.fbody = null; + + auto tf = fd.type.toTypeFunction(); + auto tf2 = fd2.type.toTypeFunction(); + tf2.parameterList = tf.parameterList; // transfer parameter list. + } /* BUG: just like with VarDeclaration, the types should match, which needs semantic() to be run on it. * FuncDeclaration::semantic2() can detect this, but it relies overnext being set. diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index 02252fd13e5..668b079060a 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -199,6 +199,7 @@ public: void deprecation(const char *format, ...); bool checkDeprecated(const Loc &loc, Scope *sc); Module *getModule(); + bool isCsymbol(); Module *getAccessModule(); Dsymbol *pastMixin(); Dsymbol *toParent(); diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index 0bf9a80f37d..3a9abd2d87e 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -46,6 +46,7 @@ import dmd.func; import dmd.globals; import dmd.id; import dmd.identifier; +import dmd.importc; import dmd.init; import dmd.initsem; import dmd.hdrgen; @@ -891,6 +892,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor bool isBlit = false; d_uns64 sz; + if (sc.flags & SCOPE.Cfile && !dsym._init) + { + addDefaultCInitializer(dsym); + } if (!dsym._init && !(dsym.storage_class & (STC.static_ | STC.gshared | STC.extern_)) && fd && @@ -900,7 +905,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { // Provide a default initializer - //printf("Providing default initializer for '%s'\n", toChars()); + //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()); diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 5dedcba5627..b1760dd23cf 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -5529,6 +5529,20 @@ extern (C++) final class TemplateValueParameter : TemplateParameter override bool declareParameter(Scope* sc) { + /* + Do type semantic earlier. + + This means for certain erroneous value parameters + their "type" can be known earlier and thus a better + error message given. + + For example: + `template test(x* x) {}` + now yields "undefined identifier" rather than the opaque + "variable `x` is used as a type". + */ + if (valType) + valType = valType.typeSemantic(loc, sc); auto v = new VarDeclaration(loc, valType, ident, null); v.storage_class = STC.templateparameter; return sc.insert(v) !is null; diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index e6b7e3014f1..749a50a38f3 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -3985,7 +3985,7 @@ extern (C++) final class FuncExp : Expression } else { - assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer); + assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors); tx = tfx.pointerTo(); } //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars()); diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index ec2bce47b47..48e47cef250 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -316,6 +316,9 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* p ie.lwr = sem(ie.lwr); ie.upr = sem(ie.upr); + if (ie.lwr.isErrorExp() || ie.upr.isErrorExp()) + errors = true; + if (lengthVar != ae.lengthVar && sc.func) { // If $ was used, declare it now @@ -536,16 +539,16 @@ private Expression resolveUFCS(Scope* sc, CallExp ce) ce.e1 = ey; if (isDotOpDispatch(ey)) { - uint errors = global.startGagging(); - e = ce.syntaxCopy().expressionSemantic(sc); - if (!global.endGagging(errors)) - return e; - // even opDispatch and UFCS must have valid arguments, // so now that we've seen indication of a problem, // check them for issues. Expressions* originalArguments = Expression.arraySyntaxCopy(ce.arguments); + uint errors = global.startGagging(); + e = ce.expressionSemantic(sc); + if (!global.endGagging(errors)) + return e; + if (arrayExpressionSemantic(originalArguments, sc)) return ErrorExp.get(); @@ -2792,6 +2795,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.error("undefined identifier `%s`, did you mean %s `%s`?", exp.ident.toChars(), s2.kind(), s2.toChars()); else if (const p = Scope.search_correct_C(exp.ident)) exp.error("undefined identifier `%s`, did you mean `%s`?", exp.ident.toChars(), p); + else if (exp.ident == Id.dollar) + exp.error("undefined identifier `$`"); else exp.error("undefined identifier `%s`", exp.ident.toChars()); @@ -4244,6 +4249,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } } + if (sc.flags & SCOPE.Cfile) + { + /* See if need to rewrite the AST because of cast/call ambiguity + */ + if (auto e = castCallAmbiguity(exp, sc)) + { + result = expressionSemantic(e, sc); + return; + } + } if (Expression ex = resolveUFCS(sc, exp)) { @@ -4425,24 +4440,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile)) { const numArgs = exp.arguments ? exp.arguments.length : 0; - if (e1org.parens && numArgs >= 1) - { - /* Ambiguous cases arise from CParser where there is not enough - * information to determine if we have a function call or a cast. - * ( type-name ) ( identifier ) ; - * ( identifier ) ( identifier ) ; - * If exp.e1 is a type-name, then this is a cast. - */ - Expression arg; - foreach (a; (*exp.arguments)[]) - { - arg = arg ? new CommaExp(a.loc, arg, a) : a; - } - auto t = exp.e1.isTypeExp().type; - auto e = new CastExp(exp.loc, arg, t); - result = e.expressionSemantic(sc); - return; - } /* Ambiguous cases arise from CParser where there is not enough * information to determine if we have a function call or declaration. @@ -6406,6 +6403,18 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars()); //printf("e1.op = %d, '%s'\n", e1.op, Token::toChars(e1.op)); } + + if (sc.flags & SCOPE.Cfile) + { + /* See if need to rewrite the AST because of cast/call ambiguity + */ + if (auto e = castCallAmbiguity(exp, sc)) + { + result = expressionSemantic(e, sc); + return; + } + } + if (exp.arrow) // ImportC only exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc); @@ -8059,6 +8068,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } assert(!exp.type); + if (sc.flags & SCOPE.Cfile) + { + /* See if need to rewrite the AST because of cast/call ambiguity + */ + if (auto e = castCallAmbiguity(exp, sc)) + { + result = expressionSemantic(e, sc); + return; + } + } + result = exp.carraySemantic(sc); // C semantics if (result) return; @@ -8452,6 +8472,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return; } + if (sc.flags & SCOPE.Cfile) + { + /* See if need to rewrite the AST because of cast/call ambiguity + */ + if (auto e = castCallAmbiguity(exp, sc)) + { + result = expressionSemantic(e, sc); + return; + } + } + if (Expression ex = binSemantic(exp, sc)) { result = ex; @@ -13050,7 +13081,7 @@ private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions e = resolveProperties(sc, e); if (i >= nfields) { - if (i <= sd.fields.dim && e.op == EXP.null_) + if (i < sd.fields.dim && e.op == EXP.null_) { // CTFE sometimes creates null as hidden pointer; we'll allow this. continue; diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d index 0dad1a83a8b..5ee961f4596 100644 --- a/gcc/d/dmd/importc.d +++ b/gcc/d/dmd/importc.d @@ -15,13 +15,18 @@ module dmd.importc; import core.stdc.stdio; +import dmd.astenums; import dmd.dcast; +import dmd.declaration; import dmd.dscope; import dmd.dsymbol; import dmd.expression; import dmd.expressionsem; import dmd.identifier; +import dmd.init; import dmd.mtype; +import dmd.tokens; +import dmd.typesem; /************************************** * C11 does not allow array or function parameters. @@ -84,7 +89,7 @@ Expression arrayFuncConv(Expression e, Scope* sc) } else if (t.isTypeFunction()) { - e = e.addressOf(); + e = new AddrExp(e.loc, e); } else return e; @@ -169,3 +174,89 @@ Expression carraySemantic(ArrayExp ae, Scope* sc) auto ep = new PtrExp(ae.loc, new AddExp(ae.loc, e1, e2)); return ep.expressionSemantic(sc); } + +/****************************************** + * Determine default initializer for const global symbol. + */ +void addDefaultCInitializer(VarDeclaration dsym) +{ + //printf("addDefaultCInitializer() %s\n", dsym.toChars()); + if (!(dsym.storage_class & (STC.static_ | STC.gshared))) + return; + if (dsym.storage_class & (STC.extern_ | STC.field | STC.in_ | STC.foreach_ | STC.parameter | STC.result)) + return; + + Type t = dsym.type; + if (t.isTypeSArray() && t.isTypeSArray().isIncomplete()) + { + dsym._init = new VoidInitializer(dsym.loc); + return; // incomplete arrays will be diagnosed later + } + + if (t.isMutable()) + return; + + auto e = dsym.type.defaultInit(dsym.loc, true); + dsym._init = new ExpInitializer(dsym.loc, e); +} + +/******************************************** + * Resolve cast/call grammar ambiguity. + * Params: + * e = expression that might be a cast, might be a call + * sc = context + * Returns: + * null means leave as is, !=null means rewritten AST + */ +Expression castCallAmbiguity(Expression e, Scope* sc) +{ + Expression* pe = &e; + + while (1) + { + // Walk down the postfix expressions till we find a CallExp or something else + switch ((*pe).op) + { + case EXP.dotIdentifier: + pe = &(*pe).isDotIdExp().e1; + continue; + + case EXP.plusPlus: + case EXP.minusMinus: + pe = &(*pe).isPostExp().e1; + continue; + + case EXP.array: + pe = &(*pe).isArrayExp().e1; + continue; + + case EXP.call: + auto ce = (*pe).isCallExp(); + if (ce.e1.parens) + { + ce.e1 = expressionSemantic(ce.e1, sc); + if (ce.e1.op == EXP.type) + { + const numArgs = ce.arguments ? ce.arguments.length : 0; + if (numArgs >= 1) + { + ce.e1.parens = false; + Expression arg; + foreach (a; (*ce.arguments)[]) + { + arg = arg ? new CommaExp(a.loc, arg, a) : a; + } + auto t = ce.e1.isTypeExp().type; + *pe = arg; + return new CastExp(ce.loc, e, t); + } + } + } + return null; + + default: + return null; + } + } +} + diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index c5aa0f46dd1..51ee27d00fe 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -434,11 +434,22 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ return i; } if (sc.flags & SCOPE.Cfile) + { /* the interpreter turns (char*)"string" into &"string"[0] which then * it cannot interpret. Resolve that case by doing optimize() first */ i.exp = i.exp.optimize(WANTvalue); - i.exp = i.exp.ctfeInterpret(); + if (i.exp.isSymOffExp()) + { + /* `static variable cannot be read at compile time` + * https://issues.dlang.org/show_bug.cgi?id=22513 + * Maybe this would be better addressed in ctfeInterpret()? + */ + needInterpret = NeedInterpret.INITnointerpret; + } + } + if (needInterpret) + i.exp = i.exp.ctfeInterpret(); if (i.exp.op == EXP.voidExpression) error(i.loc, "variables cannot be initialized with an expression of type `void`. Use `void` initialization instead."); } diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index d38cce4ca00..bb76a1a3a69 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -2073,6 +2073,7 @@ class Lexer bool overflow = false; bool anyBinaryDigitsNoSingleUS = false; bool anyHexDigitsNoSingleUS = false; + char errorDigit = 0; dchar c = *p; if (c == '0') { @@ -2093,8 +2094,7 @@ class Lexer case '8': case '9': - if (Ccompile) - error("octal digit expected, not `%c`", c); + errorDigit = cast(char) c; base = 8; break; case 'x': @@ -2205,12 +2205,9 @@ class Lexer // got a digit here, set any necessary flags, check for errors anyHexDigitsNoSingleUS = true; anyBinaryDigitsNoSingleUS = true; - if (!err && d >= base) + if (!errorDigit && d >= base) { - error("%s digit expected, not `%c`", base == 2 ? "binary".ptr : - base == 8 ? "octal".ptr : - "decimal".ptr, c); - err = true; + errorDigit = cast(char) c; } // Avoid expensive overflow check if we aren't at risk of overflow if (n <= 0x0FFF_FFFF_FFFF_FFFFUL) @@ -2224,6 +2221,13 @@ class Lexer } } Ldone: + if (errorDigit) + { + error("%s digit expected, not `%c`", base == 2 ? "binary".ptr : + base == 8 ? "octal".ptr : + "decimal".ptr, errorDigit); + err = true; + } if (overflow && !err) { error("integer overflow"); diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index 4d250c04771..bafeaa332dc 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -523,8 +523,14 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) { // Deal with $ result = resolveOpDollar(sc, ae, ie, &e0); + if (result.op == EXP.error) + { + if (!e0 && !search_function(ad, Id.dollar)) { + ae.loc.errorSupplemental("Aggregate declaration '%s' does not define 'opDollar'", ae.e1.toChars()); + } return; + } /* Rewrite a[i..j] as: * a.opSlice(i, j) */ @@ -597,11 +603,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) /* Rewrite op(e1) as: * op(e1.aliasthis) */ - Expression e1 = resolveAliasThis(sc, e.e1); - result = e.copy(); - (cast(UnaExp)result).e1 = e1; - result = result.op_overload(sc); - return; + if (auto e1 = resolveAliasThis(sc, e.e1, true)) + { + result = e.copy(); + (cast(UnaExp)result).e1 = e1; + result = result.op_overload(sc); + return; + } } } } diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index 6b2176b2911..ca9e0b3b616 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -26,6 +26,7 @@ import dmd.expressionsem; import dmd.globals; import dmd.init; import dmd.mtype; +import dmd.printast; import dmd.root.ctfloat; import dmd.sideeffect; import dmd.tokens; @@ -270,6 +271,7 @@ package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type) */ Expression Expression_optimize(Expression e, int result, bool keepLvalue) { + //printf("Expression_optimize() %s\n", e.toChars()); Expression ret = e; void error() @@ -459,6 +461,59 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) return; } } + if (e.e1.isDotVarExp()) + { + /****************************** + * Run down the left side of the a.b.c expression to determine the + * leftmost variable being addressed (`a`), and accumulate the offsets of the `.b` and `.c`. + * Params: + * e = the DotVarExp or VarExp + * var = set to the VarExp at the end, or null if doesn't end in VarExp + * offset = accumulation of all the .var offsets encountered + * Returns: true on error + */ + static bool getVarAndOffset(Expression e, ref VarDeclaration var, ref uint offset) + { + if (e.type.size() == SIZE_INVALID) // trigger computation of v.offset + return true; + + if (auto dve = e.isDotVarExp()) + { + auto v = dve.var.isVarDeclaration(); + if (!v || !v.isField() || v.isBitFieldDeclaration()) + return false; + + if (getVarAndOffset(dve.e1, var, offset)) + return true; + offset += v.offset; + } + else if (auto ve = e.isVarExp()) + { + if (!ve.var.isReference() && + !ve.var.isImportedSymbol() && + ve.var.isDataseg() && + ve.var.isCsymbol()) + { + var = ve.var.isVarDeclaration(); + } + } + return false; + } + + uint offset; + VarDeclaration var; + if (getVarAndOffset(e.e1, var, offset)) + { + ret = ErrorExp.get(); + return; + } + if (var) + { + ret = new SymOffExp(e.loc, var, offset, false); + ret.type = e.type; + return; + } + } if (auto ae = e.e1.isIndexExp()) { // Convert &array[n] to &array+n diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 2229e7853db..94056aba806 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -5758,7 +5758,26 @@ LagainStc: nextToken(); } else - check(TOK.semicolon, "statement"); + { + /* + * https://issues.dlang.org/show_bug.cgi?id=22529 + * Avoid empty declaration error in case of missing semicolon + * followed by another token and another semicolon. E.g.: + * + * foo() + * return; + * + * When the missing `;` error is emitted, token is sitting on return. + * If we simply use `check` to emit the error, the token is advanced + * to `;` and the empty statement error would follow. To avoid that, + * we check if the next token is a semicolon and simply output the error, + * otherwise we fall back on the old path (advancing the token). + */ + if (token.value != TOK.semicolon && peek(&token).value == TOK.semicolon) + error("found `%s` when expecting `;` following statement", token.toChars()); + else + check(TOK.semicolon, "statement"); + } s = new AST.ExpStatement(loc, exp); break; } diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d index b9f0c5e2eb8..33b5e7f350a 100644 --- a/gcc/d/dmd/printast.d +++ b/gcc/d/dmd/printast.d @@ -82,6 +82,24 @@ extern (C++) final class PrintASTVisitor : Visitor printf(".var: %s\n", e.var ? e.var.toChars() : ""); } + override void visit(SymOffExp e) + { + printIndent(indent); + printf("SymOff %s\n", e.type ? e.type.toChars() : ""); + printIndent(indent + 2); + printf(".var: %s\n", e.var ? e.var.toChars() : ""); + printIndent(indent + 2); + printf(".offset: %llx\n", e.offset); + } + + override void visit(VarExp e) + { + printIndent(indent); + printf("Var %s\n", e.type ? e.type.toChars() : ""); + printIndent(indent + 2); + printf(".var: %s\n", e.var ? e.var.toChars() : ""); + } + override void visit(DsymbolExp e) { visit(cast(Expression)e); @@ -120,6 +138,15 @@ extern (C++) final class PrintASTVisitor : Visitor printAST(e.e1, indent + 2); } + override void visit(DotVarExp e) + { + printIndent(indent); + printf("DotVar %s\n", e.type ? e.type.toChars() : ""); + printIndent(indent + 2); + printf(".var: %s\n", e.var.toChars()); + printAST(e.e1, indent + 2); + } + override void visit(BinExp e) { visit(cast(Expression)e); diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 893f96b4ea9..da328fdcaf9 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -235,6 +235,18 @@ private extern(C++) final class Semantic3Visitor : Visitor if (funcdecl.errors || isError(funcdecl.parent)) { funcdecl.errors = true; + + // Mark that the return type could not be inferred + if (funcdecl.inferRetType) + { + assert(funcdecl.type); + auto tf = funcdecl.type.isTypeFunction(); + + // Only change the return type s.t. other analysis is + // still possible e.g. missmatched parameter types + if (tf && !tf.next) + tf.next = Type.terror; + } return; } //printf("FuncDeclaration::semantic3('%s.%s', %p, sc = %p, loc = %s)\n", funcdecl.parent.toChars(), funcdecl.toChars(), funcdecl, sc, funcdecl.loc.toChars()); diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 6979cdf7977..91855ac05b6 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -2471,64 +2471,69 @@ private extern (C++) final class StatementSemanticVisitor : Visitor { Expression initialExp = cs.exp; - cs.exp = cs.exp.implicitCastTo(sc, sw.condition.type); - cs.exp = cs.exp.optimize(WANTvalue | WANTexpand); - - Expression e = cs.exp; - // Remove all the casts the user and/or implicitCastTo may introduce - // otherwise we'd sometimes fail the check below. - while (e.op == EXP.cast_) - e = (cast(CastExp)e).e1; - - /* This is where variables are allowed as case expressions. - */ - if (e.op == EXP.variable) - { - VarExp ve = cast(VarExp)e; - VarDeclaration v = ve.var.isVarDeclaration(); - Type t = cs.exp.type.toBasetype(); - if (v && (t.isintegral() || t.ty == Tclass)) + // The switch'ed value has errors and doesn't provide the actual type + // Don't touch the case to not replace it with an `ErrorExp` even if it is valid + if (sw.condition.type && !sw.condition.type.isTypeError()) + { + cs.exp = cs.exp.implicitCastTo(sc, sw.condition.type); + cs.exp = cs.exp.optimize(WANTvalue | WANTexpand); + + Expression e = cs.exp; + // Remove all the casts the user and/or implicitCastTo may introduce + // otherwise we'd sometimes fail the check below. + while (e.op == EXP.cast_) + e = (cast(CastExp)e).e1; + + /* This is where variables are allowed as case expressions. + */ + if (e.op == EXP.variable) { - /* Flag that we need to do special code generation - * for this, i.e. generate a sequence of if-then-else - */ - sw.hasVars = 1; - - /* TODO check if v can be uninitialized at that point. - */ - if (!v.isConst() && !v.isImmutable()) - { - cs.error("`case` variables have to be `const` or `immutable`"); - } - - if (sw.isFinal) - { - cs.error("`case` variables not allowed in `final switch` statements"); - errors = true; - } - - /* Find the outermost scope `scx` that set `sw`. - * Then search scope `scx` for a declaration of `v`. - */ - for (Scope* scx = sc; scx; scx = scx.enclosing) + VarExp ve = cast(VarExp)e; + VarDeclaration v = ve.var.isVarDeclaration(); + Type t = cs.exp.type.toBasetype(); + if (v && (t.isintegral() || t.ty == Tclass)) { - if (scx.enclosing && scx.enclosing.sw == sw) - continue; - assert(scx.sw == sw); + /* Flag that we need to do special code generation + * for this, i.e. generate a sequence of if-then-else + */ + sw.hasVars = 1; + + /* TODO check if v can be uninitialized at that point. + */ + if (!v.isConst() && !v.isImmutable()) + { + cs.error("`case` variables have to be `const` or `immutable`"); + } - if (!scx.search(cs.exp.loc, v.ident, null)) + if (sw.isFinal) { - cs.error("`case` variable `%s` declared at %s cannot be declared in `switch` body", - v.toChars(), v.loc.toChars()); + cs.error("`case` variables not allowed in `final switch` statements"); errors = true; } - break; + + /* Find the outermost scope `scx` that set `sw`. + * Then search scope `scx` for a declaration of `v`. + */ + for (Scope* scx = sc; scx; scx = scx.enclosing) + { + if (scx.enclosing && scx.enclosing.sw == sw) + continue; + assert(scx.sw == sw); + + if (!scx.search(cs.exp.loc, v.ident, null)) + { + cs.error("`case` variable `%s` declared at %s cannot be declared in `switch` body", + v.toChars(), v.loc.toChars()); + errors = true; + } + break; + } + goto L1; } - goto L1; } + else + cs.exp = cs.exp.ctfeInterpret(); } - else - cs.exp = cs.exp.ctfeInterpret(); if (StringExp se = cs.exp.toStringExp()) cs.exp = se; @@ -2539,6 +2544,8 @@ private extern (C++) final class StatementSemanticVisitor : Visitor } L1: + // // Don't check other cases if this has errors + if (!cs.exp.isErrorExp()) foreach (cs2; *sw.cases) { //printf("comparing '%s' with '%s'\n", exp.toChars(), cs.exp.toChars()); @@ -2877,9 +2884,6 @@ private extern (C++) final class StatementSemanticVisitor : Visitor if (rs.exp.op == EXP.call) rs.exp = valueNoDtor(rs.exp); - if (e0) - e0 = e0.optimize(WANTvalue); - /* Void-return function can have void / noreturn typed expression * on return statement. */ @@ -2904,7 +2908,10 @@ private extern (C++) final class StatementSemanticVisitor : Visitor rs.exp = null; } if (e0) + { + e0 = e0.optimize(WANTvalue); e0 = checkGC(sc, e0); + } } if (rs.exp) diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d index 7a875a5d663..8e434a373d2 100644 --- a/gcc/d/dmd/target.d +++ b/gcc/d/dmd/target.d @@ -323,7 +323,7 @@ struct TargetC /// https://docs.microsoft.com/en-us/cpp/cpp/cpp-bit-fields?view=msvc-160 Gcc_Clang, /// gcc and clang } - + bool crtDestructorsSupported = true; /// Not all platforms support crt_destructor ubyte longsize; /// size of a C `long` or `unsigned long` type ubyte long_doublesize; /// size of a C `long double` ubyte wchar_tsize; /// size of a C `wchar_t` type diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h index 13636932078..6348d93b67d 100644 --- a/gcc/d/dmd/target.h +++ b/gcc/d/dmd/target.h @@ -70,6 +70,7 @@ struct TargetC Gcc_Clang, // gcc and clang }; + uint8_t crtDestructorsSupported; // Not all platforms support crt_destructor uint8_t longsize; // size of a C 'long' or 'unsigned long' type uint8_t long_doublesize; // size of a C 'long double' uint8_t wchar_tsize; // size of a C 'wchar_t' type diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 2609af56ac0..2d98d5eeed8 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -52,38 +52,22 @@ enum TOK : ushort new_, delete_, star, - symbolOffset, variable, - dotVariable, - dotIdentifier, - dotTemplateInstance, - dotType, slice, - arrayLength, version_, module_, dollar, template_, - dotTemplateDeclaration, declaration, typeof_, pragma_, - dSymbol, typeid_, uadd, remove, - newAnonymousClass, comment, - arrayLiteral, - assocArrayLiteral, - structLiteral, - classReference, - thrownException, - delegatePointer, - delegateFunctionPointer, // Operators - lessThan = 54, + lessThan, greaterThan, lessOrEqual, greaterOrEqual, @@ -94,7 +78,7 @@ enum TOK : ushort index, is_, - leftShift = 64, + leftShift, rightShift, leftShiftAssign, rightShiftAssign, @@ -136,7 +120,7 @@ enum TOK : ushort preMinusMinus, // Numeric literals - int32Literal = 104, + int32Literal, uns32Literal, int64Literal, uns64Literal, @@ -150,22 +134,21 @@ enum TOK : ushort imaginary80Literal, // Char constants - charLiteral = 116, + charLiteral, wcharLiteral, dcharLiteral, // Leaf operators - identifier = 119, + identifier, string_, hexadecimalString, this_, super_, - halt, tuple, error, // Basic types - void_ = 127, + void_, int8, uns8, int16, @@ -191,7 +174,7 @@ enum TOK : ushort bool_, // Aggregates - struct_ = 151, + struct_, class_, interface_, union_, @@ -223,7 +206,7 @@ enum TOK : ushort immutable_, // Statements - if_ = 181, + if_, else_, while_, for_, @@ -249,7 +232,7 @@ enum TOK : ushort onScopeSuccess, // Contracts - invariant_ = 205, + invariant_, // Testing unittest_, @@ -259,7 +242,7 @@ enum TOK : ushort ref_, macro_, - parameters = 210, + parameters, traits, overloadSet, pure_, @@ -279,18 +262,9 @@ enum TOK : ushort vector, pound, - interval = 229, - voidExpression, - cantExpression, - showCtfeContext, - - objcClassReference, - vectorArray, - arrow, // -> colonColon, // :: wchar_tLiteral, - compoundLiteral, // ( type-name ) { initializer-list } // C only keywords inline, @@ -885,33 +859,17 @@ extern (C++) struct Token // For debugging TOK.error: "error", - TOK.dotIdentifier: "dotid", - TOK.dotTemplateDeclaration: "dottd", - TOK.dotTemplateInstance: "dotti", - TOK.dotVariable: "dotvar", - TOK.dotType: "dottype", - TOK.symbolOffset: "symoff", - TOK.arrayLength: "arraylength", - TOK.arrayLiteral: "arrayliteral", - TOK.assocArrayLiteral: "assocarrayliteral", - TOK.structLiteral: "structliteral", TOK.string_: "string", - TOK.dSymbol: "symbol", TOK.tuple: "tuple", TOK.declaration: "declaration", TOK.onScopeExit: "scope(exit)", TOK.onScopeSuccess: "scope(success)", TOK.onScopeFailure: "scope(failure)", - TOK.delegatePointer: "delegateptr", // Finish up TOK.reserved: "reserved", TOK.remove: "remove", - TOK.newAnonymousClass: "newanonclass", TOK.comment: "comment", - TOK.classReference: "classreference", - TOK.thrownException: "thrownexception", - TOK.delegateFunctionPointer: "delegatefuncptr", TOK.int32Literal: "int32v", TOK.uns32Literal: "uns32v", TOK.int64Literal: "int64v", @@ -928,19 +886,9 @@ extern (C++) struct Token TOK.wcharLiteral: "wcharv", TOK.dcharLiteral: "dcharv", TOK.wchar_tLiteral: "wchar_tv", - TOK.compoundLiteral: "compoundliteral", - TOK.halt: "halt", TOK.hexadecimalString: "xstring", - TOK.interval: "interval", - TOK.voidExpression: "voidexp", - TOK.cantExpression: "cantexp", - TOK.showCtfeContext : "showCtfeContext", - - TOK.objcClassReference: "class", - TOK.vectorArray: "vectorarray", - // C only keywords TOK.inline : "inline", TOK.register : "register", diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index f3e4411217e..2e1d1f44492 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -61,35 +61,19 @@ enum class TOK : unsigned short new_, delete_, star, - symbolOffset, variable, - dotVariable, - dotIdentifier, - dotTemplateInstance, - dotType, slice, - arrayLength, version_, module_, dollar, template_, - dotTemplateDeclaration, declaration, typeof_, pragma_, - dSymbol, typeid_, uadd, remove, - newAnonymousClass, comment, - arrayLiteral, - assocArrayLiteral, - structLiteral, - classReference, - thrownException, - delegatePointer, - delegateFunctionPointer, // Operators lessThan, // 54 @@ -169,7 +153,6 @@ enum class TOK : unsigned short hexadecimalString, this_, super_, - halt, tuple, error, @@ -288,18 +271,9 @@ enum class TOK : unsigned short vector, pound, - interval, // 229 - voidExpression, - cantExpression, - showCtfeContext, - - objcClassReference, - vectorArray, - arrow, // -> colonColon, // :: wchar_tLiteral, - compoundLiteral, // ( type-name ) { initializer-list } // C only keywords inline_, diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 417d2c11af4..2a864161ff6 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -1709,13 +1709,22 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) } else if (e.op == EXP.variable) // special case: variable is used as a type { + /* + N.B. This branch currently triggers for the following code + template test(x* x) + { + + } + i.e. the compiler prints "variable x is used as a type" + which isn't a particularly good error message (x is a variable?). + */ Dsymbol varDecl = mtype.toDsymbol(sc); const(Loc) varDeclLoc = varDecl.getLoc(); - Module varDeclModule = varDecl.getModule(); + Module varDeclModule = varDecl.getModule(); //This can be null .error(loc, "variable `%s` is used as a type", mtype.toChars()); - - if (varDeclModule != sc._module) // variable is imported + //Check for null to avoid https://issues.dlang.org/show_bug.cgi?id=22574 + if ((varDeclModule !is null) && varDeclModule != sc._module) // variable is imported { const(Loc) varDeclModuleImportLoc = varDeclModule.getLoc(); .errorSupplemental( @@ -4630,11 +4639,12 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) * Params: * mt = the type for which the init expression is returned * loc = the location where the expression needs to be evaluated + * isCfile = default initializers are different with C * * Returns: * The initialization expression for the type. */ -extern (C++) Expression defaultInit(Type mt, const ref Loc loc) +extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfile = false) { Expression visitBasic(TypeBasic mt) { @@ -4647,12 +4657,12 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc) switch (mt.ty) { case Tchar: - value = 0xFF; + value = isCfile ? 0 : 0xFF; break; case Twchar: case Tdchar: - value = 0xFFFF; + value = isCfile ? 0 : 0xFFFF; break; case Timaginary32: @@ -4661,14 +4671,15 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc) case Tfloat32: case Tfloat64: case Tfloat80: - return new RealExp(loc, target.RealProperties.nan, mt); + return new RealExp(loc, isCfile ? CTFloat.zero : target.RealProperties.nan, mt); case Tcomplex32: case Tcomplex64: case Tcomplex80: { // Can't use fvalue + I*fvalue (the im part becomes a quiet NaN). - const cvalue = complex_t(target.RealProperties.nan, target.RealProperties.nan); + const cvalue = isCfile ? complex_t(CTFloat.zero, CTFloat.zero) + : complex_t(target.RealProperties.nan, target.RealProperties.nan); return new ComplexExp(loc, cvalue, mt); } @@ -4686,7 +4697,7 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc) { //printf("TypeVector::defaultInit()\n"); assert(mt.basetype.ty == Tsarray); - Expression e = mt.basetype.defaultInit(loc); + Expression e = mt.basetype.defaultInit(loc, isCfile); auto ve = new VectorExp(loc, e, mt); ve.type = mt; ve.dim = cast(int)(mt.basetype.size(loc) / mt.elementType().size(loc)); @@ -4700,9 +4711,9 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc) printf("TypeSArray::defaultInit() '%s'\n", mt.toChars()); } if (mt.next.ty == Tvoid) - return mt.tuns8.defaultInit(loc); + return mt.tuns8.defaultInit(loc, isCfile); else - return mt.next.defaultInit(loc); + return mt.next.defaultInit(loc, isCfile); } Expression visitFunction(TypeFunction mt) diff --git a/gcc/d/gdc.texi b/gcc/d/gdc.texi index d37d205e870..bfec1568857 100644 --- a/gcc/d/gdc.texi +++ b/gcc/d/gdc.texi @@ -267,15 +267,16 @@ Sets the C++ name mangling compatibility to the version identified by @table @samp @item c++98 @item c++03 -Sets @code{__traits(getTargetInfo "cppStd")} to @code{199711}. +Sets @code{__traits(getTargetInfo, "cppStd")} to @code{199711}. @item c++11 -Sets @code{__traits(getTargetInfo "cppStd")} to @code{201103}. +Sets @code{__traits(getTargetInfo, "cppStd")} to @code{201103}. @item c++14 -Sets @code{__traits(getTargetInfo "cppStd")} to @code{201402}. +Sets @code{__traits(getTargetInfo, "cppStd")} to @code{201402}. @item c++17 -Sets @code{__traits(getTargetInfo "cppStd")} to @code{201703}. +Sets @code{__traits(getTargetInfo, "cppStd")} to @code{201703}. +This is the default. @item c++20 -Sets @code{__traits(getTargetInfo "cppStd")} to @code{202002}. +Sets @code{__traits(getTargetInfo, "cppStd")} to @code{202002}. @end table @item -fno-invariants diff --git a/gcc/testsuite/gdc.test/compilable/cppmangle.d b/gcc/testsuite/gdc.test/compilable/cppmangle.d index 1820de90991..8c112d1e548 100644 --- a/gcc/testsuite/gdc.test/compilable/cppmangle.d +++ b/gcc/testsuite/gdc.test/compilable/cppmangle.d @@ -7,6 +7,12 @@ import core.stdc.stdio; +version (CppRuntime_Clang) version = CppMangle_Itanium; +version (CppRuntime_DigitalMars) version = CppMangle_MSVC; +version (CppRuntime_Gcc) version = CppMangle_Itanium; +version (CppRuntime_Microsoft) version = CppMangle_MSVC; +version (CppRuntime_Sun) version = CppMangle_Itanium; + extern (C++) int foob(int i, int j, int k); class C @@ -45,23 +51,26 @@ void test1() c.bar(4, 5, 6); } -version (Posix) +version (CppMangle_Itanium) { static assert(foo.mangleof == "_Z3fooiii"); static assert(foob.mangleof == "_Z4foobiii"); static assert(C.bar.mangleof == "_ZN1C3barEiii"); } -version (Win32) -{ - static assert(foo.mangleof == "?foo@@YAHHHH@Z"); - static assert(foob.mangleof == "?foob@@YAHHHH@Z"); - static assert(C.bar.mangleof == "?bar@C@@UAEHHHH@Z"); -} -version (Win64) +version (CppMangle_MSVC) { - static assert(foo.mangleof == "?foo@@YAHHHH@Z"); - static assert(foob.mangleof == "?foob@@YAHHHH@Z"); - static assert(C.bar.mangleof == "?bar@C@@UEAAHHHH@Z"); + version (Win32) + { + static assert(foo.mangleof == "?foo@@YAHHHH@Z"); + static assert(foob.mangleof == "?foob@@YAHHHH@Z"); + static assert(C.bar.mangleof == "?bar@C@@UAEHHHH@Z"); + } + version (Win64) + { + static assert(foo.mangleof == "?foo@@YAHHHH@Z"); + static assert(foob.mangleof == "?foob@@YAHHHH@Z"); + static assert(C.bar.mangleof == "?bar@C@@UEAAHHHH@Z"); + } } /****************************************/ @@ -81,7 +90,7 @@ void test2() assert(i == 8); } -version (Posix) +version (CppMangle_Itanium) { static assert (getD.mangleof == "_Z4getDv"); static assert (D.bar.mangleof == "_ZN1D3barEiii"); @@ -118,7 +127,7 @@ void test3() assert(i == 8); } -version (Posix) +version (CppMangle_Itanium) { static assert (callE.mangleof == "_Z5callEP1E"); static assert (E.bar.mangleof == "_ZN1E3barEiii"); @@ -134,7 +143,7 @@ void test4() foo4(null); } -version (Posix) +version (CppMangle_Itanium) { static assert(foo4.mangleof == "_Z4foo4Pc"); } @@ -160,7 +169,7 @@ void test5() assert(f.p == cast(void*)b); } -version (Posix) +version (CppMangle_Itanium) { static assert(bar5.getFoo.mangleof == "_ZN4bar56getFooEi"); static assert (newBar.mangleof == "_Z6newBarv"); @@ -190,7 +199,7 @@ void test6() assert(f.d == 2.5); } -version (Posix) +version (CppMangle_Itanium) { static assert (foo6.mangleof == "_Z4foo6v"); } @@ -221,7 +230,7 @@ void test8() foo8(&c); } -version (Posix) +version (CppMangle_Itanium) { static assert(foo8.mangleof == "_Z4foo8PKc"); } @@ -239,7 +248,7 @@ void test9() foobar9(a, a); } -version (Posix) +version (CppMangle_Itanium) { static assert(foobar9.mangleof == "_Z7foobar9P5elem9S0_"); } @@ -298,7 +307,7 @@ extern (C++) void test10058l(void* function(void*), void* function(const (void)*), const(void)* function(void*)) { } } -version (Posix) +version (CppMangle_Itanium) { static assert(test10058a.mangleof == "_Z10test10058aPv"); static assert(test10058b.mangleof == "_Z10test10058bPFvPvE"); @@ -329,7 +338,7 @@ class CallExp static void test11696d(Loc, Expression*, Expression*); } -version (Posix) +version (CppMangle_Itanium) { static assert(CallExp.test11696a.mangleof == "_ZN7CallExp10test11696aE3LocP10ExpressionS2_"); static assert(CallExp.test11696b.mangleof == "_ZN7CallExp10test11696bE3LocP10ExpressionPS2_"); @@ -353,7 +362,7 @@ extern(C++, `N13337a`, `N13337b`, `N13337c`) void foo13337_3(S13337_2 s); } -version (Posix) +version (CppMangle_Itanium) { static assert(foo13337.mangleof == "_ZN7N13337a7N13337b7N13337c8foo13337ENS1_6S13337E"); static assert(foo13337_2.mangleof == "_ZN7N13337a7N13337b7N13337c10foo13337_2ENS1_6S13337E"); @@ -383,7 +392,7 @@ extern(C++) } } -version (Posix) +version (CppMangle_Itanium) { static assert(Struct7030.foo.mangleof == "_ZNK10Struct70303fooEi"); static assert(Struct7030.bar.mangleof == "_ZN10Struct70303barEi"); @@ -494,7 +503,7 @@ extern (C++) void func_20413(pair!(int, float), pair!(float, int)); } -version (Posix) +version (CppMangle_Itanium) { // https://issues.dlang.org/show_bug.cgi?id=17947 static assert(std.pair!(void*, void*).swap.mangleof == "_ZNSt4pairIPvS0_E4swapERS1_"); @@ -531,7 +540,7 @@ alias T36 = int ********** ********** ********** **********; extern (C++) void test36(T36, T36*) { } -version (Posix) +version (CppMangle_Itanium) { static assert(test36.mangleof == "_Z6test36PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPiPS12_"); } @@ -545,7 +554,7 @@ int test37(T)(){ return 0;} extern(C++, `SPACE`) int test37(T)(){ return 0;} -version (Posix) // all non-Windows machines +version (CppMangle_Itanium) // all non-Windows machines { static assert(SPACE.test37!int.mangleof == "_ZN5SPACE6test37IiEEiv"); static assert(test37!int.mangleof == "_ZN5SPACE6test37IiEEiv"); @@ -556,11 +565,11 @@ version (Posix) // all non-Windows machines extern (C++) void test15388(typeof(null)); -version (Posix) +version (CppMangle_Itanium) { static assert(test15388.mangleof == "_Z9test15388Dn"); } -version (Windows) +version (CppMangle_MSVC) { static assert(test15388.mangleof == "?test15388@@YAX$$T@Z"); } @@ -583,7 +592,7 @@ extern (C++) struct Test14086_S ~this(); } -version(Posix) +version (CppMangle_Itanium) { static assert(Test14086.__ctor.mangleof == "_ZN9Test14086C1Ev"); static assert(Test14086.__dtor.mangleof == "_ZN9Test14086D1Ev"); @@ -591,21 +600,24 @@ version(Posix) static assert(Test14086_S.__ctor.mangleof == "_ZN11Test14086_SC1Ei"); static assert(Test14086_S.__dtor.mangleof == "_ZN11Test14086_SD1Ev"); } -version(Win32) -{ - static assert(Test14086.__ctor.mangleof == "??0Test14086@@QAE@XZ"); - static assert(Test14086.__dtor.mangleof == "??1Test14086@@UAE@XZ"); - static assert(Test14086_2.__dtor.mangleof == "??1Test14086_2@@QAE@XZ"); - static assert(Test14086_S.__ctor.mangleof == "??0Test14086_S@@QAE@H@Z"); - static assert(Test14086_S.__dtor.mangleof == "??1Test14086_S@@QAE@XZ"); -} -version(Win64) +version (CppMangle_MSVC) { - static assert(Test14086.__ctor.mangleof == "??0Test14086@@QEAA@XZ"); - static assert(Test14086.__dtor.mangleof == "??1Test14086@@UEAA@XZ"); - static assert(Test14086_2.__dtor.mangleof == "??1Test14086_2@@QEAA@XZ"); - static assert(Test14086_S.__ctor.mangleof == "??0Test14086_S@@QEAA@H@Z"); - static assert(Test14086_S.__dtor.mangleof == "??1Test14086_S@@QEAA@XZ"); + version (Win32) + { + static assert(Test14086.__ctor.mangleof == "??0Test14086@@QAE@XZ"); + static assert(Test14086.__dtor.mangleof == "??1Test14086@@UAE@XZ"); + static assert(Test14086_2.__dtor.mangleof == "??1Test14086_2@@QAE@XZ"); + static assert(Test14086_S.__ctor.mangleof == "??0Test14086_S@@QAE@H@Z"); + static assert(Test14086_S.__dtor.mangleof == "??1Test14086_S@@QAE@XZ"); + } + version (Win64) + { + static assert(Test14086.__ctor.mangleof == "??0Test14086@@QEAA@XZ"); + static assert(Test14086.__dtor.mangleof == "??1Test14086@@UEAA@XZ"); + static assert(Test14086_2.__dtor.mangleof == "??1Test14086_2@@QEAA@XZ"); + static assert(Test14086_S.__ctor.mangleof == "??0Test14086_S@@QEAA@H@Z"); + static assert(Test14086_S.__dtor.mangleof == "??1Test14086_S@@QEAA@XZ"); + } } /**************************************/ @@ -623,17 +635,20 @@ struct S18888(alias arg = T18888) alias I = T18888!(arg!int); } -version(Posix) +version (CppMangle_Itanium) { static assert(S18888!().I.fun.mangleof == "_ZN6T18888IS_IiEE3funEv"); } -version(Win32) -{ - static assert(S18888!().I.fun.mangleof == "?fun@?$T18888@U?$T18888@H@@@@QAEXXZ"); -} -version(Win64) +version (CppMangle_MSVC) { - static assert(S18888!().I.fun.mangleof == "?fun@?$T18888@U?$T18888@H@@@@QEAAXXZ"); + version (Win32) + { + static assert(S18888!().I.fun.mangleof == "?fun@?$T18888@U?$T18888@H@@@@QAEXXZ"); + } + version (Win64) + { + static assert(S18888!().I.fun.mangleof == "?fun@?$T18888@U?$T18888@H@@@@QEAAXXZ"); + } } /**************************************/ @@ -653,26 +668,29 @@ extern (C++) class C18890_2 Agg s; } -version (Posix) +version (CppMangle_Itanium) { static assert(C18890.__dtor.mangleof == "_ZN6C18890D1Ev"); static assert(C18890.__xdtor.mangleof == "_ZN6C18890D1Ev"); static assert(C18890_2.__dtor.mangleof == "_ZN8C18890_26__dtorEv"); static assert(C18890_2.__xdtor.mangleof == "_ZN8C18890_2D1Ev"); } -version (Win32) +version (CppMangle_MSVC) { - static assert(C18890.__dtor.mangleof == "??1C18890@@UAE@XZ"); - static assert(C18890.__xdtor.mangleof == "??_GC18890@@UAEPAXI@Z"); - static assert(C18890_2.__dtor.mangleof == "?__dtor@C18890_2@@UAEXXZ"); - static assert(C18890_2.__xdtor.mangleof == "??_GC18890_2@@UAEPAXI@Z"); -} -version (Win64) -{ - static assert(C18890.__dtor.mangleof == "??1C18890@@UEAA@XZ"); - static assert(C18890.__xdtor.mangleof == "??_GC18890@@UEAAPEAXI@Z"); - static assert(C18890_2.__dtor.mangleof == "?__dtor@C18890_2@@UEAAXXZ"); - static assert(C18890_2.__xdtor.mangleof == "??_GC18890_2@@UEAAPEAXI@Z"); + version (Win32) + { + static assert(C18890.__dtor.mangleof == "??1C18890@@UAE@XZ"); + static assert(C18890.__xdtor.mangleof == "??_GC18890@@UAEPAXI@Z"); + static assert(C18890_2.__dtor.mangleof == "?__dtor@C18890_2@@UAEXXZ"); + static assert(C18890_2.__xdtor.mangleof == "??_GC18890_2@@UAEPAXI@Z"); + } + version (Win64) + { + static assert(C18890.__dtor.mangleof == "??1C18890@@UEAA@XZ"); + static assert(C18890.__xdtor.mangleof == "??_GC18890@@UEAAPEAXI@Z"); + static assert(C18890_2.__dtor.mangleof == "?__dtor@C18890_2@@UEAAXXZ"); + static assert(C18890_2.__xdtor.mangleof == "??_GC18890_2@@UEAAPEAXI@Z"); + } } /**************************************/ @@ -688,20 +706,23 @@ extern (C++) class C18891 Agg s; } -version (Posix) +version (CppMangle_Itanium) { static assert(C18891.__dtor.mangleof == "_ZN6C18891D1Ev"); static assert(C18891.__xdtor.mangleof == "_ZN6C18891D1Ev"); } -version (Win32) +version (CppMangle_MSVC) { - static assert(C18891.__dtor.mangleof == "??1C18891@@UAE@XZ"); - static assert(C18891.__xdtor.mangleof == "??_GC18891@@UAEPAXI@Z"); -} -version (Win64) -{ - static assert(C18891.__dtor.mangleof == "??1C18891@@UEAA@XZ"); - static assert(C18891.__xdtor.mangleof == "??_GC18891@@UEAAPEAXI@Z"); + version (Win32) + { + static assert(C18891.__dtor.mangleof == "??1C18891@@UAE@XZ"); + static assert(C18891.__xdtor.mangleof == "??_GC18891@@UAEPAXI@Z"); + } + version (Win64) + { + static assert(C18891.__dtor.mangleof == "??1C18891@@UEAA@XZ"); + static assert(C18891.__xdtor.mangleof == "??_GC18891@@UEAAPEAXI@Z"); + } } /**************************************/ @@ -719,7 +740,7 @@ extern (C++) struct TestOperators int opAssign(int); } -version (Posix) +version (CppMangle_Itanium) { static assert(TestOperators.opUnary!"*".mangleof == "_ZN13TestOperatorsdeEv"); static assert(TestOperators.opUnary!"++".mangleof == "_ZN13TestOperatorsppEv"); @@ -753,73 +774,76 @@ version (Posix) static assert(TestOperators.opIndex.mangleof == "_ZN13TestOperatorsixEi"); static assert(TestOperators.opCall.mangleof == "_ZN13TestOperatorsclEif"); } -version (Win32) -{ - static assert(TestOperators.opUnary!"*".mangleof == "??DTestOperators@@QAEHXZ"); - static assert(TestOperators.opUnary!"++".mangleof == "??ETestOperators@@QAEHXZ"); - static assert(TestOperators.opUnary!"--".mangleof == "??FTestOperators@@QAEHXZ"); - static assert(TestOperators.opUnary!"-".mangleof == "??GTestOperators@@QAEHXZ"); - static assert(TestOperators.opUnary!"+".mangleof == "??HTestOperators@@QAEHXZ"); - static assert(TestOperators.opUnary!"~".mangleof == "??STestOperators@@QAEHXZ"); - static assert(TestOperators.opBinary!">>".mangleof == "??5TestOperators@@QAEHH@Z"); - static assert(TestOperators.opBinary!"<<".mangleof == "??6TestOperators@@QAEHH@Z"); - static assert(TestOperators.opBinary!"*".mangleof == "??DTestOperators@@QAEHH@Z"); - static assert(TestOperators.opBinary!"-".mangleof == "??GTestOperators@@QAEHH@Z"); - static assert(TestOperators.opBinary!"+".mangleof == "??HTestOperators@@QAEHH@Z"); - static assert(TestOperators.opBinary!"&".mangleof == "??ITestOperators@@QAEHH@Z"); - static assert(TestOperators.opBinary!"/".mangleof == "??KTestOperators@@QAEHH@Z"); - static assert(TestOperators.opBinary!"%".mangleof == "??LTestOperators@@QAEHH@Z"); - static assert(TestOperators.opBinary!"^".mangleof == "??TTestOperators@@QAEHH@Z"); - static assert(TestOperators.opBinary!"|".mangleof == "??UTestOperators@@QAEHH@Z"); - static assert(TestOperators.opOpAssign!"*".mangleof == "??XTestOperators@@QAEHH@Z"); - static assert(TestOperators.opOpAssign!"+".mangleof == "??YTestOperators@@QAEHH@Z"); - static assert(TestOperators.opOpAssign!"-".mangleof == "??ZTestOperators@@QAEHH@Z"); - static assert(TestOperators.opOpAssign!"/".mangleof == "??_0TestOperators@@QAEHH@Z"); - static assert(TestOperators.opOpAssign!"%".mangleof == "??_1TestOperators@@QAEHH@Z"); - static assert(TestOperators.opOpAssign!">>".mangleof == "??_2TestOperators@@QAEHH@Z"); - static assert(TestOperators.opOpAssign!"<<".mangleof == "??_3TestOperators@@QAEHH@Z"); - static assert(TestOperators.opOpAssign!"&".mangleof == "??_4TestOperators@@QAEHH@Z"); - static assert(TestOperators.opOpAssign!"|".mangleof == "??_5TestOperators@@QAEHH@Z"); - static assert(TestOperators.opOpAssign!"^".mangleof == "??_6TestOperators@@QAEHH@Z"); - static assert(TestOperators.opCast!int.mangleof == "??BTestOperators@@QAEHXZ"); - static assert(TestOperators.opAssign.mangleof == "??4TestOperators@@QAEHH@Z"); - static assert(TestOperators.opEquals.mangleof == "??8TestOperators@@QAE_NH@Z"); - static assert(TestOperators.opIndex.mangleof == "??ATestOperators@@QAEHH@Z"); - static assert(TestOperators.opCall.mangleof == "??RTestOperators@@QAEHHM@Z"); -} -version (Win64) -{ - static assert(TestOperators.opUnary!"*".mangleof == "??DTestOperators@@QEAAHXZ"); - static assert(TestOperators.opUnary!"++".mangleof == "??ETestOperators@@QEAAHXZ"); - static assert(TestOperators.opUnary!"--".mangleof == "??FTestOperators@@QEAAHXZ"); - static assert(TestOperators.opUnary!"-".mangleof == "??GTestOperators@@QEAAHXZ"); - static assert(TestOperators.opUnary!"+".mangleof == "??HTestOperators@@QEAAHXZ"); - static assert(TestOperators.opUnary!"~".mangleof == "??STestOperators@@QEAAHXZ"); - static assert(TestOperators.opBinary!">>".mangleof == "??5TestOperators@@QEAAHH@Z"); - static assert(TestOperators.opBinary!"<<".mangleof == "??6TestOperators@@QEAAHH@Z"); - static assert(TestOperators.opBinary!"*".mangleof == "??DTestOperators@@QEAAHH@Z"); - static assert(TestOperators.opBinary!"-".mangleof == "??GTestOperators@@QEAAHH@Z"); - static assert(TestOperators.opBinary!"+".mangleof == "??HTestOperators@@QEAAHH@Z"); - static assert(TestOperators.opBinary!"&".mangleof == "??ITestOperators@@QEAAHH@Z"); - static assert(TestOperators.opBinary!"/".mangleof == "??KTestOperators@@QEAAHH@Z"); - static assert(TestOperators.opBinary!"%".mangleof == "??LTestOperators@@QEAAHH@Z"); - static assert(TestOperators.opBinary!"^".mangleof == "??TTestOperators@@QEAAHH@Z"); - static assert(TestOperators.opBinary!"|".mangleof == "??UTestOperators@@QEAAHH@Z"); - static assert(TestOperators.opOpAssign!"*".mangleof == "??XTestOperators@@QEAAHH@Z"); - static assert(TestOperators.opOpAssign!"+".mangleof == "??YTestOperators@@QEAAHH@Z"); - static assert(TestOperators.opOpAssign!"-".mangleof == "??ZTestOperators@@QEAAHH@Z"); - static assert(TestOperators.opOpAssign!"/".mangleof == "??_0TestOperators@@QEAAHH@Z"); - static assert(TestOperators.opOpAssign!"%".mangleof == "??_1TestOperators@@QEAAHH@Z"); - static assert(TestOperators.opOpAssign!">>".mangleof == "??_2TestOperators@@QEAAHH@Z"); - static assert(TestOperators.opOpAssign!"<<".mangleof == "??_3TestOperators@@QEAAHH@Z"); - static assert(TestOperators.opOpAssign!"&".mangleof == "??_4TestOperators@@QEAAHH@Z"); - static assert(TestOperators.opOpAssign!"|".mangleof == "??_5TestOperators@@QEAAHH@Z"); - static assert(TestOperators.opOpAssign!"^".mangleof == "??_6TestOperators@@QEAAHH@Z"); - static assert(TestOperators.opCast!int.mangleof == "??BTestOperators@@QEAAHXZ"); - static assert(TestOperators.opAssign.mangleof == "??4TestOperators@@QEAAHH@Z"); - static assert(TestOperators.opEquals.mangleof == "??8TestOperators@@QEAA_NH@Z"); - static assert(TestOperators.opIndex.mangleof == "??ATestOperators@@QEAAHH@Z"); - static assert(TestOperators.opCall.mangleof == "??RTestOperators@@QEAAHHM@Z"); +version (CppMangle_MSVC) +{ + version (Win32) + { + static assert(TestOperators.opUnary!"*".mangleof == "??DTestOperators@@QAEHXZ"); + static assert(TestOperators.opUnary!"++".mangleof == "??ETestOperators@@QAEHXZ"); + static assert(TestOperators.opUnary!"--".mangleof == "??FTestOperators@@QAEHXZ"); + static assert(TestOperators.opUnary!"-".mangleof == "??GTestOperators@@QAEHXZ"); + static assert(TestOperators.opUnary!"+".mangleof == "??HTestOperators@@QAEHXZ"); + static assert(TestOperators.opUnary!"~".mangleof == "??STestOperators@@QAEHXZ"); + static assert(TestOperators.opBinary!">>".mangleof == "??5TestOperators@@QAEHH@Z"); + static assert(TestOperators.opBinary!"<<".mangleof == "??6TestOperators@@QAEHH@Z"); + static assert(TestOperators.opBinary!"*".mangleof == "??DTestOperators@@QAEHH@Z"); + static assert(TestOperators.opBinary!"-".mangleof == "??GTestOperators@@QAEHH@Z"); + static assert(TestOperators.opBinary!"+".mangleof == "??HTestOperators@@QAEHH@Z"); + static assert(TestOperators.opBinary!"&".mangleof == "??ITestOperators@@QAEHH@Z"); + static assert(TestOperators.opBinary!"/".mangleof == "??KTestOperators@@QAEHH@Z"); + static assert(TestOperators.opBinary!"%".mangleof == "??LTestOperators@@QAEHH@Z"); + static assert(TestOperators.opBinary!"^".mangleof == "??TTestOperators@@QAEHH@Z"); + static assert(TestOperators.opBinary!"|".mangleof == "??UTestOperators@@QAEHH@Z"); + static assert(TestOperators.opOpAssign!"*".mangleof == "??XTestOperators@@QAEHH@Z"); + static assert(TestOperators.opOpAssign!"+".mangleof == "??YTestOperators@@QAEHH@Z"); + static assert(TestOperators.opOpAssign!"-".mangleof == "??ZTestOperators@@QAEHH@Z"); + static assert(TestOperators.opOpAssign!"/".mangleof == "??_0TestOperators@@QAEHH@Z"); + static assert(TestOperators.opOpAssign!"%".mangleof == "??_1TestOperators@@QAEHH@Z"); + static assert(TestOperators.opOpAssign!">>".mangleof == "??_2TestOperators@@QAEHH@Z"); + static assert(TestOperators.opOpAssign!"<<".mangleof == "??_3TestOperators@@QAEHH@Z"); + static assert(TestOperators.opOpAssign!"&".mangleof == "??_4TestOperators@@QAEHH@Z"); + static assert(TestOperators.opOpAssign!"|".mangleof == "??_5TestOperators@@QAEHH@Z"); + static assert(TestOperators.opOpAssign!"^".mangleof == "??_6TestOperators@@QAEHH@Z"); + static assert(TestOperators.opCast!int.mangleof == "??BTestOperators@@QAEHXZ"); + static assert(TestOperators.opAssign.mangleof == "??4TestOperators@@QAEHH@Z"); + static assert(TestOperators.opEquals.mangleof == "??8TestOperators@@QAE_NH@Z"); + static assert(TestOperators.opIndex.mangleof == "??ATestOperators@@QAEHH@Z"); + static assert(TestOperators.opCall.mangleof == "??RTestOperators@@QAEHHM@Z"); + } + version (Win64) + { + static assert(TestOperators.opUnary!"*".mangleof == "??DTestOperators@@QEAAHXZ"); + static assert(TestOperators.opUnary!"++".mangleof == "??ETestOperators@@QEAAHXZ"); + static assert(TestOperators.opUnary!"--".mangleof == "??FTestOperators@@QEAAHXZ"); + static assert(TestOperators.opUnary!"-".mangleof == "??GTestOperators@@QEAAHXZ"); + static assert(TestOperators.opUnary!"+".mangleof == "??HTestOperators@@QEAAHXZ"); + static assert(TestOperators.opUnary!"~".mangleof == "??STestOperators@@QEAAHXZ"); + static assert(TestOperators.opBinary!">>".mangleof == "??5TestOperators@@QEAAHH@Z"); + static assert(TestOperators.opBinary!"<<".mangleof == "??6TestOperators@@QEAAHH@Z"); + static assert(TestOperators.opBinary!"*".mangleof == "??DTestOperators@@QEAAHH@Z"); + static assert(TestOperators.opBinary!"-".mangleof == "??GTestOperators@@QEAAHH@Z"); + static assert(TestOperators.opBinary!"+".mangleof == "??HTestOperators@@QEAAHH@Z"); + static assert(TestOperators.opBinary!"&".mangleof == "??ITestOperators@@QEAAHH@Z"); + static assert(TestOperators.opBinary!"/".mangleof == "??KTestOperators@@QEAAHH@Z"); + static assert(TestOperators.opBinary!"%".mangleof == "??LTestOperators@@QEAAHH@Z"); + static assert(TestOperators.opBinary!"^".mangleof == "??TTestOperators@@QEAAHH@Z"); + static assert(TestOperators.opBinary!"|".mangleof == "??UTestOperators@@QEAAHH@Z"); + static assert(TestOperators.opOpAssign!"*".mangleof == "??XTestOperators@@QEAAHH@Z"); + static assert(TestOperators.opOpAssign!"+".mangleof == "??YTestOperators@@QEAAHH@Z"); + static assert(TestOperators.opOpAssign!"-".mangleof == "??ZTestOperators@@QEAAHH@Z"); + static assert(TestOperators.opOpAssign!"/".mangleof == "??_0TestOperators@@QEAAHH@Z"); + static assert(TestOperators.opOpAssign!"%".mangleof == "??_1TestOperators@@QEAAHH@Z"); + static assert(TestOperators.opOpAssign!">>".mangleof == "??_2TestOperators@@QEAAHH@Z"); + static assert(TestOperators.opOpAssign!"<<".mangleof == "??_3TestOperators@@QEAAHH@Z"); + static assert(TestOperators.opOpAssign!"&".mangleof == "??_4TestOperators@@QEAAHH@Z"); + static assert(TestOperators.opOpAssign!"|".mangleof == "??_5TestOperators@@QEAAHH@Z"); + static assert(TestOperators.opOpAssign!"^".mangleof == "??_6TestOperators@@QEAAHH@Z"); + static assert(TestOperators.opCast!int.mangleof == "??BTestOperators@@QEAAHXZ"); + static assert(TestOperators.opAssign.mangleof == "??4TestOperators@@QEAAHH@Z"); + static assert(TestOperators.opEquals.mangleof == "??8TestOperators@@QEAA_NH@Z"); + static assert(TestOperators.opIndex.mangleof == "??ATestOperators@@QEAAHH@Z"); + static assert(TestOperators.opCall.mangleof == "??RTestOperators@@QEAAHHM@Z"); + } } import cppmangle2; @@ -839,14 +863,14 @@ extern(C++, `Namespace18922`) void func18922_3(Struct18922) {} } -version (Posix) +version (CppMangle_Itanium) { static assert(func18922.mangleof == "_ZN14Namespace189229func18922ENS_11Struct18922E"); static assert(func18922_1.mangleof == "_ZN14Namespace1892211func18922_1ENS_11Struct18922E"); static assert(func18922_2.mangleof == "_ZN14Namespace1892211func18922_2ENS_11Struct18922E"); static assert(func18922_3.mangleof == "_ZN14Namespace1892211func18922_3ENS_11Struct18922E"); } -else version(Windows) +else version (CppMangle_MSVC) { static assert(func18922.mangleof == "?func18922@Namespace18922@@YAXUStruct18922@1@@Z"); static assert(func18922_1.mangleof == "?func18922_1@Namespace18922@@YAXUStruct18922@1@@Z"); @@ -858,7 +882,7 @@ else version(Windows) // https://issues.dlang.org/show_bug.cgi?id=18957 // extern(C++) doesn't mangle 'std' correctly on posix systems -version (Posix) +version (CppMangle_Itanium) { // https://godbolt.org/z/C5T2LQ /+ @@ -881,7 +905,7 @@ extern(C++) struct test19043(T) {} extern(C++) void test19043a(test19043!(const(char)) a) {} extern(C++) void test19043b(T)(T a) {} -version(Windows) +version (CppMangle_MSVC) { static assert(test19043a.mangleof == "?test19043a@@YAXU?$test19043@$$CBD@@@Z"); static assert(test19043b!(test19043!(const(char))).mangleof == @@ -890,7 +914,7 @@ version(Windows) // https://issues.dlang.org/show_bug.cgi?id=16479 // Missing substitution while mangling C++ template parameter for functions -version (Posix) extern (C++) +version (CppMangle_Itanium) extern (C++) { // Make sure aliases are still resolved alias Alias16479 = int; @@ -1084,15 +1108,18 @@ extern(C++, (AliasSeq!(Tup, "yay"))) { void test19278_4(); } -version(Win64) +version (CppMangle_MSVC) { - static assert(test19278.mangleof == "?test19278@helloworld@@YAXXZ"); - static assert(test19278_2.mangleof == "?test19278_2@lookup@@YAXXZ"); - static assert(test19278_3.mangleof == "?test19278_3@world@hello@@YAXXZ"); - static assert(test19278_4.mangleof == "?test19278_4@yay@world@hello@@YAXXZ"); - static assert(test19278_var.mangleof == "?test19278_var@world@hello@@3_KA"); + version (Win64) + { + static assert(test19278.mangleof == "?test19278@helloworld@@YAXXZ"); + static assert(test19278_2.mangleof == "?test19278_2@lookup@@YAXXZ"); + static assert(test19278_3.mangleof == "?test19278_3@world@hello@@YAXXZ"); + static assert(test19278_4.mangleof == "?test19278_4@yay@world@hello@@YAXXZ"); + static assert(test19278_var.mangleof == "?test19278_var@world@hello@@3_KA"); + } } -else version(Posix) +else version (CppMangle_Itanium) { static assert(test19278.mangleof == "_ZN10helloworld9test19278Ev"); static assert(test19278_2.mangleof == "_ZN6lookup11test19278_2Ev"); @@ -1105,23 +1132,26 @@ else version(Posix) // https://issues.dlang.org/show_bug.cgi?id=18958 // Issue 18958 - extern(C++) wchar, dchar mangling not correct -version(Posix) +version (Posix) enum __c_wchar_t : dchar; -else version(Windows) +else version (Windows) enum __c_wchar_t : wchar; alias wchar_t = __c_wchar_t; extern (C++) void test_char_mangling(char, wchar, dchar, wchar_t); -version (Posix) +version (CppMangle_Itanium) { static assert(test_char_mangling.mangleof == "_Z18test_char_manglingcDsDiw"); } -version (Win64) +version (CppMangle_MSVC) { - static assert(test_char_mangling.mangleof == "?test_char_mangling@@YAXD_S_U_W@Z"); + version (Win64) + { + static assert(test_char_mangling.mangleof == "?test_char_mangling@@YAXD_S_U_W@Z"); + } } // https://github.com/dlang/dmd/pull/10021/files#r294055424 -version (Posix) +version (CppMangle_Itanium) { extern(C++, PR10021_NS) struct PR10021_Struct(T){} extern(C++) void PR10021_fun(int i)(PR10021_Struct!int); @@ -1129,7 +1159,7 @@ version (Posix) } // https://github.com/dlang/dmd/pull/10021#discussion_r294095749 -version (Posix) +version (CppMangle_Itanium) { extern(C++, "a", "b") struct PR10021_Struct2 @@ -1142,7 +1172,7 @@ version (Posix) } /// https://issues.dlang.org/show_bug.cgi?id=20022 -version (Posix) +version (CppMangle_Itanium) { extern(C++, `ns20022`) enum Enum20022_1 { A = 1, } extern(C++) void fun20022_1(Enum20022_1); @@ -1167,7 +1197,7 @@ version (Posix) } // https://issues.dlang.org/show_bug.cgi?id=20094 -version (Posix) +version (CppMangle_Itanium) { extern(C++, "ns20094") { @@ -1180,7 +1210,7 @@ version (Posix) } // https://issues.dlang.org/show_bug.cgi?id=20223 -version (Posix) +version (CppMangle_Itanium) { extern(C++) { @@ -1206,7 +1236,7 @@ version (Posix) } // https://issues.dlang.org/show_bug.cgi?id=20224 -version (Posix) +version (CppMangle_Itanium) { extern(C++) public int test20224_1(T)(set20224!T set); // ok extern(C++) public int test20224_2(T)(ref set20224!T set); // segfault @@ -1228,7 +1258,7 @@ version (Posix) /**************************************/ -version (Posix) +version (CppMangle_Itanium) { extern (C++) struct Loc2 {}; extern (C++) class FuncDeclaration @@ -1251,7 +1281,7 @@ extern(C++, `bar`) // https://issues.dlang.org/show_bug.cgi?id=20700 // Only testing on WIn64 because the mangling includes 'E', // and the bug can be tested on either platform -version (Win64) extern(C++) +version (CppMangle_MSVC) version (Win64) extern(C++) { void test20700_1(Struct20700); extern(C++, class) struct Struct20700 {} @@ -1285,12 +1315,15 @@ extern (C++) alias fpcpp = noreturn function(); int funccpp(fpcpp); - version (Posix) + version (CppMangle_Itanium) static assert(funccpp.mangleof == "_Z7funccppPFvvE"); - version (Win32) - static assert(funccpp.mangleof == "?funccpp@@YAHP6AXXZ@Z"); + version (CppMangle_MSVC) + { + version (Win32) + static assert(funccpp.mangleof == "?funccpp@@YAHP6AXXZ@Z"); - version (Win64) - static assert(funccpp.mangleof == "?funccpp@@YAHP6AXXZ@Z"); + version (Win64) + static assert(funccpp.mangleof == "?funccpp@@YAHP6AXXZ@Z"); + } } diff --git a/gcc/testsuite/gdc.test/compilable/cppmangle3.d b/gcc/testsuite/gdc.test/compilable/cppmangle3.d index 531509cf4c6..93e49c72c18 100644 --- a/gcc/testsuite/gdc.test/compilable/cppmangle3.d +++ b/gcc/testsuite/gdc.test/compilable/cppmangle3.d @@ -3,6 +3,11 @@ // https://issues.dlang.org/show_bug.cgi?id=19920 module cppmangle3; +version (CppRuntime_Clang) version = CppMangle_Itanium; +version (CppRuntime_DigitalMars) version = CppMangle_MSVC; +version (CppRuntime_Gcc) version = CppMangle_Itanium; +version (CppRuntime_Microsoft) version = CppMangle_MSVC; +version (CppRuntime_Sun) version = CppMangle_Itanium; extern(C++, "true") { @@ -23,8 +28,8 @@ extern(C++, "std", "chrono") void func(); } -version(Windows) static assert(func.mangleof == "?func@chrono@std@@YAXXZ"); -else static assert(func.mangleof == "_ZNSt6chrono4funcEv"); +version(CppMangle_MSVC) static assert(func.mangleof == "?func@chrono@std@@YAXXZ"); +else static assert(func.mangleof == "_ZNSt6chrono4funcEv"); struct Foo { diff --git a/gcc/testsuite/gdc.test/compilable/issue21203.d b/gcc/testsuite/gdc.test/compilable/issue21203.d new file mode 100644 index 00000000000..30291a35e62 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/issue21203.d @@ -0,0 +1,210 @@ +version (CppRuntime_Clang) version = CppMangle_Itanium; +version (CppRuntime_Gcc) version = CppMangle_Itanium; +version (CppRuntime_Sun) version = CppMangle_Itanium; + +template ScopeClass(C , string name = C.stringof) +//if (is(C == class) && __traits(getLinkage, C) == "C++") +{ + //enum name = C.stringof; + enum ns = __traits(getCppNamespaces,C); + extern(C++, class) + { + extern(C++,(ns)) + { + pragma(mangle, C, name) + struct ScopeClass + { + char[__traits(classInstanceSize, C)] buffer; + //... all the things ... + } + } + } +} + +// Basic tests +extern(C++) +{ + class MyClassA {} + void funa(ScopeClass!MyClassA); // mangles MyClass + void funb(const ScopeClass!MyClassA); // mangles const MyClass + void func(ref ScopeClass!MyClassA); // mangles MyClass& + void fund(ref const ScopeClass!MyClassA); // mangles const MyClass& + void fune(const(ScopeClass!MyClassA)*); +} + +version (CppMangle_Itanium) +{ + static assert(funa.mangleof == "_Z4funa8MyClassA"); + static assert(funb.mangleof == "_Z4funb8MyClassA"); + static assert(func.mangleof == "_Z4funcR8MyClassA"); + static assert(fund.mangleof == "_Z4fundRK8MyClassA"); + static assert(fune.mangleof == "_Z4funePK8MyClassA"); +} +else version (CppRuntime_Microsoft) +{ + static assert(funa.mangleof == "?funa@@YAXVMyClassA@@@Z"); + static assert(funb.mangleof == "?funb@@YAXVMyClassA@@@Z"); + static if (size_t.sizeof == ulong.sizeof) + { + static assert(func.mangleof == "?func@@YAXAEAVMyClassA@@@Z"); + static assert(fund.mangleof == "?fund@@YAXAEBVMyClassA@@@Z"); + static assert(fune.mangleof == "?fune@@YAXPEBVMyClassA@@@Z"); + } + else + { + static assert(func.mangleof == "?func@@YAXAAVMyClassA@@@Z"); + static assert(fund.mangleof == "?fund@@YAXABVMyClassA@@@Z"); + static assert(fune.mangleof == "?fune@@YAXPBVMyClassA@@@Z"); + } +} + +//Basic tests with a namespace +extern(C++, "ns") +{ + class MyClassB {} + void funf(ScopeClass!MyClassB); // mangles MyClass + void fung(const ScopeClass!MyClassB); // mangles const MyClass + void funh(ref ScopeClass!MyClassB); // mangles MyClass& + void funi(ref const ScopeClass!MyClassB); // mangles const MyClass& + void funj(const(ScopeClass!MyClassB)*); +} + +version (CppMangle_Itanium) +{ + static assert(funf.mangleof == "_ZN2ns4funfENS_8MyClassBE"); + static assert(fung.mangleof == "_ZN2ns4fungENS_8MyClassBE"); + static assert(funh.mangleof == "_ZN2ns4funhERNS_8MyClassBE"); + static assert(funi.mangleof == "_ZN2ns4funiERKNS_8MyClassBE"); + static assert(funj.mangleof == "_ZN2ns4funjEPKNS_8MyClassBE"); +} +else version (CppRuntime_Microsoft) +{ + static assert(funf.mangleof == "?funf@ns@@YAXVMyClassB@1@@Z"); + static assert(fung.mangleof == "?fung@ns@@YAXVMyClassB@1@@Z"); + static if (size_t.sizeof == ulong.sizeof) + { + static assert(funh.mangleof == "?funh@ns@@YAXAEAVMyClassB@1@@Z"); + static assert(funi.mangleof == "?funi@ns@@YAXAEBVMyClassB@1@@Z"); + static assert(funj.mangleof == "?funj@ns@@YAXPEBVMyClassB@1@@Z"); + } + else + { + static assert(funh.mangleof == "?funh@ns@@YAXAAVMyClassB@1@@Z"); + static assert(funi.mangleof == "?funi@ns@@YAXABVMyClassB@1@@Z"); + static assert(funj.mangleof == "?funj@ns@@YAXPBVMyClassB@1@@Z"); + } +} + +//Templates +extern(C++) +{ + void funTempl(T)(); + class MyClassC {} + alias funTemplA = funTempl!(ScopeClass!MyClassC); + alias funTemplB = funTempl!(const ScopeClass!MyClassC); + alias funTemplC = funTempl!(const(ScopeClass!MyClassC)*); + // N.B funTempl!([const] ref ScopeClass!MyClassC) is not permissable in D +} +version (CppMangle_Itanium) +{ + static assert(funTemplA.mangleof == "_Z8funTemplI8MyClassCEvv"); + static assert(funTemplB.mangleof == "_Z8funTemplIK8MyClassCEvv"); + static assert(funTemplC.mangleof == "_Z8funTemplIPK8MyClassCEvv"); +} +else version (CppRuntime_Microsoft) +{ + static assert(funTemplA.mangleof == "??$funTempl@VMyClassC@@@@YAXXZ"); + static assert(funTemplB.mangleof == "??$funTempl@$$CBVMyClassC@@@@YAXXZ"); + static if (size_t.sizeof == ulong.sizeof) + static assert(funTemplC.mangleof == "??$funTempl@PEBVMyClassC@@@@YAXXZ"); + else + static assert(funTemplC.mangleof == "??$funTempl@PBVMyClassC@@@@YAXXZ"); +} + +template _function(F) +{ +extern(C++, "std") +{ + extern(C++, struct) + pragma(mangle, "function") + class _function + { + } +} +} +template FunctionOf(F) +{ + F f; + alias FunctionOf = typeof(*f); +} +extern(C++) void funk(ScopeClass!(_function!(FunctionOf!(void function(int))),"function") a ){ } + +version (CppMangle_Itanium) +{ + static assert(funk.mangleof == "_Z4funkSt8functionIFviEE"); +} +else version (CppRuntime_Microsoft) +{ + static assert(funk.mangleof == "?funk@@YAXV?$function@$$A6AXH@Z@std@@@Z"); +} + +extern(C++, "ns") +{ + pragma(mangle, "function") + class _function2 + { + public final void test(); + } +} + +version (CppMangle_Itanium) +{ + static assert(_function2.test.mangleof == "_ZN2ns8function4testEv"); +} +else version (CppRuntime_Microsoft) +{ + static if (size_t.sizeof == ulong.sizeof) + static assert(_function2.test.mangleof == "?test@function@ns@@QEAAXXZ"); + else + static assert(_function2.test.mangleof == "?test@function@ns@@QAEXXZ"); +} + +extern(C++, "ns") +{ + template _function3(T) + { + pragma(mangle, _function3, "function") + class _function3 + { + public final void test(); + } + } +} + +version (CppMangle_Itanium) +{ + static assert(_function3!(int).test.mangleof == "_ZN2ns8functionIiE4testEv"); +} +else version (CppRuntime_Microsoft) +{ + static if (size_t.sizeof == ulong.sizeof) + static assert(_function3!(int).test.mangleof == "?test@?$function@H@ns@@QEAAXXZ"); + else + static assert(_function3!(int).test.mangleof == "?test@?$function@H@ns@@QAEXXZ"); +} + +extern(C++) +{ + struct Foo {} + pragma(mangle, Foo) struct Foo_Doppelganger {} + + void funl(Foo_Doppelganger f); +} +version (CppMangle_Itanium) +{ + static assert(funl.mangleof == "_Z4funl3Foo"); +} +else version (CppRuntime_Microsoft) +{ + static assert(funl.mangleof == "?funl@@YAXUFoo@@@Z"); +} diff --git a/gcc/testsuite/gdc.test/compilable/issue21340.d b/gcc/testsuite/gdc.test/compilable/issue21340.d new file mode 100644 index 00000000000..22eda6e3e02 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/issue21340.d @@ -0,0 +1,38 @@ +version (CppRuntime_Clang) version = CppMangle_Itanium; +version (CppRuntime_Gcc) version = CppMangle_Itanium; +version (CppRuntime_Sun) version = CppMangle_Itanium; + +template ScopeClass(C) +if (is(C == class) && __traits(getLinkage, C) == "C++") +{ + + extern(C++, class) + extern(C++, __traits(getCppNamespaces,C)) + extern(C++, (ns)) + class ScopeClass { } +} +extern(C++) class Foo {} +extern(C++) void test(ScopeClass!Foo) +{ +} +version(CppMangle_Itanium) +{ + static assert (test.mangleof == "_Z4testP10ScopeClassIP3FooE"); +} +else version (CppRuntime_Microsoft) +{ + version (Win32) + { + static assert (test.mangleof == "?test@@YAXPAV?$ScopeClass@PAVFoo@@@@@Z"); + } + version (Win64) + { + static assert (test.mangleof == "?test@@YAXPEAV?$ScopeClass@PEAVFoo@@@@@Z"); + } +} +alias AliasSeq(T...) = T; +alias ns = AliasSeq!(); +immutable ns2 = AliasSeq!(); +extern(C++,(ns)) class Bar {} +extern(C++,) class Baz {} +extern(C++, (ns2)) class Quux {} diff --git a/gcc/testsuite/gdc.test/compilable/test10028.d b/gcc/testsuite/gdc.test/compilable/test10028.d new file mode 100644 index 00000000000..4dc5523e3eb --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test10028.d @@ -0,0 +1,7 @@ +enum E:char[4]{ str = "abcd" } +enum x = { + int[char[4]] aa; + aa[E.str] = 1; + foreach(key,val; aa) {} + return aa["abcd"]; +}(); diff --git a/gcc/testsuite/gdc.test/compilable/test20236.d b/gcc/testsuite/gdc.test/compilable/test20236.d new file mode 100644 index 00000000000..d50c874785c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test20236.d @@ -0,0 +1,22 @@ +// https://issues.dlang.org/show_bug.cgi?id=20236 + +/* +TEST_OUTPUT: +--- +--- +*/ + +struct X +{ + alias y this; + deprecated int y() { return 5; } + int x() { return 5; } +} + +void main() +{ + static void func(int) {} + with(X.init) { + func(x); + } +} diff --git a/gcc/testsuite/gdc.test/compilable/test20860.d b/gcc/testsuite/gdc.test/compilable/test20860.d new file mode 100644 index 00000000000..78b9ddd64ce --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test20860.d @@ -0,0 +1,16 @@ +// https://issues.dlang.org/show_bug.cgi?id=20860 + +struct A +{ + this(int a) {} + /// + void opDispatch(string methodName, Params...)(Params params) { + } + + ~this() {} +} + +void main() +{ + A(3).test(); +} diff --git a/gcc/testsuite/gdc.test/compilable/test21073.d b/gcc/testsuite/gdc.test/compilable/test21073.d new file mode 100644 index 00000000000..47d788128b3 --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test21073.d @@ -0,0 +1,16 @@ +// 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/test21414.d b/gcc/testsuite/gdc.test/compilable/test21414.d new file mode 100644 index 00000000000..e8a201cfb1c --- /dev/null +++ b/gcc/testsuite/gdc.test/compilable/test21414.d @@ -0,0 +1,13 @@ +// https://issues.dlang.org/show_bug.cgi?id=21414 + +struct State +{ + string s; + + immutable this(string s) + { + this.s = s; + } +} + +immutable rootState = new immutable State("b"); diff --git a/gcc/testsuite/gdc.test/fail_compilation/b15875.d b/gcc/testsuite/gdc.test/fail_compilation/b15875.d index daa79b74a19..15f362bc885 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/b15875.d +++ b/gcc/testsuite/gdc.test/fail_compilation/b15875.d @@ -1,6 +1,6 @@ /* TEST_OUTPUT: --- -fail_compilation/b15875.d(9): Error: circular reference to variable `a` +fail_compilation/b15875.d(9): Error: undefined identifier `a` fail_compilation/b15875.d(10): Error: circular reference to `b15875.f` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail116.d b/gcc/testsuite/gdc.test/fail_compilation/fail116.d index 66a01c68ac0..64f225d0994 100644 --- a/gcc/testsuite/gdc.test/fail_compilation/fail116.d +++ b/gcc/testsuite/gdc.test/fail_compilation/fail116.d @@ -1,7 +1,7 @@ /* TEST_OUTPUT: --- -fail_compilation/fail116.d(11): Error: circular `typeof` definition +fail_compilation/fail116.d(11): Error: undefined identifier `x` fail_compilation/fail116.d(16): Error: template instance `square!1.2` does not match template declaration `square(_error_ x)` --- */ diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20616.d b/gcc/testsuite/gdc.test/fail_compilation/fail20616.d new file mode 100644 index 00000000000..0f76e315ac7 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail20616.d @@ -0,0 +1,26 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail20616.d(16): Error: undefined identifier `$` +fail_compilation/fail20616.d(16): Aggregate declaration 'X()' does not define 'opDollar' +fail_compilation/fail20616.d(18): Error: undefined identifier `$` +fail_compilation/fail20616.d(18): Aggregate declaration 'b' does not define 'opDollar' +--- +*/ +module fail20616; + +void g() { + struct X { + auto opSlice(size_t a, size_t b) { return ""; } + } + auto x = X()[0 .. $]; + auto b = X(); + auto c = b[0 .. $ - 1]; + auto v = [1, 2, 3]; + auto d = v[$.. $]; +} + +int main() { + g(); + return 0; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22529.d b/gcc/testsuite/gdc.test/fail_compilation/fail22529.d new file mode 100644 index 00000000000..3bec3c0f7d3 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22529.d @@ -0,0 +1,14 @@ +// https://issues.dlang.org/show_bug.cgi?id=22529 + +/* +TEST_OUTPUT: +--- +fail_compilation/fail22529.d(13): Error: found `return` when expecting `;` following statement +--- +*/ + +void main() +{ + foo() + return; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22570.d b/gcc/testsuite/gdc.test/fail_compilation/fail22570.d new file mode 100644 index 00000000000..cb8c286650d --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/fail22570.d @@ -0,0 +1,21 @@ +// https://issues.dlang.org/show_bug.cgi?id=22570 + +/* +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` +--- +*/ + +struct S +{ + Object o1; +} + +void main() @safe +{ + S[] s; + s = [S(null, null)]; + s ~= S(null, null); +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice22516.d b/gcc/testsuite/gdc.test/fail_compilation/ice22516.d new file mode 100644 index 00000000000..1c71f38d23a --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/ice22516.d @@ -0,0 +1,21 @@ +/++ +https://issues.dlang.org/show_bug.cgi?id=22516 + +TEST_OUTPUT: +--- +fail_compilation/ice22516.d(18): Error: undefined identifier `X` +--- ++/ + +struct Data +{ + void function() eval; + +} + +struct Builtins +{ + X x; + + Data myData = { (){} }; +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22574.d b/gcc/testsuite/gdc.test/fail_compilation/test22574.d new file mode 100644 index 00000000000..2a7b8849816 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test22574.d @@ -0,0 +1,12 @@ +//https://issues.dlang.org/show_bug.cgi?id=22574 +/* +TEST_OUTPUT: +--- +fail_compilation/test22574.d(100): Error: undefined identifier `x` +--- +*/ +#line 100 +template test(x* x) +{ + +} diff --git a/gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d b/gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d new file mode 100644 index 00000000000..a0d1d122e63 --- /dev/null +++ b/gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d @@ -0,0 +1,101 @@ +/++ +https://issues.dlang.org/show_bug.cgi?id=22514 +TEST_OUTPUT: +--- +fail_compilation/test_switch_error.d(13): Error: undefined identifier `doesNotExist` +fail_compilation/test_switch_error.d(16): Error: undefined identifier `alsoDoesNotExits` +fail_compilation/test_switch_error.d(19): Error: duplicate `case 2` in `switch` statement +--- +++/ + +void test1() +{ + switch (doesNotExist) + { + case 1: + alsoDoesNotExits(); + break; + case 2: break; + case 2: break; + } +} + +/++ +TEST_OUTPUT: +--- +fail_compilation/test_switch_error.d(105): Error: undefined identifier `doesNotExist` +--- +++/ +#line 100 + +enum foo = 1; + +void test2() +{ + switch (doesNotExist) + { + case foo: break; + } +} + +/++ +TEST_OUTPUT: +--- +fail_compilation/test_switch_error.d(206): Error: undefined identifier `a` +fail_compilation/test_switch_error.d(207): Error: undefined identifier `b` +--- +++/ +#line 200 + +void test3() +{ + + switch (1) + { + case a: break; + case b: break; + } +} + +/++ +TEST_OUTPUT: +--- +fail_compilation/test_switch_error.d(303): Error: undefined identifier `doesNotExits` +--- +++/ +#line 300 + +void test4() +{ + auto foo = doesNotExits(); + switch (1) + { + case foo: break; + case foo: break; + } +} + +/++ +TEST_OUTPUT: +--- +fail_compilation/test_switch_error.d(405): Error: `case` variables have to be `const` or `immutable` +fail_compilation/test_switch_error.d(412): Error: `case` variables not allowed in `final switch` statements +--- +++/ +#line 400 + +void test5(int i) +{ + switch (i) + { + case i: break; + default: break; + } + + const int j = i; + final switch (i) + { + case j: break; + + } +} diff --git a/gcc/testsuite/gdc.test/runnable/interpret.d b/gcc/testsuite/gdc.test/runnable/interpret.d index 989fb2e1e90..d8059d32a91 100644 --- a/gcc/testsuite/gdc.test/runnable/interpret.d +++ b/gcc/testsuite/gdc.test/runnable/interpret.d @@ -3660,6 +3660,28 @@ void test20133() auto rtest2 = fun20133_2(); } +/************************************************/ +// https://issues.dlang.org/show_bug.cgi?id=22530 + +class D22530 { } + +class C22530 +{ + D22530 y = new D22530; + alias y this; +} + +void test22530() +{ + // fixed + static assert(cast(D22530)(new C22530) is null); + static assert((1 ? cast(D22530)(new C22530) : new D22530) is null); + + // runtime version already works + assert(cast(D22530)(new C22530) is null); + assert((1 ? cast(D22530)(new C22530) : new D22530) is null); +} + /************************************************/ int main() @@ -3789,6 +3811,7 @@ int main() test20400(); test21878(); test20133(); + test22530(); printf("Success\n"); return 0; diff --git a/gcc/testsuite/gdc.test/runnable/test16579.d b/gcc/testsuite/gdc.test/runnable/test16579.d new file mode 100644 index 00000000000..e42ead9b99c --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test16579.d @@ -0,0 +1,57 @@ +// REQUIRED_ARGS: -unittest +// PERMUTE_ARGS: +// https://issues.dlang.org/show_bug.cgi?id=16579 + +struct Thing +{ + enum Instance = Thing(); + int a = 42; + + void iter() + { + assert(this.a == 42); + } +} + +void main() +{ + return Thing.Instance.iter; // Added 'return' +} + +// From https://issues.dlang.org/show_bug.cgi?id=16576 + +alias a = test2!(); +alias b = test3!(); + + +template test2() +{ + struct Thing{ + static enum Instance = Thing([0, 1, 2, 3]); + int[] array; + void iter(in string str) const{ + foreach(j, tup; this.array) assert(tup == j); + assert(this.array && this.array.length == 4); + } + } + unittest{ + auto test(in string str){return Thing.Instance.iter(str);} + test("?"); + } +} + +template test3() +{ + struct Thing{ + static enum Instance = Thing([0, 1, 2, 3]); + int[] array; + void iter() const{ + foreach(j, tup; this.array) assert(tup == j); + assert(this.array && this.array.length == 4); + } + } + unittest{ + auto test(){return Thing.Instance.iter();} + test(); + } +} diff --git a/gcc/testsuite/gdc.test/runnable/test18054.d b/gcc/testsuite/gdc.test/runnable/test18054.d new file mode 100644 index 00000000000..610dff11e7a --- /dev/null +++ b/gcc/testsuite/gdc.test/runnable/test18054.d @@ -0,0 +1,41 @@ +/+ +REQUIRED_ARGS: -d +RUN_OUTPUT: +--- +float: 1 == 1 +double: 1 == 1 +real: 1 == 1 +ifloat: 1 == 1 +idouble: 1 == 1 +ireal: 1 == 1 +cfloat: 1 == 1 +cdouble: 1 == 1 +creal: 1 == 1 +--- ++/ + +import core.stdc.stdio : printf; + +void test(T, string lit)() +{ + T d = mixin(lit); + bool runtime = cast(bool) d; + bool folded = cast(bool) mixin(lit); + + printf((T.stringof ~ ": %d == %d\n\0").ptr, runtime, folded); +} + +void main() +{ + test!(float, "0.5f"); + test!(double, "0.5" ); + test!(real, "0.5L"); + + test!(ifloat, "0.5i"); + test!(idouble, "0.5i"); + test!(ireal, "0.5i"); + + test!(cfloat, "0.3 + 0.5i"); + test!(cdouble, "0.3 + 0.5i"); + test!(creal, "0.3 + 0.5i"); +} diff --git a/gcc/testsuite/gdc.test/runnable_cxx/cppa.d b/gcc/testsuite/gdc.test/runnable_cxx/cppa.d index e6db3c4da43..c60d6c66ef3 100644 --- a/gcc/testsuite/gdc.test/runnable_cxx/cppa.d +++ b/gcc/testsuite/gdc.test/runnable_cxx/cppa.d @@ -442,28 +442,54 @@ void test13161() version (linux) { - extern(C++, __gnu_cxx) + static if (__traits(getTargetInfo, "cppStd") < 201703) { - struct new_allocator(T) + // See note on std::allocator below. + extern(C++, __gnu_cxx) { - alias size_type = size_t; - static if (is(T : char)) - void deallocate(T*, size_type) { } - else - void deallocate(T*, size_type); + 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) - { (cast(__gnu_cxx.new_allocator!T*)&this).deallocate(p, 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); + } } } @@ -476,12 +502,21 @@ extern (C++, std) { } - // https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html - version (none) + version (CppRuntime_Gcc) { - extern (C++, __cxx11) + // https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html + static if (__traits(getTargetInfo, "cppStd") >= 201103) + { + extern (C++, __cxx11) + { + struct basic_string(T, C = char_traits!T, A = allocator!T) + { + } + } + } + else { - struct basic_string(T, C = char_traits!T, A = allocator!T) + extern (C++, class) struct basic_string(T, C = char_traits!T, A = allocator!T) { } } diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cppb.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cppb.cpp index ab1ea0a5a55..ea4fb1c8a0e 100644 --- a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cppb.cpp +++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cppb.cpp @@ -1,36 +1,3 @@ -/* -GCC 5.1 introduced new implementations of std::string and std::list: - -https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html - -This causes e.g. std::string to be actually defined as -std::__cxx11::string. - -On machines with GCC 5.1, this manifests as a linker error when -running the cppa.d / cppb.cpp test: - -cppa.o: In function `_D4cppa6test14FZv': -cppa.d:(.text._D4cppa6test14FZv+0x11): undefined reference to `foo14a(std::string*)' -cppa.d:(.text._D4cppa6test14FZv+0x18): undefined reference to `foo14b(std::basic_string, std::allocator >*)' -cppa.d:(.text._D4cppa6test14FZv+0x3a): undefined reference to `foo14f(std::char_traits*, std::string*, std::string*)' -cppa.o: In function `_D4cppa7testeh3FZv': -cppa.d:(.text._D4cppa7testeh3FZv+0x19): undefined reference to `throwle()' -collect2: error: ld returned 1 exit status ---- errorlevel 1 - -When the .cpp file is compiled with g++ 5.3.0, the actual function -signatures in the cppb.o object file are: - -foo14a(std::__cxx11::basic_string, std::allocator >*) -foo14b(std::__cxx11::basic_string, std::allocator >*) -foo14f(std::char_traits*, std::__cxx11::basic_string, std::allocator >*, std::__cxx11::basic_string, std::allocator >*) - -Fortunately, it is easily possible to disable the new feature -by defining _GLIBCXX_USE_CXX11_ABI as 0 before including any standard -headers. -*/ -#define _GLIBCXX_USE_CXX11_ABI 0 - #include #include #include diff --git a/libphobos/configure b/libphobos/configure index 14298a0dc4f..17b26565505 100755 --- a/libphobos/configure +++ b/libphobos/configure @@ -15566,7 +15566,7 @@ SPEC_PHOBOS_DEPS="$LIBS" # Libdruntime / phobos soname version -libtool_VERSION=2:0:0 +libtool_VERSION=3:0:0 # Set default flags (after DRUNTIME_WERROR!) diff --git a/libphobos/configure.ac b/libphobos/configure.ac index 3b5a830cccf..c961e68105a 100644 --- a/libphobos/configure.ac +++ b/libphobos/configure.ac @@ -265,7 +265,7 @@ SPEC_PHOBOS_DEPS="$LIBS" AC_SUBST(SPEC_PHOBOS_DEPS) # Libdruntime / phobos soname version -libtool_VERSION=2:0:0 +libtool_VERSION=3:0:0 AC_SUBST(libtool_VERSION) # Set default flags (after DRUNTIME_WERROR!) diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index edb101758b8..b3da9063ce3 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -1,4 +1,4 @@ -bc58b1e9ea68051af9094651a26313371297b79f +6364e010bc87f3621028c8ac648133535c126fb3 The first line of this file holds the git revision number of the last merge done from the dlang/druntime repository. diff --git a/libphobos/libdruntime/core/internal/traits.d b/libphobos/libdruntime/core/internal/traits.d index 60d9be3ac9b..0d733f2b384 100644 --- a/libphobos/libdruntime/core/internal/traits.d +++ b/libphobos/libdruntime/core/internal/traits.d @@ -185,22 +185,38 @@ template dtorIsNothrow(T) } // taken from std.meta.allSatisfy -enum allSatisfy(alias pred, items...) = +template allSatisfy(alias F, T...) { - static foreach (item; items) - static if (!pred!item) - if (__ctfe) return false; - return true; -}(); + static foreach (Ti; T) + { + static if (!is(typeof(allSatisfy) == bool) && // not yet defined + !F!(Ti)) + { + enum allSatisfy = false; + } + } + static if (!is(typeof(allSatisfy) == bool)) // if not yet defined + { + enum allSatisfy = true; + } +} // taken from std.meta.anySatisfy -enum anySatisfy(alias pred, items...) = +template anySatisfy(alias F, Ts...) { - static foreach (item; items) - static if (pred!item) - if (__ctfe) return true; - return false; -}(); + static foreach (T; Ts) + { + static if (!is(typeof(anySatisfy) == bool) && // not yet defined + F!T) + { + enum anySatisfy = true; + } + } + static if (!is(typeof(anySatisfy) == bool)) // if not yet defined + { + enum anySatisfy = false; + } +} // simplified from std.traits.maxAlignment template maxAlignment(Ts...) diff --git a/libphobos/libdruntime/core/lifetime.d b/libphobos/libdruntime/core/lifetime.d index b45e95f4226..8fb61a547d5 100644 --- a/libphobos/libdruntime/core/lifetime.d +++ b/libphobos/libdruntime/core/lifetime.d @@ -2111,9 +2111,6 @@ private T trustedMoveImpl(T)(return scope ref T source) @trusted // target must be first-parameter, because in void-functions DMD + dip1000 allows it to take the place of a return-scope private void moveEmplaceImpl(T)(scope ref T target, return scope ref T source) { - import core.stdc.string : memcpy, memset; - import core.internal.traits; - // TODO: this assert pulls in half of phobos. we need to work out an alternative assert strategy. // static if (!is(T == class) && hasAliasing!T) if (!__ctfe) // { @@ -2124,11 +2121,16 @@ private void moveEmplaceImpl(T)(scope ref T target, return scope ref T source) static if (is(T == struct)) { + import core.internal.traits; + // Unsafe when compiling without -preview=dip1000 assert((() @trusted => &source !is &target)(), "source and target must not be identical"); static if (hasElaborateAssign!T || !isAssignable!T) + { + import core.stdc.string : memcpy; () @trusted { memcpy(&target, &source, T.sizeof); }(); + } else target = source; @@ -2146,15 +2148,21 @@ private void moveEmplaceImpl(T)(scope ref T target, return scope ref T source) enum sz = T.sizeof; static if (__traits(isZeroInit, T)) + { + import core.stdc.string : memset; () @trusted { memset(&source, 0, sz); }(); + } else + { + import core.stdc.string : memcpy; () @trusted { memcpy(&source, __traits(initSymbol, T).ptr, sz); }(); + } } } else static if (__traits(isStaticArray, T)) { for (size_t i = 0; i < source.length; ++i) - move(source[i], target[i]); + moveEmplaceImpl(target[i], source[i]); } else { @@ -2204,6 +2212,34 @@ pure nothrow @nogc @system unittest assert(val == 0); } +@betterC +pure nothrow @nogc @system unittest +{ + static struct Foo + { + pure nothrow @nogc: + this(int* ptr) { _ptr = ptr; } + ~this() { if (_ptr) ++*_ptr; } + int* _ptr; + } + + int val; + { + Foo[1] foo1 = void; // uninitialized + Foo[1] foo2 = [Foo(&val)];// initialized + assert(foo2[0]._ptr is &val); + + // Using `move(foo2, foo1)` would have an undefined effect because it would destroy + // the uninitialized foo1. + // moveEmplace directly overwrites foo1 without destroying or initializing it first. + moveEmplace(foo2, foo1); + assert(foo1[0]._ptr is &val); + assert(foo2[0]._ptr is null); + assert(val == 0); + } + assert(val == 1); +} + // issue 18913 @safe unittest { @@ -2222,17 +2258,10 @@ pure nothrow @nogc @system unittest f(move(ncarray)); } -/** - * This is called for a delete statement where the value - * being deleted is a pointer to a struct with a destructor - * but doesn't have an overloaded delete operator. - * - * Params: - * p = pointer to the value to be deleted - */ -void _d_delstruct(T)(ref T *p) +/// Implementation of `_d_delstruct` and `_d_delstructTrace` +template _d_delstructImpl(T) { - if (p) + private void _d_delstructImpure(ref T p) { debug(PRINTF) printf("_d_delstruct(%p)\n", p); @@ -2242,21 +2271,61 @@ void _d_delstruct(T)(ref T *p) GC.free(p); p = null; } + + /** + * This is called for a delete statement where the value being deleted is a + * pointer to a struct with a destructor but doesn't have an overloaded + * `delete` operator. + * + * Params: + * p = pointer to the value to be deleted + * + * Bugs: + * This function template was ported from a much older runtime hook that + * bypassed safety, purity, and throwabilty checks. To prevent breaking + * existing code, this function template is temporarily declared + * `@trusted` until the implementation can be brought up to modern D + * expectations. + */ + void _d_delstruct(ref T p) @trusted @nogc pure nothrow + { + if (p) + { + alias Type = void function(ref T P) @nogc pure nothrow; + (cast(Type) &_d_delstructImpure)(p); + } + } + + import core.internal.array.utils : _d_HookTraceImpl; + + private enum errorMessage = "Cannot delete struct if compiling without support for runtime type information!"; + + /** + * TraceGC wrapper around $(REF _d_delstruct, core,lifetime,_d_delstructImpl). + * + * Bugs: + * This function template was ported from a much older runtime hook that + * bypassed safety, purity, and throwabilty checks. To prevent breaking + * existing code, this function template is temporarily declared + * `@trusted` until the implementation can be brought up to modern D + * expectations. + */ + alias _d_delstructTrace = _d_HookTraceImpl!(T, _d_delstruct, errorMessage); } -@system unittest +@system pure nothrow unittest { int dtors = 0; struct S { ~this() { ++dtors; } } S *s = new S(); - _d_delstruct(s); + _d_delstructImpl!(typeof(s))._d_delstruct(s); assert(s == null); assert(dtors == 1); } -@system unittest +@system pure unittest { int innerDtors = 0; int outerDtors = 0; @@ -2277,16 +2346,16 @@ void _d_delstruct(T)(ref T *p) { ++outerDtors; - _d_delstruct(i1); + _d_delstructImpl!(typeof(i1))._d_delstruct(i1); assert(i1 == null); - _d_delstruct(i2); + _d_delstructImpl!(typeof(i2))._d_delstruct(i2); assert(i2 == null); } } Outer *o = new Outer(0); - _d_delstruct(o); + _d_delstructImpl!(typeof(o))._d_delstruct(o); assert(o == null); assert(innerDtors == 2); diff --git a/libphobos/libdruntime/core/runtime.d b/libphobos/libdruntime/core/runtime.d index b08ec52a246..81d2d261a80 100644 --- a/libphobos/libdruntime/core/runtime.d +++ b/libphobos/libdruntime/core/runtime.d @@ -798,7 +798,7 @@ else static if (hasExecinfo) private class DefaultTraceInfo : Throwable.TraceInf enum CALL_INSTRUCTION_SIZE = 1; static if (__traits(compiles, backtrace((void**).init, int.init))) - numframes = backtrace(this.callstack.ptr, MAXFRAMES); + numframes = cast(int) backtrace(this.callstack.ptr, MAXFRAMES); // Backtrace succeeded, adjust the frame to point to the caller if (numframes >= 2) foreach (ref elem; this.callstack) diff --git a/libphobos/libdruntime/core/sys/openbsd/execinfo.d b/libphobos/libdruntime/core/sys/openbsd/execinfo.d index f5b317f2bfc..cd9cd166e57 100644 --- a/libphobos/libdruntime/core/sys/openbsd/execinfo.d +++ b/libphobos/libdruntime/core/sys/openbsd/execinfo.d @@ -11,137 +11,10 @@ module core.sys.openbsd.execinfo; version (OpenBSD): extern (C): nothrow: +@nogc: -version (GNU) - version = BacktraceExternal; - -version (BacktraceExternal) -{ - size_t backtrace(void**, size_t); - char** backtrace_symbols(const(void*)*, size_t); - void backtrace_symbols_fd(const(void*)*, size_t, int); - char** backtrace_symbols_fmt(const(void*)*, size_t, const char*); - int backtrace_symbols_fd_fmt(const(void*)*, size_t, int, const char*); -} -else -{ - import core.sys.openbsd.dlfcn; - - // Use extern (D) so that these functions don't collide with libexecinfo. - - extern (D) int backtrace(void** buffer, int size) - { - import core.thread : thread_stackBottom; - - void** p, pend=cast(void**)thread_stackBottom(); - version (D_InlineAsm_X86) - asm nothrow @trusted { mov p[EBP], EBP; } - else version (D_InlineAsm_X86_64) - asm nothrow @trusted { mov p[RBP], RBP; } - else - static assert(false, "Architecture not supported."); - - int i; - for (; i < size && p < pend; ++i) - { - buffer[i] = *(p + 1); - auto pnext = cast(void**)*p; - if (pnext <= p) break; - p = pnext; - } - return i; - } - - - extern (D) char** backtrace_symbols(const(void*)* buffer, int size) - { - static void* realloc(void* p, size_t len) nothrow - { - static import cstdlib=core.stdc.stdlib; - auto res = cstdlib.realloc(p, len); - if (res is null) cstdlib.free(p); - return res; - } - - if (size <= 0) return null; - - size_t pos = size * (char*).sizeof; - char** p = cast(char**)realloc(null, pos); - if (p is null) return null; - - Dl_info info; - foreach (i, addr; buffer[0 .. size]) - { - if (dladdr(addr, &info) == 0) - (cast(ubyte*)&info)[0 .. info.sizeof] = 0; - fixupDLInfo(addr, info); - - immutable len = formatStackFrame(null, 0, addr, info); - assert(len > 0); - - p = cast(char**)realloc(p, pos + len); - if (p is null) return null; - - formatStackFrame(cast(char*)p + pos, len, addr, info) == len || assert(0); - - p[i] = cast(char*)pos; - pos += len; - } - foreach (i; 0 .. size) - { - pos = cast(size_t)p[i]; - p[i] = cast(char*)p + pos; - } - return p; - } - - - extern (D) void backtrace_symbols_fd(const(void*)* buffer, int size, int fd) - { - import core.sys.posix.unistd : write; - import core.stdc.stdlib : alloca; - - if (size <= 0) return; - - Dl_info info; - foreach (i, addr; buffer[0 .. size]) - { - if (dladdr(addr, &info) == 0) - (cast(ubyte*)&info)[0 .. info.sizeof] = 0; - fixupDLInfo(addr, info); - - enum maxAlloca = 1024; - enum min = (size_t a, size_t b) => a <= b ? a : b; - immutable len = min(formatStackFrame(null, 0, addr, info), maxAlloca); - assert(len > 0); - - auto p = cast(char*)alloca(len); - if (p is null) return; - - formatStackFrame(p, len, addr, info) >= len || assert(0); - p[len - 1] = '\n'; - write(fd, p, len); - } - } - - - private void fixupDLInfo(const(void)* addr, ref Dl_info info) - { - if (info.dli_fname is null) info.dli_fname = "???"; - if (info.dli_fbase is null) info.dli_fbase = null; - if (info.dli_sname is null) info.dli_sname = "???"; - if (info.dli_saddr is null) info.dli_saddr = cast(void*)addr; - } - - - private size_t formatStackFrame(char* p, size_t plen, const(void)* addr, const ref Dl_info info) - { - import core.stdc.stdio : snprintf; - - immutable off = addr - info.dli_saddr; - immutable len = snprintf(p, plen, "%p <%s+%zd> at %s", - addr, info.dli_sname, off, info.dli_fname); - assert(len > 0); - return cast(size_t)len + 1; // + '\0' - } -} +size_t backtrace(void**, size_t); +char** backtrace_symbols(const(void*)*, size_t); +void backtrace_symbols_fd(const(void*)*, size_t, int); +char** backtrace_symbols_fmt(const(void*)*, size_t, const char*); +int backtrace_symbols_fd_fmt(const(void*)*, size_t, int, const char*); diff --git a/libphobos/libdruntime/core/sys/posix/sys/stat.d b/libphobos/libdruntime/core/sys/posix/sys/stat.d index 6b4d022b825..7d0b1708e2d 100644 --- a/libphobos/libdruntime/core/sys/posix/sys/stat.d +++ b/libphobos/libdruntime/core/sys/posix/sys/stat.d @@ -340,26 +340,23 @@ version (CRuntime_Glibc) } c_long[14] st_pad5; } + static if (!__USE_FILE_OFFSET64) + static assert(stat_t.sizeof == 144); + else + static assert(stat_t.sizeof == 160); } else version (MIPS64) { struct stat_t { - c_ulong st_dev; + dev_t st_dev; int[3] st_pad1; - static if (!__USE_FILE_OFFSET64) - { - ino_t st_ino; - } - else - { - c_ulong st_ino; - } + ino_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; - c_ulong st_rdev; + dev_t st_rdev; static if (!__USE_FILE_OFFSET64) { uint[2] st_pad2; @@ -368,8 +365,8 @@ version (CRuntime_Glibc) } else { - c_long[3] st_pad2; - c_long st_size; + uint[3] st_pad2; + off_t st_size; } static if (__USE_MISC || __USE_XOPEN2K8) { @@ -394,15 +391,26 @@ version (CRuntime_Glibc) } blksize_t st_blksize; uint st_pad4; + blkcnt_t st_blocks; + int[14] st_pad5; + } + version (MIPS_N32) + { static if (!__USE_FILE_OFFSET64) - { - blkcnt_t st_blocks; - } + static assert(stat_t.sizeof == 160); else - { - c_long st_blocks; - } - c_long[14] st_pad5; + static assert(stat_t.sizeof == 176); + } + else version (MIPS_O64) + { + static if (!__USE_FILE_OFFSET64) + static assert(stat_t.sizeof == 160); + else + static assert(stat_t.sizeof == 176); + } + else + { + static assert(stat_t.sizeof == 216); } } else version (PPC) diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d index fee19ae65f0..29b5d58de5b 100644 --- a/libphobos/libdruntime/object.d +++ b/libphobos/libdruntime/object.d @@ -4651,7 +4651,7 @@ public import core.internal.array.construction : _d_arrayctor; public import core.internal.array.construction : _d_arraysetctor; public import core.internal.array.capacity: _d_arraysetlengthTImpl; -public import core.lifetime : _d_delstruct; +public import core.lifetime : _d_delstructImpl; public import core.internal.dassert: _d_assert_fail; diff --git a/libphobos/libdruntime/rt/monitor_.d b/libphobos/libdruntime/rt/monitor_.d index 763f4392822..0f1d0e97004 100644 --- a/libphobos/libdruntime/rt/monitor_.d +++ b/libphobos/libdruntime/rt/monitor_.d @@ -6,10 +6,6 @@ * Authors: Walter Bright, Sean Kelly, Martin Nowak * Source: $(DRUNTIMESRC rt/_monitor_.d) */ - -/* NOTE: This file has been patched from the original DMD distribution to - * work with the GDC compiler. - */ module rt.monitor_; import core.atomic, core.stdc.stdlib, core.stdc.string; @@ -175,37 +171,7 @@ package: alias IMonitor = Object.Monitor; alias DEvent = void delegate(Object); -version (GNU) -{ - import gcc.config; - static if (GNU_Thread_Model == ThreadModel.Single) - version = SingleThreaded; - // Ignore ThreadModel, we don't want posix threads on windows and - // will always use native threading instead. -} - -version (SingleThreaded) -{ -@nogc: - alias Mutex = int; - - void initMutex(Mutex* mtx) - { - } - - void destroyMutex(Mutex* mtx) - { - } - - void lockMutex(Mutex* mtx) - { - } - - void unlockMutex(Mutex* mtx) - { - } -} -else version (Windows) +version (Windows) { version (CRuntime_DigitalMars) { diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index 68fefcb1ae4..c9d166b03a7 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -1,4 +1,4 @@ -12329adb67fb43891d6e4e543e7257bc34db0aa7 +575b67a9b4f78415f96ca77ad50b2de4c667cc74 The first line of this file holds the git revision number of the last merge done from the dlang/phobos repository. diff --git a/libphobos/src/std/algorithm/searching.d b/libphobos/src/std/algorithm/searching.d index 96352064c55..55a14385e8a 100644 --- a/libphobos/src/std/algorithm/searching.d +++ b/libphobos/src/std/algorithm/searching.d @@ -638,7 +638,7 @@ Returns: */ size_t count(alias pred = "a == b", Range, E)(Range haystack, E needle) if (isInputRange!Range && !isInfinite!Range && - is(typeof(binaryFun!pred(haystack.front, needle)) : bool)) + is(typeof(binaryFun!pred(haystack.front, needle)))) { bool pred2(ElementType!Range a) { return binaryFun!pred(a, needle); } return count!pred2(haystack); @@ -693,7 +693,7 @@ if (isInputRange!Range && !isInfinite!Range && size_t count(alias pred = "a == b", R1, R2)(R1 haystack, R2 needle) if (isForwardRange!R1 && !isInfinite!R1 && isForwardRange!R2 && - is(typeof(binaryFun!pred(haystack.front, needle.front)) : bool)) + is(typeof(binaryFun!pred(haystack.front, needle.front)))) { assert(!needle.empty, "Cannot count occurrences of an empty range"); @@ -716,7 +716,7 @@ if (isForwardRange!R1 && !isInfinite!R1 && /// Ditto size_t count(alias pred, R)(R haystack) if (isInputRange!R && !isInfinite!R && - is(typeof(unaryFun!pred(haystack.front)) : bool)) + is(typeof(unaryFun!pred(haystack.front)))) { size_t result; alias T = ElementType!R; //For narrow strings forces dchar iteration @@ -745,6 +745,12 @@ if (isInputRange!R && !isInfinite!R) assert([1, 2, 3].count([2, 3]) == 1); } +// https://issues.dlang.org/show_bug.cgi?id=22582 +@safe unittest +{ + assert([1, 2, 3].count!"a & 1" == 2); +} + /++ Counts elements in the given $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) diff --git a/libphobos/src/std/datetime/timezone.d b/libphobos/src/std/datetime/timezone.d index a55411b02d5..28255f4ef99 100644 --- a/libphobos/src/std/datetime/timezone.d +++ b/libphobos/src/std/datetime/timezone.d @@ -2464,7 +2464,8 @@ public: if (!tzName.extension().empty || !tzName.startsWith(subName) || baseName(tzName) == "leapseconds" || - tzName == "+VERSION") + tzName == "+VERSION" || + tzName == "SECURITY") { continue; } diff --git a/libphobos/src/std/parallelism.d b/libphobos/src/std/parallelism.d index bd467d21c3f..971cfa07e2b 100644 --- a/libphobos/src/std/parallelism.d +++ b/libphobos/src/std/parallelism.d @@ -2738,7 +2738,7 @@ public: immutable size_t nBytesNeeded = nWorkUnits * RTask.sizeof; import core.stdc.stdlib : malloc, free; - if (nBytesNeeded < maxStack) + if (nBytesNeeded <= maxStack) { tasks = (cast(RTask*) buf.ptr)[0 .. nWorkUnits]; } @@ -3045,11 +3045,11 @@ public: Since the underlying data for this struct is heap-allocated, this struct has reference semantics when passed between functions. - The main uses cases for `WorkerLocalStorageStorage` are: + The main uses cases for `WorkerLocalStorage` are: 1. Performing parallel reductions with an imperative, as opposed to functional, programming style. In this case, it's useful to treat - `WorkerLocalStorageStorage` as local to each thread for only the parallel + `WorkerLocalStorage` as local to each thread for only the parallel portion of an algorithm. 2. Recycling temporary buffers across iterations of a parallel foreach loop. diff --git a/libphobos/src/std/regex/package.d b/libphobos/src/std/regex/package.d index 82207b6cc68..8db0b1e1f59 100644 --- a/libphobos/src/std/regex/package.d +++ b/libphobos/src/std/regex/package.d @@ -70,7 +70,7 @@ $(TR $(TD Objects) $(TD ... // multi-pattern regex - auto multi = regex([`\d+,\d+`,`(a-z]+):(\d+)`]); + auto multi = regex([`\d+,\d+`, `([a-z]+):(\d+)`]); auto m = "abc:43 12,34".matchAll(multi); assert(m.front.whichPattern == 2); assert(m.front[1] == "abc"); @@ -80,9 +80,17 @@ $(TR $(TD Objects) $(TD assert(m.front[1] == "12"); ... - // The result of the `matchAll/matchFirst` is directly testable with if/assert/while. - // e.g. test if a string consists of letters: - assert(matchFirst("Letter", `^\p{L}+$`)); + // The result of `matchAll/matchFirst` is directly testable with `if/assert/while`, + // e.g. test if a string consists of letters only: + assert(matchFirst("LettersOnly", `^\p{L}+$`)); + + // And we can take advantage of the ability to define a variable in the $(LINK2 https://dlang.org/spec/statement.html#IfCondition `IfCondition`): + if (const auto captures = matchFirst("At l34st one digit, but maybe more...", `((\d)(\d*))`)) + { + assert(captures[2] == "3"); + assert(captures[3] == "4"); + assert(captures[1] == "34"); + } --- $(SECTION Syntax and general information) diff --git a/libphobos/src/std/traits.d b/libphobos/src/std/traits.d index 154141588ba..c1d6bc97402 100644 --- a/libphobos/src/std/traits.d +++ b/libphobos/src/std/traits.d @@ -829,6 +829,10 @@ private template fqnType(T, { enum fqnType = "dstring"; } + else static if (is(T == typeof(null))) + { + enum fqnType = "typeof(null)"; + } else static if (isBasicType!T && !is(T == enum)) { enum fqnType = chain!((Unqual!T).stringof); @@ -919,6 +923,7 @@ private template fqnType(T, static assert(fqn!(string) == "string"); static assert(fqn!(wstring) == "wstring"); static assert(fqn!(dstring) == "dstring"); + static assert(fqn!(typeof(null)) == "typeof(null)"); static assert(fqn!(void) == "void"); static assert(fqn!(const(void)) == "const(void)"); static assert(fqn!(shared(void)) == "shared(void)"); diff --git a/libphobos/testsuite/libphobos.traits/all_satisfy.d b/libphobos/testsuite/libphobos.traits/all_satisfy.d new file mode 100644 index 00000000000..2c008ce927e --- /dev/null +++ b/libphobos/testsuite/libphobos.traits/all_satisfy.d @@ -0,0 +1,24 @@ +// https://issues.dlang.org/show_bug.cgi?id=22210 + +import core.internal.traits : allSatisfy; + +enum isHashable(T) = __traits(compiles, + () { T.init; } +); + +class A +{ + static if (isHashable!B) {} +} + +class B +{ + static if (isHashable!C) {} +} + +class C +{ + static if (allSatisfy!(isHashable, int, B)) {} +} + +void main() {} diff --git a/libphobos/testsuite/libphobos.traits/traits.exp b/libphobos/testsuite/libphobos.traits/traits.exp new file mode 100644 index 00000000000..cb785382f51 --- /dev/null +++ b/libphobos/testsuite/libphobos.traits/traits.exp @@ -0,0 +1,27 @@ +# Copyright (C) 2021 Free Software Foundation, Inc. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . + +# Initialize dg. +dg-init + +# Gather a list of all tests. +set tests [lsort [find $srcdir/$subdir *.d]] + +# Main loop. +dg-runtest $tests "" $DEFAULT_DFLAGS + +# All done. +dg-finish