aboutsummaryrefslogtreecommitdiff
path: root/gcc/d
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2022-03-13 12:28:05 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2022-03-13 13:20:02 +0100
commit7e28750395889d16a9cba49cd5935ced7dc00ce8 (patch)
treed2a981788cda569e1a226540c009c09ea1b4ac73 /gcc/d
parent1b85638affe6c987a33427c54e0369b819cd7915 (diff)
downloadgcc-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/MERGE2
-rw-r--r--gcc/d/dmd/VERSION2
-rw-r--r--gcc/d/dmd/common/outbuffer.d35
-rw-r--r--gcc/d/dmd/constfold.d5
-rw-r--r--gcc/d/dmd/cparse.d265
-rw-r--r--gcc/d/dmd/dcast.d8
-rw-r--r--gcc/d/dmd/dclass.d44
-rw-r--r--gcc/d/dmd/declaration.d7
-rw-r--r--gcc/d/dmd/declaration.h1
-rw-r--r--gcc/d/dmd/dmodule.d26
-rw-r--r--gcc/d/dmd/dsymbol.d80
-rw-r--r--gcc/d/dmd/dsymbol.h7
-rw-r--r--gcc/d/dmd/dsymbolsem.d49
-rw-r--r--gcc/d/dmd/dtemplate.d6
-rw-r--r--gcc/d/dmd/dtoh.d9
-rw-r--r--gcc/d/dmd/escape.d23
-rw-r--r--gcc/d/dmd/expression.d16
-rw-r--r--gcc/d/dmd/expressionsem.d81
-rw-r--r--gcc/d/dmd/importc.d5
-rw-r--r--gcc/d/dmd/lexer.d344
-rw-r--r--gcc/d/dmd/mtype.d20
-rw-r--r--gcc/d/dmd/mtype.h2
-rw-r--r--gcc/d/dmd/opover.d45
-rw-r--r--gcc/d/dmd/optimize.d53
-rw-r--r--gcc/d/dmd/parse.d6
-rw-r--r--gcc/d/dmd/statementsem.d105
-rw-r--r--gcc/d/dmd/tokens.d21
-rw-r--r--gcc/d/dmd/tokens.h1
-rw-r--r--gcc/d/dmd/typesem.d16
-rw-r--r--gcc/d/imports.cc6
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. */