aboutsummaryrefslogtreecommitdiff
path: root/gcc/d
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2022-07-26 17:42:23 +0200
committerIain Buclaw <ibuclaw@gdcproject.org>2022-08-03 13:01:53 +0200
commitb6df113247b9f3f7c3db0e65c481dad5bcfddfb4 (patch)
tree31466a07292ad0cc289de7c23e39ba31b9e8b7c3 /gcc/d
parent64ce76d940501cb04d14a0d36752b4f93473531c (diff)
downloadgcc-b6df113247b9f3f7c3db0e65c481dad5bcfddfb4.zip
gcc-b6df113247b9f3f7c3db0e65c481dad5bcfddfb4.tar.gz
gcc-b6df113247b9f3f7c3db0e65c481dad5bcfddfb4.tar.bz2
d: Merge upstream dmd d7772a2369, phobos 5748ca43f.
In upstream dmd, the compiler front-end and run-time have been merged together into one repository. Both dmd and libdruntime now track that. D front-end changes: - Deprecated `scope(failure)' blocks that contain `return' statements. - Deprecated using integers for `version' or `debug' conditions. - Deprecated returning a discarded void value from a function. - `new' can now allocate an associative array. D runtime changes: - Added avx512f detection to core.cpuid module. Phobos changes: - Changed std.experimental.logger.core.sharedLog to return shared(Logger). gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd d7772a2369. * dmd/VERSION: Bump version to v2.100.1. * d-codegen.cc (get_frameinfo): Check whether decision to generate closure changed since semantic finished. * d-lang.cc (d_handle_option): Remove handling of -fdebug=level and -fversion=level. * decl.cc (DeclVisitor::visit (VarDeclaration *)): Generate evaluation of noreturn variable initializers before throw. * expr.cc (ExprVisitor::visit (AssignExp *)): Don't generate assignment for noreturn types, only evaluate for side effects. * lang.opt (fdebug=): Undocument -fdebug=level. (fversion=): Undocument -fversion=level. libphobos/ChangeLog: * configure: Regenerate. * configure.ac (libtool_VERSION): Update to 4:0:0. * libdruntime/MERGE: Merge upstream druntime d7772a2369. * libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add core/internal/array/duplication.d. * libdruntime/Makefile.in: Regenerate. * src/MERGE: Merge upstream phobos 5748ca43f. * testsuite/libphobos.gc/nocollect.d:
Diffstat (limited to 'gcc/d')
-rw-r--r--gcc/d/d-codegen.cc7
-rw-r--r--gcc/d/d-lang.cc20
-rw-r--r--gcc/d/decl.cc7
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/VERSION2
-rw-r--r--gcc/d/dmd/arrayop.d4
-rw-r--r--gcc/d/dmd/chkformat.d494
-rw-r--r--gcc/d/dmd/clone.d4
-rw-r--r--gcc/d/dmd/constfold.d123
-rw-r--r--gcc/d/dmd/cparse.d2
-rw-r--r--gcc/d/dmd/dcast.d14
-rw-r--r--gcc/d/dmd/declaration.h1
-rw-r--r--gcc/d/dmd/dinterpret.d11
-rw-r--r--gcc/d/dmd/dmodule.d8
-rw-r--r--gcc/d/dmd/dsymbol.d26
-rw-r--r--gcc/d/dmd/dsymbolsem.d7
-rw-r--r--gcc/d/dmd/dtemplate.d2
-rw-r--r--gcc/d/dmd/entity.d21
-rw-r--r--gcc/d/dmd/escape.d33
-rw-r--r--gcc/d/dmd/expressionsem.d113
-rw-r--r--gcc/d/dmd/file_manager.d6
-rw-r--r--gcc/d/dmd/func.d62
-rw-r--r--gcc/d/dmd/impcnvtab.d55
-rw-r--r--gcc/d/dmd/initsem.d39
-rw-r--r--gcc/d/dmd/lexer.d2
-rw-r--r--gcc/d/dmd/mustuse.d2
-rw-r--r--gcc/d/dmd/optimize.d2
-rw-r--r--gcc/d/dmd/parse.d32
-rw-r--r--gcc/d/dmd/semantic3.d10
-rw-r--r--gcc/d/dmd/statementsem.d50
-rw-r--r--gcc/d/dmd/transitivevisitor.d6
-rw-r--r--gcc/d/dmd/typesem.d13
-rw-r--r--gcc/d/expr.cc11
-rw-r--r--gcc/d/lang.opt4
34 files changed, 810 insertions, 385 deletions
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index 2d90899..3fd4bee 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -2826,8 +2826,15 @@ get_frameinfo (FuncDeclaration *fd)
DECL_LANG_FRAMEINFO (fds) = ffi;
+ const bool requiresClosure = fd->requiresClosure;
if (fd->needsClosure ())
{
+ /* This can shift due to templates being expanded that access alias
+ symbols, give it a decent error for now. */
+ if (requiresClosure != fd->requiresClosure
+ && (fd->nrvo_var || global.params.betterC))
+ fd->checkClosure ();
+
/* Set-up a closure frame, this will be allocated on the heap. */
FRAMEINFO_CREATES_FRAME (ffi) = 1;
FRAMEINFO_IS_CLOSURE (ffi) = 1;
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 6e4350f..04147ed 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -456,16 +456,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
break;
case OPT_fdebug_:
- if (ISDIGIT (arg[0]))
- {
- int level = integral_argument (arg);
- if (level != -1)
- {
- global.params.debuglevel = level;
- break;
- }
- }
-
if (Identifier::isValidIdentifier (CONST_CAST (char *, arg)))
{
if (!global.params.debugids)
@@ -713,16 +703,6 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
break;
case OPT_fversion_:
- if (ISDIGIT (arg[0]))
- {
- int level = integral_argument (arg);
- if (level != -1)
- {
- global.params.versionlevel = level;
- break;
- }
- }
-
if (Identifier::isValidIdentifier (CONST_CAST (char *, arg)))
{
if (!global.params.versionids)
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index 3caa465..58cea4d 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -646,9 +646,12 @@ public:
if (!d->isDataseg () && !d->isMember ()
&& d->_init && !d->_init->isVoidInitializer ())
{
+ /* Evaluate RHS for side effects first. */
+ Expression *ie = initializerToExpression (d->_init);
+ add_stmt (build_expr (ie));
+
Expression *e = d->type->defaultInitLiteral (d->loc);
- tree exp = build_expr (e);
- add_stmt (exp);
+ add_stmt (build_expr (e));
}
return;
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 8324c1c..c358b69 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-56589f0f4d724c1c8022c57509a243f16a04228a
+d7772a236983ec37b92d21b28bad3cd2de57b945
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 5ea2ba0..83a14f5 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@
-v2.100.0
+v2.100.1
diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d
index 16cbe62..272e751 100644
--- a/gcc/d/dmd/arrayop.d
+++ b/gcc/d/dmd/arrayop.d
@@ -111,8 +111,8 @@ bool checkNonAssignmentArrayOp(Expression e, bool suggestion = false)
* evaluation order as the actual array operations have no
* side-effect.
* References:
- * https://github.com/dlang/druntime/blob/master/src/object.d#L3944
- * https://github.com/dlang/druntime/blob/master/src/core/internal/array/operations.d
+ * https://github.com/dlang/dmd/blob/cdfadf8a18f474e6a1b8352af2541efe3e3467cc/druntime/src/object.d#L4694
+ * https://github.com/dlang/dmd/blob/master/druntime/src/core/internal/array/operations.d
*/
Expression arrayOp(BinExp e, Scope* sc)
{
diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d
index a3f3bc4..e118d70 100644
--- a/gcc/d/dmd/chkformat.d
+++ b/gcc/d/dmd/chkformat.d
@@ -62,7 +62,7 @@ import dmd.target;
bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expression[] args, bool isVa_list)
{
//printf("checkPrintFormat('%.*s')\n", cast(int)format.length, format.ptr);
- size_t n, gnu_m_count; // index in args / number of Format.GNU_m
+ size_t n; // index in args
for (size_t i = 0; i < format.length;)
{
if (format[i] != '%')
@@ -79,6 +79,8 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
if (fmt == Format.percent)
continue; // "%%", no arguments
+ if (fmt == Format.GNU_m)
+ continue; // "%m", no arguments
if (isVa_list)
{
@@ -88,14 +90,11 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
continue;
}
- if (fmt == Format.GNU_m)
- ++gnu_m_count;
-
Expression getNextArg(ref bool skip)
{
if (n == args.length)
{
- if (args.length < (n + 1) - gnu_m_count)
+ if (args.length < (n + 1))
deprecation(loc, "more format specifiers than %d arguments", cast(int)n);
else
skip = true;
@@ -207,7 +206,6 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
errorMsg(null, e, "ptrdiff_t", t);
break;
- case Format.GNU_a: // Format.GNU_a is only for scanf
case Format.lg:
case Format.g: // double
if (t.ty != Tfloat64 && t.ty != Timaginary64)
@@ -289,8 +287,8 @@ bool checkPrintfFormat(ref const Loc loc, scope const char[] format, scope Expre
break;
case Format.GNU_m:
- break; // not assert(0) because it may go through it if there are extra arguments
-
+ case Format.POSIX_ms:
+ case Format.POSIX_mls:
case Format.percent:
assert(0);
}
@@ -481,8 +479,6 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres
errorMsg(null, e, "real*", t);
break;
- case Format.GNU_a:
- case Format.GNU_m:
case Format.c:
case Format.s: // pointer to char string
if (!(t.ty == Tpointer && (tnext.ty == Tchar || tnext.ty == Tint8 || tnext.ty == Tuns8)))
@@ -500,10 +496,23 @@ bool checkScanfFormat(ref const Loc loc, scope const char[] format, scope Expres
errorMsg(null, e, "void**", t);
break;
+ case Format.POSIX_ms: // pointer to pointer to char string
+ Type tnext2 = tnext ? tnext.nextOf() : null;
+ if (!(t.ty == Tpointer && tnext.ty == Tpointer && (tnext2.ty == Tchar || tnext2.ty == Tint8 || tnext2.ty == Tuns8)))
+ errorMsg(null, e, "char**", t);
+ break;
+
+ case Format.POSIX_mls: // pointer to pointer to wchar_t string
+ Type tnext2 = tnext ? tnext.nextOf() : null;
+ if (!(t.ty == Tpointer && tnext.ty == Tpointer && tnext2.ty.isSomeChar && tnext2.size() == target.c.wchar_tsize))
+ errorMsg(null, e, "wchar_t**", t);
+ break;
+
case Format.error:
deprecation(loc, "format specifier `\"%.*s\"` is invalid", cast(int)slice.length, slice.ptr);
break;
+ case Format.GNU_m:
case Format.percent:
assert(0);
}
@@ -567,35 +576,97 @@ Format parseScanfFormatSpecifier(scope const char[] format, ref size_t idx,
return error();
}
- /* Read the scanset
- * A scanset can be anything, so we just check that it is paired
+ /* Read the specifier
*/
- if (format[i] == '[')
+ Format specifier;
+ Modifier flags = Modifier.none;
+ switch (format[i])
{
- while (i < length)
- {
- if (format[i] == ']')
- break;
+ case 'm':
+ // https://pubs.opengroup.org/onlinepubs/9699919799/functions/scanf.html
+ // POSIX.1-2017 C Extension (CX)
+ flags = Modifier.m;
++i;
- }
+ if (i == length)
+ return error();
+ if (format[i] == 'l')
+ {
+ ++i;
+ if (i == length)
+ return error();
+ flags = Modifier.ml;
+ }
- // no `]` found
- if (i == length)
- return error();
+ // Check valid conversion types for %m.
+ if (format[i] == 'c' || format[i] == 's')
+ specifier = flags == Modifier.ml ? Format.POSIX_mls :
+ Format.POSIX_ms;
+ else if (format[i] == 'C' || format[i] == 'S')
+ specifier = flags == Modifier.m ? Format.POSIX_mls :
+ Format.error;
+ else if (format[i] == '[')
+ goto case '[';
+ else
+ specifier = Format.error;
+ ++i;
+ break;
- ++i;
- // no specifier after `]`
- // it could be mixed with the one above, but then idx won't have the right index
- if (i == length)
- return error();
- }
+ case 'l':
+ // Look for wchar_t scanset %l[..]
+ immutable j = i + 1;
+ if (j < length && format[j] == '[')
+ {
+ i = j;
+ flags = Modifier.l;
+ goto case '[';
+ }
+ goto default;
- /* Read the specifier
- */
- char genSpec;
- Format specifier = parseGenericFormatSpecifier(format, i, genSpec);
- if (specifier == Format.error)
- return error();
+ case '[':
+ // Read the scanset
+ i++;
+ if (i == length)
+ return error();
+ // If the conversion specifier begins with `[]` or `[^]`, the right
+ // bracket character is not the terminator, but in the scanlist.
+ if (format[i] == '^')
+ {
+ i++;
+ if (i == length)
+ return error();
+ }
+ if (format[i] == ']')
+ {
+ i++;
+ if (i == length)
+ return error();
+ }
+ // A scanset can be anything, so we just check that it is paired
+ while (i < length)
+ {
+ if (format[i] == ']')
+ break;
+ ++i;
+ }
+ // no `]` found
+ if (i == length)
+ return error();
+
+ specifier = flags == Modifier.none ? Format.s :
+ flags == Modifier.l ? Format.ls :
+ flags == Modifier.m ? Format.POSIX_ms :
+ flags == Modifier.ml ? Format.POSIX_mls :
+ Format.error;
+ ++i;
+ break;
+
+ default:
+ char genSpec;
+ specifier = parseGenericFormatSpecifier(format, i, genSpec);
+ if (specifier == Format.error)
+ return error();
+ break;
+ }
idx = i;
return specifier; // success
@@ -613,11 +684,13 @@ Format parseScanfFormatSpecifier(scope const char[] format, ref size_t idx,
* even if `Format.error` is returned
* widthStar = set if * for width
* precisionStar = set if * for precision
+ * useGNUExts = true if parsing GNU format extensions
* Returns:
* Format
*/
Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx,
- out bool widthStar, out bool precisionStar) nothrow pure @safe
+ out bool widthStar, out bool precisionStar, bool useGNUExts =
+ findCondition(global.versionids, Identifier.idPool("CRuntime_Glibc"))) nothrow pure @safe
{
auto i = idx;
assert(format[i] == '%');
@@ -730,14 +803,33 @@ Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx,
/* Read the specifier
*/
char genSpec;
- Format specifier = parseGenericFormatSpecifier(format, i, genSpec);
- if (specifier == Format.error)
- return error();
+ Format specifier;
+ switch (format[i])
+ {
+ case 'm':
+ // https://www.gnu.org/software/libc/manual/html_node/Other-Output-Conversions.html
+ if (useGNUExts)
+ {
+ specifier = Format.GNU_m;
+ genSpec = format[i];
+ ++i;
+ break;
+ }
+ goto default;
+
+ default:
+ specifier = parseGenericFormatSpecifier(format, i, genSpec);
+ if (specifier == Format.error)
+ return error();
+ break;
+ }
switch (genSpec)
{
case 'c':
case 's':
+ case 'C':
+ case 'S':
if (hash || zero)
return error();
break;
@@ -748,6 +840,11 @@ Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx,
return error();
break;
+ case 'm':
+ if (hash || zero || flags)
+ return error();
+ break;
+
case 'n':
if (hash || zero || precision || width || flags)
return error();
@@ -761,6 +858,22 @@ Format parsePrintfFormatSpecifier(scope const char[] format, ref size_t idx,
return specifier; // success
}
+/* Different kinds of conversion modifiers. */
+enum Modifier
+{
+ none,
+ h, // short
+ hh, // char
+ j, // intmax_t
+ l, // wint_t/wchar_t
+ ll, // long long int
+ L, // long double
+ m, // char**
+ ml, // wchar_t**
+ t, // ptrdiff_t
+ z // size_t
+}
+
/* Different kinds of formatting specifications, variations we don't
care about are merged. (Like we don't care about the difference between
f, e, g, a, etc.)
@@ -799,8 +912,9 @@ enum Format
jn, // pointer to intmax_t
zn, // pointer to size_t
tn, // pointer to ptrdiff_t
- GNU_a, // GNU ext. : address to a string with no maximum size (scanf)
- GNU_m, // GNU ext. : string corresponding to the error code in errno (printf) / length modifier (scanf)
+ GNU_m, // GNU ext. : string corresponding to the error code in errno (printf)
+ POSIX_ms, // POSIX ext. : dynamically allocated char string (scanf)
+ POSIX_mls, // POSIX ext. : dynamically allocated wchar_t string (scanf)
percent, // %% (i.e. no argument)
error, // invalid format specification
}
@@ -820,38 +934,48 @@ enum Format
* Format
*/
Format parseGenericFormatSpecifier(scope const char[] format,
- ref size_t idx, out char genSpecifier, bool useGNUExts =
- findCondition(global.versionids, Identifier.idPool("CRuntime_Glibc"))) nothrow pure @trusted
+ ref size_t idx, out char genSpecifier) nothrow pure @safe
{
const length = format.length;
/* Read the `length modifier`
*/
const lm = format[idx];
- bool lm1; // if jztL
- bool lm2; // if `hh` or `ll`
- if (lm == 'j' ||
- lm == 'z' ||
- lm == 't' ||
- lm == 'L')
+ Modifier flags;
+ switch (lm)
{
- ++idx;
- if (idx == length)
- return Format.error;
- lm1 = true;
- }
- else if (lm == 'h' || lm == 'l')
- {
- ++idx;
- if (idx == length)
- return Format.error;
- lm2 = lm == format[idx];
- if (lm2)
- {
+ case 'j':
+ case 'z':
+ case 't':
+ case 'L':
+ flags = lm == 'j' ? Modifier.j :
+ lm == 'z' ? Modifier.z :
+ lm == 't' ? Modifier.t :
+ Modifier.L;
++idx;
if (idx == length)
return Format.error;
- }
+ break;
+
+ case 'h':
+ case 'l':
+ ++idx;
+ if (idx == length)
+ return Format.error;
+ if (lm == format[idx])
+ {
+ flags = lm == 'h' ? Modifier.hh : Modifier.ll;
+ ++idx;
+ if (idx == length)
+ return Format.error;
+ }
+ else
+ flags = lm == 'h' ? Modifier.h : Modifier.l;
+ break;
+
+ default:
+ flags = Modifier.none;
+ break;
}
/* Read the `specifier`
@@ -863,103 +987,88 @@ Format parseGenericFormatSpecifier(scope const char[] format,
{
case 'd':
case 'i':
- if (lm == 'L')
- specifier = Format.error;
- else
- specifier = lm == 'h' && lm2 ? Format.hhd :
- lm == 'h' ? Format.hd :
- lm == 'l' && lm2 ? Format.lld :
- lm == 'l' ? Format.ld :
- lm == 'j' ? Format.jd :
- lm == 'z' ? Format.zd :
- lm == 't' ? Format.td :
- Format.d;
+ specifier = flags == Modifier.none ? Format.d :
+ flags == Modifier.hh ? Format.hhd :
+ flags == Modifier.h ? Format.hd :
+ flags == Modifier.ll ? Format.lld :
+ flags == Modifier.l ? Format.ld :
+ flags == Modifier.j ? Format.jd :
+ flags == Modifier.z ? Format.zd :
+ flags == Modifier.t ? Format.td :
+ Format.error;
break;
case 'u':
case 'o':
case 'x':
case 'X':
- if (lm == 'L')
- specifier = Format.error;
- else
- specifier = lm == 'h' && lm2 ? Format.hhu :
- lm == 'h' ? Format.hu :
- lm == 'l' && lm2 ? Format.llu :
- lm == 'l' ? Format.lu :
- lm == 'j' ? Format.ju :
- lm == 'z' ? Format.zd :
- lm == 't' ? Format.td :
- Format.u;
+ specifier = flags == Modifier.none ? Format.u :
+ flags == Modifier.hh ? Format.hhu :
+ flags == Modifier.h ? Format.hu :
+ flags == Modifier.ll ? Format.llu :
+ flags == Modifier.l ? Format.lu :
+ flags == Modifier.j ? Format.ju :
+ flags == Modifier.z ? Format.zd :
+ flags == Modifier.t ? Format.td :
+ Format.error;
break;
- case 'a':
- if (useGNUExts)
- {
- // https://www.gnu.org/software/libc/manual/html_node/Dynamic-String-Input.html
- specifier = Format.GNU_a;
- break;
- }
- goto case;
-
case 'f':
case 'F':
case 'e':
case 'E':
case 'g':
case 'G':
+ case 'a':
case 'A':
- if (lm == 'L')
- specifier = Format.Lg;
- else if (lm1 || lm2 || lm == 'h')
- specifier = Format.error;
- else
- specifier = lm == 'l' ? Format.lg : Format.g;
+ specifier = flags == Modifier.none ? Format.g :
+ flags == Modifier.L ? Format.Lg :
+ flags == Modifier.l ? Format.lg :
+ Format.error;
break;
case 'c':
- if (lm1 || lm2 || lm == 'h')
- specifier = Format.error;
- else
- specifier = lm == 'l' ? Format.lc : Format.c;
+ specifier = flags == Modifier.none ? Format.c :
+ flags == Modifier.l ? Format.lc :
+ Format.error;
break;
case 's':
- if (lm1 || lm2 || lm == 'h')
- specifier = Format.error;
- else
- specifier = lm == 'l' ? Format.ls : Format.s;
+ specifier = flags == Modifier.none ? Format.s :
+ flags == Modifier.l ? Format.ls :
+ Format.error;
break;
case 'p':
- if (lm1 || lm2 || lm == 'h' || lm == 'l')
- specifier = Format.error;
- else
- specifier = Format.p;
+ specifier = flags == Modifier.none ? Format.p :
+ Format.error;
break;
case 'n':
- if (lm == 'L')
- specifier = Format.error;
- else
- specifier = lm == 'l' && lm2 ? Format.lln :
- lm == 'l' ? Format.ln :
- lm == 'h' && lm2 ? Format.hhn :
- lm == 'h' ? Format.hn :
- lm == 'j' ? Format.jn :
- lm == 'z' ? Format.zn :
- lm == 't' ? Format.tn :
- Format.n;
+ specifier = flags == Modifier.none ? Format.n :
+ flags == Modifier.ll ? Format.lln :
+ flags == Modifier.l ? Format.ln :
+ flags == Modifier.hh ? Format.hhn :
+ flags == Modifier.h ? Format.hn :
+ flags == Modifier.j ? Format.jn :
+ flags == Modifier.z ? Format.zn :
+ flags == Modifier.t ? Format.tn :
+ Format.error;
break;
- case 'm':
- if (useGNUExts)
- {
- // https://www.gnu.org/software/libc/manual/html_node/Other-Output-Conversions.html
- specifier = Format.GNU_m;
- break;
- }
- goto default;
+ case 'C':
+ // POSIX.1-2017 X/Open System Interfaces (XSI)
+ // %C format is equivalent to %lc
+ specifier = flags == Modifier.none ? Format.lc :
+ Format.error;
+ break;
+
+ case 'S':
+ // POSIX.1-2017 X/Open System Interfaces (XSI)
+ // %S format is equivalent to %ls
+ specifier = flags == Modifier.none ? Format.ls :
+ Format.error;
+ break;
default:
specifier = Format.error;
@@ -1126,11 +1235,14 @@ unittest
assert(idx == 2);
idx = 0;
- Format g = parsePrintfFormatSpecifier("%a", idx, widthStar, precisionStar);
- assert(g == Format.g || g == Format.GNU_a);
+ assert(parsePrintfFormatSpecifier("%a", idx, widthStar, precisionStar) == Format.g);
assert(idx == 2);
idx = 0;
+ assert(parsePrintfFormatSpecifier("%La", idx, widthStar, precisionStar) == Format.Lg);
+ assert(idx == 3);
+
+ idx = 0;
assert(parsePrintfFormatSpecifier("%A", idx, widthStar, precisionStar) == Format.g);
assert(idx == 2);
@@ -1296,8 +1408,7 @@ unittest
assert(idx == 2);
idx = 0;
- g = parseScanfFormatSpecifier("%a", idx, asterisk);
- assert(g == Format.g || g == Format.GNU_a);
+ assert(parseScanfFormatSpecifier("%a", idx, asterisk) == Format.g);
assert(idx == 2);
idx = 0;
@@ -1322,15 +1433,25 @@ unittest
// scansets
idx = 0;
- assert(parseScanfFormatSpecifier("%[a-zA-Z]s", idx, asterisk) == Format.s);
- assert(idx == 10);
+ assert(parseScanfFormatSpecifier("%[a-zA-Z]", idx, asterisk) == Format.s);
+ assert(idx == 9);
assert(!asterisk);
idx = 0;
- assert(parseScanfFormatSpecifier("%*25[a-z]hhd", idx, asterisk) == Format.hhd);
- assert(idx == 12);
+ assert(parseScanfFormatSpecifier("%*25l[a-z]", idx, asterisk) == Format.ls);
+ assert(idx == 10);
assert(asterisk);
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%[]]", idx, asterisk) == Format.s);
+ assert(idx == 4);
+ assert(!asterisk);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%[^]]", idx, asterisk) == Format.s);
+ assert(idx == 5);
+ assert(!asterisk);
+
// Too short formats
foreach (s; ["%", "% ", "%#", "%0", "%*", "%1", "%19",
"%j", "%z", "%t", "%l", "%h", "%ll", "%hh", "%K"])
@@ -1354,11 +1475,108 @@ unittest
}
// Invalid scansets
- foreach (s; ["%[]", "%[s", "%[0-9lld", "%[", "%[a-z]"])
+ foreach (s; ["%[]", "%[^", "%[^]", "%[s", "%[0-9lld", "%[", "%l[^]"])
+ {
+ idx = 0;
+ assert(parseScanfFormatSpecifier(s, idx, asterisk) == Format.error);
+ assert(idx == s.length);
+ }
+
+ // Posix extensions
+ foreach (s; ["%jm", "%zm", "%tm", "%Lm", "%hm", "%hhm", "%lm", "%llm",
+ "%m", "%ma", "%md", "%ml", "%mm", "%mlb", "%mlj", "%mlr", "%mlz",
+ "%LC", "%lC", "%llC", "%jC", "%tC", "%hC", "%hhC", "%zC",
+ "%LS", "%lS", "%llS", "%jS", "%tS", "%hS", "%hhS", "%zS"])
{
idx = 0;
assert(parseScanfFormatSpecifier(s, idx, asterisk) == Format.error);
assert(idx == s.length);
}
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%mc", idx, asterisk) == Format.POSIX_ms);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%ms", idx, asterisk) == Format.POSIX_ms);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%m[0-9]", idx, asterisk) == Format.POSIX_ms);
+ assert(idx == 7);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%mlc", idx, asterisk) == Format.POSIX_mls);
+ assert(idx == 4);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%mls", idx, asterisk) == Format.POSIX_mls);
+ assert(idx == 4);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%ml[^0-9]", idx, asterisk) == Format.POSIX_mls);
+ assert(idx == 9);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%mC", idx, asterisk) == Format.POSIX_mls);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%mS", idx, asterisk) == Format.POSIX_mls);
+ assert(idx == 3);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%C", idx, widthStar, precisionStar) == Format.lc);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%C", idx, asterisk) == Format.lc);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parsePrintfFormatSpecifier("%S", idx, widthStar, precisionStar) == Format.ls);
+ assert(idx == 2);
+
+ idx = 0;
+ assert(parseScanfFormatSpecifier("%S", idx, asterisk) == Format.ls);
+ assert(idx == 2);
+
+ // GNU extensions: explicitly toggle ISO/GNU flag.
+ // ISO printf()
+ bool useGNUExts = false;
+ {
+ foreach (s; ["%jm", "%zm", "%tm", "%Lm", "%hm", "%hhm", "%lm", "%llm",
+ "%#m", "%+m", "%-m", "% m", "%0m"])
+ {
+ idx = 0;
+ assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.error);
+ assert(idx == s.length);
+ }
+ foreach (s; ["%m", "%md", "%mz", "%mc", "%mm", "%msyz", "%ml", "%mlz", "%mlc", "%mlm"])
+ {
+ idx = 0;
+ assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.error);
+ assert(idx == 2);
+ }
+ }
+
+ // GNU printf()
+ useGNUExts = true;
+ {
+ foreach (s; ["%jm", "%zm", "%tm", "%Lm", "%hm", "%hhm", "%lm", "%llm",
+ "%#m", "%+m", "%-m", "% m", "%0m"])
+ {
+ idx = 0;
+ assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.error);
+ assert(idx == s.length);
+ }
+
+ // valid cases, all parsed as `%m`
+ foreach (s; ["%m", "%md", "%mz", "%mc", "%mm", "%msyz", "%ml", "%mlz", "%mlc", "%mlm"])
+ {
+ idx = 0;
+ assert(parsePrintfFormatSpecifier(s, idx, widthStar, precisionStar, useGNUExts) == Format.GNU_m);
+ assert(idx == 2);
+ }
+ }
}
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index cf4ccbb..1a26eaa 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -1121,6 +1121,10 @@ private DtorDeclaration buildExternDDtor(AggregateDeclaration ad, Scope* sc)
if (!dtor)
return null;
+ // Don't try to call `@disable`d dtors
+ if (dtor.storage_class & STC.disable)
+ return null;
+
// Generate shim only when ABI incompatible on target platform
if (ad.classKind != ClassKind.cpp || !target.cpp.wrapDtorInExternD)
return dtor;
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
index d90542f..f4e44e8 100644
--- a/gcc/d/dmd/constfold.d
+++ b/gcc/d/dmd/constfold.d
@@ -234,99 +234,9 @@ UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2)
UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2)
{
- UnionExp ue = void;
- if (type.isreal())
- {
- emplaceExp!(RealExp)(&ue, loc, e1.toReal() - e2.toReal(), type);
- }
- else if (type.isimaginary())
- {
- emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() - e2.toImaginary(), type);
- }
- else if (type.iscomplex())
- {
- // This rigamarole is necessary so that -0.0 doesn't get
- // converted to +0.0 by doing an extraneous add with +0.0
- auto c1 = complex_t(CTFloat.zero);
- real_t r1 = CTFloat.zero;
- real_t i1 = CTFloat.zero;
- auto c2 = complex_t(CTFloat.zero);
- real_t r2 = CTFloat.zero;
- real_t i2 = CTFloat.zero;
- auto v = complex_t(CTFloat.zero);
- int x;
- if (e1.type.isreal())
- {
- r1 = e1.toReal();
- x = 0;
- }
- else if (e1.type.isimaginary())
- {
- i1 = e1.toImaginary();
- x = 3;
- }
- else
- {
- c1 = e1.toComplex();
- x = 6;
- }
- if (e2.type.isreal())
- {
- r2 = e2.toReal();
- }
- else if (e2.type.isimaginary())
- {
- i2 = e2.toImaginary();
- x += 1;
- }
- else
- {
- c2 = e2.toComplex();
- x += 2;
- }
- switch (x)
- {
- case 0 + 0:
- v = complex_t(r1 - r2);
- break;
- case 0 + 1:
- v = complex_t(r1, -i2);
- break;
- case 0 + 2:
- v = complex_t(r1 - creall(c2), -cimagl(c2));
- break;
- case 3 + 0:
- v = complex_t(-r2, i1);
- break;
- case 3 + 1:
- v = complex_t(CTFloat.zero, i1 - i2);
- break;
- case 3 + 2:
- v = complex_t(-creall(c2), i1 - cimagl(c2));
- break;
- case 6 + 0:
- v = complex_t(creall(c1) - r2, cimagl(c1));
- break;
- case 6 + 1:
- v = complex_t(creall(c1), cimagl(c1) - i2);
- break;
- case 6 + 2:
- v = c1 - c2;
- break;
- default:
- assert(0);
- }
- emplaceExp!(ComplexExp)(&ue, loc, v, type);
- }
- else if (SymOffExp soe = e1.isSymOffExp())
- {
- emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset - e2.toInteger());
- ue.exp().type = type;
- }
- else
- {
- emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() - e2.toInteger(), type);
- }
+ // Compute e1-e2 as e1+(-e2)
+ UnionExp neg = Neg(e2.type, e2);
+ UnionExp ue = Add(loc, type, e1, neg.exp());
return ue;
}
@@ -1213,6 +1123,10 @@ UnionExp ArrayLength(Type type, Expression e1)
Expression e = (cast(TypeSArray)e1.type.toBasetype()).dim;
emplaceExp!(UnionExp)(&ue, e);
}
+ else if (e1.isNullExp())
+ {
+ emplaceExp!(IntegerExp)(&ue, loc, 0, type);
+ }
else
cantExp(ue);
return ue;
@@ -1505,17 +1419,11 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
Type t2 = e2.type.toBasetype();
//printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
//printf("\tt1 = %s, t2 = %s, type = %s\n", t1.toChars(), t2.toChars(), type.toChars());
- if (e1.op == EXP.null_ && (e2.op == EXP.int64 || e2.op == EXP.structLiteral))
- {
- e = e2;
- t = t1;
- goto L2;
- }
- else if ((e1.op == EXP.int64 || e1.op == EXP.structLiteral) && e2.op == EXP.null_)
+
+ /* e is the non-null operand, t is the type of the null operand
+ */
+ UnionExp catNull(Expression e, Type t)
{
- e = e1;
- t = t2;
- L2:
Type tn = e.type.toBasetype();
if (tn.ty.isSomeChar)
{
@@ -1545,6 +1453,15 @@ UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
assert(ue.exp().type);
return ue;
}
+
+ if (e1.op == EXP.null_ && (e2.op == EXP.int64 || e2.op == EXP.structLiteral))
+ {
+ return catNull(e2, t1);
+ }
+ else if ((e1.op == EXP.int64 || e1.op == EXP.structLiteral) && e2.op == EXP.null_)
+ {
+ return catNull(e1, t2);
+ }
else if (e1.op == EXP.null_ && e2.op == EXP.null_)
{
if (type == e1.type)
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index a3bebb7..2679a63 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -1675,7 +1675,7 @@ final class CParser(AST) : Parser!AST
auto stags = applySpecifier(stag, specifier);
symbols.push(stags);
- if (tt.tok == TOK.enum_)
+ if (0 && tt.tok == TOK.enum_) // C11 proscribes enums with no members, but we allow it
{
if (!tt.members)
error(tt.loc, "`enum %s` has no members", stag.toChars());
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index 12051d9..afd19f3 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -1106,9 +1106,14 @@ MATCH implicitConvTo(Expression e, Type t)
MATCH visitCond(CondExp e)
{
- auto result = visit(e);
- if (result != MATCH.nomatch)
- return result;
+ e.econd = e.econd.optimize(WANTvalue);
+ const opt = e.econd.toBool();
+ if (opt.isPresent())
+ {
+ auto result = visit(e);
+ if (result != MATCH.nomatch)
+ return result;
+ }
MATCH m1 = e.e1.implicitConvTo(t);
MATCH m2 = e.e2.implicitConvTo(t);
@@ -2942,6 +2947,9 @@ Lagain:
t1 = Type.basic[ty1];
t2 = Type.basic[ty2];
+
+ if (!(t1 && t2))
+ return null;
e1 = e1.castTo(sc, t1);
e2 = e2.castTo(sc, t2);
return Lret(Type.basic[ty]);
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 2c7d381..c8f6c2a 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -684,6 +684,7 @@ public:
const char *kind() const override;
bool isUnique();
bool needsClosure();
+ bool checkClosure();
bool hasNestedFrameRefs();
ParameterList getParameterList();
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index 5841a25..890c3b6 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -2352,6 +2352,7 @@ public:
if (ExpInitializer ie = v._init.isExpInitializer())
{
result = interpretRegion(ie.exp, istate, goal);
+ return;
}
else if (v._init.isVoidInitializer())
{
@@ -2359,12 +2360,16 @@ public:
// There is no AssignExp for void initializers,
// so set it here.
setValue(v, result);
+ return;
}
- else
+ else if (v._init.isArrayInitializer())
{
- e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
- result = CTFEExp.cantexp;
+ result = v._init.initializerToExpression(v.type);
+ if (result !is null)
+ return;
}
+ e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
+ result = CTFEExp.cantexp;
}
else if (v.type.size() == 0)
{
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index 0be938f..5e802da 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -619,7 +619,7 @@ extern (C++) final class Module : Package
else
{
// if module is not named 'package' but we're trying to read 'package.d', we're looking for a package module
- bool isPackageMod = (strcmp(toChars(), "package") != 0) && (strcmp(srcfile.name(), package_d) == 0 || (strcmp(srcfile.name(), package_di) == 0));
+ bool isPackageMod = (strcmp(toChars(), "package") != 0) && isPackageFileName(srcfile);
if (isPackageMod)
.error(loc, "importing package '%s' requires a 'package.d' file which cannot be found in '%s'", toChars(), srcfile.toChars());
else
@@ -824,8 +824,7 @@ extern (C++) final class Module : Package
const(char)* srcname = srcfile.toChars();
//printf("Module::parse(srcname = '%s')\n", srcname);
- isPackageFile = (strcmp(srcfile.name(), package_d) == 0 ||
- strcmp(srcfile.name(), package_di) == 0);
+ isPackageFile = isPackageFileName(srcfile);
const(char)[] buf = cast(const(char)[]) this.src;
bool needsReencoding = true;
@@ -1032,8 +1031,7 @@ extern (C++) final class Module : Package
}
assert(dst);
Module m = ppack ? ppack.isModule() : null;
- if (m && (strcmp(m.srcfile.name(), package_d) != 0 &&
- strcmp(m.srcfile.name(), package_di) != 0))
+ if (m && !isPackageFileName(m.srcfile))
{
.error(md.loc, "package name '%s' conflicts with usage as a module name in file %s", ppack.toPrettyChars(), m.srcfile.toChars());
}
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index 2b608f6..c940ff0 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -2441,6 +2441,15 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
auto sd = s.isScopeDsymbol(); // new declaration
auto sd2 = s2.isScopeDsymbol(); // existing declaration
+ static if (log) void print(EnumDeclaration sd)
+ {
+ printf("members: %p\n", sd.members);
+ printf("symtab: %p\n", sd.symtab);
+ printf("endlinnum: %d\n", sd.endlinnum);
+ printf("type: %s\n", sd.type.toChars());
+ printf("memtype: %s\n", sd.memtype.toChars());
+ }
+
if (!sd2)
{
/* Look in tag table
@@ -2473,6 +2482,23 @@ Dsymbol handleTagSymbols(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsymbol sds)
{
sd2.members = sd.members; // transfer definition to sd2
sd.members = null;
+ if (auto ed2 = sd2.isEnumDeclaration())
+ {
+ auto ed = sd.isEnumDeclaration();
+ if (ed.memtype != ed2.memtype)
+ return null; // conflict
+
+ // transfer ed's members to sd2
+ ed2.members.foreachDsymbol( (s)
+ {
+ if (auto em = s.isEnumMember())
+ em.ed = ed2;
+ });
+
+ ed2.type = ed.type;
+ ed2.memtype = ed.memtype;
+ ed2.added = false;
+ }
return sd2;
}
else
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 11a51f1..7f57cbe 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -2023,7 +2023,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
override void visit(EnumDeclaration ed)
{
//printf("EnumDeclaration::semantic(sd = %p, '%s') %s\n", sc.scopesym, sc.scopesym.toChars(), ed.toChars());
- //printf("EnumDeclaration::semantic() %p %s\n", this, ed.toChars());
+ //printf("EnumDeclaration::semantic() %p %s\n", ed, ed.toChars());
if (ed.semanticRun >= PASS.semanticdone)
return; // semantic() already completed
if (ed.semanticRun == PASS.semantic)
@@ -4442,7 +4442,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
invd.semanticRun < PASS.semantic &&
!ad.isUnionDeclaration() // users are on their own with union fields
)
+ {
+ invd.fixupInvariantIdent(ad.invs.length);
ad.invs.push(invd);
+ }
if (!invd.type)
invd.type = new TypeFunction(ParameterList(), Type.tvoid, LINK.d, invd.storage_class);
@@ -5713,6 +5716,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
*/
void addEnumMembers(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds)
{
+ //printf("addEnumMembers(ed: %p)\n", ed);
if (ed.added)
return;
ed.added = true;
@@ -5736,6 +5740,7 @@ void addEnumMembers(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds)
em.ed = ed;
if (isCEnum)
{
+ //printf("adding EnumMember %s to %p\n", em.toChars(), ed);
em.addMember(sc, ed); // add em to ed's symbol table
em.addMember(sc, sds); // add em to symbol table that ed is in
em.parent = ed; // restore it after previous addMember() changed it
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index c0a8e9f..02f12e4 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -7323,7 +7323,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
errors = true;
}
L1:
- //printf("\tnested inside %s\n", enclosing.toChars());
+ //printf("\tnested inside %s as it references %s\n", enclosing.toChars(), sa.toChars());
nested |= 1;
}
}
diff --git a/gcc/d/dmd/entity.d b/gcc/d/dmd/entity.d
index ef2fdef..c29d499 100644
--- a/gcc/d/dmd/entity.d
+++ b/gcc/d/dmd/entity.d
@@ -17,18 +17,27 @@ import core.stdc.ctype;
nothrow:
-public int HtmlNamedEntity(const(char)* p, size_t length)
+/**********************************
+ * See if `name` is an HTML Named Entity
+ * Params:
+ * name = name of the entity
+ * Returns:
+ * code point corresponding to the named entity
+ * ~0 for not recognized as a named entity
+ */
+public uint HtmlNamedEntity(scope const char[] name) pure @nogc @safe
{
- int tableIndex = tolower(*p) - 'a';
- if (tableIndex >= 0 && tableIndex < 26)
+ const firstC = tolower(name[0]);
+ if (firstC >= 'a' && firstC <= 'z')
{
- foreach (entity; namesTable[tableIndex])
+ // Linear search (use hash table instead?)
+ foreach (entity; namesTable[firstC - 'a'])
{
- if (entity.name == p[0 .. length])
+ if (entity.name == name)
return entity.value;
}
}
- return -1;
+ return ~0;
}
private:
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index 0646f57..fb5e092 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -351,7 +351,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, STC
{
unsafeAssign!"scope variable"(v);
}
- else if (v.storage_class & STC.variadic && p == sc.func)
+ else if (v.isTypesafeVariadicParameter && p == sc.func)
{
Type tb = v.type.toBasetype();
if (tb.ty == Tarray || tb.ty == Tsarray)
@@ -649,7 +649,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
Dsymbol p = v.toParent2();
if (va && !vaIsRef && !va.isScope() && !v.isScope() &&
- (va.storage_class & v.storage_class & (STC.maybescope | STC.variadic)) == STC.maybescope &&
+ !v.isTypesafeVariadicParameter && !va.isTypesafeVariadicParameter &&
+ (va.storage_class & v.storage_class & STC.maybescope) &&
p == fd)
{
/* Add v to va's list of dependencies
@@ -663,7 +664,8 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
!(v.storage_class & STC.return_) &&
v.isParameter() &&
fd.flags & FUNCFLAG.returnInprocess &&
- p == fd)
+ p == fd &&
+ !v.isTypesafeVariadicParameter)
{
if (log) printf("inferring 'return' for parameter %s in function %s\n", v.toChars(), fd.toChars());
inferReturn(fd, v, /*returnScope:*/ true); // infer addition of 'return' to make `return scope`
@@ -735,7 +737,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
}
result |= sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to non-scope `%s`", v, e1);
}
- else if (v.storage_class & STC.variadic && p == fd)
+ else if (v.isTypesafeVariadicParameter && p == fd)
{
Type tb = v.type.toBasetype();
if (tb.ty == Tarray || tb.ty == Tsarray)
@@ -1022,7 +1024,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
continue;
}
}
- else if (v.storage_class & STC.variadic && p == sc.func)
+ else if (v.isTypesafeVariadicParameter && p == sc.func)
{
Type tb = v.type.toBasetype();
if (tb.ty == Tarray || tb.ty == Tsarray)
@@ -1194,7 +1196,8 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
v.isParameter() &&
!v.doNotInferReturn &&
sc.func.flags & FUNCFLAG.returnInprocess &&
- p == sc.func)
+ p == sc.func &&
+ !v.isTypesafeVariadicParameter)
{
inferReturn(sc.func, v, /*returnScope:*/ true); // infer addition of 'return'
continue;
@@ -1250,7 +1253,7 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
}
}
}
- else if (v.storage_class & STC.variadic && p == sc.func)
+ else if (v.isTypesafeVariadicParameter && p == sc.func)
{
Type tb = v.type.toBasetype();
if (tb.ty == Tarray || tb.ty == Tsarray)
@@ -1627,7 +1630,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool re
{
if (tb.ty == Tsarray)
return;
- if (v.storage_class & STC.variadic)
+ if (v.isTypesafeVariadicParameter)
{
er.byvalue.push(v);
return;
@@ -1943,7 +1946,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retR
VarDeclaration v = ve.var.isVarDeclaration();
if (tb.ty == Tarray || tb.ty == Tsarray)
{
- if (v && v.storage_class & STC.variadic)
+ if (v && v.isTypesafeVariadicParameter)
{
er.pushRef(v, retRefTransition);
return;
@@ -2586,3 +2589,15 @@ private bool checkScopeVarAddr(VarDeclaration v, Expression e, Scope* sc, bool g
return sc.setUnsafeDIP1000(gag, e.loc,
"cannot take address of `scope` variable `%s` since `scope` applies to first indirection only", v);
}
+
+/****************************
+ * Determine if `v` is a typesafe variadic parameter.
+ * Params:
+ * v = variable to check
+ * Returns:
+ * true if `v` is a variadic parameter
+ */
+bool isTypesafeVariadicParameter(VarDeclaration v)
+{
+ return !!(v.storage_class & STC.variadic);
+}
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 35ba5fa..30baabd 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -3463,8 +3463,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (!exp.arguments && exp.newtype.isTypeSArray())
{
auto ts = exp.newtype.isTypeSArray();
- edim = ts.dim;
- exp.newtype = ts.next;
+ // check `new Value[Key]`
+ ts.dim = ts.dim.expressionSemantic(sc);
+ if (ts.dim.op == EXP.type)
+ {
+ exp.newtype = new TypeAArray(ts.next, ts.dim.isTypeExp().type);
+ }
+ else
+ {
+ edim = ts.dim;
+ exp.newtype = ts.next;
+ }
}
ClassDeclaration cdthis = null;
@@ -3518,18 +3527,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
return setError();
}
- //https://issues.dlang.org/show_bug.cgi?id=20547
- //exp.arguments are the "parameters" to [], not to a real function
- //so the errors that come from preFunctionParameters are misleading
- if (originalNewtype.ty == Tsarray)
- {
- if (preFunctionParameters(sc, exp.arguments, false))
- {
- exp.error("cannot create a `%s` with `new`", originalNewtype.toChars());
- return setError();
- }
- }
- else if (preFunctionParameters(sc, exp.arguments))
+ if (preFunctionParameters(sc, exp.arguments))
{
return setError();
}
@@ -3885,6 +3883,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.type = exp.type.pointerTo();
}
+ else if (tb.ty == Taarray)
+ {
+ // e.g. `new Alias(args)`
+ if (nargs)
+ {
+ exp.error("`new` cannot take arguments for an associative array");
+ return setError();
+ }
+ }
else
{
exp.error("cannot create a `%s` with `new`", exp.type.toChars());
@@ -5019,7 +5026,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
err = true;
}
- if (tf.trust <= TRUST.system && sc.setUnsafe())
+ if (tf.trust <= TRUST.system && sc.setUnsafe(true, exp.loc,
+ "`@safe` function `%s` cannot call `@system` `%s`", sc.func, exp.e1))
{
exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`",
sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
@@ -7588,11 +7596,20 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
// Check for unsafe casts
- if (!isSafeCast(ex, t1b, tob) &&
- (!sc.func && sc.stc & STC.safe || sc.setUnsafe()))
+ if (!isSafeCast(ex, t1b, tob))
{
- exp.error("cast from `%s` to `%s` not allowed in safe code", exp.e1.type.toChars(), exp.to.toChars());
- return setError();
+ // This is an ad-hoc fix for https://issues.dlang.org/show_bug.cgi?id=19646
+ // Should be replaced by a more general @system variables implementation
+ if (!sc.func && sc.stc & STC.safe)
+ {
+ exp.error("cast from `%s` to `%s` not allowed in safe code", exp.e1.type.toChars(), exp.to.toChars());
+ return setError();
+ }
+
+ if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
+ {
+ return setError();
+ }
}
// `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
@@ -8900,6 +8917,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) ||
e2x.checkSharedAccess(sc))
return setError();
+
+ if (e2x.type.isTypeNoreturn() && !e2x.isAssertExp() && !e2x.isThrowExp() && !e2x.isCallExp())
+ {
+ auto msg = new StringExp(e2x.loc, "Accessed expression of type `noreturn`");
+ msg.type = Type.tstring;
+ e2x = new AssertExp(e2x.loc, IntegerExp.literal!0, msg);
+ e2x.type = Type.tnoreturn;
+ return setResult(e2x);
+ }
exp.e2 = e2x;
}
@@ -9896,9 +9922,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
ae.e2.type.nextOf &&
ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf);
+ /* Unlike isArrayCtor above, lower all Rvalues. If the RHS is a literal,
+ * then we do want to make a temporary for it and call its destructor.
+ */
const isArraySetCtor =
(ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) &&
- ae.e2.isLvalue &&
(ae.e2.type.ty == Tstruct || ae.e2.type.ty == Tsarray) &&
ae.e1.type.nextOf &&
ae.e1.type.nextOf.equivalent(ae.e2.type);
@@ -10302,6 +10330,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// `__appendtmp*` will be destroyed together with the array `exp.e1`.
auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration();
vd.storage_class |= STC.nodtor;
+ // Be more explicit that this "declaration" is local to the expression
+ vd.storage_class |= STC.exptemp;
}
auto ale = new ArrayLengthExp(exp.loc, value1);
@@ -11870,6 +11900,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
//printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
+ // https://issues.dlang.org/show_bug.cgi?id=22390
+ // Equality comparison between array of noreturns simply lowers to length equality comparison
+ if (t1.nextOf.isTypeNoreturn() && t2.nextOf.isTypeNoreturn())
+ {
+ Expression exp_l1 = new DotIdExp(exp.e1.loc, exp.e1, Id.length);
+ Expression exp_l2 = new DotIdExp(exp.e2.loc, exp.e2, Id.length);
+ auto e = new EqualExp(EXP.equal, exp.loc, exp_l1, exp_l2);
+ result = e.expressionSemantic(sc);
+ return;
+ }
+
if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays"))
return setError();
@@ -12638,7 +12679,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
e = new CommaExp(exp.loc, eleft, e);
e.type = Type.tvoid; // ambiguous type?
}
- return e;
+ return e.expressionSemantic(sc);
}
if (auto o = s.isOverloadSet())
{
@@ -13131,26 +13172,24 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
{
//printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
- if (v)
+ if (v is null)
+ return true;
+
+ if (!v.canTakeAddressOf())
+ {
+ exp.error("cannot take address of `%s`", exp.toChars());
+ return false;
+ }
+ if (sc.func && !sc.intypeof && !v.isDataseg())
{
- if (!v.canTakeAddressOf())
+ v.storage_class &= ~STC.maybescope;
+ v.doNotInferScope = true;
+ if (global.params.useDIP1000 != FeatureState.enabled &&
+ !(v.storage_class & STC.temp) &&
+ sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func))
{
- exp.error("cannot take address of `%s`", exp.toChars());
return false;
}
- if (sc.func && !sc.intypeof && !v.isDataseg())
- {
- const(char)* p = v.isParameter() ? "parameter" : "local";
- v.storage_class &= ~STC.maybescope;
- v.doNotInferScope = true;
- if (global.params.useDIP1000 != FeatureState.enabled &&
- !(v.storage_class & STC.temp) &&
- sc.setUnsafe())
- {
- exp.error("cannot take address of %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars());
- return false;
- }
- }
}
return true;
}
diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d
index 9fe40bf..0ea7303 100644
--- a/gcc/d/dmd/file_manager.d
+++ b/gcc/d/dmd/file_manager.d
@@ -20,6 +20,12 @@ import dmd.identifier;
enum package_d = "package." ~ mars_ext;
enum package_di = "package." ~ hdr_ext;
+/// Returns: whether a file with `name` is a special "package.d" module
+bool isPackageFileName(scope FileName fileName) nothrow
+{
+ return FileName.equals(fileName.name, package_d) || FileName.equals(fileName.name, package_di);
+}
+
final class FileManager
{
private StringTable!(const(ubyte)[]) files;
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index 83bc2ea..7475cb4 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -867,6 +867,8 @@ extern (C++) class FuncDeclaration : Declaration
auto f = s.isFuncDeclaration();
if (!f)
return 0;
+ if (f.storage_class & STC.disable)
+ return 0;
if (t.equals(f.type))
{
fd = f;
@@ -2048,9 +2050,11 @@ extern (C++) class FuncDeclaration : Declaration
}
if (!found)
{
- //printf("\tadding sibling %s\n", fdthis.toPrettyChars());
+ //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars());
if (!sc.intypeof && !(sc.flags & SCOPE.compile))
+ {
siblingCallers.push(fdthis);
+ }
}
}
@@ -2164,7 +2168,6 @@ extern (C++) class FuncDeclaration : Declaration
return false;
Lyes:
- //printf("\tneeds closure\n");
return true;
}
@@ -2176,14 +2179,21 @@ extern (C++) class FuncDeclaration : Declaration
* Returns:
* true if any errors occur.
*/
- extern (D) final bool checkClosure()
+ extern (C++) final bool checkClosure()
{
+ //printf("checkClosure() %s\n", toChars());
if (!needsClosure())
return false;
if (setGC())
{
- error("is `@nogc` yet allocates closures with the GC");
+ error("is `@nogc` yet allocates closure for `%s()` with the GC", toChars());
+ if (global.gag) // need not report supplemental errors
+ return true;
+ }
+ else if (global.params.betterC)
+ {
+ error("is `-betterC` yet allocates closure for `%s()` with the GC", toChars());
if (global.gag) // need not report supplemental errors
return true;
}
@@ -2216,7 +2226,7 @@ extern (C++) class FuncDeclaration : Declaration
break LcheckAncestorsOfANestedRef;
}
a.push(f);
- .errorSupplemental(f.loc, "%s closes over variable %s at %s",
+ .errorSupplemental(f.loc, "`%s` closes over variable `%s` at %s",
f.toPrettyChars(), v.toChars(), v.loc.toChars());
break LcheckAncestorsOfANestedRef;
}
@@ -3293,7 +3303,8 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
td.kind(), td.parent.toPrettyChars(), td.ident.toChars(),
tiargsBuf.peekChars(), fargsBuf.peekChars());
- printCandidates(loc, td, sc.isDeprecated());
+ if (!global.gag || global.params.showGaggedErrors)
+ printCandidates(loc, td, sc.isDeprecated());
return null;
}
/* This case used to happen when several ctors are mixed in an agregate.
@@ -3331,7 +3342,8 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
{
.error(loc, "none of the overloads of `%s` are callable using a %sobject",
fd.ident.toChars(), thisBuf.peekChars());
- printCandidates(loc, fd, sc.isDeprecated());
+ if (!global.gag || global.params.showGaggedErrors)
+ printCandidates(loc, fd, sc.isDeprecated());
return null;
}
@@ -3361,18 +3373,23 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
{
.error(loc, "none of the overloads of `%s` are callable using argument types `%s`",
fd.toChars(), fargsBuf.peekChars());
- printCandidates(loc, fd, sc.isDeprecated());
+ if (!global.gag || global.params.showGaggedErrors)
+ printCandidates(loc, fd, sc.isDeprecated());
return null;
}
.error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
tf.modToChars(), fargsBuf.peekChars());
+
// re-resolve to check for supplemental message
- const(char)* failMessage;
- functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage);
- if (failMessage)
- errorSupplemental(loc, failMessage);
+ if (!global.gag || global.params.showGaggedErrors)
+ {
+ const(char)* failMessage;
+ functionResolve(m, orig_s, loc, sc, tiargs, tthis, fargs, &failMessage);
+ if (failMessage)
+ errorSupplemental(loc, failMessage);
+ }
return null;
}
@@ -4220,6 +4237,7 @@ extern (C++) final class InvariantDeclaration : FuncDeclaration
{
extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, Identifier id, Statement fbody)
{
+ // Make a unique invariant for now; we'll fix it up as we add it to the aggregate invariant list.
super(loc, endloc, id ? id : Identifier.generateId("__invariant"), stc, null);
this.fbody = fbody;
}
@@ -4256,6 +4274,15 @@ extern (C++) final class InvariantDeclaration : FuncDeclaration
{
v.visit(this);
}
+
+ extern (D) void fixupInvariantIdent(size_t offset)
+ {
+ OutBuffer idBuf;
+ idBuf.writestring("__invariant");
+ idBuf.print(offset);
+
+ ident = Identifier.idPool(idBuf[]);
+ }
}
@@ -4447,12 +4474,15 @@ void errorSupplementalInferredSafety(FuncDeclaration fd, int maxDepth, bool depr
errorFunc(s.loc, s.fmtStr,
s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : "");
}
- else if (FuncDeclaration fd2 = cast(FuncDeclaration) s.arg0)
+ else if (s.arg0.dyncast() == DYNCAST.dsymbol)
{
- if (maxDepth > 0)
+ if (FuncDeclaration fd2 = (cast(Dsymbol) s.arg0).isFuncDeclaration())
{
- errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars());
- errorSupplementalInferredSafety(fd2, maxDepth - 1, deprecation);
+ if (maxDepth > 0)
+ {
+ errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars());
+ errorSupplementalInferredSafety(fd2, maxDepth - 1, deprecation);
+ }
}
}
}
diff --git a/gcc/d/dmd/impcnvtab.d b/gcc/d/dmd/impcnvtab.d
index ab46f5e..832c331 100644
--- a/gcc/d/dmd/impcnvtab.d
+++ b/gcc/d/dmd/impcnvtab.d
@@ -64,6 +64,57 @@ enum ImpCnvTab impCnvTab = generateImpCnvTab();
ImpCnvTab generateImpCnvTab()
{
+ TY[TMAX] typeTYs =
+ [
+ Tarray,
+ Tsarray,
+ Taarray,
+ Tpointer,
+ Treference,
+ Tfunction,
+ Tident,
+ Tclass,
+ Tstruct,
+ Tenum,
+ Tdelegate,
+ Tnone,
+ Tvoid,
+ Tint8,
+ Tuns8,
+ Tint16,
+ Tuns16,
+ Tint32,
+ Tuns32,
+ Tint64,
+ Tuns64,
+ Tfloat32,
+ Tfloat64,
+ Tfloat80,
+ Timaginary32,
+ Timaginary64,
+ Timaginary80,
+ Tcomplex32,
+ Tcomplex64,
+ Tcomplex80,
+ Tbool,
+ Tchar,
+ Twchar,
+ Tdchar,
+ Terror,
+ Tinstance,
+ Ttypeof,
+ Ttuple,
+ Tslice,
+ Treturn,
+ Tnull,
+ Tvector,
+ Tint128,
+ Tuns128,
+ Ttraits,
+ Tmixin,
+ Tnoreturn,
+ Ttag,
+ ];
ImpCnvTab impCnvTab;
// Set conversion tables
@@ -375,5 +426,9 @@ ImpCnvTab generateImpCnvTab()
X(Tcomplex80,Tcomplex80, Tcomplex80,Tcomplex80, Tcomplex80);
+ // "No type is implicitly convertible to noreturn, but noreturn is implicitly convertible to every other type"
+ foreach(convertToTy; typeTYs)
+ X(Tnoreturn, convertToTy, convertToTy, convertToTy, convertToTy);
+
return impCnvTab;
}
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index a1963da..a576712 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -567,18 +567,40 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
i.exp = e.optimize(WANTvalue);
}
}
+
+ // Look for the case of statically initializing an array with a single member.
+ // Recursively strip static array / enum layers until a compatible element is found,
+ // and return an `ArrayLiteralExp` repeating the initializer, or `null` if no match found
+ // int[2][3] = 7 => [[7, 7], [7, 7], [7, 7]]
+ // int[2] = new Object => null
+ Expression sarrayRepeat(Type tb)
{
- // Look for the case of statically initializing an array
- // with a single member.
- auto tba = tb.isTypeSArray();
- if (tba && !tba.next.equals(ti.toBasetype().nextOf()) && i.exp.implicitConvTo(tba.next))
+ auto tsa = tb.isTypeSArray();
+ if (!tsa)
+ return null;
+
+ // printf("i.exp = %s, tsa = %s\n", i.exp.toChars(), tsa.toChars());
+ Expression elem = null;
+ if (i.exp.implicitConvTo(tb.nextOf()))
+ elem = i.exp.implicitCastTo(sc, tb.nextOf());
+ else if (auto ae = sarrayRepeat(tb.nextOf().toBasetype()))
+ elem = ae;
+ else
+ return null;
+
+ auto arrayElements = new Expressions(cast(size_t) tsa.dim.toInteger());
+ foreach (ref e; *arrayElements)
+ e = elem;
+ return new ArrayLiteralExp(i.exp.loc, tb, elem, arrayElements);
+ }
+
+ if (auto sa = sarrayRepeat(tb))
{
- /* If the variable is not actually used in compile time, array creation is
- * redundant. So delay it until invocation of toExpression() or toDt().
- */
- t = tb.nextOf();
+ // printf("sa = %s\n", sa.toChars());
+ i.exp = sa;
}
+ {
auto tta = t.isTypeSArray();
if (i.exp.implicitConvTo(t))
{
@@ -595,6 +617,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
}
else
{
+ auto tba = tb.isTypeSArray();
// Look for mismatch of compile-time known length to emit
// better diagnostic message, as same as AssignExp::semantic.
if (tba && i.exp.implicitConvTo(tba.next.arrayOf()) > MATCH.nomatch)
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index ef918e2..11afcdd 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -1326,7 +1326,7 @@ class Lexer
switch (*p)
{
case ';':
- c = HtmlNamedEntity(idstart, p - idstart);
+ c = HtmlNamedEntity(idstart[0 .. p - idstart]);
if (c == ~0)
{
error(loc, "unnamed character entity &%.*s;", cast(int)(p - idstart), idstart);
diff --git a/gcc/d/dmd/mustuse.d b/gcc/d/dmd/mustuse.d
index 4eb4228..369d60e 100644
--- a/gcc/d/dmd/mustuse.d
+++ b/gcc/d/dmd/mustuse.d
@@ -98,7 +98,7 @@ void checkMustUseReserved(Dsymbol sym)
*/
private bool isAssignment(Expression e)
{
- if (e.isAssignExp || e.isBinAssignExp)
+ if (e.isAssignExp || e.isBinAssignExp || e.isConstructExp || e.isBlitExp)
return true;
if (auto ce = e.isCallExp())
{
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index 2b7b9ac..be28d08 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -1120,7 +1120,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
e.e1 = ci;
}
}
- if (e.e1.op == EXP.string_ || e.e1.op == EXP.arrayLiteral || e.e1.op == EXP.assocArrayLiteral || e.e1.type.toBasetype().ty == Tsarray)
+ if (e.e1.op == EXP.string_ || e.e1.op == EXP.arrayLiteral || e.e1.op == EXP.assocArrayLiteral || e.e1.type.toBasetype().ty == Tsarray || e.e1.op == EXP.null_)
{
ret = ArrayLength(e.type, e.e1).copy();
}
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 4e3fd53..a2c364e 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -2186,7 +2186,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (token.value == TOK.identifier)
s = new AST.DebugSymbol(token.loc, token.ident);
else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
+ {
+ // @@@DEPRECATED_2.111@@@
+ // Deprecated in 2.101, remove in 2.111
+ deprecation("`debug = <integer>` is deprecated, use debug identifiers instead");
+
s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue);
+ }
else
{
error("identifier or integer expected, not `%s`", token.toChars());
@@ -2215,7 +2221,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (token.value == TOK.identifier)
id = token.ident;
else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
+ {
+ // @@@DEPRECATED_2.111@@@
+ // Deprecated in 2.101, remove in 2.111
+ deprecation("`debug( <integer> )` is deprecated, use debug identifiers instead");
+
level = cast(uint)token.unsvalue;
+ }
else
error("identifier or integer expected inside `debug(...)`, not `%s`", token.toChars());
loc = token.loc;
@@ -2235,7 +2247,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (token.value == TOK.identifier)
s = new AST.VersionSymbol(token.loc, token.ident);
else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
+ {
+ // @@@DEPRECATED_2.111@@@
+ // Deprecated in 2.101, remove in 2.111
+ deprecation("`version = <integer>` is deprecated, use version identifiers instead");
s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue);
+ }
else
{
error("identifier or integer expected, not `%s`", token.toChars());
@@ -2269,7 +2286,13 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (token.value == TOK.identifier)
id = token.ident;
else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
+ {
+ // @@@DEPRECATED_2.111@@@
+ // Deprecated in 2.101, remove in 2.111
+ deprecation("`version( <integer> )` is deprecated, use version identifiers instead");
+
level = cast(uint)token.unsvalue;
+ }
else if (token.value == TOK.unittest_)
id = Identifier.idPool(Token.toString(TOK.unittest_));
else if (token.value == TOK.assert_)
@@ -9312,13 +9335,10 @@ LagainStc:
{
AST.TypeAArray taa = cast(AST.TypeAArray)t;
AST.Type index = taa.index;
+ // `new Type[expr]` is a static array
auto edim = AST.typeToExpression(index);
- if (!edim)
- {
- error("cannot create a `%s` with `new`", t.toChars);
- return new AST.NullExp(loc);
- }
- t = new AST.TypeSArray(taa.next, edim);
+ if (edim)
+ t = new AST.TypeSArray(taa.next, edim);
}
else if (token.value == TOK.leftParenthesis && t.ty != Tsarray)
{
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index c5d7667..6f37770 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -470,14 +470,6 @@ private extern(C++) final class Semantic3Visitor : Visitor
if (f.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
{
stc |= STC.variadic;
- auto vtypeb = vtype.toBasetype();
- if (vtypeb.ty == Tarray || vtypeb.ty == Tclass)
- {
- /* Since it'll be pointing into the stack for the array
- * contents, it needs to be `scope`
- */
- stc |= STC.scope_;
- }
}
if ((funcdecl.flags & FUNCFLAG.inferScope) && !(fparam.storageClass & STC.scope_))
@@ -1379,7 +1371,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
funcdecl.flags &= ~FUNCFLAG.semantic3Errors;
if (funcdecl.type.ty == Terror)
funcdecl.errors = true;
- //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent.toChars(), toChars(), sc, loc.toChars());
+ //printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", funcdecl.parent.toChars(), funcdecl.toChars(), sc, funcdecl.loc.toChars());
//fflush(stdout);
}
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index f23b988..e5e5753 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -733,9 +733,26 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
{
assert(oaggr.type);
- fs.error("invalid `foreach` aggregate `%s` of type `%s`", oaggr.toChars(), oaggr.type.toPrettyChars());
- if (isAggregate(fs.aggr.type))
- fs.loc.errorSupplemental("maybe define `opApply()`, range primitives, or use `.tupleof`");
+ fs.error("invalid `%s` aggregate `%s` of type `%s`",
+ Token.toChars(fs.op), oaggr.toChars(), oaggr.type.toPrettyChars());
+
+ if (auto ad = isAggregate(fs.aggr.type))
+ {
+ if (fs.op == TOK.foreach_reverse_)
+ {
+ fs.loc.errorSupplemental("`foreach_reverse` works with bidirectional ranges"~
+ " (implementing `back` and `popBack`), aggregates implementing" ~
+ " `opApplyReverse`, or the result of an aggregate's `.tupleof` property");
+ fs.loc.errorSupplemental("https://dlang.org/phobos/std_range_primitives.html#isBidirectionalRange");
+ }
+ else
+ {
+ fs.loc.errorSupplemental("`foreach` works with input ranges"~
+ " (implementing `front` and `popFront`), aggregates implementing" ~
+ " `opApply`, or the result of an aggregate's `.tupleof` property");
+ fs.loc.errorSupplemental("https://dlang.org/phobos/std_range_primitives.html#isInputRange");
+ }
+ }
return setError();
}
@@ -2828,10 +2845,20 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
rs.error("`return` statements cannot be in contracts");
errors = true;
}
- if (sc.os && sc.os.tok != TOK.onScopeFailure)
+ if (sc.os)
{
- rs.error("`return` statements cannot be in `%s` bodies", Token.toChars(sc.os.tok));
- errors = true;
+ // @@@DEPRECATED_2.112@@@
+ // Deprecated in 2.100, transform into an error in 2.112
+ if (sc.os.tok == TOK.onScopeFailure)
+ {
+ rs.deprecation("`return` statements cannot be in `scope(failure)` bodies.");
+ deprecationSupplemental(rs.loc, "Use try-catch blocks for this purpose");
+ }
+ else
+ {
+ rs.error("`return` statements cannot be in `%s` bodies", Token.toChars(sc.os.tok));
+ errors = true;
+ }
}
if (sc.tf)
{
@@ -2913,6 +2940,17 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
rs.exp.type = texp;
}
+ // @@@DEPRECATED_2.111@@@
+ const olderrors = global.startGagging();
+ // uncomment to turn deprecation into an error when
+ // deprecation cycle is over
+ if (discardValue(rs.exp))
+ {
+ //errors = true;
+ }
+ if (global.endGagging(olderrors))
+ rs.exp.deprecation("`%s` has no effect", rs.exp.toChars());
+
/* Replace:
* return exp;
* with:
diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d
index 25dee7f..5791a88 100644
--- a/gcc/d/dmd/transitivevisitor.d
+++ b/gcc/d/dmd/transitivevisitor.d
@@ -862,6 +862,12 @@ package mixin template ParseVisitMethods(AST)
visitFuncBody(d);
}
+ override void visit(AST.CtorDeclaration d)
+ {
+ //printf("Visiting CtorDeclaration\n");
+ visitFuncBody(d);
+ }
+
override void visit(AST.StaticCtorDeclaration d)
{
//printf("Visiting StaticCtorDeclaration\n");
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index 0469b92..b1f1b1f 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -1272,6 +1272,16 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
errors = true;
}
+ const bool isTypesafeVariadic = i + 1 == dim &&
+ tf.parameterList.varargs == VarArg.typesafe &&
+ (t.isTypeDArray() || t.isTypeClass());
+ if (isTypesafeVariadic)
+ {
+ /* typesafe variadic arguments are constructed on the stack, so must be `scope`
+ */
+ fparam.storageClass |= STC.scope_ | STC.scopeinferred;
+ }
+
if (fparam.storageClass & STC.return_)
{
if (fparam.isReference())
@@ -1300,8 +1310,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
}
}
- if (i + 1 == dim && tf.parameterList.varargs == VarArg.typesafe &&
- (t.isTypeDArray() || t.isTypeClass()))
+ if (isTypesafeVariadic)
{
/* This is because they can be constructed on the stack
* https://dlang.org/spec/function.html#typesafe_variadic_functions
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index 1bb10a8..40c2689 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -873,6 +873,17 @@ public:
gcc_unreachable ();
}
+ /* Look for exp = noreturn; */
+ if (e->e2->type->isTypeNoreturn ())
+ {
+ /* If the RHS is a `noreturn' expression, there is no point generating
+ any code for the assignment, just evaluate side effects. */
+ tree t1 = build_expr (e->e1);
+ tree t2 = build_expr (e->e2);
+ this->result_ = compound_expr (t1, t2);
+ return;
+ }
+
/* Look for array[] = n; */
if (e->e1->op == EXP::slice)
{
diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt
index bd9c61d..da65239 100644
--- a/gcc/d/lang.opt
+++ b/gcc/d/lang.opt
@@ -249,7 +249,7 @@ Compile in debug code.
fdebug=
D Joined RejectNegative
--fdebug=<level|ident> Compile in debug code, code <= <level>, or code identified by <ident>.
+-fdebug=<ident> Compile in debug code identified by <ident>.
fdoc
D
@@ -466,7 +466,7 @@ Compile in unittest code.
fversion=
D Joined RejectNegative
--fversion=<level|ident> Compile in version code >= <level> or identified by <ident>.
+-fversion=<ident> Compile in version code identified by <ident>.
fweak-templates
D Var(flag_weak_templates) Init(1)