aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd
diff options
context:
space:
mode:
authorIain Buclaw <ibuclaw@gdcproject.org>2025-01-05 14:40:13 +0100
committerIain Buclaw <ibuclaw@gdcproject.org>2025-01-05 14:40:13 +0100
commitf5351b38a8aff438b41cae0d133fd38d56d8cd1f (patch)
tree6c3ebcd181efe8e57c3e6fe4af8f595996b713ff /gcc/d/dmd
parenta676a516701789730aa482bcef4adcb683ba0140 (diff)
downloadgcc-f5351b38a8aff438b41cae0d133fd38d56d8cd1f.zip
gcc-f5351b38a8aff438b41cae0d133fd38d56d8cd1f.tar.gz
gcc-f5351b38a8aff438b41cae0d133fd38d56d8cd1f.tar.bz2
d: Merge upstream dmd, druntime 66b93fc24a, phobos 0c28620c3
Synchronizing with the upstream release of v2.109.1. D front-end changes: - Import dmd v2.109.1. - Copying from `const(void)[]' to `void[]' is now disallowed with `-fpreview=fiximmutableconv'. - Import expressions are now treated as hex strings. - Using boolean values other than 0 or 1 in `@safe' code is now deprecated. D runtime changes: - Import dmd v2.109.1. Phobos changes: - Import dmd v2.109.1. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd 66b93fc24a. * dmd/VERSION: Bump version to v2.109.1. * d-builtins.cc (build_frontend_type): Update for new front-end interface. (matches_builtin_type): Likewise. * d-codegen.cc (identity_compare_p): Likewise. (call_side_effect_free_p): Likewise. * d-convert.cc (convert_expr): Likewise. (check_valist_conversion): Likewise. * d-lang.cc (d_types_compatible_p): Likewise. * d-target.cc (Target::isVectorTypeSupported): Likewise. (Target::isReturnOnStack): Likewise. (Target::preferPassByRef): Likewise. * decl.cc (class DeclVisitor): Likewise. * expr.cc (class ExprVisitor): Likewise. * typeinfo.cc (class TypeInfoVisitor): Likewise. * types.cc (class TypeVisitor): Likewise. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 66b93fc24a. * src/MERGE: Merge upstream phobos 0c28620c3. * src/Makefile.am (PHOBOS_DSOURCES): Add std/internal/test/sumtype_example_overloads.d. * src/Makefile.in: Regenerate.
Diffstat (limited to 'gcc/d/dmd')
-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.d2
-rw-r--r--gcc/d/dmd/arrayop.d1
-rw-r--r--gcc/d/dmd/chkformat.d1
-rw-r--r--gcc/d/dmd/clone.d10
-rw-r--r--gcc/d/dmd/compiler.d1
-rw-r--r--gcc/d/dmd/cond.d4
-rw-r--r--gcc/d/dmd/constfold.d2
-rw-r--r--gcc/d/dmd/cparse.d60
-rw-r--r--gcc/d/dmd/cppmangle.d2
-rw-r--r--gcc/d/dmd/ctfeexpr.d1
-rw-r--r--gcc/d/dmd/cxxfrontend.d28
-rw-r--r--gcc/d/dmd/dcast.d458
-rw-r--r--gcc/d/dmd/declaration.h2
-rw-r--r--gcc/d/dmd/dimport.d7
-rw-r--r--gcc/d/dmd/dinterpret.d2
-rw-r--r--gcc/d/dmd/doc.d2
-rw-r--r--gcc/d/dmd/dstruct.d4
-rw-r--r--gcc/d/dmd/dsymbolsem.d6
-rw-r--r--gcc/d/dmd/dtemplate.d55
-rw-r--r--gcc/d/dmd/expression.d7
-rw-r--r--gcc/d/dmd/expressionsem.d57
-rw-r--r--gcc/d/dmd/func.d357
-rw-r--r--gcc/d/dmd/funcsem.d361
-rw-r--r--gcc/d/dmd/hdrgen.d16
-rw-r--r--gcc/d/dmd/id.d1
-rw-r--r--gcc/d/dmd/mtype.d626
-rw-r--r--gcc/d/dmd/mtype.h35
-rw-r--r--gcc/d/dmd/objc.d4
-rw-r--r--gcc/d/dmd/optimize.d45
-rw-r--r--gcc/d/dmd/safe.d63
-rw-r--r--gcc/d/dmd/semantic2.d9
-rw-r--r--gcc/d/dmd/sideeffect.d1
-rw-r--r--gcc/d/dmd/statement.d103
-rw-r--r--gcc/d/dmd/statementsem.d2
-rw-r--r--gcc/d/dmd/target.d6
-rw-r--r--gcc/d/dmd/target.h4
-rw-r--r--gcc/d/dmd/typesem.d146
-rw-r--r--gcc/d/dmd/visitor.d5
41 files changed, 1339 insertions, 1163 deletions
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 77e8562..d458bea 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-07bc5b9b3c81cc0d4314e0040de981124b363ea5
+66b93fc24a7ab5e2a8aa7f53c613df4abddc188b
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 baac0d7..0787594 100644
--- a/gcc/d/dmd/README.md
+++ b/gcc/d/dmd/README.md
@@ -251,6 +251,8 @@ Note that these groups have no strict meaning, the category assignments are a bi
| [hdrgen.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/hdrgen.d) | Convert an AST into D source code for `.di` header generation, as well as `-vcg-ast` and error messages |
| [json.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/json.d) | Describe the module in a `.json` file for the `-X` flag |
| [dtoh.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dtoh.d) | C++ header generation from D source files |
+| [disasm86.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/backend/disasm86.d) | x86-64 dissassembly generation
+| [disasmarm.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/backend/arm/disasmarm.d) | AArch64 disassembly generation
### Utility
diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION
index 3d80c3d..ffc1c3e 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@
-v2.109.0
+v2.109.1
diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d
index 2c7622a..78cb87f 100644
--- a/gcc/d/dmd/aggregate.d
+++ b/gcc/d/dmd/aggregate.d
@@ -37,7 +37,7 @@ import dmd.identifier;
import dmd.location;
import dmd.mtype;
import dmd.tokens;
-import dmd.typesem : defaultInit, addMod;
+import dmd.typesem : defaultInit, addMod, size;
import dmd.visitor;
/**
diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d
index d0ec5eb..e30160d 100644
--- a/gcc/d/dmd/arrayop.d
+++ b/gcc/d/dmd/arrayop.d
@@ -16,6 +16,7 @@ module dmd.arrayop;
import core.stdc.stdio;
import dmd.arraytypes;
import dmd.astenums;
+import dmd.dcast : implicitConvTo;
import dmd.declaration;
import dmd.dscope;
import dmd.dsymbol;
diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d
index 5024f9b..bbc7b86 100644
--- a/gcc/d/dmd/chkformat.d
+++ b/gcc/d/dmd/chkformat.d
@@ -21,6 +21,7 @@ import dmd.globals;
import dmd.identifier;
import dmd.location;
import dmd.mtype;
+import dmd.typesem;
import dmd.target;
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index 2e4833e..17b33d8 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -57,7 +57,7 @@ StorageClass mergeFuncAttrs(StorageClass s1, const FuncDeclaration f) pure
return s1;
StorageClass s2 = (f.storage_class & STC.disable);
- TypeFunction tf = cast(TypeFunction)f.type;
+ auto tf = cast(TypeFunction)f.type;
if (tf.trust == TRUST.safe)
s2 |= STC.safe;
else if (tf.trust == TRUST.system)
@@ -177,7 +177,7 @@ private bool needOpAssign(StructDeclaration sd)
Type tv = v.type.baseElemOf();
if (tv.ty == Tstruct)
{
- TypeStruct ts = cast(TypeStruct)tv;
+ auto ts = cast(TypeStruct)tv;
if (ts.sym.isUnionDeclaration())
continue;
if (needOpAssign(ts.sym))
@@ -314,7 +314,7 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
else if (sd.dtor)
{
//printf("\tswap copy\n");
- TypeFunction tdtor = cast(TypeFunction)sd.dtor.type;
+ auto tdtor = cast(TypeFunction)sd.dtor.type;
assert(tdtor.ty == Tfunction);
auto idswap = Identifier.generateId("__swap");
@@ -435,7 +435,7 @@ bool needOpEquals(StructDeclaration sd)
auto tvbase = tv.baseElemOf();
if (tvbase.ty == Tstruct)
{
- TypeStruct ts = cast(TypeStruct)tvbase;
+ auto ts = cast(TypeStruct)tvbase;
if (ts.sym.isUnionDeclaration() && ts.sym.fields.length != 1)
continue;
if (needOpEquals(ts.sym))
@@ -762,7 +762,7 @@ private bool needToHash(StructDeclaration sd)
auto tvbase = tv.baseElemOf();
if (tvbase.ty == Tstruct)
{
- TypeStruct ts = cast(TypeStruct)tvbase;
+ auto ts = cast(TypeStruct)tvbase;
if (ts.sym.isUnionDeclaration())
continue;
if (needToHash(ts.sym))
diff --git a/gcc/d/dmd/compiler.d b/gcc/d/dmd/compiler.d
index 65330cf..3b00194 100644
--- a/gcc/d/dmd/compiler.d
+++ b/gcc/d/dmd/compiler.d
@@ -16,6 +16,7 @@ import dmd.ctfeexpr;
import dmd.dmodule;
import dmd.expression;
import dmd.mtype;
+import dmd.typesem;
import dmd.root.array;
extern (C++) __gshared
diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d
index e194664..02dde1b 100644
--- a/gcc/d/dmd/cond.d
+++ b/gcc/d/dmd/cond.d
@@ -659,9 +659,9 @@ extern (C++) final class VersionCondition : DVCondition
case "AVR":
case "BigEndian":
case "BSD":
- case "CppRuntime_Clang":
+ case "CppRuntime_LLVM":
case "CppRuntime_DigitalMars":
- case "CppRuntime_Gcc":
+ case "CppRuntime_GNU":
case "CppRuntime_Microsoft":
case "CppRuntime_Sun":
case "CRuntime_Bionic":
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
index 6ec31d5..54d50cf 100644
--- a/gcc/d/dmd/constfold.d
+++ b/gcc/d/dmd/constfold.d
@@ -36,7 +36,7 @@ import dmd.root.utf;
import dmd.sideeffect;
import dmd.target;
import dmd.tokens;
-import dmd.typesem : toDsymbol, equivalent, sarrayOf;
+import dmd.typesem : toDsymbol, equivalent, sarrayOf, size;
private enum LOG = false;
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index 7fbcd6d..a4e3c7e 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -27,6 +27,7 @@ import dmd.root.array;
import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.tokens;
+import dmd.typesem : size;
/***********************************************************
*/
@@ -1872,22 +1873,30 @@ final class CParser(AST) : Parser!AST
* init-declarator:
* declarator simple-asm-expr (opt) gnu-attributes (opt)
* declarator simple-asm-expr (opt) gnu-attributes (opt) = initializer
+ *
+ * Clang also allows simple-asm-expr after gnu-attributes.
*/
+ while (1)
+ {
+ if (token.value == TOK.asm_)
+ {
+ asmName = cparseGnuAsmLabel();
+ /* This is a data definition, there cannot now be a
+ * function definition.
+ */
+ first = false;
+ }
+ else if (token.value == TOK.__attribute__)
+ cparseGnuAttributes(specifier);
+ else
+ break;
+ }
+
switch (token.value)
{
case TOK.assign:
case TOK.comma:
case TOK.semicolon:
- case TOK.asm_:
- case TOK.__attribute__:
- if (token.value == TOK.asm_)
- asmName = cparseGnuAsmLabel();
- if (token.value == TOK.__attribute__)
- {
- cparseGnuAttributes(specifier);
- if (token.value == TOK.leftCurly)
- break; // function definition
- }
/* This is a data definition, there cannot now be a
* function definition.
*/
@@ -3626,6 +3635,12 @@ final class CParser(AST) : Parser!AST
* type on the target machine. It's the opposite of __attribute__((packed))
*/
}
+ else if (token.ident == Id.packed)
+ {
+ specifier.packalign.set(1);
+ specifier.packalign.setPack(true);
+ nextToken();
+ }
else if (token.ident == Id.always_inline) // https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
{
specifier.scw |= SCW.xinline;
@@ -3974,7 +3989,7 @@ final class CParser(AST) : Parser!AST
members = new AST.Dsymbols(); // so `members` will be non-null even with 0 members
while (token.value != TOK.rightCurly)
{
- cparseStructDeclaration(members);
+ cparseStructDeclaration(members, packalign);
if (token.value == TOK.endOfFile)
break;
@@ -3988,6 +4003,24 @@ final class CParser(AST) : Parser!AST
* struct-declarator (opt)
*/
}
+
+ /* GNU Extensions
+ * Parse the postfix gnu-attributes (opt)
+ */
+ Specifier specifier;
+ if (token.value == TOK.__attribute__)
+ cparseGnuAttributes(specifier);
+ if (!specifier.packalign.isUnknown)
+ {
+ packalign.set(specifier.packalign.get());
+ packalign.setPack(specifier.packalign.isPack());
+ foreach (ref d; (*members)[])
+ {
+ auto decls = new AST.Dsymbols(1);
+ (*decls)[0] = d;
+ d = new AST.AlignDeclaration(d.loc, specifier.packalign, decls);
+ }
+ }
}
else if (!tag)
error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion));
@@ -4019,8 +4052,9 @@ final class CParser(AST) : Parser!AST
* declarator (opt) : constant-expression
* Params:
* members = where to put the fields (members)
+ * packalign = alignment to use for struct members
*/
- void cparseStructDeclaration(AST.Dsymbols* members)
+ void cparseStructDeclaration(AST.Dsymbols* members, structalign_t packalign)
{
//printf("cparseStructDeclaration()\n");
if (token.value == TOK._Static_assert)
@@ -4031,7 +4065,7 @@ final class CParser(AST) : Parser!AST
}
Specifier specifier;
- specifier.packalign = this.packalign;
+ specifier.packalign = packalign.isUnknown ? this.packalign : packalign;
auto tspec = cparseSpecifierQualifierList(LVL.member, specifier);
if (!tspec)
{
diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d
index 334088b..0609778 100644
--- a/gcc/d/dmd/cppmangle.d
+++ b/gcc/d/dmd/cppmangle.d
@@ -2197,7 +2197,7 @@ private extern(C++) final class ComponentVisitor : Visitor
/// Set to the result of the comparison
private bool result;
- public this(RootObject base) @safe
+ public this(RootObject base) @trusted
{
switch (base.dyncast())
{
diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d
index d2fcf5f..8ed70c6 100644
--- a/gcc/d/dmd/ctfeexpr.d
+++ b/gcc/d/dmd/ctfeexpr.d
@@ -17,6 +17,7 @@ import dmd.arraytypes;
import dmd.astenums;
import dmd.constfold;
import dmd.compiler;
+import dmd.dcast : implicitConvTo;
import dmd.dclass;
import dmd.declaration;
import dmd.dinterpret;
diff --git a/gcc/d/dmd/cxxfrontend.d b/gcc/d/dmd/cxxfrontend.d
index 403588b..0b3096d 100644
--- a/gcc/d/dmd/cxxfrontend.d
+++ b/gcc/d/dmd/cxxfrontend.d
@@ -265,10 +265,16 @@ bool functionSemantic3(FuncDeclaration fd)
return dmd.funcsem.functionSemantic3(fd);
}
-MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* names)
+MATCH leastAsSpecialized(FuncDeclaration fd, FuncDeclaration g, Identifiers* names)
{
import dmd.funcsem;
- return dmd.funcsem.leastAsSpecialized(f, g, names);
+ return dmd.funcsem.leastAsSpecialized(fd, g, names);
+}
+
+PURE isPure(FuncDeclaration fd)
+{
+ import dmd.funcsem;
+ return dmd.funcsem.isPure(fd);
}
/***********************************************************
@@ -627,6 +633,24 @@ Type referenceTo(Type type)
return dmd.typesem.referenceTo(type);
}
+uinteger_t size(Type type)
+{
+ import dmd.typesem;
+ return dmd.typesem.size(type);
+}
+
+uinteger_t size(Type type, const ref Loc loc)
+{
+ import dmd.typesem;
+ return dmd.typesem.size(type, loc);
+}
+
+MATCH implicitConvTo(Type from, Type to)
+{
+ import dmd.dcast;
+ return dmd.dcast.implicitConvTo(from, to);
+}
+
/***********************************************************
* typinf.d
*/
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index 78781f4..2905967 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -20,6 +20,7 @@ import dmd.arraytypes;
import dmd.astenums;
import dmd.dclass;
import dmd.declaration;
+import dmd.denum;
import dmd.dinterpret;
import dmd.dscope;
import dmd.dstruct;
@@ -1468,6 +1469,463 @@ MATCH implicitConvTo(Expression e, Type t)
}
}
+/********************************
+ * Determine if 'from' can be implicitly converted
+ * to type 'to'.
+ * Returns:
+ * MATCH.nomatch, MATCH.convert, MATCH.constant, MATCH.exact
+ */
+MATCH implicitConvTo(Type from, Type to)
+{
+ MATCH visitType(Type from)
+ {
+ //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
+ //printf("from: %s\n", from.toChars());
+ //printf("to : %s\n", to.toChars());
+ if (from.equals(to))
+ return MATCH.exact;
+ return MATCH.nomatch;
+
+ }
+
+ MATCH visitBasic(TypeBasic from)
+ {
+ //printf("TypeBasic::implicitConvTo(%s) from %s\n", to.toChars(), from.toChars());
+ if (from == to)
+ return MATCH.exact;
+
+ if (from.ty == to.ty)
+ {
+ if (from.mod == to.mod)
+ return MATCH.exact;
+ else if (MODimplicitConv(from.mod, to.mod))
+ return MATCH.constant;
+ else if (!((from.mod ^ to.mod) & MODFlags.shared_)) // for wild matching
+ return MATCH.constant;
+ else
+ return MATCH.convert;
+ }
+
+ if (from.ty == Tvoid || to.ty == Tvoid)
+ return MATCH.nomatch;
+ if (to.ty == Tbool)
+ return MATCH.nomatch;
+
+ TypeBasic tob;
+ if (to.ty == Tvector && to.deco)
+ {
+ TypeVector tv = cast(TypeVector)to;
+ tob = tv.elementType();
+ }
+ else if (auto te = to.isTypeEnum())
+ {
+ EnumDeclaration ed = te.sym;
+ if (ed.isSpecial())
+ {
+ /* Special enums that allow implicit conversions to them
+ * with a MATCH.convert
+ */
+ tob = to.toBasetype().isTypeBasic();
+ }
+ else
+ return MATCH.nomatch;
+ }
+ else
+ tob = to.isTypeBasic();
+ if (!tob)
+ return MATCH.nomatch;
+
+ if (from.flags & TFlags.integral)
+ {
+ // Disallow implicit conversion of integers to imaginary or complex
+ if (tob.flags & (TFlags.imaginary | TFlags.complex))
+ return MATCH.nomatch;
+
+ // If converting from integral to integral
+ if (tob.flags & TFlags.integral)
+ {
+ const sz = size(from, Loc.initial);
+ const tosz = tob.size(Loc.initial);
+
+ /* Can't convert to smaller size
+ */
+ if (sz > tosz)
+ return MATCH.nomatch;
+ /* Can't change sign if same size
+ */
+ //if (sz == tosz && (flags ^ tob.flags) & TFlags.unsigned)
+ // return MATCH.nomatch;
+ }
+ }
+ else if (from.flags & TFlags.floating)
+ {
+ // Disallow implicit conversion of floating point to integer
+ if (tob.flags & TFlags.integral)
+ return MATCH.nomatch;
+
+ assert(tob.flags & TFlags.floating || to.ty == Tvector);
+
+ // Disallow implicit conversion from complex to non-complex
+ if (from.flags & TFlags.complex && !(tob.flags & TFlags.complex))
+ return MATCH.nomatch;
+
+ // Disallow implicit conversion of real or imaginary to complex
+ if (from.flags & (TFlags.real_ | TFlags.imaginary) && tob.flags & TFlags.complex)
+ return MATCH.nomatch;
+
+ // Disallow implicit conversion to-from real and imaginary
+ if ((from.flags & (TFlags.real_ | TFlags.imaginary)) != (tob.flags & (TFlags.real_ | TFlags.imaginary)))
+ return MATCH.nomatch;
+ }
+ return MATCH.convert;
+
+ }
+
+ MATCH visitVector(TypeVector from)
+ {
+ //printf("TypeVector::implicitConvTo(%s) from %s\n", to.toChars(), from.toChars());
+ if (from == to)
+ return MATCH.exact;
+ if (to.ty != Tvector)
+ return MATCH.nomatch;
+
+ TypeVector tv = cast(TypeVector)to;
+ assert(from.basetype.ty == Tsarray && tv.basetype.ty == Tsarray);
+
+ // Can't convert to a vector which has different size.
+ if (from.basetype.size() != tv.basetype.size())
+ return MATCH.nomatch;
+
+ // Allow conversion to void[]
+ if (tv.basetype.nextOf().ty == Tvoid)
+ return MATCH.convert;
+
+ // Otherwise implicitly convertible only if basetypes are.
+ return from.basetype.implicitConvTo(tv.basetype);
+ }
+
+ MATCH visitSArray(TypeSArray from)
+ {
+ //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), from.toChars());
+ if (auto ta = to.isTypeDArray())
+ {
+ if (!MODimplicitConv(from.next.mod, ta.next.mod))
+ return MATCH.nomatch;
+
+ /* Allow conversion to void[]
+ */
+ if (ta.next.ty == Tvoid)
+ {
+ return MATCH.convert;
+ }
+
+ MATCH m = from.next.constConv(ta.next);
+ if (m > MATCH.nomatch)
+ {
+ return MATCH.convert;
+ }
+ return MATCH.nomatch;
+ }
+ if (auto tsa = to.isTypeSArray())
+ {
+ if (from == to)
+ return MATCH.exact;
+
+ if (from.dim.equals(tsa.dim))
+ {
+ MATCH m = from.next.implicitConvTo(tsa.next);
+
+ /* Allow conversion to non-interface base class.
+ */
+ if (m == MATCH.convert &&
+ from.next.ty == Tclass)
+ {
+ if (auto toc = tsa.next.isTypeClass)
+ {
+ if (!toc.sym.isInterfaceDeclaration)
+ return MATCH.convert;
+ }
+ }
+
+ /* Since static arrays are value types, allow
+ * conversions from const elements to non-const
+ * ones, just like we allow conversion from const int
+ * to int.
+ */
+ if (m >= MATCH.constant)
+ {
+ if (from.mod != to.mod)
+ m = MATCH.constant;
+ return m;
+ }
+ }
+ }
+ return MATCH.nomatch;
+ }
+
+ MATCH visitDArray(TypeDArray from)
+ {
+ //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), from.toChars());
+ if (from.equals(to))
+ return MATCH.exact;
+
+ if (auto ta = to.isTypeDArray())
+ {
+ if (!MODimplicitConv(from.next.mod, ta.next.mod))
+ return MATCH.nomatch; // not const-compatible
+
+ /* Allow conversion to void[]
+ */
+ if (from.next.ty != Tvoid && ta.next.ty == Tvoid)
+ {
+ return MATCH.convert;
+ }
+
+ MATCH m = from.next.constConv(ta.next);
+ if (m > MATCH.nomatch)
+ {
+ if (m == MATCH.exact && from.mod != to.mod)
+ m = MATCH.constant;
+ return m;
+ }
+ }
+
+ return visitType(from);
+ }
+
+ MATCH visitAArray(TypeAArray from)
+ {
+ //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), from.toChars());
+ if (from.equals(to))
+ return MATCH.exact;
+
+ if (auto ta = to.isTypeAArray())
+ {
+ if (!MODimplicitConv(from.next.mod, ta.next.mod))
+ return MATCH.nomatch; // not const-compatible
+
+ if (!MODimplicitConv(from.index.mod, ta.index.mod))
+ return MATCH.nomatch; // not const-compatible
+
+ MATCH m = from.next.constConv(ta.next);
+ MATCH mi = from.index.constConv(ta.index);
+ if (m > MATCH.nomatch && mi > MATCH.nomatch)
+ {
+ return MODimplicitConv(from.mod, to.mod) ? MATCH.constant : MATCH.nomatch;
+ }
+ }
+ return visitType(from);
+ }
+
+ /+
+ + Checks whether this function type is convertible to ` to`
+ + when used in a function pointer / delegate.
+ +
+ + Params:
+ + to = target type
+ +
+ + Returns:
+ + MATCH.nomatch: `to` is not a covaraint function
+ + MATCH.convert: `to` is a covaraint function
+ + MATCH.exact: `to` is identical to this function
+ +/
+ MATCH implicitPointerConv(TypeFunction tf, Type to)
+ {
+ assert(to);
+
+ if (tf.equals(to))
+ return MATCH.constant;
+
+ if (tf.covariant(to) == Covariant.yes)
+ {
+ Type tret = tf.nextOf();
+ Type toret = to.nextOf();
+ if (tret.ty == Tclass && toret.ty == Tclass)
+ {
+ /* https://issues.dlang.org/show_bug.cgi?id=10219
+ * Check covariant interface return with offset tweaking.
+ * interface I {}
+ * class C : Object, I {}
+ * I function() dg = function C() {} // should be error
+ */
+ int offset = 0;
+ if (toret.isBaseOf(tret, &offset) && offset != 0)
+ return MATCH.nomatch;
+ }
+ return MATCH.convert;
+ }
+
+ return MATCH.nomatch;
+ }
+
+ MATCH visitPointer(TypePointer from)
+ {
+ //printf("TypePointer::implicitConvTo(to = %s) %s\n", to.toChars(), from.toChars());
+ if (from.equals(to))
+ return MATCH.exact;
+
+ // Only convert between pointers
+ auto tp = to.isTypePointer();
+ if (!tp)
+ return MATCH.nomatch;
+
+ assert(from.next);
+ assert(tp.next);
+
+ // Conversion to void*
+ if (tp.next.ty == Tvoid)
+ {
+ // Function pointer conversion doesn't check constness?
+ if (from.next.ty == Tfunction)
+ return MATCH.convert;
+
+ if (!MODimplicitConv(from.next.mod, tp.next.mod))
+ return MATCH.nomatch; // not const-compatible
+
+ return from.next.ty == Tvoid ? MATCH.constant : MATCH.convert;
+ }
+
+ // Conversion between function pointers
+ if (auto thisTf = from.next.isTypeFunction())
+ return implicitPointerConv(thisTf, tp.next);
+
+ // Default, no implicit conversion between the pointer targets
+ MATCH m = from.next.constConv(tp.next);
+
+ if (m == MATCH.exact && from.mod != to.mod)
+ m = MATCH.constant;
+ return m;
+ }
+
+ MATCH visitDelegate(TypeDelegate from)
+ {
+ //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", from, to);
+ //printf("from: %s\n", from.toChars());
+ //printf("to : %s\n", to.toChars());
+ if (from.equals(to))
+ return MATCH.exact;
+
+ if (auto toDg = to.isTypeDelegate())
+ {
+ MATCH m = implicitPointerConv(from.next.isTypeFunction(), toDg.next);
+
+ // Retain the old behaviour for this refactoring
+ // Should probably be changed to constant to match function pointers
+ if (m > MATCH.convert)
+ m = MATCH.convert;
+
+ return m;
+ }
+
+ return MATCH.nomatch;
+ }
+
+ MATCH visitStruct(TypeStruct from)
+ {
+ //printf("TypeStruct::implicitConvTo(%s => %s)\n", from.toChars(), to.toChars());
+ MATCH m = from.implicitConvToWithoutAliasThis(to);
+ return m == MATCH.nomatch ? from.implicitConvToThroughAliasThis(to) : m;
+ }
+
+ MATCH visitEnum(TypeEnum from)
+ {
+ import dmd.enumsem : getMemtype;
+
+ MATCH m;
+ //printf("TypeEnum::implicitConvTo() %s to %s\n", from.toChars(), to.toChars());
+ if (from.ty == to.ty && from.sym == (cast(TypeEnum)to).sym)
+ m = (from.mod == to.mod) ? MATCH.exact : MATCH.constant;
+ else if (from.sym.getMemtype(Loc.initial).implicitConvTo(to))
+ m = MATCH.convert; // match with conversions
+ else
+ m = MATCH.nomatch; // no match
+ return m;
+ }
+
+ MATCH visitClass(TypeClass from)
+ {
+ //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to.toChars(), from.toChars());
+ MATCH m = from.implicitConvToWithoutAliasThis(to);
+ return m ? m : from.implicitConvToThroughAliasThis(to);
+ }
+
+ MATCH visitTuple(TypeTuple from)
+ {
+ if (from == to)
+ return MATCH.exact;
+ if (auto tt = to.isTypeTuple())
+ {
+ if (from.arguments.length == tt.arguments.length)
+ {
+ MATCH m = MATCH.exact;
+ for (size_t i = 0; i < tt.arguments.length; i++)
+ {
+ Parameter arg1 = (*from.arguments)[i];
+ Parameter arg2 = (*tt.arguments)[i];
+ MATCH mi = arg1.type.implicitConvTo(arg2.type);
+ if (mi < m)
+ m = mi;
+ }
+ return m;
+ }
+ }
+ return MATCH.nomatch;
+ }
+
+ MATCH visitNull(TypeNull from)
+ {
+ //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", from, to);
+ //printf("from: %s\n", from.toChars());
+ //printf("to : %s\n", to.toChars());
+ MATCH m = visitType(cast(Type)from);
+ if (m != MATCH.nomatch)
+ return m;
+
+ //NULL implicitly converts to any pointer type or dynamic array
+ //if (type.ty == Tpointer && type.nextOf().ty == Tvoid)
+ {
+ Type tb = to.toBasetype();
+ if (tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tclass || tb.ty == Tdelegate)
+ return MATCH.constant;
+ }
+
+ return MATCH.nomatch;
+ }
+
+ MATCH visitNoreturn(TypeNoreturn from)
+ {
+ //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", from, to);
+ //printf("from: %s\n", from.toChars());
+ //printf("to : %s\n", to.toChars());
+ if (from.equals(to))
+ return MATCH.exact;
+
+ // Different qualifiers?
+ if (to.ty == Tnoreturn)
+ return MATCH.constant;
+
+ // Implicitly convertible to any type
+ return MATCH.convert;
+ }
+
+ switch(from.ty)
+ {
+ default: return from.isTypeBasic() ? visitBasic(from.isTypeBasic()) : visitType(from);
+ case Tvector: return visitVector(from.isTypeVector());
+ case Tsarray: return visitSArray(from.isTypeSArray());
+ case Tarray: return visitDArray(from.isTypeDArray());
+ case Taarray: return visitAArray(from.isTypeAArray());
+ case Tpointer: return visitPointer(from.isTypePointer());
+ case Tdelegate: return visitDelegate(from.isTypeDelegate());
+ case Tstruct: return visitStruct(from.isTypeStruct());
+ case Tenum: return visitEnum(from.isTypeEnum());
+ case Tclass: return visitClass(from.isTypeClass());
+ case Ttuple: return visitTuple(from.isTypeTuple());
+ case Tnull: return visitNull(from.isTypeNull());
+ case Tnoreturn: return visitNoreturn(from.isTypeNoreturn());
+ }
+}
+
/**
* Same as implicitConvTo(); except follow C11 rules, which are quite a bit
* more permissive than D.
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index fdfe8a8..8f706fb 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -35,6 +35,7 @@ namespace dmd
bool functionSemantic(FuncDeclaration* fd);
bool functionSemantic3(FuncDeclaration* fd);
MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, Identifiers *names);
+ PURE isPure(FuncDeclaration *f);
}
//enum STC : ulong from astenums.d:
@@ -719,7 +720,6 @@ public:
bool isCodeseg() const override final;
bool isOverloadable() const override final;
bool isAbstract() override final;
- PURE isPure();
bool isSafe();
bool isTrusted();
bool isNogc();
diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d
index 2efdd31..4c4c063 100644
--- a/gcc/d/dmd/dimport.d
+++ b/gcc/d/dmd/dimport.d
@@ -165,11 +165,10 @@ extern (C++) final class Import : Dsymbol
* https://issues.dlang.org/show_bug.cgi?id=5412
*/
assert(ident && ident == s.ident);
- Import imp;
- if (!aliasId && (imp = s.isImport()) !is null && !imp.aliasId)
- return true;
- else
+ if (aliasId)
return false;
+ const imp = s.isImport();
+ return imp && !imp.aliasId;
}
override inout(Import) isImport() inout
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index 5493fc1..52520be 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -50,7 +50,7 @@ import dmd.rootobject;
import dmd.root.utf;
import dmd.statement;
import dmd.tokens;
-import dmd.typesem : mutableOf, equivalent, pointerTo, sarrayOf, arrayOf;
+import dmd.typesem : mutableOf, equivalent, pointerTo, sarrayOf, arrayOf, size;
import dmd.utils : arrayCastBigEndian;
import dmd.visitor;
diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d
index a8b43da..84048af 100644
--- a/gcc/d/dmd/doc.d
+++ b/gcc/d/dmd/doc.d
@@ -2587,7 +2587,7 @@ TypeFunction isTypeFunction(Dsymbol s) @safe
{
Type t = f.originalType ? f.originalType : f.type;
if (t.ty == Tfunction)
- return cast(TypeFunction)t;
+ return (() @trusted => cast(TypeFunction)t)();
}
return null;
}
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index 416bd57..64f19d9 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -456,7 +456,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
Type tv = v.type.baseElemOf();
if (tv.ty == Tstruct)
{
- TypeStruct ts = cast(TypeStruct)tv;
+ auto ts = cast(TypeStruct)tv;
StructDeclaration sd = ts.sym;
if (!sd.isPOD())
{
@@ -608,7 +608,7 @@ bool _isZeroInit(Expression exp)
case EXP.string_:
{
- StringExp se = cast(StringExp)exp;
+ auto se = cast(StringExp)exp;
if (se.type.toBasetype().ty == Tarray) // if initializing a dynamic array
return se.len == 0;
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 4a21b14..e32f5fa 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -7270,7 +7270,7 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
// If the bit-field spans more units of alignment than its type,
// start a new field at the next alignment boundary.
if (fieldState.bitOffset == fieldState.fieldSize * 8 &&
- fieldState.bitOffset + bfd.fieldWidth > memalignsize * 8)
+ fieldState.bitOffset + bfd.fieldWidth > memsize * 8)
{
if (log) printf("more units of alignment than its type\n");
startNewField(); // the bit field is full
@@ -7278,10 +7278,10 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
else
{
// if alignment boundary is crossed
- uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset;
+ uint start = (fieldState.fieldOffset * 8 + fieldState.bitOffset) % (memalignsize * 8);
uint end = start + bfd.fieldWidth;
//printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
- if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
+ if (start / (memsize * 8) != (end - 1) / (memsize * 8))
{
if (log) printf("alignment is crossed\n");
startNewField();
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index 33ec6b1..8fcbbad 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -89,7 +89,7 @@ private enum LOG = false;
enum IDX_NOTFOUND = 0x12345678;
-pure nothrow @nogc @safe
+pure nothrow @nogc @trusted
{
/********************************************
@@ -143,6 +143,11 @@ inout(TemplateParameter) isTemplateParameter(inout RootObject o)
return cast(inout(TemplateParameter))o;
}
+} // end @trusted casts
+
+pure nothrow @nogc @safe
+{
+
/**************************************
* Is this Object an error?
*/
@@ -282,6 +287,18 @@ private bool match(RootObject o1, RootObject o2)
o1, o1.toChars(), o1.dyncast(), o2, o2.toChars(), o2.dyncast());
}
+ bool yes()
+ {
+ static if (log)
+ printf("\t. match\n");
+ return true;
+ }
+ bool no()
+ {
+ static if (log)
+ printf("\t. nomatch\n");
+ return false;
+ }
/* A proper implementation of the various equals() overrides
* should make it possible to just do o1.equals(o2), but
* we'll do that another day.
@@ -294,7 +311,7 @@ private bool match(RootObject o1, RootObject o2)
{
auto t2 = isType(o2);
if (!t2)
- goto Lnomatch;
+ return no();
static if (log)
{
@@ -302,15 +319,15 @@ private bool match(RootObject o1, RootObject o2)
printf("\tt2 = %s\n", t2.toChars());
}
if (!t1.equals(t2))
- goto Lnomatch;
+ return no();
- goto Lmatch;
+ return yes();
}
if (auto e1 = getExpression(o1))
{
auto e2 = getExpression(o2);
if (!e2)
- goto Lnomatch;
+ return no();
static if (log)
{
@@ -323,15 +340,15 @@ private bool match(RootObject o1, RootObject o2)
// as well as expression equality to ensure templates are properly
// matched.
if (!(e1.type && e2.type && e1.type.equals(e2.type)) || !e1.equals(e2))
- goto Lnomatch;
+ return no();
- goto Lmatch;
+ return yes();
}
if (auto s1 = isDsymbol(o1))
{
auto s2 = isDsymbol(o2);
if (!s2)
- goto Lnomatch;
+ return no();
static if (log)
{
@@ -339,17 +356,17 @@ private bool match(RootObject o1, RootObject o2)
printf("\ts2 = %s \n", s2.kind(), s2.toChars());
}
if (!s1.equals(s2))
- goto Lnomatch;
+ return no();
if (s1.parent != s2.parent && !s1.isFuncDeclaration() && !s2.isFuncDeclaration())
- goto Lnomatch;
+ return no();
- goto Lmatch;
+ return yes();
}
if (auto u1 = isTuple(o1))
{
auto u2 = isTuple(o2);
if (!u2)
- goto Lnomatch;
+ return no();
static if (log)
{
@@ -357,19 +374,11 @@ private bool match(RootObject o1, RootObject o2)
printf("\tu2 = %s\n", u2.toChars());
}
if (!arrayObjectMatch(u1.objects, u2.objects))
- goto Lnomatch;
+ return no();
- goto Lmatch;
+ return yes();
}
-Lmatch:
- static if (log)
- printf("\t. match\n");
- return true;
-
-Lnomatch:
- static if (log)
- printf("\t. nomatch\n");
- return false;
+ return yes();
}
/************************************
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index a26f3ab..b5fb0e2 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -21,6 +21,7 @@ import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
+import dmd.dcast : implicitConvTo;
import dmd.dclass;
import dmd.declaration;
import dmd.dimport;
@@ -426,7 +427,7 @@ extern (C++) abstract class Expression : ASTNode
* is returned via e0.
* Otherwise 'e' is directly returned and e0 is set to NULL.
*/
- extern (D) static Expression extractLast(Expression e, out Expression e0) @safe
+ extern (D) static Expression extractLast(Expression e, out Expression e0) @trusted
{
if (e.op != EXP.comma)
{
@@ -709,7 +710,7 @@ extern (C++) abstract class Expression : ASTNode
return true;
}
- final pure inout nothrow @nogc @safe
+ final pure inout nothrow @nogc @trusted
{
inout(IntegerExp) isIntegerExp() { return op == EXP.int64 ? cast(typeof(return))this : null; }
inout(ErrorExp) isErrorExp() { return op == EXP.error ? cast(typeof(return))this : null; }
@@ -3868,7 +3869,7 @@ extern (C++) final class VectorExp : UnaExp
uint dim = ~0; // number of elements in the vector
OwnedBy ownedByCtfe = OwnedBy.code;
- extern (D) this(const ref Loc loc, Expression e, Type t) @safe
+ extern (D) this(const ref Loc loc, Expression e, Type t) @trusted
{
super(loc, EXP.vector, e);
assert(t.ty == Tvector);
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 481806d..a69b64d 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -7752,6 +7752,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (auto fmResult = global.fileManager.getFileContents(fileName))
{
se = new StringExp(e.loc, fmResult);
+ se.hexString = true;
}
else
{
@@ -9251,13 +9252,27 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
// Check for unsafe casts
- if (!isSafeCast(ex, t1b, tob))
+ string msg;
+ if (!isSafeCast(ex, t1b, tob, msg))
{
- if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
+ if (sc.setUnsafe(false, exp.loc,
+ "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
{
+ if (msg.length)
+ errorSupplemental(exp.loc, "%s", (msg ~ '\0').ptr);
return setError();
}
}
+ else if (msg.length) // deprecated unsafe
+ {
+ const err = sc.setUnsafePreview(FeatureState.default_, false, exp.loc,
+ "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to);
+ // if message was printed
+ if (sc.func && sc.func.isSafeBypassingInference() && !sc.isDeprecated())
+ deprecationSupplemental(exp.loc, "%s", (msg ~ '\0').ptr);
+ if (err)
+ return setError();
+ }
// `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
// to handle certain casts. Those casts which `object.__ArrayCast` does not support are filtered out.
@@ -11413,11 +11428,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
else
e2x = e2x.implicitCastTo(sc, exp.e1.type);
}
- if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid)
- {
- if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code"))
- return setError();
- }
}
else
{
@@ -11449,6 +11459,33 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
}
}
}
+
+ if (exp.e1.op == EXP.slice &&
+ (t1.ty == Tarray || t1.ty == Tsarray) &&
+ t1.nextOf().toBasetype().ty == Tvoid)
+ {
+ if (t2.nextOf().implicitConvTo(t1.nextOf()))
+ {
+ if (sc.setUnsafe(false, exp.loc, "cannot copy `%s` to `%s` in `@safe` code", t2, t1))
+ return setError();
+ }
+ else
+ {
+ // copying from non-void to void was overlooked, deprecate
+ if (sc.setUnsafePreview(FeatureState.default_, false, exp.loc,
+ "cannot copy `%s` to `%s` in `@safe` code", t2, t1))
+ return setError();
+ }
+ if (global.params.fixImmutableConv && !t2.implicitConvTo(t1))
+ {
+ error(exp.loc, "cannot copy `%s` to `%s`",
+ t2.toChars(), t1.toChars());
+ errorSupplemental(exp.loc,
+ "Source data has incompatible type qualifier(s)");
+ errorSupplemental(exp.loc, "Use `cast(%s)` to force copy", t1.toChars());
+ return setError();
+ }
+ }
if (e2x.op == EXP.error)
{
result = e2x;
@@ -11837,6 +11874,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
(tb2.ty == Tarray || tb2.ty == Tsarray) &&
(exp.e2.implicitConvTo(exp.e1.type) ||
(tb2.nextOf().implicitConvTo(tb1next) &&
+ // Do not strip const(void)[]
+ (!global.params.fixImmutableConv || tb1next.ty != Tvoid) &&
(tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
{
// EXP.concatenateAssign
@@ -12586,7 +12625,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
exp.type = tb.nextOf().arrayOf();
if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod)
{
- exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
+ // Do not strip const(void)[]
+ if (!global.params.fixImmutableConv || tb.nextOf().ty != Tvoid)
+ exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
}
if (Type tbn = tb.nextOf())
{
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index cb19b14..54ff826 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -731,72 +731,6 @@ extern (C++) class FuncDeclaration : Declaration
inferScope = true;
}
- final PURE isPure()
- {
- //printf("FuncDeclaration::isPure() '%s'\n", toChars());
-
-
- TypeFunction tf = type.toTypeFunction();
- if (purityInprocess)
- setImpure();
- if (tf.purity == PURE.fwdref)
- tf.purityLevel();
- PURE purity = tf.purity;
- if (purity > PURE.weak && isNested())
- purity = PURE.weak;
- if (purity > PURE.weak && needThis())
- {
- // The attribute of the 'this' reference affects purity strength
- if (type.mod & MODFlags.immutable_)
- {
- }
- else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
- purity = PURE.const_;
- else
- purity = PURE.weak;
- }
- tf.purity = purity;
- // ^ This rely on the current situation that every FuncDeclaration has a
- // unique TypeFunction.
- return purity;
- }
-
- extern (D) final PURE isPureBypassingInference()
- {
- if (purityInprocess)
- return PURE.fwdref;
- else
- return isPure();
- }
-
- /**************************************
- * The function is doing something impure, so mark it as impure.
- *
- * Params:
- * loc = location of impure action
- * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
- * arg0 = (optional) argument to format string
- *
- * Returns: `true` if there's a purity error
- */
- extern (D) final bool setImpure(Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null)
- {
- if (purityInprocess)
- {
- purityInprocess = false;
- if (fmt)
- pureViolation = new AttributeViolation(loc, fmt, this, arg0); // impure action
- else if (arg0)
- pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function
-
- if (fes)
- fes.func.setImpure(loc, fmt, arg0);
- }
- else if (isPure())
- return true;
- return false;
- }
-
extern (D) final uint flags()
{
return bitFields;
@@ -977,187 +911,6 @@ extern (C++) class FuncDeclaration : Declaration
}
}
- /********************************************
- * See if pointers from function parameters, mutable globals, or uplevel functions
- * could leak into return value.
- * Returns:
- * true if the function return value is isolated from
- * any inputs to the function
- */
- extern (D) final bool isReturnIsolated()
- {
- //printf("isReturnIsolated(this: %s)\n", this.toChars);
- TypeFunction tf = type.toTypeFunction();
- assert(tf.next);
-
- Type treti = tf.next;
- if (tf.isref)
- return isTypeIsolatedIndirect(treti); // check influence from parameters
-
- return isTypeIsolated(treti);
- }
-
- /********************
- * See if pointers from function parameters, mutable globals, or uplevel functions
- * could leak into type `t`.
- * Params:
- * t = type to check if it is isolated
- * Returns:
- * true if `t` is isolated from
- * any inputs to the function
- */
- extern (D) final bool isTypeIsolated(Type t)
- {
- StringTable!Type parentTypes;
- const uniqueTypeID = t.getUniqueID();
- if (uniqueTypeID)
- {
- const cacheResultPtr = uniqueTypeID in isTypeIsolatedCache;
- if (cacheResultPtr !is null)
- return *cacheResultPtr;
-
- parentTypes._init();
- const isIsolated = isTypeIsolated(t, parentTypes);
- isTypeIsolatedCache[uniqueTypeID] = isIsolated;
- return isIsolated;
- }
- else
- {
- parentTypes._init();
- return isTypeIsolated(t, parentTypes);
- }
- }
-
- ///ditto
- extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes)
- {
- //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
-
- t = t.baseElemOf();
- switch (t.ty)
- {
- case Tarray:
- case Tpointer:
- return isTypeIsolatedIndirect(t.nextOf()); // go down one level
-
- case Taarray:
- case Tclass:
- return isTypeIsolatedIndirect(t);
-
- case Tstruct:
- /* Drill down and check the struct's fields
- */
- auto sym = t.toDsymbol(null).isStructDeclaration();
- const tName = t.toChars.toDString;
- const entry = parentTypes.insert(tName, t);
- if (entry == null)
- {
- //we've already seen this type in a parent, not isolated
- return false;
- }
- foreach (v; sym.fields)
- {
- Type tmi = v.type.addMod(t.mod);
- //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n",
- // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
- if (!isTypeIsolated(tmi, parentTypes))
- return false;
- }
- return true;
-
- default:
- return true;
- }
- }
-
- /********************************************
- * Params:
- * t = type of object to test one level of indirection down
- * Returns:
- * true if an object typed `t` has no indirections
- * which could have come from the function's parameters, mutable
- * globals, or uplevel functions.
- */
- private bool isTypeIsolatedIndirect(Type t)
- {
- //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
- assert(t);
-
- /* Since `t` is one level down from an indirection, it could pick
- * up a reference to a mutable global or an outer function, so
- * return false.
- */
- if (!isPureBypassingInference() || isNested())
- return false;
-
- TypeFunction tf = type.toTypeFunction();
-
- //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
-
- foreach (i, fparam; tf.parameterList)
- {
- Type tp = fparam.type;
- if (!tp)
- continue;
-
- if (fparam.isLazy() || fparam.isReference())
- {
- if (!traverseIndirections(tp, t))
- return false;
- continue;
- }
-
- /* Goes down one level of indirection, then calls traverseIndirection() on
- * the result.
- * Returns:
- * true if t is isolated from tp
- */
- static bool traverse(Type tp, Type t)
- {
- tp = tp.baseElemOf();
- switch (tp.ty)
- {
- case Tarray:
- case Tpointer:
- return traverseIndirections(tp.nextOf(), t);
-
- case Taarray:
- case Tclass:
- return traverseIndirections(tp, t);
-
- case Tstruct:
- /* Drill down and check the struct's fields
- */
- auto sym = tp.toDsymbol(null).isStructDeclaration();
- foreach (v; sym.fields)
- {
- Type tprmi = v.type.addMod(tp.mod);
- //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
- if (!traverse(tprmi, t))
- return false;
- }
- return true;
-
- default:
- return true;
- }
- }
-
- if (!traverse(tp, t))
- return false;
- }
- // The 'this' reference is a parameter, too
- if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis())
- {
- Type tthis = ad.getType().addMod(tf.mod);
- //printf("\ttthis = %s\n", tthis.toChars());
- if (!traverseIndirections(tthis, t))
- return false;
- }
-
- return true;
- }
-
/****************************************
* Determine if function needs a static frame pointer.
* Returns:
@@ -1766,116 +1519,6 @@ unittest
assert(mismatches.isMutable);
}
-/**************************************
- * Performs type-based alias analysis between a newly created value and a pre-
- * existing memory reference:
- *
- * Assuming that a reference A to a value of type `ta` was available to the code
- * that created a reference B to a value of type `tb`, it returns whether B
- * might alias memory reachable from A based on the types involved (either
- * directly or via any number of indirections in either A or B).
- *
- * This relation is not symmetric in the two arguments. For example, a
- * a `const(int)` reference can point to a pre-existing `int`, but not the other
- * way round.
- *
- * Examples:
- *
- * ta, tb, result
- * `const(int)`, `int`, `false`
- * `int`, `const(int)`, `true`
- * `int`, `immutable(int)`, `false`
- * const(immutable(int)*), immutable(int)*, false // BUG: returns true
- *
- * Params:
- * ta = value type being referred to
- * tb = referred to value type that could be constructed from ta
- *
- * Returns:
- * true if reference to `tb` is isolated from reference to `ta`
- */
-private bool traverseIndirections(Type ta, Type tb)
-{
- //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
-
- static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
- {
- //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
- ta = ta.baseElemOf();
- tb = tb.baseElemOf();
-
- // First, check if the pointed-to types are convertible to each other such
- // that they might alias directly.
- static bool mayAliasDirect(Type source, Type target)
- {
- return
- // if source is the same as target or can be const-converted to target
- source.constConv(target) != MATCH.nomatch ||
- // if target is void and source can be const-converted to target
- (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
- }
-
- if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
- {
- //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
- return false;
- }
- if (ta.nextOf() && ta.nextOf() == tb.nextOf())
- {
- //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
- return true;
- }
-
- if (tb.ty == Tclass || tb.ty == Tstruct)
- {
- /* Traverse the type of each field of the aggregate
- */
- bool* found = table.getLvalue(tb.deco);
- if (*found == true)
- return true; // We have already seen this symbol, break the cycle
- else
- *found = true;
-
- AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
- foreach (v; sym.fields)
- {
- Type tprmi = v.type.addMod(tb.mod);
- //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
- if (!traverse(ta, tprmi, table, reversePass))
- return false;
- }
- }
- else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
- {
- Type tind = tb.nextOf();
- if (!traverse(ta, tind, table, reversePass))
- return false;
- }
- else if (tb.hasPointers())
- {
- // BUG: consider the context pointer of delegate types
- return false;
- }
-
- // Still no match, so try breaking up ta if we have not done so yet.
- if (!reversePass)
- {
- scope newTable = AssocArray!(const(char)*, bool)();
- return traverse(tb, ta, newTable, true);
- }
-
- return true;
- }
-
- // To handle arbitrary levels of indirections in both parameters, we
- // recursively descend into aggregate members/levels of indirection in both
- // `ta` and `tb` while avoiding cycles. Start with the original types.
- scope table = AssocArray!(const(char)*, bool)();
- const result = traverse(ta, tb, table, false);
- //printf(" returns %d\n", result);
- return result;
-}
-
/* For all functions between outerFunc and f, mark them as needing
* a closure.
*/
diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d
index ee36a16..594e481 100644
--- a/gcc/d/dmd/funcsem.d
+++ b/gcc/d/dmd/funcsem.d
@@ -2539,7 +2539,7 @@ void buildEnsureRequire(FuncDeclaration thisfd)
/* Rewrite contracts as nested functions, then call them. Doing it as nested
* functions means that overriding functions can call them.
*/
- TypeFunction f = cast(TypeFunction) thisfd.type;
+ auto f = cast(TypeFunction) thisfd.type;
/* Make a copy of the parameters and make them all ref */
static Parameters* toRefCopy(ParameterList parameterList)
{
@@ -3062,3 +3062,362 @@ extern (D) bool checkNRVO(FuncDeclaration fd)
}
return true;
}
+
+/**************************************
+ * The function is doing something impure, so mark it as impure.
+ *
+ * Params:
+ * fd = function declaration to mark
+ * loc = location of impure action
+ * fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
+ * arg0 = (optional) argument to format string
+ *
+ * Returns: `true` if there's a purity error
+ */
+extern (D) bool setImpure(FuncDeclaration fd, Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null)
+{
+ if (fd.purityInprocess)
+ {
+ fd.purityInprocess = false;
+ if (fmt)
+ fd.pureViolation = new AttributeViolation(loc, fmt, fd, arg0); // impure action
+ else if (arg0)
+ fd.pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function
+
+ if (fd.fes)
+ fd.fes.func.setImpure(loc, fmt, arg0);
+ }
+ else if (fd.isPure())
+ return true;
+ return false;
+}
+
+PURE isPure(FuncDeclaration fd)
+{
+ //printf("FuncDeclaration::isPure() '%s'\n", toChars());
+
+
+ TypeFunction tf = fd.type.toTypeFunction();
+ if (fd.purityInprocess)
+ fd.setImpure();
+ if (tf.purity == PURE.fwdref)
+ tf.purityLevel();
+ PURE purity = tf.purity;
+ if (purity > PURE.weak && fd.isNested())
+ purity = PURE.weak;
+ if (purity > PURE.weak && fd.needThis())
+ {
+ // The attribute of the 'this' reference affects purity strength
+ if (fd.type.mod & MODFlags.immutable_)
+ {
+ }
+ else if (fd.type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
+ purity = PURE.const_;
+ else
+ purity = PURE.weak;
+ }
+ tf.purity = purity;
+ // ^ This rely on the current situation that every FuncDeclaration has a
+ // unique TypeFunction.
+ return purity;
+}
+
+extern (D) PURE isPureBypassingInference(FuncDeclaration fd)
+{
+ if (fd.purityInprocess)
+ return PURE.fwdref;
+ else
+ return fd.isPure();
+}
+
+/**************************************
+ * Performs type-based alias analysis between a newly created value and a pre-
+ * existing memory reference:
+ *
+ * Assuming that a reference A to a value of type `ta` was available to the code
+ * that created a reference B to a value of type `tb`, it returns whether B
+ * might alias memory reachable from A based on the types involved (either
+ * directly or via any number of indirections in either A or B).
+ *
+ * This relation is not symmetric in the two arguments. For example, a
+ * a `const(int)` reference can point to a pre-existing `int`, but not the other
+ * way round.
+ *
+ * Examples:
+ *
+ * ta, tb, result
+ * `const(int)`, `int`, `false`
+ * `int`, `const(int)`, `true`
+ * `int`, `immutable(int)`, `false`
+ * const(immutable(int)*), immutable(int)*, false // BUG: returns true
+ *
+ * Params:
+ * ta = value type being referred to
+ * tb = referred to value type that could be constructed from ta
+ *
+ * Returns:
+ * true if reference to `tb` is isolated from reference to `ta`
+ */
+bool traverseIndirections(Type ta, Type tb)
+{
+ //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
+
+ static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
+ {
+ //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
+ ta = ta.baseElemOf();
+ tb = tb.baseElemOf();
+
+ // First, check if the pointed-to types are convertible to each other such
+ // that they might alias directly.
+ static bool mayAliasDirect(Type source, Type target)
+ {
+ return
+ // if source is the same as target or can be const-converted to target
+ source.constConv(target) != MATCH.nomatch ||
+ // if target is void and source can be const-converted to target
+ (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
+ }
+
+ if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
+ {
+ //printf(" true mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
+ return false;
+ }
+ if (ta.nextOf() && ta.nextOf() == tb.nextOf())
+ {
+ //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
+ return true;
+ }
+
+ if (tb.ty == Tclass || tb.ty == Tstruct)
+ {
+ /* Traverse the type of each field of the aggregate
+ */
+ bool* found = table.getLvalue(tb.deco);
+ if (*found == true)
+ return true; // We have already seen this symbol, break the cycle
+ else
+ *found = true;
+
+ AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
+ foreach (v; sym.fields)
+ {
+ Type tprmi = v.type.addMod(tb.mod);
+ //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
+ if (!traverse(ta, tprmi, table, reversePass))
+ return false;
+ }
+ }
+ else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
+ {
+ Type tind = tb.nextOf();
+ if (!traverse(ta, tind, table, reversePass))
+ return false;
+ }
+ else if (tb.hasPointers())
+ {
+ // BUG: consider the context pointer of delegate types
+ return false;
+ }
+
+ // Still no match, so try breaking up ta if we have not done so yet.
+ if (!reversePass)
+ {
+ scope newTable = AssocArray!(const(char)*, bool)();
+ return traverse(tb, ta, newTable, true);
+ }
+
+ return true;
+ }
+
+ // To handle arbitrary levels of indirections in both parameters, we
+ // recursively descend into aggregate members/levels of indirection in both
+ // `ta` and `tb` while avoiding cycles. Start with the original types.
+ scope table = AssocArray!(const(char)*, bool)();
+ const result = traverse(ta, tb, table, false);
+ //printf(" returns %d\n", result);
+ return result;
+}
+
+/********************************************
+ * Params:
+ * fd = function declaration to check
+ * t = type of object to test one level of indirection down
+ * Returns:
+ * true if an object typed `t` has no indirections
+ * which could have come from the function's parameters, mutable
+ * globals, or uplevel functions.
+ */
+bool isTypeIsolatedIndirect(FuncDeclaration fd, Type t)
+{
+ //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
+ assert(t);
+
+ /* Since `t` is one level down from an indirection, it could pick
+ * up a reference to a mutable global or an outer function, so
+ * return false.
+ */
+ if (!fd.isPureBypassingInference() || fd.isNested())
+ return false;
+
+ TypeFunction tf = fd.type.toTypeFunction();
+
+ //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
+
+ foreach (i, fparam; tf.parameterList)
+ {
+ Type tp = fparam.type;
+ if (!tp)
+ continue;
+
+ if (fparam.isLazy() || fparam.isReference())
+ {
+ if (!traverseIndirections(tp, t))
+ return false;
+ continue;
+ }
+
+ /* Goes down one level of indirection, then calls traverseIndirection() on
+ * the result.
+ * Returns:
+ * true if t is isolated from tp
+ */
+ static bool traverse(Type tp, Type t)
+ {
+ tp = tp.baseElemOf();
+ switch (tp.ty)
+ {
+ case Tarray:
+ case Tpointer:
+ return traverseIndirections(tp.nextOf(), t);
+
+ case Taarray:
+ case Tclass:
+ return traverseIndirections(tp, t);
+
+ case Tstruct:
+ /* Drill down and check the struct's fields
+ */
+ auto sym = tp.toDsymbol(null).isStructDeclaration();
+ foreach (v; sym.fields)
+ {
+ Type tprmi = v.type.addMod(tp.mod);
+ //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
+ if (!traverse(tprmi, t))
+ return false;
+ }
+ return true;
+
+ default:
+ return true;
+ }
+ }
+
+ if (!traverse(tp, t))
+ return false;
+ }
+ // The 'this' reference is a parameter, too
+ if (AggregateDeclaration ad = fd.isCtorDeclaration() ? null : fd.isThis())
+ {
+ Type tthis = ad.getType().addMod(tf.mod);
+ //printf("\ttthis = %s\n", tthis.toChars());
+ if (!traverseIndirections(tthis, t))
+ return false;
+ }
+
+ return true;
+}
+
+/********************************************
+ * See if pointers from function parameters, mutable globals, or uplevel functions
+ * could leak into return value.
+ * Returns:
+ * true if the function return value is isolated from
+ * any inputs to the function
+ */
+extern (D) bool isReturnIsolated(FuncDeclaration fd)
+{
+ //printf("isReturnIsolated(this: %s)\n", this.toChars);
+ TypeFunction tf = fd.type.toTypeFunction();
+ assert(tf.next);
+
+ Type treti = tf.next;
+ if (tf.isref)
+ return fd.isTypeIsolatedIndirect(treti); // check influence from parameters
+
+ return fd.isTypeIsolated(treti);
+}
+
+/********************
+ * See if pointers from function parameters, mutable globals, or uplevel functions
+ * could leak into type `t`.
+ * Params:
+ * t = type to check if it is isolated
+ * Returns:
+ * true if `t` is isolated from
+ * any inputs to the function
+ */
+extern (D) bool isTypeIsolated(FuncDeclaration fd, Type t)
+{
+ StringTable!Type parentTypes;
+ const uniqueTypeID = t.getUniqueID();
+ if (uniqueTypeID)
+ {
+ const cacheResultPtr = uniqueTypeID in fd.isTypeIsolatedCache;
+ if (cacheResultPtr !is null)
+ return *cacheResultPtr;
+
+ parentTypes._init();
+ const isIsolated = fd.isTypeIsolated(t, parentTypes);
+ fd.isTypeIsolatedCache[uniqueTypeID] = isIsolated;
+ return isIsolated;
+ }
+ else
+ {
+ parentTypes._init();
+ return fd.isTypeIsolated(t, parentTypes);
+ }
+}
+
+///ditto
+extern (D) bool isTypeIsolated(FuncDeclaration fd, Type t, ref StringTable!Type parentTypes)
+{
+ //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
+
+ t = t.baseElemOf();
+ switch (t.ty)
+ {
+ case Tarray:
+ case Tpointer:
+ return fd.isTypeIsolatedIndirect(t.nextOf()); // go down one level
+
+ case Taarray:
+ case Tclass:
+ return fd.isTypeIsolatedIndirect(t);
+
+ case Tstruct:
+ /* Drill down and check the struct's fields
+ */
+ auto sym = t.toDsymbol(null).isStructDeclaration();
+ const tName = t.toChars.toDString;
+ const entry = parentTypes.insert(tName, t);
+ if (entry == null)
+ {
+ //we've already seen this type in a parent, not isolated
+ return false;
+ }
+ foreach (v; sym.fields)
+ {
+ Type tmi = v.type.addMod(t.mod);
+ //printf("\tt = %s, v: %s, vtype: %s, tmi = %s\n",
+ // t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
+ if (!fd.isTypeIsolated(tmi, parentTypes))
+ return false;
+ }
+ return true;
+
+ default:
+ return true;
+ }
+}
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
index 1e72cf7..a44fb28 100644
--- a/gcc/d/dmd/hdrgen.d
+++ b/gcc/d/dmd/hdrgen.d
@@ -3933,9 +3933,9 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te
buf.writeByte(' ');
}
- void ignoreReturn(string str)
+ void dg(string str)
{
- if (str != "return")
+ if (str != "return" && str != "scope")
{
// don't write 'ref' for ctors
if ((ident == Id.ctor) && str == "ref")
@@ -3944,7 +3944,7 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te
buf.writeByte(' ');
}
}
- t.attributesApply(&ignoreReturn);
+ t.attributesApply(&dg);
if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen)
{
@@ -3977,7 +3977,15 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te
buf.writeByte(')');
}
parametersToBuffer(t.parameterList, buf, hgs);
- if (t.isreturn)
+ if (t.isreturnscope && !t.isreturninferred)
+ {
+ buf.writestring(" return scope");
+ }
+ else if (t.isScopeQual && !t.isscopeinferred)
+ {
+ buf.writestring(" scope");
+ }
+ if (t.isreturn && !t.isreturnscope && !t.isreturninferred)
{
buf.writestring(" return");
}
diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d
index dfaf8f5..f676361 100644
--- a/gcc/d/dmd/id.d
+++ b/gcc/d/dmd/id.d
@@ -574,6 +574,7 @@ immutable Msgtable[] msgtable =
{ "define" },
{ "undef" },
{ "ident" },
+ { "packed" },
];
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index a91a0a4..6a2d349 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -21,6 +21,7 @@ import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
+import dmd.dcast : implicitConvTo;
import dmd.dclass;
import dmd.declaration;
import dmd.denum;
@@ -30,7 +31,6 @@ import dmd.dtemplate;
import dmd.enumsem;
import dmd.errors;
import dmd.expression;
-import dmd.funcsem;
import dmd.globals;
import dmd.hdrgen;
import dmd.id;
@@ -618,20 +618,9 @@ extern (C++) abstract class Type : ASTNode
stringtable = stringtable.init;
}
- final uinteger_t size()
- {
- return size(Loc.initial);
- }
-
- uinteger_t size(const ref Loc loc)
- {
- error(loc, "no size for type `%s`", toChars());
- return SIZE_INVALID;
- }
-
uint alignsize()
{
- return cast(uint)size(Loc.initial);
+ return cast(uint)size(this, Loc.initial);
}
/*********************************
@@ -1293,22 +1282,6 @@ extern (C++) abstract class Type : ASTNode
return ((te = isTypeEnum()) !is null) ? te.toBasetype2() : this;
}
- /********************************
- * Determine if 'this' can be implicitly converted
- * to type 'to'.
- * Returns:
- * MATCH.nomatch, MATCH.convert, MATCH.constant, MATCH.exact
- */
- MATCH implicitConvTo(Type to)
- {
- //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
- //printf("from: %s\n", toChars());
- //printf("to : %s\n", to.toChars());
- if (this.equals(to))
- return MATCH.exact;
- return MATCH.nomatch;
- }
-
/*******************************
* Determine if converting 'this' to 'to' is an identity operation,
* a conversion to const operation, or the types aren't the same.
@@ -1582,7 +1555,7 @@ extern (C++) abstract class Type : ASTNode
}
}
- final pure inout nothrow @nogc @safe
+ final pure inout nothrow @nogc @trusted
{
inout(TypeError) isTypeError() { return ty == Terror ? cast(typeof(return))this : null; }
inout(TypeVector) isTypeVector() { return ty == Tvector ? cast(typeof(return))this : null; }
@@ -1656,11 +1629,6 @@ extern (C++) final class TypeError : Type
return this;
}
- override uinteger_t size(const ref Loc loc)
- {
- return SIZE_INVALID;
- }
-
override Expression defaultInitLiteral(const ref Loc loc)
{
return ErrorExp.get();
@@ -2116,83 +2084,6 @@ extern (C++) final class TypeBasic : Type
return this;
}
- override uinteger_t size(const ref Loc loc)
- {
- uint size;
- //printf("TypeBasic::size()\n");
- switch (ty)
- {
- case Tint8:
- case Tuns8:
- size = 1;
- break;
-
- case Tint16:
- case Tuns16:
- size = 2;
- break;
-
- case Tint32:
- case Tuns32:
- case Tfloat32:
- case Timaginary32:
- size = 4;
- break;
-
- case Tint64:
- case Tuns64:
- case Tfloat64:
- case Timaginary64:
- size = 8;
- break;
-
- case Tfloat80:
- case Timaginary80:
- size = target.realsize;
- break;
-
- case Tcomplex32:
- size = 8;
- break;
-
- case Tcomplex64:
- case Tint128:
- case Tuns128:
- size = 16;
- break;
-
- case Tcomplex80:
- size = target.realsize * 2;
- break;
-
- case Tvoid:
- //size = Type::size(); // error message
- size = 1;
- break;
-
- case Tbool:
- size = 1;
- break;
-
- case Tchar:
- size = 1;
- break;
-
- case Twchar:
- size = 2;
- break;
-
- case Tdchar:
- size = 4;
- break;
-
- default:
- assert(0);
- }
- //printf("TypeBasic::size() = %d\n", size);
- return size;
- }
-
override uint alignsize()
{
return target.alignsize(this);
@@ -2234,98 +2125,6 @@ extern (C++) final class TypeBasic : Type
return (flags & TFlags.unsigned) != 0;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeBasic::implicitConvTo(%s) from %s\n", to.toChars(), toChars());
- if (this == to)
- return MATCH.exact;
-
- if (ty == to.ty)
- {
- if (mod == to.mod)
- return MATCH.exact;
- else if (MODimplicitConv(mod, to.mod))
- return MATCH.constant;
- else if (!((mod ^ to.mod) & MODFlags.shared_)) // for wild matching
- return MATCH.constant;
- else
- return MATCH.convert;
- }
-
- if (ty == Tvoid || to.ty == Tvoid)
- return MATCH.nomatch;
- if (to.ty == Tbool)
- return MATCH.nomatch;
-
- TypeBasic tob;
- if (to.ty == Tvector && to.deco)
- {
- TypeVector tv = cast(TypeVector)to;
- tob = tv.elementType();
- }
- else if (auto te = to.isTypeEnum())
- {
- EnumDeclaration ed = te.sym;
- if (ed.isSpecial())
- {
- /* Special enums that allow implicit conversions to them
- * with a MATCH.convert
- */
- tob = to.toBasetype().isTypeBasic();
- }
- else
- return MATCH.nomatch;
- }
- else
- tob = to.isTypeBasic();
- if (!tob)
- return MATCH.nomatch;
-
- if (flags & TFlags.integral)
- {
- // Disallow implicit conversion of integers to imaginary or complex
- if (tob.flags & (TFlags.imaginary | TFlags.complex))
- return MATCH.nomatch;
-
- // If converting from integral to integral
- if (tob.flags & TFlags.integral)
- {
- const sz = size(Loc.initial);
- const tosz = tob.size(Loc.initial);
-
- /* Can't convert to smaller size
- */
- if (sz > tosz)
- return MATCH.nomatch;
- /* Can't change sign if same size
- */
- //if (sz == tosz && (flags ^ tob.flags) & TFlags.unsigned)
- // return MATCH.nomatch;
- }
- }
- else if (flags & TFlags.floating)
- {
- // Disallow implicit conversion of floating point to integer
- if (tob.flags & TFlags.integral)
- return MATCH.nomatch;
-
- assert(tob.flags & TFlags.floating || to.ty == Tvector);
-
- // Disallow implicit conversion from complex to non-complex
- if (flags & TFlags.complex && !(tob.flags & TFlags.complex))
- return MATCH.nomatch;
-
- // Disallow implicit conversion of real or imaginary to complex
- if (flags & (TFlags.real_ | TFlags.imaginary) && tob.flags & TFlags.complex)
- return MATCH.nomatch;
-
- // Disallow implicit conversion to-from real and imaginary
- if ((flags & (TFlags.real_ | TFlags.imaginary)) != (tob.flags & (TFlags.real_ | TFlags.imaginary)))
- return MATCH.nomatch;
- }
- return MATCH.convert;
- }
-
override bool isZeroInit(const ref Loc loc)
{
switch (ty)
@@ -2396,11 +2195,6 @@ extern (C++) final class TypeVector : Type
return new TypeVector(basetype.syntaxCopy());
}
- override uinteger_t size(const ref Loc loc)
- {
- return basetype.size();
- }
-
override uint alignsize()
{
return cast(uint)basetype.size();
@@ -2432,29 +2226,6 @@ extern (C++) final class TypeVector : Type
return false;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeVector::implicitConvTo(%s) from %s\n", to.toChars(), toChars());
- if (this == to)
- return MATCH.exact;
- if (to.ty != Tvector)
- return MATCH.nomatch;
-
- TypeVector tv = cast(TypeVector)to;
- assert(basetype.ty == Tsarray && tv.basetype.ty == Tsarray);
-
- // Can't convert to a vector which has different size.
- if (basetype.size() != tv.basetype.size())
- return MATCH.nomatch;
-
- // Allow conversion to void[]
- if (tv.basetype.nextOf().ty == Tvoid)
- return MATCH.convert;
-
- // Otherwise implicitly convertible only if basetypes are.
- return basetype.implicitConvTo(tv.basetype);
- }
-
override Expression defaultInitLiteral(const ref Loc loc)
{
//printf("TypeVector::defaultInitLiteral()\n");
@@ -2545,22 +2316,6 @@ extern (C++) final class TypeSArray : TypeArray
return dim.isIntegerExp() && dim.isIntegerExp().getInteger() == 0;
}
- override uinteger_t size(const ref Loc loc)
- {
- //printf("TypeSArray::size()\n");
- const n = numberOfElems(loc);
- const elemsize = baseElemOf().size(loc);
- bool overflow = false;
- const sz = mulu(n, elemsize, overflow);
- if (overflow || sz >= uint.max)
- {
- if (elemsize != SIZE_INVALID && n != uint.max)
- error(loc, "static array `%s` size overflowed to %lld", toChars(), cast(long)sz);
- return SIZE_INVALID;
- }
- return sz;
- }
-
override uint alignsize()
{
return next.alignsize();
@@ -2592,65 +2347,6 @@ extern (C++) final class TypeSArray : TypeArray
return TypeNext.constConv(to);
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
- if (auto ta = to.isTypeDArray())
- {
- if (!MODimplicitConv(next.mod, ta.next.mod))
- return MATCH.nomatch;
-
- /* Allow conversion to void[]
- */
- if (ta.next.ty == Tvoid)
- {
- return MATCH.convert;
- }
-
- MATCH m = next.constConv(ta.next);
- if (m > MATCH.nomatch)
- {
- return MATCH.convert;
- }
- return MATCH.nomatch;
- }
- if (auto tsa = to.isTypeSArray())
- {
- if (this == to)
- return MATCH.exact;
-
- if (dim.equals(tsa.dim))
- {
- MATCH m = next.implicitConvTo(tsa.next);
-
- /* Allow conversion to non-interface base class.
- */
- if (m == MATCH.convert &&
- next.ty == Tclass)
- {
- if (auto toc = tsa.next.isTypeClass)
- {
- if (!toc.sym.isInterfaceDeclaration)
- return MATCH.convert;
- }
- }
-
- /* Since static arrays are value types, allow
- * conversions from const elements to non-const
- * ones, just like we allow conversion from const int
- * to int.
- */
- if (m >= MATCH.constant)
- {
- if (mod != to.mod)
- m = MATCH.constant;
- return m;
- }
- }
- }
- return MATCH.nomatch;
- }
-
override Expression defaultInitLiteral(const ref Loc loc)
{
static if (LOGDEFAULTINIT)
@@ -2736,12 +2432,6 @@ extern (C++) final class TypeDArray : TypeArray
return result;
}
- override uinteger_t size(const ref Loc loc)
- {
- //printf("TypeDArray::size()\n");
- return target.ptrsize * 2;
- }
-
override uint alignsize()
{
// A DArray consists of two ptr-sized values, so align it on pointer size
@@ -2765,35 +2455,6 @@ extern (C++) final class TypeDArray : TypeArray
return true;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
- if (equals(to))
- return MATCH.exact;
-
- if (auto ta = to.isTypeDArray())
- {
- if (!MODimplicitConv(next.mod, ta.next.mod))
- return MATCH.nomatch; // not const-compatible
-
- /* Allow conversion to void[]
- */
- if (next.ty != Tvoid && ta.next.ty == Tvoid)
- {
- return MATCH.convert;
- }
-
- MATCH m = next.constConv(ta.next);
- if (m > MATCH.nomatch)
- {
- if (m == MATCH.exact && mod != to.mod)
- m = MATCH.constant;
- return m;
- }
- }
- return Type.implicitConvTo(to);
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -2835,11 +2496,6 @@ extern (C++) final class TypeAArray : TypeArray
return result;
}
- override uinteger_t size(const ref Loc loc)
- {
- return target.ptrsize;
- }
-
override bool isZeroInit(const ref Loc loc)
{
return true;
@@ -2850,30 +2506,6 @@ extern (C++) final class TypeAArray : TypeArray
return true;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
- if (equals(to))
- return MATCH.exact;
-
- if (auto ta = to.isTypeAArray())
- {
- if (!MODimplicitConv(next.mod, ta.next.mod))
- return MATCH.nomatch; // not const-compatible
-
- if (!MODimplicitConv(index.mod, ta.index.mod))
- return MATCH.nomatch; // not const-compatible
-
- MATCH m = next.constConv(ta.next);
- MATCH mi = index.constConv(ta.index);
- if (m > MATCH.nomatch && mi > MATCH.nomatch)
- {
- return MODimplicitConv(mod, to.mod) ? MATCH.constant : MATCH.nomatch;
- }
- }
- return Type.implicitConvTo(to);
- }
-
override MATCH constConv(Type to)
{
if (auto taa = to.isTypeAArray())
@@ -2922,50 +2554,6 @@ extern (C++) final class TypePointer : TypeNext
return result;
}
- override uinteger_t size(const ref Loc loc)
- {
- return target.ptrsize;
- }
-
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypePointer::implicitConvTo(to = %s) %s\n", to.toChars(), toChars());
- if (equals(to))
- return MATCH.exact;
-
- // Only convert between pointers
- auto tp = to.isTypePointer();
- if (!tp)
- return MATCH.nomatch;
-
- assert(this.next);
- assert(tp.next);
-
- // Conversion to void*
- if (tp.next.ty == Tvoid)
- {
- // Function pointer conversion doesn't check constness?
- if (this.next.ty == Tfunction)
- return MATCH.convert;
-
- if (!MODimplicitConv(next.mod, tp.next.mod))
- return MATCH.nomatch; // not const-compatible
-
- return this.next.ty == Tvoid ? MATCH.constant : MATCH.convert;
- }
-
- // Conversion between function pointers
- if (auto thisTf = this.next.isTypeFunction())
- return thisTf.implicitPointerConv(tp.next);
-
- // Default, no implicit conversion between the pointer targets
- MATCH m = next.constConv(tp.next);
-
- if (m == MATCH.exact && mod != to.mod)
- m = MATCH.constant;
- return m;
- }
-
override MATCH constConv(Type to)
{
if (next.ty == Tfunction)
@@ -3020,11 +2608,6 @@ extern (C++) final class TypeReference : TypeNext
return result;
}
- override uinteger_t size(const ref Loc loc)
- {
- return target.ptrsize;
- }
-
override bool isZeroInit(const ref Loc loc)
{
return true;
@@ -3285,47 +2868,6 @@ extern (C++) final class TypeFunction : TypeNext
return newArgs;
}
- /+
- + Checks whether this function type is convertible to ` to`
- + when used in a function pointer / delegate.
- +
- + Params:
- + to = target type
- +
- + Returns:
- + MATCH.nomatch: `to` is not a covaraint function
- + MATCH.convert: `to` is a covaraint function
- + MATCH.exact: `to` is identical to this function
- +/
- private MATCH implicitPointerConv(Type to)
- {
- assert(to);
-
- if (this.equals(to))
- return MATCH.constant;
-
- if (this.covariant(to) == Covariant.yes)
- {
- Type tret = this.nextOf();
- Type toret = to.nextOf();
- if (tret.ty == Tclass && toret.ty == Tclass)
- {
- /* https://issues.dlang.org/show_bug.cgi?id=10219
- * Check covariant interface return with offset tweaking.
- * interface I {}
- * class C : Object, I {}
- * I function() dg = function C() {} // should be error
- */
- int offset = 0;
- if (toret.isBaseOf(tret, &offset) && offset != 0)
- return MATCH.nomatch;
- }
- return MATCH.convert;
- }
-
- return MATCH.nomatch;
- }
-
/** Extends TypeNext.constConv by also checking for matching attributes **/
override MATCH constConv(Type to)
{
@@ -3447,39 +2989,11 @@ extern (C++) final class TypeDelegate : TypeNext
return result;
}
- override uinteger_t size(const ref Loc loc)
- {
- return target.ptrsize * 2;
- }
-
override uint alignsize()
{
return target.ptrsize;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", this, to);
- //printf("from: %s\n", toChars());
- //printf("to : %s\n", to.toChars());
- if (this.equals(to))
- return MATCH.exact;
-
- if (auto toDg = to.isTypeDelegate())
- {
- MATCH m = this.next.isTypeFunction().implicitPointerConv(toDg.next);
-
- // Retain the old behaviour for this refactoring
- // Should probably be changed to constant to match function pointers
- if (m > MATCH.convert)
- m = MATCH.convert;
-
- return m;
- }
-
- return MATCH.nomatch;
- }
-
override bool isZeroInit(const ref Loc loc)
{
return true;
@@ -3534,11 +3048,6 @@ extern (C++) final class TypeTraits : Type
{
v.visit(this);
}
-
- override uinteger_t size(const ref Loc loc)
- {
- return SIZE_INVALID;
- }
}
/******
@@ -3648,12 +3157,6 @@ extern (C++) abstract class TypeQualified : Type
idents.push(e);
}
- override uinteger_t size(const ref Loc loc)
- {
- error(this.loc, "size of type `%s` is not known", toChars());
- return SIZE_INVALID;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3759,14 +3262,6 @@ extern (C++) final class TypeTypeof : TypeQualified
return t;
}
- override uinteger_t size(const ref Loc loc)
- {
- if (exp.type)
- return exp.type.size(loc);
- else
- return TypeQualified.size(loc);
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3825,11 +3320,6 @@ extern (C++) final class TypeStruct : Type
return "struct";
}
- override uinteger_t size(const ref Loc loc)
- {
- return sym.size(loc);
- }
-
override uint alignsize()
{
sym.size(Loc.initial); // give error for forward references
@@ -3895,7 +3385,7 @@ extern (C++) final class TypeStruct : Type
/* Copy from the initializer symbol for larger symbols,
* otherwise the literals expressed as code get excessively large.
*/
- if (size(loc) > target.ptrsize * 4 && !needsNested())
+ if (size(this, loc) > target.ptrsize * 4 && !needsNested())
structinit.useStaticInit = true;
structinit.type = this;
@@ -4028,7 +3518,7 @@ extern (C++) final class TypeStruct : Type
* The check should check for overlap of v with the previous field,
* not just starting at the same point
*/
- if (v.offset == offset) // v is at same offset as previous field
+ if (!global.params.fixImmutableConv && v.offset == offset) // v is at same offset as previous field
continue; // ignore
Type tvf = v.type.addMod(mod); // from type
@@ -4065,13 +3555,6 @@ extern (C++) final class TypeStruct : Type
return MATCH.nomatch;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to.toChars());
- MATCH m = implicitConvToWithoutAliasThis(to);
- return m == MATCH.nomatch ? implicitConvToThroughAliasThis(to) : m;
- }
-
override MATCH constConv(Type to)
{
if (equals(to))
@@ -4129,11 +3612,6 @@ extern (C++) final class TypeEnum : Type
return this;
}
- override uinteger_t size(const ref Loc loc)
- {
- return sym.getMemtype(loc).size(loc);
- }
-
Type memType()
{
return sym.getMemtype(Loc.initial);
@@ -4212,19 +3690,6 @@ extern (C++) final class TypeEnum : Type
return memType().needsNested();
}
- override MATCH implicitConvTo(Type to)
- {
- MATCH m;
- //printf("TypeEnum::implicitConvTo() %s to %s\n", toChars(), to.toChars());
- if (ty == to.ty && sym == (cast(TypeEnum)to).sym)
- m = (mod == to.mod) ? MATCH.exact : MATCH.constant;
- else if (sym.getMemtype(Loc.initial).implicitConvTo(to))
- m = MATCH.convert; // match with conversions
- else
- m = MATCH.nomatch; // no match
- return m;
- }
-
override MATCH constConv(Type to)
{
if (equals(to))
@@ -4292,11 +3757,6 @@ extern (C++) final class TypeClass : Type
return "class";
}
- override uinteger_t size(const ref Loc loc)
- {
- return target.ptrsize;
- }
-
override TypeClass syntaxCopy()
{
return this;
@@ -4337,13 +3797,6 @@ extern (C++) final class TypeClass : Type
return m;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to.toChars(), toChars());
- MATCH m = implicitConvToWithoutAliasThis(to);
- return m ? m : implicitConvToThroughAliasThis(to);
- }
-
override MATCH constConv(Type to)
{
if (equals(to))
@@ -4542,29 +3995,6 @@ extern (C++) final class TypeTuple : Type
return false;
}
- override MATCH implicitConvTo(Type to)
- {
- if (this == to)
- return MATCH.exact;
- if (auto tt = to.isTypeTuple())
- {
- if (arguments.length == tt.arguments.length)
- {
- MATCH m = MATCH.exact;
- for (size_t i = 0; i < tt.arguments.length; i++)
- {
- Parameter arg1 = (*arguments)[i];
- Parameter arg2 = (*tt.arguments)[i];
- MATCH mi = arg1.type.implicitConvTo(arg2.type);
- if (mi < m)
- m = mi;
- }
- return m;
- }
- }
- return MATCH.nomatch;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -4626,36 +4056,11 @@ extern (C++) final class TypeNull : Type
return this;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", this, to);
- //printf("from: %s\n", toChars());
- //printf("to : %s\n", to.toChars());
- MATCH m = Type.implicitConvTo(to);
- if (m != MATCH.nomatch)
- return m;
-
- // NULL implicitly converts to any pointer type or dynamic array
- //if (type.ty == Tpointer && type.nextOf().ty == Tvoid)
- {
- Type tb = to.toBasetype();
- if (tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tclass || tb.ty == Tdelegate)
- return MATCH.constant;
- }
-
- return MATCH.nomatch;
- }
-
override bool isBoolean()
{
return true;
}
- override uinteger_t size(const ref Loc loc)
- {
- return tvoidptr.size(loc);
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -4683,22 +4088,6 @@ extern (C++) final class TypeNoreturn : Type
return this;
}
- override MATCH implicitConvTo(Type to)
- {
- //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", this, to);
- //printf("from: %s\n", toChars());
- //printf("to : %s\n", to.toChars());
- if (this.equals(to))
- return MATCH.exact;
-
- // Different qualifiers?
- if (to.ty == Tnoreturn)
- return MATCH.constant;
-
- // Implicitly convertible to any type
- return MATCH.convert;
- }
-
override MATCH constConv(Type to)
{
// Either another noreturn or conversion to any type
@@ -4710,11 +4099,6 @@ extern (C++) final class TypeNoreturn : Type
return true; // bottom type can be implicitly converted to any other type
}
- override uinteger_t size(const ref Loc loc)
- {
- return 0;
- }
-
override uint alignsize()
{
return 0;
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index 1121711..11c27c6 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -228,8 +228,6 @@ public:
char *toPrettyChars(bool QualifyTypes = false);
static void _init();
- uinteger_t size();
- virtual uinteger_t size(const Loc &loc);
virtual unsigned alignsize();
void modToBuffer(OutBuffer& buf) const;
char *modToChars() const;
@@ -266,7 +264,6 @@ public:
virtual Type *makeSharedWildConst();
virtual Type *makeMutable();
Type *toBasetype();
- virtual MATCH implicitConvTo(Type *to);
virtual MATCH constConv(Type *to);
virtual unsigned char deduceWild(Type *t, bool isRef);
@@ -323,7 +320,6 @@ public:
const char *kind() override;
TypeError *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
Expression *defaultInitLiteral(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -358,7 +354,6 @@ public:
const char *kind() override;
TypeBasic *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
bool isintegral() override;
bool isfloating() override;
@@ -367,7 +362,6 @@ public:
bool iscomplex() override;
bool isscalar() override;
bool isunsigned() override;
- MATCH implicitConvTo(Type *to) override;
bool isZeroInit(const Loc &loc) override;
// For eliminating dynamic_cast
@@ -383,14 +377,12 @@ public:
static TypeVector *create(Type *basetype);
const char *kind() override;
TypeVector *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
bool isintegral() override;
bool isfloating() override;
bool isscalar() override;
bool isunsigned() override;
bool isBoolean() override;
- MATCH implicitConvTo(Type *to) override;
Expression *defaultInitLiteral(const Loc &loc) override;
TypeBasic *elementType();
bool isZeroInit(const Loc &loc) override;
@@ -413,13 +405,11 @@ public:
const char *kind() override;
TypeSArray *syntaxCopy() override;
bool isIncomplete();
- uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
bool isString() override;
bool isZeroInit(const Loc &loc) override;
structalign_t alignment() override;
MATCH constConv(Type *to) override;
- MATCH implicitConvTo(Type *to) override;
Expression *defaultInitLiteral(const Loc &loc) override;
bool hasUnsafeBitpatterns() override;
bool hasVoidInitPointers() override;
@@ -437,12 +427,10 @@ class TypeDArray final : public TypeArray
public:
const char *kind() override;
TypeDArray *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
bool isString() override;
bool isZeroInit(const Loc &loc) override;
bool isBoolean() override;
- MATCH implicitConvTo(Type *to) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -456,10 +444,8 @@ public:
static TypeAArray *create(Type *t, Type *index);
const char *kind() override;
TypeAArray *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
bool isZeroInit(const Loc &loc) override;
bool isBoolean() override;
- MATCH implicitConvTo(Type *to) override;
MATCH constConv(Type *to) override;
void accept(Visitor *v) override { v->visit(this); }
@@ -471,8 +457,6 @@ public:
static TypePointer *create(Type *t);
const char *kind() override;
TypePointer *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
- MATCH implicitConvTo(Type *to) override;
MATCH constConv(Type *to) override;
bool isscalar() override;
bool isZeroInit(const Loc &loc) override;
@@ -485,7 +469,6 @@ class TypeReference final : public TypeNext
public:
const char *kind() override;
TypeReference *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
bool isZeroInit(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -615,9 +598,7 @@ public:
static TypeDelegate *create(TypeFunction *t);
const char *kind() override;
TypeDelegate *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
- MATCH implicitConvTo(Type *to) override;
bool isZeroInit(const Loc &loc) override;
bool isBoolean() override;
@@ -634,7 +615,6 @@ class TypeTraits final : public Type
const char *kind() override;
TypeTraits *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -657,7 +637,6 @@ public:
// representing ident.ident!tiargs.ident. ... etc.
Objects idents;
- uinteger_t size(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -694,7 +673,6 @@ public:
const char *kind() override;
TypeTypeof *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -727,7 +705,6 @@ public:
static TypeStruct *create(StructDeclaration *sym);
const char *kind() override;
- uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
TypeStruct *syntaxCopy() override;
structalign_t alignment() override;
@@ -741,7 +718,6 @@ public:
bool hasVoidInitPointers() override;
bool hasUnsafeBitpatterns() override;
bool hasInvariant() override;
- MATCH implicitConvTo(Type *to) override;
MATCH constConv(Type *to) override;
unsigned char deduceWild(Type *t, bool isRef) override;
@@ -755,7 +731,6 @@ public:
const char *kind() override;
TypeEnum *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
Type *memType(const Loc &loc);
bool isintegral() override;
@@ -771,7 +746,6 @@ public:
bool needsDestruction() override;
bool needsCopyOrPostblit() override;
bool needsNested() override;
- MATCH implicitConvTo(Type *to) override;
MATCH constConv(Type *to) override;
bool isZeroInit(const Loc &loc) override;
bool hasVoidInitPointers() override;
@@ -790,10 +764,8 @@ public:
CPPMANGLE cppmangle;
const char *kind() override;
- uinteger_t size(const Loc &loc) override;
TypeClass *syntaxCopy() override;
ClassDeclaration *isClassHandle() override;
- MATCH implicitConvTo(Type *to) override;
MATCH constConv(Type *to) override;
unsigned char deduceWild(Type *t, bool isRef) override;
bool isZeroInit(const Loc &loc) override;
@@ -838,10 +810,8 @@ public:
const char *kind() override;
TypeNull *syntaxCopy() override;
- MATCH implicitConvTo(Type *to) override;
bool isBoolean() override;
- uinteger_t size(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -850,10 +820,8 @@ class TypeNoreturn final : public Type
public:
const char *kind() override;
TypeNoreturn *syntaxCopy() override;
- MATCH implicitConvTo(Type* to) override;
MATCH constConv(Type* to) override;
bool isBoolean() override;
- uinteger_t size(const Loc& loc) override;
unsigned alignsize() override;
void accept(Visitor *v) override { v->visit(this); }
@@ -902,4 +870,7 @@ namespace dmd
Type *addMod(Type *type, MOD mod);
Type *addStorageClass(Type *type, StorageClass stc);
Type *substWildTo(Type *type, unsigned mod);
+ uinteger_t size(Type *type);
+ uinteger_t size(Type *type, const Loc &loc);
+ MATCH implicitConvTo(Type* from, Type* to);
}
diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d
index 624210b..a922719 100644
--- a/gcc/d/dmd/objc.d
+++ b/gcc/d/dmd/objc.d
@@ -96,7 +96,7 @@ struct ObjcSelector
extern (C++) static ObjcSelector* create(FuncDeclaration fdecl)
{
OutBuffer buf;
- TypeFunction ftype = cast(TypeFunction)fdecl.type;
+ auto ftype = cast(TypeFunction)fdecl.type;
const id = fdecl.ident.toString();
const nparams = ftype.parameterList.length;
// Special case: property setter
@@ -571,7 +571,7 @@ extern(C++) private final class Supported : Objc
{
if (!fd.objc.selector)
return;
- TypeFunction tf = cast(TypeFunction)fd.type;
+ auto tf = cast(TypeFunction)fd.type;
if (fd.objc.selector.paramCount != tf.parameterList.parameters.length)
.error(fd.loc, "%s `%s` number of colons in Objective-C selector must match number of parameters", fd.kind, fd.toPrettyChars);
if (fd.parent && fd.parent.isTemplateInstance())
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index 2c89a58..ab1b67c 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -110,7 +110,7 @@ Expression expandVar(int result, VarDeclaration v)
}
if (ei.op == EXP.construct || ei.op == EXP.blit)
{
- AssignExp ae = cast(AssignExp)ei;
+ auto ae = cast(AssignExp)ei;
ei = ae.e2;
if (ei.isConst() == 1)
{
@@ -1238,18 +1238,21 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
if (expOptimize(e.e1, WANTvalue))
return;
const oror = e.op == EXP.orOr;
- if (e.e1.toBool().hasValue(oror))
+ void returnE_e1()
{
- // Replace with (e1, oror)
- ret = IntegerExp.createBool(oror);
- ret = Expression.combine(e.e1, ret);
- if (e.type.toBasetype().ty == Tvoid)
+ ret = e.e1;
+ if (!e.e1.type.equals(e.type))
{
- ret = new CastExp(e.loc, ret, Type.tvoid);
+ ret = new CastExp(e.loc, ret, e.type);
ret.type = e.type;
+ ret = optimize(ret, result, false);
}
- ret = optimize(ret, result, false);
- return;
+ }
+ if (e.e1.toBool().hasValue(oror))
+ {
+ // e_true || e2 -> e_true
+ // e_false && e2 -> e_false
+ return returnE_e1();
}
expOptimize(e.e2, WANTvalue);
if (e.e1.isConst())
@@ -1263,6 +1266,7 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
}
else if (e1Opt.hasValue(!oror))
{
+
if (e.type.toBasetype().ty == Tvoid)
ret = e.e2;
else
@@ -1272,6 +1276,29 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
}
}
}
+ else if (e.e2.isConst())
+ {
+ const e2Opt = e.e2.toBool();
+ if (e2Opt.hasValue(oror))
+ {
+ // e1 || true -> (e1, true)
+ // e1 && false -> (e1, false)
+ ret = IntegerExp.createBool(oror);
+ ret = Expression.combine(e.e1, ret);
+ if (e.type.toBasetype().ty == Tvoid)
+ {
+ ret = new CastExp(e.loc, ret, Type.tvoid);
+ ret.type = e.type;
+ }
+ ret = optimize(ret, result, false);
+ }
+ else if (e2Opt.hasValue(!oror))
+ {
+ // e1 || false -> e1
+ // e1 && true -> e1
+ return returnE_e1();
+ }
+ }
}
void visitCmp(CmpExp e)
diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d
index 5064ac2..f1bd6c9 100644
--- a/gcc/d/dmd/safe.d
+++ b/gcc/d/dmd/safe.d
@@ -17,6 +17,7 @@ import core.stdc.stdio;
import dmd.aggregate;
import dmd.astenums;
+import dmd.dcast : implicitConvTo;
import dmd.dclass;
import dmd.declaration;
import dmd.dscope;
@@ -26,7 +27,7 @@ import dmd.identifier;
import dmd.mtype;
import dmd.target;
import dmd.tokens;
-import dmd.typesem : hasPointers, arrayOf;
+import dmd.typesem : hasPointers, arrayOf, size;
import dmd.funcsem : setUnsafe, setUnsafePreview;
/*************************************************************
@@ -49,7 +50,7 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
//printf("checkUnsafeAccess(e: '%s', readonly: %d, printmsg: %d)\n", e.toChars(), readonly, printmsg);
if (e.op != EXP.dotVariable)
return false;
- DotVarExp dve = cast(DotVarExp)e;
+ auto dve = cast(DotVarExp)e;
if (VarDeclaration v = dve.var.isVarDeclaration())
{
if (!sc.func)
@@ -156,10 +157,11 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
* e = expression to be cast
* tfrom = type of e
* tto = type to cast e to
+ * msg = reason why cast is unsafe or deprecated
* Returns:
- * true if @safe
+ * true if @safe or deprecated
*/
-bool isSafeCast(Expression e, Type tfrom, Type tto)
+bool isSafeCast(Expression e, Type tfrom, Type tto, ref string msg)
{
// Implicit conversions are always safe
if (tfrom.implicitConvTo(tto))
@@ -175,18 +177,34 @@ bool isSafeCast(Expression e, Type tfrom, Type tto)
{
ClassDeclaration cdfrom = tfromb.isClassHandle();
ClassDeclaration cdto = ttob.isClassHandle();
-
int offset;
+
+ if (cdfrom == cdto)
+ goto Lsame;
+
if (!cdfrom.isBaseOf(cdto, &offset) &&
!((cdfrom.isInterfaceDeclaration() || cdto.isInterfaceDeclaration())
&& cdfrom.classKind == ClassKind.d && cdto.classKind == ClassKind.d))
+ {
+ msg = "Source object type is incompatible with target type";
return false;
+ }
+ // no RTTI
if (cdfrom.isCPPinterface() || cdto.isCPPinterface())
+ {
+ msg = "No dynamic type information for extern(C++) classes";
return false;
+ }
+ if (cdfrom.classKind == ClassKind.cpp || cdto.classKind == ClassKind.cpp)
+ msg = "No dynamic type information for extern(C++) classes";
+ Lsame:
if (!MODimplicitConv(tfromb.mod, ttob.mod))
+ {
+ msg = "Incompatible type qualifier";
return false;
+ }
return true;
}
@@ -210,22 +228,52 @@ bool isSafeCast(Expression e, Type tfrom, Type tto)
{
if (ttob.ty == Tarray && e.op == EXP.arrayLiteral)
return true;
+ msg = "`void` data may contain pointers and target element type is mutable";
return false;
}
// If the struct is opaque we don't know about the struct members then the cast becomes unsafe
- if (ttobn.ty == Tstruct && !(cast(TypeStruct)ttobn).sym.members ||
- tfromn.ty == Tstruct && !(cast(TypeStruct)tfromn).sym.members)
+ if (ttobn.ty == Tstruct && !(cast(TypeStruct)ttobn).sym.members)
+ {
+ msg = "Target element type is opaque";
+ return false;
+ }
+ if (tfromn.ty == Tstruct && !(cast(TypeStruct)tfromn).sym.members)
+ {
+ msg = "Source element type is opaque";
return false;
+ }
+
+ if (e.op != EXP.arrayLiteral)
+ {
+ // For bool, only 0 and 1 are safe values
+ // Runtime array cast reinterprets data
+ if (ttobn.ty == Tbool && tfromn.ty != Tbool)
+ msg = "Source element may have bytes which are not 0 or 1";
+ else if (ttobn.hasUnsafeBitpatterns())
+ msg = "Target element type has unsafe bit patterns";
+
+ // Can't alias a bool pointer with a non-bool pointer
+ if (ttobn.ty != Tbool && tfromn.ty == Tbool && ttobn.isMutable())
+ msg = "Target element could be assigned a byte which is not 0 or 1";
+ else if (tfromn.hasUnsafeBitpatterns() && ttobn.isMutable())
+ msg = "Source element type has unsafe bit patterns and target element type is mutable";
+ }
const frompointers = tfromn.hasPointers();
const topointers = ttobn.hasPointers();
if (frompointers && !topointers && ttobn.isMutable())
+ {
+ msg = "Target element type is mutable and source element type contains a pointer";
return false;
+ }
if (!frompointers && topointers)
+ {
+ msg = "Target element type contains a pointer";
return false;
+ }
if (!topointers &&
ttobn.ty != Tfunction && tfromn.ty != Tfunction &&
@@ -235,6 +283,7 @@ bool isSafeCast(Expression e, Type tfrom, Type tto)
return true;
}
}
+ msg = "Source type is incompatible with target type containing a pointer";
return false;
}
diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d
index 4bb3902..06a5eef 100644
--- a/gcc/d/dmd/semantic2.d
+++ b/gcc/d/dmd/semantic2.d
@@ -315,7 +315,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
return arrayHasInvalidEnumInitializer((cast(StructLiteralExp)e).elements);
if (e.op == EXP.assocArrayLiteral)
{
- AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e;
+ auto ae = cast(AssocArrayLiteralExp)e;
return arrayHasInvalidEnumInitializer(ae.values) ||
arrayHasInvalidEnumInitializer(ae.keys);
}
@@ -888,4 +888,11 @@ private extern(C++) final class StaticAAVisitor : SemanticTimeTransitiveVisitor
aaExp.lowering = loweredExp;
}
+
+ // https://issues.dlang.org/show_bug.cgi?id=24602
+ // TODO: Is this intionally not visited by SemanticTimeTransitiveVisitor?
+ override void visit(ClassReferenceExp crExp)
+ {
+ this.visit(crExp.value);
+ }
}
diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d
index 1d4745a..57a6639 100644
--- a/gcc/d/dmd/sideeffect.d
+++ b/gcc/d/dmd/sideeffect.d
@@ -18,6 +18,7 @@ import dmd.errors;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
+import dmd.funcsem;
import dmd.globals;
import dmd.id;
import dmd.identifier;
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
index a79b78a..81891ff 100644
--- a/gcc/d/dmd/statement.d
+++ b/gcc/d/dmd/statement.d
@@ -267,57 +267,58 @@ extern (C++) abstract class Statement : ASTNode
pure nothrow @nogc
inout(ReturnStatement) endsWithReturnStatement() inout { return null; }
- final pure inout nothrow @nogc @safe:
-
- /********************
- * A cheaper method of doing downcasting of Statements.
- * Returns:
- * the downcast statement if it can be downcasted, otherwise `null`
- */
- inout(ErrorStatement) isErrorStatement() { return stmt == STMT.Error ? cast(typeof(return))this : null; }
- inout(PeelStatement) isPeelStatement() { return stmt == STMT.Peel ? cast(typeof(return))this : null; }
- inout(ScopeStatement) isScopeStatement() { return stmt == STMT.Scope ? cast(typeof(return))this : null; }
- inout(ExpStatement) isExpStatement() { return stmt == STMT.Exp ? cast(typeof(return))this : null; }
- inout(CompoundStatement) isCompoundStatement() { return stmt == STMT.Compound ? cast(typeof(return))this : null; }
- inout(ReturnStatement) isReturnStatement() { return stmt == STMT.Return ? cast(typeof(return))this : null; }
- inout(IfStatement) isIfStatement() { return stmt == STMT.If ? cast(typeof(return))this : null; }
- inout(ConditionalStatement) isConditionalStatement() { return stmt == STMT.Conditional ? cast(typeof(return))this : null; }
- inout(StaticForeachStatement) isStaticForeachStatement() { return stmt == STMT.StaticForeach ? cast(typeof(return))this : null; }
- inout(CaseStatement) isCaseStatement() { return stmt == STMT.Case ? cast(typeof(return))this : null; }
- inout(DefaultStatement) isDefaultStatement() { return stmt == STMT.Default ? cast(typeof(return))this : null; }
- inout(LabelStatement) isLabelStatement() { return stmt == STMT.Label ? cast(typeof(return))this : null; }
- inout(GotoStatement) isGotoStatement() { return stmt == STMT.Goto ? cast(typeof(return))this : null; }
- inout(GotoDefaultStatement) isGotoDefaultStatement() { return stmt == STMT.GotoDefault ? cast(typeof(return))this : null; }
- inout(GotoCaseStatement) isGotoCaseStatement() { return stmt == STMT.GotoCase ? cast(typeof(return))this : null; }
- inout(BreakStatement) isBreakStatement() { return stmt == STMT.Break ? cast(typeof(return))this : null; }
- inout(DtorExpStatement) isDtorExpStatement() { return stmt == STMT.DtorExp ? cast(typeof(return))this : null; }
- inout(MixinStatement) isMixinStatement() { return stmt == STMT.Mixin ? cast(typeof(return))this : null; }
- inout(ForwardingStatement) isForwardingStatement() { return stmt == STMT.Forwarding ? cast(typeof(return))this : null; }
- inout(DoStatement) isDoStatement() { return stmt == STMT.Do ? cast(typeof(return))this : null; }
- inout(WhileStatement) isWhileStatement() { return stmt == STMT.While ? cast(typeof(return))this : null; }
- inout(ForStatement) isForStatement() { return stmt == STMT.For ? cast(typeof(return))this : null; }
- inout(ForeachStatement) isForeachStatement() { return stmt == STMT.Foreach ? cast(typeof(return))this : null; }
- inout(SwitchStatement) isSwitchStatement() { return stmt == STMT.Switch ? cast(typeof(return))this : null; }
- inout(ContinueStatement) isContinueStatement() { return stmt == STMT.Continue ? cast(typeof(return))this : null; }
- inout(WithStatement) isWithStatement() { return stmt == STMT.With ? cast(typeof(return))this : null; }
- inout(TryCatchStatement) isTryCatchStatement() { return stmt == STMT.TryCatch ? cast(typeof(return))this : null; }
- inout(ThrowStatement) isThrowStatement() { return stmt == STMT.Throw ? cast(typeof(return))this : null; }
- inout(DebugStatement) isDebugStatement() { return stmt == STMT.Debug ? cast(typeof(return))this : null; }
- inout(TryFinallyStatement) isTryFinallyStatement() { return stmt == STMT.TryFinally ? cast(typeof(return))this : null; }
- inout(ScopeGuardStatement) isScopeGuardStatement() { return stmt == STMT.ScopeGuard ? cast(typeof(return))this : null; }
- inout(SwitchErrorStatement) isSwitchErrorStatement() { return stmt == STMT.SwitchError ? cast(typeof(return))this : null; }
- inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; }
- inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; }
- inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; }
- inout(CompoundAsmStatement) isCompoundAsmStatement() { return stmt == STMT.CompoundAsm ? cast(typeof(return))this : null; }
- inout(PragmaStatement) isPragmaStatement() { return stmt == STMT.Pragma ? cast(typeof(return))this : null; }
- inout(StaticAssertStatement) isStaticAssertStatement() { return stmt == STMT.StaticAssert ? cast(typeof(return))this : null; }
- inout(CaseRangeStatement) isCaseRangeStatement() { return stmt == STMT.CaseRange ? cast(typeof(return))this : null; }
- inout(SynchronizedStatement) isSynchronizedStatement() { return stmt == STMT.Synchronized ? cast(typeof(return))this : null; }
- inout(AsmStatement) isAsmStatement() { return stmt == STMT.Asm ? cast(typeof(return))this : null; }
- inout(InlineAsmStatement) isInlineAsmStatement() { return stmt == STMT.InlineAsm ? cast(typeof(return))this : null; }
- inout(GccAsmStatement) isGccAsmStatement() { return stmt == STMT.GccAsm ? cast(typeof(return))this : null; }
- inout(ImportStatement) isImportStatement() { return stmt == STMT.Import ? cast(typeof(return))this : null; }
+ final pure inout nothrow @nogc @trusted
+ {
+ /********************
+ * A cheaper method of doing downcasting of Statements.
+ * Returns:
+ * the downcast statement if it can be downcasted, otherwise `null`
+ */
+ inout(ErrorStatement) isErrorStatement() { return stmt == STMT.Error ? cast(typeof(return))this : null; }
+ inout(PeelStatement) isPeelStatement() { return stmt == STMT.Peel ? cast(typeof(return))this : null; }
+ inout(ScopeStatement) isScopeStatement() { return stmt == STMT.Scope ? cast(typeof(return))this : null; }
+ inout(ExpStatement) isExpStatement() { return stmt == STMT.Exp ? cast(typeof(return))this : null; }
+ inout(CompoundStatement) isCompoundStatement() { return stmt == STMT.Compound ? cast(typeof(return))this : null; }
+ inout(ReturnStatement) isReturnStatement() { return stmt == STMT.Return ? cast(typeof(return))this : null; }
+ inout(IfStatement) isIfStatement() { return stmt == STMT.If ? cast(typeof(return))this : null; }
+ inout(ConditionalStatement) isConditionalStatement() { return stmt == STMT.Conditional ? cast(typeof(return))this : null; }
+ inout(StaticForeachStatement) isStaticForeachStatement() { return stmt == STMT.StaticForeach ? cast(typeof(return))this : null; }
+ inout(CaseStatement) isCaseStatement() { return stmt == STMT.Case ? cast(typeof(return))this : null; }
+ inout(DefaultStatement) isDefaultStatement() { return stmt == STMT.Default ? cast(typeof(return))this : null; }
+ inout(LabelStatement) isLabelStatement() { return stmt == STMT.Label ? cast(typeof(return))this : null; }
+ inout(GotoStatement) isGotoStatement() { return stmt == STMT.Goto ? cast(typeof(return))this : null; }
+ inout(GotoDefaultStatement) isGotoDefaultStatement() { return stmt == STMT.GotoDefault ? cast(typeof(return))this : null; }
+ inout(GotoCaseStatement) isGotoCaseStatement() { return stmt == STMT.GotoCase ? cast(typeof(return))this : null; }
+ inout(BreakStatement) isBreakStatement() { return stmt == STMT.Break ? cast(typeof(return))this : null; }
+ inout(DtorExpStatement) isDtorExpStatement() { return stmt == STMT.DtorExp ? cast(typeof(return))this : null; }
+ inout(MixinStatement) isMixinStatement() { return stmt == STMT.Mixin ? cast(typeof(return))this : null; }
+ inout(ForwardingStatement) isForwardingStatement() { return stmt == STMT.Forwarding ? cast(typeof(return))this : null; }
+ inout(DoStatement) isDoStatement() { return stmt == STMT.Do ? cast(typeof(return))this : null; }
+ inout(WhileStatement) isWhileStatement() { return stmt == STMT.While ? cast(typeof(return))this : null; }
+ inout(ForStatement) isForStatement() { return stmt == STMT.For ? cast(typeof(return))this : null; }
+ inout(ForeachStatement) isForeachStatement() { return stmt == STMT.Foreach ? cast(typeof(return))this : null; }
+ inout(SwitchStatement) isSwitchStatement() { return stmt == STMT.Switch ? cast(typeof(return))this : null; }
+ inout(ContinueStatement) isContinueStatement() { return stmt == STMT.Continue ? cast(typeof(return))this : null; }
+ inout(WithStatement) isWithStatement() { return stmt == STMT.With ? cast(typeof(return))this : null; }
+ inout(TryCatchStatement) isTryCatchStatement() { return stmt == STMT.TryCatch ? cast(typeof(return))this : null; }
+ inout(ThrowStatement) isThrowStatement() { return stmt == STMT.Throw ? cast(typeof(return))this : null; }
+ inout(DebugStatement) isDebugStatement() { return stmt == STMT.Debug ? cast(typeof(return))this : null; }
+ inout(TryFinallyStatement) isTryFinallyStatement() { return stmt == STMT.TryFinally ? cast(typeof(return))this : null; }
+ inout(ScopeGuardStatement) isScopeGuardStatement() { return stmt == STMT.ScopeGuard ? cast(typeof(return))this : null; }
+ inout(SwitchErrorStatement) isSwitchErrorStatement() { return stmt == STMT.SwitchError ? cast(typeof(return))this : null; }
+ inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; }
+ inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; }
+ inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; }
+ inout(CompoundAsmStatement) isCompoundAsmStatement() { return stmt == STMT.CompoundAsm ? cast(typeof(return))this : null; }
+ inout(PragmaStatement) isPragmaStatement() { return stmt == STMT.Pragma ? cast(typeof(return))this : null; }
+ inout(StaticAssertStatement) isStaticAssertStatement() { return stmt == STMT.StaticAssert ? cast(typeof(return))this : null; }
+ inout(CaseRangeStatement) isCaseRangeStatement() { return stmt == STMT.CaseRange ? cast(typeof(return))this : null; }
+ inout(SynchronizedStatement) isSynchronizedStatement() { return stmt == STMT.Synchronized ? cast(typeof(return))this : null; }
+ inout(AsmStatement) isAsmStatement() { return stmt == STMT.Asm ? cast(typeof(return))this : null; }
+ inout(InlineAsmStatement) isInlineAsmStatement() { return stmt == STMT.InlineAsm ? cast(typeof(return))this : null; }
+ inout(GccAsmStatement) isGccAsmStatement() { return stmt == STMT.GccAsm ? cast(typeof(return))this : null; }
+ inout(ImportStatement) isImportStatement() { return stmt == STMT.Import ? cast(typeof(return))this : null; }
+ }
}
/***********************************************************
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index d0e1b9a..c5c8a12 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -1381,7 +1381,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
p.type = p.type.addStorageClass(sc).typeSemantic(loc, sc2);
if (!exp.implicitConvTo(p.type))
{
- error(fs.loc, "cannot implicilty convert range element of type `%s` to variable `%s` of type `%s`",
+ error(fs.loc, "cannot implicitly convert tuple element of type `%s` to variable `%s` of type `%s`",
exp.type.toChars(), p.toChars(), p.type.toChars());
return retError();
}
diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d
index dadf519..d86be85 100644
--- a/gcc/d/dmd/target.d
+++ b/gcc/d/dmd/target.d
@@ -25,6 +25,8 @@
module dmd.target;
+import core.stdc.stdio;
+
import dmd.astenums : CHECKENABLE;
import dmd.globals : Param;
@@ -344,8 +346,8 @@ struct TargetCPP
enum Runtime : ubyte
{
Unspecified,
- Clang,
- Gcc,
+ LLVM,
+ GNU,
Microsoft,
Sun
}
diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h
index a5caa74..a380bb8 100644
--- a/gcc/d/dmd/target.h
+++ b/gcc/d/dmd/target.h
@@ -84,8 +84,8 @@ struct TargetCPP
enum class Runtime : unsigned char
{
Unspecified,
- Clang,
- Gcc,
+ LLVM,
+ GNU,
Microsoft,
Sun
};
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index 31ebc4c..33d825a 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -1299,6 +1299,152 @@ Type getIndirection(Type t)
return null;
}
+uinteger_t size(Type t)
+{
+ return size(t, Loc.initial);
+}
+
+uinteger_t size(Type t, const ref Loc loc)
+{
+
+ uinteger_t visitType(Type t)
+ {
+ error(loc, "no size for type `%s`", t.toChars());
+ return SIZE_INVALID;
+ }
+
+ uinteger_t visitBasic(TypeBasic t)
+ {
+ uint size;
+ //printf("TypeBasic::size()\n");
+ switch (t.ty)
+ {
+ case Tint8:
+ case Tuns8:
+ size = 1;
+ break;
+
+ case Tint16:
+ case Tuns16:
+ size = 2;
+ break;
+
+ case Tint32:
+ case Tuns32:
+ case Tfloat32:
+ case Timaginary32:
+ size = 4;
+ break;
+
+ case Tint64:
+ case Tuns64:
+ case Tfloat64:
+ case Timaginary64:
+ size = 8;
+ break;
+
+ case Tfloat80:
+ case Timaginary80:
+ size = target.realsize;
+ break;
+
+ case Tcomplex32:
+ size = 8;
+ break;
+
+ case Tcomplex64:
+ case Tint128:
+ case Tuns128:
+ size = 16;
+ break;
+
+ case Tcomplex80:
+ size = target.realsize * 2;
+ break;
+
+ case Tvoid:
+ //size = Type::size(); // error message
+ size = 1;
+ break;
+
+ case Tbool:
+ size = 1;
+ break;
+
+ case Tchar:
+ size = 1;
+ break;
+
+ case Twchar:
+ size = 2;
+ break;
+
+ case Tdchar:
+ size = 4;
+ break;
+
+ default:
+ assert(0);
+ }
+
+ //printf("TypeBasic::size() = %d\n", size);
+ return size;
+ }
+
+ uinteger_t visitSArray(TypeSArray t)
+ {
+ //printf("TypeSArray::size()\n");
+ const n = t.numberOfElems(loc);
+ const elemsize = t.baseElemOf().size(loc);
+ bool overflow = false;
+ const sz = mulu(n, elemsize, overflow);
+ if (overflow || sz >= uint.max)
+ {
+ if (elemsize != SIZE_INVALID && n != uint.max)
+ error(loc, "static array `%s` size overflowed to %lld", t.toChars(), cast(long)sz);
+ return SIZE_INVALID;
+ }
+ return sz;
+
+ }
+
+ uinteger_t visitTypeQualified(TypeQualified t)
+ {
+ if (t.ty == Ttypeof)
+ {
+ auto type = (cast(TypeTypeof)t).exp.type;
+ if (type)
+ return type.size(loc);
+ }
+
+ error(t.loc, "size of type `%s` is not known", t.toChars());
+ return SIZE_INVALID;
+ }
+
+ switch(t.ty)
+ {
+ default: return t.isTypeBasic() ? visitBasic(t.isTypeBasic()) : visitType(t);
+ case Ttraits:
+ case Terror: return SIZE_INVALID;
+ case Tvector: return t.isTypeVector().basetype.size();
+ case Tsarray: return visitSArray(t.isTypeSArray());
+ case Tdelegate:
+ case Tarray: return target.ptrsize * 2;
+ case Tpointer:
+ case Treference:
+ case Tclass:
+ case Taarray: return target.ptrsize;
+ case Tident:
+ case Tinstance:
+ case Ttypeof:
+ case Treturn: return visitTypeQualified(cast(TypeQualified)t);
+ case Tstruct: return t.isTypeStruct().sym.size(loc);
+ case Tenum: return t.isTypeEnum().sym.getMemtype(loc).size(loc);
+ case Tnull: return t.tvoidptr.size(loc);
+ case Tnoreturn: return 0;
+ }
+}
+
/******************************************
* Perform semantic analysis on a type.
* Params:
diff --git a/gcc/d/dmd/visitor.d b/gcc/d/dmd/visitor.d
index abfd8ca..9082909 100644
--- a/gcc/d/dmd/visitor.d
+++ b/gcc/d/dmd/visitor.d
@@ -162,6 +162,11 @@ extern (C++) class SemanticTimeTransitiveVisitor : SemanticTimePermissiveVisitor
}
}
+ override void visit(ASTCodegen.ClassReferenceExp e)
+ {
+ e.value.accept(this);
+ }
+
override void visit(ASTCodegen.CompoundLiteralExp e)
{
if (e.initializer)