]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
d: Merge upstream dmd c11e1d1708, druntime e60bfd11bd, phobos 8729740e3
authorIain Buclaw <ibuclaw@symmetryinvestments.com>
Sun, 29 Dec 2024 05:40:04 +0000 (06:40 +0100)
committerIain Buclaw <ibuclaw@gdcproject.org>
Sun, 5 Jan 2025 12:30:24 +0000 (13:30 +0100)
Synchronizing the compiler with the upstream release of v2.108.1.

D front-end changes:

        - Import dmd v2.108.1.
- Add experimental support for language editions, enabled by
  adding the UDA `@__edition_latest_do_not_use' before module
  declarations.
- [Next Edition] Aliasing a member of a type instance is now an
  error.
- Added `__ctfeWrite' to write messages from CTFE.
- `-fdump-c++-spec' generates signatures for `extern(Windows)'
  and `extern(System)' functions.
- `foreach_reverse' on a delegate is now an error.
- ImportC has improved Unicode support.

D runtime changes:

        - Mark unsafe unittest @trusted.

Phobos changes:

        - Mark unsafe functions @trusted.

gcc/d/ChangeLog:

* Make-lang.in (D_FRONTEND_OBJS): Add d/attribsem.o,
d/common-charactertables.o, d/common-identifiertables.o.
* d-attribs.cc (apply_user_attributes): Update for new front-end
interface.
* d-builtins.cc (d_init_versions): Predefine CppRuntime_GNU.
* d-incpath.cc (add_globalpaths): Update for new front-end interface.
(add_filepaths): Likewise.
(add_import_paths): Likewise.
* d-lang.cc (d_post_options): Likewise.
* dmd/MERGE: Merge upstream dmd c11e1d1708.
* dmd/VERSION: Bump version to v2.108.1.

libphobos/ChangeLog:

* libdruntime/MERGE: Merge upstream druntime e60bfd11bd.
* src/MERGE: Merge upstream phobos 8729740e3.

gcc/testsuite/ChangeLog:

* gdc.dg/torture/pr96435.d: Add dg-warning.

85 files changed:
gcc/d/Make-lang.in
gcc/d/d-attribs.cc
gcc/d/d-builtins.cc
gcc/d/d-incpath.cc
gcc/d/d-lang.cc
gcc/d/dmd/MERGE
gcc/d/dmd/README.md
gcc/d/dmd/VERSION
gcc/d/dmd/arrayop.d
gcc/d/dmd/astenums.d
gcc/d/dmd/attrib.d
gcc/d/dmd/attrib.h
gcc/d/dmd/attribsem.d [new file with mode: 0644]
gcc/d/dmd/common/charactertables.d [new file with mode: 0644]
gcc/d/dmd/common/charactertables.h [new file with mode: 0644]
gcc/d/dmd/common/file.d
gcc/d/dmd/common/identifiertables.d [new file with mode: 0644]
gcc/d/dmd/common/outbuffer.d
gcc/d/dmd/cond.h
gcc/d/dmd/cparse.d
gcc/d/dmd/cppmangle.d
gcc/d/dmd/cxxfrontend.d
gcc/d/dmd/dcast.d
gcc/d/dmd/dclass.d
gcc/d/dmd/declaration.d
gcc/d/dmd/dmangle.d
gcc/d/dmd/dmodule.d
gcc/d/dmd/doc.d
gcc/d/dmd/dscope.d
gcc/d/dmd/dstruct.d
gcc/d/dmd/dsymbol.d
gcc/d/dmd/dsymbol.h
gcc/d/dmd/dsymbolsem.d
gcc/d/dmd/dtemplate.d
gcc/d/dmd/dtoh.d
gcc/d/dmd/errors.h
gcc/d/dmd/escape.d
gcc/d/dmd/expression.d
gcc/d/dmd/expression.h
gcc/d/dmd/expressionsem.d
gcc/d/dmd/file_manager.d
gcc/d/dmd/func.d
gcc/d/dmd/funcsem.d
gcc/d/dmd/globals.d
gcc/d/dmd/globals.h
gcc/d/dmd/id.d
gcc/d/dmd/identifier.d
gcc/d/dmd/init.d
gcc/d/dmd/init.h
gcc/d/dmd/initsem.d
gcc/d/dmd/lexer.d
gcc/d/dmd/module.h
gcc/d/dmd/mtype.d
gcc/d/dmd/mtype.h
gcc/d/dmd/mustuse.d
gcc/d/dmd/ob.d
gcc/d/dmd/objc.d
gcc/d/dmd/opover.d
gcc/d/dmd/parse.d
gcc/d/dmd/pragmasem.d
gcc/d/dmd/root/array.h
gcc/d/dmd/root/bitarray.h
gcc/d/dmd/root/dcompat.h
gcc/d/dmd/root/file.d
gcc/d/dmd/root/filename.d
gcc/d/dmd/root/filename.h
gcc/d/dmd/root/rmem.d
gcc/d/dmd/root/string.d
gcc/d/dmd/root/utf.d
gcc/d/dmd/safe.d
gcc/d/dmd/semantic2.d
gcc/d/dmd/semantic3.d
gcc/d/dmd/statement.h
gcc/d/dmd/statementsem.d
gcc/d/dmd/target.d
gcc/d/dmd/target.h
gcc/d/dmd/tokens.h
gcc/d/dmd/traits.d
gcc/d/dmd/typesem.d
gcc/d/dmd/utils.d
gcc/testsuite/gdc.dg/torture/pr96435.d
libphobos/libdruntime/MERGE
libphobos/libdruntime/core/sync/mutex.d
libphobos/src/MERGE
libphobos/src/std/bitmanip.d

index 6b591262622576704e2e282ac4d19d2fc0c0725e..914d54b0bb28bd481a720d937548e7907dd81cfa 100644 (file)
@@ -84,6 +84,7 @@ D_FRONTEND_OBJS = \
        d/arrayop.o \
        d/arraytypes.o \
        d/attrib.o \
+       d/attribsem.o \
        d/ast_node.o \
        d/astcodegen.o \
        d/astenums.o \
@@ -94,7 +95,9 @@ D_FRONTEND_OBJS = \
        d/chkformat.o \
        d/clone.o \
        d/common-bitfields.o \
+       d/common-charactertables.o \
        d/common-file.o \
+       d/common-identifiertables.o \
        d/common-outbuffer.o \
        d/common-smallbuffer.o \
        d/compiler.o \
index 26ec927be7205373144bb08eea04715d97d0c4a8..77315dc5d58d0106951b1388ee6e1f9ba849a095 100644 (file)
@@ -440,7 +440,7 @@ apply_user_attributes (Dsymbol *sym, tree node)
   if (TYPE_P (node) && !COMPLETE_TYPE_P (node))
     attr_flags |= ATTR_FLAG_TYPE_IN_PLACE;
 
-  Expressions *attrs = uda->getAttributes ();
+  Expressions *attrs = dmd::getAttributes (uda);
   decl_attributes (&node, build_attributes (attrs), attr_flags);
 
   input_location = saved_location;
index e23e091e4310f12df881dc5c600c4b90bb5d7549..233342aab015a985908ce2be4bec79875a00316f 100644 (file)
@@ -522,6 +522,7 @@ d_init_versions (void)
   targetdm.d_cpu_versions ();
   targetdm.d_os_versions ();
 
+  VersionCondition::addPredefinedGlobalIdent ("CppRuntime_GNU");
   VersionCondition::addPredefinedGlobalIdent ("CppRuntime_Gcc");
 }
 
index 8cec07b1facbcb354174ab391e9e006fabdf0ba2..3f62f437cb986cabc033f58250be37ae7c361368 100644 (file)
@@ -67,47 +67,41 @@ prefixed_path (const char *path, const char *iprefix)
 /* Add PATHS to the global import lookup path.  */
 
 static void
-add_globalpaths (Strings *paths)
+add_globalpaths (Strings &paths)
 {
-  if (paths)
+  for (size_t i = 0; i < paths.length; i++)
     {
-      for (size_t i = 0; i < paths->length; i++)
-       {
-         const char *path = (*paths)[i];
-         const char *target = lrealpath (path);
-
-         if (target == NULL || !FileName::exists (target))
-           {
-             if (target)
-               free (CONST_CAST (char *, target));
-             continue;
-           }
+      const char *path = paths[i];
+      const char *target = lrealpath (path);
 
-         global.path.push (target);
+      if (target == NULL || !FileName::exists (target))
+       {
+         if (target)
+           free (CONST_CAST (char *, target));
+         continue;
        }
+
+      global.path.push (target);
     }
 }
 
 /* Add PATHS to the global file import lookup path.  */
 
 static void
-add_filepaths (Strings *paths)
+add_filepaths (Strings &paths)
 {
-  if (paths)
+  for (size_t i = 0; i < paths.length; i++)
     {
-      for (size_t i = 0; i < paths->length; i++)
-       {
-         const char *path = (*paths)[i];
-         const char *target = lrealpath (path);
-
-         if (!FileName::exists (target))
-           {
-             free (CONST_CAST (char *, target));
-             continue;
-           }
+      const char *path = paths[i];
+      const char *target = lrealpath (path);
 
-         global.filePath.push (target);
+      if (!FileName::exists (target))
+       {
+         free (CONST_CAST (char *, target));
+         continue;
        }
+
+      global.filePath.push (target);
     }
 }
 
@@ -168,7 +162,11 @@ add_import_paths (const char *iprefix, const char *imultilib, bool stdinc)
     {
       const char *path = global.params.imppath[i];
       if (path)
-       add_globalpaths (FileName::splitPath (path));
+       {
+         Strings array;
+         FileName::appendSplitPath (path, array);
+         add_globalpaths (array);
+       }
     }
 
   /* Add string import search paths.  */
@@ -176,6 +174,10 @@ add_import_paths (const char *iprefix, const char *imultilib, bool stdinc)
     {
       const char *path = global.params.fileImppath[i];
       if (path)
-       add_filepaths (FileName::splitPath (path));
+       {
+         Strings array;
+         FileName::appendSplitPath (path, array);
+         add_filepaths (array);
+       }
     }
 }
index 274cb5d92ef0f538d0d528fd177e6940f92c4d72..f642248055813be57024a3a9a8d3aa558a42e183 100644 (file)
@@ -934,6 +934,10 @@ d_post_options (const char ** fn)
      fields with params.  */
   global.compileEnv.previewIn = global.params.previewIn;
   global.compileEnv.ddocOutput = global.params.ddoc.doOutput;
+  global.compileEnv.cCharLookupTable =
+    IdentifierCharLookup::forTable (IdentifierTable::C11);
+  global.compileEnv.dCharLookupTable =
+    IdentifierCharLookup::forTable (IdentifierTable::LR);
 
   if (warn_return_type == -1)
     warn_return_type = 0;
index dc47db87a80c8f1793d091c9eda6982763ee56aa..46d435ef8dba83a36d3ac82a717c5ba0a5ce69a2 100644 (file)
@@ -1,4 +1,4 @@
-b65767825f365dbc153457fc86e1054b03196c6d
+c11e1d1708646c9ac81ac2aafb57fa1ef5d289ad
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
index 282e818378332f72a7649107078b9dfcc7f3be1b..d784d07df21389c9ec00b86c3f4e07739dc27e6d 100644 (file)
@@ -109,6 +109,7 @@ Note that these groups have no strict meaning, the category assignments are a bi
 
 | File                                                                                      | Purpose                                                           |
 |-------------------------------------------------------------------------------------------|-------------------------------------------------------------------|
+| [attribsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/attribsem.d)               | Attribute semantics                                               |
 | [dsymbolsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dsymbolsem.d)             | Do semantic 1 pass (symbol identifiers/types)                     |
 | [enumsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/enumsem.d)                   | Enum semantics                                                    |
 | [funcsem.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/funcsem.d)                   | Function semantics                                                |
index 5868b8749552b20dabaab75e95f6e1d522972269..99582f5e05fa596d569308e093864c6c41b95819 100644 (file)
@@ -1 +1 @@
-v2.108.0
+v2.108.1
index af3875ea6c5f75bb32b0b832970805f4f0fddf38..d0ec5ebcdbe91db144c3be6ff795b1013444f3ef 100644 (file)
@@ -145,7 +145,10 @@ Expression arrayOp(BinExp e, Scope* sc)
         if (auto te = id.isTemplateExp())
             arrayOp = te.td;
         else
-            ObjectNotFound(idArrayOp);   // fatal error
+        {
+            ObjectNotFound(e.loc, idArrayOp);   // fatal error
+            return ErrorExp.get();
+        }
     }
 
     auto fd = resolveFuncCall(e.loc, sc, arrayOp, tiargs, null, ArgumentList(args), FuncResolveFlag.standard);
index 4fc15141c3976e5156b0ea800a1902845c009584..1e30b9f8fc2520b7cba716f388b69c7841411d46 100644 (file)
@@ -18,6 +18,15 @@ enum Sizeok : ubyte
     done,               /// size of aggregate is set correctly
 }
 
+/// D Language version
+enum Edition : ubyte
+{
+    none,
+    legacy,          /// Before the introduction of editions
+    v2024,           /// Experimental first new edition
+    latest = v2024   /// Newest edition that this compiler knows of
+}
+
 enum Baseok : ubyte
 {
     none,               /// base classes not computed yet
@@ -441,6 +450,24 @@ enum FileType : ubyte
     c,    /// C source file
 }
 
+/// In which context checks for assertions, contracts, bounds checks etc. are enabled
+enum CHECKENABLE : ubyte
+{
+    _default,     /// initial value
+    off,          /// never do checking
+    on,           /// always do checking
+    safeonly,     /// do checking only in @safe functions
+}
+
+/// What should happend when an assertion fails
+enum CHECKACTION : ubyte
+{
+    D,            /// call D assert on failure
+    C,            /// call C assert on failure
+    halt,         /// cause program halt on failure
+    context,      /// call D assert with the error context on failure
+}
+
 extern (C++) struct structalign_t
 {
   private:
index d7d3eca6f8da0859ccdfe020d2f91bd3eecf0551..1c8eb57726121458e812054c8f93cfe34d8ff736 100644 (file)
@@ -35,7 +35,6 @@ import dmd.dsymbol;
 import dmd.dsymbolsem;
 import dmd.errors;
 import dmd.expression;
-import dmd.expressionsem;
 import dmd.func;
 import dmd.globals;
 import dmd.hdrgen : visibilityToBuffer;
@@ -1121,21 +1120,6 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
         return udas;
     }
 
-    Expressions* getAttributes()
-    {
-        if (auto sc = _scope)
-        {
-            _scope = null;
-            arrayExpressionSemantic(atts.peekSlice(), sc);
-        }
-        auto exps = new Expressions();
-        if (userAttribDecl && userAttribDecl !is this)
-            exps.push(new TupleExp(Loc.initial, userAttribDecl.getAttributes()));
-        if (atts && atts.length)
-            exps.push(new TupleExp(Loc.initial, atts));
-        return exps;
-    }
-
     override const(char)* kind() const
     {
         return "UserAttribute";
@@ -1231,43 +1215,6 @@ bool isCoreUda(Dsymbol sym, Identifier ident)
     return _module && _module.isCoreModule(Id.attribute);
 }
 
-/**
- * Iterates the UDAs attached to the given symbol.
- *
- * Params:
- *  sym = the symbol to get the UDAs from
- *  sc = scope to use for semantic analysis of UDAs
- *  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)
-{
-    if (!sym.userAttribDecl)
-        return 0;
-
-    auto udas = sym.userAttribDecl.getAttributes();
-    arrayExpressionSemantic(udas.peekSlice(), sc, true);
-
-    return udas.each!((uda) {
-        if (!uda.isTupleExp())
-            return 0;
-
-        auto exps = uda.isTupleExp().exps;
-
-        return exps.each!((e) {
-            assert(e);
-
-            if (auto result = dg(e))
-                return result;
-
-            return 0;
-        });
-    });
-}
-
 /**
  * Iterates the UDAs attached to the given symbol, without performing semantic
  * analysis.
index 344a7e929a7b65ede7f0e27d0ad82b3c466d8088..d4c41ec94f36f3f3ebc61592cb3c5c7305ec7b06 100644 (file)
@@ -17,6 +17,11 @@ class Expression;
 class Condition;
 class StaticForeach;
 
+namespace dmd
+{
+    Expressions *getAttributes(UserAttributeDeclaration *a);
+}
+
 /**************************************************************/
 
 class AttribDeclaration : public Dsymbol
@@ -226,7 +231,6 @@ public:
 
     UserAttributeDeclaration *syntaxCopy(Dsymbol *s) override;
     Scope *newScope(Scope *sc) override;
-    Expressions *getAttributes();
     const char *kind() const override;
     void accept(Visitor *v) override { v->visit(this); }
 };
diff --git a/gcc/d/dmd/attribsem.d b/gcc/d/dmd/attribsem.d
new file mode 100644 (file)
index 0000000..44647ee
--- /dev/null
@@ -0,0 +1,87 @@
+/**
+ * Does semantic analysis for attributes.
+ *
+ * The term 'attribute' refers to things that can apply to a larger scope than a single declaration.
+ * Among them are:
+ * - Alignment (`align(8)`)
+ * - User defined attributes (`@UDA`)
+ * - Function Attributes (`@safe`)
+ * - Storage classes (`static`, `__gshared`)
+ * - Mixin declarations  (`mixin("int x;")`)
+ * - Conditional compilation (`static if`, `static foreach`)
+ * - Linkage (`extern(C)`)
+ * - Anonymous structs / unions
+ * - Protection (`private`, `public`)
+ * - Deprecated declarations (`@deprecated`)
+ *
+ * Copyright:   Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
+ * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/attribsem.d, _attrib.d)
+ * Documentation:  https://dlang.org/phobos/dmd_attribsem.html
+ * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/attribsem.d
+ */
+
+module dmd.attribsem;
+
+import dmd.arraytypes;
+import dmd.attrib;
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.expression;
+import dmd.expressionsem;
+import dmd.location;
+import dmd.root.array; // for each
+
+
+Expressions* getAttributes(UserAttributeDeclaration a)
+{
+    if (auto sc = a._scope)
+    {
+        a._scope = null;
+        arrayExpressionSemantic(a.atts.peekSlice(), sc);
+    }
+    auto exps = new Expressions();
+    if (a.userAttribDecl && a.userAttribDecl !is a)
+        exps.push(new TupleExp(Loc.initial, a.userAttribDecl.getAttributes()));
+    if (a.atts && a.atts.length)
+        exps.push(new TupleExp(Loc.initial, a.atts));
+    return exps;
+}
+
+/**
+ * Iterates the UDAs attached to the given symbol.
+ *
+ * Params:
+ *  sym = the symbol to get the UDAs from
+ *  sc = scope to use for semantic analysis of UDAs
+ *  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)
+{
+    if (!sym.userAttribDecl)
+        return 0;
+
+    auto udas = sym.userAttribDecl.getAttributes();
+    arrayExpressionSemantic(udas.peekSlice(), sc, true);
+
+    return udas.each!((uda) {
+        if (!uda.isTupleExp())
+            return 0;
+
+        auto exps = uda.isTupleExp().exps;
+
+        return exps.each!((e) {
+            assert(e);
+
+            if (auto result = dg(e))
+                return result;
+
+            return 0;
+        });
+    });
+}
diff --git a/gcc/d/dmd/common/charactertables.d b/gcc/d/dmd/common/charactertables.d
new file mode 100644 (file)
index 0000000..ac89807
--- /dev/null
@@ -0,0 +1,267 @@
+/**
+ * Character tables related to identifiers.
+ *
+ * Supports UAX31, C99, C11 and least restrictive (All).
+ *
+ * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Authors:   $(LINK2 https://cattermole.co.nz, Richard (Rikki) Andrew Cattermole)
+ * 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/charactertables.d, common/charactertables.d)
+ * Documentation: https://dlang.org/phobos/dmd_common_charactertables.html
+ * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/charactertables.d
+ */
+module dmd.common.charactertables;
+
+@safe nothrow @nogc pure:
+
+extern(C++):
+
+///
+enum IdentifierTable {
+    UAX31, ///
+    C99, ///
+    C11, ///
+    LR, /// Least Restrictive aka All
+}
+
+///
+struct IdentifierCharLookup
+{
+    @safe nothrow @nogc pure:
+
+    ///
+    extern(C++) bool function(dchar) isStart;
+    ///
+    extern(C++) bool function(dchar) isContinue;
+
+    /// Lookup the table given the table name
+    extern(C++) static IdentifierCharLookup forTable(IdentifierTable table)
+    {
+        import dmd.common.identifiertables;
+
+        // Awful solution to require these lambdas.
+        // However without them the extern(C++) ABI issues crop up for isInRange,
+        //  and then it can't access the tables.
+        final switch(table) {
+            case IdentifierTable.UAX31:
+                return IdentifierCharLookup(
+                        (c) => isInRange!UAX31_Start(c),
+                        (c) => isInRange!UAX31_Continue(c));
+            case IdentifierTable.C99:
+                return IdentifierCharLookup(
+                        (c) => isInRange!FixedTable_C99_Start(c),
+                        (c) => isInRange!FixedTable_C99_Continue(c));
+            case IdentifierTable.C11:
+                return IdentifierCharLookup(
+                        (c) => isInRange!FixedTable_C11_Start(c),
+                        (c) => isInRange!FixedTable_C11_Continue(c));
+            case IdentifierTable.LR:
+                return IdentifierCharLookup(
+                        (c) => isInRange!LeastRestrictive_Start(c),
+                        (c) => isInRange!LeastRestrictive_Continue(c));
+        }
+    }
+}
+
+/**
+Convenience function for use in places where we just don't care,
+what the identifier ranges are, or if it is start/continue.
+
+Returns: is character a member of least restrictive of all.
+*/
+bool isAnyIdentifierCharacter(dchar c)
+{
+    import dmd.common.identifiertables;
+    return isInRange!LeastRestrictive_OfAll(c);
+}
+
+///
+unittest
+{
+    assert(isAnyIdentifierCharacter('ÄŸ'));
+}
+
+/**
+Convenience function for use in places where we just don't care,
+what the identifier ranges are.
+
+Returns: is character a member of restrictive Start
+*/
+bool isAnyStart(dchar c)
+{
+    import dmd.common.identifiertables;
+    return isInRange!LeastRestrictive_Start(c);
+}
+
+///
+unittest
+{
+    assert(isAnyStart('ÄŸ'));
+}
+
+/**
+Convenience function for use in places where we just don't care,
+what the identifier ranges are.
+
+Returns: is character a member of least restrictive Continue
+*/
+bool isAnyContinue(dchar c)
+{
+    import dmd.common.identifiertables;
+    return isInRange!LeastRestrictive_Continue(c);
+}
+
+///
+unittest
+{
+    assert(isAnyContinue('ÄŸ'));
+}
+
+/// UTF line separator
+enum LS = 0x2028;
+/// UTF paragraph separator
+enum PS = 0x2029;
+
+private
+{
+    enum CMoctal  = 0x1;
+    enum CMhex    = 0x2;
+    enum CMidchar = 0x4;
+    enum CMzerosecond = 0x8;
+    enum CMdigitsecond = 0x10;
+    enum CMsinglechar = 0x20;
+}
+
+///
+bool isoctal(const char c)
+{
+    return (cmtable[c] & CMoctal) != 0;
+}
+
+///
+bool ishex(const char c)
+{
+    return (cmtable[c] & CMhex) != 0;
+}
+
+///
+bool isidchar(const char c)
+{
+    return (cmtable[c] & CMidchar) != 0;
+}
+
+///
+bool isZeroSecond(const char c)
+{
+    return (cmtable[c] & CMzerosecond) != 0;
+}
+
+///
+bool isDigitSecond(const char c)
+{
+    return (cmtable[c] & CMdigitsecond) != 0;
+}
+
+///
+bool issinglechar(const char c)
+{
+    return (cmtable[c] & CMsinglechar) != 0;
+}
+
+///
+bool c_isxdigit(const int c)
+{
+    return (( c >= '0' && c <= '9') ||
+        ( c >= 'a' && c <= 'f') ||
+        ( c >= 'A' && c <= 'F'));
+}
+
+///
+bool c_isalnum(const int c)
+{
+    return (( c >= '0' && c <= '9') ||
+        ( c >= 'a' && c <= 'z') ||
+        ( c >= 'A' && c <= 'Z'));
+}
+
+extern(D) private:
+
+// originally from dmd.root.utf
+bool isInRange(alias Ranges)(dchar c)
+{
+    size_t high = Ranges.length - 1;
+    // Shortcut search if c is out of range
+    size_t low = (c < Ranges[0][0] || Ranges[high][1] < c) ? high + 1 : 0;
+    // Binary search
+    while (low <= high)
+    {
+        const size_t mid = low + ((high - low) >> 1);
+        if (c < Ranges[mid][0])
+            high = mid - 1;
+        else if (Ranges[mid][1] < c)
+            low = mid + 1;
+        else
+        {
+            assert(Ranges[mid][0] <= c && c <= Ranges[mid][1]);
+            return true;
+        }
+    }
+    return false;
+}
+
+/********************************************
+ * Do our own char maps
+ */
+// originally from dmd.lexer (was private)
+static immutable cmtable = ()
+{
+    ubyte[256] table;
+    foreach (const c; 0 .. table.length)
+    {
+        if ('0' <= c && c <= '7')
+            table[c] |= CMoctal;
+        if (c_isxdigit(c))
+            table[c] |= CMhex;
+        if (c_isalnum(c) || c == '_')
+            table[c] |= CMidchar;
+
+        switch (c)
+        {
+            case 'x': case 'X':
+            case 'b': case 'B':
+                table[c] |= CMzerosecond;
+                break;
+
+            case '0': .. case '9':
+            case 'e': case 'E':
+            case 'f': case 'F':
+            case 'l': case 'L':
+            case 'p': case 'P':
+            case 'u': case 'U':
+            case 'i':
+            case '.':
+            case '_':
+                table[c] |= CMzerosecond | CMdigitsecond;
+                break;
+
+            default:
+                break;
+        }
+
+        switch (c)
+        {
+            case '\\':
+            case '\n':
+            case '\r':
+            case 0:
+            case 0x1A:
+            case '\'':
+                break;
+            default:
+                if (!(c & 0x80))
+                    table[c] |= CMsinglechar;
+                break;
+        }
+    }
+    return table;
+}();
diff --git a/gcc/d/dmd/common/charactertables.h b/gcc/d/dmd/common/charactertables.h
new file mode 100644 (file)
index 0000000..10a81d3
--- /dev/null
@@ -0,0 +1,29 @@
+/**
+ * Character tables related to identifiers.
+ *
+ * Supports UAX31, C99, C11 and least restrictive (All).
+ *
+ * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * Authors:   $(LINK2 https://cattermole.co.nz, Richard (Rikki) Andrew Cattermole)
+ * 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/charactertables.d, common/charactertables.d)
+ */
+
+#pragma once
+
+enum class IdentifierTable
+{
+    UAX31,
+    C99,
+    C11,
+    LR, // Least Restrictive aka All
+};
+
+struct IdentifierCharLookup final
+{
+    bool(*isStart)(char32_t);
+    bool(*isContinue)(char32_t);
+
+    // constructor not provided here.
+    static IdentifierCharLookup forTable(IdentifierTable table);
+};
index 80677f66ff89441abb73598a9e4294996720ae0a..52da6ee07925b41a9b1a48342144b7d844cb3545 100644 (file)
 
 module dmd.common.file;
 
+import core.stdc.stdio;
+import core.stdc.stdlib;
+import core.stdc.string;
+import core.stdc.limits;
+
 import core.stdc.errno : errno;
 import core.stdc.stdio : fprintf, remove, rename, stderr;
 import core.stdc.stdlib;
 import core.stdc.string : strerror, strlen, memcpy;
 
 import dmd.common.smallbuffer;
+import dmd.root.filename;
+import dmd.root.rmem;
 
 version (Windows)
 {
+    import core.stdc.wchar_;
     import core.sys.windows.winbase;
     import core.sys.windows.winnls : CP_ACP;
     import core.sys.windows.winnt;
@@ -32,6 +40,7 @@ version (Windows)
 }
 else version (Posix)
 {
+    import core.sys.posix.dirent;
     import core.sys.posix.fcntl;
     import core.sys.posix.sys.mman;
     import core.sys.posix.sys.stat;
@@ -566,7 +575,7 @@ else version (Windows)
     private ulong fileSize(HANDLE fd)
     {
         ulong result;
-        if (GetFileSizeEx(fd, cast(LARGE_INTEGER*) &result) == 0)
+        if (GetFileSizeEx(fd, cast(LARGE_INTEGER*) &result))
             return result;
         return ulong.max;
     }
@@ -587,3 +596,163 @@ private auto ref fakePure(F)(scope F fun) pure
     mixin("alias PureFun = " ~ F.stringof ~ " pure;");
     return (cast(PureFun) fun)();
 }
+
+/***********************************
+ * Recursively search all the directories and files under dir_path
+ * for files that match one of the extensions in exts[].
+ * Pass the matches to sink.
+ * Params:
+ *      dir_path = root of directories to search
+ *      exts = array of filename extensions to match
+ *      recurse = go into subdirectories
+ *      filenameSink = accepts the resulting matches
+ * Returns:
+ *      true for failed to open the directory
+ */
+bool findFiles(const char* dir_path, const char[][] exts, bool recurse, void delegate(const(char)[]) nothrow filenameSink)
+{
+    enum log = false;
+    if (log) printf("findFiles() dir_path: %s\n", dir_path);
+    version (Windows)
+    {
+        debug
+            enum BufLength = 10;        // trigger any reallocation bugs
+        else
+            enum BufLength = 100;
+        char[BufLength + 1] buf = void;
+        char* fullPath = buf.ptr;
+        size_t fullPathLength = BufLength;
+
+        // fullPath = dir_path \ *.*
+        const dir_pathLength = strlen(dir_path);
+        auto count = dir_pathLength + 1 + 3;
+        if (count > fullPathLength)
+        {
+            fullPathLength = count;
+            fullPath = cast(char*)Mem.xrealloc_noscan(fullPath == buf.ptr ? null : fullPath, fullPathLength + 1);
+        }
+        memcpy(fullPath, dir_path, dir_pathLength);
+        strcpy(fullPath + dir_pathLength, "\\*.*".ptr);
+
+        if (log) printf("fullPath: %s\n", fullPath);
+
+        WIN32_FIND_DATAW ffd = void;
+        HANDLE hFind = fullPath[0 .. strlen(fullPath)].extendedPathThen!(p => FindFirstFileW(p.ptr, &ffd));
+        if (hFind == INVALID_HANDLE_VALUE)
+            return true;
+
+        do
+        {
+            if (log) wprintf("ffd.cFileName: %s\n", ffd.cFileName.ptr);
+            if (ffd.cFileName[0] == 0)
+                continue; // ignore
+
+            if (ffd.cFileName[0] == '.')
+                continue;           // ignore files that start with a ., also ignore . and .. directories
+
+            const(char)[] name = toNarrowStringz(ffd.cFileName[0 .. wcslen(ffd.cFileName.ptr)], null);
+            if (log) printf("name: %s\n", name.ptr);
+
+            // fullPath = dir_path \ name.ptr
+            count = dir_pathLength + 1 + name.length;
+            if (count > fullPathLength)
+            {
+                fullPathLength = count;
+                fullPath = cast(char*)Mem.xrealloc_noscan(fullPath == buf.ptr ? null : fullPath, fullPathLength + 1);
+            }
+            strcpy(fullPath + dir_pathLength + 1, name.ptr);
+
+            if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+            {
+                if (recurse)
+                    findFiles(fullPath, exts, recurse, filenameSink);
+            }
+            else
+            {
+                const(char)[] nameExt = FileName.ext(name);
+                foreach (ext; exts[])
+                {
+                    if (nameExt == ext)
+                    {
+                        if (log) printf("adding %s\n", fullPath);
+                        filenameSink(fullPath[0 .. count]);
+                    }
+                }
+            }
+            mem.xfree(cast(void*)name.ptr);
+
+        } while (FindNextFileW(hFind, &ffd) != 0);
+
+        if (fullPath != buf.ptr)
+            mem.xfree(fullPath);
+        FindClose(hFind);
+        if (log) printf("findFiles() exit\n");
+        return false;
+    }
+    else version (Posix)
+    {
+        DIR* dir = opendir(dir_path);
+        if (!dir)
+            return true;
+
+        debug
+            enum BufLength = 10;        // trigger any reallocation bugs
+        else
+            enum BufLength = 100;
+        char[BufLength + 1] buf = void;
+        char* fullPath = buf.ptr;
+        size_t fullPathLength = BufLength;
+
+        dirent* entry;
+        while ((entry = readdir(dir)) != null)
+        {
+            //printf("entry: %s\n", entry.d_name.ptr);
+            if (entry.d_name[0] == '.')
+                continue;           // ignore files that start with a .
+
+            // fullPath = dir_path / entry.d_name.ptr
+            const dir_pathLength = strlen(dir_path);
+            const count = dir_pathLength + 1 + strlen(entry.d_name.ptr);
+            if (count > fullPathLength)
+            {
+                fullPathLength = count;
+                fullPath = cast(char*)Mem.xrealloc_noscan(fullPath == buf.ptr ? null : fullPath, fullPathLength + 1);
+            }
+            memcpy(fullPath, dir_path, dir_pathLength);
+            fullPath[dir_pathLength] = '/';
+            strcpy(fullPath + dir_pathLength + 1, entry.d_name.ptr);
+
+            stat_t statbuf;
+            if (lstat(fullPath, &statbuf) == -1)
+                continue;
+
+            const(char)[] name = entry.d_name.ptr[0 .. strlen(entry.d_name.ptr)]; // convert to D string
+            if (!name.length)
+                continue; // ignore
+
+            if (S_ISDIR(statbuf.st_mode))
+            {
+                if (recurse && !(name == "." || name == ".."))
+                    findFiles(fullPath, exts, recurse, filenameSink);
+            }
+            else if (S_ISREG(statbuf.st_mode))
+            {
+                foreach (ext; exts)
+                {
+                    if (FileName.ext(name) == ext)
+                    {
+                        //printf("%s\n", fullPath);
+                        filenameSink(fullPath[0 .. count]);
+                    }
+                }
+            }
+        }
+
+        if (fullPath != buf.ptr)
+            mem.xfree(fullPath);
+        closedir(dir);
+        return false;
+    }
+    else
+        static assert(0);
+}
diff --git a/gcc/d/dmd/common/identifiertables.d b/gcc/d/dmd/common/identifiertables.d
new file mode 100644 (file)
index 0000000..b87e9fa
--- /dev/null
@@ -0,0 +1,4241 @@
+// Generated by compiler/tools/unicode_tables.d DO NOT MODIFY!!!
+module dmd.common.identifiertables;
+
+/**
+UAX31 profile Start
+Entries: 136892
+*/
+static immutable dchar[2][] UAX31_Start = [
+    [0xAA, 0xAA],
+    [0xB5, 0xB5],
+    [0xBA, 0xBA],
+    [0xC0, 0xD6],
+    [0xD8, 0xF6],
+    [0xF8, 0x2C1],
+    [0x2C6, 0x2D1],
+    [0x2E0, 0x2E4],
+    [0x2EC, 0x2EC],
+    [0x2EE, 0x2EE],
+    [0x370, 0x374],
+    [0x376, 0x377],
+    [0x37B, 0x37D],
+    [0x37F, 0x37F],
+    [0x386, 0x386],
+    [0x388, 0x38A],
+    [0x38C, 0x38C],
+    [0x38E, 0x3A1],
+    [0x3A3, 0x3F5],
+    [0x3F7, 0x481],
+    [0x48A, 0x52F],
+    [0x531, 0x556],
+    [0x559, 0x559],
+    [0x560, 0x588],
+    [0x5D0, 0x5EA],
+    [0x5EF, 0x5F2],
+    [0x620, 0x64A],
+    [0x66E, 0x66F],
+    [0x671, 0x6D3],
+    [0x6D5, 0x6D5],
+    [0x6E5, 0x6E6],
+    [0x6EE, 0x6EF],
+    [0x6FA, 0x6FC],
+    [0x6FF, 0x6FF],
+    [0x710, 0x710],
+    [0x712, 0x72F],
+    [0x74D, 0x7A5],
+    [0x7B1, 0x7B1],
+    [0x7CA, 0x7EA],
+    [0x7F4, 0x7F5],
+    [0x7FA, 0x7FA],
+    [0x800, 0x815],
+    [0x81A, 0x81A],
+    [0x824, 0x824],
+    [0x828, 0x828],
+    [0x840, 0x858],
+    [0x860, 0x86A],
+    [0x870, 0x887],
+    [0x889, 0x88E],
+    [0x8A0, 0x8C9],
+    [0x904, 0x939],
+    [0x93D, 0x93D],
+    [0x950, 0x950],
+    [0x958, 0x961],
+    [0x971, 0x980],
+    [0x985, 0x98C],
+    [0x98F, 0x990],
+    [0x993, 0x9A8],
+    [0x9AA, 0x9B0],
+    [0x9B2, 0x9B2],
+    [0x9B6, 0x9B9],
+    [0x9BD, 0x9BD],
+    [0x9CE, 0x9CE],
+    [0x9DC, 0x9DD],
+    [0x9DF, 0x9E1],
+    [0x9F0, 0x9F1],
+    [0x9FC, 0x9FC],
+    [0xA05, 0xA0A],
+    [0xA0F, 0xA10],
+    [0xA13, 0xA28],
+    [0xA2A, 0xA30],
+    [0xA32, 0xA33],
+    [0xA35, 0xA36],
+    [0xA38, 0xA39],
+    [0xA59, 0xA5C],
+    [0xA5E, 0xA5E],
+    [0xA72, 0xA74],
+    [0xA85, 0xA8D],
+    [0xA8F, 0xA91],
+    [0xA93, 0xAA8],
+    [0xAAA, 0xAB0],
+    [0xAB2, 0xAB3],
+    [0xAB5, 0xAB9],
+    [0xABD, 0xABD],
+    [0xAD0, 0xAD0],
+    [0xAE0, 0xAE1],
+    [0xAF9, 0xAF9],
+    [0xB05, 0xB0C],
+    [0xB0F, 0xB10],
+    [0xB13, 0xB28],
+    [0xB2A, 0xB30],
+    [0xB32, 0xB33],
+    [0xB35, 0xB39],
+    [0xB3D, 0xB3D],
+    [0xB5C, 0xB5D],
+    [0xB5F, 0xB61],
+    [0xB71, 0xB71],
+    [0xB83, 0xB83],
+    [0xB85, 0xB8A],
+    [0xB8E, 0xB90],
+    [0xB92, 0xB95],
+    [0xB99, 0xB9A],
+    [0xB9C, 0xB9C],
+    [0xB9E, 0xB9F],
+    [0xBA3, 0xBA4],
+    [0xBA8, 0xBAA],
+    [0xBAE, 0xBB9],
+    [0xBD0, 0xBD0],
+    [0xC05, 0xC0C],
+    [0xC0E, 0xC10],
+    [0xC12, 0xC28],
+    [0xC2A, 0xC39],
+    [0xC3D, 0xC3D],
+    [0xC58, 0xC5A],
+    [0xC5D, 0xC5D],
+    [0xC60, 0xC61],
+    [0xC80, 0xC80],
+    [0xC85, 0xC8C],
+    [0xC8E, 0xC90],
+    [0xC92, 0xCA8],
+    [0xCAA, 0xCB3],
+    [0xCB5, 0xCB9],
+    [0xCBD, 0xCBD],
+    [0xCDD, 0xCDE],
+    [0xCE0, 0xCE1],
+    [0xCF1, 0xCF2],
+    [0xD04, 0xD0C],
+    [0xD0E, 0xD10],
+    [0xD12, 0xD3A],
+    [0xD3D, 0xD3D],
+    [0xD4E, 0xD4E],
+    [0xD54, 0xD56],
+    [0xD5F, 0xD61],
+    [0xD7A, 0xD7F],
+    [0xD85, 0xD96],
+    [0xD9A, 0xDB1],
+    [0xDB3, 0xDBB],
+    [0xDBD, 0xDBD],
+    [0xDC0, 0xDC6],
+    [0xE01, 0xE30],
+    [0xE32, 0xE32],
+    [0xE40, 0xE46],
+    [0xE81, 0xE82],
+    [0xE84, 0xE84],
+    [0xE86, 0xE8A],
+    [0xE8C, 0xEA3],
+    [0xEA5, 0xEA5],
+    [0xEA7, 0xEB0],
+    [0xEB2, 0xEB2],
+    [0xEBD, 0xEBD],
+    [0xEC0, 0xEC4],
+    [0xEC6, 0xEC6],
+    [0xEDC, 0xEDF],
+    [0xF00, 0xF00],
+    [0xF40, 0xF47],
+    [0xF49, 0xF6C],
+    [0xF88, 0xF8C],
+    [0x1000, 0x102A],
+    [0x103F, 0x103F],
+    [0x1050, 0x1055],
+    [0x105A, 0x105D],
+    [0x1061, 0x1061],
+    [0x1065, 0x1066],
+    [0x106E, 0x1070],
+    [0x1075, 0x1081],
+    [0x108E, 0x108E],
+    [0x10A0, 0x10C5],
+    [0x10C7, 0x10C7],
+    [0x10CD, 0x10CD],
+    [0x10D0, 0x10FA],
+    [0x10FC, 0x1248],
+    [0x124A, 0x124D],
+    [0x1250, 0x1256],
+    [0x1258, 0x1258],
+    [0x125A, 0x125D],
+    [0x1260, 0x1288],
+    [0x128A, 0x128D],
+    [0x1290, 0x12B0],
+    [0x12B2, 0x12B5],
+    [0x12B8, 0x12BE],
+    [0x12C0, 0x12C0],
+    [0x12C2, 0x12C5],
+    [0x12C8, 0x12D6],
+    [0x12D8, 0x1310],
+    [0x1312, 0x1315],
+    [0x1318, 0x135A],
+    [0x1380, 0x138F],
+    [0x13A0, 0x13F5],
+    [0x13F8, 0x13FD],
+    [0x1401, 0x166C],
+    [0x166F, 0x167F],
+    [0x1681, 0x169A],
+    [0x16A0, 0x16EA],
+    [0x16EE, 0x16F8],
+    [0x1700, 0x1711],
+    [0x171F, 0x1731],
+    [0x1740, 0x1751],
+    [0x1760, 0x176C],
+    [0x176E, 0x1770],
+    [0x1780, 0x17B3],
+    [0x17D7, 0x17D7],
+    [0x17DC, 0x17DC],
+    [0x1820, 0x1878],
+    [0x1880, 0x18A8],
+    [0x18AA, 0x18AA],
+    [0x18B0, 0x18F5],
+    [0x1900, 0x191E],
+    [0x1950, 0x196D],
+    [0x1970, 0x1974],
+    [0x1980, 0x19AB],
+    [0x19B0, 0x19C9],
+    [0x1A00, 0x1A16],
+    [0x1A20, 0x1A54],
+    [0x1AA7, 0x1AA7],
+    [0x1B05, 0x1B33],
+    [0x1B45, 0x1B4C],
+    [0x1B83, 0x1BA0],
+    [0x1BAE, 0x1BAF],
+    [0x1BBA, 0x1BE5],
+    [0x1C00, 0x1C23],
+    [0x1C4D, 0x1C4F],
+    [0x1C5A, 0x1C7D],
+    [0x1C80, 0x1C88],
+    [0x1C90, 0x1CBA],
+    [0x1CBD, 0x1CBF],
+    [0x1CE9, 0x1CEC],
+    [0x1CEE, 0x1CF3],
+    [0x1CF5, 0x1CF6],
+    [0x1CFA, 0x1CFA],
+    [0x1D00, 0x1DBF],
+    [0x1E00, 0x1F15],
+    [0x1F18, 0x1F1D],
+    [0x1F20, 0x1F45],
+    [0x1F48, 0x1F4D],
+    [0x1F50, 0x1F57],
+    [0x1F59, 0x1F59],
+    [0x1F5B, 0x1F5B],
+    [0x1F5D, 0x1F5D],
+    [0x1F5F, 0x1F7D],
+    [0x1F80, 0x1FB4],
+    [0x1FB6, 0x1FBC],
+    [0x1FBE, 0x1FBE],
+    [0x1FC2, 0x1FC4],
+    [0x1FC6, 0x1FCC],
+    [0x1FD0, 0x1FD3],
+    [0x1FD6, 0x1FDB],
+    [0x1FE0, 0x1FEC],
+    [0x1FF2, 0x1FF4],
+    [0x1FF6, 0x1FFC],
+    [0x2071, 0x2071],
+    [0x207F, 0x207F],
+    [0x2090, 0x209C],
+    [0x2102, 0x2102],
+    [0x2107, 0x2107],
+    [0x210A, 0x2113],
+    [0x2115, 0x2115],
+    [0x2118, 0x211D],
+    [0x2124, 0x2124],
+    [0x2126, 0x2126],
+    [0x2128, 0x2128],
+    [0x212A, 0x2139],
+    [0x213C, 0x213F],
+    [0x2145, 0x2149],
+    [0x214E, 0x214E],
+    [0x2160, 0x2188],
+    [0x2C00, 0x2CE4],
+    [0x2CEB, 0x2CEE],
+    [0x2CF2, 0x2CF3],
+    [0x2D00, 0x2D25],
+    [0x2D27, 0x2D27],
+    [0x2D2D, 0x2D2D],
+    [0x2D30, 0x2D67],
+    [0x2D6F, 0x2D6F],
+    [0x2D80, 0x2D96],
+    [0x2DA0, 0x2DA6],
+    [0x2DA8, 0x2DAE],
+    [0x2DB0, 0x2DB6],
+    [0x2DB8, 0x2DBE],
+    [0x2DC0, 0x2DC6],
+    [0x2DC8, 0x2DCE],
+    [0x2DD0, 0x2DD6],
+    [0x2DD8, 0x2DDE],
+    [0x3005, 0x3007],
+    [0x3021, 0x3029],
+    [0x3031, 0x3035],
+    [0x3038, 0x303C],
+    [0x3041, 0x3096],
+    [0x309D, 0x309F],
+    [0x30A1, 0x30FA],
+    [0x30FC, 0x30FF],
+    [0x3105, 0x312F],
+    [0x3131, 0x318E],
+    [0x31A0, 0x31BF],
+    [0x31F0, 0x31FF],
+    [0x3400, 0x4DBF],
+    [0x4E00, 0xA48C],
+    [0xA4D0, 0xA4FD],
+    [0xA500, 0xA60C],
+    [0xA610, 0xA61F],
+    [0xA62A, 0xA62B],
+    [0xA640, 0xA66E],
+    [0xA67F, 0xA69D],
+    [0xA6A0, 0xA6EF],
+    [0xA717, 0xA71F],
+    [0xA722, 0xA788],
+    [0xA78B, 0xA7CA],
+    [0xA7D0, 0xA7D1],
+    [0xA7D3, 0xA7D3],
+    [0xA7D5, 0xA7D9],
+    [0xA7F2, 0xA801],
+    [0xA803, 0xA805],
+    [0xA807, 0xA80A],
+    [0xA80C, 0xA822],
+    [0xA840, 0xA873],
+    [0xA882, 0xA8B3],
+    [0xA8F2, 0xA8F7],
+    [0xA8FB, 0xA8FB],
+    [0xA8FD, 0xA8FE],
+    [0xA90A, 0xA925],
+    [0xA930, 0xA946],
+    [0xA960, 0xA97C],
+    [0xA984, 0xA9B2],
+    [0xA9CF, 0xA9CF],
+    [0xA9E0, 0xA9E4],
+    [0xA9E6, 0xA9EF],
+    [0xA9FA, 0xA9FE],
+    [0xAA00, 0xAA28],
+    [0xAA40, 0xAA42],
+    [0xAA44, 0xAA4B],
+    [0xAA60, 0xAA76],
+    [0xAA7A, 0xAA7A],
+    [0xAA7E, 0xAAAF],
+    [0xAAB1, 0xAAB1],
+    [0xAAB5, 0xAAB6],
+    [0xAAB9, 0xAABD],
+    [0xAAC0, 0xAAC0],
+    [0xAAC2, 0xAAC2],
+    [0xAADB, 0xAADD],
+    [0xAAE0, 0xAAEA],
+    [0xAAF2, 0xAAF4],
+    [0xAB01, 0xAB06],
+    [0xAB09, 0xAB0E],
+    [0xAB11, 0xAB16],
+    [0xAB20, 0xAB26],
+    [0xAB28, 0xAB2E],
+    [0xAB30, 0xAB5A],
+    [0xAB5C, 0xAB69],
+    [0xAB70, 0xABE2],
+    [0xAC00, 0xD7A3],
+    [0xD7B0, 0xD7C6],
+    [0xD7CB, 0xD7FB],
+    [0xF900, 0xFA6D],
+    [0xFA70, 0xFAD9],
+    [0xFB00, 0xFB06],
+    [0xFB13, 0xFB17],
+    [0xFB1D, 0xFB1D],
+    [0xFB1F, 0xFB28],
+    [0xFB2A, 0xFB36],
+    [0xFB38, 0xFB3C],
+    [0xFB3E, 0xFB3E],
+    [0xFB40, 0xFB41],
+    [0xFB43, 0xFB44],
+    [0xFB46, 0xFBB1],
+    [0xFBD3, 0xFC5D],
+    [0xFC64, 0xFD3D],
+    [0xFD50, 0xFD8F],
+    [0xFD92, 0xFDC7],
+    [0xFDF0, 0xFDF9],
+    [0xFE71, 0xFE71],
+    [0xFE73, 0xFE73],
+    [0xFE77, 0xFE77],
+    [0xFE79, 0xFE79],
+    [0xFE7B, 0xFE7B],
+    [0xFE7D, 0xFE7D],
+    [0xFE7F, 0xFEFC],
+    [0xFF21, 0xFF3A],
+    [0xFF41, 0xFF5A],
+    [0xFF66, 0xFF9D],
+    [0xFFA0, 0xFFBE],
+    [0xFFC2, 0xFFC7],
+    [0xFFCA, 0xFFCF],
+    [0xFFD2, 0xFFD7],
+    [0xFFDA, 0xFFDC],
+    [0x10000, 0x1000B],
+    [0x1000D, 0x10026],
+    [0x10028, 0x1003A],
+    [0x1003C, 0x1003D],
+    [0x1003F, 0x1004D],
+    [0x10050, 0x1005D],
+    [0x10080, 0x100FA],
+    [0x10140, 0x10174],
+    [0x10280, 0x1029C],
+    [0x102A0, 0x102D0],
+    [0x10300, 0x1031F],
+    [0x1032D, 0x1034A],
+    [0x10350, 0x10375],
+    [0x10380, 0x1039D],
+    [0x103A0, 0x103C3],
+    [0x103C8, 0x103CF],
+    [0x103D1, 0x103D5],
+    [0x10400, 0x1049D],
+    [0x104B0, 0x104D3],
+    [0x104D8, 0x104FB],
+    [0x10500, 0x10527],
+    [0x10530, 0x10563],
+    [0x10570, 0x1057A],
+    [0x1057C, 0x1058A],
+    [0x1058C, 0x10592],
+    [0x10594, 0x10595],
+    [0x10597, 0x105A1],
+    [0x105A3, 0x105B1],
+    [0x105B3, 0x105B9],
+    [0x105BB, 0x105BC],
+    [0x10600, 0x10736],
+    [0x10740, 0x10755],
+    [0x10760, 0x10767],
+    [0x10780, 0x10785],
+    [0x10787, 0x107B0],
+    [0x107B2, 0x107BA],
+    [0x10800, 0x10805],
+    [0x10808, 0x10808],
+    [0x1080A, 0x10835],
+    [0x10837, 0x10838],
+    [0x1083C, 0x1083C],
+    [0x1083F, 0x10855],
+    [0x10860, 0x10876],
+    [0x10880, 0x1089E],
+    [0x108E0, 0x108F2],
+    [0x108F4, 0x108F5],
+    [0x10900, 0x10915],
+    [0x10920, 0x10939],
+    [0x10980, 0x109B7],
+    [0x109BE, 0x109BF],
+    [0x10A00, 0x10A00],
+    [0x10A10, 0x10A13],
+    [0x10A15, 0x10A17],
+    [0x10A19, 0x10A35],
+    [0x10A60, 0x10A7C],
+    [0x10A80, 0x10A9C],
+    [0x10AC0, 0x10AC7],
+    [0x10AC9, 0x10AE4],
+    [0x10B00, 0x10B35],
+    [0x10B40, 0x10B55],
+    [0x10B60, 0x10B72],
+    [0x10B80, 0x10B91],
+    [0x10C00, 0x10C48],
+    [0x10C80, 0x10CB2],
+    [0x10CC0, 0x10CF2],
+    [0x10D00, 0x10D23],
+    [0x10E80, 0x10EA9],
+    [0x10EB0, 0x10EB1],
+    [0x10F00, 0x10F1C],
+    [0x10F27, 0x10F27],
+    [0x10F30, 0x10F45],
+    [0x10F70, 0x10F81],
+    [0x10FB0, 0x10FC4],
+    [0x10FE0, 0x10FF6],
+    [0x11003, 0x11037],
+    [0x11071, 0x11072],
+    [0x11075, 0x11075],
+    [0x11083, 0x110AF],
+    [0x110D0, 0x110E8],
+    [0x11103, 0x11126],
+    [0x11144, 0x11144],
+    [0x11147, 0x11147],
+    [0x11150, 0x11172],
+    [0x11176, 0x11176],
+    [0x11183, 0x111B2],
+    [0x111C1, 0x111C4],
+    [0x111DA, 0x111DA],
+    [0x111DC, 0x111DC],
+    [0x11200, 0x11211],
+    [0x11213, 0x1122B],
+    [0x1123F, 0x11240],
+    [0x11280, 0x11286],
+    [0x11288, 0x11288],
+    [0x1128A, 0x1128D],
+    [0x1128F, 0x1129D],
+    [0x1129F, 0x112A8],
+    [0x112B0, 0x112DE],
+    [0x11305, 0x1130C],
+    [0x1130F, 0x11310],
+    [0x11313, 0x11328],
+    [0x1132A, 0x11330],
+    [0x11332, 0x11333],
+    [0x11335, 0x11339],
+    [0x1133D, 0x1133D],
+    [0x11350, 0x11350],
+    [0x1135D, 0x11361],
+    [0x11400, 0x11434],
+    [0x11447, 0x1144A],
+    [0x1145F, 0x11461],
+    [0x11480, 0x114AF],
+    [0x114C4, 0x114C5],
+    [0x114C7, 0x114C7],
+    [0x11580, 0x115AE],
+    [0x115D8, 0x115DB],
+    [0x11600, 0x1162F],
+    [0x11644, 0x11644],
+    [0x11680, 0x116AA],
+    [0x116B8, 0x116B8],
+    [0x11700, 0x1171A],
+    [0x11740, 0x11746],
+    [0x11800, 0x1182B],
+    [0x118A0, 0x118DF],
+    [0x118FF, 0x11906],
+    [0x11909, 0x11909],
+    [0x1190C, 0x11913],
+    [0x11915, 0x11916],
+    [0x11918, 0x1192F],
+    [0x1193F, 0x1193F],
+    [0x11941, 0x11941],
+    [0x119A0, 0x119A7],
+    [0x119AA, 0x119D0],
+    [0x119E1, 0x119E1],
+    [0x119E3, 0x119E3],
+    [0x11A00, 0x11A00],
+    [0x11A0B, 0x11A32],
+    [0x11A3A, 0x11A3A],
+    [0x11A50, 0x11A50],
+    [0x11A5C, 0x11A89],
+    [0x11A9D, 0x11A9D],
+    [0x11AB0, 0x11AF8],
+    [0x11C00, 0x11C08],
+    [0x11C0A, 0x11C2E],
+    [0x11C40, 0x11C40],
+    [0x11C72, 0x11C8F],
+    [0x11D00, 0x11D06],
+    [0x11D08, 0x11D09],
+    [0x11D0B, 0x11D30],
+    [0x11D46, 0x11D46],
+    [0x11D60, 0x11D65],
+    [0x11D67, 0x11D68],
+    [0x11D6A, 0x11D89],
+    [0x11D98, 0x11D98],
+    [0x11EE0, 0x11EF2],
+    [0x11F02, 0x11F02],
+    [0x11F04, 0x11F10],
+    [0x11F12, 0x11F33],
+    [0x11FB0, 0x11FB0],
+    [0x12000, 0x12399],
+    [0x12400, 0x1246E],
+    [0x12480, 0x12543],
+    [0x12F90, 0x12FF0],
+    [0x13000, 0x1342F],
+    [0x13441, 0x13446],
+    [0x14400, 0x14646],
+    [0x16800, 0x16A38],
+    [0x16A40, 0x16A5E],
+    [0x16A70, 0x16ABE],
+    [0x16AD0, 0x16AED],
+    [0x16B00, 0x16B2F],
+    [0x16B40, 0x16B43],
+    [0x16B63, 0x16B77],
+    [0x16B7D, 0x16B8F],
+    [0x16E40, 0x16E7F],
+    [0x16F00, 0x16F4A],
+    [0x16F50, 0x16F50],
+    [0x16F93, 0x16F9F],
+    [0x16FE0, 0x16FE1],
+    [0x16FE3, 0x16FE3],
+    [0x17000, 0x187F7],
+    [0x18800, 0x18CD5],
+    [0x18D00, 0x18D08],
+    [0x1AFF0, 0x1AFF3],
+    [0x1AFF5, 0x1AFFB],
+    [0x1AFFD, 0x1AFFE],
+    [0x1B000, 0x1B122],
+    [0x1B132, 0x1B132],
+    [0x1B150, 0x1B152],
+    [0x1B155, 0x1B155],
+    [0x1B164, 0x1B167],
+    [0x1B170, 0x1B2FB],
+    [0x1BC00, 0x1BC6A],
+    [0x1BC70, 0x1BC7C],
+    [0x1BC80, 0x1BC88],
+    [0x1BC90, 0x1BC99],
+    [0x1D400, 0x1D454],
+    [0x1D456, 0x1D49C],
+    [0x1D49E, 0x1D49F],
+    [0x1D4A2, 0x1D4A2],
+    [0x1D4A5, 0x1D4A6],
+    [0x1D4A9, 0x1D4AC],
+    [0x1D4AE, 0x1D4B9],
+    [0x1D4BB, 0x1D4BB],
+    [0x1D4BD, 0x1D4C3],
+    [0x1D4C5, 0x1D505],
+    [0x1D507, 0x1D50A],
+    [0x1D50D, 0x1D514],
+    [0x1D516, 0x1D51C],
+    [0x1D51E, 0x1D539],
+    [0x1D53B, 0x1D53E],
+    [0x1D540, 0x1D544],
+    [0x1D546, 0x1D546],
+    [0x1D54A, 0x1D550],
+    [0x1D552, 0x1D6A5],
+    [0x1D6A8, 0x1D6C0],
+    [0x1D6C2, 0x1D6DA],
+    [0x1D6DC, 0x1D6FA],
+    [0x1D6FC, 0x1D714],
+    [0x1D716, 0x1D734],
+    [0x1D736, 0x1D74E],
+    [0x1D750, 0x1D76E],
+    [0x1D770, 0x1D788],
+    [0x1D78A, 0x1D7A8],
+    [0x1D7AA, 0x1D7C2],
+    [0x1D7C4, 0x1D7CB],
+    [0x1DF00, 0x1DF1E],
+    [0x1DF25, 0x1DF2A],
+    [0x1E030, 0x1E06D],
+    [0x1E100, 0x1E12C],
+    [0x1E137, 0x1E13D],
+    [0x1E14E, 0x1E14E],
+    [0x1E290, 0x1E2AD],
+    [0x1E2C0, 0x1E2EB],
+    [0x1E4D0, 0x1E4EB],
+    [0x1E7E0, 0x1E7E6],
+    [0x1E7E8, 0x1E7EB],
+    [0x1E7ED, 0x1E7EE],
+    [0x1E7F0, 0x1E7FE],
+    [0x1E800, 0x1E8C4],
+    [0x1E900, 0x1E943],
+    [0x1E94B, 0x1E94B],
+    [0x1EE00, 0x1EE03],
+    [0x1EE05, 0x1EE1F],
+    [0x1EE21, 0x1EE22],
+    [0x1EE24, 0x1EE24],
+    [0x1EE27, 0x1EE27],
+    [0x1EE29, 0x1EE32],
+    [0x1EE34, 0x1EE37],
+    [0x1EE39, 0x1EE39],
+    [0x1EE3B, 0x1EE3B],
+    [0x1EE42, 0x1EE42],
+    [0x1EE47, 0x1EE47],
+    [0x1EE49, 0x1EE49],
+    [0x1EE4B, 0x1EE4B],
+    [0x1EE4D, 0x1EE4F],
+    [0x1EE51, 0x1EE52],
+    [0x1EE54, 0x1EE54],
+    [0x1EE57, 0x1EE57],
+    [0x1EE59, 0x1EE59],
+    [0x1EE5B, 0x1EE5B],
+    [0x1EE5D, 0x1EE5D],
+    [0x1EE5F, 0x1EE5F],
+    [0x1EE61, 0x1EE62],
+    [0x1EE64, 0x1EE64],
+    [0x1EE67, 0x1EE6A],
+    [0x1EE6C, 0x1EE72],
+    [0x1EE74, 0x1EE77],
+    [0x1EE79, 0x1EE7C],
+    [0x1EE7E, 0x1EE7E],
+    [0x1EE80, 0x1EE89],
+    [0x1EE8B, 0x1EE9B],
+    [0x1EEA1, 0x1EEA3],
+    [0x1EEA5, 0x1EEA9],
+    [0x1EEAB, 0x1EEBB],
+    [0x20000, 0x2A6DF],
+    [0x2A700, 0x2B739],
+    [0x2B740, 0x2B81D],
+    [0x2B820, 0x2CEA1],
+    [0x2CEB0, 0x2EBE0],
+    [0x2EBF0, 0x2EE5D],
+    [0x2F800, 0x2FA1D],
+    [0x30000, 0x3134A],
+    [0x31350, 0x323AF],
+];
+
+/**
+UAX31 profile Continue
+Entries: 140026
+*/
+static immutable dchar[2][] UAX31_Continue = [
+    [0xAA, 0xAA],
+    [0xB5, 0xB5],
+    [0xB7, 0xB7],
+    [0xBA, 0xBA],
+    [0xC0, 0xD6],
+    [0xD8, 0xF6],
+    [0xF8, 0x2C1],
+    [0x2C6, 0x2D1],
+    [0x2E0, 0x2E4],
+    [0x2EC, 0x2EC],
+    [0x2EE, 0x2EE],
+    [0x300, 0x374],
+    [0x376, 0x377],
+    [0x37B, 0x37D],
+    [0x37F, 0x37F],
+    [0x386, 0x38A],
+    [0x38C, 0x38C],
+    [0x38E, 0x3A1],
+    [0x3A3, 0x3F5],
+    [0x3F7, 0x481],
+    [0x483, 0x487],
+    [0x48A, 0x52F],
+    [0x531, 0x556],
+    [0x559, 0x559],
+    [0x560, 0x588],
+    [0x591, 0x5BD],
+    [0x5BF, 0x5BF],
+    [0x5C1, 0x5C2],
+    [0x5C4, 0x5C5],
+    [0x5C7, 0x5C7],
+    [0x5D0, 0x5EA],
+    [0x5EF, 0x5F2],
+    [0x610, 0x61A],
+    [0x620, 0x669],
+    [0x66E, 0x6D3],
+    [0x6D5, 0x6DC],
+    [0x6DF, 0x6E8],
+    [0x6EA, 0x6FC],
+    [0x6FF, 0x6FF],
+    [0x710, 0x74A],
+    [0x74D, 0x7B1],
+    [0x7C0, 0x7F5],
+    [0x7FA, 0x7FA],
+    [0x7FD, 0x7FD],
+    [0x800, 0x82D],
+    [0x840, 0x85B],
+    [0x860, 0x86A],
+    [0x870, 0x887],
+    [0x889, 0x88E],
+    [0x898, 0x8E1],
+    [0x8E3, 0x963],
+    [0x966, 0x96F],
+    [0x971, 0x983],
+    [0x985, 0x98C],
+    [0x98F, 0x990],
+    [0x993, 0x9A8],
+    [0x9AA, 0x9B0],
+    [0x9B2, 0x9B2],
+    [0x9B6, 0x9B9],
+    [0x9BC, 0x9C4],
+    [0x9C7, 0x9C8],
+    [0x9CB, 0x9CE],
+    [0x9D7, 0x9D7],
+    [0x9DC, 0x9DD],
+    [0x9DF, 0x9E3],
+    [0x9E6, 0x9F1],
+    [0x9FC, 0x9FC],
+    [0x9FE, 0x9FE],
+    [0xA01, 0xA03],
+    [0xA05, 0xA0A],
+    [0xA0F, 0xA10],
+    [0xA13, 0xA28],
+    [0xA2A, 0xA30],
+    [0xA32, 0xA33],
+    [0xA35, 0xA36],
+    [0xA38, 0xA39],
+    [0xA3C, 0xA3C],
+    [0xA3E, 0xA42],
+    [0xA47, 0xA48],
+    [0xA4B, 0xA4D],
+    [0xA51, 0xA51],
+    [0xA59, 0xA5C],
+    [0xA5E, 0xA5E],
+    [0xA66, 0xA75],
+    [0xA81, 0xA83],
+    [0xA85, 0xA8D],
+    [0xA8F, 0xA91],
+    [0xA93, 0xAA8],
+    [0xAAA, 0xAB0],
+    [0xAB2, 0xAB3],
+    [0xAB5, 0xAB9],
+    [0xABC, 0xAC5],
+    [0xAC7, 0xAC9],
+    [0xACB, 0xACD],
+    [0xAD0, 0xAD0],
+    [0xAE0, 0xAE3],
+    [0xAE6, 0xAEF],
+    [0xAF9, 0xAFF],
+    [0xB01, 0xB03],
+    [0xB05, 0xB0C],
+    [0xB0F, 0xB10],
+    [0xB13, 0xB28],
+    [0xB2A, 0xB30],
+    [0xB32, 0xB33],
+    [0xB35, 0xB39],
+    [0xB3C, 0xB44],
+    [0xB47, 0xB48],
+    [0xB4B, 0xB4D],
+    [0xB55, 0xB57],
+    [0xB5C, 0xB5D],
+    [0xB5F, 0xB63],
+    [0xB66, 0xB6F],
+    [0xB71, 0xB71],
+    [0xB82, 0xB83],
+    [0xB85, 0xB8A],
+    [0xB8E, 0xB90],
+    [0xB92, 0xB95],
+    [0xB99, 0xB9A],
+    [0xB9C, 0xB9C],
+    [0xB9E, 0xB9F],
+    [0xBA3, 0xBA4],
+    [0xBA8, 0xBAA],
+    [0xBAE, 0xBB9],
+    [0xBBE, 0xBC2],
+    [0xBC6, 0xBC8],
+    [0xBCA, 0xBCD],
+    [0xBD0, 0xBD0],
+    [0xBD7, 0xBD7],
+    [0xBE6, 0xBEF],
+    [0xC00, 0xC0C],
+    [0xC0E, 0xC10],
+    [0xC12, 0xC28],
+    [0xC2A, 0xC39],
+    [0xC3C, 0xC44],
+    [0xC46, 0xC48],
+    [0xC4A, 0xC4D],
+    [0xC55, 0xC56],
+    [0xC58, 0xC5A],
+    [0xC5D, 0xC5D],
+    [0xC60, 0xC63],
+    [0xC66, 0xC6F],
+    [0xC80, 0xC83],
+    [0xC85, 0xC8C],
+    [0xC8E, 0xC90],
+    [0xC92, 0xCA8],
+    [0xCAA, 0xCB3],
+    [0xCB5, 0xCB9],
+    [0xCBC, 0xCC4],
+    [0xCC6, 0xCC8],
+    [0xCCA, 0xCCD],
+    [0xCD5, 0xCD6],
+    [0xCDD, 0xCDE],
+    [0xCE0, 0xCE3],
+    [0xCE6, 0xCEF],
+    [0xCF1, 0xCF3],
+    [0xD00, 0xD0C],
+    [0xD0E, 0xD10],
+    [0xD12, 0xD44],
+    [0xD46, 0xD48],
+    [0xD4A, 0xD4E],
+    [0xD54, 0xD57],
+    [0xD5F, 0xD63],
+    [0xD66, 0xD6F],
+    [0xD7A, 0xD7F],
+    [0xD81, 0xD83],
+    [0xD85, 0xD96],
+    [0xD9A, 0xDB1],
+    [0xDB3, 0xDBB],
+    [0xDBD, 0xDBD],
+    [0xDC0, 0xDC6],
+    [0xDCA, 0xDCA],
+    [0xDCF, 0xDD4],
+    [0xDD6, 0xDD6],
+    [0xDD8, 0xDDF],
+    [0xDE6, 0xDEF],
+    [0xDF2, 0xDF3],
+    [0xE01, 0xE3A],
+    [0xE40, 0xE4E],
+    [0xE50, 0xE59],
+    [0xE81, 0xE82],
+    [0xE84, 0xE84],
+    [0xE86, 0xE8A],
+    [0xE8C, 0xEA3],
+    [0xEA5, 0xEA5],
+    [0xEA7, 0xEBD],
+    [0xEC0, 0xEC4],
+    [0xEC6, 0xEC6],
+    [0xEC8, 0xECE],
+    [0xED0, 0xED9],
+    [0xEDC, 0xEDF],
+    [0xF00, 0xF00],
+    [0xF18, 0xF19],
+    [0xF20, 0xF29],
+    [0xF35, 0xF35],
+    [0xF37, 0xF37],
+    [0xF39, 0xF39],
+    [0xF3E, 0xF47],
+    [0xF49, 0xF6C],
+    [0xF71, 0xF84],
+    [0xF86, 0xF97],
+    [0xF99, 0xFBC],
+    [0xFC6, 0xFC6],
+    [0x1000, 0x1049],
+    [0x1050, 0x109D],
+    [0x10A0, 0x10C5],
+    [0x10C7, 0x10C7],
+    [0x10CD, 0x10CD],
+    [0x10D0, 0x10FA],
+    [0x10FC, 0x1248],
+    [0x124A, 0x124D],
+    [0x1250, 0x1256],
+    [0x1258, 0x1258],
+    [0x125A, 0x125D],
+    [0x1260, 0x1288],
+    [0x128A, 0x128D],
+    [0x1290, 0x12B0],
+    [0x12B2, 0x12B5],
+    [0x12B8, 0x12BE],
+    [0x12C0, 0x12C0],
+    [0x12C2, 0x12C5],
+    [0x12C8, 0x12D6],
+    [0x12D8, 0x1310],
+    [0x1312, 0x1315],
+    [0x1318, 0x135A],
+    [0x135D, 0x135F],
+    [0x1369, 0x1371],
+    [0x1380, 0x138F],
+    [0x13A0, 0x13F5],
+    [0x13F8, 0x13FD],
+    [0x1401, 0x166C],
+    [0x166F, 0x167F],
+    [0x1681, 0x169A],
+    [0x16A0, 0x16EA],
+    [0x16EE, 0x16F8],
+    [0x1700, 0x1715],
+    [0x171F, 0x1734],
+    [0x1740, 0x1753],
+    [0x1760, 0x176C],
+    [0x176E, 0x1770],
+    [0x1772, 0x1773],
+    [0x1780, 0x17D3],
+    [0x17D7, 0x17D7],
+    [0x17DC, 0x17DD],
+    [0x17E0, 0x17E9],
+    [0x180B, 0x180D],
+    [0x180F, 0x1819],
+    [0x1820, 0x1878],
+    [0x1880, 0x18AA],
+    [0x18B0, 0x18F5],
+    [0x1900, 0x191E],
+    [0x1920, 0x192B],
+    [0x1930, 0x193B],
+    [0x1946, 0x196D],
+    [0x1970, 0x1974],
+    [0x1980, 0x19AB],
+    [0x19B0, 0x19C9],
+    [0x19D0, 0x19DA],
+    [0x1A00, 0x1A1B],
+    [0x1A20, 0x1A5E],
+    [0x1A60, 0x1A7C],
+    [0x1A7F, 0x1A89],
+    [0x1A90, 0x1A99],
+    [0x1AA7, 0x1AA7],
+    [0x1AB0, 0x1ABD],
+    [0x1ABF, 0x1ACE],
+    [0x1B00, 0x1B4C],
+    [0x1B50, 0x1B59],
+    [0x1B6B, 0x1B73],
+    [0x1B80, 0x1BF3],
+    [0x1C00, 0x1C37],
+    [0x1C40, 0x1C49],
+    [0x1C4D, 0x1C7D],
+    [0x1C80, 0x1C88],
+    [0x1C90, 0x1CBA],
+    [0x1CBD, 0x1CBF],
+    [0x1CD0, 0x1CD2],
+    [0x1CD4, 0x1CFA],
+    [0x1D00, 0x1F15],
+    [0x1F18, 0x1F1D],
+    [0x1F20, 0x1F45],
+    [0x1F48, 0x1F4D],
+    [0x1F50, 0x1F57],
+    [0x1F59, 0x1F59],
+    [0x1F5B, 0x1F5B],
+    [0x1F5D, 0x1F5D],
+    [0x1F5F, 0x1F7D],
+    [0x1F80, 0x1FB4],
+    [0x1FB6, 0x1FBC],
+    [0x1FBE, 0x1FBE],
+    [0x1FC2, 0x1FC4],
+    [0x1FC6, 0x1FCC],
+    [0x1FD0, 0x1FD3],
+    [0x1FD6, 0x1FDB],
+    [0x1FE0, 0x1FEC],
+    [0x1FF2, 0x1FF4],
+    [0x1FF6, 0x1FFC],
+    [0x200C, 0x200D],
+    [0x203F, 0x2040],
+    [0x2054, 0x2054],
+    [0x2071, 0x2071],
+    [0x207F, 0x207F],
+    [0x2090, 0x209C],
+    [0x20D0, 0x20DC],
+    [0x20E1, 0x20E1],
+    [0x20E5, 0x20F0],
+    [0x2102, 0x2102],
+    [0x2107, 0x2107],
+    [0x210A, 0x2113],
+    [0x2115, 0x2115],
+    [0x2118, 0x211D],
+    [0x2124, 0x2124],
+    [0x2126, 0x2126],
+    [0x2128, 0x2128],
+    [0x212A, 0x2139],
+    [0x213C, 0x213F],
+    [0x2145, 0x2149],
+    [0x214E, 0x214E],
+    [0x2160, 0x2188],
+    [0x2C00, 0x2CE4],
+    [0x2CEB, 0x2CF3],
+    [0x2D00, 0x2D25],
+    [0x2D27, 0x2D27],
+    [0x2D2D, 0x2D2D],
+    [0x2D30, 0x2D67],
+    [0x2D6F, 0x2D6F],
+    [0x2D7F, 0x2D96],
+    [0x2DA0, 0x2DA6],
+    [0x2DA8, 0x2DAE],
+    [0x2DB0, 0x2DB6],
+    [0x2DB8, 0x2DBE],
+    [0x2DC0, 0x2DC6],
+    [0x2DC8, 0x2DCE],
+    [0x2DD0, 0x2DD6],
+    [0x2DD8, 0x2DDE],
+    [0x2DE0, 0x2DFF],
+    [0x3005, 0x3007],
+    [0x3021, 0x302F],
+    [0x3031, 0x3035],
+    [0x3038, 0x303C],
+    [0x3041, 0x3096],
+    [0x3099, 0x309A],
+    [0x309D, 0x309F],
+    [0x30A1, 0x30FF],
+    [0x3105, 0x312F],
+    [0x3131, 0x318E],
+    [0x31A0, 0x31BF],
+    [0x31F0, 0x31FF],
+    [0x3400, 0x4DBF],
+    [0x4E00, 0xA48C],
+    [0xA4D0, 0xA4FD],
+    [0xA500, 0xA60C],
+    [0xA610, 0xA62B],
+    [0xA640, 0xA66F],
+    [0xA674, 0xA67D],
+    [0xA67F, 0xA6F1],
+    [0xA717, 0xA71F],
+    [0xA722, 0xA788],
+    [0xA78B, 0xA7CA],
+    [0xA7D0, 0xA7D1],
+    [0xA7D3, 0xA7D3],
+    [0xA7D5, 0xA7D9],
+    [0xA7F2, 0xA827],
+    [0xA82C, 0xA82C],
+    [0xA840, 0xA873],
+    [0xA880, 0xA8C5],
+    [0xA8D0, 0xA8D9],
+    [0xA8E0, 0xA8F7],
+    [0xA8FB, 0xA8FB],
+    [0xA8FD, 0xA92D],
+    [0xA930, 0xA953],
+    [0xA960, 0xA97C],
+    [0xA980, 0xA9C0],
+    [0xA9CF, 0xA9D9],
+    [0xA9E0, 0xA9FE],
+    [0xAA00, 0xAA36],
+    [0xAA40, 0xAA4D],
+    [0xAA50, 0xAA59],
+    [0xAA60, 0xAA76],
+    [0xAA7A, 0xAAC2],
+    [0xAADB, 0xAADD],
+    [0xAAE0, 0xAAEF],
+    [0xAAF2, 0xAAF6],
+    [0xAB01, 0xAB06],
+    [0xAB09, 0xAB0E],
+    [0xAB11, 0xAB16],
+    [0xAB20, 0xAB26],
+    [0xAB28, 0xAB2E],
+    [0xAB30, 0xAB5A],
+    [0xAB5C, 0xAB69],
+    [0xAB70, 0xABEA],
+    [0xABEC, 0xABED],
+    [0xABF0, 0xABF9],
+    [0xAC00, 0xD7A3],
+    [0xD7B0, 0xD7C6],
+    [0xD7CB, 0xD7FB],
+    [0xF900, 0xFA6D],
+    [0xFA70, 0xFAD9],
+    [0xFB00, 0xFB06],
+    [0xFB13, 0xFB17],
+    [0xFB1D, 0xFB28],
+    [0xFB2A, 0xFB36],
+    [0xFB38, 0xFB3C],
+    [0xFB3E, 0xFB3E],
+    [0xFB40, 0xFB41],
+    [0xFB43, 0xFB44],
+    [0xFB46, 0xFBB1],
+    [0xFBD3, 0xFC5D],
+    [0xFC64, 0xFD3D],
+    [0xFD50, 0xFD8F],
+    [0xFD92, 0xFDC7],
+    [0xFDF0, 0xFDF9],
+    [0xFE00, 0xFE0F],
+    [0xFE20, 0xFE2F],
+    [0xFE33, 0xFE34],
+    [0xFE4D, 0xFE4F],
+    [0xFE71, 0xFE71],
+    [0xFE73, 0xFE73],
+    [0xFE77, 0xFE77],
+    [0xFE79, 0xFE79],
+    [0xFE7B, 0xFE7B],
+    [0xFE7D, 0xFE7D],
+    [0xFE7F, 0xFEFC],
+    [0xFF10, 0xFF19],
+    [0xFF21, 0xFF3A],
+    [0xFF3F, 0xFF3F],
+    [0xFF41, 0xFF5A],
+    [0xFF65, 0xFFBE],
+    [0xFFC2, 0xFFC7],
+    [0xFFCA, 0xFFCF],
+    [0xFFD2, 0xFFD7],
+    [0xFFDA, 0xFFDC],
+    [0x10000, 0x1000B],
+    [0x1000D, 0x10026],
+    [0x10028, 0x1003A],
+    [0x1003C, 0x1003D],
+    [0x1003F, 0x1004D],
+    [0x10050, 0x1005D],
+    [0x10080, 0x100FA],
+    [0x10140, 0x10174],
+    [0x101FD, 0x101FD],
+    [0x10280, 0x1029C],
+    [0x102A0, 0x102D0],
+    [0x102E0, 0x102E0],
+    [0x10300, 0x1031F],
+    [0x1032D, 0x1034A],
+    [0x10350, 0x1037A],
+    [0x10380, 0x1039D],
+    [0x103A0, 0x103C3],
+    [0x103C8, 0x103CF],
+    [0x103D1, 0x103D5],
+    [0x10400, 0x1049D],
+    [0x104A0, 0x104A9],
+    [0x104B0, 0x104D3],
+    [0x104D8, 0x104FB],
+    [0x10500, 0x10527],
+    [0x10530, 0x10563],
+    [0x10570, 0x1057A],
+    [0x1057C, 0x1058A],
+    [0x1058C, 0x10592],
+    [0x10594, 0x10595],
+    [0x10597, 0x105A1],
+    [0x105A3, 0x105B1],
+    [0x105B3, 0x105B9],
+    [0x105BB, 0x105BC],
+    [0x10600, 0x10736],
+    [0x10740, 0x10755],
+    [0x10760, 0x10767],
+    [0x10780, 0x10785],
+    [0x10787, 0x107B0],
+    [0x107B2, 0x107BA],
+    [0x10800, 0x10805],
+    [0x10808, 0x10808],
+    [0x1080A, 0x10835],
+    [0x10837, 0x10838],
+    [0x1083C, 0x1083C],
+    [0x1083F, 0x10855],
+    [0x10860, 0x10876],
+    [0x10880, 0x1089E],
+    [0x108E0, 0x108F2],
+    [0x108F4, 0x108F5],
+    [0x10900, 0x10915],
+    [0x10920, 0x10939],
+    [0x10980, 0x109B7],
+    [0x109BE, 0x109BF],
+    [0x10A00, 0x10A03],
+    [0x10A05, 0x10A06],
+    [0x10A0C, 0x10A13],
+    [0x10A15, 0x10A17],
+    [0x10A19, 0x10A35],
+    [0x10A38, 0x10A3A],
+    [0x10A3F, 0x10A3F],
+    [0x10A60, 0x10A7C],
+    [0x10A80, 0x10A9C],
+    [0x10AC0, 0x10AC7],
+    [0x10AC9, 0x10AE6],
+    [0x10B00, 0x10B35],
+    [0x10B40, 0x10B55],
+    [0x10B60, 0x10B72],
+    [0x10B80, 0x10B91],
+    [0x10C00, 0x10C48],
+    [0x10C80, 0x10CB2],
+    [0x10CC0, 0x10CF2],
+    [0x10D00, 0x10D27],
+    [0x10D30, 0x10D39],
+    [0x10E80, 0x10EA9],
+    [0x10EAB, 0x10EAC],
+    [0x10EB0, 0x10EB1],
+    [0x10EFD, 0x10F1C],
+    [0x10F27, 0x10F27],
+    [0x10F30, 0x10F50],
+    [0x10F70, 0x10F85],
+    [0x10FB0, 0x10FC4],
+    [0x10FE0, 0x10FF6],
+    [0x11000, 0x11046],
+    [0x11066, 0x11075],
+    [0x1107F, 0x110BA],
+    [0x110C2, 0x110C2],
+    [0x110D0, 0x110E8],
+    [0x110F0, 0x110F9],
+    [0x11100, 0x11134],
+    [0x11136, 0x1113F],
+    [0x11144, 0x11147],
+    [0x11150, 0x11173],
+    [0x11176, 0x11176],
+    [0x11180, 0x111C4],
+    [0x111C9, 0x111CC],
+    [0x111CE, 0x111DA],
+    [0x111DC, 0x111DC],
+    [0x11200, 0x11211],
+    [0x11213, 0x11237],
+    [0x1123E, 0x11241],
+    [0x11280, 0x11286],
+    [0x11288, 0x11288],
+    [0x1128A, 0x1128D],
+    [0x1128F, 0x1129D],
+    [0x1129F, 0x112A8],
+    [0x112B0, 0x112EA],
+    [0x112F0, 0x112F9],
+    [0x11300, 0x11303],
+    [0x11305, 0x1130C],
+    [0x1130F, 0x11310],
+    [0x11313, 0x11328],
+    [0x1132A, 0x11330],
+    [0x11332, 0x11333],
+    [0x11335, 0x11339],
+    [0x1133B, 0x11344],
+    [0x11347, 0x11348],
+    [0x1134B, 0x1134D],
+    [0x11350, 0x11350],
+    [0x11357, 0x11357],
+    [0x1135D, 0x11363],
+    [0x11366, 0x1136C],
+    [0x11370, 0x11374],
+    [0x11400, 0x1144A],
+    [0x11450, 0x11459],
+    [0x1145E, 0x11461],
+    [0x11480, 0x114C5],
+    [0x114C7, 0x114C7],
+    [0x114D0, 0x114D9],
+    [0x11580, 0x115B5],
+    [0x115B8, 0x115C0],
+    [0x115D8, 0x115DD],
+    [0x11600, 0x11640],
+    [0x11644, 0x11644],
+    [0x11650, 0x11659],
+    [0x11680, 0x116B8],
+    [0x116C0, 0x116C9],
+    [0x11700, 0x1171A],
+    [0x1171D, 0x1172B],
+    [0x11730, 0x11739],
+    [0x11740, 0x11746],
+    [0x11800, 0x1183A],
+    [0x118A0, 0x118E9],
+    [0x118FF, 0x11906],
+    [0x11909, 0x11909],
+    [0x1190C, 0x11913],
+    [0x11915, 0x11916],
+    [0x11918, 0x11935],
+    [0x11937, 0x11938],
+    [0x1193B, 0x11943],
+    [0x11950, 0x11959],
+    [0x119A0, 0x119A7],
+    [0x119AA, 0x119D7],
+    [0x119DA, 0x119E1],
+    [0x119E3, 0x119E4],
+    [0x11A00, 0x11A3E],
+    [0x11A47, 0x11A47],
+    [0x11A50, 0x11A99],
+    [0x11A9D, 0x11A9D],
+    [0x11AB0, 0x11AF8],
+    [0x11C00, 0x11C08],
+    [0x11C0A, 0x11C36],
+    [0x11C38, 0x11C40],
+    [0x11C50, 0x11C59],
+    [0x11C72, 0x11C8F],
+    [0x11C92, 0x11CA7],
+    [0x11CA9, 0x11CB6],
+    [0x11D00, 0x11D06],
+    [0x11D08, 0x11D09],
+    [0x11D0B, 0x11D36],
+    [0x11D3A, 0x11D3A],
+    [0x11D3C, 0x11D3D],
+    [0x11D3F, 0x11D47],
+    [0x11D50, 0x11D59],
+    [0x11D60, 0x11D65],
+    [0x11D67, 0x11D68],
+    [0x11D6A, 0x11D8E],
+    [0x11D90, 0x11D91],
+    [0x11D93, 0x11D98],
+    [0x11DA0, 0x11DA9],
+    [0x11EE0, 0x11EF6],
+    [0x11F00, 0x11F10],
+    [0x11F12, 0x11F3A],
+    [0x11F3E, 0x11F42],
+    [0x11F50, 0x11F59],
+    [0x11FB0, 0x11FB0],
+    [0x12000, 0x12399],
+    [0x12400, 0x1246E],
+    [0x12480, 0x12543],
+    [0x12F90, 0x12FF0],
+    [0x13000, 0x1342F],
+    [0x13440, 0x13455],
+    [0x14400, 0x14646],
+    [0x16800, 0x16A38],
+    [0x16A40, 0x16A5E],
+    [0x16A60, 0x16A69],
+    [0x16A70, 0x16ABE],
+    [0x16AC0, 0x16AC9],
+    [0x16AD0, 0x16AED],
+    [0x16AF0, 0x16AF4],
+    [0x16B00, 0x16B36],
+    [0x16B40, 0x16B43],
+    [0x16B50, 0x16B59],
+    [0x16B63, 0x16B77],
+    [0x16B7D, 0x16B8F],
+    [0x16E40, 0x16E7F],
+    [0x16F00, 0x16F4A],
+    [0x16F4F, 0x16F87],
+    [0x16F8F, 0x16F9F],
+    [0x16FE0, 0x16FE1],
+    [0x16FE3, 0x16FE4],
+    [0x16FF0, 0x16FF1],
+    [0x17000, 0x187F7],
+    [0x18800, 0x18CD5],
+    [0x18D00, 0x18D08],
+    [0x1AFF0, 0x1AFF3],
+    [0x1AFF5, 0x1AFFB],
+    [0x1AFFD, 0x1AFFE],
+    [0x1B000, 0x1B122],
+    [0x1B132, 0x1B132],
+    [0x1B150, 0x1B152],
+    [0x1B155, 0x1B155],
+    [0x1B164, 0x1B167],
+    [0x1B170, 0x1B2FB],
+    [0x1BC00, 0x1BC6A],
+    [0x1BC70, 0x1BC7C],
+    [0x1BC80, 0x1BC88],
+    [0x1BC90, 0x1BC99],
+    [0x1BC9D, 0x1BC9E],
+    [0x1CF00, 0x1CF2D],
+    [0x1CF30, 0x1CF46],
+    [0x1D165, 0x1D169],
+    [0x1D16D, 0x1D172],
+    [0x1D17B, 0x1D182],
+    [0x1D185, 0x1D18B],
+    [0x1D1AA, 0x1D1AD],
+    [0x1D242, 0x1D244],
+    [0x1D400, 0x1D454],
+    [0x1D456, 0x1D49C],
+    [0x1D49E, 0x1D49F],
+    [0x1D4A2, 0x1D4A2],
+    [0x1D4A5, 0x1D4A6],
+    [0x1D4A9, 0x1D4AC],
+    [0x1D4AE, 0x1D4B9],
+    [0x1D4BB, 0x1D4BB],
+    [0x1D4BD, 0x1D4C3],
+    [0x1D4C5, 0x1D505],
+    [0x1D507, 0x1D50A],
+    [0x1D50D, 0x1D514],
+    [0x1D516, 0x1D51C],
+    [0x1D51E, 0x1D539],
+    [0x1D53B, 0x1D53E],
+    [0x1D540, 0x1D544],
+    [0x1D546, 0x1D546],
+    [0x1D54A, 0x1D550],
+    [0x1D552, 0x1D6A5],
+    [0x1D6A8, 0x1D6C0],
+    [0x1D6C2, 0x1D6DA],
+    [0x1D6DC, 0x1D6FA],
+    [0x1D6FC, 0x1D714],
+    [0x1D716, 0x1D734],
+    [0x1D736, 0x1D74E],
+    [0x1D750, 0x1D76E],
+    [0x1D770, 0x1D788],
+    [0x1D78A, 0x1D7A8],
+    [0x1D7AA, 0x1D7C2],
+    [0x1D7C4, 0x1D7CB],
+    [0x1D7CE, 0x1D7FF],
+    [0x1DA00, 0x1DA36],
+    [0x1DA3B, 0x1DA6C],
+    [0x1DA75, 0x1DA75],
+    [0x1DA84, 0x1DA84],
+    [0x1DA9B, 0x1DA9F],
+    [0x1DAA1, 0x1DAAF],
+    [0x1DF00, 0x1DF1E],
+    [0x1DF25, 0x1DF2A],
+    [0x1E000, 0x1E006],
+    [0x1E008, 0x1E018],
+    [0x1E01B, 0x1E021],
+    [0x1E023, 0x1E024],
+    [0x1E026, 0x1E02A],
+    [0x1E030, 0x1E06D],
+    [0x1E08F, 0x1E08F],
+    [0x1E100, 0x1E12C],
+    [0x1E130, 0x1E13D],
+    [0x1E140, 0x1E149],
+    [0x1E14E, 0x1E14E],
+    [0x1E290, 0x1E2AE],
+    [0x1E2C0, 0x1E2F9],
+    [0x1E4D0, 0x1E4F9],
+    [0x1E7E0, 0x1E7E6],
+    [0x1E7E8, 0x1E7EB],
+    [0x1E7ED, 0x1E7EE],
+    [0x1E7F0, 0x1E7FE],
+    [0x1E800, 0x1E8C4],
+    [0x1E8D0, 0x1E8D6],
+    [0x1E900, 0x1E94B],
+    [0x1E950, 0x1E959],
+    [0x1EE00, 0x1EE03],
+    [0x1EE05, 0x1EE1F],
+    [0x1EE21, 0x1EE22],
+    [0x1EE24, 0x1EE24],
+    [0x1EE27, 0x1EE27],
+    [0x1EE29, 0x1EE32],
+    [0x1EE34, 0x1EE37],
+    [0x1EE39, 0x1EE39],
+    [0x1EE3B, 0x1EE3B],
+    [0x1EE42, 0x1EE42],
+    [0x1EE47, 0x1EE47],
+    [0x1EE49, 0x1EE49],
+    [0x1EE4B, 0x1EE4B],
+    [0x1EE4D, 0x1EE4F],
+    [0x1EE51, 0x1EE52],
+    [0x1EE54, 0x1EE54],
+    [0x1EE57, 0x1EE57],
+    [0x1EE59, 0x1EE59],
+    [0x1EE5B, 0x1EE5B],
+    [0x1EE5D, 0x1EE5D],
+    [0x1EE5F, 0x1EE5F],
+    [0x1EE61, 0x1EE62],
+    [0x1EE64, 0x1EE64],
+    [0x1EE67, 0x1EE6A],
+    [0x1EE6C, 0x1EE72],
+    [0x1EE74, 0x1EE77],
+    [0x1EE79, 0x1EE7C],
+    [0x1EE7E, 0x1EE7E],
+    [0x1EE80, 0x1EE89],
+    [0x1EE8B, 0x1EE9B],
+    [0x1EEA1, 0x1EEA3],
+    [0x1EEA5, 0x1EEA9],
+    [0x1EEAB, 0x1EEBB],
+    [0x1FBF0, 0x1FBF9],
+    [0x20000, 0x2A6DF],
+    [0x2A700, 0x2B739],
+    [0x2B740, 0x2B81D],
+    [0x2B820, 0x2CEA1],
+    [0x2CEB0, 0x2EBE0],
+    [0x2EBF0, 0x2EE5D],
+    [0x2F800, 0x2FA1D],
+    [0x30000, 0x3134A],
+    [0x31350, 0x323AF],
+    [0xE0100, 0xE01EF],
+];
+
+/**
+C99 Start
+Entries: 34958
+*/
+alias FixedTable_C99_Start = FixedTable_C99_Continue;
+
+/**
+C99 Continue
+Entries: 34958
+*/
+static immutable dchar[2][] FixedTable_C99_Continue = [
+    [0xAA, 0xAA],
+    [0xB5, 0xB5],
+    [0xB7, 0xB7],
+    [0xBA, 0xBA],
+    [0xC0, 0xD6],
+    [0xD8, 0xF6],
+    [0xF8, 0x1F5],
+    [0x1FA, 0x217],
+    [0x250, 0x2A8],
+    [0x2B0, 0x2B8],
+    [0x2BB, 0x2BB],
+    [0x2BD, 0x2C1],
+    [0x2D0, 0x2D1],
+    [0x2E0, 0x2E4],
+    [0x37A, 0x37A],
+    [0x386, 0x386],
+    [0x388, 0x38A],
+    [0x38C, 0x38C],
+    [0x38E, 0x3A1],
+    [0x3A3, 0x3CE],
+    [0x3D0, 0x3D6],
+    [0x3DA, 0x3DA],
+    [0x3DC, 0x3DC],
+    [0x3DE, 0x3DE],
+    [0x3E0, 0x3E0],
+    [0x3E2, 0x3F3],
+    [0x401, 0x40C],
+    [0x40E, 0x44F],
+    [0x451, 0x45C],
+    [0x45E, 0x481],
+    [0x490, 0x4C4],
+    [0x4C7, 0x4C8],
+    [0x4CB, 0x4CC],
+    [0x4D0, 0x4EB],
+    [0x4EE, 0x4F5],
+    [0x4F8, 0x4F9],
+    [0x531, 0x556],
+    [0x559, 0x559],
+    [0x561, 0x587],
+    [0x5B0, 0x5B9],
+    [0x5BB, 0x5BD],
+    [0x5BF, 0x5BF],
+    [0x5C1, 0x5C2],
+    [0x5D0, 0x5EA],
+    [0x5F0, 0x5F2],
+    [0x621, 0x63A],
+    [0x640, 0x652],
+    [0x660, 0x669],
+    [0x670, 0x6B7],
+    [0x6BA, 0x6BE],
+    [0x6C0, 0x6CE],
+    [0x6D0, 0x6DC],
+    [0x6E5, 0x6E8],
+    [0x6EA, 0x6ED],
+    [0x6F0, 0x6F9],
+    [0x901, 0x903],
+    [0x905, 0x939],
+    [0x93D, 0x94D],
+    [0x950, 0x952],
+    [0x958, 0x963],
+    [0x966, 0x96F],
+    [0x981, 0x983],
+    [0x985, 0x98C],
+    [0x98F, 0x990],
+    [0x993, 0x9A8],
+    [0x9AA, 0x9B0],
+    [0x9B2, 0x9B2],
+    [0x9B6, 0x9B9],
+    [0x9BE, 0x9C4],
+    [0x9C7, 0x9C8],
+    [0x9CB, 0x9CD],
+    [0x9DC, 0x9DD],
+    [0x9DF, 0x9E3],
+    [0x9E6, 0x9F1],
+    [0xA02, 0xA02],
+    [0xA05, 0xA0A],
+    [0xA0F, 0xA10],
+    [0xA13, 0xA28],
+    [0xA2A, 0xA30],
+    [0xA32, 0xA33],
+    [0xA35, 0xA36],
+    [0xA38, 0xA39],
+    [0xA3E, 0xA42],
+    [0xA47, 0xA48],
+    [0xA4B, 0xA4D],
+    [0xA59, 0xA5C],
+    [0xA5E, 0xA5E],
+    [0xA66, 0xA6F],
+    [0xA74, 0xA74],
+    [0xA81, 0xA83],
+    [0xA85, 0xA8B],
+    [0xA8D, 0xA8D],
+    [0xA8F, 0xA91],
+    [0xA93, 0xAA8],
+    [0xAAA, 0xAB0],
+    [0xAB2, 0xAB3],
+    [0xAB5, 0xAB9],
+    [0xABD, 0xAC5],
+    [0xAC7, 0xAC9],
+    [0xACB, 0xACD],
+    [0xAD0, 0xAD0],
+    [0xAE0, 0xAE0],
+    [0xAE6, 0xAEF],
+    [0xB01, 0xB03],
+    [0xB05, 0xB0C],
+    [0xB0F, 0xB10],
+    [0xB13, 0xB28],
+    [0xB2A, 0xB30],
+    [0xB32, 0xB33],
+    [0xB36, 0xB39],
+    [0xB3D, 0xB43],
+    [0xB47, 0xB48],
+    [0xB4B, 0xB4D],
+    [0xB5C, 0xB5D],
+    [0xB5F, 0xB61],
+    [0xB66, 0xB6F],
+    [0xB82, 0xB83],
+    [0xB85, 0xB8A],
+    [0xB8E, 0xB90],
+    [0xB92, 0xB95],
+    [0xB99, 0xB9A],
+    [0xB9C, 0xB9C],
+    [0xB9E, 0xB9F],
+    [0xBA3, 0xBA4],
+    [0xBA8, 0xBAA],
+    [0xBAE, 0xBB5],
+    [0xBB7, 0xBB9],
+    [0xBBE, 0xBC2],
+    [0xBC6, 0xBC8],
+    [0xBCA, 0xBCD],
+    [0xBE7, 0xBEF],
+    [0xC01, 0xC03],
+    [0xC05, 0xC0C],
+    [0xC0E, 0xC10],
+    [0xC12, 0xC28],
+    [0xC2A, 0xC33],
+    [0xC35, 0xC39],
+    [0xC3E, 0xC44],
+    [0xC46, 0xC48],
+    [0xC4A, 0xC4D],
+    [0xC60, 0xC61],
+    [0xC66, 0xC6F],
+    [0xC82, 0xC83],
+    [0xC85, 0xC8C],
+    [0xC8E, 0xC90],
+    [0xC92, 0xCA8],
+    [0xCAA, 0xCB3],
+    [0xCB5, 0xCB9],
+    [0xCBE, 0xCC4],
+    [0xCC6, 0xCC8],
+    [0xCCA, 0xCCD],
+    [0xCDE, 0xCDE],
+    [0xCE0, 0xCE1],
+    [0xCE6, 0xCEF],
+    [0xD02, 0xD03],
+    [0xD05, 0xD0C],
+    [0xD0E, 0xD10],
+    [0xD12, 0xD28],
+    [0xD2A, 0xD39],
+    [0xD3E, 0xD43],
+    [0xD46, 0xD48],
+    [0xD4A, 0xD4D],
+    [0xD60, 0xD61],
+    [0xD66, 0xD6F],
+    [0xE01, 0xE3A],
+    [0xE40, 0xE5B],
+    [0xE81, 0xE82],
+    [0xE84, 0xE84],
+    [0xE87, 0xE88],
+    [0xE8A, 0xE8A],
+    [0xE8D, 0xE8D],
+    [0xE94, 0xE97],
+    [0xE99, 0xE9F],
+    [0xEA1, 0xEA3],
+    [0xEA5, 0xEA5],
+    [0xEA7, 0xEA7],
+    [0xEAA, 0xEAB],
+    [0xEAD, 0xEAE],
+    [0xEB0, 0xEB9],
+    [0xEBB, 0xEBD],
+    [0xEC0, 0xEC4],
+    [0xEC6, 0xEC6],
+    [0xEC8, 0xECD],
+    [0xED0, 0xED9],
+    [0xEDC, 0xEDD],
+    [0xF00, 0xF00],
+    [0xF18, 0xF19],
+    [0xF20, 0xF33],
+    [0xF35, 0xF35],
+    [0xF37, 0xF37],
+    [0xF39, 0xF39],
+    [0xF3E, 0xF47],
+    [0xF49, 0xF69],
+    [0xF71, 0xF84],
+    [0xF86, 0xF8B],
+    [0xF90, 0xF95],
+    [0xF97, 0xF97],
+    [0xF99, 0xFAD],
+    [0xFB1, 0xFB7],
+    [0xFB9, 0xFB9],
+    [0x10A0, 0x10C5],
+    [0x10D0, 0x10F6],
+    [0x1E00, 0x1E9B],
+    [0x1EA0, 0x1EF9],
+    [0x1F00, 0x1F15],
+    [0x1F18, 0x1F1D],
+    [0x1F20, 0x1F45],
+    [0x1F48, 0x1F4D],
+    [0x1F50, 0x1F57],
+    [0x1F59, 0x1F59],
+    [0x1F5B, 0x1F5B],
+    [0x1F5D, 0x1F5D],
+    [0x1F5F, 0x1F7D],
+    [0x1F80, 0x1FB4],
+    [0x1FB6, 0x1FBC],
+    [0x1FBE, 0x1FBE],
+    [0x1FC2, 0x1FC4],
+    [0x1FC6, 0x1FCC],
+    [0x1FD0, 0x1FD3],
+    [0x1FD6, 0x1FDB],
+    [0x1FE0, 0x1FEC],
+    [0x1FF2, 0x1FF4],
+    [0x1FF6, 0x1FFC],
+    [0x203F, 0x2040],
+    [0x207F, 0x207F],
+    [0x2102, 0x2102],
+    [0x2107, 0x2107],
+    [0x210A, 0x2113],
+    [0x2115, 0x2115],
+    [0x2118, 0x211D],
+    [0x2124, 0x2124],
+    [0x2126, 0x2126],
+    [0x2128, 0x2128],
+    [0x212A, 0x2131],
+    [0x2133, 0x2138],
+    [0x2160, 0x2182],
+    [0x3005, 0x3007],
+    [0x3021, 0x3029],
+    [0x3041, 0x3093],
+    [0x309B, 0x309C],
+    [0x30A1, 0x30F6],
+    [0x30FB, 0x30FC],
+    [0x3105, 0x312C],
+    [0x4E00, 0x9FA5],
+    [0xAC00, 0xD7A3],
+];
+
+/**
+C11 Start
+Entries: 971620
+*/
+alias FixedTable_C11_Start = FixedTable_C11_Continue;
+
+/**
+C11 Continue
+Entries: 971620
+*/
+static immutable dchar[2][] FixedTable_C11_Continue = [
+    [0xA8, 0xA8],
+    [0xAA, 0xAA],
+    [0xAD, 0xAD],
+    [0xAF, 0xAF],
+    [0xB2, 0xB5],
+    [0xB7, 0xBA],
+    [0xBC, 0xBE],
+    [0xC0, 0xD6],
+    [0xD8, 0xF6],
+    [0xF8, 0xFF],
+    [0x100, 0x167F],
+    [0x1681, 0x180D],
+    [0x180F, 0x1FFF],
+    [0x200B, 0x200D],
+    [0x202A, 0x202E],
+    [0x203F, 0x2040],
+    [0x2054, 0x2054],
+    [0x2060, 0x206F],
+    [0x2070, 0x218F],
+    [0x2460, 0x24FF],
+    [0x2776, 0x2793],
+    [0x2C00, 0x2DFF],
+    [0x2E80, 0x2FFF],
+    [0x3004, 0x3007],
+    [0x3021, 0x302F],
+    [0x3031, 0x303F],
+    [0x3040, 0xD7FF],
+    [0xF900, 0xFD3D],
+    [0xFD40, 0xFDCF],
+    [0xFDF0, 0xFE44],
+    [0xFE47, 0xFFFD],
+    [0x10000, 0x1FFFD],
+    [0x20000, 0x2FFFD],
+    [0x30000, 0x3FFFD],
+    [0x40000, 0x4FFFD],
+    [0x50000, 0x5FFFD],
+    [0x60000, 0x6FFFD],
+    [0x70000, 0x7FFFD],
+    [0x80000, 0x8FFFD],
+    [0x90000, 0x9FFFD],
+    [0xA0000, 0xAFFFD],
+    [0xB0000, 0xBFFFD],
+    [0xC0000, 0xCFFFD],
+    [0xD0000, 0xDFFFD],
+    [0xE0000, 0xEFFFD],
+];
+
+/**
+Least restrictive with both Start and Continue
+Entries: 860486
+*/
+static immutable dchar[2][] LeastRestrictive_OfAll = [
+    [0xA8, 0xA8],
+    [0xAA, 0xAA],
+    [0xAD, 0xAD],
+    [0xAF, 0xAF],
+    [0xB2, 0xB5],
+    [0xB7, 0xBA],
+    [0xBC, 0xBE],
+    [0xC0, 0xD6],
+    [0xD8, 0xF6],
+    [0xF8, 0x217],
+    [0x250, 0x2A8],
+    [0x2B0, 0x2B8],
+    [0x2BB, 0x2BB],
+    [0x2BD, 0x2C1],
+    [0x2C6, 0x2D1],
+    [0x2E0, 0x2E4],
+    [0x2EC, 0x2EC],
+    [0x2EE, 0x2EE],
+    [0x300, 0x374],
+    [0x376, 0x377],
+    [0x37A, 0x37D],
+    [0x37F, 0x37F],
+    [0x386, 0x386],
+    [0x388, 0x38A],
+    [0x38C, 0x38C],
+    [0x38E, 0x3A1],
+    [0x3A3, 0x3D6],
+    [0x3DA, 0x3DA],
+    [0x3DC, 0x3DC],
+    [0x3DE, 0x3DE],
+    [0x3E0, 0x3E0],
+    [0x3E2, 0x3F3],
+    [0x3F7, 0x40C],
+    [0x40E, 0x44F],
+    [0x451, 0x45C],
+    [0x45E, 0x481],
+    [0x483, 0x487],
+    [0x48A, 0x4C4],
+    [0x4C7, 0x4C8],
+    [0x4CB, 0x4CC],
+    [0x4D0, 0x4EB],
+    [0x4EE, 0x4F5],
+    [0x4F8, 0x4F9],
+    [0x531, 0x556],
+    [0x559, 0x559],
+    [0x560, 0x587],
+    [0x591, 0x5B9],
+    [0x5BB, 0x5BD],
+    [0x5BF, 0x5BF],
+    [0x5C1, 0x5C2],
+    [0x5C4, 0x5C5],
+    [0x5C7, 0x5C7],
+    [0x5D0, 0x5EA],
+    [0x5EF, 0x5F2],
+    [0x610, 0x61A],
+    [0x620, 0x63A],
+    [0x640, 0x652],
+    [0x660, 0x669],
+    [0x66E, 0x6BE],
+    [0x6C0, 0x6CE],
+    [0x6D0, 0x6D5],
+    [0x6DF, 0x6E8],
+    [0x6EA, 0x6F9],
+    [0x6FF, 0x6FF],
+    [0x710, 0x710],
+    [0x712, 0x72F],
+    [0x74D, 0x7A5],
+    [0x7B1, 0x7B1],
+    [0x7C0, 0x7EA],
+    [0x7F4, 0x7F5],
+    [0x7FA, 0x7FA],
+    [0x7FD, 0x7FD],
+    [0x800, 0x815],
+    [0x81A, 0x81A],
+    [0x824, 0x824],
+    [0x828, 0x828],
+    [0x840, 0x858],
+    [0x860, 0x86A],
+    [0x870, 0x887],
+    [0x889, 0x88E],
+    [0x898, 0x8C9],
+    [0x8E3, 0x939],
+    [0x93D, 0x94D],
+    [0x950, 0x952],
+    [0x958, 0x963],
+    [0x966, 0x96F],
+    [0x971, 0x983],
+    [0x985, 0x98C],
+    [0x98F, 0x990],
+    [0x993, 0x9A8],
+    [0x9AA, 0x9B0],
+    [0x9B2, 0x9B2],
+    [0x9B6, 0x9B9],
+    [0x9BC, 0x9C4],
+    [0x9C7, 0x9C8],
+    [0x9CB, 0x9CE],
+    [0x9D7, 0x9D7],
+    [0x9DC, 0x9DD],
+    [0x9DF, 0x9E3],
+    [0x9E6, 0x9F1],
+    [0x9FC, 0x9FC],
+    [0x9FE, 0x9FE],
+    [0xA01, 0xA02],
+    [0xA05, 0xA0A],
+    [0xA0F, 0xA10],
+    [0xA13, 0xA28],
+    [0xA2A, 0xA30],
+    [0xA32, 0xA33],
+    [0xA35, 0xA36],
+    [0xA38, 0xA39],
+    [0xA3C, 0xA3C],
+    [0xA3E, 0xA42],
+    [0xA47, 0xA48],
+    [0xA4B, 0xA4D],
+    [0xA51, 0xA51],
+    [0xA59, 0xA5C],
+    [0xA5E, 0xA5E],
+    [0xA66, 0xA6F],
+    [0xA72, 0xA74],
+    [0xA81, 0xA83],
+    [0xA85, 0xA8B],
+    [0xA8D, 0xA8D],
+    [0xA8F, 0xA91],
+    [0xA93, 0xAA8],
+    [0xAAA, 0xAB0],
+    [0xAB2, 0xAB3],
+    [0xAB5, 0xAB9],
+    [0xABC, 0xABD],
+    [0xAC7, 0xAC9],
+    [0xACB, 0xACD],
+    [0xAD0, 0xAD0],
+    [0xAE0, 0xAE0],
+    [0xAE6, 0xAEF],
+    [0xAF9, 0xAFF],
+    [0xB01, 0xB03],
+    [0xB05, 0xB0C],
+    [0xB0F, 0xB10],
+    [0xB13, 0xB28],
+    [0xB2A, 0xB30],
+    [0xB32, 0xB33],
+    [0xB35, 0xB39],
+    [0xB3C, 0xB43],
+    [0xB47, 0xB48],
+    [0xB4B, 0xB4D],
+    [0xB55, 0xB57],
+    [0xB5C, 0xB5D],
+    [0xB5F, 0xB61],
+    [0xB66, 0xB6F],
+    [0xB71, 0xB71],
+    [0xB82, 0xB83],
+    [0xB85, 0xB8A],
+    [0xB8E, 0xB90],
+    [0xB92, 0xB95],
+    [0xB99, 0xB9A],
+    [0xB9C, 0xB9C],
+    [0xB9E, 0xB9F],
+    [0xBA3, 0xBA4],
+    [0xBA8, 0xBAA],
+    [0xBAE, 0xBB5],
+    [0xBB7, 0xBB9],
+    [0xBBE, 0xBC2],
+    [0xBC6, 0xBC8],
+    [0xBCA, 0xBCD],
+    [0xBD0, 0xBD0],
+    [0xBD7, 0xBD7],
+    [0xBE6, 0xBEF],
+    [0xC00, 0xC03],
+    [0xC05, 0xC0C],
+    [0xC0E, 0xC10],
+    [0xC12, 0xC28],
+    [0xC2A, 0xC33],
+    [0xC35, 0xC39],
+    [0xC3C, 0xC44],
+    [0xC46, 0xC48],
+    [0xC4A, 0xC4D],
+    [0xC55, 0xC56],
+    [0xC58, 0xC5A],
+    [0xC5D, 0xC5D],
+    [0xC60, 0xC61],
+    [0xC66, 0xC6F],
+    [0xC80, 0xC83],
+    [0xC85, 0xC8C],
+    [0xC8E, 0xC90],
+    [0xC92, 0xCA8],
+    [0xCAA, 0xCB3],
+    [0xCB5, 0xCB9],
+    [0xCBC, 0xCC4],
+    [0xCC6, 0xCC8],
+    [0xCCA, 0xCCD],
+    [0xCD5, 0xCD6],
+    [0xCDD, 0xCDE],
+    [0xCE0, 0xCE1],
+    [0xCE6, 0xCEF],
+    [0xCF1, 0xCF2],
+    [0xD00, 0xD0C],
+    [0xD0E, 0xD10],
+    [0xD12, 0xD39],
+    [0xD3D, 0xD43],
+    [0xD46, 0xD48],
+    [0xD4A, 0xD4E],
+    [0xD54, 0xD57],
+    [0xD5F, 0xD61],
+    [0xD66, 0xD6F],
+    [0xD7A, 0xD7F],
+    [0xD81, 0xD83],
+    [0xD85, 0xD96],
+    [0xD9A, 0xDB1],
+    [0xDB3, 0xDBB],
+    [0xDBD, 0xDBD],
+    [0xDC0, 0xDC6],
+    [0xDCA, 0xDCA],
+    [0xDCF, 0xDD4],
+    [0xDD6, 0xDD6],
+    [0xDD8, 0xDDF],
+    [0xDE6, 0xDEF],
+    [0xDF2, 0xDF3],
+    [0xE01, 0xE32],
+    [0xE40, 0xE4E],
+    [0xE50, 0xE59],
+    [0xE81, 0xE82],
+    [0xE84, 0xE84],
+    [0xE86, 0xE88],
+    [0xE8A, 0xE8A],
+    [0xE8C, 0xE8D],
+    [0xE94, 0xE97],
+    [0xE99, 0xE9F],
+    [0xEA1, 0xEA3],
+    [0xEA5, 0xEA5],
+    [0xEA7, 0xEAB],
+    [0xEAD, 0xEAE],
+    [0xEB0, 0xEB9],
+    [0xEBB, 0xEBD],
+    [0xEC0, 0xEC4],
+    [0xEC6, 0xEC6],
+    [0xEC8, 0xECE],
+    [0xED0, 0xED9],
+    [0xEDC, 0xEDF],
+    [0xF00, 0xF00],
+    [0xF18, 0xF19],
+    [0xF20, 0xF29],
+    [0xF35, 0xF35],
+    [0xF37, 0xF37],
+    [0xF39, 0xF39],
+    [0xF3E, 0xF47],
+    [0xF49, 0xF6C],
+    [0xF71, 0xF84],
+    [0xF86, 0xF95],
+    [0xF97, 0xF97],
+    [0xF99, 0xFB7],
+    [0xFB9, 0xFB9],
+    [0xFC6, 0xFC6],
+    [0x1000, 0x103F],
+    [0x1050, 0x105D],
+    [0x1061, 0x1061],
+    [0x1065, 0x1066],
+    [0x106E, 0x1070],
+    [0x1075, 0x1081],
+    [0x108E, 0x108E],
+    [0x10A0, 0x10C5],
+    [0x10C7, 0x10C7],
+    [0x10CD, 0x10CD],
+    [0x10D0, 0x10FA],
+    [0x10FC, 0x1248],
+    [0x124A, 0x124D],
+    [0x1250, 0x1256],
+    [0x1258, 0x1258],
+    [0x125A, 0x125D],
+    [0x1260, 0x1288],
+    [0x128A, 0x128D],
+    [0x1290, 0x12B0],
+    [0x12B2, 0x12B5],
+    [0x12B8, 0x12BE],
+    [0x12C0, 0x12C0],
+    [0x12C2, 0x12C5],
+    [0x12C8, 0x12D6],
+    [0x12D8, 0x1310],
+    [0x1312, 0x1315],
+    [0x1318, 0x135A],
+    [0x135D, 0x135F],
+    [0x1369, 0x1371],
+    [0x1380, 0x138F],
+    [0x13A0, 0x13F5],
+    [0x13F8, 0x13FD],
+    [0x1401, 0x166C],
+    [0x166F, 0x167F],
+    [0x1681, 0x169A],
+    [0x16A0, 0x16EA],
+    [0x16EE, 0x16F8],
+    [0x1700, 0x1711],
+    [0x171F, 0x1731],
+    [0x1740, 0x1751],
+    [0x1760, 0x176C],
+    [0x176E, 0x1770],
+    [0x1772, 0x1773],
+    [0x1780, 0x17B3],
+    [0x17D7, 0x17D7],
+    [0x17DC, 0x17DC],
+    [0x17E0, 0x17E9],
+    [0x180B, 0x180D],
+    [0x180F, 0x1878],
+    [0x1880, 0x18A8],
+    [0x18AA, 0x18AA],
+    [0x18B0, 0x18F5],
+    [0x1900, 0x191E],
+    [0x1920, 0x192B],
+    [0x1930, 0x193B],
+    [0x1946, 0x196D],
+    [0x1970, 0x1974],
+    [0x1980, 0x19AB],
+    [0x19B0, 0x19C9],
+    [0x19D0, 0x19DA],
+    [0x1A00, 0x1A16],
+    [0x1A20, 0x1A54],
+    [0x1A60, 0x1A7C],
+    [0x1A7F, 0x1A89],
+    [0x1A90, 0x1A99],
+    [0x1AA7, 0x1AA7],
+    [0x1AB0, 0x1ABD],
+    [0x1ABF, 0x1ACE],
+    [0x1B00, 0x1B33],
+    [0x1B45, 0x1B4C],
+    [0x1B50, 0x1B59],
+    [0x1B6B, 0x1B73],
+    [0x1B80, 0x1BA0],
+    [0x1BAE, 0x1BAF],
+    [0x1BBA, 0x1BE5],
+    [0x1C00, 0x1C37],
+    [0x1C40, 0x1C49],
+    [0x1C4D, 0x1C7D],
+    [0x1C80, 0x1C88],
+    [0x1C90, 0x1CBA],
+    [0x1CBD, 0x1CBF],
+    [0x1CD0, 0x1CD2],
+    [0x1CD4, 0x1CEC],
+    [0x1CEE, 0x1CF3],
+    [0x1CF5, 0x1CF6],
+    [0x1CFA, 0x1CFA],
+    [0x1D00, 0x1EF9],
+    [0x1F00, 0x1F15],
+    [0x1F18, 0x1F1D],
+    [0x1F20, 0x1F45],
+    [0x1F48, 0x1F4D],
+    [0x1F50, 0x1F57],
+    [0x1F59, 0x1F59],
+    [0x1F5B, 0x1F5B],
+    [0x1F5D, 0x1F5D],
+    [0x1F5F, 0x1F7D],
+    [0x1F80, 0x1FB4],
+    [0x1FB6, 0x1FBC],
+    [0x1FBE, 0x1FBE],
+    [0x1FC2, 0x1FC4],
+    [0x1FC6, 0x1FCC],
+    [0x1FD0, 0x1FD3],
+    [0x1FD6, 0x1FDB],
+    [0x1FE0, 0x1FEC],
+    [0x1FF2, 0x1FF4],
+    [0x1FF6, 0x1FFC],
+    [0x200B, 0x200D],
+    [0x202A, 0x202E],
+    [0x203F, 0x2040],
+    [0x2054, 0x2054],
+    [0x2060, 0x2071],
+    [0x207F, 0x207F],
+    [0x2090, 0x209C],
+    [0x20D0, 0x20DC],
+    [0x20E1, 0x20E1],
+    [0x20E5, 0x20F0],
+    [0x2102, 0x2102],
+    [0x2107, 0x2107],
+    [0x210A, 0x2113],
+    [0x2115, 0x2115],
+    [0x2118, 0x211D],
+    [0x2124, 0x2124],
+    [0x2126, 0x2126],
+    [0x2128, 0x2128],
+    [0x212A, 0x2138],
+    [0x213C, 0x213F],
+    [0x2145, 0x2149],
+    [0x214E, 0x214E],
+    [0x2160, 0x2188],
+    [0x2460, 0x24FF],
+    [0x2776, 0x2793],
+    [0x2C00, 0x2CE4],
+    [0x2CEB, 0x2CF3],
+    [0x2D00, 0x2D25],
+    [0x2D27, 0x2D27],
+    [0x2D2D, 0x2D2D],
+    [0x2D30, 0x2D67],
+    [0x2D6F, 0x2D6F],
+    [0x2D7F, 0x2D96],
+    [0x2DA0, 0x2DA6],
+    [0x2DA8, 0x2DAE],
+    [0x2DB0, 0x2DB6],
+    [0x2DB8, 0x2DBE],
+    [0x2DC0, 0x2DC6],
+    [0x2DC8, 0x2DCE],
+    [0x2DD0, 0x2DD6],
+    [0x2DD8, 0x2DDE],
+    [0x2DE0, 0x2DFF],
+    [0x2E80, 0x2FFF],
+    [0x3004, 0x3007],
+    [0x3021, 0x302F],
+    [0x3031, 0x303C],
+    [0x3041, 0x3096],
+    [0x3099, 0x309F],
+    [0x30A1, 0x30FC],
+    [0x3105, 0x312F],
+    [0x3131, 0x318E],
+    [0x31A0, 0x31BF],
+    [0x31F0, 0x31FF],
+    [0x3400, 0x4DBF],
+    [0x4E00, 0xA48C],
+    [0xA4D0, 0xA4FD],
+    [0xA500, 0xA60C],
+    [0xA610, 0xA61F],
+    [0xA62A, 0xA62B],
+    [0xA640, 0xA66F],
+    [0xA674, 0xA67D],
+    [0xA67F, 0xA6EF],
+    [0xA717, 0xA71F],
+    [0xA722, 0xA788],
+    [0xA78B, 0xA7CA],
+    [0xA7D0, 0xA7D1],
+    [0xA7D3, 0xA7D3],
+    [0xA7D5, 0xA7D9],
+    [0xA7F2, 0xA805],
+    [0xA807, 0xA80A],
+    [0xA80C, 0xA822],
+    [0xA82C, 0xA82C],
+    [0xA840, 0xA873],
+    [0xA880, 0xA8B3],
+    [0xA8D0, 0xA8D9],
+    [0xA8E0, 0xA8F7],
+    [0xA8FB, 0xA8FB],
+    [0xA8FD, 0xA8FE],
+    [0xA90A, 0xA925],
+    [0xA930, 0xA946],
+    [0xA960, 0xA97C],
+    [0xA980, 0xA9B2],
+    [0xA9CF, 0xA9CF],
+    [0xA9E0, 0xA9E4],
+    [0xA9E6, 0xA9EF],
+    [0xA9FA, 0xA9FE],
+    [0xAA00, 0xAA28],
+    [0xAA40, 0xAA42],
+    [0xAA44, 0xAA4B],
+    [0xAA50, 0xAA59],
+    [0xAA60, 0xAA76],
+    [0xAA7A, 0xAA7A],
+    [0xAA7E, 0xAAAF],
+    [0xAAB1, 0xAAB1],
+    [0xAAB5, 0xAAB6],
+    [0xAAB9, 0xAABD],
+    [0xAAC0, 0xAAC0],
+    [0xAAC2, 0xAAC2],
+    [0xAADB, 0xAADD],
+    [0xAAE0, 0xAAEA],
+    [0xAAF2, 0xAAF4],
+    [0xAB01, 0xAB06],
+    [0xAB09, 0xAB0E],
+    [0xAB11, 0xAB16],
+    [0xAB20, 0xAB26],
+    [0xAB28, 0xAB2E],
+    [0xAB30, 0xAB5A],
+    [0xAB5C, 0xAB69],
+    [0xAB70, 0xABE2],
+    [0xABEC, 0xABED],
+    [0xABF0, 0xABF9],
+    [0xAC00, 0xD7A3],
+    [0xD7B0, 0xD7C6],
+    [0xD7CB, 0xD7FB],
+    [0xF900, 0xFA6D],
+    [0xFA70, 0xFAD9],
+    [0xFB00, 0xFB06],
+    [0xFB13, 0xFB17],
+    [0xFB1D, 0xFB1D],
+    [0xFB1F, 0xFB28],
+    [0xFB2A, 0xFB36],
+    [0xFB38, 0xFB3C],
+    [0xFB3E, 0xFB3E],
+    [0xFB40, 0xFB41],
+    [0xFB43, 0xFB44],
+    [0xFB46, 0xFBB1],
+    [0xFBD3, 0xFC5D],
+    [0xFC64, 0xFD3D],
+    [0xFD40, 0xFD8F],
+    [0xFD92, 0xFDC7],
+    [0xFDF0, 0xFDF9],
+    [0xFE00, 0xFE0F],
+    [0xFE20, 0xFE2F],
+    [0xFE33, 0xFE34],
+    [0xFE47, 0xFE71],
+    [0xFE73, 0xFE73],
+    [0xFE77, 0xFE77],
+    [0xFE79, 0xFE79],
+    [0xFE7B, 0xFE7B],
+    [0xFE7D, 0xFE7D],
+    [0xFE7F, 0xFEFC],
+    [0xFF10, 0xFF19],
+    [0xFF21, 0xFF3A],
+    [0xFF3F, 0xFF3F],
+    [0xFF41, 0xFF5A],
+    [0xFF65, 0xFF9D],
+    [0xFFA0, 0xFFBE],
+    [0xFFC2, 0xFFC7],
+    [0xFFCA, 0xFFCF],
+    [0xFFD2, 0xFFD7],
+    [0xFFDA, 0xFFDC],
+    [0x10000, 0x1000B],
+    [0x1000D, 0x10026],
+    [0x10028, 0x1003A],
+    [0x1003C, 0x1003D],
+    [0x1003F, 0x1004D],
+    [0x10050, 0x1005D],
+    [0x10080, 0x100FA],
+    [0x10140, 0x10174],
+    [0x101FD, 0x101FD],
+    [0x10280, 0x1029C],
+    [0x102A0, 0x102D0],
+    [0x102E0, 0x102E0],
+    [0x10300, 0x1031F],
+    [0x1032D, 0x1034A],
+    [0x10350, 0x10375],
+    [0x10380, 0x1039D],
+    [0x103A0, 0x103C3],
+    [0x103C8, 0x103CF],
+    [0x103D1, 0x103D5],
+    [0x10400, 0x1049D],
+    [0x104A0, 0x104A9],
+    [0x104B0, 0x104D3],
+    [0x104D8, 0x104FB],
+    [0x10500, 0x10527],
+    [0x10530, 0x10563],
+    [0x10570, 0x1057A],
+    [0x1057C, 0x1058A],
+    [0x1058C, 0x10592],
+    [0x10594, 0x10595],
+    [0x10597, 0x105A1],
+    [0x105A3, 0x105B1],
+    [0x105B3, 0x105B9],
+    [0x105BB, 0x105BC],
+    [0x10600, 0x10736],
+    [0x10740, 0x10755],
+    [0x10760, 0x10767],
+    [0x10780, 0x10785],
+    [0x10787, 0x107B0],
+    [0x107B2, 0x107BA],
+    [0x10800, 0x10805],
+    [0x10808, 0x10808],
+    [0x1080A, 0x10835],
+    [0x10837, 0x10838],
+    [0x1083C, 0x1083C],
+    [0x1083F, 0x10855],
+    [0x10860, 0x10876],
+    [0x10880, 0x1089E],
+    [0x108E0, 0x108F2],
+    [0x108F4, 0x108F5],
+    [0x10900, 0x10915],
+    [0x10920, 0x10939],
+    [0x10980, 0x109B7],
+    [0x109BE, 0x109BF],
+    [0x10A00, 0x10A03],
+    [0x10A05, 0x10A06],
+    [0x10A0C, 0x10A13],
+    [0x10A15, 0x10A17],
+    [0x10A19, 0x10A35],
+    [0x10A38, 0x10A3A],
+    [0x10A3F, 0x10A3F],
+    [0x10A60, 0x10A7C],
+    [0x10A80, 0x10A9C],
+    [0x10AC0, 0x10AC7],
+    [0x10AC9, 0x10AE6],
+    [0x10B00, 0x10B35],
+    [0x10B40, 0x10B55],
+    [0x10B60, 0x10B72],
+    [0x10B80, 0x10B91],
+    [0x10C00, 0x10C48],
+    [0x10C80, 0x10CB2],
+    [0x10CC0, 0x10CF2],
+    [0x10D00, 0x10D23],
+    [0x10D30, 0x10D39],
+    [0x10E80, 0x10EA9],
+    [0x10EAB, 0x10EAC],
+    [0x10EB0, 0x10EB1],
+    [0x10EFD, 0x10F1C],
+    [0x10F27, 0x10F27],
+    [0x10F30, 0x10F45],
+    [0x10F70, 0x10F81],
+    [0x10FB0, 0x10FC4],
+    [0x10FE0, 0x10FF6],
+    [0x11000, 0x11037],
+    [0x11066, 0x11072],
+    [0x11075, 0x11075],
+    [0x1107F, 0x110AF],
+    [0x110C2, 0x110C2],
+    [0x110D0, 0x110E8],
+    [0x110F0, 0x110F9],
+    [0x11100, 0x11126],
+    [0x11136, 0x1113F],
+    [0x11144, 0x11147],
+    [0x11150, 0x11173],
+    [0x11176, 0x11176],
+    [0x11180, 0x111B2],
+    [0x111C1, 0x111C4],
+    [0x111C9, 0x111CC],
+    [0x111CE, 0x111DA],
+    [0x111DC, 0x111DC],
+    [0x11200, 0x11211],
+    [0x11213, 0x11237],
+    [0x1123E, 0x11240],
+    [0x11280, 0x11286],
+    [0x11288, 0x11288],
+    [0x1128A, 0x1128D],
+    [0x1128F, 0x1129D],
+    [0x1129F, 0x112A8],
+    [0x112B0, 0x112EA],
+    [0x112F0, 0x112F9],
+    [0x11300, 0x11303],
+    [0x11305, 0x1130C],
+    [0x1130F, 0x11310],
+    [0x11313, 0x11328],
+    [0x1132A, 0x11330],
+    [0x11332, 0x11333],
+    [0x11335, 0x11339],
+    [0x1133B, 0x1133D],
+    [0x11347, 0x11348],
+    [0x1134B, 0x1134D],
+    [0x11350, 0x11350],
+    [0x11357, 0x11357],
+    [0x1135D, 0x11363],
+    [0x11366, 0x1136C],
+    [0x11370, 0x11374],
+    [0x11400, 0x1144A],
+    [0x11450, 0x11459],
+    [0x1145E, 0x11461],
+    [0x11480, 0x114C5],
+    [0x114C7, 0x114C7],
+    [0x114D0, 0x114D9],
+    [0x11580, 0x115B5],
+    [0x115B8, 0x115C0],
+    [0x115D8, 0x115DD],
+    [0x11600, 0x11640],
+    [0x11644, 0x11644],
+    [0x11650, 0x11659],
+    [0x11680, 0x116B8],
+    [0x116C0, 0x116C9],
+    [0x11700, 0x1171A],
+    [0x1171D, 0x1172B],
+    [0x11730, 0x11739],
+    [0x11740, 0x11746],
+    [0x11800, 0x1183A],
+    [0x118A0, 0x118E9],
+    [0x118FF, 0x11906],
+    [0x11909, 0x11909],
+    [0x1190C, 0x11913],
+    [0x11915, 0x11916],
+    [0x11918, 0x11935],
+    [0x11937, 0x11938],
+    [0x1193B, 0x1193F],
+    [0x11941, 0x11941],
+    [0x11950, 0x11959],
+    [0x119A0, 0x119A7],
+    [0x119AA, 0x119D7],
+    [0x119DA, 0x119E1],
+    [0x119E3, 0x119E3],
+    [0x11A00, 0x11A32],
+    [0x11A3A, 0x11A3A],
+    [0x11A47, 0x11A47],
+    [0x11A50, 0x11A89],
+    [0x11A9D, 0x11A9D],
+    [0x11AB0, 0x11AF8],
+    [0x11C00, 0x11C08],
+    [0x11C0A, 0x11C36],
+    [0x11C38, 0x11C40],
+    [0x11C50, 0x11C59],
+    [0x11C72, 0x11C8F],
+    [0x11C92, 0x11CA7],
+    [0x11CA9, 0x11CB6],
+    [0x11D00, 0x11D06],
+    [0x11D08, 0x11D09],
+    [0x11D0B, 0x11D36],
+    [0x11D3A, 0x11D3A],
+    [0x11D3C, 0x11D3D],
+    [0x11D3F, 0x11D46],
+    [0x11D50, 0x11D59],
+    [0x11D60, 0x11D65],
+    [0x11D67, 0x11D68],
+    [0x11D6A, 0x11D89],
+    [0x11D90, 0x11D91],
+    [0x11D93, 0x11D98],
+    [0x11DA0, 0x11DA9],
+    [0x11EE0, 0x11EF2],
+    [0x11F00, 0x11F02],
+    [0x11F04, 0x11F10],
+    [0x11F12, 0x11F33],
+    [0x11F3E, 0x11F42],
+    [0x11F50, 0x11F59],
+    [0x11FB0, 0x11FB0],
+    [0x12000, 0x12399],
+    [0x12400, 0x1246E],
+    [0x12480, 0x12543],
+    [0x12F90, 0x12FF0],
+    [0x13000, 0x1342F],
+    [0x13440, 0x13446],
+    [0x14400, 0x14646],
+    [0x16800, 0x16A38],
+    [0x16A40, 0x16A5E],
+    [0x16A60, 0x16A69],
+    [0x16A70, 0x16ABE],
+    [0x16AC0, 0x16AC9],
+    [0x16AD0, 0x16AED],
+    [0x16AF0, 0x16AF4],
+    [0x16B00, 0x16B2F],
+    [0x16B40, 0x16B43],
+    [0x16B50, 0x16B59],
+    [0x16B63, 0x16B77],
+    [0x16B7D, 0x16B8F],
+    [0x16E40, 0x16E7F],
+    [0x16F00, 0x16F4A],
+    [0x16F4F, 0x16F50],
+    [0x16F8F, 0x16F9F],
+    [0x16FE0, 0x16FE1],
+    [0x16FE3, 0x16FE3],
+    [0x16FF0, 0x16FF1],
+    [0x17000, 0x187F7],
+    [0x18800, 0x18CD5],
+    [0x18D00, 0x18D08],
+    [0x1AFF0, 0x1AFF3],
+    [0x1AFF5, 0x1AFFB],
+    [0x1AFFD, 0x1AFFE],
+    [0x1B000, 0x1B122],
+    [0x1B132, 0x1B132],
+    [0x1B150, 0x1B152],
+    [0x1B155, 0x1B155],
+    [0x1B164, 0x1B167],
+    [0x1B170, 0x1B2FB],
+    [0x1BC00, 0x1BC6A],
+    [0x1BC70, 0x1BC7C],
+    [0x1BC80, 0x1BC88],
+    [0x1BC90, 0x1BC99],
+    [0x1BC9D, 0x1BC9E],
+    [0x1CF00, 0x1CF2D],
+    [0x1CF30, 0x1CF46],
+    [0x1D165, 0x1D169],
+    [0x1D16D, 0x1D172],
+    [0x1D17B, 0x1D182],
+    [0x1D185, 0x1D18B],
+    [0x1D1AA, 0x1D1AD],
+    [0x1D242, 0x1D244],
+    [0x1D400, 0x1D454],
+    [0x1D456, 0x1D49C],
+    [0x1D49E, 0x1D49F],
+    [0x1D4A2, 0x1D4A2],
+    [0x1D4A5, 0x1D4A6],
+    [0x1D4A9, 0x1D4AC],
+    [0x1D4AE, 0x1D4B9],
+    [0x1D4BB, 0x1D4BB],
+    [0x1D4BD, 0x1D4C3],
+    [0x1D4C5, 0x1D505],
+    [0x1D507, 0x1D50A],
+    [0x1D50D, 0x1D514],
+    [0x1D516, 0x1D51C],
+    [0x1D51E, 0x1D539],
+    [0x1D53B, 0x1D53E],
+    [0x1D540, 0x1D544],
+    [0x1D546, 0x1D546],
+    [0x1D54A, 0x1D550],
+    [0x1D552, 0x1D6A5],
+    [0x1D6A8, 0x1D6C0],
+    [0x1D6C2, 0x1D6DA],
+    [0x1D6DC, 0x1D6FA],
+    [0x1D6FC, 0x1D714],
+    [0x1D716, 0x1D734],
+    [0x1D736, 0x1D74E],
+    [0x1D750, 0x1D76E],
+    [0x1D770, 0x1D788],
+    [0x1D78A, 0x1D7A8],
+    [0x1D7AA, 0x1D7C2],
+    [0x1D7C4, 0x1D7CB],
+    [0x1D7CE, 0x1D7FF],
+    [0x1DA00, 0x1DA36],
+    [0x1DA3B, 0x1DA6C],
+    [0x1DA75, 0x1DA75],
+    [0x1DA84, 0x1DA84],
+    [0x1DA9B, 0x1DA9F],
+    [0x1DAA1, 0x1DAAF],
+    [0x1DF00, 0x1DF1E],
+    [0x1DF25, 0x1DF2A],
+    [0x1E000, 0x1E006],
+    [0x1E008, 0x1E018],
+    [0x1E01B, 0x1E021],
+    [0x1E023, 0x1E024],
+    [0x1E026, 0x1E02A],
+    [0x1E030, 0x1E06D],
+    [0x1E08F, 0x1E08F],
+    [0x1E100, 0x1E12C],
+    [0x1E130, 0x1E13D],
+    [0x1E140, 0x1E149],
+    [0x1E14E, 0x1E14E],
+    [0x1E290, 0x1E2AE],
+    [0x1E2C0, 0x1E2F9],
+    [0x1E4D0, 0x1E4F9],
+    [0x1E7E0, 0x1E7E6],
+    [0x1E7E8, 0x1E7EB],
+    [0x1E7ED, 0x1E7EE],
+    [0x1E7F0, 0x1E7FE],
+    [0x1E800, 0x1E8C4],
+    [0x1E8D0, 0x1E8D6],
+    [0x1E900, 0x1E94B],
+    [0x1E950, 0x1E959],
+    [0x1EE00, 0x1EE03],
+    [0x1EE05, 0x1EE1F],
+    [0x1EE21, 0x1EE22],
+    [0x1EE24, 0x1EE24],
+    [0x1EE27, 0x1EE27],
+    [0x1EE29, 0x1EE32],
+    [0x1EE34, 0x1EE37],
+    [0x1EE39, 0x1EE39],
+    [0x1EE3B, 0x1EE3B],
+    [0x1EE42, 0x1EE42],
+    [0x1EE47, 0x1EE47],
+    [0x1EE49, 0x1EE49],
+    [0x1EE4B, 0x1EE4B],
+    [0x1EE4D, 0x1EE4F],
+    [0x1EE51, 0x1EE52],
+    [0x1EE54, 0x1EE54],
+    [0x1EE57, 0x1EE57],
+    [0x1EE59, 0x1EE59],
+    [0x1EE5B, 0x1EE5B],
+    [0x1EE5D, 0x1EE5D],
+    [0x1EE5F, 0x1EE5F],
+    [0x1EE61, 0x1EE62],
+    [0x1EE64, 0x1EE64],
+    [0x1EE67, 0x1EE6A],
+    [0x1EE6C, 0x1EE72],
+    [0x1EE74, 0x1EE77],
+    [0x1EE79, 0x1EE7C],
+    [0x1EE7E, 0x1EE7E],
+    [0x1EE80, 0x1EE89],
+    [0x1EE8B, 0x1EE9B],
+    [0x1EEA1, 0x1EEA3],
+    [0x1EEA5, 0x1EEA9],
+    [0x1EEAB, 0x1EEBB],
+    [0x1FBF0, 0x1FBF9],
+    [0x20000, 0x2B739],
+    [0x2B740, 0x2B81D],
+    [0x2B820, 0x2CEA1],
+    [0x2CEB0, 0x2EBE0],
+    [0x2EBF0, 0x2EE5D],
+    [0x2F800, 0x2FA1D],
+    [0x30000, 0x323AF],
+    [0x40000, 0x4FFFD],
+    [0x50000, 0x5FFFD],
+    [0x60000, 0x6FFFD],
+    [0x70000, 0x7FFFD],
+    [0x80000, 0x8FFFD],
+    [0x90000, 0x9FFFD],
+    [0xA0000, 0xAFFFD],
+    [0xB0000, 0xBFFFD],
+    [0xC0000, 0xCFFFD],
+    [0xD0000, 0xDFFFD],
+    [0xE0000, 0xEFFFD],
+];
+
+/**
+Least restrictive Start
+Entries: 858717
+*/
+static immutable dchar[2][] LeastRestrictive_Start = [
+    [0xA8, 0xA8],
+    [0xAA, 0xAA],
+    [0xAD, 0xAD],
+    [0xAF, 0xAF],
+    [0xB2, 0xB5],
+    [0xB7, 0xBA],
+    [0xBC, 0xBE],
+    [0xC0, 0xD6],
+    [0xD8, 0xF6],
+    [0xF8, 0x217],
+    [0x250, 0x2A8],
+    [0x2B0, 0x2B8],
+    [0x2BB, 0x2BB],
+    [0x2BD, 0x2C1],
+    [0x2C6, 0x2D1],
+    [0x2E0, 0x2E4],
+    [0x2EC, 0x2EC],
+    [0x2EE, 0x2EE],
+    [0x370, 0x374],
+    [0x376, 0x377],
+    [0x37A, 0x37D],
+    [0x37F, 0x37F],
+    [0x386, 0x386],
+    [0x388, 0x38A],
+    [0x38C, 0x38C],
+    [0x38E, 0x3A1],
+    [0x3A3, 0x3CE],
+    [0x3D0, 0x3D6],
+    [0x3DA, 0x3DA],
+    [0x3DC, 0x3DC],
+    [0x3DE, 0x3DE],
+    [0x3E0, 0x3E0],
+    [0x3E2, 0x3F3],
+    [0x3F7, 0x40C],
+    [0x40E, 0x44F],
+    [0x451, 0x45C],
+    [0x45E, 0x481],
+    [0x48A, 0x4C4],
+    [0x4C7, 0x4C8],
+    [0x4CB, 0x4CC],
+    [0x4D0, 0x4EB],
+    [0x4EE, 0x4F5],
+    [0x4F8, 0x4F9],
+    [0x531, 0x556],
+    [0x559, 0x559],
+    [0x560, 0x587],
+    [0x5B0, 0x5B9],
+    [0x5BB, 0x5BD],
+    [0x5BF, 0x5BF],
+    [0x5C1, 0x5C2],
+    [0x5D0, 0x5EA],
+    [0x5EF, 0x5F2],
+    [0x620, 0x63A],
+    [0x640, 0x652],
+    [0x660, 0x669],
+    [0x66E, 0x6BE],
+    [0x6C0, 0x6CE],
+    [0x6D0, 0x6D5],
+    [0x6E5, 0x6E8],
+    [0x6EA, 0x6FC],
+    [0x6FF, 0x6FF],
+    [0x710, 0x710],
+    [0x712, 0x72F],
+    [0x74D, 0x7A5],
+    [0x7B1, 0x7B1],
+    [0x7CA, 0x7EA],
+    [0x7F4, 0x7F5],
+    [0x7FA, 0x7FA],
+    [0x800, 0x815],
+    [0x81A, 0x81A],
+    [0x824, 0x824],
+    [0x828, 0x828],
+    [0x840, 0x858],
+    [0x860, 0x86A],
+    [0x870, 0x887],
+    [0x889, 0x88E],
+    [0x8A0, 0x8C9],
+    [0x901, 0x939],
+    [0x93D, 0x94D],
+    [0x950, 0x952],
+    [0x958, 0x963],
+    [0x966, 0x96F],
+    [0x971, 0x983],
+    [0x985, 0x98C],
+    [0x98F, 0x990],
+    [0x993, 0x9A8],
+    [0x9AA, 0x9B0],
+    [0x9B2, 0x9B2],
+    [0x9B6, 0x9B9],
+    [0x9BD, 0x9C4],
+    [0x9C7, 0x9C8],
+    [0x9CB, 0x9CE],
+    [0x9DC, 0x9DD],
+    [0x9DF, 0x9E3],
+    [0x9E6, 0x9F1],
+    [0x9FC, 0x9FC],
+    [0xA02, 0xA02],
+    [0xA05, 0xA0A],
+    [0xA0F, 0xA10],
+    [0xA13, 0xA28],
+    [0xA2A, 0xA30],
+    [0xA32, 0xA33],
+    [0xA35, 0xA36],
+    [0xA38, 0xA39],
+    [0xA3E, 0xA42],
+    [0xA47, 0xA48],
+    [0xA4B, 0xA4D],
+    [0xA59, 0xA5C],
+    [0xA5E, 0xA5E],
+    [0xA66, 0xA6F],
+    [0xA72, 0xA74],
+    [0xA81, 0xA83],
+    [0xA85, 0xA8B],
+    [0xA8D, 0xA8D],
+    [0xA8F, 0xA91],
+    [0xA93, 0xAA8],
+    [0xAAA, 0xAB0],
+    [0xAB2, 0xAB3],
+    [0xAB5, 0xAB9],
+    [0xABD, 0xABD],
+    [0xAC7, 0xAC9],
+    [0xACB, 0xACD],
+    [0xAD0, 0xAD0],
+    [0xAE0, 0xAE0],
+    [0xAE6, 0xAEF],
+    [0xAF9, 0xAF9],
+    [0xB01, 0xB03],
+    [0xB05, 0xB0C],
+    [0xB0F, 0xB10],
+    [0xB13, 0xB28],
+    [0xB2A, 0xB30],
+    [0xB32, 0xB33],
+    [0xB35, 0xB39],
+    [0xB3D, 0xB43],
+    [0xB47, 0xB48],
+    [0xB4B, 0xB4D],
+    [0xB5C, 0xB5D],
+    [0xB5F, 0xB61],
+    [0xB66, 0xB6F],
+    [0xB71, 0xB71],
+    [0xB82, 0xB83],
+    [0xB85, 0xB8A],
+    [0xB8E, 0xB90],
+    [0xB92, 0xB95],
+    [0xB99, 0xB9A],
+    [0xB9C, 0xB9C],
+    [0xB9E, 0xB9F],
+    [0xBA3, 0xBA4],
+    [0xBA8, 0xBAA],
+    [0xBAE, 0xBB5],
+    [0xBB7, 0xBB9],
+    [0xBBE, 0xBC2],
+    [0xBC6, 0xBC8],
+    [0xBCA, 0xBCD],
+    [0xBD0, 0xBD0],
+    [0xBE7, 0xBEF],
+    [0xC01, 0xC03],
+    [0xC05, 0xC0C],
+    [0xC0E, 0xC10],
+    [0xC12, 0xC28],
+    [0xC2A, 0xC33],
+    [0xC35, 0xC39],
+    [0xC3D, 0xC44],
+    [0xC46, 0xC48],
+    [0xC4A, 0xC4D],
+    [0xC58, 0xC5A],
+    [0xC5D, 0xC5D],
+    [0xC60, 0xC61],
+    [0xC66, 0xC6F],
+    [0xC80, 0xC80],
+    [0xC82, 0xC83],
+    [0xC85, 0xC8C],
+    [0xC8E, 0xC90],
+    [0xC92, 0xCA8],
+    [0xCAA, 0xCB3],
+    [0xCB5, 0xCB9],
+    [0xCBD, 0xCC4],
+    [0xCC6, 0xCC8],
+    [0xCCA, 0xCCD],
+    [0xCDD, 0xCDE],
+    [0xCE0, 0xCE1],
+    [0xCE6, 0xCEF],
+    [0xCF1, 0xCF2],
+    [0xD02, 0xD0C],
+    [0xD0E, 0xD10],
+    [0xD12, 0xD28],
+    [0xD2A, 0xD39],
+    [0xD3D, 0xD43],
+    [0xD46, 0xD48],
+    [0xD4A, 0xD4E],
+    [0xD54, 0xD56],
+    [0xD5F, 0xD61],
+    [0xD66, 0xD6F],
+    [0xD7A, 0xD7F],
+    [0xD85, 0xD96],
+    [0xD9A, 0xDB1],
+    [0xDB3, 0xDBB],
+    [0xDBD, 0xDBD],
+    [0xDC0, 0xDC6],
+    [0xE01, 0xE30],
+    [0xE32, 0xE32],
+    [0xE40, 0xE5B],
+    [0xE81, 0xE82],
+    [0xE84, 0xE84],
+    [0xE86, 0xE88],
+    [0xE8A, 0xE8A],
+    [0xE8C, 0xE8D],
+    [0xE94, 0xE97],
+    [0xE99, 0xE9F],
+    [0xEA1, 0xEA3],
+    [0xEA5, 0xEA5],
+    [0xEA7, 0xEAB],
+    [0xEAD, 0xEAE],
+    [0xEB0, 0xEB2],
+    [0xEBB, 0xEBD],
+    [0xEC0, 0xEC4],
+    [0xEC6, 0xEC6],
+    [0xEC8, 0xECD],
+    [0xED0, 0xED9],
+    [0xEDC, 0xEDD],
+    [0xF00, 0xF00],
+    [0xF18, 0xF19],
+    [0xF20, 0xF33],
+    [0xF35, 0xF35],
+    [0xF37, 0xF37],
+    [0xF39, 0xF39],
+    [0xF3E, 0xF47],
+    [0xF49, 0xF69],
+    [0xF71, 0xF84],
+    [0xF86, 0xF8C],
+    [0xF90, 0xF95],
+    [0xF97, 0xF97],
+    [0xF99, 0xFAD],
+    [0xFB1, 0xFB7],
+    [0xFB9, 0xFB9],
+    [0x1000, 0x102A],
+    [0x103F, 0x103F],
+    [0x1050, 0x1055],
+    [0x105A, 0x105D],
+    [0x1061, 0x1061],
+    [0x1065, 0x1066],
+    [0x106E, 0x1070],
+    [0x1075, 0x1081],
+    [0x108E, 0x108E],
+    [0x10A0, 0x10C5],
+    [0x10C7, 0x10C7],
+    [0x10CD, 0x10CD],
+    [0x10D0, 0x10FA],
+    [0x10FC, 0x1248],
+    [0x124A, 0x124D],
+    [0x1250, 0x1256],
+    [0x1258, 0x1258],
+    [0x125A, 0x125D],
+    [0x1260, 0x1288],
+    [0x128A, 0x128D],
+    [0x1290, 0x12B0],
+    [0x12B2, 0x12B5],
+    [0x12B8, 0x12BE],
+    [0x12C0, 0x12C0],
+    [0x12C2, 0x12C5],
+    [0x12C8, 0x12D6],
+    [0x12D8, 0x1310],
+    [0x1312, 0x1315],
+    [0x1318, 0x135A],
+    [0x1380, 0x138F],
+    [0x13A0, 0x13F5],
+    [0x13F8, 0x13FD],
+    [0x1401, 0x166C],
+    [0x166F, 0x167F],
+    [0x1681, 0x169A],
+    [0x16A0, 0x16EA],
+    [0x16EE, 0x16F8],
+    [0x1700, 0x1711],
+    [0x171F, 0x1731],
+    [0x1740, 0x1751],
+    [0x1760, 0x176C],
+    [0x176E, 0x1770],
+    [0x1780, 0x17B3],
+    [0x17D7, 0x17D7],
+    [0x17DC, 0x17DC],
+    [0x180F, 0x1878],
+    [0x1880, 0x18A8],
+    [0x18AA, 0x18AA],
+    [0x18B0, 0x18F5],
+    [0x1900, 0x191E],
+    [0x1950, 0x196D],
+    [0x1970, 0x1974],
+    [0x1980, 0x19AB],
+    [0x19B0, 0x19C9],
+    [0x1A00, 0x1A16],
+    [0x1A20, 0x1A54],
+    [0x1AA7, 0x1AA7],
+    [0x1B05, 0x1B33],
+    [0x1B45, 0x1B4C],
+    [0x1B83, 0x1BA0],
+    [0x1BAE, 0x1BAF],
+    [0x1BBA, 0x1BE5],
+    [0x1C00, 0x1C23],
+    [0x1C4D, 0x1C4F],
+    [0x1C5A, 0x1C7D],
+    [0x1C80, 0x1C88],
+    [0x1C90, 0x1CBA],
+    [0x1CBD, 0x1CBF],
+    [0x1CE9, 0x1CEC],
+    [0x1CEE, 0x1CF3],
+    [0x1CF5, 0x1CF6],
+    [0x1CFA, 0x1CFA],
+    [0x1D00, 0x1DBF],
+    [0x1E00, 0x1EF9],
+    [0x1F00, 0x1F15],
+    [0x1F18, 0x1F1D],
+    [0x1F20, 0x1F45],
+    [0x1F48, 0x1F4D],
+    [0x1F50, 0x1F57],
+    [0x1F59, 0x1F59],
+    [0x1F5B, 0x1F5B],
+    [0x1F5D, 0x1F5D],
+    [0x1F5F, 0x1F7D],
+    [0x1F80, 0x1FB4],
+    [0x1FB6, 0x1FBC],
+    [0x1FBE, 0x1FBE],
+    [0x1FC2, 0x1FC4],
+    [0x1FC6, 0x1FCC],
+    [0x1FD0, 0x1FD3],
+    [0x1FD6, 0x1FDB],
+    [0x1FE0, 0x1FEC],
+    [0x1FF2, 0x1FF4],
+    [0x1FF6, 0x1FFC],
+    [0x200B, 0x200D],
+    [0x202A, 0x202E],
+    [0x203F, 0x2040],
+    [0x2054, 0x2054],
+    [0x2060, 0x2071],
+    [0x207F, 0x207F],
+    [0x2090, 0x209C],
+    [0x2102, 0x2102],
+    [0x2107, 0x2107],
+    [0x210A, 0x2113],
+    [0x2115, 0x2115],
+    [0x2118, 0x211D],
+    [0x2124, 0x2124],
+    [0x2126, 0x2126],
+    [0x2128, 0x2128],
+    [0x212A, 0x2138],
+    [0x213C, 0x213F],
+    [0x2145, 0x2149],
+    [0x214E, 0x214E],
+    [0x2160, 0x2188],
+    [0x2460, 0x24FF],
+    [0x2776, 0x2793],
+    [0x2C00, 0x2CE4],
+    [0x2CEB, 0x2CEE],
+    [0x2CF2, 0x2CF3],
+    [0x2D00, 0x2D25],
+    [0x2D27, 0x2D27],
+    [0x2D2D, 0x2D2D],
+    [0x2D30, 0x2D67],
+    [0x2D6F, 0x2D6F],
+    [0x2D80, 0x2D96],
+    [0x2DA0, 0x2DA6],
+    [0x2DA8, 0x2DAE],
+    [0x2DB0, 0x2DB6],
+    [0x2DB8, 0x2DBE],
+    [0x2DC0, 0x2DC6],
+    [0x2DC8, 0x2DCE],
+    [0x2DD0, 0x2DD6],
+    [0x2DD8, 0x2DDE],
+    [0x2E80, 0x2FFF],
+    [0x3004, 0x3007],
+    [0x3021, 0x3029],
+    [0x3031, 0x3035],
+    [0x3038, 0x303C],
+    [0x3041, 0x3096],
+    [0x309B, 0x309F],
+    [0x30A1, 0x30FF],
+    [0x3105, 0x312F],
+    [0x3131, 0x318E],
+    [0x31A0, 0x31BF],
+    [0x31F0, 0x31FF],
+    [0x3400, 0x4DBF],
+    [0x4E00, 0xA48C],
+    [0xA4D0, 0xA4FD],
+    [0xA500, 0xA60C],
+    [0xA610, 0xA61F],
+    [0xA62A, 0xA62B],
+    [0xA640, 0xA66E],
+    [0xA67F, 0xA69D],
+    [0xA6A0, 0xA6EF],
+    [0xA717, 0xA71F],
+    [0xA722, 0xA788],
+    [0xA78B, 0xA7CA],
+    [0xA7D0, 0xA7D1],
+    [0xA7D3, 0xA7D3],
+    [0xA7D5, 0xA7D9],
+    [0xA7F2, 0xA801],
+    [0xA803, 0xA805],
+    [0xA807, 0xA80A],
+    [0xA80C, 0xA822],
+    [0xA840, 0xA873],
+    [0xA882, 0xA8B3],
+    [0xA8F2, 0xA8F7],
+    [0xA8FB, 0xA8FB],
+    [0xA8FD, 0xA8FE],
+    [0xA90A, 0xA925],
+    [0xA930, 0xA946],
+    [0xA960, 0xA97C],
+    [0xA984, 0xA9B2],
+    [0xA9CF, 0xA9CF],
+    [0xA9E0, 0xA9E4],
+    [0xA9E6, 0xA9EF],
+    [0xA9FA, 0xA9FE],
+    [0xAA00, 0xAA28],
+    [0xAA40, 0xAA42],
+    [0xAA44, 0xAA4B],
+    [0xAA60, 0xAA76],
+    [0xAA7A, 0xAA7A],
+    [0xAA7E, 0xAAAF],
+    [0xAAB1, 0xAAB1],
+    [0xAAB5, 0xAAB6],
+    [0xAAB9, 0xAABD],
+    [0xAAC0, 0xAAC0],
+    [0xAAC2, 0xAAC2],
+    [0xAADB, 0xAADD],
+    [0xAAE0, 0xAAEA],
+    [0xAAF2, 0xAAF4],
+    [0xAB01, 0xAB06],
+    [0xAB09, 0xAB0E],
+    [0xAB11, 0xAB16],
+    [0xAB20, 0xAB26],
+    [0xAB28, 0xAB2E],
+    [0xAB30, 0xAB5A],
+    [0xAB5C, 0xAB69],
+    [0xAB70, 0xABE2],
+    [0xAC00, 0xD7A3],
+    [0xD7B0, 0xD7C6],
+    [0xD7CB, 0xD7FB],
+    [0xF900, 0xFA6D],
+    [0xFA70, 0xFAD9],
+    [0xFB00, 0xFB06],
+    [0xFB13, 0xFB17],
+    [0xFB1D, 0xFB1D],
+    [0xFB1F, 0xFB28],
+    [0xFB2A, 0xFB36],
+    [0xFB38, 0xFB3C],
+    [0xFB3E, 0xFB3E],
+    [0xFB40, 0xFB41],
+    [0xFB43, 0xFB44],
+    [0xFB46, 0xFBB1],
+    [0xFBD3, 0xFC5D],
+    [0xFC64, 0xFD3D],
+    [0xFD40, 0xFD8F],
+    [0xFD92, 0xFDC7],
+    [0xFDF0, 0xFDF9],
+    [0xFE47, 0xFE71],
+    [0xFE73, 0xFE73],
+    [0xFE77, 0xFE77],
+    [0xFE79, 0xFE79],
+    [0xFE7B, 0xFE7B],
+    [0xFE7D, 0xFE7D],
+    [0xFE7F, 0xFEFC],
+    [0xFF21, 0xFF3A],
+    [0xFF41, 0xFF5A],
+    [0xFF66, 0xFF9D],
+    [0xFFA0, 0xFFBE],
+    [0xFFC2, 0xFFC7],
+    [0xFFCA, 0xFFCF],
+    [0xFFD2, 0xFFD7],
+    [0xFFDA, 0xFFDC],
+    [0x10000, 0x1000B],
+    [0x1000D, 0x10026],
+    [0x10028, 0x1003A],
+    [0x1003C, 0x1003D],
+    [0x1003F, 0x1004D],
+    [0x10050, 0x1005D],
+    [0x10080, 0x100FA],
+    [0x10140, 0x10174],
+    [0x10280, 0x1029C],
+    [0x102A0, 0x102D0],
+    [0x10300, 0x1031F],
+    [0x1032D, 0x1034A],
+    [0x10350, 0x10375],
+    [0x10380, 0x1039D],
+    [0x103A0, 0x103C3],
+    [0x103C8, 0x103CF],
+    [0x103D1, 0x103D5],
+    [0x10400, 0x1049D],
+    [0x104B0, 0x104D3],
+    [0x104D8, 0x104FB],
+    [0x10500, 0x10527],
+    [0x10530, 0x10563],
+    [0x10570, 0x1057A],
+    [0x1057C, 0x1058A],
+    [0x1058C, 0x10592],
+    [0x10594, 0x10595],
+    [0x10597, 0x105A1],
+    [0x105A3, 0x105B1],
+    [0x105B3, 0x105B9],
+    [0x105BB, 0x105BC],
+    [0x10600, 0x10736],
+    [0x10740, 0x10755],
+    [0x10760, 0x10767],
+    [0x10780, 0x10785],
+    [0x10787, 0x107B0],
+    [0x107B2, 0x107BA],
+    [0x10800, 0x10805],
+    [0x10808, 0x10808],
+    [0x1080A, 0x10835],
+    [0x10837, 0x10838],
+    [0x1083C, 0x1083C],
+    [0x1083F, 0x10855],
+    [0x10860, 0x10876],
+    [0x10880, 0x1089E],
+    [0x108E0, 0x108F2],
+    [0x108F4, 0x108F5],
+    [0x10900, 0x10915],
+    [0x10920, 0x10939],
+    [0x10980, 0x109B7],
+    [0x109BE, 0x109BF],
+    [0x10A00, 0x10A00],
+    [0x10A10, 0x10A13],
+    [0x10A15, 0x10A17],
+    [0x10A19, 0x10A35],
+    [0x10A60, 0x10A7C],
+    [0x10A80, 0x10A9C],
+    [0x10AC0, 0x10AC7],
+    [0x10AC9, 0x10AE4],
+    [0x10B00, 0x10B35],
+    [0x10B40, 0x10B55],
+    [0x10B60, 0x10B72],
+    [0x10B80, 0x10B91],
+    [0x10C00, 0x10C48],
+    [0x10C80, 0x10CB2],
+    [0x10CC0, 0x10CF2],
+    [0x10D00, 0x10D23],
+    [0x10E80, 0x10EA9],
+    [0x10EB0, 0x10EB1],
+    [0x10F00, 0x10F1C],
+    [0x10F27, 0x10F27],
+    [0x10F30, 0x10F45],
+    [0x10F70, 0x10F81],
+    [0x10FB0, 0x10FC4],
+    [0x10FE0, 0x10FF6],
+    [0x11003, 0x11037],
+    [0x11071, 0x11072],
+    [0x11075, 0x11075],
+    [0x11083, 0x110AF],
+    [0x110D0, 0x110E8],
+    [0x11103, 0x11126],
+    [0x11144, 0x11144],
+    [0x11147, 0x11147],
+    [0x11150, 0x11172],
+    [0x11176, 0x11176],
+    [0x11183, 0x111B2],
+    [0x111C1, 0x111C4],
+    [0x111DA, 0x111DA],
+    [0x111DC, 0x111DC],
+    [0x11200, 0x11211],
+    [0x11213, 0x1122B],
+    [0x1123F, 0x11240],
+    [0x11280, 0x11286],
+    [0x11288, 0x11288],
+    [0x1128A, 0x1128D],
+    [0x1128F, 0x1129D],
+    [0x1129F, 0x112A8],
+    [0x112B0, 0x112DE],
+    [0x11305, 0x1130C],
+    [0x1130F, 0x11310],
+    [0x11313, 0x11328],
+    [0x1132A, 0x11330],
+    [0x11332, 0x11333],
+    [0x11335, 0x11339],
+    [0x1133D, 0x1133D],
+    [0x11350, 0x11350],
+    [0x1135D, 0x11361],
+    [0x11400, 0x11434],
+    [0x11447, 0x1144A],
+    [0x1145F, 0x11461],
+    [0x11480, 0x114AF],
+    [0x114C4, 0x114C5],
+    [0x114C7, 0x114C7],
+    [0x11580, 0x115AE],
+    [0x115D8, 0x115DB],
+    [0x11600, 0x1162F],
+    [0x11644, 0x11644],
+    [0x11680, 0x116AA],
+    [0x116B8, 0x116B8],
+    [0x11700, 0x1171A],
+    [0x11740, 0x11746],
+    [0x11800, 0x1182B],
+    [0x118A0, 0x118DF],
+    [0x118FF, 0x11906],
+    [0x11909, 0x11909],
+    [0x1190C, 0x11913],
+    [0x11915, 0x11916],
+    [0x11918, 0x1192F],
+    [0x1193F, 0x1193F],
+    [0x11941, 0x11941],
+    [0x119A0, 0x119A7],
+    [0x119AA, 0x119D0],
+    [0x119E1, 0x119E1],
+    [0x119E3, 0x119E3],
+    [0x11A00, 0x11A00],
+    [0x11A0B, 0x11A32],
+    [0x11A3A, 0x11A3A],
+    [0x11A50, 0x11A50],
+    [0x11A5C, 0x11A89],
+    [0x11A9D, 0x11A9D],
+    [0x11AB0, 0x11AF8],
+    [0x11C00, 0x11C08],
+    [0x11C0A, 0x11C2E],
+    [0x11C40, 0x11C40],
+    [0x11C72, 0x11C8F],
+    [0x11D00, 0x11D06],
+    [0x11D08, 0x11D09],
+    [0x11D0B, 0x11D30],
+    [0x11D46, 0x11D46],
+    [0x11D60, 0x11D65],
+    [0x11D67, 0x11D68],
+    [0x11D6A, 0x11D89],
+    [0x11D98, 0x11D98],
+    [0x11EE0, 0x11EF2],
+    [0x11F02, 0x11F02],
+    [0x11F04, 0x11F10],
+    [0x11F12, 0x11F33],
+    [0x11FB0, 0x11FB0],
+    [0x12000, 0x12399],
+    [0x12400, 0x1246E],
+    [0x12480, 0x12543],
+    [0x12F90, 0x12FF0],
+    [0x13000, 0x1342F],
+    [0x13441, 0x13446],
+    [0x14400, 0x14646],
+    [0x16800, 0x16A38],
+    [0x16A40, 0x16A5E],
+    [0x16A70, 0x16ABE],
+    [0x16AD0, 0x16AED],
+    [0x16B00, 0x16B2F],
+    [0x16B40, 0x16B43],
+    [0x16B63, 0x16B77],
+    [0x16B7D, 0x16B8F],
+    [0x16E40, 0x16E7F],
+    [0x16F00, 0x16F4A],
+    [0x16F50, 0x16F50],
+    [0x16F93, 0x16F9F],
+    [0x16FE0, 0x16FE1],
+    [0x16FE3, 0x16FE3],
+    [0x17000, 0x187F7],
+    [0x18800, 0x18CD5],
+    [0x18D00, 0x18D08],
+    [0x1AFF0, 0x1AFF3],
+    [0x1AFF5, 0x1AFFB],
+    [0x1AFFD, 0x1AFFE],
+    [0x1B000, 0x1B122],
+    [0x1B132, 0x1B132],
+    [0x1B150, 0x1B152],
+    [0x1B155, 0x1B155],
+    [0x1B164, 0x1B167],
+    [0x1B170, 0x1B2FB],
+    [0x1BC00, 0x1BC6A],
+    [0x1BC70, 0x1BC7C],
+    [0x1BC80, 0x1BC88],
+    [0x1BC90, 0x1BC99],
+    [0x1D400, 0x1D454],
+    [0x1D456, 0x1D49C],
+    [0x1D49E, 0x1D49F],
+    [0x1D4A2, 0x1D4A2],
+    [0x1D4A5, 0x1D4A6],
+    [0x1D4A9, 0x1D4AC],
+    [0x1D4AE, 0x1D4B9],
+    [0x1D4BB, 0x1D4BB],
+    [0x1D4BD, 0x1D4C3],
+    [0x1D4C5, 0x1D505],
+    [0x1D507, 0x1D50A],
+    [0x1D50D, 0x1D514],
+    [0x1D516, 0x1D51C],
+    [0x1D51E, 0x1D539],
+    [0x1D53B, 0x1D53E],
+    [0x1D540, 0x1D544],
+    [0x1D546, 0x1D546],
+    [0x1D54A, 0x1D550],
+    [0x1D552, 0x1D6A5],
+    [0x1D6A8, 0x1D6C0],
+    [0x1D6C2, 0x1D6DA],
+    [0x1D6DC, 0x1D6FA],
+    [0x1D6FC, 0x1D714],
+    [0x1D716, 0x1D734],
+    [0x1D736, 0x1D74E],
+    [0x1D750, 0x1D76E],
+    [0x1D770, 0x1D788],
+    [0x1D78A, 0x1D7A8],
+    [0x1D7AA, 0x1D7C2],
+    [0x1D7C4, 0x1D7CB],
+    [0x1DF00, 0x1DF1E],
+    [0x1DF25, 0x1DF2A],
+    [0x1E030, 0x1E06D],
+    [0x1E100, 0x1E12C],
+    [0x1E137, 0x1E13D],
+    [0x1E14E, 0x1E14E],
+    [0x1E290, 0x1E2AD],
+    [0x1E2C0, 0x1E2EB],
+    [0x1E4D0, 0x1E4EB],
+    [0x1E7E0, 0x1E7E6],
+    [0x1E7E8, 0x1E7EB],
+    [0x1E7ED, 0x1E7EE],
+    [0x1E7F0, 0x1E7FE],
+    [0x1E800, 0x1E8C4],
+    [0x1E900, 0x1E943],
+    [0x1E94B, 0x1E94B],
+    [0x1EE00, 0x1EE03],
+    [0x1EE05, 0x1EE1F],
+    [0x1EE21, 0x1EE22],
+    [0x1EE24, 0x1EE24],
+    [0x1EE27, 0x1EE27],
+    [0x1EE29, 0x1EE32],
+    [0x1EE34, 0x1EE37],
+    [0x1EE39, 0x1EE39],
+    [0x1EE3B, 0x1EE3B],
+    [0x1EE42, 0x1EE42],
+    [0x1EE47, 0x1EE47],
+    [0x1EE49, 0x1EE49],
+    [0x1EE4B, 0x1EE4B],
+    [0x1EE4D, 0x1EE4F],
+    [0x1EE51, 0x1EE52],
+    [0x1EE54, 0x1EE54],
+    [0x1EE57, 0x1EE57],
+    [0x1EE59, 0x1EE59],
+    [0x1EE5B, 0x1EE5B],
+    [0x1EE5D, 0x1EE5D],
+    [0x1EE5F, 0x1EE5F],
+    [0x1EE61, 0x1EE62],
+    [0x1EE64, 0x1EE64],
+    [0x1EE67, 0x1EE6A],
+    [0x1EE6C, 0x1EE72],
+    [0x1EE74, 0x1EE77],
+    [0x1EE79, 0x1EE7C],
+    [0x1EE7E, 0x1EE7E],
+    [0x1EE80, 0x1EE89],
+    [0x1EE8B, 0x1EE9B],
+    [0x1EEA1, 0x1EEA3],
+    [0x1EEA5, 0x1EEA9],
+    [0x1EEAB, 0x1EEBB],
+    [0x20000, 0x2B739],
+    [0x2B740, 0x2B81D],
+    [0x2B820, 0x2CEA1],
+    [0x2CEB0, 0x2EBE0],
+    [0x2EBF0, 0x2EE5D],
+    [0x2F800, 0x2FA1D],
+    [0x30000, 0x323AF],
+    [0x40000, 0x4FFFD],
+    [0x50000, 0x5FFFD],
+    [0x60000, 0x6FFFD],
+    [0x70000, 0x7FFFD],
+    [0x80000, 0x8FFFD],
+    [0x90000, 0x9FFFD],
+    [0xA0000, 0xAFFFD],
+    [0xB0000, 0xBFFFD],
+    [0xC0000, 0xCFFFD],
+    [0xD0000, 0xDFFFD],
+    [0xE0000, 0xEFFFD],
+];
+
+/**
+Least restrictive Continue
+Entries: 796056
+*/
+static immutable dchar[2][] LeastRestrictive_Continue = [
+    [0xA8, 0xA8],
+    [0xAA, 0xAA],
+    [0xAD, 0xAD],
+    [0xAF, 0xAF],
+    [0xB2, 0xB5],
+    [0xB7, 0xBA],
+    [0xBC, 0xBE],
+    [0xC0, 0xD6],
+    [0xD8, 0xF6],
+    [0xF8, 0x217],
+    [0x250, 0x2A8],
+    [0x2B0, 0x2B8],
+    [0x2BB, 0x2BB],
+    [0x2BD, 0x2C1],
+    [0x2C6, 0x2D1],
+    [0x2E0, 0x2E4],
+    [0x2EC, 0x2EC],
+    [0x2EE, 0x2EE],
+    [0x300, 0x374],
+    [0x376, 0x377],
+    [0x37A, 0x37D],
+    [0x37F, 0x37F],
+    [0x386, 0x386],
+    [0x388, 0x38A],
+    [0x38C, 0x38C],
+    [0x38E, 0x3A1],
+    [0x3A3, 0x3D6],
+    [0x3DA, 0x3DA],
+    [0x3DC, 0x3DC],
+    [0x3DE, 0x3DE],
+    [0x3E0, 0x3E0],
+    [0x3E2, 0x3F3],
+    [0x3F7, 0x40C],
+    [0x40E, 0x44F],
+    [0x451, 0x45C],
+    [0x45E, 0x481],
+    [0x483, 0x487],
+    [0x48A, 0x4C4],
+    [0x4C7, 0x4C8],
+    [0x4CB, 0x4CC],
+    [0x4D0, 0x4EB],
+    [0x4EE, 0x4F5],
+    [0x4F8, 0x4F9],
+    [0x531, 0x556],
+    [0x559, 0x559],
+    [0x560, 0x587],
+    [0x591, 0x5B9],
+    [0x5BB, 0x5BD],
+    [0x5BF, 0x5BF],
+    [0x5C1, 0x5C2],
+    [0x5C4, 0x5C5],
+    [0x5C7, 0x5C7],
+    [0x5D0, 0x5EA],
+    [0x5EF, 0x5F2],
+    [0x610, 0x61A],
+    [0x620, 0x63A],
+    [0x640, 0x652],
+    [0x660, 0x669],
+    [0x66E, 0x6B7],
+    [0x6BA, 0x6BE],
+    [0x6C0, 0x6CE],
+    [0x6D0, 0x6DC],
+    [0x6DF, 0x6E8],
+    [0x6EA, 0x6ED],
+    [0x6F0, 0x6F9],
+    [0x6FF, 0x6FF],
+    [0x710, 0x74A],
+    [0x74D, 0x7B1],
+    [0x7C0, 0x7F5],
+    [0x7FA, 0x7FA],
+    [0x7FD, 0x7FD],
+    [0x800, 0x82D],
+    [0x840, 0x85B],
+    [0x860, 0x86A],
+    [0x870, 0x887],
+    [0x889, 0x88E],
+    [0x898, 0x8E1],
+    [0x8E3, 0x903],
+    [0x905, 0x939],
+    [0x93D, 0x94D],
+    [0x950, 0x952],
+    [0x958, 0x963],
+    [0x966, 0x96F],
+    [0x971, 0x983],
+    [0x985, 0x98C],
+    [0x98F, 0x990],
+    [0x993, 0x9A8],
+    [0x9AA, 0x9B0],
+    [0x9B2, 0x9B2],
+    [0x9B6, 0x9B9],
+    [0x9BC, 0x9C4],
+    [0x9C7, 0x9C8],
+    [0x9CB, 0x9CD],
+    [0x9D7, 0x9D7],
+    [0x9DC, 0x9DD],
+    [0x9DF, 0x9E3],
+    [0x9E6, 0x9F1],
+    [0x9FC, 0x9FC],
+    [0x9FE, 0x9FE],
+    [0xA01, 0xA02],
+    [0xA05, 0xA0A],
+    [0xA0F, 0xA10],
+    [0xA13, 0xA28],
+    [0xA2A, 0xA30],
+    [0xA32, 0xA33],
+    [0xA35, 0xA36],
+    [0xA38, 0xA39],
+    [0xA3C, 0xA3C],
+    [0xA3E, 0xA42],
+    [0xA47, 0xA48],
+    [0xA4B, 0xA4D],
+    [0xA51, 0xA51],
+    [0xA59, 0xA5C],
+    [0xA5E, 0xA5E],
+    [0xA66, 0xA6F],
+    [0xA74, 0xA74],
+    [0xA81, 0xA83],
+    [0xA85, 0xA8B],
+    [0xA8D, 0xA8D],
+    [0xA8F, 0xA91],
+    [0xA93, 0xAA8],
+    [0xAAA, 0xAB0],
+    [0xAB2, 0xAB3],
+    [0xAB5, 0xAB9],
+    [0xABC, 0xAC5],
+    [0xAC7, 0xAC9],
+    [0xACB, 0xACD],
+    [0xAD0, 0xAD0],
+    [0xAE0, 0xAE0],
+    [0xAE6, 0xAEF],
+    [0xAF9, 0xAFF],
+    [0xB01, 0xB03],
+    [0xB05, 0xB0C],
+    [0xB0F, 0xB10],
+    [0xB13, 0xB28],
+    [0xB2A, 0xB30],
+    [0xB32, 0xB33],
+    [0xB35, 0xB39],
+    [0xB3C, 0xB43],
+    [0xB47, 0xB48],
+    [0xB4B, 0xB4D],
+    [0xB55, 0xB57],
+    [0xB5C, 0xB5D],
+    [0xB5F, 0xB61],
+    [0xB66, 0xB6F],
+    [0xB71, 0xB71],
+    [0xB82, 0xB83],
+    [0xB85, 0xB8A],
+    [0xB8E, 0xB90],
+    [0xB92, 0xB95],
+    [0xB99, 0xB9A],
+    [0xB9C, 0xB9C],
+    [0xB9E, 0xB9F],
+    [0xBA3, 0xBA4],
+    [0xBA8, 0xBAA],
+    [0xBAE, 0xBB5],
+    [0xBB7, 0xBB9],
+    [0xBBE, 0xBC2],
+    [0xBC6, 0xBC8],
+    [0xBCA, 0xBCD],
+    [0xBD0, 0xBD0],
+    [0xBD7, 0xBD7],
+    [0xBE6, 0xBEF],
+    [0xC00, 0xC03],
+    [0xC05, 0xC0C],
+    [0xC0E, 0xC10],
+    [0xC12, 0xC28],
+    [0xC2A, 0xC33],
+    [0xC35, 0xC39],
+    [0xC3C, 0xC44],
+    [0xC46, 0xC48],
+    [0xC4A, 0xC4D],
+    [0xC55, 0xC56],
+    [0xC58, 0xC5A],
+    [0xC5D, 0xC5D],
+    [0xC60, 0xC61],
+    [0xC66, 0xC6F],
+    [0xC80, 0xC83],
+    [0xC85, 0xC8C],
+    [0xC8E, 0xC90],
+    [0xC92, 0xCA8],
+    [0xCAA, 0xCB3],
+    [0xCB5, 0xCB9],
+    [0xCBC, 0xCC4],
+    [0xCC6, 0xCC8],
+    [0xCCA, 0xCCD],
+    [0xCD5, 0xCD6],
+    [0xCDD, 0xCDE],
+    [0xCE0, 0xCE1],
+    [0xCE6, 0xCEF],
+    [0xCF1, 0xCF3],
+    [0xD00, 0xD03],
+    [0xD05, 0xD0C],
+    [0xD0E, 0xD10],
+    [0xD12, 0xD39],
+    [0xD3E, 0xD43],
+    [0xD46, 0xD48],
+    [0xD4A, 0xD4E],
+    [0xD54, 0xD57],
+    [0xD5F, 0xD61],
+    [0xD66, 0xD6F],
+    [0xD7A, 0xD7F],
+    [0xD81, 0xD83],
+    [0xD85, 0xD96],
+    [0xD9A, 0xDB1],
+    [0xDB3, 0xDBB],
+    [0xDBD, 0xDBD],
+    [0xDC0, 0xDC6],
+    [0xDCA, 0xDCA],
+    [0xDCF, 0xDD4],
+    [0xDD6, 0xDD6],
+    [0xDD8, 0xDDF],
+    [0xDE6, 0xDEF],
+    [0xDF2, 0xDF3],
+    [0xE01, 0xE3A],
+    [0xE40, 0xE4E],
+    [0xE50, 0xE59],
+    [0xE81, 0xE82],
+    [0xE84, 0xE84],
+    [0xE86, 0xE88],
+    [0xE8A, 0xE8A],
+    [0xE8C, 0xE8D],
+    [0xE94, 0xE97],
+    [0xE99, 0xE9F],
+    [0xEA1, 0xEA3],
+    [0xEA5, 0xEA5],
+    [0xEA7, 0xEAB],
+    [0xEAD, 0xEAE],
+    [0xEB0, 0xEB9],
+    [0xEBB, 0xEBD],
+    [0xEC0, 0xEC4],
+    [0xEC6, 0xEC6],
+    [0xEC8, 0xECE],
+    [0xED0, 0xED9],
+    [0xEDC, 0xEDF],
+    [0xF00, 0xF00],
+    [0xF18, 0xF19],
+    [0xF20, 0xF29],
+    [0xF35, 0xF35],
+    [0xF37, 0xF37],
+    [0xF39, 0xF39],
+    [0xF3E, 0xF47],
+    [0xF49, 0xF6C],
+    [0xF71, 0xF84],
+    [0xF86, 0xF95],
+    [0xF97, 0xF97],
+    [0xF99, 0xFB7],
+    [0xFB9, 0xFB9],
+    [0xFC6, 0xFC6],
+    [0x1000, 0x1049],
+    [0x1050, 0x109D],
+    [0x10A0, 0x10C5],
+    [0x10C7, 0x10C7],
+    [0x10CD, 0x10CD],
+    [0x10D0, 0x10FA],
+    [0x10FC, 0x1248],
+    [0x124A, 0x124D],
+    [0x1250, 0x1256],
+    [0x1258, 0x1258],
+    [0x125A, 0x125D],
+    [0x1260, 0x1288],
+    [0x128A, 0x128D],
+    [0x1290, 0x12B0],
+    [0x12B2, 0x12B5],
+    [0x12B8, 0x12BE],
+    [0x12C0, 0x12C0],
+    [0x12C2, 0x12C5],
+    [0x12C8, 0x12D6],
+    [0x12D8, 0x1310],
+    [0x1312, 0x1315],
+    [0x1318, 0x135A],
+    [0x135D, 0x135F],
+    [0x1369, 0x1371],
+    [0x1380, 0x138F],
+    [0x13A0, 0x13F5],
+    [0x13F8, 0x13FD],
+    [0x1401, 0x166C],
+    [0x166F, 0x167F],
+    [0x1681, 0x169A],
+    [0x16A0, 0x16EA],
+    [0x16EE, 0x16F8],
+    [0x1700, 0x1715],
+    [0x171F, 0x1734],
+    [0x1740, 0x1753],
+    [0x1760, 0x176C],
+    [0x176E, 0x1770],
+    [0x1772, 0x1773],
+    [0x1780, 0x17D3],
+    [0x17D7, 0x17D7],
+    [0x17DC, 0x17DD],
+    [0x17E0, 0x17E9],
+    [0x180B, 0x180D],
+    [0x180F, 0x1819],
+    [0x1820, 0x1878],
+    [0x1880, 0x18AA],
+    [0x18B0, 0x18F5],
+    [0x1900, 0x191E],
+    [0x1920, 0x192B],
+    [0x1930, 0x193B],
+    [0x1946, 0x196D],
+    [0x1970, 0x1974],
+    [0x1980, 0x19AB],
+    [0x19B0, 0x19C9],
+    [0x19D0, 0x19DA],
+    [0x1A00, 0x1A1B],
+    [0x1A20, 0x1A5E],
+    [0x1A60, 0x1A7C],
+    [0x1A7F, 0x1A89],
+    [0x1A90, 0x1A99],
+    [0x1AA7, 0x1AA7],
+    [0x1AB0, 0x1ABD],
+    [0x1ABF, 0x1ACE],
+    [0x1B00, 0x1B4C],
+    [0x1B50, 0x1B59],
+    [0x1B6B, 0x1B73],
+    [0x1B80, 0x1BF3],
+    [0x1C00, 0x1C37],
+    [0x1C40, 0x1C49],
+    [0x1C4D, 0x1C7D],
+    [0x1C80, 0x1C88],
+    [0x1C90, 0x1CBA],
+    [0x1CBD, 0x1CBF],
+    [0x1CD0, 0x1CD2],
+    [0x1CD4, 0x1CFA],
+    [0x1D00, 0x1EF9],
+    [0x1F00, 0x1F15],
+    [0x1F18, 0x1F1D],
+    [0x1F20, 0x1F45],
+    [0x1F48, 0x1F4D],
+    [0x1F50, 0x1F57],
+    [0x1F59, 0x1F59],
+    [0x1F5B, 0x1F5B],
+    [0x1F5D, 0x1F5D],
+    [0x1F5F, 0x1F7D],
+    [0x1F80, 0x1FB4],
+    [0x1FB6, 0x1FBC],
+    [0x1FBE, 0x1FBE],
+    [0x1FC2, 0x1FC4],
+    [0x1FC6, 0x1FCC],
+    [0x1FD0, 0x1FD3],
+    [0x1FD6, 0x1FDB],
+    [0x1FE0, 0x1FEC],
+    [0x1FF2, 0x1FF4],
+    [0x1FF6, 0x1FFC],
+    [0x200B, 0x200D],
+    [0x202A, 0x202E],
+    [0x203F, 0x2040],
+    [0x2054, 0x2054],
+    [0x2060, 0x2071],
+    [0x207F, 0x207F],
+    [0x2090, 0x209C],
+    [0x20D0, 0x20DC],
+    [0x20E1, 0x20E1],
+    [0x20E5, 0x20F0],
+    [0x2102, 0x2102],
+    [0x2107, 0x2107],
+    [0x210A, 0x2113],
+    [0x2115, 0x2115],
+    [0x2118, 0x211D],
+    [0x2124, 0x2124],
+    [0x2126, 0x2126],
+    [0x2128, 0x2128],
+    [0x212A, 0x2138],
+    [0x213C, 0x213F],
+    [0x2145, 0x2149],
+    [0x214E, 0x214E],
+    [0x2160, 0x2188],
+    [0x2460, 0x24FF],
+    [0x2776, 0x2793],
+    [0x2C00, 0x2CE4],
+    [0x2CEB, 0x2CF3],
+    [0x2D00, 0x2D25],
+    [0x2D27, 0x2D27],
+    [0x2D2D, 0x2D2D],
+    [0x2D30, 0x2D67],
+    [0x2D6F, 0x2D6F],
+    [0x2D7F, 0x2D96],
+    [0x2DA0, 0x2DA6],
+    [0x2DA8, 0x2DAE],
+    [0x2DB0, 0x2DB6],
+    [0x2DB8, 0x2DBE],
+    [0x2DC0, 0x2DC6],
+    [0x2DC8, 0x2DCE],
+    [0x2DD0, 0x2DD6],
+    [0x2DD8, 0x2DDE],
+    [0x2DE0, 0x2DFF],
+    [0x2E80, 0x2FFF],
+    [0x3004, 0x3007],
+    [0x3021, 0x302F],
+    [0x3031, 0x303C],
+    [0x3041, 0x3096],
+    [0x3099, 0x309F],
+    [0x30A1, 0x30FC],
+    [0x3105, 0x312F],
+    [0x3131, 0x318E],
+    [0x31A0, 0x31BF],
+    [0x31F0, 0x31FF],
+    [0x3400, 0x4DBF],
+    [0x4E00, 0xA48C],
+    [0xA4D0, 0xA4FD],
+    [0xA500, 0xA60C],
+    [0xA610, 0xA62B],
+    [0xA640, 0xA66F],
+    [0xA674, 0xA67D],
+    [0xA67F, 0xA6F1],
+    [0xA717, 0xA71F],
+    [0xA722, 0xA788],
+    [0xA78B, 0xA7CA],
+    [0xA7D0, 0xA7D1],
+    [0xA7D3, 0xA7D3],
+    [0xA7D5, 0xA7D9],
+    [0xA7F2, 0xA827],
+    [0xA82C, 0xA82C],
+    [0xA840, 0xA873],
+    [0xA880, 0xA8C5],
+    [0xA8D0, 0xA8D9],
+    [0xA8E0, 0xA8F7],
+    [0xA8FB, 0xA8FB],
+    [0xA8FD, 0xA92D],
+    [0xA930, 0xA953],
+    [0xA960, 0xA97C],
+    [0xA980, 0xA9C0],
+    [0xA9CF, 0xA9D9],
+    [0xA9E0, 0xA9FE],
+    [0xAA00, 0xAA36],
+    [0xAA40, 0xAA4D],
+    [0xAA50, 0xAA59],
+    [0xAA60, 0xAA76],
+    [0xAA7A, 0xAAC2],
+    [0xAADB, 0xAADD],
+    [0xAAE0, 0xAAEF],
+    [0xAAF2, 0xAAF6],
+    [0xAB01, 0xAB06],
+    [0xAB09, 0xAB0E],
+    [0xAB11, 0xAB16],
+    [0xAB20, 0xAB26],
+    [0xAB28, 0xAB2E],
+    [0xAB30, 0xAB5A],
+    [0xAB5C, 0xAB69],
+    [0xAB70, 0xABEA],
+    [0xABEC, 0xABED],
+    [0xABF0, 0xABF9],
+    [0xAC00, 0xD7A3],
+    [0xD7B0, 0xD7C6],
+    [0xD7CB, 0xD7FB],
+    [0xF900, 0xFA6D],
+    [0xFA70, 0xFAD9],
+    [0xFB00, 0xFB06],
+    [0xFB13, 0xFB17],
+    [0xFB1D, 0xFB28],
+    [0xFB2A, 0xFB36],
+    [0xFB38, 0xFB3C],
+    [0xFB3E, 0xFB3E],
+    [0xFB40, 0xFB41],
+    [0xFB43, 0xFB44],
+    [0xFB46, 0xFBB1],
+    [0xFBD3, 0xFC5D],
+    [0xFC64, 0xFD3D],
+    [0xFD40, 0xFD8F],
+    [0xFD92, 0xFDC7],
+    [0xFDF0, 0xFDF9],
+    [0xFE00, 0xFE0F],
+    [0xFE20, 0xFE2F],
+    [0xFE33, 0xFE34],
+    [0xFE47, 0xFE4F],
+    [0xFE71, 0xFE71],
+    [0xFE73, 0xFE73],
+    [0xFE77, 0xFE77],
+    [0xFE79, 0xFE79],
+    [0xFE7B, 0xFE7B],
+    [0xFE7D, 0xFE7D],
+    [0xFE7F, 0xFEFC],
+    [0xFF10, 0xFF19],
+    [0xFF21, 0xFF3A],
+    [0xFF3F, 0xFF3F],
+    [0xFF41, 0xFF5A],
+    [0xFF65, 0xFFBE],
+    [0xFFC2, 0xFFC7],
+    [0xFFCA, 0xFFCF],
+    [0xFFD2, 0xFFD7],
+    [0xFFDA, 0xFFDC],
+    [0x10000, 0x1000B],
+    [0x1000D, 0x10026],
+    [0x10028, 0x1003A],
+    [0x1003C, 0x1003D],
+    [0x1003F, 0x1004D],
+    [0x10050, 0x1005D],
+    [0x10080, 0x100FA],
+    [0x10140, 0x10174],
+    [0x101FD, 0x101FD],
+    [0x10280, 0x1029C],
+    [0x102A0, 0x102D0],
+    [0x102E0, 0x102E0],
+    [0x10300, 0x1031F],
+    [0x1032D, 0x1034A],
+    [0x10350, 0x1037A],
+    [0x10380, 0x1039D],
+    [0x103A0, 0x103C3],
+    [0x103C8, 0x103CF],
+    [0x103D1, 0x103D5],
+    [0x10400, 0x1049D],
+    [0x104A0, 0x104A9],
+    [0x104B0, 0x104D3],
+    [0x104D8, 0x104FB],
+    [0x10500, 0x10527],
+    [0x10530, 0x10563],
+    [0x10570, 0x1057A],
+    [0x1057C, 0x1058A],
+    [0x1058C, 0x10592],
+    [0x10594, 0x10595],
+    [0x10597, 0x105A1],
+    [0x105A3, 0x105B1],
+    [0x105B3, 0x105B9],
+    [0x105BB, 0x105BC],
+    [0x10600, 0x10736],
+    [0x10740, 0x10755],
+    [0x10760, 0x10767],
+    [0x10780, 0x10785],
+    [0x10787, 0x107B0],
+    [0x107B2, 0x107BA],
+    [0x10800, 0x10805],
+    [0x10808, 0x10808],
+    [0x1080A, 0x10835],
+    [0x10837, 0x10838],
+    [0x1083C, 0x1083C],
+    [0x1083F, 0x10855],
+    [0x10860, 0x10876],
+    [0x10880, 0x1089E],
+    [0x108E0, 0x108F2],
+    [0x108F4, 0x108F5],
+    [0x10900, 0x10915],
+    [0x10920, 0x10939],
+    [0x10980, 0x109B7],
+    [0x109BE, 0x109BF],
+    [0x10A00, 0x10A03],
+    [0x10A05, 0x10A06],
+    [0x10A0C, 0x10A13],
+    [0x10A15, 0x10A17],
+    [0x10A19, 0x10A35],
+    [0x10A38, 0x10A3A],
+    [0x10A3F, 0x10A3F],
+    [0x10A60, 0x10A7C],
+    [0x10A80, 0x10A9C],
+    [0x10AC0, 0x10AC7],
+    [0x10AC9, 0x10AE6],
+    [0x10B00, 0x10B35],
+    [0x10B40, 0x10B55],
+    [0x10B60, 0x10B72],
+    [0x10B80, 0x10B91],
+    [0x10C00, 0x10C48],
+    [0x10C80, 0x10CB2],
+    [0x10CC0, 0x10CF2],
+    [0x10D00, 0x10D27],
+    [0x10D30, 0x10D39],
+    [0x10E80, 0x10EA9],
+    [0x10EAB, 0x10EAC],
+    [0x10EB0, 0x10EB1],
+    [0x10EFD, 0x10F1C],
+    [0x10F27, 0x10F27],
+    [0x10F30, 0x10F50],
+    [0x10F70, 0x10F85],
+    [0x10FB0, 0x10FC4],
+    [0x10FE0, 0x10FF6],
+    [0x11000, 0x11046],
+    [0x11066, 0x11075],
+    [0x1107F, 0x110BA],
+    [0x110C2, 0x110C2],
+    [0x110D0, 0x110E8],
+    [0x110F0, 0x110F9],
+    [0x11100, 0x11134],
+    [0x11136, 0x1113F],
+    [0x11144, 0x11147],
+    [0x11150, 0x11173],
+    [0x11176, 0x11176],
+    [0x11180, 0x111C4],
+    [0x111C9, 0x111CC],
+    [0x111CE, 0x111DA],
+    [0x111DC, 0x111DC],
+    [0x11200, 0x11211],
+    [0x11213, 0x11237],
+    [0x1123E, 0x11241],
+    [0x11280, 0x11286],
+    [0x11288, 0x11288],
+    [0x1128A, 0x1128D],
+    [0x1128F, 0x1129D],
+    [0x1129F, 0x112A8],
+    [0x112B0, 0x112EA],
+    [0x112F0, 0x112F9],
+    [0x11300, 0x11303],
+    [0x11305, 0x1130C],
+    [0x1130F, 0x11310],
+    [0x11313, 0x11328],
+    [0x1132A, 0x11330],
+    [0x11332, 0x11333],
+    [0x11335, 0x11339],
+    [0x1133B, 0x11344],
+    [0x11347, 0x11348],
+    [0x1134B, 0x1134D],
+    [0x11350, 0x11350],
+    [0x11357, 0x11357],
+    [0x1135D, 0x11363],
+    [0x11366, 0x1136C],
+    [0x11370, 0x11374],
+    [0x11400, 0x1144A],
+    [0x11450, 0x11459],
+    [0x1145E, 0x11461],
+    [0x11480, 0x114C5],
+    [0x114C7, 0x114C7],
+    [0x114D0, 0x114D9],
+    [0x11580, 0x115B5],
+    [0x115B8, 0x115C0],
+    [0x115D8, 0x115DD],
+    [0x11600, 0x11640],
+    [0x11644, 0x11644],
+    [0x11650, 0x11659],
+    [0x11680, 0x116B8],
+    [0x116C0, 0x116C9],
+    [0x11700, 0x1171A],
+    [0x1171D, 0x1172B],
+    [0x11730, 0x11739],
+    [0x11740, 0x11746],
+    [0x11800, 0x1183A],
+    [0x118A0, 0x118E9],
+    [0x118FF, 0x11906],
+    [0x11909, 0x11909],
+    [0x1190C, 0x11913],
+    [0x11915, 0x11916],
+    [0x11918, 0x11935],
+    [0x11937, 0x11938],
+    [0x1193B, 0x11943],
+    [0x11950, 0x11959],
+    [0x119A0, 0x119A7],
+    [0x119AA, 0x119D7],
+    [0x119DA, 0x119E1],
+    [0x119E3, 0x119E4],
+    [0x11A00, 0x11A3E],
+    [0x11A47, 0x11A47],
+    [0x11A50, 0x11A99],
+    [0x11A9D, 0x11A9D],
+    [0x11AB0, 0x11AF8],
+    [0x11C00, 0x11C08],
+    [0x11C0A, 0x11C36],
+    [0x11C38, 0x11C40],
+    [0x11C50, 0x11C59],
+    [0x11C72, 0x11C8F],
+    [0x11C92, 0x11CA7],
+    [0x11CA9, 0x11CB6],
+    [0x11D00, 0x11D06],
+    [0x11D08, 0x11D09],
+    [0x11D0B, 0x11D36],
+    [0x11D3A, 0x11D3A],
+    [0x11D3C, 0x11D3D],
+    [0x11D3F, 0x11D47],
+    [0x11D50, 0x11D59],
+    [0x11D60, 0x11D65],
+    [0x11D67, 0x11D68],
+    [0x11D6A, 0x11D8E],
+    [0x11D90, 0x11D91],
+    [0x11D93, 0x11D98],
+    [0x11DA0, 0x11DA9],
+    [0x11EE0, 0x11EF6],
+    [0x11F00, 0x11F10],
+    [0x11F12, 0x11F3A],
+    [0x11F3E, 0x11F42],
+    [0x11F50, 0x11F59],
+    [0x11FB0, 0x11FB0],
+    [0x12000, 0x12399],
+    [0x12400, 0x1246E],
+    [0x12480, 0x12543],
+    [0x12F90, 0x12FF0],
+    [0x13000, 0x1342F],
+    [0x13440, 0x13455],
+    [0x14400, 0x14646],
+    [0x16800, 0x16A38],
+    [0x16A40, 0x16A5E],
+    [0x16A60, 0x16A69],
+    [0x16A70, 0x16ABE],
+    [0x16AC0, 0x16AC9],
+    [0x16AD0, 0x16AED],
+    [0x16AF0, 0x16AF4],
+    [0x16B00, 0x16B36],
+    [0x16B40, 0x16B43],
+    [0x16B50, 0x16B59],
+    [0x16B63, 0x16B77],
+    [0x16B7D, 0x16B8F],
+    [0x16E40, 0x16E7F],
+    [0x16F00, 0x16F4A],
+    [0x16F4F, 0x16F87],
+    [0x16F8F, 0x16F9F],
+    [0x16FE0, 0x16FE1],
+    [0x16FE3, 0x16FE4],
+    [0x16FF0, 0x16FF1],
+    [0x17000, 0x187F7],
+    [0x18800, 0x18CD5],
+    [0x18D00, 0x18D08],
+    [0x1AFF0, 0x1AFF3],
+    [0x1AFF5, 0x1AFFB],
+    [0x1AFFD, 0x1AFFE],
+    [0x1B000, 0x1B122],
+    [0x1B132, 0x1B132],
+    [0x1B150, 0x1B152],
+    [0x1B155, 0x1B155],
+    [0x1B164, 0x1B167],
+    [0x1B170, 0x1B2FB],
+    [0x1BC00, 0x1BC6A],
+    [0x1BC70, 0x1BC7C],
+    [0x1BC80, 0x1BC88],
+    [0x1BC90, 0x1BC99],
+    [0x1BC9D, 0x1BC9E],
+    [0x1CF00, 0x1CF2D],
+    [0x1CF30, 0x1CF46],
+    [0x1D165, 0x1D169],
+    [0x1D16D, 0x1D172],
+    [0x1D17B, 0x1D182],
+    [0x1D185, 0x1D18B],
+    [0x1D1AA, 0x1D1AD],
+    [0x1D242, 0x1D244],
+    [0x1D400, 0x1D454],
+    [0x1D456, 0x1D49C],
+    [0x1D49E, 0x1D49F],
+    [0x1D4A2, 0x1D4A2],
+    [0x1D4A5, 0x1D4A6],
+    [0x1D4A9, 0x1D4AC],
+    [0x1D4AE, 0x1D4B9],
+    [0x1D4BB, 0x1D4BB],
+    [0x1D4BD, 0x1D4C3],
+    [0x1D4C5, 0x1D505],
+    [0x1D507, 0x1D50A],
+    [0x1D50D, 0x1D514],
+    [0x1D516, 0x1D51C],
+    [0x1D51E, 0x1D539],
+    [0x1D53B, 0x1D53E],
+    [0x1D540, 0x1D544],
+    [0x1D546, 0x1D546],
+    [0x1D54A, 0x1D550],
+    [0x1D552, 0x1D6A5],
+    [0x1D6A8, 0x1D6C0],
+    [0x1D6C2, 0x1D6DA],
+    [0x1D6DC, 0x1D6FA],
+    [0x1D6FC, 0x1D714],
+    [0x1D716, 0x1D734],
+    [0x1D736, 0x1D74E],
+    [0x1D750, 0x1D76E],
+    [0x1D770, 0x1D788],
+    [0x1D78A, 0x1D7A8],
+    [0x1D7AA, 0x1D7C2],
+    [0x1D7C4, 0x1D7CB],
+    [0x1D7CE, 0x1D7FF],
+    [0x1DA00, 0x1DA36],
+    [0x1DA3B, 0x1DA6C],
+    [0x1DA75, 0x1DA75],
+    [0x1DA84, 0x1DA84],
+    [0x1DA9B, 0x1DA9F],
+    [0x1DAA1, 0x1DAAF],
+    [0x1DF00, 0x1DF1E],
+    [0x1DF25, 0x1DF2A],
+    [0x1E000, 0x1E006],
+    [0x1E008, 0x1E018],
+    [0x1E01B, 0x1E021],
+    [0x1E023, 0x1E024],
+    [0x1E026, 0x1E02A],
+    [0x1E030, 0x1E06D],
+    [0x1E08F, 0x1E08F],
+    [0x1E100, 0x1E12C],
+    [0x1E130, 0x1E13D],
+    [0x1E140, 0x1E149],
+    [0x1E14E, 0x1E14E],
+    [0x1E290, 0x1E2AE],
+    [0x1E2C0, 0x1E2F9],
+    [0x1E4D0, 0x1E4F9],
+    [0x1E7E0, 0x1E7E6],
+    [0x1E7E8, 0x1E7EB],
+    [0x1E7ED, 0x1E7EE],
+    [0x1E7F0, 0x1E7FE],
+    [0x1E800, 0x1E8C4],
+    [0x1E8D0, 0x1E8D6],
+    [0x1E900, 0x1E94B],
+    [0x1E950, 0x1E959],
+    [0x1EE00, 0x1EE03],
+    [0x1EE05, 0x1EE1F],
+    [0x1EE21, 0x1EE22],
+    [0x1EE24, 0x1EE24],
+    [0x1EE27, 0x1EE27],
+    [0x1EE29, 0x1EE32],
+    [0x1EE34, 0x1EE37],
+    [0x1EE39, 0x1EE39],
+    [0x1EE3B, 0x1EE3B],
+    [0x1EE42, 0x1EE42],
+    [0x1EE47, 0x1EE47],
+    [0x1EE49, 0x1EE49],
+    [0x1EE4B, 0x1EE4B],
+    [0x1EE4D, 0x1EE4F],
+    [0x1EE51, 0x1EE52],
+    [0x1EE54, 0x1EE54],
+    [0x1EE57, 0x1EE57],
+    [0x1EE59, 0x1EE59],
+    [0x1EE5B, 0x1EE5B],
+    [0x1EE5D, 0x1EE5D],
+    [0x1EE5F, 0x1EE5F],
+    [0x1EE61, 0x1EE62],
+    [0x1EE64, 0x1EE64],
+    [0x1EE67, 0x1EE6A],
+    [0x1EE6C, 0x1EE72],
+    [0x1EE74, 0x1EE77],
+    [0x1EE79, 0x1EE7C],
+    [0x1EE7E, 0x1EE7E],
+    [0x1EE80, 0x1EE89],
+    [0x1EE8B, 0x1EE9B],
+    [0x1EEA1, 0x1EEA3],
+    [0x1EEA5, 0x1EEA9],
+    [0x1EEAB, 0x1EEBB],
+    [0x1FBF0, 0x1FBF9],
+    [0x20000, 0x2B739],
+    [0x2B740, 0x2B81D],
+    [0x2B820, 0x2CEA1],
+    [0x2CEB0, 0x2EBE0],
+    [0x2EBF0, 0x2EE5D],
+    [0x2F800, 0x2FA1D],
+    [0x30000, 0x323AF],
+    [0x40000, 0x4FFFD],
+    [0x50000, 0x5FFFD],
+    [0x60000, 0x6FFFD],
+    [0x70000, 0x7FFFD],
+    [0x80000, 0x8FFFD],
+    [0x90000, 0x9FFFD],
+    [0xA0000, 0xAFFFD],
+    [0xB0000, 0xBFFFD],
+    [0xC0000, 0xCFFFD],
+    [0xD0000, 0xDFFFD],
+    [0xE0000, 0xE01EF],
+];
index cb2439ff746d859eb9b2339b694ef2341e93810a..f3801cb69cae2c00d4c163f83e8ee5579c711618 100644 (file)
@@ -141,7 +141,7 @@ struct OutBuffer
     memory buffer. The config variables `notlinehead`, `doindent` etc. are
     not changed.
     */
-    extern (C++) void destroy() pure nothrow @trusted
+    extern (C++) void destroy() pure nothrow
     {
         dtor();
         fileMapping = null;
@@ -247,7 +247,7 @@ struct OutBuffer
     /**
      * Writes a 16 bit value, no reserve check.
      */
-    @trusted nothrow
+    nothrow
     void write16n(int v)
     {
         auto x = cast(ushort) v;
@@ -367,7 +367,6 @@ struct OutBuffer
     }
 
     // Position buffer to accept the specified number of bytes at offset
-    @trusted
     void position(size_t where, size_t nbytes) nothrow
     {
         if (where + nbytes > data.length)
@@ -382,7 +381,7 @@ struct OutBuffer
     /**
      * Writes an 8 bit byte, no reserve check.
      */
-    extern (C++) @trusted nothrow
+    extern (C++) nothrow @safe
     void writeByten(int b)
     {
         this.data[offset++] = cast(ubyte) b;
index fe497c2da7e14ddea7235d69aa9c8f7e6137de9b..fc3ebd4625d49c8066201c46d584f4c921847d36 100644 (file)
@@ -39,8 +39,8 @@ public:
 
     virtual Condition *syntaxCopy() = 0;
     virtual int include(Scope *sc) = 0;
-    virtual DebugCondition *isDebugCondition() { return NULL; }
-    virtual VersionCondition *isVersionCondition() { return NULL; }
+    virtual DebugCondition *isDebugCondition() { return nullptr; }
+    virtual VersionCondition *isVersionCondition() { return nullptr; }
     void accept(Visitor *v) override { v->visit(this); }
 };
 
index aeedb493efc36bb8d577987f953d27d971565de4..7fbcd6d9bc1f581898cf9659d3b426ebce9a4635 100644 (file)
@@ -35,7 +35,7 @@ final class CParser(AST) : Parser!AST
     AST.Dsymbols* symbols;      // symbols declared in current scope
 
     bool addFuncName;           /// add declaration of __func__ to function symbol table
-    bool importBuiltins;        /// seen use of C compiler builtins, so import __builtins;
+    bool importBuiltins;        /// seen use of C compiler builtins, so import __importc_builtins;
 
     private
     {
@@ -89,6 +89,9 @@ final class CParser(AST) : Parser!AST
         this.wchar_tsize = target.wchar_tsize;
 
         // C `char` is always unsigned in ImportC
+
+        // We know that we are parsing out C, due the parent not knowing this, we have to setup tables here.
+        charLookup = compileEnv.cCharLookupTable;
     }
 
     /********************************************
@@ -125,7 +128,7 @@ final class CParser(AST) : Parser!AST
                     /* Seen references to C builtin functions.
                      * Import their definitions
                      */
-                    auto s = new AST.Import(Loc.initial, null, Id.builtins, null, false);
+                    auto s = new AST.Import(Loc.initial, null, Id.importc_builtins, null, false);
                     wrap.push(s);
                 }
 
@@ -1919,6 +1922,14 @@ final class CParser(AST) : Parser!AST
                 auto s = cparseFunctionDefinition(id, dt.isTypeFunction(), specifier);
                 typedefTab.setDim(typedefTabLengthSave);
                 symbols = symbolsSave;
+                if (specifier.mod & MOD.x__stdcall)
+                {
+                    // If this function is __stdcall, wrap it in a LinkDeclaration so that
+                    // it's extern(Windows) when imported in D.
+                    auto decls = new AST.Dsymbols(1);
+                    (*decls)[0] = s;
+                    s = new AST.LinkDeclaration(s.loc, LINK.windows, decls);
+                }
                 symbols.push(s);
                 return;
             }
@@ -2071,13 +2082,14 @@ final class CParser(AST) : Parser!AST
                     }
                 }
                 s = applySpecifier(s, specifier);
-                if (level == LVL.local)
+                if (level == LVL.local || (specifier.mod & MOD.x__stdcall))
                 {
-                    // Wrap the declaration in `extern (C) { declaration }`
+                    // Wrap the declaration in `extern (C/Windows) { declaration }`
                     // Necessary for function pointers, but harmless to apply to all.
                     auto decls = new AST.Dsymbols(1);
                     (*decls)[0] = s;
-                    s = new AST.LinkDeclaration(s.loc, linkage, decls);
+                    const lkg = specifier.mod & MOD.x__stdcall ? LINK.windows : linkage;
+                    s = new AST.LinkDeclaration(s.loc, lkg, decls);
                 }
                 symbols.push(s);
             }
@@ -5860,13 +5872,15 @@ final class CParser(AST) : Parser!AST
 
         const(char)* endp = &slice[length - 7];
 
+        AST.Dsymbols newSymbols;
+
         size_t[void*] defineTab;    // hash table of #define's turned into Symbol's
-                                    // indexed by Identifier, returns index into symbols[]
+                                    // indexed by Identifier, returns index into newSymbols[]
                                     // The memory for this is leaked
 
-        void addVar(AST.Dsymbol s)
+        void addSym(AST.Dsymbol s)
         {
-            //printf("addVar() %s\n", s.toChars());
+            //printf("addSym() %s\n", s.toChars());
             if (auto v = s.isVarDeclaration())
                 v.isCmacro(true);       // mark it as coming from a C #define
             /* If it's already defined, replace the earlier
@@ -5874,13 +5888,22 @@ final class CParser(AST) : Parser!AST
              */
             if (size_t* pd = cast(void*)s.ident in defineTab)
             {
-                //printf("replacing %s\n", v.toChars());
-                (*symbols)[*pd] = s;
+                //printf("replacing %s\n", s.toChars());
+                newSymbols[*pd] = s;
                 return;
             }
-            assert(symbols, "symbols is null");
-            defineTab[cast(void*)s.ident] = symbols.length;
-            symbols.push(s);
+            defineTab[cast(void*)s.ident] = newSymbols.length;
+            newSymbols.push(s);
+        }
+
+        void removeSym(Identifier ident)
+        {
+            //printf("removeSym() %s\n", ident.toChars());
+            if (size_t* pd = cast(void*)ident in defineTab)
+            {
+                //printf("removing %s\n", ident.toChars());
+                newSymbols[*pd] = null;
+            }
         }
 
         while (p < endp)
@@ -5924,7 +5947,7 @@ final class CParser(AST) : Parser!AST
                                  */
                                 AST.Expression e = new AST.IntegerExp(scanloc, intvalue, t);
                                 auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
-                                addVar(v);
+                                addSym(v);
                                 ++p;
                                 continue;
                             }
@@ -5947,7 +5970,7 @@ final class CParser(AST) : Parser!AST
                                  */
                                 AST.Expression e = new AST.RealExp(scanloc, floatvalue, t);
                                 auto v = new AST.VarDeclaration(scanloc, t, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
-                                addVar(v);
+                                addSym(v);
                                 ++p;
                                 continue;
                             }
@@ -5965,7 +5988,7 @@ final class CParser(AST) : Parser!AST
                                  */
                                 AST.Expression e = new AST.StringExp(scanloc, str[0 .. len], len, 1, postfix);
                                 auto v = new AST.VarDeclaration(scanloc, null, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
-                                addVar(v);
+                                addSym(v);
                                 ++p;
                                 continue;
                             }
@@ -6001,7 +6024,7 @@ final class CParser(AST) : Parser!AST
                             AST.TemplateParameters* tpl = new AST.TemplateParameters();
                             AST.Expression constraint = null;
                             auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, constraint, decldefs, false);
-                            addVar(tempdecl);
+                            addSym(tempdecl);
                             ++p;
                             continue;
                         }
@@ -6092,7 +6115,7 @@ final class CParser(AST) : Parser!AST
                             AST.Dsymbols* decldefs = new AST.Dsymbols();
                             decldefs.push(fd);
                             auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, null, decldefs, false);
-                            addVar(tempdecl);
+                            addSym(tempdecl);
 
                             ++p;
                             continue;
@@ -6103,6 +6126,14 @@ final class CParser(AST) : Parser!AST
                     }
                 }
             }
+            else if (p[0 .. 6] == "#undef")
+            {
+                p += 6;
+                nextToken();
+                //printf("undef %s\n", token.toChars());
+                if (token.value == TOK.identifier)
+                    removeSym(token.ident);
+            }
             // scan to end of line
             while (*p)
                 ++p;
@@ -6110,6 +6141,16 @@ final class CParser(AST) : Parser!AST
             scanloc.linnum = scanloc.linnum + 1;
         }
 
+        if (newSymbols.length)
+        {
+            assert(symbols, "symbols is null");
+            symbols.reserve(newSymbols.length);
+
+            foreach (sym; newSymbols)
+                if (sym) // undefined entries are null
+                    symbols.push(sym);
+        }
+
         scanloc = scanlocSave;
         eSink = save;
         defines = buf;
index 0116aa35c8c05fcaab3d298b1c0cb9af5e438d64..334088b381cd6d979aa61b74c60b24e1cd25f870 100644 (file)
@@ -49,19 +49,30 @@ import dmd.typesem;
 import dmd.visitor;
 
 
-// helper to check if an identifier is a C++ operator
-enum CppOperator { Cast, Assign, Eq, Index, Call, Unary, Binary, OpAssign, Unknown }
-package CppOperator isCppOperator(Identifier id)
+// C++ operators
+enum CppOperator { Unknown, Cast, Assign, Eq, Index, Call, Unary, Binary, OpAssign }
+
+/**************
+ * Check if id is a C++ operator
+ * Params:
+ *      id = identifier to be checked
+ * Returns:
+ *      CppOperator, or Unknown if not a C++ operator
+ */
+package CppOperator isCppOperator(const scope Identifier id)
 {
-    __gshared const(Identifier)[] operators = null;
-    if (!operators)
-        operators = [Id._cast, Id.assign, Id.eq, Id.index, Id.call, Id.opUnary, Id.opBinary, Id.opOpAssign];
-    foreach (i, op; operators)
-    {
-        if (op == id)
-            return cast(CppOperator)i;
+    with (Id) with (CppOperator)
+    {
+        return (id == _cast)      ? Cast     :
+               (id == assign)     ? Assign   :
+               (id == eq)         ? Eq       :
+               (id == index)      ? Index    :
+               (id == call)       ? Call     :
+               (id == opUnary)    ? Unary    :
+               (id == opBinary)   ? Binary   :
+               (id == opOpAssign) ? OpAssign :
+                                    Unknown  ;
     }
-    return CppOperator.Unknown;
 }
 
 ///
@@ -71,6 +82,8 @@ const(char)* toCppMangleItanium(Dsymbol s)
     OutBuffer buf;
     scope CppMangleVisitor v = new CppMangleVisitor(&buf, s.loc);
     v.mangleOf(s);
+    if (v.errors)
+        fatal();
     return buf.extractChars();
 }
 
@@ -82,6 +95,8 @@ const(char)* cppTypeInfoMangleItanium(Dsymbol s)
     buf.writestring("_ZTI");    // "TI" means typeinfo structure
     scope CppMangleVisitor v = new CppMangleVisitor(&buf, s.loc);
     v.cpp_mangle_name(s, false);
+    if (v.errors)
+        fatal();
     return buf.extractChars();
 }
 
@@ -93,6 +108,8 @@ const(char)* cppThunkMangleItanium(FuncDeclaration fd, int offset)
     buf.printf("_ZThn%u_", offset);  // "Th" means thunk, "n%u" is the call offset
     scope CppMangleVisitor v = new CppMangleVisitor(&buf, fd.loc);
     v.mangle_function_encoding(fd);
+    if (v.errors)
+        fatal();
     return buf.extractChars();
 }
 
@@ -163,6 +180,7 @@ private final class CppMangleVisitor : Visitor
     Objects components;         /// array of components available for substitution
     OutBuffer* buf;             /// append the mangling to buf[]
     Loc loc;                    /// location for use in error messages
+    bool errors;                /// failed to mangle properly
 
     /**
      * Constructor
@@ -484,7 +502,8 @@ private final class CppMangleVisitor : Visitor
             else
             {
                 .error(ti.loc, "%s `%s` internal compiler error: C++ `%s` template value parameter is not supported", ti.kind, ti.toPrettyChars, tv.valType.toChars());
-                fatal();
+                errors = true;
+                return;
             }
         }
         else if (tp.isTemplateAliasParameter())
@@ -519,13 +538,13 @@ private final class CppMangleVisitor : Visitor
             else
             {
                 .error(ti.loc, "%s `%s` internal compiler error: C++ `%s` template alias parameter is not supported", ti.kind, ti.toPrettyChars, o.toChars());
-                fatal();
+                errors = true;
             }
         }
         else if (tp.isTemplateThisParameter())
         {
             .error(ti.loc, "%s `%s` internal compiler error: C++ `%s` template this parameter is not supported", ti.kind, ti.toPrettyChars, o.toChars());
-            fatal();
+            errors = true;
         }
         else
         {
@@ -574,7 +593,8 @@ private final class CppMangleVisitor : Visitor
                     if (t is null)
                     {
                         .error(ti.loc, "%s `%s` internal compiler error: C++ `%s` template value parameter is not supported", ti.kind, ti.toPrettyChars, (*ti.tiargs)[j].toChars());
-                        fatal();
+                        errors = true;
+                        return false;
                     }
                     t.accept(this);
                 }
@@ -1012,7 +1032,8 @@ private final class CppMangleVisitor : Visitor
         if (!(d.storage_class & (STC.extern_ | STC.field | STC.gshared)))
         {
             .error(d.loc, "%s `%s` internal compiler error: C++ static non-`__gshared` non-`extern` variables not supported", d.kind, d.toPrettyChars);
-            fatal();
+            errors = true;
+            return;
         }
         Dsymbol p = d.toParent();
         if (p && !p.isModule()) //for example: char Namespace1::beta[6] should be mangled as "_ZN10Namespace14betaE"
@@ -1348,7 +1369,8 @@ private final class CppMangleVisitor : Visitor
                 // Static arrays in D are passed by value; no counterpart in C++
                 .error(loc, "internal compiler error: unable to pass static array `%s` to extern(C++) function, use pointer instead",
                     t.toChars());
-                fatal();
+                errors = true;
+                return;
             }
             auto prev = this.context.push({
                     TypeFunction tf;
@@ -1386,7 +1408,7 @@ private final class CppMangleVisitor : Visitor
         else
             p = "";
         .error(loc, "internal compiler error: %stype `%s` cannot be mapped to C++\n", p, t.toChars());
-        fatal(); //Fatal, because this error should be handled in frontend
+        errors = true; //Fatal, because this error should be handled in frontend
     }
 
     /****************************
index a0432d2e1b46c8e07e44c5a2baf297d3234b541a..c0805b838ff92b5f58c832b6b3fffc0cee2b5bb5 100644 (file)
@@ -13,6 +13,7 @@ module dmd.cxxfrontend;
 import dmd.aggregate : AggregateDeclaration;
 import dmd.arraytypes;
 import dmd.astenums;
+import dmd.attrib;
 import dmd.common.outbuffer : OutBuffer;
 import dmd.denum : EnumDeclaration;
 import dmd.dmodule /*: Module*/;
@@ -34,6 +35,15 @@ import dmd.statement : Statement, AsmStatement, GccAsmStatement;
 // NB: At some point in the future, we can switch to shortened function syntax.
 extern (C++, "dmd"):
 
+/***********************************************************
+ * atrtibsem.d
+ */
+Expressions* getAttributes(UserAttributeDeclaration a)
+{
+    import dmd.attribsem;
+    return dmd.attribsem.getAttributes(a);
+}
+
 /***********************************************************
  * cppmangle.d
  */
index 8a713f424d6475760fe8cb3301cf7ab03b96defc..78781f4ced7c3b3dd47224c47a04e3ba90e19b03 100644 (file)
@@ -69,7 +69,7 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t)
 {
     Expression visit(Expression e)
     {
-        // printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
+        //printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
         if (const match = (sc && sc.flags & SCOPE.Cfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t))
         {
             // no need for an extra cast when matching is exact
@@ -2257,7 +2257,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
         Type tb = t.toBasetype();
         if (tb.ty == Tarray)
         {
-            if (checkArrayLiteralEscape(sc, ae, false))
+            if (checkArrayLiteralEscape(*sc, ae, false))
             {
                 return ErrorExp.get();
             }
index 8bac1f4ea266e63a10c3c2fe52f6658a4204538b..2199d5d1a7777582bd57baa24cfba5e3ea23c97a 100644 (file)
@@ -26,6 +26,7 @@ import dmd.dsymbol;
 import dmd.dsymbolsem;
 import dmd.errors;
 import dmd.func;
+import dmd.funcsem;
 import dmd.id;
 import dmd.identifier;
 import dmd.location;
index 3f9769d71550e3717eb18861b1e2eb04fbb2e346..a1202ed628a736732b2a37d10f47a47f3a00ff89 100644 (file)
@@ -27,6 +27,7 @@ import dmd.dtemplate;
 import dmd.errors;
 import dmd.expression;
 import dmd.func;
+import dmd.funcsem;
 import dmd.globals;
 import dmd.gluelayer;
 import dmd.id;
@@ -38,6 +39,7 @@ import dmd.location;
 import dmd.mtype;
 import dmd.common.outbuffer;
 import dmd.rootobject;
+import dmd.root.filename;
 import dmd.target;
 import dmd.tokens;
 import dmd.typesem;
@@ -213,9 +215,21 @@ bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1)
 
 /******************************************
  */
-void ObjectNotFound(Identifier id)
+void ObjectNotFound(Loc loc, Identifier id)
 {
-    error(Loc.initial, "`%s` not found. object.d may be incorrectly installed or corrupt.", id.toChars());
+    error(loc, "`%s` not found. object.d may be incorrectly installed or corrupt.", id.toChars());
+    version (IN_LLVM)
+    {
+        errorSupplemental(loc, "ldc2 might not be correctly installed.");
+        errorSupplemental(loc, "Please check your ldc2.conf configuration file.");
+        errorSupplemental(loc, "Installation instructions can be found at http://wiki.dlang.org/LDC.");
+    }
+    else version (MARS)
+    {
+        errorSupplemental(loc, "dmd might not be correctly installed. Run 'dmd -man' for installation instructions.");
+        const dmdConfFile = global.inifilename.length ? FileName.canonicalName(global.inifilename) : "not found";
+        errorSupplemental(loc, "config file: %.*s", cast(int)dmdConfFile.length, dmdConfFile.ptr);
+    }
     fatal();
 }
 
@@ -1370,7 +1384,7 @@ extern (C++) class VarDeclaration : Declaration
     /*************************************
      * Return true if we can take the address of this variable.
      */
-    final bool canTakeAddressOf()
+    final bool canTakeAddressOf() @safe
     {
         return !(storage_class & STC.manifest);
     }
@@ -1378,7 +1392,7 @@ extern (C++) class VarDeclaration : Declaration
     /******************************************
      * Return true if variable needs to call the destructor.
      */
-    final bool needsScopeDtor()
+    final bool needsScopeDtor() @safe
     {
         //printf("VarDeclaration::needsScopeDtor() %s %d\n", toChars(), edtor && !(storage_class & STC.nodtor));
         return edtor && !(storage_class & STC.nodtor);
@@ -1832,7 +1846,7 @@ extern (C++) final class TypeInfoStructDeclaration : TypeInfoDeclaration
         super(tinfo);
         if (!Type.typeinfostruct)
         {
-            ObjectNotFound(Id.TypeInfo_Struct);
+            ObjectNotFound(loc, Id.TypeInfo_Struct);
         }
         type = Type.typeinfostruct.type;
     }
@@ -1857,7 +1871,7 @@ extern (C++) final class TypeInfoClassDeclaration : TypeInfoDeclaration
         super(tinfo);
         if (!Type.typeinfoclass)
         {
-            ObjectNotFound(Id.TypeInfo_Class);
+            ObjectNotFound(loc, Id.TypeInfo_Class);
         }
         type = Type.typeinfoclass.type;
     }
@@ -1882,7 +1896,7 @@ extern (C++) final class TypeInfoInterfaceDeclaration : TypeInfoDeclaration
         super(tinfo);
         if (!Type.typeinfointerface)
         {
-            ObjectNotFound(Id.TypeInfo_Interface);
+            ObjectNotFound(loc, Id.TypeInfo_Interface);
         }
         type = Type.typeinfointerface.type;
     }
@@ -1907,7 +1921,7 @@ extern (C++) final class TypeInfoPointerDeclaration : TypeInfoDeclaration
         super(tinfo);
         if (!Type.typeinfopointer)
         {
-            ObjectNotFound(Id.TypeInfo_Pointer);
+            ObjectNotFound(loc, Id.TypeInfo_Pointer);
         }
         type = Type.typeinfopointer.type;
     }
@@ -1932,7 +1946,7 @@ extern (C++) final class TypeInfoArrayDeclaration : TypeInfoDeclaration
         super(tinfo);
         if (!Type.typeinfoarray)
         {
-            ObjectNotFound(Id.TypeInfo_Array);
+            ObjectNotFound(loc, Id.TypeInfo_Array);
         }
         type = Type.typeinfoarray.type;
     }
@@ -1957,7 +1971,7 @@ extern (C++) final class TypeInfoStaticArrayDeclaration : TypeInfoDeclaration
         super(tinfo);
         if (!Type.typeinfostaticarray)
         {
-            ObjectNotFound(Id.TypeInfo_StaticArray);
+            ObjectNotFound(loc, Id.TypeInfo_StaticArray);
         }
         type = Type.typeinfostaticarray.type;
     }
@@ -1982,7 +1996,7 @@ extern (C++) final class TypeInfoAssociativeArrayDeclaration : TypeInfoDeclarati
         super(tinfo);
         if (!Type.typeinfoassociativearray)
         {
-            ObjectNotFound(Id.TypeInfo_AssociativeArray);
+            ObjectNotFound(loc, Id.TypeInfo_AssociativeArray);
         }
         type = Type.typeinfoassociativearray.type;
     }
@@ -2007,7 +2021,7 @@ extern (C++) final class TypeInfoEnumDeclaration : TypeInfoDeclaration
         super(tinfo);
         if (!Type.typeinfoenum)
         {
-            ObjectNotFound(Id.TypeInfo_Enum);
+            ObjectNotFound(loc, Id.TypeInfo_Enum);
         }
         type = Type.typeinfoenum.type;
     }
@@ -2032,7 +2046,7 @@ extern (C++) final class TypeInfoFunctionDeclaration : TypeInfoDeclaration
         super(tinfo);
         if (!Type.typeinfofunction)
         {
-            ObjectNotFound(Id.TypeInfo_Function);
+            ObjectNotFound(loc, Id.TypeInfo_Function);
         }
         type = Type.typeinfofunction.type;
     }
@@ -2057,7 +2071,7 @@ extern (C++) final class TypeInfoDelegateDeclaration : TypeInfoDeclaration
         super(tinfo);
         if (!Type.typeinfodelegate)
         {
-            ObjectNotFound(Id.TypeInfo_Delegate);
+            ObjectNotFound(loc, Id.TypeInfo_Delegate);
         }
         type = Type.typeinfodelegate.type;
     }
@@ -2082,7 +2096,7 @@ extern (C++) final class TypeInfoTupleDeclaration : TypeInfoDeclaration
         super(tinfo);
         if (!Type.typeinfotypelist)
         {
-            ObjectNotFound(Id.TypeInfo_Tuple);
+            ObjectNotFound(loc, Id.TypeInfo_Tuple);
         }
         type = Type.typeinfotypelist.type;
     }
@@ -2107,7 +2121,7 @@ extern (C++) final class TypeInfoConstDeclaration : TypeInfoDeclaration
         super(tinfo);
         if (!Type.typeinfoconst)
         {
-            ObjectNotFound(Id.TypeInfo_Const);
+            ObjectNotFound(loc, Id.TypeInfo_Const);
         }
         type = Type.typeinfoconst.type;
     }
@@ -2132,7 +2146,7 @@ extern (C++) final class TypeInfoInvariantDeclaration : TypeInfoDeclaration
         super(tinfo);
         if (!Type.typeinfoinvariant)
         {
-            ObjectNotFound(Id.TypeInfo_Invariant);
+            ObjectNotFound(loc, Id.TypeInfo_Invariant);
         }
         type = Type.typeinfoinvariant.type;
     }
@@ -2157,7 +2171,7 @@ extern (C++) final class TypeInfoSharedDeclaration : TypeInfoDeclaration
         super(tinfo);
         if (!Type.typeinfoshared)
         {
-            ObjectNotFound(Id.TypeInfo_Shared);
+            ObjectNotFound(loc, Id.TypeInfo_Shared);
         }
         type = Type.typeinfoshared.type;
     }
@@ -2182,7 +2196,7 @@ extern (C++) final class TypeInfoWildDeclaration : TypeInfoDeclaration
         super(tinfo);
         if (!Type.typeinfowild)
         {
-            ObjectNotFound(Id.TypeInfo_Wild);
+            ObjectNotFound(loc, Id.TypeInfo_Wild);
         }
         type = Type.typeinfowild.type;
     }
@@ -2207,7 +2221,7 @@ extern (C++) final class TypeInfoVectorDeclaration : TypeInfoDeclaration
         super(tinfo);
         if (!Type.typeinfovector)
         {
-            ObjectNotFound(Id.TypeInfo_Vector);
+            ObjectNotFound(loc, Id.TypeInfo_Vector);
         }
         type = Type.typeinfovector.type;
     }
index 33428ded2d1db7504a5062c2afbcc4eb6e7d9d55..d4eecb94a97b53f80ecb8718cf48d627fd13aa53 100644 (file)
@@ -72,12 +72,14 @@ void mangleToBuffer(TemplateInstance ti, ref OutBuffer buf)
 /// Returns: `true` if the given character is a valid mangled character
 package bool isValidMangling(dchar c) nothrow
 {
+    import dmd.common.charactertables;
+
     return
         c >= 'A' && c <= 'Z' ||
         c >= 'a' && c <= 'z' ||
         c >= '0' && c <= '9' ||
         c != 0 && strchr("$%().:?@[]_", c) ||
-        isUniAlpha(c);
+        isAnyIdentifierCharacter(c);
 }
 
 // valid mangled characters
@@ -147,6 +149,7 @@ import dmd.dtemplate;
 import dmd.errors;
 import dmd.expression;
 import dmd.func;
+import dmd.funcsem;
 import dmd.globals;
 import dmd.id;
 import dmd.identifier;
index 58bf3fd0757ec2ed74cbab369a47d42131d54f4a..a1a337bd3a526e1838ad9a9b0d94c69819b5ad6f 100644 (file)
@@ -24,6 +24,7 @@ import dmd.astenums;
 import dmd.common.outbuffer;
 import dmd.compiler;
 import dmd.cparse;
+import dmd.declaration;
 import dmd.dimport;
 import dmd.dmacro;
 import dmd.doc;
@@ -357,6 +358,7 @@ extern (C++) final class Module : Package
     FileType filetype;          // source file type
     bool hasAlwaysInlines;      // contains references to functions that must be inlined
     bool isPackageFile;         // if it is a package.d
+    Edition edition;            // language edition that this module is compiled with
     Package pkg;                // if isPackageFile is true, the Package that contains this package.d
     Strings contentImportedFiles; // array of files whose content was imported
     int needmoduleinfo;
@@ -454,7 +456,7 @@ extern (C++) final class Module : Package
             FileName.exists(filename) == 1)
         {
             FileName.free(srcfilename.ptr);
-            srcfilename = FileName.removeExt(filename); // just does a mem.strdup(filename)
+            srcfilename = FileName.sansExt(filename);
         }
         else if (!FileName.equalsExt(srcfilename, mars_ext) &&
                  !FileName.equalsExt(srcfilename, hdr_ext) &&
@@ -476,6 +478,8 @@ extern (C++) final class Module : Package
             setDocfile();
         if (doHdrGen)
             hdrfile = setOutfilename(global.params.dihdr.name, global.params.dihdr.dir, arg, hdr_ext);
+
+        this.edition = Edition.legacy;
     }
 
     extern (D) this(const(char)[] filename, Identifier ident, int doDocComment, int doHdrGen)
@@ -609,41 +613,30 @@ extern (C++) final class Module : Package
      */
     private void onFileReadError(const ref Loc loc)
     {
-        if (FileName.equals(srcfile.toString(), "object.d"))
+        const name = srcfile.toString();
+        if (FileName.equals(name, "object.d"))
         {
-            .error(loc, "cannot find source code for runtime library file 'object.d'");
-            version (IN_LLVM)
-            {
-                errorSupplemental(loc, "ldc2 might not be correctly installed.");
-                errorSupplemental(loc, "Please check your ldc2.conf configuration file.");
-                errorSupplemental(loc, "Installation instructions can be found at http://wiki.dlang.org/LDC.");
-            }
-            version (MARS)
-            {
-                errorSupplemental(loc, "dmd might not be correctly installed. Run 'dmd -man' for installation instructions.");
-                const dmdConfFile = global.inifilename.length ? FileName.canonicalName(global.inifilename) : "not found";
-                errorSupplemental(loc, "config file: %.*s", cast(int)dmdConfFile.length, dmdConfFile.ptr);
-            }
+            ObjectNotFound(loc, ident);
         }
         else if (FileName.ext(this.arg) || !loc.isValid())
         {
             // Modules whose original argument name has an extension, or do not
             // have a valid location come from the command-line.
             // Error that their file cannot be found and return early.
-            .error(loc, "cannot find input file `%s`", srcfile.toChars());
+            .error(loc, "cannot find input file `%.*s`", cast(int)name.length, name.ptr);
         }
         else
         {
             // if module is not named 'package' but we're trying to read 'package.d', we're looking for a package module
             bool isPackageMod = (strcmp(toChars(), "package") != 0) && isPackageFileName(srcfile);
             if (isPackageMod)
-                .error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%s'", toChars(), srcfile.toChars());
+                .error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%.*s'", toChars(), cast(int)name.length, name.ptr);
             else
             {
                 .error(loc, "unable to read module `%s`", toChars());
-                const pkgfile = FileName.combine(FileName.removeExt(srcfile.toString()), package_d);
-                .errorSupplemental(loc, "Expected '%s' or '%s' in one of the following import paths:",
-                    srcfile.toChars(), pkgfile.ptr);
+                const pkgfile = FileName.combine(FileName.sansExt(name), package_d);
+                .errorSupplemental(loc, "Expected '%.*s' or '%.*s' in one of the following import paths:",
+                    cast(int)name.length, name.ptr, cast(int)pkgfile.length, pkgfile.ptr);
             }
         }
         if (!global.gag)
@@ -657,7 +650,7 @@ extern (C++) final class Module : Package
             }
             else
             {
-                fprintf(stderr, "Specify path to file '%s' with -I switch\n", srcfile.toChars());
+                fprintf(stderr, "Specify path to file '%.*s' with -I switch\n", cast(int)name.length, name.ptr);
             }
 
             removeHdrFilesAndFail(global.params, Module.amodules);
index c00c1cc8f40d8555f83066dbba3d6de62433a782..a8b43da625b3b1fc520ccfe3a9e6e7952c8c93c6 100644 (file)
@@ -2106,43 +2106,13 @@ int getMarkdownIndent(ref OutBuffer buf, size_t from, size_t to) @safe
     return indent;
 }
 
-/************************************************
- * Scan forward to one of:
- *      start of identifier
- *      beginning of next line
- *      end of buf
- */
-size_t skiptoident(ref OutBuffer buf, size_t i) @safe
-{
-    const slice = buf[];
-    while (i < slice.length)
-    {
-        dchar c;
-        size_t oi = i;
-        if (utf_decodeChar(slice, i, c))
-        {
-            /* Ignore UTF errors, but still consume input
-             */
-            break;
-        }
-        if (c >= 0x80)
-        {
-            if (!isUniAlpha(c))
-                continue;
-        }
-        else if (!(isalpha(c) || c == '_' || c == '\n'))
-            continue;
-        i = oi;
-        break;
-    }
-    return i;
-}
-
 /************************************************
  * Scan forward past end of identifier.
  */
 size_t skippastident(ref OutBuffer buf, size_t i) @safe
 {
+    import dmd.common.charactertables;
+
     const slice = buf[];
     while (i < slice.length)
     {
@@ -2156,7 +2126,8 @@ size_t skippastident(ref OutBuffer buf, size_t i) @safe
         }
         if (c >= 0x80)
         {
-            if (isUniAlpha(c))
+            // we don't care if it is start/continue here
+            if (isAnyIdentifierCharacter(c))
                 continue;
         }
         else if (isalnum(c) || c == '_')
@@ -2173,6 +2144,8 @@ size_t skippastident(ref OutBuffer buf, size_t i) @safe
  */
 size_t skipPastIdentWithDots(ref OutBuffer buf, size_t i) @safe
 {
+    import dmd.common.charactertables;
+
     const slice = buf[];
     bool lastCharWasDot;
     while (i < slice.length)
@@ -2203,7 +2176,8 @@ size_t skipPastIdentWithDots(ref OutBuffer buf, size_t i) @safe
         {
             if (c >= 0x80)
             {
-                if (isUniAlpha(c))
+                // we don't care if it is start/continue here
+                if (isAnyIdentifierCharacter(c))
                 {
                     lastCharWasDot = false;
                     continue;
@@ -5249,6 +5223,8 @@ bool isCVariadicArg(const(char)[] p) @nogc nothrow pure @safe
 @trusted
 bool isIdStart(const(char)* p) @nogc nothrow pure
 {
+    import dmd.common.charactertables;
+
     dchar c = *p;
     if (isalpha(c) || c == '_')
         return true;
@@ -5257,7 +5233,7 @@ bool isIdStart(const(char)* p) @nogc nothrow pure
         size_t i = 0;
         if (utf_decodeChar(p[0 .. 4], i, c))
             return false; // ignore errors
-        if (isUniAlpha(c))
+        if (isAnyStart(c))
             return true;
     }
     return false;
@@ -5269,6 +5245,8 @@ bool isIdStart(const(char)* p) @nogc nothrow pure
 @trusted
 bool isIdTail(const(char)* p) @nogc nothrow pure
 {
+    import dmd.common.charactertables;
+
     dchar c = *p;
     if (isalnum(c) || c == '_')
         return true;
@@ -5277,7 +5255,7 @@ bool isIdTail(const(char)* p) @nogc nothrow pure
         size_t i = 0;
         if (utf_decodeChar(p[0 .. 4], i, c))
             return false; // ignore errors
-        if (isUniAlpha(c))
+        if (isAnyContinue(c))
             return true;
     }
     return false;
index 76a26a245fb48573cb1fc016843acfe2eb954a36..4719529554780cbbd4f37a3d2d5b75f4480bb34a 100644 (file)
@@ -830,12 +830,18 @@ extern (C++) struct Scope
     /// Returns: whether to raise DIP1000 warnings (FeatureStabe.default) or errors (FeatureState.enabled)
     extern (D) FeatureState useDIP1000()
     {
-        return (flags & SCOPE.dip1000) ? FeatureState.enabled : FeatureState.disabled;
+        return (flags & SCOPE.dip1000 || hasEdition(Edition.v2024)) ? FeatureState.enabled : FeatureState.disabled;
     }
 
     /// Returns: whether to raise DIP25 warnings (FeatureStabe.default) or errors (FeatureState.enabled)
     extern (D) FeatureState useDIP25()
     {
-        return (flags & SCOPE.dip25) ? FeatureState.enabled : FeatureState.disabled;
+        return (flags & SCOPE.dip25 || hasEdition(Edition.v2024)) ? FeatureState.enabled : FeatureState.disabled;
+    }
+
+    /// Returns: whether this scope compiles with `edition` or later
+    extern (D) bool hasEdition(Edition edition)
+    {
+        return _module && _module.edition >= edition;
     }
 }
index df4d07a81d997f331df317f5b1bcc3665b9f603f..339b22323af11bc54a8bfccd3dc7b024e82c02c4 100644 (file)
@@ -28,6 +28,7 @@ import dmd.dtemplate;
 import dmd.errors;
 import dmd.expression;
 import dmd.func;
+import dmd.funcsem;
 import dmd.globals;
 import dmd.id;
 import dmd.identifier;
@@ -222,7 +223,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
         bool hasCopyCtor;           // copy constructor
         bool hasPointerField;       // members with indirections
         bool hasVoidInitPointers;   // void-initialized unsafe fields
-        bool hasSystemFields;      // @system members
+        bool hasUnsafeBitpatterns;  // @system members, pointers, bool
         bool hasFieldWithInvariant; // invariants
         bool computedTypeProperties;// the above 3 fields are computed
         // Even if struct is defined as non-root symbol, some built-in operations
@@ -395,13 +396,16 @@ extern (C++) class StructDeclaration : AggregateDeclaration
         foreach (vd; fields)
         {
             if (vd.storage_class & STC.ref_ || vd.hasPointers())
+            {
                 hasPointerField = true;
+                hasUnsafeBitpatterns = true;
+            }
 
             if (vd._init && vd._init.isVoidInitializer() && vd.type.hasPointers())
                 hasVoidInitPointers = true;
 
-            if (vd.storage_class & STC.system || vd.type.hasSystemFields())
-                hasSystemFields = true;
+            if (vd.storage_class & STC.system || vd.type.hasUnsafeBitpatterns())
+                hasUnsafeBitpatterns = true;
 
             if (!vd._init && vd.type.hasVoidInitPointers())
                 hasVoidInitPointers = true;
index b831c32c28bdc808748afe1eaecfc65f2028ccc9..90b2d9fda6b58418676ee06d94af2c8a9fb095ff 100644 (file)
@@ -453,7 +453,7 @@ extern (C++) class Dsymbol : ASTNode
      *
      * See also `parent`, `toParent` and `toParent2`.
      */
-    final inout(Dsymbol) pastMixin() inout
+    final inout(Dsymbol) pastMixin() inout @safe
     {
         //printf("Dsymbol::pastMixin() %s\n", toChars());
         if (!isTemplateMixin() && !isForwardingAttribDeclaration() && !isForwardingScopeDsymbol())
@@ -503,13 +503,13 @@ extern (C++) class Dsymbol : ASTNode
      *  // s.toParentLocal() == FuncDeclaration('mod.test')
      * ---
      */
-    final inout(Dsymbol) toParent() inout
+    final inout(Dsymbol) toParent() inout @safe
     {
         return parent ? parent.pastMixin() : null;
     }
 
     /// ditto
-    final inout(Dsymbol) toParent2() inout
+    final inout(Dsymbol) toParent2() inout @safe
     {
         if (!parent || !parent.isTemplateInstance && !parent.isForwardingAttribDeclaration() && !parent.isForwardingScopeDsymbol())
             return parent;
index f8454354fed536cfd29c7ad05e0926ccb3c4f3a4..ce29073e2ea8527176ad08c132938a445331028f 100644 (file)
@@ -222,9 +222,9 @@ public:
     Dsymbol *toParent2();
     Dsymbol *toParentDecl();
     Dsymbol *toParentLocal();
-    Dsymbol *toParentP(Dsymbol *p1, Dsymbol *p2 = NULL);
+    Dsymbol *toParentP(Dsymbol *p1, Dsymbol *p2 = nullptr);
     TemplateInstance *isInstantiated();
-    bool followInstantiationContext(Dsymbol *p1, Dsymbol *p2 = NULL);
+    bool followInstantiationContext(Dsymbol *p1, Dsymbol *p2 = nullptr);
     TemplateInstance *isSpeculative();
     Ungag ungagSpeculative();
 
@@ -269,61 +269,61 @@ public:
     bool inNonRoot();
 
     // Eliminate need for dynamic_cast
-    virtual Package *isPackage() { return NULL; }
-    virtual Module *isModule() { return NULL; }
-    virtual EnumMember *isEnumMember() { return NULL; }
-    virtual TemplateDeclaration *isTemplateDeclaration() { return NULL; }
-    virtual TemplateInstance *isTemplateInstance() { return NULL; }
-    virtual TemplateMixin *isTemplateMixin() { return NULL; }
-    virtual ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return NULL; }
-    virtual Nspace *isNspace() { return NULL; }
-    virtual Declaration *isDeclaration() { return NULL; }
-    virtual StorageClassDeclaration *isStorageClassDeclaration(){ return NULL; }
-    virtual ExpressionDsymbol *isExpressionDsymbol() { return NULL; }
-    virtual AliasAssign *isAliasAssign() { return NULL; }
-    virtual ThisDeclaration *isThisDeclaration() { return NULL; }
-    virtual BitFieldDeclaration *isBitFieldDeclaration() { return NULL; }
-    virtual TypeInfoDeclaration *isTypeInfoDeclaration() { return NULL; }
-    virtual TupleDeclaration *isTupleDeclaration() { return NULL; }
-    virtual AliasDeclaration *isAliasDeclaration() { return NULL; }
-    virtual AggregateDeclaration *isAggregateDeclaration() { return NULL; }
-    virtual FuncDeclaration *isFuncDeclaration() { return NULL; }
-    virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return NULL; }
-    virtual OverDeclaration *isOverDeclaration() { return NULL; }
-    virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return NULL; }
-    virtual CtorDeclaration *isCtorDeclaration() { return NULL; }
-    virtual PostBlitDeclaration *isPostBlitDeclaration() { return NULL; }
-    virtual DtorDeclaration *isDtorDeclaration() { return NULL; }
-    virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return NULL; }
-    virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return NULL; }
-    virtual SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return NULL; }
-    virtual SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return NULL; }
-    virtual InvariantDeclaration *isInvariantDeclaration() { return NULL; }
-    virtual UnitTestDeclaration *isUnitTestDeclaration() { return NULL; }
-    virtual NewDeclaration *isNewDeclaration() { return NULL; }
-    virtual VarDeclaration *isVarDeclaration() { return NULL; }
-    virtual VersionSymbol *isVersionSymbol() { return NULL; }
-    virtual DebugSymbol *isDebugSymbol() { return NULL; }
-    virtual ClassDeclaration *isClassDeclaration() { return NULL; }
-    virtual StructDeclaration *isStructDeclaration() { return NULL; }
-    virtual UnionDeclaration *isUnionDeclaration() { return NULL; }
-    virtual InterfaceDeclaration *isInterfaceDeclaration() { return NULL; }
-    virtual ScopeDsymbol *isScopeDsymbol() { return NULL; }
-    virtual ForwardingScopeDsymbol *isForwardingScopeDsymbol() { return NULL; }
-    virtual WithScopeSymbol *isWithScopeSymbol() { return NULL; }
-    virtual ArrayScopeSymbol *isArrayScopeSymbol() { return NULL; }
-    virtual Import *isImport() { return NULL; }
-    virtual EnumDeclaration *isEnumDeclaration() { return NULL; }
-    virtual SymbolDeclaration *isSymbolDeclaration() { return NULL; }
-    virtual AttribDeclaration *isAttribDeclaration() { return NULL; }
-    virtual AnonDeclaration *isAnonDeclaration() { return NULL; }
-    virtual CPPNamespaceDeclaration *isCPPNamespaceDeclaration() { return NULL; }
-    virtual VisibilityDeclaration *isVisibilityDeclaration() { return NULL; }
-    virtual OverloadSet *isOverloadSet() { return NULL; }
-    virtual MixinDeclaration *isMixinDeclaration() { return NULL; }
-    virtual StaticAssert *isStaticAssert() { return NULL; }
-    virtual StaticIfDeclaration *isStaticIfDeclaration() { return NULL; }
-    virtual CAsmDeclaration *isCAsmDeclaration() { return NULL; }
+    virtual Package *isPackage() { return nullptr; }
+    virtual Module *isModule() { return nullptr; }
+    virtual EnumMember *isEnumMember() { return nullptr; }
+    virtual TemplateDeclaration *isTemplateDeclaration() { return nullptr; }
+    virtual TemplateInstance *isTemplateInstance() { return nullptr; }
+    virtual TemplateMixin *isTemplateMixin() { return nullptr; }
+    virtual ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return nullptr; }
+    virtual Nspace *isNspace() { return nullptr; }
+    virtual Declaration *isDeclaration() { return nullptr; }
+    virtual StorageClassDeclaration *isStorageClassDeclaration(){ return nullptr; }
+    virtual ExpressionDsymbol *isExpressionDsymbol() { return nullptr; }
+    virtual AliasAssign *isAliasAssign() { return nullptr; }
+    virtual ThisDeclaration *isThisDeclaration() { return nullptr; }
+    virtual BitFieldDeclaration *isBitFieldDeclaration() { return nullptr; }
+    virtual TypeInfoDeclaration *isTypeInfoDeclaration() { return nullptr; }
+    virtual TupleDeclaration *isTupleDeclaration() { return nullptr; }
+    virtual AliasDeclaration *isAliasDeclaration() { return nullptr; }
+    virtual AggregateDeclaration *isAggregateDeclaration() { return nullptr; }
+    virtual FuncDeclaration *isFuncDeclaration() { return nullptr; }
+    virtual FuncAliasDeclaration *isFuncAliasDeclaration() { return nullptr; }
+    virtual OverDeclaration *isOverDeclaration() { return nullptr; }
+    virtual FuncLiteralDeclaration *isFuncLiteralDeclaration() { return nullptr; }
+    virtual CtorDeclaration *isCtorDeclaration() { return nullptr; }
+    virtual PostBlitDeclaration *isPostBlitDeclaration() { return nullptr; }
+    virtual DtorDeclaration *isDtorDeclaration() { return nullptr; }
+    virtual StaticCtorDeclaration *isStaticCtorDeclaration() { return nullptr; }
+    virtual StaticDtorDeclaration *isStaticDtorDeclaration() { return nullptr; }
+    virtual SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return nullptr; }
+    virtual SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return nullptr; }
+    virtual InvariantDeclaration *isInvariantDeclaration() { return nullptr; }
+    virtual UnitTestDeclaration *isUnitTestDeclaration() { return nullptr; }
+    virtual NewDeclaration *isNewDeclaration() { return nullptr; }
+    virtual VarDeclaration *isVarDeclaration() { return nullptr; }
+    virtual VersionSymbol *isVersionSymbol() { return nullptr; }
+    virtual DebugSymbol *isDebugSymbol() { return nullptr; }
+    virtual ClassDeclaration *isClassDeclaration() { return nullptr; }
+    virtual StructDeclaration *isStructDeclaration() { return nullptr; }
+    virtual UnionDeclaration *isUnionDeclaration() { return nullptr; }
+    virtual InterfaceDeclaration *isInterfaceDeclaration() { return nullptr; }
+    virtual ScopeDsymbol *isScopeDsymbol() { return nullptr; }
+    virtual ForwardingScopeDsymbol *isForwardingScopeDsymbol() { return nullptr; }
+    virtual WithScopeSymbol *isWithScopeSymbol() { return nullptr; }
+    virtual ArrayScopeSymbol *isArrayScopeSymbol() { return nullptr; }
+    virtual Import *isImport() { return nullptr; }
+    virtual EnumDeclaration *isEnumDeclaration() { return nullptr; }
+    virtual SymbolDeclaration *isSymbolDeclaration() { return nullptr; }
+    virtual AttribDeclaration *isAttribDeclaration() { return nullptr; }
+    virtual AnonDeclaration *isAnonDeclaration() { return nullptr; }
+    virtual CPPNamespaceDeclaration *isCPPNamespaceDeclaration() { return nullptr; }
+    virtual VisibilityDeclaration *isVisibilityDeclaration() { return nullptr; }
+    virtual OverloadSet *isOverloadSet() { return nullptr; }
+    virtual MixinDeclaration *isMixinDeclaration() { return nullptr; }
+    virtual StaticAssert *isStaticAssert() { return nullptr; }
+    virtual StaticIfDeclaration *isStaticIfDeclaration() { return nullptr; }
+    virtual CAsmDeclaration *isCAsmDeclaration() { return nullptr; }
     void accept(Visitor *v) override { v->visit(this); }
 };
 
index b13f98aee73be4003becdfbb5037fca92d2d7658..65a1b04365026c4b7dd4c14473e876d31febf819 100644 (file)
@@ -21,6 +21,7 @@ import dmd.arraytypes;
 import dmd.astcodegen;
 import dmd.astenums;
 import dmd.attrib;
+import dmd.attribsem;
 import dmd.clone;
 import dmd.cond;
 import dmd.dcast;
@@ -1072,8 +1073,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         // Calculate type size + safety checks
         if (sc && sc.func)
         {
-            if (dsym._init && dsym._init.isVoidInitializer())
+            if (dsym._init && dsym._init.isVoidInitializer() && !(dsym.storage_class & STC.temp))
             {
+                // Don't do these checks for STC.temp vars because the generated `opAssign`
+                // for a struct with postblit and destructor void initializes a temporary
+                // __swap variable, which can be trusted
 
                 if (dsym.type.hasPointers()) // also computes type size
                     sc.setUnsafe(false, dsym.loc,
@@ -1081,9 +1085,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                 else if (dsym.type.hasInvariant())
                     sc.setUnsafe(false, dsym.loc,
                         "`void` initializers for structs with invariants are not allowed in safe functions");
-                else if (dsym.type.hasSystemFields())
+                else if (dsym.type.toBasetype().ty == Tbool)
                     sc.setUnsafePreview(global.params.systemVariables, false, dsym.loc,
-                        "`void` initializers for `@system` variables not allowed in safe functions");
+                        "a `bool` must be 0 or 1, so void intializing it is not allowed in safe functions");
+                else if (dsym.type.hasUnsafeBitpatterns())
+                    sc.setUnsafePreview(global.params.systemVariables, false, dsym.loc,
+                        "`void` initializers for types with unsafe bit patterns are not allowed in safe functions");
             }
             else if (!dsym._init &&
                      !(dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field | STC.parameter)) &&
@@ -1251,7 +1258,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                                 {
                                     import dmd.escape : setUnsafeDIP1000;
                                     const inSafeFunc = sc.func && sc.func.isSafeBypassingInference();   // isSafeBypassingInference may call setUnsafe().
-                                    if (sc.setUnsafeDIP1000(false, dsym.loc, "`scope` allocation of `%s` requires that constructor be annotated with `scope`", dsym))
+                                    if (setUnsafeDIP1000(*sc, false, dsym.loc, "`scope` allocation of `%s` requires that constructor be annotated with `scope`", dsym))
                                         errorSupplemental(ne.member.loc, "is the location of the constructor");
                                 }
                                 ne.onstack = 1;
@@ -3379,8 +3386,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             {
                 void badObjectDotD()
                 {
-                    .error(cldec.loc, "%s `%s` missing or corrupt object.d", cldec.kind, cldec.toPrettyChars);
-                    fatal();
+                    ObjectNotFound(cldec.loc, cldec.ident);
                 }
 
                 if (!cldec.object || cldec.object.errors)
@@ -5295,6 +5301,24 @@ void aliasSemantic(AliasDeclaration ds, Scope* sc)
     // Detect `alias sym = sym;` to prevent creating loops in overload overnext lists.
     if (auto tident = ds.type.isTypeIdentifier())
     {
+        if (sc.hasEdition(Edition.v2024) && tident.idents.length)
+        {
+            alias mt = tident;
+            Dsymbol pscopesym;
+            Dsymbol s = sc.search(ds.loc, mt.ident, pscopesym);
+            // detect `alias a = var1.member_var;` which confusingly resolves to
+            // `typeof(var1).member_var`, which can be valid inside the aggregate type
+            if (s && s.isVarDeclaration() &&
+                mt.ident != Id.This && mt.ident != Id._super)
+            {
+                s = tident.toDsymbol(sc);
+                if (s && s.isVarDeclaration()) {
+                    error(mt.loc, "cannot alias member of variable `%s`", mt.ident.toChars());
+                    errorSupplemental(mt.loc, "Use `typeof(%s)` instead to preserve behaviour",
+                        mt.ident.toChars());
+                }
+            }
+        }
         // Selective imports are allowed to alias to the same name `import mod : sym=sym`.
         if (!ds._import)
         {
index d181facfc249b39aa644188aba9e0ef71f465086..fb11821f42cfa8507e3b3b56cef02a031c0d68eb 100644 (file)
@@ -5767,7 +5767,7 @@ struct TemplateInstanceBox
         assert(this.ti.hash);
     }
 
-    size_t toHash() const @trusted pure nothrow
+    size_t toHash() const @safe pure nothrow
     {
         assert(ti.hash);
         return ti.hash;
index 2e2ced4b0d1b94072cccd64ada43d7b8b5d3e0d2..883091be9e30cb416ea2b439977997edb64a7bbb 100644 (file)
@@ -104,7 +104,8 @@ void genCppHdrFiles(ref Modules ms)
 
     // Emit array compatibility because extern(C++) types may have slices
     // as members (as opposed to function parameters)
-    buf.writestring(`
+    if (v.hasDArray)
+        buf.writestring(`
 #ifdef CUSTOM_D_ARRAY_TYPE
 #define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
 #else
@@ -131,6 +132,17 @@ struct _d_dynamicArray final
     }
 };
 #endif
+`);
+
+    if (v.hasExternSystem)
+        buf.writestring(`
+#ifndef _WIN32
+#define EXTERN_SYSTEM_AFTER __stdcall
+#define EXTERN_SYSTEM_BEFORE
+#else
+#define EXTERN_SYSTEM_AFTER
+#define EXTERN_SYSTEM_BEFORE extern "C"
+#endif
 `);
 
     if (v.hasReal)
@@ -248,7 +260,14 @@ public:
     OutBuffer* buf;
 
     /// The generated header uses `real` emitted as `_d_real`?
-    bool hasReal;
+    bool hasReal = false;
+
+    /// The generated header has extern(System) functions,
+    /// which needs support macros in the header
+    bool hasExternSystem = false;
+
+    /// There are functions taking slices, which need a compatibility struct for C++
+    bool hasDArray = false;
 
     /// The generated header should contain comments for skipped declarations?
     const bool printIgnored;
@@ -745,7 +764,7 @@ public:
 
         // Note that tf might be null for templated (member) functions
         auto tf = cast(AST.TypeFunction)fd.type;
-        if ((tf && (tf.linkage != LINK.c || adparent) && tf.linkage != LINK.cpp) || (!tf && fd.isPostBlitDeclaration()))
+        if ((tf && (tf.linkage != LINK.c || adparent) && tf.linkage != LINK.cpp && tf.linkage != LINK.windows) || (!tf && fd.isPostBlitDeclaration()))
         {
             ignored("function %s because of linkage", fd.toPrettyChars());
             return checkFunctionNeedsPlaceholder(fd);
@@ -793,8 +812,17 @@ public:
 
         writeProtection(fd.visibility.kind);
 
-        if (tf && tf.linkage == LINK.c)
+        if (fd._linkage == LINK.system)
+        {
+            hasExternSystem = true;
+            buf.writestring("EXTERN_SYSTEM_BEFORE ");
+        }
+        else if (tf && tf.linkage == LINK.c)
             buf.writestring("extern \"C\" ");
+        else if (tf && tf.linkage == LINK.windows)
+        {
+            // __stdcall is printed after return type
+        }
         else if (!adparent)
             buf.writestring("extern ");
         if (adparent && fd.isStatic())
@@ -2058,6 +2086,8 @@ public:
     {
         debug (Debug_DtoH) mixin(traceVisit!t);
 
+        hasDArray = true;
+
         if (t.isConst() || t.isImmutable())
             buf.writestring("const ");
         buf.writestring("_d_dynamicArray< ");
@@ -2261,8 +2291,8 @@ public:
      * Writes the function signature to `buf`.
      *
      * Params:
-     *   fd     = the function to print
      *   tf     = fd's type
+     *   fd     = the function to print
      */
     private void funcToBuffer(AST.TypeFunction tf, AST.FuncDeclaration fd)
     {
@@ -2297,6 +2327,15 @@ public:
             if (tf.isref)
                 buf.writeByte('&');
             buf.writeByte(' ');
+
+            if (fd._linkage == LINK.system)
+            {
+                buf.writestring("EXTERN_SYSTEM_AFTER ");
+            }
+            else if (tf.linkage == LINK.windows)
+            {
+                buf.writestring("__stdcall ");
+            }
             writeIdentifier(fd);
         }
 
index a47b5aada56182a8a44b7423cc9cf214c59be974..7a9683b9e67e19123546d6a4be5b561a3f9352b2 100644 (file)
@@ -42,7 +42,7 @@ D_ATTRIBUTE_FORMAT(1, 2) void message(const char *format, ...);
 D_ATTRIBUTE_FORMAT(2, 3) void message(const Loc& loc, const char *format, ...);
 D_ATTRIBUTE_FORMAT(1, 2) void tip(const char *format, ...);
 
-D_ATTRIBUTE_FORMAT(2, 0) void verrorReport(const Loc& loc, const char *format, va_list ap, ErrorKind kind, const char *p1 = NULL, const char *p2 = NULL);
+D_ATTRIBUTE_FORMAT(2, 0) void verrorReport(const Loc& loc, const char *format, va_list ap, ErrorKind kind, const char *p1 = nullptr, const char *p2 = nullptr);
 D_ATTRIBUTE_FORMAT(2, 0) void verrorReportSupplemental(const Loc& loc, const char* format, va_list ap, ErrorKind kind);
 
 #if defined(__GNUC__) || defined(__clang__)
index 3e17ff4736d343ab62895d19c089cc941251d2ab..08bd6fd2fdd662beeef71f1cd3a32f814de833f0 100644 (file)
@@ -25,6 +25,7 @@ import dmd.dsymbol;
 import dmd.errors;
 import dmd.expression;
 import dmd.func;
+import dmd.funcsem;
 import dmd.globals : FeatureState;
 import dmd.id;
 import dmd.identifier;
@@ -73,7 +74,7 @@ package(dmd) struct EscapeState
  *      `true` if error
  */
 public
-bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
+bool checkMutableArguments(ref Scope sc, FuncDeclaration fd, TypeFunction tf,
     Expression ethis, Expressions* arguments, bool gag)
 {
     enum log = false;
@@ -92,7 +93,8 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
 
     struct EscapeBy
     {
-        EscapeByResults er;
+        VarDeclarations byref;
+        VarDeclarations byvalue;
         Parameter param;        // null if no Parameter for this argument
         bool isMutable;         // true if reference to mutable
     }
@@ -150,14 +152,21 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
             refs = true;
             auto var = outerVars[i - (len - outerVars.length)];
             eb.isMutable = var.type.isMutable();
-            eb.er.pushRef(var, false);
+            eb.byref.push(var);
             continue;
         }
 
+        void onRef(VarDeclaration v, bool transition) { eb.byref.push(v); }
+        void onValue(VarDeclaration v) { eb.byvalue.push(v); }
+        void onFunc(FuncDeclaration fd, bool called) {}
+        void onExp(Expression e, bool transition) {}
+
+        scope EscapeByResults er = EscapeByResults(&onRef, &onValue, &onFunc, &onExp);
+
         if (refs)
-            escapeByRef(arg, &eb.er);
+            escapeByRef(arg, er);
         else
-            escapeByValue(arg, &eb.er);
+            escapeByValue(arg, er);
     }
 
     void checkOnePair(size_t i, ref EscapeBy eb, ref EscapeBy eb2,
@@ -193,7 +202,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
 
     void escape(size_t i, ref EscapeBy eb, bool byval)
     {
-        foreach (VarDeclaration v; byval ? eb.er.byvalue : eb.er.byref)
+        foreach (VarDeclaration v; byval ? eb.byvalue : eb.byref)
         {
             if (log)
             {
@@ -204,7 +213,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
                 continue;
             foreach (ref eb2; escapeBy[i + 1 .. $])
             {
-                foreach (VarDeclaration v2; byval ? eb2.er.byvalue : eb2.er.byref)
+                foreach (VarDeclaration v2; byval ? eb2.byvalue : eb2.byref)
                 {
                     checkOnePair(i, eb, eb2, v, v2, byval);
                 }
@@ -231,7 +240,7 @@ bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
  *      `true` if any elements escaped
  */
 public
-bool checkArrayLiteralEscape(Scope *sc, ArrayLiteralExp ae, bool gag)
+bool checkArrayLiteralEscape(ref Scope sc, ArrayLiteralExp ae, bool gag)
 {
     bool errors;
     if (ae.basis)
@@ -255,7 +264,7 @@ bool checkArrayLiteralEscape(Scope *sc, ArrayLiteralExp ae, bool gag)
  *      `true` if any elements escaped
  */
 public
-bool checkAssocArrayLiteralEscape(Scope *sc, AssocArrayLiteralExp ae, bool gag)
+bool checkAssocArrayLiteralEscape(ref Scope sc, AssocArrayLiteralExp ae, bool gag)
 {
     bool errors;
     foreach (ex; *ae.keys)
@@ -324,7 +333,7 @@ void printScopeFailure(E)(E printFunc, VarDeclaration v, int recursionLimit)
  *      `true` if pointers to the stack can escape via assignment
  */
 public
-bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId, VarDeclaration vPar, STC parStc, Expression arg, bool assertmsg, bool gag)
+bool checkParamArgumentEscape(ref Scope sc, FuncDeclaration fdc, Identifier parId, VarDeclaration vPar, STC parStc, Expression arg, bool assertmsg, bool gag)
 {
     enum log = false;
     if (log) printf("checkParamArgumentEscape(arg: %s par: %s parSTC: %llx)\n",
@@ -335,22 +344,6 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId,
     if (!arg.type.hasPointers())
         return false;
 
-    EscapeByResults er;
-
-    escapeByValue(arg, &er);
-
-    if (parStc & STC.scope_)
-    {
-        // These errors only apply to non-scope parameters
-        // When the parameter is `scope`, only `checkScopeVarAddr` on `er.byref` is needed
-        er.byfunc.setDim(0);
-        er.byvalue.setDim(0);
-        er.byexp.setDim(0);
-    }
-
-    if (!er.byref.length && !er.byvalue.length && !er.byfunc.length && !er.byexp.length)
-        return false;
-
     bool result = false;
 
     /* 'v' is assigned unsafely to 'par'
@@ -382,11 +375,11 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId,
         }
     }
 
-    foreach (VarDeclaration v; er.byvalue)
+    void onValue(VarDeclaration v)
     {
         if (log) printf("byvalue %s\n", v.toChars());
-        if (v.isDataseg())
-            continue;
+        if (parStc & STC.scope_ || v.isDataseg())
+            return;
 
         Dsymbol p = v.toParent2();
 
@@ -402,11 +395,11 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId,
         }
     }
 
-    foreach (VarDeclaration v; er.byref)
+    void onRef(VarDeclaration v, bool retRefTransition)
     {
         if (log) printf("byref %s\n", v.toChars());
         if (v.isDataseg())
-            continue;
+            return;
 
         Dsymbol p = v.toParent2();
 
@@ -414,19 +407,21 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId,
         if (checkScopeVarAddr(v, arg, sc, gag))
         {
             result = true;
-            continue;
+            return;
         }
 
         if (p == sc.func && !(parStc & STC.scope_))
         {
             unsafeAssign!"reference to local variable"(v);
-            continue;
+            return;
         }
     }
 
-    foreach (FuncDeclaration fd; er.byfunc)
+    void onFunc(FuncDeclaration fd, bool called)
     {
         //printf("fd = %s, %d\n", fd.toChars(), fd.tookAddressOf);
+        if (parStc & STC.scope_)
+            return;
         VarDeclarations vars;
         findAllOuterAccessedVariables(fd, &vars);
 
@@ -442,16 +437,15 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId,
             if ((v.isReference() || v.isScope()) && p == sc.func)
             {
                 unsafeAssign!"reference to local"(v);
-                continue;
+                return;
             }
         }
     }
 
-    if (!sc.func)
-        return result;
-
-    foreach (Expression ee; er.byexp)
+    void onExp(Expression ee, bool retRefTransition)
     {
+        if (parStc & STC.scope_)
+            return;
         const(char)* msg = parId ?
             "reference to stack allocated value returned by `%s` assigned to non-scope parameter `%s`" :
             "reference to stack allocated value returned by `%s` assigned to non-scope anonymous parameter";
@@ -459,6 +453,8 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId,
         result |= sc.setUnsafeDIP1000(gag, ee.loc, msg, ee, parId);
     }
 
+    scope EscapeByResults er = EscapeByResults(&onRef, &onValue, &onFunc, &onExp);
+    escapeByValue(arg, er);
     return result;
 }
 
@@ -476,7 +472,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId,
  *      `true` if assignment to `firstArg` would cause an error
  */
 public
-bool checkParamArgumentReturn(Scope* sc, Expression firstArg, Expression arg, Parameter param, bool gag)
+bool checkParamArgumentReturn(ref Scope sc, Expression firstArg, Expression arg, Parameter param, bool gag)
 {
     enum log = false;
     if (log) printf("checkParamArgumentReturn(firstArg: %s arg: %s)\n",
@@ -512,7 +508,7 @@ bool checkParamArgumentReturn(Scope* sc, Expression firstArg, Expression arg, Pa
  *      `true` if construction would cause an escaping reference error
  */
 public
-bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag)
+bool checkConstructorEscape(ref Scope sc, CallExp ce, bool gag)
 {
     enum log = false;
     if (log) printf("checkConstructorEscape(%s, %s)\n", ce.toChars(), ce.type.toChars());
@@ -609,7 +605,7 @@ ReturnParamDest returnParamDest(TypeFunction tf, Type tthis)
  *      `true` if pointers to the stack can escape via assignment
  */
 public
-bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
+bool checkAssignEscape(ref Scope sc, Expression e, bool gag, bool byRef)
 {
     enum log = false;
     if (log) printf("checkAssignEscape(e: %s, byRef: %d)\n", e.toChars(), byRef);
@@ -646,16 +642,6 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
         return false;
 
     VarDeclaration va = expToVariable(e1);
-    EscapeByResults er;
-
-    if (byRef)
-        escapeByRef(e2, &er);
-    else
-        escapeByValue(e2, &er);
-
-    if (!er.byref.length && !er.byvalue.length && !er.byfunc.length && !er.byexp.length)
-        return false;
-
 
     if (va && e.op == EXP.concatenateElemAssign)
     {
@@ -685,7 +671,6 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
 
     FuncDeclaration fd = sc.func;
 
-
     // Determine if va is a `ref` parameter, so it has a lifetime exceding the function scope
     const bool vaIsRef = va && va.isParameter() && va.isReference();
     if (log && vaIsRef) printf("va is ref `%s`\n", va.toChars());
@@ -701,7 +686,10 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
                 vaIsFirstRef = va == fd.vthis;
                 break;
             case ReturnParamDest.firstArg:
-                vaIsFirstRef = (*fd.parameters)[0] == va;
+                // While you'd expect fd.parameters[0] to exist in this case, the compiler-generated
+                // expression that initializes an `out int* p = null` is analyzed before fd.parameters
+                // is created, so we still do a null and length check
+                vaIsFirstRef = fd.parameters && 0 < fd.parameters.length && (*fd.parameters)[0] == va;
                 break;
             case ReturnParamDest.returnVal:
                 break;
@@ -710,14 +698,14 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
     if (log && vaIsFirstRef) printf("va is first ref `%s`\n", va.toChars());
 
     bool result = false;
-    foreach (VarDeclaration v; er.byvalue)
+    void onValue(VarDeclaration v)
     {
         if (log) printf("byvalue: %s\n", v.toChars());
         if (v.isDataseg())
-            continue;
+            return;
 
         if (v == va)
-            continue;
+            return;
 
         Dsymbol p = v.toParent2();
 
@@ -729,7 +717,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
             /* Add v to va's list of dependencies
              */
             va.addMaybe(v);
-            continue;
+            return;
         }
 
         if (vaIsFirstRef && p == fd)
@@ -746,7 +734,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
             {
                 // va=v, where v is `return scope`
                 if (inferScope(va))
-                    continue;
+                    return;
             }
 
             // If va's lifetime encloses v's, then error
@@ -761,7 +749,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
                         break;
                     case EnclosedBy.longerScope:
                         if (v.storage_class & STC.temp)
-                            continue;
+                            return;
                         msg = "scope variable `%s` assigned to `%s` with longer lifetime";
                         break;
                     case EnclosedBy.refVar:
@@ -775,7 +763,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
                 if (sc.setUnsafeDIP1000(gag, ae.loc, msg, v, va))
                 {
                     result = true;
-                    continue;
+                    return;
                 }
             }
 
@@ -793,14 +781,14 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
                     if (isRefReturnScope(va.storage_class))
                         va.storage_class |= STC.returnScope;
                 }
-                continue;
+                return;
             }
             result |= sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to non-scope `%s`", v, e1);
         }
         else if (v.isTypesafeVariadicArray && p == fd)
         {
             if (inferScope(va))
-                continue;
+                return;
             result |= sc.setUnsafeDIP1000(gag, ae.loc, "variadic variable `%s` assigned to non-scope `%s`", v, e1);
         }
         else
@@ -813,16 +801,16 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
         }
     }
 
-    foreach (VarDeclaration v; er.byref)
+    void onRef(VarDeclaration v, bool retRefTransition)
     {
         if (log) printf("byref: %s\n", v.toChars());
         if (v.isDataseg())
-            continue;
+            return;
 
         if (checkScopeVarAddr(v, ae, sc, gag))
         {
             result = true;
-            continue;
+            return;
         }
 
         if (va && va.isScope() && !v.isReference())
@@ -852,7 +840,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
             if (sc.setUnsafeDIP1000(gag, ae.loc, "address of variable `%s` assigned to `%s` with longer lifetime", v, va))
             {
                 result = true;
-                continue;
+                return;
             }
         }
 
@@ -860,21 +848,21 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
             notMaybeScope(v, e);
 
         if (p != sc.func)
-            continue;
+            return;
 
         if (inferScope(va))
         {
             if (v.isReturn() && !va.isReturn())
                 va.storage_class |= STC.return_ | STC.returninferred;
-            continue;
+            return;
         }
         if (e1.op == EXP.structLiteral)
-            continue;
+            return;
 
         result |= sc.setUnsafeDIP1000(gag, ae.loc, "reference to local variable `%s` assigned to non-scope `%s`", v, e1);
     }
 
-    foreach (FuncDeclaration func; er.byfunc)
+    void onFunc(FuncDeclaration func, bool called)
     {
         if (log) printf("byfunc: %s, %d\n", func.toChars(), func.tookAddressOf);
         VarDeclarations vars;
@@ -899,7 +887,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
                 notMaybeScope(v, e);
 
             if (!(v.isReference() || v.isScope()) || p != fd)
-                continue;
+                return;
 
             if (va && !va.isDataseg() && (va.isScope() || va.maybeScope))
             {
@@ -908,14 +896,14 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
                  */
                 //if (!va.isScope())
                     //va.storage_class |= STC.scope_ | STC.scopeinferred;
-                continue;
+                return;
             }
             result |= sc.setUnsafeDIP1000(gag, ae.loc,
                 "reference to local `%s` assigned to non-scope `%s` in @safe code", v, e1);
         }
     }
 
-    foreach (Expression ee; er.byexp)
+    void onExp(Expression ee, bool retRefTransition)
     {
         if (log) printf("byexp: %s\n", ee.toChars());
 
@@ -928,7 +916,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
                 sc.eSink.deprecation(ee.loc, "slice of static array temporary returned by `%s` assigned to longer lived variable `%s`",
                     ee.toChars(), e1.toChars());
             //result = true;
-            continue;
+            return;
         }
 
         if (ee.op == EXP.call && ee.type.toBasetype().isTypeStruct() &&
@@ -937,7 +925,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
             if (sc.setUnsafeDIP1000(gag, ee.loc, "address of struct temporary returned by `%s` assigned to longer lived variable `%s`", ee, e1))
             {
                 result = true;
-                continue;
+                return;
             }
         }
 
@@ -947,17 +935,24 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
             if (sc.setUnsafeDIP1000(gag, ee.loc, "address of struct literal `%s` assigned to longer lived variable `%s`", ee, e1))
             {
                 result = true;
-                continue;
+                return;
             }
         }
 
         if (inferScope(va))
-            continue;
+            return;
 
         result |= sc.setUnsafeDIP1000(gag, ee.loc,
             "reference to stack allocated value returned by `%s` assigned to non-scope `%s`", ee, e1);
     }
 
+    scope EscapeByResults er = EscapeByResults(&onRef, &onValue, &onFunc, &onExp);
+
+    if (byRef)
+        escapeByRef(e2, er);
+    else
+        escapeByValue(e2, er);
+
     return result;
 }
 
@@ -973,35 +968,35 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
  *      `true` if pointers to the stack can escape
  */
 public
-bool checkThrowEscape(Scope* sc, Expression e, bool gag)
+bool checkThrowEscape(ref Scope sc, Expression e, bool gag)
 {
     //printf("[%s] checkThrowEscape, e = %s\n", e.loc.toChars(), e.toChars());
-    EscapeByResults er;
-
-    escapeByValue(e, &er);
-
-    if (!er.byref.length && !er.byvalue.length && !er.byexp.length)
-        return false;
 
     bool result = false;
-    foreach (VarDeclaration v; er.byvalue)
+    void onRef(VarDeclaration v, bool retRefTransition) {}
+    void onValue(VarDeclaration v)
     {
         //printf("byvalue %s\n", v.toChars());
         if (v.isDataseg())
-            continue;
+            return;
 
         if (v.isScope() && !v.iscatchvar)       // special case: allow catch var to be rethrown
                                                 // despite being `scope`
         {
             // https://issues.dlang.org/show_bug.cgi?id=17029
             result |= sc.setUnsafeDIP1000(gag, e.loc, "scope variable `%s` may not be thrown", v);
-            continue;
+            return;
         }
         else
         {
             notMaybeScope(v, new ThrowExp(e.loc, e));
         }
     }
+    void onFunc(FuncDeclaration fd, bool called) {}
+    void onExp(Expression exp, bool retRefTransition) {}
+
+    scope EscapeByResults er = EscapeByResults(&onRef, &onValue, &onFunc, &onExp);
+    escapeByValue(e, er);
     return result;
 }
 
@@ -1017,7 +1012,7 @@ bool checkThrowEscape(Scope* sc, Expression e, bool gag)
  *      `true` if pointers to the stack can escape
  */
 public
-bool checkNewEscape(Scope* sc, Expression e, bool gag)
+bool checkNewEscape(ref Scope sc, Expression e, bool gag)
 {
     import dmd.globals: FeatureState;
     import dmd.errors: previewErrorFunc;
@@ -1025,19 +1020,13 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
     //printf("[%s] checkNewEscape, e = %s\n", e.loc.toChars(), e.toChars());
     enum log = false;
     if (log) printf("[%s] checkNewEscape, e: `%s`\n", e.loc.toChars(), e.toChars());
-    EscapeByResults er;
-
-    escapeByValue(e, &er);
-
-    if (!er.byref.length && !er.byvalue.length && !er.byexp.length)
-        return false;
 
     bool result = false;
-    foreach (VarDeclaration v; er.byvalue)
+    void onValue(VarDeclaration v)
     {
         if (log) printf("byvalue `%s`\n", v.toChars());
         if (v.isDataseg())
-            continue;
+            return;
 
         Dsymbol p = v.toParent2();
 
@@ -1057,7 +1046,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
             {
                 // https://issues.dlang.org/show_bug.cgi?id=20868
                 result |= sc.setUnsafeDIP1000(gag, e.loc, "scope variable `%s` may not be copied into allocated memory", v);
-                continue;
+                return;
             }
         }
         else if (v.isTypesafeVariadicArray && p == sc.func)
@@ -1072,7 +1061,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
         }
     }
 
-    foreach (VarDeclaration v; er.byref)
+    void onRef(VarDeclaration v, bool retRefTransition)
     {
         if (log) printf("byref `%s`\n", v.toChars());
 
@@ -1083,11 +1072,11 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
             const(char)* msg = v.isParameter() ?
                 "copying `%s` into allocated memory escapes a reference to parameter `%s`" :
                 "copying `%s` into allocated memory escapes a reference to local variable `%s`";
-            return sc.setUnsafePreview(fs, gag, e.loc, msg, e, v);
+            return setUnsafePreview(&sc, fs, gag, e.loc, msg, e, v);
         }
 
         if (v.isDataseg())
-            continue;
+            return;
 
         Dsymbol p = v.toParent2();
 
@@ -1096,7 +1085,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
             if (p == sc.func)
             {
                 result |= escapingRef(v, sc.useDIP1000);
-                continue;
+                return;
             }
         }
 
@@ -1104,7 +1093,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
          * Infer the addition of 'return', or set result to be the offending expression.
          */
         if (!v.isReference())
-            continue;
+            return;
 
         // https://dlang.org/spec/function.html#return-ref-parameters
         if (p == sc.func)
@@ -1112,16 +1101,16 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
             //printf("escaping reference to local ref variable %s\n", v.toChars());
             //printf("storage class = x%llx\n", v.storage_class);
             result |= escapingRef(v, sc.useDIP25);
-            continue;
+            return;
         }
         // Don't need to be concerned if v's parent does not return a ref
         FuncDeclaration func = p.isFuncDeclaration();
         if (!func || !func.type)
-            continue;
+            return;
         if (auto tf = func.type.isTypeFunction())
         {
             if (!tf.isref)
-                continue;
+                return;
 
             const(char)* msg = "storing reference to outer local variable `%s` into allocated memory causes it to escape";
             if (!gag)
@@ -1135,7 +1124,9 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
         }
     }
 
-    foreach (Expression ee; er.byexp)
+    void onFunc(FuncDeclaration fd, bool called) {}
+
+    void onExp(Expression ee, bool retRefTransition)
     {
         if (log) printf("byexp %s\n", ee.toChars());
         if (!gag)
@@ -1144,6 +1135,9 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
         result = true;
     }
 
+    scope EscapeByResults er = EscapeByResults(&onRef, &onValue, &onFunc, &onExp);
+    escapeByValue(e, er);
+
     return result;
 }
 
@@ -1160,7 +1154,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
  *      `true` if pointers to the stack can escape
  */
 public
-bool checkReturnEscape(Scope* sc, Expression e, bool gag)
+bool checkReturnEscape(ref Scope sc, Expression e, bool gag)
 {
     //printf("[%s] checkReturnEscape, e: %s\n", e.loc.toChars(), e.toChars());
     return checkReturnEscapeImpl(sc, e, false, gag);
@@ -1178,7 +1172,7 @@ bool checkReturnEscape(Scope* sc, Expression e, bool gag)
  *      `true` if references to the stack can escape
  */
 public
-bool checkReturnEscapeRef(Scope* sc, Expression e, bool gag)
+bool checkReturnEscapeRef(ref Scope sc, Expression e, bool gag)
 {
     version (none)
     {
@@ -1200,26 +1194,17 @@ bool checkReturnEscapeRef(Scope* sc, Expression e, bool gag)
  * Returns:
  *      `true` if references to the stack can escape
  */
-private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
+private bool checkReturnEscapeImpl(ref Scope sc, Expression e, bool refs, bool gag)
 {
     enum log = false;
     if (log) printf("[%s] checkReturnEscapeImpl, refs: %d e: `%s`\n", e.loc.toChars(), refs, e.toChars());
-    EscapeByResults er;
-
-    if (refs)
-        escapeByRef(e, &er);
-    else
-        escapeByValue(e, &er);
-
-    if (!er.byref.length && !er.byvalue.length && !er.byexp.length)
-        return false;
 
     bool result = false;
-    foreach (VarDeclaration v; er.byvalue)
+    void onValue(VarDeclaration v)
     {
         if (log) printf("byvalue `%s`\n", v.toChars());
         if (v.isDataseg())
-            continue;
+            return;
 
         const vsr = buildScopeRef(v.storage_class);
 
@@ -1227,7 +1212,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
 
         if (p == sc.func && inferReturn(sc.func, v, /*returnScope:*/ true))
         {
-            continue;
+            return;
         }
 
         if (v.isScope())
@@ -1237,7 +1222,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
             if (vsr == ScopeRef.ReturnScope ||
                 vsr == ScopeRef.Ref_ReturnScope)
             {
-                continue;
+                return;
             }
 
             auto pfunc = p.isFuncDeclaration();
@@ -1251,15 +1236,20 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
                  *        return s;     // s is inferred as 'scope' but incorrectly tested in foo()
                  *    return null; }
                  */
-                !(!refs && p.parent == sc.func && pfunc.fes) &&
+                !(!refs && p.parent == sc.func && pfunc.fes)
+               )
+            {
                 /*
                  *  auto p(scope string s) {
                  *      string scfunc() { return s; }
                  *  }
                  */
-                !(!refs && sc.func.isFuncDeclaration().getLevel(pfunc, sc.intypeof) > 0)
-               )
-            {
+                if (sc.func.isFuncDeclaration().getLevel(pfunc, sc.intypeof) > 0 &&
+                    inferReturn(sc.func, sc.func.vthis, /*returnScope*/ !refs))
+                {
+                    return;
+                }
+
                 if (v.isParameter() && !v.isReturn())
                 {
                     // https://issues.dlang.org/show_bug.cgi?id=23191
@@ -1269,14 +1259,14 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
                             "scope parameter `%s` may not be returned", v.toChars()
                         );
                         result = true;
-                        continue;
+                        return;
                     }
                 }
                 else
                 {
                     // https://issues.dlang.org/show_bug.cgi?id=17029
                     result |= sc.setUnsafeDIP1000(gag, e.loc, "scope variable `%s` may not be returned", v);
-                    continue;
+                    return;
                 }
             }
         }
@@ -1293,7 +1283,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
         }
     }
 
-    foreach (i, VarDeclaration v; er.byref[])
+    void onRef(VarDeclaration v, bool retRefTransition)
     {
         if (log)
         {
@@ -1310,7 +1300,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
 
             if (v.isParameter() && v.isReference())
             {
-                if (sc.setUnsafePreview(featureState, gag, e.loc, msg, e, v) ||
+                if (setUnsafePreview(&sc, featureState, gag, e.loc, msg, e, v) ||
                     sc.func.isSafeBypassingInference())
                 {
                     result = true;
@@ -1329,7 +1319,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
             }
             else
             {
-                if (er.refRetRefTransition[i])
+                if (retRefTransition)
                 {
                     result |= sc.setUnsafeDIP1000(gag, e.loc, msg, e, v);
                 }
@@ -1343,7 +1333,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
         }
 
         if (v.isDataseg())
-            continue;
+            return;
 
         const vsr = buildScopeRef(v.storage_class);
 
@@ -1358,7 +1348,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
             if (checkScopeVarAddr(v, e, sc, gag))
             {
                 result = true;
-                continue;
+                return;
             }
         }
 
@@ -1367,7 +1357,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
             if (p == sc.func)
             {
                 escapingRef(v, FeatureState.enabled);
-                continue;
+                return;
             }
             FuncDeclaration fd = p.isFuncDeclaration();
             if (fd && sc.func.returnInprocess)
@@ -1394,7 +1384,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
             if (p == sc.func && (vsr == ScopeRef.Ref || vsr == ScopeRef.RefScope) &&
                 inferReturn(sc.func, v, /*returnScope:*/ false))
             {
-                continue;
+                return;
             }
             else
             {
@@ -1405,7 +1395,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
                     //printf("escaping reference to local ref variable %s\n", v.toChars());
                     //printf("storage class = x%llx\n", v.storage_class);
                     escapingRef(v, sc.useDIP25);
-                    continue;
+                    return;
                 }
                 // Don't need to be concerned if v's parent does not return a ref
                 FuncDeclaration fd = p.isFuncDeclaration();
@@ -1418,7 +1408,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
                         if (!gag)
                             previewErrorFunc(sc.isDeprecated(), sc.useDIP25)(e.loc, msg, v.toChars());
                         result = true;
-                        continue;
+                        return;
                     }
                 }
 
@@ -1426,10 +1416,16 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
         }
     }
 
-    foreach (i, Expression ee; er.byexp[])
+    void onFunc(FuncDeclaration fd, bool called)
+    {
+        if (called && fd.isNested())
+            result |= sc.setUnsafeDIP1000(gag, e.loc, "escaping local variable through nested function `%s`", fd);
+    }
+
+    void onExp(Expression ee, bool retRefTransition)
     {
         if (log) printf("byexp %s\n", ee.toChars());
-        if (er.expRetRefTransition[i])
+        if (retRefTransition)
         {
             result |= sc.setUnsafeDIP1000(gag, ee.loc,
                 "escaping reference to stack allocated value returned by `%s`", ee);
@@ -1441,6 +1437,15 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
             result = true;
         }
     }
+
+
+    scope EscapeByResults er = EscapeByResults(&onRef, &onValue, &onFunc, &onExp);
+
+    if (refs)
+        escapeByRef(e, er);
+    else
+        escapeByValue(e, er);
+
     return result;
 }
 
@@ -1541,11 +1546,10 @@ private bool inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope)
  * Params:
  *      e = expression to be returned by value
  *      er = where to place collected data
- *      live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`.
-  *     retRefTransition = if `e` is returned through a `return ref scope` function call
+  *     retRefTransition = if `e` is returned through a `return (ref) scope` function call
  */
 public
-void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false)
+void escapeByValue(Expression e, ref scope EscapeByResults er, bool retRefTransition = false)
 {
     //printf("[%s] escapeByValue, e: %s\n", e.loc.toChars(), e.toChars());
 
@@ -1560,14 +1564,14 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
          * but it'll be placed in static data so no need to check it.
          */
         if (e.e1.op != EXP.structLiteral)
-            escapeByRef(e.e1, er, live, retRefTransition);
+            escapeByRef(e.e1, er, retRefTransition);
     }
 
     void visitSymOff(SymOffExp e)
     {
         VarDeclaration v = e.var.isVarDeclaration();
         if (v)
-            er.pushRef(v, retRefTransition);
+            er.byRef(v, retRefTransition);
     }
 
     void visitVar(VarExp e)
@@ -1576,28 +1580,28 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
         {
             if (v.type.hasPointers() || // not tracking non-pointers
                 v.storage_class & STC.lazy_) // lazy variables are actually pointers
-                er.byvalue.push(v);
+                er.byValue(v);
         }
     }
 
     void visitThis(ThisExp e)
     {
         if (e.var)
-            er.byvalue.push(e.var);
+            er.byValue(e.var);
     }
 
     void visitPtr(PtrExp e)
     {
-        if (live && e.type.hasPointers())
-            escapeByValue(e.e1, er, live, retRefTransition);
+        if (er.live && e.type.hasPointers())
+            escapeByValue(e.e1, er, retRefTransition);
     }
 
     void visitDotVar(DotVarExp e)
     {
         auto t = e.e1.type.toBasetype();
-        if (e.type.hasPointers() && (live || t.ty == Tstruct))
+        if (e.type.hasPointers() && (er.live || t.ty == Tstruct))
         {
-            escapeByValue(e.e1, er, live, retRefTransition);
+            escapeByValue(e.e1, er, retRefTransition);
         }
     }
 
@@ -1605,16 +1609,16 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
     {
         Type t = e.e1.type.toBasetype();
         if (t.ty == Tclass || t.ty == Tpointer)
-            escapeByValue(e.e1, er, live, retRefTransition);
+            escapeByValue(e.e1, er, retRefTransition);
         else
-            escapeByRef(e.e1, er, live, retRefTransition);
-        er.byfunc.push(e.func);
+            escapeByRef(e.e1, er, retRefTransition);
+        er.byFunc(e.func, false);
     }
 
     void visitFunc(FuncExp e)
     {
         if (e.fd.tok == TOK.delegate_)
-            er.byfunc.push(e.fd);
+            er.byFunc(e.fd, false);
     }
 
     void visitTuple(TupleExp e)
@@ -1628,11 +1632,11 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
         if (tb.ty == Tsarray || tb.ty == Tarray)
         {
             if (e.basis)
-                escapeByValue(e.basis, er, live, retRefTransition);
+                escapeByValue(e.basis, er, retRefTransition);
             foreach (el; *e.elements)
             {
                 if (el)
-                    escapeByValue(el, er, live, retRefTransition);
+                    escapeByValue(el, er, retRefTransition);
             }
         }
     }
@@ -1644,7 +1648,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
             foreach (ex; *e.elements)
             {
                 if (ex)
-                    escapeByValue(ex, er, live, retRefTransition);
+                    escapeByValue(ex, er, retRefTransition);
             }
         }
     }
@@ -1657,7 +1661,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
             foreach (ex; *e.arguments)
             {
                 if (ex)
-                    escapeByValue(ex, er, live, retRefTransition);
+                    escapeByValue(ex, er, retRefTransition);
             }
         }
     }
@@ -1669,10 +1673,10 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
         Type tb = e.type.toBasetype();
         if (tb.ty == Tarray && e.e1.type.toBasetype().ty == Tsarray)
         {
-            escapeByRef(e.e1, er, live, retRefTransition);
+            escapeByRef(e.e1, er, retRefTransition);
         }
         else
-            escapeByValue(e.e1, er, live, retRefTransition);
+            escapeByValue(e.e1, er, retRefTransition);
     }
 
     void visitSlice(SliceExp e)
@@ -1687,7 +1691,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
                     return;
                 if (v.isTypesafeVariadicArray)
                 {
-                    er.byvalue.push(v);
+                    er.byValue(v);
                     return;
                 }
             }
@@ -1697,18 +1701,18 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
         {
             Type tb = e.type.toBasetype();
             if (tb.ty != Tsarray)
-                escapeByRef(e.e1, er, live, retRefTransition);
+                escapeByRef(e.e1, er, retRefTransition);
         }
         else
-            escapeByValue(e.e1, er, live, retRefTransition);
+            escapeByValue(e.e1, er, retRefTransition);
     }
 
     void visitIndex(IndexExp e)
     {
         if (e.e1.type.toBasetype().ty == Tsarray ||
-            live && e.type.hasPointers())
+            er.live && e.type.hasPointers())
         {
-            escapeByValue(e.e1, er, live, retRefTransition);
+            escapeByValue(e.e1, er, retRefTransition);
         }
     }
 
@@ -1717,30 +1721,30 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
         Type tb = e.type.toBasetype();
         if (tb.ty == Tpointer)
         {
-            escapeByValue(e.e1, er, live, retRefTransition);
-            escapeByValue(e.e2, er, live, retRefTransition);
+            escapeByValue(e.e1, er, retRefTransition);
+            escapeByValue(e.e2, er, retRefTransition);
         }
     }
 
     void visitBinAssign(BinAssignExp e)
     {
-        escapeByValue(e.e1, er, live, retRefTransition);
+        escapeByValue(e.e1, er, retRefTransition);
     }
 
     void visitAssign(AssignExp e)
     {
-        escapeByValue(e.e1, er, live, retRefTransition);
+        escapeByValue(e.e1, er, retRefTransition);
     }
 
     void visitComma(CommaExp e)
     {
-        escapeByValue(e.e2, er, live, retRefTransition);
+        escapeByValue(e.e2, er, retRefTransition);
     }
 
     void visitCond(CondExp e)
     {
-        escapeByValue(e.e1, er, live, retRefTransition);
-        escapeByValue(e.e2, er, live, retRefTransition);
+        escapeByValue(e.e1, er, retRefTransition);
+        escapeByValue(e.e2, er, retRefTransition);
     }
 
     void visitCall(CallExp e)
@@ -1782,11 +1786,11 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
                                 if (auto fd = dve.var.isFuncDeclaration())
                                     if (fd.isCtorDeclaration() && tf.next.toBasetype().isTypeStruct())
                                     {
-                                        escapeByValue(arg, er, live, retRefTransition);
+                                        escapeByValue(arg, er, retRefTransition);
                                     }
                         }
                         else
-                            escapeByValue(arg, er, live, retRefTransition);
+                            escapeByValue(arg, er, true);
                     }
                     else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
                     {
@@ -1797,10 +1801,10 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
                              * as:
                              *   p;
                              */
-                            escapeByValue(arg, er, live, retRefTransition);
+                            escapeByValue(arg, er, retRefTransition);
                         }
                         else
-                            escapeByRef(arg, er, live, retRefTransition);
+                            escapeByRef(arg, er, retRefTransition);
                     }
                 }
             }
@@ -1843,7 +1847,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
                 if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
                 {
                     if (!tf.isref || tf.isctor)
-                        escapeByValue(dve.e1, er, live, retRefTransition);
+                        escapeByValue(dve.e1, er, retRefTransition);
                 }
                 else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
                 {
@@ -1854,10 +1858,10 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
                          * as:
                          *   this;
                          */
-                        escapeByValue(dve.e1, er, live, retRefTransition);
+                        escapeByValue(dve.e1, er, retRefTransition);
                     }
                     else
-                        escapeByRef(dve.e1, er, live, psr == ScopeRef.ReturnRef_Scope);
+                        escapeByRef(dve.e1, er, psr == ScopeRef.ReturnRef_Scope);
                 }
             }
 
@@ -1865,7 +1869,12 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
             if (fd && fd.isNested())
             {
                 if (tf.isreturn && tf.isScopeQual)
-                    er.pushExp(e, false);
+                {
+                    if (tf.isreturnscope)
+                        er.byFunc(fd, true);
+                    else
+                        er.byExp(e, false);
+                }
             }
         }
 
@@ -1875,7 +1884,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
         if (t1.isTypeDelegate())
         {
             if (tf.isreturn)
-                escapeByValue(e.e1, er, live, retRefTransition);
+                escapeByValue(e.e1, er, retRefTransition);
         }
 
         /* If it's a nested function that is 'return scope'
@@ -1886,7 +1895,12 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
             if (fd && fd.isNested())
             {
                 if (tf.isreturn && tf.isScopeQual)
-                    er.pushExp(e, false);
+                {
+                    if (tf.isreturnscope)
+                        er.byFunc(fd, true);
+                    else
+                        er.byExp(e, false);
+                }
             }
         }
     }
@@ -1940,11 +1954,10 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
  * Params:
  *      e = expression to be returned by 'ref'
  *      er = where to place collected data
- *      live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`.
- *      retRefTransition = if `e` is returned through a `return ref scope` function call
+ *      retRefTransition = if `e` is returned through a `return (ref) scope` function call
  */
 private
-void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false)
+void escapeByRef(Expression e, ref scope EscapeByResults er, bool retRefTransition = false)
 {
     //printf("[%s] escapeByRef, e: %s, retRefTransition: %d\n", e.loc.toChars(), e.toChars(), retRefTransition);
     void visit(Expression e)
@@ -1965,27 +1978,27 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR
                 if (ExpInitializer ez = v._init.isExpInitializer())
                 {
                     if (auto ce = ez.exp.isConstructExp())
-                        escapeByRef(ce.e2, er, live, retRefTransition);
+                        escapeByRef(ce.e2, er, retRefTransition);
                     else
-                        escapeByRef(ez.exp, er, live, retRefTransition);
+                        escapeByRef(ez.exp, er, retRefTransition);
                 }
             }
             else
-                er.pushRef(v, retRefTransition);
+                er.byRef(v, retRefTransition);
         }
     }
 
     void visitThis(ThisExp e)
     {
         if (e.var && e.var.toParent2().isFuncDeclaration().hasDualContext())
-            escapeByValue(e, er, live, retRefTransition);
+            escapeByValue(e, er, retRefTransition);
         else if (e.var)
-            er.pushRef(e.var, retRefTransition);
+            er.byRef(e.var, retRefTransition);
     }
 
     void visitPtr(PtrExp e)
     {
-        escapeByValue(e.e1, er, live, retRefTransition);
+        escapeByValue(e.e1, er, retRefTransition);
     }
 
     void visitIndex(IndexExp e)
@@ -1996,17 +2009,17 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR
             VarDeclaration v = ve.var.isVarDeclaration();
             if (v && v.isTypesafeVariadicArray)
             {
-                er.pushRef(v, retRefTransition);
+                er.byRef(v, retRefTransition);
                 return;
             }
         }
         if (tb.ty == Tsarray)
         {
-            escapeByRef(e.e1, er, live, retRefTransition);
+            escapeByRef(e.e1, er, retRefTransition);
         }
         else if (tb.ty == Tarray)
         {
-            escapeByValue(e.e1, er, live, retRefTransition);
+            escapeByValue(e.e1, er, retRefTransition);
         }
     }
 
@@ -2017,40 +2030,40 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR
             foreach (ex; *e.elements)
             {
                 if (ex)
-                    escapeByRef(ex, er, live, retRefTransition);
+                    escapeByRef(ex, er, retRefTransition);
             }
         }
-        er.pushExp(e, retRefTransition);
+        er.byExp(e, retRefTransition);
     }
 
     void visitDotVar(DotVarExp e)
     {
         Type t1b = e.e1.type.toBasetype();
         if (t1b.ty == Tclass)
-            escapeByValue(e.e1, er, live, retRefTransition);
+            escapeByValue(e.e1, er, retRefTransition);
         else
-            escapeByRef(e.e1, er, live, retRefTransition);
+            escapeByRef(e.e1, er, retRefTransition);
     }
 
     void visitBinAssign(BinAssignExp e)
     {
-        escapeByRef(e.e1, er, live, retRefTransition);
+        escapeByRef(e.e1, er, retRefTransition);
     }
 
     void visitAssign(AssignExp e)
     {
-        escapeByRef(e.e1, er, live, retRefTransition);
+        escapeByRef(e.e1, er, retRefTransition);
     }
 
     void visitComma(CommaExp e)
     {
-        escapeByRef(e.e2, er, live, retRefTransition);
+        escapeByRef(e.e2, er, retRefTransition);
     }
 
     void visitCond(CondExp e)
     {
-        escapeByRef(e.e1, er, live, retRefTransition);
-        escapeByRef(e.e2, er, live, retRefTransition);
+        escapeByRef(e.e1, er, retRefTransition);
+        escapeByRef(e.e2, er, retRefTransition);
     }
 
     void visitCall(CallExp e)
@@ -2080,16 +2093,16 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR
                         const stc = tf.parameterStorageClass(null, p);
                         ScopeRef psr = buildScopeRef(stc);
                         if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
-                            escapeByRef(arg, er, live, retRefTransition);
+                            escapeByRef(arg, er, retRefTransition);
                         else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
                         {
                             if (auto de = arg.isDelegateExp())
                             {
                                 if (de.func.isNested())
-                                    er.pushExp(de, false);
+                                    er.byExp(de, false);
                             }
                             else
-                                escapeByValue(arg, er, live, retRefTransition);
+                                escapeByValue(arg, er, retRefTransition);
                         }
                     }
                 }
@@ -2103,7 +2116,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR
                 // https://issues.dlang.org/show_bug.cgi?id=20149#c10
                 if (dve.var.isCtorDeclaration())
                 {
-                    er.pushExp(e, false);
+                    er.byExp(e, false);
                     return;
                 }
 
@@ -2119,23 +2132,23 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR
 
                 const psr = buildScopeRef(stc);
                 if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
-                    escapeByRef(dve.e1, er, live, psr == ScopeRef.ReturnRef_Scope);
+                    escapeByRef(dve.e1, er, psr == ScopeRef.ReturnRef_Scope);
                 else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
-                    escapeByValue(dve.e1, er, live, retRefTransition);
+                    escapeByValue(dve.e1, er, retRefTransition);
 
                 // If it's also a nested function that is 'return ref'
                 if (FuncDeclaration fd = dve.var.isFuncDeclaration())
                 {
                     if (fd.isNested() && tf.isreturn)
                     {
-                        er.pushExp(e, false);
+                        er.byExp(e, false);
                     }
                 }
             }
             // If it's a delegate, check it too
             if (e.e1.op == EXP.variable && t1.ty == Tdelegate)
             {
-                escapeByValue(e.e1, er, live, retRefTransition);
+                escapeByValue(e.e1, er, retRefTransition);
             }
 
             /* If it's a nested function that is 'return ref'
@@ -2146,12 +2159,12 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR
                 if (fd && fd.isNested())
                 {
                     if (tf.isreturn)
-                        er.pushExp(e, false);
+                        er.byExp(e, false);
                 }
             }
         }
         else
-            er.pushExp(e, retRefTransition);
+            er.byExp(e, retRefTransition);
     }
 
     switch (e.op)
@@ -2181,15 +2194,8 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR
 public
 struct EscapeByResults
 {
-    VarDeclarations byref;      // array into which variables being returned by ref are inserted
-    VarDeclarations byvalue;    // array into which variables with values containing pointers are inserted
-    private FuncDeclarations byfunc; // nested functions that are turned into delegates
-    private Expressions byexp;       // array into which temporaries being returned by ref are inserted
-
-    import dmd.root.array: Array;
-
-    /**
-     * Whether the variable / expression went through a `return ref scope` function call
+    /*
+     * retRefTransition = Whether the variable / expression went through a `return (ref) scope` function call
      *
      * This is needed for the dip1000 by default transition, since the rules for
      * disambiguating `return scope ref` have changed. Therefore, functions in legacy code
@@ -2197,46 +2203,26 @@ struct EscapeByResults
      * are being escaped, which is an error even in `@system` code. By keeping track of this
      * information, variables escaped through `return ref` can be treated as a deprecation instead
      * of error, see test/fail_compilation/dip1000_deprecation.d
+     *
+     * Additionally, return scope can be inferred wrongly instead of scope, in which
+     * case the code could give false positives even without @safe or dip1000:
+     * https://issues.dlang.org/show_bug.cgi?id=23657
      */
-    private Array!bool refRetRefTransition;
-    private Array!bool expRetRefTransition;
-
-    /** Reset arrays so the storage can be used again
-     */
-    void reset()
-    {
-        byref.setDim(0);
-        byvalue.setDim(0);
-        byfunc.setDim(0);
-        byexp.setDim(0);
-
-        refRetRefTransition.setDim(0);
-        expRetRefTransition.setDim(0);
-    }
-
-    /**
-     * Escape variable `v` by reference
-     * Params:
-     *   v = variable to escape
-     *   retRefTransition = `v` is escaped through a `return ref scope` function call
-     */
-    void pushRef(VarDeclaration v, bool retRefTransition)
-    {
-        byref.push(v);
-        refRetRefTransition.push(retRefTransition);
-    }
 
-    /**
-     * Escape a reference to expression `e`
-     * Params:
-     *   e = expression to escape
-     *   retRefTransition = `e` is escaped through a `return ref scope` function call
-     */
-    void pushExp(Expression e, bool retRefTransition)
-    {
-        byexp.push(e);
-        expRetRefTransition.push(retRefTransition);
-    }
+    /// called on variables being returned by ref / address
+    void delegate(VarDeclaration, bool retRefTransition) byRef;
+    /// called on variables with values containing pointers
+    void delegate(VarDeclaration) byValue;
+    /// called on nested functions that are turned into delegates
+    /// When `called` is true, it means the delegate escapes variables
+    /// from the closure through a call to it, while `false` means the
+    /// delegate itself escapes.
+    void delegate(FuncDeclaration, bool called) byFunc;
+    /// called when expression temporaries are being returned by ref / address
+    void delegate(Expression, bool retRefTransition) byExp;
+
+    /// if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`.
+    bool live = false;
 }
 
 /*************************
@@ -2586,10 +2572,10 @@ private void addMaybe(VarDeclaration va, VarDeclaration v)
 
 // `setUnsafePreview` partially evaluated for dip1000
 public
-bool setUnsafeDIP1000(Scope* sc, bool gag, Loc loc, const(char)* msg,
+bool setUnsafeDIP1000(ref Scope sc, bool gag, Loc loc, const(char)* msg,
     RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
 {
-    return setUnsafePreview(sc, sc.useDIP1000, gag, loc, msg, arg0, arg1, arg2);
+    return setUnsafePreview(&sc, sc.useDIP1000, gag, loc, msg, arg0, arg1, arg2);
 }
 
 /***************************************
@@ -2606,7 +2592,7 @@ bool setUnsafeDIP1000(Scope* sc, bool gag, Loc loc, const(char)* msg,
  * Returns:
  *     true if taking the address of `v` is problematic because of the lack of transitive `scope`
  */
-private bool checkScopeVarAddr(VarDeclaration v, Expression e, Scope* sc, bool gag)
+private bool checkScopeVarAddr(VarDeclaration v, Expression e, ref Scope sc, bool gag)
 {
     if (v.storage_class & STC.temp)
         return false;
index 479ad3ade5f32f5be7c8658df7ed52b4d72dc726..a26f3ab83b998c5ed8852d411821b0f7d7a9e8b3 100644 (file)
@@ -3824,6 +3824,7 @@ extern (C++) final class CastExp : UnaExp
 {
     Type to;                    // type to cast to
     ubyte mod = cast(ubyte)~0;  // MODxxxxx
+    bool trusted; // assume cast is safe
 
     extern (D) this(const ref Loc loc, Expression e, Type t) @safe
     {
index 2f6bb84acb9b2f98ff7f0728b53f0dcbb964b0ba..1ff6c4c863e4094e144e8222a76d2b0cca777b38 100644 (file)
@@ -474,7 +474,7 @@ public:
     d_bool isOriginal;            // used when moving instances to indicate `this is this.origin`
     OwnedBy ownedByCtfe;
 
-    static StructLiteralExp *create(const Loc &loc, StructDeclaration *sd, void *elements, Type *stype = NULL);
+    static StructLiteralExp *create(const Loc &loc, StructDeclaration *sd, void *elements, Type *stype = nullptr);
     bool equals(const RootObject * const o) const override;
     StructLiteralExp *syntaxCopy() override;
 
index 7ae7f400d1661ba52c1e6af0d6f25a72466a5038..3502a1cecf79d3fb28da2b75a5102043f2ba636e 100644 (file)
@@ -3222,7 +3222,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                 /* Argument value can be assigned to firstArg.
                  * Check arg to see if it matters.
                  */
-                err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
+                err |= checkParamArgumentReturn(*sc, firstArg, arg, p, false);
             }
             // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
             // as lazy parameters to the next function, but that isn't escaping.
@@ -3236,7 +3236,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                  * Check arg to see if it matters.
                  */
                 VarDeclaration vPar = fd ? (fd.parameters ? (*fd.parameters)[i] : null) : null;
-                err |= checkParamArgumentEscape(sc, fd, p.ident, vPar, cast(STC) pStc, arg, false, false);
+                err |= checkParamArgumentEscape(*sc, fd, p.ident, vPar, cast(STC) pStc, arg, false, false);
             }
 
             // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference
@@ -3375,7 +3375,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
             }
             err |= arg.checkValue();
             err |= arg.checkSharedAccess(sc);
-            err |= checkParamArgumentEscape(sc, fd, Id.dotdotdot, null, cast(STC) tf.parameterList.stc, arg, false, false);
+            err |= checkParamArgumentEscape(*sc, fd, Id.dotdotdot, null, cast(STC) tf.parameterList.stc, arg, false, false);
             arg = arg.optimize(WANTvalue);
         }
         (*arguments)[i] = arg;
@@ -3575,7 +3575,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
      */
     if (global.params.useDIP1021 && (tf.trust == TRUST.safe || tf.trust == TRUST.default_) ||
         tf.islive)
-        err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false);
+        err |= checkMutableArguments(*sc, fd, tf, ethis, arguments, false);
 
     // If D linkage and variadic, add _arguments[] as first argument
     if (tf.isDstyleVariadic())
@@ -4466,7 +4466,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         semanticTypeInfo(sc, e.type);
 
-        if (checkAssocArrayLiteralEscape(sc, e, false))
+        if (checkAssocArrayLiteralEscape(*sc, e, false))
             return setError();
 
         result = e;
@@ -5206,7 +5206,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                  */
                 foreach (arg; *exp.arguments)
                 {
-                    if (arg && checkNewEscape(sc, arg, false))
+                    if (arg && checkNewEscape(*sc, arg, false))
                         return setError();
                 }
             }
@@ -5335,7 +5335,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 lowering = new DotIdExp(exp.loc, lowering, Id.object);
 
                 auto tbn = exp.type.nextOf();
-                while (tbn.ty == Tarray)
+                size_t i = nargs;
+                while (tbn.ty == Tarray && --i)
                     tbn = tbn.nextOf();
                 auto unqualTbn = tbn.unqualify(MODFlags.wild | MODFlags.const_ |
                     MODFlags.immutable_ | MODFlags.shared_);
@@ -6316,7 +6317,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 tthis = ue.e1.type;
                 if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isScopeQual))
                 {
-                    if (checkParamArgumentEscape(sc, exp.f, Id.This, exp.f.vthis, STC.undefined_, ethis, false, false))
+                    if (checkParamArgumentEscape(*sc, exp.f, Id.This, exp.f.vthis, STC.undefined_, ethis, false, false))
                         return setError();
                 }
             }
@@ -8046,7 +8047,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             exp.msg = resolveProperties(sc, exp.msg);
             exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf());
             exp.msg = exp.msg.optimize(WANTvalue);
-            checkParamArgumentEscape(sc, null, null, null, STC.undefined_, exp.msg, true, false);
+            checkParamArgumentEscape(*sc, null, null, null, STC.undefined_, exp.msg, true, false);
         }
 
         if (exp.msg && exp.msg.op == EXP.error)
@@ -10054,7 +10055,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
 
                 semanticTypeInfo(sc, taa);
-                checkNewEscape(sc, exp.e2, false);
+                checkNewEscape(*sc, exp.e2, false);
 
                 exp.type = taa.next;
                 break;
@@ -10088,7 +10089,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
                 if (length <= index)
                 {
-                    error(exp.loc, "array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length);
+                    error(exp.loc, "sequence index `[%llu]` is outside bounds `[0 .. %llu]`", index, cast(ulong)length);
                     return setError();
                 }
                 Expression e;
@@ -10750,7 +10751,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                         dvx.e1 = e1x;
                         auto cx = cast(CallExp)ce.copy();
                         cx.e1 = dvx;
-                        if (checkConstructorEscape(sc, cx, false))
+                        if (checkConstructorEscape(*sc, cx, false))
                             return setError();
 
                         Expression e0;
@@ -11511,9 +11512,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
          * `checkAssignExp` expects only AssignExps.
          */
         if (res == exp) // no `AA[k] = v` rewrite was performed
-            checkAssignEscape(sc, res, false, false);
+            checkAssignEscape(*sc, res, false, false);
         else
-            checkNewEscape(sc, assignElem, false); // assigning to AA puts it on heap
+            checkNewEscape(*sc, assignElem, false); // assigning to AA puts it on heap
 
         if (auto ae = res.isConstructExp())
         {
@@ -11861,10 +11862,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             if (tb2.checkPostblit(exp.e2.loc, sc))
                 return setError();
 
-            if (checkNewEscape(sc, exp.e2, false))
+            if (checkNewEscape(*sc, exp.e2, false))
                 return setError();
 
-            exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, tb1next));
+            auto ecast = exp.e2.castTo(sc, tb1next);
+            if (auto ce = ecast.isCastExp())
+                ce.trusted = true;
+
+            exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, ecast);
             exp.e2 = doCopyOrMove(sc, exp.e2);
         }
         else if (tb1.ty == Tarray &&
@@ -11938,9 +11943,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         auto assignElem = exp.e2;
         auto res = exp.reorderSettingAAElem(sc);
         if (res != exp) // `AA[k] = v` rewrite was performed
-            checkNewEscape(sc, assignElem, false);
+            checkNewEscape(*sc, assignElem, false);
         else if (exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign)
-            checkAssignEscape(sc, res, false, false);
+            checkAssignEscape(*sc, res, false, false);
 
         result = res;
 
@@ -12511,7 +12516,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 exp.e2 = exp.e2.implicitCastTo(sc, tb1next);
                 exp.type = tb1next.arrayOf();
             L2elem:
-                if (checkNewEscape(sc, exp.e2, false))
+                if (checkNewEscape(*sc, exp.e2, false))
                     return setError();
                 result = exp.optimize(WANTvalue);
                 trySetCatExpLowering(result);
@@ -12545,7 +12550,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 exp.e1 = exp.e1.implicitCastTo(sc, tb2next);
                 exp.type = tb2next.arrayOf();
             L1elem:
-                if (checkNewEscape(sc, exp.e1, false))
+                if (checkNewEscape(*sc, exp.e1, false))
                     return setError();
                 result = exp.optimize(WANTvalue);
                 trySetCatExpLowering(result);
@@ -15331,8 +15336,10 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
     Expression visitSlice(SliceExp exp)
     {
         exp.e1 = exp.e1.resolveLoc(loc, sc);
-        exp.lwr = exp.lwr.resolveLoc(loc, sc);
-        exp.upr = exp.upr.resolveLoc(loc, sc);
+        if (exp.lwr)
+            exp.lwr = exp.lwr.resolveLoc(loc, sc);
+        if (exp.upr)
+            exp.upr = exp.upr.resolveLoc(loc, sc);
 
         return exp;
     }
@@ -15732,7 +15739,15 @@ private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
             return visit(_this);
         }
         if (_this.isLvalue())
+        {
+            with (_this)
+            if (!trusted && !e1.type.pointerTo().implicitConvTo(to.pointerTo()))
+                sc.setUnsafePreview(FeatureState.default_, false, loc,
+                    "cast from `%s` to `%s` cannot be used as an lvalue in @safe code",
+                    e1.type, to);
+
             return _this;
+        }
         return visit(_this);
     }
 
index c696a5c240f73ca8d1c1eabec25f8e41b56e5b7f..6ad3d621708d3cea0878997378d37b7d2d8e160c 100644 (file)
 module dmd.file_manager;
 
 import core.stdc.stdio;
+import dmd.common.outbuffer;
 import dmd.root.stringtable : StringTable;
 import dmd.root.file : File, Buffer;
 import dmd.root.filename : FileName, isDirSeparator;
 import dmd.root.string : toDString;
+import dmd.errors;
 import dmd.globals;
 import dmd.identifier;
 import dmd.location;
@@ -70,44 +72,84 @@ private struct PathStack
     }
 }
 
-final class FileManager
+/***************************
+ * Cache path lookups so the operating system
+ * is only consulted once for each path.
+ */
+private struct PathCache
 {
-    private StringTable!(const(ubyte)[]) files;  // contents of files indexed by file name
-    private StringTable!(bool) packageStatus;
+    /* for filespec "a/b/c/d.ext"
+     * a b and c are directories, a, a/b, a/b/c are paths.
+     */
 
-    // check if the package path of the given path exists. The input path is
-    // expected to contain the full path to the module, so the parent
-    // directories of that path are checked.
-    private bool packageExists(const(char)[] p) nothrow
+    StringTable!(bool) pathStatus;      // cached value of does a path exist or not
+
+  nothrow:
+
+    /**
+     * Determine if the path part of path/filename exists.
+     * Cache the results for the path and each left-justified subpath of the path.
+     * Params:
+     *  filespec = path/filename
+     * Returns:
+     *  true if path exists, false if it does not
+     */
+    bool pathExists(const(char)[] filespec) nothrow
     {
-        // step 1, look for the closest parent path that is cached
+        /* look for the longest leftmost parent path that is cached
+         * by starting at the right and working to the left
+         */
         bool exists = true;
-        auto st = PathStack(p);
+        auto st = PathStack(filespec);
         while (st.up) {
-            if (auto cached = packageStatus.lookup(st.cur)) {
+            if (auto cached = pathStatus.lookup(st.cur)) {
                 exists = cached.value;
                 break;
             }
         }
-        // found a parent that is cached (or reached the end of the stack).
-        // step 2, traverse back up the stack storing either false if the
-        // parent doesn't exist, or the result of the `exists` call if it does.
+        /* found a parent path that is cached (or reached the left end of the path).
+         * Now move right caching the results of those directories.
+         * Once a directory is found to not exist, all the directories
+         * to the right of it do not exist
+         */
         while (st.down) {
             if (!exists)
-                packageStatus.insert(st.cur, false);
+                pathStatus.insert(st.cur, false);
             else
-                exists = packageStatus.insert(st.cur, FileName.exists(st.cur) == 2).value;
+                exists = pathStatus.insert(st.cur, FileName.exists(st.cur) == 2).value;
         }
 
-        // at this point, exists should be the answer.
         return exists;
     }
 
+    /**
+     * Ask if path ends in a directory.
+     * Cache result for speed.
+     * Params:
+     *  path = a path
+     * Returns:
+     *  true if it's a path, false if not
+     */
+    bool isExistingPath(const char[] path)
+    {
+        auto cached = pathStatus.lookup(path);
+        if (!cached)
+            cached = pathStatus.insert(path, FileName.exists(path) == 2);
+        return cached.value;
+    }
+}
+
+final class FileManager
+{
+    private StringTable!(const(ubyte)[]) files;  // contents of files indexed by file name
+
+    private PathCache pathCache;
+
     ///
     public this () nothrow
     {
         this.files._init();
-        this.packageStatus._init();
+        this.pathCache.pathStatus._init();
     }
 
 nothrow:
@@ -117,18 +159,18 @@ nothrow:
     * Does not open the file.
     * Params:
     *      filename = as supplied by the user
-    *      path = path to look for filename
+    *      paths = paths to look for filename
     * Returns:
     *      the found file name or
     *      `null` if it is not different from filename.
     */
-    const(char)[] lookForSourceFile(const char[] filename, const char*[] path)
+    const(char)[] lookForSourceFile(const char[] filename, const char*[] paths)
     {
         //printf("lookForSourceFile(`%.*s`)\n", cast(int)filename.length, filename.ptr);
-        /* Search along path[] for .di file, then .d file.
+        /* Search along paths[] for .di file, then .d file.
         */
         // see if we should check for the module locally.
-        bool checkLocal = packageExists(filename);
+        bool checkLocal = pathCache.pathExists(filename);
         const sdi = FileName.forceExt(filename, hdr_ext);
         if (checkLocal && FileName.exists(sdi) == 1)
             return sdi;
@@ -144,12 +186,9 @@ nothrow:
 
         if (checkLocal)
         {
-            auto cached = packageStatus.lookup(filename);
-            if (!cached)
-                cached = packageStatus.insert(filename, FileName.exists(filename) == 2);
-            if (cached.value)
+            if (pathCache.isExistingPath(filename))
             {
-                /* The filename exists and it's a directory.
+                /* The filename exists but it's a directory.
                  * Therefore, the result should be: filename/package.d
                  * iff filename/package.d is a file
                  */
@@ -167,15 +206,15 @@ nothrow:
 
         if (FileName.absolute(filename))
             return null;
-        if (!path.length)
+        if (!paths.length)
             return null;
-        foreach (entry; path)
+        foreach (entry; paths)
         {
             const p = entry.toDString();
 
             const(char)[] n = FileName.combine(p, sdi);
 
-            if (!packageExists(n)) {
+            if (!pathCache.pathExists(n)) {
                 FileName.free(n.ptr);
                 continue; // no need to check for anything else.
             }
@@ -190,19 +229,11 @@ nothrow:
             }
             FileName.free(n.ptr);
 
-            const b = FileName.removeExt(filename);
-            n = FileName.combine(p, b);
-            FileName.free(b.ptr);
-
+            n = FileName.combine(p, FileName.sansExt(filename));
             scope(exit) FileName.free(n.ptr);
 
             // also cache this if we are looking for package.d[i]
-            auto cached = packageStatus.lookup(n);
-            if (!cached) {
-                cached = packageStatus.insert(n, FileName.exists(n) == 2);
-            }
-
-            if (cached.value)
+            if (pathCache.isExistingPath(n))
             {
                 const n2i = FileName.combine(n, package_di);
                 if (FileName.exists(n2i) == 1)
@@ -216,7 +247,7 @@ nothrow:
             }
         }
 
-        /* ImportC: No D modules found, now search along path[] for .i file, then .c file.
+        /* ImportC: No D modules found, now search along paths[] for .i file, then .c file.
          */
         const si = FileName.forceExt(filename, i_ext);
         if (FileName.exists(si) == 1)
@@ -227,7 +258,7 @@ nothrow:
         if (FileName.exists(sc) == 1)
             return sc;
         scope(exit) FileName.free(sc.ptr);
-        foreach (entry; path)
+        foreach (entry; paths)
         {
             const p = entry.toDString();
 
@@ -261,128 +292,31 @@ nothrow:
         if (auto val = files.lookup(name))      // if `name` is cached
             return val.value;                   // return its contents
 
+        OutBuffer buf;
         if (name == "__stdin.d")                // special name for reading from stdin
         {
-            const ubyte[] buffer = readFromStdin().extractSlice();
-            if (this.files.insert(name, buffer) is null)
-                // this.files already contains the name
-                assert(0, "stdin: Insert after lookup failure should never return `null`");
-            return buffer;
+            if (readFromStdin(buf))
+                fatal();
         }
+        else
+        {
+            if (FileName.exists(name) != 1) // if not an ordinary file
+                return null;
 
-        if (FileName.exists(name) != 1) // if not an ordinary file
-            return null;
+            if (File.read(name, buf))
+                return null;        // failed
+        }
 
-        auto readResult = File.read(name);
-        if (!readResult.success)
-            return null;
+        buf.write32(0);         // terminating dchar 0
 
-        const ubyte[] fb = readResult.extractSlice();
+        const length = buf.length;
+        const ubyte[] fb = cast(ubyte[])(buf.extractSlice()[0 .. length - 4]);
         if (files.insert(name, fb) is null)
             assert(0, "Insert after lookup failure should never return `null`");
 
         return fb;
     }
 
-    /**********************************
-     * Take `text` and turn it into an InputRange that emits
-     * slices into `text` for each line.
-     * Params:
-     *  text = array of characters
-     * Returns:
-     *  InputRange accessing `text` as a sequence of lines
-     * Reference:
-     *  `std.string.splitLines()`
-     */
-    auto splitLines(const char[] text)
-    {
-        struct Range
-        {
-          @safe:
-          @nogc:
-          nothrow:
-          pure:
-          private:
-
-            const char[] text;
-            size_t index;       // index of start of line
-            size_t eolIndex;    // index of end of line before newline characters
-            size_t nextIndex;   // index past end of line
-
-            public this(const char[] text)
-            {
-                this.text = text;
-            }
-
-            public bool empty() { return index == text.length; }
-
-            public void popFront() { advance(); index = nextIndex; }
-
-            public const(char)[] front() { advance(); return text[index .. eolIndex]; }
-
-            private void advance()
-            {
-                if (index != nextIndex) // if already advanced
-                    return;
-
-                for (size_t i = index; i < text.length; ++i)
-                {
-                    switch (text[i])
-                    {
-                        case '\v', '\f', '\n':
-                            eolIndex = i;
-                            nextIndex = i + 1;
-                            return;
-
-                        case '\r':
-                            if (i + 1 < text.length && text[i + 1] == '\n') // decode "\r\n"
-                            {
-                                eolIndex = i;
-                                nextIndex = i + 2;
-                                return;
-                            }
-                            eolIndex = i;
-                            nextIndex = i + 1;
-                            return;
-
-                        /* Manually decode:
-                         *  NEL is C2 85
-                         */
-                        case 0xC2:
-                            if (i + 1 < text.length && text[i + 1] == 0x85)
-                            {
-                                eolIndex = i;
-                                nextIndex = i + 2;
-                                return;
-                            }
-                            break;
-
-                        /* Manually decode:
-                         *  lineSep is E2 80 A8
-                         *  paraSep is E2 80 A9
-                         */
-                        case 0xE2:
-                            if (i + 2 < text.length &&
-                                text[i + 1] == 0x80 &&
-                                (text[i + 2] == 0xA8 || text[i + 2] == 0xA9)
-                               )
-                            {
-                                eolIndex = i;
-                                nextIndex = i + 3;
-                                return;
-                            }
-                            break;
-
-                        default:
-                            break;
-                    }
-                }
-            }
-        }
-
-        return Range(text);
-    }
-
     /**
      * Adds the contents of a file to the table.
      * Params:
@@ -398,44 +332,34 @@ nothrow:
     }
 }
 
-private Buffer readFromStdin() nothrow
+private bool readFromStdin(ref OutBuffer sink) nothrow
 {
     import core.stdc.stdio;
     import dmd.errors;
-    import dmd.root.rmem;
 
-    enum bufIncrement = 128 * 1024;
-    size_t pos = 0;
-    size_t sz = bufIncrement;
+    enum BufIncrement = 128 * 1024;
 
-    ubyte* buffer = null;
-    for (;;)
+    for (size_t j; 1; ++j)
     {
-        buffer = cast(ubyte*)mem.xrealloc(buffer, sz + 4); // +2 for sentinel and +2 for lexer
+        char[] buffer = sink.allocate(BufIncrement);
 
         // Fill up buffer
+        size_t filled = 0;
         do
         {
-            assert(sz > pos);
-            size_t rlen = fread(buffer + pos, 1, sz - pos, stdin);
-            pos += rlen;
+            filled += fread(buffer.ptr + filled, 1, buffer.length - filled, stdin);
             if (ferror(stdin))
             {
                 import core.stdc.errno;
                 error(Loc.initial, "cannot read from stdin, errno = %d", errno);
-                fatal();
+                return true;
             }
-            if (feof(stdin))
+            if (feof(stdin)) // successful completion
             {
-                // We're done
-                assert(pos < sz + 2);
-                buffer[pos .. pos + 4] = '\0';
-                return Buffer(buffer[0 .. pos]);
+                sink.setsize(j * BufIncrement + filled);
+                return false;
             }
-        } while (pos < sz);
-
-        // Buffer full, expand
-        sz += bufIncrement;
+        } while (filled < BufIncrement);
     }
 
     assert(0);
index 7003c2b1192317140b6c8c073e9689a8eb2ca02d..f3d7aba26ba627858e81acc18a804d53e957d3f7 100644 (file)
@@ -109,7 +109,8 @@ enum BUILTIN : ubyte
     yl2xp1,
     toPrecFloat,
     toPrecDouble,
-    toPrecReal
+    toPrecReal,
+    ctfeWrite,
 }
 
 private struct FUNCFLAG
@@ -512,149 +513,6 @@ extern (C++) class FuncDeclaration : Declaration
         return true;
     }
 
-    /********************************************
-     * Find function in overload list that exactly matches t.
-     */
-    extern (D) final FuncDeclaration overloadExactMatch(Type t)
-    {
-        FuncDeclaration fd;
-        overloadApply(this, (Dsymbol s)
-        {
-            auto f = s.isFuncDeclaration();
-            if (!f)
-                return 0;
-            if (f.storage_class & STC.disable)
-                return 0;
-            if (t.equals(f.type))
-            {
-                fd = f;
-                return 1;
-            }
-
-            /* Allow covariant matches, as long as the return type
-             * is just a const conversion.
-             * This allows things like pure functions to match with an impure function type.
-             */
-            if (t.ty == Tfunction)
-            {
-                auto tf = cast(TypeFunction)f.type;
-                if (tf.covariant(t) == Covariant.yes &&
-                    tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
-                {
-                    fd = f;
-                    return 1;
-                }
-            }
-            return 0;
-        });
-        return fd;
-    }
-
-    /********************************************
-     * Find function in overload list that matches to the 'this' modifier.
-     * There's four result types.
-     *
-     * 1. If the 'tthis' matches only one candidate, it's an "exact match".
-     *    Returns the function and 'hasOverloads' is set to false.
-     *      eg. If 'tthis" is mutable and there's only one mutable method.
-     * 2. If there's two or more match candidates, but a candidate function will be
-     *    a "better match".
-     *    Returns the better match function but 'hasOverloads' is set to true.
-     *      eg. If 'tthis' is mutable, and there's both mutable and const methods,
-     *          the mutable method will be a better match.
-     * 3. If there's two or more match candidates, but there's no better match,
-     *    Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
-     *      eg. If 'tthis' is mutable, and there's two or more mutable methods.
-     * 4. If there's no candidates, it's "no match" and returns null with error report.
-     *      e.g. If 'tthis' is const but there's no const methods.
-     */
-    extern (D) final FuncDeclaration overloadModMatch(const ref Loc loc, Type tthis, ref bool hasOverloads)
-    {
-        //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
-        MatchAccumulator m;
-        overloadApply(this, (Dsymbol s)
-        {
-            auto f = s.isFuncDeclaration();
-            if (!f || f == m.lastf) // skip duplicates
-                return 0;
-
-            auto tf = f.type.toTypeFunction();
-            //printf("tf = %s\n", tf.toChars());
-
-            MATCH match;
-            if (tthis) // non-static functions are preferred than static ones
-            {
-                if (f.needThis())
-                    match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod);
-                else
-                    match = MATCH.constant; // keep static function in overload candidates
-            }
-            else // static functions are preferred than non-static ones
-            {
-                if (f.needThis())
-                    match = MATCH.convert;
-                else
-                    match = MATCH.exact;
-            }
-            if (match == MATCH.nomatch)
-                return 0;
-
-            if (match > m.last) goto LcurrIsBetter;
-            if (match < m.last) goto LlastIsBetter;
-
-            // See if one of the matches overrides the other.
-            if (m.lastf.overrides(f)) goto LlastIsBetter;
-            if (f.overrides(m.lastf)) goto LcurrIsBetter;
-
-            //printf("\tambiguous\n");
-            m.nextf = f;
-            m.count++;
-            return 0;
-
-        LlastIsBetter:
-            //printf("\tlastbetter\n");
-            m.count++; // count up
-            return 0;
-
-        LcurrIsBetter:
-            //printf("\tisbetter\n");
-            if (m.last <= MATCH.convert)
-            {
-                // clear last secondary matching
-                m.nextf = null;
-                m.count = 0;
-            }
-            m.last = match;
-            m.lastf = f;
-            m.count++; // count up
-            return 0;
-        });
-
-        if (m.count == 1)       // exact match
-        {
-            hasOverloads = false;
-        }
-        else if (m.count > 1)   // better or ambiguous match
-        {
-            hasOverloads = true;
-        }
-        else                    // no match
-        {
-            hasOverloads = true;
-            auto tf = this.type.toTypeFunction();
-            assert(tthis);
-            assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
-            {
-                OutBuffer thisBuf, funcBuf;
-                MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
-                MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
-                .error(loc, "%smethod %s is not callable using a %sobject", kind, toPrettyChars,
-                    funcBuf.peekChars(), this.toPrettyChars(), thisBuf.peekChars());
-            }
-        }
-        return m.lastf;
-    }
-
     /********************************************
      * find function template root in overload list
      */
@@ -855,43 +713,6 @@ extern (C++) class FuncDeclaration : Declaration
         return level;
     }
 
-    /***********************************
-     * Determine lexical level difference from `this` to nested function `fd`.
-     * Issue error if `this` cannot call `fd`.
-     *
-     * Params:
-     *      loc = location for error messages
-     *      sc = context
-     *      fd = target of call
-     *      decl = The `Declaration` that triggered this check.
-     *             Used to provide a better error message only.
-     * Returns:
-     *      0       same level
-     *      >0      decrease nesting by number
-     *      -1      increase nesting by 1 (`fd` is nested within 'this')
-     *      LevelError  error
-     */
-    extern (D) final int getLevelAndCheck(const ref Loc loc, Scope* sc, FuncDeclaration fd,
-                                          Declaration decl)
-    {
-        int level = getLevel(fd, sc.intypeof);
-        if (level != LevelError)
-            return level;
-
-        // Don't give error if in template constraint
-        if (!(sc.flags & SCOPE.constraint))
-        {
-            const(char)* xstatic = isStatic() ? "`static` " : "";
-            // better diagnostics for static functions
-            .error(loc, "%s%s `%s` cannot access %s `%s` in frame of function `%s`",
-                   xstatic, kind(), toPrettyChars(), decl.kind(), decl.toChars(),
-                   fd.toPrettyChars());
-                .errorSupplemental(decl.loc, "`%s` declared here", decl.toChars());
-            return LevelError;
-        }
-        return 1;
-    }
-
     enum LevelError = -2;
 
     override const(char)* toPrettyChars(bool QualifyTypes = false)
@@ -990,47 +811,6 @@ extern (C++) class FuncDeclaration : Declaration
         return false;
     }
 
-    /**********************************
-     * Decide if attributes for this function can be inferred from examining
-     * the function body.
-     * Returns:
-     *  true if can
-     */
-    final bool canInferAttributes(Scope* sc)
-    {
-        if (!fbody)
-            return false;
-
-        if (isVirtualMethod() &&
-            /*
-             * https://issues.dlang.org/show_bug.cgi?id=21719
-             *
-             * If we have an auto virtual function we can infer
-             * the attributes.
-             */
-            !(inferRetType && !isCtorDeclaration()))
-            return false;               // since they may be overridden
-
-        if (sc.func &&
-            /********** this is for backwards compatibility for the moment ********/
-            (!isMember() || sc.func.isSafeBypassingInference() && !isInstantiated()))
-            return true;
-
-        if (isFuncLiteralDeclaration() ||               // externs are not possible with literals
-            (storage_class & STC.inference) ||           // do attribute inference
-            (inferRetType && !isCtorDeclaration()))
-            return true;
-
-        if (isInstantiated())
-        {
-            auto ti = parent.isTemplateInstance();
-            if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == ident)
-                return true;
-        }
-
-        return false;
-    }
-
     /*****************************************
      * Initialize for inferring the attributes of this function.
      */
@@ -1633,101 +1413,6 @@ extern (C++) class FuncDeclaration : Declaration
         return result;
     }
 
-    /*********************************************
-     * In the current function, we are calling 'this' function.
-     * 1. Check to see if the current function can call 'this' function, issue error if not.
-     * 2. If the current function is not the parent of 'this' function, then add
-     *    the current function to the list of siblings of 'this' function.
-     * 3. If the current function is a literal, and it's accessing an uplevel scope,
-     *    then mark it as a delegate.
-     * Returns true if error occurs.
-     */
-    extern (D) final bool checkNestedReference(Scope* sc, const ref Loc loc)
-    {
-        //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
-
-        if (auto fld = this.isFuncLiteralDeclaration())
-        {
-            if (fld.tok == TOK.reserved)
-            {
-                fld.tok = TOK.function_;
-                fld.vthis = null;
-            }
-        }
-
-        if (!parent || parent == sc.parent)
-            return false;
-        if (ident == Id.require || ident == Id.ensure)
-            return false;
-        if (!isThis() && !isNested())
-            return false;
-
-        // The current function
-        FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
-        if (!fdthis)
-            return false; // out of function scope
-
-        Dsymbol p = toParentLocal();
-        Dsymbol p2 = toParent2();
-
-        // Function literals from fdthis to p must be delegates
-        ensureStaticLinkTo(fdthis, p);
-        if (p != p2)
-            ensureStaticLinkTo(fdthis, p2);
-
-        if (isNested())
-        {
-            // The function that this function is in
-            bool checkEnclosing(FuncDeclaration fdv)
-            {
-                if (!fdv)
-                    return false;
-                if (fdv == fdthis)
-                    return false;
-
-                //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
-                //printf("fdv  = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
-                //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
-
-                // Add this function to the list of those which called us
-                if (fdthis != this)
-                {
-                    bool found = false;
-                    for (size_t i = 0; i < siblingCallers.length; ++i)
-                    {
-                        if (siblingCallers[i] == fdthis)
-                            found = true;
-                    }
-                    if (!found)
-                    {
-                        //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars());
-                        if (!sc.intypeof && !(sc.flags & SCOPE.compile))
-                        {
-                            siblingCallers.push(fdthis);
-                            computedEscapingSiblings = false;
-                        }
-                    }
-                }
-
-                const lv = fdthis.getLevelAndCheck(loc, sc, fdv, this);
-                if (lv == LevelError)
-                    return true; // error
-                if (lv == -1)
-                    return false; // downlevel call
-                if (lv == 0)
-                    return false; // same level call
-
-                return false; // Uplevel call
-            }
-
-            if (checkEnclosing(p.isFuncDeclaration()))
-                return true;
-            if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration()))
-                return true;
-        }
-        return false;
-    }
-
     /*******************************
      * Look at all the variables in this function that are referenced
      * by nested functions, and determine if a closure needs to be
@@ -1922,147 +1607,6 @@ extern (C++) class FuncDeclaration : Declaration
         return false;
     }
 
-    /****************************************************
-     * Check whether result variable can be built.
-     * Returns:
-     *     `true` if the function has a return type that
-     *     is different from `void`.
-     */
-    extern (D) private bool canBuildResultVar()
-    {
-        auto f = cast(TypeFunction)type;
-        return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
-    }
-
-    /****************************************************
-     * Merge into this function the 'in' contracts of all it overrides.
-     * 'in's are OR'd together, i.e. only one of them needs to pass.
-     */
-    extern (D) final Statement mergeFrequire(Statement sf, Expressions* params)
-    {
-        /* If a base function and its override both have an IN contract, then
-         * only one of them needs to succeed. This is done by generating:
-         *
-         * void derived.in() {
-         *  try {
-         *    base.in();
-         *  }
-         *  catch () {
-         *    ... body of derived.in() ...
-         *  }
-         * }
-         *
-         * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
-         * If base.in() throws, then derived.in()'s body is executed.
-         */
-
-        foreach (fdv; foverrides)
-        {
-            /* The semantic pass on the contracts of the overridden functions must
-             * be completed before code generation occurs.
-             * https://issues.dlang.org/show_bug.cgi?id=3602
-             */
-            if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
-            {
-                assert(fdv._scope);
-                Scope* sc = fdv._scope.push();
-                sc.stc &= ~STC.override_;
-                fdv.semantic3(sc);
-                sc.pop();
-            }
-
-            sf = fdv.mergeFrequire(sf, params);
-            if (!sf || !fdv.fdrequire)
-                return null;
-            //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
-            /* Make the call:
-                *   try { __require(params); }
-                *   catch (Throwable) { frequire; }
-                */
-            params = Expression.arraySyntaxCopy(params);
-            Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
-            Statement s2 = new ExpStatement(loc, e);
-
-            auto c = new Catch(loc, getThrowable(), null, sf);
-            c.internalCatch = true;
-            auto catches = new Catches();
-            catches.push(c);
-            sf = new TryCatchStatement(loc, s2, catches);
-        }
-        return sf;
-    }
-
-    /****************************************************
-     * Merge into this function the 'in' contracts of all it overrides.
-     */
-    extern (D) final Statement mergeFrequireInclusivePreview(Statement sf, Expressions* params)
-    {
-        /* If a base function and its override both have an IN contract, then
-         * the override in contract must widen the guarantee of the base contract.
-         * This is checked by generating:
-         *
-         * void derived.in() {
-         *  try {
-         *    ... body of derived.in() ...
-         *  }
-         *  catch () {
-         *    // derived in rejected this argument. so parent must also reject it, or we've tightened the contract.
-         *    base.in();
-         *    assert(false, "Logic error: " ~ thr.msg);
-         *  }
-         * }
-         */
-
-        foreach (fdv; foverrides)
-        {
-            /* The semantic pass on the contracts of the overridden functions must
-             * be completed before code generation occurs.
-             * https://issues.dlang.org/show_bug.cgi?id=3602
-             */
-            if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
-            {
-                assert(fdv._scope);
-                Scope* sc = fdv._scope.push();
-                sc.stc &= ~STC.override_;
-                fdv.semantic3(sc);
-                sc.pop();
-            }
-
-            sf = fdv.mergeFrequireInclusivePreview(sf, params);
-            if (sf && fdv.fdrequire)
-            {
-                const loc = this.fdrequire.loc;
-
-                //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
-                /* Make the call:
-                 *   try { frequire; }
-                 *   catch (Throwable thr) { __require(params); assert(false, "Logic error: " ~ thr.msg); }
-                 */
-                Identifier id = Identifier.generateId("thr");
-                params = Expression.arraySyntaxCopy(params);
-                Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
-                Statement s2 = new ExpStatement(loc, e);
-                // assert(false, ...)
-                // TODO make this a runtime helper to allow:
-                // - chaining the original expression
-                // - nogc concatenation
-                Expression msg = new StringExp(loc, "Logic error: in-contract was tighter than parent in-contract");
-                Statement fail = new ExpStatement(loc, new AssertExp(loc, IntegerExp.literal!0, msg));
-
-                Statement s3 = new CompoundStatement(loc, s2, fail);
-
-                auto c = new Catch(loc, getThrowable(), id, s3);
-                c.internalCatch = true;
-                auto catches = new Catches();
-                catches.push(c);
-                sf = new TryCatchStatement(loc, sf, catches);
-            }
-            else
-                return null;
-        }
-        return sf;
-    }
-
     /****************************************************
      * Determine whether an 'out' contract is declared inside
      * the given function or any of its overrides.
@@ -2084,232 +1628,6 @@ extern (C++) class FuncDeclaration : Declaration
         return false;
     }
 
-    /****************************************************
-     * Rewrite contracts as statements.
-     */
-    final void buildEnsureRequire()
-    {
-
-        if (frequires)
-        {
-            /*   in { statements1... }
-             *   in { statements2... }
-             *   ...
-             * becomes:
-             *   in { { statements1... } { statements2... } ... }
-             */
-            assert(frequires.length);
-            auto loc = (*frequires)[0].loc;
-            auto s = new Statements;
-            foreach (r; *frequires)
-            {
-                s.push(new ScopeStatement(r.loc, r, r.loc));
-            }
-            frequire = new CompoundStatement(loc, s);
-        }
-
-        if (fensures)
-        {
-            /*   out(id1) { statements1... }
-             *   out(id2) { statements2... }
-             *   ...
-             * becomes:
-             *   out(__result) { { ref id1 = __result; { statements1... } }
-             *                   { ref id2 = __result; { statements2... } } ... }
-             */
-            assert(fensures.length);
-            auto loc = (*fensures)[0].ensure.loc;
-            auto s = new Statements;
-            foreach (r; *fensures)
-            {
-                if (r.id && canBuildResultVar())
-                {
-                    auto rloc = r.ensure.loc;
-                    auto resultId = new IdentifierExp(rloc, Id.result);
-                    auto init = new ExpInitializer(rloc, resultId);
-                    auto stc = STC.ref_ | STC.temp | STC.result;
-                    auto decl = new VarDeclaration(rloc, null, r.id, init, stc);
-                    auto sdecl = new ExpStatement(rloc, decl);
-                    s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
-                }
-                else
-                {
-                    s.push(r.ensure);
-                }
-            }
-            fensure = new CompoundStatement(loc, s);
-        }
-
-        if (!isVirtual())
-            return;
-
-        /* Rewrite contracts as nested functions, then call them. Doing it as nested
-         * functions means that overriding functions can call them.
-         */
-        TypeFunction f = cast(TypeFunction) type;
-
-        /* Make a copy of the parameters and make them all ref */
-        static Parameters* toRefCopy(ParameterList parameterList)
-        {
-            auto result = new Parameters();
-
-            foreach (n, p; parameterList)
-            {
-                p = p.syntaxCopy();
-                if (!p.isLazy())
-                    p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
-                p.defaultArg = null; // won't be the same with ref
-                result.push(p);
-            }
-
-            return result;
-        }
-
-        if (frequire)
-        {
-            /*   in { ... }
-             * becomes:
-             *   void __require(ref params) { ... }
-             *   __require(params);
-             */
-            Loc loc = frequire.loc;
-            fdrequireParams = new Expressions();
-            if (parameters)
-            {
-                foreach (vd; *parameters)
-                    fdrequireParams.push(new VarExp(loc, vd));
-            }
-            auto fo = cast(TypeFunction)(originalType ? originalType : f);
-            auto fparams = toRefCopy(fo.parameterList);
-            auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
-            tf.isnothrow = f.isnothrow;
-            tf.isnogc = f.isnogc;
-            tf.purity = f.purity;
-            tf.trust = f.trust;
-            auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf);
-            fd.fbody = frequire;
-            Statement s1 = new ExpStatement(loc, fd);
-            Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdrequireParams);
-            Statement s2 = new ExpStatement(loc, e);
-            frequire = new CompoundStatement(loc, s1, s2);
-            fdrequire = fd;
-        }
-
-        /* We need to set fdensureParams here and not in the block below to
-         * have the parameters available when calling a base class ensure(),
-         * even if this function doesn't have an out contract.
-         */
-        fdensureParams = new Expressions();
-        if (canBuildResultVar())
-            fdensureParams.push(new IdentifierExp(loc, Id.result));
-        if (parameters)
-        {
-            foreach (vd; *parameters)
-                fdensureParams.push(new VarExp(loc, vd));
-        }
-
-        if (fensure)
-        {
-            /*   out (result) { ... }
-             * becomes:
-             *   void __ensure(ref tret result, ref params) { ... }
-             *   __ensure(result, params);
-             */
-            Loc loc = fensure.loc;
-            auto fparams = new Parameters();
-            if (canBuildResultVar())
-            {
-                Parameter p = new Parameter(loc, STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
-                fparams.push(p);
-            }
-            auto fo = cast(TypeFunction)(originalType ? originalType : f);
-            fparams.pushSlice((*toRefCopy(fo.parameterList))[]);
-            auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
-            tf.isnothrow = f.isnothrow;
-            tf.isnogc = f.isnogc;
-            tf.purity = f.purity;
-            tf.trust = f.trust;
-            auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf);
-            fd.fbody = fensure;
-            Statement s1 = new ExpStatement(loc, fd);
-            Expression e = new CallExp(loc, new VarExp(loc, fd, false), fdensureParams);
-            Statement s2 = new ExpStatement(loc, e);
-            fensure = new CompoundStatement(loc, s1, s2);
-            fdensure = fd;
-        }
-    }
-
-    /****************************************************
-     * Merge into this function the 'out' contracts of all it overrides.
-     * 'out's are AND'd together, i.e. all of them need to pass.
-     */
-    extern (D) final Statement mergeFensure(Statement sf, Identifier oid, Expressions* params)
-    {
-        /* Same comments as for mergeFrequire(), except that we take care
-         * of generating a consistent reference to the 'result' local by
-         * explicitly passing 'result' to the nested function as a reference
-         * argument.
-         * This won't work for the 'this' parameter as it would require changing
-         * the semantic code for the nested function so that it looks on the parameter
-         * list for the 'this' pointer, something that would need an unknown amount
-         * of tweaking of various parts of the compiler that I'd rather leave alone.
-         */
-        foreach (fdv; foverrides)
-        {
-            /* The semantic pass on the contracts of the overridden functions must
-             * be completed before code generation occurs.
-             * https://issues.dlang.org/show_bug.cgi?id=3602 and
-             * https://issues.dlang.org/show_bug.cgi?id=5230
-             */
-            if (needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
-            {
-                assert(fdv._scope);
-                Scope* sc = fdv._scope.push();
-                sc.stc &= ~STC.override_;
-                fdv.semantic3(sc);
-                sc.pop();
-            }
-
-            sf = fdv.mergeFensure(sf, oid, params);
-            if (fdv.fdensure)
-            {
-                //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
-                // Make the call: __ensure(result, params)
-                params = Expression.arraySyntaxCopy(params);
-                if (canBuildResultVar())
-                {
-                    Type t1 = fdv.type.nextOf().toBasetype();
-                    Type t2 = this.type.nextOf().toBasetype();
-                    if (t1.isBaseOf(t2, null))
-                    {
-                        /* Making temporary reference variable is necessary
-                         * in covariant return.
-                         * https://issues.dlang.org/show_bug.cgi?id=5204
-                         * https://issues.dlang.org/show_bug.cgi?id=10479
-                         */
-                        Expression* eresult = &(*params)[0];
-                        auto ei = new ExpInitializer(Loc.initial, *eresult);
-                        auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei);
-                        v.storage_class |= STC.temp;
-                        auto de = new DeclarationExp(Loc.initial, v);
-                        auto ve = new VarExp(Loc.initial, v);
-                        *eresult = new CommaExp(Loc.initial, de, ve);
-                    }
-                }
-                Expression e = new CallExp(loc, new VarExp(loc, fdv.fdensure, false), params);
-                Statement s2 = new ExpStatement(loc, e);
-
-                if (sf)
-                {
-                    sf = new CompoundStatement(sf.loc, s2, sf);
-                }
-                else
-                    sf = s2;
-            }
-        }
-        return sf;
-    }
-
     /*********************************************
      * Returns: the function's parameter list, and whether
      * it is variadic or not.
@@ -2544,7 +1862,7 @@ extern (C++) class FuncDeclaration : Declaration
         return this;
     }
 
-    inout(FuncDeclaration) toAliasFunc() inout
+    inout(FuncDeclaration) toAliasFunc() inout @safe
     {
         return this;
     }
@@ -3073,56 +2391,6 @@ extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
         return false;
     }
 
-    /*******************************
-     * Modify all expression type of return statements to tret.
-     *
-     * On function literals, return type may be modified based on the context type
-     * after its semantic3 is done, in FuncExp::implicitCastTo.
-     *
-     *  A function() dg = (){ return new B(); } // OK if is(B : A) == true
-     *
-     * If B to A conversion is convariant that requires offseet adjusting,
-     * all return statements should be adjusted to return expressions typed A.
-     */
-    extern (D) void modifyReturns(Scope* sc, Type tret)
-    {
-        import dmd.statement_rewrite_walker;
-
-        extern (C++) final class RetWalker : StatementRewriteWalker
-        {
-            alias visit = typeof(super).visit;
-        public:
-            Scope* sc;
-            Type tret;
-            FuncLiteralDeclaration fld;
-
-            override void visit(ReturnStatement s)
-            {
-                Expression exp = s.exp;
-                if (exp && !exp.type.equals(tret))
-                    s.exp = exp.implicitCastTo(sc, tret);
-            }
-        }
-
-        if (semanticRun < PASS.semantic3done)
-            return;
-
-        if (fes)
-            return;
-
-        scope RetWalker w = new RetWalker();
-        w.sc = sc;
-        w.tret = tret;
-        w.fld = this;
-        fbody.accept(w);
-
-        // Also update the inferred function type to match the new return type.
-        // This is required so the code generator does not try to cast the
-        // modified returns back to the original type.
-        if (inferRetType && type.nextOf() != tret)
-            type.toTypeFunction().next = tret;
-    }
-
     override inout(FuncLiteralDeclaration) isFuncLiteralDeclaration() inout
     {
         return this;
@@ -3654,136 +2922,6 @@ extern (C++) final class NewDeclaration : FuncDeclaration
     }
 }
 
-/**************************************
- * When a traits(compiles) is used on a function literal call
- * we need to take into account if the body of the function
- * violates any attributes, however, we must not affect the
- * attribute inference on the outer function. The attributes
- * of the function literal still need to be inferred, therefore
- * we need a way to check for the scope that the traits compiles
- * introduces.
- *
- * Params:
- *   sc = scope to be checked for
- *
- * Returns: `true` if the provided scope is the root
- * of the traits compiles list of scopes.
- */
-bool isRootTraitsCompilesScope(Scope* sc)
-{
-    return (sc.flags & SCOPE.compile) && !(sc.func.flags & SCOPE.compile);
-}
-
-/**************************************
- * A statement / expression in this scope is not `@safe`,
- * so mark the enclosing function as `@system`
- *
- * Params:
- *   sc = scope that the unsafe statement / expression is in
- *   gag = surpress error message (used in escape.d)
- *   loc = location of error
- *   fmt = printf-style format string
- *   arg0  = (optional) argument for first %s format specifier
- *   arg1  = (optional) argument for second %s format specifier
- *   arg2  = (optional) argument for third %s format specifier
- * Returns: whether there's a safe error
- */
-bool setUnsafe(Scope* sc,
-    bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
-    RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
-{
-    if (sc.intypeof)
-        return false; // typeof(cast(int*)0) is safe
-
-    if (sc.flags & SCOPE.debug_) // debug {} scopes are permissive
-        return false;
-
-    if (!sc.func)
-    {
-        if (sc.varDecl)
-        {
-            if (sc.varDecl.storage_class & STC.safe)
-            {
-                .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
-                return true;
-            }
-            else if (!(sc.varDecl.storage_class & STC.trusted))
-            {
-                sc.varDecl.storage_class |= STC.system;
-                sc.varDecl.systemInferred = true;
-            }
-        }
-        return false;
-    }
-
-
-    if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
-    {
-        if (sc.func.isSafeBypassingInference())
-        {
-            // Message wil be gagged, but still call error() to update global.errors and for
-            // -verrors=spec
-            .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
-            return true;
-        }
-        return false;
-    }
-
-    return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2);
-}
-
-/***************************************
- * Like `setUnsafe`, but for safety errors still behind preview switches
- *
- * Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
- * the behavior changes based on the setting:
- *
- * - In case of `-revert=fs`, it does nothing.
- * - In case of `-preview=fs`, it's the same as `setUnsafe`
- * - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
- *
- * Params:
- *   sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
- *   fs = feature state from the preview flag
- *   gag = surpress error message
- *   loc = location of error
- *   msg = printf-style format string
- *   arg0  = (optional) argument for first %s format specifier
- *   arg1  = (optional) argument for second %s format specifier
- *   arg2  = (optional) argument for third %s format specifier
- * Returns: whether an actual safe error (not deprecation) occured
- */
-bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg,
-    RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
-{
-    //printf("setUnsafePreview() fs:%d %s\n", fs, msg);
-    with (FeatureState) final switch (fs)
-    {
-      case disabled:
-        return false;
-
-      case enabled:
-        return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);
-
-      case default_:
-        if (!sc.func)
-            return false;
-        if (sc.func.isSafeBypassingInference())
-        {
-            if (!gag && !sc.isDeprecated())
-            {
-                deprecation(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
-            }
-        }
-        else if (!sc.func.safetyViolation)
-        {
-            import dmd.func : AttributeViolation;
-            sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
-        }
-        return false;
-    }
-}
-
 /// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure`
 ///
 /// Has two modes:
index 2cadc4019110ddc901b31cce95dae1344c114d92..e058deb0f94d85c21a484fcac88554536a15d653 100644 (file)
@@ -1891,6 +1891,309 @@ Expression addInvariant(AggregateDeclaration ad, VarDeclaration vthis)
     return e;
 }
 
+/********************************************
+ * Find function in overload list that exactly matches t.
+ */
+FuncDeclaration overloadExactMatch(FuncDeclaration thisfd, Type t)
+{
+    FuncDeclaration fd;
+    overloadApply(thisfd, (Dsymbol s)
+    {
+        auto f = s.isFuncDeclaration();
+        if (!f)
+            return 0;
+        if (f.storage_class & STC.disable)
+            return 0;
+        if (t.equals(f.type))
+        {
+            fd = f;
+            return 1;
+        }
+        /* Allow covariant matches, as long as the return type
+         * is just a const conversion.
+         * This allows things like pure functions to match with an impure function type.
+         */
+        if (t.ty == Tfunction)
+        {
+            auto tf = cast(TypeFunction)f.type;
+            if (tf.covariant(t) == Covariant.yes &&
+                tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
+            {
+                fd = f;
+                return 1;
+            }
+        }
+        return 0;
+    });
+    return fd;
+}
+
+/********************************************
+ * Find function in overload list that matches to the 'this' modifier.
+ * There's four result types.
+ *
+ * 1. If the 'tthis' matches only one candidate, it's an "exact match".
+ *    Returns the function and 'hasOverloads' is set to false.
+ *      eg. If 'tthis" is mutable and there's only one mutable method.
+ * 2. If there's two or more match candidates, but a candidate function will be
+ *    a "better match".
+ *    Returns the better match function but 'hasOverloads' is set to true.
+ *      eg. If 'tthis' is mutable, and there's both mutable and const methods,
+ *          the mutable method will be a better match.
+ * 3. If there's two or more match candidates, but there's no better match,
+ *    Returns null and 'hasOverloads' is set to true to represent "ambiguous match".
+ *      eg. If 'tthis' is mutable, and there's two or more mutable methods.
+ * 4. If there's no candidates, it's "no match" and returns null with error report.
+ *      e.g. If 'tthis' is const but there's no const methods.
+ */
+FuncDeclaration overloadModMatch(FuncDeclaration thisfd, const ref Loc loc, Type tthis, ref bool hasOverloads)
+{
+    //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars());
+    MatchAccumulator m;
+    overloadApply(thisfd, (Dsymbol s)
+    {
+        auto f = s.isFuncDeclaration();
+        if (!f || f == m.lastf) // skip duplicates
+            return 0;
+        auto tf = f.type.toTypeFunction();
+        //printf("tf = %s\n", tf.toChars());
+        MATCH match;
+        if (tthis) // non-static functions are preferred than static ones
+        {
+            if (f.needThis())
+                match = f.isCtorDeclaration() ? MATCH.exact : MODmethodConv(tthis.mod, tf.mod);
+            else
+                match = MATCH.constant; // keep static function in overload candidates
+        }
+        else // static functions are preferred than non-static ones
+        {
+            if (f.needThis())
+                match = MATCH.convert;
+            else
+                match = MATCH.exact;
+        }
+        if (match == MATCH.nomatch)
+            return 0;
+        if (match > m.last) goto LcurrIsBetter;
+        if (match < m.last) goto LlastIsBetter;
+        // See if one of the matches overrides the other.
+        if (m.lastf.overrides(f)) goto LlastIsBetter;
+        if (f.overrides(m.lastf)) goto LcurrIsBetter;
+        //printf("\tambiguous\n");
+        m.nextf = f;
+        m.count++;
+        return 0;
+    LlastIsBetter:
+        //printf("\tlastbetter\n");
+        m.count++; // count up
+        return 0;
+    LcurrIsBetter:
+        //printf("\tisbetter\n");
+        if (m.last <= MATCH.convert)
+        {
+            // clear last secondary matching
+            m.nextf = null;
+            m.count = 0;
+        }
+        m.last = match;
+        m.lastf = f;
+        m.count++; // count up
+        return 0;
+    });
+    if (m.count == 1)       // exact match
+    {
+        hasOverloads = false;
+    }
+    else if (m.count > 1)   // better or ambiguous match
+    {
+        hasOverloads = true;
+    }
+    else                    // no match
+    {
+        hasOverloads = true;
+        auto tf = thisfd.type.toTypeFunction();
+        assert(tthis);
+        assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch
+        {
+            OutBuffer thisBuf, funcBuf;
+            MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
+            MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
+            .error(loc, "%smethod %s is not callable using a %sobject", thisfd.kind, thisfd.toPrettyChars,
+                funcBuf.peekChars(), thisfd.toPrettyChars(), thisBuf.peekChars());
+        }
+    }
+    return m.lastf;
+}
+
+/***********************************
+ * Determine lexical level difference from `fd` to nested function `target`.
+ * Issue error if `fd` cannot call `target`.
+ *
+ * Params:
+ *      fd = function
+ *      loc = location for error messages
+ *      sc = context
+ *      target = target of call
+ *      decl = The `Declaration` that triggered this check.
+ *             Used to provide a better error message only.
+ * Returns:
+ *      0       same level
+ *      >0      decrease nesting by number
+ *      -1      increase nesting by 1 (`target` is nested within 'fd')
+ *      LevelError  error
+ */
+int getLevelAndCheck(FuncDeclaration fd, const ref Loc loc, Scope* sc, FuncDeclaration target,
+                     Declaration decl)
+{
+    int level = fd.getLevel(target, sc.intypeof);
+    if (level != fd.LevelError)
+        return level;
+    // Don't give error if in template constraint
+    if (!(sc.flags & SCOPE.constraint))
+    {
+        const(char)* xstatic = fd.isStatic() ? "`static` " : "";
+        // better diagnostics for static functions
+        .error(loc, "%s%s `%s` cannot access %s `%s` in frame of function `%s`",
+               xstatic, fd.kind(), fd.toPrettyChars(), decl.kind(), decl.toChars(),
+               target.toPrettyChars());
+            .errorSupplemental(decl.loc, "`%s` declared here", decl.toChars());
+        return fd.LevelError;
+    }
+    return 1;
+}
+
+/**********************************
+ * Decide if attributes for this function can be inferred from examining
+ * the function body.
+ * Returns:
+ *  true if can
+ */
+bool canInferAttributes(FuncDeclaration fd, Scope* sc)
+{
+    if (!fd.fbody)
+        return false;
+    if (fd.isVirtualMethod() &&
+        /*
+         * https://issues.dlang.org/show_bug.cgi?id=21719
+         *
+         * If we have an auto virtual function we can infer
+         * the attributes.
+         */
+        !(fd.inferRetType && !fd.isCtorDeclaration()))
+        return false;               // since they may be overridden
+    if (sc.func &&
+        /********** this is for backwards compatibility for the moment ********/
+        (!fd.isMember() || sc.func.isSafeBypassingInference() && !fd.isInstantiated()))
+        return true;
+    if (fd.isFuncLiteralDeclaration() ||               // externs are not possible with literals
+        (fd.storage_class & STC.inference) ||           // do attribute inference
+        (fd.inferRetType && !fd.isCtorDeclaration()))
+        return true;
+    if (fd.isInstantiated())
+    {
+        auto ti = fd.parent.isTemplateInstance();
+        if (ti is null || ti.isTemplateMixin() || ti.tempdecl.ident == fd.ident)
+            return true;
+    }
+    return false;
+}
+
+/*********************************************
+ * In the current function, we are calling 'this' function.
+ * 1. Check to see if the current function can call 'this' function, issue error if not.
+ * 2. If the current function is not the parent of 'this' function, then add
+ *    the current function to the list of siblings of 'this' function.
+ * 3. If the current function is a literal, and it's accessing an uplevel scope,
+ *    then mark it as a delegate.
+ * Returns true if error occurs.
+ */
+bool checkNestedReference(FuncDeclaration fd, Scope* sc, const ref Loc loc)
+{
+    //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
+    if (auto fld = fd.isFuncLiteralDeclaration())
+    {
+        if (fld.tok == TOK.reserved)
+        {
+            fld.tok = TOK.function_;
+            fld.vthis = null;
+        }
+    }
+    if (!fd.parent || fd.parent == sc.parent)
+        return false;
+    if (fd.ident == Id.require || fd.ident == Id.ensure)
+        return false;
+    if (!fd.isThis() && !fd.isNested())
+        return false;
+    // The current function
+    FuncDeclaration fdthis = sc.parent.isFuncDeclaration();
+    if (!fdthis)
+        return false; // out of function scope
+    Dsymbol p = fd.toParentLocal();
+    Dsymbol p2 = fd.toParent2();
+    // Function literals from fdthis to p must be delegates
+    ensureStaticLinkTo(fdthis, p);
+    if (p != p2)
+        ensureStaticLinkTo(fdthis, p2);
+    if (fd.isNested())
+    {
+        // The function that this function is in
+        bool checkEnclosing(FuncDeclaration fdv)
+        {
+            if (!fdv)
+                return false;
+            if (fdv == fdthis)
+                return false;
+            //printf("this = %s in [%s]\n", this.toChars(), this.loc.toChars());
+            //printf("fdv  = %s in [%s]\n", fdv .toChars(), fdv .loc.toChars());
+            //printf("fdthis = %s in [%s]\n", fdthis.toChars(), fdthis.loc.toChars());
+            // Add this function to the list of those which called us
+            if (fdthis != fd)
+            {
+                bool found = false;
+                for (size_t i = 0; i < fd.siblingCallers.length; ++i)
+                {
+                    if (fd.siblingCallers[i] == fdthis)
+                        found = true;
+                }
+                if (!found)
+                {
+                    //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars());
+                    if (!sc.intypeof && !(sc.flags & SCOPE.compile))
+                    {
+                        fd.siblingCallers.push(fdthis);
+                        fd.computedEscapingSiblings = false;
+                    }
+                }
+            }
+            const lv = fdthis.getLevelAndCheck(loc, sc, fdv, fd);
+            if (lv == fd.LevelError)
+                return true; // error
+            if (lv == -1)
+                return false; // downlevel call
+            if (lv == 0)
+                return false; // same level call
+            return false; // Uplevel call
+        }
+        if (checkEnclosing(p.isFuncDeclaration()))
+            return true;
+        if (checkEnclosing(p == p2 ? null : p2.isFuncDeclaration()))
+            return true;
+    }
+    return false;
+}
+
+/****************************************************
+ * Check whether result variable can be built.
+ * Returns:
+ *     `true` if the function has a return type that
+ *     is different from `void`.
+ */
+private bool canBuildResultVar(FuncDeclaration fd)
+{
+    auto f = cast(TypeFunction)fd.type;
+    return f && f.nextOf() && f.nextOf().toBasetype().ty != Tvoid;
+}
+
 /****************************************************
  * Declare result variable lazily.
  */
@@ -1923,3 +2226,512 @@ void buildResultVar(FuncDeclaration fd, Scope* sc, Type tret)
         assert(fd.vresult.parent == fd);
     }
 }
+
+/****************************************************
+ * Merge into this function the 'in' contracts of all it overrides.
+ * 'in's are OR'd together, i.e. only one of them needs to pass.
+ */
+Statement mergeFrequire(FuncDeclaration fd, Statement sf, Expressions* params)
+{
+    /* If a base function and its override both have an IN contract, then
+     * only one of them needs to succeed. This is done by generating:
+     *
+     * void derived.in() {
+     *  try {
+     *    base.in();
+     *  }
+     *  catch () {
+     *    ... body of derived.in() ...
+     *  }
+     * }
+     *
+     * So if base.in() doesn't throw, derived.in() need not be executed, and the contract is valid.
+     * If base.in() throws, then derived.in()'s body is executed.
+     */
+    foreach (fdv; fd.foverrides)
+    {
+        /* The semantic pass on the contracts of the overridden functions must
+         * be completed before code generation occurs.
+         * https://issues.dlang.org/show_bug.cgi?id=3602
+         */
+        if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
+        {
+            assert(fdv._scope);
+            Scope* sc = fdv._scope.push();
+            sc.stc &= ~STC.override_;
+            fdv.semantic3(sc);
+            sc.pop();
+        }
+        sf = fdv.mergeFrequire(sf, params);
+        if (!sf || !fdv.fdrequire)
+            return null;
+        //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
+        /* Make the call:
+            *   try { __require(params); }
+            *   catch (Throwable) { frequire; }
+            */
+        params = Expression.arraySyntaxCopy(params);
+        Expression e = new CallExp(fd.loc, new VarExp(fd.loc, fdv.fdrequire, false), params);
+        Statement s2 = new ExpStatement(fd.loc, e);
+        auto c = new Catch(fd.loc, getThrowable(), null, sf);
+        c.internalCatch = true;
+        auto catches = new Catches();
+        catches.push(c);
+        sf = new TryCatchStatement(fd.loc, s2, catches);
+    }
+    return sf;
+}
+
+/****************************************************
+ * Merge into this function the 'in' contracts of all it overrides.
+ */
+Statement mergeFrequireInclusivePreview(FuncDeclaration fd, Statement sf, Expressions* params)
+{
+    /* If a base function and its override both have an IN contract, then
+     * the override in contract must widen the guarantee of the base contract.
+     * This is checked by generating:
+     *
+     * void derived.in() {
+     *  try {
+     *    ... body of derived.in() ...
+     *  }
+     *  catch () {
+     *    // derived in rejected this argument. so parent must also reject it, or we've tightened the contract.
+     *    base.in();
+     *    assert(false, "Logic error: " ~ thr.msg);
+     *  }
+     * }
+     */
+    foreach (fdv; fd.foverrides)
+    {
+        /* The semantic pass on the contracts of the overridden functions must
+         * be completed before code generation occurs.
+         * https://issues.dlang.org/show_bug.cgi?id=3602
+         */
+        if (fdv.frequires && fdv.semanticRun != PASS.semantic3done)
+        {
+            assert(fdv._scope);
+            Scope* sc = fdv._scope.push();
+            sc.stc &= ~STC.override_;
+            fdv.semantic3(sc);
+            sc.pop();
+        }
+        sf = fdv.mergeFrequireInclusivePreview(sf, params);
+        if (sf && fdv.fdrequire)
+        {
+            const loc = fd.fdrequire.loc;
+            //printf("fdv.frequire: %s\n", fdv.frequire.toChars());
+            /* Make the call:
+             *   try { frequire; }
+             *   catch (Throwable thr) { __require(params); assert(false, "Logic error: " ~ thr.msg); }
+             */
+            Identifier id = Identifier.generateId("thr");
+            params = Expression.arraySyntaxCopy(params);
+            Expression e = new CallExp(loc, new VarExp(loc, fdv.fdrequire, false), params);
+            Statement s2 = new ExpStatement(loc, e);
+            // assert(false, ...)
+            // TODO make this a runtime helper to allow:
+            // - chaining the original expression
+            // - nogc concatenation
+            Expression msg = new StringExp(loc, "Logic error: in-contract was tighter than parent in-contract");
+            Statement fail = new ExpStatement(loc, new AssertExp(loc, IntegerExp.literal!0, msg));
+            Statement s3 = new CompoundStatement(loc, s2, fail);
+            auto c = new Catch(loc, getThrowable(), id, s3);
+            c.internalCatch = true;
+            auto catches = new Catches();
+            catches.push(c);
+            sf = new TryCatchStatement(loc, sf, catches);
+        }
+        else
+            return null;
+    }
+    return sf;
+}
+
+/****************************************************
+ * Rewrite contracts as statements.
+ */
+void buildEnsureRequire(FuncDeclaration thisfd)
+{
+    if (thisfd.frequires)
+    {
+        /*   in { statements1... }
+         *   in { statements2... }
+         *   ...
+         * becomes:
+         *   in { { statements1... } { statements2... } ... }
+         */
+        assert(thisfd.frequires.length);
+        auto loc = (*thisfd.frequires)[0].loc;
+        auto s = new Statements;
+        foreach (r; *thisfd.frequires)
+        {
+            s.push(new ScopeStatement(r.loc, r, r.loc));
+        }
+        thisfd.frequire = new CompoundStatement(loc, s);
+    }
+    if (thisfd.fensures)
+    {
+        /*   out(id1) { statements1... }
+         *   out(id2) { statements2... }
+         *   ...
+         * becomes:
+         *   out(__result) { { ref id1 = __result; { statements1... } }
+         *                   { ref id2 = __result; { statements2... } } ... }
+         */
+        assert(thisfd.fensures.length);
+        auto loc = (*thisfd.fensures)[0].ensure.loc;
+        auto s = new Statements;
+        foreach (r; *thisfd.fensures)
+        {
+            if (r.id && thisfd.canBuildResultVar())
+            {
+                auto rloc = r.ensure.loc;
+                auto resultId = new IdentifierExp(rloc, Id.result);
+                auto init = new ExpInitializer(rloc, resultId);
+                auto stc = STC.ref_ | STC.temp | STC.result;
+                auto decl = new VarDeclaration(rloc, null, r.id, init, stc);
+                auto sdecl = new ExpStatement(rloc, decl);
+                s.push(new ScopeStatement(rloc, new CompoundStatement(rloc, sdecl, r.ensure), rloc));
+            }
+            else
+            {
+                s.push(r.ensure);
+            }
+        }
+        thisfd.fensure = new CompoundStatement(loc, s);
+    }
+    if (!thisfd.isVirtual())
+        return;
+    /* Rewrite contracts as nested functions, then call them. Doing it as nested
+     * functions means that overriding functions can call them.
+     */
+    TypeFunction f = cast(TypeFunction) thisfd.type;
+    /* Make a copy of the parameters and make them all ref */
+    static Parameters* toRefCopy(ParameterList parameterList)
+    {
+        auto result = new Parameters();
+        foreach (n, p; parameterList)
+        {
+            p = p.syntaxCopy();
+            if (!p.isLazy())
+                p.storageClass = (p.storageClass | STC.ref_) & ~STC.out_;
+            p.defaultArg = null; // won't be the same with ref
+            result.push(p);
+        }
+        return result;
+    }
+    if (thisfd.frequire)
+    {
+        /*   in { ... }
+         * becomes:
+         *   void __require(ref params) { ... }
+         *   __require(params);
+         */
+        Loc loc = thisfd.frequire.loc;
+        thisfd.fdrequireParams = new Expressions();
+        if (thisfd.parameters)
+        {
+            foreach (vd; *thisfd.parameters)
+                thisfd.fdrequireParams.push(new VarExp(loc, vd));
+        }
+        auto fo = cast(TypeFunction)(thisfd.originalType ? thisfd.originalType : f);
+        auto fparams = toRefCopy(fo.parameterList);
+        auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
+        tf.isnothrow = f.isnothrow;
+        tf.isnogc = f.isnogc;
+        tf.purity = f.purity;
+        tf.trust = f.trust;
+        auto fd = new FuncDeclaration(loc, loc, Id.require, STC.undefined_, tf);
+        fd.fbody = thisfd.frequire;
+        Statement s1 = new ExpStatement(loc, fd);
+        Expression e = new CallExp(loc, new VarExp(loc, fd, false), thisfd.fdrequireParams);
+        Statement s2 = new ExpStatement(loc, e);
+        thisfd.frequire = new CompoundStatement(loc, s1, s2);
+        thisfd.fdrequire = fd;
+    }
+    /* We need to set fdensureParams here and not in the block below to
+     * have the parameters available when calling a base class ensure(),
+     * even if this function doesn't have an out contract.
+     */
+    thisfd.fdensureParams = new Expressions();
+    if (thisfd.canBuildResultVar())
+        thisfd.fdensureParams.push(new IdentifierExp(thisfd.loc, Id.result));
+    if (thisfd.parameters)
+    {
+        foreach (vd; *thisfd.parameters)
+            thisfd.fdensureParams.push(new VarExp(thisfd.loc, vd));
+    }
+    if (thisfd.fensure)
+    {
+        /*   out (result) { ... }
+         * becomes:
+         *   void __ensure(ref tret result, ref params) { ... }
+         *   __ensure(result, params);
+         */
+        Loc loc = thisfd.fensure.loc;
+        auto fparams = new Parameters();
+        if (thisfd.canBuildResultVar())
+        {
+            Parameter p = new Parameter(loc, STC.ref_ | STC.const_, f.nextOf(), Id.result, null, null);
+            fparams.push(p);
+        }
+        auto fo = cast(TypeFunction)(thisfd.originalType ? thisfd.originalType : f);
+        fparams.pushSlice((*toRefCopy(fo.parameterList))[]);
+        auto tf = new TypeFunction(ParameterList(fparams), Type.tvoid, LINK.d);
+        tf.isnothrow = f.isnothrow;
+        tf.isnogc = f.isnogc;
+        tf.purity = f.purity;
+        tf.trust = f.trust;
+        auto fd = new FuncDeclaration(loc, loc, Id.ensure, STC.undefined_, tf);
+        fd.fbody = thisfd.fensure;
+        Statement s1 = new ExpStatement(loc, fd);
+        Expression e = new CallExp(loc, new VarExp(loc, fd, false), thisfd.fdensureParams);
+        Statement s2 = new ExpStatement(loc, e);
+        thisfd.fensure = new CompoundStatement(loc, s1, s2);
+        thisfd.fdensure = fd;
+    }
+}
+
+/****************************************************
+ * Merge into this function the 'out' contracts of all it overrides.
+ * 'out's are AND'd together, i.e. all of them need to pass.
+ */
+Statement mergeFensure(FuncDeclaration fd, Statement sf, Identifier oid, Expressions* params)
+{
+    /* Same comments as for mergeFrequire(), except that we take care
+     * of generating a consistent reference to the 'result' local by
+     * explicitly passing 'result' to the nested function as a reference
+     * argument.
+     * This won't work for the 'this' parameter as it would require changing
+     * the semantic code for the nested function so that it looks on the parameter
+     * list for the 'this' pointer, something that would need an unknown amount
+     * of tweaking of various parts of the compiler that I'd rather leave alone.
+     */
+    foreach (fdv; fd.foverrides)
+    {
+        /* The semantic pass on the contracts of the overridden functions must
+         * be completed before code generation occurs.
+         * https://issues.dlang.org/show_bug.cgi?id=3602 and
+         * https://issues.dlang.org/show_bug.cgi?id=5230
+         */
+        if (fd.needsFensure(fdv) && fdv.semanticRun != PASS.semantic3done)
+        {
+            assert(fdv._scope);
+            Scope* sc = fdv._scope.push();
+            sc.stc &= ~STC.override_;
+            fdv.semantic3(sc);
+            sc.pop();
+        }
+        sf = fdv.mergeFensure(sf, oid, params);
+        if (fdv.fdensure)
+        {
+            //printf("fdv.fensure: %s\n", fdv.fensure.toChars());
+            // Make the call: __ensure(result, params)
+            params = Expression.arraySyntaxCopy(params);
+            if (fd.canBuildResultVar())
+            {
+                Type t1 = fdv.type.nextOf().toBasetype();
+                Type t2 = fd.type.nextOf().toBasetype();
+                if (t1.isBaseOf(t2, null))
+                {
+                    /* Making temporary reference variable is necessary
+                     * in covariant return.
+                     * https://issues.dlang.org/show_bug.cgi?id=5204
+                     * https://issues.dlang.org/show_bug.cgi?id=10479
+                     */
+                    Expression* eresult = &(*params)[0];
+                    auto ei = new ExpInitializer(Loc.initial, *eresult);
+                    auto v = new VarDeclaration(Loc.initial, t1, Identifier.generateId("__covres"), ei);
+                    v.storage_class |= STC.temp;
+                    auto de = new DeclarationExp(Loc.initial, v);
+                    auto ve = new VarExp(Loc.initial, v);
+                    *eresult = new CommaExp(Loc.initial, de, ve);
+                }
+            }
+            Expression e = new CallExp(fd.loc, new VarExp(fd.loc, fdv.fdensure, false), params);
+            Statement s2 = new ExpStatement(fd.loc, e);
+            if (sf)
+            {
+                sf = new CompoundStatement(sf.loc, s2, sf);
+            }
+            else
+                sf = s2;
+        }
+    }
+    return sf;
+}
+
+/*******************************
+ * Modify all expression type of return statements to tret.
+ *
+ * On function literals, return type may be modified based on the context type
+ * after its semantic3 is done, in FuncExp::implicitCastTo.
+ *
+ *  A function() dg = (){ return new B(); } // OK if is(B : A) == true
+ *
+ * If B to A conversion is convariant that requires offseet adjusting,
+ * all return statements should be adjusted to return expressions typed A.
+ */
+void modifyReturns(FuncLiteralDeclaration fld, Scope* sc, Type tret)
+{
+    import dmd.statement_rewrite_walker;
+    extern (C++) final class RetWalker : StatementRewriteWalker
+    {
+        alias visit = typeof(super).visit;
+    public:
+        Scope* sc;
+        Type tret;
+        FuncLiteralDeclaration fld;
+        override void visit(ReturnStatement s)
+        {
+            Expression exp = s.exp;
+            if (exp && !exp.type.equals(tret))
+                s.exp = exp.implicitCastTo(sc, tret);
+        }
+    }
+    if (fld.semanticRun < PASS.semantic3done)
+        return;
+    if (fld.fes)
+        return;
+    scope RetWalker w = new RetWalker();
+    w.sc = sc;
+    w.tret = tret;
+    w.fld = fld;
+    fld.fbody.accept(w);
+    // Also update the inferred function type to match the new return type.
+    // This is required so the code generator does not try to cast the
+    // modified returns back to the original type.
+    if (fld.inferRetType && fld.type.nextOf() != tret)
+        fld.type.toTypeFunction().next = tret;
+}
+
+/**************************************
+ * When a traits(compiles) is used on a function literal call
+ * we need to take into account if the body of the function
+ * violates any attributes, however, we must not affect the
+ * attribute inference on the outer function. The attributes
+ * of the function literal still need to be inferred, therefore
+ * we need a way to check for the scope that the traits compiles
+ * introduces.
+ *
+ * Params:
+ *   sc = scope to be checked for
+ *
+ * Returns: `true` if the provided scope is the root
+ * of the traits compiles list of scopes.
+ */
+bool isRootTraitsCompilesScope(Scope* sc)
+{
+    return (sc.flags & SCOPE.compile) && !(sc.func.flags & SCOPE.compile);
+}
+
+/**************************************
+ * A statement / expression in this scope is not `@safe`,
+ * so mark the enclosing function as `@system`
+ *
+ * Params:
+ *   sc = scope that the unsafe statement / expression is in
+ *   gag = surpress error message (used in escape.d)
+ *   loc = location of error
+ *   fmt = printf-style format string
+ *   arg0  = (optional) argument for first %s format specifier
+ *   arg1  = (optional) argument for second %s format specifier
+ *   arg2  = (optional) argument for third %s format specifier
+ * Returns: whether there's a safe error
+ */
+bool setUnsafe(Scope* sc,
+    bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
+    RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
+{
+    if (sc.intypeof)
+        return false; // typeof(cast(int*)0) is safe
+
+    if (sc.flags & SCOPE.debug_) // debug {} scopes are permissive
+        return false;
+
+    if (!sc.func)
+    {
+        if (sc.varDecl)
+        {
+            if (sc.varDecl.storage_class & STC.safe)
+            {
+                .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+                return true;
+            }
+            else if (!(sc.varDecl.storage_class & STC.trusted))
+            {
+                sc.varDecl.storage_class |= STC.system;
+                sc.varDecl.systemInferred = true;
+            }
+        }
+        return false;
+    }
+
+
+    if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
+    {
+        if (sc.func.isSafeBypassingInference())
+        {
+            // Message wil be gagged, but still call error() to update global.errors and for
+            // -verrors=spec
+            .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+            return true;
+        }
+        return false;
+    }
+
+    return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2);
+}
+
+/***************************************
+ * Like `setUnsafe`, but for safety errors still behind preview switches
+ *
+ * Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
+ * the behavior changes based on the setting:
+ *
+ * - In case of `-revert=fs`, it does nothing.
+ * - In case of `-preview=fs`, it's the same as `setUnsafe`
+ * - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
+ *
+ * Params:
+ *   sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
+ *   fs = feature state from the preview flag
+ *   gag = surpress error message
+ *   loc = location of error
+ *   msg = printf-style format string
+ *   arg0  = (optional) argument for first %s format specifier
+ *   arg1  = (optional) argument for second %s format specifier
+ *   arg2  = (optional) argument for third %s format specifier
+ * Returns: whether an actual safe error (not deprecation) occured
+ */
+bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg,
+    RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
+{
+    //printf("setUnsafePreview() fs:%d %s\n", fs, msg);
+    with (FeatureState) final switch (fs)
+    {
+      case disabled:
+        return false;
+
+      case enabled:
+        return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);
+
+      case default_:
+        if (!sc.func)
+            return false;
+        if (sc.func.isSafeBypassingInference())
+        {
+            if (!gag && !sc.isDeprecated())
+            {
+                deprecation(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+            }
+        }
+        else if (!sc.func.safetyViolation)
+        {
+            import dmd.func : AttributeViolation;
+            sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
+        }
+        return false;
+    }
+}
index af7b1fa371d0afdf82abbfb9f582b50f88037f1b..c97aeb6d4d08fa86f37be0ca4eeca88100a7b3d3 100644 (file)
@@ -40,24 +40,6 @@ enum DiagnosticReporting : ubyte
     off,          /// disable diagnostic
 }
 
-/// In which context checks for assertions, contracts, bounds checks etc. are enabled
-enum CHECKENABLE : ubyte
-{
-    _default,     /// initial value
-    off,          /// never do checking
-    on,           /// always do checking
-    safeonly,     /// do checking only in @safe functions
-}
-
-/// What should happend when an assertion fails
-enum CHECKACTION : ubyte
-{
-    D,            /// call D assert on failure
-    C,            /// call C assert on failure
-    halt,         /// cause program halt on failure
-    context,      /// call D assert with the error context on failure
-}
-
 /**
 Each flag represents a field that can be included in the JSON output.
 
@@ -90,6 +72,16 @@ enum FeatureState : ubyte
     enabled  = 2,  /// Specified as `-preview=`
 }
 
+/// Different identifier tables specifiable by CLI
+enum CLIIdentifierTable : ubyte
+{
+    default_ = 0, /// Not specified by user
+    C99      = 1, /// Tables from C99 standard
+    C11      = 2, /// Tables from C11 standard
+    UAX31    = 3, /// Tables from the Unicode Standard Annex 31: UNICODE IDENTIFIERS AND SYNTAX
+    All      = 4, /// The least restrictive set of all other tables
+}
+
 extern(C++) struct Output
 {
     bool doOutput;      // Output is enabled
@@ -217,6 +209,9 @@ extern (C++) struct Param
 
     CHECKACTION checkAction = CHECKACTION.D; // action to take when bounds, asserts or switch defaults are violated
 
+    CLIIdentifierTable dIdentifierTable = CLIIdentifierTable.default_;
+    CLIIdentifierTable cIdentifierTable = CLIIdentifierTable.default_;
+
     const(char)[] argv0;                // program name
     Array!(const(char)*) modFileAliasStrings; // array of char*'s of -I module filename alias strings
     Array!(const(char)*) imppath;       // array of char*'s of where to look for import modules
@@ -289,6 +284,7 @@ extern (C++) struct Global
 
     Param params;           /// command line parameters
     uint errors;            /// number of errors reported so far
+    uint deprecations;      /// number of deprecations reported so far
     uint warnings;          /// number of warnings reported so far
     uint gag;               /// !=0 means gag reporting of errors & warnings
     uint gaggedErrors;      /// number of errors reported while gagged
index f553ae6d8a9e7466fd64102825c3907cbe301c43..bd28d7be7b8be638865d254554a081c061980d2d 100644 (file)
@@ -13,6 +13,7 @@
 #include "root/dcompat.h"
 #include "root/ctfloat.h"
 #include "common/outbuffer.h"
+#include "common/charactertables.h"
 #include "root/filename.h"
 #include "compiler.h"
 
@@ -82,6 +83,16 @@ enum class FeatureState : unsigned char
     enabled  = 2,  /// Specified as `-preview=`
 };
 
+/// Different identifier tables specifiable by CLI
+enum class CLIIdentifierTable : unsigned char
+{
+    default_ = 0, /// Not specified by user
+    C99      = 1, /// Tables from C99 standard
+    C11      = 2, /// Tables from C11 standard
+    UAX31    = 3, /// Tables from the Unicode Standard Annex 31: UNICODE IDENTIFIERS AND SYNTAX
+    All      = 4, /// The least restrictive set of all other tables
+};
+
 struct Output
 {
     /// Configuration for the compiler generator
@@ -200,6 +211,9 @@ struct Param
 
     CHECKACTION checkAction;       // action to take when bounds, asserts or switch defaults are violated
 
+    CLIIdentifierTable dIdentifierTable;
+    CLIIdentifierTable cIdentifierTable;
+
     DString  argv0;    // program name
     Array<const char *> modFileAliasStrings; // array of char*'s of -I module filename alias strings
     Array<const char *> imppath;     // array of char*'s of where to look for import modules
@@ -274,6 +288,9 @@ struct CompileEnv
     DString timestamp;
     d_bool previewIn;
     d_bool ddocOutput;
+    d_bool masm;
+    IdentifierCharLookup cCharLookupTable;
+    IdentifierCharLookup dCharLookupTable;
 };
 
 struct Global
@@ -290,6 +307,7 @@ struct Global
 
     Param params;
     unsigned errors;         // number of errors reported so far
+    unsigned deprecations;   // number of deprecations reported so far
     unsigned warnings;       // number of warnings reported so far
     unsigned gag;            // !=0 means gag reporting of errors & warnings
     unsigned gaggedErrors;   // number of errors reported while gagged
index 5ad324d60527d94f9dfc637b1215e62e96415157..6dbc60b020ccc64d84fc653a8b2088c548562e45 100644 (file)
@@ -448,6 +448,8 @@ immutable Msgtable[] msgtable =
     { "outp"},
     { "outpl"},
     { "outpw"},
+    { "builtinsModuleName", "builtins" },
+    { "ctfeWrite", "__ctfeWrite" },
 
     // Traits
     { "isAbstractClass" },
@@ -529,6 +531,9 @@ immutable Msgtable[] msgtable =
     { "udaMustUse", "mustuse" },
     { "udaStandalone", "standalone" },
 
+    // Editions
+    { "__edition_latest_do_not_use", },
+
     // C names, for undefined identifier error messages
     { "NULL" },
     { "TRUE" },
@@ -553,7 +558,7 @@ immutable Msgtable[] msgtable =
     { "_align", "align" },
     { "aligned" },
     { "__pragma", "pragma" },
-    { "builtins", "__builtins" },
+    { "importc_builtins", "__importc_builtins" },
     { "builtin_va_list", "__builtin_va_list" },
     { "builtin_va_arg", "__builtin_va_arg" },
     { "va_list_tag", "__va_list_tag" },
index 8ace310937db9ef47190f5661b97aef1db1850df..6fd0d3ad5ec6bde95c839c9b24791390c1bfd80f 100644 (file)
@@ -269,12 +269,12 @@ nothrow:
     /********************************************
      * Create an identifier in the string table.
      */
-    static Identifier idPool(const(char)* s, uint len)
+    static Identifier idPool(scope const(char)* s, uint len)
     {
         return idPool(s[0 .. len]);
     }
 
-    extern (D) static Identifier idPool(const(char)[] s, bool isAnonymous = false)
+    extern (D) static Identifier idPool(scope const(char)[] s, bool isAnonymous = false)
     {
         auto sv = stringtable.update(s);
         auto id = sv.value;
@@ -292,7 +292,7 @@ nothrow:
      *  s = string for keyword
      *  value = TOK.xxxx for the keyword
      */
-    extern (D) static void idPool(const(char)[] s, TOK value)
+    extern (D) static void idPool(scope const(char)[] s, TOK value)
     {
         auto sv = stringtable.insert(s, null);
         assert(sv);
@@ -315,28 +315,83 @@ nothrow:
     /**********************************
      * ditto
      */
-    extern (D) static bool isValidIdentifier(const(char)[] str) @safe
+    extern (D) static bool isValidIdentifier(const(char)[] str) @trusted
     {
+        import dmd.common.charactertables;
+
         if (str.length == 0 ||
             (str[0] >= '0' && str[0] <= '9')) // beware of isdigit() on signed chars
         {
             return false;
         }
 
-        size_t idx = 0;
-        while (idx < str.length)
+        // In a previous implementation this was implemented quite naively,
+        //  by utilizing the libc.
+        // However we can do better, by copying the lexer approach to identifier validation.
+
+        const(char)* p = &str[0], pEnd = str.ptr + str.length;
+
+        // handle start characters
         {
-            dchar dc;
-            const s = utf_decodeChar(str, idx, dc);
-            if (s ||
-                !((dc >= 0x80 && isUniAlpha(dc)) || isalnum(dc) || dc == '_'))
+            const c = *p;
+
+            if (isidchar(c))
+                p++;
+            else if (c & 0x80)
             {
+                size_t countDecoded;
+                dchar decoded;
+
+                if (utf_decodeChar(p[0 .. pEnd - p], countDecoded, decoded) is null ||
+                    isAnyStart(decoded))
+                    p += countDecoded;
+                else
+                    return false;
+            }
+            else
                 return false;
+        }
+
+        // handle continue characters
+        while(p !is pEnd)
+        {
+            const c = *p;
+
+            if (isidchar(c)) // handles ASCII subset
+            {
+                p++;
+                continue;
             }
+            else if (c & 0x80)
+            {
+                size_t countDecoded;
+                dchar decoded;
+
+                if (utf_decodeChar(p[0 .. pEnd - p], countDecoded, decoded) is null ||
+                    isAnyContinue(decoded))
+                {
+                    p += countDecoded;
+                    continue;
+                }
+                else
+                    return false;
+            }
+            else
+                return false;
         }
+
         return true;
     }
 
+    ///
+    unittest
+    {
+        assert(Identifier.isValidIdentifier("tes123_t".ptr));
+        assert(!Identifier.isValidIdentifier("tes123_^t".ptr));
+        assert(Identifier.isValidIdentifier("te123s_ÄŸt".ptr));
+        assert(!Identifier.isValidIdentifier("t^e123s_ÄŸt".ptr));
+    }
+
     extern (D) static Identifier lookup(const(char)* s, size_t len)
     {
         return lookup(s[0 .. len]);
index 62bd41eea9382d0fba0da3d9771f3fcd3f3c7cbd..7d9e3e6033d8ff1193c8b03d997239b02ae68f3c 100644 (file)
@@ -51,38 +51,38 @@ extern (C++) class Initializer : ASTNode
         this.kind = kind;
     }
 
-    final inout(ErrorInitializer) isErrorInitializer() inout @nogc nothrow pure
+    final inout(ErrorInitializer) isErrorInitializer() inout @nogc nothrow pure @trusted
     {
         // Use void* cast to skip dynamic casting call
         return kind == InitKind.error ? cast(inout ErrorInitializer)cast(void*)this : null;
     }
 
-    final inout(VoidInitializer) isVoidInitializer() inout @nogc nothrow pure
+    final inout(VoidInitializer) isVoidInitializer() inout @nogc nothrow pure @trusted
     {
         return kind == InitKind.void_ ? cast(inout VoidInitializer)cast(void*)this : null;
     }
 
-    final inout(DefaultInitializer) isDefaultInitializer() inout @nogc nothrow pure
+    final inout(DefaultInitializer) isDefaultInitializer() inout @nogc nothrow pure @trusted
     {
         return kind == InitKind.default_ ? cast(inout DefaultInitializer)cast(void*)this : null;
     }
 
-    final inout(StructInitializer) isStructInitializer() inout @nogc nothrow pure
+    final inout(StructInitializer) isStructInitializer() inout @nogc nothrow pure @trusted
     {
         return kind == InitKind.struct_ ? cast(inout StructInitializer)cast(void*)this : null;
     }
 
-    final inout(ArrayInitializer) isArrayInitializer() inout @nogc nothrow pure
+    final inout(ArrayInitializer) isArrayInitializer() inout @nogc nothrow pure @trusted
     {
         return kind == InitKind.array ? cast(inout ArrayInitializer)cast(void*)this : null;
     }
 
-    final inout(ExpInitializer) isExpInitializer() inout @nogc nothrow pure
+    final inout(ExpInitializer) isExpInitializer() inout @nogc nothrow pure @trusted
     {
         return kind == InitKind.exp ? cast(inout ExpInitializer)cast(void*)this : null;
     }
 
-    final inout(CInitializer) isCInitializer() inout @nogc nothrow pure
+    final inout(CInitializer) isCInitializer() inout @nogc nothrow pure @trusted
     {
         return kind == InitKind.C_ ? cast(inout CInitializer)cast(void*)this : null;
     }
index 2485d78bb59e08f43e9105fa9f486ccbad3739c3..2ee69f622b3582e0df2fe7b28c16683c05c753f4 100644 (file)
@@ -126,6 +126,6 @@ public:
 
 namespace dmd
 {
-    Expression *initializerToExpression(Initializer *init, Type *t = NULL, const bool isCfile = false);
+    Expression *initializerToExpression(Initializer *init, Type *t = nullptr, const bool isCfile = false);
     Initializer *initializerSemantic(Initializer *init, Scope *sc, Type *&tx, NeedInterpret needInterpret);
 }
index b07699e19fe27d9ec97e4a9c0bdde80fbc3c4c84..8faad30f53918d46a464c6079a3f18a7b08f3d22 100644 (file)
@@ -868,11 +868,13 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
                          * by the initializer syntax. if a CInitializer has a Designator, it is probably
                          * a nested anonymous struct
                          */
-                        if (cix.initializerList.length)
+                        int found;
+                        foreach (dix; cix.initializerList)
                         {
-                            DesigInit dix = cix.initializerList[0];
                             Designators* dlistx = dix.designatorList;
-                            if (dlistx && (*dlistx).length == 1 && (*dlistx)[0].ident)
+                            if (!dlistx)
+                                continue;
+                            if ((*dlistx).length == 1 && (*dlistx)[0].ident)
                             {
                                 auto id = (*dlistx)[0].ident;
                                 foreach (k, f; sd.fields[])         // linear search for now
@@ -883,11 +885,18 @@ Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
                                         si.addInit(id, dix.initializer);
                                         ++fieldi;
                                         ++index;
-                                        continue Loop1;
+                                        ++found;
+                                        break;
                                     }
                                 }
                             }
+                            else {
+                                error(ci.loc, "only 1 designator currently allowed for C struct field initializer `%s`", toChars(ci));
+                            }
                         }
+
+                        if (found == cix.initializerList.length)
+                            continue Loop1;
                     }
 
                     VarDeclaration field;
index c9c506e9cf3c147a56302049f04312ce44ef4438..26a56c2b1fd1cedcefdd396eacc0ba9cec05c1ef 100644 (file)
@@ -22,9 +22,11 @@ import dmd.errorsink;
 import dmd.id;
 import dmd.identifier;
 import dmd.location;
+import dmd.common.smallbuffer;
+import dmd.common.outbuffer;
+import dmd.common.charactertables;
 import dmd.root.array;
 import dmd.root.ctfloat;
-import dmd.common.outbuffer;
 import dmd.root.port;
 import dmd.root.rmem;
 import dmd.root.utf;
@@ -42,6 +44,8 @@ version (DMDLIB)
  */
 struct CompileEnv
 {
+    import dmd.common.charactertables;
+
     uint versionNumber;      /// __VERSION__
     const(char)[] date;      /// __DATE__
     const(char)[] time;      /// __TIME__
@@ -51,6 +55,10 @@ struct CompileEnv
     bool previewIn;          /// `in` means `[ref] scope const`, accepts rvalues
     bool ddocOutput;         /// collect embedded documentation comments
     bool masm;               /// use MASM inline asm syntax
+
+    // these need a default otherwise tests won't work.
+    IdentifierCharLookup cCharLookupTable; /// C identifier table (set to the lexer by the C parser)
+    IdentifierCharLookup dCharLookupTable; /// D identifier table
 }
 
 /***********************************************************
@@ -66,6 +74,8 @@ class Lexer
 
     Token token;
 
+    IdentifierCharLookup charLookup; /// Character table for identifiers
+
     // For ImportC
     bool Ccompile;              /// true if compiling ImportC
 
@@ -142,6 +152,8 @@ class Lexer
         {
             this.compileEnv.versionNumber = 1;
             this.compileEnv.vendor = "DLF";
+            this.compileEnv.cCharLookupTable = IdentifierCharLookup.forTable(IdentifierTable.LR);
+            this.compileEnv.dCharLookupTable = IdentifierCharLookup.forTable(IdentifierTable.LR);
         }
         //initKeywords();
         /* If first line starts with '#!', ignore the line
@@ -175,6 +187,11 @@ class Lexer
             }
             endOfLine();
         }
+
+        // setup the identifier table lookup functions
+        // C tables are setup in its parser constructor
+        // Due to us not knowing if we're in C at this point in time.
+        charLookup = this.compileEnv.dCharLookupTable;
     }
 
     /***********************
@@ -306,6 +323,8 @@ class Lexer
         t.blockComment = null;
         t.lineComment = null;
 
+        size_t universalCharacterName4, universalCharacterName8;
+
         while (1)
         {
             t.ptr = p;
@@ -395,10 +414,35 @@ class Lexer
                 continue; // skip white space
 
             case '\\':
-                if (Ccompile && (p[1] == '\r' || p[1] == '\n'))
+                if (Ccompile)
                 {
-                    ++p; // ignore \ followed by new line, like VC does
-                    continue;
+                    if (p[1] == '\r' || p[1] == '\n')
+                    {
+                        ++p; // ignore \ followed by new line, like VC does
+                        continue;
+                    }
+                    else if (p[1] == 'u')
+                    {
+                        // Universal Character Name (C) 2 byte
+                        // \uXXXX
+                        // let the main case handling for identifiers process this
+
+                        // case_indent will always increment, so subtract to prevent branching on the fast path
+                        p--;
+
+                        goto case_ident;
+                    }
+                    else if (p[1] == 'U')
+                    {
+                        // Universal Character Name (C) 4 byte
+                        // \UXXXXXXXX
+                        // let the main case handling for identifiers process this
+
+                        // case_indent will always increment, so subtract to prevent branching on the fast path
+                        p--;
+
+                        goto case_ident;
+                    }
                 }
                 goto default;
 
@@ -586,23 +630,161 @@ class Lexer
             case '_':
             case_ident:
                 {
-                    while (1)
+        IdentLoop: while (1)
                     {
+                        // If this is changed, change the decrement in C's universal character name code above
+                        // For syntax \uXXXX and \UXXXXXXXX
                         const c = *++p;
+
+                        // Is this the first character of the identifier
+                        // For the universal character name this will line up,
+                        //  for the main switch it won't since it wasn't the first,
+                        //  for the default it won't either because a decode increments.
+                        const isStartCharacter = t.ptr is p;
+
                         if (isidchar(c))
                             continue;
                         else if (c & 0x80)
                         {
                             const s = p;
                             const u = decodeUTF();
-                            if (isUniAlpha(u))
-                                continue;
-                            error(t.loc, "char 0x%04x not allowed in identifier", u);
+
+                            if (isStartCharacter)
+                            {
+                                if (charLookup.isStart(u))
+                                    continue;
+                                error(t.loc, "character 0x%04x is not allowed as a start character in an identifier", u);
+                            }
+                            else
+                            {
+                                if (charLookup.isContinue(u))
+                                    continue;
+                                error(t.loc, "character 0x%04x is not allowed as a continue character in an identifier", u);
+                            }
+
                             p = s;
                         }
+                        else if (Ccompile && c == '\\')
+                        {
+                            uint times;
+                            const s = p;
+                            p++;
+
+                            if (*p == 'u')
+                            {
+                                // Universal Character Name (C) 2 byte
+                                // \uXXXX
+                                p++;
+                                times = 4;
+                            }
+                            else if (*p == 'U')
+                            {
+                                // Universal Character Name (C) 4 byte
+                                // \UXXXXXXXX
+                                p++;
+                                times = 8;
+                            }
+                            else
+                            {
+                                error(t.loc, "char 0x%x is not allowed to follow '\\' expecting a C universal character name in format \\uXXXX or \\UXXXXXXXX with hex digits instead of X with invalid u/U", *p);
+                                p = s;
+                                break;
+                            }
+
+                            foreach(_; 0 .. times)
+                            {
+                                const hc = *p;
+                                p++;
+
+                                if ((hc >= '0' && hc <= '9') || (hc >= 'a' && hc <= 'f') || (hc >= 'A' && hc <= 'F'))
+                                    continue;
+
+                                error(t.loc, "char 0x%x is not allowed to follow '\\' expecting a C universal character name in format \\uXXXX or \\UXXXXXXXX with hex digits instead of X with invalid hex digit", hc);
+                                p = s;
+                                break IdentLoop;
+                            }
+
+                            continue;
+                        }
                         break;
                     }
-                    Identifier id = Identifier.idPool((cast(char*)t.ptr)[0 .. p - t.ptr], false);
+
+                    Identifier id;
+
+                    if (universalCharacterName4 > 0 || universalCharacterName8 > 0)
+                    {
+                        auto priorValidation = t.ptr[0 .. p - t.ptr];
+                        const(char)* priorVPtr = priorValidation.ptr;
+                        const possibleLength = (
+                            priorValidation.length - (
+                                (universalCharacterName4 * 6) +
+                                (universalCharacterName8 * 10)
+                            )) + (
+                                (universalCharacterName4 * 3) +
+                                (universalCharacterName8 * 4)
+                            );
+
+                        char[64] buffer = void;
+                        SmallBuffer!char sb = SmallBuffer!char(possibleLength, buffer[]);
+
+                        char[] storage = sb.extent;
+                        size_t offset;
+
+                        while(priorVPtr < &priorValidation[$-1] + 1)
+                        {
+                            if (*priorVPtr == '\\')
+                            {
+                                dchar tempDchar = 0;
+                                uint times;
+
+                                // universal character name (C)
+                                if (priorVPtr[1] == 'u')
+                                    times = 4;
+                                else if (priorVPtr[1] == 'U')
+                                    times = 8;
+                                else
+                                    assert(0, "ICE: Universal character name is 2 or 4 bytes only");
+                                priorVPtr += 2;
+
+                                foreach(_; 0 .. times)
+                                {
+                                    char c = *++priorVPtr;
+                                    if (c >= '0' && c <= '9')
+                                        c -= '0';
+                                    else if (c >= 'a' && c <= 'f')
+                                        c -= 'a' - 10;
+                                    else if (c >= 'A' && c <= 'F')
+                                        c -= 'A' - 10;
+
+                                    tempDchar <<= 4;
+                                    tempDchar |= c;
+                                }
+
+                                utf_encodeChar(&storage[offset], tempDchar);
+                                offset += utf_codeLengthChar(tempDchar);
+
+                                // Could be an error instead of a warning,
+                                //  but hey it was written specifically so why worry?
+                                if (priorVPtr is priorValidation.ptr)
+                                {
+                                    if (!charLookup.isStart(tempDchar))
+                                        warning(t.loc, "char 0x%x is not allowed start character for an identifier", tempDchar);
+                                }
+                                else
+                                {
+                                    if (!charLookup.isContinue(tempDchar))
+                                        warning(t.loc, "char 0x%x is not allowed continue character for an identifier", tempDchar);
+                                }
+                            }
+                            else
+                                storage[offset++] = *++priorVPtr;
+                        }
+
+                        id = Identifier.idPool(storage[0 .. offset], false);
+                    }
+                    else
+                        id = Identifier.idPool((cast(char*)t.ptr)[0 .. p - t.ptr], false);
+
                     t.ident = id;
                     t.value = cast(TOK)id.getValue();
 
@@ -1174,9 +1356,11 @@ class Lexer
                     if (c & 0x80)
                     {
                         c = decodeUTF();
-                        // Check for start of unicode identifier
-                        if (isUniAlpha(c))
+
+                        // Check for start of an identifier
+                        if (charLookup.isStart(c))
                             goto case_ident;
+
                         if (c == PS || c == LS)
                         {
                             endOfLine();
@@ -1688,7 +1872,7 @@ class Lexer
                     delimright = ']';
                 else if (c == '<')
                     delimright = '>';
-                else if (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c)))
+                else if (isalpha(c) || c == '_' || (c >= 0x80 && charLookup.isStart(c)))
                 {
                     // Start of identifier; must be a heredoc
                     Token tok;
@@ -1736,7 +1920,9 @@ class Lexer
                 }
                 else if (c == delimright)
                     goto Ldone;
-                if (startline && (isalpha(c) || c == '_' || (c >= 0x80 && isUniAlpha(c))) && hereid)
+
+                // we're looking for a new identifier token
+                if (startline && (isalpha(c) || c == '_' || (c >= 0x80 && charLookup.isStart(c))) && hereid)
                 {
                     Token tok;
                     auto psave = p;
@@ -2988,6 +3174,11 @@ class Lexer
         eSink.deprecation(loc, format, args);
     }
 
+    void warning(T...)(const ref Loc loc, const(char)* format, T args)
+    {
+        eSink.warning(loc, format, args);
+    }
+
     void deprecation(T...)(const(char)* format, T args)
     {
         eSink.deprecation(token.loc, format, args);
@@ -3416,124 +3607,6 @@ class Lexer
     }
 }
 
-
-/******************************* Private *****************************************/
-
-private:
-
-private enum LS = 0x2028;       // UTF line separator
-private enum PS = 0x2029;       // UTF paragraph separator
-
-/********************************************
- * Do our own char maps
- */
-private static immutable cmtable = ()
-{
-    ubyte[256] table;
-    foreach (const c; 0 .. table.length)
-    {
-        if ('0' <= c && c <= '7')
-            table[c] |= CMoctal;
-        if (c_isxdigit(c))
-            table[c] |= CMhex;
-        if (c_isalnum(c) || c == '_')
-            table[c] |= CMidchar;
-
-        switch (c)
-        {
-            case 'x': case 'X':
-            case 'b': case 'B':
-                table[c] |= CMzerosecond;
-                break;
-
-            case '0': .. case '9':
-            case 'e': case 'E':
-            case 'f': case 'F':
-            case 'l': case 'L':
-            case 'p': case 'P':
-            case 'u': case 'U':
-            case 'i':
-            case '.':
-            case '_':
-                table[c] |= CMzerosecond | CMdigitsecond;
-                break;
-
-            default:
-                break;
-        }
-
-        switch (c)
-        {
-            case '\\':
-            case '\n':
-            case '\r':
-            case 0:
-            case 0x1A:
-            case '\'':
-                break;
-            default:
-                if (!(c & 0x80))
-                    table[c] |= CMsinglechar;
-                break;
-        }
-    }
-    return table;
-}();
-
-private
-{
-    enum CMoctal  = 0x1;
-    enum CMhex    = 0x2;
-    enum CMidchar = 0x4;
-    enum CMzerosecond = 0x8;
-    enum CMdigitsecond = 0x10;
-    enum CMsinglechar = 0x20;
-}
-
-private bool isoctal(const char c) pure @nogc @safe
-{
-    return (cmtable[c] & CMoctal) != 0;
-}
-
-private bool ishex(const char c) pure @nogc @safe
-{
-    return (cmtable[c] & CMhex) != 0;
-}
-
-private bool isidchar(const char c) pure @nogc @safe
-{
-    return (cmtable[c] & CMidchar) != 0;
-}
-
-private bool isZeroSecond(const char c) pure @nogc @safe
-{
-    return (cmtable[c] & CMzerosecond) != 0;
-}
-
-private bool isDigitSecond(const char c) pure @nogc @safe
-{
-    return (cmtable[c] & CMdigitsecond) != 0;
-}
-
-private bool issinglechar(const char c) pure @nogc @safe
-{
-    return (cmtable[c] & CMsinglechar) != 0;
-}
-
-private bool c_isxdigit(const int c) pure @nogc @safe
-{
-    return (( c >= '0' && c <= '9') ||
-            ( c >= 'a' && c <= 'f') ||
-            ( c >= 'A' && c <= 'F'));
-}
-
-private bool c_isalnum(const int c) pure @nogc @safe
-{
-    return (( c >= '0' && c <= '9') ||
-            ( c >= 'a' && c <= 'z') ||
-            ( c >= 'A' && c <= 'Z'));
-}
-
 /******************************* Unittest *****************************************/
 
 unittest
index 379e8e6973aa31c1114450b319d2aee38465a887..7f02bec2f3a0333f5de673ca12a209d67fc3932f 100644 (file)
@@ -28,6 +28,14 @@ enum PKG
     PKGpackage  // already determined that's an actual package
 };
 
+enum class Edition : unsigned char
+{
+    none = 0u,
+    legacy = 1u,
+    v2024 = 2u,
+    latest = 2u,
+};
+
 class Package : public ScopeDsymbol
 {
 public:
@@ -75,6 +83,7 @@ public:
     FileType filetype;  // source file type
     d_bool hasAlwaysInlines; // contains references to functions that must be inlined
     d_bool isPackageFile; // if it is a package.d
+    Edition edition;    // language edition that this module is compiled with
     Package *pkg;       // if isPackageFile is true, the Package that contains this package.d
     Strings contentImportedFiles;  // array of files whose content was imported
     int needmoduleinfo;
index 715ee12159cb927aa19e9aa12d21b98503247738..dcfe183559497f76ea3cb1394ffe048e4596b340 100644 (file)
@@ -1412,7 +1412,7 @@ extern (C++) abstract class Type : ASTNode
      * Returns:
      *  true if so
      */
-    bool hasSystemFields()
+    bool hasUnsafeBitpatterns()
     {
         return false;
     }
@@ -1690,7 +1690,7 @@ extern (C++) abstract class TypeNext : Type
      * type is meant to be inferred, and semantic() hasn't yet ben run
      * on the function. After semantic(), it must no longer be NULL.
      */
-    override final Type nextOf()
+    override final Type nextOf() @safe
     {
         return next;
     }
@@ -2340,6 +2340,11 @@ extern (C++) final class TypeBasic : Type
         }
     }
 
+    override bool hasUnsafeBitpatterns()
+    {
+        return ty == Tbool;
+    }
+
     // For eliminating dynamic_cast
     override TypeBasic isTypeBasic()
     {
@@ -2657,9 +2662,9 @@ extern (C++) final class TypeSArray : TypeArray
         return ae;
     }
 
-    override bool hasSystemFields()
+    override bool hasUnsafeBitpatterns()
     {
-        return next.hasSystemFields();
+        return next.hasUnsafeBitpatterns();
     }
 
     override bool hasVoidInitPointers()
@@ -3170,7 +3175,7 @@ extern (C++) final class TypeFunction : TypeNext
      * Returns:
      *  true if D-style variadic
      */
-    bool isDstyleVariadic() const pure nothrow
+    bool isDstyleVariadic() const pure nothrow @safe
     {
         return linkage == LINK.d && parameterList.varargs == VarArg.variadic;
     }
@@ -3487,7 +3492,7 @@ extern (C++) final class TypeDelegate : TypeNext
  * This is a shell containing a TraitsExp that can be
  * either resolved to a type or to a symbol.
  *
- * The point is to allow AliasDeclarationY to use `__traits()`, see https://issues.dlang.org/show_bug.cgi?id=7804.
+ * The point is to allow AliasDeclarationY to use `__traits()`, see $(LINK https://issues.dlang.org/show_bug.cgi?id=7804).
  */
 extern (C++) final class TypeTraits : Type
 {
@@ -3976,11 +3981,11 @@ extern (C++) final class TypeStruct : Type
         return sym.hasVoidInitPointers;
     }
 
-    override bool hasSystemFields()
+    override bool hasUnsafeBitpatterns()
     {
         sym.size(Loc.initial); // give error for forward references
         sym.determineTypeProperties();
-        return sym.hasSystemFields;
+        return sym.hasUnsafeBitpatterns;
     }
 
     override bool hasInvariant()
@@ -3992,84 +3997,71 @@ extern (C++) final class TypeStruct : Type
 
     extern (D) MATCH implicitConvToWithoutAliasThis(Type to)
     {
-        MATCH m;
+        //printf("TypeStruct::implicitConvToWithoutAliasThis(%s => %s)\n", toChars(), to.toChars());
 
-        if (ty == to.ty && sym == (cast(TypeStruct)to).sym)
+        auto tos = to.isTypeStruct();
+        if (!(tos && sym == tos.sym))
+            return MATCH.nomatch;
+
+        if (mod == to.mod)
+            return MATCH.exact;
+
+        if (MODimplicitConv(mod, to.mod))
+            return MATCH.constant;
+
+        /* Check all the fields. If they can all be converted,
+         * allow the conversion.
+         */
+        MATCH m = MATCH.constant;
+        uint offset = ~0; // must never match a field offset
+        foreach (v; sym.fields[])
         {
-            m = MATCH.exact; // exact match
-            if (mod != to.mod)
-            {
-                m = MATCH.constant;
-                if (MODimplicitConv(mod, to.mod))
-                {
-                }
-                else
-                {
-                    /* Check all the fields. If they can all be converted,
-                     * allow the conversion.
-                     */
-                    uint offset = ~0; // dead-store to prevent spurious warning
-                    for (size_t i = 0; i < sym.fields.length; i++)
-                    {
-                        VarDeclaration v = sym.fields[i];
-                        if (i == 0)
-                        {
-                        }
-                        else if (v.offset == offset)
-                        {
-                            if (m > MATCH.nomatch)
-                                continue;
-                        }
-                        else
-                        {
-                            if (m == MATCH.nomatch)
-                                return m;
-                        }
-
-                        // 'from' type
-                        Type tvf = v.type.addMod(mod);
-
-                        // 'to' type
-                        Type tv = v.type.addMod(to.mod);
-
-                        // field match
-                        MATCH mf = tvf.implicitConvTo(tv);
-                        //printf("\t%s => %s, match = %d\n", v.type.toChars(), tv.toChars(), mf);
-
-                        if (mf == MATCH.nomatch)
-                            return mf;
-                        if (mf < m) // if field match is worse
-                            m = mf;
-                        offset = v.offset;
-                    }
-                }
-            }
+            /* Why are we only looking at the first member of a union?
+             * The check should check for overlap of v with the previous field,
+             * not just starting at the same point
+             */
+            if (v.offset == offset) // v is at same offset as previous field
+                continue;       // ignore
+
+            Type tvf = v.type.addMod(mod);    // from type
+            Type tvt  = v.type.addMod(to.mod); // to type
+
+            // field match
+            MATCH mf = tvf.implicitConvTo(tvt);
+            //printf("\t%s => %s, match = %d\n", v.type.toChars(), tvt.toChars(), mf);
+
+            if (mf == MATCH.nomatch)
+                return MATCH.nomatch;
+            if (mf < m) // if field match is worse
+                m = mf;
+            offset = v.offset;
         }
         return m;
     }
 
     extern (D) MATCH implicitConvToThroughAliasThis(Type to)
     {
-        MATCH m;
-        if (!(ty == to.ty && sym == (cast(TypeStruct)to).sym) && sym.aliasthis && !(att & AliasThisRec.tracing))
+        auto tos = to.isTypeStruct();
+        if (!(tos && sym == tos.sym) &&
+            sym.aliasthis &&
+            !(att & AliasThisRec.tracing))
         {
             if (auto ato = aliasthisOf(this))
             {
                 att = cast(AliasThisRec)(att | AliasThisRec.tracing);
-                m = ato.implicitConvTo(to);
+                MATCH m = ato.implicitConvTo(to);
                 att = cast(AliasThisRec)(att & ~AliasThisRec.tracing);
+                return m;
             }
-            else
-                m = MATCH.nomatch; // no match
         }
-        return m;
+        return MATCH.nomatch;
     }
 
     override MATCH implicitConvTo(Type to)
     {
         //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to.toChars());
         MATCH m = implicitConvToWithoutAliasThis(to);
-        return m ? m : implicitConvToThroughAliasThis(to);
+        return m == MATCH.nomatch ? implicitConvToThroughAliasThis(to) : m;
     }
 
     override MATCH constConv(Type to)
@@ -4252,9 +4244,9 @@ extern (C++) final class TypeEnum : Type
         return memType().hasVoidInitPointers();
     }
 
-    override bool hasSystemFields()
+    override bool hasUnsafeBitpatterns()
     {
-        return memType().hasSystemFields();
+        return memType().hasUnsafeBitpatterns();
     }
 
     override bool hasInvariant()
index ad64b120f400cf41ee6dbdbd77658664f66bda11..1121711a99fa6ecfb26a2169e3b0283a89cb1509 100644 (file)
@@ -276,7 +276,7 @@ public:
     virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0
     virtual int hasWild() const;
     virtual bool hasVoidInitPointers();
-    virtual bool hasSystemFields();
+    virtual bool hasUnsafeBitpatterns();
     virtual bool hasInvariant();
     virtual Type *nextOf();
     Type *baseElemOf();
@@ -421,7 +421,7 @@ public:
     MATCH constConv(Type *to) override;
     MATCH implicitConvTo(Type *to) override;
     Expression *defaultInitLiteral(const Loc &loc) override;
-    bool hasSystemFields() override;
+    bool hasUnsafeBitpatterns() override;
     bool hasVoidInitPointers() override;
     bool hasInvariant() override;
     bool needsDestruction() override;
@@ -739,7 +739,7 @@ public:
     bool needsCopyOrPostblit() override;
     bool needsNested() override;
     bool hasVoidInitPointers() override;
-    bool hasSystemFields() override;
+    bool hasUnsafeBitpatterns() override;
     bool hasInvariant() override;
     MATCH implicitConvTo(Type *to) override;
     MATCH constConv(Type *to) override;
@@ -775,7 +775,7 @@ public:
     MATCH constConv(Type *to) override;
     bool isZeroInit(const Loc &loc) override;
     bool hasVoidInitPointers() override;
-    bool hasSystemFields() override;
+    bool hasUnsafeBitpatterns() override;
     bool hasInvariant() override;
     Type *nextOf() override;
 
@@ -877,7 +877,7 @@ namespace dmd
     // return the symbol to which type t resolves
     Dsymbol *toDsymbol(Type *t, Scope *sc);
     bool equivalent(Type *src, Type *t);
-    Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false);
+    Covariant covariant(Type *, Type *, StorageClass * = nullptr, bool = false);
     bool isBaseOf(Type *tthis, Type *t, int *poffset);
     Type *trySemantic(Type *type, const Loc &loc, Scope *sc);
     Type *pointerTo(Type *type);
index c2fa5fbd02370633d0da86b517a3143b09b583ee..fc7618bfc0ed9378686383ba90bbe51f5447ad1f 100644 (file)
@@ -202,7 +202,7 @@ private bool isIncrementOrDecrement(Expression e)
  */
 private bool hasMustUseAttribute(Dsymbol sym, Scope* sc)
 {
-    import dmd.attrib : foreachUda;
+    import dmd.attribsem : foreachUda;
 
     bool result = false;
 
index 0a5981589c6f12458a13dc52b1fd8c5e7b0f7f83..756caf870bcb3a81cf9286bdd6741a0bede6667c 100644 (file)
@@ -7,6 +7,9 @@
  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ob.d, _ob.d)
  * Documentation:  https://dlang.org/phobos/dmd_escape.html
  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ob.d
+ * Bug reports: use 'live' keyword:
+ *              https://issues.dlang.org/buglist.cgi?bug_status=NEW&bug_status=REOPENED&keywords=live
+ * References:  https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md Argument Ownership and Function Calls
  */
 
 module dmd.ob;
@@ -32,6 +35,7 @@ import dmd.expression;
 import dmd.foreachvar;
 import dmd.func;
 import dmd.globals;
+import dmd.hdrgen;
 import dmd.identifier;
 import dmd.init;
 import dmd.location;
@@ -40,6 +44,7 @@ import dmd.printast;
 import dmd.statement;
 import dmd.stmtstate;
 import dmd.tokens;
+import dmd.typesem;
 import dmd.visitor;
 
 import dmd.root.bitarray;
@@ -226,6 +231,8 @@ struct PtrVarState
      * are being merged
      * Params:
      *  pvs = path to be merged with `this`
+     *  vi = variable's index into gen[]
+     *  gen = array of variable states
      */
     void combine(ref PtrVarState pvs, size_t vi, PtrVarState[] gen)
     {
@@ -280,6 +287,9 @@ struct PtrVarState
     }
 
     /***********************
+     * Print a bracketed list of all the variables that depend on 'this'
+     * Params:
+     *  vars = variables that depend on 'this'
      */
     void print(VarDeclaration[] vars)
     {
@@ -846,7 +856,7 @@ void toObNodes(ref ObNodes obnodes, Statement s)
             case STMT.Mixin:
             case STMT.Peel:
             case STMT.Synchronized:
-                debug printf("s: %s\n", s.toChars());
+                debug printf("s: %s\n", toChars(s));
                 assert(0);              // should have been rewritten
         }
     }
@@ -1113,8 +1123,8 @@ bool isTrackableVar(VarDeclaration v)
     /* Assume types with a destructor are doing their own tracking,
      * such as being a ref counted type
      */
-    if (v.needsScopeDtor())
-        return false;
+//    if (v.needsScopeDtor())
+//        return false;
 
     /* Not tracking function parameters that are not mutable
      */
@@ -1231,7 +1241,8 @@ void allocStates(ref ObState obstate)
  */
 bool isBorrowedPtr(VarDeclaration v)
 {
-    return v.isScope() && !v.isowner && v.type.nextOf().isMutable();
+    return v.isScope() && !v.isowner &&
+        v.type.hasPointersToMutableFields();
 }
 
 /******************************
@@ -1241,7 +1252,7 @@ bool isBorrowedPtr(VarDeclaration v)
  */
 bool isReadonlyPtr(VarDeclaration v)
 {
-    return v.isScope() && !v.type.nextOf().isMutable();
+    return v.isScope() && !v.type.hasPointersToMutableFields();
 }
 
 /***************************************
@@ -1251,7 +1262,7 @@ void genKill(ref ObState obstate, ObNode* ob)
 {
     enum log = false;
     if (log)
-        printf("-----------computeGenKill()-----------\n");
+        printf("-----------computeGenKill() %d -----------\n", ob.index);
 
     /***************
      * Assigning result of expression `e` to variable `v`.
@@ -1274,8 +1285,6 @@ void genKill(ref ObState obstate, ObNode* ob)
                 pvs.state = PtrState.Owner;
             pvs.deps.zero();
 
-            EscapeByResults er;
-            escapeByValue(e, &er, true);
             bool any = false;           // if any variables are assigned to v
 
             void by(VarDeclaration r)
@@ -1305,10 +1314,7 @@ void genKill(ref ObState obstate, ObNode* ob)
                 }
             }
 
-            foreach (VarDeclaration v2; er.byvalue)
-                by(v2);
-            foreach (VarDeclaration v2; er.byref)
-                by(v2);
+            escapeLive(e, &by);
 
             /* Make v an Owner for initializations like:
              *    scope v = malloc();
@@ -1435,6 +1441,41 @@ void genKill(ref ObState obstate, ObNode* ob)
                     assert(t.ty == Tdelegate);
                     tf = t.nextOf().isTypeFunction();
                     assert(tf);
+
+                }
+
+                if (auto dve = ce.e1.isDotVarExp())
+                {
+                    if (!t.isTypeDelegate() && dve.e1.isVarExp())
+                    {
+                        //printf("dve: %s\n", dve.toChars());
+
+                        void byf(VarDeclaration v)
+                        {
+                            //printf("byf v: %s\n", v.ident.toChars());
+                            if (!isTrackableVar(v))
+                                return;
+
+                            const vi = obstate.vars.find(v);
+                            if (vi == size_t.max)
+                                return;
+
+                            auto fd = dve.var.isFuncDeclaration();
+                            if (fd && fd.storage_class & STC.scope_)
+                            {
+                                // borrow
+                                obstate.varStack.push(vi);
+                                obstate.mutableStack.push(isMutableRef(dve.e1.type.toBasetype()));
+                            }
+                            else
+                            {
+                                // move (i.e. consume arg)
+                                makeUndefined(vi, ob.gen);
+                            }
+                        }
+
+                        escapeLive(dve.e1, &byf);
+                    }
                 }
 
                 // j=1 if _arguments[] is first argument
@@ -1450,14 +1491,13 @@ void genKill(ref ObState obstate, ObNode* ob)
                         Parameter p = tf.parameterList[i - j];
                         auto pt = p.type.toBasetype();
 
-                        EscapeByResults er;
-                        escapeByValue(arg, &er, true);
 
                         if (!(p.storageClass & STC.out_ && arg.isVarExp()))
                             arg.accept(this);
 
                         void by(VarDeclaration v)
                         {
+                            //printf("by v: %s\n", v.ident.toChars());
                             if (!isTrackableVar(v))
                                 return;
 
@@ -1484,18 +1524,12 @@ void genKill(ref ObState obstate, ObNode* ob)
                             }
                         }
 
-                        foreach (VarDeclaration v2; er.byvalue)
-                            by(v2);
-                        foreach (VarDeclaration v2; er.byref)
-                            by(v2);
+                        escapeLive(arg, &by);
                     }
                     else // variadic args
                     {
                         arg.accept(this);
 
-                        EscapeByResults er;
-                        escapeByValue(arg, &er, true);
-
                         void byv(VarDeclaration v)
                         {
                             if (!isTrackableVar(v))
@@ -1517,10 +1551,7 @@ void genKill(ref ObState obstate, ObNode* ob)
                                 makeUndefined(vi, ob.gen);
                         }
 
-                        foreach (VarDeclaration v2; er.byvalue)
-                            byv(v2);
-                        foreach (VarDeclaration v2; er.byref)
-                            byv(v2);
+                        escapeLive(arg, &byv);
                     }
                 }
 
@@ -1721,6 +1752,15 @@ void genKill(ref ObState obstate, ObNode* ob)
     }
 
     foreachExp(ob, ob.exp);
+
+    if (log)
+    {
+        printf("  gen:\n");
+        foreach (i, ref pvs2; ob.gen[])
+        {
+            printf("    %s: ", obstate.vars[i].toChars()); pvs2.print(obstate.vars[]);
+        }
+    }
 }
 
 /***************************************
@@ -1945,6 +1985,25 @@ void doDataFlowAnalysis(ref ObState obstate)
 }
 
 
+/***************************************
+ * Check for escaping variables using DIP1000's `escapeByValue`, with `live` set to `true`
+ * Params:
+ *   e = expression to check
+ *   onVar = gets called for each variable escaped through `e`, either by value or by ref
+ */
+void escapeLive(Expression e, scope void delegate(VarDeclaration) onVar)
+{
+    scope EscapeByResults er = EscapeByResults(
+        (VarDeclaration v, bool) => onVar(v),
+        onVar,
+        (FuncDeclaration f, bool) {},
+        (Expression e, bool) {},
+        true,
+    );
+
+    escapeByValue(e, er, true);
+}
+
 /***************************************
  * Check for Ownership/Borrowing errors.
  */
@@ -1976,8 +2035,6 @@ void checkObErrors(ref ObState obstate)
             }
             pvs.deps.zero();
 
-            EscapeByResults er;
-            escapeByValue(e, &er, true);
 
             void by(VarDeclaration r)   // `v` = `r`
             {
@@ -2015,10 +2072,7 @@ void checkObErrors(ref ObState obstate)
                 }
             }
 
-            foreach (VarDeclaration v2; er.byvalue)
-                by(v2);
-            foreach (VarDeclaration v2; er.byref)
-                by(v2);
+            escapeLive(e, &by);
         }
         else
         {
@@ -2157,8 +2211,6 @@ void checkObErrors(ref ObState obstate)
                         if (!(p.storageClass & STC.out_ && arg.isVarExp()))
                             arg.accept(this);
 
-                        EscapeByResults er;
-                        escapeByValue(arg, &er, true);
 
                         void by(VarDeclaration v)
                         {
@@ -2192,18 +2244,11 @@ void checkObErrors(ref ObState obstate)
                             }
                         }
 
-                        foreach (VarDeclaration v2; er.byvalue)
-                            by(v2);
-                        foreach (VarDeclaration v2; er.byref)
-                            by(v2);
+                        escapeLive(arg, &by);
                     }
                     else // variadic args
                     {
                         arg.accept(this);
-
-                        EscapeByResults er;
-                        escapeByValue(arg, &er, true);
-
                         void byv(VarDeclaration v)
                         {
                             if (!isTrackableVar(v))
@@ -2231,10 +2276,7 @@ void checkObErrors(ref ObState obstate)
                             }
                         }
 
-                        foreach (VarDeclaration v2; er.byvalue)
-                            byv(v2);
-                        foreach (VarDeclaration v2; er.byref)
-                            byv(v2);
+                        escapeLive(arg, &byv);
                     }
                 }
 
@@ -2460,7 +2502,7 @@ void checkObErrors(ref ObState obstate)
     {
         static if (log)
         {
-            printf("%d: %s\n", obi, ob.exp ? ob.exp.toChars() : "".ptr);
+            printf("%d: %s\n", cast(int) obi, ob.exp ? ob.exp.toChars() : "".ptr);
             printf("  input:\n");
             foreach (i, ref pvs; ob.input[])
             {
@@ -2490,7 +2532,9 @@ void checkObErrors(ref ObState obstate)
                     if (s1 != s2 && (s1 == PtrState.Owner || s2 == PtrState.Owner))
                     {
                         auto v = obstate.vars[i];
-                        .error(ob.exp ? ob.exp.loc : v.loc, "%s `%s` is both %s and %s", v.kind, v.toPrettyChars, PtrStateToChars(s1), PtrStateToChars(s2));
+                        // Don't worry about non-pointers
+                        if (hasPointers(v.type))
+                            .error(ob.exp ? ob.exp.loc : v.loc, "%s `%s` is both %s and %s", v.kind, v.toPrettyChars, PtrStateToChars(s1), PtrStateToChars(s2));
                     }
                     pvs1.combine(*pvs2, i, ob.gen);
                 }
@@ -2522,9 +2566,6 @@ void checkObErrors(ref ObState obstate)
 
         if (ob.obtype == ObType.retexp)
         {
-            EscapeByResults er;
-            escapeByValue(ob.exp, &er, true);
-
             void by(VarDeclaration r)   // `r` is the rvalue
             {
                 const ri = obstate.vars.find(r);
@@ -2552,11 +2593,7 @@ void checkObErrors(ref ObState obstate)
                     }
                 }
             }
-
-            foreach (VarDeclaration v2; er.byvalue)
-                by(v2);
-            foreach (VarDeclaration v2; er.byref)
-                by(v2);
+            escapeLive(ob.exp, &by);
         }
 
         if (ob.obtype == ObType.return_ || ob.obtype == ObType.retexp)
@@ -2649,6 +2686,9 @@ void makeChildrenUndefined(size_t vi, PtrVarState[] gen)
 
 /********************
  * Recursively make Undefined vi undefined and all who list vi as a dependency
+ * Params:
+ *    vi = variable's index
+ *    gen = array of the states of variables
  */
 void makeUndefined(size_t vi, PtrVarState[] gen)
 {
index 2f36d5d13da472a6fdd01232ea9d59b1da281058..624210bf527905a2d11f0e5c76400e2ac7f64d93 100644 (file)
@@ -17,6 +17,7 @@ import dmd.aggregate;
 import dmd.arraytypes;
 import dmd.astenums;
 import dmd.attrib;
+import dmd.attribsem;
 import dmd.cond;
 import dmd.dclass;
 import dmd.declaration;
index 70eeaff7f47e97b96223a86d03bbe690628ca226..0d32d7d9713d1099e4bd32f1ca4d361b78d04a37 100644 (file)
@@ -29,6 +29,7 @@ import dmd.errors;
 import dmd.expression;
 import dmd.expressionsem;
 import dmd.func;
+import dmd.funcsem;
 import dmd.globals;
 import dmd.hdrgen;
 import dmd.id;
index 646c4b7d3dbc6cfdc5657655094185810b709410..a7a930335ad5227f0cf1429488128c5b281780ae 100644 (file)
@@ -233,6 +233,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                     }
                     else
                     {
+                        static if (is(typeof(mod.edition)))
+                            if (exps && exps.length > 0)
+                                if (auto id = (*exps)[0].isIdentifierExp())
+                                    if (id.ident == Id.__edition_latest_do_not_use)
+                                    {
+                                        mod.edition = Edition.latest;
+                                        continue;
+                                    }
+
                         udas = AST.UserAttributeDeclaration.concat(udas, exps);
                     }
                     if (stc)
@@ -5960,9 +5969,18 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                 goto Lexp;
             goto case;
 
+        // FunctionLiteral `auto ref (`
+        case TOK.auto_:
+            if (peekNext() == TOK.ref_ && peekNext2() == TOK.leftParenthesis)
+                goto Lexp;
+            goto Ldeclaration;
+        case TOK.ref_:
+            if (peekNext() == TOK.leftParenthesis)
+                goto Lexp;
+            goto Ldeclaration;
+
         case TOK.alias_:
         case TOK.const_:
-        case TOK.auto_:
         case TOK.abstract_:
         case TOK.extern_:
         case TOK.align_:
@@ -5972,7 +5990,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
         case TOK.deprecated_:
         case TOK.nothrow_:
         case TOK.pure_:
-        case TOK.ref_:
         case TOK.gshared:
         case TOK.at:
         case TOK.struct_:
@@ -9580,9 +9597,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
 
     void usageOfBodyKeyword()
     {
-        version (none)  // disable obsolete warning
+        if (mod.edition >= Edition.v2024)
         {
-            eSink.warning(token.loc, "usage of identifer `body` as a keyword is obsolete. Use `do` instead.");
+            eSink.error(token.loc, "usage of identifer `body` as a keyword is obsolete. Use `do` instead.");
         }
     }
 }
index b52b5516263d522035928bc94dc1d822fe6aefe4..4dceb595e54fef5a20d2e54b0db44f8aa324883a 100644 (file)
@@ -67,6 +67,8 @@ void pragmaDeclSemantic(PragmaDeclaration pd, Scope* sc)
         }
         version (all)
         {
+            import dmd.common.charactertables;
+
             /* Note: D language specification should not have any assumption about backend
              * implementation. Ideally pragma(mangle) can accept a string of any content.
              *
@@ -94,7 +96,7 @@ void pragmaDeclSemantic(PragmaDeclaration pd, Scope* sc)
                     .error(pd.loc, "%s `%s` %.*s", pd.kind, pd.toPrettyChars, cast(int)msg.length, msg.ptr);
                     break;
                 }
-                if (!isUniAlpha(c))
+                if (!isAnyIdentifierCharacter(c))
                 {
                     .error(pd.loc, "%s `%s` char `0x%04x` not allowed in mangled name", pd.kind, pd.toPrettyChars, c);
                     break;
index 3e2880431e94ed345d6f92981f416736ceb6afb1..cb8f8dc7381ea745865c69a95db3fedaba9b9ebd 100644 (file)
@@ -26,7 +26,7 @@ struct Array
   public:
     Array()
     {
-        data.ptr = NULL;
+        data.ptr = nullptr;
         length = 0;
         data.length = 0;
     }
@@ -86,7 +86,7 @@ struct Array
                 if (nentries <= SMALLARRAYCAP)
                 {
                     data.length = SMALLARRAYCAP;
-                    data.ptr = SMALLARRAYCAP ? &smallarray[0] : NULL;
+                    data.ptr = SMALLARRAYCAP ? &smallarray[0] : nullptr;
                 }
                 else
                 {
index 2a8270335879e4270fe641047db57d5809387e9b..0bea2d55a0666d6c6024d7dd97dc10d7fdef09ae 100644 (file)
@@ -15,7 +15,7 @@ struct BitArray
 {
     BitArray()
       : len(0)
-      , ptr(NULL)
+      , ptr(nullptr)
     {}
 
     ~BitArray()
index db2b2c6abcdd3248586995e3ac8afabf67bd0684..e397fa75c1042636fbd7f3a32847dde5a23ef5ad 100644 (file)
@@ -18,7 +18,7 @@ struct DArray
     size_t length;
     T *ptr;
 
-    DArray() : length(0), ptr(NULL) { }
+    DArray() : length(0), ptr(nullptr) { }
 
     DArray(size_t length_in, T *ptr_in)
         : length(length_in), ptr(ptr_in) { }
index a4362e171785cdc282c9028a38d864699e242600..ee7170e230c8059866df10edb4e159c6352bd80c 100644 (file)
@@ -19,11 +19,13 @@ import core.sys.posix.fcntl;
 import core.sys.posix.unistd;
 import core.sys.windows.winbase;
 import core.sys.windows.winnt;
+
 import dmd.root.filename;
 import dmd.root.rmem;
 import dmd.root.string;
 
 import dmd.common.file;
+import dmd.common.outbuffer;
 import dmd.common.smallbuffer;
 
 nothrow:
@@ -76,62 +78,52 @@ struct File
     }
 
 nothrow:
-    /// Read the full content of a file.
-    static ReadResult read(const(char)[] name)
+    /** Read the full content of a file, and append it to `buffer`
+     * Params:
+     *  name = name of file
+     *  buffer = file contents appended to it
+     * Returns:
+     *  false = success, true = failed
+     */
+    static bool read(const char[] name, ref OutBuffer buffer)
     {
-        ReadResult result;
+        enum Success = false;
+        enum Failure = true;
 
         version (Posix)
         {
-            size_t size;
-            stat_t buf;
-            ssize_t numread;
-            //printf("File::read('%s')\n",name);
+            //printf("File::read('%.*s')\n", cast(int)name.length, name.ptr);
             int fd = name.toCStringThen!(slice => open(slice.ptr, O_RDONLY));
             if (fd == -1)
             {
                 //perror("\topen error");
-                return result;
+                return Failure;
             }
             //printf("\tfile opened\n");
-            if (fstat(fd, &buf))
+            stat_t statbuf;
+            if (fstat(fd, &statbuf))
             {
                 //perror("\tfstat error");
                 close(fd);
-                return result;
+                return Failure;
             }
-            size = cast(size_t)buf.st_size;
-            ubyte* buffer = cast(ubyte*)mem.xmalloc_noscan(size + 4);
-            numread = .read(fd, buffer, size);
+            size_t size = cast(size_t)statbuf.st_size;
+            auto buf = buffer.allocate(size);
+            ssize_t numread = .read(fd, buf.ptr, size);
             if (numread != size)
             {
                 //perror("\tread error");
-                goto err2;
+                close(fd);
+                return Failure;
             }
             if (close(fd) == -1)
             {
                 //perror("\tclose error");
-                goto err;
+                return Failure;
             }
-            // Always store a wchar ^Z past end of buffer so scanner has a
-            // sentinel, although ^Z got obselete, so fill with two 0s and add
-            // two more so lexer doesn't read pass the buffer.
-            buffer[size .. size + 4] = 0;
-
-            result.success = true;
-            result.buffer.data = buffer[0 .. size];
-            return result;
-        err2:
-            close(fd);
-        err:
-            mem.xfree(buffer);
-            return result;
         }
         else version (Windows)
         {
-            DWORD size;
-            DWORD numread;
-
             // work around Windows file path length limitation
             // (see documentation for extendedPathThen).
             HANDLE h = name.extendedPathThen!
@@ -143,32 +135,24 @@ nothrow:
                                   FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
                                   null));
             if (h == INVALID_HANDLE_VALUE)
-                return result;
-            size = GetFileSize(h, null);
-            ubyte* buffer = cast(ubyte*)mem.xmalloc_noscan(size + 4);
-            if (ReadFile(h, buffer, size, &numread, null) != TRUE)
-                goto err2;
-            if (numread != size)
-                goto err2;
+                return Failure;
+            DWORD size = GetFileSize(h, null);
+            auto buf = buffer.allocate(size);
+            DWORD numread;
+            if (ReadFile(h, buf.ptr, size, &numread, null) != TRUE ||
+                numread != size)
+            {
+                CloseHandle(h);
+                return Failure;
+            }
             if (!CloseHandle(h))
-                goto err;
-            // Always store a wchar ^Z past end of buffer so scanner has a
-            // sentinel, although ^Z got obselete, so fill with two 0s and add
-            // two more so lexer doesn't read pass the buffer.
-            buffer[size .. size + 4] = 0;
-            result.success = true;
-            result.buffer.data = buffer[0 .. size];
-            return result;
-        err2:
-            CloseHandle(h);
-        err:
-            mem.xfree(buffer);
-            return result;
+                return Failure;
         }
         else
         {
-            assert(0);
+            static assert(0);
         }
+        return Success;
     }
 
     /// Write a file, returning `true` on success.
index d9f1a04057dff00a03444fef1564dba339b32f05..1fbe0ae360974b16c192fd5e839e922043967f10 100644 (file)
@@ -13,6 +13,7 @@ module dmd.root.filename;
 
 import core.stdc.ctype;
 import core.stdc.errno;
+import core.stdc.stdio;
 import core.stdc.string;
 
 import dmd.common.file;
@@ -269,6 +270,20 @@ nothrow:
         assert(removeExt("/foo/bar/frontend.di"[]) == "/foo/bar/frontend");
     }
 
+    /********************************
+     * Slice of file name without extension.
+     * Params:
+     *  filename = file name
+     * Returns:
+     *  the slice
+     */
+    extern (D) static const(char)[] sansExt(const char[] filename)
+    {
+        auto e = ext(filename);
+        size_t length = e.length;
+        return filename[0 .. filename.length - (length ? length + 1 : 0)]; // +1 for .
+    }
+
     /********************************
      * Return filename name excluding path (read-only).
      */
@@ -452,17 +467,15 @@ nothrow:
             assert(buildPath("a/", "bb", "ccc") == "a/bb/ccc");
     }
 
-    // Split a path into an Array of paths
-    extern (C++) static Strings* splitPath(const(char)* path)
+    // Split a path and append the results to `array`
+    extern (C++) static void appendSplitPath(const(char)* path, ref Strings array)
     {
-        auto array = new Strings();
         int sink(const(char)* p) nothrow
         {
             array.push(p);
             return 0;
         }
         splitPath(&sink, path);
-        return array;
     }
 
     /****
@@ -846,6 +859,7 @@ nothrow:
     {
         if (!name.length)
             return 0;
+        //static int count; printf("count: %d %.*s\n", ++count, cast(int)name.length, name.ptr);
         version (Posix)
         {
             stat_t st;
index e8c8b11fffdd54b74f3c3d28f7ae2b22923143a2..b4d25b91703ec82439b1c2c394e3f8ded71b1675 100644 (file)
@@ -22,7 +22,7 @@ public:
     static FileName create(const char *name);
     static bool equals(const char *name1, const char *name2);
     static bool absolute(const char *name);
-    static const char *toAbsolute(const char *name, const char *base = NULL);
+    static const char *toAbsolute(const char *name, const char *base = nullptr);
     static const char *ext(const char *);
     const char *ext();
     static const char *removeExt(const char *str);
@@ -31,7 +31,7 @@ public:
     static const char *path(const char *);
 
     static const char *combine(const char *path, const char *name);
-    static Strings *splitPath(const char *path);
+    static void appendSplitPath(const char *path, Strings& array);
     static const char *defaultExt(const char *name, const char *ext);
     static const char *forceExt(const char *name, const char *ext);
     static bool equalsExt(const char *name, const char *ext);
index 19652072376bf52b043fd50523366b9715b898d0..c6986c0b56fecec0898b03b7b5ab73af387c0bc5 100644 (file)
@@ -318,7 +318,7 @@ Params:
 
 Returns: A null-terminated copy of the input array.
 */
-extern (D) char[] xarraydup(const(char)[] s) pure nothrow
+extern (D) char[] xarraydup(scope const(char)[] s) pure nothrow
 {
     if (!s)
         return null;
index e82b0d2fe6d0b4c7194a79b7c8d07e0aab5d1099..4b4c3e1f6457fb99bee41afb1d4c3329509a86e2 100644 (file)
@@ -10,6 +10,9 @@
  */
 module dmd.root.string;
 
+import core.stdc.string;
+import dmd.root.rmem;
+
 /// Slices a `\0`-terminated C-string, excluding the terminator
 inout(char)[] toDString (inout(char)* s) pure nothrow @nogc
 {
@@ -87,6 +90,23 @@ unittest
     assert(null.toCStringThen!((v) => v == "\0"));
 }
 
+/*********************************************
+ * Convert a D string to a C string by allocating memory,
+ * copying it, and adding a terminating 0.
+ * Params:
+ *      s = string to copy
+ * Result:
+ *      0-terminated copy of s
+ */
+char[] toCString(scope const(char)[] s) nothrow
+{
+    const length = s.length;
+    char* p = cast(char*)mem.xmalloc_noscan(length + 1);
+    memcpy(p, s.ptr, length);
+    p[length] = 0;
+    return p[0 .. length];
+}
+
 /**
  * Strips one leading line terminator of the given string.
  *
@@ -274,6 +294,15 @@ do
     return true;
 }
 
+///ditto
+nothrow @nogc pure @safe
+bool startsWith(scope const(char)[] str, scope const(char)[] prefix)
+{
+    if (str.length < prefix.length)
+        return false;
+    return str[0 .. prefix.length] == prefix;
+}
+
 ///
 @system pure nothrow @nogc
 unittest
@@ -286,3 +315,170 @@ unittest
     assert(ptr.startsWith("123"));
     assert(!ptr.startsWith("1234"));
 }
+
+/**********************************
+ * Take `text` and turn it into an InputRange that emits
+ * slices into `text` for each line.
+ * Params:
+ *  text = array of characters
+ * Returns:
+ *  InputRange accessing `text` as a sequence of lines
+ * Reference:
+ *  `std.string.splitLines()`
+ */
+auto splitLines(const char[] text)
+{
+    struct Range
+    {
+      @safe:
+      @nogc:
+      nothrow:
+      pure:
+      private:
+
+        const char[] text;
+        size_t index;       // index of start of line
+        size_t eolIndex;    // index of end of line before newline characters
+        size_t nextIndex;   // index past end of line
+
+        public this(const char[] text)
+        {
+            this.text = text;
+        }
+
+        public bool empty() { return index == text.length; }
+
+        public void popFront() { advance(); index = nextIndex; }
+
+        public const(char)[] front() { advance(); return text[index .. eolIndex]; }
+
+        private void advance()
+        {
+            if (index != nextIndex) // if already advanced
+                return;
+
+            for (size_t i = index; i < text.length; ++i)
+            {
+                switch (text[i])
+                {
+                    case '\v', '\f', '\n':
+                        eolIndex = i;
+                        nextIndex = i + 1;
+                        return;
+
+                    case '\r':
+                        if (i + 1 < text.length && text[i + 1] == '\n') // decode "\r\n"
+                        {
+                            eolIndex = i;
+                            nextIndex = i + 2;
+                            return;
+                        }
+                        eolIndex = i;
+                        nextIndex = i + 1;
+                        return;
+
+                    /* Manually decode:
+                     *  NEL is C2 85
+                     */
+                    case 0xC2:
+                        if (i + 1 < text.length && text[i + 1] == 0x85)
+                        {
+                            eolIndex = i;
+                            nextIndex = i + 2;
+                            return;
+                        }
+                        break;
+
+                    /* Manually decode:
+                     *  lineSep is E2 80 A8
+                     *  paraSep is E2 80 A9
+                     */
+                    case 0xE2:
+                        if (i + 2 < text.length &&
+                            text[i + 1] == 0x80 &&
+                            (text[i + 2] == 0xA8 || text[i + 2] == 0xA9)
+                           )
+                        {
+                            eolIndex = i;
+                            nextIndex = i + 3;
+                            return;
+                        }
+                        break;
+
+                    default:
+                        break;
+                }
+            }
+        }
+    }
+
+    return Range(text);
+}
+
+private struct FindSplit
+{
+@nogc nothrow pure @safe:
+    const(char)[][3] elem;
+
+    ref const(char)[] opIndex(size_t i) scope return { return elem[i]; }
+    bool opCast() const scope { return elem[1].length > 0; }
+}
+
+/**
+Find a substring in a string and split the string into before and after parts.
+Params:
+  str = string to look into
+  needle = substring to find in str (must not be empty)
+Returns:
+   a `FindSplit` object that casts to `true` iff `needle` was found inside `str`.
+   In that case, `split[1]` is the needle, and `split[0]`/`split[2]` are before/after the needle.
+*/
+FindSplit findSplit(return scope const(char)[] str, scope const(char)[] needle)
+{
+    if (needle.length > str.length)
+        return FindSplit([str, null, null]);
+
+    foreach (i; 0 .. str.length - needle.length + 1)
+    {
+        if (str[i .. i+needle.length] == needle[])
+            return FindSplit([ str[0 .. i], str[i .. i+needle.length], str[i+needle.length .. $] ]);
+    }
+    return FindSplit([str, null, null]);
+}
+
+unittest
+{
+    auto s = findSplit("a b c", "c");
+    assert(s[0] == "a b ");
+    assert(s[1] == "c");
+    assert(s[2] == "");
+    auto s1 = findSplit("a b c", "b");
+    assert(s1[0] == "a ");
+    assert(s1[1] == "b");
+    assert(s1[2] == " c");
+    assert(!findSplit("a b c", "d"));
+    assert(!findSplit("", "d"));
+}
+
+/**
+Find a string inbetween two substrings
+Params:
+  str = string to look into
+  l = substring to find on the left
+  r = substring to find on the right
+Returns:
+   substring of `str` inbetween `l` and `r`
+*/
+const(char)[] findBetween(const(char)[] str, const(char)[] l, const(char)[] r)
+{
+    if (auto s0 = str.findSplit(l))
+        if (auto s1 = s0[2].findSplit(r))
+            return s1[0];
+    return null;
+}
+
+unittest
+{
+    assert(findBetween("a b c", "a ", " c") == "b");
+    assert(findBetween("a b c", "a ", " d") == null);
+}
index 7d732f2fbe856fbcf790d76c6c1ed39f452310f6..36f0b985c3affa0e6234adc755d05644060d9d9a 100644 (file)
@@ -27,281 +27,6 @@ bool utf_isValidDchar(dchar c)
     return false;
 }
 
-/*******************************
- * Return !=0 if unicode alpha.
- * Use table from C99 Appendix D.
- */
-bool isUniAlpha(dchar c)
-{
-    static immutable wchar[2][] ALPHA_TABLE =
-    [
-        [0x00AA, 0x00AA],
-        [0x00B5, 0x00B5],
-        [0x00B7, 0x00B7],
-        [0x00BA, 0x00BA],
-        [0x00C0, 0x00D6],
-        [0x00D8, 0x00F6],
-        [0x00F8, 0x01F5],
-        [0x01FA, 0x0217],
-        [0x0250, 0x02A8],
-        [0x02B0, 0x02B8],
-        [0x02BB, 0x02BB],
-        [0x02BD, 0x02C1],
-        [0x02D0, 0x02D1],
-        [0x02E0, 0x02E4],
-        [0x037A, 0x037A],
-        [0x0386, 0x0386],
-        [0x0388, 0x038A],
-        [0x038C, 0x038C],
-        [0x038E, 0x03A1],
-        [0x03A3, 0x03CE],
-        [0x03D0, 0x03D6],
-        [0x03DA, 0x03DA],
-        [0x03DC, 0x03DC],
-        [0x03DE, 0x03DE],
-        [0x03E0, 0x03E0],
-        [0x03E2, 0x03F3],
-        [0x0401, 0x040C],
-        [0x040E, 0x044F],
-        [0x0451, 0x045C],
-        [0x045E, 0x0481],
-        [0x0490, 0x04C4],
-        [0x04C7, 0x04C8],
-        [0x04CB, 0x04CC],
-        [0x04D0, 0x04EB],
-        [0x04EE, 0x04F5],
-        [0x04F8, 0x04F9],
-        [0x0531, 0x0556],
-        [0x0559, 0x0559],
-        [0x0561, 0x0587],
-        [0x05B0, 0x05B9],
-        [0x05BB, 0x05BD],
-        [0x05BF, 0x05BF],
-        [0x05C1, 0x05C2],
-        [0x05D0, 0x05EA],
-        [0x05F0, 0x05F2],
-        [0x0621, 0x063A],
-        [0x0640, 0x0652],
-        [0x0660, 0x0669],
-        [0x0670, 0x06B7],
-        [0x06BA, 0x06BE],
-        [0x06C0, 0x06CE],
-        [0x06D0, 0x06DC],
-        [0x06E5, 0x06E8],
-        [0x06EA, 0x06ED],
-        [0x06F0, 0x06F9],
-        [0x0901, 0x0903],
-        [0x0905, 0x0939],
-        [0x093D, 0x094D],
-        [0x0950, 0x0952],
-        [0x0958, 0x0963],
-        [0x0966, 0x096F],
-        [0x0981, 0x0983],
-        [0x0985, 0x098C],
-        [0x098F, 0x0990],
-        [0x0993, 0x09A8],
-        [0x09AA, 0x09B0],
-        [0x09B2, 0x09B2],
-        [0x09B6, 0x09B9],
-        [0x09BE, 0x09C4],
-        [0x09C7, 0x09C8],
-        [0x09CB, 0x09CD],
-        [0x09DC, 0x09DD],
-        [0x09DF, 0x09E3],
-        [0x09E6, 0x09F1],
-        [0x0A02, 0x0A02],
-        [0x0A05, 0x0A0A],
-        [0x0A0F, 0x0A10],
-        [0x0A13, 0x0A28],
-        [0x0A2A, 0x0A30],
-        [0x0A32, 0x0A33],
-        [0x0A35, 0x0A36],
-        [0x0A38, 0x0A39],
-        [0x0A3E, 0x0A42],
-        [0x0A47, 0x0A48],
-        [0x0A4B, 0x0A4D],
-        [0x0A59, 0x0A5C],
-        [0x0A5E, 0x0A5E],
-        [0x0A66, 0x0A6F],
-        [0x0A74, 0x0A74],
-        [0x0A81, 0x0A83],
-        [0x0A85, 0x0A8B],
-        [0x0A8D, 0x0A8D],
-        [0x0A8F, 0x0A91],
-        [0x0A93, 0x0AA8],
-        [0x0AAA, 0x0AB0],
-        [0x0AB2, 0x0AB3],
-        [0x0AB5, 0x0AB9],
-        [0x0ABD, 0x0AC5],
-        [0x0AC7, 0x0AC9],
-        [0x0ACB, 0x0ACD],
-        [0x0AD0, 0x0AD0],
-        [0x0AE0, 0x0AE0],
-        [0x0AE6, 0x0AEF],
-        [0x0B01, 0x0B03],
-        [0x0B05, 0x0B0C],
-        [0x0B0F, 0x0B10],
-        [0x0B13, 0x0B28],
-        [0x0B2A, 0x0B30],
-        [0x0B32, 0x0B33],
-        [0x0B36, 0x0B39],
-        [0x0B3D, 0x0B43],
-        [0x0B47, 0x0B48],
-        [0x0B4B, 0x0B4D],
-        [0x0B5C, 0x0B5D],
-        [0x0B5F, 0x0B61],
-        [0x0B66, 0x0B6F],
-        [0x0B82, 0x0B83],
-        [0x0B85, 0x0B8A],
-        [0x0B8E, 0x0B90],
-        [0x0B92, 0x0B95],
-        [0x0B99, 0x0B9A],
-        [0x0B9C, 0x0B9C],
-        [0x0B9E, 0x0B9F],
-        [0x0BA3, 0x0BA4],
-        [0x0BA8, 0x0BAA],
-        [0x0BAE, 0x0BB5],
-        [0x0BB7, 0x0BB9],
-        [0x0BBE, 0x0BC2],
-        [0x0BC6, 0x0BC8],
-        [0x0BCA, 0x0BCD],
-        [0x0BE7, 0x0BEF],
-        [0x0C01, 0x0C03],
-        [0x0C05, 0x0C0C],
-        [0x0C0E, 0x0C10],
-        [0x0C12, 0x0C28],
-        [0x0C2A, 0x0C33],
-        [0x0C35, 0x0C39],
-        [0x0C3E, 0x0C44],
-        [0x0C46, 0x0C48],
-        [0x0C4A, 0x0C4D],
-        [0x0C60, 0x0C61],
-        [0x0C66, 0x0C6F],
-        [0x0C82, 0x0C83],
-        [0x0C85, 0x0C8C],
-        [0x0C8E, 0x0C90],
-        [0x0C92, 0x0CA8],
-        [0x0CAA, 0x0CB3],
-        [0x0CB5, 0x0CB9],
-        [0x0CBE, 0x0CC4],
-        [0x0CC6, 0x0CC8],
-        [0x0CCA, 0x0CCD],
-        [0x0CDE, 0x0CDE],
-        [0x0CE0, 0x0CE1],
-        [0x0CE6, 0x0CEF],
-        [0x0D02, 0x0D03],
-        [0x0D05, 0x0D0C],
-        [0x0D0E, 0x0D10],
-        [0x0D12, 0x0D28],
-        [0x0D2A, 0x0D39],
-        [0x0D3E, 0x0D43],
-        [0x0D46, 0x0D48],
-        [0x0D4A, 0x0D4D],
-        [0x0D60, 0x0D61],
-        [0x0D66, 0x0D6F],
-        [0x0E01, 0x0E3A],
-        [0x0E40, 0x0E5B],
-        [0x0E81, 0x0E82],
-        [0x0E84, 0x0E84],
-        [0x0E87, 0x0E88],
-        [0x0E8A, 0x0E8A],
-        [0x0E8D, 0x0E8D],
-        [0x0E94, 0x0E97],
-        [0x0E99, 0x0E9F],
-        [0x0EA1, 0x0EA3],
-        [0x0EA5, 0x0EA5],
-        [0x0EA7, 0x0EA7],
-        [0x0EAA, 0x0EAB],
-        [0x0EAD, 0x0EAE],
-        [0x0EB0, 0x0EB9],
-        [0x0EBB, 0x0EBD],
-        [0x0EC0, 0x0EC4],
-        [0x0EC6, 0x0EC6],
-        [0x0EC8, 0x0ECD],
-        [0x0ED0, 0x0ED9],
-        [0x0EDC, 0x0EDD],
-        [0x0F00, 0x0F00],
-        [0x0F18, 0x0F19],
-        [0x0F20, 0x0F33],
-        [0x0F35, 0x0F35],
-        [0x0F37, 0x0F37],
-        [0x0F39, 0x0F39],
-        [0x0F3E, 0x0F47],
-        [0x0F49, 0x0F69],
-        [0x0F71, 0x0F84],
-        [0x0F86, 0x0F8B],
-        [0x0F90, 0x0F95],
-        [0x0F97, 0x0F97],
-        [0x0F99, 0x0FAD],
-        [0x0FB1, 0x0FB7],
-        [0x0FB9, 0x0FB9],
-        [0x10A0, 0x10C5],
-        [0x10D0, 0x10F6],
-        [0x1E00, 0x1E9B],
-        [0x1EA0, 0x1EF9],
-        [0x1F00, 0x1F15],
-        [0x1F18, 0x1F1D],
-        [0x1F20, 0x1F45],
-        [0x1F48, 0x1F4D],
-        [0x1F50, 0x1F57],
-        [0x1F59, 0x1F59],
-        [0x1F5B, 0x1F5B],
-        [0x1F5D, 0x1F5D],
-        [0x1F5F, 0x1F7D],
-        [0x1F80, 0x1FB4],
-        [0x1FB6, 0x1FBC],
-        [0x1FBE, 0x1FBE],
-        [0x1FC2, 0x1FC4],
-        [0x1FC6, 0x1FCC],
-        [0x1FD0, 0x1FD3],
-        [0x1FD6, 0x1FDB],
-        [0x1FE0, 0x1FEC],
-        [0x1FF2, 0x1FF4],
-        [0x1FF6, 0x1FFC],
-        [0x203F, 0x2040],
-        [0x207F, 0x207F],
-        [0x2102, 0x2102],
-        [0x2107, 0x2107],
-        [0x210A, 0x2113],
-        [0x2115, 0x2115],
-        [0x2118, 0x211D],
-        [0x2124, 0x2124],
-        [0x2126, 0x2126],
-        [0x2128, 0x2128],
-        [0x212A, 0x2131],
-        [0x2133, 0x2138],
-        [0x2160, 0x2182],
-        [0x3005, 0x3007],
-        [0x3021, 0x3029],
-        [0x3041, 0x3093],
-        [0x309B, 0x309C],
-        [0x30A1, 0x30F6],
-        [0x30FB, 0x30FC],
-        [0x3105, 0x312C],
-        [0x4E00, 0x9FA5],
-        [0xAC00, 0xD7A3]
-    ];
-
-    size_t high = ALPHA_TABLE.length - 1;
-    // Shortcut search if c is out of range
-    size_t low = (c < ALPHA_TABLE[0][0] || ALPHA_TABLE[high][1] < c) ? high + 1 : 0;
-    // Binary search
-    while (low <= high)
-    {
-        const size_t mid = low + ((high - low) >> 1);
-        if (c < ALPHA_TABLE[mid][0])
-            high = mid - 1;
-        else if (ALPHA_TABLE[mid][1] < c)
-            low = mid + 1;
-        else
-        {
-            assert(ALPHA_TABLE[mid][0] <= c && c <= ALPHA_TABLE[mid][1]);
-            return true;
-        }
-    }
-    return false;
-}
-
 /**
  * Returns the code length of c in code units.
  */
index 1e5fb47a3dc710df454f3168ee536217ab83680a..5064ac2d9cdbf5ff41ea7d8855d96ecb4a66c28e 100644 (file)
@@ -27,7 +27,7 @@ import dmd.mtype;
 import dmd.target;
 import dmd.tokens;
 import dmd.typesem : hasPointers, arrayOf;
-import dmd.func : setUnsafe, setUnsafePreview;
+import dmd.funcsem : setUnsafe, setUnsafePreview;
 
 /*************************************************************
  * Check for unsafe access in @safe code:
@@ -75,6 +75,7 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
         if (ad.sizeok != Sizeok.done)
             ad.determineSize(ad.loc);
 
+        import dmd.globals : FeatureState;
         const hasPointers = v.type.hasPointers();
         if (hasPointers)
         {
@@ -87,7 +88,6 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
                 }
                 else
                 {
-                    import dmd.globals : FeatureState;
                     // @@@DEPRECATED_2.116@@@
                     // https://issues.dlang.org/show_bug.cgi?id=20655
                     // Inferring `@system` because of union access breaks code,
@@ -111,6 +111,17 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
             }
         }
 
+        // @@@DEPRECATED_2.119@@@
+        // https://issues.dlang.org/show_bug.cgi?id=24477
+        // Should probably be turned into an error in a new edition
+        if (v.type.hasUnsafeBitpatterns() && v.overlapped && sc.setUnsafePreview(
+            FeatureState.default_, !printmsg, e.loc,
+            "cannot access overlapped field `%s.%s` with unsafe bit patterns in `@safe` code", ad, v)
+        )
+        {
+            return true;
+        }
+
         if (readonly || !e.type.isMutable())
             return false;
 
index f5ce0c0ada63df3dca58549cc07537446c252ec3..4bb39028f0418a9da1a66fc4106d077790e1ac3b 100644 (file)
@@ -40,6 +40,7 @@ import dmd.escape;
 import dmd.expression;
 import dmd.expressionsem;
 import dmd.func;
+import dmd.funcsem;
 import dmd.globals;
 import dmd.id;
 import dmd.identifier;
index 882d1a9a35529c86bed7b937e250c4b1dfa7afc6..d88face9c6c88417e5400ddd2d5b4baea92ff025 100644 (file)
@@ -424,9 +424,12 @@ private extern(C++) final class Semantic3Visitor : Visitor
                             .error(funcdecl.loc, "%s `%s` `object.TypeInfo_Tuple` could not be found, but is implicitly used in D-style variadic functions", funcdecl.kind, funcdecl.toPrettyChars);
                         else
                             .error(funcdecl.loc, "%s `%s` `object.TypeInfo` could not be found, but is implicitly used in D-style variadic functions", funcdecl.kind, funcdecl.toPrettyChars);
-                        fatal();
+                        funcdecl.errors = true;
                     }
+                }
 
+                if (!funcdecl.errors && f.linkage == LINK.d)
+                {
                     // Declare _arguments[]
                     funcdecl.v_arguments = new VarDeclaration(funcdecl.loc, Type.typeinfotypelist.type, Id._arguments_typeinfo, null);
                     funcdecl.v_arguments.storage_class |= STC.temp | STC.parameter;
@@ -442,7 +445,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                     sc2.insert(_arguments);
                     _arguments.parent = funcdecl;
                 }
-                if (f.linkage == LINK.d || f.parameterList.length)
+                if (!funcdecl.errors && (f.linkage == LINK.d || f.parameterList.length))
                 {
                     // Declare _argptr
                     Type t = target.va_listType(funcdecl.loc, sc);
@@ -906,26 +909,26 @@ private extern(C++) final class Semantic3Visitor : Visitor
                             }
                         }
 
-                        const hasCopyCtor = exp.type.ty == Tstruct && (cast(TypeStruct)exp.type).sym.hasCopyCtor;
-                        // if a copy constructor is present, the return type conversion will be handled by it
-                        if (!(hasCopyCtor && exp.isLvalue()))
+                        // Function returns a reference
+                        if (f.isref)
                         {
-                            if (f.isref && !MODimplicitConv(exp.type.mod, tret.mod) && !tret.isTypeSArray())
+                            if (!MODimplicitConv(exp.type.mod, tret.mod) && !tret.isTypeSArray())
                                 error(exp.loc, "expression `%s` of type `%s` is not implicitly convertible to return type `ref %s`",
                                       exp.toChars(), exp.type.toChars(), tret.toChars());
                             else
                                 exp = exp.implicitCastTo(sc2, tret);
-                        }
 
-                        if (f.isref)
-                        {
-                            // Function returns a reference
                             exp = exp.toLvalue(sc2, "`ref` return");
-                            checkReturnEscapeRef(sc2, exp, false);
+                            checkReturnEscapeRef(*sc2, exp, false);
                             exp = exp.optimize(WANTvalue, /*keepLvalue*/ true);
                         }
                         else
                         {
+                            // if a copy constructor is present, the return type conversion will be handled by it
+                            const hasCopyCtor = exp.type.ty == Tstruct && (cast(TypeStruct)exp.type).sym.hasCopyCtor;
+                            if (!hasCopyCtor || !exp.isLvalue())
+                                exp = exp.implicitCastTo(sc2, tret);
+
                             exp = exp.optimize(WANTvalue);
 
                             /* https://issues.dlang.org/show_bug.cgi?id=10789
@@ -935,7 +938,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                                 exp = doCopyOrMove(sc2, exp, f.next);
 
                             if (tret.hasPointers())
-                                checkReturnEscape(sc2, exp, false);
+                                checkReturnEscape(*sc2, exp, false);
                         }
 
                         exp = checkGC(sc2, exp);
index ea80e510c52a19efe34c093b29699c9de1ac2b88..943723824fc5987ac99412376f3fc573172ffa87 100644 (file)
@@ -119,40 +119,40 @@ public:
     bool hasCode();
     virtual Statement *last();
 
-    virtual ReturnStatement *endsWithReturnStatement() { return NULL; }
-
-    ErrorStatement       *isErrorStatement()       { return stmt == STMTerror       ? (ErrorStatement*)this       : NULL; }
-    ScopeStatement       *isScopeStatement()       { return stmt == STMTscope       ? (ScopeStatement*)this       : NULL; }
-    ExpStatement         *isExpStatement()         { return stmt == STMTexp         ? (ExpStatement*)this         : NULL; }
-    CompoundStatement    *isCompoundStatement()    { return stmt == STMTcompound    ? (CompoundStatement*)this    : NULL; }
-    ReturnStatement      *isReturnStatement()      { return stmt == STMTreturn      ? (ReturnStatement*)this      : NULL; }
-    IfStatement          *isIfStatement()          { return stmt == STMTif          ? (IfStatement*)this          : NULL; }
-    ConditionalStatement *isConditionalStatement() { return stmt == STMTconditional ? (ConditionalStatement*)this : NULL; }
-    StaticForeachStatement *isStaticForeachStatement() { return stmt == STMTstaticForeach ? (StaticForeachStatement*)this : NULL; }
-    CaseStatement        *isCaseStatement()        { return stmt == STMTcase        ? (CaseStatement*)this        : NULL; }
-    DefaultStatement     *isDefaultStatement()     { return stmt == STMTdefault     ? (DefaultStatement*)this     : NULL; }
-    LabelStatement       *isLabelStatement()       { return stmt == STMTlabel       ? (LabelStatement*)this       : NULL; }
-    GotoDefaultStatement *isGotoDefaultStatement() { return stmt == STMTgotoDefault ? (GotoDefaultStatement*)this : NULL; }
-    GotoCaseStatement    *isGotoCaseStatement()    { return stmt == STMTgotoCase    ? (GotoCaseStatement*)this    : NULL; }
-    BreakStatement       *isBreakStatement()       { return stmt == STMTbreak       ? (BreakStatement*)this       : NULL; }
-    DtorExpStatement     *isDtorExpStatement()     { return stmt == STMTdtorExp     ? (DtorExpStatement*)this     : NULL; }
-    MixinStatement       *isMixinStatement()       { return stmt == STMTmixin       ? (MixinStatement*)this       : NULL; }
-    ForwardingStatement  *isForwardingStatement()  { return stmt == STMTforwarding  ? (ForwardingStatement*)this  : NULL; }
-    DoStatement          *isDoStatement()          { return stmt == STMTdo          ? (DoStatement*)this          : NULL; }
-    ForStatement         *isForStatement()         { return stmt == STMTfor         ? (ForStatement*)this         : NULL; }
-    ForeachStatement     *isForeachStatement()     { return stmt == STMTforeach     ? (ForeachStatement*)this     : NULL; }
-    SwitchStatement      *isSwitchStatement()      { return stmt == STMTswitch      ? (SwitchStatement*)this      : NULL; }
-    ContinueStatement    *isContinueStatement()    { return stmt == STMTcontinue    ? (ContinueStatement*)this    : NULL; }
-    WithStatement        *isWithStatement()        { return stmt == STMTwith        ? (WithStatement*)this        : NULL; }
-    TryCatchStatement    *isTryCatchStatement()    { return stmt == STMTtryCatch    ? (TryCatchStatement*)this    : NULL; }
-    ThrowStatement       *isThrowStatement()       { return stmt == STMTthrow       ? (ThrowStatement*)this       : NULL; }
-    DebugStatement       *isDebugStatement()       { return stmt == STMTdebug       ? (DebugStatement*)this       : NULL; }
-    TryFinallyStatement  *isTryFinallyStatement()  { return stmt == STMTtryFinally  ? (TryFinallyStatement*)this  : NULL; }
-    ScopeGuardStatement  *isScopeGuardStatement()  { return stmt == STMTscopeGuard  ? (ScopeGuardStatement*)this  : NULL; }
-    SwitchErrorStatement  *isSwitchErrorStatement()  { return stmt == STMTswitchError  ? (SwitchErrorStatement*)this  : NULL; }
-    UnrolledLoopStatement *isUnrolledLoopStatement() { return stmt == STMTunrolledLoop ? (UnrolledLoopStatement*)this : NULL; }
-    ForeachRangeStatement *isForeachRangeStatement() { return stmt == STMTforeachRange ? (ForeachRangeStatement*)this : NULL; }
-    CompoundDeclarationStatement *isCompoundDeclarationStatement() { return stmt == STMTcompoundDeclaration ? (CompoundDeclarationStatement*)this : NULL; }
+    virtual ReturnStatement *endsWithReturnStatement() { return nullptr; }
+
+    ErrorStatement       *isErrorStatement()       { return stmt == STMTerror       ? (ErrorStatement*)this       : nullptr; }
+    ScopeStatement       *isScopeStatement()       { return stmt == STMTscope       ? (ScopeStatement*)this       : nullptr; }
+    ExpStatement         *isExpStatement()         { return stmt == STMTexp         ? (ExpStatement*)this         : nullptr; }
+    CompoundStatement    *isCompoundStatement()    { return stmt == STMTcompound    ? (CompoundStatement*)this    : nullptr; }
+    ReturnStatement      *isReturnStatement()      { return stmt == STMTreturn      ? (ReturnStatement*)this      : nullptr; }
+    IfStatement          *isIfStatement()          { return stmt == STMTif          ? (IfStatement*)this          : nullptr; }
+    ConditionalStatement *isConditionalStatement() { return stmt == STMTconditional ? (ConditionalStatement*)this : nullptr; }
+    StaticForeachStatement *isStaticForeachStatement() { return stmt == STMTstaticForeach ? (StaticForeachStatement*)this : nullptr; }
+    CaseStatement        *isCaseStatement()        { return stmt == STMTcase        ? (CaseStatement*)this        : nullptr; }
+    DefaultStatement     *isDefaultStatement()     { return stmt == STMTdefault     ? (DefaultStatement*)this     : nullptr; }
+    LabelStatement       *isLabelStatement()       { return stmt == STMTlabel       ? (LabelStatement*)this       : nullptr; }
+    GotoDefaultStatement *isGotoDefaultStatement() { return stmt == STMTgotoDefault ? (GotoDefaultStatement*)this : nullptr; }
+    GotoCaseStatement    *isGotoCaseStatement()    { return stmt == STMTgotoCase    ? (GotoCaseStatement*)this    : nullptr; }
+    BreakStatement       *isBreakStatement()       { return stmt == STMTbreak       ? (BreakStatement*)this       : nullptr; }
+    DtorExpStatement     *isDtorExpStatement()     { return stmt == STMTdtorExp     ? (DtorExpStatement*)this     : nullptr; }
+    MixinStatement       *isMixinStatement()       { return stmt == STMTmixin       ? (MixinStatement*)this       : nullptr; }
+    ForwardingStatement  *isForwardingStatement()  { return stmt == STMTforwarding  ? (ForwardingStatement*)this  : nullptr; }
+    DoStatement          *isDoStatement()          { return stmt == STMTdo          ? (DoStatement*)this          : nullptr; }
+    ForStatement         *isForStatement()         { return stmt == STMTfor         ? (ForStatement*)this         : nullptr; }
+    ForeachStatement     *isForeachStatement()     { return stmt == STMTforeach     ? (ForeachStatement*)this     : nullptr; }
+    SwitchStatement      *isSwitchStatement()      { return stmt == STMTswitch      ? (SwitchStatement*)this      : nullptr; }
+    ContinueStatement    *isContinueStatement()    { return stmt == STMTcontinue    ? (ContinueStatement*)this    : nullptr; }
+    WithStatement        *isWithStatement()        { return stmt == STMTwith        ? (WithStatement*)this        : nullptr; }
+    TryCatchStatement    *isTryCatchStatement()    { return stmt == STMTtryCatch    ? (TryCatchStatement*)this    : nullptr; }
+    ThrowStatement       *isThrowStatement()       { return stmt == STMTthrow       ? (ThrowStatement*)this       : nullptr; }
+    DebugStatement       *isDebugStatement()       { return stmt == STMTdebug       ? (DebugStatement*)this       : nullptr; }
+    TryFinallyStatement  *isTryFinallyStatement()  { return stmt == STMTtryFinally  ? (TryFinallyStatement*)this  : nullptr; }
+    ScopeGuardStatement  *isScopeGuardStatement()  { return stmt == STMTscopeGuard  ? (ScopeGuardStatement*)this  : nullptr; }
+    SwitchErrorStatement  *isSwitchErrorStatement()  { return stmt == STMTswitchError  ? (SwitchErrorStatement*)this  : nullptr; }
+    UnrolledLoopStatement *isUnrolledLoopStatement() { return stmt == STMTunrolledLoop ? (UnrolledLoopStatement*)this : nullptr; }
+    ForeachRangeStatement *isForeachRangeStatement() { return stmt == STMTforeachRange ? (ForeachRangeStatement*)this : nullptr; }
+    CompoundDeclarationStatement *isCompoundDeclarationStatement() { return stmt == STMTcompoundDeclaration ? (CompoundDeclarationStatement*)this : nullptr; }
 
     void accept(Visitor *v) override { v->visit(this); }
 };
index 1bf36e3082d89b7d094c34f4b5733ffc32ec94b9..ae68d6a67e71ba81565c7b9118f56248823492ed 100644 (file)
@@ -989,7 +989,18 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
                          (tn.ty != tv.ty && tn.ty.isSomeChar && tv.ty.isSomeChar)) &&
                         !Type.tsize_t.implicitConvTo(tindex))
                     {
-                        deprecation(fs.loc, "foreach: loop index implicitly converted from `size_t` to `%s`",
+                        bool err = true;
+                        if (tab.isTypeDArray())
+                        {
+                            // check if overflow is possible
+                            const maxLen = IntRange.fromType(tindex).imax.value + 1;
+                            if (auto ale = fs.aggr.isArrayLiteralExp())
+                                err = ale.elements.length > maxLen;
+                            else if (auto se = fs.aggr.isSliceExp())
+                                err = !(se.upr && se.upr.isConst() && se.upr.toInteger() <= maxLen);
+                        }
+                        if (err)
+                            deprecation(fs.loc, "foreach: loop index implicitly converted from `size_t` to `%s`",
                                        tindex.toChars());
                     }
                 }
@@ -1398,7 +1409,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
             }
         case Tdelegate:
             if (fs.op == TOK.foreach_reverse_)
-                deprecation(fs.loc, "cannot use `foreach_reverse` with a delegate");
+                error(fs.loc, "cannot use `foreach_reverse` with a delegate");
             return retStmt(apply());
         case Terror:
             return retError();
@@ -2652,11 +2663,11 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
                      */
                     Scope* sc2 = sc.push();
                     sc2.eSink = global.errorSinkNull;
-                    bool err = checkReturnEscapeRef(sc2, rs.exp, true);
+                    bool err = checkReturnEscapeRef(*sc2, rs.exp, true);
                     sc2.pop();
 
                     if (err)
-                        turnOffRef(() { checkReturnEscapeRef(sc, rs.exp, false); });
+                        turnOffRef(() { checkReturnEscapeRef(*sc, rs.exp, false); });
                     else if (!rs.exp.type.constConv(tf.next))
                         turnOffRef(
                             () => rs.loc.errorSupplemental("cannot implicitly convert `%s` of type `%s` to `%s`",
@@ -3018,8 +3029,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
                  */
                 if (!ClassDeclaration.object)
                 {
-                    error(ss.loc, "missing or corrupt object.d");
-                    fatal();
+                    ObjectNotFound(ss.loc, Id.Object);
+                    return setError();
                 }
 
                 Type t = ClassDeclaration.object.type;
@@ -3690,7 +3701,7 @@ public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc)
         exp.loc.deprecation("cannot throw object of qualified type `%s`", exp.type.toChars());
         //return false;
     }
-    checkThrowEscape(sc, exp, false);
+    checkThrowEscape(*sc, exp, false);
 
     ClassDeclaration cd = exp.type.toBasetype().isClassHandle();
     if (!cd || ((cd != ClassDeclaration.throwable) && !ClassDeclaration.throwable.isBaseOf(cd, null)))
index cff1d2e9bec1df103c925ff6fcc2b44919536768..87826b50df1d5ababc7627b0de871b83e811c521 100644 (file)
@@ -25,7 +25,8 @@
 
 module dmd.target;
 
-import dmd.globals : Param, CHECKENABLE;
+import dmd.astenums : CHECKENABLE;
+import dmd.globals : Param;
 
 enum CPU : ubyte
 {
index 120950570d4c66b124e0d1b68acdecaec81f1071..6237cf148361a0e17323866e2d2e9d3767517fbb 100644 (file)
@@ -198,7 +198,7 @@ public:
     unsigned fieldalign(Type *type);
     Type *va_listType(const Loc &loc, Scope *sc);  // get type of va_list
     int isVectorTypeSupported(int sz, Type *type);
-    bool isVectorOpSupported(Type *type, EXP op, Type *t2 = NULL);
+    bool isVectorOpSupported(Type *type, EXP op, Type *t2 = nullptr);
     // ABI and backend.
     LINK systemLinkage();
     TypeTuple *toArgTypes(Type *t);
index ef91001a99692b1008cc093fc4a0b2dd1cedf135..929897a3fa6f6e4962de90e170dc3b9978a6a114 100644 (file)
@@ -476,7 +476,7 @@ struct Token
         Identifier *ident;
     };
 
-    Token() : next(NULL) {}
+    Token() : next(nullptr) {}
     const char *toChars() const;
 
     static const char *toChars(TOK value);
index be7aa9923c03697483a84952ec1a773929937a46..81d42e6e8be537b07941004d7c958598e458c2cc 100644 (file)
@@ -20,6 +20,7 @@ import dmd.arraytypes;
 import dmd.astcodegen;
 import dmd.astenums;
 import dmd.attrib;
+import dmd.attribsem;
 import dmd.canthrow;
 import dmd.dclass;
 import dmd.declaration;
@@ -1245,7 +1246,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
             // @@@DEPRECATION 2.100.2
             if (auto td = s.isTemplateDeclaration())
             {
-                if (td.overnext || td.overroot)
+                if (td.overnext)
                 {
                     deprecation(e.loc, "`__traits(getAttributes)` may only be used for individual functions, not the overload set `%s`", td.ident.toChars());
                     deprecationSupplemental(e.loc, "the result of `__traits(getOverloads)` may be used to select the desired function to extract attributes from");
index b2b9e38ead4d9a7979ea592452e24f8a8ac89f38..195fdc723a21b11539d922f9c212265f2c738c32 100644 (file)
@@ -1686,7 +1686,7 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
 
             if (!ClassDeclaration.object)
             {
-                .error(Loc.initial, "missing or corrupt object.d");
+                ObjectNotFound(Loc.initial, cd.ident);
                 return error();
             }
 
index 72d80367bbe9d60a5acd0a9ed87e7c67e6a2aed4..9228ba69b1c5c85ac0a1245a948e086832419f48 100644 (file)
@@ -52,16 +52,18 @@ const(char)* toWinPath(const(char)* src)
  * Params:
  *   loc = The line number information from where the call originates
  *   filename = Path to file
+ *   buf = append contents of file to
+ * Returns:
+ *   true on failure
  */
-Buffer readFile(Loc loc, const(char)[] filename)
+bool readFile(Loc loc, const(char)[] filename, ref OutBuffer buf)
 {
-    auto result = File.read(filename);
-    if (!result.success)
+    if (File.read(filename, buf))
     {
         error(loc, "error reading file `%.*s`", cast(int)filename.length, filename.ptr);
-        fatal();
+        return true;
     }
-    return Buffer(result.extractSlice());
+    return false;
 }
 
 
index 896b25f7cb4ee9395edb2e46c7154ebff41570bd..0fbfd471d136219d323f8d1ddee2f70d96d1bc9f 100644 (file)
@@ -7,8 +7,8 @@
     union U { int i; bool b; }
     U u;
     u.i = 0x81818181;
-    assert(array[u.b] == 678);
-    return u.b;
+    assert(array[u.b] == 678); // { dg-warning "cannot access overlapped field" }
+    return u.b; // { dg-warning "cannot access overlapped field" }
 }
 
 @safe void main()
index dc47db87a80c8f1793d091c9eda6982763ee56aa..44c7e3fc4dc7173e2c453a920b514a0a30db5029 100644 (file)
@@ -1,4 +1,4 @@
-b65767825f365dbc153457fc86e1054b03196c6d
+e60bfd11bd6a523418f94d1d821b7af71f5ad05b
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
index e7380c467254a02295c9df6077388cb668f50400..5f547cd04ef67ecbebf46be3b752bd90913e0c48 100644 (file)
@@ -317,7 +317,7 @@ unittest
             cargo = 42;
         }
 
-        void useResource() shared @safe nothrow @nogc
+        void useResource() shared @trusted nothrow @nogc
         {
             mtx.lock_nothrow();
             (cast() cargo) += 1;
index a4f25db810ed8f6b174c053a2fbf591a5828225b..79cd1816499785dc5c4da39c60698558c77d5b83 100644 (file)
@@ -1,4 +1,4 @@
-92dc5a4e98591a0e6b0af4ff0f84f096fea09016
+8729740e3221cd6dcccdbbbb12b452d0ee9c1ee1
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
index c9813e35476dfb94610b8a7ff51fa291a7c806be..61c6c20f3da94b580076ce8de758bee05d7c087e 100644 (file)
@@ -3274,7 +3274,7 @@ if (canSwapEndianness!T && n == T.sizeof)
     assert(c == littleEndianToNative!dchar(swappedC));
 }
 
-private T endianToNativeImpl(bool swap, T, size_t n)(ubyte[n] val) @nogc nothrow pure @safe
+private T endianToNativeImpl(bool swap, T, size_t n)(ubyte[n] val) @nogc nothrow pure @trusted
 if (__traits(isIntegral, T) && n == T.sizeof)
 {
     if (!__ctfe)