/* Search for type matching size and signedness. */
if (unsignedp != dtype->isunsigned ()
- || size != dtype->size ())
+ || size != dmd::size (dtype))
continue;
return dmd::addMod (dtype, mod);
dtype = Type::basic[i];
/* Search for type matching size. */
- if (dtype->size () != size)
+ if (dmd::size (dtype) != size)
continue;
return dmd::addMod (dtype, mod);
dtype = Type::basic[i];
/* Search for type matching size. */
- if (dtype->size () != size)
+ if (dmd::size (dtype) != size)
continue;
return dmd::addMod (dtype, mod);
break;
dtype = dmd::addMod (dmd::sarrayOf (dtype, nunits), mod);
- if (target.isVectorTypeSupported (dtype->size (), dtype->nextOf ()))
+ if (target.isVectorTypeSupported (dmd::size (dtype), dtype->nextOf ()))
break;
dtype = dmd::addMod (TypeVector::create (dtype), mod);
if (((tb1->isTypePointer () && tb2->isTypePointer ())
|| (tb1->isTypeVector () && tb2->isTypeVector ()))
- && tb1->implicitConvTo (tb2) != MATCH::nomatch)
+ && dmd::implicitConvTo (tb1, tb2) != MATCH::nomatch)
return true;
if (tb1->isintegral () == tb2->isintegral ()
- && tb1->size () == tb2->size ())
+ && dmd::size (tb1) == dmd::size (tb2))
return true;
return false;
if (offset != vd->offset)
return false;
- offset += vd->type->size ();
+ offset += dmd::size (vd->type);
}
}
return false;
/* Only consider it as `pure' if it can't modify its arguments. */
- if (func->isPure () == PURE::const_)
+ if (dmd::isPure (func) == PURE::const_)
return true;
}
case TY::Tstruct:
if (tbtype->ty == TY::Tstruct)
{
- if (totype->size () == etype->size ())
+ if (dmd::size (totype) == dmd::size (etype))
{
/* Allowed to cast to structs with same type size. */
result = build_vconvert (build_ctype (totype), exp);
else if (tbtype->ty == TY::Tarray)
{
dinteger_t dim = ebtype->isTypeSArray ()->dim->toInteger ();
- dinteger_t esize = ebtype->nextOf ()->size ();
- dinteger_t tsize = tbtype->nextOf ()->size ();
+ dinteger_t esize = dmd::size (ebtype->nextOf ());
+ dinteger_t tsize = dmd::size (tbtype->nextOf ());
tree ptrtype = build_ctype (dmd::pointerTo (tbtype->nextOf ()));
{
/* And allows casting a static array to any struct type too.
Type sizes should have already been checked by the frontend. */
- gcc_assert (totype->size () == etype->size ());
+ gcc_assert (dmd::size (totype) == dmd::size (etype));
result = build_vconvert (build_ctype (totype), exp);
}
- else if (tbtype->ty == TY::Tvector && tbtype->size () == ebtype->size ())
+ else if (tbtype->ty == TY::Tvector
+ && dmd::size (tbtype) == dmd::size (ebtype))
{
/* Allow casting from array to vector as if its an unaligned load. */
tree type = build_ctype (totype);
else if (tbtype->ty == TY::Tarray)
{
/* Assume tvoid->size() == 1. */
- dinteger_t fsize = ebtype->nextOf ()->toBasetype ()->size ();
- dinteger_t tsize = tbtype->nextOf ()->toBasetype ()->size ();
+ dinteger_t fsize = dmd::size (ebtype->nextOf ()->toBasetype ());
+ dinteger_t tsize = dmd::size (tbtype->nextOf ()->toBasetype ());
if (fsize != tsize)
{
case TY::Tvector:
if (tbtype->ty == TY::Tsarray)
{
- if (tbtype->size () == ebtype->size ())
+ if (dmd::size (tbtype) == dmd::size (ebtype))
return build_vconvert (build_ctype (totype), exp);
}
break;
&& valist_array_p (decl->type));
/* OK if conversion between types is allowed. */
- if (type->implicitConvTo (totype) != MATCH::nomatch)
+ if (dmd::implicitConvTo (type, totype) != MATCH::nomatch)
return;
if (in_assignment)
return true;
/* Type system allows implicit conversion between. */
- if (tx->implicitConvTo (ty) != MATCH::nomatch
- || ty->implicitConvTo (tx) != MATCH::nomatch)
+ if (dmd::implicitConvTo (tx, ty) != MATCH::nomatch
+ || dmd::implicitConvTo (ty, tx) != MATCH::nomatch)
return true;
}
/* In [simd/vector extensions], which vector types are supported depends on
the target. The implementation is expected to only support the vector
types that are implemented in the target's hardware. */
- unsigned HOST_WIDE_INT nunits = sz / type->size ();
+ unsigned HOST_WIDE_INT nunits = sz / dmd::size (type);
tree ctype = build_vector_type (build_ctype (type), nunits);
if (!targetm.vector_mode_supported_p (TYPE_MODE (ctype)))
return false;
Type *tn = tf->next->toBasetype ();
- if (tn->size () == SIZE_INVALID)
+ if (dmd::size (tn) == SIZE_INVALID)
return false;
return (tn->ty == TY::Tstruct || tn->ty == TY::Tsarray);
{
/* See note in Target::isReturnOnStack. */
Type *tb = param_type->toBasetype ();
- if (tb->size () == SIZE_INVALID)
+ if (dmd::size (tb) == SIZE_INVALID)
return false;
return (tb->ty == TY::Tstruct || tb->ty == TY::Tsarray);
return;
/* How big a symbol can be should depend on back-end. */
- tree size = build_integer_cst (d->type->size (d->loc),
+ tree size = build_integer_cst (dmd::size (d->type, d->loc),
build_ctype (Type::tsize_t));
if (!valid_constant_size_p (size))
{
-07bc5b9b3c81cc0d4314e0040de981124b363ea5
+66b93fc24a7ab5e2a8aa7f53c613df4abddc188b
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
| [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
import dmd.location;
import dmd.mtype;
import dmd.tokens;
-import dmd.typesem : defaultInit, addMod;
+import dmd.typesem : defaultInit, addMod, size;
import dmd.visitor;
/**
import core.stdc.stdio;
import dmd.arraytypes;
import dmd.astenums;
+import dmd.dcast : implicitConvTo;
import dmd.declaration;
import dmd.dscope;
import dmd.dsymbol;
import dmd.identifier;
import dmd.location;
import dmd.mtype;
+import dmd.typesem;
import dmd.target;
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)
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))
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");
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))
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))
import dmd.dmodule;
import dmd.expression;
import dmd.mtype;
+import dmd.typesem;
import dmd.root.array;
extern (C++) __gshared
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":
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;
import dmd.common.outbuffer;
import dmd.root.rmem;
import dmd.tokens;
+import dmd.typesem : size;
/***********************************************************
*/
* 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.
*/
* 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;
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;
* 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));
* 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)
}
Specifier specifier;
- specifier.packalign = this.packalign;
+ specifier.packalign = packalign.isUnknown ? this.packalign : packalign;
auto tspec = cparseSpecifierQualifierList(LVL.member, specifier);
if (!tspec)
{
/// Set to the result of the comparison
private bool result;
- public this(RootObject base) @safe
+ public this(RootObject base) @trusted
{
switch (base.dyncast())
{
import dmd.astenums;
import dmd.constfold;
import dmd.compiler;
+import dmd.dcast : implicitConvTo;
import dmd.dclass;
import dmd.declaration;
import dmd.dinterpret;
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);
}
/***********************************************************
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
*/
import dmd.astenums;
import dmd.dclass;
import dmd.declaration;
+import dmd.denum;
import dmd.dinterpret;
import dmd.dscope;
import dmd.dstruct;
}
}
+/********************************
+ * 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.
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:
bool isCodeseg() const override final;
bool isOverloadable() const override final;
bool isAbstract() override final;
- PURE isPure();
bool isSafe();
bool isTrusted();
bool isNogc();
* 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
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;
{
Type t = f.originalType ? f.originalType : f.type;
if (t.ty == Tfunction)
- return cast(TypeFunction)t;
+ return (() @trusted => cast(TypeFunction)t)();
}
return null;
}
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())
{
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;
// 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
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();
enum IDX_NOTFOUND = 0x12345678;
-pure nothrow @nogc @safe
+pure nothrow @nogc @trusted
{
/********************************************
return cast(inout(TemplateParameter))o;
}
+} // end @trusted casts
+
+pure nothrow @nogc @safe
+{
+
/**************************************
* Is this Object an error?
*/
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.
{
auto t2 = isType(o2);
if (!t2)
- goto Lnomatch;
+ return no();
static if (log)
{
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)
{
// 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)
{
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)
{
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();
}
/************************************
import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
+import dmd.dcast : implicitConvTo;
import dmd.dclass;
import dmd.declaration;
import dmd.dimport;
* 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)
{
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; }
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);
if (auto fmResult = global.fileManager.getFileContents(fileName))
{
se = new StringExp(e.loc, fmResult);
+ se.hexString = true;
}
else
{
}
// 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.
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
{
}
}
}
+
+ 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;
(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
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())
{
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;
}
}
- /********************************************
- * 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:
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.
*/
/* 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)
{
}
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;
+ }
+}
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")
buf.writeByte(' ');
}
}
- t.attributesApply(&ignoreReturn);
+ t.attributesApply(&dg);
if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen)
{
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");
}
{ "define" },
{ "undef" },
{ "ident" },
+ { "packed" },
];
import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
+import dmd.dcast : implicitConvTo;
import dmd.dclass;
import dmd.declaration;
import dmd.denum;
import dmd.enumsem;
import dmd.errors;
import dmd.expression;
-import dmd.funcsem;
import dmd.globals;
import dmd.hdrgen;
import dmd.id;
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);
}
/*********************************
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.
}
}
- 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; }
return this;
}
- override uinteger_t size(const ref Loc loc)
- {
- return SIZE_INVALID;
- }
-
override Expression defaultInitLiteral(const ref Loc loc)
{
return ErrorExp.get();
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);
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)
return new TypeVector(basetype.syntaxCopy());
}
- override uinteger_t size(const ref Loc loc)
- {
- return basetype.size();
- }
-
override uint alignsize()
{
return cast(uint)basetype.size();
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");
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();
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)
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
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);
return result;
}
- override uinteger_t size(const ref Loc loc)
- {
- return target.ptrsize;
- }
-
override bool isZeroInit(const ref Loc loc)
{
return true;
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())
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)
return result;
}
- override uinteger_t size(const ref Loc loc)
- {
- return target.ptrsize;
- }
-
override bool isZeroInit(const ref Loc loc)
{
return true;
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)
{
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;
{
v.visit(this);
}
-
- override uinteger_t size(const ref Loc loc)
- {
- return SIZE_INVALID;
- }
}
/******
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);
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);
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
/* 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;
* 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
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))
return this;
}
- override uinteger_t size(const ref Loc loc)
- {
- return sym.getMemtype(loc).size(loc);
- }
-
Type memType()
{
return sym.getMemtype(Loc.initial);
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))
return "class";
}
- override uinteger_t size(const ref Loc loc)
- {
- return target.ptrsize;
- }
-
override TypeClass syntaxCopy()
{
return this;
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))
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);
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);
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
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;
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;
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);
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); }
};
const char *kind() override;
TypeBasic *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
bool isintegral() override;
bool isfloating() override;
bool iscomplex() override;
bool isscalar() override;
bool isunsigned() override;
- MATCH implicitConvTo(Type *to) override;
bool isZeroInit(const Loc &loc) override;
// For eliminating dynamic_cast
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;
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;
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); }
};
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); }
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;
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); }
};
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;
const char *kind() override;
TypeTraits *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
// representing ident.ident!tiargs.ident. ... etc.
Objects idents;
- uinteger_t size(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
const char *kind() override;
TypeTypeof *syntaxCopy() override;
- uinteger_t size(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
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;
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;
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;
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;
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;
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); }
};
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); }
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);
}
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
{
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())
}
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)
{
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())
}
else if (e1Opt.hasValue(!oror))
{
+
if (e.type.toBasetype().ty == Tvoid)
ret = e.e2;
else
}
}
}
+ 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)
import dmd.aggregate;
import dmd.astenums;
+import dmd.dcast : implicitConvTo;
import dmd.dclass;
import dmd.declaration;
import dmd.dscope;
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;
/*************************************************************
//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)
* 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))
{
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;
}
{
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 &&
return true;
}
}
+ msg = "Source type is incompatible with target type containing a pointer";
return false;
}
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);
}
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);
+ }
}
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
+import dmd.funcsem;
import dmd.globals;
import dmd.id;
import dmd.identifier;
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; }
+ }
}
/***********************************************************
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();
}
module dmd.target;
+import core.stdc.stdio;
+
import dmd.astenums : CHECKENABLE;
import dmd.globals : Param;
enum Runtime : ubyte
{
Unspecified,
- Clang,
- Gcc,
+ LLVM,
+ GNU,
Microsoft,
Sun
}
enum class Runtime : unsigned char
{
Unspecified,
- Clang,
- Gcc,
+ LLVM,
+ GNU,
Microsoft,
Sun
};
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:
}
}
+ override void visit(ASTCodegen.ClassReferenceExp e)
+ {
+ e.value.accept(this);
+ }
+
override void visit(ASTCodegen.CompoundLiteralExp e)
{
if (e.initializer)
if (t1elem->ty != TY::Tstruct
|| identity_compare_p (t1elem->isTypeStruct ()->sym))
{
- tree size = size_mult_expr (t1len, size_int (t1elem->size ()));
+ tree size =
+ size_mult_expr (t1len, size_int (dmd::size (t1elem)));
result = build_memcmp_call (t1ptr, t2ptr, size);
result = build_boolop (code, result, integer_zero_node);
The frontend should have already guaranteed that static arrays
have same size. */
if (tb1->ty == TY::Tsarray && tb2->ty == TY::Tsarray)
- gcc_assert (tb1->size () == tb2->size ());
+ gcc_assert (dmd::size (tb1) == dmd::size (tb2));
else
{
tree tlencmp = build_boolop (code, t1len, t2len);
if (integer_zerop (t2))
{
tree size = size_mult_expr (d_array_length (t1),
- size_int (etype->size ()));
+ size_int (dmd::size (etype)));
result = build_memset_call (d_array_ptr (t1), size);
}
else
tree t2ptr = d_array_ptr (t2);
/* Generate: memcpy(to, from, size) */
- tree size = size_mult_expr (t1len, size_int (etype->size ()));
+ tree size =
+ size_mult_expr (t1len, size_int (dmd::size (etype)));
tree result = build_memcpy_call (t1ptr, t2ptr, size);
/* Insert check that array lengths match and do not overlap. */
{
/* Generate: _d_arraycopy() */
this->result_ = build_libcall (LIBCALL_ARRAYCOPY, e->type, 3,
- size_int (etype->size ()),
+ size_int (dmd::size (etype)),
d_array_convert (e->e2),
d_array_convert (e->e1));
}
|| (e->op == EXP::construct && e->e2->op == EXP::arrayLiteral)
|| (e->op == EXP::construct && e->e2->op == EXP::call)
|| (e->op == EXP::construct && !lvalue && postblit)
- || (e->op == EXP::blit || e->e1->type->size () == 0))
+ || (e->op == EXP::blit || dmd::size (e->e1->type) == 0))
{
tree t1 = build_expr (e->e1);
tree t2 = convert_for_assignment (e->e2, e->e1->type);
/* Index the associative array. */
tree result = build_libcall (libcall, dmd::pointerTo (e->type), 4,
ptr, tinfo,
- size_int (tb1->nextOf ()->size ()),
+ size_int (dmd::size (tb1->nextOf ())),
build_address (key));
if (!e->indexIsInBounds && array_bounds_check ())
/* Allocating memory for a new pointer. */
TypePointer *tpointer = tb->isTypePointer ();
- if (tpointer->next->size () == 0)
+ if (dmd::size (tpointer->next) == 0)
{
/* Pointer element size is unknown. */
this->result_ = d_convert (build_ctype (e->type),
/* Now copy the constructor into memory. */
tree size = size_mult_expr (size_int (e->elements->length),
- size_int (tb->nextOf ()->size ()));
+ size_int (dmd::size (tb->nextOf ())));
tree result = build_memcpy_call (mem, build_address (ctor), size);
/* Default initializer for enum. */
if (ed->members && !d->tinfo->isZeroInit ())
{
- tree length = size_int (ed->type->size ());
+ tree length = size_int (dmd::size (ed->type));
tree ptr = build_address (enum_initializer_decl (ed));
this->layout_field (d_array_value (array_type_node, length, ptr));
}
TYPE_UNSIGNED (t->ctype) = TYPE_UNSIGNED (basetype);
SET_TYPE_ALIGN (t->ctype, TYPE_ALIGN (basetype));
TYPE_SIZE (t->ctype) = NULL_TREE;
- TYPE_PRECISION (t->ctype) = t->size (t->sym->loc) * 8;
+ TYPE_PRECISION (t->ctype) = dmd::size (t, t->sym->loc) * 8;
layout_type (t->ctype);
import core.stdc.stdio;
-version (CppRuntime_Clang) version = CppMangle_Itanium;
-version (CppRuntime_Gcc) version = CppMangle_Itanium;
+version (CppRuntime_LLVM) version = CppMangle_Itanium;
+version (CppRuntime_GNU) version = CppMangle_Itanium;
version (CppRuntime_Microsoft) version = CppMangle_MSVC;
version (CppRuntime_Sun) version = CppMangle_Itanium;
// https://issues.dlang.org/show_bug.cgi?id=19920
module cppmangle3;
-version (CppRuntime_Clang) version = CppMangle_Itanium;
-version (CppRuntime_Gcc) version = CppMangle_Itanium;
+version (CppRuntime_LLVM) version = CppMangle_Itanium;
+version (CppRuntime_GNU) version = CppMangle_Itanium;
version (CppRuntime_Microsoft) version = CppMangle_MSVC;
version (CppRuntime_Sun) version = CppMangle_Itanium;
return this;
}
- ref SafeS foo3() return scope
+ ref SafeS foo3() scope
{
static SafeS s;
return s;
}
+ ref SafeS foo4() scope return
+ {
+ return this;
+ }
+
int* p;
}
--- /dev/null
+// REQUIRED_ARGS: -Jcompilable/imports/
+// EXTRA_FILES: imports/imp16088.d imports/test21227/a..b.txt imports/test21227/a.txt imports/test21227/..foo/a.txt
+
+// https://issues.dlang.org/show_bug.cgi?id=16088
+
+void bar(string x) {}
+auto foo()
+{
+ import("imp16088.d").bar;
+}
+
+
+// https://issues.dlang.org/show_bug.cgi?id=21227
+
+void test21227()
+{
+ import("./test21227/a.txt").bar;
+ import("test21227//a..b.txt").bar;
+ import("test21227/..foo/a.txt").bar;
+
+ version(Windows)
+ {
+ import(r".\test21227\a.txt").bar;
+ import(r"test21227\\a..b.txt").bar;
+ import(r"test21227\..foo\a.txt").bar;
+ }
+}
+
+// Test that it's treated like a hex string, allowing implicit conversion to byte array
+
+// Can't test whole contents because line endings may vary
+enum expectedStart = "module imports.imp16088;";
+
+immutable ubyte[] s0 = import("imp16088.d");
+
+static assert(s0[0 .. expectedStart.length] == "module imports.imp16088;");
-version (CppRuntime_Clang) version = CppMangle_Itanium;
-version (CppRuntime_Gcc) version = CppMangle_Itanium;
-version (CppRuntime_Sun) version = CppMangle_Itanium;
+version (CppRuntime_LLVM) version = CppMangle_Itanium;
+version (CppRuntime_GNU) version = CppMangle_Itanium;
+version (CppRuntime_Sun) version = CppMangle_Itanium;
template ScopeClass(C , string name = C.stringof)
//if (is(C == class) && __traits(getLinkage, C) == "C++")
-version (CppRuntime_Clang) version = CppMangle_Itanium;
-version (CppRuntime_Gcc) version = CppMangle_Itanium;
+version (CppRuntime_LLVM) version = CppMangle_Itanium;
+version (CppRuntime_GNU) version = CppMangle_Itanium;
version (CppRuntime_Sun) version = CppMangle_Itanium;
template ScopeClass(C)
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=24566
+
+void test24566a()
+{
+ enum a = true;
+ bool b = true;
+ enum str = "a";
+ if (a && str.length > 1 && str[1] == 'a') {}
+ if (b && str.length > 1 && str[1] == 'a') {}
+ if (!b && str.length > 1 && str[1] == 'a') {}
+ if (str.length > 1 && b && str[1] == 'a') {}
+}
+
+void test24566b()
+{
+ enum a = false;
+ bool b = false;
+ enum str = "a";
+ if (a || str.length <= 1 || str[1] == 'a') {}
+ if (b || str.length <= 1 || str[1] == 'a') {}
+ if (!b || str.length <= 1 || str[1] == 'a') {}
+ if (str.length <= 1 || b || str[1] == 'a') {}
+}
+++ /dev/null
-// REQUIRED_ARGS: -Jcompilable/imports/
-// EXTRA_FILES: imports/imp16088.d
-
-// https://issues.dlang.org/show_bug.cgi?id=16088
-
-void bar(string x) {}
-auto foo()
-{
- import("imp16088.d").bar;
-}
+++ /dev/null
-// REQUIRED_ARGS: -Jcompilable/imports
-// EXTRA_FILES: imports/test21227/a..b.txt imports/test21227/a.txt imports/test21227/..foo/a.txt
-
-// https://issues.dlang.org/show_bug.cgi?id=21227
-
-void bar(string x) {}
-void test21227()
-{
- import("./test21227/a.txt").bar;
- import("test21227//a..b.txt").bar;
- import("test21227/..foo/a.txt").bar;
-
- version(Windows)
- {
- import(r".\test21227\a.txt").bar;
- import(r"test21227\\a..b.txt").bar;
- import(r"test21227\..foo\a.txt").bar;
- }
-}
--- /dev/null
+/*
+REQUIRED_ARGS: -de -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/bool_cast.d(17): Deprecation: cast from `ubyte[]` to `bool[]` not allowed in safe code
+fail_compilation/bool_cast.d(17): Source element may have bytes which are not 0 or 1
+fail_compilation/bool_cast.d(22): Deprecation: cast from `int*` to `bool*` not allowed in safe code
+fail_compilation/bool_cast.d(22): Source element may have bytes which are not 0 or 1
+fail_compilation/bool_cast.d(24): Deprecation: cast from `bool*` to `byte*` not allowed in safe code
+fail_compilation/bool_cast.d(24): Target element could be assigned a byte which is not 0 or 1
+---
+*/
+
+void main() @safe
+{
+ ubyte[] a = [2, 4];
+ auto b = cast(bool[]) a; // reinterprets a's data
+ auto c = cast(bool[]) [2, 4]; // OK, literal cast applies to each element
+ auto d = cast(const(byte)[]) b; // OK, result's elements are const
+
+ int i = 2;
+ auto p = cast(bool*) &i;
+ bool v;
+ auto bp = cast(byte*) &v;
+ *bp = 2; // v is now invalid
+}
REQUIRED_ARGS: -preview=dip1000 -de
TEST_OUTPUT:
---
-fail_compilation/cast_qual.d(15): Deprecation: cast from `const(int)` to `int` cannot be used as an lvalue in @safe code
fail_compilation/cast_qual.d(17): Deprecation: cast from `const(int)` to `int` cannot be used as an lvalue in @safe code
+fail_compilation/cast_qual.d(19): Deprecation: cast from `const(int)` to `int` cannot be used as an lvalue in @safe code
+fail_compilation/cast_qual.d(25): Error: cast from `const(Object)` to `object.Object` not allowed in safe code
+fail_compilation/cast_qual.d(25): Incompatible type qualifier
---
*/
cast() i = 5; // NG
auto q = &cast(const) j; // OK, int* to const int*
}
+
+void test() {
+ const Object co;
+ auto o = cast() co;
+}
--- /dev/null
+// See also: fail20000.d
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/cpp_cast.d(19): Error: cast from `cpp_cast.I` to `cpp_cast.C` not allowed in safe code
+fail_compilation/cpp_cast.d(19): No dynamic type information for extern(C++) classes
+fail_compilation/cpp_cast.d(21): Deprecation: cast from `cpp_cast.C` to `cpp_cast.D` not allowed in safe code
+fail_compilation/cpp_cast.d(21): No dynamic type information for extern(C++) classes
+---
+*/
+extern(C++) interface I { void f(); }
+extern(C++) class C : I { void f() { } }
+extern(C++) class D : C { }
+
+void main() @safe
+{
+ I i;
+ C c = cast(C) i; // unsafe
+ i = cast(I) c; // OK
+ c = cast(D) c; // reinterpret cast
+ c = cast(C) new D; // OK
+}
/*
TEST_OUTPUT:
---
-fail_compilation/fail13577.d(27): Error: cannot implicilty convert range element of type `int[]` to variable `x` of type `immutable(int[])`
+fail_compilation/fail13577.d(27): Error: cannot implicitly convert tuple element of type `int[]` to variable `x` of type `immutable(int[])`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail20000.d(25): Error: cast from `fail20000.DClass` to `fail20000.CppClass` not allowed in safe code
-fail_compilation/fail20000.d(26): Error: cast from `fail20000.DInterface` to `fail20000.CppClass` not allowed in safe code
-fail_compilation/fail20000.d(27): Error: cast from `fail20000.CppClass2` to `fail20000.CppClass` not allowed in safe code
-fail_compilation/fail20000.d(28): Error: cast from `fail20000.CppInterface2` to `fail20000.CppClass` not allowed in safe code
-fail_compilation/fail20000.d(30): Error: cast from `fail20000.DClass` to `fail20000.CppInterface` not allowed in safe code
-fail_compilation/fail20000.d(31): Error: cast from `fail20000.DInterface` to `fail20000.CppInterface` not allowed in safe code
-fail_compilation/fail20000.d(32): Error: cast from `fail20000.CppClass2` to `fail20000.CppInterface` not allowed in safe code
-fail_compilation/fail20000.d(33): Error: cast from `fail20000.CppInterface2` to `fail20000.CppInterface` not allowed in safe code
-fail_compilation/fail20000.d(35): Error: cast from `fail20000.CppClass` to `fail20000.DClass` not allowed in safe code
-fail_compilation/fail20000.d(36): Error: cast from `fail20000.CppInterface` to `fail20000.DClass` not allowed in safe code
-fail_compilation/fail20000.d(38): Error: cast from `fail20000.CppClass` to `fail20000.DInterface` not allowed in safe code
-fail_compilation/fail20000.d(39): Error: cast from `fail20000.CppInterface` to `fail20000.DInterface` not allowed in safe code
+fail_compilation/fail20000.d(37): Error: cast from `fail20000.DClass` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(37): Source object type is incompatible with target type
+fail_compilation/fail20000.d(38): Error: cast from `fail20000.DInterface` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(38): Source object type is incompatible with target type
+fail_compilation/fail20000.d(39): Error: cast from `fail20000.CppClass2` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(39): Source object type is incompatible with target type
+fail_compilation/fail20000.d(40): Error: cast from `fail20000.CppInterface2` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(40): Source object type is incompatible with target type
+fail_compilation/fail20000.d(42): Error: cast from `fail20000.DClass` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(42): Source object type is incompatible with target type
+fail_compilation/fail20000.d(43): Error: cast from `fail20000.DInterface` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(43): Source object type is incompatible with target type
+fail_compilation/fail20000.d(44): Error: cast from `fail20000.CppClass2` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(44): Source object type is incompatible with target type
+fail_compilation/fail20000.d(45): Error: cast from `fail20000.CppInterface2` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(45): Source object type is incompatible with target type
+fail_compilation/fail20000.d(47): Error: cast from `fail20000.CppClass` to `fail20000.DClass` not allowed in safe code
+fail_compilation/fail20000.d(47): Source object type is incompatible with target type
+fail_compilation/fail20000.d(48): Error: cast from `fail20000.CppInterface` to `fail20000.DClass` not allowed in safe code
+fail_compilation/fail20000.d(48): Source object type is incompatible with target type
+fail_compilation/fail20000.d(50): Error: cast from `fail20000.CppClass` to `fail20000.DInterface` not allowed in safe code
+fail_compilation/fail20000.d(50): Source object type is incompatible with target type
+fail_compilation/fail20000.d(51): Error: cast from `fail20000.CppInterface` to `fail20000.DInterface` not allowed in safe code
+fail_compilation/fail20000.d(51): Source object type is incompatible with target type
---
*/
extern(C++) class CppClass { int a; }
/*
-DISABLED: freebsd32 linux32 osx32 win32
+DISABLED: freebsd32 openbsd32 linux32 osx32 win32
TEST_OUTPUT:
---
fail_compilation/ice20042.d(18): Error: slice operation `cast(__vector(float[4]))[nanF, nanF, nanF, nanF] = [1.0F, 2.0F, 3.0F, 4.0F][0..4]` cannot be evaluated at compile time
/*
-DISABLED: freebsd32 linux32 osx32 win32
+DISABLED: freebsd32 openbsd32 linux32 osx32 win32
TEST_OUTPUT:
---
fail_compilation/ice20264.d(12): Error: cannot modify expression `cast(__vector(float[4]))a` because it is not an lvalue
lead to unfortunate test failures, see
https://github.com/dlang/dmd/pull/6831#issuecomment-304495842.
-DISABLED: win32 win64 linux osx freebsd
+DISABLED: win32 win64 linux osx freebsd openbsd
*/
/*
fail_compilation/reserved_version.d(212): Error: version identifier `Emscripten` is reserved and cannot be set
fail_compilation/reserved_version.d(213): Error: version identifier `WebAssembly` is reserved and cannot be set
fail_compilation/reserved_version.d(214): Error: version identifier `WASI` is reserved and cannot be set
-fail_compilation/reserved_version.d(215): Error: version identifier `CppRuntime_Clang` is reserved and cannot be set
+fail_compilation/reserved_version.d(215): Error: version identifier `CppRuntime_LLVM` is reserved and cannot be set
fail_compilation/reserved_version.d(216): Error: version identifier `CppRuntime_DigitalMars` is reserved and cannot be set
-fail_compilation/reserved_version.d(217): Error: version identifier `CppRuntime_Gcc` is reserved and cannot be set
+fail_compilation/reserved_version.d(217): Error: version identifier `CppRuntime_GNU` is reserved and cannot be set
fail_compilation/reserved_version.d(218): Error: version identifier `CppRuntime_Microsoft` is reserved and cannot be set
fail_compilation/reserved_version.d(219): Error: version identifier `CppRuntime_Sun` is reserved and cannot be set
fail_compilation/reserved_version.d(220): Error: version identifier `D_PIE` is reserved and cannot be set
version = Emscripten;
version = WebAssembly;
version = WASI;
-version = CppRuntime_Clang;
+version = CppRuntime_LLVM;
version = CppRuntime_DigitalMars;
-version = CppRuntime_Gcc;
+version = CppRuntime_GNU;
version = CppRuntime_Microsoft;
version = CppRuntime_Sun;
version = D_PIE;
debug = CRuntime_Newlib;
debug = CRuntime_UClibc;
debug = CRuntime_WASI;
-debug = CppRuntime_Clang;
+debug = CppRuntime_LLVM;
debug = CppRuntime_DigitalMars;
-debug = CppRuntime_Gcc;
+debug = CppRuntime_GNU;
debug = CppRuntime_Microsoft;
debug = CppRuntime_Sun;
debug = D_Coverage;
// REQUIRED_ARGS: -version=CRuntime_Newlib
// REQUIRED_ARGS: -version=CRuntime_UClibc
// REQUIRED_ARGS: -version=CRuntime_WASI
-// REQUIRED_ARGS: -version=CppRuntime_Clang
+// REQUIRED_ARGS: -version=CppRuntime_LLVM
// REQUIRED_ARGS: -version=CppRuntime_DigitalMars
-// REQUIRED_ARGS: -version=CppRuntime_Gcc
+// REQUIRED_ARGS: -version=CppRuntime_GNU
// REQUIRED_ARGS: -version=CppRuntime_Microsoft
// REQUIRED_ARGS: -version=CppRuntime_Sun
// REQUIRED_ARGS: -version=D_Coverage
// REQUIRED_ARGS: -debug=CRuntime_Newlib
// REQUIRED_ARGS: -debug=CRuntime_UClibc
// REQUIRED_ARGS: -debug=CRuntime_WASI
-// REQUIRED_ARGS: -debug=CppRuntime_Clang
+// REQUIRED_ARGS: -debug=CppRuntime_LLVM
// REQUIRED_ARGS: -debug=CppRuntime_DigitalMars
-// REQUIRED_ARGS: -debug=CppRuntime_Gcc
+// REQUIRED_ARGS: -debug=CppRuntime_GNU
// REQUIRED_ARGS: -debug=CppRuntime_Microsoft
// REQUIRED_ARGS: -debug=CppRuntime_Sun
// REQUIRED_ARGS: -debug=D_Coverage
Error: version identifier `CRuntime_Newlib` is reserved and cannot be set
Error: version identifier `CRuntime_UClibc` is reserved and cannot be set
Error: version identifier `CRuntime_WASI` is reserved and cannot be set
-Error: version identifier `CppRuntime_Clang` is reserved and cannot be set
+Error: version identifier `CppRuntime_LLVM` is reserved and cannot be set
Error: version identifier `CppRuntime_DigitalMars` is reserved and cannot be set
-Error: version identifier `CppRuntime_Gcc` is reserved and cannot be set
+Error: version identifier `CppRuntime_GNU` is reserved and cannot be set
Error: version identifier `CppRuntime_Microsoft` is reserved and cannot be set
Error: version identifier `CppRuntime_Sun` is reserved and cannot be set
Error: version identifier `D_Coverage` is reserved and cannot be set
TEST_OUTPUT:
---
fail_compilation/retref2.d(18): Error: function `ref int retref2.D.foo(return ref int)` does not override any function, did you mean to override `ref int retref2.C.foo(ref int)`?
-fail_compilation/retref2.d(19): Error: function `ref scope int retref2.D.bar() return` does not override any function, did you mean to override `ref int retref2.C.bar()`?
+fail_compilation/retref2.d(19): Error: function `ref int retref2.D.bar() scope return` does not override any function, did you mean to override `ref int retref2.C.bar()`?
---
*/
TEST_OUTPUT:
---
fail_compilation/shared.d(3004): Error: cast from `void*` to `shared(int*)` not allowed in safe code
+fail_compilation/shared.d(3004): `void` data may contain pointers and target element type is mutable
fail_compilation/shared.d(3005): Error: cast from `void*` to `shared(const(int*))` not allowed in safe code
+fail_compilation/shared.d(3005): Source type is incompatible with target type containing a pointer
fail_compilation/shared.d(3008): Error: cast from `shared(void*)` to `int*` not allowed in safe code
+fail_compilation/shared.d(3008): `void` data may contain pointers and target element type is mutable
fail_compilation/shared.d(3009): Error: cast from `shared(void*)` to `shared(const(int*))` not allowed in safe code
+fail_compilation/shared.d(3009): Source type is incompatible with target type containing a pointer
---
*/
--- /dev/null
+/*
+REQUIRED_ARGS: -preview=dip1000 -de
+TEST_OUTPUT:
+---
+fail_compilation/system_ptr_cast.d(20): Deprecation: cast from `S*` to `int*` not allowed in safe code
+fail_compilation/system_ptr_cast.d(20): Source element type has unsafe bit patterns and target element type is mutable
+fail_compilation/system_ptr_cast.d(24): Deprecation: cast from `int*` to `S*` not allowed in safe code
+fail_compilation/system_ptr_cast.d(24): Target element type has unsafe bit patterns
+---
+*/
+
+struct S
+{
+ @system int i;
+}
+
+void main() @safe
+{
+ S s;
+ auto p = cast(int*) &s;
+ *p = 8;
+
+ int i = 8;
+ auto ps = cast(S*) &i;
+}
/* REQUIRED_ARGS: -preview=fixImmutableConv
TEST_OUTPUT:
---
-fail_compilation/test15660.d(20): Error: cannot implicitly convert expression `f(v)` of type `int[]` to `immutable(int[])`
+fail_compilation/test15660.d(26): Error: cannot implicitly convert expression `f(v)` of type `int[]` to `immutable(int[])`
+fail_compilation/test15660.d(34): Error: cannot copy `const(void)[]` to `void[]`
+fail_compilation/test15660.d(34): Source data has incompatible type qualifier(s)
+fail_compilation/test15660.d(34): Use `cast(void[])` to force copy
+fail_compilation/test15660.d(36): Error: cannot copy `const(int*)[]` to `void[]`
+fail_compilation/test15660.d(36): Source data has incompatible type qualifier(s)
+fail_compilation/test15660.d(36): Use `cast(void[])` to force copy
---
*/
void[] v;
immutable x = f(v);
}
+
+// https://issues.dlang.org/show_bug.cgi?id=17148
+void f(int*[] a, const int*[] b) @system
+{
+ void[] a1 = a;
+ const(void)[] b1 = b;
+ a1[] = b1[];
+ *a[0] = 0; //modify const data
+ a1[] = new const(int*)[2];
+}
/*
* TEST_OUTPUT:
---
-fail_compilation/test15672.d(15): Error: cast from `void[]` to `byte[]` not allowed in safe code
-fail_compilation/test15672.d(25): Error: cast from `void*` to `byte*` not allowed in safe code
+fail_compilation/test15672.d(17): Error: cast from `void[]` to `byte[]` not allowed in safe code
+fail_compilation/test15672.d(17): `void` data may contain pointers and target element type is mutable
+fail_compilation/test15672.d(27): Error: cast from `void*` to `byte*` not allowed in safe code
+fail_compilation/test15672.d(27): `void` data may contain pointers and target element type is mutable
---
*/
// https://issues.dlang.org/show_bug.cgi?id=15672
REQUIRED_ARGS: -m32
TEST_OUTPUT:
---
-fail_compilation/test15703.d(16): Error: cast from `Object[]` to `uint[]` not allowed in safe code
-fail_compilation/test15703.d(18): Error: cast from `object.Object` to `const(uint)*` not allowed in safe code
-fail_compilation/test15703.d(21): Error: cast from `uint[]` to `Object[]` not allowed in safe code
+fail_compilation/test15703.d(23): Error: cast from `Object[]` to `uint[]` not allowed in safe code
+fail_compilation/test15703.d(23): Target element type is mutable and source element type contains a pointer
+fail_compilation/test15703.d(25): Error: cast from `object.Object` to `const(uint)*` not allowed in safe code
+fail_compilation/test15703.d(25): Source type is incompatible with target type containing a pointer
+fail_compilation/test15703.d(28): Error: cast from `uint[]` to `Object[]` not allowed in safe code
+fail_compilation/test15703.d(28): Target element type contains a pointer
+fail_compilation/test15703.d(44): Error: cast from `int[]` to `S[]` not allowed in safe code
+fail_compilation/test15703.d(44): Target element type is opaque
+fail_compilation/test15703.d(45): Error: cast from `S[]` to `int[]` not allowed in safe code
+fail_compilation/test15703.d(45): Source element type is opaque
---
*/
const(ubyte)[] a;
auto b = cast(const(uint[])) a;
}
+
+struct S;
+
+void opaque() @safe
+{
+ auto a = [1, 2];
+ S[] b = cast(S[]) a;
+ a = cast(int[]) b;
+}
/*
* TEST_OUTPUT:
---
-fail_compilation/test15704.d(15): Error: cannot copy `void[]` to `void[]` in `@safe` code
+fail_compilation/test15704.d(17): Error: cannot copy `void[]` to `void[]` in `@safe` code
+fail_compilation/test15704.d(18): Error: cannot copy `const(void)[]` to `void[]` in `@safe` code
+fail_compilation/test15704.d(19): Deprecation: cannot copy `int[]` to `void[]` in `@safe` code
---
*/
void[] arr2 = [ 123, 345, 567 ];
arr1[] = arr2[]; // overwrites pointers with arbitrary ints
+ arr1[] = new const(void)[3];
+ arr1[] = [5];
}
/* TEST_OUTPUT:
---
-fail_compilation/test19646.d(11): Error: cast from `const(int)*` to `int*` not allowed in safe code
-fail_compilation/test19646.d(17): Error: `@safe` variable `z` cannot be initialized by calling `@system` function `f`
+fail_compilation/test19646.d(12): Error: cast from `const(int)*` to `int*` not allowed in safe code
+fail_compilation/test19646.d(12): Source type is incompatible with target type containing a pointer
+fail_compilation/test19646.d(18): Error: `@safe` variable `z` cannot be initialized by calling `@system` function `f`
---
https://issues.dlang.org/show_bug.cgi?id=19646
*/
--- /dev/null
+/*
+REQUIRED_ARGS: -preview=fixImmutableConv
+TEST_OUTPUT:
+---
+fail_compilation/union_conv.d(18): Error: cannot implicitly convert expression `c` of type `const(U)` to `U`
+---
+*/
+
+union U
+{
+ int i;
+ int* p;
+}
+
+void main()
+{
+ const U c;
+ U m = c;
+}
--- /dev/null
+/*
+REQUIRED_ARGS: -preview=fixImmutableConv
+TEST_OUTPUT:
+---
+fail_compilation/void_cat.d(15): Error: cannot copy `const(void)[]` to `void[]`
+fail_compilation/void_cat.d(15): Source data has incompatible type qualifier(s)
+fail_compilation/void_cat.d(15): Use `cast(void[])` to force copy
+fail_compilation/void_cat.d(19): Error: cannot append type `const(void)[]` to type `void[]`
+---
+*/
+
+void g(int*[] a, const(int*)[] b) @system
+{
+ void[] va = a;
+ va[] = va.init ~ b; // a now contains b's data
+ *a[0] = 0; // modify const data
+
+ const(void)[] vb = b;
+ va ~= vb; // also leaks const pointers into void[]
+ // va could be copied into `a` via another void[]
+}
/* REQUIRED_ARGS: -mcpu=avx
-DISABLED: win32 freebsd32 linux32 osx32
+DISABLED: win32 freebsd32 openbsd32 linux32 osx32
TEST_OUTPUT:
---
fail_compilation/xmmslice.d(110): Error: `__vector(int[4])` cannot be sliced with `[]`
--- /dev/null
+shared static this() {
+ throw new Exception("module constructor");
+}
+
+shared static ~this() {
+ import core.stdc.stdio;
+ puts("module destructor");
+}
+
+void main() {}
/////////////////////////////////////////////
+// https://issues.dlang.org/show_bug.cgi?id=24602
+
+class Set
+{
+ bool[string] aa;
+
+ this(bool[string] aa)
+ {
+ this.aa = aa;
+ }
+}
+
+class Bar
+{
+ Set x = new Set(["a": 1, "b": 0]);
+}
+
+void testClassLiteral()
+{
+ assert(new Bar().x.aa["a"] == 1);
+ assert(new Bar().x.aa["b"] == 0);
+}
+
+/////////////////////////////////////////////
+
+
void main()
{
testSimple();
testLocalStatic();
testEnumInit();
testStaticArray();
+ testClassLiteral();
}
// PERMUTE_ARGS: -unittest -O -release -inline -fPIC -g
+// TRANSFORM_OUTPUT: remove_lines("warning: sprintf\(\) is often misused")
extern(C) int printf(const char*, ...);
extern(C) int sprintf(char*, const char*, ...);
// REQUIRED_ARGS: -g
-// REQUIRED_ARGS(linux freebsd dragonflybsd): -L-export-dynamic
+// REQUIRED_ARGS(linux freebsd openbsd dragonflybsd): -L-export-dynamic
// PERMUTE_ARGS:
// DISABLED: osx
-// REQUIRED_ARGS: -g\r
-// REQUIRED_ARGS(linux freebsd dragonflybsd): -L-export-dynamic\r
-// PERMUTE_ARGS:\r
-// DISABLED: osx\r
-\r
-void run19086()\r
-{\r
- long x = 1;\r
- int y = 0;\r
-#line 20\r
- throw newException();\r
-}\r
-\r
-// moved here to keep run19086 short\r
-Exception newException() { return new Exception("hi"); }\r
-\r
-void test19086()\r
-{\r
- try\r
- {\r
- run19086();\r
- }\r
- catch(Exception e)\r
- {\r
- int line = findLineStackTrace(e.toString(), "run19086");\r
- assert(line >= 20 && line <= 21);\r
- }\r
-}\r
-\r
-int findLineStackTrace(string msg, string func)\r
-{\r
- // find line number of _Dmain in stack trace\r
- // on linux: file.d:line _Dmain [addr]\r
- // on windows: addr in _Dmain at file.d(line)\r
- int line = 0;\r
- bool found = false;\r
- for (size_t pos = 0; pos + func.length < msg.length; pos++)\r
- {\r
- if (msg[pos] == '\n')\r
- {\r
- line = 0;\r
- found = false;\r
- }\r
- else if ((msg[pos] == ':' || msg[pos] == '(') && line == 0)\r
- {\r
- for (pos++; pos < msg.length && msg[pos] >= '0' && msg[pos] <= '9'; pos++)\r
- line = line * 10 + msg[pos] - '0';\r
- if (line > 0 && found)\r
- return line;\r
- }\r
- else if (msg[pos .. pos + func.length] == func)\r
- {\r
- found = true;\r
- if (line > 0 && found)\r
- return line;\r
- }\r
- }\r
- return 0;\r
-}\r
-\r
-void main()\r
-{\r
- test19086();\r
-}\r
+// REQUIRED_ARGS: -g
+// REQUIRED_ARGS(linux freebsd openbsd dragonflybsd): -L-export-dynamic
+// PERMUTE_ARGS:
+// DISABLED: osx
+
+void run19086()
+{
+ long x = 1;
+ int y = 0;
+#line 20
+ throw newException();
+}
+
+// moved here to keep run19086 short
+Exception newException() { return new Exception("hi"); }
+
+void test19086()
+{
+ try
+ {
+ run19086();
+ }
+ catch(Exception e)
+ {
+ int line = findLineStackTrace(e.toString(), "run19086");
+ assert(line >= 20 && line <= 21);
+ }
+}
+
+int findLineStackTrace(string msg, string func)
+{
+ // find line number of _Dmain in stack trace
+ // on linux: file.d:line _Dmain [addr]
+ // on windows: addr in _Dmain at file.d(line)
+ int line = 0;
+ bool found = false;
+ for (size_t pos = 0; pos + func.length < msg.length; pos++)
+ {
+ if (msg[pos] == '\n')
+ {
+ line = 0;
+ found = false;
+ }
+ else if ((msg[pos] == ':' || msg[pos] == '(') && line == 0)
+ {
+ for (pos++; pos < msg.length && msg[pos] >= '0' && msg[pos] <= '9'; pos++)
+ line = line * 10 + msg[pos] - '0';
+ if (line > 0 && found)
+ return line;
+ }
+ else if (msg[pos .. pos + func.length] == func)
+ {
+ found = true;
+ if (line > 0 && found)
+ return line;
+ }
+ }
+ return 0;
+}
+
+void main()
+{
+ test19086();
+}
// PERMUTE_ARGS:
+// TRANSFORM_OUTPUT: remove_lines("warning: rand\(\) may return deterministic values")
// Quick, dirty and inefficient AA using linear search, useful for testing.
struct LinearAA(K, V) {
+// TRANSFORM_OUTPUT: remove_lines("warning: vsprintf\(\) is often misused")
+
alias TypeTuple(T...) = T;
class A { }
/*
PERMUTE_ARGS: -O
+TRANSFORM_OUTPUT: remove_lines("warning: sprintf\(\) is often misused")
*/
/*
// EXTRA_CPP_SOURCES: cpp_abi_tests.cpp
-// CXXFLAGS(linux freebsd osx netbsd dragonflybsd): -std=c++11
+// CXXFLAGS(linux freebsd osx openbsd netbsd dragonflybsd): -std=c++11
// N.B MSVC doesn't have a C++11 switch, but it defaults to the latest fully-supported standard
// N.B MSVC 2013 doesn't support char16_t/char32_t
// Disabled on windows because it needs bindings
-version (CppRuntime_Clang)
+version (CppRuntime_LLVM)
{
extern(C++, `std`, `__1`)
{
// PERMUTE_ARGS: -g
// EXTRA_CPP_SOURCES: cppb.cpp
// EXTRA_FILES: extra-files/cppb.h
-// CXXFLAGS(linux freebsd osx netbsd dragonflybsd): -std=c++11
+// CXXFLAGS(linux freebsd osx openbsd netbsd dragonflybsd): -std=c++11
// druntime isn't linked, this prevents missing symbols '_d_arraybounds_slicep':
// REQUIRED_ARGS: -checkaction=C
+// TRANSFORM_OUTPUT: remove_lines("warning: vsprintf\(\) is often misused")
// N.B MSVC doesn't have a C++11 switch, but it defaults to the latest fully-supported standard
{
}
- version (CppRuntime_Gcc)
+ version (CppRuntime_GNU)
{
// https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
static if (__traits(getTargetInfo, "cppStd") >= 201103)
--- /dev/null
+extern "C" int printf(const char *, ...);
+
+#define Foo(T) \
+ T fooD(T param); \
+ T fooCpp(T param) \
+ { \
+ printf("fooCpp %d [%p]\n", param.a, ¶m); \
+ return fooD(T{2 * param.a}); \
+ }
+
+struct POD
+{
+ int a;
+};
+Foo(POD);
+
+struct CtorOnly
+{
+ int a;
+ CtorOnly() : a(0) {}
+ CtorOnly(int a) : a(a) {}
+};
+Foo(CtorOnly);
+
+struct DtorOnly
+{
+ int a;
+ ~DtorOnly(); // implemented in D
+};
+Foo(DtorOnly);
+
+struct CtorDtor
+{
+ int a;
+ CtorDtor(int a) : a(a) {}
+ ~CtorDtor(); // implemented in D
+};
+Foo(CtorDtor);
+
+struct Copy
+{
+ int a;
+ Copy(int a) : a(a) {}
+ ~Copy(); // implemented in D
+ Copy(const Copy &rhs) : a(rhs.a) { printf("cppcpy %d [%p]\n", a, this); }
+};
+Foo(Copy);
+
+struct CopyAndMove
+{
+ int a;
+ CopyAndMove(int a) : a(a) {}
+ ~CopyAndMove(); // implemented in D
+ CopyAndMove(const CopyAndMove &rhs) : a(rhs.a) { printf("cppcpy %d [%p]\n", a, this); }
+ CopyAndMove(CopyAndMove &&) = default;
+};
+Foo(CopyAndMove);
+
+struct MoveOnly
+{
+ int a;
+ MoveOnly(int a) : a(a) {}
+ ~MoveOnly(); // implemented in D
+ MoveOnly(const MoveOnly &) = delete;
+ MoveOnly(MoveOnly &&) = default;
+};
+Foo(MoveOnly);
+
+struct MemberWithCtor
+{
+ int a;
+ CtorOnly m;
+};
+Foo(MemberWithCtor);
--- /dev/null
+// EXTRA_CPP_SOURCES: cpp_nonpod_byval.cpp
+// CXXFLAGS(linux osx freebsd dragonflybsd): -std=c++11
+
+extern (C) int printf(const(char)*, ...);
+
+extern (C++):
+
+template Foo(T)
+{
+ T fooCpp(T param); // calls fooD() with a new, doubled literal
+
+ T fooD(T param)
+ {
+ printf("fooD %d [%p]\n", param.a, ¶m);
+ assert(param.a == 2 * 123);
+ static if (__traits(compiles, { T copy = param; }))
+ return param; // invokes postblit
+ else
+ return T(param.a);
+ }
+}
+
+void test(T)()
+{
+ printf(".: %.*s\n", cast(int) T.stringof.length, T.stringof.ptr);
+
+ {
+ auto result = fooCpp(T(123));
+ assert(result.a == 246);
+ }
+
+ static if (__traits(hasMember, T, "numDtor"))
+ {
+ // fooCpp param + fooD param + result => 3 T instances.
+ // There may be an additional destruction of the moved-from T literal
+ // in fooCpp, depending on in-place construction vs. move.
+ assert(T.numDtor == 3 || T.numDtor == 4);
+ }
+}
+
+struct POD
+{
+ int a;
+}
+mixin Foo!POD;
+
+struct CtorOnly
+{
+ int a;
+ this(int a) { this.a = a; }
+}
+mixin Foo!CtorOnly;
+
+struct DtorOnly
+{
+ static __gshared int numDtor = 0;
+ int a;
+ ~this() { printf("dtor %d [%p]\n", a, &this); ++numDtor; }
+}
+mixin Foo!DtorOnly;
+
+struct CtorDtor
+{
+ static __gshared int numDtor = 0;
+ int a;
+ this(int a) { this.a = a; }
+ ~this() { printf("dtor %d [%p]\n", a, &this); ++numDtor; }
+}
+mixin Foo!CtorDtor;
+
+struct Copy
+{
+ static __gshared int numDtor = 0;
+ int a;
+ this(int a) { this.a = a; }
+ ~this() { printf("dtor %d [%p]\n", a, &this); ++numDtor; }
+ this(this) { printf("post %d [%p]\n", a, &this); }
+}
+mixin Foo!Copy;
+
+struct CopyAndMove
+{
+ static __gshared int numDtor = 0;
+ int a;
+ this(int a) { this.a = a; }
+ ~this() { printf("dtor %d [%p]\n", a, &this); ++numDtor; }
+ this(this) { printf("post %d [%p]\n", a, &this); }
+}
+mixin Foo!CopyAndMove;
+
+struct MoveOnly
+{
+ static __gshared int numDtor = 0;
+ int a;
+ this(int a) { this.a = a; }
+ ~this() { printf("dtor %d [%p]\n", a, &this); ++numDtor; }
+ this(this) @disable;
+}
+mixin Foo!MoveOnly;
+
+struct MemberWithCtor
+{
+ int a;
+ CtorOnly m;
+}
+mixin Foo!MemberWithCtor;
+
+void main()
+{
+ test!POD();
+ test!CtorOnly();
+ test!DtorOnly();
+ test!CtorDtor();
+ test!Copy();
+ test!CopyAndMove();
+ test!MoveOnly();
+ test!MemberWithCtor();
+}
-07bc5b9b3c81cc0d4314e0040de981124b363ea5
+66b93fc24a7ab5e2a8aa7f53c613df4abddc188b
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
{
bool overflow;
immutable uint r = addu (uint.max - i, uint.max - i, overflow);
- assert (r == 2 * (uint.max - i));
- assert (overflow);
+ assert(r == 2 * (uint.max - i));
+ assert(overflow);
}
bool overflow;
dim = dim * GROW_FAC;
// used during runtime.
- size_t delegate(scope const void *) nothrow hashFn = (scope const void* val) {
+ typeof(Impl.hashFn) hashFn = (scope const void* val) {
auto x = cast(K*)val;
return hashOf(*x);
};
return overflowedError(optname, str);
i++;
- break;
}
else // unexpected non-digit character
{
i = 0;
- break;
}
+ break;
}
}
static assert(is(BaseElemOf!(int[1][2]) == int));
static assert(is(BaseElemOf!(int[1][]) == int[1][]));
static assert(is(BaseElemOf!(int[][1]) == int[]));
- static enum E : int[2]{ test = [0, 1] }
+ enum E : int[2]{ test = [0, 1] }
static assert(is(BaseElemOf!(E) == int));
}
template hasUDA(alias symbol, alias attribute)
{
- alias attrs = __traits(getAttributes, symbol);
+ enum isAttr(T) = is(T == attribute);
- static foreach (a; attrs)
- {
- static if (is(a == attribute))
- {
- enum hasUDA = true;
- }
- }
-
- static if (!__traits(compiles, (hasUDA == true)))
- enum hasUDA = false;
+ enum hasUDA = anySatisfy!(isAttr, __traits(getAttributes, symbol));
}
unittest
{
- struct SomeUDA{}
+ enum SomeUDA;
struct Test
{
int woUDA;
- @SomeUDA int withUDA;
+ @SomeUDA int oneUDA;
+ @SomeUDA @SomeUDA int twoUDAs;
}
- static assert(hasUDA!(Test.withUDA, SomeUDA));
+ static assert(hasUDA!(Test.oneUDA, SomeUDA));
+ static assert(hasUDA!(Test.twoUDAs, SomeUDA));
static assert(!hasUDA!(Test.woUDA, SomeUDA));
}
// Initialize the object in its pre-ctor state
const initializer = __traits(initSymbol, T);
- (() @trusted { (cast(void*) chunk)[0 .. initializer.length] = initializer[]; })();
+ () @trusted { (cast(void*) chunk)[0 .. initializer.length] = cast(void[]) initializer[]; }();
static if (isInnerClass!T)
{
debug(PRINTF) printf(" p = %p\n", p);
// initialize it
- p[0 .. init.length] = init[];
+ p[0 .. init.length] = cast(void[]) init[];
import core.internal.traits : hasIndirections;
if (hasIndirections!T)
}
// initialize it
- p[0 .. init.length] = init[];
+ p[0 .. init.length] = cast(void[]) init[];
debug(PRINTF) printf("initialization done\n");
return cast(T) p;
static extern (C) void unittestSegvHandler( int signum, siginfo_t* info, void* ptr ) nothrow
{
- static enum MAXFRAMES = 128;
+ enum MAXFRAMES = 128;
void*[MAXFRAMES] callstack;
auto numframes = backtrace( callstack.ptr, MAXFRAMES );
private:
int numframes;
- static enum MAXFRAMES = 128;
+ enum MAXFRAMES = 128;
void*[MAXFRAMES] callstack = void;
private:
///
enum size_t max_size = size_t.max / T.sizeof;
}
- else version (CppRuntime_Gcc)
+ else version (CppRuntime_GNU)
{
///
T* allocate(size_t count, const(void)* = null) @nogc
///
enum size_t max_size = (ptrdiff_t.max < size_t.max ? cast(size_t)ptrdiff_t.max : size_t.max) / T.sizeof;
}
- else version (CppRuntime_Clang)
+ else version (CppRuntime_LLVM)
{
///
T* allocate(size_t count, const(void)* = null) @nogc
}
}
}
-version (CppRuntime_Clang)
+version (CppRuntime_LLVM)
{
// Helper for container swap
package(core.stdcpp) void __swap_allocator(Alloc)(ref Alloc __a1, ref Alloc __a2)
private:
T[N ? N : 1] _Elems;
}
- else version (CppRuntime_Gcc)
+ else version (CppRuntime_GNU)
{
///
inout(T)* data() inout @safe { static if (N > 0) { return &_M_elems[0]; } else { return null; } }
_Placeholder _M_placeholder;
}
}
- else version (CppRuntime_Clang)
+ else version (CppRuntime_LLVM)
{
///
inout(T)* data() inout @trusted { static if (N > 0) { return &__elems_[0]; } else { return cast(inout(T)*)__elems_.ptr; } }
import core.stdcpp.xutility : __cplusplus, CppStdRevision;
import core.attribute : weak;
-version (CppRuntime_Gcc)
+version (CppRuntime_GNU)
version = GenericBaseException;
-version (CppRuntime_Clang)
+version (CppRuntime_LLVM)
version = GenericBaseException;
version (CppRuntime_Sun)
version = GenericBaseException;
_Compressed_pair!(Deleter, pointer) _Mypair;
}
- else version (CppRuntime_Gcc)
+ else version (CppRuntime_GNU)
{
///
ref inout(deleter_type) get_deleter() inout nothrow { return _M_t.get!1; }
tuple!(pointer, Deleter) _M_t;
}
- else version (CppRuntime_Clang)
+ else version (CppRuntime_LLVM)
{
///
ref inout(deleter_type) get_deleter() inout nothrow { return __ptr_.second; }
version = _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT;
}
-version (CppRuntime_Gcc)
+version (CppRuntime_GNU)
{
version (_GLIBCXX_USE_CXX98_ABI)
{
_String_alloc!(_String_base_types!(T, Alloc)) _Base;
}
- else version (CppRuntime_Gcc)
+ else version (CppRuntime_GNU)
{
version (_GLIBCXX_USE_CXX98_ABI)
{
__d[0 .. __n] = __s[0 .. __n];
}
}
- else version (CppRuntime_Clang)
+ else version (CppRuntime_LLVM)
{
//----------------------------------------------------------------------------------
- // Clang/libc++ implementation
+ // libc++ implementation
//----------------------------------------------------------------------------------
///
alias __data = _Mydata;
alias __size = _Mysize;
}
- else version (CppRuntime_Gcc)
+ else version (CppRuntime_GNU)
{
size_t _M_len;
const(T)* _M_str;
alias __data = _M_str;
alias __size = _M_len;
}
- else version (CppRuntime_Clang)
+ else version (CppRuntime_LLVM)
{
const value_type* __data;
size_type __size;
//virtual ~this();
}
}
-else version (CppRuntime_Gcc)
+else version (CppRuntime_GNU)
{
import core.stdcpp.exception;
@weak override const(char)* what() const nothrow { return "bad typeid"; }
}
}
-else version (CppRuntime_Clang)
+else version (CppRuntime_LLVM)
{
import core.stdcpp.exception;
@nogc:
-version (CppRuntime_Clang)
+version (CppRuntime_LLVM)
{
import core.internal.traits : AliasSeq;
enum StdNamespace = AliasSeq!("std", "__1");
void _Xoverflow_error(const(char)* message) nothrow;
void _Xruntime_error(const(char)* message) nothrow;
}
-else version (CppRuntime_Clang)
+else version (CppRuntime_LLVM)
{
import core.stdcpp.type_traits : is_empty;
@property ref inout(_T2) __value2_() inout nothrow @trusted @nogc { return *__get_base2(); }
}
}
-version (CppRuntime_Gcc)
+version (CppRuntime_GNU)
{
import core.atomic;
}
*/
-version (linux)
+version (CRuntime_Bionic)
+{
+ struct dirent
+ {
+ ulong d_ino;
+ long d_off;
+ ushort d_reclen;
+ ubyte d_type;
+ char[256] d_name = 0;
+ }
+}
+else version (linux)
{
struct dirent
{
}
else version (CRuntime_Bionic)
{
- enum
+ enum RTLD_LOCAL = 0;
+ enum RTLD_LAZY = 0x00001;
+ enum RTLD_NOLOAD = 0x00004;
+ enum RTLD_NODELETE = 0x01000;
+
+ version (D_LP64)
+ {
+ enum RTLD_NOW = 0x00002;
+ enum RTLD_GLOBAL = 0x00100;
+ }
+ else // NDK: 'LP32 is broken for historical reasons'
{
- RTLD_NOW = 0,
- RTLD_LAZY = 1,
- RTLD_LOCAL = 0,
- RTLD_GLOBAL = 2
+ enum RTLD_NOW = 0;
+ enum RTLD_GLOBAL = 0x00002;
}
int dladdr(const scope void*, Dl_info*);
version (SPARC) version = SPARC_Any;
version (SPARC64) version = SPARC_Any;
+// Android uses 64-bit offsets for stat, but 32-bit offsets for most
+// other types on 32-bit architectures.
+version (CRuntime_Bionic)
+ private enum __USE_FILE_OFFSET64 = true;
+
version (Posix):
extern (C) nothrow @nogc:
int statvfs (const char * file, statvfs_t* buf);
int fstatvfs (int fildes, statvfs_t *buf);
}
+}
+else version (CRuntime_Musl)
+{
+ struct statvfs_t
+ {
+ c_ulong f_bsize;
+ c_ulong f_frsize;
+ fsblkcnt_t f_blocks;
+ fsblkcnt_t f_bfree;
+ fsblkcnt_t f_bavail;
+ fsfilcnt_t f_files;
+ fsfilcnt_t f_ffree;
+ fsfilcnt_t f_favail;
+ static if (true /+__BYTE_ORDER == __LITTLE_ENDIAN+/)
+ {
+ c_ulong f_fsid;
+ byte[2*int.sizeof-c_long.sizeof] __padding;
+ }
+ else
+ {
+ byte[2*int.sizeof-c_long.sizeof] __padding;
+ c_ulong f_fsid;
+ }
+ c_ulong f_flag;
+ c_ulong f_namemax;
+ uint f_type;
+ int[5] __reserved;
+ }
+
+ enum FFlag
+ {
+ ST_RDONLY = 1, /* Mount read-only. */
+ ST_NOSUID = 2,
+ ST_NODEV = 4, /* Disallow access to device special files. */
+ ST_NOEXEC = 8, /* Disallow program execution. */
+ ST_SYNCHRONOUS = 16, /* Writes are synced at once. */
+ ST_MANDLOCK = 64, /* Allow mandatory locks on an FS. */
+ ST_WRITE = 128, /* Write on file/directory/symlink. */
+ ST_APPEND = 256, /* Append-only file. */
+ ST_IMMUTABLE = 512, /* Immutable file. */
+ ST_NOATIME = 1024, /* Do not update access times. */
+ ST_NODIRATIME = 2048, /* Do not update directory access times. */
+ ST_RELATIME = 4096 /* Update atime relative to mtime/ctime. */
+
+ }
+
+ int statvfs (const char * file, statvfs_t* buf);
+ int fstatvfs (int fildes, statvfs_t *buf);
+ alias statvfs statvfs64;
+ alias fstatvfs fstatvfs64;
}
else version (NetBSD)
{
if (context is null)
{
version (Win64)
- static enum INTERNALFRAMES = 3;
+ enum INTERNALFRAMES = 3;
else version (Win32)
- static enum INTERNALFRAMES = 2;
+ enum INTERNALFRAMES = 2;
skip += INTERNALFRAMES; //skip the stack frames within the StackTrace class
}
{
//When a exception context is given the first stack frame is repeated for some reason
version (Win64)
- static enum INTERNALFRAMES = 1;
+ enum INTERNALFRAMES = 1;
else version (Win32)
- static enum INTERNALFRAMES = 1;
+ enum INTERNALFRAMES = 1;
skip += INTERNALFRAMES;
}
status = sem_init( &suspendCount, 0, 0 );
assert( status == 0 );
}
- _mainThreadStore[] = __traits(initSymbol, Thread)[];
+ _mainThreadStore[] = cast(void[]) __traits(initSymbol, Thread)[];
Thread.sm_main = attachThread((cast(Thread)_mainThreadStore.ptr).__ctor());
}
// destruct manually as object.destroy is not @nogc
(cast(ThreadT) cast(void*) ThreadBase.sm_main).__dtor();
_d_monitordelete_nogc(ThreadBase.sm_main);
- _mainThreadStore[] = __traits(initSymbol, ThreadT)[];
+ _mainThreadStore[] = cast(void[]) __traits(initSymbol, ThreadT)[];
ThreadBase.sm_main = null;
assert(ThreadBase.sm_tbeg && ThreadBase.sm_tlen == 1);
}
}
-/****
- * Boolean flag set to true while the runtime is initialized.
- */
-__gshared bool _isRuntimeInitialized;
-
-
/****
* Gets called on program startup just before GC is initialized.
*/
void initSections() nothrow @nogc
{
- _isRuntimeInitialized = true;
}
*/
void finiSections() nothrow @nogc
{
- _isRuntimeInitialized = false;
}
alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
}
// don't initialize modules before rt_init was called (see Bugzilla 11378)
- if (_isRuntimeInitialized)
+ if (isRuntimeInitialized())
{
registerGCRanges(pdso);
// rt_loadLibrary will run tls ctors, so do this only for dlopen
*data._slot = null;
// don't finalizes modules after rt_term was called (see Bugzilla 11378)
- if (_isRuntimeInitialized)
+ if (isRuntimeInitialized())
{
// rt_unloadLibrary already ran tls dtors, so do this only for dlclose
immutable runTlsDtors = !_rtLoading;
import core.sys.darwin.mach.dyld;
import core.sys.darwin.mach.getsect;
import core.sys.posix.pthread;
+import rt.dmain2;
import rt.minfo;
import core.internal.container.array;
import core.internal.container.hashtab;
}
}
-/****
- * Boolean flag set to true while the runtime is initialized.
- */
-__gshared bool _isRuntimeInitialized;
-
/****
* Gets called on program startup just before GC is initialized.
*/
void initSections() nothrow @nogc
{
- _isRuntimeInitialized = true;
}
/***
*/
void finiSections() nothrow @nogc
{
- _isRuntimeInitialized = false;
}
alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
}
// don't initialize modules before rt_init was called
- if (_isRuntimeInitialized)
+ if (isRuntimeInitialized())
{
registerGCRanges(pdso);
// rt_loadLibrary will run tls ctors, so do this only for dlopen
*data._slot = null;
// don't finalizes modules after rt_term was called (see Bugzilla 11378)
- if (_isRuntimeInitialized)
+ if (isRuntimeInitialized())
{
// rt_unloadLibrary already ran tls dtors, so do this only for dlclose
immutable runTlsDtors = !_rtLoading;
import core.sys.windows.winbase;
import core.sys.windows.windef;
import core.sys.windows.winnt;
+import rt.dmain2;
import rt.minfo;
import core.internal.container.array;
import core.internal.container.hashtab;
}
}
-/****
- * Boolean flag set to true while the runtime is initialized.
- */
-__gshared bool _isRuntimeInitialized;
-
/****
* Gets called on program startup just before GC is initialized.
*/
void initSections() nothrow @nogc
{
- _isRuntimeInitialized = true;
}
/***
*/
void finiSections() nothrow @nogc
{
- _isRuntimeInitialized = false;
}
alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
}
// don't initialize modules before rt_init was called
- if (_isRuntimeInitialized)
+ if (isRuntimeInitialized())
{
registerGCRanges(pdso);
// rt_loadLibrary will run tls ctors, so do this only for dlopen
*data._slot = null;
// don't finalizes modules after rt_term was called (see Bugzilla 11378)
- if (_isRuntimeInitialized)
+ if (isRuntimeInitialized())
{
// rt_unloadLibrary already ran tls dtors, so do this only for dlclose
immutable runTlsDtors = !_rtLoading;
{
if (!b.filled)
continue;
- pval[0 .. valsz] = b.entry[off .. valsz + off];
+ pval[0 .. valsz] = cast(void[]) b.entry[off .. valsz + off];
pval += valsz;
}
// postblit is done in object.values
{
if (!b.filled)
continue;
- pkey[0 .. keysz] = b.entry[0 .. keysz];
+ pkey[0 .. keysz] = cast(void[]) b.entry[0 .. keysz];
pkey += keysz;
}
// postblit is done in object.keys
/**
* Keep track of how often rt_init/rt_term were called.
*/
-shared size_t _initCount;
+private shared size_t _initCount;
/**********************************************
* Initialize druntime.
return 0;
}
+/**
+ * Indicates whether druntime has been or is being initialized.
+ */
+bool isRuntimeInitialized() @nogc nothrow {
+ return atomicLoad!(MemoryOrder.raw)(_initCount) != 0;
+}
+
/**********************************************
* Trace handler
*/
}
// initialize it
- p[0 .. init.length] = init[];
+ p[0 .. init.length] = cast(void[]) init[];
debug(PRINTF) printf("initialization done\n");
return cast(Object) p;
if (resetMemory)
{
auto w = (*pc).initializer;
- p[0 .. w.length] = w[];
+ p[0 .. w.length] = cast(void[]) w[];
}
}
catch (Exception e)
else version (CRuntime_Microsoft)
public import rt.sections_win64;
else version (CRuntime_Bionic)
- public import rt.sections_android;
+ public import rt.sections_elf_shared;
else version (CRuntime_UClibc)
public import rt.sections_elf_shared;
else
-de1dea109f40fe4a551578369c474e48845daec1
+0c28620c301c9ae3136b1e1e5af55c290dbc7aae
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
std/internal/math/errorfunction.d std/internal/math/gammafunction.d \
std/internal/memory.d std/internal/scopebuffer.d \
std/internal/test/dummyrange.d std/internal/test/range.d \
- std/internal/test/uda.d std/internal/unicode_comp.d \
- std/internal/unicode_decomp.d std/internal/unicode_grapheme.d \
- std/internal/unicode_norm.d std/internal/unicode_tables.d \
- std/internal/windows/advapi32.d std/json.d std/logger/core.d \
- std/logger/filelogger.d std/logger/multilogger.d \
- std/logger/nulllogger.d std/logger/package.d std/math/algebraic.d \
- std/math/constants.d std/math/exponential.d std/math/hardware.d \
- std/math/operations.d std/math/package.d std/math/remainder.d \
- std/math/rounding.d std/math/traits.d std/math/trigonometry.d \
- std/mathspecial.d std/meta.d std/mmfile.d std/net/curl.d \
- std/net/isemail.d std/numeric.d std/outbuffer.d std/package.d \
- std/parallelism.d std/path.d std/process.d std/random.d \
+ std/internal/test/sumtype_example_overloads.d std/internal/test/uda.d \
+ std/internal/unicode_comp.d std/internal/unicode_decomp.d \
+ std/internal/unicode_grapheme.d std/internal/unicode_norm.d \
+ std/internal/unicode_tables.d std/internal/windows/advapi32.d \
+ std/json.d std/logger/core.d std/logger/filelogger.d \
+ std/logger/multilogger.d std/logger/nulllogger.d std/logger/package.d \
+ std/math/algebraic.d std/math/constants.d std/math/exponential.d \
+ std/math/hardware.d std/math/operations.d std/math/package.d \
+ std/math/remainder.d std/math/rounding.d std/math/traits.d \
+ std/math/trigonometry.d std/mathspecial.d std/meta.d std/mmfile.d \
+ std/net/curl.d std/net/isemail.d std/numeric.d std/outbuffer.d \
+ std/package.d std/parallelism.d std/path.d std/process.d std/random.d \
std/range/interfaces.d std/range/package.d std/range/primitives.d \
std/regex/internal/backtracking.d std/regex/internal/generator.d \
std/regex/internal/ir.d std/regex/internal/kickstart.d \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/scopebuffer.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/test/dummyrange.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/test/range.lo \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/test/sumtype_example_overloads.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/test/uda.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_comp.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_decomp.lo \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/math/errorfunction.d std/internal/math/gammafunction.d \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/memory.d std/internal/scopebuffer.d \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/test/dummyrange.d std/internal/test/range.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/test/uda.d std/internal/unicode_comp.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_decomp.d std/internal/unicode_grapheme.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_norm.d std/internal/unicode_tables.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/windows/advapi32.d std/json.d std/logger/core.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/logger/filelogger.d std/logger/multilogger.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/logger/nulllogger.d std/logger/package.d std/math/algebraic.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/constants.d std/math/exponential.d std/math/hardware.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/operations.d std/math/package.d std/math/remainder.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/rounding.d std/math/traits.d std/math/trigonometry.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/mathspecial.d std/meta.d std/mmfile.d std/net/curl.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/net/isemail.d std/numeric.d std/outbuffer.d std/package.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/parallelism.d std/path.d std/process.d std/random.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/test/sumtype_example_overloads.d std/internal/test/uda.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_comp.d std/internal/unicode_decomp.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_grapheme.d std/internal/unicode_norm.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/unicode_tables.d std/internal/windows/advapi32.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/json.d std/logger/core.d std/logger/filelogger.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/logger/multilogger.d std/logger/nulllogger.d std/logger/package.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/algebraic.d std/math/constants.d std/math/exponential.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/hardware.d std/math/operations.d std/math/package.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/remainder.d std/math/rounding.d std/math/traits.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/math/trigonometry.d std/mathspecial.d std/meta.d std/mmfile.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/net/curl.d std/net/isemail.d std/numeric.d std/outbuffer.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/package.d std/parallelism.d std/path.d std/process.d std/random.d \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/range/interfaces.d std/range/package.d std/range/primitives.d \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/internal/backtracking.d std/regex/internal/generator.d \
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/regex/internal/ir.d std/regex/internal/kickstart.d \
@: > std/internal/test/$(am__dirstamp)
std/internal/test/dummyrange.lo: std/internal/test/$(am__dirstamp)
std/internal/test/range.lo: std/internal/test/$(am__dirstamp)
+std/internal/test/sumtype_example_overloads.lo: \
+ std/internal/test/$(am__dirstamp)
std/internal/test/uda.lo: std/internal/test/$(am__dirstamp)
std/internal/unicode_comp.lo: std/internal/$(am__dirstamp)
std/internal/unicode_decomp.lo: std/internal/$(am__dirstamp)
auto fmt = "Number: %6.4e\nString: %s";
auto f = FormatSpec!char(fmt);
- assert(f.writeUpToNextSpec(a) == true);
+ assert(f.writeUpToNextSpec(a));
assert(a.data == "Number: ");
assert(f.trailing == "\nString: %s");
assert(f.width == 6);
assert(f.precision == 4);
- assert(f.writeUpToNextSpec(a) == true);
+ assert(f.writeUpToNextSpec(a));
assert(a.data == "Number: \nString: ");
assert(f.trailing == "");
assert(f.spec == 's');
- assert(f.writeUpToNextSpec(a) == false);
+ assert(!f.writeUpToNextSpec(a));
assert(a.data == "Number: \nString: ");
}
--- /dev/null
+/++
+For testing only.
+
+Overload set used in std.sumtype example. Needs its own internal module so that
+it can be available for `make publictests` without polluting the public API.
++/
+module std.internal.test.sumtype_example_overloads;
+
+import std.sumtype;
+
+@safe
+{
+ string handle(int) { return "got an int"; }
+ string handle(string) { return "got a string"; }
+ string handle(double) { return "got a double"; }
+ alias handle = match!handle;
+}
* If x is 0 and n is negative, the result is the same as the result of a
* division by zero.
*/
-typeof(Unqual!(F).init * Unqual!(G).init) pow(F, G)(F x, G n) @nogc @trusted pure nothrow
+typeof(Unqual!(F).init * Unqual!(G).init) pow(F, G)(F x, G n) @nogc @safe pure nothrow
if (isIntegral!(F) && isIntegral!(G))
{
import std.traits : isSigned;
{
size_t minLen = min(buf.length, remainingData.length);
if (minLen == 0) return 0;
- buf[0 .. minLen] = remainingData[0 .. minLen];
+ buf[0 .. minLen] = cast(void[]) remainingData[0 .. minLen];
remainingData = remainingData[minLen..$];
return minLen;
};
{
size_t minLen = min(buf.length, sendData.length);
if (minLen == 0) return 0;
- buf[0 .. minLen] = sendData[0 .. minLen];
+ buf[0 .. minLen] = cast(void[]) sendData[0 .. minLen];
sendData = sendData[minLen..$];
return minLen;
};
{
size_t bitsNum = IntegralType.sizeof * 8;
- auto first = cast(IntegralType)(1);
+ auto first = IntegralType(1);
// 2 ^ (bitsNum - 1)
- auto second = cast(IntegralType)(cast(IntegralType)(1) << (bitsNum - 2));
+ auto second = cast(IntegralType)(IntegralType(1) << (bitsNum - 2));
IntegralType[] a = [first, second];
auto bw = Bitwise!(IntegralType[])(a);
auto bw2 = bw[0 .. $ - 5];
auto bw3 = bw2[];
- assert(bw2.length == (bw.length - 5));
+ assert(bw2.length == bw.length - 5);
assert(bw2.length == bw3.length);
bw2.popFront();
assert(bw2.length != bw3.length);
assertCTFEable!(
{
// Test the isNumeric(in string) function
- assert(isNumeric("1") == true );
- assert(isNumeric("1.0") == true );
- assert(isNumeric("1e-1") == true );
- assert(isNumeric("12345xxxx890") == false );
- assert(isNumeric("567L") == true );
- assert(isNumeric("23UL") == true );
- assert(isNumeric("-123..56f") == false );
- assert(isNumeric("12.3.5.6") == false );
- assert(isNumeric(" 12.356") == false );
- assert(isNumeric("123 5.6") == false );
- assert(isNumeric("1233E-1+1.0e-1i") == true );
-
- assert(isNumeric("123.00E-5+1234.45E-12Li") == true);
- assert(isNumeric("123.00e-5+1234.45E-12iL") == false);
- assert(isNumeric("123.00e-5+1234.45e-12uL") == false);
- assert(isNumeric("123.00E-5+1234.45e-12lu") == false);
-
- assert(isNumeric("123fi") == true);
- assert(isNumeric("123li") == true);
- assert(isNumeric("--123L") == false);
- assert(isNumeric("+123.5UL") == false);
- assert(isNumeric("123f") == true);
- assert(isNumeric("123.u") == false);
+ assert(isNumeric("1"));
+ assert(isNumeric("1.0"));
+ assert(isNumeric("1e-1"));
+ assert(!isNumeric("12345xxxx890"));
+ assert(isNumeric("567L"));
+ assert(isNumeric("23UL"));
+ assert(!isNumeric("-123..56f"));
+ assert(!isNumeric("12.3.5.6"));
+ assert(!isNumeric(" 12.356"));
+ assert(!isNumeric("123 5.6"));
+ assert(isNumeric("1233E-1+1.0e-1i"));
+
+ assert(isNumeric("123.00E-5+1234.45E-12Li"));
+ assert(!isNumeric("123.00e-5+1234.45E-12iL"));
+ assert(!isNumeric("123.00e-5+1234.45e-12uL"));
+ assert(!isNumeric("123.00E-5+1234.45e-12lu"));
+
+ assert(isNumeric("123fi"));
+ assert(isNumeric("123li"));
+ assert(!isNumeric("--123L"));
+ assert(!isNumeric("+123.5UL"));
+ assert(isNumeric("123f"));
+ assert(!isNumeric("123.u"));
// @@@BUG@@ to!string(float) is not CTFEable.
// Related: formatValue(T) if (is(FloatingPointTypeOf!T))
if (!__ctfe)
{
- assert(isNumeric(to!string(real.nan)) == true);
- assert(isNumeric(to!string(-real.infinity)) == true);
+ assert(isNumeric(to!string(real.nan)));
+ assert(isNumeric(to!string(-real.infinity)));
}
string s = "$250.99-";
- assert(isNumeric(s[1 .. s.length - 2]) == true);
- assert(isNumeric(s) == false);
- assert(isNumeric(s[0 .. s.length - 1]) == false);
+ assert(isNumeric(s[1 .. $ - 2]));
+ assert(!isNumeric(s));
+ assert(!isNumeric(s[0 .. $ - 1]));
});
assert(!isNumeric("-"));
* No dependency on runtime type information (`TypeInfo`).
* Compatibility with BetterC.
+$(H3 List of examples)
+
+* [Basic usage](#basic-usage)
+* [Matching with an overload set](#matching-with-an-overload-set)
+* [Recursive SumTypes](#recursive-sumtypes)
+* [Memory corruption](#memory-corruption) (why assignment can be `@system`)
+* [Avoiding unintentional matches](#avoiding-unintentional-matches)
+* [Multiple dispatch](#multiple-dispatch)
+
License: Boost License 1.0
Authors: Paul Backus
Source: $(PHOBOSSRC std/sumtype.d)
assert(!isFahrenheit(t3));
}
-/** $(DIVID introspection-based-matching, $(H3 Introspection-based matching))
+/** $(DIVID matching-with-an-overload-set, $(H3 Matching with an overload set))
+ *
+ * Instead of writing `match` handlers inline as lambdas, you can write them as
+ * overloads of a function. An `alias` can be used to create an additional
+ * overload for the `SumType` itself.
+ *
+ * For example, with this overload set:
*
- * In the `length` and `horiz` functions below, the handlers for `match` do not
- * specify the types of their arguments. Instead, matching is done based on how
- * the argument is used in the body of the handler: any type with `x` and `y`
- * properties will be matched by the `rect` handlers, and any type with `r` and
- * `theta` properties will be matched by the `polar` handlers.
+ * ---
+ * string handle(int n) { return "got an int"; }
+ * string handle(string s) { return "got a string"; }
+ * string handle(double d) { return "got a double"; }
+ * alias handle = match!handle;
+ * ---
+ *
+ * Usage would look like this:
*/
version (D_BetterC) {} else
@safe unittest
{
- import std.math.operations : isClose;
- import std.math.trigonometry : cos;
- import std.math.constants : PI;
- import std.math.algebraic : sqrt;
-
- struct Rectangular { double x, y; }
- struct Polar { double r, theta; }
- alias Vector = SumType!(Rectangular, Polar);
-
- double length(Vector v)
- {
- return v.match!(
- rect => sqrt(rect.x^^2 + rect.y^^2),
- polar => polar.r
- );
- }
-
- double horiz(Vector v)
- {
- return v.match!(
- rect => rect.x,
- polar => polar.r * cos(polar.theta)
- );
- }
+ alias ExampleSumType = SumType!(int, string, double);
- Vector u = Rectangular(1, 1);
- Vector v = Polar(1, PI/4);
+ ExampleSumType a = 123;
+ ExampleSumType b = "hello";
+ ExampleSumType c = 3.14;
- assert(length(u).isClose(sqrt(2.0)));
- assert(length(v).isClose(1));
- assert(horiz(u).isClose(1));
- assert(horiz(v).isClose(sqrt(0.5)));
+ assert(a.handle == "got an int");
+ assert(b.handle == "got a string");
+ assert(c.handle == "got a double");
}
-/** $(DIVID arithmetic-expression-evaluator, $(H3 Arithmetic expression evaluator))
+/** $(DIVID recursive-sumtypes, $(H3 Recursive SumTypes))
*
* This example makes use of the special placeholder type `This` to define a
* [recursive data type](https://en.wikipedia.org/wiki/Recursive_data_type): an
assert(pprint(*myExpr) == "(a + (2 * b))");
}
+// For the "Matching with an overload set" example above
+// Needs public import to work with `make publictests`
+version (unittest) public import std.internal.test.sumtype_example_overloads;
+
import std.format.spec : FormatSpec, singleSpec;
import std.meta : AliasSeq, Filter, IndexOf = staticIndexOf, Map = staticMap;
import std.meta : NoDuplicates;
*
* The special type `This` can be used as a placeholder to create
* self-referential types, just like with `Algebraic`. See the
- * ["Arithmetic expression evaluator" example](#arithmetic-expression-evaluator) for
- * usage.
+ * ["Recursive SumTypes" example](#recursive-sumtypes) for usage.
*
* A `SumType` is initialized by default to hold the `.init` value of its
* first member type, just like a regular union. The version identifier
* overloads are considered as potential matches.
*
* Templated handlers are also accepted, and will match any type for which they
- * can be [implicitly instantiated](https://dlang.org/glossary.html#ifti). See
- * ["Introspection-based matching"](#introspection-based-matching) for an
- * example of templated handler usage.
+ * can be [implicitly instantiated](https://dlang.org/glossary.html#ifti).
+ * (Remember that a $(DDSUBLINK spec/expression,function_literals, function literal)
+ * without an explicit argument type is considered a template.)
*
* If multiple [SumType]s are passed to match, their values are passed to the
* handlers as separate arguments, and matching is done for each possible
encode(buf, '\u0000'); assert(buf[0] == '\u0000');
encode(buf, '\uD7FF'); assert(buf[0] == '\uD7FF');
encode(buf, '\uE000'); assert(buf[0] == '\uE000');
- encode(buf, 0xFFFE ); assert(buf[0] == 0xFFFE);
- encode(buf, 0xFFFF ); assert(buf[0] == 0xFFFF);
+ encode(buf, 0xFFFE); assert(buf[0] == 0xFFFE);
+ encode(buf, 0xFFFF); assert(buf[0] == 0xFFFF);
encode(buf, '\U0010FFFF'); assert(buf[0] == '\U0010FFFF');
assertThrown!UTFException(encode(buf, cast(dchar) 0xD800));
encode(buf, '\u0000'); assert(buf[0] == '\u0000');
encode(buf, '\uD7FF'); assert(buf[1] == '\uD7FF');
encode(buf, '\uE000'); assert(buf[2] == '\uE000');
- encode(buf, 0xFFFE ); assert(buf[3] == 0xFFFE);
- encode(buf, 0xFFFF ); assert(buf[4] == 0xFFFF);
+ encode(buf, 0xFFFE); assert(buf[3] == 0xFFFE);
+ encode(buf, 0xFFFF); assert(buf[4] == 0xFFFF);
encode(buf, '\U0010FFFF'); assert(buf[5] == '\U0010FFFF');
assertThrown!UTFException(encode(buf, cast(dchar) 0xD800));