diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-03-13 12:28:05 +0100 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-03-13 13:20:02 +0100 |
commit | 7e28750395889d16a9cba49cd5935ced7dc00ce8 (patch) | |
tree | d2a981788cda569e1a226540c009c09ea1b4ac73 /gcc/d | |
parent | 1b85638affe6c987a33427c54e0369b819cd7915 (diff) | |
download | gcc-7e28750395889d16a9cba49cd5935ced7dc00ce8.zip gcc-7e28750395889d16a9cba49cd5935ced7dc00ce8.tar.gz gcc-7e28750395889d16a9cba49cd5935ced7dc00ce8.tar.bz2 |
d: Merge upstream dmd 02a3fafc6, druntime 26b58167, phobos 16cb085b5.
D front-end changes:
- Import dmd v2.099.0.
- The deprecation period for D1-style operators has ended, any use
of the D1 overload operators will now result in a compiler error.
- `scope' as a type constraint on class, struct, union, and enum
declarations has been deprecated.
- Fix segmentation fault when emplacing a new front-end Expression
node during CTFE (PR104835).
D runtime changes:
- Import druntime v2.099.0.
- Fix C bindings for stdint types (PR104738).
- Fix bus error when allocating new array on the GC (PR104742).
- Fix bus error when allocating new pointer on the GC (PR104745).
Phobos changes:
- Import phobos v2.099.0.
- New function `bind' in `std.functional'.
gcc/d/ChangeLog:
* dmd/MERGE: Merge upstream dmd 02a3fafc6.
* dmd/VERSION: Update version to v2.099.0.
* imports.cc (ImportVisitor::visit (EnumDeclaration *)): Don't cache
decl in front-end AST node.
(ImportVisitor::visit (AggregateDeclaration *)): Likewise.
(ImportVisitor::visit (ClassDeclaration *)): Likewise.
libphobos/ChangeLog:
* libdruntime/MERGE: Merge upstream druntime 26b58167.
* src/MERGE: Merge upstream phobos 16cb085b5.
Diffstat (limited to 'gcc/d')
-rw-r--r-- | gcc/d/dmd/MERGE | 2 | ||||
-rw-r--r-- | gcc/d/dmd/VERSION | 2 | ||||
-rw-r--r-- | gcc/d/dmd/common/outbuffer.d | 35 | ||||
-rw-r--r-- | gcc/d/dmd/constfold.d | 5 | ||||
-rw-r--r-- | gcc/d/dmd/cparse.d | 265 | ||||
-rw-r--r-- | gcc/d/dmd/dcast.d | 8 | ||||
-rw-r--r-- | gcc/d/dmd/dclass.d | 44 | ||||
-rw-r--r-- | gcc/d/dmd/declaration.d | 7 | ||||
-rw-r--r-- | gcc/d/dmd/declaration.h | 1 | ||||
-rw-r--r-- | gcc/d/dmd/dmodule.d | 26 | ||||
-rw-r--r-- | gcc/d/dmd/dsymbol.d | 80 | ||||
-rw-r--r-- | gcc/d/dmd/dsymbol.h | 7 | ||||
-rw-r--r-- | gcc/d/dmd/dsymbolsem.d | 49 | ||||
-rw-r--r-- | gcc/d/dmd/dtemplate.d | 6 | ||||
-rw-r--r-- | gcc/d/dmd/dtoh.d | 9 | ||||
-rw-r--r-- | gcc/d/dmd/escape.d | 23 | ||||
-rw-r--r-- | gcc/d/dmd/expression.d | 16 | ||||
-rw-r--r-- | gcc/d/dmd/expressionsem.d | 81 | ||||
-rw-r--r-- | gcc/d/dmd/importc.d | 5 | ||||
-rw-r--r-- | gcc/d/dmd/lexer.d | 344 | ||||
-rw-r--r-- | gcc/d/dmd/mtype.d | 20 | ||||
-rw-r--r-- | gcc/d/dmd/mtype.h | 2 | ||||
-rw-r--r-- | gcc/d/dmd/opover.d | 45 | ||||
-rw-r--r-- | gcc/d/dmd/optimize.d | 53 | ||||
-rw-r--r-- | gcc/d/dmd/parse.d | 6 | ||||
-rw-r--r-- | gcc/d/dmd/statementsem.d | 105 | ||||
-rw-r--r-- | gcc/d/dmd/tokens.d | 21 | ||||
-rw-r--r-- | gcc/d/dmd/tokens.h | 1 | ||||
-rw-r--r-- | gcc/d/dmd/typesem.d | 16 | ||||
-rw-r--r-- | gcc/d/imports.cc | 6 |
30 files changed, 749 insertions, 541 deletions
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE index 71dc2b0..2200889 100644 --- a/gcc/d/dmd/MERGE +++ b/gcc/d/dmd/MERGE @@ -1,4 +1,4 @@ -423f19b41089f627808bf16ff21c60c0791712ba +cbba5f41a32cfed7f22a213d537f8e2dee0b92f7 The first line of this file holds the git revision number of the last merge done from the dlang/dmd repository. diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION index 4bb69df..17724c6 100644 --- a/gcc/d/dmd/VERSION +++ b/gcc/d/dmd/VERSION @@ -1 +1 @@ -v2.099.0-rc.1 +v2.099.0 diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d index fafe90e..0705c18 100644 --- a/gcc/d/dmd/common/outbuffer.d +++ b/gcc/d/dmd/common/outbuffer.d @@ -662,6 +662,8 @@ struct OutBuffer return cast(char)data[i]; } + alias opDollar = length; + /*********************************** * Extract the data as a slice and take ownership of it. * @@ -879,3 +881,36 @@ unittest s = unsignedToTempString(29, buf[], 16); assert(s == "1d"); } + +unittest +{ + OutBuffer buf; + buf.writeUTF8(0x0000_0011); + buf.writeUTF8(0x0000_0111); + buf.writeUTF8(0x0000_1111); + buf.writeUTF8(0x0001_1111); + buf.writeUTF8(0x0010_0000); + assert(buf[] == "\x11\U00000111\U00001111\U00011111\U00100000"); + + buf.reset(); + buf.writeUTF16(0x0000_0011); + buf.writeUTF16(0x0010_FFFF); + assert(buf[] == cast(string) "\u0011\U0010FFFF"w); +} + +unittest +{ + OutBuffer buf; + buf.doindent = true; + + const(char)[] s = "abc"; + buf.writestring(s); + buf.level += 1; + buf.indent(); + buf.writestring("abs"); + + assert(buf[] == "abc\tabs"); + + buf.setsize(4); + assert(buf.length == 4); +} diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d index 7bc890f..96ca520 100644 --- a/gcc/d/dmd/constfold.d +++ b/gcc/d/dmd/constfold.d @@ -1230,7 +1230,7 @@ UnionExp ArrayLength(Type type, Expression e1) /* Also return EXP.cantExpression if this fails */ -UnionExp Index(Type type, Expression e1, Expression e2) +UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds) { UnionExp ue = void; Loc loc = e1.loc; @@ -1255,8 +1255,9 @@ UnionExp Index(Type type, Expression e1, Expression e2) TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype(); uinteger_t length = tsa.dim.toInteger(); uinteger_t i = e2.toInteger(); - if (i >= length) + if (i >= length && (e1.op == EXP.arrayLiteral || !indexIsInBounds)) { + // C code only checks bounds if an ArrayLiteralExp e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length); emplaceExp!(ErrorExp)(&ue); } diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d index 3ded10a..2edab14 100644 --- a/gcc/d/dmd/cparse.d +++ b/gcc/d/dmd/cparse.d @@ -22,6 +22,7 @@ import dmd.identifier; import dmd.lexer; import dmd.parse; import dmd.errors; +import dmd.root.array; import dmd.root.filename; import dmd.common.outbuffer; import dmd.root.rmem; @@ -38,6 +39,24 @@ final class CParser(AST) : Parser!AST bool addFuncName; /// add declaration of __func__ to function symbol table bool importBuiltins; /// seen use of C compiler builtins, so import __builtins; + private + { + structalign_t packalign; // current state of #pragma pack alignment + + // #pragma pack stack + Array!Identifier* records; // identifers (or null) + Array!structalign_t* packs; // parallel alignment values + } + + /** C allows declaring a function with a typedef: + * typedef int (myfunc)(); myfunc fun; + * but we need to distinguish `fun` being a function as opposed to a variable in the + * parse pass. This is accomplished by having a simple symbol table of typedefs + * where we know, by syntax, if they are function types or non-function types. + * funcTypeIds is the symbol table, of the identifiers of typedefs of function types. + */ + AST.Identifiers funcTypeIds; /// Identifiers in this are typedefs of function types + extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment, const ref TARGET target) { @@ -47,6 +66,7 @@ final class CParser(AST) : Parser!AST mod = _module; linkage = LINK.c; Ccompile = true; + this.packalign.setDefault(); // Configure sizes for C `long`, `long double`, `wchar_t`, ... this.boolsize = target.boolsize; @@ -130,6 +150,7 @@ final class CParser(AST) : Parser!AST //printf("cparseStatement()\n"); + const funcTypeIdsLengthSave = funcTypeIds.length; auto symbolsSave = symbols; if (!(flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope))) symbols = new AST.Dsymbols(); @@ -572,6 +593,7 @@ final class CParser(AST) : Parser!AST if (pEndloc) *pEndloc = prevloc; symbols = symbolsSave; + funcTypeIds.setDim(funcTypeIdsLengthSave); return s; } @@ -1551,6 +1573,7 @@ final class CParser(AST) : Parser!AST return; } + const funcTypeIdsLengthSave = funcTypeIds.length; auto symbolsSave = symbols; Specifier specifier; specifier.packalign = this.packalign; @@ -1660,11 +1683,13 @@ final class CParser(AST) : Parser!AST t.value == TOK.leftCurly) // start of compound-statement { auto s = cparseFunctionDefinition(id, dt.isTypeFunction(), specifier); + funcTypeIds.setDim(funcTypeIdsLengthSave); symbols = symbolsSave; symbols.push(s); return; } AST.Dsymbol s = null; + funcTypeIds.setDim(funcTypeIdsLengthSave); symbols = symbolsSave; if (!symbols) symbols = new AST.Dsymbols; // lazilly create it @@ -1722,6 +1747,10 @@ final class CParser(AST) : Parser!AST } } } + else if (isFunctionTypedef(dt)) + { + funcTypeIds.push(id); // remember function typedefs + } if (isalias) s = new AST.AliasDeclaration(token.loc, id, dt); } @@ -1743,7 +1772,8 @@ final class CParser(AST) : Parser!AST } // declare the symbol assert(id); - if (dt.isTypeFunction()) + + if (isFunctionTypedef(dt)) { if (hasInitializer) error("no initializer for function declaration"); @@ -4546,5 +4576,238 @@ final class CParser(AST) : Parser!AST return s; } + /******************************** + * Determines if type t is a function type. + * Make this work without needing semantic analysis. + * Params: + * t = type to test + * Returns: + * true if it represents a function + */ + bool isFunctionTypedef(AST.Type t) + { + //printf("isFunctionTypedef() %s\n", t.toChars()); + if (t.isTypeFunction()) + return true; + if (auto tid = t.isTypeIdentifier()) + { + /* Scan array of typedef identifiers that are an alias for + * a function type + */ + foreach (ftid; funcTypeIds[]) + { + if (tid.ident == ftid) + { + return true; + } + } + } + return false; + } + + //} + + /******************************************************************************/ + /********************************* Directive Parser ***************************/ + //{ + + override bool parseSpecialTokenSequence() + { + Token n; + scan(&n); + if (n.value == TOK.int32Literal) + { + poundLine(n, true); + return true; + } + if (n.value == TOK.identifier) + { + if (n.ident == Id.line) + { + poundLine(n, false); + return true; + } + else if (n.ident == Id.__pragma) + { + pragmaDirective(scanloc); + return true; + } + } + error("C preprocessor directive `#%s` is not supported", n.toChars()); + return false; + } + + /********************************************* + * C11 6.10.6 Pragma directive + * # pragma pp-tokens(opt) new-line + * The C preprocessor sometimes leaves pragma directives in + * the preprocessed output. Ignore them. + * Upon return, p is at start of next line. + */ + private void pragmaDirective(const ref Loc loc) + { + Token n; + scan(&n); + if (n.value == TOK.identifier && n.ident == Id.pack) + return pragmaPack(loc); + skipToNextLine(); + } + + /********* + * # pragma pack + * https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html + * https://docs.microsoft.com/en-us/cpp/preprocessor/pack + * Scanner is on the `pack` + * Params: + * startloc = location to use for error messages + */ + private void pragmaPack(const ref Loc startloc) + { + const loc = startloc; + Token n; + scan(&n); + if (n.value != TOK.leftParenthesis) + { + error(loc, "left parenthesis expected to follow `#pragma pack`"); + skipToNextLine(); + return; + } + + void closingParen() + { + if (n.value != TOK.rightParenthesis) + { + error(loc, "right parenthesis expected to close `#pragma pack(`"); + } + skipToNextLine(); + } + + void setPackAlign(ref const Token t) + { + const n = t.unsvalue; + if (n < 1 || n & (n - 1) || ushort.max < n) + error(loc, "pack must be an integer positive power of 2, not 0x%llx", cast(ulong)n); + packalign.set(cast(uint)n); + packalign.setPack(true); + } + + scan(&n); + + if (!records) + { + records = new Array!Identifier; + packs = new Array!structalign_t; + } + + /* # pragma pack ( show ) + */ + if (n.value == TOK.identifier && n.ident == Id.show) + { + if (packalign.isDefault()) + warning(startloc, "current pack attribute is default"); + else + warning(startloc, "current pack attribute is %d", packalign.get()); + scan(&n); + return closingParen(); + } + /* # pragma pack ( push ) + * # pragma pack ( push , identifier ) + * # pragma pack ( push , integer ) + * # pragma pack ( push , identifier , integer ) + */ + if (n.value == TOK.identifier && n.ident == Id.push) + { + scan(&n); + Identifier record = null; + if (n.value == TOK.comma) + { + scan(&n); + if (n.value == TOK.identifier) + { + record = n.ident; + scan(&n); + if (n.value == TOK.comma) + { + scan(&n); + if (n.value == TOK.int32Literal) + { + setPackAlign(n); + scan(&n); + } + else + error(loc, "alignment value expected, not `%s`", n.toChars()); + } + } + else if (n.value == TOK.int32Literal) + { + setPackAlign(n); + scan(&n); + } + else + error(loc, "alignment value expected, not `%s`", n.toChars()); + } + this.records.push(record); + this.packs.push(packalign); + return closingParen(); + } + /* # pragma pack ( pop ) + * # pragma pack ( pop PopList ) + * PopList : + * , IdentifierOrInteger + * , IdentifierOrInteger PopList + * IdentifierOrInteger: + * identifier + * integer + */ + if (n.value == TOK.identifier && n.ident == Id.pop) + { + scan(&n); + while (n.value == TOK.comma) + { + scan(&n); + if (n.value == TOK.identifier) + { + for (size_t len = this.records.length; len; --len) + { + if ((*this.records)[len - 1] == n.ident) + { + packalign = (*this.packs)[len - 1]; + this.records.setDim(len - 1); + this.packs.setDim(len - 1); + break; + } + } + scan(&n); + } + else if (n.value == TOK.int32Literal) + { + setPackAlign(n); + this.records.push(null); + this.packs.push(packalign); + scan(&n); + } + } + return closingParen(); + } + /* # pragma pack ( integer ) + */ + if (n.value == TOK.int32Literal) + { + setPackAlign(n); + scan(&n); + return closingParen(); + } + /* # pragma pack ( ) + */ + if (n.value == TOK.rightParenthesis) + { + packalign.setDefault(); + return closingParen(); + } + + error(loc, "unrecognized `#pragma pack(%s)`", n.toChars()); + skipToNextLine(); + } + //} } diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d index f1afa76..69036ad 100644 --- a/gcc/d/dmd/dcast.d +++ b/gcc/d/dmd/dcast.d @@ -2443,7 +2443,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) { printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars()); } - __gshared const(char)* msg = "cannot form delegate due to covariant return type"; + static immutable msg = "cannot form delegate due to covariant return type"; Type tb = t.toBasetype(); Type typeb = e.type.toBasetype(); @@ -2453,7 +2453,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) int offset; e.func.tookAddressOf++; if (e.func.tintro && e.func.tintro.nextOf().isBaseOf(e.func.type.nextOf(), &offset) && offset) - e.error("%s", msg); + e.error("%s", msg.ptr); auto result = e.copy(); result.type = t; return result; @@ -2469,7 +2469,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) { int offset; if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset) - e.error("%s", msg); + e.error("%s", msg.ptr); if (f != e.func) // if address not already marked as taken f.tookAddressOf++; auto result = new DelegateExp(e.loc, e.e1, f, false, e.vthis2); @@ -2477,7 +2477,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) return result; } if (e.func.tintro) - e.error("%s", msg); + e.error("%s", msg.ptr); } } diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d index ce463c0..15ac8d9 100644 --- a/gcc/d/dmd/dclass.d +++ b/gcc/d/dmd/dclass.d @@ -205,7 +205,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration super(loc, id); - __gshared const(char)* msg = "only object.d can define this reserved class name"; + static immutable msg = "only object.d can define this reserved class name"; if (baseclasses) { @@ -232,37 +232,37 @@ extern (C++) class ClassDeclaration : AggregateDeclaration if (id == Id.TypeInfo) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.dtypeinfo = this; } if (id == Id.TypeInfo_Class) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfoclass = this; } if (id == Id.TypeInfo_Interface) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfointerface = this; } if (id == Id.TypeInfo_Struct) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfostruct = this; } if (id == Id.TypeInfo_Pointer) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfopointer = this; } if (id == Id.TypeInfo_Array) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfoarray = this; } if (id == Id.TypeInfo_StaticArray) @@ -274,61 +274,61 @@ extern (C++) class ClassDeclaration : AggregateDeclaration if (id == Id.TypeInfo_AssociativeArray) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfoassociativearray = this; } if (id == Id.TypeInfo_Enum) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfoenum = this; } if (id == Id.TypeInfo_Function) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfofunction = this; } if (id == Id.TypeInfo_Delegate) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfodelegate = this; } if (id == Id.TypeInfo_Tuple) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfotypelist = this; } if (id == Id.TypeInfo_Const) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfoconst = this; } if (id == Id.TypeInfo_Invariant) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfoinvariant = this; } if (id == Id.TypeInfo_Shared) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfoshared = this; } if (id == Id.TypeInfo_Wild) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfowild = this; } if (id == Id.TypeInfo_Vector) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); Type.typeinfovector = this; } } @@ -336,32 +336,32 @@ extern (C++) class ClassDeclaration : AggregateDeclaration if (id == Id.Object) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); object = this; } if (id == Id.Throwable) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); throwable = this; } if (id == Id.Exception) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); exception = this; } if (id == Id.Error) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); errorException = this; } if (id == Id.cpp_type_info_ptr) { if (!inObject) - error("%s", msg); + error("%s", msg.ptr); cpp_type_info_ptr = this; } diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d index cdf9355..585ac2f0 100644 --- a/gcc/d/dmd/declaration.d +++ b/gcc/d/dmd/declaration.d @@ -29,6 +29,7 @@ import dmd.errors; import dmd.expression; import dmd.func; import dmd.globals; +import dmd.gluelayer; import dmd.id; import dmd.identifier; import dmd.init; @@ -227,6 +228,8 @@ extern (C++) abstract class Declaration : Dsymbol enum wasRead = 1; // set if AliasDeclaration was read enum ignoreRead = 2; // ignore any reads of AliasDeclaration + Symbol* isym; // import version of csym + // overridden symbol with pragma(mangle, "...") const(char)[] mangleOverride; @@ -679,10 +682,12 @@ extern (C++) final class TupleDeclaration : Declaration } /*********************************************************** + * https://dlang.org/spec/declaration.html#AliasDeclaration */ extern (C++) final class AliasDeclaration : Declaration { - Dsymbol aliassym; + Dsymbol aliassym; // alias ident = aliassym; + Dsymbol overnext; // next in overload list Dsymbol _import; // !=null if unresolved internal alias for selective import diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h index e30acb4..93e3a5a 100644 --- a/gcc/d/dmd/declaration.h +++ b/gcc/d/dmd/declaration.h @@ -119,6 +119,7 @@ public: LINK linkage; short inuse; // used to detect cycles uint8_t adFlags; + Symbol* isym; // import version of csym DString mangleOverride; // overridden symbol with pragma(mangle, "...") const char *kind() const; diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d index 6568442..00fa031 100644 --- a/gcc/d/dmd/dmodule.d +++ b/gcc/d/dmd/dmodule.d @@ -675,24 +675,28 @@ extern (C++) final class Module : Package //printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars()); - if (global.params.emitMakeDeps) - { - global.params.makeDeps.push(srcfile.toChars()); - } + + bool success; if (auto readResult = FileManager.fileManager.lookup(srcfile)) { srcBuffer = readResult; - return true; + success = true; } - - auto readResult = File.read(srcfile.toChars()); - if (loadSourceBuffer(loc, readResult)) + else { - FileManager.fileManager.add(srcfile, srcBuffer); - return true; + auto readResult = File.read(srcfile.toChars()); + if (loadSourceBuffer(loc, readResult)) + { + FileManager.fileManager.add(srcfile, srcBuffer); + success = true; + } } - return false; + if (success && global.params.emitMakeDeps) + { + global.params.makeDeps.push(srcfile.toChars()); + } + return success; } /// syntactic parse diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d index 200cb76..f8ada2b 100644 --- a/gcc/d/dmd/dsymbol.d +++ b/gcc/d/dmd/dsymbol.d @@ -245,8 +245,6 @@ extern (C++) class Dsymbol : ASTNode /// C++ namespace this symbol belongs to CPPNamespaceDeclaration cppnamespace; Symbol* csym; // symbol for code generator - Symbol* isym; // import version of csym - const(char)* comment; // documentation comment for this Dsymbol const Loc loc; // where defined Scope* _scope; // !=null means context to use for semantic() const(char)* prettystring; // cached value of toPrettyChars() @@ -257,10 +255,6 @@ extern (C++) class Dsymbol : ASTNode DeprecatedDeclaration depdecl; // customized deprecation message UserAttributeDeclaration userAttribDecl; // user defined attributes - // !=null means there's a ddoc unittest associated with this symbol - // (only use this with ddoc) - UnitTestDeclaration ddocUnittest; - final extern (D) this() { //printf("Dsymbol::Dsymbol(%p)\n", this); @@ -811,7 +805,7 @@ extern (C++) class Dsymbol : ASTNode Dsymbol s2 = sds.symtabLookup(this,ident); // If using C tag/prototype/forward declaration rules - if (sc.flags & SCOPE.Cfile) + if (sc.flags & SCOPE.Cfile && !this.isImport()) { if (handleTagSymbols(*sc, this, s2, sds)) return; @@ -1214,17 +1208,65 @@ extern (C++) class Dsymbol : ASTNode */ void addComment(const(char)* comment) { - //if (comment) - // printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars()); - if (!this.comment) - this.comment = comment; - else if (comment && strcmp(cast(char*)comment, cast(char*)this.comment) != 0) + if (!comment || !*comment) + return; + + //printf("addComment '%s' to Dsymbol %p '%s'\n", comment, this, toChars()); + void* h = cast(void*)this; // just the pointer is the key + auto p = h in commentHashTable; + if (!p) + { + commentHashTable[h] = comment; + return; + } + if (strcmp(*p, comment) != 0) { // Concatenate the two - this.comment = Lexer.combineComments(this.comment.toDString(), comment.toDString(), true); + *p = Lexer.combineComments((*p).toDString(), comment.toDString(), true); } } + /// get documentation comment for this Dsymbol + final const(char)* comment() + { + //printf("getcomment: %p '%s'\n", this, this.toChars()); + if (auto p = cast(void*)this in commentHashTable) + { + //printf("comment: '%s'\n", *p); + return *p; + } + return null; + } + + /* Shell around addComment() to avoid disruption for the moment */ + final void comment(const(char)* comment) { addComment(comment); } + + private extern (D) __gshared const(char)*[void*] commentHashTable; + + + /********************************** + * Get ddoc unittest associated with this symbol. + * (only use this with ddoc) + * Returns: ddoc unittest, null if none + */ + final UnitTestDeclaration ddocUnittest() + { + if (auto p = cast(void*)this in ddocUnittestHashTable) + return *p; + return null; + } + + /********************************** + * Set ddoc unittest associated with this symbol. + */ + final void ddocUnittest(UnitTestDeclaration utd) + { + ddocUnittestHashTable[cast(void*)this] = utd; + } + + private extern (D) __gshared UnitTestDeclaration[void*] ddocUnittestHashTable; + + /**************************************** * Returns true if this symbol is defined in a non-root module without instantiation. */ @@ -1247,6 +1289,18 @@ extern (C++) class Dsymbol : ASTNode return false; } + /** + * Deinitializes the global state of the compiler. + * + * This can be used to restore the state set by `_init` to its original + * state. + */ + static void deinitialize() + { + commentHashTable = commentHashTable.init; + ddocUnittestHashTable = ddocUnittestHashTable.init; + } + /************ */ override void accept(Visitor v) diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h index 03d5c3d..c5af06e 100644 --- a/gcc/d/dmd/dsymbol.h +++ b/gcc/d/dmd/dsymbol.h @@ -175,8 +175,6 @@ public: /// C++ namespace this symbol belongs to CPPNamespaceDeclaration *namespace_; Symbol *csym; // symbol for code generator - Symbol *isym; // import version of csym - const utf8_t *comment; // documentation comment for this Dsymbol Loc loc; // where defined Scope *_scope; // !=NULL means context to use for semantic() const utf8_t *prettystring; @@ -185,7 +183,6 @@ public: unsigned short localNum; // perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab DeprecatedDeclaration *depdecl; // customized deprecation message UserAttributeDeclaration *userAttribDecl; // user defined attributes - UnitTestDeclaration *ddocUnittest; // !=NULL means there's a ddoc unittest associated with this symbol (only use this with ddoc) static Dsymbol *create(Identifier *); const char *toChars() const; @@ -252,6 +249,10 @@ public: virtual void checkCtorConstInit() { } virtual void addComment(const utf8_t *comment); + const utf8_t *comment(); // current value of comment + + UnitTestDeclaration *ddocUnittest(); + void ddocUnittest(UnitTestDeclaration *); bool inNonRoot(); diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d index ef25717..b68d840 100644 --- a/gcc/d/dmd/dsymbolsem.d +++ b/gcc/d/dmd/dsymbolsem.d @@ -2140,6 +2140,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor Module.dprogress++; + // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.100 + // Make an error in 2.110 + if (sc.stc & STC.scope_) + deprecation(ed.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); + Scope* sce; if (ed.isAnonymous()) sce = sc; @@ -3085,6 +3091,25 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor return null; } + if (sc.flags & SCOPE.Cfile) + { + /* C11 allows a function to be declared with a typedef, D does not. + */ + if (auto ti = funcdecl.type.isTypeIdentifier()) + { + auto tj = ti.typeSemantic(funcdecl.loc, sc); + if (auto tjf = tj.isTypeFunction()) + { + /* Copy the type instead of just pointing to it, + * as we don't merge function types + */ + auto tjf2 = new TypeFunction(tjf.parameterList, tjf.next, tjf.linkage); + funcdecl.type = tjf2; + funcdecl.originalType = tjf2; + } + } + } + if (!getFunctionType(funcdecl)) return; @@ -3550,6 +3575,15 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor default: { + if (vi >= cd.vtbl.length) + { + /* the derived class cd doesn't have its vtbl[] allocated yet. + * https://issues.dlang.org/show_bug.cgi?id=21008 + */ + funcdecl.error("circular reference to class `%s`", cd.toChars()); + funcdecl.errors = true; + return; + } FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration(); FuncDeclaration fdc = cd.vtbl[vi].isFuncDeclaration(); // This function is covariant with fdv @@ -4625,6 +4659,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor sd.deferred.semantic2(sc); sd.deferred.semantic3(sc); } + + // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.100 + // Make an error in 2.110 + if (sd.storage_class & STC.scope_) + deprecation(sd.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); } void interfaceSemantic(ClassDeclaration cd) @@ -5283,12 +5323,11 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor } //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this); - // @@@DEPRECATED_2.097@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint - // Deprecated in 2.087 - // Make an error in 2.091 + // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint + // Deprecated in 2.100 + // Make an error in 2.110 // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036 - if (0 && // deprecation disabled for now to accommodate existing extensive use - cldec.storage_class & STC.scope_) + if (cldec.storage_class & STC.scope_) deprecation(cldec.loc, "`scope` as a type constraint is deprecated. Use `scope` at the usage site."); } diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d index 6abe69a..adb91ed 100644 --- a/gcc/d/dmd/dtemplate.d +++ b/gcc/d/dmd/dtemplate.d @@ -7806,10 +7806,10 @@ struct TemplateInstanceBox /* Used when a proposed instance is used to see if there's * an existing instance. */ - static if (__VERSION__ >= 2099) - res = (cast()ti).equalsx(cast()s.ti); - else // https://issues.dlang.org/show_bug.cgi?id=22717 + static if (__VERSION__ < 2099) // https://issues.dlang.org/show_bug.cgi?id=22717 res = (cast()s.ti).equalsx(cast()ti); + else + res = (cast()ti).equalsx(cast()s.ti); } debug (FindExistingInstance) ++(res ? nHits : nCollisions); diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d index a34e2cca..285b834 100644 --- a/gcc/d/dmd/dtoh.d +++ b/gcc/d/dmd/dtoh.d @@ -180,6 +180,15 @@ struct _d_dynamicArray final `); } + // prevent trailing newlines + version (Windows) + while (buf.length >= 4 && buf[$-4..$] == "\r\n\r\n") + buf.remove(buf.length - 2, 2); + else + while (buf.length >= 2 && buf[$-2..$] == "\n\n") + buf.remove(buf.length - 1, 1); + + if (global.params.cxxhdrname is null) { // Write to stdout; assume it succeeds diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d index 35c1f76..be11f26 100644 --- a/gcc/d/dmd/escape.d +++ b/gcc/d/dmd/escape.d @@ -497,7 +497,7 @@ bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag) { Expression arg = (*ce.arguments)[i]; if (!arg.type.hasPointers()) - return false; + continue; //printf("\targ[%d]: %s\n", i, arg.toChars()); @@ -620,7 +620,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag) return false; if (va == fd.vthis) // `this` of a non-static member function is considered to be the first parameter return true; - if (fd.parameters && fd.parameters.length && (*fd.parameters)[0] == va) // va is first parameter + if (!fd.vthis && fd.parameters && fd.parameters.length && (*fd.parameters)[0] == va) // va is first parameter return true; } return false; @@ -1029,7 +1029,6 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) */ !(p.parent == sc.func)) { - // Only look for errors if in module listed on command line if (global.params.useDIP1000 == FeatureState.enabled // https://issues.dlang.org/show_bug.cgi?id=17029 && sc.func.setUnsafe()) // https://issues.dlang.org/show_bug.cgi?id=20868 { @@ -1095,7 +1094,6 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag) continue; // https://dlang.org/spec/function.html#return-ref-parameters - // Only look for errors if in module listed on command line if (p == sc.func) { //printf("escaping reference to local ref variable %s\n", v.toChars()); @@ -1246,7 +1244,6 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) !(!refs && sc.func.isFuncDeclaration().getLevel(pfunc, sc.intypeof) > 0) ) { - // Only look for errors if in module listed on command line // https://issues.dlang.org/show_bug.cgi?id=17029 if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe()) { @@ -1278,11 +1275,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag) { if (log) { - printf("byref `%s`\n", v.toChars()); - if (v.storage_class & STC.return_) printf(" return"); - if (v.storage_class & STC.ref_) printf(" ref"); - if (v.storage_class & STC.scope_) printf(" scope"); - printf("\n"); + printf("byref `%s` %s\n", v.toChars(), toChars(buildScopeRef(v.storage_class))); } // 'featureState' tells us whether to emit an error or a deprecation, @@ -1714,9 +1707,10 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false) { Parameter p = tf.parameterList[i - j]; const stc = tf.parameterStorageClass(null, p); - if ((stc & (STC.scope_)) && (stc & STC.return_)) + ScopeRef psr = buildScopeRef(stc); + if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) arg.accept(this); - else if ((stc & (STC.ref_)) && (stc & STC.return_)) + else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) { if (tf.isref) { @@ -1974,9 +1968,10 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false) { Parameter p = tf.parameterList[i - j]; const stc = tf.parameterStorageClass(null, p); - if ((stc & (STC.out_ | STC.ref_)) && (stc & STC.return_)) + ScopeRef psr = buildScopeRef(stc); + if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) arg.accept(this); - else if ((stc & STC.scope_) && (stc & STC.return_)) + else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) { if (auto de = arg.isDelegateExp()) { diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d index 2b41219..45fefc0 100644 --- a/gcc/d/dmd/expression.d +++ b/gcc/d/dmd/expression.d @@ -72,10 +72,15 @@ import dmd.typesem; import dmd.visitor; enum LOGSEMANTIC = false; + void emplaceExp(T : Expression, Args...)(void* p, Args args) { - scope tmp = new T(args); - memcpy(p, cast(void*)tmp, __traits(classInstanceSize, T)); + static if (__VERSION__ < 2099) + const init = typeid(T).initializer; + else + const init = __traits(initSymbol, T); + p[0 .. __traits(classInstanceSize, T)] = init[]; + (cast(T)p).__ctor(args); } void emplaceExp(T : UnionExp)(T* p, Expression e) @@ -5831,6 +5836,13 @@ extern (C++) final class IndexExp : BinExp //printf("IndexExp::IndexExp('%s')\n", toChars()); } + extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool indexIsInBounds) + { + super(loc, EXP.index, __traits(classInstanceSize, IndexExp), e1, e2); + this.indexIsInBounds = indexIsInBounds; + //printf("IndexExp::IndexExp('%s')\n", toChars()); + } + override IndexExp syntaxCopy() { auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy()); diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d index 6692fb9..f8e5af4 100644 --- a/gcc/d/dmd/expressionsem.d +++ b/gcc/d/dmd/expressionsem.d @@ -5279,6 +5279,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor // The mangling change only works for D mangling } + if (!(sc.flags & SCOPE.Cfile)) { /* https://issues.dlang.org/show_bug.cgi?id=21272 * If we are in a foreach body we need to extract the @@ -7057,19 +7058,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); } } - else if (exp.e1.op == EXP.call) + else if (auto ce = exp.e1.isCallExp()) { - CallExp ce = cast(CallExp)exp.e1; - if (ce.e1.type.ty == Tfunction) - { - TypeFunction tf = cast(TypeFunction)ce.e1.type; - if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) - && tf.next.hasPointers() && sc.func.setUnsafe()) - { - exp.error("cannot take address of `ref return` of `%s()` in `@safe` function `%s`", - ce.e1.toChars(), sc.func.toChars()); - } - } + if (!checkAddressCall(sc, ce, "take address of")) + return setError(); } else if (exp.e1.op == EXP.index) { @@ -7800,7 +7792,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); Type t1b = exp.e1.type.toBasetype(); - if (t1b.ty == Tpointer) + if (auto tp = t1b.isTypePointer()) { if (t1b.isPtrToFunction()) { @@ -7809,7 +7801,27 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } if (!exp.lwr || !exp.upr) { - exp.error("need upper and lower bound to slice pointer"); + exp.error("upper and lower bounds are needed to slice a pointer"); + if (auto ad = isAggregate(tp.next.toBasetype())) + { + auto s = search_function(ad, Id.index); + if (!s) s = search_function(ad, Id.slice); + if (s) + { + auto fd = s.isFuncDeclaration(); + if ((fd && !fd.getParameterList().length) || s.isTemplateDeclaration()) + { + exp.errorSupplemental( + "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`", + exp.e1.toChars(), + s.ident.toChars(), + exp.e1.toChars() + ); + } + + } + } + return setError(); } if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe()) @@ -7844,6 +7856,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (v && !checkAddressVar(sc, exp.e1, v)) return setError(); } + // https://issues.dlang.org/show_bug.cgi?id=22539 + if (auto ce = exp.e1.isCallExp()) + { + if (!checkAddressCall(sc, ce, "slice static array of")) + return setError(); + } } } else if (t1b.ty == Ttuple) @@ -8446,7 +8464,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (length) { auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1)); - exp.indexIsInBounds = bounds.contains(getIntRange(exp.e2)); + // OR it in, because it might already be set for C array indexing + exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2)); } } } @@ -12943,6 +12962,38 @@ bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v) return true; } +/**************************************************** + * Determine if the address of a `ref return` value of + * a function call with type `tf` can be taken safely. + * + * This is currently stricter than necessary: it can be safe to take the + * address of a `ref` with pointer type when the pointer isn't `scope`, but + * that involves inspecting the function arguments and parameter types, which + * is left as a future enhancement. + * + * Params: + * sc = context + * ce = function call in question + * action = for the error message, how the pointer is taken, e.g. "slice static array of" + * Returns: + * `true` if ok, `false` for error + */ +private bool checkAddressCall(Scope* sc, CallExp ce, const(char)* action) +{ + if (auto tf = ce.e1.type.isTypeFunction()) + { + if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) + && tf.next.hasPointers() && sc.func.setUnsafe()) + { + ce.error("cannot %s `ref return` of `%s()` in `@safe` function `%s`", + action, ce.e1.toChars(), sc.func.toChars()); + ce.errorSupplemental("return type `%s` has pointers that may be `scope`", tf.next.toChars()); + return false; + } + } + return true; +} + /******************************* * Checks the attributes of a function. * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`) diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d index a48b339..72e0e1a 100644 --- a/gcc/d/dmd/importc.d +++ b/gcc/d/dmd/importc.d @@ -159,7 +159,8 @@ Expression carraySemantic(ArrayExp ae, Scope* sc) if (t1.isTypeDArray() || t1.isTypeSArray()) { e2 = e2.expressionSemantic(sc).arrayFuncConv(sc); - return new IndexExp(ae.loc, e1, e2).expressionSemantic(sc); + // C doesn't do array bounds checking, so `true` turns it off + return new IndexExp(ae.loc, e1, e2, true).expressionSemantic(sc); } e1 = e1.arrayFuncConv(sc); // e1 might still be a function call @@ -167,7 +168,7 @@ Expression carraySemantic(ArrayExp ae, Scope* sc) auto t2 = e2.type.toBasetype(); if (t2.isTypeDArray() || t2.isTypeSArray()) { - return new IndexExp(ae.loc, e2, e1).expressionSemantic(sc); // swap operands + return new IndexExp(ae.loc, e2, e1, true).expressionSemantic(sc); // swap operands } e2 = e2.arrayFuncConv(sc); diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d index 965b3b4..dbdf6a5 100644 --- a/gcc/d/dmd/lexer.d +++ b/gcc/d/dmd/lexer.d @@ -68,8 +68,6 @@ class Lexer ubyte long_doublesize; /// size of C long double, 8 or D real.sizeof ubyte wchar_tsize; /// size of C wchar_t, 2 or 4 - structalign_t packalign; /// current state of #pragma pack alignment (ImportC) - private { const(char)* base; // pointer to start of buffer @@ -89,10 +87,6 @@ class Lexer int lastDocLine; // last line of previous doc comment Token* tokenFreelist; - - // ImportC #pragma pack stack - Array!Identifier* records; // identifers (or null) - Array!structalign_t* packs; // parallel alignment values } nothrow: @@ -124,7 +118,6 @@ class Lexer this.commentToken = commentToken; this.inTokenStringConstant = 0; this.lastDocLine = 0; - this.packalign.setDefault(); //initKeywords(); /* If first line starts with '#!', ignore the line */ @@ -381,24 +374,18 @@ class Lexer goto case_ident; case 'r': - if (p[1] != '"') + if (Ccompile || p[1] != '"') goto case_ident; p++; goto case '`'; case '`': + if (Ccompile) + goto default; wysiwygStringConstant(t); return; - case 'x': - if (p[1] != '"') - goto case_ident; - p++; - auto start = p; - OutBuffer hexString; - t.value = hexStringConstant(t); - hexString.write(start[0 .. p - start]); - error("Built-in hex string literals are obsolete, use `std.conv.hexString!%s` instead.", hexString.extractChars()); - return; case 'q': + if (Ccompile) + goto case_ident; if (p[1] == '"') { p++; @@ -438,7 +425,7 @@ class Lexer //case 'u': case 'v': case 'w': - /*case 'x':*/ + case 'x': case 'y': case 'z': case 'A': @@ -676,6 +663,7 @@ class Lexer endOfLine(); continue; case '+': + if (!Ccompile) { int nest; startLoc = loc(); @@ -745,6 +733,7 @@ class Lexer } continue; } + break; default: break; } @@ -1051,35 +1040,8 @@ class Lexer case '#': { p++; - Token n; - scan(&n); - if (Ccompile && n.value == TOK.int32Literal) - { - poundLine(n, true); + if (parseSpecialTokenSequence()) continue; - } - if (n.value == TOK.identifier) - { - if (n.ident == Id.line) - { - poundLine(n, false); - continue; - } - else if (n.ident == Id.__pragma && Ccompile) - { - pragmaDirective(scanloc); - continue; - } - else - { - const locx = loc(); - warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars()); - } - } - else if (n.value == TOK.if_) - { - error("C preprocessor directive `#if` is not supported, use `version` or `static if`"); - } t.value = TOK.pound; return; } @@ -1388,84 +1350,6 @@ class Lexer } } - /************************************** - * Lex hex strings: - * x"0A ae 34FE BD" - */ - private TOK hexStringConstant(Token* t) - { - Loc start = loc(); - uint n = 0; - uint v = ~0; // dead assignment, needed to suppress warning - p++; - stringbuffer.setsize(0); - while (1) - { - dchar c = *p++; - switch (c) - { - case ' ': - case '\t': - case '\v': - case '\f': - continue; // skip white space - case '\r': - if (*p == '\n') - continue; // ignore '\r' if followed by '\n' - // Treat isolated '\r' as if it were a '\n' - goto case '\n'; - case '\n': - endOfLine(); - continue; - case 0: - case 0x1A: - error("unterminated string constant starting at %s", start.toChars()); - t.setString(); - // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token). - p--; - return TOK.hexadecimalString; - case '"': - if (n & 1) - { - error("odd number (%d) of hex characters in hex string", n); - stringbuffer.writeByte(v); - } - t.setString(stringbuffer); - stringPostfix(t); - return TOK.hexadecimalString; - default: - 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; - else if (c & 0x80) - { - p--; - const u = decodeUTF(); - p++; - if (u == PS || u == LS) - endOfLine(); - else - error("non-hex character \\u%04x in hex string", u); - } - else - error("non-hex character '%c' in hex string", c); - if (n & 1) - { - v = (v << 4) | c; - stringbuffer.writeByte(v); - } - else - v = c; - n++; - break; - } - } - assert(0); // see bug 15731 - } - /** Lex a delimited string. Some examples of delimited strings are: --- @@ -2666,6 +2550,37 @@ class Lexer va_end(args); } + /*************************************** + * Parse special token sequence: + * Returns: + * true if the special token sequence was handled + * References: + * https://dlang.org/spec/lex.html#special-token-sequence + */ + bool parseSpecialTokenSequence() + { + Token n; + scan(&n); + if (n.value == TOK.identifier) + { + if (n.ident == Id.line) + { + poundLine(n, false); + return true; + } + else + { + const locx = loc(); + warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars()); + } + } + else if (n.value == TOK.if_) + { + error("C preprocessor directive `#if` is not supported, use `version` or `static if`"); + } + return false; + } + /********************************************* * Parse line/file preprocessor directive: * #line linnum [filespec] @@ -2680,7 +2595,7 @@ class Lexer * References: * linemarker https://gcc.gnu.org/onlinedocs/gcc-11.1.0/cpp/Preprocessor-Output.html */ - private void poundLine(ref Token tok, bool linemarker) + final void poundLine(ref Token tok, bool linemarker) { auto linnum = this.scanloc.linnum; const(char)* filespec = null; @@ -2806,183 +2721,10 @@ class Lexer error(loc, "#line integer [\"filespec\"]\\n expected"); } - /********************************************* - * C11 6.10.6 Pragma directive - * # pragma pp-tokens(opt) new-line - * The C preprocessor sometimes leaves pragma directives in - * the preprocessed output. Ignore them. - * Upon return, p is at start of next line. - */ - private void pragmaDirective(const ref Loc loc) - { - Token n; - scan(&n); - if (n.value == TOK.identifier && n.ident == Id.pack) - return pragmaPack(loc); - skipToNextLine(); - } - - /********* - * ImportC - * # pragma pack - * https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html - * https://docs.microsoft.com/en-us/cpp/preprocessor/pack - * Scanner is on the `pack` - * Params: - * startloc = location to use for error messages - */ - private void pragmaPack(const ref Loc startloc) - { - const loc = startloc; - Token n; - scan(&n); - if (n.value != TOK.leftParenthesis) - { - error(loc, "left parenthesis expected to follow `#pragma pack`"); - skipToNextLine(); - return; - } - - void closingParen() - { - if (n.value != TOK.rightParenthesis) - { - error(loc, "right parenthesis expected to close `#pragma pack(`"); - } - skipToNextLine(); - } - - void setPackAlign(ref const Token t) - { - const n = t.unsvalue; - if (n < 1 || n & (n - 1) || ushort.max < n) - error(loc, "pack must be an integer positive power of 2, not 0x%llx", cast(ulong)n); - packalign.set(cast(uint)n); - packalign.setPack(true); - } - - scan(&n); - - if (!records) - { - records = new Array!Identifier; - packs = new Array!structalign_t; - } - - /* # pragma pack ( show ) - */ - if (n.value == TOK.identifier && n.ident == Id.show) - { - if (packalign.isDefault()) - warning(startloc, "current pack attribute is default"); - else - warning(startloc, "current pack attribute is %d", packalign.get()); - scan(&n); - return closingParen(); - } - /* # pragma pack ( push ) - * # pragma pack ( push , identifier ) - * # pragma pack ( push , integer ) - * # pragma pack ( push , identifier , integer ) - */ - if (n.value == TOK.identifier && n.ident == Id.push) - { - scan(&n); - Identifier record = null; - if (n.value == TOK.comma) - { - scan(&n); - if (n.value == TOK.identifier) - { - record = n.ident; - scan(&n); - if (n.value == TOK.comma) - { - scan(&n); - if (n.value == TOK.int32Literal) - { - setPackAlign(n); - scan(&n); - } - else - error(loc, "alignment value expected, not `%s`", n.toChars()); - } - } - else if (n.value == TOK.int32Literal) - { - setPackAlign(n); - scan(&n); - } - else - error(loc, "alignment value expected, not `%s`", n.toChars()); - } - this.records.push(record); - this.packs.push(packalign); - return closingParen(); - } - /* # pragma pack ( pop ) - * # pragma pack ( pop PopList ) - * PopList : - * , IdentifierOrInteger - * , IdentifierOrInteger PopList - * IdentifierOrInteger: - * identifier - * integer - */ - if (n.value == TOK.identifier && n.ident == Id.pop) - { - scan(&n); - while (n.value == TOK.comma) - { - scan(&n); - if (n.value == TOK.identifier) - { - for (size_t len = this.records.length; len; --len) - { - if ((*this.records)[len - 1] == n.ident) - { - packalign = (*this.packs)[len - 1]; - this.records.setDim(len - 1); - this.packs.setDim(len - 1); - break; - } - } - scan(&n); - } - else if (n.value == TOK.int32Literal) - { - setPackAlign(n); - this.records.push(null); - this.packs.push(packalign); - scan(&n); - } - } - return closingParen(); - } - /* # pragma pack ( integer ) - */ - if (n.value == TOK.int32Literal) - { - setPackAlign(n); - scan(&n); - return closingParen(); - } - /* # pragma pack ( ) - */ - if (n.value == TOK.rightParenthesis) - { - packalign.setDefault(); - return closingParen(); - } - - error(loc, "unrecognized `#pragma pack(%s)`", n.toChars()); - skipToNextLine(); - } - /*************************************** * Scan forward to start of next line. */ - private void skipToNextLine() + final void skipToNextLine() { while (1) { @@ -3557,5 +3299,3 @@ unittest assert(tok == TOK.endOfFile); } } - - diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d index 9297ad9..18af772 100644 --- a/gcc/d/dmd/mtype.d +++ b/gcc/d/dmd/mtype.d @@ -4214,6 +4214,7 @@ extern (C++) final class TypeFunction : TypeNext inoutParam = 0x0400, // inout on the parameters inoutQual = 0x0800, // inout on the qualifier isctor = 0x1000, // the function is a constructor + isreturnscope = 0x2000, // `this` is returned by value } LINK linkage; // calling convention @@ -4247,6 +4248,8 @@ extern (C++) final class TypeFunction : TypeNext this.isref = true; if (stc & STC.return_) this.isreturn = true; + if (stc & STC.returnScope) + this.isreturnscope = true; if (stc & STC.returninferred) this.isreturninferred = true; if (stc & STC.scope_) @@ -4285,6 +4288,7 @@ extern (C++) final class TypeFunction : TypeNext t.isproperty = isproperty; t.isref = isref; t.isreturn = isreturn; + t.isreturnscope = isreturnscope; t.isScopeQual = isScopeQual; t.isreturninferred = isreturninferred; t.isscopeinferred = isscopeinferred; @@ -4507,6 +4511,7 @@ extern (C++) final class TypeFunction : TypeNext tf.isproperty = t.isproperty; tf.isref = t.isref; tf.isreturn = t.isreturn; + tf.isreturnscope = t.isreturnscope; tf.isScopeQual = t.isScopeQual; tf.isreturninferred = t.isreturninferred; tf.isscopeinferred = t.isscopeinferred; @@ -4573,6 +4578,7 @@ extern (C++) final class TypeFunction : TypeNext t.isproperty = isproperty; t.isref = isref; t.isreturn = isreturn; + t.isreturnscope = isreturnscope; t.isScopeQual = isScopeQual; t.isreturninferred = isreturninferred; t.isscopeinferred = isscopeinferred; @@ -5136,6 +5142,18 @@ extern (C++) final class TypeFunction : TypeNext else funcFlags &= ~FunctionFlag.isreturn; } + /// set or get if the function has the `returnscope` attribute + bool isreturnscope() const pure nothrow @safe @nogc + { + return (funcFlags & FunctionFlag.isreturnscope) != 0; + } + /// ditto + void isreturnscope(bool v) pure nothrow @safe @nogc + { + if (v) funcFlags |= FunctionFlag.isreturnscope; + else funcFlags &= ~FunctionFlag.isreturnscope; + } + /// set or get if the function has the `scope` attribute bool isScopeQual() const pure nothrow @safe @nogc { @@ -6384,7 +6402,7 @@ extern (C++) final class TypeClass : Type /* Conversion derived to const(base) */ int offset = 0; - if (to.isBaseOf(this, &offset) && MODimplicitConv(mod, to.mod)) + if (to.isBaseOf(this, &offset) && offset == 0 && MODimplicitConv(mod, to.mod)) { // Disallow: // derived to base diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h index cb60236..3f085b0 100644 --- a/gcc/d/dmd/mtype.h +++ b/gcc/d/dmd/mtype.h @@ -625,6 +625,8 @@ public: void isref(bool v); bool isreturn() const; void isreturn(bool v); + bool isreturnscope() const; + void isreturnscope(bool v); bool isScopeQual() const; void isScopeQual(bool v); bool isreturninferred() const; diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d index 01708d6..fc64377 100644 --- a/gcc/d/dmd/opover.d +++ b/gcc/d/dmd/opover.d @@ -396,13 +396,10 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) fd = search_function(ad, id); if (fd) { - // @@@DEPRECATED_2.098@@@. - // Deprecated in 2.088 - // Make an error in 2.098 - e.deprecation("`%s` is deprecated. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); - // Rewrite +e1 as e1.add() - result = build_overload(e.loc, sc, e.e1, null, fd); - return result; + // @@@DEPRECATED_2.110@@@. + // Deprecated in 2.088, made an error in 2.100 + e.error("`%s` is obsolete. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); + return ErrorExp.get(); } } // Didn't find it. Forward to aliasthis @@ -670,13 +667,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) s = search_function(ad1, id); if (s && id != Id.assign) { - // @@@DEPRECATED_2.098@@@. - // Deprecated in 2.088 - // Make an error in 2.098 + // @@@DEPRECATED_2.110@@@. + // Deprecated in 2.088, made an error in 2.100 if (id == Id.postinc || id == Id.postdec) - e.deprecation("`%s` is deprecated. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); + e.error("`%s` is obsolete. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); else - e.deprecation("`%s` is deprecated. Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); + e.error("`%s` is obsolete. Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr); + return ErrorExp.get(); } } if (ad2 && id_r) @@ -689,10 +686,10 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) s_r = null; if (s_r) { - // @@@DEPRECATED_2.098@@@. - // Deprecated in 2.088 - // Make an error in 2.098 - e.deprecation("`%s` is deprecated. Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), EXPtoString(e.op).ptr); + // @@@DEPRECATED_2.110@@@. + // Deprecated in 2.088, made an error in 2.100 + e.error("`%s` is obsolete. Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), EXPtoString(e.op).ptr); + return ErrorExp.get(); } } } @@ -1232,12 +1229,12 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null) s = search_function(ad1, id); if (s) { - // @@@DEPRECATED_2.098@@@. - // Deprecated in 2.088 - // Make an error in 2.098 + // @@@DEPRECATED_2.110@@@. + // Deprecated in 2.088, made an error in 2.100 scope char[] op = EXPtoString(e.op).dup; op[$-1] = '\0'; // remove trailing `=` - e.deprecation("`%s` is deprecated. Use `opOpAssign(string op)(...) if (op == \"%s\")` instead.", id.toChars(), op.ptr); + e.error("`%s` is obsolete. Use `opOpAssign(string op)(...) if (op == \"%s\")` instead.", id.toChars(), op.ptr); + return ErrorExp.get(); } } @@ -1552,7 +1549,8 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out * Params: * fes = the foreach statement * sc = context - * sapply = null or opApply or delegate + * sapply = null or opApply or delegate, overload resolution has not been done. + * Do overload resolution on sapply. * Returns: * false for errors */ @@ -1588,8 +1586,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply) */ if (FuncDeclaration fd = sapply.isFuncDeclaration()) { - auto fdapply = findBestOpApplyMatch(ethis, fd, fes.parameters); - if (fdapply) + if (auto fdapply = findBestOpApplyMatch(ethis, fd, fes.parameters)) { // Fill in any missing types on foreach parameters[] matchParamsToOpApply(fdapply.type.isTypeFunction(), fes.parameters, true); @@ -1598,7 +1595,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply) } return false; } - return sapply !is null; + return true; // shouldn't this be false? } Parameter p = (*fes.parameters)[0]; diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d index 10c265f..cc02bd9 100644 --- a/gcc/d/dmd/optimize.d +++ b/gcc/d/dmd/optimize.d @@ -338,9 +338,9 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) void visitTuple(TupleExp e) { expOptimize(e.e0, WANTvalue); - for (size_t i = 0; i < e.exps.dim; i++) + foreach (ref ex; (*e.exps)[]) { - expOptimize((*e.exps)[i], WANTvalue); + expOptimize(ex, WANTvalue); } } @@ -349,9 +349,9 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) if (e.elements) { expOptimize(e.basis, result & WANTexpand); - for (size_t i = 0; i < e.elements.dim; i++) + foreach (ref ex; (*e.elements)[]) { - expOptimize((*e.elements)[i], result & WANTexpand); + expOptimize(ex, result & WANTexpand); } } } @@ -359,9 +359,9 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) void visitAssocArrayLiteral(AssocArrayLiteralExp e) { assert(e.keys.dim == e.values.dim); - for (size_t i = 0; i < e.keys.dim; i++) + foreach (i, ref ekey; (*e.keys)[]) { - expOptimize((*e.keys)[i], result & WANTexpand); + expOptimize(ekey, result & WANTexpand); expOptimize((*e.values)[i], result & WANTexpand); } } @@ -374,9 +374,9 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) e.stageflags |= stageOptimize; if (e.elements) { - for (size_t i = 0; i < e.elements.dim; i++) + foreach (ref ex; (*e.elements)[]) { - expOptimize((*e.elements)[i], result & WANTexpand); + expOptimize(ex, result & WANTexpand); } } e.stageflags = old; @@ -647,9 +647,9 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) // Optimize parameters if (e.arguments) { - for (size_t i = 0; i < e.arguments.dim; i++) + foreach (ref arg; (*e.arguments)[]) { - expOptimize((*e.arguments)[i], WANTvalue); + expOptimize(arg, WANTvalue); } } } @@ -663,16 +663,16 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) if (e.arguments) { Type t1 = e.e1.type.toBasetype(); - if (t1.ty == Tdelegate) - t1 = t1.nextOf(); + if (auto td = t1.isTypeDelegate()) + t1 = td.next; // t1 can apparently be void for __ArrayDtor(T) calls if (auto tf = t1.isTypeFunction()) { - for (size_t i = 0; i < e.arguments.dim; i++) + foreach (i, ref arg; (*e.arguments)[]) { Parameter p = tf.parameterList[i]; bool keep = p && p.isReference(); - expOptimize((*e.arguments)[i], WANTvalue, keep); + expOptimize(arg, WANTvalue, keep); } } } @@ -719,14 +719,17 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) } } - if (e.e1.op == EXP.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant) + // Returning e.e1 with changing its type + void returnE_e1() { - //printf(" returning2 %s\n", e.e1.toChars()); - L1: - // Returning e1 with changing its type ret = (e1old == e.e1 ? e.e1.copy() : e.e1); ret.type = e.type; - return; + } + + if (e.e1.op == EXP.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant) + { + //printf(" returning2 %s\n", e.e1.toChars()); + return returnE_e1(); } /* The first test here is to prevent infinite loops */ @@ -738,7 +741,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) if (e.e1.op == EXP.null_ && (e.type.ty == Tpointer || e.type.ty == Tclass || e.type.ty == Tarray)) { //printf(" returning3 %s\n", e.e1.toChars()); - goto L1; + return returnE_e1(); } if (e.type.ty == Tclass && e.e1.type.ty == Tclass) { @@ -750,7 +753,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) if (cdfrom.errors || cdto.errors) return error(); if (cdto == ClassDeclaration.object && !cdfrom.isInterfaceDeclaration()) - goto L1; // can always convert a class to Object + return returnE_e1(); // can always convert a class to Object // Need to determine correct offset before optimizing away the cast. // https://issues.dlang.org/show_bug.cgi?id=16980 cdfrom.size(e.loc); @@ -760,13 +763,13 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) if (cdto.isBaseOf(cdfrom, &offset) && offset == 0) { //printf(" returning4 %s\n", e.e1.toChars()); - goto L1; + return returnE_e1(); } } if (e.e1.type.mutableOf().unSharedOf().equals(e.to.mutableOf().unSharedOf())) { //printf(" returning5 %s\n", e.e1.toChars()); - goto L1; + return returnE_e1(); } if (e.e1.isConst()) { @@ -781,7 +784,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) return error(); if (esz == e1sz) - goto L1; + return returnE_e1(); } return; } @@ -1065,7 +1068,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue) // Don't optimize to an array literal element directly in case an lvalue is requested if (keepLvalue && ex.op == EXP.arrayLiteral) return; - ret = Index(e.type, ex, e.e2).copy(); + ret = Index(e.type, ex, e.e2, e.indexIsInBounds).copy(); if (CTFEExp.isCantExp(ret) || (!ret.isErrorExp() && keepLvalue && !ret.isLvalue())) ret = e; } diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d index e83b326..480a96c 100644 --- a/gcc/d/dmd/parse.d +++ b/gcc/d/dmd/parse.d @@ -1971,7 +1971,6 @@ class Parser(AST) : Lexer case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: - case TOK.hexadecimalString: case TOK.file: case TOK.fileFullPath: case TOK.line: @@ -5623,7 +5622,6 @@ LagainStc: case TOK.true_: case TOK.false_: case TOK.string_: - case TOK.hexadecimalString: case TOK.leftParenthesis: case TOK.cast_: case TOK.mul: @@ -7106,7 +7104,6 @@ LagainStc: case TOK.wcharLiteral: case TOK.dcharLiteral: case TOK.string_: - case TOK.hexadecimalString: case TOK.file: case TOK.fileFullPath: case TOK.line: @@ -7987,7 +7984,6 @@ LagainStc: break; case TOK.string_: - case TOK.hexadecimalString: { // cat adjacent strings auto s = token.ustring; @@ -7997,7 +7993,7 @@ LagainStc: { const prev = token; nextToken(); - if (token.value == TOK.string_ || token.value == TOK.hexadecimalString) + if (token.value == TOK.string_) { if (token.postfix) { diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d index 88520e8..f229918 100644 --- a/gcc/d/dmd/statementsem.d +++ b/gcc/d/dmd/statementsem.d @@ -866,7 +866,6 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor assert(t.ty == Tdelegate); tfld = cast(TypeFunction)t.nextOf(); } - //printf("tfld = %s\n", tfld.toChars()); } } } @@ -1442,12 +1441,12 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor /* Call: * _aApply(aggr, flde) */ - __gshared const(char)** fntab = + static immutable fntab = [ "cc", "cw", "cd", "wc", "cc", "wd", "dc", "dw", "dd" - ]; + ]; const(size_t) BUFFER_LEN = 7 + 1 + 2 + dim.sizeof * 3 + 1; char[BUFFER_LEN] fdname; @@ -1470,7 +1469,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor assert(0); } const(char)* r = (fs.op == TOK.foreach_reverse_) ? "R" : ""; - int j = sprintf(fdname.ptr, "_aApply%s%.*s%llu", r, 2, fntab[flag], cast(ulong)dim); + int j = sprintf(fdname.ptr, "_aApply%s%.*s%llu", r, 2, fntab[flag].ptr, cast(ulong)dim); assert(j < BUFFER_LEN); FuncDeclaration fdapply; @@ -2475,68 +2474,66 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor Expression initialExp = cs.exp; // The switch'ed value has errors and doesn't provide the actual type - // Don't touch the case to not replace it with an `ErrorExp` even if it is valid + // Omit the cast to enable further semantic (exluding the check for matching types) if (sw.condition.type && !sw.condition.type.isTypeError()) - { cs.exp = cs.exp.implicitCastTo(sc, sw.condition.type); - cs.exp = cs.exp.optimize(WANTvalue | WANTexpand); + cs.exp = cs.exp.optimize(WANTvalue | WANTexpand); + + Expression e = cs.exp; + // Remove all the casts the user and/or implicitCastTo may introduce + // otherwise we'd sometimes fail the check below. + while (e.op == EXP.cast_) + e = (cast(CastExp)e).e1; + + /* This is where variables are allowed as case expressions. + */ + if (e.op == EXP.variable) + { + VarExp ve = cast(VarExp)e; + VarDeclaration v = ve.var.isVarDeclaration(); + Type t = cs.exp.type.toBasetype(); + if (v && (t.isintegral() || t.ty == Tclass)) + { + /* Flag that we need to do special code generation + * for this, i.e. generate a sequence of if-then-else + */ + sw.hasVars = 1; + + /* TODO check if v can be uninitialized at that point. + */ + if (!v.isConst() && !v.isImmutable()) + { + cs.error("`case` variables have to be `const` or `immutable`"); + } - Expression e = cs.exp; - // Remove all the casts the user and/or implicitCastTo may introduce - // otherwise we'd sometimes fail the check below. - while (e.op == EXP.cast_) - e = (cast(CastExp)e).e1; + if (sw.isFinal) + { + cs.error("`case` variables not allowed in `final switch` statements"); + errors = true; + } - /* This is where variables are allowed as case expressions. - */ - if (e.op == EXP.variable) - { - VarExp ve = cast(VarExp)e; - VarDeclaration v = ve.var.isVarDeclaration(); - Type t = cs.exp.type.toBasetype(); - if (v && (t.isintegral() || t.ty == Tclass)) + /* Find the outermost scope `scx` that set `sw`. + * Then search scope `scx` for a declaration of `v`. + */ + for (Scope* scx = sc; scx; scx = scx.enclosing) { - /* Flag that we need to do special code generation - * for this, i.e. generate a sequence of if-then-else - */ - sw.hasVars = 1; - - /* TODO check if v can be uninitialized at that point. - */ - if (!v.isConst() && !v.isImmutable()) - { - cs.error("`case` variables have to be `const` or `immutable`"); - } + if (scx.enclosing && scx.enclosing.sw == sw) + continue; + assert(scx.sw == sw); - if (sw.isFinal) + if (!scx.search(cs.exp.loc, v.ident, null)) { - cs.error("`case` variables not allowed in `final switch` statements"); + cs.error("`case` variable `%s` declared at %s cannot be declared in `switch` body", + v.toChars(), v.loc.toChars()); errors = true; } - - /* Find the outermost scope `scx` that set `sw`. - * Then search scope `scx` for a declaration of `v`. - */ - for (Scope* scx = sc; scx; scx = scx.enclosing) - { - if (scx.enclosing && scx.enclosing.sw == sw) - continue; - assert(scx.sw == sw); - - if (!scx.search(cs.exp.loc, v.ident, null)) - { - cs.error("`case` variable `%s` declared at %s cannot be declared in `switch` body", - v.toChars(), v.loc.toChars()); - errors = true; - } - break; - } - goto L1; + break; } + goto L1; } - else - cs.exp = cs.exp.ctfeInterpret(); } + else + cs.exp = cs.exp.ctfeInterpret(); if (StringExp se = cs.exp.toStringExp()) cs.exp = se; diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d index 0b1d158..6e56eb2 100644 --- a/gcc/d/dmd/tokens.d +++ b/gcc/d/dmd/tokens.d @@ -124,7 +124,6 @@ enum TOK : ubyte // Leaf operators identifier, string_, - hexadecimalString, this_, super_, error, @@ -854,8 +853,6 @@ extern (C++) struct Token TOK.wchar_tLiteral: "wchar_tv", TOK.whitespace: "whitespace", - TOK.hexadecimalString: "xstring", - // C only keywords TOK.inline : "inline", TOK.register : "register", @@ -1008,24 +1005,6 @@ nothrow: p = buf.extractSlice().ptr; } break; - case TOK.hexadecimalString: - { - OutBuffer buf; - buf.writeByte('x'); - buf.writeByte('"'); - foreach (size_t i; 0 .. len) - { - if (i) - buf.writeByte(' '); - buf.printf("%02x", ustring[i]); - } - buf.writeByte('"'); - if (postfix) - buf.writeByte(postfix); - buf.writeByte(0); - p = buf.extractSlice().ptr; - break; - } case TOK.identifier: case TOK.enum_: case TOK.struct_: diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h index 6dfd0ce..c404cab 100644 --- a/gcc/d/dmd/tokens.h +++ b/gcc/d/dmd/tokens.h @@ -133,7 +133,6 @@ enum class TOK : unsigned char // Leaf operators identifier, string_, - hexadecimalString, this_, super_, error, diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d index 1f03836..57188af 100644 --- a/gcc/d/dmd/typesem.d +++ b/gcc/d/dmd/typesem.d @@ -666,9 +666,13 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) Type visitType(Type t) { + // @@@DEPRECATED_2.110@@@ + // Use of `cent` and `ucent` has always been an error. + // Starting from 2.100, recommend core.int128 as a replace for the + // lack of compiler support. if (t.ty == Tint128 || t.ty == Tuns128) { - .error(loc, "`cent` and `ucent` types not implemented"); + .error(loc, "`cent` and `ucent` types are obsolete, use `core.int128.Cent` instead"); return error(); } @@ -1188,6 +1192,8 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc) tf.isref = true; if (sc.stc & STC.return_) tf.isreturn = true; + if (sc.stc & STC.returnScope) + tf.isreturnscope = true; if (sc.stc & STC.returninferred) tf.isreturninferred = true; if (sc.stc & STC.scope_) @@ -3828,10 +3834,10 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag) * e.opDot().ident */ e = build_overload(e.loc, sc, e, null, fd); - // @@@DEPRECATED_2.092@@@. - e.deprecation("`opDot` is deprecated. Use `alias this`"); - e = new DotIdExp(e.loc, e, ident); - return returnExp(e.expressionSemantic(sc)); + // @@@DEPRECATED_2.110@@@. + // Deprecated in 2.082, made an error in 2.100. + e.error("`opDot` is obsolete. Use `alias this`"); + return ErrorExp.get(); } /* Look for overloaded opDispatch to see if we should forward request diff --git a/gcc/d/imports.cc b/gcc/d/imports.cc index 29c0fbf..6747ee5 100644 --- a/gcc/d/imports.cc +++ b/gcc/d/imports.cc @@ -106,20 +106,20 @@ public: tree type = build_ctype (d->type); /* Not all kinds of D enums create a TYPE_DECL. */ if (TREE_CODE (type) == ENUMERAL_TYPE) - d->isym = this->make_import (TYPE_STUB_DECL (type)); + this->result_ = this->make_import (TYPE_STUB_DECL (type)); } void visit (AggregateDeclaration *d) { tree type = build_ctype (d->type); - d->isym = this->make_import (TYPE_STUB_DECL (type)); + this->result_ = this->make_import (TYPE_STUB_DECL (type)); } void visit (ClassDeclaration *d) { /* Want the RECORD_TYPE, not POINTER_TYPE. */ tree type = TREE_TYPE (build_ctype (d->type)); - d->isym = this->make_import (TYPE_STUB_DECL (type)); + this->result_ = this->make_import (TYPE_STUB_DECL (type)); } /* For now, ignore importing other kinds of dsymbols. */ |