d: Merge upstream dmd 93108bb9e, druntime 6364e010, phobos 575b67a9b.
authorIain Buclaw <ibuclaw@gdcproject.org>
Wed, 15 Dec 2021 18:47:02 +0000 (19:47 +0100)
committerIain Buclaw <ibuclaw@gdcproject.org>
Wed, 15 Dec 2021 18:51:30 +0000 (19:51 +0100)
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.

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.

68 files changed:
gcc/d/d-lang.cc
gcc/d/dmd/MERGE
gcc/d/dmd/VERSION
gcc/d/dmd/constfold.d
gcc/d/dmd/cparse.d
gcc/d/dmd/ctfeexpr.d
gcc/d/dmd/dinterpret.d
gcc/d/dmd/dsymbol.d
gcc/d/dmd/dsymbol.h
gcc/d/dmd/dsymbolsem.d
gcc/d/dmd/dtemplate.d
gcc/d/dmd/expression.d
gcc/d/dmd/expressionsem.d
gcc/d/dmd/importc.d
gcc/d/dmd/initsem.d
gcc/d/dmd/lexer.d
gcc/d/dmd/opover.d
gcc/d/dmd/optimize.d
gcc/d/dmd/parse.d
gcc/d/dmd/printast.d
gcc/d/dmd/semantic3.d
gcc/d/dmd/statementsem.d
gcc/d/dmd/target.d
gcc/d/dmd/target.h
gcc/d/dmd/tokens.d
gcc/d/dmd/tokens.h
gcc/d/dmd/typesem.d
gcc/d/gdc.texi
gcc/testsuite/gdc.test/compilable/cppmangle.d
gcc/testsuite/gdc.test/compilable/cppmangle3.d
gcc/testsuite/gdc.test/compilable/issue21203.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/issue21340.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test10028.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test20236.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test20860.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test21073.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test21414.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/b15875.d
gcc/testsuite/gdc.test/fail_compilation/fail116.d
gcc/testsuite/gdc.test/fail_compilation/fail20616.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/fail22529.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/fail22570.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/ice22516.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/test22574.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/interpret.d
gcc/testsuite/gdc.test/runnable/test16579.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/test18054.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable_cxx/cppa.d
gcc/testsuite/gdc.test/runnable_cxx/extra-files/cppb.cpp
libphobos/configure
libphobos/configure.ac
libphobos/libdruntime/MERGE
libphobos/libdruntime/core/internal/traits.d
libphobos/libdruntime/core/lifetime.d
libphobos/libdruntime/core/runtime.d
libphobos/libdruntime/core/sys/openbsd/execinfo.d
libphobos/libdruntime/core/sys/posix/sys/stat.d
libphobos/libdruntime/object.d
libphobos/libdruntime/rt/monitor_.d
libphobos/src/MERGE
libphobos/src/std/algorithm/searching.d
libphobos/src/std/datetime/timezone.d
libphobos/src/std/parallelism.d
libphobos/src/std/regex/package.d
libphobos/src/std/traits.d
libphobos/testsuite/libphobos.traits/all_satisfy.d [new file with mode: 0644]
libphobos/testsuite/libphobos.traits/traits.exp [new file with mode: 0644]

index 2c5d206..d762195 100644 (file)
@@ -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;
index 4bae16c..d7eff4f 100644 (file)
@@ -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.
index fa5940e..822edd4 100644 (file)
@@ -1 +1 @@
-v2.098.0
+v2.098.1-beta.1
index 3ca23f2..3cc358e 100644 (file)
@@ -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())
     {
index dfc45e0..b1532ad 100644 (file)
@@ -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);
index 9cd09ba..baacaa6 100644 (file)
@@ -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
         {
index 891adb3..8f20c38 100644 (file)
@@ -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)
index b1d1b1d..0f75157 100644 (file)
@@ -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.
index 02252fd..668b079 100644 (file)
@@ -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();
index 0bf9a80..3a9abd2 100644 (file)
@@ -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());
 
index 5dedcba..b1760dd 100644 (file)
@@ -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;
index e6b7e30..749a50a 100644 (file)
@@ -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());
index ec2bce4..48e47ce 100644 (file)
@@ -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;
index 0dad1a8..5ee961f 100644 (file)
@@ -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;
+        }
+    }
+}
+
index c5aa0f4..51ee27d 100644 (file)
@@ -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.");
         }
index d38cce4..bb76a1a 100644 (file)
@@ -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");
index 4d250c0..bafeaa3 100644 (file)
@@ -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;
+                    }
                 }
             }
         }
index 6b2176b..ca9e0b3 100644 (file)
@@ -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
index 2229e78..94056ab 100644 (file)
@@ -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;
             }
index b9f0c5e..33b5e7f 100644 (file)
@@ -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);
index 893f96b..da328fd 100644 (file)
@@ -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());
index 6979cdf..91855ac 100644 (file)
@@ -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)
index 7a875a5..8e434a3 100644 (file)
@@ -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
index 1363693..6348d93 100644 (file)
@@ -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
index 2609af5..2d98d5e 100644 (file)
@@ -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",
index f3e4411..2e1d1f4 100644 (file)
@@ -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_,
index 417d2c1..2a86416 100644 (file)
@@ -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)
index d37d205..bfec156 100644 (file)
@@ -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
index 1820de9..8c112d1 100644 (file)
@@ -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");
+    }
 }
index 531509c..93e49c7 100644 (file)
@@ -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 (file)
index 0000000..30291a3
--- /dev/null
@@ -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 (file)
index 0000000..22eda6e
--- /dev/null
@@ -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 (file)
index 0000000..4dc5523
--- /dev/null
@@ -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 (file)
index 0000000..d50c874
--- /dev/null
@@ -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 (file)
index 0000000..78b9ddd
--- /dev/null
@@ -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 (file)
index 0000000..47d7881
--- /dev/null
@@ -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 (file)
index 0000000..e8a201c
--- /dev/null
@@ -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");
index daa79b7..15f362b 100644 (file)
@@ -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`
 ---
 */
index 66a01c6..64f225d 100644 (file)
@@ -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 (file)
index 0000000..0f76e31
--- /dev/null
@@ -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 (file)
index 0000000..3bec3c0
--- /dev/null
@@ -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 (file)
index 0000000..cb8c286
--- /dev/null
@@ -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 (file)
index 0000000..1c71f38
--- /dev/null
@@ -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 (file)
index 0000000..2a7b884
--- /dev/null
@@ -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 (file)
index 0000000..a0d1d12
--- /dev/null
@@ -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;
+
+    }
+}
index 989fb2e..d8059d3 100644 (file)
@@ -3661,6 +3661,28 @@ void test20133()
 }
 
 /************************************************/
+// 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 (file)
index 0000000..e42ead9
--- /dev/null
@@ -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 (file)
index 0000000..610dff1
--- /dev/null
@@ -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");
+}
index e6db3c4..c60d6c6 100644 (file)
@@ -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)
             {
             }
         }
index ab1ea0a..ea4fb1c 100644 (file)
@@ -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<int, std::char_traits<int>, std::allocator<int> >*)'
-cppa.d:(.text._D4cppa6test14FZv+0x3a): undefined reference to `foo14f(std::char_traits<char>*, 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<char, std::char_traits<char>, std::allocator<char> >*)
-foo14b(std::__cxx11::basic_string<int, std::char_traits<int>, std::allocator<int> >*)
-foo14f(std::char_traits<char>*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >*)
-
-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 <stdio.h>
 #include <stdint.h>
 #include <assert.h>
index 14298a0..17b2656 100755 (executable)
@@ -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!)
index 3b5a830..c961e68 100644 (file)
@@ -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!)
index edb1017..b3da906 100644 (file)
@@ -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.
index 60d9be3..0d733f2 100644 (file)
@@ -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...)
index b45e95f..8fb61a5 100644 (file)
@@ -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);
index b08ec52..81d2d26 100644 (file)
@@ -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)
index f5b317f..cd9cd16 100644 (file)
@@ -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*);
index 6b4d022..7d0b170 100644 (file)
@@ -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)
index fee19ae..29b5d58 100644 (file)
@@ -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;
 
index 763f439..0f1d0e9 100644 (file)
@@ -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)
     {
index 68fefcb..c9d166b 100644 (file)
@@ -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.
index 9635206..55a1438 100644 (file)
@@ -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)
index a55411b..28255f4 100644 (file)
@@ -2464,7 +2464,8 @@ public:
                         if (!tzName.extension().empty ||
                             !tzName.startsWith(subName) ||
                             baseName(tzName) == "leapseconds" ||
-                            tzName == "+VERSION")
+                            tzName == "+VERSION" ||
+                            tzName == "SECURITY")
                         {
                             continue;
                         }
index bd467d2..971cfa0 100644 (file)
@@ -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.
index 82207b6..8db0b1e 100644 (file)
@@ -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)
index 1541415..c1d6bc9 100644 (file)
@@ -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 (file)
index 0000000..2c008ce
--- /dev/null
@@ -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 (file)
index 0000000..cb78538
--- /dev/null
@@ -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
+# <http://www.gnu.org/licenses/>.
+
+# 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