diff options
author | Iain Buclaw <ibuclaw@symmetryinvestments.com> | 2024-12-29 06:40:04 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2025-01-05 13:30:24 +0100 |
commit | 332cf038fda109ea0612eeba7a85441293ba6984 (patch) | |
tree | ca5c381d189ace8afa4cf40369cd7d2063bc00a4 | |
parent | 31f1bec65ba257adc346f952fd79a1ec3165a2e6 (diff) | |
download | gcc-332cf038fda109ea0612eeba7a85441293ba6984.zip gcc-332cf038fda109ea0612eeba7a85441293ba6984.tar.gz gcc-332cf038fda109ea0612eeba7a85441293ba6984.tar.bz2 |
d: Merge upstream dmd c11e1d1708, druntime e60bfd11bd, phobos 8729740e3
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, 7288 insertions, 2326 deletions
diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in index 6b59126..914d54b 100644 --- a/gcc/d/Make-lang.in +++ b/gcc/d/Make-lang.in @@ -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 \ diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc index 26ec927..77315dc 100644 --- a/gcc/d/d-attribs.cc +++ b/gcc/d/d-attribs.cc @@ -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; diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc index e23e091..233342a 100644 --- a/gcc/d/d-builtins.cc +++ b/gcc/d/d-builtins.cc @@ -522,6 +522,7 @@ d_init_versions (void) targetdm.d_cpu_versions (); targetdm.d_os_versions (); + VersionCondition::addPredefinedGlobalIdent ("CppRuntime_GNU"); VersionCondition::addPredefinedGlobalIdent ("CppRuntime_Gcc"); } diff --git a/gcc/d/d-incpath.cc b/gcc/d/d-incpath.cc index 8cec07b..3f62f43 100644 --- a/gcc/d/d-incpath.cc +++ b/gcc/d/d-incpath.cc @@ -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); + } } } diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc index 274cb5d..f642248 100644 --- a/gcc/d/d-lang.cc +++ b/gcc/d/d-lang.cc @@ -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; diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index dc47db8..46d435e 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -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. diff --git a/gcc/d/dmd/README.md b/gcc/d/dmd/README.md index 282e818..d784d07 100644 --- a/gcc/d/dmd/README.md +++ b/gcc/d/dmd/README.md @@ -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 | diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index 5868b87..99582f5 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.108.0 +v2.108.1 diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d index af3875e..d0ec5eb 100644 --- a/gcc/d/dmd/arrayop.d +++ b/gcc/d/dmd/arrayop.d @@ -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); diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d index 4fc1514..1e30b9f 100644 --- a/gcc/d/dmd/astenums.d +++ b/gcc/d/dmd/astenums.d @@ -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: diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d index d7d3eca6..1c8eb57 100644 --- a/gcc/d/dmd/attrib.d +++ b/gcc/d/dmd/attrib.d @@ -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"; @@ -1232,43 +1216,6 @@ bool isCoreUda(Dsymbol sym, Identifier ident) } /** - * 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. * diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h index 344a7e9..d4c41ec 100644 --- a/gcc/d/dmd/attrib.h +++ b/gcc/d/dmd/attrib.h @@ -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 index 0000000..44647ee --- /dev/null +++ b/gcc/d/dmd/attribsem.d @@ -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 index 0000000..ac89807 --- /dev/null +++ b/gcc/d/dmd/common/charactertables.d @@ -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 index 0000000..10a81d3 --- /dev/null +++ b/gcc/d/dmd/common/charactertables.h @@ -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); +}; diff --git a/gcc/d/dmd/common/file.d b/gcc/d/dmd/common/file.d index 80677f6..52da6ee 100644 --- a/gcc/d/dmd/common/file.d +++ b/gcc/d/dmd/common/file.d @@ -14,15 +14,23 @@ 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 index 0000000..b87e9fa --- /dev/null +++ b/gcc/d/dmd/common/identifiertables.d @@ -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], +]; diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d index cb2439f..f3801cb 100644 --- a/gcc/d/dmd/common/outbuffer.d +++ b/gcc/d/dmd/common/outbuffer.d @@ -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; diff --git a/gcc/d/dmd/cond.h b/gcc/d/dmd/cond.h index fe497c2d..fc3ebd4 100644 --- a/gcc/d/dmd/cond.h +++ b/gcc/d/dmd/cond.h @@ -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); } }; diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index aeedb49..7fbcd6d 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -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; diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d index 0116aa3..334088b 100644 --- a/gcc/d/dmd/cppmangle.d +++ b/gcc/d/dmd/cppmangle.d @@ -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 } /**************************** diff --git a/gcc/d/dmd/cxxfrontend.d b/gcc/d/dmd/cxxfrontend.d index a0432d2..c0805b8 100644 --- a/gcc/d/dmd/cxxfrontend.d +++ b/gcc/d/dmd/cxxfrontend.d @@ -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*/; @@ -35,6 +36,15 @@ import dmd.statement : Statement, AsmStatement, GccAsmStatement; extern (C++, "dmd"): /*********************************************************** + * atrtibsem.d + */ +Expressions* getAttributes(UserAttributeDeclaration a) +{ + import dmd.attribsem; + return dmd.attribsem.getAttributes(a); +} + +/*********************************************************** * cppmangle.d */ const(char)* toCppMangleItanium(Dsymbol s) diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index 8a713f4..78781f4 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -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(); } diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index 8bac1f4..2199d5d 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -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; diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index 3f9769d..a1202ed 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -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; } diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d index 33428de..d4eecb9 100644 --- a/gcc/d/dmd/dmangle.d +++ b/gcc/d/dmd/dmangle.d @@ -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; diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 58bf3fd..a1a337b 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -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); diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d index c00c1cc..a8b43da 100644 --- a/gcc/d/dmd/doc.d +++ b/gcc/d/dmd/doc.d @@ -2107,42 +2107,12 @@ int getMarkdownIndent(ref OutBuffer buf, size_t from, size_t to) @safe } /************************************************ - * 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; diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d index 76a26a2..4719529 100644 --- a/gcc/d/dmd/dscope.d +++ b/gcc/d/dmd/dscope.d @@ -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; } } diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d index df4d07a..339b223 100644 --- a/gcc/d/dmd/dstruct.d +++ b/gcc/d/dmd/dstruct.d @@ -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; diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index b831c32..90b2d9f 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -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; diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index f845435..ce29073 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -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); } }; diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index b13f98a..65a1b04 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -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) { diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index d181fac..fb11821 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -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; diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index 2e2ced4..883091b 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -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 @@ -133,6 +134,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) { hashIf(buf, "!defined(_d_real)"); @@ -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); } diff --git a/gcc/d/dmd/errors.h b/gcc/d/dmd/errors.h index a47b5aa..7a9683b 100644 --- a/gcc/d/dmd/errors.h +++ b/gcc/d/dmd/errors.h @@ -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__) diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 3e17ff4..08bd6fd 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -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; diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 479ad3a..a26f3ab 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -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 { diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h index 2f6bb84..1ff6c4c 100644 --- a/gcc/d/dmd/expression.h +++ b/gcc/d/dmd/expression.h @@ -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; diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 7ae7f40..3502a1c 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -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); } diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d index c696a5c..6ad3d62 100644 --- a/gcc/d/dmd/file_manager.d +++ b/gcc/d/dmd/file_manager.d @@ -11,10 +11,12 @@ 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); diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d index 7003c2b..f3d7aba 100644 --- a/gcc/d/dmd/func.d +++ b/gcc/d/dmd/func.d @@ -109,7 +109,8 @@ enum BUILTIN : ubyte yl2xp1, toPrecFloat, toPrecDouble, - toPrecReal + toPrecReal, + ctfeWrite, } private struct FUNCFLAG @@ -513,149 +514,6 @@ extern (C++) class FuncDeclaration : Declaration } /******************************************** - * 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 */ extern (D) final TemplateDeclaration findTemplateDeclRoot() @@ -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 @@ -1923,147 +1608,6 @@ extern (C++) class FuncDeclaration : Declaration } /**************************************************** - * 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. * Params: @@ -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: diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d index 2cadc40..e058deb 100644 --- a/gcc/d/dmd/funcsem.d +++ b/gcc/d/dmd/funcsem.d @@ -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; + } +} diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d index af7b1fa..c97aeb6 100644 --- a/gcc/d/dmd/globals.d +++ b/gcc/d/dmd/globals.d @@ -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 diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h index f553ae6..bd28d7b 100644 --- a/gcc/d/dmd/globals.h +++ b/gcc/d/dmd/globals.h @@ -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 diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d index 5ad324d..6dbc60b 100644 --- a/gcc/d/dmd/id.d +++ b/gcc/d/dmd/id.d @@ -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" }, diff --git a/gcc/d/dmd/identifier.d b/gcc/d/dmd/identifier.d index 8ace310..6fd0d3a 100644 --- a/gcc/d/dmd/identifier.d +++ b/gcc/d/dmd/identifier.d @@ -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]); diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d index 62bd41e..7d9e3e6 100644 --- a/gcc/d/dmd/init.d +++ b/gcc/d/dmd/init.d @@ -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; } diff --git a/gcc/d/dmd/init.h b/gcc/d/dmd/init.h index 2485d78..2ee69f6 100644 --- a/gcc/d/dmd/init.h +++ b/gcc/d/dmd/init.h @@ -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); } diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d index b07699e..8faad30 100644 --- a/gcc/d/dmd/initsem.d +++ b/gcc/d/dmd/initsem.d @@ -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; diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index c9c506e..26a56c2 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -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 diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h index 379e8e6..7f02bec2 100644 --- a/gcc/d/dmd/module.h +++ b/gcc/d/dmd/module.h @@ -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; diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 715ee12..dcfe183 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -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() diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index ad64b12..1121711 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -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); diff --git a/gcc/d/dmd/mustuse.d b/gcc/d/dmd/mustuse.d index c2fa5fb..fc7618b 100644 --- a/gcc/d/dmd/mustuse.d +++ b/gcc/d/dmd/mustuse.d @@ -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; diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d index 0a59815..756caf8 100644 --- a/gcc/d/dmd/ob.d +++ b/gcc/d/dmd/ob.d @@ -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[]); + } + } } /*************************************** @@ -1946,6 +1986,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. */ void checkObErrors(ref ObState obstate) @@ -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) { diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d index 2f36d5d..624210b 100644 --- a/gcc/d/dmd/objc.d +++ b/gcc/d/dmd/objc.d @@ -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; diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index 70eeaff..0d32d7d 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -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; diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index 646c4b7..a7a9303 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -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."); } } } diff --git a/gcc/d/dmd/pragmasem.d b/gcc/d/dmd/pragmasem.d index b52b551..4dceb59 100644 --- a/gcc/d/dmd/pragmasem.d +++ b/gcc/d/dmd/pragmasem.d @@ -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; diff --git a/gcc/d/dmd/root/array.h b/gcc/d/dmd/root/array.h index 3e28804..cb8f8dc 100644 --- a/gcc/d/dmd/root/array.h +++ b/gcc/d/dmd/root/array.h @@ -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 { diff --git a/gcc/d/dmd/root/bitarray.h b/gcc/d/dmd/root/bitarray.h index 2a82703..0bea2d5 100644 --- a/gcc/d/dmd/root/bitarray.h +++ b/gcc/d/dmd/root/bitarray.h @@ -15,7 +15,7 @@ struct BitArray { BitArray() : len(0) - , ptr(NULL) + , ptr(nullptr) {} ~BitArray() diff --git a/gcc/d/dmd/root/dcompat.h b/gcc/d/dmd/root/dcompat.h index db2b2c6..e397fa7 100644 --- a/gcc/d/dmd/root/dcompat.h +++ b/gcc/d/dmd/root/dcompat.h @@ -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) { } diff --git a/gcc/d/dmd/root/file.d b/gcc/d/dmd/root/file.d index a4362e1..ee7170e 100644 --- a/gcc/d/dmd/root/file.d +++ b/gcc/d/dmd/root/file.d @@ -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. diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d index d9f1a04..1fbe0ae 100644 --- a/gcc/d/dmd/root/filename.d +++ b/gcc/d/dmd/root/filename.d @@ -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; @@ -270,6 +271,20 @@ nothrow: } /******************************** + * 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). */ extern (C++) static const(char)* name(const(char)* str) pure @nogc @@ -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; diff --git a/gcc/d/dmd/root/filename.h b/gcc/d/dmd/root/filename.h index e8c8b11..b4d25b9 100644 --- a/gcc/d/dmd/root/filename.h +++ b/gcc/d/dmd/root/filename.h @@ -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); diff --git a/gcc/d/dmd/root/rmem.d b/gcc/d/dmd/root/rmem.d index 1965207..c6986c0 100644 --- a/gcc/d/dmd/root/rmem.d +++ b/gcc/d/dmd/root/rmem.d @@ -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; diff --git a/gcc/d/dmd/root/string.d b/gcc/d/dmd/root/string.d index e82b0d2..4b4c3e1 100644 --- a/gcc/d/dmd/root/string.d +++ b/gcc/d/dmd/root/string.d @@ -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); +} diff --git a/gcc/d/dmd/root/utf.d b/gcc/d/dmd/root/utf.d index 7d732f2..36f0b98 100644 --- a/gcc/d/dmd/root/utf.d +++ b/gcc/d/dmd/root/utf.d @@ -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. */ diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d index 1e5fb47..5064ac2 100644 --- a/gcc/d/dmd/safe.d +++ b/gcc/d/dmd/safe.d @@ -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; diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d index f5ce0c0..4bb3902 100644 --- a/gcc/d/dmd/semantic2.d +++ b/gcc/d/dmd/semantic2.d @@ -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; diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d index 882d1a9..d88face 100644 --- a/gcc/d/dmd/semantic3.d +++ b/gcc/d/dmd/semantic3.d @@ -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); diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h index ea80e51..9437238 100644 --- a/gcc/d/dmd/statement.h +++ b/gcc/d/dmd/statement.h @@ -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); } }; diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 1bf36e3..ae68d6a 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -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))) diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d index cff1d2e..87826b5 100644 --- a/gcc/d/dmd/target.d +++ b/gcc/d/dmd/target.d @@ -25,7 +25,8 @@ module dmd.target; -import dmd.globals : Param, CHECKENABLE; +import dmd.astenums : CHECKENABLE; +import dmd.globals : Param; enum CPU : ubyte { diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h index 1209505..6237cf14 100644 --- a/gcc/d/dmd/target.h +++ b/gcc/d/dmd/target.h @@ -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); diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index ef91001..929897a 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -476,7 +476,7 @@ struct Token Identifier *ident; }; - Token() : next(NULL) {} + Token() : next(nullptr) {} const char *toChars() const; static const char *toChars(TOK value); diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d index be7aa99..81d42e6 100644 --- a/gcc/d/dmd/traits.d +++ b/gcc/d/dmd/traits.d @@ -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"); diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index b2b9e38..195fdc7 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -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(); } diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d index 72d8036..9228ba6 100644 --- a/gcc/d/dmd/utils.d +++ b/gcc/d/dmd/utils.d @@ -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; } diff --git a/gcc/testsuite/gdc.dg/torture/pr96435.d b/gcc/testsuite/gdc.dg/torture/pr96435.d index 896b25f..0fbfd47 100644 --- a/gcc/testsuite/gdc.dg/torture/pr96435.d +++ b/gcc/testsuite/gdc.dg/torture/pr96435.d @@ -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() diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE index dc47db8..44c7e3f 100644 --- a/libphobos/libdruntime/MERGE +++ b/libphobos/libdruntime/MERGE @@ -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. diff --git a/libphobos/libdruntime/core/sync/mutex.d b/libphobos/libdruntime/core/sync/mutex.d index e7380c46..5f547cd 100644 --- a/libphobos/libdruntime/core/sync/mutex.d +++ b/libphobos/libdruntime/core/sync/mutex.d @@ -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; diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE index a4f25db..79cd181 100644 --- a/libphobos/src/MERGE +++ b/libphobos/src/MERGE @@ -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. diff --git a/libphobos/src/std/bitmanip.d b/libphobos/src/std/bitmanip.d index c9813e3..61c6c20 100644 --- a/libphobos/src/std/bitmanip.d +++ b/libphobos/src/std/bitmanip.d @@ -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) |