d: Merge upstream dmd 4d1bfcf14, druntime 9ba9a6ae, phobos c0cc5e917.
authorIain Buclaw <ibuclaw@gdcproject.org>
Wed, 13 Apr 2022 12:34:49 +0000 (13:34 +0100)
committerIain Buclaw <ibuclaw@gdcproject.org>
Wed, 13 Apr 2022 14:02:57 +0000 (15:02 +0100)
D front-end changes:

    - Import dmd v2.099.1.
    - Added `@mustuse' attribute, implmenting DIP 1038.
    - Added `.tupleof` property for static arrays

D runtime changes:

    - Import druntime v2.099.1.

Phobos changes:

    - Import phobos v2.099.1.
    - Zlib bindings have been updated to 1.2.12.

gcc/d/ChangeLog:

* Make-lang.in (D_FRONTEND_OBJS): Add d/common-bitfields.o,
d/mustuse.o.
* d-ctfloat.cc (CTFloat::isIdentical): Don't treat NaN values as
identical.
* dmd/MERGE: Merge upstream dmd 4d1bfcf14.
* expr.cc (ExprVisitor::visit (VoidInitExp *)): New.

libphobos/ChangeLog:

* libdruntime/MERGE: Merge upstream druntime 9ba9a6ae.
* src/MERGE: Merge upstream phobos c0cc5e917.

93 files changed:
gcc/d/Make-lang.in
gcc/d/d-ctfloat.cc
gcc/d/dmd/MERGE
gcc/d/dmd/README.md
gcc/d/dmd/VERSION
gcc/d/dmd/arrayop.d
gcc/d/dmd/attrib.d
gcc/d/dmd/common/README.md
gcc/d/dmd/common/bitfields.d [new file with mode: 0644]
gcc/d/dmd/common/file.d
gcc/d/dmd/common/outbuffer.d
gcc/d/dmd/common/string.d
gcc/d/dmd/constfold.d
gcc/d/dmd/ctfeexpr.d
gcc/d/dmd/dcast.d
gcc/d/dmd/declaration.d
gcc/d/dmd/dmangle.d
gcc/d/dmd/dmodule.d
gcc/d/dmd/dsymbol.d
gcc/d/dmd/dsymbolsem.d
gcc/d/dmd/dtemplate.d
gcc/d/dmd/escape.d
gcc/d/dmd/expression.d
gcc/d/dmd/expressionsem.d
gcc/d/dmd/file_manager.d
gcc/d/dmd/hdrgen.d
gcc/d/dmd/id.d
gcc/d/dmd/initsem.d
gcc/d/dmd/json.d
gcc/d/dmd/lexer.d
gcc/d/dmd/mtype.d
gcc/d/dmd/mtype.h
gcc/d/dmd/mustuse.d [new file with mode: 0644]
gcc/d/dmd/opover.d
gcc/d/dmd/optimize.d
gcc/d/dmd/root/aav.d
gcc/d/dmd/root/array.d
gcc/d/dmd/root/complex.d
gcc/d/dmd/root/file.d
gcc/d/dmd/root/longdouble.d
gcc/d/dmd/root/optional.d
gcc/d/dmd/semantic2.d
gcc/d/dmd/statementsem.d
gcc/d/dmd/tokens.d
gcc/d/dmd/traits.d
gcc/d/dmd/typesem.d
gcc/d/dmd/utils.d
gcc/d/expr.cc
gcc/testsuite/gdc.test/compilable/extra-files/header1.d
gcc/testsuite/gdc.test/compilable/imports/imp17434a.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/imports/imp17434b.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/interpret3.d
gcc/testsuite/gdc.test/compilable/json.d
gcc/testsuite/gdc.test/compilable/mixintype2.d
gcc/testsuite/gdc.test/compilable/must_use_assign.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/must_use_not_reserved.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/must_use_opassign.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/must_use_opopassign.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/must_use_opunary.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/must_use_suppress.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test17419.d
gcc/testsuite/gdc.test/compilable/test17434.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test17434a.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test19097.d
gcc/testsuite/gdc.test/compilable/test22988.d [new file with mode: 0644]
gcc/testsuite/gdc.test/compilable/test22997.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/diag14235.d
gcc/testsuite/gdc.test/fail_compilation/diag8101.d
gcc/testsuite/gdc.test/fail_compilation/diag_funclit.d
gcc/testsuite/gdc.test/fail_compilation/diagin.d
gcc/testsuite/gdc.test/fail_compilation/fail2656.d
gcc/testsuite/gdc.test/fail_compilation/fail99.d
gcc/testsuite/gdc.test/fail_compilation/fix19059.d
gcc/testsuite/gdc.test/fail_compilation/ice10922.d
gcc/testsuite/gdc.test/fail_compilation/ice9540.d
gcc/testsuite/gdc.test/fail_compilation/must_use.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/must_use_comma.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/must_use_opunary.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/must_use_reserved.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/must_use_template.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/must_use_union.d [new file with mode: 0644]
gcc/testsuite/gdc.test/fail_compilation/test11176.d
gcc/testsuite/gdc.test/fail_compilation/test17284.d
gcc/testsuite/gdc.test/fail_compilation/test19097.d
gcc/testsuite/gdc.test/fail_compilation/test21008.d
gcc/testsuite/gdc.test/runnable/test20603.d [new file with mode: 0644]
gcc/testsuite/gdc.test/runnable/xtest46.d
libphobos/libdruntime/MERGE
libphobos/libdruntime/core/int128.d
libphobos/libdruntime/core/lifetime.d
libphobos/src/MERGE
libphobos/src/etc/c/zlib.d
libphobos/src/std/regex/internal/parser.d

index 6c90657d65f6cccaa1b9596553d49b97a48bfd44..f3e34c54015154edb10d569e74ce1260c3468081 100644 (file)
@@ -89,6 +89,7 @@ D_FRONTEND_OBJS = \
        d/canthrow.o \
        d/chkformat.o \
        d/clone.o \
+       d/common-bitfields.o \
        d/common-file.o \
        d/common-outbuffer.o \
        d/common-string.o \
@@ -143,6 +144,7 @@ D_FRONTEND_OBJS = \
        d/lambdacomp.o \
        d/lexer.o \
        d/mtype.o \
+       d/mustuse.o \
        d/nogc.o \
        d/nspace.o \
        d/ob.o \
index 6e6d10ff0a45c1fa0ecb7ea34daa9245e3dc1145..c4d9a44c59ba14ed46f2c7d2dfd81f08fb7b14ff 100644 (file)
@@ -55,8 +55,7 @@ CTFloat::isIdentical (real_t x, real_t y)
 {
   real_value rx = x.rv ();
   real_value ry = y.rv ();
-  return (REAL_VALUE_ISNAN (rx) && REAL_VALUE_ISNAN (ry))
-    || real_identical (&rx, &ry);
+  return real_identical (&rx, &ry);
 }
 
 /* Return true if real_t value R is NaN.  */
index ca409df346dcdeed69138d03c11cd599903a3337..f36d65e7d84eaf47c9895ddccee93731682223d5 100644 (file)
@@ -1,4 +1,4 @@
-47871363d804f54b29ccfd444b082c19716c2301
+4d1bfcf142928cf1c097b0a2689485c1b14f4f53
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
index f613ab28577713c3a400e9eba4f37d984ecd46fd..b14310312cda575a4d9339d72e25edc43151be5e 100644 (file)
@@ -130,6 +130,8 @@ Note that these groups have no strict meaning, the category assignments are a bi
 | [impcnvtab.d](https://github.com/dlang/dmd/blob/master/src/dmd/impcnvtab.d)   | Define an implicit conversion table for basic types                                        |
 | [importc.d](https://github.com/dlang/dmd/blob/master/src/dmd/importc.d)       | Helpers specific to ImportC                                                                |
 | [sideeffect.d](https://github.com/dlang/dmd/blob/master/src/dmd/sideeffect.d) | Extract side-effects of expressions for certain lowerings.                                 |
+| [mustuse.d](https://github.com/dlang/dmd/blob/master/src/dmd/mustuse.d)       | Helpers related to the `@mustuse` attribute                                                |
+
 
 **Compile Time Function Execution (CTFE)**
 
index 16f49a73f4d971826ffc8ed54df4fe85347c5211..28a360921abff987bf4460d9deabca92de7913c9 100644 (file)
@@ -1 +1 @@
-v2.099.1-beta.1
+v2.099.1
index 52f39d34d0f0b2afa3638300341726da56d0d712..16cbe620bc5cb1ad8d588a06acb29d2c43bf8a6a 100644 (file)
@@ -158,7 +158,7 @@ Expression arrayOp(BinExp e, Scope* sc)
 /// ditto
 Expression arrayOp(BinAssignExp e, Scope* sc)
 {
-    //printf("BinAssignExp.arrayOp() %s\n", toChars());
+    //printf("BinAssignExp.arrayOp() %s\n", e.toChars());
 
     /* Check that the elements of e1 can be assigned to
      */
index 9c2bbd672a7a06ef9c0675cef8ac8e8d58c1a0d0..1e84b55d181a194c3eb4c52f4d53af0dc5485136 100644 (file)
@@ -44,7 +44,6 @@ import dmd.mtype;
 import dmd.objc; // for objc.addSymbols
 import dmd.common.outbuffer;
 import dmd.root.array; // for each
-import dmd.target; // for target.systemLinkage
 import dmd.tokens;
 import dmd.visitor;
 
@@ -399,7 +398,7 @@ extern (C++) final class LinkDeclaration : AttribDeclaration
     {
         super(loc, null, decl);
         //printf("LinkDeclaration(linkage = %d, decl = %p)\n", linkage, decl);
-        this.linkage = (linkage == LINK.system) ? target.systemLinkage() : linkage;
+        this.linkage = linkage;
     }
 
     static LinkDeclaration create(const ref Loc loc, LINK p, Dsymbols* decl)
@@ -994,7 +993,7 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration
     // Decide if 'then' or 'else' code should be included
     override Dsymbols* include(Scope* sc)
     {
-        //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, scope);
+        //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
 
         if (errors)
             return null;
@@ -1057,7 +1056,7 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
      */
     override Dsymbols* include(Scope* sc)
     {
-        //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, scope);
+        //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
 
         if (errors || onStack)
             return null;
@@ -1496,12 +1495,7 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
         if (global.params.cplusplus < CppStdRevision.cpp11)
             return;
 
-        // Avoid `if` at the call site
-        if (sym.userAttribDecl is null || sym.userAttribDecl.atts is null)
-            return;
-
-        foreach (exp; *sym.userAttribDecl.atts)
-        {
+        foreachUdaNoSemantic(sym, (exp) {
             if (isGNUABITag(exp))
             {
                 if (sym.isCPPNamespaceDeclaration() || sym.isNspace())
@@ -1515,9 +1509,10 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
                     sym.errors = true;
                 }
                 // Only one `@gnuAbiTag` is allowed by semantic2
-                return;
+                return 1; // break
             }
-        }
+            return 0; // continue
+        });
     }
 }
 
@@ -1544,14 +1539,14 @@ bool isCoreUda(Dsymbol sym, Identifier ident)
 /**
  * Iterates the UDAs attached to the given symbol.
  *
- * If `dg` returns `!= 0`, it will stop the iteration and return that
- * value, otherwise it will return 0.
- *
  * Params:
  *  sym = the symbol to get the UDAs from
  *  sc = scope to use for semantic analysis of UDAs
- *  dg = called once for each UDA. If `dg` returns `!= 0`, it will stop the
- *      iteration and return that value, otherwise it will return `0`.
+ *  dg = called once for each UDA
+ *
+ * Returns:
+ *  If `dg` returns `!= 0`, stops the iteration and returns that value.
+ *  Otherwise, returns 0.
  */
 int foreachUda(Dsymbol sym, Scope* sc, int delegate(Expression) dg)
 {
@@ -1577,3 +1572,32 @@ int foreachUda(Dsymbol sym, Scope* sc, int delegate(Expression) dg)
         });
     });
 }
+
+/**
+ * Iterates the UDAs attached to the given symbol, without performing semantic
+ * analysis.
+ *
+ * Use this function instead of `foreachUda` if semantic analysis of `sym` is
+ * still in progress.
+ *
+ * Params:
+ *  sym = the symbol to get the UDAs from
+ *  dg = called once for each UDA
+ *
+ * Returns:
+ *  If `dg` returns `!= 0`, stops the iteration and returns that value.
+ *  Otherwise, returns 0.
+ */
+int foreachUdaNoSemantic(Dsymbol sym, int delegate(Expression) dg)
+{
+    if (sym.userAttribDecl is null || sym.userAttribDecl.atts is null)
+        return 0;
+
+    foreach (exp; *sym.userAttribDecl.atts)
+    {
+        if (auto result = dg(exp))
+            return result;
+    }
+
+    return 0;
+}
index a9b65c3dd8d7cf4f19a5a2028b588332060c09bb..fb282dcf0a1daa4ac7abd5ad2105a805111817fa 100644 (file)
@@ -2,6 +2,7 @@
 
 | File                                                                               | Purpose                                                         |
 |------------------------------------------------------------------------------------|-----------------------------------------------------------------|
+| [bitfields.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/bitfields.d) | Pack multiple boolean fields into bit fields                    |
 | [file.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/file.d)           | Functions and objects dedicated to file I/O and management      |
 | [outbuffer.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/outbuffer.d) | An expandable buffer in which you can write text or binary data |
 | [string.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/string.d)       | Common string functions including filename manipulation         |
diff --git a/gcc/d/dmd/common/bitfields.d b/gcc/d/dmd/common/bitfields.d
new file mode 100644 (file)
index 0000000..d17983d
--- /dev/null
@@ -0,0 +1,70 @@
+/**
+ * A library bitfields utility
+ *
+ * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
+ * Authors:   Dennis Korpel
+ * License:   $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source:    $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/bitfields.d, common/bitfields.d)
+ * Documentation: https://dlang.org/phobos/dmd_common_bitfields.html
+ * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/bitfields.d
+ */
+module dmd.common.bitfields;
+
+/**
+ * Generate code for bit fields inside a struct/class body
+ * Params:
+ *   S = type of a struct with only boolean fields, which should become bit fields
+ *   T = type of bit fields variable, must have enough bits to store all booleans
+ * Returns: D code with a bit fields variable and getter / setter functions
+ */
+extern (D) string generateBitFields(S, T)()
+if (__traits(isUnsigned, T))
+{
+    string result = "extern (C++) pure nothrow @nogc @safe final {";
+    enum structName = __traits(identifier, S);
+
+    foreach (size_t i, mem; __traits(allMembers, S))
+    {
+        static assert(is(typeof(__traits(getMember, S, mem)) == bool));
+        static assert(i < T.sizeof * 8, "too many fields for bit field storage of type `"~T.stringof~"`");
+        enum mask = "(1 << "~i.stringof~")";
+        result ~= "
+        /// set or get the corresponding "~structName~" member
+        bool "~mem~"() const { return !!(bitFields & "~mask~"); }
+        /// ditto
+        bool "~mem~"(bool v)
+        {
+            v ? (bitFields |= "~mask~") : (bitFields &= ~"~mask~");
+            return v;
+        }";
+    }
+    return result ~ "}\n private "~T.stringof~" bitFields;\n";
+}
+
+///
+unittest
+{
+    static struct B
+    {
+        bool x;
+        bool y;
+        bool z;
+    }
+
+    static struct S
+    {
+        mixin(generateBitFields!(B, ubyte));
+    }
+
+    S s;
+    assert(!s.x);
+    s.x = true;
+    assert(s.x);
+    s.x = false;
+    assert(!s.x);
+
+    s.y = true;
+    assert(s.y);
+    assert(!s.x);
+    assert(!s.z);
+}
index e4483d5f9477945ef0b8c344251f170204996c06..8f34b5319a9814754a27b894c4282e99f2cc975a 100644 (file)
@@ -25,6 +25,8 @@ import core.sys.posix.unistd;
 
 import dmd.common.string;
 
+nothrow:
+
 /**
 Encapsulated management of a memory-mapped file.
 
@@ -52,6 +54,8 @@ struct FileMapping(Datum)
     private const(char)* name;
     // state }
 
+  nothrow:
+
     /**
     Open `filename` and map it in memory. If `Datum` is `const`, opens for
     read-only and maps the content in memory; no error is issued if the file
index 0705c1880c055b872856960c1a8fb9f3b7660178..7e46d294f3d3d4dd807261dc95ff93d343a8d3cb 100644 (file)
@@ -16,6 +16,8 @@ import core.stdc.stdio;
 import core.stdc.string;
 import core.stdc.stdlib;
 
+nothrow:
+
 // In theory these functions should also restore errno, but we don't care because
 // we abort application on error anyway.
 extern (C) private pure @system @nogc nothrow
@@ -54,6 +56,8 @@ struct OutBuffer
     int level;
     // state }
 
+  nothrow:
+
     /**
     Construct given size.
     */
index d3bc24f2667d4c37a1686823a9763d7e6d20dced..48bf9bb5b553839e1af59f89dd9d02d362f60c71 100644 (file)
@@ -10,6 +10,8 @@
  */
 module dmd.common.string;
 
+nothrow:
+
 /**
 Defines a temporary array using a fixed-length buffer as back store. If the length
 of the buffer suffices, it is readily used. Otherwise, `malloc` is used to
@@ -26,6 +28,8 @@ struct SmallBuffer(T)
     private T[] _extent;
     private bool needsFree;
 
+  nothrow:
+
     @disable this(); // no default ctor
     @disable this(ref const SmallBuffer!T); // noncopyable, nonassignable
 
index 75ba9ea1e0a3470d59b986cd822732e0cd42884f..bf66408f1d4e69d362fcf56a2017eaad81b8b2bf 100644 (file)
@@ -936,7 +936,7 @@ UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expressio
     {
         if (e1.type.isreal())
         {
-            cmp = RealIdentical(e1.toReal(), e2.toReal());
+            cmp = CTFloat.isIdentical(e1.toReal(), e2.toReal());
         }
         else if (e1.type.isimaginary())
         {
index 32aed16e79693f2d65f64ef055db5f7282c3c6b2..11229d4bd4f5d24addb8dd97aff6712456ab9cbe 100644 (file)
@@ -1269,7 +1269,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
         real_t r1 = e1.type.isreal() ? e1.toReal() : e1.toImaginary();
         real_t r2 = e1.type.isreal() ? e2.toReal() : e2.toImaginary();
         if (identity)
-            return !RealIdentical(r1, r2);
+            return !CTFloat.isIdentical(r1, r2);
         if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
         {
             return 1;   // they are not equal
@@ -1399,7 +1399,7 @@ bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2)
         cmp = (es1.var == es2.var && es1.offset == es2.offset);
     }
     else if (e1.type.isreal())
-        cmp = RealIdentical(e1.toReal(), e2.toReal());
+        cmp = CTFloat.isIdentical(e1.toReal(), e2.toReal());
     else if (e1.type.isimaginary())
         cmp = RealIdentical(e1.toImaginary(), e2.toImaginary());
     else if (e1.type.iscomplex())
index 685987b734d42a38bf3c0cf0a538a93dfbe8f69a..83978391e42657c60977eb73c880bc6c075a5d01 100644 (file)
@@ -432,7 +432,7 @@ MATCH implicitConvTo(Expression e, Type t)
                 return MATCH.nomatch;
             goto case Tuns8;
         case Tuns8:
-            //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value);
+            //printf("value = %llu %llu\n", cast(dinteger_t)cast(ubyte)value, value);
             if (cast(ubyte)value != value)
                 return MATCH.nomatch;
             break;
@@ -492,8 +492,8 @@ MATCH implicitConvTo(Expression e, Type t)
             break;
 
         case Tpointer:
-            //printf("type = %s\n", type.toBasetype()->toChars());
-            //printf("t = %s\n", t.toBasetype()->toChars());
+            //printf("type = %s\n", type.toBasetype().toChars());
+            //printf("t = %s\n", t.toBasetype().toChars());
             if (ty == Tpointer && e.type.toBasetype().nextOf().ty == t.toBasetype().nextOf().ty)
             {
                 /* Allow things like:
@@ -1107,6 +1107,10 @@ MATCH implicitConvTo(Expression e, Type t)
 
     MATCH visitCond(CondExp e)
     {
+        auto result = visit(e);
+        if (result != MATCH.nomatch)
+            return result;
+
         MATCH m1 = e.e1.implicitConvTo(t);
         MATCH m2 = e.e2.implicitConvTo(t);
         //printf("CondExp: m1 %d m2 %d\n", m1, m2);
@@ -2077,7 +2081,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
         if (auto tsa = tb.isTypeSArray())
         {
             size_t dim2 = cast(size_t)tsa.dim.toInteger();
-            //printf("dim from = %d, to = %d\n", (int)se.len, (int)dim2);
+            //printf("dim from = %d, to = %d\n", cast(int)se.len, cast(int)dim2);
 
             // Changing dimensions
             if (dim2 != se.len)
index c0e40a5263a08f70405951f7a6865d9fb16d7982..45eb582745a21ac34f6d5af9e3a46ec900a88e11 100644 (file)
@@ -1083,29 +1083,12 @@ extern (C++) class VarDeclaration : Declaration
         bool isArgDtorVar;      /// temporary created to handle scope destruction of a function argument
     }
 
-    private ushort bitFields;       // stores multiple booleans for BitFields
+    import dmd.common.bitfields : generateBitFields;
+    mixin(generateBitFields!(BitFields, ushort));
+
     byte canassign;                 // it can be assigned to
     ubyte isdataseg;                // private data for isDataseg 0 unset, 1 true, 2 false
 
-    // Generate getter and setter functions for `bitFields`
-    extern (D) mixin(() {
-        string result = "extern (C++) pure nothrow @nogc @safe final {";
-        foreach (size_t i, mem; __traits(allMembers, BitFields))
-        {
-            result ~= "
-            /// set or get the corresponding BitFields member
-            bool "~mem~"() const { return !!(bitFields & (1 << "~i.stringof~")); }
-            /// ditto
-            bool "~mem~"(bool v)
-            {
-                v ? (bitFields |= (1 << "~i.stringof~")) : (bitFields &= ~(1 << "~i.stringof~"));
-                return v;
-            }";
-        }
-        return result ~ "}";
-    }());
-
-
     final extern (D) this(const ref Loc loc, Type type, Identifier ident, Initializer _init, StorageClass storage_class = STC.undefined_)
     in
     {
index c3662a734d85f94f90ff6a700e2e94fdcb587c9a..1f895e03af05eb66afba9e954b02ac4d73c7e64f 100644 (file)
@@ -340,7 +340,6 @@ public:
         final switch (t.linkage)
         {
         case LINK.default_:
-        case LINK.system:
         case LINK.d:
             mc = 'F';
             break;
@@ -356,6 +355,8 @@ public:
         case LINK.objc:
             mc = 'Y';
             break;
+        case LINK.system:
+            assert(0);
         }
         buf.writeByte(mc);
 
@@ -1340,7 +1341,9 @@ extern (D) const(char)[] externallyMangledIdentifier(Declaration d)
     {
         if (d.linkage != LINK.d && d.localNum)
             d.error("the same declaration cannot be in multiple scopes with non-D linkage");
-        final switch (d.linkage)
+
+        const l = d.linkage == LINK.system ? target.systemLinkage() : d.linkage;
+        final switch (l)
         {
             case LINK.d:
                 break;
@@ -1354,9 +1357,10 @@ extern (D) const(char)[] externallyMangledIdentifier(Declaration d)
                 return p.toDString();
             }
             case LINK.default_:
-            case LINK.system:
                 d.error("forward declaration");
                 return d.ident.toString();
+            case LINK.system:
+                assert(0);
         }
     }
     return null;
index c7e6418bf46b35b51744d09e4170cd5b4fecf5e3..e9c4c954efdd2dccef574d6ee15ff8d95445b8cb 100644 (file)
@@ -69,7 +69,7 @@ void semantic3OnDependencies(Module m)
 /**
  * Remove generated .di files on error and exit
  */
-void removeHdrFilesAndFail(ref Param params, ref Modules modules)
+void removeHdrFilesAndFail(ref Param params, ref Modules modules) nothrow
 {
     if (params.doHdrGeneration)
     {
@@ -94,7 +94,7 @@ void removeHdrFilesAndFail(ref Param params, ref Modules modules)
  * Returns:
  *  the filename of the child package or module
  */
-private const(char)[] getFilename(Identifier[] packages, Identifier ident)
+private const(char)[] getFilename(Identifier[] packages, Identifier ident) nothrow
 {
     const(char)[] filename = ident.toString();
 
@@ -157,14 +157,14 @@ extern (C++) class Package : ScopeDsymbol
     uint tag;        // auto incremented tag, used to mask package tree in scopes
     Module mod;     // !=null if isPkgMod == PKG.module_
 
-    final extern (D) this(const ref Loc loc, Identifier ident)
+    final extern (D) this(const ref Loc loc, Identifier ident) nothrow
     {
         super(loc, ident);
         __gshared uint packageTag;
         this.tag = packageTag++;
     }
 
-    override const(char)* kind() const
+    override const(char)* kind() const nothrow
     {
         return "package";
     }
@@ -664,7 +664,7 @@ extern (C++) final class Module : Package
         //printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars());
         if (auto result = global.fileManager.lookup(srcfile))
         {
-            this.src = result.data;
+            this.src = result;
             if (global.params.emitMakeDeps)
                 global.params.makeDeps.push(srcfile.toChars());
             return true;
@@ -1380,7 +1380,7 @@ extern (C++) final class Module : Package
         a.setDim(0);
     }
 
-    extern (D) static void clearCache()
+    extern (D) static void clearCache() nothrow
     {
         foreach (Module m; amodules)
             m.searchCacheIdent = null;
@@ -1391,7 +1391,7 @@ extern (C++) final class Module : Package
      * return true if it imports m.
      * Can be used to detect circular imports.
      */
-    int imports(Module m)
+    int imports(Module m) nothrow
     {
         //printf("%s Module::imports(%s)\n", toChars(), m.toChars());
         version (none)
@@ -1414,14 +1414,14 @@ extern (C++) final class Module : Package
         return false;
     }
 
-    bool isRoot()
+    bool isRoot() nothrow
     {
         return this.importedFrom == this;
     }
 
     // true if the module source file is directly
     // listed in command line.
-    bool isCoreModule(Identifier ident)
+    bool isCoreModule(Identifier ident) nothrow
     {
         return this.ident == ident && parent && parent.ident == Id.core && !parent.parent;
     }
@@ -1440,7 +1440,7 @@ extern (C++) final class Module : Package
 
     uint[uint] ctfe_cov; /// coverage information from ctfe execution_count[line]
 
-    override inout(Module) isModule() inout
+    override inout(Module) isModule() inout nothrow
     {
         return this;
     }
@@ -1455,7 +1455,7 @@ extern (C++) final class Module : Package
      * Params:
      *    buf = The buffer to write to
      */
-    void fullyQualifiedName(ref OutBuffer buf)
+    void fullyQualifiedName(ref OutBuffer buf) nothrow
     {
         buf.writestring(ident.toString());
 
@@ -1469,7 +1469,7 @@ extern (C++) final class Module : Package
     /** Lazily initializes and returns the escape table.
     Turns out it eats a lot of memory.
     */
-    extern(D) Escape* escapetable()
+    extern(D) Escape* escapetable() nothrow
     {
         if (!_escapetable)
             _escapetable = new Escape();
index cb6c278fc4409f0fc11b720e2f7f29c79e12332f..2021e2afd8e1e70fddfabe85ff06bf78255bfbb6 100644 (file)
@@ -112,12 +112,12 @@ struct Ungag
 {
     uint oldgag;
 
-    extern (D) this(uint old)
+    extern (D) this(uint old) nothrow
     {
         this.oldgag = old;
     }
 
-    extern (C++) ~this()
+    extern (C++) ~this() nothrow
     {
         global.gag = oldgag;
     }
@@ -255,27 +255,27 @@ extern (C++) class Dsymbol : ASTNode
     DeprecatedDeclaration depdecl;           // customized deprecation message
     UserAttributeDeclaration userAttribDecl;    // user defined attributes
 
-    final extern (D) this()
+    final extern (D) this() nothrow
     {
         //printf("Dsymbol::Dsymbol(%p)\n", this);
         loc = Loc(null, 0, 0);
     }
 
-    final extern (D) this(Identifier ident)
+    final extern (D) this(Identifier ident) nothrow
     {
         //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
         this.loc = Loc(null, 0, 0);
         this.ident = ident;
     }
 
-    final extern (D) this(const ref Loc loc, Identifier ident)
+    final extern (D) this(const ref Loc loc, Identifier ident) nothrow
     {
         //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
         this.loc = loc;
         this.ident = ident;
     }
 
-    static Dsymbol create(Identifier ident)
+    static Dsymbol create(Identifier ident) nothrow
     {
         return new Dsymbol(ident);
     }
@@ -800,6 +800,22 @@ extern (C++) class Dsymbol : ASTNode
             if (isAliasDeclaration() && !_scope)
                 setScope(sc);
             Dsymbol s2 = sds.symtabLookup(this,ident);
+            /* https://issues.dlang.org/show_bug.cgi?id=17434
+             *
+             * If we are trying to add an import to the symbol table
+             * that has already been introduced, then keep the one with
+             * larger visibility. This is fine for imports because if
+             * we have multiple imports of the same file, if a single one
+             * is public then the symbol is reachable.
+             */
+            if (auto i1 = isImport())
+            {
+                if (auto i2 = s2.isImport())
+                {
+                    if (sc.explicitVisibility && sc.visibility > i2.visibility)
+                        sds.symtab.update(this);
+                }
+            }
 
             // If using C tag/prototype/forward declaration rules
             if (sc.flags & SCOPE.Cfile && !this.isImport())
@@ -933,14 +949,7 @@ extern (C++) class Dsymbol : ASTNode
                 TemplateInstance ti = st.isTemplateInstance();
                 sm = s.search(loc, ti.name);
                 if (!sm)
-                {
-                    sm = s.search_correct(ti.name);
-                    if (sm)
-                        .error(loc, "template identifier `%s` is not a member of %s `%s`, did you mean %s `%s`?", ti.name.toChars(), s.kind(), s.toPrettyChars(), sm.kind(), sm.toChars());
-                    else
-                        .error(loc, "template identifier `%s` is not a member of %s `%s`", ti.name.toChars(), s.kind(), s.toPrettyChars());
                     return null;
-                }
                 sm = sm.toAlias();
                 TemplateDeclaration td = sm.isTemplateDeclaration();
                 if (!td)
@@ -1381,16 +1390,16 @@ private:
     BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages
 
 public:
-    final extern (D) this()
+    final extern (D) this() nothrow
     {
     }
 
-    final extern (D) this(Identifier ident)
+    final extern (D) this(Identifier ident) nothrow
     {
         super(ident);
     }
 
-    final extern (D) this(const ref Loc loc, Identifier ident)
+    final extern (D) this(const ref Loc loc, Identifier ident) nothrow
     {
         super(loc, ident);
     }
@@ -1604,7 +1613,7 @@ public:
         return os;
     }
 
-    void importScope(Dsymbol s, Visibility visibility)
+    void importScope(Dsymbol s, Visibility visibility) nothrow
     {
         //printf("%s.ScopeDsymbol::importScope(%s, %d)\n", toChars(), s.toChars(), visibility);
         // No circular or redundant import's
@@ -1631,7 +1640,7 @@ public:
         }
     }
 
-    extern (D) final void addAccessiblePackage(Package p, Visibility visibility)
+    extern (D) final void addAccessiblePackage(Package p, Visibility visibility) nothrow
     {
         auto pary = visibility.kind == Visibility.Kind.private_ ? &privateAccessiblePackages : &accessiblePackages;
         if (pary.length <= p.tag)
@@ -1639,7 +1648,7 @@ public:
         (*pary)[p.tag] = true;
     }
 
-    bool isPackageAccessible(Package p, Visibility visibility, int flags = 0)
+    bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) nothrow
     {
         if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] ||
             visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag])
@@ -1654,7 +1663,7 @@ public:
         return false;
     }
 
-    override final bool isforwardRef()
+    override final bool isforwardRef() nothrow
     {
         return (members is null);
     }
@@ -1742,7 +1751,7 @@ public:
      * Returns:
      *   null if already in table, `s` if inserted
      */
-    Dsymbol symtabInsert(Dsymbol s)
+    Dsymbol symtabInsert(Dsymbol s) nothrow
     {
         return symtab.insert(s);
     }
@@ -1755,7 +1764,7 @@ public:
      * Returns:
      *   Dsymbol if found, null if not
      */
-    Dsymbol symtabLookup(Dsymbol s, Identifier id)
+    Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow
     {
         return symtab.lookup(id);
     }
@@ -1838,7 +1847,7 @@ extern (C++) final class WithScopeSymbol : ScopeDsymbol
 {
     WithStatement withstate;
 
-    extern (D) this(WithStatement withstate)
+    extern (D) this(WithStatement withstate) nothrow
     {
         this.withstate = withstate;
     }
@@ -1898,7 +1907,7 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
     private RootObject arrayContent;
     Scope* sc;
 
-    extern (D) this(Scope* sc, Expression exp)
+    extern (D) this(Scope* sc, Expression exp) nothrow
     {
         super(exp.loc, null);
         assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array);
@@ -1906,13 +1915,13 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
         this.arrayContent = exp;
     }
 
-    extern (D) this(Scope* sc, TypeTuple type)
+    extern (D) this(Scope* sc, TypeTuple type) nothrow
     {
         this.sc = sc;
         this.arrayContent = type;
     }
 
-    extern (D) this(Scope* sc, TupleDeclaration td)
+    extern (D) this(Scope* sc, TupleDeclaration td) nothrow
     {
         this.sc = sc;
         this.arrayContent = td;
@@ -2109,7 +2118,7 @@ extern (C++) final class OverloadSet : Dsymbol
 {
     Dsymbols a;     // array of Dsymbols
 
-    extern (D) this(Identifier ident, OverloadSet os = null)
+    extern (D) this(Identifier ident, OverloadSet os = null) nothrow
     {
         super(ident);
         if (os)
@@ -2118,7 +2127,7 @@ extern (C++) final class OverloadSet : Dsymbol
         }
     }
 
-    void push(Dsymbol s)
+    void push(Dsymbol s) nothrow
     {
         a.push(s);
     }
@@ -2152,12 +2161,13 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
      * Can be `null` before being lazily initialized.
      */
     ScopeDsymbol forward;
-    extern (D) this(ScopeDsymbol forward)
+    extern (D) this(ScopeDsymbol forward) nothrow
     {
         super(null);
         this.forward = forward;
     }
-    override Dsymbol symtabInsert(Dsymbol s)
+
+    override Dsymbol symtabInsert(Dsymbol s) nothrow
     {
         assert(forward);
         if (auto d = s.isDeclaration())
@@ -2188,7 +2198,7 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
      * and
      *     static foreach (i; [0]) { enum i = 2; }
      */
-    override Dsymbol symtabLookup(Dsymbol s, Identifier id)
+    override Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow
     {
         assert(forward);
         // correctly diagnose clashing foreach loop variables.
@@ -2219,7 +2229,7 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
 
     override const(char)* kind()const{ return "local scope"; }
 
-    override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout
+    override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout nothrow
     {
         return this;
     }
@@ -2234,13 +2244,13 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
 extern (C++) final class ExpressionDsymbol : Dsymbol
 {
     Expression exp;
-    this(Expression exp)
+    this(Expression exp) nothrow
     {
         super();
         this.exp = exp;
     }
 
-    override inout(ExpressionDsymbol) isExpressionDsymbol() inout
+    override inout(ExpressionDsymbol) isExpressionDsymbol() inout nothrow
     {
         return this;
     }
@@ -2259,7 +2269,7 @@ extern (C++) final class AliasAssign : Dsymbol
     Dsymbol aliassym; /// replace previous RHS of AliasDeclaration with `aliassym`
                       /// only one of type and aliassym can be != null
 
-    extern (D) this(const ref Loc loc, Identifier ident, Type type, Dsymbol aliassym)
+    extern (D) this(const ref Loc loc, Identifier ident, Type type, Dsymbol aliassym) nothrow
     {
         super(loc, null);
         this.ident = ident;
@@ -2299,6 +2309,8 @@ extern (C++) final class DsymbolTable : RootObject
 {
     AssocArray!(Identifier, Dsymbol) tab;
 
+  nothrow:
+
    /***************************
     * Look up Identifier in symbol table
     * Params:
index c9906363cc8cd396be353b831a120f6c1fc33686..1ccaab56da6a3240696f6a84d89b7be3ea394afd 100644 (file)
@@ -51,6 +51,7 @@ import dmd.init;
 import dmd.initsem;
 import dmd.hdrgen;
 import dmd.mtype;
+import dmd.mustuse;
 import dmd.nogc;
 import dmd.nspace;
 import dmd.objc;
@@ -542,7 +543,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                     Parameter arg = Parameter.getNth(tt.arguments, pos);
                     arg.type = arg.type.typeSemantic(dsym.loc, sc);
                     //printf("[%d] iexps.dim = %d, ", pos, iexps.dim);
-                    //printf("e = (%s %s, %s), ", Token::tochars[e.op], e.toChars(), e.type.toChars());
+                    //printf("e = (%s %s, %s), ", Token.tochars[e.op], e.toChars(), e.type.toChars());
                     //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
 
                     if (e != ie)
@@ -581,7 +582,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                             arg = Parameter.getNth(tt.arguments, pos + u);
                             arg.type = arg.type.typeSemantic(dsym.loc, sc);
                             //printf("[%d+%d] exps.dim = %d, ", pos, u, exps.dim);
-                            //printf("ee = (%s %s, %s), ", Token::tochars[ee.op], ee.toChars(), ee.type.toChars());
+                            //printf("ee = (%s %s, %s), ", Token.tochars[ee.op], ee.toChars(), ee.type.toChars());
                             //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
 
                             size_t iexps_dim = iexps.dim - 1 + exps.dim;
@@ -2046,6 +2047,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
         ed.semanticRun = PASS.semantic;
         UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage);
+        checkMustUseReserved(ed);
 
         if (!ed.members && !ed.memtype) // enum ident;
         {
@@ -3017,7 +3019,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         if ((funcdecl.storage_class & STC.TYPECTOR) && !(ad || funcdecl.isNested()))
             funcdecl.storage_class &= ~STC.TYPECTOR;
 
-        //printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration::isFinal());
+        //printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration.isFinal());
 
         if (sc.flags & SCOPE.compile)
             funcdecl.flags |= FUNCFLAG.compileTimeOnly; // don't emit code for this function
@@ -3056,6 +3058,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         funcdecl.visibility = sc.visibility;
         funcdecl.userAttribDecl = sc.userAttribDecl;
         UserAttributeDeclaration.checkGNUABITag(funcdecl, funcdecl.linkage);
+        checkMustUseReserved(funcdecl);
 
         if (!funcdecl.originalType)
             funcdecl.originalType = funcdecl.type.syntaxCopy();
@@ -4092,7 +4095,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
     override void visit(PostBlitDeclaration pbd)
     {
         //printf("PostBlitDeclaration::semantic() %s\n", toChars());
-        //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id::dtor.toChars(), ident, Id::dtor);
+        //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id.dtor.toChars(), ident, Id.dtor);
         //printf("stc = x%llx\n", sc.stc);
         if (pbd.semanticRun >= PASS.semanticdone)
             return;
@@ -4129,7 +4132,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
     override void visit(DtorDeclaration dd)
     {
         //printf("DtorDeclaration::semantic() %s\n", toChars());
-        //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id::dtor.toChars(), ident, Id::dtor);
+        //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id.dtor.toChars(), ident, Id.dtor);
         if (dd.semanticRun >= PASS.semanticdone)
             return;
         if (dd._scope)
@@ -4770,6 +4773,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         }
         cldec.semanticRun = PASS.semantic;
         UserAttributeDeclaration.checkGNUABITag(cldec, sc.linkage);
+        checkMustUseReserved(cldec);
 
         if (cldec.baseok < Baseok.done)
         {
@@ -5475,6 +5479,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                 idec.classKind = ClassKind.cpp;
             idec.cppnamespace = sc.namespace;
             UserAttributeDeclaration.checkGNUABITag(idec, sc.linkage);
+            checkMustUseReserved(idec);
 
             if (sc.linkage == LINK.objc)
                 objc.setObjc(idec);
index a5ec63ca763e0177ff8236e50b2bce8ab973dace..fb41e2bd05f5c4e224d6f4c118862d18ab5e579a 100644 (file)
@@ -2626,7 +2626,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
             printf("\t%s %s\n", arg.type.toChars(), arg.toChars());
             //printf("\tty = %d\n", arg.type.ty);
         }
-        //printf("stc = %llx\n", dstart.scope.stc);
+        //printf("stc = %llx\n", dstart._scope.stc);
         //printf("match:t/f = %d/%d\n", ta_last, m.last);
     }
 
@@ -4332,7 +4332,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
             {
                 TypeStruct tp = cast(TypeStruct)tparam;
 
-                //printf("\t%d\n", (MATCH) t.implicitConvTo(tp));
+                //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
                 if (wm && t.deduceWild(tparam, false))
                 {
                     result = MATCH.constant;
@@ -4513,7 +4513,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
             {
                 TypeClass tp = cast(TypeClass)tparam;
 
-                //printf("\t%d\n", (MATCH) t.implicitConvTo(tp));
+                //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
                 if (wm && t.deduceWild(tparam, false))
                 {
                     result = MATCH.constant;
index 4196c05489d25a519329b2637fd893aff18a6be1..78b9a07f3a37e098377a02a1f27bd8508f7ac73b 100644 (file)
@@ -440,22 +440,33 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp
  *      sc = used to determine current function and module
  *      firstArg = `ref` argument through which `arg` may be assigned
  *      arg = initializer for parameter
+ *      param = parameter declaration corresponding to `arg`
  *      gag = do not print error messages
  * Returns:
  *      `true` if assignment to `firstArg` would cause an error
  */
-bool checkParamArgumentReturn(Scope* sc, Expression firstArg, Expression arg, bool gag)
+bool checkParamArgumentReturn(Scope* sc, Expression firstArg, Expression arg, Parameter param, bool gag)
 {
     enum log = false;
     if (log) printf("checkParamArgumentReturn(firstArg: %s arg: %s)\n",
         firstArg.toChars(), arg.toChars());
     //printf("type = %s, %d\n", arg.type.toChars(), arg.type.hasPointers());
 
-    if (!arg.type.hasPointers())
+    if (!(param.storageClass & STC.return_))
+        return false;
+
+    if (!arg.type.hasPointers() && !param.isReference())
         return false;
 
+    // `byRef` needed for `assign(ref int* x, ref int i) {x = &i};`
+    // Note: taking address of scope pointer is not allowed
+    // `assign(ref int** x, return ref scope int* i) {x = &i};`
+    // Thus no return ref/return scope ambiguity here
+    const byRef = param.isReference() && !(param.storageClass & STC.scope_)
+        && !(param.storageClass & STC.returnScope); // fixme: it's possible to infer returnScope without scope with vaIsFirstRef
+
     scope e = new AssignExp(arg.loc, firstArg, arg);
-    return checkAssignEscape(sc, e, gag);
+    return checkAssignEscape(sc, e, gag, byRef);
 }
 
 /*****************************************************
@@ -496,23 +507,13 @@ bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag)
     foreach (const i; 0 .. n)
     {
         Expression arg = (*ce.arguments)[i];
-        if (!arg.type.hasPointers())
-            continue;
-
         //printf("\targ[%d]: %s\n", i, arg.toChars());
 
         if (i - j < nparams && i >= j)
         {
             Parameter p = tf.parameterList[i - j];
-
-            if (p.storageClass & STC.return_)
-            {
-                /* Fake `dve.e1 = arg;` and look for scope violations
-                 */
-                scope e = new AssignExp(arg.loc, dve.e1, arg);
-                if (checkAssignEscape(sc, e, gag))
-                    return true;
-            }
+            if (checkParamArgumentReturn(sc, dve.e1, arg, p, gag))
+                return true;
         }
     }
 
@@ -529,13 +530,14 @@ bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag)
  *      sc = used to determine current function and module
  *      e = `AssignExp` or `CatAssignExp` to check for any pointers to the stack
  *      gag = do not print error messages
+ *      byRef = set to `true` if `e1` of `e` gets assigned a reference to `e2`
  * Returns:
  *      `true` if pointers to the stack can escape via assignment
  */
-bool checkAssignEscape(Scope* sc, Expression e, bool gag)
+bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
 {
     enum log = false;
-    if (log) printf("checkAssignEscape(e: %s)\n", e.toChars());
+    if (log) printf("checkAssignEscape(e: %s, byRef: %d)\n", e.toChars(), byRef);
     if (e.op != EXP.assign && e.op != EXP.blit && e.op != EXP.construct &&
         e.op != EXP.concatenateAssign && e.op != EXP.concatenateElemAssign && e.op != EXP.concatenateDcharAssign)
         return false;
@@ -561,7 +563,10 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
 
     EscapeByResults er;
 
-    escapeByValue(e2, &er);
+    if (byRef)
+        escapeByRef(e2, &er);
+    else
+        escapeByValue(e2, &er);
 
     if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim)
         return false;
@@ -789,8 +794,18 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
 
         Dsymbol p = v.toParent2();
 
+        if (vaIsFirstRef && v.isParameter() &&
+            !(v.storage_class & STC.return_) &&
+            fd.flags & FUNCFLAG.returnInprocess &&
+            p == fd)
+        {
+            //if (log) printf("inferring 'return' for parameter %s in function %s\n", v.toChars(), fd.toChars());
+            inferReturn(fd, v, /*returnScope:*/ false);
+        }
+
         // If va's lifetime encloses v's, then error
         if (va &&
+            !(vaIsFirstRef && (v.storage_class & STC.return_)) &&
             (va.enclosesLifetimeOf(v) || (va.isReference() && !(va.storage_class & STC.temp)) || va.isDataseg()) &&
             fd.setUnsafe())
         {
index 07d885b0beef5bae9fa4f60f234a7471511dc830..24030eb42d029a5d08f90e05672a477ca66b28a2 100644 (file)
@@ -1660,6 +1660,7 @@ extern (C++) abstract class Expression : ASTNode
         inout(MixinExp)     isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; }
         inout(ImportExp)    isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; }
         inout(AssertExp)    isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; }
+        inout(ThrowExp)     isThrowExp() { return op == EXP.throw_ ? cast(typeof(return))this : null; }
         inout(DotIdExp)     isDotIdExp() { return op == EXP.dotIdentifier ? cast(typeof(return))this : null; }
         inout(DotTemplateExp) isDotTemplateExp() { return op == EXP.dotTemplateDeclaration ? cast(typeof(return))this : null; }
         inout(DotVarExp)    isDotVarExp() { return op == EXP.dotVariable ? cast(typeof(return))this : null; }
@@ -2684,7 +2685,7 @@ extern (C++) final class StringExp : Expression
         const len2 = se2.len;
 
         assert(this.sz == se2.sz, "Comparing string expressions of different sizes");
-        //printf("sz = %d, len1 = %d, len2 = %d\n", sz, (int)len1, (int)len2);
+        //printf("sz = %d, len1 = %d, len2 = %d\n", sz, cast(int)len1, cast(int)len2);
         if (len1 == len2)
         {
             switch (sz)
index 7b7c489295a9df76fe6bbd2b158280885ed4db8e..64cd7ab849c076adf276cd72d5fa0753cf03ddf5 100644 (file)
@@ -56,6 +56,7 @@ import dmd.initsem;
 import dmd.inline;
 import dmd.intrange;
 import dmd.mtype;
+import dmd.mustuse;
 import dmd.nspace;
 import dmd.opover;
 import dmd.optimize;
@@ -713,7 +714,7 @@ private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2
  */
 Expression resolvePropertiesOnly(Scope* sc, Expression e1)
 {
-    //printf("e1 = %s %s\n", Token::toChars(e1.op), e1.toChars());
+    //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
 
     Expression handleOverloadSet(OverloadSet os)
     {
@@ -2033,7 +2034,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                  * Check arg to see if it matters.
                  */
                 if (global.params.useDIP1000 == FeatureState.enabled)
-                    err |= checkParamArgumentReturn(sc, firstArg, arg, false);
+                    err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
             }
             else if (tf.parameterEscapes(tthis, p))
             {
@@ -3261,7 +3262,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 // printf("apply fix for issue 9490: add `this.` to `%s`...\n", e.toChars());
                 e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false);
             }
-            //printf("e = %s %s\n", Token::toChars(e.op), e.toChars());
+            //printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
             e = e.expressionSemantic(sc);
         }
         else if (t)
@@ -6032,7 +6033,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             auto fileName = FileName(name.toDString);
             if (auto fmResult = global.fileManager.lookup(fileName))
             {
-                se = new StringExp(e.loc, fmResult.data);
+                se = new StringExp(e.loc, fmResult);
             }
             else
             {
@@ -6047,9 +6048,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     // take ownership of buffer (probably leaking)
                     auto data = readResult.extractSlice();
                     se = new StringExp(e.loc, data);
-
-                    FileBuffer* fileBuffer = new FileBuffer(data);
-                    global.fileManager.add(fileName, fileBuffer);
+                    global.fileManager.add(fileName, data);
                 }
             }
         }
@@ -6388,7 +6387,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         static if (LOGSEMANTIC)
         {
             printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
-            //printf("e1.op = %d, '%s'\n", e1.op, Token::toChars(e1.op));
+            //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
         }
 
         if (sc.flags & SCOPE.Cfile)
@@ -8177,7 +8176,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
 
         if (e.type is Type.tvoid)
+        {
+            checkMustUse(e.e1, sc);
             discardValue(e.e1);
+        }
         else if (!e.allowCommaExp && !e.isGenerated)
             e.error("Using the result of a comma expression is not allowed");
     }
@@ -8956,7 +8958,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
                     Parameter arg = Parameter.getNth(tt.arguments, u);
                     //printf("[%d] iexps.dim = %d, ", u, iexps.dim);
-                    //printf("e = (%s %s, %s), ", Token::tochars[e.op], e.toChars(), e.type.toChars());
+                    //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
                     //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
 
                     if (!arg || !e.type.implicitConvTo(arg.type))
@@ -9849,7 +9851,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
          * `reorderSettingAAElem` creates a tree of comma expressions, however,
          * `checkAssignExp` expects only AssignExps.
          */
-        checkAssignEscape(sc, Expression.extractLast(res, tmp), false);
+        checkAssignEscape(sc, Expression.extractLast(res, tmp), false, false);
 
         if (auto ae = res.isConstructExp())
         {
@@ -10124,7 +10126,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                  */
                 if (isRecursiveAliasThis(exp.att1, exp.e1.type))
                     return null;
-                //printf("att %s e1 = %s\n", Token::toChars(e.op), e.e1.type.toChars());
+                //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
                 Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident);
                 BinExp be = cast(BinExp)exp.copy();
                 be.e1 = e1;
@@ -10142,7 +10144,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                  */
                 if (isRecursiveAliasThis(exp.att2, exp.e2.type))
                     return null;
-                //printf("att %s e2 = %s\n", Token::toChars(e.op), e.e2.type.toChars());
+                //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
                 Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident);
                 BinExp be = cast(BinExp)exp.copy();
                 be.e2 = e2;
@@ -10169,7 +10171,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         auto res = exp.reorderSettingAAElem(sc);
         if ((exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign) &&
             global.params.useDIP1000 == FeatureState.enabled)
-            checkAssignEscape(sc, res, false);
+            checkAssignEscape(sc, res, false, false);
         result = res;
     }
 
@@ -12803,129 +12805,125 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
         return false;
     }
 
-    //printf("checkSharedAccess() %s\n", e.toChars());
-
-    static extern(C++) final class SharedCheckVisitor : SemanticTimeTransitiveVisitor
-    {
-        /// In case we don't know which expression triggered it,
-        /// e.g. for `visit(Type)` overload
-        Expression original;
-        /// Where the result is stored (`true` == error)
-        bool result;
-        /// Whether we should allow one level of dereferencing
-        bool allowRef;
+    //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
 
-        /// Ctor
-        this(Expression oe, bool allowRef_)
-        {
-            this.original = oe;
-            this.allowRef = allowRef_;
-        }
+    /* In case we don't know which expression triggered it,
+     * e.g. for `visit(Type)` overload
+     */
+    Expression original = e;
 
-        void sharedError(Expression e)
+    bool check(Expression e, bool allowRef)
+    {
+        bool sharedError(Expression e)
         {
             // https://dlang.org/phobos/core_atomic.html
             e.error("direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars());
-            this.result = true;
+            return true;
         }
 
-        /// Introduce base class overrides
-        alias visit = SemanticTimeTransitiveVisitor.visit;
-
         // Error by default
-        override void visit(Expression e)
+        bool visit(Expression e)
         {
             if (e.type.isShared())
-                this.sharedError(e);
+                return sharedError(e);
+            return false;
         }
 
-        /// Ditto
-        override void visit(Type t)
+        bool visitNew(NewExp e)
         {
+            if (e.thisexp)
+                check(e.thisexp, false);
             // Note: This handles things like `new shared(Throwable).msg`,
             // where accessing `msg` would violate `shared`.
-            if (t.isShared())
-                this.sharedError(this.original);
+            if (e.newtype.isShared())
+                return sharedError(original);
+            return false;
         }
 
-        // Those have no indirections / can be ignored
-        override void visit(ErrorExp e) {}
-        override void visit(ComplexExp e) {}
-        override void visit(IntegerExp e) {}
-        override void visit(NullExp e) {}
-
-        override void visit(VarExp e)
+        bool visitVar(VarExp e)
         {
-            if (!this.allowRef && e.var.type.isShared())
-                this.sharedError(e);
+            if (!allowRef && e.var.type.isShared())
+                return sharedError(e);
+            return false;
         }
 
-        override void visit(AddrExp e)
+        bool visitAddr(AddrExp e)
         {
-            this.allowRef = true;
-            e.e1.accept(this);
+            return check(e.e1, true);
         }
 
-        override void visit(PtrExp e)
+        bool visitPtr(PtrExp e)
         {
-            if (!this.allowRef && e.type.isShared())
-                return this.sharedError(e);
+            if (!allowRef && e.type.isShared())
+                return sharedError(e);
 
             if (e.e1.type.isShared())
-                return this.sharedError(e);
+                return sharedError(e);
 
-            this.allowRef = false;
-            e.e1.accept(this);
+            return check(e.e1, false);
         }
 
-        override void visit(DotVarExp e)
+        bool visitDotVar(DotVarExp e)
         {
             auto fd = e.var.isFuncDeclaration();
             const sharedFunc = fd && fd.type.isShared;
 
-            if (!this.allowRef && e.type.isShared() && !sharedFunc)
-                return this.sharedError(e);
+            if (!allowRef && e.type.isShared() && !sharedFunc)
+                return sharedError(e);
 
-            // Allow to use `DotVarExp` within value types
-            if (e.e1.type.ty == Tsarray || e.e1.type.ty == Tstruct)
-                return e.e1.accept(this);
+            // Allow using `DotVarExp` within value types
+            if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
+                return check(e.e1, allowRef);
 
             // If we end up with a single `VarExp`, it might be a `ref` param
             // `shared ref T` param == `shared(T)*`.
             if (auto ve = e.e1.isVarExp())
             {
-                this.allowRef = this.allowRef && (ve.var.storage_class & STC.ref_);
-                return e.e1.accept(this);
+                return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
             }
 
-            this.allowRef = false;
-            return e.e1.accept(this);
+            return check(e.e1, false);
         }
 
-        override void visit(IndexExp e)
+        bool visitIndex(IndexExp e)
         {
-            if (!this.allowRef && e.type.isShared())
-                return this.sharedError(e);
+            if (!allowRef && e.type.isShared())
+                return sharedError(e);
 
             if (e.e1.type.isShared())
-                return this.sharedError(e);
+                return sharedError(e);
 
-            this.allowRef = false;
-            e.e1.accept(this);
+            return check(e.e1, false);
         }
 
-        override void visit(CommaExp e)
+        bool visitComma(CommaExp e)
         {
             // Cannot be `return ref` since we can't use the return,
             // but it's better to show that error than an unrelated `shared` one
-            this.allowRef = true;
-            e.e2.accept(this);
+            return check(e.e2, true);
+        }
+
+        switch (e.op)
+        {
+            default:              return visit(e);
+
+            // Those have no indirections / can be ignored
+            case EXP.call:
+            case EXP.error:
+            case EXP.complex80:
+            case EXP.int64:
+            case EXP.null_:       return false;
+
+            case EXP.variable:    return visitVar(e.isVarExp());
+            case EXP.new_:        return visitNew(e.isNewExp());
+            case EXP.address:     return visitAddr(e.isAddrExp());
+            case EXP.star:        return visitPtr(e.isPtrExp());
+            case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
+            case EXP.index:       return visitIndex(e.isIndexExp());
         }
     }
 
-    scope visitor = new SharedCheckVisitor(e, returnRef);
-    e.accept(visitor);
-    return visitor.result;
+    return check(e, returnRef);
 }
 
 
index b86c7995562670a2e9ff67c5031149150f263b7a..9fe40bf06036f28de425e9fbd1e4b3494872f394 100644 (file)
@@ -11,7 +11,7 @@
 module dmd.file_manager;
 
 import dmd.root.stringtable : StringTable;
-import dmd.root.file : File, FileBuffer;
+import dmd.root.file : File, Buffer;
 import dmd.root.filename : FileName;
 import dmd.root.string : toDString;
 import dmd.globals;
@@ -22,7 +22,7 @@ enum package_di = "package." ~ hdr_ext;
 
 final class FileManager
 {
-    private StringTable!(FileBuffer*) files;
+    private StringTable!(const(ubyte)[]) files;
 
     ///
     public this () nothrow
@@ -146,7 +146,7 @@ nothrow:
      * Returns: the loaded source file if it was found in memory,
      *      otherwise `null`
      */
-    const(FileBuffer)* lookup(FileName filename)
+    const(ubyte)[] lookup(FileName filename)
     {
         const name = filename.toString;
         if (auto val = files.lookup(name))
@@ -154,7 +154,7 @@ nothrow:
 
         if (name == "__stdin.d")
         {
-            auto buffer = new FileBuffer(readFromStdin().extractSlice());
+            auto buffer = readFromStdin().extractSlice();
             if (this.files.insert(name, buffer) is null)
                 assert(0, "stdin: Insert after lookup failure should never return `null`");
             return buffer;
@@ -167,7 +167,7 @@ nothrow:
         if (!readResult.success)
             return null;
 
-        FileBuffer* fb = new FileBuffer(readResult.extractSlice());
+        auto fb = readResult.extractSlice();
         if (files.insert(name, fb) is null)
             assert(0, "Insert after lookup failure should never return `null`");
 
@@ -187,17 +187,17 @@ nothrow:
         const(char)[][] lines;
         if (const buffer = lookup(file))
         {
-            const slice = buffer.data[0 .. buffer.data.length];
+            const slice = buffer;
             size_t start, end;
-            ubyte c;
             for (auto i = 0; i < slice.length; i++)
             {
-                c = slice[i];
+                const c = slice[i];
                 if (c == '\n' || c == '\r')
                 {
                     if (i != 0)
                     {
                         end = i;
+                        // Appending lines one at a time will certainly be slow
                         lines ~= cast(const(char)[])slice[start .. end];
                     }
                     // Check for Windows-style CRLF newlines
@@ -234,18 +234,21 @@ nothrow:
     }
 
     /**
-     * Adds a FileBuffer to the table.
-     *
-     * Returns: The FileBuffer added, or null
+     * Adds the contents of a file to the table.
+     * Params:
+     *  filename = name of the file
+     *  buffer = contents of the file
+     * Returns:
+     *  the buffer added, or null
      */
-    FileBuffer* add(FileName filename, FileBuffer* filebuffer)
+    const(ubyte)[] add(FileName filename, const(ubyte)[] buffer)
     {
-        auto val = files.insert(filename.toString, filebuffer);
+        auto val = files.insert(filename.toString, buffer);
         return val == null ? null : val.value;
     }
 }
 
-private FileBuffer readFromStdin() nothrow
+private Buffer readFromStdin() nothrow
 {
     import core.stdc.stdio;
     import dmd.errors;
@@ -277,7 +280,7 @@ private FileBuffer readFromStdin() nothrow
                 // We're done
                 assert(pos < sz + 2);
                 buffer[pos .. pos + 4] = '\0';
-                return FileBuffer(buffer[0 .. pos]);
+                return Buffer(buffer[0 .. pos]);
             }
         } while (pos < sz);
 
index a3afbe50796a02caf14bc26dd11e33dcc7dd7537..69fdf27e1dbd9af39846306a1e49243e57136319 100644 (file)
@@ -1538,6 +1538,13 @@ public:
             }
             else if (hgs.tpltMember == 0 && global.params.hdrStripPlainFunctions)
             {
+                if (!f.fbody)
+                {
+                    // this can happen on interfaces / abstract functions, see `allowsContractWithoutBody`
+                    if (f.fensures || f.frequires)
+                        buf.writenl();
+                    contractsToBuffer(f);
+                }
                 buf.writeByte(';');
                 buf.writenl();
             }
@@ -1548,19 +1555,9 @@ public:
             bodyToBuffer(f);
     }
 
-    void bodyToBuffer(FuncDeclaration f)
+    /// Returns: whether `do` is needed to write the function body
+    bool contractsToBuffer(FuncDeclaration f)
     {
-        if (!f.fbody || (hgs.hdrgen && global.params.hdrStripPlainFunctions && !hgs.autoMember && !hgs.tpltMember))
-        {
-            buf.writeByte(';');
-            buf.writenl();
-            return;
-        }
-        const savetlpt = hgs.tpltMember;
-        const saveauto = hgs.autoMember;
-        hgs.tpltMember = 0;
-        hgs.autoMember = 0;
-        buf.writenl();
         bool requireDo = false;
         // in{}
         if (f.frequires)
@@ -1619,6 +1616,29 @@ public:
                 }
             }
         }
+        return requireDo;
+    }
+
+    void bodyToBuffer(FuncDeclaration f)
+    {
+        if (!f.fbody || (hgs.hdrgen && global.params.hdrStripPlainFunctions && !hgs.autoMember && !hgs.tpltMember))
+        {
+            if (!f.fbody && (f.fensures || f.frequires))
+            {
+                buf.writenl();
+                contractsToBuffer(f);
+            }
+            buf.writeByte(';');
+            buf.writenl();
+            return;
+        }
+        const savetlpt = hgs.tpltMember;
+        const saveauto = hgs.autoMember;
+        hgs.tpltMember = 0;
+        hgs.autoMember = 0;
+        buf.writenl();
+        bool requireDo = contractsToBuffer(f);
+
         if (requireDo)
         {
             buf.writestring("do");
@@ -1788,26 +1808,17 @@ public:
     }
 }
 
-private extern (C++) final class ExpressionPrettyPrintVisitor : Visitor
+/*********************************************
+ * Print expression to buffer.
+ */
+private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hgs)
 {
-    alias visit = Visitor.visit;
-public:
-    OutBuffer* buf;
-    HdrGenState* hgs;
-
-    extern (D) this(OutBuffer* buf, HdrGenState* hgs)
-    {
-        this.buf = buf;
-        this.hgs = hgs;
-    }
-
-    ////////////////////////////////////////////////////////////////////////////
-    override void visit(Expression e)
+    void visit(Expression e)
     {
         buf.writestring(EXPtoString(e.op));
     }
 
-    override void visit(IntegerExp e)
+    void visitInteger(IntegerExp e)
     {
         const dinteger_t v = e.toInteger();
         if (e.type)
@@ -1907,12 +1918,12 @@ public:
             buf.print(v);
     }
 
-    override void visit(ErrorExp e)
+    void visitError(ErrorExp e)
     {
         buf.writestring("__error");
     }
 
-    override void visit(VoidInitExp e)
+    void visitVoidInit(VoidInitExp e)
     {
         buf.writestring("__void");
     }
@@ -1922,12 +1933,12 @@ public:
         .floatToBuffer(type, value, buf, hgs.hdrgen);
     }
 
-    override void visit(RealExp e)
+    void visitReal(RealExp e)
     {
         floatToBuffer(e.type, e.value);
     }
 
-    override void visit(ComplexExp e)
+    void visitComplex(ComplexExp e)
     {
         /* Print as:
          *  (re+imi)
@@ -1939,7 +1950,7 @@ public:
         buf.writestring("i)");
     }
 
-    override void visit(IdentifierExp e)
+    void visitIdentifier(IdentifierExp e)
     {
         if (hgs.hdrgen || hgs.ddoc)
             buf.writestring(e.ident.toHChars2());
@@ -1947,27 +1958,27 @@ public:
             buf.writestring(e.ident.toString());
     }
 
-    override void visit(DsymbolExp e)
+    void visitDsymbol(DsymbolExp e)
     {
         buf.writestring(e.s.toChars());
     }
 
-    override void visit(ThisExp e)
+    void visitThis(ThisExp e)
     {
         buf.writestring("this");
     }
 
-    override void visit(SuperExp e)
+    void visitSuper(SuperExp e)
     {
         buf.writestring("super");
     }
 
-    override void visit(NullExp e)
+    void visitNull(NullExp e)
     {
         buf.writestring("null");
     }
 
-    override void visit(StringExp e)
+    void visitString(StringExp e)
     {
         buf.writeByte('"');
         const o = buf.length;
@@ -1982,14 +1993,14 @@ public:
             buf.writeByte(e.postfix);
     }
 
-    override void visit(ArrayLiteralExp e)
+    void visitArrayLiteral(ArrayLiteralExp e)
     {
         buf.writeByte('[');
         argsToBuffer(e.elements, buf, hgs, e.basis);
         buf.writeByte(']');
     }
 
-    override void visit(AssocArrayLiteralExp e)
+    void visitAssocArrayLiteral(AssocArrayLiteralExp e)
     {
         buf.writeByte('[');
         foreach (i, key; *e.keys)
@@ -2004,7 +2015,7 @@ public:
         buf.writeByte(']');
     }
 
-    override void visit(StructLiteralExp e)
+    void visitStructLiteral(StructLiteralExp e)
     {
         buf.writestring(e.sd.toChars());
         buf.writeByte('(');
@@ -2024,7 +2035,7 @@ public:
         buf.writeByte(')');
     }
 
-    override void visit(CompoundLiteralExp e)
+    void visitCompoundLiteral(CompoundLiteralExp e)
     {
         buf.writeByte('(');
         typeToBuffer(e.type, null, buf, hgs);
@@ -2032,12 +2043,12 @@ public:
         e.initializer.initializerToBuffer(buf, hgs);
     }
 
-    override void visit(TypeExp e)
+    void visitType(TypeExp e)
     {
         typeToBuffer(e.type, null, buf, hgs);
     }
 
-    override void visit(ScopeExp e)
+    void visitScope(ScopeExp e)
     {
         if (e.sds.isTemplateInstance())
         {
@@ -2059,12 +2070,12 @@ public:
         }
     }
 
-    override void visit(TemplateExp e)
+    void visitTemplate(TemplateExp e)
     {
         buf.writestring(e.td.toChars());
     }
 
-    override void visit(NewExp e)
+    void visitNew(NewExp e)
     {
         if (e.thisexp)
         {
@@ -2081,7 +2092,7 @@ public:
         }
     }
 
-    override void visit(NewAnonClassExp e)
+    void visitNewAnonClass(NewAnonClassExp e)
     {
         if (e.thisexp)
         {
@@ -2100,7 +2111,7 @@ public:
             e.cd.dsymbolToBuffer(buf, hgs);
     }
 
-    override void visit(SymOffExp e)
+    void visitSymOff(SymOffExp e)
     {
         if (e.offset)
             buf.printf("(& %s%+lld)", e.var.toChars(), e.offset);
@@ -2110,22 +2121,22 @@ public:
             buf.printf("& %s", e.var.toChars());
     }
 
-    override void visit(VarExp e)
+    void visitVar(VarExp e)
     {
         buf.writestring(e.var.toChars());
     }
 
-    override void visit(OverExp e)
+    void visitOver(OverExp e)
     {
         buf.writestring(e.vars.ident.toString());
     }
 
-    override void visit(TupleExp e)
+    void visitTuple(TupleExp e)
     {
         if (e.e0)
         {
             buf.writeByte('(');
-            e.e0.accept(this);
+            e.e0.expressionPrettyPrint(buf, hgs);
             buf.writestring(", tuple(");
             argsToBuffer(e.exps, buf, hgs);
             buf.writestring("))");
@@ -2138,13 +2149,13 @@ public:
         }
     }
 
-    override void visit(FuncExp e)
+    void visitFunc(FuncExp e)
     {
         e.fd.dsymbolToBuffer(buf, hgs);
         //buf.writestring(e.fd.toChars());
     }
 
-    override void visit(DeclarationExp e)
+    void visitDeclaration(DeclarationExp e)
     {
         /* Normal dmd execution won't reach here - regular variable declarations
          * are handled in visit(ExpStatement), so here would be used only when
@@ -2170,14 +2181,14 @@ public:
         }
     }
 
-    override void visit(TypeidExp e)
+    void visitTypeid(TypeidExp e)
     {
         buf.writestring("typeid(");
         objectToBuffer(e.obj, buf, hgs);
         buf.writeByte(')');
     }
 
-    override void visit(TraitsExp e)
+    void visitTraits(TraitsExp e)
     {
         buf.writestring("__traits(");
         if (e.ident)
@@ -2193,12 +2204,12 @@ public:
         buf.writeByte(')');
     }
 
-    override void visit(HaltExp e)
+    void visitHalt(HaltExp e)
     {
         buf.writestring("halt");
     }
 
-    override void visit(IsExp e)
+    void visitIs(IsExp e)
     {
         buf.writestring("is(");
         typeToBuffer(e.targ, e.id, buf, hgs);
@@ -2223,13 +2234,13 @@ public:
         buf.writeByte(')');
     }
 
-    override void visit(UnaExp e)
+    void visitUna(UnaExp e)
     {
         buf.writestring(EXPtoString(e.op));
         expToBuffer(e.e1, precedence[e.op], buf, hgs);
     }
 
-    override void visit(BinExp e)
+    void visitBin(BinExp e)
     {
         expToBuffer(e.e1, precedence[e.op], buf, hgs);
         buf.writeByte(' ');
@@ -2238,7 +2249,7 @@ public:
         expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1), buf, hgs);
     }
 
-    override void visit(CommaExp e)
+    void visitComma(CommaExp e)
     {
         // CommaExp is generated by the compiler so it shouldn't
         // appear in error messages or header files.
@@ -2251,7 +2262,7 @@ public:
         // the old path
         if (!ve || !(ve.var.storage_class & STC.temp))
         {
-            visit(cast(BinExp)e);
+            visitBin(cast(BinExp)e);
             return;
         }
 
@@ -2281,25 +2292,25 @@ public:
         }
 
         // not one of the known cases, go on the old path
-        visit(cast(BinExp)e);
+        visitBin(cast(BinExp)e);
         return;
     }
 
-    override void visit(MixinExp e)
+    void visitMixin(MixinExp e)
     {
         buf.writestring("mixin(");
         argsToBuffer(e.exps, buf, hgs, null);
         buf.writeByte(')');
     }
 
-    override void visit(ImportExp e)
+    void visitImport(ImportExp e)
     {
         buf.writestring("import(");
         expToBuffer(e.e1, PREC.assign, buf, hgs);
         buf.writeByte(')');
     }
 
-    override void visit(AssertExp e)
+    void visitAssert(AssertExp e)
     {
         buf.writestring("assert(");
         expToBuffer(e.e1, PREC.assign, buf, hgs);
@@ -2311,13 +2322,13 @@ public:
         buf.writeByte(')');
     }
 
-    override void visit(ThrowExp e)
+    void visitThrow(ThrowExp e)
     {
         buf.writestring("throw ");
         expToBuffer(e.e1, PREC.unary, buf, hgs);
     }
 
-    override void visit(DotIdExp e)
+    void visitDotId(DotIdExp e)
     {
         expToBuffer(e.e1, PREC.primary, buf, hgs);
         if (e.arrow)
@@ -2327,28 +2338,28 @@ public:
         buf.writestring(e.ident.toString());
     }
 
-    override void visit(DotTemplateExp e)
+    void visitDotTemplate(DotTemplateExp e)
     {
         expToBuffer(e.e1, PREC.primary, buf, hgs);
         buf.writeByte('.');
         buf.writestring(e.td.toChars());
     }
 
-    override void visit(DotVarExp e)
+    void visitDotVar(DotVarExp e)
     {
         expToBuffer(e.e1, PREC.primary, buf, hgs);
         buf.writeByte('.');
         buf.writestring(e.var.toChars());
     }
 
-    override void visit(DotTemplateInstanceExp e)
+    void visitDotTemplateInstance(DotTemplateInstanceExp e)
     {
         expToBuffer(e.e1, PREC.primary, buf, hgs);
         buf.writeByte('.');
         e.ti.dsymbolToBuffer(buf, hgs);
     }
 
-    override void visit(DelegateExp e)
+    void visitDelegate(DelegateExp e)
     {
         buf.writeByte('&');
         if (!e.func.isNested() || e.func.needThis())
@@ -2359,14 +2370,14 @@ public:
         buf.writestring(e.func.toChars());
     }
 
-    override void visit(DotTypeExp e)
+    void visitDotType(DotTypeExp e)
     {
         expToBuffer(e.e1, PREC.primary, buf, hgs);
         buf.writeByte('.');
         buf.writestring(e.sym.toChars());
     }
 
-    override void visit(CallExp e)
+    void visitCall(CallExp e)
     {
         if (e.e1.op == EXP.type)
         {
@@ -2375,7 +2386,7 @@ public:
              * This is ok since types in constructor calls
              * can never depend on parens anyway
              */
-            e.e1.accept(this);
+            e.e1.expressionPrettyPrint(buf, hgs);
         }
         else
             expToBuffer(e.e1, precedence[e.op], buf, hgs);
@@ -2384,19 +2395,19 @@ public:
         buf.writeByte(')');
     }
 
-    override void visit(PtrExp e)
+    void visitPtr(PtrExp e)
     {
         buf.writeByte('*');
         expToBuffer(e.e1, precedence[e.op], buf, hgs);
     }
 
-    override void visit(DeleteExp e)
+    void visitDelete(DeleteExp e)
     {
         buf.writestring("delete ");
         expToBuffer(e.e1, precedence[e.op], buf, hgs);
     }
 
-    override void visit(CastExp e)
+    void visitCast(CastExp e)
     {
         buf.writestring("cast(");
         if (e.to)
@@ -2409,7 +2420,7 @@ public:
         expToBuffer(e.e1, precedence[e.op], buf, hgs);
     }
 
-    override void visit(VectorExp e)
+    void visitVector(VectorExp e)
     {
         buf.writestring("cast(");
         typeToBuffer(e.to, null, buf, hgs);
@@ -2417,13 +2428,13 @@ public:
         expToBuffer(e.e1, precedence[e.op], buf, hgs);
     }
 
-    override void visit(VectorArrayExp e)
+    void visitVectorArray(VectorArrayExp e)
     {
         expToBuffer(e.e1, PREC.primary, buf, hgs);
         buf.writestring(".array");
     }
 
-    override void visit(SliceExp e)
+    void visitSlice(SliceExp e)
     {
         expToBuffer(e.e1, precedence[e.op], buf, hgs);
         buf.writeByte('[');
@@ -2442,32 +2453,32 @@ public:
         buf.writeByte(']');
     }
 
-    override void visit(ArrayLengthExp e)
+    void visitArrayLength(ArrayLengthExp e)
     {
         expToBuffer(e.e1, PREC.primary, buf, hgs);
         buf.writestring(".length");
     }
 
-    override void visit(IntervalExp e)
+    void visitInterval(IntervalExp e)
     {
         expToBuffer(e.lwr, PREC.assign, buf, hgs);
         buf.writestring("..");
         expToBuffer(e.upr, PREC.assign, buf, hgs);
     }
 
-    override void visit(DelegatePtrExp e)
+    void visitDelegatePtr(DelegatePtrExp e)
     {
         expToBuffer(e.e1, PREC.primary, buf, hgs);
         buf.writestring(".ptr");
     }
 
-    override void visit(DelegateFuncptrExp e)
+    void visitDelegateFuncptr(DelegateFuncptrExp e)
     {
         expToBuffer(e.e1, PREC.primary, buf, hgs);
         buf.writestring(".funcptr");
     }
 
-    override void visit(ArrayExp e)
+    void visitArray(ArrayExp e)
     {
         expToBuffer(e.e1, PREC.primary, buf, hgs);
         buf.writeByte('[');
@@ -2475,14 +2486,14 @@ public:
         buf.writeByte(']');
     }
 
-    override void visit(DotExp e)
+    void visitDot(DotExp e)
     {
         expToBuffer(e.e1, PREC.primary, buf, hgs);
         buf.writeByte('.');
         expToBuffer(e.e2, PREC.primary, buf, hgs);
     }
 
-    override void visit(IndexExp e)
+    void visitIndex(IndexExp e)
     {
         expToBuffer(e.e1, PREC.primary, buf, hgs);
         buf.writeByte('[');
@@ -2490,19 +2501,19 @@ public:
         buf.writeByte(']');
     }
 
-    override void visit(PostExp e)
+    void visitPost(PostExp e)
     {
         expToBuffer(e.e1, precedence[e.op], buf, hgs);
         buf.writestring(EXPtoString(e.op));
     }
 
-    override void visit(PreExp e)
+    void visitPre(PreExp e)
     {
         buf.writestring(EXPtoString(e.op));
         expToBuffer(e.e1, precedence[e.op], buf, hgs);
     }
 
-    override void visit(RemoveExp e)
+    void visitRemove(RemoveExp e)
     {
         expToBuffer(e.e1, PREC.primary, buf, hgs);
         buf.writestring(".remove(");
@@ -2510,7 +2521,7 @@ public:
         buf.writeByte(')');
     }
 
-    override void visit(CondExp e)
+    void visitCond(CondExp e)
     {
         expToBuffer(e.econd, PREC.oror, buf, hgs);
         buf.writestring(" ? ");
@@ -2519,15 +2530,90 @@ public:
         expToBuffer(e.e2, PREC.cond, buf, hgs);
     }
 
-    override void visit(DefaultInitExp e)
+    void visitDefaultInit(DefaultInitExp e)
     {
         buf.writestring(EXPtoString(e.op));
     }
 
-    override void visit(ClassReferenceExp e)
+    void visitClassReference(ClassReferenceExp e)
     {
         buf.writestring(e.value.toChars());
     }
+
+    switch (e.op)
+    {
+        default:
+            if (auto be = e.isBinExp())
+                return visitBin(be);
+            else if (auto ue = e.isUnaExp())
+                return visitUna(ue);
+            else if (auto de = e.isDefaultInitExp())
+                return visitDefaultInit(e.isDefaultInitExp());
+            return visit(e);
+
+        case EXP.int64:         return visitInteger(e.isIntegerExp());
+        case EXP.error:         return visitError(e.isErrorExp());
+        case EXP.void_:         return visitVoidInit(e.isVoidInitExp());
+        case EXP.float64:       return visitReal(e.isRealExp());
+        case EXP.complex80:     return visitComplex(e.isComplexExp());
+        case EXP.identifier:    return visitIdentifier(e.isIdentifierExp());
+        case EXP.dSymbol:       return visitDsymbol(e.isDsymbolExp());
+        case EXP.this_:         return visitThis(e.isThisExp());
+        case EXP.super_:        return visitSuper(e.isSuperExp());
+        case EXP.null_:         return visitNull(e.isNullExp());
+        case EXP.string_:       return visitString(e.isStringExp());
+        case EXP.arrayLiteral:  return visitArrayLiteral(e.isArrayLiteralExp());
+        case EXP.assocArrayLiteral:     return visitAssocArrayLiteral(e.isAssocArrayLiteralExp());
+        case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp());
+        case EXP.compoundLiteral:       return visitCompoundLiteral(e.isCompoundLiteralExp());
+        case EXP.type:          return visitType(e.isTypeExp());
+        case EXP.scope_:        return visitScope(e.isScopeExp());
+        case EXP.template_:     return visitTemplate(e.isTemplateExp());
+        case EXP.new_:          return visitNew(e.isNewExp());
+        case EXP.newAnonymousClass:     return visitNewAnonClass(e.isNewAnonClassExp());
+        case EXP.symbolOffset:  return visitSymOff(e.isSymOffExp());
+        case EXP.variable:      return visitVar(e.isVarExp());
+        case EXP.overloadSet:   return visitOver(e.isOverExp());
+        case EXP.tuple:         return visitTuple(e.isTupleExp());
+        case EXP.function_:     return visitFunc(e.isFuncExp());
+        case EXP.declaration:   return visitDeclaration(e.isDeclarationExp());
+        case EXP.typeid_:       return visitTypeid(e.isTypeidExp());
+        case EXP.traits:        return visitTraits(e.isTraitsExp());
+        case EXP.halt:          return visitHalt(e.isHaltExp());
+        case EXP.is_:           return visitIs(e.isExp());
+        case EXP.comma:         return visitComma(e.isCommaExp());
+        case EXP.mixin_:        return visitMixin(e.isMixinExp());
+        case EXP.import_:       return visitImport(e.isImportExp());
+        case EXP.assert_:       return visitAssert(e.isAssertExp());
+        case EXP.throw_:        return visitThrow(e.isThrowExp());
+        case EXP.dotIdentifier: return visitDotId(e.isDotIdExp());
+        case EXP.dotTemplateDeclaration:        return visitDotTemplate(e.isDotTemplateExp());
+        case EXP.dotVariable:   return visitDotVar(e.isDotVarExp());
+        case EXP.dotTemplateInstance:   return visitDotTemplateInstance(e.isDotTemplateInstanceExp());
+        case EXP.delegate_:     return visitDelegate(e.isDelegateExp());
+        case EXP.dotType:       return visitDotType(e.isDotTypeExp());
+        case EXP.call:          return visitCall(e.isCallExp());
+        case EXP.star:          return visitPtr(e.isPtrExp());
+        case EXP.delete_:       return visitDelete(e.isDeleteExp());
+        case EXP.cast_:         return visitCast(e.isCastExp());
+        case EXP.vector:        return visitVector(e.isVectorExp());
+        case EXP.vectorArray:   return visitVectorArray(e.isVectorArrayExp());
+        case EXP.slice:         return visitSlice(e.isSliceExp());
+        case EXP.arrayLength:   return visitArrayLength(e.isArrayLengthExp());
+        case EXP.interval:      return visitInterval(e.isIntervalExp());
+        case EXP.delegatePointer:       return visitDelegatePtr(e.isDelegatePtrExp());
+        case EXP.delegateFunctionPointer:       return visitDelegateFuncptr(e.isDelegateFuncptrExp());
+        case EXP.array:         return visitArray(e.isArrayExp());
+        case EXP.dot:           return visitDot(e.isDotExp());
+        case EXP.index:         return visitIndex(e.isIndexExp());
+        case EXP.minusMinus:
+        case EXP.plusPlus:      return visitPost(e.isPostExp());
+        case EXP.preMinusMinus:
+        case EXP.prePlusPlus:   return visitPre(e.isPreExp());
+        case EXP.remove:        return visitRemove(e.isRemoveExp());
+        case EXP.question:      return visitCond(e.isCondExp());
+        case EXP.classReference:        return visitClassReference(e.isClassReferenceExp());
+    }
 }
 
 /**
@@ -2547,7 +2633,7 @@ void floatToBuffer(Type type, const real_t value, OutBuffer* buf, const bool all
         (ie, 8 chars more than mantissa). Plus one for trailing \0.
         Plus one for rounding. */
     const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1;
-    char[BUFFER_LEN] buffer;
+    char[BUFFER_LEN] buffer = void;
     CTFloat.sprint(buffer.ptr, 'g', value);
     assert(strlen(buffer.ptr) < BUFFER_LEN);
     if (allowHex)
@@ -2754,7 +2840,7 @@ bool stcToBuffer(OutBuffer* buf, StorageClass stc)
     }
     if (stc & STC.returninferred)
     {
-        //buf.writestring("return-inferred ");
+        //buf.writestring((stc & STC.returnScope) ? "return-scope-inferred " : "return-ref-inferred ");
         stc &= ~(STC.return_ | STC.returninferred);
     }
 
@@ -2958,8 +3044,7 @@ void functionToBufferWithIdent(TypeFunction tf, OutBuffer* buf, const(char)* ide
 
 void toCBuffer(const Expression e, OutBuffer* buf, HdrGenState* hgs)
 {
-    scope v = new ExpressionPrettyPrintVisitor(buf, hgs);
-    (cast() e).accept(v);
+    expressionPrettyPrint(cast()e, buf, hgs);
 }
 
 /**************************************************
@@ -3221,8 +3306,7 @@ private void sizeToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs)
 
 private void expressionToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs)
 {
-    scope v = new ExpressionPrettyPrintVisitor(buf, hgs);
-    e.accept(v);
+    expressionPrettyPrint(e, buf, hgs);
 }
 
 /**************************************************
index 2ec75ab25167a95277249d3e7131fd2141d92525..11455afe263770003b194dfd16ad762c79daae58 100644 (file)
@@ -491,6 +491,7 @@ immutable Msgtable[] msgtable =
     { "udaGNUAbiTag", "gnuAbiTag" },
     { "udaSelector", "selector" },
     { "udaOptional", "optional"},
+    { "udaMustUse", "mustuse" },
 
     // C names, for undefined identifier error messages
     { "NULL" },
index 649d88e3d592d75a9cc5f704b84f1fff48fc2d97..616712b463d81668817310cbe6c0f8b3292dc612 100644 (file)
@@ -554,26 +554,39 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                     i.exp = e.optimize(WANTvalue);
             }
         }
+        {
         // Look for the case of statically initializing an array
         // with a single member.
-        if (tb.ty == Tsarray && !tb.nextOf().equals(ti.toBasetype().nextOf()) && i.exp.implicitConvTo(tb.nextOf()))
+        auto tba = tb.isTypeSArray();
+        if (tba && !tba.next.equals(ti.toBasetype().nextOf()) && i.exp.implicitConvTo(tba.next))
         {
             /* If the variable is not actually used in compile time, array creation is
              * redundant. So delay it until invocation of toExpression() or toDt().
              */
             t = tb.nextOf();
         }
+
+        auto tta = t.isTypeSArray();
         if (i.exp.implicitConvTo(t))
         {
             i.exp = i.exp.implicitCastTo(sc, t);
         }
+        else if (sc.flags & SCOPE.Cfile && i.exp.isStringExp() &&
+            tta && (tta.next.ty == Tint8 || tta.next.ty == Tuns8) &&
+            ti.ty == Tpointer && ti.nextOf().ty == Tchar)
+        {
+            /* unsigned char bbb[1] = "";
+             *   signed char ccc[1] = "";
+             */
+            i.exp = i.exp.castTo(sc, t);
+        }
         else
         {
             // Look for mismatch of compile-time known length to emit
             // better diagnostic message, as same as AssignExp::semantic.
-            if (tb.ty == Tsarray && i.exp.implicitConvTo(tb.nextOf().arrayOf()) > MATCH.nomatch)
+            if (tba && i.exp.implicitConvTo(tba.next.arrayOf()) > MATCH.nomatch)
             {
-                uinteger_t dim1 = tb.isTypeSArray().dim.toInteger();
+                uinteger_t dim1 = tba.dim.toInteger();
                 uinteger_t dim2 = dim1;
                 if (auto ale = i.exp.isArrayLiteralExp())
                 {
@@ -596,6 +609,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
             if (global.endGagging(errors))
                 currExp.error("cannot implicitly convert expression `%s` of type `%s` to `%s`", currExp.toChars(), et.toChars(), t.toChars());
         }
+        }
     L1:
         if (i.exp.op == EXP.error)
         {
@@ -1059,7 +1073,7 @@ Initializer inferType(Initializer init, Scope* sc)
 
     Initializer visitC(CInitializer i)
     {
-        //printf(CInitializer::inferType()\n");
+        //printf("CInitializer.inferType()\n");
         error(i.loc, "TODO C inferType initializers not supported yet");
         return new ErrorInitializer();
     }
@@ -1331,6 +1345,10 @@ private bool hasNonConstPointers(Expression e)
     }
     if (auto ae = e.isAddrExp())
     {
+        if (ae.type.nextOf().isImmutable() || ae.type.nextOf().isConst())
+        {
+            return false;
+        }
         if (auto se = ae.e1.isStructLiteralExp())
         {
             if (!(se.stageflags & stageSearchPointers))
index 3183c8dbb79a4dfeac8b4f22df49f9b5e31f6f36..fc270390fa4ac18662696f36eea667828277a09e 100644 (file)
@@ -319,10 +319,7 @@ public:
             // Should not be printed
             //property(name, "d");
             break;
-        case LINK.system:
-            // Should not be printed
-            //property(name, "system");
-            break;
+        case LINK.system:   return property(name, "system");
         case LINK.c:        return property(name, "c");
         case LINK.cpp:      return property(name, "cpp");
         case LINK.windows:  return property(name, "windows");
index 7cd4bfd59227247b8c1fd61134d9f9ff204413ef..b778bc82d77ca61bd5993dae22f4b8dbf5e09776 100644 (file)
@@ -108,8 +108,8 @@ class Lexer
         size_t endoffset, bool doDocComment, bool commentToken) pure
     {
         scanloc = Loc(filename, 1, 1);
-        //printf("Lexer::Lexer(%p,%d)\n",base,length);
-        //printf("lexer.filename = %s\n", filename);
+        // debug printf("Lexer::Lexer(%p)\n", base);
+        // debug printf("lexer.filename = %s\n", filename);
         token = Token.init;
         this.base = base;
         this.end = base + endoffset;
@@ -2122,7 +2122,7 @@ class Lexer
                 // can't translate invalid octal value, just show a generic message
                 error("octal literals larger than 7 are no longer supported");
             else
-                error("octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!%llo%.*s` instead",
+                error("octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!\"%llo%.*s\"` instead",
                     n, cast(int)(p - psuffix), psuffix, n, cast(int)(p - psuffix), psuffix);
         }
         TOK result;
@@ -2926,7 +2926,7 @@ class Lexer
      */
     static const(char)* combineComments(const(char)[] c1, const(char)[] c2, bool newParagraph) pure
     {
-        //printf("Lexer::combineComments('%s', '%s', '%i')\n", c1, c2, newParagraph);
+        //debug printf("Lexer::combineComments('%*.s', '%*.s', '%i')\n", cast(int) c1.length, c1.ptr, cast(int) c2.length, c2.ptr, newParagraph);
         const(int) newParagraphSize = newParagraph ? 1 : 0; // Size of the combining '\n'
         if (!c1)
             return c2.ptr;
index b2c7aa461ca5948acfb079a15e9c5e80b76e1f48..50dd20b70b991a2a6cbaed2ad40680d9367a8a5d 100644 (file)
@@ -4200,27 +4200,28 @@ extern (C++) final class TypeFunction : TypeNext
 
     // These flags can be accessed like `bool` properties,
     // getters and setters are generated for them
-    private enum FunctionFlag : uint
-    {
-        none            = 0,
-        isnothrow       = 0x0001, // nothrow
-        isnogc          = 0x0002, // is @nogc
-        isproperty      = 0x0004, // can be called without parentheses
-        isref           = 0x0008, // returns a reference
-        isreturn        = 0x0010, // 'this' is returned by ref
-        isScopeQual     = 0x0020, // 'this' is scope
-        isreturninferred= 0x0040, // 'this' is return from inference
-        isscopeinferred = 0x0080, // 'this' is scope from inference
-        islive          = 0x0100, // is @live
-        incomplete      = 0x0200, // return type or default arguments removed
-        isInOutParam    = 0x0400, // inout on the parameters
-        isInOutQual     = 0x0800, // inout on the qualifier
-        isctor          = 0x1000, // the function is a constructor
-        isreturnscope   = 0x2000, // `this` is returned by value
-    }
+    private extern (D) static struct BitFields
+    {
+        bool isnothrow;        /// nothrow
+        bool isnogc;           /// is @nogc
+        bool isproperty;       /// can be called without parentheses
+        bool isref;            /// returns a reference
+        bool isreturn;         /// 'this' is returned by ref
+        bool isScopeQual;      /// 'this' is scope
+        bool isreturninferred; /// 'this' is return from inference
+        bool isscopeinferred;  /// 'this' is scope from inference
+        bool islive;           /// is @live
+        bool incomplete;       /// return type or default arguments removed
+        bool isInOutParam;     /// inout on the parameters
+        bool isInOutQual;      /// inout on the qualifier
+        bool isctor;           /// the function is a constructor
+        bool isreturnscope;    /// `this` is returned by value
+    }
+
+    import dmd.common.bitfields : generateBitFields;
+    mixin(generateBitFields!(BitFields, ushort));
 
     LINK linkage;               // calling convention
-    FunctionFlag funcFlags;
     TRUST trust;                // level of trust
     PURE purity = PURE.impure;
     byte inuse;
@@ -4684,6 +4685,16 @@ extern (C++) final class TypeFunction : TypeNext
             match = MATCH.convert; // match ... with a "conversion" match level
         }
 
+        // https://issues.dlang.org/show_bug.cgi?id=22997
+        if (parameterList.varargs == VarArg.none && nparams > nargs && !parameterList[nargs].defaultArg)
+        {
+            OutBuffer buf;
+            buf.printf("too few arguments, expected `%d`, got `%d`", cast(int)nparams, cast(int)nargs);
+            if (pMessage)
+                *pMessage = buf.extractChars();
+            goto Nomatch;
+        }
+
         foreach (u, p; parameterList)
         {
             if (u == nargs)
@@ -5086,41 +5097,21 @@ extern (C++) final class TypeFunction : TypeNext
         return false;
     }
 
-    // Generate getter / setter functions for `FunctionFlag` members so they can be
-    // treated like regular `bool` fields, instead of requiring bit twiddling to read/write
-    extern (D) mixin(() {
-        string result = "extern(C++) pure nothrow @safe @nogc {";
-        foreach (string mem; __traits(allMembers, FunctionFlag))
-        {
-            result ~= "
-            /// set or get if the function has the FunctionFlag attribute of the same name
-            bool "~mem~"() const { return (funcFlags & FunctionFlag."~mem~") != 0; }
-            /// ditto
-            void "~mem~"(bool v)
-            {
-                if (v) funcFlags |= FunctionFlag."~mem~";
-                else funcFlags &= ~FunctionFlag."~mem~";
-            }";
-        }
-        return result ~ "}\n";
-    }());
 
     /// Returns: `true` the function is `isInOutQual` or `isInOutParam` ,`false` otherwise.
     bool iswild() const pure nothrow @safe @nogc
     {
-        return (funcFlags & (FunctionFlag.isInOutParam | FunctionFlag.isInOutQual)) != 0;
+        return isInOutParam || isInOutQual;
     }
 
     /// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other`
     bool attributesEqual(const scope TypeFunction other) const pure nothrow @safe @nogc
     {
-        enum attributes = FunctionFlag.isnothrow
-                        | FunctionFlag.isnogc
-                        | FunctionFlag.islive;
-
         return this.trust == other.trust &&
                 this.purity == other.purity &&
-                (this.funcFlags & attributes) == (other.funcFlags & attributes);
+                this.isnothrow == other.isnothrow &&
+                this.isnogc == other.isnogc &&
+                this.islive == other.islive;
     }
 
     override void accept(Visitor v)
index 07c574d42b79e88ef6d23f8ad1dbdbbd528f0b5a..e0b6339bf23c89a26df15e78171a7e8290e1c01f 100644 (file)
@@ -595,8 +595,8 @@ public:
     // .next is the return type
 
     ParameterList parameterList; // function parameters
+    uint16_t bitFields;
     LINK linkage;                // calling convention
-    unsigned funcFlags;
     TRUST trust;                 // level of trust
     PURE purity;                 // PURExxxx
     char inuse;
diff --git a/gcc/d/dmd/mustuse.d b/gcc/d/dmd/mustuse.d
new file mode 100644 (file)
index 0000000..4eb4228
--- /dev/null
@@ -0,0 +1,244 @@
+/**
+ * Compile-time checks associated with the @mustuse attribute.
+ *
+ * Copyright: Copyright (C) 2022 by The D Language Foundation, All Rights Reserved
+ * License:   $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source:    $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mustuse.d, _mustuse.d)
+ * Documentation:  https://dlang.org/phobos/dmd_mustuse.html
+ * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/mustuse.d
+ */
+
+module dmd.mustuse;
+
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.expression;
+import dmd.globals;
+import dmd.identifier;
+
+// Used in isIncrementOrDecrement
+private static const StringExp plusPlus, minusMinus;
+
+// Loc.initial cannot be used in static initializers, so
+// these need a static constructor.
+static this()
+{
+    plusPlus = new StringExp(Loc.initial, "++");
+    minusMinus = new StringExp(Loc.initial, "--");
+}
+
+/**
+ * Check whether discarding an expression would violate the requirements of
+ * @mustuse. If so, emit an error.
+ *
+ * Params:
+ *   e = the expression to check
+ *   sc = scope in which `e` was semantically analyzed
+ *
+ * Returns: true on error, false on success.
+ */
+bool checkMustUse(Expression e, Scope* sc)
+{
+    import dmd.id : Id;
+
+    assert(e.type);
+    if (auto sym = e.type.toDsymbol(sc))
+    {
+        auto sd = sym.isStructDeclaration();
+        // isStructDeclaration returns non-null for both structs and unions
+        if (sd && hasMustUseAttribute(sd, sc) && !isAssignment(e) && !isIncrementOrDecrement(e))
+        {
+            e.error("ignored value of `@%s` type `%s`; prepend a `cast(void)` if intentional",
+                Id.udaMustUse.toChars(), e.type.toPrettyChars(true));
+            return true;
+        }
+    }
+    return false;
+}
+
+/**
+ * Called from a symbol's semantic to check for reserved usage of @mustuse.
+ *
+ * If such usage is found, emits an errror.
+ *
+ * Params:
+ *   sym = symbol to check
+ */
+void checkMustUseReserved(Dsymbol sym)
+{
+    import dmd.attrib : foreachUdaNoSemantic;
+    import dmd.errors : error;
+    import dmd.id : Id;
+
+    // Can't use foreachUda (and by extension hasMustUseAttribute) while
+    // semantic analysis of `sym` is still in progress
+    foreachUdaNoSemantic(sym, (exp) {
+        if (isMustUseAttribute(exp))
+        {
+            if (sym.isFuncDeclaration())
+            {
+                error(sym.loc, "`@%s` on functions is reserved for future use",
+                    Id.udaMustUse.toChars());
+                sym.errors = true;
+            }
+            else if (sym.isClassDeclaration() || sym.isEnumDeclaration())
+            {
+                error(sym.loc, "`@%s` on `%s` types is reserved for future use",
+                    Id.udaMustUse.toChars(), sym.kind());
+                sym.errors = true;
+            }
+        }
+        return 0; // continue
+    });
+}
+
+/**
+ * Returns: true if the given expression is an assignment, either simple (a = b)
+ * or compound (a += b, etc).
+ */
+private bool isAssignment(Expression e)
+{
+    if (e.isAssignExp || e.isBinAssignExp)
+        return true;
+    if (auto ce = e.isCallExp())
+    {
+        if (auto fd = ce.f)
+        {
+            auto id = fd.ident;
+            if (id && isAssignmentOpId(id))
+                return true;
+        }
+    }
+    return false;
+}
+
+/**
+ * Returns: true if id is the identifier of an assignment operator overload.
+ */
+private bool isAssignmentOpId(Identifier id)
+{
+    import dmd.id : Id;
+
+    return id == Id.assign
+        || id == Id.addass
+        || id == Id.subass
+        || id == Id.mulass
+        || id == Id.divass
+        || id == Id.modass
+        || id == Id.andass
+        || id == Id.orass
+        || id == Id.xorass
+        || id == Id.shlass
+        || id == Id.shrass
+        || id == Id.ushrass
+        || id == Id.catass
+        || id == Id.indexass
+        || id == Id.slice
+        || id == Id.sliceass
+        || id == Id.opOpAssign
+        || id == Id.opIndexOpAssign
+        || id == Id.opSliceOpAssign
+        || id == Id.powass;
+}
+
+/**
+ * Returns: true if the given expression is an increment (++) or decrement (--).
+ */
+private bool isIncrementOrDecrement(Expression e)
+{
+    import dmd.dtemplate : isExpression;
+    import dmd.globals : Loc;
+    import dmd.id : Id;
+    import dmd.tokens : EXP;
+
+    if (e.op == EXP.plusPlus
+        || e.op == EXP.minusMinus
+        || e.op == EXP.prePlusPlus
+        || e.op == EXP.preMinusMinus)
+        return true;
+    if (auto call = e.isCallExp())
+    {
+        // Check for overloaded preincrement
+        // e.g., a.opUnary!"++"
+        if (auto fd = call.f)
+        {
+            if (fd.ident == Id.opUnary && fd.parent)
+            {
+                if (auto ti = fd.parent.isTemplateInstance())
+                {
+                    auto tiargs = ti.tiargs;
+                    if (tiargs && tiargs.length >= 1)
+                    {
+                        if (auto argExp = (*tiargs)[0].isExpression())
+                        {
+                            auto op = argExp.isStringExp();
+                            if (op && (op.compare(plusPlus) == 0 || op.compare(minusMinus) == 0))
+                                return true;
+                        }
+                    }
+                }
+            }
+        }
+    }
+    else if (auto comma = e.isCommaExp())
+    {
+        // Check for overloaded postincrement
+        // e.g., (auto tmp = a, ++a, tmp)
+        if (comma.e1)
+        {
+            if (auto left = comma.e1.isCommaExp())
+            {
+                if (auto middle = left.e2)
+                {
+                    if (middle && isIncrementOrDecrement(middle))
+                        return true;
+                }
+            }
+        }
+    }
+    return false;
+}
+
+/**
+ * Returns: true if the given symbol has the @mustuse attribute.
+ */
+private bool hasMustUseAttribute(Dsymbol sym, Scope* sc)
+{
+    import dmd.attrib : foreachUda;
+
+    bool result = false;
+
+    foreachUda(sym, sc, (Expression uda) {
+        if (isMustUseAttribute(uda))
+        {
+            result = true;
+            return 1; // break
+        }
+        return 0; // continue
+    });
+
+    return result;
+}
+
+/**
+ * Returns: true if the given expression is core.attribute.mustuse.
+ */
+private bool isMustUseAttribute(Expression e)
+{
+    import dmd.attrib : isCoreUda;
+    import dmd.id : Id;
+
+    // Logic based on dmd.objc.Supported.declaredAsOptionalCount
+    auto typeExp = e.isTypeExp;
+    if (!typeExp)
+        return false;
+
+    auto typeEnum = typeExp.type.isTypeEnum();
+    if (!typeEnum)
+        return false;
+
+    if (isCoreUda(typeEnum.sym, Id.udaMustUse))
+        return true;
+
+    return false;
+}
index dbd761fed2f4955ad3c621f578c4a2b6a7f89ad5..4f6903cbab721284a49b34cb0fa781a223477743 100644 (file)
@@ -213,7 +213,7 @@ private Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinE
      */
     if (isRecursiveAliasThis(e.att1, e.e1.type))
         return null;
-    //printf("att %s e1 = %s\n", Token::toChars(e.op), e.e1.type.toChars());
+    //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
     BinExp be = cast(BinExp)e.copy();
     // Resolve 'alias this' but in case of assigment don't resolve properties yet
     // because 'e1 = e2' could mean 'e1(e2)' or 'e1() = e2'
@@ -241,7 +241,7 @@ private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinE
      */
     if (isRecursiveAliasThis(e.att2, e.e2.type))
         return null;
-    //printf("att %s e2 = %s\n", Token::toChars(e.op), e.e2.type.toChars());
+    //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
     BinExp be = cast(BinExp)e.copy();
     be.e2 = resolveAliasThis(sc, e.e2, true);
     if (!be.e2)
index 3745a15da421c5e7305f3da6e2418dad161bcfba..3b8b1b6fa6c988c1d7b67522156cda8e3e26a3af 100644 (file)
@@ -271,7 +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());
+    //printf("Expression_optimize() e: %s result: %d keepLvalue %d\n", e.toChars(), result, keepLvalue);
     Expression ret = e;
 
     void error()
@@ -426,7 +426,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
 
     void visitAddr(AddrExp e)
     {
-        //printf("AddrExp::optimize(result = %d) %s\n", result, e.toChars());
+        //printf("AddrExp::optimize(result = %d, keepLvalue = %d) %s\n", result, keepLvalue, e.toChars());
         /* Rewrite &(a,b) as (a,&b)
          */
         if (auto ce = e.e1.isCommaExp())
@@ -438,7 +438,8 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
         }
         // Keep lvalue-ness
         if (expOptimize(e.e1, result, true))
-            return;
+            return;                     // error return
+
         // Convert &*ex to ex
         if (auto pe = e.e1.isPtrExp())
         {
@@ -515,6 +516,23 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
                         }
                     }
                 }
+                else if (auto ei = e.isIndexExp())
+                {
+                    if (auto ve = ei.e1.isVarExp())
+                    {
+                        if (!ve.var.isReference() &&
+                            !ve.var.isImportedSymbol() &&
+                            ve.var.isDataseg() &&
+                            ve.var.isCsymbol())
+                        {
+                            if (auto ie = ei.e2.isIntegerExp())
+                            {
+                                var = ve.var.isVarDeclaration();
+                                offset += ie.toInteger() * ve.type.toBasetype().nextOf().size();
+                            }
+                        }
+                    }
+                }
                 return false;
             }
 
@@ -538,7 +556,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
                 return;
             }
         }
-        if (auto ae = e.e1.isIndexExp())
+        else if (auto ae = e.e1.isIndexExp())
         {
             // Convert &array[n] to &array+n
             if (ae.e2.isIntegerExp() && ae.e1.isVarExp())
@@ -551,9 +569,10 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
                     sinteger_t dim = ts.dim.toInteger();
                     if (index < 0 || index >= dim)
                     {
-                        /* 0 for C static arrays means size is unknown, no need to check
+                        /* 0 for C static arrays means size is unknown, no need to check,
+                         * and address one past the end is OK, too
                          */
-                        if (!(dim == 0 && ve.var.isCsymbol()))
+                        if (!((dim == 0 || dim == index) && ve.var.isCsymbol()))
                         {
                             e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
                             return error();
@@ -585,9 +604,10 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
                     sinteger_t dim = ts.dim.toInteger();
                     if (index < 0 || index >= dim)
                     {
-                        /* 0 for C static arrays means size is unknown, no need to check
+                        /* 0 for C static arrays means size is unknown, no need to check,
+                         * and address one past the end is OK, too
                          */
-                        if (!(dim == 0 && ve.var.isCsymbol()))
+                        if (!((dim == 0 || dim == index) && ve.var.isCsymbol()))
                         {
                             e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
                             return error();
index ba5d3312d8a5dccf2ff24340db8d2b8a9d46e33f..beceb0f0707b395058bdf70ba606fd80b55bc705 100644 (file)
@@ -14,6 +14,8 @@ module dmd.root.aav;
 import core.stdc.string;
 import dmd.root.rmem;
 
+nothrow:
+
 private size_t hash(size_t a) pure nothrow @nogc @safe
 {
     a ^= (a >> 20) ^ (a >> 12);
index cd2d7096d3dbec1355654e69e695f83b2a238825..c2eb3e15c2cd02aed45044300844d886893b3e00 100644 (file)
@@ -137,7 +137,7 @@ public:
 
     void reserve(size_t nentries) pure nothrow
     {
-        //printf("Array::reserve: length = %d, data.length = %d, nentries = %d\n", (int)length, (int)data.length, (int)nentries);
+        //printf("Array::reserve: length = %d, data.length = %d, nentries = %d\n", cast(int)length, cast(int)data.length, cast(int)nentries);
 
         // Cold path
         void enlarge(size_t nentries)
index d9a396d9677b7885c532cc77ba102c168d1c97e5..a7a74381ef999a6c2f77a23f205e8e87c8e6ad80 100644 (file)
@@ -13,11 +13,15 @@ module dmd.root.complex;
 
 import dmd.root.ctfloat;
 
+nothrow:
+
 extern (C++) struct complex_t
 {
     real_t re;
     real_t im;
 
+  nothrow:
+
     this() @disable;
 
     this(real_t re)
index a01cfdc2aacef4b42b0de4a289970e6eab5e1313..b40413c9ef15790e81120d7a556b8e6e9f4b71bd 100644 (file)
@@ -26,11 +26,15 @@ import dmd.root.string;
 import dmd.common.file;
 import dmd.common.string;
 
-/// Owns a (rmem-managed) file buffer.
-struct FileBuffer
+nothrow:
+
+/// Owns a (rmem-managed) buffer.
+struct Buffer
 {
     ubyte[] data;
 
+  nothrow:
+
     this(this) @disable;
 
     ~this() pure nothrow
@@ -54,7 +58,7 @@ struct File
     static struct ReadResult
     {
         bool success;
-        FileBuffer buffer;
+        Buffer buffer;
 
         /// Transfers ownership of the buffer to the caller.
         ubyte[] extractSlice() pure nothrow @nogc @safe
index 27fcf9c849fbdeda7fb10297af156595efbfaaa8..d6753aa84906e0b6c6c6c708ddb2245e70aad1e3 100644 (file)
@@ -29,6 +29,8 @@ nothrow:
 // Type used by the front-end for compile-time reals
 struct longdouble
 {
+nothrow:
+@nogc:
     extern (D) this(T)(T r)
     {
         this.set(cast(SetType!T)r);
index f2f7389efd26efb76484e39b498f0674973781a9..266846bcb0b23f58c6be8da33b6167130ad28ae1 100644 (file)
@@ -10,6 +10,8 @@
  */
 module dmd.root.optional;
 
+nothrow:
+
 ///
 unittest
 {
@@ -45,6 +47,8 @@ extern (C++) struct Optional(T)
     /// whether `value` is set
     private bool present;
 
+  nothrow:
+
     /// Creates an `Optional` with the given value
     this(T value)
     {
index b9029a16ef88723abaf7f968306eac0e20bd5c0a..cd65920e38b66009a8f16f29870700a21c34c962 100644 (file)
@@ -478,7 +478,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
         i.mod.semantic2(null);
         if (i.mod.needmoduleinfo)
         {
-            //printf("module5 %s because of %s\n", sc.module.toChars(), mod.toChars());
+            //printf("module5 %s because of %s\n", sc._module.toChars(), mod.toChars());
             if (sc)
                 sc._module.needmoduleinfo = 1;
         }
index c2967d65d5f4a7d5b52bd4cec6481fd44b1153d2..2916bbc38dd79282abfdd7bf2e426f95473e94c6 100644 (file)
@@ -51,6 +51,7 @@ import dmd.importc;
 import dmd.init;
 import dmd.intrange;
 import dmd.mtype;
+import dmd.mustuse;
 import dmd.nogc;
 import dmd.opover;
 import dmd.parse;
@@ -211,7 +212,8 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
             if (f.checkForwardRef(s.exp.loc))
                 s.exp = ErrorExp.get();
         }
-
+        if (checkMustUse(s.exp, sc))
+            s.exp = ErrorExp.get();
         if (!(sc.flags & SCOPE.Cfile) && discardValue(s.exp))
             s.exp = ErrorExp.get();
 
index 43feab15f22543dcc83f7c7e0dd745baf37c4d99..03e80245a744a0e57422ebf4436d21d1e33ed0cf 100644 (file)
@@ -591,7 +591,7 @@ shared static this() nothrow
     Identifier.initTable();
     foreach (kw; keywords)
     {
-        //printf("keyword[%d] = '%s'\n",kw, tochars[kw].ptr);
+        //printf("keyword[%d] = '%s'\n",kw, Token.tochars[kw].ptr);
         Identifier.idPool(Token.tochars[kw].ptr, Token.tochars[kw].length, cast(uint)kw);
     }
 }
index 4b15e8c4739a4ab5edebbdae4cc714304169345c..04e1c47d16e944c8f1a5ab26f041dc4618a54d49 100644 (file)
@@ -1278,7 +1278,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
             {
                 s = s.isImport().mod;
             }
-            //printf("getAttributes %s, attrs = %p, scope = %p\n", s.toChars(), s.userAttribDecl, s.scope);
+            //printf("getAttributes %s, attrs = %p, scope = %p\n", s.toChars(), s.userAttribDecl, s._scope);
             udad = s.userAttribDecl;
         }
         else
@@ -1514,7 +1514,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
         TypeFunction tf = toTypeFunction(o, fd);
 
         if (tf)
-            link = tf.linkage;
+        {
+            link = fd ? fd.linkage : tf.linkage;
+        }
         else
         {
             auto s = getDsymbol(o);
@@ -1730,69 +1732,33 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
             bool err = false;
 
             auto t = isType(o);
-            while (t)
+            auto ex = isExpression(o);
+            if (t)
             {
-                if (auto tm = t.isTypeMixin())
+                Dsymbol s;
+                t.resolve(e.loc, sc2, ex, t, s);
+                if (t)
                 {
-                    /* The mixin string could be a type or an expression.
-                     * Have to try compiling it to see.
-                     */
-                    OutBuffer buf;
-                    if (expressionsToString(buf, sc, tm.exps))
-                    {
+                    t.typeSemantic(e.loc, sc2);
+                    if (t.ty == Terror)
                         err = true;
-                        break;
-                    }
-                    const olderrors = global.errors;
-                    const len = buf.length;
-                    buf.writeByte(0);
-                    const str = buf.extractSlice()[0 .. len];
-                    scope p = new Parser!ASTCodegen(e.loc, sc._module, str, false);
-                    p.nextToken();
-                    //printf("p.loc.linnum = %d\n", p.loc.linnum);
-
-                    o = p.parseTypeOrAssignExp(TOK.endOfFile);
-                    if (olderrors != global.errors || p.token.value != TOK.endOfFile)
-                    {
-                        err = true;
-                        break;
-                    }
-                    t = o.isType();
                 }
-                else
-                    break;
+                else if (s && s.errors)
+                    err = true;
             }
-
-            if (!err)
+            if (ex)
             {
-                auto ex = t ? t.typeToExpression() : isExpression(o);
-                if (!ex && t)
-                {
-                    Dsymbol s;
-                    t.resolve(e.loc, sc2, ex, t, s);
-                    if (t)
-                    {
-                        t.typeSemantic(e.loc, sc2);
-                        if (t.ty == Terror)
-                            err = true;
-                    }
-                    else if (s && s.errors)
-                        err = true;
-                }
-                if (ex)
+                ex = ex.expressionSemantic(sc2);
+                ex = resolvePropertiesOnly(sc2, ex);
+                ex = ex.optimize(WANTvalue);
+                if (sc2.func && sc2.func.type.ty == Tfunction)
                 {
-                    ex = ex.expressionSemantic(sc2);
-                    ex = resolvePropertiesOnly(sc2, ex);
-                    ex = ex.optimize(WANTvalue);
-                    if (sc2.func && sc2.func.type.ty == Tfunction)
-                    {
-                        const tf = cast(TypeFunction)sc2.func.type;
-                        err |= tf.isnothrow && canThrow(ex, sc2.func, false);
-                    }
-                    ex = checkGC(sc2, ex);
-                    if (ex.op == EXP.error)
-                        err = true;
+                    const tf = cast(TypeFunction)sc2.func.type;
+                    err |= tf.isnothrow && canThrow(ex, sc2.func, false);
                 }
+                ex = checkGC(sc2, ex);
+                if (ex.op == EXP.error)
+                    err = true;
             }
 
             // Carefully detach the scope from the parent and throw it away as
index bcdbec5fe2d5b5a3fd61b46016afefa37c4c2178..b26741242f9ed5c65a7c40060748411ee133e627 100644 (file)
@@ -1220,6 +1220,9 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
             tf.islive = true;
 
         tf.linkage = sc.linkage;
+        if (tf.linkage == LINK.system)
+            tf.linkage = target.systemLinkage();
+
         version (none)
         {
             /* If the parent is @safe, then this function defaults to safe
@@ -2281,10 +2284,7 @@ RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc)
         return null;
     }
 
-    Type t = o.isType();
-    Expression e = t ? t.typeToExpression() : o.isExpression();
-
-    return (!e && t) ? t : e;
+    return o;
 }
 
 
@@ -3619,12 +3619,31 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
                 e.error("`%s` is not an expression", e.toChars());
                 return ErrorExp.get();
             }
-            else if (checkUnsafeDotExp(sc, e, ident, flag))
+            else if (mt.dim.toUInteger() < 1 && checkUnsafeDotExp(sc, e, ident, flag))
             {
+                // .ptr on static array is @safe unless size is 0
+                // https://issues.dlang.org/show_bug.cgi?id=20853
                 return ErrorExp.get();
             }
             e = e.castTo(sc, e.type.nextOf().pointerTo());
         }
+        else if (ident == Id._tupleof)
+        {
+            if (e.isTypeExp())
+            {
+                e.error("`.tupleof` cannot be used on type `%s`", mt.toChars);
+                return ErrorExp.get();
+            }
+            else
+            {
+                const length = cast(size_t)mt.dim.toUInteger();
+                auto exps = new Expressions();
+                exps.reserve(length);
+                foreach (i; 0 .. length)
+                    exps.push(new IndexExp(e.loc, e, new IntegerExp(e.loc, i, Type.tsize_t)));
+                e = new TupleExp(e.loc, exps);
+            }
+        }
         else
         {
             e = visitArray(mt);
index 67e4d86a43e194655822104a41eefd2f1afcde4f..cdfe3cb61aab66da8c703a4a8a50c47c8f941611 100644 (file)
@@ -19,6 +19,7 @@ import dmd.root.filename;
 import dmd.common.outbuffer;
 import dmd.root.string;
 
+nothrow:
 
 /**
  * Normalize path by turning forward slashes into backslashes
@@ -52,13 +53,13 @@ const(char)* toWinPath(const(char)* src)
  *   loc = The line number information from where the call originates
  *   filename = Path to file
  */
-FileBuffer readFile(Loc loc, const(char)* filename)
+Buffer readFile(Loc loc, const(char)* filename)
 {
     return readFile(loc, filename.toDString());
 }
 
 /// Ditto
-FileBuffer readFile(Loc loc, const(char)[] filename)
+Buffer readFile(Loc loc, const(char)[] filename)
 {
     auto result = File.read(filename);
     if (!result.success)
@@ -66,7 +67,7 @@ FileBuffer readFile(Loc loc, const(char)[] filename)
         error(loc, "error reading file `%.*s`", cast(int)filename.length, filename.ptr);
         fatal();
     }
-    return FileBuffer(result.extractSlice());
+    return Buffer(result.extractSlice());
 }
 
 
index 61a2b50b149105b5aa6136f13d2324f7016f2043..c683d9da333da36724998a5bee87385b263de0a2 100644 (file)
@@ -3006,6 +3006,16 @@ public:
     this->result_ = var;
   }
 
+  /* Build an uninitialized value, generated from void initializers.  */
+
+  void visit (VoidInitExp *e)
+  {
+    /* The front-end only generates these for the initializer of globals.
+       Represent `void' as zeroes, regardless of the type's default value.  */
+    gcc_assert (this->constp_);
+    this->result_ = build_zero_cst (build_ctype (e->type));
+  }
+
   /* These expressions are mainly just a placeholders in the frontend.
      We shouldn't see them here.  */
 
index 3c2e90ab8acb82d7872ce68fc25278594fe5b6de..93f05a50c31f71558122cc198f53327cb5b8e9de 100644 (file)
@@ -607,3 +607,13 @@ T throwStuff(T)(T t)
     if (false) test13x(1, throw new Exception(""), 2);
     return t ? t : throw new Exception("Bad stuff happens!");
 }
+
+class C12344
+{
+    abstract int c12344(int x) in(x > 0) out(result) {assert(result > 0);};
+}
+
+interface I12344
+{
+    int i12344(int x) in(x > 0) out(result) {assert(result > 0);};
+}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp17434a.d b/gcc/testsuite/gdc.test/compilable/imports/imp17434a.d
new file mode 100644 (file)
index 0000000..5046cbb
--- /dev/null
@@ -0,0 +1 @@
+module imp17434a.test1;
diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp17434b.d b/gcc/testsuite/gdc.test/compilable/imports/imp17434b.d
new file mode 100644 (file)
index 0000000..88c37ab
--- /dev/null
@@ -0,0 +1,6 @@
+module imp.imports17434b;
+
+void testing()
+{
+    return;
+}
index ff85856b62ed6d3821d09357e434e0a307881817..2c9a84eddfb804ac7185e52a3b8798458bb91871 100644 (file)
@@ -2473,12 +2473,12 @@ static assert(checkPass("foobar") == 1);
 
 struct Toq
 {
-    const(char)* m;
+    char* m;
 }
 
 Toq ptrRet(bool b)
 {
-    string x = "abc";
+    char[] x = "abc".dup;
     return Toq(b ? x[0 .. 1].ptr : null);
 }
 
@@ -7808,3 +7808,101 @@ int test9937()
 }
 
 static assert(test9937());
+
+/************************************************/
+// static array .tupleof
+
+struct SArrayTupleEquiv(T)
+{
+    T f1;
+    T f2;
+}
+
+// basic .tupleof invariants
+bool testSArrayTupleA()
+{
+    int[2] xs;
+    assert(xs.tupleof == TypeTuple!(0, 0));
+    assert(xs.tupleof == (cast(int[2])[0, 0]).tupleof);
+
+    xs.tupleof = TypeTuple!(1, 2);
+    assert(xs.tupleof == TypeTuple!(1, 2));
+
+    auto ys = SArrayTupleEquiv!int(1, 2);
+    assert(xs.tupleof == ys.tupleof);
+
+    return true;
+}
+static assert(testSArrayTupleA());
+
+// tuples with side effects
+bool testSArrayTupleB()
+{
+    // Counter records lifetime events in copies/dtors, as a cheap way to check that .tupleof for
+    // static arrays exhibit all the same side effects as an equivalent struct's .tupleof
+    int[int] copies;
+    int[int] dtors;
+    struct Counter
+    {
+        int id = -1;
+
+        this(this)
+        {
+            copies[id] = copies.get(id, 0) + 1;
+        }
+
+        ~this()
+        {
+            dtors[id] = dtors.get(id, 0) + 1;
+        }
+    }
+
+    void consume(Counter, Counter) {}
+    Counter[2] produce(int id1, int id2)
+    {
+        return [Counter(id1), Counter(id2)];
+    }
+
+    // first sample expected behavior from struct .tupleof
+    // braces create a subscope, shortening lifetimes
+    {
+        auto a = SArrayTupleEquiv!Counter(Counter(0), Counter(1));
+
+        typeof(a) b;
+        b.tupleof = a.tupleof;
+
+        Counter x, y;
+        TypeTuple!(x, y) = a.tupleof;
+
+        a.tupleof[0] = Counter(2);
+        a.tupleof[1] = Counter(3);
+        consume(a.tupleof);
+
+        a.tupleof = produce(4, 5).tupleof;
+    }
+    int[int][2] expected = [copies.dup, dtors.dup];
+    copies = null; // .clear is not CTFE friendly
+    dtors = null;
+
+    // the real test -- sample behavior of array .tupleof
+    {
+        Counter[2] a = [Counter(0), Counter(1)];
+
+        typeof(a) b;
+        b.tupleof = a.tupleof;
+
+        Counter x, y;
+        TypeTuple!(x, y) = a.tupleof;
+
+        a.tupleof[0] = Counter(2);
+        a.tupleof[1] = Counter(3);
+        consume(a.tupleof);
+
+        a.tupleof = produce(4, 5).tupleof;
+    }
+    assert(expected[0] == copies);
+    assert(expected[1] == dtors);
+
+    return true;
+}
+static assert(testSArrayTupleB());
index 73d3101b8356bfb33116c3e19c92822af1054648..f4d68e7dc8c6ef13bbeb3ad2c90924012c878926 100644 (file)
@@ -203,14 +203,14 @@ extern(C) int vlinakgeC;
 extern(C++) __gshared int vlinkageCpp;
 extern(Windows) int vlinkageWindows;
 extern(Objective-C) int vlinkageObjc;
-
+extern(System) int vlinkageSystem;
 extern int flinkageDefault();
 extern(D) int flinkageD();
 extern(C) int linakgeC();
 extern(C++) int flinkageCpp();
 extern(Windows) int flinkageWindows();
 extern(Objective-C) int flinkageObjc();
-
+extern(System) int flinkageSystem();
 mixin template test18211(int n)
 {
     static foreach (i; 0 .. n>10 ? 10 : n)
index d160bd410ad16511f8b0d5ec7f251210a96786b7..a61adc570fa885de50087f3514eea647447e2e80 100644 (file)
@@ -115,3 +115,9 @@ void test_statements_22356()
     mixin("int") y22356, z22356;
     static assert(is(typeof(y22356) == int) && is(typeof(z22356) == int));
 }
+
+/**************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=22969
+
+enum e = 0;
+alias a = mixin("e");
diff --git a/gcc/testsuite/gdc.test/compilable/must_use_assign.d b/gcc/testsuite/gdc.test/compilable/must_use_assign.d
new file mode 100644 (file)
index 0000000..bd1983a
--- /dev/null
@@ -0,0 +1,9 @@
+import core.attribute;
+
+@mustuse struct S {}
+
+void test()
+{
+    S a, b;
+    a = b;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/must_use_not_reserved.d b/gcc/testsuite/gdc.test/compilable/must_use_not_reserved.d
new file mode 100644 (file)
index 0000000..c600119
--- /dev/null
@@ -0,0 +1,5 @@
+import core.attribute;
+
+@mustuse int n;
+@mustuse alias A = int;
+@mustuse template tpl() {}
diff --git a/gcc/testsuite/gdc.test/compilable/must_use_opassign.d b/gcc/testsuite/gdc.test/compilable/must_use_opassign.d
new file mode 100644 (file)
index 0000000..8e877dd
--- /dev/null
@@ -0,0 +1,15 @@
+import core.attribute;
+
+@mustuse struct S
+{
+    ref S opAssign(S rhs) return
+    {
+        return this;
+    }
+}
+
+void test()
+{
+    S a, b;
+    a = b;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/must_use_opopassign.d b/gcc/testsuite/gdc.test/compilable/must_use_opopassign.d
new file mode 100644 (file)
index 0000000..0176354
--- /dev/null
@@ -0,0 +1,15 @@
+import core.attribute;
+
+@mustuse struct S
+{
+    ref S opOpAssign(string op)(S rhs) return
+    {
+        return this;
+    }
+}
+
+void test()
+{
+    S a, b;
+    a += b;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/must_use_opunary.d b/gcc/testsuite/gdc.test/compilable/must_use_opunary.d
new file mode 100644 (file)
index 0000000..fc9650e
--- /dev/null
@@ -0,0 +1,18 @@
+import core.attribute;
+
+@mustuse struct S
+{
+    ref S opUnary(string op)() return
+    {
+        return this;
+    }
+}
+
+void test()
+{
+    S s;
+    ++s;
+    --s;
+    s++;
+    s--;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/must_use_suppress.d b/gcc/testsuite/gdc.test/compilable/must_use_suppress.d
new file mode 100644 (file)
index 0000000..63ad75c
--- /dev/null
@@ -0,0 +1,10 @@
+import core.attribute;
+
+@mustuse struct S {}
+
+S fun() { return S(); }
+
+void test()
+{
+    cast(void) fun();
+}
index e34e7da54446c1f4a8f24ab78831c385b4713e71..1a92a1c9112a2e32d2e79bd99dba2e0310a2033f 100644 (file)
@@ -17,10 +17,7 @@ static assert(__traits(getLinkage, food) == "D");
 static assert(__traits(getLinkage, foocpp) == "C++");
 static assert(__traits(getLinkage, foow) == "Windows");
 static assert(__traits(getLinkage, fooobjc) == "Objective-C");
-version (Windows)
-    static assert(__traits(getLinkage, foos) == "Windows");
-else
-    static assert(__traits(getLinkage, foos) == "C");
+static assert(__traits(getLinkage, foos) == "System");
 
 extern (C) int global;
 static assert(__traits(getLinkage, global) == "C");
diff --git a/gcc/testsuite/gdc.test/compilable/test17434.d b/gcc/testsuite/gdc.test/compilable/test17434.d
new file mode 100644 (file)
index 0000000..82bfa57
--- /dev/null
@@ -0,0 +1,11 @@
+// https://issues.dlang.org/show_bug.cgi?id=17434
+
+// EXTRA_FILES: test17434a.d imports/imp17434a.d imports/imp17434b.d
+module test17434;
+
+import test17434a;
+
+void main()
+{
+    imports.imp17434b.testing();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test17434a.d b/gcc/testsuite/gdc.test/compilable/test17434a.d
new file mode 100644 (file)
index 0000000..c9175fe
--- /dev/null
@@ -0,0 +1,5 @@
+// EXTRA_FILES: imports/imp17434a.d imports/imp17434b.d
+module test17434a;
+
+private import imports.imp17434a;
+public  import imports.imp17434b;
index 19e189caf5dd5bb9d2116d96b4862c508f3be02c..a6d300248816d8788e8a6317ce2c54eba661a260 100644 (file)
@@ -21,3 +21,43 @@ void foo(scope int* pf)
     betty(rf, pf);
     boop(rf, pf);
 }
+
+// https://issues.dlang.org/show_bug.cgi?id=22801
+struct Wrapper
+{
+    int* ptr;
+
+    this(return ref int var) @safe
+    {
+        this.ptr = &var;
+    }
+}
+
+void main() @safe
+{
+    int i;
+    auto w = Wrapper(i);
+    auto wt = WrapperT!()(i);
+}
+
+void assign(ref scope int* x, return ref int y) @safe
+{
+    x = &y;
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=22967
+// inference of `return ref` when assigned to first parameter
+struct WrapperT()
+{
+    int* ptr;
+
+    this(ref int var) @safe
+    {
+        this.ptr = &var;
+    }
+
+    static void assignInferred(ref scope int* xi, ref int yi) @safe
+    {
+        xi = &yi;
+    }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test22988.d b/gcc/testsuite/gdc.test/compilable/test22988.d
new file mode 100644 (file)
index 0000000..6be3921
--- /dev/null
@@ -0,0 +1,15 @@
+// https://issues.dlang.org/show_bug.cgi?id=22988
+
+enum a1 = 0;
+enum b1 = a1 ? 1 << a1 - 1 : 0;
+
+enum l = 0;
+enum int[l] a2 = [];
+enum b2 = l ? a2[l - 1] : 0;
+
+enum a3 = 0 ? 1 << -1 : 0;
+
+enum int[0] a4 = [];
+enum b4 = 0 ? a4[0] : 0;
+
+enum b5 = false ? (1 << -1) : 0;
diff --git a/gcc/testsuite/gdc.test/compilable/test22997.d b/gcc/testsuite/gdc.test/compilable/test22997.d
new file mode 100644 (file)
index 0000000..3cad527
--- /dev/null
@@ -0,0 +1,14 @@
+// https://issues.dlang.org/show_bug.cgi?id=22997
+
+struct Forward {}
+
+struct Foo
+{
+    this(ref typeof(this) rhs)
+    {
+        this(rhs, Forward.init);
+    }
+
+    this(ref typeof(this) rhs, Forward) {}
+    this(typeof(this) rhs, int i, double d, string s) {}
+}
index 3c8a98e6e3551de852174e9b47ca2fcb41b4c8f9..29261b4ea1c266f4a3fae67a5c5f971bfda52607 100644 (file)
@@ -2,8 +2,8 @@
 EXTRA_FILES: imports/a14235.d
 TEST_OUTPUT:
 ---
-fail_compilation/diag14235.d(12): Error: template identifier `Undefined` is not a member of module `imports.a14235`
-fail_compilation/diag14235.d(13): Error: template identifier `Something` is not a member of module `imports.a14235`, did you mean struct `SomeThing(T...)`?
+fail_compilation/diag14235.d(12): Error: undefined identifier `Undefined` in module `imports.a14235`
+fail_compilation/diag14235.d(13): Error: undefined identifier `Something` in module `imports.a14235`, did you mean struct `SomeThing(T...)`?
 fail_compilation/diag14235.d(14): Error: `imports.a14235.SomeClass` is not a template, it is a class
 ---
 */
index 282665ff8d517aa6bf5242415ce7a45d74dc6a79..301472ca28a89a1a5d3f377ac67f32365c0f6c67 100644 (file)
@@ -2,7 +2,7 @@
 TEST_OUTPUT:
 ---
 fail_compilation/diag8101.d(57): Error: function `diag8101.f_0(int)` is not callable using argument types `()`
-fail_compilation/diag8101.d(57):        missing argument for parameter #1: `int`
+fail_compilation/diag8101.d(57):        too few arguments, expected `1`, got `0`
 fail_compilation/diag8101.d(58): Error: none of the overloads of `f_1` are callable using argument types `()`
 fail_compilation/diag8101.d(33):        Candidates are: `diag8101.f_1(int)`
 fail_compilation/diag8101.d(34):                        `diag8101.f_1(int, int)`
index b46c562e87d3c88fbd4acec0986b6e3a65bd069a..1279d7c2a2a8eb6f9a4c39935665436cafd69e47 100644 (file)
@@ -2,7 +2,7 @@
 TEST_OUTPUT:
 ---
 fail_compilation/diag_funclit.d(103): Error: function literal `__lambda1(x, y, z)` is not callable using argument types `()`
-fail_compilation/diag_funclit.d(103):        missing argument for parameter #1: `x`
+fail_compilation/diag_funclit.d(103):        too few arguments, expected `3`, got `0`
 fail_compilation/diag_funclit.d(106): Error: function literal `__lambda2(x, y, z)` is not callable using argument types `(int, string, int, int)`
 fail_compilation/diag_funclit.d(106):        too many arguments, expected `3`, got `4`
 fail_compilation/diag_funclit.d(108): Error: function literal `__lambda3(x, y, string z = "Hello")` is not callable using argument types `(int, int, string, string)`
index eb88a23151a76b4d71cdbbe8c4fee8e8ac72cabd..1418ced43a2558b565a387031b0e8f84f4d0076a 100644 (file)
@@ -3,7 +3,7 @@ PERMUTE_ARGS: -preview=in
 TEST_OUTPUT:
 ---
 fail_compilation/diagin.d(14): Error: function `diagin.foo(in int)` is not callable using argument types `()`
-fail_compilation/diagin.d(14):        missing argument for parameter #1: `in int`
+fail_compilation/diagin.d(14):        too few arguments, expected `1`, got `0`
 fail_compilation/diagin.d(16): Error: none of the overloads of template `diagin.foo1` are callable using argument types `!()(bool[])`
 fail_compilation/diagin.d(20):        Candidate is: `foo1(T)(in T v, string)`
 ---
index ffd38de4502db556ea32534be0a4524cf2b051d2..520c1b14bfb95fa9f092cbb2dcf6742719b6067c 100644 (file)
@@ -1,20 +1,20 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail2656.d(21): Error: octal literals `0123` are no longer supported, use `std.conv.octal!123` instead
-fail_compilation/fail2656.d(22): Error: octal literals `01000000000000000000000` are no longer supported, use `std.conv.octal!1000000000000000000000` instead
-fail_compilation/fail2656.d(23): Error: octal literals `0100000L` are no longer supported, use `std.conv.octal!100000L` instead
-fail_compilation/fail2656.d(24): Error: octal literals `01777777777777777777777u` are no longer supported, use `std.conv.octal!1777777777777777777777u` instead
-fail_compilation/fail2656.d(25): Error: octal literals `017777777777uL` are no longer supported, use `std.conv.octal!17777777777uL` instead
-fail_compilation/fail2656.d(26): Error: octal literals `0177777` are no longer supported, use `std.conv.octal!177777` instead
-fail_compilation/fail2656.d(27): Error: octal literals `020000000000L` are no longer supported, use `std.conv.octal!20000000000L` instead
-fail_compilation/fail2656.d(28): Error: octal literals `0200000u` are no longer supported, use `std.conv.octal!200000u` instead
-fail_compilation/fail2656.d(29): Error: octal literals `037777777777uL` are no longer supported, use `std.conv.octal!37777777777uL` instead
-fail_compilation/fail2656.d(30): Error: octal literals `040000000000` are no longer supported, use `std.conv.octal!40000000000` instead
-fail_compilation/fail2656.d(31): Error: octal literals `0777777777777777777777L` are no longer supported, use `std.conv.octal!777777777777777777777L` instead
-fail_compilation/fail2656.d(32): Error: octal literals `077777u` are no longer supported, use `std.conv.octal!77777u` instead
-fail_compilation/fail2656.d(33): Error: octal literals `077777uL` are no longer supported, use `std.conv.octal!77777uL` instead
-fail_compilation/fail2656.d(34): Error: octal literals `077777uL` are no longer supported, use `std.conv.octal!77777uL` instead
+fail_compilation/fail2656.d(21): Error: octal literals `0123` are no longer supported, use `std.conv.octal!"123"` instead
+fail_compilation/fail2656.d(22): Error: octal literals `01000000000000000000000` are no longer supported, use `std.conv.octal!"1000000000000000000000"` instead
+fail_compilation/fail2656.d(23): Error: octal literals `0100000L` are no longer supported, use `std.conv.octal!"100000L"` instead
+fail_compilation/fail2656.d(24): Error: octal literals `01777777777777777777777u` are no longer supported, use `std.conv.octal!"1777777777777777777777u"` instead
+fail_compilation/fail2656.d(25): Error: octal literals `017777777777uL` are no longer supported, use `std.conv.octal!"17777777777uL"` instead
+fail_compilation/fail2656.d(26): Error: octal literals `0177777` are no longer supported, use `std.conv.octal!"177777"` instead
+fail_compilation/fail2656.d(27): Error: octal literals `020000000000L` are no longer supported, use `std.conv.octal!"20000000000L"` instead
+fail_compilation/fail2656.d(28): Error: octal literals `0200000u` are no longer supported, use `std.conv.octal!"200000u"` instead
+fail_compilation/fail2656.d(29): Error: octal literals `037777777777uL` are no longer supported, use `std.conv.octal!"37777777777uL"` instead
+fail_compilation/fail2656.d(30): Error: octal literals `040000000000` are no longer supported, use `std.conv.octal!"40000000000"` instead
+fail_compilation/fail2656.d(31): Error: octal literals `0777777777777777777777L` are no longer supported, use `std.conv.octal!"777777777777777777777L"` instead
+fail_compilation/fail2656.d(32): Error: octal literals `077777u` are no longer supported, use `std.conv.octal!"77777u"` instead
+fail_compilation/fail2656.d(33): Error: octal literals `077777uL` are no longer supported, use `std.conv.octal!"77777uL"` instead
+fail_compilation/fail2656.d(34): Error: octal literals `077777uL` are no longer supported, use `std.conv.octal!"77777uL"` instead
 ---
 */
 
index c147b810ee6754654d36c23e90c3339770ffaa15..e4cba9530bfcb8f5c2159ad1a64d81ddb93832e1 100644 (file)
@@ -2,7 +2,7 @@
 TEST_OUTPUT:
 ---
 fail_compilation/fail99.d(13): Error: delegate `dg(int)` is not callable using argument types `()`
-fail_compilation/fail99.d(13):        missing argument for parameter #1: `int`
+fail_compilation/fail99.d(13):        too few arguments, expected `1`, got `0`
 ---
 */
 
index 0be003a2f3b73a614c93bdd17682cf9e3a8aef4f..b6bd9d33cf91e0d8bc20e1a33e2cc691f601569c 100644 (file)
@@ -5,7 +5,7 @@ fail_compilation/fix19059.d(16): Error: octal digit expected, not `8`
 fail_compilation/fix19059.d(16): Error: octal literals larger than 7 are no longer supported
 fail_compilation/fix19059.d(17): Error: octal digit expected, not `9`
 fail_compilation/fix19059.d(17): Error: octal literals larger than 7 are no longer supported
-fail_compilation/fix19059.d(18): Error: octal literals `010` are no longer supported, use `std.conv.octal!10` instead
+fail_compilation/fix19059.d(18): Error: octal literals `010` are no longer supported, use `std.conv.octal!"10"` instead
 ---
  */
 
index c227ee55eb4f18cf55dc02a7e68a17216d9bdceb..f3a7a57a689546d188ec1172b23f4c5fa6748f3d 100644 (file)
@@ -2,7 +2,7 @@
 TEST_OUTPUT:
 ---
 fail_compilation/ice10922.d(10): Error: function `ice10922.__lambda4(in uint n)` is not callable using argument types `()`
-fail_compilation/ice10922.d(10):        missing argument for parameter #1: `in uint n`
+fail_compilation/ice10922.d(10):        too few arguments, expected `1`, got `0`
 ---
 */
 
index f95cb974c79b11ad5bd863903507303727a6f8f4..ce705078ac0c2791180e9173a94e4a5ca81b1228 100644 (file)
@@ -2,7 +2,7 @@
 TEST_OUTPUT:
 ---
 fail_compilation/ice9540.d(35): Error: function `ice9540.A.test.AddFront!(this, f).AddFront.dg(int _param_0)` is not callable using argument types `()`
-fail_compilation/ice9540.d(35):        missing argument for parameter #1: `int _param_0`
+fail_compilation/ice9540.d(35):        too few arguments, expected `1`, got `0`
 fail_compilation/ice9540.d(26): Error: template instance `ice9540.A.test.AddFront!(this, f)` error instantiating
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/must_use.d b/gcc/testsuite/gdc.test/fail_compilation/must_use.d
new file mode 100644 (file)
index 0000000..e3b5fed
--- /dev/null
@@ -0,0 +1,16 @@
+/+
+TEST_OUTPUT:
+---
+fail_compilation/must_use.d(15): Error: ignored value of `@mustuse` type `must_use.S`; prepend a `cast(void)` if intentional
+---
++/
+import core.attribute;
+
+@mustuse struct S {}
+
+S fun() { return S(); }
+
+void test()
+{
+    fun();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/must_use_comma.d b/gcc/testsuite/gdc.test/fail_compilation/must_use_comma.d
new file mode 100644 (file)
index 0000000..4621ab5
--- /dev/null
@@ -0,0 +1,17 @@
+/+
+TEST_OUTPUT:
+---
+fail_compilation/must_use_comma.d(16): Error: ignored value of `@mustuse` type `must_use_comma.S`; prepend a `cast(void)` if intentional
+---
++/
+import core.attribute;
+
+@mustuse struct S {}
+
+S fun() { return S(); }
+void sideEffect() {}
+
+void test()
+{
+    (fun(), sideEffect());
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/must_use_opunary.d b/gcc/testsuite/gdc.test/fail_compilation/must_use_opunary.d
new file mode 100644 (file)
index 0000000..59248a9
--- /dev/null
@@ -0,0 +1,21 @@
+/+
+TEST_OUTPUT:
+---
+fail_compilation/must_use_opunary.d(20): Error: ignored value of `@mustuse` type `must_use_opunary.S`; prepend a `cast(void)` if intentional
+---
++/
+import core.attribute;
+
+@mustuse struct S
+{
+    ref S opUnary(string op)() return
+    {
+        return this;
+    }
+}
+
+void test()
+{
+    S s;
+    -s;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/must_use_reserved.d b/gcc/testsuite/gdc.test/fail_compilation/must_use_reserved.d
new file mode 100644 (file)
index 0000000..96edbd3
--- /dev/null
@@ -0,0 +1,20 @@
+/+
+TEST_OUTPUT:
+---
+fail_compilation/must_use_reserved.d(14): Error: `@mustuse` on `class` types is reserved for future use
+fail_compilation/must_use_reserved.d(15): Error: `@mustuse` on `interface` types is reserved for future use
+fail_compilation/must_use_reserved.d(16): Error: `@mustuse` on `enum` types is reserved for future use
+fail_compilation/must_use_reserved.d(17): Error: `@mustuse` on functions is reserved for future use
+fail_compilation/must_use_reserved.d(19): Error: `@mustuse` on `class` types is reserved for future use
+fail_compilation/must_use_reserved.d(20): Error: template instance `must_use_reserved.CT!int` error instantiating
+---
++/
+import core.attribute;
+
+@mustuse class C {}
+@mustuse interface I {}
+@mustuse enum E { x }
+@mustuse int fun() { return 0; }
+
+@mustuse class CT(T) {}
+alias _ = CT!int;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/must_use_template.d b/gcc/testsuite/gdc.test/fail_compilation/must_use_template.d
new file mode 100644 (file)
index 0000000..eeaa774
--- /dev/null
@@ -0,0 +1,16 @@
+/+
+TEST_OUTPUT:
+---
+fail_compilation/must_use_template.d(15): Error: ignored value of `@mustuse` type `must_use_template.S!int`; prepend a `cast(void)` if intentional
+---
++/
+import core.attribute;
+
+@mustuse struct S(T) {}
+
+S!int fun() { return S!int(); }
+
+void test()
+{
+    fun();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/must_use_union.d b/gcc/testsuite/gdc.test/fail_compilation/must_use_union.d
new file mode 100644 (file)
index 0000000..d42b324
--- /dev/null
@@ -0,0 +1,16 @@
+/+
+TEST_OUTPUT:
+---
+fail_compilation/must_use_union.d(15): Error: ignored value of `@mustuse` type `must_use_union.U`; prepend a `cast(void)` if intentional
+---
++/
+import core.attribute;
+
+@mustuse union U {}
+
+U fun() { return U(); }
+
+void test()
+{
+    fun();
+}
index cf60b80fd7a2affff18a9fed660f2dc1d41619e1..5ef7324ce8ca8a94f0ada34077fa018dd99214de 100644 (file)
@@ -12,6 +12,10 @@ fail_compilation/test11176.d(16): Error: `b.ptr` cannot be used in `@safe` code,
     return *b.ptr;
 }
 
-@safe ubyte oops(ubyte[3] b) {
+@safe ubyte oops(ubyte[0] b) {
+    return *b.ptr;
+}
+
+@safe ubyte cool(ubyte[1] b) {
     return *b.ptr;
 }
index 713be42e595284fb34f5a5a219f714ea553dcce8..5bb3c2cc9f6dacf558c6141e41592236ae772e45 100644 (file)
@@ -1,8 +1,8 @@
+/*
 TEST_OUTPUT:
 ---
-fail_compilation/test17284.d(1): Error: no identifier for declarator `TEST_OUTPUT`
-fail_compilation/test17284.d(1): Error: declaration expected, not `:`
-fail_compilation/test17284.d(12): Error: unmatched closing brace
+fail_compilation/test17284.d(16): Error: field `U.c` cannot access pointers in `@safe` code that overlap other fields
+pure nothrow @safe void(U t)
 ---
 */
 
index 034813b5316c06feae39396232ac662a185789f7..9c025a83ff052210c1015a84adb923eed4c3aee5 100644 (file)
@@ -1,12 +1,19 @@
 /* REQUIRED_ARGS: -preview=dip1000
  * TEST_OUTPUT:
 ---
-fail_compilation/test19097.d(37): Error: scope variable `s` may not be returned
-fail_compilation/test19097.d(66): Error: scope variable `z` assigned to `refPtr` with longer lifetime
-fail_compilation/test19097.d(97): Error: scope variable `s` may not be returned
+fail_compilation/test19097.d(44): Error: scope variable `s` may not be returned
+fail_compilation/test19097.d(48): Error: scope variable `s1` may not be returned
+fail_compilation/test19097.d(77): Error: scope variable `z` assigned to `refPtr` with longer lifetime
+fail_compilation/test19097.d(108): Error: scope variable `s4` may not be returned
+fail_compilation/test19097.d(126): Error: scope variable `s5c` may not be returned
+fail_compilation/test19097.d(130): Error: scope variable `s5m` may not be returned
+fail_compilation/test19097.d(147): Error: scope variable `s6c` may not be returned
+fail_compilation/test19097.d(151): Error: scope variable `s6m` may not be returned
 ---
  */
 
+// Test extended return-scope / return-ref semantics, e.g. assigning to `this` or the first parameter
+
 // https://issues.dlang.org/show_bug.cgi?id=19097
 
 @safe:
@@ -35,6 +42,10 @@ S thorin()
     int i;
     S s = S(&i); // should infer scope for s
     return s;    // so this should error
+
+    S s1;
+    s1.mem(&i);
+    return s1;
 }
 
 /************************/
@@ -93,6 +104,49 @@ struct S4
 int* escape2()
 {
     int x;
-    auto s = S4(0, &x);
-    return s.p;
+    auto s4 = S4(0, &x);
+    return s4.p;
+}
+
+/************************/
+// https://issues.dlang.org/show_bug.cgi?id=22801
+struct S5
+{
+    int* a;
+    this(return ref int b) { a = &b; }
+
+    int* c;
+    void mem(return ref int d) scope { c = &d; }
+}
+
+S5 frerin()
+{
+    int i;
+    S5 s5c = S5(i); // should infer scope for s
+    return s5c;    // so this should error
+
+    S5 s5m;
+    s5m.mem(i);
+    return s5m;
+}
+
+
+struct S6
+{
+    int** a;
+    this(return ref int* b) { a = &b; }
+
+    int** c;
+    void mem(return ref int* d) scope { c = &d; }
+}
+
+S6 dis()
+{
+    int* i = null;
+    S6 s6c = S6(i); // should infer scope for s
+    return s6c;    // so this should error
+
+    S6 s6m;
+    s6m.mem(i);
+    return s6m;
 }
index d5cf96a6c3ac985686afa68302918dc18dcab694..998cf1752d0269b547e8f09e8a0f25114615aeab 100644 (file)
@@ -5,12 +5,12 @@ fail_compilation/test21008.d(110): Error: function `test21008.C.after` circular
 fail_compilation/test21008.d(117): Error: need `this` for `toString` of type `string()`
 fail_compilation/test21008.d(117): Error: need `this` for `toHash` of type `nothrow @trusted $?:32=uint|64=ulong$()`
 fail_compilation/test21008.d(117): Error: function `object.Object.opCmp(Object o)` is not callable using argument types `()`
-fail_compilation/test21008.d(117):        missing argument for parameter #1: `Object o`
+fail_compilation/test21008.d(117):        too few arguments, expected `1`, got `0`
 fail_compilation/test21008.d(117): Error: function `object.Object.opEquals(Object o)` is not callable using argument types `()`
-fail_compilation/test21008.d(117):        missing argument for parameter #1: `Object o`
+fail_compilation/test21008.d(117):        too few arguments, expected `1`, got `0`
 fail_compilation/test21008.d(117): Error: `Monitor` has no effect
 fail_compilation/test21008.d(117): Error: function `object.Object.factory(string classname)` is not callable using argument types `()`
-fail_compilation/test21008.d(117):        missing argument for parameter #1: `string classname`
+fail_compilation/test21008.d(117):        too few arguments, expected `1`, got `0`
 fail_compilation/test21008.d(105):        called from here: `handleMiddlewareAnnotation()`
 fail_compilation/test21008.d(108): Error: class `test21008.C` no size because of forward reference
 ---
diff --git a/gcc/testsuite/gdc.test/runnable/test20603.d b/gcc/testsuite/gdc.test/runnable/test20603.d
new file mode 100644 (file)
index 0000000..47fd398
--- /dev/null
@@ -0,0 +1,31 @@
+// https://issues.dlang.org/show_bug.cgi?id=20603
+
+enum immutable(int)* x = new int(3);
+enum const(int)* y = new int(5);
+
+struct Base {
+    union {
+        int overlap;
+        immutable(Sub)* sub;
+    }
+
+    this(Sub) {
+        sub = new Sub;
+    }
+}
+
+struct Sub {
+    Base base;
+}
+
+immutable c0 = Base(Sub.init);
+
+void main()
+{
+    enum const(int)* z = new int(9);
+
+    assert(*x == 3);
+    assert(*y == 5);
+    assert(*z == 9);
+    assert(c0.sub.base.sub == null);
+}
index eeaa1dbe72d3f9ba69a075796843bc8ad4c47ab9..8ae08ad2e47e148920e75dc881862db448ee2b58 100644 (file)
@@ -3816,8 +3816,8 @@ void test153()
 /***************************************************/
 // https://issues.dlang.org/show_bug.cgi?id=3632
 
-
-void test154() {
+void test154()
+{
     float f;
     assert(f is float.init);
     double d;
@@ -3832,6 +3832,87 @@ void test154() {
 
 /***************************************************/
 
+__gshared int global3632 = 1;
+
+void test3632()
+{
+    int test(T)()
+    {
+        static struct W
+        {
+            T f;
+            this(T g) { if (__ctfe || global3632) f = g; }
+        }
+        auto nan = W(T.nan);
+        auto nan2 = W(T.nan);
+        auto init = W(T.init);
+        auto init2 = W(T.init);
+        auto zero = W(cast(T)0);
+        auto zero2 = W(cast(T)0);
+        auto nzero2 = W(-cast(T)0);
+
+        // Struct equality
+        assert(!(nan == nan2));
+        assert(!(nan == init2));
+        assert(!(init == init2));
+        assert( (zero == zero2));
+        assert( (zero == nzero2));
+
+        // Float equality
+        assert(!(nan.f == nan2.f));
+        assert(!(nan.f == init2.f));
+        assert(!(init.f == init2.f));
+        assert( (zero.f == zero2.f));
+        assert( (zero.f == nzero2.f));
+
+        // Struct identity
+        assert( (nan is nan2));
+        assert( (nan is init2));
+        assert( (init is init2));
+        assert( (zero is zero2));
+        assert(!(zero is nzero2));
+
+        // Float identity
+        assert( (nan.f is nan2.f));
+        assert( (nan.f is init2.f));
+        assert( (init.f is init2.f));
+        assert( (zero.f is zero2.f));
+        assert(!(zero.f is nzero2.f));
+
+        // Struct !identity
+        assert(!(nan !is nan2));
+        assert( (nan  is init2));
+        assert(!(init !is init2));
+        assert(!(zero !is zero2));
+        assert( (zero !is nzero2));
+
+        // float !identity
+        assert(!(nan.f !is nan2.f));
+        assert( (nan.f is init2.f));
+        assert(!(init.f !is init2.f));
+        assert(!(zero.f !is zero2.f));
+        assert( (zero.f !is nzero2.f));
+
+        // .init identity
+        assert(W.init is W.init);
+
+        return 1;
+    }
+
+    auto rtF = test!float();
+    enum ctF = test!float();
+    auto rtD = test!double();
+    enum ctD = test!double();
+    auto rtR = test!real();
+    enum ctR = test!real();
+
+    assert(float.nan !is -float.nan);
+    assert(double.nan !is -double.nan);
+    assert(real.nan !is -real.nan);
+}
+
+/***************************************************/
+
 void test6545()
 {
     static int[] func()
@@ -8142,6 +8223,7 @@ int main()
     test155();
     test156();
     test658();
+    test3632();
     test4258();
     test4539();
     test4963();
index b1da32e43e1c6dc90a2124c33a7d189ba9c0f449..5e2566c9ceb99288b94c04ea04759f13a76ed2fc 100644 (file)
@@ -1,4 +1,4 @@
-c52e28b723ccfbe845a95e8e7b528e3cc0b9d790
+9ba9a6ae2b8f6811cb85107cb56701df04f36ac6
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/druntime repository.
index 2f628c031387f4f3b7ac0e7a3332edf589e570a7..e4326fd54c36e6aaab602ef16224834c2836421b 100644 (file)
@@ -18,15 +18,26 @@ alias I = long;
 alias U = ulong;
 enum Ubits = uint(U.sizeof * 8);
 
-align(16) struct Cent
+version (X86_64) private enum Cent_alignment = 16;
+else             private enum Cent_alignment = (size_t.sizeof * 2);
+
+align(Cent_alignment) struct Cent
 {
-    U lo;      // low 64 bits
-    U hi;      // high 64 bits
+    version (LittleEndian)
+    {
+        U lo;  // low 64 bits
+        U hi;  // high 64 bits
+    }
+    else
+    {
+        U hi;  // high 64 bits
+        U lo;  // low 64 bits
+    }
 }
 
-enum One = Cent(1);
-enum Zero = Cent();
-enum MinusOne = neg(One);
+enum Cent One = { lo:1 };
+enum Cent Zero = { lo:0 };
+enum Cent MinusOne = neg(One);
 
 /*****************************
  * Test against 0
@@ -320,7 +331,8 @@ Cent ror(Cent c, uint n)
 pure
 Cent and(Cent c1, Cent c2)
 {
-    return Cent(c1.lo & c2.lo, c1.hi & c2.hi);
+    const Cent ret = { lo:c1.lo & c2.lo, hi:c1.hi & c2.hi };
+    return ret;
 }
 
 /****************************
@@ -334,7 +346,8 @@ Cent and(Cent c1, Cent c2)
 pure
 Cent or(Cent c1, Cent c2)
 {
-    return Cent(c1.lo | c2.lo, c1.hi | c2.hi);
+    const Cent ret = { lo:c1.lo | c2.lo, hi:c1.hi | c2.hi };
+    return ret;
 }
 
 /****************************
@@ -348,7 +361,8 @@ Cent or(Cent c1, Cent c2)
 pure
 Cent xor(Cent c1, Cent c2)
 {
-    return Cent(c1.lo ^ c2.lo, c1.hi ^ c2.hi);
+    const Cent ret = { lo:c1.lo ^ c2.lo, hi:c1.hi ^ c2.hi };
+    return ret;
 }
 
 /****************************
@@ -363,7 +377,8 @@ pure
 Cent add(Cent c1, Cent c2)
 {
     U r = cast(U)(c1.lo + c2.lo);
-    return Cent(r, cast(U)(c1.hi + c2.hi + (r < c1.lo)));
+    const Cent ret = { lo:r, hi:cast(U)(c1.hi + c2.hi + (r < c1.lo)) };
+    return ret;
 }
 
 /****************************
@@ -419,9 +434,9 @@ Cent mul(Cent c1, Cent c2)
     const c1h1 = c1.hi >> mulshift;
     r3 = c1h1 * c2l0 + (r3 & mulmask);
 
-    return Cent((r0 & mulmask) + (r1 & mulmask) * (mulmask + 1),
-                (r2 & mulmask) + (r3 & mulmask) * (mulmask + 1));
-
+    const Cent ret = { lo:(r0 & mulmask) + (r1 & mulmask) * (mulmask + 1),
+                       hi:(r2 & mulmask) + (r3 & mulmask) * (mulmask + 1) };
+    return ret;
 }
 
 
@@ -523,8 +538,10 @@ Cent udivmod(Cent c1, Cent c2, out Cent modulus)
     if (c1.hi == 0 && c2.hi == 0)
     {
         // Single precision divide
-        modulus = Cent(c1.lo % c2.lo);
-        return Cent(c1.lo / c2.lo);
+        const Cent rem = { lo:c1.lo % c2.lo };
+        modulus = rem;
+        const Cent ret = { lo:c1.lo / c2.lo };
+        return ret;
     }
     if (c1.hi == 0)
     {
@@ -539,10 +556,11 @@ Cent udivmod(Cent c1, Cent c2, out Cent modulus)
         const q1 = (c1.hi < c2.lo) ? 0 : (c1.hi / c2.lo);
         if (q1)
             c1.hi = c1.hi % c2.lo;
-        U rem;
-        const q0 = udivmod128_64(c1, c2.lo, rem);
-        modulus = Cent(rem);
-        return Cent(q0, q1);
+        Cent rem;
+        const q0 = udivmod128_64(c1, c2.lo, rem.lo);
+        modulus = rem;
+        const Cent ret = { lo:q0, hi:q1 };
+        return ret;
     }
 
     // Full cent precision division.
@@ -560,10 +578,10 @@ Cent udivmod(Cent c1, Cent c2, out Cent modulus)
 
     // Get quotient from divide unsigned operation.
     U rem_ignored;
-    const q1 = udivmod128_64(u1, v1, rem_ignored);
+    const Cent q1 = { lo:udivmod128_64(u1, v1, rem_ignored) };
 
     // Undo normalization and division of c1 by 2.
-    Cent quotient = shr(shl(Cent(q1), shift), 63);
+    Cent quotient = shr(shl(q1, shift), 63);
 
     // Make quotient correct or too small by 1
     if (tst(quotient))
@@ -770,44 +788,44 @@ version (unittest)
 
 unittest
 {
-    const C0 = Zero;
-    const C1 = One;
-    const C2 = Cent(2);
-    const C3 = Cent(3);
-    const C5 = Cent(5);
-    const C10 = Cent(10);
-    const C20 = Cent(20);
-    const C30 = Cent(30);
-    const C100 = Cent(100);
-
-    const Cm1 =  neg(One);
-    const Cm3 =  neg(C3);
-    const Cm10 = neg(C10);
-
-    const C3_1 = Cent(1,3);
-    const C3_2 = Cent(2,3);
-    const C4_8  = Cent(8, 4);
-    const C5_0  = Cent(0, 5);
-    const C7_1 = Cent(1,7);
-    const C7_9 = Cent(9,7);
-    const C9_3 = Cent(3,9);
-    const C10_0 = Cent(0,10);
-    const C10_1 = Cent(1,10);
-    const C10_3 = Cent(3,10);
-    const C11_3 = Cent(3,11);
-    const C20_0 = Cent(0,20);
-    const C90_30 = Cent(30,90);
-
-    const Cm10_0 = inc(com(C10_0)); // Cent(0, -10);
-    const Cm10_1 = inc(com(C10_1)); // Cent(-1, -11);
-    const Cm10_3 = inc(com(C10_3)); // Cent(-3, -11);
-    const Cm20_0 = inc(com(C20_0)); // Cent(0, -20);
-
-    enum Cs_3 = Cent(3, I.min);
-
-    const Cbig_1 = Cent(0xa3ccac1832952398, 0xc3ac542864f652f8);
-    const Cbig_2 = Cent(0x5267b85f8a42fc20, 0);
-    const Cbig_3 = Cent(0xf0000000ffffffff, 0);
+    const Cent C0 = Zero;
+    const Cent C1 = One;
+    const Cent C2 = { lo:2 };
+    const Cent C3 = { lo:3 };
+    const Cent C5 = { lo:5 };
+    const Cent C10 = { lo:10 };
+    const Cent C20 = { lo:20 };
+    const Cent C30 = { lo:30 };
+    const Cent C100 = { lo:100 };
+
+    const Cent Cm1 =  neg(One);
+    const Cent Cm3 =  neg(C3);
+    const Cent Cm10 = neg(C10);
+
+    const Cent C3_1 = { lo:1, hi:3 };
+    const Cent C3_2 = { lo:2, hi:3 };
+    const Cent C4_8  = { lo:8, hi:4 };
+    const Cent C5_0  = { lo:0, hi:5 };
+    const Cent C7_1 = { lo:1, hi:7 };
+    const Cent C7_9 = { lo:9, hi:7 };
+    const Cent C9_3 = { lo:3, hi:9 };
+    const Cent C10_0 = { lo:0, hi:10 };
+    const Cent C10_1 = { lo:1, hi:10 };
+    const Cent C10_3 = { lo:3, hi:10 };
+    const Cent C11_3 = { lo:3, hi:11 };
+    const Cent C20_0 = { lo:0, hi:20 };
+    const Cent C90_30 = { lo:30, hi:90 };
+
+    const Cent Cm10_0 = inc(com(C10_0)); // Cent(lo=0,  hi=-10);
+    const Cent Cm10_1 = inc(com(C10_1)); // Cent(lo=-1, hi=-11);
+    const Cent Cm10_3 = inc(com(C10_3)); // Cent(lo=-3, hi=-11);
+    const Cent Cm20_0 = inc(com(C20_0)); // Cent(lo=0,  hi=-20);
+
+    enum Cent Cs_3 = { lo:3, hi:I.min };
+
+    const Cent Cbig_1 = { lo:0xa3ccac1832952398, hi:0xc3ac542864f652f8 };
+    const Cent Cbig_2 = { lo:0x5267b85f8a42fc20, hi:0 };
+    const Cent Cbig_3 = { lo:0xf0000000ffffffff, hi:0 };
 
     /************************/
 
@@ -893,12 +911,20 @@ unittest
     assert(div(mul(C90_30, C2), C2) == C90_30);
     assert(div(mul(C90_30, C2), C90_30) == C2);
 
-    assert(divmod(Cbig_1, Cbig_2, modulus) == Cent(0x4496aa309d4d4a2f, U.max));
-    assert(modulus == Cent(0xd83203d0fdc799b8, U.max));
-    assert(udivmod(Cbig_1, Cbig_2, modulus) == Cent(0x5fe0e9bace2bedad, 2));
-    assert(modulus == Cent(0x2c923125a68721f8, 0));
-    assert(div(Cbig_1, Cbig_3) == Cent(0xbfa6c02b5aff8b86, U.max));
-    assert(udiv(Cbig_1, Cbig_3) == Cent(0xd0b7d13b48cb350f, 0));
+    const Cent Cb1divb2 = { lo:0x4496aa309d4d4a2f, hi:U.max };
+    const Cent Cb1modb2 = { lo:0xd83203d0fdc799b8, hi:U.max };
+    assert(divmod(Cbig_1, Cbig_2, modulus) == Cb1divb2);
+    assert(modulus == Cb1modb2);
+
+    const Cent Cb1udivb2 = { lo:0x5fe0e9bace2bedad, hi:2 };
+    const Cent Cb1umodb2 = { lo:0x2c923125a68721f8, hi:0 };
+    assert(udivmod(Cbig_1, Cbig_2, modulus) == Cb1udivb2);
+    assert(modulus == Cb1umodb2);
+
+    const Cent Cb1divb3 = { lo:0xbfa6c02b5aff8b86, hi:U.max };
+    const Cent Cb1udivb3 = { lo:0xd0b7d13b48cb350f, hi:0 };
+    assert(div(Cbig_1, Cbig_3) == Cb1divb3);
+    assert(udiv(Cbig_1, Cbig_3) == Cb1udivb3);
 
     assert(mul(Cm10, C1) == Cm10);
     assert(mul(C1, Cm10) == Cm10);
index 3a7c8e02b8a20925a0adcfca1ff07bf7f5a7f772..47fed9dc5140f7b88d2f0b37724806956d1c2aef 100644 (file)
@@ -1273,7 +1273,9 @@ void copyEmplace(S, T)(ref S source, ref T target) @system
         }
         else static if (__traits(hasCopyConstructor, T))
         {
-            emplace(cast(Unqual!(T)*) &target); // blit T.init
+            // https://issues.dlang.org/show_bug.cgi?id=22766
+            import core.internal.lifetime : emplaceInitializer;
+            emplaceInitializer(*(cast(Unqual!T*)&target));
             static if (__traits(isNested, T))
             {
                  // copy context pointer
@@ -1373,6 +1375,22 @@ void copyEmplace(S, T)(ref S source, ref T target) @system
     static assert(!__traits(compiles, copyEmplace(ss, t)));
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=22766
+@system pure nothrow @nogc unittest
+{
+    static struct S
+    {
+        @disable this();
+        this(int) @safe pure nothrow @nogc{}
+        this(ref const(S) other) @safe pure nothrow @nogc {}
+    }
+
+    S s1 = S(1);
+    S s2 = void;
+    copyEmplace(s1, s2);
+    assert(s2 == S(1));
+}
+
 version (DigitalMars) version (X86) version (Posix) version = DMD_X86_Posix;
 
 // don't violate immutability for reference types
index 7306c1071a16c48d57feb88c5816bf4f5c8ec959..0feb0b01ef5fec762df27b150ff576b840825137 100644 (file)
@@ -1,4 +1,4 @@
-99e9c1b7741e0f4e6f2a8c14883c4828d092701d
+c0cc5e917db105301dd1199b4b3c854626526407
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
index a1b20fedce9085215de2c17cbe4427ed5685822e..73c6534d8da5df0c331e15c2c2a2e75ab83a18ed 100644 (file)
@@ -2,15 +2,16 @@
 /* updated from 1.2.1 to 1.2.3 by Thomas Kuehne */
 /* updated from 1.2.3 to 1.2.8 by Dmitry Atamanov */
 /* updated from 1.2.8 to 1.2.11 by Iain Buclaw */
+/* updated from 1.2.11 to 1.2.12 by Brian Callahan */
 
 module etc.c.zlib;
 
 import core.stdc.config;
 
 /* zlib.h -- interface of the 'zlib' general purpose compression library
-  version 1.2.11, January 15th, 2017
+  version 1.2.12, March 11th, 2022
 
-  Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler
+  Copyright (C) 1995-2022 Jean-loup Gailly and Mark Adler
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -42,8 +43,8 @@ nothrow:
 extern (C):
 
 // Those are extern(D) as they should be mangled
-extern(D) immutable string ZLIB_VERSION = "1.2.11";
-extern(D) immutable ZLIB_VERNUM = 0x12b0;
+extern(D) immutable string ZLIB_VERSION = "1.2.12";
+extern(D) immutable ZLIB_VERNUM = 0x12c0;
 
 /*
     The 'zlib' compression library provides in-memory compression and
@@ -566,8 +567,7 @@ int deflateInit2(z_streamp strm,
 }
 /*
      This is another version of deflateInit with more compression options.  The
-   fields next_in, zalloc, zfree and opaque must be initialized before by the
-   caller.
+   fields zalloc, zfree and opaque must be initialized before by the caller.
 
      The method parameter is the compression method.  It must be Z_DEFLATED in
    this version of the library.
@@ -586,7 +586,7 @@ int deflateInit2(z_streamp strm,
    with deflateInit2() with this initialization, or at least in that case use 9
    with inflateInit2().
 
-     windowBits can also be -8..-15 for raw deflate.  In this case, -windowBits
+     windowBits can also be -8 .. -15 for raw deflate.  In this case, -windowBits
    determines the window size.  deflate() will then generate raw deflate data
    with no zlib header or trailer, and will not compute a check value.
 
@@ -728,11 +728,12 @@ int deflateParams(z_streamp strm, int level, int strategy);
    used to switch between compression and straight copy of the input data, or
    to switch to a different kind of input data requiring a different strategy.
    If the compression approach (which is a function of the level) or the
-   strategy is changed, and if any input has been consumed in a previous
-   deflate() call, then the input available so far is compressed with the old
-   level and strategy using deflate(strm, Z_BLOCK).  There are three approaches
-   for the compression levels 0, 1 .. 3, and 4 .. 9 respectively.  The new level
-   and strategy will take effect at the next call of deflate().
+   strategy is changed, and if there have been any deflate() calls since the
+   state was initialized or reset, then the input available so far is
+   compressed with the old level and strategy using deflate(strm, Z_BLOCK).
+   There are three approaches for the compression levels 0, 1 .. 3, and 4 .. 9
+   respectively.  The new level and strategy will take effect at the next call
+   of deflate().
 
      If a deflate(strm, Z_BLOCK) is performed by deflateParams(), and it does
    not have enough output space to complete, then the parameter change will not
@@ -856,7 +857,7 @@ int inflateInit2(z_streamp strm, int windowBits)
      windowBits can also be zero to request that inflate use the window size in
    the zlib header of the compressed stream.
 
-     windowBits can also be -8..-15 for raw inflate.  In this case, -windowBits
+     windowBits can also be -8 .. -15 for raw inflate.  In this case, -windowBits
    determines the window size.  inflate() will then process raw deflate data,
    not looking for a zlib or gzip header, not generating a check value, and not
    looking for any check values for comparison at the end of the stream.  This
@@ -873,9 +874,11 @@ int inflateInit2(z_streamp strm, int windowBits)
    detection, or add 16 to decode only the gzip format (the zlib format will
    return a Z_DATA_ERROR).  If a gzip stream is being decoded, strm->adler is a
    CRC-32 instead of an Adler-32.  Unlike the gunzip utility and gzread() (see
-   below), inflate() will not automatically decode concatenated gzip streams.
-   inflate() will return Z_STREAM_END at the end of the gzip stream.  The state
-   would need to be reset to continue decoding a subsequent gzip stream.
+   below), inflate() will *not* automatically decode concatenated gzip members.
+   inflate() will return Z_STREAM_END at the end of the gzip member.  The state
+   would need to be reset to continue decoding a subsequent gzip member.  This
+   *must* be done if there is more data after a gzip member, in order for the
+   decompression to be compliant with the gzip standard (RFC 1952).
 
      inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
    memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
@@ -1311,14 +1314,14 @@ alias z_size_t = size_t;
 
 gzFile gzopen(const(char)* path, const(char)* mode);
 /*
-     Opens a gzip (.gz) file for reading or writing.  The mode parameter is as
-   in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
-   a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
-   compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
-   for fixed code compression as in "wb9F".  (See the description of
-   deflateInit2 for more information about the strategy parameter.)  'T' will
-   request transparent writing or appending with no compression and not using
-   the gzip format.
+     Open the gzip (.gz) file at path for reading and decompressing, or
+   compressing and writing.  The mode parameter is as in fopen ("rb" or "wb")
+   but can also include a compression level ("wb9") or a strategy: 'f' for
+   filtered data as in "wb6f", 'h' for Huffman-only compression as in "wb1h",
+   'R' for run-length encoding as in "wb1R", or 'F' for fixed code compression
+   as in "wb9F".  (See the description of deflateInit2 for more information
+   about the strategy parameter.)  'T' will request transparent writing or
+   appending with no compression and not using the gzip format.
 
      "a" can be used instead of "w" to request that the gzip stream that will
    be written be appended to the file.  "+" will result in an error, since
@@ -1348,9 +1351,9 @@ gzFile gzopen(const(char)* path, const(char)* mode);
 
 gzFile gzdopen(int fd, const(char)* mode);
 /*
-     gzdopen associates a gzFile with the file descriptor fd.  File descriptors
-   are obtained from calls like open, dup, creat, pipe or fileno (if the file
-   has been previously opened with fopen).  The mode parameter is as in gzopen.
+     Associate a gzFile with the file descriptor fd.  File descriptors are
+   obtained from calls like open, dup, creat, pipe or fileno (if the file has
+   been previously opened with fopen).  The mode parameter is as in gzopen.
 
      The next call of gzclose on the returned gzFile will also close the file
    descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
@@ -1371,13 +1374,13 @@ gzFile gzdopen(int fd, const(char)* mode);
 
 int gzbuffer(gzFile file, uint size);
 /*
-     Set the internal buffer size used by this library's functions.  The
-   default buffer size is 8192 bytes.  This function must be called after
-   gzopen() or gzdopen(), and before any other calls that read or write the
-   file.  The buffer memory allocation is always deferred to the first read or
-   write.  Three times that size in buffer space is allocated.  A larger buffer
-   size of, for example, 64K or 128K bytes will noticeably increase the speed
-   of decompression (reading).
+     Set the internal buffer size used by this library's functions for file to
+   size.  The default buffer size is 8192 bytes.  This function must be called
+   after gzopen() or gzdopen(), and before any other calls that read or write
+   the file.  The buffer memory allocation is always deferred to the first read
+   or write.  Three times that size in buffer space is allocated.  A larger
+   buffer size of, for example, 64K or 128K bytes will noticeably increase the
+   speed of decompression (reading).
 
      The new buffer size also affects the maximum length for gzprintf().
 
@@ -1387,9 +1390,9 @@ int gzbuffer(gzFile file, uint size);
 
 int gzsetparams(gzFile file, int level, int strategy);
 /*
-     Dynamically update the compression level or strategy.  See the description
-   of deflateInit2 for the meaning of these parameters.  Previously provided
-   data is flushed before the parameter change.
+     Dynamically update the compression level and strategy for file.  See the
+   description of deflateInit2 for the meaning of these parameters. Previously
+   provided data is flushed before applying the parameter changes.
 
      gzsetparams returns Z_OK if success, Z_STREAM_ERROR if the file was not
    opened for writing, Z_ERRNO if there is an error writing the flushed data,
@@ -1398,7 +1401,7 @@ int gzsetparams(gzFile file, int level, int strategy);
 
 int gzread(gzFile file, void* buf, uint len);
 /*
-     Reads the given number of uncompressed bytes from the compressed file.  If
+     Read and decompress up to len uncompressed bytes from file into buf.  If
    the input file is not in gzip format, gzread copies the given number of
    bytes into the buffer directly from the file.
 
@@ -1428,11 +1431,11 @@ int gzread(gzFile file, void* buf, uint len);
 
 z_size_t gzfread(void* buf, z_size_t size, z_size_t nitems, gzFile file);
 /*
-     Read up to nitems items of size size from file to buf, otherwise operating
-   as gzread() does.  This duplicates the interface of stdio's fread(), with
-   size_t request and return types.  If the library defines size_t, then
-   z_size_t is identical to size_t.  If not, then z_size_t is an unsigned
-   integer type that can contain a pointer.
+     Read and decompress up to nitems items of size size from file into buf,
+   otherwise operating as gzread() does.  This duplicates the interface of
+   stdio's fread(), with size_t request and return types.  If the library
+   defines size_t, then z_size_t is identical to size_t.  If not, then z_size_t
+   is an unsigned integer type that can contain a pointer.
 
      gzfread() returns the number of full items read of size size, or zero if
    the end of the file was reached and a full item could not be read, or if
@@ -1453,14 +1456,13 @@ z_size_t gzfread(void* buf, z_size_t size, z_size_t nitems, gzFile file);
 
 int gzwrite(gzFile file, void* buf, uint len);
 /*
-     Writes the given number of uncompressed bytes into the compressed file.
-   gzwrite returns the number of uncompressed bytes written or 0 in case of
-   error.
+     Compress and write the len uncompressed bytes at buf to file. gzwrite
+   returns the number of uncompressed bytes written or 0 in case of error.
 */
 
 z_size_t gzfwrite(void* buf, z_size_t size, z_size_t nitems, gzFile file);
 /*
-     gzfwrite() writes nitems items of size size from buf to file, duplicating
+     Compress and write nitems items of size size from buf to file, duplicating
    the interface of stdio's fwrite(), with size_t request and return types.  If
    the library defines size_t, then z_size_t is identical to size_t.  If not,
    then z_size_t is an unsigned integer type that can contain a pointer.
@@ -1473,22 +1475,22 @@ z_size_t gzfwrite(void* buf, z_size_t size, z_size_t nitems, gzFile file);
 
 int gzprintf(gzFile file, const(char)* format, ...);
 /*
-     Converts, formats, and writes the arguments to the compressed file under
-   control of the format string, as in fprintf.  gzprintf returns the number of
+     Convert, format, compress, and write the arguments (...) to file under
+   control of the string format, as in fprintf.  gzprintf returns the number of
    uncompressed bytes actually written, or a negative zlib error code in case
    of error.  The number of uncompressed bytes written is limited to 8191, or
    one less than the buffer size given to gzbuffer().  The caller should assure
    that this limit is not exceeded.  If it is exceeded, then gzprintf() will
    return an error (0) with nothing written.  In this case, there may also be a
    buffer overflow with unpredictable consequences, which is possible only if
-   zlib was compiled with the insecure functions sprintf() or vsprintf()
+   zlib was compiled with the insecure functions sprintf() or vsprintf(),
    because the secure snprintf() or vsnprintf() functions were not available.
    This can be determined using zlibCompileFlags().
 */
 
 int gzputs(gzFile file, const(char)* s);
 /*
-     Writes the given null-terminated string to the compressed file, excluding
+     Compress and write the given null-terminated string s to file, excluding
    the terminating null character.
 
      gzputs returns the number of characters written, or -1 in case of error.
@@ -1496,11 +1498,12 @@ int gzputs(gzFile file, const(char)* s);
 
 const(char)* gzgets(gzFile file, const(char)* buf, int len);
 /*
-     Reads bytes from the compressed file until len-1 characters are read, or a
-   newline character is read and transferred to buf, or an end-of-file
-   condition is encountered.  If any characters are read or if len == 1, the
-   string is terminated with a null character.  If no characters are read due
-   to an end-of-file or len < 1, then the buffer is left untouched.
+     Read and decompress bytes from file into buf, until len-1 characters are
+   read, or until a newline character is read and transferred to buf, or an
+   end-of-file condition is encountered.  If any characters are read or if len
+   is one, the string is terminated with a null character.  If no characters
+   are read due to an end-of-file or len is less than one, then the buffer is
+   left untouched.
 
      gzgets returns buf which is a null-terminated string, or it returns NULL
    for end-of-file or in case of error.  If there was an error, the contents at
@@ -1509,13 +1512,13 @@ const(char)* gzgets(gzFile file, const(char)* buf, int len);
 
 int gzputc(gzFile file, int c);
 /*
-     Writes c, converted to an unsigned char, into the compressed file.  gzputc
+     Compress and write c, converted to an unsigned char, into file.  gzputc
    returns the value that was written, or -1 in case of error.
 */
 
 int gzgetc(gzFile file);
 /*
-     Reads one byte from the compressed file.  gzgetc returns this byte or -1
+     Read and decompress one byte from file.  gzgetc returns this byte or -1
    in case of end of file or error.  This is implemented as a macro for speed.
    As such, it does not do all of the checking the other functions do.  I.e.
    it does not check to see if file is NULL, nor whether the structure file
@@ -1524,8 +1527,8 @@ int gzgetc(gzFile file);
 
 int gzungetc(int c, gzFile file);
 /*
-     Push one character back onto the stream to be read as the first character
-   on the next read.  At least one character of push-back is allowed.
+     Push c back onto the stream for file to be read as the first character on
+   the next read.  At least one character of push-back is always allowed.
    gzungetc() returns the character pushed, or -1 on failure.  gzungetc() will
    fail if c is -1, and may fail if a character has been pushed but not read
    yet.  If gzungetc is used immediately after gzopen or gzdopen, at least the
@@ -1536,9 +1539,9 @@ int gzungetc(int c, gzFile file);
 
 int gzflush(gzFile file, int flush);
 /*
-     Flushes all pending output into the compressed file.  The parameter flush
-   is as in the deflate() function.  The return value is the zlib error number
-   (see function gzerror below).  gzflush is only permitted when writing.
+     Flush all pending output to file.  The parameter flush is as in the
+   deflate() function.  The return value is the zlib error number (see function
+   gzerror below).  gzflush is only permitted when writing.
 
      If the flush parameter is Z_FINISH, the remaining data is written and the
    gzip stream is completed in the output.  If gzwrite() is called again, a new
@@ -1551,8 +1554,8 @@ int gzflush(gzFile file, int flush);
 
 z_off_t gzseek(gzFile file, z_off_t offset, int whence);
 /*
-     Sets the starting position for the next gzread or gzwrite on the given
-   compressed file.  The offset represents a number of bytes in the
+     Set the starting position to offset relative to whence for the next gzread
+   or gzwrite on file.  The offset represents a number of bytes in the
    uncompressed data stream.  The whence parameter is defined as in lseek(2);
    the value SEEK_END is not supported.
 
@@ -1569,39 +1572,39 @@ z_off_t gzseek(gzFile file, z_off_t offset, int whence);
 
 int gzrewind(gzFile file);
 /*
-     Rewinds the given file. This function is supported only for reading.
+     Rewind file. This function is supported only for reading.
 
-     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+     gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET).
 */
 
 z_off_t gztell(gzFile file);
 /*
-     Returns the starting position for the next gzread or gzwrite on the given
-   compressed file.  This position represents a number of bytes in the
-   uncompressed data stream, and is zero when starting, even if appending or
-   reading a gzip stream from the middle of a file using gzdopen().
+     Return the starting position for the next gzread or gzwrite on file.
+   This position represents a number of bytes in the uncompressed data stream,
+   and is zero when starting, even if appending or reading a gzip stream from
+   the middle of a file using gzdopen().
 
      gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
 */
 
 z_off_t gzoffset(gzFile file);
 /*
-     Returns the current offset in the file being read or written.  This offset
-   includes the count of bytes that precede the gzip stream, for example when
-   appending or when using gzdopen() for reading.  When reading, the offset
-   does not include as yet unused buffered input.  This information can be used
-   for a progress indicator.  On error, gzoffset() returns -1.
+     Return the current compressed (actual) read or write offset of file.  This
+   offset includes the count of bytes that precede the gzip stream, for example
+   when appending or when using gzdopen() for reading.  When reading, the
+   offset does not include as yet unused buffered input.  This information can
+   be used for a progress indicator.  On error, gzoffset() returns -1.
 */
 
 int gzeof(gzFile file);
 /*
-     Returns true (1) if the end-of-file indicator has been set while reading,
-   false (0) otherwise.  Note that the end-of-file indicator is set only if the
-   read tried to go past the end of the input, but came up short.  Therefore,
-   just like feof(), gzeof() may return false even if there is no more data to
-   read, in the event that the last read request was for the exact number of
-   bytes remaining in the input file.  This will happen if the input file size
-   is an exact multiple of the buffer size.
+     Return true (1) if the end-of-file indicator for file has been set while
+   reading, false (0) otherwise.  Note that the end-of-file indicator is set
+   only if the read tried to go past the end of the input, but came up short.
+   Therefore, just like feof(), gzeof() may return false even if there is no
+   more data to read, in the event that the last read request was for the exact
+   number of bytes remaining in the input file.  This will happen if the input
+   file size is an exact multiple of the buffer size.
 
      If gzeof() returns true, then the read functions will return no more data,
    unless the end-of-file indicator is reset by gzclearerr() and the input file
@@ -1610,7 +1613,7 @@ int gzeof(gzFile file);
 
 int gzdirect(gzFile file);
 /*
-     Returns true (1) if file is being copied directly while reading, or false
+     Return true (1) if file is being copied directly while reading, or false
    (0) if file is a gzip stream being decompressed.
 
      If the input file is empty, gzdirect() will return true, since the input
@@ -1631,8 +1634,8 @@ int gzdirect(gzFile file);
 
 int gzclose(gzFile file);
 /*
-     Flushes all pending output if necessary, closes the compressed file and
-   deallocates the (de)compression state.  Note that once file is closed, you
+     Flush all pending output for file, if necessary, close file and
+   deallocate the (de)compression state.  Note that once file is closed, you
    cannot call gzerror with file, since its structures have been deallocated.
    gzclose must not be called more than once on the same file, just as free
    must not be called more than once on the same allocation.
@@ -1656,10 +1659,10 @@ int gzclose_w(gzFile file);
 
 const(char)* gzerror(gzFile file, int* errnum);
 /*
-     Returns the error message for the last error which occurred on the given
-   compressed file.  errnum is set to zlib error number.  If an error occurred
-   in the file system and not in the compression library, errnum is set to
-   Z_ERRNO and the application may consult errno to get the exact error code.
+     Return the error message for the last error which occurred on file.
+   errnum is set to zlib error number.  If an error occurred in the file system
+   and not in the compression library, errnum is set to Z_ERRNO and the
+   application may consult errno to get the exact error code.
 
      The application must not modify the returned string.  Future calls to
    this function may invalidate the previously returned string.  If file is
@@ -1672,7 +1675,7 @@ const(char)* gzerror(gzFile file, int* errnum);
 
 void gzclearerr(gzFile file);
 /*
-     Clears the error and end-of-file flags for file.  This is analogous to the
+     Clear the error and end-of-file flags for file.  This is analogous to the
    clearerr() function in stdio.  This is useful for continuing to read a gzip
    file that is being written concurrently.
 */
@@ -1688,8 +1691,9 @@ void gzclearerr(gzFile file);
 uint adler32(uint adler, const(ubyte)* buf, uint len);
 /*
      Update a running Adler-32 checksum with the bytes buf[0 .. len-1] and
-   return the updated checksum.  If buf is Z_NULL, this function returns the
-   required initial value for the checksum.
+   return the updated checksum. An Adler-32 value is in the range of a 32-bit
+   unsigned integer. If buf is Z_NULL, this function returns the required
+   initial value for the checksum.
 
      An Adler-32 checksum is almost as reliable as a CRC-32 but can be computed
    much faster.
@@ -1722,9 +1726,10 @@ uint adler32_combine(uint adler1, uint adler2, z_off_t len2);
 uint crc32(uint crc, const(ubyte)* buf, uint len);
 /*
      Update a running CRC-32 with the bytes buf[0 .. len-1] and return the
-   updated CRC-32.  If buf is Z_NULL, this function returns the required
-   initial value for the crc.  Pre- and post-conditioning (one's complement) is
-   performed within this function so it shouldn't be done by the application.
+   updated CRC-32. A CRC-32 value is in the range of a 32-bit unsigned integer.
+   If buf is Z_NULL, this function returns the required initial value for the
+   crc. Pre- and post-conditioning (one's complement) is performed within this
+   function so it shouldn't be done by the application.
 
    Usage example:
 
@@ -1736,7 +1741,7 @@ uint crc32(uint crc, const(ubyte)* buf, uint len);
      if (crc != original_crc) error();
 */
 
-uint crc32_z(uint adler, const(ubyte)* buf, z_size_t len);
+uint crc32_z(uint crc, const(ubyte)* buf, z_size_t len);
 /*
      Same as crc32(), but with a size_t length.
 */
@@ -1751,6 +1756,18 @@ uint crc32_combine(uint crc1, uint crc2, z_off_t len2);
    len2.
 */
 
+uint crc32_combine_gen(z_off_t len2);
+/*
+     Return the operator corresponding to length len2, to be used with
+   crc32_combine_op().
+*/
+
+uint crc32_combine_op(uint crc1, uint crc2, uint op);
+/*
+     Give the same result as crc32_combine(), using op in place of len2. op is
+   is generated from len2 by crc32_combine_gen(). This will be faster than
+   crc32_combine() if the generated op is used more than once.
+*/
 
                         /* various hacks, don't look :) */
 
index 41ca6872a7a2bec644966b79e1135d6e7e061ece..448bb99a9a132fd2a7c37cae59abec446b316a40 100644 (file)
@@ -841,7 +841,7 @@ if (isForwardRange!R && is(ElementType!R : dchar))
         switch (front)
         {
         case '*', '?', '+', '|', '{', '}':
-            error("'*', '+', '?', '{', '}' not allowed in atom");
+            return error("'*', '+', '?', '{', '}' not allowed in atom");
         case '.':
             if (re_flags & RegexOption.singleline)
                 g.put(Bytecode(IR.Any, 0));