aboutsummaryrefslogtreecommitdiff
path: root/gcc/d
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2022-04-21 14:25:26 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2022-04-21 20:03:08 +0100
commitae56e2da05e823e63972aff3118a659d7ca7a8b9 (patch)
tree13932a03f44d3892b2ea8accebe7e55fed6142e0 /gcc/d
parent93dd7f36f2066ec52137178ee52052f293e5e743 (diff)
downloadgcc-ae56e2da05e823e63972aff3118a659d7ca7a8b9.zip
gcc-ae56e2da05e823e63972aff3118a659d7ca7a8b9.tar.gz
gcc-ae56e2da05e823e63972aff3118a659d7ca7a8b9.tar.bz2
d: Merge upstream dmd eb7bee331, druntime 27834edb, phobos ac296f80c.
D front-end changes: - Import dmd v2.100.0-beta.1. - Print deprecation messages for scope violations unless `-frevert=dip1000' is used. - Fixed a missed case of switch case fallthrough not being caught by the compiler. D runtime changes: - Import druntime v2.100.0-beta.1. Phobos changes: - Import phobos v2.100.0-beta.1. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd eb7bee331. * dmd/VERSION: Update version to v2.100.0-beta.1. * d-lang.cc (d_handle_option): Handle OPT_frevert_dip1000. * lang.opt (frevert=dip1000): New option. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 27834edb. * src/MERGE: Merge upstream phobos ac296f80c. * src/Makefile.am (PHOBOS_DSOURCES): Add std/int128.d. * src/Makefile.in: Regenerate.
Diffstat (limited to 'gcc/d')
-rw-r--r--gcc/d/d-lang.cc5
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/VERSION2
-rw-r--r--gcc/d/dmd/aggregate.d22
-rw-r--r--gcc/d/dmd/astenums.d1
-rw-r--r--gcc/d/dmd/blockexit.d15
-rw-r--r--gcc/d/dmd/clone.d6
-rw-r--r--gcc/d/dmd/cparse.d22
-rw-r--r--gcc/d/dmd/declaration.d18
-rw-r--r--gcc/d/dmd/dmodule.d6
-rw-r--r--gcc/d/dmd/dsymbol.d4
-rw-r--r--gcc/d/dmd/dsymbolsem.d9
-rw-r--r--gcc/d/dmd/errors.d16
-rw-r--r--gcc/d/dmd/escape.d61
-rw-r--r--gcc/d/dmd/expression.d11
-rw-r--r--gcc/d/dmd/expression.h2
-rw-r--r--gcc/d/dmd/expressionsem.d29
-rw-r--r--gcc/d/dmd/initsem.d8
-rw-r--r--gcc/d/dmd/lexer.d55
-rw-r--r--gcc/d/dmd/mtype.d92
-rw-r--r--gcc/d/dmd/mtype.h2
-rw-r--r--gcc/d/dmd/optimize.d13
-rw-r--r--gcc/d/dmd/parse.d98
-rw-r--r--gcc/d/dmd/statement.d8
-rw-r--r--gcc/d/dmd/transitivevisitor.d4
-rw-r--r--gcc/d/dmd/typesem.d11
-rw-r--r--gcc/d/dmd/utils.d2
-rw-r--r--gcc/d/lang.opt4
28 files changed, 329 insertions, 199 deletions
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 6957162..9adcabd 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -637,12 +637,17 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
break;
case OPT_frevert_all:
+ global.params.useDIP1000 = FeatureState::disabled;
global.params.useDIP25 = FeatureState::disabled;
global.params.dtorFields = FeatureState::disabled;
global.params.fix16997 = !value;
global.params.markdown = !value;
break;
+ case OPT_frevert_dip1000:
+ global.params.useDIP1000 = FeatureState::disabled;
+ break;
+
case OPT_frevert_dip25:
global.params.useDIP25 = FeatureState::disabled;
break;
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index f36d65e..2bc9b95 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-4d1bfcf142928cf1c097b0a2689485c1b14f4f53
+eb7bee331a13026eeb4dcbf9d43d5d4e744a4d26
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 28a3609..2450fd5 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@
-v2.099.1
+v2.100.0-beta.1
diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d
index 8895aa5..f4b5e8a 100644
--- a/gcc/d/dmd/aggregate.d
+++ b/gcc/d/dmd/aggregate.d
@@ -58,6 +58,28 @@ enum ClassKind : ubyte
}
/**
+ * Give a nice string for a class kind for error messages
+ * Params:
+ * c = class kind
+ * Returns:
+ * 0-terminated string for `c`
+ */
+const(char)* toChars(ClassKind c)
+{
+ final switch (c)
+ {
+ case ClassKind.d:
+ return "D";
+ case ClassKind.cpp:
+ return "C++";
+ case ClassKind.objc:
+ return "Objective-C";
+ case ClassKind.c:
+ return "C";
+ }
+}
+
+/**
* If an aggregate has a pargma(mangle, ...) this holds the information
* to mangle.
*/
diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d
index 1a2cf8b..bf19693 100644
--- a/gcc/d/dmd/astenums.d
+++ b/gcc/d/dmd/astenums.d
@@ -28,6 +28,7 @@ enum Baseok : ubyte
enum MODFlags : int
{
+ none = 0, // default (mutable)
const_ = 1, // type is const
immutable_ = 4, // type is immutable
shared_ = 2, // type is shared
diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d
index afd7ac0..22c9dde 100644
--- a/gcc/d/dmd/blockexit.d
+++ b/gcc/d/dmd/blockexit.d
@@ -139,16 +139,21 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
// Allow if last case/default was empty
CaseStatement sc = slast.isCaseStatement();
DefaultStatement sd = slast.isDefaultStatement();
- if (sc && (!sc.statement.hasCode() || sc.statement.isCaseStatement() || sc.statement.isErrorStatement()))
- {
- }
- else if (sd && (!sd.statement.hasCode() || sd.statement.isCaseStatement() || sd.statement.isErrorStatement()))
+ auto sl = (sc ? sc.statement : (sd ? sd.statement : null));
+
+ if (sl && (!sl.hasCode() || sl.isErrorStatement()))
{
}
else if (func.getModule().filetype != FileType.c)
{
const(char)* gototype = s.isCaseStatement() ? "case" : "default";
- s.error("switch case fallthrough - use 'goto %s;' if intended", gototype);
+ // @@@DEPRECATED_2.110@@@ https://issues.dlang.org/show_bug.cgi?id=22999
+ // Deprecated in 2.100
+ // Make an error in 2.110
+ if (sl && sl.isCaseStatement())
+ s.deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype);
+ else
+ s.error("switch case fallthrough - use 'goto %s;' if intended", gototype);
}
}
}
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index 2ed0dc7..9c8c1c3 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -912,8 +912,8 @@ void buildDtors(AggregateDeclaration ad, Scope* sc)
ex = new DotVarExp(loc, ex, v);
// This is a hack so we can call destructors on const/immutable objects.
- // Do it as a type 'paint'.
- ex = new CastExp(loc, ex, v.type.mutableOf());
+ // Do it as a type 'paint', `cast()`
+ ex = new CastExp(loc, ex, MODFlags.none);
if (stc & STC.safe)
stc = (stc & ~STC.safe) | STC.trusted;
@@ -1588,7 +1588,7 @@ private bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor)
auto tf = ctorDecl.type.toTypeFunction();
const dim = tf.parameterList.length;
- if (dim == 1)
+ if (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))
{
auto param = tf.parameterList[0];
if (param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index bb12aa7..53bf26e 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -259,6 +259,7 @@ final class CParser(AST) : Parser!AST
case TOK.plusPlus:
case TOK.minusMinus:
case TOK.sizeof_:
+ case TOK._Generic:
Lexp:
auto exp = cparseExpression();
if (token.value == TOK.identifier && exp.op == EXP.identifier)
@@ -2399,15 +2400,13 @@ final class CParser(AST) : Parser!AST
if (idx.length > 2 && idx[0] == '_' && idx[1] == '_') // leading double underscore
importBuiltins = true; // probably one of those compiler extensions
t = null;
- if (scw & SCW.xtypedef)
- {
- /* Punch through to what the typedef is, to support things like:
- * typedef T* T;
- */
- auto pt = lookupTypedef(previd);
- if (pt && *pt) // if previd is a known typedef
- t = *pt;
- }
+
+ /* Punch through to what the typedef is, to support things like:
+ * typedef T* T;
+ */
+ auto pt = lookupTypedef(previd);
+ if (pt && *pt) // if previd is a known typedef
+ t = *pt;
if (!t)
t = new AST.TypeIdentifier(loc, previd);
@@ -2745,6 +2744,11 @@ final class CParser(AST) : Parser!AST
Specifier specifier;
specifier.packalign.setDefault();
auto tspec = cparseSpecifierQualifierList(LVL.global, specifier);
+ if (tspec && specifier.mod & MOD.xconst)
+ {
+ tspec = toConst(tspec);
+ specifier.mod = MOD.xnone; // 'used' it
+ }
Identifier id;
return cparseDeclarator(DTR.xabstract, tspec, id, specifier);
}
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 45eb582..a533d30 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -379,7 +379,7 @@ extern (C++) abstract class Declaration : Dsymbol
if (e1 && e1.op == EXP.this_ && isField())
{
- VarDeclaration vthis = (cast(ThisExp)e1).var;
+ VarDeclaration vthis = e1.isThisExp().var;
for (Scope* scx = sc; scx; scx = scx.enclosing)
{
if (scx.func == vthis.parent && (scx.flags & SCOPE.contract))
@@ -656,9 +656,8 @@ extern (C++) final class TupleDeclaration : Declaration
if (o.dyncast() == DYNCAST.expression)
{
Expression e = cast(Expression)o;
- if (e.op == EXP.dSymbol)
+ if (DsymbolExp ve = e.isDsymbolExp())
{
- DsymbolExp ve = cast(DsymbolExp)e;
Declaration d = ve.s.isDeclaration();
if (d && d.needThis())
{
@@ -1143,7 +1142,7 @@ extern (C++) class VarDeclaration : Declaration
assert(o.dyncast() == DYNCAST.expression);
Expression e = cast(Expression)o;
assert(e.op == EXP.dSymbol);
- DsymbolExp se = cast(DsymbolExp)e;
+ DsymbolExp se = e.isDsymbolExp();
se.s.setFieldOffset(ad, fieldState, isunion);
}
return;
@@ -1441,16 +1440,17 @@ extern (C++) class VarDeclaration : Declaration
const sdsz = sd.type.size();
assert(sdsz != SIZE_INVALID && sdsz != 0);
const n = sz / sdsz;
- e = new SliceExp(loc, e, new IntegerExp(loc, 0, Type.tsize_t), new IntegerExp(loc, n, Type.tsize_t));
+ SliceExp se = new SliceExp(loc, e, new IntegerExp(loc, 0, Type.tsize_t),
+ new IntegerExp(loc, n, Type.tsize_t));
// Prevent redundant bounds check
- (cast(SliceExp)e).upperIsInBounds = true;
- (cast(SliceExp)e).lowerIsLessThanUpper = true;
+ se.upperIsInBounds = true;
+ se.lowerIsLessThanUpper = true;
// This is a hack so we can call destructors on const/immutable objects.
- e.type = sd.type.arrayOf();
+ se.type = sd.type.arrayOf();
- e = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), e);
+ e = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se);
}
return e;
}
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index e9c4c95..2d9f651 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -1133,8 +1133,10 @@ extern (C++) final class Module : Package
// If it isn't there, some compiler rewrites, like
// classinst == classinst -> .object.opEquals(classinst, classinst)
// would fail inside object.d.
- if (members.dim == 0 || (*members)[0].ident != Id.object ||
- (*members)[0].isImport() is null)
+ if (filetype != FileType.c &&
+ (members.dim == 0 ||
+ (*members)[0].ident != Id.object ||
+ (*members)[0].isImport() is null))
{
auto im = new Import(Loc.initial, null, Id.object, null, 0);
members.shift(im);
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index 2021e2a..74eaa1d 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -838,7 +838,8 @@ extern (C++) class Dsymbol : ASTNode
}
if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
{
- if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
+ if (ident == Id.__sizeof ||
+ !(sc && sc.flags & SCOPE.Cfile) && (ident == Id.__xalignof || ident == Id._mangleof))
{
error("`.%s` property cannot be redefined", ident.toChars());
errors = true;
@@ -2523,6 +2524,7 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
if (i1) // vd is the definition
{
+ vd2.storage_class |= STC.extern_; // so toObjFile() won't emit it
sds.symtab.update(vd); // replace vd2 with the definition
return vd;
}
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 1ccaab5..5415401 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -2874,7 +2874,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
sc = sc.endCTFE();
resolved = resolved.ctfeInterpret();
StringExp name = resolved.toStringExp();
- TupleExp tup = name ? null : resolved.toTupleExp();
+ TupleExp tup = name ? null : resolved.isTupleExp();
if (!tup && !name)
{
error(ns.loc, "expected string expression for namespace name, got `%s`", ns.identExp.toChars());
@@ -4621,7 +4621,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
buildOpAssign(sd, sc2);
buildOpEquals(sd, sc2);
- if (global.params.useTypeInfo && Type.dtypeinfo) // these functions are used for TypeInfo
+ if (!(sc2.flags & SCOPE.Cfile) &&
+ global.params.useTypeInfo && Type.dtypeinfo) // these functions are used for TypeInfo
{
sd.xeq = buildXopEquals(sd, sc2);
sd.xcmp = buildXopCmp(sd, sc2);
@@ -5023,6 +5024,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
cldec.com = true;
if (cldec.baseClass.isCPPclass())
cldec.classKind = ClassKind.cpp;
+ if (cldec.classKind != cldec.baseClass.classKind)
+ cldec.error("with %s linkage cannot inherit from class `%s` with %s linkage",
+ cldec.classKind.toChars(), cldec.baseClass.toChars(), cldec.baseClass.classKind.toChars());
+
if (cldec.baseClass.stack)
cldec.stack = true;
cldec.enclosing = cldec.baseClass.enclosing;
diff --git a/gcc/d/dmd/errors.d b/gcc/d/dmd/errors.d
index 114bd44..62e86a1 100644
--- a/gcc/d/dmd/errors.d
+++ b/gcc/d/dmd/errors.d
@@ -434,8 +434,20 @@ else
pragma(printf) extern (C++) void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap);
/**
- * Call this after printing out fatal error messages to clean up and exit
- * the compiler.
+ * The type of the fatal error handler
+ * Returns: true if error handling is done, false to do exit(EXIT_FAILURE)
+ */
+alias FatalErrorHandler = bool delegate();
+
+/**
+ * The fatal error handler.
+ * If non-null it will be called for every fatal() call issued by the compiler.
+ */
+__gshared FatalErrorHandler fatalErrorHandler;
+
+/**
+ * Call this after printing out fatal error messages to clean up and exit the
+ * compiler. You can also set a fatalErrorHandler to override this behaviour.
*/
extern (C++) void fatal();
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index 78b9a07..44c3757 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -316,24 +316,27 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp
*/
void unsafeAssign(VarDeclaration v, const char* desc)
{
- if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe())
+ if (setUnsafeDIP1000(sc.func))
{
if (!gag)
{
if (assertmsg)
{
- error(arg.loc, "%s `%s` assigned to non-scope parameter calling `assert()`",
+ previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+ (arg.loc, "%s `%s` assigned to non-scope parameter calling `assert()`",
desc, v.toChars());
}
else
{
- error(arg.loc, "%s `%s` assigned to non-scope parameter `%s` calling %s",
+ previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+ (arg.loc, "%s `%s` assigned to non-scope parameter `%s` calling %s",
desc, v.toChars(),
par ? par.toChars() : "this",
fdc ? fdc.toPrettyChars() : "indirectly");
}
}
- result = true;
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ result = true;
}
}
@@ -774,7 +777,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
if (v.isDataseg())
continue;
- if (global.params.useDIP1000 == FeatureState.enabled)
+ if (global.params.useDIP1000 != FeatureState.disabled)
{
if (va && va.isScope() && !v.isReference())
{
@@ -782,12 +785,18 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
{
va.doNotInferReturn = true;
}
- else if (fd.setUnsafe())
+ else if (setUnsafeDIP1000(fd))
{
if (!gag)
- error(ae.loc, "address of local variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars());
- result = true;
- continue;
+ previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+ (ae.loc, "address of local variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars());
+
+
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ {
+ result = true;
+ continue;
+ }
}
}
}
@@ -976,12 +985,11 @@ bool checkThrowEscape(Scope* sc, Expression e, bool gag)
if (v.isScope() && !v.iscatchvar) // special case: allow catch var to be rethrown
// despite being `scope`
{
+ if (!gag)
+ previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+ (e.loc, "scope variable `%s` may not be thrown", v.toChars());
if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029
- {
- if (!gag)
- error(e.loc, "scope variable `%s` may not be thrown", v.toChars());
result = true;
- }
continue;
}
else
@@ -1042,13 +1050,16 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
*/
!(p.parent == sc.func))
{
- 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
+ if (setUnsafeDIP1000(sc.func)) // https://issues.dlang.org/show_bug.cgi?id=20868
{
+ // Only look for errors if in module listed on command line
if (!gag)
- error(e.loc, "scope variable `%s` may not be copied into allocated memory", v.toChars());
- result = true;
+ previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+ (e.loc, "scope variable `%s` may not be copied into allocated memory", v.toChars());
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ result = true;
}
+
continue;
}
}
@@ -1258,11 +1269,13 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
)
{
// https://issues.dlang.org/show_bug.cgi?id=17029
- if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe())
+ if (setUnsafeDIP1000(sc.func))
{
if (!gag)
- error(e.loc, "scope variable `%s` may not be returned", v.toChars());
- result = true;
+ previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+ (e.loc, "scope variable `%s` may not be returned", v.toChars());
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ result = true;
}
continue;
}
@@ -2341,3 +2354,11 @@ private void addMaybe(VarDeclaration va, VarDeclaration v)
va.maybes = new VarDeclarations();
va.maybes.push(v);
}
+
+
+private bool setUnsafeDIP1000(FuncDeclaration f)
+{
+ return global.params.useDIP1000 == FeatureState.enabled
+ ? f.setUnsafe()
+ : f.isSafeBypassingInference();
+}
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 24030eb..107e85b 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -967,11 +967,6 @@ extern (C++) abstract class Expression : ASTNode
return null;
}
- TupleExp toTupleExp()
- {
- return null;
- }
-
/***************************************
* Return !=0 if expression is an lvalue.
*/
@@ -1746,6 +1741,7 @@ extern (C++) abstract class Expression : ASTNode
inout(ModuleInitExp) isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; }
inout(FuncInitExp) isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; }
inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; }
+ inout(ObjcClassReferenceExp) isObjcClassReferenceExp() { return op == EXP.objcClassReference ? cast(typeof(return))this : null; }
inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; }
inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; }
@@ -2888,11 +2884,6 @@ extern (C++) final class TupleExp : Expression
return new TupleExp(loc, exps);
}
- override TupleExp toTupleExp()
- {
- return this;
- }
-
override TupleExp syntaxCopy()
{
return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps));
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index 9522b23..a0d63e0 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -103,7 +103,6 @@ public:
virtual real_t toImaginary();
virtual complex_t toComplex();
virtual StringExp *toStringExp();
- virtual TupleExp *toTupleExp();
virtual bool isLvalue();
virtual Expression *toLvalue(Scope *sc, Expression *e);
virtual Expression *modifiableLvalue(Scope *sc, Expression *e);
@@ -406,7 +405,6 @@ public:
Expressions *exps;
static TupleExp *create(const Loc &loc, Expressions *exps);
- TupleExp *toTupleExp();
TupleExp *syntaxCopy();
bool equals(const RootObject *o) const;
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 64cd7ab..22a1f45 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -2028,7 +2028,9 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
//printf("type: %s\n", arg.type.toChars());
//printf("param: %s\n", p.toChars());
- if (firstArg && p.storageClass & STC.return_)
+ const pStc = tf.parameterStorageClass(tthis, p);
+
+ if (firstArg && (pStc & STC.return_))
{
/* Argument value can be assigned to firstArg.
* Check arg to see if it matters.
@@ -2036,7 +2038,9 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
if (global.params.useDIP1000 == FeatureState.enabled)
err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
}
- else if (tf.parameterEscapes(tthis, p))
+ // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
+ // as lazy parameters to the next function, but that isn't escaping.
+ else if (!(pStc & (STC.scope_ | STC.lazy_)))
{
/* Argument value can escape from the called function.
* Check arg to see if it matters.
@@ -2044,7 +2048,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
if (global.params.useDIP1000 == FeatureState.enabled)
err |= checkParamArgumentEscape(sc, fd, p, arg, false, false);
}
- else if (!(p.storageClass & STC.return_))
+ else if (!(pStc & STC.return_))
{
/* Argument value cannot escape from the called function.
*/
@@ -3229,7 +3233,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
Type t = cle.type.typeSemantic(cle.loc, sc);
auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret);
- auto e = initializerToExpression(init, t);
+ auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
if (!e)
{
error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars());
@@ -12195,7 +12199,7 @@ Expression semanticX(DotIdExp exp, Scope* sc)
if (Expression ex = unaSemantic(exp, sc))
return ex;
- if (exp.ident == Id._mangleof)
+ if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
{
// symbol.mangleof
@@ -12304,6 +12308,8 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
//{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
+ const cfile = (sc.flags & SCOPE.Cfile) != 0;
+
/* Special case: rewrite this.id and super.id
* to be classtype.id and baseclasstype.id
* if we have no this pointer.
@@ -12555,7 +12561,16 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
exp.error("undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars());
return ErrorExp.get();
}
- else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum && exp.ident != Id._init && exp.ident != Id.__sizeof && exp.ident != Id.__xalignof && exp.ident != Id.offsetof && exp.ident != Id._mangleof && exp.ident != Id.stringof)
+ else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum &&
+ !(
+ exp.ident == Id.__sizeof ||
+ exp.ident == Id.__xalignof ||
+ !cfile &&
+ (exp.ident == Id._mangleof ||
+ exp.ident == Id.offsetof ||
+ exp.ident == Id._init ||
+ exp.ident == Id.stringof)
+ ))
{
Type t1bn = t1b.nextOf();
if (flag)
@@ -12590,7 +12605,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
return e;
}
- else if (sc.flags & SCOPE.Cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp())
+ else if (cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp())
{
// Sizeof string literal includes the terminating 0
auto se = exp.e1.isStringExp();
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index 616712b..c84a9f6 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -695,7 +695,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
assert(sc);
auto tm = vd.type.addMod(ts.mod);
auto iz = di.initializer.initializerSemantic(sc, tm, needInterpret);
- auto ex = iz.initializerToExpression();
+ auto ex = iz.initializerToExpression(null, true);
if (ex.op == EXP.error)
{
errors = true;
@@ -1100,6 +1100,8 @@ Initializer inferType(Initializer init, Scope* sc)
*/
extern (C++) Expression initializerToExpression(Initializer init, Type itype = null, const bool isCfile = false)
{
+ //printf("initializerToExpression() isCfile: %d\n", isCfile);
+
Expression visitVoid(VoidInitializer)
{
return null;
@@ -1197,7 +1199,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
assert(j < edim);
if (Initializer iz = init.value[i])
{
- if (Expression ex = iz.initializerToExpression())
+ if (Expression ex = iz.initializerToExpression(null, isCfile))
{
(*elements)[j] = ex;
++j;
@@ -1285,7 +1287,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
Expression visitC(CInitializer i)
{
- //printf("CInitializer.initializerToExpression()\n");
+ //printf("CInitializer.initializerToExpression(null, true)\n");
return null;
}
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index b778bc8..5945da3 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -1236,28 +1236,47 @@ class Lexer
{
uint v = 0;
int n = 0;
- while (1)
+ if (Ccompile && ndigits == 2)
{
- if (isdigit(cast(char)c))
- c -= '0';
- else if (islower(c))
- c -= 'a' - 10;
- else
- c -= 'A' - 10;
- v = v * 16 + c;
- c = *++p;
- if (++n == ndigits)
- break;
- if (!ishex(cast(char)c))
+ /* C11 6.4.4.4-7 one to infinity hex digits
+ */
+ do
{
- .error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits);
- break;
- }
+ if (isdigit(cast(char)c))
+ c -= '0';
+ else if (islower(c))
+ c -= 'a' - 10;
+ else
+ c -= 'A' - 10;
+ v = v * 16 + c;
+ c = *++p;
+ } while (ishex(cast(char)c));
}
- if (ndigits != 2 && !utf_isValidDchar(v))
+ else
{
- .error(loc, "invalid UTF character \\U%08x", v);
- v = '?'; // recover with valid UTF character
+ while (1)
+ {
+ if (isdigit(cast(char)c))
+ c -= '0';
+ else if (islower(c))
+ c -= 'a' - 10;
+ else
+ c -= 'A' - 10;
+ v = v * 16 + c;
+ c = *++p;
+ if (++n == ndigits)
+ break;
+ if (!ishex(cast(char)c))
+ {
+ .error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits);
+ break;
+ }
+ }
+ if (ndigits != 2 && !utf_isValidDchar(v))
+ {
+ .error(loc, "invalid UTF character \\U%08x", v);
+ v = '?'; // recover with valid UTF character
+ }
}
c = v;
}
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 50dd20b..13df0d7 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -4360,29 +4360,6 @@ extern (C++) final class TypeFunction : TypeNext
return linkage == LINK.d && parameterList.varargs == VarArg.variadic;
}
- /***************************
- * Examine function signature for parameter p and see if
- * the value of p can 'escape' the scope of the function.
- * This is useful to minimize the needed annotations for the parameters.
- * Params:
- * tthis = type of `this` parameter, null if none
- * p = parameter to this function
- * Returns:
- * true if escapes via assignment to global or through a parameter
- */
- bool parameterEscapes(Type tthis, Parameter p)
- {
- /* Scope parameters do not escape.
- * Allow 'lazy' to imply 'scope' -
- * lazy parameters can be passed along
- * as lazy parameters to the next function, but that isn't
- * escaping.
- */
- if (parameterStorageClass(tthis, p) & (STC.scope_ | STC.lazy_))
- return false;
- return true;
- }
-
/************************************
* Take the specified storage class for p,
* and use the function signature to infer whether
@@ -4410,7 +4387,7 @@ extern (C++) final class TypeFunction : TypeNext
/* If haven't inferred the return type yet, can't infer storage classes
*/
- if (!nextOf())
+ if (!nextOf() || !isnothrow())
return stc;
purityLevel();
@@ -4461,37 +4438,12 @@ extern (C++) final class TypeFunction : TypeNext
}
}
- /* Inferring STC.return_ here has false positives
- * for pure functions, producing spurious error messages
- * about escaping references.
- * Give up on it for now.
- */
- version (none)
- {
- stc |= STC.scope_;
-
- Type tret = nextOf().toBasetype();
- if (isref || tret.hasPointers())
- {
- /* The result has references, so p could be escaping
- * that way.
- */
- stc |= STC.return_;
- }
- }
+ // Check escaping through return value
+ Type tret = nextOf().toBasetype();
+ if (isref || tret.hasPointers())
+ return stc | STC.scope_ | STC.return_ | STC.returnScope;
else
- {
- // Check escaping through return value
- Type tret = nextOf().toBasetype();
- if (isref || tret.hasPointers() || !isnothrow())
- {
- return stc;
- }
-
- stc |= STC.scope_;
- }
-
- return stc;
+ return stc | STC.scope_;
}
override Type addStorageClass(StorageClass stc)
@@ -4791,14 +4743,40 @@ extern (C++) final class TypeFunction : TypeNext
m = MATCH.exact;
else
{
- m = MATCH.nomatch;
if (pMessage)
{
+ /* https://issues.dlang.org/show_bug.cgi?id=22202
+ *
+ * If a function was deduced by semantic on the CallExp,
+ * it means that resolveFuncCall completed succesfully.
+ * Therefore, there exists a callable copy constructor,
+ * however, it cannot be called because scope constraints
+ * such as purity, safety or nogc.
+ */
OutBuffer buf;
- buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
- argStruct.toChars(), targ.toChars(), tprm.toChars());
+ auto callExp = e.isCallExp();
+ if (auto f = callExp.f)
+ {
+ char[] s;
+ if (!f.isPure && sc.func.setImpure())
+ s ~= "pure ";
+ if (!f.isSafe() && !f.isTrusted() && sc.func.setUnsafe())
+ s ~= "@safe ";
+ if (!f.isNogc && sc.func.setGC())
+ s ~= "nogc ";
+ s[$-1] = '\0';
+ buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr);
+
+ }
+ else
+ {
+ buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
+ argStruct.toChars(), targ.toChars(), tprm.toChars());
+ }
+
*pMessage = buf.extractChars();
}
+ m = MATCH.nomatch;
goto Nomatch;
}
}
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index e0b6339..6ba47df 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -109,6 +109,7 @@ enum class TY : uint8_t
*/
enum MODFlags
{
+ MODnone = 0, // default (mutable)
MODconst = 1, // type is const
MODimmutable = 4, // type is immutable
MODshared = 2, // type is shared
@@ -608,7 +609,6 @@ public:
void purityLevel();
bool hasLazyParameters();
bool isDstyleVariadic() const;
- bool parameterEscapes(Parameter *p);
StorageClass parameterStorageClass(Parameter *p);
Type *addStorageClass(StorageClass stc);
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index 3b8b1b6..3cc36b4 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -593,7 +593,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
return;
}
}
- // Convert &((a.b)[n]) to (&a.b)+n
+ // Convert &((a.b)[index]) to (&a.b)+index*elementsize
else if (ae.e2.isIntegerExp() && ae.e1.isDotVarExp())
{
sinteger_t index = ae.e2.toInteger();
@@ -614,9 +614,18 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
}
}
+ import core.checkedint : mulu;
+ bool overflow;
+ const offset = mulu(index, ts.nextOf().size(e.loc), overflow); // index*elementsize
+ if (overflow)
+ {
+ e.error("array offset overflow");
+ return error();
+ }
+
auto pe = new AddrExp(e.loc, ve);
pe.type = e.type;
- ret = new AddExp(e.loc, pe, ae.e2);
+ ret = new AddExp(e.loc, pe, new IntegerExp(e.loc, offset, Type.tsize_t));
ret.type = e.type;
return;
}
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 7b1b63c..4b9c0f2 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -987,23 +987,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
nextToken();
if (token.value == TOK.assign)
{
- nextToken();
- if (token.value == TOK.identifier)
- s = new AST.DebugSymbol(token.loc, token.ident);
- else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
- s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue);
- else
- {
- error("identifier or integer expected, not `%s`", token.toChars());
- s = null;
- }
- nextToken();
- if (token.value != TOK.semicolon)
- error("semicolon expected");
- nextToken();
+ s = parseDebugSpecification();
break;
}
-
condition = parseDebugCondition();
goto Lcondition;
@@ -1012,20 +998,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
nextToken();
if (token.value == TOK.assign)
{
- nextToken();
- if (token.value == TOK.identifier)
- s = new AST.VersionSymbol(token.loc, token.ident);
- else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
- s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue);
- else
- {
- error("identifier or integer expected, not `%s`", token.toChars());
- s = null;
- }
- nextToken();
- if (token.value != TOK.semicolon)
- error("semicolon expected");
- nextToken();
+ s = parseVersionSpecification();
break;
}
condition = parseVersionCondition();
@@ -2197,6 +2170,26 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
return qualified;
}
+ private AST.DebugSymbol parseDebugSpecification()
+ {
+ AST.DebugSymbol s;
+ nextToken();
+ if (token.value == TOK.identifier)
+ s = new AST.DebugSymbol(token.loc, token.ident);
+ else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
+ s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue);
+ else
+ {
+ error("identifier or integer expected, not `%s`", token.toChars());
+ s = null;
+ }
+ nextToken();
+ if (token.value != TOK.semicolon)
+ error("semicolon expected");
+ nextToken();
+ return s;
+ }
+
/**************************************
* Parse a debug conditional
*/
@@ -2224,6 +2217,29 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
/**************************************
+ * Parse a version specification
+ */
+ private AST.VersionSymbol parseVersionSpecification()
+ {
+ AST.VersionSymbol s;
+ nextToken();
+ if (token.value == TOK.identifier)
+ s = new AST.VersionSymbol(token.loc, token.ident);
+ else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
+ s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue);
+ else
+ {
+ error("identifier or integer expected, not `%s`", token.toChars());
+ s = null;
+ }
+ nextToken();
+ if (token.value != TOK.semicolon)
+ error("semicolon expected");
+ nextToken();
+ return s;
+ }
+
+ /**************************************
* Parse a version conditional
*/
private AST.Condition parseVersionCondition()
@@ -6053,10 +6069,14 @@ LagainStc:
nextToken();
if (token.value == TOK.assign)
{
- error("debug conditions can only be declared at module scope");
- nextToken();
- nextToken();
- goto Lerror;
+ if (auto ds = parseDebugSpecification())
+ {
+ if (ds.ident)
+ ds.error("declaration must be at module level");
+ else
+ ds.error("level declaration must be at module level");
+ }
+ break;
}
cond = parseDebugCondition();
goto Lcondition;
@@ -6065,10 +6085,14 @@ LagainStc:
nextToken();
if (token.value == TOK.assign)
{
- error("version conditions can only be declared at module scope");
- nextToken();
- nextToken();
- goto Lerror;
+ if (auto vs = parseVersionSpecification())
+ {
+ if (vs.ident)
+ vs.error("declaration must be at module level");
+ else
+ vs.error("level declaration must be at module level");
+ }
+ break;
}
cond = parseVersionCondition();
goto Lcondition;
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
index ae03b8a..7171324 100644
--- a/gcc/d/dmd/statement.d
+++ b/gcc/d/dmd/statement.d
@@ -315,6 +315,14 @@ extern (C++) abstract class Statement : ASTNode
override void visit(ImportStatement s)
{
}
+
+ override void visit(CaseStatement s)
+ {
+ }
+
+ override void visit(DefaultStatement s)
+ {
+ }
}
scope HasCode hc = new HasCode();
diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d
index 615c49f..0acad6a 100644
--- a/gcc/d/dmd/transitivevisitor.d
+++ b/gcc/d/dmd/transitivevisitor.d
@@ -17,7 +17,9 @@ import core.stdc.stdio;
extern(C++) class ParseTimeTransitiveVisitor(AST) : PermissiveVisitor!AST
{
alias visit = PermissiveVisitor!AST.visit;
- mixin ParseVisitMethods!AST;
+
+ mixin ParseVisitMethods!AST __methods;
+ alias visit = __methods.visit;
}
/* This mixin implements the AST traversal logic for parse time AST nodes. The same code
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index b267412..f63b177 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -1843,7 +1843,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
mtype.sym = e.isScopeExp().sds;
break;
case EXP.tuple:
- TupleExp te = e.toTupleExp();
+ TupleExp te = e.isTupleExp();
Objects* elems = new Objects(te.exps.dim);
foreach (i; 0 .. elems.dim)
{
@@ -2306,7 +2306,8 @@ extern (C++) Type merge(Type type)
case Tident:
case Tinstance:
case Tmixin:
- return type;
+ case Ttag:
+ return type; // don't merge placeholder types
case Tsarray:
// prevents generating the mangle if the array dim is not yet known
@@ -3904,7 +3905,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
assert(e.op != EXP.dot);
// https://issues.dlang.org/show_bug.cgi?id=14010
- if (ident == Id._mangleof)
+ if (!(sc.flags & SCOPE.Cfile) && ident == Id._mangleof)
{
return mt.getProperty(sc, e.loc, ident, flag & 1);
}
@@ -4656,7 +4657,7 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi
{
static if (LOGDEFAULTINIT)
{
- printf("TypeBasic::defaultInit() '%s'\n", mt.toChars());
+ printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt.toChars(), isCfile);
}
dinteger_t value = 0;
@@ -4714,7 +4715,7 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi
{
static if (LOGDEFAULTINIT)
{
- printf("TypeSArray::defaultInit() '%s'\n", mt.toChars());
+ printf("TypeSArray::defaultInit() '%s' isCfile %d\n", mt.toChars(), isCfile);
}
if (mt.next.ty == Tvoid)
return mt.tuns8.defaultInit(loc, isCfile);
diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d
index cdfe3cb..7f3fb64 100644
--- a/gcc/d/dmd/utils.d
+++ b/gcc/d/dmd/utils.d
@@ -84,7 +84,7 @@ extern (D) void writeFile(Loc loc, const(char)[] filename, const void[] data)
ensurePathToNameExists(Loc.initial, filename);
if (!File.update(filename, data))
{
- error(loc, "Error writing file '%*.s'", cast(int) filename.length, filename.ptr);
+ error(loc, "Error writing file '%.*s'", cast(int) filename.length, filename.ptr);
fatal();
}
}
diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt
index 51e8e5c..b4b8152 100644
--- a/gcc/d/lang.opt
+++ b/gcc/d/lang.opt
@@ -396,6 +396,10 @@ frevert=all
D RejectNegative
Turn off all revertable D language features.
+frevert=dip1000
+D RejectNegative
+Revert DIP1000: Scoped pointers.
+
frevert=dip25
D RejectNegative
Revert DIP25: Sealed references.