summaryrefslogtreecommitdiff
path: root/gcc/d
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d')
-rw-r--r--gcc/d/ChangeLog16
-rw-r--r--gcc/d/Make-lang.in2
-rw-r--r--gcc/d/d-ctfloat.cc3
-rw-r--r--gcc/d/d-lang.cc5
-rw-r--r--gcc/d/d-port.cc8
-rw-r--r--gcc/d/dmd/MERGE2
-rw-r--r--gcc/d/dmd/README.md2
-rw-r--r--gcc/d/dmd/VERSION2
-rw-r--r--gcc/d/dmd/aggregate.d22
-rw-r--r--gcc/d/dmd/arrayop.d2
-rw-r--r--gcc/d/dmd/astenums.d1
-rw-r--r--gcc/d/dmd/attrib.d58
-rw-r--r--gcc/d/dmd/blockexit.d15
-rw-r--r--gcc/d/dmd/clone.d6
-rw-r--r--gcc/d/dmd/common/README.md1
-rw-r--r--gcc/d/dmd/common/bitfields.d70
-rw-r--r--gcc/d/dmd/common/file.d4
-rw-r--r--gcc/d/dmd/common/outbuffer.d4
-rw-r--r--gcc/d/dmd/common/string.d4
-rw-r--r--gcc/d/dmd/constfold.d2
-rw-r--r--gcc/d/dmd/cparse.d117
-rw-r--r--gcc/d/dmd/ctfeexpr.d4
-rw-r--r--gcc/d/dmd/dcast.d12
-rw-r--r--gcc/d/dmd/declaration.d41
-rw-r--r--gcc/d/dmd/dmangle.d10
-rw-r--r--gcc/d/dmd/dmodule.d30
-rw-r--r--gcc/d/dmd/dscope.d2
-rw-r--r--gcc/d/dmd/dsymbol.d86
-rw-r--r--gcc/d/dmd/dsymbolsem.d24
-rw-r--r--gcc/d/dmd/dtemplate.d6
-rw-r--r--gcc/d/dmd/errors.d16
-rw-r--r--gcc/d/dmd/escape.d112
-rw-r--r--gcc/d/dmd/expression.d14
-rw-r--r--gcc/d/dmd/expression.h8
-rw-r--r--gcc/d/dmd/expressionsem.d218
-rw-r--r--gcc/d/dmd/file_manager.d33
-rw-r--r--gcc/d/dmd/hdrgen.d282
-rw-r--r--gcc/d/dmd/id.d1
-rw-r--r--gcc/d/dmd/initsem.d34
-rw-r--r--gcc/d/dmd/json.d5
-rw-r--r--gcc/d/dmd/lexer.d63
-rw-r--r--gcc/d/dmd/mtype.d169
-rw-r--r--gcc/d/dmd/mtype.h4
-rw-r--r--gcc/d/dmd/mustuse.d244
-rw-r--r--gcc/d/dmd/opover.d4
-rw-r--r--gcc/d/dmd/optimize.d49
-rw-r--r--gcc/d/dmd/parse.d98
-rw-r--r--gcc/d/dmd/root/aav.d2
-rw-r--r--gcc/d/dmd/root/array.d2
-rw-r--r--gcc/d/dmd/root/complex.d4
-rw-r--r--gcc/d/dmd/root/file.d10
-rw-r--r--gcc/d/dmd/root/longdouble.d2
-rw-r--r--gcc/d/dmd/root/optional.d4
-rw-r--r--gcc/d/dmd/root/port.h5
-rw-r--r--gcc/d/dmd/semantic2.d2
-rw-r--r--gcc/d/dmd/statement.d8
-rw-r--r--gcc/d/dmd/statementsem.d4
-rw-r--r--gcc/d/dmd/tokens.d2
-rw-r--r--gcc/d/dmd/traits.d80
-rw-r--r--gcc/d/dmd/transitivevisitor.d4
-rw-r--r--gcc/d/dmd/typesem.d40
-rw-r--r--gcc/d/dmd/utils.d9
-rw-r--r--gcc/d/expr.cc10
-rw-r--r--gcc/d/lang.opt4
64 files changed, 1418 insertions, 689 deletions
diff --git a/gcc/d/ChangeLog b/gcc/d/ChangeLog
index f1afaf20331..bb179bcf7e9 100644
--- a/gcc/d/ChangeLog
+++ b/gcc/d/ChangeLog
@@ -1,3 +1,19 @@
+2022-04-21 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * dmd/MERGE: Merge upstream dmd eb7bee331.
+ * dmd/VERSION: Update version to v2.100.0-beta.1.
+ * d-lang.cc (d_handle_option): Handle OPT_frevert_dip1000.
+ * lang.opt (frevert=dip1000): New option.
+
+2022-04-13 Iain Buclaw <ibuclaw@gdcproject.org>
+
+ * Make-lang.in (D_FRONTEND_OBJS): Add d/common-bitfields.o,
+ d/mustuse.o.
+ * d-ctfloat.cc (CTFloat::isIdentical): Don't treat NaN values as
+ identical.
+ * dmd/MERGE: Merge upstream dmd 4d1bfcf14.
+ * expr.cc (ExprVisitor::visit (VoidInitExp *)): New.
+
2022-04-03 Iain Buclaw <ibuclaw@gdcproject.org>
* d-lang.cc: Include dmd/template.h.
diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in
index 6c90657d65f..f3e34c54015 100644
--- a/gcc/d/Make-lang.in
+++ b/gcc/d/Make-lang.in
@@ -89,6 +89,7 @@ D_FRONTEND_OBJS = \
d/canthrow.o \
d/chkformat.o \
d/clone.o \
+ d/common-bitfields.o \
d/common-file.o \
d/common-outbuffer.o \
d/common-string.o \
@@ -143,6 +144,7 @@ D_FRONTEND_OBJS = \
d/lambdacomp.o \
d/lexer.o \
d/mtype.o \
+ d/mustuse.o \
d/nogc.o \
d/nspace.o \
d/ob.o \
diff --git a/gcc/d/d-ctfloat.cc b/gcc/d/d-ctfloat.cc
index 6e6d10ff0a4..c4d9a44c59b 100644
--- a/gcc/d/d-ctfloat.cc
+++ b/gcc/d/d-ctfloat.cc
@@ -55,8 +55,7 @@ CTFloat::isIdentical (real_t x, real_t y)
{
real_value rx = x.rv ();
real_value ry = y.rv ();
- return (REAL_VALUE_ISNAN (rx) && REAL_VALUE_ISNAN (ry))
- || real_identical (&rx, &ry);
+ return real_identical (&rx, &ry);
}
/* Return true if real_t value R is NaN. */
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 69571628336..9adcabdf7cf 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -637,12 +637,17 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
break;
case OPT_frevert_all:
+ global.params.useDIP1000 = FeatureState::disabled;
global.params.useDIP25 = FeatureState::disabled;
global.params.dtorFields = FeatureState::disabled;
global.params.fix16997 = !value;
global.params.markdown = !value;
break;
+ case OPT_frevert_dip1000:
+ global.params.useDIP1000 = FeatureState::disabled;
+ break;
+
case OPT_frevert_dip25:
global.params.useDIP25 = FeatureState::disabled;
break;
diff --git a/gcc/d/d-port.cc b/gcc/d/d-port.cc
index a0e06b37683..a908cc8dbb0 100644
--- a/gcc/d/d-port.cc
+++ b/gcc/d/d-port.cc
@@ -31,11 +31,11 @@ along with GCC; see the file COPYING3. If not see
/* Compare the first N bytes of S1 and S2 without regard to the case. */
int
-Port::memicmp (const char *s1, const char *s2, size_t n)
+Port::memicmp (const char *s1, const char *s2, d_size_t n)
{
int result = 0;
- for (size_t i = 0; i < n; i++)
+ for (d_size_t i = 0; i < n; i++)
{
char c1 = s1[i];
char c2 = s2[i];
@@ -143,9 +143,9 @@ Port::readlongBE (const void *buffer)
/* Write an SZ-byte sized VALUE to BUFFER, ignoring endian-ness. */
void
-Port::valcpy (void *buffer, uint64_t value, size_t sz)
+Port::valcpy (void *buffer, uint64_t value, d_size_t sz)
{
- gcc_assert (((size_t) buffer) % sz == 0);
+ gcc_assert (((d_size_t) buffer) % sz == 0);
switch (sz)
{
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index ca409df346d..d18119193d4 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-47871363d804f54b29ccfd444b082c19716c2301
+313d28b3db7523e67880ae3baf8ef28ce9abe9bd
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/README.md b/gcc/d/dmd/README.md
index f613ab28577..b14310312cd 100644
--- a/gcc/d/dmd/README.md
+++ b/gcc/d/dmd/README.md
@@ -130,6 +130,8 @@ Note that these groups have no strict meaning, the category assignments are a bi
| [impcnvtab.d](https://github.com/dlang/dmd/blob/master/src/dmd/impcnvtab.d) | Define an implicit conversion table for basic types |
| [importc.d](https://github.com/dlang/dmd/blob/master/src/dmd/importc.d) | Helpers specific to ImportC |
| [sideeffect.d](https://github.com/dlang/dmd/blob/master/src/dmd/sideeffect.d) | Extract side-effects of expressions for certain lowerings. |
+| [mustuse.d](https://github.com/dlang/dmd/blob/master/src/dmd/mustuse.d) | Helpers related to the `@mustuse` attribute |
+
**Compile Time Function Execution (CTFE)**
diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION
index 16f49a73f4d..2450fd55ef8 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@
-v2.099.1-beta.1
+v2.100.0-beta.1
diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d
index 8895aa5e2bd..f4b5e8af7ff 100644
--- a/gcc/d/dmd/aggregate.d
+++ b/gcc/d/dmd/aggregate.d
@@ -58,6 +58,28 @@ enum ClassKind : ubyte
}
/**
+ * Give a nice string for a class kind for error messages
+ * Params:
+ * c = class kind
+ * Returns:
+ * 0-terminated string for `c`
+ */
+const(char)* toChars(ClassKind c)
+{
+ final switch (c)
+ {
+ case ClassKind.d:
+ return "D";
+ case ClassKind.cpp:
+ return "C++";
+ case ClassKind.objc:
+ return "Objective-C";
+ case ClassKind.c:
+ return "C";
+ }
+}
+
+/**
* If an aggregate has a pargma(mangle, ...) this holds the information
* to mangle.
*/
diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d
index 52f39d34d0f..16cbe620bc5 100644
--- a/gcc/d/dmd/arrayop.d
+++ b/gcc/d/dmd/arrayop.d
@@ -158,7 +158,7 @@ Expression arrayOp(BinExp e, Scope* sc)
/// ditto
Expression arrayOp(BinAssignExp e, Scope* sc)
{
- //printf("BinAssignExp.arrayOp() %s\n", toChars());
+ //printf("BinAssignExp.arrayOp() %s\n", e.toChars());
/* Check that the elements of e1 can be assigned to
*/
diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d
index 1a2cf8b0641..bf196934aed 100644
--- a/gcc/d/dmd/astenums.d
+++ b/gcc/d/dmd/astenums.d
@@ -28,6 +28,7 @@ enum Baseok : ubyte
enum MODFlags : int
{
+ none = 0, // default (mutable)
const_ = 1, // type is const
immutable_ = 4, // type is immutable
shared_ = 2, // type is shared
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
index 9c2bbd672a7..1e84b55d181 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -44,7 +44,6 @@ import dmd.mtype;
import dmd.objc; // for objc.addSymbols
import dmd.common.outbuffer;
import dmd.root.array; // for each
-import dmd.target; // for target.systemLinkage
import dmd.tokens;
import dmd.visitor;
@@ -399,7 +398,7 @@ extern (C++) final class LinkDeclaration : AttribDeclaration
{
super(loc, null, decl);
//printf("LinkDeclaration(linkage = %d, decl = %p)\n", linkage, decl);
- this.linkage = (linkage == LINK.system) ? target.systemLinkage() : linkage;
+ this.linkage = linkage;
}
static LinkDeclaration create(const ref Loc loc, LINK p, Dsymbols* decl)
@@ -994,7 +993,7 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration
// Decide if 'then' or 'else' code should be included
override Dsymbols* include(Scope* sc)
{
- //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, scope);
+ //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
if (errors)
return null;
@@ -1057,7 +1056,7 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
*/
override Dsymbols* include(Scope* sc)
{
- //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, scope);
+ //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
if (errors || onStack)
return null;
@@ -1496,12 +1495,7 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
if (global.params.cplusplus < CppStdRevision.cpp11)
return;
- // Avoid `if` at the call site
- if (sym.userAttribDecl is null || sym.userAttribDecl.atts is null)
- return;
-
- foreach (exp; *sym.userAttribDecl.atts)
- {
+ foreachUdaNoSemantic(sym, (exp) {
if (isGNUABITag(exp))
{
if (sym.isCPPNamespaceDeclaration() || sym.isNspace())
@@ -1515,9 +1509,10 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
sym.errors = true;
}
// Only one `@gnuAbiTag` is allowed by semantic2
- return;
+ return 1; // break
}
- }
+ return 0; // continue
+ });
}
}
@@ -1544,14 +1539,14 @@ bool isCoreUda(Dsymbol sym, Identifier ident)
/**
* Iterates the UDAs attached to the given symbol.
*
- * If `dg` returns `!= 0`, it will stop the iteration and return that
- * value, otherwise it will return 0.
- *
* Params:
* sym = the symbol to get the UDAs from
* sc = scope to use for semantic analysis of UDAs
- * dg = called once for each UDA. If `dg` returns `!= 0`, it will stop the
- * iteration and return that value, otherwise it will return `0`.
+ * dg = called once for each UDA
+ *
+ * Returns:
+ * If `dg` returns `!= 0`, stops the iteration and returns that value.
+ * Otherwise, returns 0.
*/
int foreachUda(Dsymbol sym, Scope* sc, int delegate(Expression) dg)
{
@@ -1577,3 +1572,32 @@ int foreachUda(Dsymbol sym, Scope* sc, int delegate(Expression) dg)
});
});
}
+
+/**
+ * Iterates the UDAs attached to the given symbol, without performing semantic
+ * analysis.
+ *
+ * Use this function instead of `foreachUda` if semantic analysis of `sym` is
+ * still in progress.
+ *
+ * Params:
+ * sym = the symbol to get the UDAs from
+ * dg = called once for each UDA
+ *
+ * Returns:
+ * If `dg` returns `!= 0`, stops the iteration and returns that value.
+ * Otherwise, returns 0.
+ */
+int foreachUdaNoSemantic(Dsymbol sym, int delegate(Expression) dg)
+{
+ if (sym.userAttribDecl is null || sym.userAttribDecl.atts is null)
+ return 0;
+
+ foreach (exp; *sym.userAttribDecl.atts)
+ {
+ if (auto result = dg(exp))
+ return result;
+ }
+
+ return 0;
+}
diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d
index afd7ac052ad..22c9dde5f7e 100644
--- a/gcc/d/dmd/blockexit.d
+++ b/gcc/d/dmd/blockexit.d
@@ -139,16 +139,21 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
// Allow if last case/default was empty
CaseStatement sc = slast.isCaseStatement();
DefaultStatement sd = slast.isDefaultStatement();
- if (sc && (!sc.statement.hasCode() || sc.statement.isCaseStatement() || sc.statement.isErrorStatement()))
- {
- }
- else if (sd && (!sd.statement.hasCode() || sd.statement.isCaseStatement() || sd.statement.isErrorStatement()))
+ auto sl = (sc ? sc.statement : (sd ? sd.statement : null));
+
+ if (sl && (!sl.hasCode() || sl.isErrorStatement()))
{
}
else if (func.getModule().filetype != FileType.c)
{
const(char)* gototype = s.isCaseStatement() ? "case" : "default";
- s.error("switch case fallthrough - use 'goto %s;' if intended", gototype);
+ // @@@DEPRECATED_2.110@@@ https://issues.dlang.org/show_bug.cgi?id=22999
+ // Deprecated in 2.100
+ // Make an error in 2.110
+ if (sl && sl.isCaseStatement())
+ s.deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype);
+ else
+ s.error("switch case fallthrough - use 'goto %s;' if intended", gototype);
}
}
}
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index 2ed0dc7bdd1..9c8c1c316bf 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -912,8 +912,8 @@ void buildDtors(AggregateDeclaration ad, Scope* sc)
ex = new DotVarExp(loc, ex, v);
// This is a hack so we can call destructors on const/immutable objects.
- // Do it as a type 'paint'.
- ex = new CastExp(loc, ex, v.type.mutableOf());
+ // Do it as a type 'paint', `cast()`
+ ex = new CastExp(loc, ex, MODFlags.none);
if (stc & STC.safe)
stc = (stc & ~STC.safe) | STC.trusted;
@@ -1588,7 +1588,7 @@ private bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor)
auto tf = ctorDecl.type.toTypeFunction();
const dim = tf.parameterList.length;
- if (dim == 1)
+ if (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))
{
auto param = tf.parameterList[0];
if (param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
diff --git a/gcc/d/dmd/common/README.md b/gcc/d/dmd/common/README.md
index a9b65c3dd8d..fb282dcf0a1 100644
--- a/gcc/d/dmd/common/README.md
+++ b/gcc/d/dmd/common/README.md
@@ -2,6 +2,7 @@
| File | Purpose |
|------------------------------------------------------------------------------------|-----------------------------------------------------------------|
+| [bitfields.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/bitfields.d) | Pack multiple boolean fields into bit fields |
| [file.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/file.d) | Functions and objects dedicated to file I/O and management |
| [outbuffer.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/outbuffer.d) | An expandable buffer in which you can write text or binary data |
| [string.d](https://github.com/dlang/dmd/blob/master/src/dmd/common/string.d) | Common string functions including filename manipulation |
diff --git a/gcc/d/dmd/common/bitfields.d b/gcc/d/dmd/common/bitfields.d
new file mode 100644
index 00000000000..d17983d66b4
--- /dev/null
+++ b/gcc/d/dmd/common/bitfields.d
@@ -0,0 +1,70 @@
+/**
+ * A library bitfields utility
+ *
+ * Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
+ * Authors: Dennis Korpel
+ * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/bitfields.d, common/bitfields.d)
+ * Documentation: https://dlang.org/phobos/dmd_common_bitfields.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/bitfields.d
+ */
+module dmd.common.bitfields;
+
+/**
+ * Generate code for bit fields inside a struct/class body
+ * Params:
+ * S = type of a struct with only boolean fields, which should become bit fields
+ * T = type of bit fields variable, must have enough bits to store all booleans
+ * Returns: D code with a bit fields variable and getter / setter functions
+ */
+extern (D) string generateBitFields(S, T)()
+if (__traits(isUnsigned, T))
+{
+ string result = "extern (C++) pure nothrow @nogc @safe final {";
+ enum structName = __traits(identifier, S);
+
+ foreach (size_t i, mem; __traits(allMembers, S))
+ {
+ static assert(is(typeof(__traits(getMember, S, mem)) == bool));
+ static assert(i < T.sizeof * 8, "too many fields for bit field storage of type `"~T.stringof~"`");
+ enum mask = "(1 << "~i.stringof~")";
+ result ~= "
+ /// set or get the corresponding "~structName~" member
+ bool "~mem~"() const { return !!(bitFields & "~mask~"); }
+ /// ditto
+ bool "~mem~"(bool v)
+ {
+ v ? (bitFields |= "~mask~") : (bitFields &= ~"~mask~");
+ return v;
+ }";
+ }
+ return result ~ "}\n private "~T.stringof~" bitFields;\n";
+}
+
+///
+unittest
+{
+ static struct B
+ {
+ bool x;
+ bool y;
+ bool z;
+ }
+
+ static struct S
+ {
+ mixin(generateBitFields!(B, ubyte));
+ }
+
+ S s;
+ assert(!s.x);
+ s.x = true;
+ assert(s.x);
+ s.x = false;
+ assert(!s.x);
+
+ s.y = true;
+ assert(s.y);
+ assert(!s.x);
+ assert(!s.z);
+}
diff --git a/gcc/d/dmd/common/file.d b/gcc/d/dmd/common/file.d
index e4483d5f947..8f34b5319a9 100644
--- a/gcc/d/dmd/common/file.d
+++ b/gcc/d/dmd/common/file.d
@@ -25,6 +25,8 @@ import core.sys.posix.unistd;
import dmd.common.string;
+nothrow:
+
/**
Encapsulated management of a memory-mapped file.
@@ -52,6 +54,8 @@ struct FileMapping(Datum)
private const(char)* name;
// state }
+ nothrow:
+
/**
Open `filename` and map it in memory. If `Datum` is `const`, opens for
read-only and maps the content in memory; no error is issued if the file
diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d
index 0705c1880c0..7e46d294f3d 100644
--- a/gcc/d/dmd/common/outbuffer.d
+++ b/gcc/d/dmd/common/outbuffer.d
@@ -16,6 +16,8 @@ import core.stdc.stdio;
import core.stdc.string;
import core.stdc.stdlib;
+nothrow:
+
// In theory these functions should also restore errno, but we don't care because
// we abort application on error anyway.
extern (C) private pure @system @nogc nothrow
@@ -54,6 +56,8 @@ struct OutBuffer
int level;
// state }
+ nothrow:
+
/**
Construct given size.
*/
diff --git a/gcc/d/dmd/common/string.d b/gcc/d/dmd/common/string.d
index d3bc24f2667..48bf9bb5b55 100644
--- a/gcc/d/dmd/common/string.d
+++ b/gcc/d/dmd/common/string.d
@@ -10,6 +10,8 @@
*/
module dmd.common.string;
+nothrow:
+
/**
Defines a temporary array using a fixed-length buffer as back store. If the length
of the buffer suffices, it is readily used. Otherwise, `malloc` is used to
@@ -26,6 +28,8 @@ struct SmallBuffer(T)
private T[] _extent;
private bool needsFree;
+ nothrow:
+
@disable this(); // no default ctor
@disable this(ref const SmallBuffer!T); // noncopyable, nonassignable
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
index 75ba9ea1e0a..bf66408f1d4 100644
--- a/gcc/d/dmd/constfold.d
+++ b/gcc/d/dmd/constfold.d
@@ -936,7 +936,7 @@ UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expressio
{
if (e1.type.isreal())
{
- cmp = RealIdentical(e1.toReal(), e2.toReal());
+ cmp = CTFloat.isIdentical(e1.toReal(), e2.toReal());
}
else if (e1.type.isimaginary())
{
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index bb12aa7c995..2b2046f3da3 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -213,16 +213,12 @@ final class CParser(AST) : Parser!AST
goto Lexp;
case TOK.leftParenthesis:
- {
- /* If tokens look like a function call, assume it is one,
- * As any type-name won't be resolved until semantic, this
- * could be rewritten later.
- */
- auto tk = &token;
- if (isFunctionCall(tk))
- goto Lexp;
- goto default;
- }
+ if (auto pt = lookupTypedef(token.ident))
+ {
+ if (*pt)
+ goto Ldeclaration;
+ }
+ goto Lexp; // function call
default:
{
@@ -259,6 +255,7 @@ final class CParser(AST) : Parser!AST
case TOK.plusPlus:
case TOK.minusMinus:
case TOK.sizeof_:
+ case TOK._Generic:
Lexp:
auto exp = cparseExpression();
if (token.value == TOK.identifier && exp.op == EXP.identifier)
@@ -1625,10 +1622,21 @@ final class CParser(AST) : Parser!AST
*/
if (token.value == TOK.semicolon)
{
- nextToken();
if (!tspec)
+ {
+ nextToken();
return; // accept empty declaration as an extension
+ }
+ if (auto ti = tspec.isTypeIdentifier())
+ {
+ // C11 6.7.2-2
+ error("type-specifier missing for declaration of `%s`", ti.ident.toChars());
+ nextToken();
+ return;
+ }
+
+ nextToken();
auto tt = tspec.isTypeTag();
if (!tt ||
!tt.id && (tt.tok == TOK.struct_ || tt.tok == TOK.union_))
@@ -1660,6 +1668,22 @@ final class CParser(AST) : Parser!AST
specifier.mod &= ~MOD.xnone; // 'used' it
}
+ void scanPastSemicolon()
+ {
+ while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
+ nextToken();
+ nextToken();
+ }
+
+ if (token.value == TOK.assign && tspec && tspec.isTypeIdentifier())
+ {
+ /* C11 6.7.2-2
+ * Special check for `const b = 1;` because some compilers allow it
+ */
+ error("type-specifier omitted for declaration of `%s`", tspec.isTypeIdentifier().ident.toChars());
+ return scanPastSemicolon();
+ }
+
bool first = true;
while (1)
{
@@ -1879,10 +1903,7 @@ final class CParser(AST) : Parser!AST
default:
error("`=`, `;` or `,` expected to end declaration instead of `%s`", token.toChars());
Lend:
- while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
- nextToken();
- nextToken();
- return;
+ return scanPastSemicolon();
}
}
}
@@ -2399,15 +2420,13 @@ final class CParser(AST) : Parser!AST
if (idx.length > 2 && idx[0] == '_' && idx[1] == '_') // leading double underscore
importBuiltins = true; // probably one of those compiler extensions
t = null;
- if (scw & SCW.xtypedef)
- {
- /* Punch through to what the typedef is, to support things like:
- * typedef T* T;
- */
- auto pt = lookupTypedef(previd);
- if (pt && *pt) // if previd is a known typedef
- t = *pt;
- }
+
+ /* Punch through to what the typedef is, to support things like:
+ * typedef T* T;
+ */
+ auto pt = lookupTypedef(previd);
+ if (pt && *pt) // if previd is a known typedef
+ t = *pt;
if (!t)
t = new AST.TypeIdentifier(loc, previd);
@@ -2529,7 +2548,14 @@ final class CParser(AST) : Parser!AST
default:
if (declarator == DTR.xdirect)
{
- error("identifier or `(` expected"); // )
+ if (!t || t.isTypeIdentifier())
+ {
+ // const arr[1];
+ error("no type-specifier for declarator");
+ t = AST.Type.tint32;
+ }
+ else
+ error("identifier or `(` expected"); // )
panic();
}
ts = t;
@@ -2745,6 +2771,16 @@ final class CParser(AST) : Parser!AST
Specifier specifier;
specifier.packalign.setDefault();
auto tspec = cparseSpecifierQualifierList(LVL.global, specifier);
+ if (!tspec)
+ {
+ error("type-specifier is missing");
+ tspec = AST.Type.tint32;
+ }
+ if (tspec && specifier.mod & MOD.xconst)
+ {
+ tspec = toConst(tspec);
+ specifier.mod = MOD.xnone; // 'used' it
+ }
Identifier id;
return cparseDeclarator(DTR.xabstract, tspec, id, specifier);
}
@@ -2825,8 +2861,18 @@ final class CParser(AST) : Parser!AST
Specifier specifier;
specifier.packalign.setDefault();
auto tspec = cparseDeclarationSpecifiers(LVL.prototype, specifier);
- if (tspec && specifier.mod & MOD.xconst)
+ if (!tspec)
{
+ error("no type-specifier for parameter");
+ tspec = AST.Type.tint32;
+ }
+
+ if (specifier.mod & MOD.xconst)
+ {
+ if ((token.value == TOK.rightParenthesis || token.value == TOK.comma) &&
+ tspec.isTypeIdentifier())
+ error("type-specifier omitted for parameter `%s`", tspec.isTypeIdentifier().ident.toChars());
+
tspec = toConst(tspec);
specifier.mod = MOD.xnone; // 'used' it
}
@@ -3396,7 +3442,12 @@ final class CParser(AST) : Parser!AST
Specifier specifier;
specifier.packalign = this.packalign;
auto tspec = cparseSpecifierQualifierList(LVL.member, specifier);
- if (tspec && specifier.mod & MOD.xconst)
+ if (!tspec)
+ {
+ error("no type-specifier for struct member");
+ tspec = AST.Type.tint32;
+ }
+ if (specifier.mod & MOD.xconst)
{
tspec = toConst(tspec);
specifier.mod = MOD.xnone; // 'used' it
@@ -3409,7 +3460,13 @@ final class CParser(AST) : Parser!AST
nextToken();
auto tt = tspec.isTypeTag();
if (!tt)
+ {
+ if (auto ti = tspec.isTypeIdentifier())
+ {
+ error("type-specifier omitted before declaration of `%s`", ti.ident.toChars());
+ }
return; // legal but meaningless empty declaration
+ }
/* If anonymous struct declaration
* struct { ... members ... };
@@ -3449,6 +3506,12 @@ final class CParser(AST) : Parser!AST
AST.Type dt;
if (token.value == TOK.colon)
{
+ if (auto ti = tspec.isTypeIdentifier())
+ {
+ error("type-specifier omitted before bit field declaration of `%s`", ti.ident.toChars());
+ tspec = AST.Type.tint32;
+ }
+
// C11 6.7.2.1-12 unnamed bit-field
id = Identifier.generateAnonymousId("BitField");
dt = tspec;
diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d
index 32aed16e796..11229d4bd4f 100644
--- a/gcc/d/dmd/ctfeexpr.d
+++ b/gcc/d/dmd/ctfeexpr.d
@@ -1269,7 +1269,7 @@ private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
real_t r1 = e1.type.isreal() ? e1.toReal() : e1.toImaginary();
real_t r2 = e1.type.isreal() ? e2.toReal() : e2.toImaginary();
if (identity)
- return !RealIdentical(r1, r2);
+ return !CTFloat.isIdentical(r1, r2);
if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
{
return 1; // they are not equal
@@ -1399,7 +1399,7 @@ bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2)
cmp = (es1.var == es2.var && es1.offset == es2.offset);
}
else if (e1.type.isreal())
- cmp = RealIdentical(e1.toReal(), e2.toReal());
+ cmp = CTFloat.isIdentical(e1.toReal(), e2.toReal());
else if (e1.type.isimaginary())
cmp = RealIdentical(e1.toImaginary(), e2.toImaginary());
else if (e1.type.iscomplex())
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index 685987b734d..83978391e42 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -432,7 +432,7 @@ MATCH implicitConvTo(Expression e, Type t)
return MATCH.nomatch;
goto case Tuns8;
case Tuns8:
- //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value);
+ //printf("value = %llu %llu\n", cast(dinteger_t)cast(ubyte)value, value);
if (cast(ubyte)value != value)
return MATCH.nomatch;
break;
@@ -492,8 +492,8 @@ MATCH implicitConvTo(Expression e, Type t)
break;
case Tpointer:
- //printf("type = %s\n", type.toBasetype()->toChars());
- //printf("t = %s\n", t.toBasetype()->toChars());
+ //printf("type = %s\n", type.toBasetype().toChars());
+ //printf("t = %s\n", t.toBasetype().toChars());
if (ty == Tpointer && e.type.toBasetype().nextOf().ty == t.toBasetype().nextOf().ty)
{
/* Allow things like:
@@ -1107,6 +1107,10 @@ MATCH implicitConvTo(Expression e, Type t)
MATCH visitCond(CondExp e)
{
+ auto result = visit(e);
+ if (result != MATCH.nomatch)
+ return result;
+
MATCH m1 = e.e1.implicitConvTo(t);
MATCH m2 = e.e2.implicitConvTo(t);
//printf("CondExp: m1 %d m2 %d\n", m1, m2);
@@ -2077,7 +2081,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
if (auto tsa = tb.isTypeSArray())
{
size_t dim2 = cast(size_t)tsa.dim.toInteger();
- //printf("dim from = %d, to = %d\n", (int)se.len, (int)dim2);
+ //printf("dim from = %d, to = %d\n", cast(int)se.len, cast(int)dim2);
// Changing dimensions
if (dim2 != se.len)
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index c0e40a5263a..a533d30ca80 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -379,7 +379,7 @@ extern (C++) abstract class Declaration : Dsymbol
if (e1 && e1.op == EXP.this_ && isField())
{
- VarDeclaration vthis = (cast(ThisExp)e1).var;
+ VarDeclaration vthis = e1.isThisExp().var;
for (Scope* scx = sc; scx; scx = scx.enclosing)
{
if (scx.func == vthis.parent && (scx.flags & SCOPE.contract))
@@ -656,9 +656,8 @@ extern (C++) final class TupleDeclaration : Declaration
if (o.dyncast() == DYNCAST.expression)
{
Expression e = cast(Expression)o;
- if (e.op == EXP.dSymbol)
+ if (DsymbolExp ve = e.isDsymbolExp())
{
- DsymbolExp ve = cast(DsymbolExp)e;
Declaration d = ve.s.isDeclaration();
if (d && d.needThis())
{
@@ -1083,29 +1082,12 @@ extern (C++) class VarDeclaration : Declaration
bool isArgDtorVar; /// temporary created to handle scope destruction of a function argument
}
- private ushort bitFields; // stores multiple booleans for BitFields
+ import dmd.common.bitfields : generateBitFields;
+ mixin(generateBitFields!(BitFields, ushort));
+
byte canassign; // it can be assigned to
ubyte isdataseg; // private data for isDataseg 0 unset, 1 true, 2 false
- // Generate getter and setter functions for `bitFields`
- extern (D) mixin(() {
- string result = "extern (C++) pure nothrow @nogc @safe final {";
- foreach (size_t i, mem; __traits(allMembers, BitFields))
- {
- result ~= "
- /// set or get the corresponding BitFields member
- bool "~mem~"() const { return !!(bitFields & (1 << "~i.stringof~")); }
- /// ditto
- bool "~mem~"(bool v)
- {
- v ? (bitFields |= (1 << "~i.stringof~")) : (bitFields &= ~(1 << "~i.stringof~"));
- return v;
- }";
- }
- return result ~ "}";
- }());
-
-
final extern (D) this(const ref Loc loc, Type type, Identifier ident, Initializer _init, StorageClass storage_class = STC.undefined_)
in
{
@@ -1160,7 +1142,7 @@ extern (C++) class VarDeclaration : Declaration
assert(o.dyncast() == DYNCAST.expression);
Expression e = cast(Expression)o;
assert(e.op == EXP.dSymbol);
- DsymbolExp se = cast(DsymbolExp)e;
+ DsymbolExp se = e.isDsymbolExp();
se.s.setFieldOffset(ad, fieldState, isunion);
}
return;
@@ -1458,16 +1440,17 @@ extern (C++) class VarDeclaration : Declaration
const sdsz = sd.type.size();
assert(sdsz != SIZE_INVALID && sdsz != 0);
const n = sz / sdsz;
- e = new SliceExp(loc, e, new IntegerExp(loc, 0, Type.tsize_t), new IntegerExp(loc, n, Type.tsize_t));
+ SliceExp se = new SliceExp(loc, e, new IntegerExp(loc, 0, Type.tsize_t),
+ new IntegerExp(loc, n, Type.tsize_t));
// Prevent redundant bounds check
- (cast(SliceExp)e).upperIsInBounds = true;
- (cast(SliceExp)e).lowerIsLessThanUpper = true;
+ se.upperIsInBounds = true;
+ se.lowerIsLessThanUpper = true;
// This is a hack so we can call destructors on const/immutable objects.
- e.type = sd.type.arrayOf();
+ se.type = sd.type.arrayOf();
- e = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), e);
+ e = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se);
}
return e;
}
diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d
index c3662a734d8..1f895e03af0 100644
--- a/gcc/d/dmd/dmangle.d
+++ b/gcc/d/dmd/dmangle.d
@@ -340,7 +340,6 @@ public:
final switch (t.linkage)
{
case LINK.default_:
- case LINK.system:
case LINK.d:
mc = 'F';
break;
@@ -356,6 +355,8 @@ public:
case LINK.objc:
mc = 'Y';
break;
+ case LINK.system:
+ assert(0);
}
buf.writeByte(mc);
@@ -1340,7 +1341,9 @@ extern (D) const(char)[] externallyMangledIdentifier(Declaration d)
{
if (d.linkage != LINK.d && d.localNum)
d.error("the same declaration cannot be in multiple scopes with non-D linkage");
- final switch (d.linkage)
+
+ const l = d.linkage == LINK.system ? target.systemLinkage() : d.linkage;
+ final switch (l)
{
case LINK.d:
break;
@@ -1354,9 +1357,10 @@ extern (D) const(char)[] externallyMangledIdentifier(Declaration d)
return p.toDString();
}
case LINK.default_:
- case LINK.system:
d.error("forward declaration");
return d.ident.toString();
+ case LINK.system:
+ assert(0);
}
}
return null;
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index c7e6418bf46..2d9f6510ba5 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -69,7 +69,7 @@ void semantic3OnDependencies(Module m)
/**
* Remove generated .di files on error and exit
*/
-void removeHdrFilesAndFail(ref Param params, ref Modules modules)
+void removeHdrFilesAndFail(ref Param params, ref Modules modules) nothrow
{
if (params.doHdrGeneration)
{
@@ -94,7 +94,7 @@ void removeHdrFilesAndFail(ref Param params, ref Modules modules)
* Returns:
* the filename of the child package or module
*/
-private const(char)[] getFilename(Identifier[] packages, Identifier ident)
+private const(char)[] getFilename(Identifier[] packages, Identifier ident) nothrow
{
const(char)[] filename = ident.toString();
@@ -157,14 +157,14 @@ extern (C++) class Package : ScopeDsymbol
uint tag; // auto incremented tag, used to mask package tree in scopes
Module mod; // !=null if isPkgMod == PKG.module_
- final extern (D) this(const ref Loc loc, Identifier ident)
+ final extern (D) this(const ref Loc loc, Identifier ident) nothrow
{
super(loc, ident);
__gshared uint packageTag;
this.tag = packageTag++;
}
- override const(char)* kind() const
+ override const(char)* kind() const nothrow
{
return "package";
}
@@ -664,7 +664,7 @@ extern (C++) final class Module : Package
//printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars());
if (auto result = global.fileManager.lookup(srcfile))
{
- this.src = result.data;
+ this.src = result;
if (global.params.emitMakeDeps)
global.params.makeDeps.push(srcfile.toChars());
return true;
@@ -1133,8 +1133,10 @@ extern (C++) final class Module : Package
// If it isn't there, some compiler rewrites, like
// classinst == classinst -> .object.opEquals(classinst, classinst)
// would fail inside object.d.
- if (members.dim == 0 || (*members)[0].ident != Id.object ||
- (*members)[0].isImport() is null)
+ if (filetype != FileType.c &&
+ (members.dim == 0 ||
+ (*members)[0].ident != Id.object ||
+ (*members)[0].isImport() is null))
{
auto im = new Import(Loc.initial, null, Id.object, null, 0);
members.shift(im);
@@ -1380,7 +1382,7 @@ extern (C++) final class Module : Package
a.setDim(0);
}
- extern (D) static void clearCache()
+ extern (D) static void clearCache() nothrow
{
foreach (Module m; amodules)
m.searchCacheIdent = null;
@@ -1391,7 +1393,7 @@ extern (C++) final class Module : Package
* return true if it imports m.
* Can be used to detect circular imports.
*/
- int imports(Module m)
+ int imports(Module m) nothrow
{
//printf("%s Module::imports(%s)\n", toChars(), m.toChars());
version (none)
@@ -1414,14 +1416,14 @@ extern (C++) final class Module : Package
return false;
}
- bool isRoot()
+ bool isRoot() nothrow
{
return this.importedFrom == this;
}
// true if the module source file is directly
// listed in command line.
- bool isCoreModule(Identifier ident)
+ bool isCoreModule(Identifier ident) nothrow
{
return this.ident == ident && parent && parent.ident == Id.core && !parent.parent;
}
@@ -1440,7 +1442,7 @@ extern (C++) final class Module : Package
uint[uint] ctfe_cov; /// coverage information from ctfe execution_count[line]
- override inout(Module) isModule() inout
+ override inout(Module) isModule() inout nothrow
{
return this;
}
@@ -1455,7 +1457,7 @@ extern (C++) final class Module : Package
* Params:
* buf = The buffer to write to
*/
- void fullyQualifiedName(ref OutBuffer buf)
+ void fullyQualifiedName(ref OutBuffer buf) nothrow
{
buf.writestring(ident.toString());
@@ -1469,7 +1471,7 @@ extern (C++) final class Module : Package
/** Lazily initializes and returns the escape table.
Turns out it eats a lot of memory.
*/
- extern(D) Escape* escapetable()
+ extern(D) Escape* escapetable() nothrow
{
if (!_escapetable)
_escapetable = new Escape();
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index c3a1d05cd7b..6339a9e36ba 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -457,6 +457,8 @@ struct Scope
if (sc.scopesym.isModule())
flags |= SearchUnqualifiedModule; // tell Module.search() that SearchLocalsOnly is to be obeyed
+ else if (sc.flags & SCOPE.Cfile && sc.scopesym.isStructDeclaration())
+ continue; // C doesn't have struct scope
if (Dsymbol s = sc.scopesym.search(loc, ident, flags))
{
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index cb6c278fc44..74eaa1d8d7a 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -112,12 +112,12 @@ struct Ungag
{
uint oldgag;
- extern (D) this(uint old)
+ extern (D) this(uint old) nothrow
{
this.oldgag = old;
}
- extern (C++) ~this()
+ extern (C++) ~this() nothrow
{
global.gag = oldgag;
}
@@ -255,27 +255,27 @@ extern (C++) class Dsymbol : ASTNode
DeprecatedDeclaration depdecl; // customized deprecation message
UserAttributeDeclaration userAttribDecl; // user defined attributes
- final extern (D) this()
+ final extern (D) this() nothrow
{
//printf("Dsymbol::Dsymbol(%p)\n", this);
loc = Loc(null, 0, 0);
}
- final extern (D) this(Identifier ident)
+ final extern (D) this(Identifier ident) nothrow
{
//printf("Dsymbol::Dsymbol(%p, ident)\n", this);
this.loc = Loc(null, 0, 0);
this.ident = ident;
}
- final extern (D) this(const ref Loc loc, Identifier ident)
+ final extern (D) this(const ref Loc loc, Identifier ident) nothrow
{
//printf("Dsymbol::Dsymbol(%p, ident)\n", this);
this.loc = loc;
this.ident = ident;
}
- static Dsymbol create(Identifier ident)
+ static Dsymbol create(Identifier ident) nothrow
{
return new Dsymbol(ident);
}
@@ -800,6 +800,22 @@ extern (C++) class Dsymbol : ASTNode
if (isAliasDeclaration() && !_scope)
setScope(sc);
Dsymbol s2 = sds.symtabLookup(this,ident);
+ /* https://issues.dlang.org/show_bug.cgi?id=17434
+ *
+ * If we are trying to add an import to the symbol table
+ * that has already been introduced, then keep the one with
+ * larger visibility. This is fine for imports because if
+ * we have multiple imports of the same file, if a single one
+ * is public then the symbol is reachable.
+ */
+ if (auto i1 = isImport())
+ {
+ if (auto i2 = s2.isImport())
+ {
+ if (sc.explicitVisibility && sc.visibility > i2.visibility)
+ sds.symtab.update(this);
+ }
+ }
// If using C tag/prototype/forward declaration rules
if (sc.flags & SCOPE.Cfile && !this.isImport())
@@ -822,7 +838,8 @@ extern (C++) class Dsymbol : ASTNode
}
if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
{
- if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
+ if (ident == Id.__sizeof ||
+ !(sc && sc.flags & SCOPE.Cfile) && (ident == Id.__xalignof || ident == Id._mangleof))
{
error("`.%s` property cannot be redefined", ident.toChars());
errors = true;
@@ -933,14 +950,7 @@ extern (C++) class Dsymbol : ASTNode
TemplateInstance ti = st.isTemplateInstance();
sm = s.search(loc, ti.name);
if (!sm)
- {
- sm = s.search_correct(ti.name);
- if (sm)
- .error(loc, "template identifier `%s` is not a member of %s `%s`, did you mean %s `%s`?", ti.name.toChars(), s.kind(), s.toPrettyChars(), sm.kind(), sm.toChars());
- else
- .error(loc, "template identifier `%s` is not a member of %s `%s`", ti.name.toChars(), s.kind(), s.toPrettyChars());
return null;
- }
sm = sm.toAlias();
TemplateDeclaration td = sm.isTemplateDeclaration();
if (!td)
@@ -1381,16 +1391,16 @@ private:
BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages
public:
- final extern (D) this()
+ final extern (D) this() nothrow
{
}
- final extern (D) this(Identifier ident)
+ final extern (D) this(Identifier ident) nothrow
{
super(ident);
}
- final extern (D) this(const ref Loc loc, Identifier ident)
+ final extern (D) this(const ref Loc loc, Identifier ident) nothrow
{
super(loc, ident);
}
@@ -1604,7 +1614,7 @@ public:
return os;
}
- void importScope(Dsymbol s, Visibility visibility)
+ void importScope(Dsymbol s, Visibility visibility) nothrow
{
//printf("%s.ScopeDsymbol::importScope(%s, %d)\n", toChars(), s.toChars(), visibility);
// No circular or redundant import's
@@ -1631,7 +1641,7 @@ public:
}
}
- extern (D) final void addAccessiblePackage(Package p, Visibility visibility)
+ extern (D) final void addAccessiblePackage(Package p, Visibility visibility) nothrow
{
auto pary = visibility.kind == Visibility.Kind.private_ ? &privateAccessiblePackages : &accessiblePackages;
if (pary.length <= p.tag)
@@ -1639,7 +1649,7 @@ public:
(*pary)[p.tag] = true;
}
- bool isPackageAccessible(Package p, Visibility visibility, int flags = 0)
+ bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) nothrow
{
if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] ||
visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag])
@@ -1654,7 +1664,7 @@ public:
return false;
}
- override final bool isforwardRef()
+ override final bool isforwardRef() nothrow
{
return (members is null);
}
@@ -1742,7 +1752,7 @@ public:
* Returns:
* null if already in table, `s` if inserted
*/
- Dsymbol symtabInsert(Dsymbol s)
+ Dsymbol symtabInsert(Dsymbol s) nothrow
{
return symtab.insert(s);
}
@@ -1755,7 +1765,7 @@ public:
* Returns:
* Dsymbol if found, null if not
*/
- Dsymbol symtabLookup(Dsymbol s, Identifier id)
+ Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow
{
return symtab.lookup(id);
}
@@ -1838,7 +1848,7 @@ extern (C++) final class WithScopeSymbol : ScopeDsymbol
{
WithStatement withstate;
- extern (D) this(WithStatement withstate)
+ extern (D) this(WithStatement withstate) nothrow
{
this.withstate = withstate;
}
@@ -1898,7 +1908,7 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
private RootObject arrayContent;
Scope* sc;
- extern (D) this(Scope* sc, Expression exp)
+ extern (D) this(Scope* sc, Expression exp) nothrow
{
super(exp.loc, null);
assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array);
@@ -1906,13 +1916,13 @@ extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
this.arrayContent = exp;
}
- extern (D) this(Scope* sc, TypeTuple type)
+ extern (D) this(Scope* sc, TypeTuple type) nothrow
{
this.sc = sc;
this.arrayContent = type;
}
- extern (D) this(Scope* sc, TupleDeclaration td)
+ extern (D) this(Scope* sc, TupleDeclaration td) nothrow
{
this.sc = sc;
this.arrayContent = td;
@@ -2109,7 +2119,7 @@ extern (C++) final class OverloadSet : Dsymbol
{
Dsymbols a; // array of Dsymbols
- extern (D) this(Identifier ident, OverloadSet os = null)
+ extern (D) this(Identifier ident, OverloadSet os = null) nothrow
{
super(ident);
if (os)
@@ -2118,7 +2128,7 @@ extern (C++) final class OverloadSet : Dsymbol
}
}
- void push(Dsymbol s)
+ void push(Dsymbol s) nothrow
{
a.push(s);
}
@@ -2152,12 +2162,13 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
* Can be `null` before being lazily initialized.
*/
ScopeDsymbol forward;
- extern (D) this(ScopeDsymbol forward)
+ extern (D) this(ScopeDsymbol forward) nothrow
{
super(null);
this.forward = forward;
}
- override Dsymbol symtabInsert(Dsymbol s)
+
+ override Dsymbol symtabInsert(Dsymbol s) nothrow
{
assert(forward);
if (auto d = s.isDeclaration())
@@ -2188,7 +2199,7 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
* and
* static foreach (i; [0]) { enum i = 2; }
*/
- override Dsymbol symtabLookup(Dsymbol s, Identifier id)
+ override Dsymbol symtabLookup(Dsymbol s, Identifier id) nothrow
{
assert(forward);
// correctly diagnose clashing foreach loop variables.
@@ -2219,7 +2230,7 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
override const(char)* kind()const{ return "local scope"; }
- override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout
+ override inout(ForwardingScopeDsymbol) isForwardingScopeDsymbol() inout nothrow
{
return this;
}
@@ -2234,13 +2245,13 @@ extern (C++) final class ForwardingScopeDsymbol : ScopeDsymbol
extern (C++) final class ExpressionDsymbol : Dsymbol
{
Expression exp;
- this(Expression exp)
+ this(Expression exp) nothrow
{
super();
this.exp = exp;
}
- override inout(ExpressionDsymbol) isExpressionDsymbol() inout
+ override inout(ExpressionDsymbol) isExpressionDsymbol() inout nothrow
{
return this;
}
@@ -2259,7 +2270,7 @@ extern (C++) final class AliasAssign : Dsymbol
Dsymbol aliassym; /// replace previous RHS of AliasDeclaration with `aliassym`
/// only one of type and aliassym can be != null
- extern (D) this(const ref Loc loc, Identifier ident, Type type, Dsymbol aliassym)
+ extern (D) this(const ref Loc loc, Identifier ident, Type type, Dsymbol aliassym) nothrow
{
super(loc, null);
this.ident = ident;
@@ -2299,6 +2310,8 @@ extern (C++) final class DsymbolTable : RootObject
{
AssocArray!(Identifier, Dsymbol) tab;
+ nothrow:
+
/***************************
* Look up Identifier in symbol table
* Params:
@@ -2511,6 +2524,7 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
if (i1) // vd is the definition
{
+ vd2.storage_class |= STC.extern_; // so toObjFile() won't emit it
sds.symtab.update(vd); // replace vd2 with the definition
return vd;
}
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index c9906363cc8..5415401e0e4 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -51,6 +51,7 @@ import dmd.init;
import dmd.initsem;
import dmd.hdrgen;
import dmd.mtype;
+import dmd.mustuse;
import dmd.nogc;
import dmd.nspace;
import dmd.objc;
@@ -542,7 +543,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
Parameter arg = Parameter.getNth(tt.arguments, pos);
arg.type = arg.type.typeSemantic(dsym.loc, sc);
//printf("[%d] iexps.dim = %d, ", pos, iexps.dim);
- //printf("e = (%s %s, %s), ", Token::tochars[e.op], e.toChars(), e.type.toChars());
+ //printf("e = (%s %s, %s), ", Token.tochars[e.op], e.toChars(), e.type.toChars());
//printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
if (e != ie)
@@ -581,7 +582,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
arg = Parameter.getNth(tt.arguments, pos + u);
arg.type = arg.type.typeSemantic(dsym.loc, sc);
//printf("[%d+%d] exps.dim = %d, ", pos, u, exps.dim);
- //printf("ee = (%s %s, %s), ", Token::tochars[ee.op], ee.toChars(), ee.type.toChars());
+ //printf("ee = (%s %s, %s), ", Token.tochars[ee.op], ee.toChars(), ee.type.toChars());
//printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
size_t iexps_dim = iexps.dim - 1 + exps.dim;
@@ -2046,6 +2047,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
ed.semanticRun = PASS.semantic;
UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage);
+ checkMustUseReserved(ed);
if (!ed.members && !ed.memtype) // enum ident;
{
@@ -2872,7 +2874,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
sc = sc.endCTFE();
resolved = resolved.ctfeInterpret();
StringExp name = resolved.toStringExp();
- TupleExp tup = name ? null : resolved.toTupleExp();
+ TupleExp tup = name ? null : resolved.isTupleExp();
if (!tup && !name)
{
error(ns.loc, "expected string expression for namespace name, got `%s`", ns.identExp.toChars());
@@ -3017,7 +3019,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
if ((funcdecl.storage_class & STC.TYPECTOR) && !(ad || funcdecl.isNested()))
funcdecl.storage_class &= ~STC.TYPECTOR;
- //printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration::isFinal());
+ //printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration.isFinal());
if (sc.flags & SCOPE.compile)
funcdecl.flags |= FUNCFLAG.compileTimeOnly; // don't emit code for this function
@@ -3056,6 +3058,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
funcdecl.visibility = sc.visibility;
funcdecl.userAttribDecl = sc.userAttribDecl;
UserAttributeDeclaration.checkGNUABITag(funcdecl, funcdecl.linkage);
+ checkMustUseReserved(funcdecl);
if (!funcdecl.originalType)
funcdecl.originalType = funcdecl.type.syntaxCopy();
@@ -4092,7 +4095,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
override void visit(PostBlitDeclaration pbd)
{
//printf("PostBlitDeclaration::semantic() %s\n", toChars());
- //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id::dtor.toChars(), ident, Id::dtor);
+ //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id.dtor.toChars(), ident, Id.dtor);
//printf("stc = x%llx\n", sc.stc);
if (pbd.semanticRun >= PASS.semanticdone)
return;
@@ -4129,7 +4132,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
override void visit(DtorDeclaration dd)
{
//printf("DtorDeclaration::semantic() %s\n", toChars());
- //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id::dtor.toChars(), ident, Id::dtor);
+ //printf("ident: %s, %s, %p, %p\n", ident.toChars(), Id.dtor.toChars(), ident, Id.dtor);
if (dd.semanticRun >= PASS.semanticdone)
return;
if (dd._scope)
@@ -4618,7 +4621,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
buildOpAssign(sd, sc2);
buildOpEquals(sd, sc2);
- if (global.params.useTypeInfo && Type.dtypeinfo) // these functions are used for TypeInfo
+ if (!(sc2.flags & SCOPE.Cfile) &&
+ global.params.useTypeInfo && Type.dtypeinfo) // these functions are used for TypeInfo
{
sd.xeq = buildXopEquals(sd, sc2);
sd.xcmp = buildXopCmp(sd, sc2);
@@ -4770,6 +4774,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
}
cldec.semanticRun = PASS.semantic;
UserAttributeDeclaration.checkGNUABITag(cldec, sc.linkage);
+ checkMustUseReserved(cldec);
if (cldec.baseok < Baseok.done)
{
@@ -5019,6 +5024,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
cldec.com = true;
if (cldec.baseClass.isCPPclass())
cldec.classKind = ClassKind.cpp;
+ if (cldec.classKind != cldec.baseClass.classKind)
+ cldec.error("with %s linkage cannot inherit from class `%s` with %s linkage",
+ cldec.classKind.toChars(), cldec.baseClass.toChars(), cldec.baseClass.classKind.toChars());
+
if (cldec.baseClass.stack)
cldec.stack = true;
cldec.enclosing = cldec.baseClass.enclosing;
@@ -5475,6 +5484,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
idec.classKind = ClassKind.cpp;
idec.cppnamespace = sc.namespace;
UserAttributeDeclaration.checkGNUABITag(idec, sc.linkage);
+ checkMustUseReserved(idec);
if (sc.linkage == LINK.objc)
objc.setObjc(idec);
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index a5ec63ca763..fb41e2bd05f 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -2626,7 +2626,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
printf("\t%s %s\n", arg.type.toChars(), arg.toChars());
//printf("\tty = %d\n", arg.type.ty);
}
- //printf("stc = %llx\n", dstart.scope.stc);
+ //printf("stc = %llx\n", dstart._scope.stc);
//printf("match:t/f = %d/%d\n", ta_last, m.last);
}
@@ -4332,7 +4332,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
{
TypeStruct tp = cast(TypeStruct)tparam;
- //printf("\t%d\n", (MATCH) t.implicitConvTo(tp));
+ //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
if (wm && t.deduceWild(tparam, false))
{
result = MATCH.constant;
@@ -4513,7 +4513,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
{
TypeClass tp = cast(TypeClass)tparam;
- //printf("\t%d\n", (MATCH) t.implicitConvTo(tp));
+ //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
if (wm && t.deduceWild(tparam, false))
{
result = MATCH.constant;
diff --git a/gcc/d/dmd/errors.d b/gcc/d/dmd/errors.d
index 114bd44e32c..62e86a1163c 100644
--- a/gcc/d/dmd/errors.d
+++ b/gcc/d/dmd/errors.d
@@ -434,8 +434,20 @@ else
pragma(printf) extern (C++) void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap);
/**
- * Call this after printing out fatal error messages to clean up and exit
- * the compiler.
+ * The type of the fatal error handler
+ * Returns: true if error handling is done, false to do exit(EXIT_FAILURE)
+ */
+alias FatalErrorHandler = bool delegate();
+
+/**
+ * The fatal error handler.
+ * If non-null it will be called for every fatal() call issued by the compiler.
+ */
+__gshared FatalErrorHandler fatalErrorHandler;
+
+/**
+ * Call this after printing out fatal error messages to clean up and exit the
+ * compiler. You can also set a fatalErrorHandler to override this behaviour.
*/
extern (C++) void fatal();
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index 4196c05489d..44c3757248b 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -316,24 +316,27 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp
*/
void unsafeAssign(VarDeclaration v, const char* desc)
{
- if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe())
+ if (setUnsafeDIP1000(sc.func))
{
if (!gag)
{
if (assertmsg)
{
- error(arg.loc, "%s `%s` assigned to non-scope parameter calling `assert()`",
+ previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+ (arg.loc, "%s `%s` assigned to non-scope parameter calling `assert()`",
desc, v.toChars());
}
else
{
- error(arg.loc, "%s `%s` assigned to non-scope parameter `%s` calling %s",
+ previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+ (arg.loc, "%s `%s` assigned to non-scope parameter `%s` calling %s",
desc, v.toChars(),
par ? par.toChars() : "this",
fdc ? fdc.toPrettyChars() : "indirectly");
}
}
- result = true;
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ result = true;
}
}
@@ -440,22 +443,33 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp
* sc = used to determine current function and module
* firstArg = `ref` argument through which `arg` may be assigned
* arg = initializer for parameter
+ * param = parameter declaration corresponding to `arg`
* gag = do not print error messages
* Returns:
* `true` if assignment to `firstArg` would cause an error
*/
-bool checkParamArgumentReturn(Scope* sc, Expression firstArg, Expression arg, bool gag)
+bool checkParamArgumentReturn(Scope* sc, Expression firstArg, Expression arg, Parameter param, bool gag)
{
enum log = false;
if (log) printf("checkParamArgumentReturn(firstArg: %s arg: %s)\n",
firstArg.toChars(), arg.toChars());
//printf("type = %s, %d\n", arg.type.toChars(), arg.type.hasPointers());
- if (!arg.type.hasPointers())
+ if (!(param.storageClass & STC.return_))
return false;
+ if (!arg.type.hasPointers() && !param.isReference())
+ return false;
+
+ // `byRef` needed for `assign(ref int* x, ref int i) {x = &i};`
+ // Note: taking address of scope pointer is not allowed
+ // `assign(ref int** x, return ref scope int* i) {x = &i};`
+ // Thus no return ref/return scope ambiguity here
+ const byRef = param.isReference() && !(param.storageClass & STC.scope_)
+ && !(param.storageClass & STC.returnScope); // fixme: it's possible to infer returnScope without scope with vaIsFirstRef
+
scope e = new AssignExp(arg.loc, firstArg, arg);
- return checkAssignEscape(sc, e, gag);
+ return checkAssignEscape(sc, e, gag, byRef);
}
/*****************************************************
@@ -496,23 +510,13 @@ bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag)
foreach (const i; 0 .. n)
{
Expression arg = (*ce.arguments)[i];
- if (!arg.type.hasPointers())
- continue;
-
//printf("\targ[%d]: %s\n", i, arg.toChars());
if (i - j < nparams && i >= j)
{
Parameter p = tf.parameterList[i - j];
-
- if (p.storageClass & STC.return_)
- {
- /* Fake `dve.e1 = arg;` and look for scope violations
- */
- scope e = new AssignExp(arg.loc, dve.e1, arg);
- if (checkAssignEscape(sc, e, gag))
- return true;
- }
+ if (checkParamArgumentReturn(sc, dve.e1, arg, p, gag))
+ return true;
}
}
@@ -529,13 +533,14 @@ bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag)
* sc = used to determine current function and module
* e = `AssignExp` or `CatAssignExp` to check for any pointers to the stack
* gag = do not print error messages
+ * byRef = set to `true` if `e1` of `e` gets assigned a reference to `e2`
* Returns:
* `true` if pointers to the stack can escape via assignment
*/
-bool checkAssignEscape(Scope* sc, Expression e, bool gag)
+bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
{
enum log = false;
- if (log) printf("checkAssignEscape(e: %s)\n", e.toChars());
+ if (log) printf("checkAssignEscape(e: %s, byRef: %d)\n", e.toChars(), byRef);
if (e.op != EXP.assign && e.op != EXP.blit && e.op != EXP.construct &&
e.op != EXP.concatenateAssign && e.op != EXP.concatenateElemAssign && e.op != EXP.concatenateDcharAssign)
return false;
@@ -561,7 +566,10 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
EscapeByResults er;
- escapeByValue(e2, &er);
+ if (byRef)
+ escapeByRef(e2, &er);
+ else
+ escapeByValue(e2, &er);
if (!er.byref.dim && !er.byvalue.dim && !er.byfunc.dim && !er.byexp.dim)
return false;
@@ -769,7 +777,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
if (v.isDataseg())
continue;
- if (global.params.useDIP1000 == FeatureState.enabled)
+ if (global.params.useDIP1000 != FeatureState.disabled)
{
if (va && va.isScope() && !v.isReference())
{
@@ -777,20 +785,36 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
{
va.doNotInferReturn = true;
}
- else if (fd.setUnsafe())
+ else if (setUnsafeDIP1000(fd))
{
if (!gag)
- error(ae.loc, "address of local variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars());
- result = true;
- continue;
+ previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+ (ae.loc, "address of local variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars());
+
+
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ {
+ result = true;
+ continue;
+ }
}
}
}
Dsymbol p = v.toParent2();
+ if (vaIsFirstRef && v.isParameter() &&
+ !(v.storage_class & STC.return_) &&
+ fd.flags & FUNCFLAG.returnInprocess &&
+ p == fd)
+ {
+ //if (log) printf("inferring 'return' for parameter %s in function %s\n", v.toChars(), fd.toChars());
+ inferReturn(fd, v, /*returnScope:*/ false);
+ }
+
// If va's lifetime encloses v's, then error
if (va &&
+ !(vaIsFirstRef && (v.storage_class & STC.return_)) &&
(va.enclosesLifetimeOf(v) || (va.isReference() && !(va.storage_class & STC.temp)) || va.isDataseg()) &&
fd.setUnsafe())
{
@@ -961,12 +985,11 @@ bool checkThrowEscape(Scope* sc, Expression e, bool gag)
if (v.isScope() && !v.iscatchvar) // special case: allow catch var to be rethrown
// despite being `scope`
{
+ if (!gag)
+ previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+ (e.loc, "scope variable `%s` may not be thrown", v.toChars());
if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029
- {
- if (!gag)
- error(e.loc, "scope variable `%s` may not be thrown", v.toChars());
result = true;
- }
continue;
}
else
@@ -1027,13 +1050,16 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
*/
!(p.parent == sc.func))
{
- if (global.params.useDIP1000 == FeatureState.enabled // https://issues.dlang.org/show_bug.cgi?id=17029
- && sc.func.setUnsafe()) // https://issues.dlang.org/show_bug.cgi?id=20868
+ if (setUnsafeDIP1000(sc.func)) // https://issues.dlang.org/show_bug.cgi?id=20868
{
+ // Only look for errors if in module listed on command line
if (!gag)
- error(e.loc, "scope variable `%s` may not be copied into allocated memory", v.toChars());
- result = true;
+ previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+ (e.loc, "scope variable `%s` may not be copied into allocated memory", v.toChars());
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ result = true;
}
+
continue;
}
}
@@ -1243,11 +1269,13 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
)
{
// https://issues.dlang.org/show_bug.cgi?id=17029
- if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe())
+ if (setUnsafeDIP1000(sc.func))
{
if (!gag)
- error(e.loc, "scope variable `%s` may not be returned", v.toChars());
- result = true;
+ previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+ (e.loc, "scope variable `%s` may not be returned", v.toChars());
+ if (global.params.useDIP1000 == FeatureState.enabled)
+ result = true;
}
continue;
}
@@ -2326,3 +2354,11 @@ private void addMaybe(VarDeclaration va, VarDeclaration v)
va.maybes = new VarDeclarations();
va.maybes.push(v);
}
+
+
+private bool setUnsafeDIP1000(FuncDeclaration f)
+{
+ return global.params.useDIP1000 == FeatureState.enabled
+ ? f.setUnsafe()
+ : f.isSafeBypassingInference();
+}
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 07d885b0bee..107e85b0793 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -967,11 +967,6 @@ extern (C++) abstract class Expression : ASTNode
return null;
}
- TupleExp toTupleExp()
- {
- return null;
- }
-
/***************************************
* Return !=0 if expression is an lvalue.
*/
@@ -1660,6 +1655,7 @@ extern (C++) abstract class Expression : ASTNode
inout(MixinExp) isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; }
inout(ImportExp) isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; }
inout(AssertExp) isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; }
+ inout(ThrowExp) isThrowExp() { return op == EXP.throw_ ? cast(typeof(return))this : null; }
inout(DotIdExp) isDotIdExp() { return op == EXP.dotIdentifier ? cast(typeof(return))this : null; }
inout(DotTemplateExp) isDotTemplateExp() { return op == EXP.dotTemplateDeclaration ? cast(typeof(return))this : null; }
inout(DotVarExp) isDotVarExp() { return op == EXP.dotVariable ? cast(typeof(return))this : null; }
@@ -1745,6 +1741,7 @@ extern (C++) abstract class Expression : ASTNode
inout(ModuleInitExp) isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; }
inout(FuncInitExp) isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; }
inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; }
+ inout(ObjcClassReferenceExp) isObjcClassReferenceExp() { return op == EXP.objcClassReference ? cast(typeof(return))this : null; }
inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; }
inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; }
@@ -2684,7 +2681,7 @@ extern (C++) final class StringExp : Expression
const len2 = se2.len;
assert(this.sz == se2.sz, "Comparing string expressions of different sizes");
- //printf("sz = %d, len1 = %d, len2 = %d\n", sz, (int)len1, (int)len2);
+ //printf("sz = %d, len1 = %d, len2 = %d\n", sz, cast(int)len1, cast(int)len2);
if (len1 == len2)
{
switch (sz)
@@ -2887,11 +2884,6 @@ extern (C++) final class TupleExp : Expression
return new TupleExp(loc, exps);
}
- override TupleExp toTupleExp()
- {
- return this;
- }
-
override TupleExp syntaxCopy()
{
return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps));
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index 9522b23a3b1..330dcdb77ec 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -103,7 +103,6 @@ public:
virtual real_t toImaginary();
virtual complex_t toComplex();
virtual StringExp *toStringExp();
- virtual TupleExp *toTupleExp();
virtual bool isLvalue();
virtual Expression *toLvalue(Scope *sc, Expression *e);
virtual Expression *modifiableLvalue(Scope *sc, Expression *e);
@@ -374,11 +373,11 @@ public:
OwnedBy ownedByCtfe;
static StringExp *create(const Loc &loc, const char *s);
- static StringExp *create(const Loc &loc, const void *s, size_t len);
+ static StringExp *create(const Loc &loc, const void *s, d_size_t len);
static void emplace(UnionExp *pue, const Loc &loc, const char *s);
bool equals(const RootObject *o) const;
- char32_t getCodeUnit(size_t i) const;
- void setCodeUnit(size_t i, char32_t c);
+ char32_t getCodeUnit(d_size_t i) const;
+ void setCodeUnit(d_size_t i, char32_t c);
StringExp *toStringExp();
StringExp *toUTF8(Scope *sc);
Optional<bool> toBool();
@@ -406,7 +405,6 @@ public:
Expressions *exps;
static TupleExp *create(const Loc &loc, Expressions *exps);
- TupleExp *toTupleExp();
TupleExp *syntaxCopy();
bool equals(const RootObject *o) const;
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 7b7c489295a..d4e96bb0f09 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -56,6 +56,7 @@ import dmd.initsem;
import dmd.inline;
import dmd.intrange;
import dmd.mtype;
+import dmd.mustuse;
import dmd.nspace;
import dmd.opover;
import dmd.optimize;
@@ -713,7 +714,7 @@ private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2
*/
Expression resolvePropertiesOnly(Scope* sc, Expression e1)
{
- //printf("e1 = %s %s\n", Token::toChars(e1.op), e1.toChars());
+ //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
Expression handleOverloadSet(OverloadSet os)
{
@@ -2027,15 +2028,19 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
//printf("type: %s\n", arg.type.toChars());
//printf("param: %s\n", p.toChars());
- if (firstArg && p.storageClass & STC.return_)
+ const pStc = tf.parameterStorageClass(tthis, p);
+
+ if (firstArg && (pStc & STC.return_))
{
/* Argument value can be assigned to firstArg.
* Check arg to see if it matters.
*/
if (global.params.useDIP1000 == FeatureState.enabled)
- err |= checkParamArgumentReturn(sc, firstArg, arg, false);
+ err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
}
- else if (tf.parameterEscapes(tthis, p))
+ // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
+ // as lazy parameters to the next function, but that isn't escaping.
+ else if (!(pStc & (STC.scope_ | STC.lazy_)))
{
/* Argument value can escape from the called function.
* Check arg to see if it matters.
@@ -2043,7 +2048,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
if (global.params.useDIP1000 == FeatureState.enabled)
err |= checkParamArgumentEscape(sc, fd, p, arg, false, false);
}
- else if (!(p.storageClass & STC.return_))
+ else if (!(pStc & STC.return_))
{
/* Argument value cannot escape from the called function.
*/
@@ -3228,7 +3233,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
Type t = cle.type.typeSemantic(cle.loc, sc);
auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret);
- auto e = initializerToExpression(init, t);
+ auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
if (!e)
{
error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars());
@@ -3261,7 +3266,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// printf("apply fix for issue 9490: add `this.` to `%s`...\n", e.toChars());
e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false);
}
- //printf("e = %s %s\n", Token::toChars(e.op), e.toChars());
+ //printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
e = e.expressionSemantic(sc);
}
else if (t)
@@ -5211,13 +5216,30 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (s.ident)
{
VarDeclaration v = s.isVarDeclaration();
- if (v && !(sc.flags & SCOPE.Cfile))
+ if (v)
{
- /* Do semantic() on initializer first so this will be illegal:
- * int a = a;
- */
- e.declaration.dsymbolSemantic(sc);
- s.parent = sc.parent;
+ if (sc.flags & SCOPE.Cfile)
+ {
+ /* Do semantic() on the type before inserting v into the symbol table
+ */
+ if (!v.originalType)
+ v.originalType = v.type.syntaxCopy();
+ Scope* sc2 = sc.push();
+ sc2.stc |= v.storage_class & STC.FUNCATTR;
+ sc2.linkage = LINK.c; // account for the extern(C) in front of the declaration
+ v.inuse++;
+ v.type = v.type.typeSemantic(v.loc, sc2);
+ v.inuse--;
+ sc2.pop();
+ }
+ else
+ {
+ /* Do semantic() on initializer first so this will be illegal:
+ * int a = a;
+ */
+ e.declaration.dsymbolSemantic(sc);
+ s.parent = sc.parent;
+ }
}
if (!sc.insert(s))
@@ -6032,7 +6054,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
auto fileName = FileName(name.toDString);
if (auto fmResult = global.fileManager.lookup(fileName))
{
- se = new StringExp(e.loc, fmResult.data);
+ se = new StringExp(e.loc, fmResult);
}
else
{
@@ -6047,9 +6069,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// take ownership of buffer (probably leaking)
auto data = readResult.extractSlice();
se = new StringExp(e.loc, data);
-
- FileBuffer* fileBuffer = new FileBuffer(data);
- global.fileManager.add(fileName, fileBuffer);
+ global.fileManager.add(fileName, data);
}
}
}
@@ -6388,7 +6408,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
static if (LOGSEMANTIC)
{
printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
- //printf("e1.op = %d, '%s'\n", e1.op, Token::toChars(e1.op));
+ //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
}
if (sc.flags & SCOPE.Cfile)
@@ -8177,7 +8197,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return;
if (e.type is Type.tvoid)
+ {
+ checkMustUse(e.e1, sc);
discardValue(e.e1);
+ }
else if (!e.allowCommaExp && !e.isGenerated)
e.error("Using the result of a comma expression is not allowed");
}
@@ -8956,7 +8979,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Parameter arg = Parameter.getNth(tt.arguments, u);
//printf("[%d] iexps.dim = %d, ", u, iexps.dim);
- //printf("e = (%s %s, %s), ", Token::tochars[e.op], e.toChars(), e.type.toChars());
+ //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
//printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
if (!arg || !e.type.implicitConvTo(arg.type))
@@ -9849,7 +9872,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
* `reorderSettingAAElem` creates a tree of comma expressions, however,
* `checkAssignExp` expects only AssignExps.
*/
- checkAssignEscape(sc, Expression.extractLast(res, tmp), false);
+ checkAssignEscape(sc, Expression.extractLast(res, tmp), false, false);
if (auto ae = res.isConstructExp())
{
@@ -10124,7 +10147,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
if (isRecursiveAliasThis(exp.att1, exp.e1.type))
return null;
- //printf("att %s e1 = %s\n", Token::toChars(e.op), e.e1.type.toChars());
+ //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident);
BinExp be = cast(BinExp)exp.copy();
be.e1 = e1;
@@ -10142,7 +10165,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
*/
if (isRecursiveAliasThis(exp.att2, exp.e2.type))
return null;
- //printf("att %s e2 = %s\n", Token::toChars(e.op), e.e2.type.toChars());
+ //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident);
BinExp be = cast(BinExp)exp.copy();
be.e2 = e2;
@@ -10169,7 +10192,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
auto res = exp.reorderSettingAAElem(sc);
if ((exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign) &&
global.params.useDIP1000 == FeatureState.enabled)
- checkAssignEscape(sc, res, false);
+ checkAssignEscape(sc, res, false, false);
result = res;
}
@@ -12193,7 +12216,7 @@ Expression semanticX(DotIdExp exp, Scope* sc)
if (Expression ex = unaSemantic(exp, sc))
return ex;
- if (exp.ident == Id._mangleof)
+ if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
{
// symbol.mangleof
@@ -12302,6 +12325,8 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
//{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
+ const cfile = (sc.flags & SCOPE.Cfile) != 0;
+
/* Special case: rewrite this.id and super.id
* to be classtype.id and baseclasstype.id
* if we have no this pointer.
@@ -12553,7 +12578,16 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
exp.error("undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars());
return ErrorExp.get();
}
- else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum && exp.ident != Id._init && exp.ident != Id.__sizeof && exp.ident != Id.__xalignof && exp.ident != Id.offsetof && exp.ident != Id._mangleof && exp.ident != Id.stringof)
+ else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum &&
+ !(
+ exp.ident == Id.__sizeof ||
+ exp.ident == Id.__xalignof ||
+ !cfile &&
+ (exp.ident == Id._mangleof ||
+ exp.ident == Id.offsetof ||
+ exp.ident == Id._init ||
+ exp.ident == Id.stringof)
+ ))
{
Type t1bn = t1b.nextOf();
if (flag)
@@ -12588,7 +12622,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
return e;
}
- else if (sc.flags & SCOPE.Cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp())
+ else if (cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp())
{
// Sizeof string literal includes the terminating 0
auto se = exp.e1.isStringExp();
@@ -12803,129 +12837,125 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
return false;
}
- //printf("checkSharedAccess() %s\n", e.toChars());
-
- static extern(C++) final class SharedCheckVisitor : SemanticTimeTransitiveVisitor
- {
- /// In case we don't know which expression triggered it,
- /// e.g. for `visit(Type)` overload
- Expression original;
- /// Where the result is stored (`true` == error)
- bool result;
- /// Whether we should allow one level of dereferencing
- bool allowRef;
+ //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
- /// Ctor
- this(Expression oe, bool allowRef_)
- {
- this.original = oe;
- this.allowRef = allowRef_;
- }
+ /* In case we don't know which expression triggered it,
+ * e.g. for `visit(Type)` overload
+ */
+ Expression original = e;
- void sharedError(Expression e)
+ bool check(Expression e, bool allowRef)
+ {
+ bool sharedError(Expression e)
{
// https://dlang.org/phobos/core_atomic.html
e.error("direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars());
- this.result = true;
+ return true;
}
- /// Introduce base class overrides
- alias visit = SemanticTimeTransitiveVisitor.visit;
-
// Error by default
- override void visit(Expression e)
+ bool visit(Expression e)
{
if (e.type.isShared())
- this.sharedError(e);
+ return sharedError(e);
+ return false;
}
- /// Ditto
- override void visit(Type t)
+ bool visitNew(NewExp e)
{
+ if (e.thisexp)
+ check(e.thisexp, false);
// Note: This handles things like `new shared(Throwable).msg`,
// where accessing `msg` would violate `shared`.
- if (t.isShared())
- this.sharedError(this.original);
+ if (e.newtype.isShared())
+ return sharedError(original);
+ return false;
}
- // Those have no indirections / can be ignored
- override void visit(ErrorExp e) {}
- override void visit(ComplexExp e) {}
- override void visit(IntegerExp e) {}
- override void visit(NullExp e) {}
-
- override void visit(VarExp e)
+ bool visitVar(VarExp e)
{
- if (!this.allowRef && e.var.type.isShared())
- this.sharedError(e);
+ if (!allowRef && e.var.type.isShared())
+ return sharedError(e);
+ return false;
}
- override void visit(AddrExp e)
+ bool visitAddr(AddrExp e)
{
- this.allowRef = true;
- e.e1.accept(this);
+ return check(e.e1, true);
}
- override void visit(PtrExp e)
+ bool visitPtr(PtrExp e)
{
- if (!this.allowRef && e.type.isShared())
- return this.sharedError(e);
+ if (!allowRef && e.type.isShared())
+ return sharedError(e);
if (e.e1.type.isShared())
- return this.sharedError(e);
+ return sharedError(e);
- this.allowRef = false;
- e.e1.accept(this);
+ return check(e.e1, false);
}
- override void visit(DotVarExp e)
+ bool visitDotVar(DotVarExp e)
{
auto fd = e.var.isFuncDeclaration();
const sharedFunc = fd && fd.type.isShared;
- if (!this.allowRef && e.type.isShared() && !sharedFunc)
- return this.sharedError(e);
+ if (!allowRef && e.type.isShared() && !sharedFunc)
+ return sharedError(e);
- // Allow to use `DotVarExp` within value types
- if (e.e1.type.ty == Tsarray || e.e1.type.ty == Tstruct)
- return e.e1.accept(this);
+ // Allow using `DotVarExp` within value types
+ if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
+ return check(e.e1, allowRef);
// If we end up with a single `VarExp`, it might be a `ref` param
// `shared ref T` param == `shared(T)*`.
if (auto ve = e.e1.isVarExp())
{
- this.allowRef = this.allowRef && (ve.var.storage_class & STC.ref_);
- return e.e1.accept(this);
+ return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
}
- this.allowRef = false;
- return e.e1.accept(this);
+ return check(e.e1, false);
}
- override void visit(IndexExp e)
+ bool visitIndex(IndexExp e)
{
- if (!this.allowRef && e.type.isShared())
- return this.sharedError(e);
+ if (!allowRef && e.type.isShared())
+ return sharedError(e);
if (e.e1.type.isShared())
- return this.sharedError(e);
+ return sharedError(e);
- this.allowRef = false;
- e.e1.accept(this);
+ return check(e.e1, false);
}
- override void visit(CommaExp e)
+ bool visitComma(CommaExp e)
{
// Cannot be `return ref` since we can't use the return,
// but it's better to show that error than an unrelated `shared` one
- this.allowRef = true;
- e.e2.accept(this);
+ return check(e.e2, true);
+ }
+
+ switch (e.op)
+ {
+ default: return visit(e);
+
+ // Those have no indirections / can be ignored
+ case EXP.call:
+ case EXP.error:
+ case EXP.complex80:
+ case EXP.int64:
+ case EXP.null_: return false;
+
+ case EXP.variable: return visitVar(e.isVarExp());
+ case EXP.new_: return visitNew(e.isNewExp());
+ case EXP.address: return visitAddr(e.isAddrExp());
+ case EXP.star: return visitPtr(e.isPtrExp());
+ case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
+ case EXP.index: return visitIndex(e.isIndexExp());
}
}
- scope visitor = new SharedCheckVisitor(e, returnRef);
- e.accept(visitor);
- return visitor.result;
+ return check(e, returnRef);
}
diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d
index b86c7995562..9fe40bf0603 100644
--- a/gcc/d/dmd/file_manager.d
+++ b/gcc/d/dmd/file_manager.d
@@ -11,7 +11,7 @@
module dmd.file_manager;
import dmd.root.stringtable : StringTable;
-import dmd.root.file : File, FileBuffer;
+import dmd.root.file : File, Buffer;
import dmd.root.filename : FileName;
import dmd.root.string : toDString;
import dmd.globals;
@@ -22,7 +22,7 @@ enum package_di = "package." ~ hdr_ext;
final class FileManager
{
- private StringTable!(FileBuffer*) files;
+ private StringTable!(const(ubyte)[]) files;
///
public this () nothrow
@@ -146,7 +146,7 @@ nothrow:
* Returns: the loaded source file if it was found in memory,
* otherwise `null`
*/
- const(FileBuffer)* lookup(FileName filename)
+ const(ubyte)[] lookup(FileName filename)
{
const name = filename.toString;
if (auto val = files.lookup(name))
@@ -154,7 +154,7 @@ nothrow:
if (name == "__stdin.d")
{
- auto buffer = new FileBuffer(readFromStdin().extractSlice());
+ auto buffer = readFromStdin().extractSlice();
if (this.files.insert(name, buffer) is null)
assert(0, "stdin: Insert after lookup failure should never return `null`");
return buffer;
@@ -167,7 +167,7 @@ nothrow:
if (!readResult.success)
return null;
- FileBuffer* fb = new FileBuffer(readResult.extractSlice());
+ auto fb = readResult.extractSlice();
if (files.insert(name, fb) is null)
assert(0, "Insert after lookup failure should never return `null`");
@@ -187,17 +187,17 @@ nothrow:
const(char)[][] lines;
if (const buffer = lookup(file))
{
- const slice = buffer.data[0 .. buffer.data.length];
+ const slice = buffer;
size_t start, end;
- ubyte c;
for (auto i = 0; i < slice.length; i++)
{
- c = slice[i];
+ const c = slice[i];
if (c == '\n' || c == '\r')
{
if (i != 0)
{
end = i;
+ // Appending lines one at a time will certainly be slow
lines ~= cast(const(char)[])slice[start .. end];
}
// Check for Windows-style CRLF newlines
@@ -234,18 +234,21 @@ nothrow:
}
/**
- * Adds a FileBuffer to the table.
- *
- * Returns: The FileBuffer added, or null
+ * Adds the contents of a file to the table.
+ * Params:
+ * filename = name of the file
+ * buffer = contents of the file
+ * Returns:
+ * the buffer added, or null
*/
- FileBuffer* add(FileName filename, FileBuffer* filebuffer)
+ const(ubyte)[] add(FileName filename, const(ubyte)[] buffer)
{
- auto val = files.insert(filename.toString, filebuffer);
+ auto val = files.insert(filename.toString, buffer);
return val == null ? null : val.value;
}
}
-private FileBuffer readFromStdin() nothrow
+private Buffer readFromStdin() nothrow
{
import core.stdc.stdio;
import dmd.errors;
@@ -277,7 +280,7 @@ private FileBuffer readFromStdin() nothrow
// We're done
assert(pos < sz + 2);
buffer[pos .. pos + 4] = '\0';
- return FileBuffer(buffer[0 .. pos]);
+ return Buffer(buffer[0 .. pos]);
}
} while (pos < sz);
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
index a3afbe50796..69fdf27e1db 100644
--- a/gcc/d/dmd/hdrgen.d
+++ b/gcc/d/dmd/hdrgen.d
@@ -1538,6 +1538,13 @@ public:
}
else if (hgs.tpltMember == 0 && global.params.hdrStripPlainFunctions)
{
+ if (!f.fbody)
+ {
+ // this can happen on interfaces / abstract functions, see `allowsContractWithoutBody`
+ if (f.fensures || f.frequires)
+ buf.writenl();
+ contractsToBuffer(f);
+ }
buf.writeByte(';');
buf.writenl();
}
@@ -1548,19 +1555,9 @@ public:
bodyToBuffer(f);
}
- void bodyToBuffer(FuncDeclaration f)
+ /// Returns: whether `do` is needed to write the function body
+ bool contractsToBuffer(FuncDeclaration f)
{
- if (!f.fbody || (hgs.hdrgen && global.params.hdrStripPlainFunctions && !hgs.autoMember && !hgs.tpltMember))
- {
- buf.writeByte(';');
- buf.writenl();
- return;
- }
- const savetlpt = hgs.tpltMember;
- const saveauto = hgs.autoMember;
- hgs.tpltMember = 0;
- hgs.autoMember = 0;
- buf.writenl();
bool requireDo = false;
// in{}
if (f.frequires)
@@ -1619,6 +1616,29 @@ public:
}
}
}
+ return requireDo;
+ }
+
+ void bodyToBuffer(FuncDeclaration f)
+ {
+ if (!f.fbody || (hgs.hdrgen && global.params.hdrStripPlainFunctions && !hgs.autoMember && !hgs.tpltMember))
+ {
+ if (!f.fbody && (f.fensures || f.frequires))
+ {
+ buf.writenl();
+ contractsToBuffer(f);
+ }
+ buf.writeByte(';');
+ buf.writenl();
+ return;
+ }
+ const savetlpt = hgs.tpltMember;
+ const saveauto = hgs.autoMember;
+ hgs.tpltMember = 0;
+ hgs.autoMember = 0;
+ buf.writenl();
+ bool requireDo = contractsToBuffer(f);
+
if (requireDo)
{
buf.writestring("do");
@@ -1788,26 +1808,17 @@ public:
}
}
-private extern (C++) final class ExpressionPrettyPrintVisitor : Visitor
+/*********************************************
+ * Print expression to buffer.
+ */
+private void expressionPrettyPrint(Expression e, OutBuffer* buf, HdrGenState* hgs)
{
- alias visit = Visitor.visit;
-public:
- OutBuffer* buf;
- HdrGenState* hgs;
-
- extern (D) this(OutBuffer* buf, HdrGenState* hgs)
- {
- this.buf = buf;
- this.hgs = hgs;
- }
-
- ////////////////////////////////////////////////////////////////////////////
- override void visit(Expression e)
+ void visit(Expression e)
{
buf.writestring(EXPtoString(e.op));
}
- override void visit(IntegerExp e)
+ void visitInteger(IntegerExp e)
{
const dinteger_t v = e.toInteger();
if (e.type)
@@ -1907,12 +1918,12 @@ public:
buf.print(v);
}
- override void visit(ErrorExp e)
+ void visitError(ErrorExp e)
{
buf.writestring("__error");
}
- override void visit(VoidInitExp e)
+ void visitVoidInit(VoidInitExp e)
{
buf.writestring("__void");
}
@@ -1922,12 +1933,12 @@ public:
.floatToBuffer(type, value, buf, hgs.hdrgen);
}
- override void visit(RealExp e)
+ void visitReal(RealExp e)
{
floatToBuffer(e.type, e.value);
}
- override void visit(ComplexExp e)
+ void visitComplex(ComplexExp e)
{
/* Print as:
* (re+imi)
@@ -1939,7 +1950,7 @@ public:
buf.writestring("i)");
}
- override void visit(IdentifierExp e)
+ void visitIdentifier(IdentifierExp e)
{
if (hgs.hdrgen || hgs.ddoc)
buf.writestring(e.ident.toHChars2());
@@ -1947,27 +1958,27 @@ public:
buf.writestring(e.ident.toString());
}
- override void visit(DsymbolExp e)
+ void visitDsymbol(DsymbolExp e)
{
buf.writestring(e.s.toChars());
}
- override void visit(ThisExp e)
+ void visitThis(ThisExp e)
{
buf.writestring("this");
}
- override void visit(SuperExp e)
+ void visitSuper(SuperExp e)
{
buf.writestring("super");
}
- override void visit(NullExp e)
+ void visitNull(NullExp e)
{
buf.writestring("null");
}
- override void visit(StringExp e)
+ void visitString(StringExp e)
{
buf.writeByte('"');
const o = buf.length;
@@ -1982,14 +1993,14 @@ public:
buf.writeByte(e.postfix);
}
- override void visit(ArrayLiteralExp e)
+ void visitArrayLiteral(ArrayLiteralExp e)
{
buf.writeByte('[');
argsToBuffer(e.elements, buf, hgs, e.basis);
buf.writeByte(']');
}
- override void visit(AssocArrayLiteralExp e)
+ void visitAssocArrayLiteral(AssocArrayLiteralExp e)
{
buf.writeByte('[');
foreach (i, key; *e.keys)
@@ -2004,7 +2015,7 @@ public:
buf.writeByte(']');
}
- override void visit(StructLiteralExp e)
+ void visitStructLiteral(StructLiteralExp e)
{
buf.writestring(e.sd.toChars());
buf.writeByte('(');
@@ -2024,7 +2035,7 @@ public:
buf.writeByte(')');
}
- override void visit(CompoundLiteralExp e)
+ void visitCompoundLiteral(CompoundLiteralExp e)
{
buf.writeByte('(');
typeToBuffer(e.type, null, buf, hgs);
@@ -2032,12 +2043,12 @@ public:
e.initializer.initializerToBuffer(buf, hgs);
}
- override void visit(TypeExp e)
+ void visitType(TypeExp e)
{
typeToBuffer(e.type, null, buf, hgs);
}
- override void visit(ScopeExp e)
+ void visitScope(ScopeExp e)
{
if (e.sds.isTemplateInstance())
{
@@ -2059,12 +2070,12 @@ public:
}
}
- override void visit(TemplateExp e)
+ void visitTemplate(TemplateExp e)
{
buf.writestring(e.td.toChars());
}
- override void visit(NewExp e)
+ void visitNew(NewExp e)
{
if (e.thisexp)
{
@@ -2081,7 +2092,7 @@ public:
}
}
- override void visit(NewAnonClassExp e)
+ void visitNewAnonClass(NewAnonClassExp e)
{
if (e.thisexp)
{
@@ -2100,7 +2111,7 @@ public:
e.cd.dsymbolToBuffer(buf, hgs);
}
- override void visit(SymOffExp e)
+ void visitSymOff(SymOffExp e)
{
if (e.offset)
buf.printf("(& %s%+lld)", e.var.toChars(), e.offset);
@@ -2110,22 +2121,22 @@ public:
buf.printf("& %s", e.var.toChars());
}
- override void visit(VarExp e)
+ void visitVar(VarExp e)
{
buf.writestring(e.var.toChars());
}
- override void visit(OverExp e)
+ void visitOver(OverExp e)
{
buf.writestring(e.vars.ident.toString());
}
- override void visit(TupleExp e)
+ void visitTuple(TupleExp e)
{
if (e.e0)
{
buf.writeByte('(');
- e.e0.accept(this);
+ e.e0.expressionPrettyPrint(buf, hgs);
buf.writestring(", tuple(");
argsToBuffer(e.exps, buf, hgs);
buf.writestring("))");
@@ -2138,13 +2149,13 @@ public:
}
}
- override void visit(FuncExp e)
+ void visitFunc(FuncExp e)
{
e.fd.dsymbolToBuffer(buf, hgs);
//buf.writestring(e.fd.toChars());
}
- override void visit(DeclarationExp e)
+ void visitDeclaration(DeclarationExp e)
{
/* Normal dmd execution won't reach here - regular variable declarations
* are handled in visit(ExpStatement), so here would be used only when
@@ -2170,14 +2181,14 @@ public:
}
}
- override void visit(TypeidExp e)
+ void visitTypeid(TypeidExp e)
{
buf.writestring("typeid(");
objectToBuffer(e.obj, buf, hgs);
buf.writeByte(')');
}
- override void visit(TraitsExp e)
+ void visitTraits(TraitsExp e)
{
buf.writestring("__traits(");
if (e.ident)
@@ -2193,12 +2204,12 @@ public:
buf.writeByte(')');
}
- override void visit(HaltExp e)
+ void visitHalt(HaltExp e)
{
buf.writestring("halt");
}
- override void visit(IsExp e)
+ void visitIs(IsExp e)
{
buf.writestring("is(");
typeToBuffer(e.targ, e.id, buf, hgs);
@@ -2223,13 +2234,13 @@ public:
buf.writeByte(')');
}
- override void visit(UnaExp e)
+ void visitUna(UnaExp e)
{
buf.writestring(EXPtoString(e.op));
expToBuffer(e.e1, precedence[e.op], buf, hgs);
}
- override void visit(BinExp e)
+ void visitBin(BinExp e)
{
expToBuffer(e.e1, precedence[e.op], buf, hgs);
buf.writeByte(' ');
@@ -2238,7 +2249,7 @@ public:
expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1), buf, hgs);
}
- override void visit(CommaExp e)
+ void visitComma(CommaExp e)
{
// CommaExp is generated by the compiler so it shouldn't
// appear in error messages or header files.
@@ -2251,7 +2262,7 @@ public:
// the old path
if (!ve || !(ve.var.storage_class & STC.temp))
{
- visit(cast(BinExp)e);
+ visitBin(cast(BinExp)e);
return;
}
@@ -2281,25 +2292,25 @@ public:
}
// not one of the known cases, go on the old path
- visit(cast(BinExp)e);
+ visitBin(cast(BinExp)e);
return;
}
- override void visit(MixinExp e)
+ void visitMixin(MixinExp e)
{
buf.writestring("mixin(");
argsToBuffer(e.exps, buf, hgs, null);
buf.writeByte(')');
}
- override void visit(ImportExp e)
+ void visitImport(ImportExp e)
{
buf.writestring("import(");
expToBuffer(e.e1, PREC.assign, buf, hgs);
buf.writeByte(')');
}
- override void visit(AssertExp e)
+ void visitAssert(AssertExp e)
{
buf.writestring("assert(");
expToBuffer(e.e1, PREC.assign, buf, hgs);
@@ -2311,13 +2322,13 @@ public:
buf.writeByte(')');
}
- override void visit(ThrowExp e)
+ void visitThrow(ThrowExp e)
{
buf.writestring("throw ");
expToBuffer(e.e1, PREC.unary, buf, hgs);
}
- override void visit(DotIdExp e)
+ void visitDotId(DotIdExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
if (e.arrow)
@@ -2327,28 +2338,28 @@ public:
buf.writestring(e.ident.toString());
}
- override void visit(DotTemplateExp e)
+ void visitDotTemplate(DotTemplateExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
buf.writeByte('.');
buf.writestring(e.td.toChars());
}
- override void visit(DotVarExp e)
+ void visitDotVar(DotVarExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
buf.writeByte('.');
buf.writestring(e.var.toChars());
}
- override void visit(DotTemplateInstanceExp e)
+ void visitDotTemplateInstance(DotTemplateInstanceExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
buf.writeByte('.');
e.ti.dsymbolToBuffer(buf, hgs);
}
- override void visit(DelegateExp e)
+ void visitDelegate(DelegateExp e)
{
buf.writeByte('&');
if (!e.func.isNested() || e.func.needThis())
@@ -2359,14 +2370,14 @@ public:
buf.writestring(e.func.toChars());
}
- override void visit(DotTypeExp e)
+ void visitDotType(DotTypeExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
buf.writeByte('.');
buf.writestring(e.sym.toChars());
}
- override void visit(CallExp e)
+ void visitCall(CallExp e)
{
if (e.e1.op == EXP.type)
{
@@ -2375,7 +2386,7 @@ public:
* This is ok since types in constructor calls
* can never depend on parens anyway
*/
- e.e1.accept(this);
+ e.e1.expressionPrettyPrint(buf, hgs);
}
else
expToBuffer(e.e1, precedence[e.op], buf, hgs);
@@ -2384,19 +2395,19 @@ public:
buf.writeByte(')');
}
- override void visit(PtrExp e)
+ void visitPtr(PtrExp e)
{
buf.writeByte('*');
expToBuffer(e.e1, precedence[e.op], buf, hgs);
}
- override void visit(DeleteExp e)
+ void visitDelete(DeleteExp e)
{
buf.writestring("delete ");
expToBuffer(e.e1, precedence[e.op], buf, hgs);
}
- override void visit(CastExp e)
+ void visitCast(CastExp e)
{
buf.writestring("cast(");
if (e.to)
@@ -2409,7 +2420,7 @@ public:
expToBuffer(e.e1, precedence[e.op], buf, hgs);
}
- override void visit(VectorExp e)
+ void visitVector(VectorExp e)
{
buf.writestring("cast(");
typeToBuffer(e.to, null, buf, hgs);
@@ -2417,13 +2428,13 @@ public:
expToBuffer(e.e1, precedence[e.op], buf, hgs);
}
- override void visit(VectorArrayExp e)
+ void visitVectorArray(VectorArrayExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
buf.writestring(".array");
}
- override void visit(SliceExp e)
+ void visitSlice(SliceExp e)
{
expToBuffer(e.e1, precedence[e.op], buf, hgs);
buf.writeByte('[');
@@ -2442,32 +2453,32 @@ public:
buf.writeByte(']');
}
- override void visit(ArrayLengthExp e)
+ void visitArrayLength(ArrayLengthExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
buf.writestring(".length");
}
- override void visit(IntervalExp e)
+ void visitInterval(IntervalExp e)
{
expToBuffer(e.lwr, PREC.assign, buf, hgs);
buf.writestring("..");
expToBuffer(e.upr, PREC.assign, buf, hgs);
}
- override void visit(DelegatePtrExp e)
+ void visitDelegatePtr(DelegatePtrExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
buf.writestring(".ptr");
}
- override void visit(DelegateFuncptrExp e)
+ void visitDelegateFuncptr(DelegateFuncptrExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
buf.writestring(".funcptr");
}
- override void visit(ArrayExp e)
+ void visitArray(ArrayExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
buf.writeByte('[');
@@ -2475,14 +2486,14 @@ public:
buf.writeByte(']');
}
- override void visit(DotExp e)
+ void visitDot(DotExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
buf.writeByte('.');
expToBuffer(e.e2, PREC.primary, buf, hgs);
}
- override void visit(IndexExp e)
+ void visitIndex(IndexExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
buf.writeByte('[');
@@ -2490,19 +2501,19 @@ public:
buf.writeByte(']');
}
- override void visit(PostExp e)
+ void visitPost(PostExp e)
{
expToBuffer(e.e1, precedence[e.op], buf, hgs);
buf.writestring(EXPtoString(e.op));
}
- override void visit(PreExp e)
+ void visitPre(PreExp e)
{
buf.writestring(EXPtoString(e.op));
expToBuffer(e.e1, precedence[e.op], buf, hgs);
}
- override void visit(RemoveExp e)
+ void visitRemove(RemoveExp e)
{
expToBuffer(e.e1, PREC.primary, buf, hgs);
buf.writestring(".remove(");
@@ -2510,7 +2521,7 @@ public:
buf.writeByte(')');
}
- override void visit(CondExp e)
+ void visitCond(CondExp e)
{
expToBuffer(e.econd, PREC.oror, buf, hgs);
buf.writestring(" ? ");
@@ -2519,15 +2530,90 @@ public:
expToBuffer(e.e2, PREC.cond, buf, hgs);
}
- override void visit(DefaultInitExp e)
+ void visitDefaultInit(DefaultInitExp e)
{
buf.writestring(EXPtoString(e.op));
}
- override void visit(ClassReferenceExp e)
+ void visitClassReference(ClassReferenceExp e)
{
buf.writestring(e.value.toChars());
}
+
+ switch (e.op)
+ {
+ default:
+ if (auto be = e.isBinExp())
+ return visitBin(be);
+ else if (auto ue = e.isUnaExp())
+ return visitUna(ue);
+ else if (auto de = e.isDefaultInitExp())
+ return visitDefaultInit(e.isDefaultInitExp());
+ return visit(e);
+
+ case EXP.int64: return visitInteger(e.isIntegerExp());
+ case EXP.error: return visitError(e.isErrorExp());
+ case EXP.void_: return visitVoidInit(e.isVoidInitExp());
+ case EXP.float64: return visitReal(e.isRealExp());
+ case EXP.complex80: return visitComplex(e.isComplexExp());
+ case EXP.identifier: return visitIdentifier(e.isIdentifierExp());
+ case EXP.dSymbol: return visitDsymbol(e.isDsymbolExp());
+ case EXP.this_: return visitThis(e.isThisExp());
+ case EXP.super_: return visitSuper(e.isSuperExp());
+ case EXP.null_: return visitNull(e.isNullExp());
+ case EXP.string_: return visitString(e.isStringExp());
+ case EXP.arrayLiteral: return visitArrayLiteral(e.isArrayLiteralExp());
+ case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp());
+ case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp());
+ case EXP.compoundLiteral: return visitCompoundLiteral(e.isCompoundLiteralExp());
+ case EXP.type: return visitType(e.isTypeExp());
+ case EXP.scope_: return visitScope(e.isScopeExp());
+ case EXP.template_: return visitTemplate(e.isTemplateExp());
+ case EXP.new_: return visitNew(e.isNewExp());
+ case EXP.newAnonymousClass: return visitNewAnonClass(e.isNewAnonClassExp());
+ case EXP.symbolOffset: return visitSymOff(e.isSymOffExp());
+ case EXP.variable: return visitVar(e.isVarExp());
+ case EXP.overloadSet: return visitOver(e.isOverExp());
+ case EXP.tuple: return visitTuple(e.isTupleExp());
+ case EXP.function_: return visitFunc(e.isFuncExp());
+ case EXP.declaration: return visitDeclaration(e.isDeclarationExp());
+ case EXP.typeid_: return visitTypeid(e.isTypeidExp());
+ case EXP.traits: return visitTraits(e.isTraitsExp());
+ case EXP.halt: return visitHalt(e.isHaltExp());
+ case EXP.is_: return visitIs(e.isExp());
+ case EXP.comma: return visitComma(e.isCommaExp());
+ case EXP.mixin_: return visitMixin(e.isMixinExp());
+ case EXP.import_: return visitImport(e.isImportExp());
+ case EXP.assert_: return visitAssert(e.isAssertExp());
+ case EXP.throw_: return visitThrow(e.isThrowExp());
+ case EXP.dotIdentifier: return visitDotId(e.isDotIdExp());
+ case EXP.dotTemplateDeclaration: return visitDotTemplate(e.isDotTemplateExp());
+ case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
+ case EXP.dotTemplateInstance: return visitDotTemplateInstance(e.isDotTemplateInstanceExp());
+ case EXP.delegate_: return visitDelegate(e.isDelegateExp());
+ case EXP.dotType: return visitDotType(e.isDotTypeExp());
+ case EXP.call: return visitCall(e.isCallExp());
+ case EXP.star: return visitPtr(e.isPtrExp());
+ case EXP.delete_: return visitDelete(e.isDeleteExp());
+ case EXP.cast_: return visitCast(e.isCastExp());
+ case EXP.vector: return visitVector(e.isVectorExp());
+ case EXP.vectorArray: return visitVectorArray(e.isVectorArrayExp());
+ case EXP.slice: return visitSlice(e.isSliceExp());
+ case EXP.arrayLength: return visitArrayLength(e.isArrayLengthExp());
+ case EXP.interval: return visitInterval(e.isIntervalExp());
+ case EXP.delegatePointer: return visitDelegatePtr(e.isDelegatePtrExp());
+ case EXP.delegateFunctionPointer: return visitDelegateFuncptr(e.isDelegateFuncptrExp());
+ case EXP.array: return visitArray(e.isArrayExp());
+ case EXP.dot: return visitDot(e.isDotExp());
+ case EXP.index: return visitIndex(e.isIndexExp());
+ case EXP.minusMinus:
+ case EXP.plusPlus: return visitPost(e.isPostExp());
+ case EXP.preMinusMinus:
+ case EXP.prePlusPlus: return visitPre(e.isPreExp());
+ case EXP.remove: return visitRemove(e.isRemoveExp());
+ case EXP.question: return visitCond(e.isCondExp());
+ case EXP.classReference: return visitClassReference(e.isClassReferenceExp());
+ }
}
/**
@@ -2547,7 +2633,7 @@ void floatToBuffer(Type type, const real_t value, OutBuffer* buf, const bool all
(ie, 8 chars more than mantissa). Plus one for trailing \0.
Plus one for rounding. */
const(size_t) BUFFER_LEN = value.sizeof * 3 + 8 + 1 + 1;
- char[BUFFER_LEN] buffer;
+ char[BUFFER_LEN] buffer = void;
CTFloat.sprint(buffer.ptr, 'g', value);
assert(strlen(buffer.ptr) < BUFFER_LEN);
if (allowHex)
@@ -2754,7 +2840,7 @@ bool stcToBuffer(OutBuffer* buf, StorageClass stc)
}
if (stc & STC.returninferred)
{
- //buf.writestring("return-inferred ");
+ //buf.writestring((stc & STC.returnScope) ? "return-scope-inferred " : "return-ref-inferred ");
stc &= ~(STC.return_ | STC.returninferred);
}
@@ -2958,8 +3044,7 @@ void functionToBufferWithIdent(TypeFunction tf, OutBuffer* buf, const(char)* ide
void toCBuffer(const Expression e, OutBuffer* buf, HdrGenState* hgs)
{
- scope v = new ExpressionPrettyPrintVisitor(buf, hgs);
- (cast() e).accept(v);
+ expressionPrettyPrint(cast()e, buf, hgs);
}
/**************************************************
@@ -3221,8 +3306,7 @@ private void sizeToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs)
private void expressionToBuffer(Expression e, OutBuffer* buf, HdrGenState* hgs)
{
- scope v = new ExpressionPrettyPrintVisitor(buf, hgs);
- e.accept(v);
+ expressionPrettyPrint(e, buf, hgs);
}
/**************************************************
diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d
index 2ec75ab2516..11455afe263 100644
--- a/gcc/d/dmd/id.d
+++ b/gcc/d/dmd/id.d
@@ -491,6 +491,7 @@ immutable Msgtable[] msgtable =
{ "udaGNUAbiTag", "gnuAbiTag" },
{ "udaSelector", "selector" },
{ "udaOptional", "optional"},
+ { "udaMustUse", "mustuse" },
// C names, for undefined identifier error messages
{ "NULL" },
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index 649d88e3d59..c84a9f69ffa 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -554,26 +554,39 @@ 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.
- if (tb.ty == Tsarray && !tb.nextOf().equals(ti.toBasetype().nextOf()) && i.exp.implicitConvTo(tb.nextOf()))
+ auto tba = tb.isTypeSArray();
+ if (tba && !tba.next.equals(ti.toBasetype().nextOf()) && i.exp.implicitConvTo(tba.next))
{
/* 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();
}
+
+ auto tta = t.isTypeSArray();
if (i.exp.implicitConvTo(t))
{
i.exp = i.exp.implicitCastTo(sc, t);
}
+ else if (sc.flags & SCOPE.Cfile && i.exp.isStringExp() &&
+ tta && (tta.next.ty == Tint8 || tta.next.ty == Tuns8) &&
+ ti.ty == Tpointer && ti.nextOf().ty == Tchar)
+ {
+ /* unsigned char bbb[1] = "";
+ * signed char ccc[1] = "";
+ */
+ i.exp = i.exp.castTo(sc, t);
+ }
else
{
// Look for mismatch of compile-time known length to emit
// better diagnostic message, as same as AssignExp::semantic.
- if (tb.ty == Tsarray && i.exp.implicitConvTo(tb.nextOf().arrayOf()) > MATCH.nomatch)
+ if (tba && i.exp.implicitConvTo(tba.next.arrayOf()) > MATCH.nomatch)
{
- uinteger_t dim1 = tb.isTypeSArray().dim.toInteger();
+ uinteger_t dim1 = tba.dim.toInteger();
uinteger_t dim2 = dim1;
if (auto ale = i.exp.isArrayLiteralExp())
{
@@ -596,6 +609,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
if (global.endGagging(errors))
currExp.error("cannot implicitly convert expression `%s` of type `%s` to `%s`", currExp.toChars(), et.toChars(), t.toChars());
}
+ }
L1:
if (i.exp.op == EXP.error)
{
@@ -681,7 +695,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
assert(sc);
auto tm = vd.type.addMod(ts.mod);
auto iz = di.initializer.initializerSemantic(sc, tm, needInterpret);
- auto ex = iz.initializerToExpression();
+ auto ex = iz.initializerToExpression(null, true);
if (ex.op == EXP.error)
{
errors = true;
@@ -1059,7 +1073,7 @@ Initializer inferType(Initializer init, Scope* sc)
Initializer visitC(CInitializer i)
{
- //printf(CInitializer::inferType()\n");
+ //printf("CInitializer.inferType()\n");
error(i.loc, "TODO C inferType initializers not supported yet");
return new ErrorInitializer();
}
@@ -1086,6 +1100,8 @@ Initializer inferType(Initializer init, Scope* sc)
*/
extern (C++) Expression initializerToExpression(Initializer init, Type itype = null, const bool isCfile = false)
{
+ //printf("initializerToExpression() isCfile: %d\n", isCfile);
+
Expression visitVoid(VoidInitializer)
{
return null;
@@ -1183,7 +1199,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
assert(j < edim);
if (Initializer iz = init.value[i])
{
- if (Expression ex = iz.initializerToExpression())
+ if (Expression ex = iz.initializerToExpression(null, isCfile))
{
(*elements)[j] = ex;
++j;
@@ -1271,7 +1287,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
Expression visitC(CInitializer i)
{
- //printf("CInitializer.initializerToExpression()\n");
+ //printf("CInitializer.initializerToExpression(null, true)\n");
return null;
}
@@ -1331,6 +1347,10 @@ private bool hasNonConstPointers(Expression e)
}
if (auto ae = e.isAddrExp())
{
+ if (ae.type.nextOf().isImmutable() || ae.type.nextOf().isConst())
+ {
+ return false;
+ }
if (auto se = ae.e1.isStructLiteralExp())
{
if (!(se.stageflags & stageSearchPointers))
diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d
index 3183c8dbb79..fc270390fa4 100644
--- a/gcc/d/dmd/json.d
+++ b/gcc/d/dmd/json.d
@@ -319,10 +319,7 @@ public:
// Should not be printed
//property(name, "d");
break;
- case LINK.system:
- // Should not be printed
- //property(name, "system");
- break;
+ case LINK.system: return property(name, "system");
case LINK.c: return property(name, "c");
case LINK.cpp: return property(name, "cpp");
case LINK.windows: return property(name, "windows");
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index 7cd4bfd5922..5945da32259 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -108,8 +108,8 @@ class Lexer
size_t endoffset, bool doDocComment, bool commentToken) pure
{
scanloc = Loc(filename, 1, 1);
- //printf("Lexer::Lexer(%p,%d)\n",base,length);
- //printf("lexer.filename = %s\n", filename);
+ // debug printf("Lexer::Lexer(%p)\n", base);
+ // debug printf("lexer.filename = %s\n", filename);
token = Token.init;
this.base = base;
this.end = base + endoffset;
@@ -1236,28 +1236,47 @@ class Lexer
{
uint v = 0;
int n = 0;
- while (1)
+ if (Ccompile && ndigits == 2)
{
- if (isdigit(cast(char)c))
- c -= '0';
- else if (islower(c))
- c -= 'a' - 10;
- else
- c -= 'A' - 10;
- v = v * 16 + c;
- c = *++p;
- if (++n == ndigits)
- break;
- if (!ishex(cast(char)c))
+ /* C11 6.4.4.4-7 one to infinity hex digits
+ */
+ do
{
- .error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits);
- break;
- }
+ if (isdigit(cast(char)c))
+ c -= '0';
+ else if (islower(c))
+ c -= 'a' - 10;
+ else
+ c -= 'A' - 10;
+ v = v * 16 + c;
+ c = *++p;
+ } while (ishex(cast(char)c));
}
- if (ndigits != 2 && !utf_isValidDchar(v))
+ else
{
- .error(loc, "invalid UTF character \\U%08x", v);
- v = '?'; // recover with valid UTF character
+ while (1)
+ {
+ if (isdigit(cast(char)c))
+ c -= '0';
+ else if (islower(c))
+ c -= 'a' - 10;
+ else
+ c -= 'A' - 10;
+ v = v * 16 + c;
+ c = *++p;
+ if (++n == ndigits)
+ break;
+ if (!ishex(cast(char)c))
+ {
+ .error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits);
+ break;
+ }
+ }
+ if (ndigits != 2 && !utf_isValidDchar(v))
+ {
+ .error(loc, "invalid UTF character \\U%08x", v);
+ v = '?'; // recover with valid UTF character
+ }
}
c = v;
}
@@ -2122,7 +2141,7 @@ class Lexer
// can't translate invalid octal value, just show a generic message
error("octal literals larger than 7 are no longer supported");
else
- error("octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!%llo%.*s` instead",
+ error("octal literals `0%llo%.*s` are no longer supported, use `std.conv.octal!\"%llo%.*s\"` instead",
n, cast(int)(p - psuffix), psuffix, n, cast(int)(p - psuffix), psuffix);
}
TOK result;
@@ -2926,7 +2945,7 @@ class Lexer
*/
static const(char)* combineComments(const(char)[] c1, const(char)[] c2, bool newParagraph) pure
{
- //printf("Lexer::combineComments('%s', '%s', '%i')\n", c1, c2, newParagraph);
+ //debug printf("Lexer::combineComments('%*.s', '%*.s', '%i')\n", cast(int) c1.length, c1.ptr, cast(int) c2.length, c2.ptr, newParagraph);
const(int) newParagraphSize = newParagraph ? 1 : 0; // Size of the combining '\n'
if (!c1)
return c2.ptr;
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index b2c7aa461ca..13df0d71f3f 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -4200,27 +4200,28 @@ extern (C++) final class TypeFunction : TypeNext
// These flags can be accessed like `bool` properties,
// getters and setters are generated for them
- private enum FunctionFlag : uint
- {
- none = 0,
- isnothrow = 0x0001, // nothrow
- isnogc = 0x0002, // is @nogc
- isproperty = 0x0004, // can be called without parentheses
- isref = 0x0008, // returns a reference
- isreturn = 0x0010, // 'this' is returned by ref
- isScopeQual = 0x0020, // 'this' is scope
- isreturninferred= 0x0040, // 'this' is return from inference
- isscopeinferred = 0x0080, // 'this' is scope from inference
- islive = 0x0100, // is @live
- incomplete = 0x0200, // return type or default arguments removed
- isInOutParam = 0x0400, // inout on the parameters
- isInOutQual = 0x0800, // inout on the qualifier
- isctor = 0x1000, // the function is a constructor
- isreturnscope = 0x2000, // `this` is returned by value
- }
+ private extern (D) static struct BitFields
+ {
+ bool isnothrow; /// nothrow
+ bool isnogc; /// is @nogc
+ bool isproperty; /// can be called without parentheses
+ bool isref; /// returns a reference
+ bool isreturn; /// 'this' is returned by ref
+ bool isScopeQual; /// 'this' is scope
+ bool isreturninferred; /// 'this' is return from inference
+ bool isscopeinferred; /// 'this' is scope from inference
+ bool islive; /// is @live
+ bool incomplete; /// return type or default arguments removed
+ bool isInOutParam; /// inout on the parameters
+ bool isInOutQual; /// inout on the qualifier
+ bool isctor; /// the function is a constructor
+ bool isreturnscope; /// `this` is returned by value
+ }
+
+ import dmd.common.bitfields : generateBitFields;
+ mixin(generateBitFields!(BitFields, ushort));
LINK linkage; // calling convention
- FunctionFlag funcFlags;
TRUST trust; // level of trust
PURE purity = PURE.impure;
byte inuse;
@@ -4359,29 +4360,6 @@ extern (C++) final class TypeFunction : TypeNext
return linkage == LINK.d && parameterList.varargs == VarArg.variadic;
}
- /***************************
- * Examine function signature for parameter p and see if
- * the value of p can 'escape' the scope of the function.
- * This is useful to minimize the needed annotations for the parameters.
- * Params:
- * tthis = type of `this` parameter, null if none
- * p = parameter to this function
- * Returns:
- * true if escapes via assignment to global or through a parameter
- */
- bool parameterEscapes(Type tthis, Parameter p)
- {
- /* Scope parameters do not escape.
- * Allow 'lazy' to imply 'scope' -
- * lazy parameters can be passed along
- * as lazy parameters to the next function, but that isn't
- * escaping.
- */
- if (parameterStorageClass(tthis, p) & (STC.scope_ | STC.lazy_))
- return false;
- return true;
- }
-
/************************************
* Take the specified storage class for p,
* and use the function signature to infer whether
@@ -4409,7 +4387,7 @@ extern (C++) final class TypeFunction : TypeNext
/* If haven't inferred the return type yet, can't infer storage classes
*/
- if (!nextOf())
+ if (!nextOf() || !isnothrow())
return stc;
purityLevel();
@@ -4460,37 +4438,12 @@ extern (C++) final class TypeFunction : TypeNext
}
}
- /* Inferring STC.return_ here has false positives
- * for pure functions, producing spurious error messages
- * about escaping references.
- * Give up on it for now.
- */
- version (none)
- {
- stc |= STC.scope_;
-
- Type tret = nextOf().toBasetype();
- if (isref || tret.hasPointers())
- {
- /* The result has references, so p could be escaping
- * that way.
- */
- stc |= STC.return_;
- }
- }
+ // Check escaping through return value
+ Type tret = nextOf().toBasetype();
+ if (isref || tret.hasPointers())
+ return stc | STC.scope_ | STC.return_ | STC.returnScope;
else
- {
- // Check escaping through return value
- Type tret = nextOf().toBasetype();
- if (isref || tret.hasPointers() || !isnothrow())
- {
- return stc;
- }
-
- stc |= STC.scope_;
- }
-
- return stc;
+ return stc | STC.scope_;
}
override Type addStorageClass(StorageClass stc)
@@ -4684,6 +4637,16 @@ extern (C++) final class TypeFunction : TypeNext
match = MATCH.convert; // match ... with a "conversion" match level
}
+ // https://issues.dlang.org/show_bug.cgi?id=22997
+ if (parameterList.varargs == VarArg.none && nparams > nargs && !parameterList[nargs].defaultArg)
+ {
+ OutBuffer buf;
+ buf.printf("too few arguments, expected `%d`, got `%d`", cast(int)nparams, cast(int)nargs);
+ if (pMessage)
+ *pMessage = buf.extractChars();
+ goto Nomatch;
+ }
+
foreach (u, p; parameterList)
{
if (u == nargs)
@@ -4780,14 +4743,40 @@ extern (C++) final class TypeFunction : TypeNext
m = MATCH.exact;
else
{
- m = MATCH.nomatch;
if (pMessage)
{
+ /* https://issues.dlang.org/show_bug.cgi?id=22202
+ *
+ * If a function was deduced by semantic on the CallExp,
+ * it means that resolveFuncCall completed succesfully.
+ * Therefore, there exists a callable copy constructor,
+ * however, it cannot be called because scope constraints
+ * such as purity, safety or nogc.
+ */
OutBuffer buf;
- buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
- argStruct.toChars(), targ.toChars(), tprm.toChars());
+ auto callExp = e.isCallExp();
+ if (auto f = callExp.f)
+ {
+ char[] s;
+ if (!f.isPure && sc.func.setImpure())
+ s ~= "pure ";
+ if (!f.isSafe() && !f.isTrusted() && sc.func.setUnsafe())
+ s ~= "@safe ";
+ if (!f.isNogc && sc.func.setGC())
+ s ~= "nogc ";
+ s[$-1] = '\0';
+ buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr);
+
+ }
+ else
+ {
+ buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
+ argStruct.toChars(), targ.toChars(), tprm.toChars());
+ }
+
*pMessage = buf.extractChars();
}
+ m = MATCH.nomatch;
goto Nomatch;
}
}
@@ -5086,41 +5075,21 @@ extern (C++) final class TypeFunction : TypeNext
return false;
}
- // Generate getter / setter functions for `FunctionFlag` members so they can be
- // treated like regular `bool` fields, instead of requiring bit twiddling to read/write
- extern (D) mixin(() {
- string result = "extern(C++) pure nothrow @safe @nogc {";
- foreach (string mem; __traits(allMembers, FunctionFlag))
- {
- result ~= "
- /// set or get if the function has the FunctionFlag attribute of the same name
- bool "~mem~"() const { return (funcFlags & FunctionFlag."~mem~") != 0; }
- /// ditto
- void "~mem~"(bool v)
- {
- if (v) funcFlags |= FunctionFlag."~mem~";
- else funcFlags &= ~FunctionFlag."~mem~";
- }";
- }
- return result ~ "}\n";
- }());
/// Returns: `true` the function is `isInOutQual` or `isInOutParam` ,`false` otherwise.
bool iswild() const pure nothrow @safe @nogc
{
- return (funcFlags & (FunctionFlag.isInOutParam | FunctionFlag.isInOutQual)) != 0;
+ return isInOutParam || isInOutQual;
}
/// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other`
bool attributesEqual(const scope TypeFunction other) const pure nothrow @safe @nogc
{
- enum attributes = FunctionFlag.isnothrow
- | FunctionFlag.isnogc
- | FunctionFlag.islive;
-
return this.trust == other.trust &&
this.purity == other.purity &&
- (this.funcFlags & attributes) == (other.funcFlags & attributes);
+ this.isnothrow == other.isnothrow &&
+ this.isnogc == other.isnogc &&
+ this.islive == other.islive;
}
override void accept(Visitor v)
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index 07c574d42b7..6ba47dfa34e 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -109,6 +109,7 @@ enum class TY : uint8_t
*/
enum MODFlags
{
+ MODnone = 0, // default (mutable)
MODconst = 1, // type is const
MODimmutable = 4, // type is immutable
MODshared = 2, // type is shared
@@ -595,8 +596,8 @@ public:
// .next is the return type
ParameterList parameterList; // function parameters
+ uint16_t bitFields;
LINK linkage; // calling convention
- unsigned funcFlags;
TRUST trust; // level of trust
PURE purity; // PURExxxx
char inuse;
@@ -608,7 +609,6 @@ public:
void purityLevel();
bool hasLazyParameters();
bool isDstyleVariadic() const;
- bool parameterEscapes(Parameter *p);
StorageClass parameterStorageClass(Parameter *p);
Type *addStorageClass(StorageClass stc);
diff --git a/gcc/d/dmd/mustuse.d b/gcc/d/dmd/mustuse.d
new file mode 100644
index 00000000000..4eb422805db
--- /dev/null
+++ b/gcc/d/dmd/mustuse.d
@@ -0,0 +1,244 @@
+/**
+ * Compile-time checks associated with the @mustuse attribute.
+ *
+ * Copyright: Copyright (C) 2022 by The D Language Foundation, All Rights Reserved
+ * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/mustuse.d, _mustuse.d)
+ * Documentation: https://dlang.org/phobos/dmd_mustuse.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/mustuse.d
+ */
+
+module dmd.mustuse;
+
+import dmd.dscope;
+import dmd.dsymbol;
+import dmd.expression;
+import dmd.globals;
+import dmd.identifier;
+
+// Used in isIncrementOrDecrement
+private static const StringExp plusPlus, minusMinus;
+
+// Loc.initial cannot be used in static initializers, so
+// these need a static constructor.
+static this()
+{
+ plusPlus = new StringExp(Loc.initial, "++");
+ minusMinus = new StringExp(Loc.initial, "--");
+}
+
+/**
+ * Check whether discarding an expression would violate the requirements of
+ * @mustuse. If so, emit an error.
+ *
+ * Params:
+ * e = the expression to check
+ * sc = scope in which `e` was semantically analyzed
+ *
+ * Returns: true on error, false on success.
+ */
+bool checkMustUse(Expression e, Scope* sc)
+{
+ import dmd.id : Id;
+
+ assert(e.type);
+ if (auto sym = e.type.toDsymbol(sc))
+ {
+ auto sd = sym.isStructDeclaration();
+ // isStructDeclaration returns non-null for both structs and unions
+ if (sd && hasMustUseAttribute(sd, sc) && !isAssignment(e) && !isIncrementOrDecrement(e))
+ {
+ e.error("ignored value of `@%s` type `%s`; prepend a `cast(void)` if intentional",
+ Id.udaMustUse.toChars(), e.type.toPrettyChars(true));
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Called from a symbol's semantic to check for reserved usage of @mustuse.
+ *
+ * If such usage is found, emits an errror.
+ *
+ * Params:
+ * sym = symbol to check
+ */
+void checkMustUseReserved(Dsymbol sym)
+{
+ import dmd.attrib : foreachUdaNoSemantic;
+ import dmd.errors : error;
+ import dmd.id : Id;
+
+ // Can't use foreachUda (and by extension hasMustUseAttribute) while
+ // semantic analysis of `sym` is still in progress
+ foreachUdaNoSemantic(sym, (exp) {
+ if (isMustUseAttribute(exp))
+ {
+ if (sym.isFuncDeclaration())
+ {
+ error(sym.loc, "`@%s` on functions is reserved for future use",
+ Id.udaMustUse.toChars());
+ sym.errors = true;
+ }
+ else if (sym.isClassDeclaration() || sym.isEnumDeclaration())
+ {
+ error(sym.loc, "`@%s` on `%s` types is reserved for future use",
+ Id.udaMustUse.toChars(), sym.kind());
+ sym.errors = true;
+ }
+ }
+ return 0; // continue
+ });
+}
+
+/**
+ * Returns: true if the given expression is an assignment, either simple (a = b)
+ * or compound (a += b, etc).
+ */
+private bool isAssignment(Expression e)
+{
+ if (e.isAssignExp || e.isBinAssignExp)
+ return true;
+ if (auto ce = e.isCallExp())
+ {
+ if (auto fd = ce.f)
+ {
+ auto id = fd.ident;
+ if (id && isAssignmentOpId(id))
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * Returns: true if id is the identifier of an assignment operator overload.
+ */
+private bool isAssignmentOpId(Identifier id)
+{
+ import dmd.id : Id;
+
+ return id == Id.assign
+ || id == Id.addass
+ || id == Id.subass
+ || id == Id.mulass
+ || id == Id.divass
+ || id == Id.modass
+ || id == Id.andass
+ || id == Id.orass
+ || id == Id.xorass
+ || id == Id.shlass
+ || id == Id.shrass
+ || id == Id.ushrass
+ || id == Id.catass
+ || id == Id.indexass
+ || id == Id.slice
+ || id == Id.sliceass
+ || id == Id.opOpAssign
+ || id == Id.opIndexOpAssign
+ || id == Id.opSliceOpAssign
+ || id == Id.powass;
+}
+
+/**
+ * Returns: true if the given expression is an increment (++) or decrement (--).
+ */
+private bool isIncrementOrDecrement(Expression e)
+{
+ import dmd.dtemplate : isExpression;
+ import dmd.globals : Loc;
+ import dmd.id : Id;
+ import dmd.tokens : EXP;
+
+ if (e.op == EXP.plusPlus
+ || e.op == EXP.minusMinus
+ || e.op == EXP.prePlusPlus
+ || e.op == EXP.preMinusMinus)
+ return true;
+ if (auto call = e.isCallExp())
+ {
+ // Check for overloaded preincrement
+ // e.g., a.opUnary!"++"
+ if (auto fd = call.f)
+ {
+ if (fd.ident == Id.opUnary && fd.parent)
+ {
+ if (auto ti = fd.parent.isTemplateInstance())
+ {
+ auto tiargs = ti.tiargs;
+ if (tiargs && tiargs.length >= 1)
+ {
+ if (auto argExp = (*tiargs)[0].isExpression())
+ {
+ auto op = argExp.isStringExp();
+ if (op && (op.compare(plusPlus) == 0 || op.compare(minusMinus) == 0))
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+ else if (auto comma = e.isCommaExp())
+ {
+ // Check for overloaded postincrement
+ // e.g., (auto tmp = a, ++a, tmp)
+ if (comma.e1)
+ {
+ if (auto left = comma.e1.isCommaExp())
+ {
+ if (auto middle = left.e2)
+ {
+ if (middle && isIncrementOrDecrement(middle))
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+/**
+ * Returns: true if the given symbol has the @mustuse attribute.
+ */
+private bool hasMustUseAttribute(Dsymbol sym, Scope* sc)
+{
+ import dmd.attrib : foreachUda;
+
+ bool result = false;
+
+ foreachUda(sym, sc, (Expression uda) {
+ if (isMustUseAttribute(uda))
+ {
+ result = true;
+ return 1; // break
+ }
+ return 0; // continue
+ });
+
+ return result;
+}
+
+/**
+ * Returns: true if the given expression is core.attribute.mustuse.
+ */
+private bool isMustUseAttribute(Expression e)
+{
+ import dmd.attrib : isCoreUda;
+ import dmd.id : Id;
+
+ // Logic based on dmd.objc.Supported.declaredAsOptionalCount
+ auto typeExp = e.isTypeExp;
+ if (!typeExp)
+ return false;
+
+ auto typeEnum = typeExp.type.isTypeEnum();
+ if (!typeEnum)
+ return false;
+
+ if (isCoreUda(typeEnum.sym, Id.udaMustUse))
+ return true;
+
+ return false;
+}
diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d
index dbd761fed2f..4f6903cbab7 100644
--- a/gcc/d/dmd/opover.d
+++ b/gcc/d/dmd/opover.d
@@ -213,7 +213,7 @@ private Expression checkAliasThisForLhs(AggregateDeclaration ad, Scope* sc, BinE
*/
if (isRecursiveAliasThis(e.att1, e.e1.type))
return null;
- //printf("att %s e1 = %s\n", Token::toChars(e.op), e.e1.type.toChars());
+ //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
BinExp be = cast(BinExp)e.copy();
// Resolve 'alias this' but in case of assigment don't resolve properties yet
// because 'e1 = e2' could mean 'e1(e2)' or 'e1() = e2'
@@ -241,7 +241,7 @@ private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinE
*/
if (isRecursiveAliasThis(e.att2, e.e2.type))
return null;
- //printf("att %s e2 = %s\n", Token::toChars(e.op), e.e2.type.toChars());
+ //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
BinExp be = cast(BinExp)e.copy();
be.e2 = resolveAliasThis(sc, e.e2, true);
if (!be.e2)
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index 3745a15da42..3cc36b49e01 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -271,7 +271,7 @@ package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type)
*/
Expression Expression_optimize(Expression e, int result, bool keepLvalue)
{
- //printf("Expression_optimize() %s\n", e.toChars());
+ //printf("Expression_optimize() e: %s result: %d keepLvalue %d\n", e.toChars(), result, keepLvalue);
Expression ret = e;
void error()
@@ -426,7 +426,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
void visitAddr(AddrExp e)
{
- //printf("AddrExp::optimize(result = %d) %s\n", result, e.toChars());
+ //printf("AddrExp::optimize(result = %d, keepLvalue = %d) %s\n", result, keepLvalue, e.toChars());
/* Rewrite &(a,b) as (a,&b)
*/
if (auto ce = e.e1.isCommaExp())
@@ -438,7 +438,8 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
}
// Keep lvalue-ness
if (expOptimize(e.e1, result, true))
- return;
+ return; // error return
+
// Convert &*ex to ex
if (auto pe = e.e1.isPtrExp())
{
@@ -515,6 +516,23 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
}
}
}
+ else if (auto ei = e.isIndexExp())
+ {
+ if (auto ve = ei.e1.isVarExp())
+ {
+ if (!ve.var.isReference() &&
+ !ve.var.isImportedSymbol() &&
+ ve.var.isDataseg() &&
+ ve.var.isCsymbol())
+ {
+ if (auto ie = ei.e2.isIntegerExp())
+ {
+ var = ve.var.isVarDeclaration();
+ offset += ie.toInteger() * ve.type.toBasetype().nextOf().size();
+ }
+ }
+ }
+ }
return false;
}
@@ -538,7 +556,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
return;
}
}
- if (auto ae = e.e1.isIndexExp())
+ else if (auto ae = e.e1.isIndexExp())
{
// Convert &array[n] to &array+n
if (ae.e2.isIntegerExp() && ae.e1.isVarExp())
@@ -551,9 +569,10 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
sinteger_t dim = ts.dim.toInteger();
if (index < 0 || index >= dim)
{
- /* 0 for C static arrays means size is unknown, no need to check
+ /* 0 for C static arrays means size is unknown, no need to check,
+ * and address one past the end is OK, too
*/
- if (!(dim == 0 && ve.var.isCsymbol()))
+ if (!((dim == 0 || dim == index) && ve.var.isCsymbol()))
{
e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
return error();
@@ -574,7 +593,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
return;
}
}
- // Convert &((a.b)[n]) to (&a.b)+n
+ // Convert &((a.b)[index]) to (&a.b)+index*elementsize
else if (ae.e2.isIntegerExp() && ae.e1.isDotVarExp())
{
sinteger_t index = ae.e2.toInteger();
@@ -585,18 +604,28 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
sinteger_t dim = ts.dim.toInteger();
if (index < 0 || index >= dim)
{
- /* 0 for C static arrays means size is unknown, no need to check
+ /* 0 for C static arrays means size is unknown, no need to check,
+ * and address one past the end is OK, too
*/
- if (!(dim == 0 && ve.var.isCsymbol()))
+ if (!((dim == 0 || dim == index) && ve.var.isCsymbol()))
{
e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
return error();
}
}
+ import core.checkedint : mulu;
+ bool overflow;
+ const offset = mulu(index, ts.nextOf().size(e.loc), overflow); // index*elementsize
+ if (overflow)
+ {
+ e.error("array offset overflow");
+ return error();
+ }
+
auto pe = new AddrExp(e.loc, ve);
pe.type = e.type;
- ret = new AddExp(e.loc, pe, ae.e2);
+ ret = new AddExp(e.loc, pe, new IntegerExp(e.loc, offset, Type.tsize_t));
ret.type = e.type;
return;
}
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 7b1b63cba82..4b9c0f2119f 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -987,23 +987,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
nextToken();
if (token.value == TOK.assign)
{
- nextToken();
- if (token.value == TOK.identifier)
- s = new AST.DebugSymbol(token.loc, token.ident);
- else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
- s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue);
- else
- {
- error("identifier or integer expected, not `%s`", token.toChars());
- s = null;
- }
- nextToken();
- if (token.value != TOK.semicolon)
- error("semicolon expected");
- nextToken();
+ s = parseDebugSpecification();
break;
}
-
condition = parseDebugCondition();
goto Lcondition;
@@ -1012,20 +998,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
nextToken();
if (token.value == TOK.assign)
{
- nextToken();
- if (token.value == TOK.identifier)
- s = new AST.VersionSymbol(token.loc, token.ident);
- else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
- s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue);
- else
- {
- error("identifier or integer expected, not `%s`", token.toChars());
- s = null;
- }
- nextToken();
- if (token.value != TOK.semicolon)
- error("semicolon expected");
- nextToken();
+ s = parseVersionSpecification();
break;
}
condition = parseVersionCondition();
@@ -2197,6 +2170,26 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
return qualified;
}
+ private AST.DebugSymbol parseDebugSpecification()
+ {
+ AST.DebugSymbol s;
+ nextToken();
+ if (token.value == TOK.identifier)
+ s = new AST.DebugSymbol(token.loc, token.ident);
+ else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
+ s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue);
+ else
+ {
+ error("identifier or integer expected, not `%s`", token.toChars());
+ s = null;
+ }
+ nextToken();
+ if (token.value != TOK.semicolon)
+ error("semicolon expected");
+ nextToken();
+ return s;
+ }
+
/**************************************
* Parse a debug conditional
*/
@@ -2224,6 +2217,29 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
/**************************************
+ * Parse a version specification
+ */
+ private AST.VersionSymbol parseVersionSpecification()
+ {
+ AST.VersionSymbol s;
+ nextToken();
+ if (token.value == TOK.identifier)
+ s = new AST.VersionSymbol(token.loc, token.ident);
+ else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
+ s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue);
+ else
+ {
+ error("identifier or integer expected, not `%s`", token.toChars());
+ s = null;
+ }
+ nextToken();
+ if (token.value != TOK.semicolon)
+ error("semicolon expected");
+ nextToken();
+ return s;
+ }
+
+ /**************************************
* Parse a version conditional
*/
private AST.Condition parseVersionCondition()
@@ -6053,10 +6069,14 @@ LagainStc:
nextToken();
if (token.value == TOK.assign)
{
- error("debug conditions can only be declared at module scope");
- nextToken();
- nextToken();
- goto Lerror;
+ if (auto ds = parseDebugSpecification())
+ {
+ if (ds.ident)
+ ds.error("declaration must be at module level");
+ else
+ ds.error("level declaration must be at module level");
+ }
+ break;
}
cond = parseDebugCondition();
goto Lcondition;
@@ -6065,10 +6085,14 @@ LagainStc:
nextToken();
if (token.value == TOK.assign)
{
- error("version conditions can only be declared at module scope");
- nextToken();
- nextToken();
- goto Lerror;
+ if (auto vs = parseVersionSpecification())
+ {
+ if (vs.ident)
+ vs.error("declaration must be at module level");
+ else
+ vs.error("level declaration must be at module level");
+ }
+ break;
}
cond = parseVersionCondition();
goto Lcondition;
diff --git a/gcc/d/dmd/root/aav.d b/gcc/d/dmd/root/aav.d
index ba5d3312d8a..beceb0f0707 100644
--- a/gcc/d/dmd/root/aav.d
+++ b/gcc/d/dmd/root/aav.d
@@ -14,6 +14,8 @@ module dmd.root.aav;
import core.stdc.string;
import dmd.root.rmem;
+nothrow:
+
private size_t hash(size_t a) pure nothrow @nogc @safe
{
a ^= (a >> 20) ^ (a >> 12);
diff --git a/gcc/d/dmd/root/array.d b/gcc/d/dmd/root/array.d
index cd2d7096d3d..c2eb3e15c2c 100644
--- a/gcc/d/dmd/root/array.d
+++ b/gcc/d/dmd/root/array.d
@@ -137,7 +137,7 @@ public:
void reserve(size_t nentries) pure nothrow
{
- //printf("Array::reserve: length = %d, data.length = %d, nentries = %d\n", (int)length, (int)data.length, (int)nentries);
+ //printf("Array::reserve: length = %d, data.length = %d, nentries = %d\n", cast(int)length, cast(int)data.length, cast(int)nentries);
// Cold path
void enlarge(size_t nentries)
diff --git a/gcc/d/dmd/root/complex.d b/gcc/d/dmd/root/complex.d
index d9a396d9677..a7a74381ef9 100644
--- a/gcc/d/dmd/root/complex.d
+++ b/gcc/d/dmd/root/complex.d
@@ -13,11 +13,15 @@ module dmd.root.complex;
import dmd.root.ctfloat;
+nothrow:
+
extern (C++) struct complex_t
{
real_t re;
real_t im;
+ nothrow:
+
this() @disable;
this(real_t re)
diff --git a/gcc/d/dmd/root/file.d b/gcc/d/dmd/root/file.d
index a01cfdc2aac..b40413c9ef1 100644
--- a/gcc/d/dmd/root/file.d
+++ b/gcc/d/dmd/root/file.d
@@ -26,11 +26,15 @@ import dmd.root.string;
import dmd.common.file;
import dmd.common.string;
-/// Owns a (rmem-managed) file buffer.
-struct FileBuffer
+nothrow:
+
+/// Owns a (rmem-managed) buffer.
+struct Buffer
{
ubyte[] data;
+ nothrow:
+
this(this) @disable;
~this() pure nothrow
@@ -54,7 +58,7 @@ struct File
static struct ReadResult
{
bool success;
- FileBuffer buffer;
+ Buffer buffer;
/// Transfers ownership of the buffer to the caller.
ubyte[] extractSlice() pure nothrow @nogc @safe
diff --git a/gcc/d/dmd/root/longdouble.d b/gcc/d/dmd/root/longdouble.d
index 27fcf9c849f..d6753aa8490 100644
--- a/gcc/d/dmd/root/longdouble.d
+++ b/gcc/d/dmd/root/longdouble.d
@@ -29,6 +29,8 @@ nothrow:
// Type used by the front-end for compile-time reals
struct longdouble
{
+nothrow:
+@nogc:
extern (D) this(T)(T r)
{
this.set(cast(SetType!T)r);
diff --git a/gcc/d/dmd/root/optional.d b/gcc/d/dmd/root/optional.d
index f2f7389efd2..266846bcb0b 100644
--- a/gcc/d/dmd/root/optional.d
+++ b/gcc/d/dmd/root/optional.d
@@ -10,6 +10,8 @@
*/
module dmd.root.optional;
+nothrow:
+
///
unittest
{
@@ -45,6 +47,8 @@ extern (C++) struct Optional(T)
/// whether `value` is set
private bool present;
+ nothrow:
+
/// Creates an `Optional` with the given value
this(T value)
{
diff --git a/gcc/d/dmd/root/port.h b/gcc/d/dmd/root/port.h
index 069a365addf..66a67605b5c 100644
--- a/gcc/d/dmd/root/port.h
+++ b/gcc/d/dmd/root/port.h
@@ -13,12 +13,13 @@
// The idea is to minimize #ifdef's in the app code.
#include "dsystem.h"
+#include "dcompat.h"
typedef unsigned char utf8_t;
struct Port
{
- static int memicmp(const char *s1, const char *s2, size_t n);
+ static int memicmp(const char *s1, const char *s2, d_size_t n);
static char *strupr(char *s);
static bool isFloat32LiteralOutOfRange(const char *s);
@@ -30,5 +31,5 @@ struct Port
static unsigned readlongBE(const void *buffer);
static unsigned readwordLE(const void *buffer);
static unsigned readwordBE(const void *buffer);
- static void valcpy(void *dst, uint64_t val, size_t size);
+ static void valcpy(void *dst, uint64_t val, d_size_t size);
};
diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d
index b9029a16ef8..cd65920e38b 100644
--- a/gcc/d/dmd/semantic2.d
+++ b/gcc/d/dmd/semantic2.d
@@ -478,7 +478,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
i.mod.semantic2(null);
if (i.mod.needmoduleinfo)
{
- //printf("module5 %s because of %s\n", sc.module.toChars(), mod.toChars());
+ //printf("module5 %s because of %s\n", sc._module.toChars(), mod.toChars());
if (sc)
sc._module.needmoduleinfo = 1;
}
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
index ae03b8a4c52..71713249009 100644
--- a/gcc/d/dmd/statement.d
+++ b/gcc/d/dmd/statement.d
@@ -315,6 +315,14 @@ extern (C++) abstract class Statement : ASTNode
override void visit(ImportStatement s)
{
}
+
+ override void visit(CaseStatement s)
+ {
+ }
+
+ override void visit(DefaultStatement s)
+ {
+ }
}
scope HasCode hc = new HasCode();
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index c2967d65d5f..2916bbc38dd 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -51,6 +51,7 @@ import dmd.importc;
import dmd.init;
import dmd.intrange;
import dmd.mtype;
+import dmd.mustuse;
import dmd.nogc;
import dmd.opover;
import dmd.parse;
@@ -211,7 +212,8 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
if (f.checkForwardRef(s.exp.loc))
s.exp = ErrorExp.get();
}
-
+ if (checkMustUse(s.exp, sc))
+ s.exp = ErrorExp.get();
if (!(sc.flags & SCOPE.Cfile) && discardValue(s.exp))
s.exp = ErrorExp.get();
diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d
index 43feab15f22..03e80245a74 100644
--- a/gcc/d/dmd/tokens.d
+++ b/gcc/d/dmd/tokens.d
@@ -591,7 +591,7 @@ shared static this() nothrow
Identifier.initTable();
foreach (kw; keywords)
{
- //printf("keyword[%d] = '%s'\n",kw, tochars[kw].ptr);
+ //printf("keyword[%d] = '%s'\n",kw, Token.tochars[kw].ptr);
Identifier.idPool(Token.tochars[kw].ptr, Token.tochars[kw].length, cast(uint)kw);
}
}
diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d
index 4b15e8c4739..04e1c47d16e 100644
--- a/gcc/d/dmd/traits.d
+++ b/gcc/d/dmd/traits.d
@@ -1278,7 +1278,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
{
s = s.isImport().mod;
}
- //printf("getAttributes %s, attrs = %p, scope = %p\n", s.toChars(), s.userAttribDecl, s.scope);
+ //printf("getAttributes %s, attrs = %p, scope = %p\n", s.toChars(), s.userAttribDecl, s._scope);
udad = s.userAttribDecl;
}
else
@@ -1514,7 +1514,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
TypeFunction tf = toTypeFunction(o, fd);
if (tf)
- link = tf.linkage;
+ {
+ link = fd ? fd.linkage : tf.linkage;
+ }
else
{
auto s = getDsymbol(o);
@@ -1730,69 +1732,33 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
bool err = false;
auto t = isType(o);
- while (t)
+ auto ex = isExpression(o);
+ if (t)
{
- if (auto tm = t.isTypeMixin())
+ Dsymbol s;
+ t.resolve(e.loc, sc2, ex, t, s);
+ if (t)
{
- /* The mixin string could be a type or an expression.
- * Have to try compiling it to see.
- */
- OutBuffer buf;
- if (expressionsToString(buf, sc, tm.exps))
- {
+ t.typeSemantic(e.loc, sc2);
+ if (t.ty == Terror)
err = true;
- break;
- }
- const olderrors = global.errors;
- const len = buf.length;
- buf.writeByte(0);
- const str = buf.extractSlice()[0 .. len];
- scope p = new Parser!ASTCodegen(e.loc, sc._module, str, false);
- p.nextToken();
- //printf("p.loc.linnum = %d\n", p.loc.linnum);
-
- o = p.parseTypeOrAssignExp(TOK.endOfFile);
- if (olderrors != global.errors || p.token.value != TOK.endOfFile)
- {
- err = true;
- break;
- }
- t = o.isType();
}
- else
- break;
+ else if (s && s.errors)
+ err = true;
}
-
- if (!err)
+ if (ex)
{
- auto ex = t ? t.typeToExpression() : isExpression(o);
- if (!ex && t)
- {
- Dsymbol s;
- t.resolve(e.loc, sc2, ex, t, s);
- if (t)
- {
- t.typeSemantic(e.loc, sc2);
- if (t.ty == Terror)
- err = true;
- }
- else if (s && s.errors)
- err = true;
- }
- if (ex)
+ ex = ex.expressionSemantic(sc2);
+ ex = resolvePropertiesOnly(sc2, ex);
+ ex = ex.optimize(WANTvalue);
+ if (sc2.func && sc2.func.type.ty == Tfunction)
{
- ex = ex.expressionSemantic(sc2);
- ex = resolvePropertiesOnly(sc2, ex);
- ex = ex.optimize(WANTvalue);
- if (sc2.func && sc2.func.type.ty == Tfunction)
- {
- const tf = cast(TypeFunction)sc2.func.type;
- err |= tf.isnothrow && canThrow(ex, sc2.func, false);
- }
- ex = checkGC(sc2, ex);
- if (ex.op == EXP.error)
- err = true;
+ const tf = cast(TypeFunction)sc2.func.type;
+ err |= tf.isnothrow && canThrow(ex, sc2.func, false);
}
+ ex = checkGC(sc2, ex);
+ if (ex.op == EXP.error)
+ err = true;
}
// Carefully detach the scope from the parent and throw it away as
diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d
index 615c49fd623..0acad6ae14a 100644
--- a/gcc/d/dmd/transitivevisitor.d
+++ b/gcc/d/dmd/transitivevisitor.d
@@ -17,7 +17,9 @@ import core.stdc.stdio;
extern(C++) class ParseTimeTransitiveVisitor(AST) : PermissiveVisitor!AST
{
alias visit = PermissiveVisitor!AST.visit;
- mixin ParseVisitMethods!AST;
+
+ mixin ParseVisitMethods!AST __methods;
+ alias visit = __methods.visit;
}
/* This mixin implements the AST traversal logic for parse time AST nodes. The same code
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index bcdbec5fe2d..f63b17752ed 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -1220,6 +1220,9 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
tf.islive = true;
tf.linkage = sc.linkage;
+ if (tf.linkage == LINK.system)
+ tf.linkage = target.systemLinkage();
+
version (none)
{
/* If the parent is @safe, then this function defaults to safe
@@ -1840,7 +1843,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
mtype.sym = e.isScopeExp().sds;
break;
case EXP.tuple:
- TupleExp te = e.toTupleExp();
+ TupleExp te = e.isTupleExp();
Objects* elems = new Objects(te.exps.dim);
foreach (i; 0 .. elems.dim)
{
@@ -2281,10 +2284,7 @@ RootObject compileTypeMixin(TypeMixin tm, Loc loc, Scope* sc)
return null;
}
- Type t = o.isType();
- Expression e = t ? t.typeToExpression() : o.isExpression();
-
- return (!e && t) ? t : e;
+ return o;
}
@@ -2306,7 +2306,8 @@ extern (C++) Type merge(Type type)
case Tident:
case Tinstance:
case Tmixin:
- return type;
+ case Ttag:
+ return type; // don't merge placeholder types
case Tsarray:
// prevents generating the mangle if the array dim is not yet known
@@ -3619,12 +3620,31 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
e.error("`%s` is not an expression", e.toChars());
return ErrorExp.get();
}
- else if (checkUnsafeDotExp(sc, e, ident, flag))
+ else if (mt.dim.toUInteger() < 1 && checkUnsafeDotExp(sc, e, ident, flag))
{
+ // .ptr on static array is @safe unless size is 0
+ // https://issues.dlang.org/show_bug.cgi?id=20853
return ErrorExp.get();
}
e = e.castTo(sc, e.type.nextOf().pointerTo());
}
+ else if (ident == Id._tupleof)
+ {
+ if (e.isTypeExp())
+ {
+ e.error("`.tupleof` cannot be used on type `%s`", mt.toChars);
+ return ErrorExp.get();
+ }
+ else
+ {
+ const length = cast(size_t)mt.dim.toUInteger();
+ auto exps = new Expressions();
+ exps.reserve(length);
+ foreach (i; 0 .. length)
+ exps.push(new IndexExp(e.loc, e, new IntegerExp(e.loc, i, Type.tsize_t)));
+ e = new TupleExp(e.loc, exps);
+ }
+ }
else
{
e = visitArray(mt);
@@ -3885,7 +3905,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
assert(e.op != EXP.dot);
// https://issues.dlang.org/show_bug.cgi?id=14010
- if (ident == Id._mangleof)
+ if (!(sc.flags & SCOPE.Cfile) && ident == Id._mangleof)
{
return mt.getProperty(sc, e.loc, ident, flag & 1);
}
@@ -4637,7 +4657,7 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi
{
static if (LOGDEFAULTINIT)
{
- printf("TypeBasic::defaultInit() '%s'\n", mt.toChars());
+ printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt.toChars(), isCfile);
}
dinteger_t value = 0;
@@ -4695,7 +4715,7 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi
{
static if (LOGDEFAULTINIT)
{
- printf("TypeSArray::defaultInit() '%s'\n", mt.toChars());
+ printf("TypeSArray::defaultInit() '%s' isCfile %d\n", mt.toChars(), isCfile);
}
if (mt.next.ty == Tvoid)
return mt.tuns8.defaultInit(loc, isCfile);
diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d
index 67e4d86a43e..7f3fb64842d 100644
--- a/gcc/d/dmd/utils.d
+++ b/gcc/d/dmd/utils.d
@@ -19,6 +19,7 @@ import dmd.root.filename;
import dmd.common.outbuffer;
import dmd.root.string;
+nothrow:
/**
* Normalize path by turning forward slashes into backslashes
@@ -52,13 +53,13 @@ const(char)* toWinPath(const(char)* src)
* loc = The line number information from where the call originates
* filename = Path to file
*/
-FileBuffer readFile(Loc loc, const(char)* filename)
+Buffer readFile(Loc loc, const(char)* filename)
{
return readFile(loc, filename.toDString());
}
/// Ditto
-FileBuffer readFile(Loc loc, const(char)[] filename)
+Buffer readFile(Loc loc, const(char)[] filename)
{
auto result = File.read(filename);
if (!result.success)
@@ -66,7 +67,7 @@ FileBuffer readFile(Loc loc, const(char)[] filename)
error(loc, "error reading file `%.*s`", cast(int)filename.length, filename.ptr);
fatal();
}
- return FileBuffer(result.extractSlice());
+ return Buffer(result.extractSlice());
}
@@ -83,7 +84,7 @@ extern (D) void writeFile(Loc loc, const(char)[] filename, const void[] data)
ensurePathToNameExists(Loc.initial, filename);
if (!File.update(filename, data))
{
- error(loc, "Error writing file '%*.s'", cast(int) filename.length, filename.ptr);
+ error(loc, "Error writing file '%.*s'", cast(int) filename.length, filename.ptr);
fatal();
}
}
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index 61a2b50b149..c683d9da333 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -3006,6 +3006,16 @@ public:
this->result_ = var;
}
+ /* Build an uninitialized value, generated from void initializers. */
+
+ void visit (VoidInitExp *e)
+ {
+ /* The front-end only generates these for the initializer of globals.
+ Represent `void' as zeroes, regardless of the type's default value. */
+ gcc_assert (this->constp_);
+ this->result_ = build_zero_cst (build_ctype (e->type));
+ }
+
/* These expressions are mainly just a placeholders in the frontend.
We shouldn't see them here. */
diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt
index 51e8e5c7e00..b4b81523c14 100644
--- a/gcc/d/lang.opt
+++ b/gcc/d/lang.opt
@@ -396,6 +396,10 @@ frevert=all
D RejectNegative
Turn off all revertable D language features.
+frevert=dip1000
+D RejectNegative
+Revert DIP1000: Scoped pointers.
+
frevert=dip25
D RejectNegative
Revert DIP25: Sealed references.