diff options
author | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-07-26 17:42:23 +0200 |
---|---|---|
committer | Iain Buclaw <ibuclaw@gdcproject.org> | 2022-08-03 13:01:53 +0200 |
commit | b6df113247b9f3f7c3db0e65c481dad5bcfddfb4 (patch) | |
tree | 31466a07292ad0cc289de7c23e39ba31b9e8b7c3 /gcc/d | |
parent | 64ce76d940501cb04d14a0d36752b4f93473531c (diff) | |
download | gcc-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')
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) |