@@ -327,7 +327,7 @@ build_attributes (Expressions *eattrs)
for (size_t i = 0; i < eattrs->length; i++)
{
Expression *attr = (*eattrs)[i];
- Dsymbol *sym = attr->type->toDsymbol (0);
+ Dsymbol *sym = toDsymbol (attr->type, NULL);
if (!sym)
{
@@ -1344,7 +1344,10 @@ d_parse_file (void)
}
if (global.params.v.templates)
- printTemplateStats ();
+ {
+ printTemplateStats (global.params.v.templatesListInstances,
+ global.errorSink);
+ }
/* Generate JSON files. */
if (global.params.json.doOutput)
@@ -782,7 +782,7 @@ public:
{
/* Do not store variables we cannot take the address of,
but keep the values for purposes of debugging. */
- if (d->type->isscalar () && !d->type->hasPointers ())
+ if (d->type->isscalar () && !hasPointers (d->type))
{
tree decl = get_symbol_decl (d);
d_pushdecl (decl);
@@ -1,4 +1,4 @@
-d8e3976a58d6aef7c2c9371028a2ca4460b5b2ce
+bce5c1f7b521d22dcf1ea4e2bc3f76d9d28274fa
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
@@ -459,3 +459,9 @@ extern (C++) struct structalign_t
bool isPack() const { return pack; }
void setPack(bool pack) { this.pack = pack; }
}
+
+/// Use to return D arrays from C++ functions
+extern (C++) struct DArray(T)
+{
+ T[] data;
+}
@@ -1038,6 +1038,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
else if (tb.ty == Tstruct && e1.op == EXP.int64)
{
// Struct = 0;
+ import dmd.typesem : toDsymbol;
StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration();
assert(sd);
auto elements = new Expressions();
@@ -1749,6 +1749,35 @@ extern (C++) final class SymbolDeclaration : Declaration
/***********************************************************
*/
+private Identifier getTypeInfoIdent(Type t)
+{
+ import dmd.dmangle;
+ import core.stdc.stdlib;
+ import dmd.root.rmem;
+ // _init_10TypeInfo_%s
+ OutBuffer buf;
+ buf.reserve(32);
+ mangleToBuffer(t, buf);
+
+ const slice = buf[];
+
+ // Allocate buffer on stack, fail over to using malloc()
+ char[128] namebuf;
+ const namelen = 19 + size_t.sizeof * 3 + slice.length + 1;
+ auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen));
+
+ const length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ",
+ cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr);
+ //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name);
+ assert(0 < length && length < namelen); // don't overflow the buffer
+
+ auto id = Identifier.idPool(name[0 .. length]);
+
+ if (name != namebuf.ptr)
+ free(name);
+ return id;
+}
+
extern (C++) class TypeInfoDeclaration : VarDeclaration
{
Type tinfo;
@@ -1416,6 +1416,7 @@ Expression interpretStatement(UnionExp* pue, Statement s, InterState* istate)
foreach (ca; *s.catches)
{
Type catype = ca.type;
+ import dmd.typesem : isBaseOf;
if (!catype.equals(extype) && !catype.isBaseOf(extype, null))
continue;
@@ -6237,6 +6238,11 @@ public:
{
if (soe.offset == 0 && soe.var.isFuncDeclaration())
return;
+ if (soe.offset == 0 && soe.var.isVarDeclaration() && soe.var.isImmutable())
+ {
+ result = getVarExp(e.loc, istate, soe.var, CTFEGoal.RValue);
+ return;
+ }
error(e.loc, "cannot dereference pointer to static variable `%s` at compile time", soe.var.toChars());
result = CTFEExp.cantexp;
return;
@@ -6359,6 +6365,7 @@ public:
{
if (auto t = isType(ex.isTypeidExp().obj))
{
+ import dmd.typesem : toDsymbol;
auto sym = t.toDsymbol(null);
if (auto ident = (sym ? sym.ident : null))
{
@@ -6643,6 +6650,7 @@ Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original)
private
bool stopPointersEscaping(const ref Loc loc, Expression e)
{
+ import dmd.typesem : hasPointers;
if (!e.type.hasPointers())
return true;
if (isPointer(e.type))
@@ -6706,7 +6714,7 @@ Statement findGotoTarget(InterState* istate, Identifier ident)
Statement target = null;
if (ident)
{
- LabelDsymbol label = istate.fd.searchLabel(ident);
+ LabelDsymbol label = istate.fd.searchLabel(ident, Loc.initial);
assert(label && label.statement);
LabelStatement ls = label.statement;
target = ls.gotoTarget ? ls.gotoTarget : ls.statement;
@@ -7263,6 +7271,33 @@ private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expressi
return eresult;
}
+/// Returns: equivalent `StringExp` from `ArrayLiteralExp ale` containing only `IntegerExp` elements
+StringExp arrayLiteralToString(ArrayLiteralExp ale)
+{
+ const len = ale.elements ? ale.elements.length : 0;
+ const size = ale.type.nextOf().size();
+
+ StringExp impl(T)()
+ {
+ T[] result = new T[len];
+ foreach (i; 0 .. len)
+ result[i] = cast(T) (*ale.elements)[i].isIntegerExp().getInteger();
+ return new StringExp(ale.loc, result[], len, cast(ubyte) size);
+ }
+
+ switch (size)
+ {
+ case 1:
+ return impl!char();
+ case 2:
+ return impl!wchar();
+ case 4:
+ return impl!dchar();
+ default:
+ assert(0);
+ }
+}
+
/* Decoding UTF strings for foreach loops. Duplicates the functionality of
* the twelve _aApplyXXn functions in aApply.d in the runtime.
*/
@@ -7299,8 +7334,10 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression
str = resolveSlice(str, &strTmp);
auto se = str.isStringExp();
- auto ale = str.isArrayLiteralExp();
- if (!se && !ale)
+ if (auto ale = str.isArrayLiteralExp())
+ se = arrayLiteralToString(ale);
+
+ if (!se)
{
error(str.loc, "CTFE internal error: cannot foreach `%s`", str.toChars());
return CTFEExp.cantexp;
@@ -7309,7 +7346,7 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression
Expression eresult = null; // ded-store to prevent spurious warning
- // Buffers for encoding; also used for decoding array literals
+ // Buffers for encoding
char[4] utf8buf = void;
wchar[2] utf16buf = void;
@@ -7323,90 +7360,11 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression
dchar rawvalue; // Holds the decoded dchar
size_t currentIndex = indx; // The index of the decoded character
- if (ale)
- {
- // If it is an array literal, copy the code points into the buffer
- size_t buflen = 1; // #code points in the buffer
- size_t n = 1; // #code points in this char
- size_t sz = cast(size_t)ale.type.nextOf().size();
+ // String literals
+ size_t saveindx; // used for reverse iteration
- switch (sz)
- {
- case 1:
- if (rvs)
- {
- // find the start of the string
- --indx;
- buflen = 1;
- while (indx > 0 && buflen < 4)
- {
- Expression r = (*ale.elements)[indx];
- char x = cast(char)r.isIntegerExp().getInteger();
- if ((x & 0xC0) != 0x80)
- break;
- --indx;
- ++buflen;
- }
- }
- else
- buflen = (indx + 4 > len) ? len - indx : 4;
- for (size_t i = 0; i < buflen; ++i)
- {
- Expression r = (*ale.elements)[indx + i];
- utf8buf[i] = cast(char)r.isIntegerExp().getInteger();
- }
- n = 0;
- errmsg = utf_decodeChar(utf8buf[0 .. buflen], n, rawvalue);
- break;
-
- case 2:
- if (rvs)
- {
- // find the start of the string
- --indx;
- buflen = 1;
- Expression r = (*ale.elements)[indx];
- ushort x = cast(ushort)r.isIntegerExp().getInteger();
- if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF)
- {
- --indx;
- ++buflen;
- }
- }
- else
- buflen = (indx + 2 > len) ? len - indx : 2;
- for (size_t i = 0; i < buflen; ++i)
- {
- Expression r = (*ale.elements)[indx + i];
- utf16buf[i] = cast(ushort)r.isIntegerExp().getInteger();
- }
- n = 0;
- errmsg = utf_decodeWchar(utf16buf[0 .. buflen], n, rawvalue);
- break;
-
- case 4:
- {
- if (rvs)
- --indx;
- Expression r = (*ale.elements)[indx];
- rawvalue = cast(dchar)r.isIntegerExp().getInteger();
- n = 1;
- }
- break;
-
- default:
- assert(0);
- }
- if (!rvs)
- indx += n;
- }
- else
+ switch (se.sz)
{
- // String literals
- size_t saveindx; // used for reverse iteration
-
- switch (se.sz)
- {
case 1:
{
if (rvs)
@@ -7450,8 +7408,8 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression
default:
assert(0);
- }
}
+
if (errmsg)
{
error(deleg.loc, "`%.*s`", cast(int)errmsg.length, errmsg.ptr);
@@ -679,23 +679,23 @@ extern (C++) final class Module : Package
/* Preprocess the file if it's a .c file
*/
FileName filename = srcfile;
- bool ifile = false; // did we generate a .i file
- scope (exit)
- {
- if (ifile)
- File.remove(filename.toChars()); // remove generated file
- }
+ const(ubyte)[] srctext;
if (global.preprocess &&
FileName.equalsExt(srcfile.toString(), c_ext) &&
FileName.exists(srcfile.toString()))
{
- filename = global.preprocess(srcfile, loc, ifile, &defines); // run C preprocessor
+ /* Apply C preprocessor to the .c file, returning the contents
+ * after preprocessing
+ */
+ srctext = global.preprocess(srcfile, loc, defines).data;
}
+ else
+ srctext = global.fileManager.getFileContents(filename);
+ this.src = srctext;
- if (auto result = global.fileManager.lookup(filename))
+ if (srctext)
{
- this.src = result;
if (global.params.makeDeps.doOutput)
global.params.makeDeps.files.push(srcfile.toChars());
return true;
@@ -1355,6 +1355,7 @@ void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc)
{
if (type.ty == Tclass || type.ty == Tstruct || type.ty == Tenum)
{
+ import dmd.typesem : toDsymbol;
if (Dsymbol s = type.toDsymbol(null)) // elaborate type
prettyPrintDsymbol(s, ad.parent);
else
@@ -97,6 +97,7 @@ extern (C++) struct Scope
Dsymbol inunion; /// != null if processing members of a union
bool nofree; /// true if shouldn't free it
bool inLoop; /// true if inside a loop (where constructor calls aren't allowed)
+ bool inDefaultArg; /// true if inside a default argument (where __FILE__, etc are evaluated at the call site)
int intypeof; /// in typeof(exp)
VarDeclaration lastVar; /// Previous symbol used to prevent goto-skips-init
ErrorSink eSink; /// sink for error messages
@@ -6553,7 +6553,8 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList
TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration();
assert(tempdecl);
- TemplateStats.incInstance(tempdecl, tempinst);
+ if (global.params.v.templates)
+ TemplateStats.incInstance(tempdecl, tempinst, global.params.v.templatesListInstances);
tempdecl.checkDeprecated(tempinst.loc, sc);
@@ -6746,7 +6747,8 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList
tempinst.parent = tempinst.enclosing ? tempinst.enclosing : tempdecl.parent;
//printf("parent = '%s'\n", parent.kind());
- TemplateStats.incUnique(tempdecl, tempinst);
+ if (global.params.v.templates)
+ TemplateStats.incUnique(tempdecl, tempinst);
TemplateInstance tempdecl_instance_idx = tempdecl.addInstance(tempinst);
@@ -56,6 +56,7 @@ import dmd.dscope;
import dmd.dsymbol;
import dmd.dsymbolsem;
import dmd.errors;
+import dmd.errorsink;
import dmd.expression;
import dmd.expressionsem;
import dmd.func;
@@ -150,7 +151,7 @@ extern (C++) bool isError(const RootObject o)
if (const e = isExpression(o))
return (e.op == EXP.error || !e.type || e.type.ty == Terror);
if (const v = isTuple(o))
- return arrayObjectIsError(&v.objects);
+ return arrayObjectIsError(v.objects);
const s = isDsymbol(o);
assert(s);
if (s.errors)
@@ -161,9 +162,9 @@ extern (C++) bool isError(const RootObject o)
/**************************************
* Are any of the Objects an error?
*/
-bool arrayObjectIsError(const Objects* args)
+bool arrayObjectIsError(const ref Objects args)
{
- foreach (const o; *args)
+ foreach (const o; args)
{
if (isError(o))
return true;
@@ -187,6 +188,13 @@ inout(Type) getType(inout RootObject o)
}
+/***********************************
+ * If oarg represents a Dsymbol, return that Dsymbol
+ * Params:
+ * oarg = argument to check
+ * Returns:
+ * Dsymbol if a symbol, null if not
+ */
Dsymbol getDsymbol(RootObject oarg)
{
//printf("getDsymbol()\n");
@@ -256,8 +264,11 @@ private Expression getExpression(RootObject o)
}
/******************************
- * If o1 matches o2, return true.
- * Else, return false.
+ * See if two objects match
+ * Params:
+ * o1 = first object
+ * o2 = second object
+ * Returns: true if they match
*/
private bool match(RootObject o1, RootObject o2)
{
@@ -343,7 +354,7 @@ private bool match(RootObject o1, RootObject o2)
printf("\tu1 = %s\n", u1.toChars());
printf("\tu2 = %s\n", u2.toChars());
}
- if (!arrayObjectMatch(&u1.objects, &u2.objects))
+ if (!arrayObjectMatch(u1.objects, u2.objects))
goto Lnomatch;
goto Lmatch;
@@ -362,15 +373,15 @@ Lnomatch:
/************************************
* Match an array of them.
*/
-private bool arrayObjectMatch(Objects* oa1, Objects* oa2)
+private bool arrayObjectMatch(ref Objects oa1, ref Objects oa2)
{
- if (oa1 == oa2)
+ if (&oa1 == &oa2)
return true;
if (oa1.length != oa2.length)
return false;
immutable oa1dim = oa1.length;
- auto oa1d = (*oa1)[].ptr;
- auto oa2d = (*oa2)[].ptr;
+ auto oa1d = oa1[].ptr;
+ auto oa2d = oa2[].ptr;
foreach (j; 0 .. oa1dim)
{
RootObject o1 = oa1d[j];
@@ -386,12 +397,12 @@ private bool arrayObjectMatch(Objects* oa1, Objects* oa2)
/************************************
* Return hash of Objects.
*/
-private size_t arrayObjectHash(Objects* oa1)
+private size_t arrayObjectHash(ref Objects oa1)
{
import dmd.root.hash : mixHash;
size_t hash = 0;
- foreach (o1; *oa1)
+ foreach (o1; oa1)
{
/* Must follow the logic of match()
*/
@@ -407,7 +418,7 @@ private size_t arrayObjectHash(Objects* oa1)
hash = mixHash(hash, mixHash(cast(size_t)cast(void*)s1.getIdent(), cast(size_t)cast(void*)s1.parent));
}
else if (auto u1 = isTuple(o1))
- hash = mixHash(hash, arrayObjectHash(&u1.objects));
+ hash = mixHash(hash, arrayObjectHash(u1.objects));
}
return hash;
}
@@ -672,7 +683,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
/**********************************
* Overload existing TemplateDeclaration 'this' with the new one 's'.
- * Return true if successful; i.e. no conflict.
+ * Params:
+ * s = symbol to be inserted
+ * Return: true if successful; i.e. no conflict.
*/
override bool overloadInsert(Dsymbol s)
{
@@ -741,6 +754,8 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
return toCharsMaybeConstraints(false);
}
+ // Note: this function is not actually `const`, because iterating the
+ // function parameter list may run dsymbolsemantic on enum types
const(char)* toCharsMaybeConstraints(bool includeConstraints) const
{
OutBuffer buf;
@@ -758,15 +773,17 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
if (onemember)
{
- const FuncDeclaration fd = onemember.isFuncDeclaration();
- if (fd && fd.type)
+ if (const fd = onemember.isFuncDeclaration())
{
- TypeFunction tf = cast(TypeFunction)fd.type;
- buf.writestring(parametersTypeToChars(tf.parameterList));
- if (tf.mod)
+ if (TypeFunction tf = cast(TypeFunction)fd.type.isTypeFunction())
{
- buf.writeByte(' ');
- buf.MODtoBuffer(tf.mod);
+ // !! Casted away const
+ buf.writestring(parametersTypeToChars(tf.parameterList));
+ if (tf.mod)
+ {
+ buf.writeByte(' ');
+ buf.MODtoBuffer(tf.mod);
+ }
}
}
}
@@ -790,7 +807,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
/****************************
* Check to see if constraint is satisfied.
*/
- extern (D) bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd)
+ private bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd)
{
/* Detect recursive attempts to instantiate this template declaration,
* https://issues.dlang.org/show_bug.cgi?id=4072
@@ -807,7 +824,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
for (TemplatePrevious* p = previous; p; p = p.prev)
{
- if (!arrayObjectMatch(p.dedargs, dedargs))
+ if (!arrayObjectMatch(*p.dedargs, *dedargs))
continue;
//printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
/* It must be a subscope of p.sc, other scope chains are not recursive
@@ -1055,7 +1072,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
* dedtypes deduced arguments
* Return match level.
*/
- extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, ArgumentList argumentList, int flag)
+ private MATCH matchWithInstance(Scope* sc, TemplateInstance ti, ref Objects dedtypes, ArgumentList argumentList, int flag)
{
enum LOGM = 0;
static if (LOGM)
@@ -1151,7 +1168,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
/* Any parameter left without a type gets the type of
* its corresponding arg
*/
- foreach (i, ref dedtype; *dedtypes)
+ foreach (i, ref dedtype; dedtypes)
{
if (!dedtype)
{
@@ -1202,7 +1219,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
}
// TODO: dedtypes => ti.tiargs ?
- if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd))
+ if (!evaluateConstraint(ti, sc, paramscope, &dedtypes, fd))
return nomatch();
}
@@ -1283,7 +1300,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
Objects dedtypes = Objects(td2.parameters.length);
// Attempt a type deduction
- MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, argumentList, 1);
+ MATCH m = td2.matchWithInstance(sc, ti, dedtypes, argumentList, 1);
if (m > MATCH.nomatch)
{
/* A non-variadic template is more specialized than a
@@ -1425,7 +1442,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
{
assert(i < parameters.length);
Declaration sparam = null;
- MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam);
+ MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, &sparam);
//printf("\tdeduceType m = %d\n", m);
if (m == MATCH.nomatch)
return nomatch();
@@ -1458,10 +1475,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
ParameterList fparameters = fd.getParameterList(); // function parameter list
const nfparams = fparameters.length; // number of function parameters
- const nfargs = argumentList.length; // number of function arguments
if (argumentList.hasNames)
return matcherror(); // TODO: resolve named args
- Expressions* fargs = argumentList.arguments; // TODO: resolve named args
+ Expression[] fargs = argumentList.arguments ? (*argumentList.arguments)[] : null;
/* Check for match of function arguments with variadic template
* parameter, such as:
@@ -1475,7 +1491,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
// TemplateTupleParameter always makes most lesser matching.
matchTiargs = MATCH.convert;
- if (nfparams == 0 && nfargs != 0) // if no function parameters
+ if (nfparams == 0 && argumentList.length != 0) // if no function parameters
{
if (!declaredTuple)
{
@@ -1498,7 +1514,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ?
if (fparam.type.ty != Tident)
continue;
- TypeIdentifier tid = cast(TypeIdentifier)fparam.type;
+ TypeIdentifier tid = fparam.type.isTypeIdentifier();
if (!tp.ident.equals(tid.ident) || tid.idents.length)
continue;
@@ -1527,7 +1543,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
hasttp = true;
Type t = new TypeIdentifier(Loc.initial, ttp.ident);
- MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes);
+ MATCH m = deduceType(tthis, paramscope, t, *parameters, *dedtypes);
if (m == MATCH.nomatch)
return nomatch();
if (m < match)
@@ -1576,7 +1592,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
//printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0);
//printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL);
size_t argi = 0;
- size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs
+ size_t nfargs2 = fargs.length; // nfargs + supplied defaultArgs
uint inoutMatch = 0; // for debugging only
for (size_t parami = 0; parami < nfparams; parami++)
{
@@ -1592,8 +1608,8 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
*/
if (fptupindex != IDX_NOTFOUND && parami == fptupindex)
{
- assert(prmtype.ty == Tident);
- TypeIdentifier tid = cast(TypeIdentifier)prmtype;
+ TypeIdentifier tid = prmtype.isTypeIdentifier();
+ assert(tid);
if (!declaredTuple)
{
/* The types of the function arguments
@@ -1606,7 +1622,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
* void foo(U, T...)(int y, T, U, double, int bar = 0) {} // rem == 2 (U, double)
*/
size_t rem = 0;
- for (size_t j = parami + 1; j < nfparams; j++)
+ foreach (j; parami + 1 .. nfparams)
{
Parameter p = fparameters[j];
if (p.defaultArg)
@@ -1616,7 +1632,10 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
if (!reliesOnTemplateParameters(p.type, (*parameters)[inferStart .. parameters.length]))
{
Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope);
- rem += pt.ty == Ttuple ? (cast(TypeTuple)pt).arguments.length : 1;
+ if (auto ptt = pt.isTypeTuple())
+ rem += ptt.arguments.length;
+ else
+ rem += 1;
}
else
{
@@ -1627,9 +1646,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
if (nfargs2 - argi < rem)
return nomatch();
declaredTuple.objects.setDim(nfargs2 - argi - rem);
- for (size_t i = 0; i < declaredTuple.objects.length; i++)
+ foreach (i; 0 .. declaredTuple.objects.length)
{
- farg = (*fargs)[argi + i];
+ farg = fargs[argi + i];
// Check invalid arguments to detect errors early.
if (farg.op == EXP.error || farg.type.ty == Terror)
@@ -1647,7 +1666,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
}
else
{
- m = deduceTypeHelper(farg.type, &tt, tid);
+ m = deduceTypeHelper(farg.type, tt, tid);
}
if (m == MATCH.nomatch)
return nomatch();
@@ -1687,20 +1706,19 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
// should copy prmtype to avoid affecting semantic result
prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope);
- if (prmtype.ty == Ttuple)
+ if (TypeTuple tt = prmtype.isTypeTuple())
{
- TypeTuple tt = cast(TypeTuple)prmtype;
- size_t tt_dim = tt.arguments.length;
+ const tt_dim = tt.arguments.length;
for (size_t j = 0; j < tt_dim; j++, ++argi)
{
Parameter p = (*tt.arguments)[j];
if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe &&
- parami + 1 == nfparams && argi < nfargs)
+ parami + 1 == nfparams && argi < fargs.length)
{
prmtype = p.type;
goto Lvarargs;
}
- if (argi >= nfargs)
+ if (argi >= fargs.length)
{
if (p.defaultArg)
continue;
@@ -1711,7 +1729,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
return nomatch();
}
- farg = (*fargs)[argi];
+ farg = fargs[argi];
if (!farg.implicitConvTo(p.type))
return nomatch();
}
@@ -1719,7 +1737,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
}
}
- if (argi >= nfargs) // if not enough arguments
+ if (argi >= fargs.length) // if not enough arguments
{
if (!fparam.defaultArg)
goto Lvarargs;
@@ -1741,7 +1759,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
* // at fparam `N start = 0`, N should be 'size_t' before
* // the deduction result from fparam.defaultArg.
*/
- if (argi == nfargs)
+ if (argi == fargs.length)
{
foreach (ref dedtype; *dedtypes)
{
@@ -1769,7 +1787,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
* the oded == oarg
*/
(*dedargs)[i] = oded;
- MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
+ MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null);
//printf("m2 = %d\n", m2);
if (m2 == MATCH.nomatch)
return nomatch();
@@ -1822,7 +1840,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
}
else
{
- farg = (*fargs)[argi];
+ farg = fargs[argi];
}
{
// Check invalid arguments to detect errors early.
@@ -1851,8 +1869,15 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
{
/* Allow expressions that have CT-known boundaries and type [] to match with [dim]
*/
- Type taai;
- if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0))
+ bool inferIndexType = (argtype.ty == Tarray) && (prmtype.ty == Tsarray || prmtype.ty == Taarray);
+ if (auto aaType = prmtype.isTypeAArray())
+ {
+ if (auto indexType = aaType.index.isTypeIdentifier())
+ {
+ inferIndexType = indexType.idents.length == 0;
+ }
+ }
+ if (inferIndexType)
{
if (StringExp se = farg.isStringExp())
{
@@ -1871,7 +1896,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
oarg = argtype;
}
- else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && (cast(TypeIdentifier)prmtype).idents.length == 0)
+ else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && prmtype.isTypeIdentifier().idents.length == 0)
{
/* The farg passing to the prmtype always make a copy. Therefore,
* we can shrink the set of the deduced type arguments for prmtype
@@ -1892,11 +1917,11 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
}
}
- if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < nfargs)
+ if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < fargs.length)
goto Lvarargs;
uint im = 0;
- MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &im, inferStart);
+ MATCH m = deduceType(oarg, paramscope, prmtype, *parameters, *dedtypes, &im, inferStart);
//printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch);
inoutMatch |= im;
@@ -1984,17 +2009,15 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
case Taarray:
{
// Perhaps we can do better with this, see TypeFunction.callMatch()
- if (tb.ty == Tsarray)
+ if (TypeSArray tsa = tb.isTypeSArray())
{
- TypeSArray tsa = cast(TypeSArray)tb;
dinteger_t sz = tsa.dim.toInteger();
- if (sz != nfargs - argi)
+ if (sz != fargs.length - argi)
return nomatch();
}
- else if (tb.ty == Taarray)
+ else if (TypeAArray taa = tb.isTypeAArray())
{
- TypeAArray taa = cast(TypeAArray)tb;
- Expression dim = new IntegerExp(instLoc, nfargs - argi, Type.tsize_t);
+ Expression dim = new IntegerExp(instLoc, fargs.length - argi, Type.tsize_t);
size_t i = templateParameterLookup(taa.index, parameters);
if (i == IDX_NOTFOUND)
@@ -2057,9 +2080,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
{
TypeArray ta = cast(TypeArray)tb;
Type tret = fparam.isLazyArray();
- for (; argi < nfargs; argi++)
+ for (; argi < fargs.length; argi++)
{
- Expression arg = (*fargs)[argi];
+ Expression arg = fargs[argi];
assert(arg);
MATCH m;
@@ -2085,7 +2108,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
else
{
uint wm = 0;
- m = deduceType(arg, paramscope, ta.next, parameters, dedtypes, &wm, inferStart);
+ m = deduceType(arg, paramscope, ta.next, *parameters, *dedtypes, &wm, inferStart);
inoutMatch |= wm;
}
if (m == MATCH.nomatch)
@@ -2112,8 +2135,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
Lmatch:
foreach (ref dedtype; *dedtypes)
{
- Type at = isType(dedtype);
- if (at)
+ if (Type at = isType(dedtype))
{
if (at.ty == Tnone)
{
@@ -2147,7 +2169,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
* the oded == oarg
*/
(*dedargs)[i] = oded;
- MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
+ MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null);
//printf("m2 = %d\n", m2);
if (m2 == MATCH.nomatch)
return nomatch();
@@ -2194,7 +2216,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
if (tparam.specialization())
{
(*dedargs)[i] = oded;
- MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
+ MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null);
//printf("m2 = %d\n", m2);
if (m2 == MATCH.nomatch)
return nomatch();
@@ -2233,7 +2255,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
sc2.minst = sc.minst;
sc2.stc |= fd.storage_class & STC.deprecated_;
- fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs);
+ fd = doHeaderInstantiation(ti, sc2, fd, tthis, argumentList.arguments);
sc2 = sc2.pop();
sc2 = sc2.pop();
@@ -2396,7 +2418,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
}
if (hasttp)
{
- tf = cast(TypeFunction)tf.addSTC(ModToStc(tthis.mod));
+ tf = tf.addSTC(ModToStc(tthis.mod)).isTypeFunction();
assert(!tf.deco);
}
}
@@ -2602,10 +2624,10 @@ extern (C++) final class TypeDeduced : Type
* tiargs = initial list of template arguments
* tthis = if !NULL, the 'this' pointer argument
* argumentList= arguments to function
- * pMessage = address to store error message, or null
+ * errorHelper = delegate to send error message to if not null
*/
void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs,
- Type tthis, ArgumentList argumentList, const(char)** pMessage = null)
+ Type tthis, ArgumentList argumentList, void delegate(const(char)*) scope errorHelper = null)
{
version (none)
{
@@ -2662,7 +2684,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
return 1;
}
//printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars());
- auto tf = cast(TypeFunction)fd.type;
+ auto tf = fd.type.isTypeFunction();
int prop = tf.isproperty ? 1 : 2;
if (property == 0)
@@ -2711,8 +2733,12 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
else if (shared_this && !shared_dtor && tthis_fd !is null)
tf.mod = tthis_fd.mod;
}
- MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, pMessage, sc);
+ const(char)* failMessage;
+ const(char)** pMessage = errorHelper ? &failMessage : null;
+ MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, errorHelper, sc);
//printf("test1: mfa = %d\n", mfa);
+ if (failMessage)
+ errorHelper(failMessage);
if (mfa == MATCH.nomatch)
return 0;
@@ -2850,7 +2876,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
auto ti = new TemplateInstance(loc, td, tiargs);
Objects dedtypes = Objects(td.parameters.length);
assert(td.semanticRun != PASS.initial);
- MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, argumentList, 0);
+ MATCH mta = td.matchWithInstance(sc, ti, dedtypes, argumentList, 0);
//printf("matchWithInstance = %d\n", mta);
if (mta == MATCH.nomatch || mta < ta_last) // no match or less match
return 0;
@@ -2869,7 +2895,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
// Check for recursive instantiation of tdx.
for (TemplatePrevious* p = tdx.previous; p; p = p.prev)
{
- if (arrayObjectMatch(p.dedargs, &dedtypesX))
+ if (arrayObjectMatch(*p.dedargs, dedtypesX))
{
//printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
/* It must be a subscope of p.sc, other scope chains are not recursive
@@ -2918,7 +2944,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null;
- auto tf = cast(TypeFunction)fd.type;
+ auto tf = fd.type.isTypeFunction();
MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, null, sc);
if (mfa < m.last)
return 0;
@@ -2979,7 +3005,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
if (isCtorCall)
{
// Constructor call requires additional check.
- auto tf = cast(TypeFunction)fd.type;
+ auto tf = fd.type.isTypeFunction();
assert(tf.next);
if (MODimplicitConv(tf.mod, tthis_fd.mod) ||
tf.isWild() && tf.isShared() == tthis_fd.isShared() ||
@@ -3175,9 +3201,8 @@ private size_t templateIdentifierLookup(Identifier id, TemplateParameters* param
private size_t templateParameterLookup(Type tparam, TemplateParameters* parameters)
{
- if (tparam.ty == Tident)
+ if (TypeIdentifier tident = tparam.isTypeIdentifier())
{
- TypeIdentifier tident = cast(TypeIdentifier)tparam;
//printf("\ttident = '%s'\n", tident.toChars());
return templateIdentifierLookup(tident.ident, parameters);
}
@@ -3267,7 +3292,7 @@ private Type rawTypeMerge(Type t1, Type t2)
return null;
}
-private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
+private MATCH deduceTypeHelper(Type t, out Type at, Type tparam)
{
// 9*9 == 81 cases
@@ -3297,7 +3322,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
// foo(U) shared(inout(const(T))) => shared(inout(const(T)))
// foo(U) immutable(T) => immutable(T)
{
- *at = t;
+ at = t;
return MATCH.exact;
}
case X(MODFlags.const_, MODFlags.const_):
@@ -3317,7 +3342,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
// foo(shared(inout(const(U)))) shared(inout(const(T))) => T
// foo(immutable(U)) immutable(T) => T
{
- *at = t.mutableOf().unSharedOf();
+ at = t.mutableOf().unSharedOf();
return MATCH.exact;
}
case X(MODFlags.const_, MODFlags.shared_ | MODFlags.const_):
@@ -3327,7 +3352,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
// foo(inout(U)) shared(inout(T)) => shared(T)
// foo(inout(const(U))) shared(inout(const(T))) => shared(T)
{
- *at = t.mutableOf();
+ at = t.mutableOf();
return MATCH.exact;
}
case X(MODFlags.const_, 0):
@@ -3345,13 +3370,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
// foo(const(U)) immutable(T) => T
// foo(shared(const(U))) immutable(T) => T
{
- *at = t.mutableOf();
+ at = t.mutableOf();
return MATCH.constant;
}
case X(MODFlags.const_, MODFlags.shared_):
// foo(const(U)) shared(T) => shared(T)
{
- *at = t;
+ at = t;
return MATCH.constant;
}
case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.const_):
@@ -3361,13 +3386,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
// foo(shared(U)) shared(inout(T)) => inout(T)
// foo(shared(U)) shared(inout(const(T))) => inout(const(T))
{
- *at = t.unSharedOf();
+ at = t.unSharedOf();
return MATCH.exact;
}
case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_):
// foo(shared(const(U))) shared(T) => T
{
- *at = t.unSharedOf();
+ at = t.unSharedOf();
return MATCH.constant;
}
case X(MODFlags.wildconst, MODFlags.immutable_):
@@ -3379,13 +3404,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
// foo(shared(inout(const(U)))) immutable(T) => T
// foo(shared(inout(const(U)))) shared(inout(T)) => T
{
- *at = t.unSharedOf().mutableOf();
+ at = t.unSharedOf().mutableOf();
return MATCH.constant;
}
case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild):
// foo(shared(const(U))) shared(inout(T)) => T
{
- *at = t.unSharedOf().mutableOf();
+ at = t.unSharedOf().mutableOf();
return MATCH.constant;
}
case X(MODFlags.wild, 0):
@@ -3499,30 +3524,16 @@ __gshared Expression emptyArrayElement = null;
* Output:
* dedtypes = [ int ] // Array of Expression/Type's
*/
-MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false)
+MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters parameters, ref Objects dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false)
{
extern (C++) final class DeduceType : Visitor
{
alias visit = Visitor.visit;
public:
- Scope* sc;
- Type tparam;
- TemplateParameters* parameters;
- Objects* dedtypes;
- uint* wm;
- size_t inferStart;
- bool ignoreAliasThis;
MATCH result;
- extern (D) this(Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm, size_t inferStart, bool ignoreAliasThis) @safe
+ extern (D) this() @safe
{
- this.sc = sc;
- this.tparam = tparam;
- this.parameters = parameters;
- this.dedtypes = dedtypes;
- this.wm = wm;
- this.inferStart = inferStart;
- this.ignoreAliasThis = ignoreAliasThis;
result = MATCH.nomatch;
}
@@ -3537,7 +3548,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
if (tparam.ty == Tident)
{
// Determine which parameter tparam is
- size_t i = templateParameterLookup(tparam, parameters);
+ size_t i = templateParameterLookup(tparam, ¶meters);
if (i == IDX_NOTFOUND)
{
if (!sc)
@@ -3548,7 +3559,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
Loc loc;
if (parameters.length)
{
- TemplateParameter tp = (*parameters)[0];
+ TemplateParameter tp = parameters[0];
loc = tp.loc;
}
@@ -3561,9 +3572,9 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
return;
}
- TemplateParameter tp = (*parameters)[i];
+ TemplateParameter tp = parameters[i];
- TypeIdentifier tident = cast(TypeIdentifier)tparam;
+ TypeIdentifier tident = tparam.isTypeIdentifier();
if (tident.idents.length > 0)
{
//printf("matching %s to %s\n", tparam.toChars(), t.toChars());
@@ -3601,21 +3612,21 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
Type tt = s.getType();
if (!tt)
goto Lnomatch;
- Type at = cast(Type)(*dedtypes)[i];
+ Type at = cast(Type)dedtypes[i];
if (at && at.ty == Tnone)
at = (cast(TypeDeduced)at).tded;
if (!at || tt.equals(at))
{
- (*dedtypes)[i] = tt;
+ dedtypes[i] = tt;
goto Lexact;
}
}
if (tp.isTemplateAliasParameter())
{
- Dsymbol s2 = cast(Dsymbol)(*dedtypes)[i];
+ Dsymbol s2 = cast(Dsymbol)dedtypes[i];
if (!s2 || s == s2)
{
- (*dedtypes)[i] = s;
+ dedtypes[i] = s;
goto Lexact;
}
}
@@ -3637,7 +3648,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
+/
if (auto ta = tp.isTemplateAliasParameter())
{
- (*dedtypes)[i] = t;
+ dedtypes[i] = t;
goto Lexact;
}
// (23578) - ensure previous behaviour for non-alias template params
@@ -3646,14 +3657,14 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
goto Lnomatch;
}
- Type at = cast(Type)(*dedtypes)[i];
+ Type at = cast(Type)dedtypes[i];
Type tt;
if (ubyte wx = wm ? deduceWildHelper(t, &tt, tparam) : 0)
{
// type vs (none)
if (!at)
{
- (*dedtypes)[i] = tt;
+ dedtypes[i] = tt;
*wm |= wx;
result = MATCH.constant;
return;
@@ -3662,11 +3673,11 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
// type vs expressions
if (at.ty == Tnone)
{
- TypeDeduced xt = cast(TypeDeduced)at;
+ auto xt = cast(TypeDeduced)at;
result = xt.matchAll(tt);
if (result > MATCH.nomatch)
{
- (*dedtypes)[i] = tt;
+ dedtypes[i] = tt;
if (result > MATCH.constant)
result = MATCH.constant; // limit level for inout matches
}
@@ -3676,29 +3687,29 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
// type vs type
if (tt.equals(at))
{
- (*dedtypes)[i] = tt; // Prefer current type match
+ dedtypes[i] = tt; // Prefer current type match
goto Lconst;
}
if (tt.implicitConvTo(at.constOf()))
{
- (*dedtypes)[i] = at.constOf().mutableOf();
+ dedtypes[i] = at.constOf().mutableOf();
*wm |= MODFlags.const_;
goto Lconst;
}
if (at.implicitConvTo(tt.constOf()))
{
- (*dedtypes)[i] = tt.constOf().mutableOf();
+ dedtypes[i] = tt.constOf().mutableOf();
*wm |= MODFlags.const_;
goto Lconst;
}
goto Lnomatch;
}
- else if (MATCH m = deduceTypeHelper(t, &tt, tparam))
+ else if (MATCH m = deduceTypeHelper(t, tt, tparam))
{
// type vs (none)
if (!at)
{
- (*dedtypes)[i] = tt;
+ dedtypes[i] = tt;
result = m;
return;
}
@@ -3706,11 +3717,11 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
// type vs expressions
if (at.ty == Tnone)
{
- TypeDeduced xt = cast(TypeDeduced)at;
+ auto xt = cast(TypeDeduced)at;
result = xt.matchAll(tt);
if (result > MATCH.nomatch)
{
- (*dedtypes)[i] = tt;
+ dedtypes[i] = tt;
}
return;
}
@@ -3740,7 +3751,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
Loc loc;
if (parameters.length)
{
- TemplateParameter tp = (*parameters)[0];
+ TemplateParameter tp = parameters[0];
loc = tp.loc;
}
@@ -3757,9 +3768,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
MATCH m = t.implicitConvTo(tparam);
if (m == MATCH.nomatch && !ignoreAliasThis)
{
- if (t.ty == Tclass)
+ if (auto tc = t.isTypeClass())
{
- TypeClass tc = cast(TypeClass)t;
if (tc.sym.aliasthis && !(tc.att & AliasThisRec.tracingDT))
{
if (auto ato = t.aliasthisOf())
@@ -3770,9 +3780,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
}
}
}
- else if (t.ty == Tstruct)
+ else if (auto ts = t.isTypeStruct())
{
- TypeStruct ts = cast(TypeStruct)t;
if (ts.sym.aliasthis && !(ts.att & AliasThisRec.tracingDT))
{
if (auto ato = t.aliasthisOf())
@@ -3822,9 +3831,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
override void visit(TypeVector t)
{
- if (tparam.ty == Tvector)
+ if (auto tp = tparam.isTypeVector())
{
- TypeVector tp = cast(TypeVector)tparam;
result = deduceType(t.basetype, sc, tp.basetype, parameters, dedtypes, wm);
return;
}
@@ -3851,25 +3859,23 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
TemplateParameter tp = null;
Expression edim = null;
size_t i;
- if (tparam.ty == Tsarray)
+ if (auto tsa = tparam.isTypeSArray())
{
- TypeSArray tsa = cast(TypeSArray)tparam;
if (tsa.dim.isVarExp() && tsa.dim.isVarExp().var.storage_class & STC.templateparameter)
{
Identifier id = tsa.dim.isVarExp().var.ident;
- i = templateIdentifierLookup(id, parameters);
+ i = templateIdentifierLookup(id, ¶meters);
assert(i != IDX_NOTFOUND);
- tp = (*parameters)[i];
+ tp = parameters[i];
}
else
edim = tsa.dim;
}
- else if (tparam.ty == Taarray)
+ else if (auto taa = tparam.isTypeAArray())
{
- TypeAArray taa = cast(TypeAArray)tparam;
- i = templateParameterLookup(taa.index, parameters);
+ i = templateParameterLookup(taa.index, ¶meters);
if (i != IDX_NOTFOUND)
- tp = (*parameters)[i];
+ tp = parameters[i];
else
{
Loc loc;
@@ -3878,7 +3884,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
// so we use that for the resolution (better error message).
if (inferStart < parameters.length)
{
- TemplateParameter loctp = (*parameters)[inferStart];
+ TemplateParameter loctp = parameters[inferStart];
loc = loctp.loc;
}
@@ -3889,7 +3895,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
edim = s ? getValue(s) : getValue(e);
}
}
- if (tp && tp.matchArg(sc, t.dim, i, parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger())
+ if (tp && tp.matchArg(sc, t.dim, i, ¶meters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger())
{
result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
return;
@@ -3903,7 +3909,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
// Extra check that index type must match
if (tparam && tparam.ty == Taarray)
{
- TypeAArray tp = cast(TypeAArray)tparam;
+ TypeAArray tp = tparam.isTypeAArray();
if (!deduceType(t.index, sc, tp.index, parameters, dedtypes))
{
result = MATCH.nomatch;
@@ -3936,7 +3942,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
// https://issues.dlang.org/show_bug.cgi?id=15243
// Resolve parameter type if it's not related with template parameters
- if (!reliesOnTemplateParameters(fparam.type, (*parameters)[inferStart .. parameters.length]))
+ if (!reliesOnTemplateParameters(fparam.type, parameters[inferStart .. parameters.length]))
{
auto tx = fparam.type.typeSemantic(Loc.initial, sc);
if (tx.ty == Terror)
@@ -3948,7 +3954,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
}
}
- size_t nfargs = t.parameterList.length;
+ const size_t nfargs = t.parameterList.length;
size_t nfparams = tp.parameterList.length;
/* See if tuple match
@@ -3963,7 +3969,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
assert(fparam.type);
if (fparam.type.ty != Tident)
goto L1;
- TypeIdentifier tid = cast(TypeIdentifier)fparam.type;
+ TypeIdentifier tid = fparam.type.isTypeIdentifier();
if (tid.idents.length)
goto L1;
@@ -3974,7 +3980,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
{
if (tupi == parameters.length)
goto L1;
- TemplateParameter tx = (*parameters)[tupi];
+ TemplateParameter tx = parameters[tupi];
TemplateTupleParameter tup = tx.isTemplateTupleParameter();
if (tup && tup.ident.equals(tid.ident))
break;
@@ -3987,7 +3993,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
/* See if existing tuple, and whether it matches or not
*/
- RootObject o = (*dedtypes)[tupi];
+ RootObject o = dedtypes[tupi];
if (o)
{
// Existing deduced argument must be a tuple, and must match
@@ -4016,7 +4022,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
Parameter arg = t.parameterList[nfparams - 1 + i];
tup.objects[i] = arg.type;
}
- (*dedtypes)[tupi] = tup;
+ dedtypes[tupi] = tup;
}
nfparams--; // don't consider the last parameter for type deduction
goto L2;
@@ -4053,7 +4059,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
// Extra check
if (tparam && tparam.ty == Tident)
{
- TypeIdentifier tp = cast(TypeIdentifier)tparam;
+ TypeIdentifier tp = tparam.isTypeIdentifier();
for (size_t i = 0; i < t.idents.length; i++)
{
RootObject id1 = t.idents[i];
@@ -4076,7 +4082,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration();
assert(tempdecl);
- TypeInstance tp = cast(TypeInstance)tparam;
+ TypeInstance tp = tparam.isTypeInstance();
//printf("tempinst.tempdecl = %p\n", tempdecl);
//printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl);
@@ -4087,7 +4093,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
/* Handle case of:
* template Foo(T : sa!(T), alias sa)
*/
- size_t i = templateIdentifierLookup(tp.tempinst.name, parameters);
+ size_t i = templateIdentifierLookup(tp.tempinst.name, ¶meters);
if (i == IDX_NOTFOUND)
{
/* Didn't find it as a parameter identifier. Try looking
@@ -4132,15 +4138,15 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
goto Lnomatch;
}
- TemplateParameter tpx = (*parameters)[i];
- if (!tpx.matchArg(sc, tempdecl, i, parameters, dedtypes, null))
+ TemplateParameter tpx = parameters[i];
+ if (!tpx.matchArg(sc, tempdecl, i, ¶meters, dedtypes, null))
goto Lnomatch;
}
else if (tempdecl != tp.tempinst.tempdecl)
goto Lnomatch;
L2:
- if (!resolveTemplateInstantiation(t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, dedtypes))
+ if (!resolveTemplateInstantiation(sc, ¶meters, t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, &dedtypes))
goto Lnomatch;
}
visit(cast(Type)t);
@@ -4151,198 +4157,6 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
result = MATCH.nomatch;
}
- /********************
- * Match template `parameters` to the target template instance.
- * Example:
- * struct Temp(U, int Z) {}
- * void foo(T)(Temp!(T, 3));
- * foo(Temp!(int, 3)());
- * Input:
- * this.parameters = template params of foo -> [T]
- * tiargs = <Temp!(int, 3)>.tiargs -> [int, 3]
- * tdtypes = <Temp!(int, 3)>.tdtypes -> [int, 3]
- * tempdecl = <struct Temp!(T, int Z)> -> [T, Z]
- * tp = <Temp!(T, 3)>
- * Output:
- * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int]
- */
- private bool resolveTemplateInstantiation(Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes)
- {
- for (size_t i = 0; 1; i++)
- {
- //printf("\ttest: tempinst.tiargs[%zu]\n", i);
- RootObject o1 = null;
- if (i < tiargs.length)
- o1 = (*tiargs)[i];
- else if (i < tdtypes.length && i < tp.tempinst.tiargs.length)
- {
- // Pick up default arg
- o1 = (*tdtypes)[i];
- }
- else if (i >= tp.tempinst.tiargs.length)
- break;
- //printf("\ttest: o1 = %s\n", o1.toChars());
- if (i >= tp.tempinst.tiargs.length)
- {
- size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0);
- while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg()))
- {
- i++;
- }
- if (i >= dim)
- break; // match if all remained parameters are dependent
- return false;
- }
-
- RootObject o2 = (*tp.tempinst.tiargs)[i];
- Type t2 = isType(o2);
- //printf("\ttest: o2 = %s\n", o2.toChars());
- size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1)
- ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND;
- if (j != IDX_NOTFOUND && j == parameters.length - 1 &&
- (*parameters)[j].isTemplateTupleParameter())
- {
- /* Given:
- * struct A(B...) {}
- * alias A!(int, float) X;
- * static if (is(X Y == A!(Z), Z...)) {}
- * deduce that Z is a tuple(int, float)
- */
-
- /* Create tuple from remaining args
- */
- size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i;
- auto vt = new Tuple(vtdim);
- for (size_t k = 0; k < vtdim; k++)
- {
- RootObject o;
- if (k < tiargs.length)
- o = (*tiargs)[i + k];
- else // Pick up default arg
- o = (*tdtypes)[i + k];
- vt.objects[k] = o;
- }
-
- Tuple v = cast(Tuple)(*dedtypes)[j];
- if (v)
- {
- if (!match(v, vt))
- return false;
- }
- else
- (*dedtypes)[j] = vt;
- break;
- }
- else if (!o1)
- break;
-
- Type t1 = isType(o1);
- Dsymbol s1 = isDsymbol(o1);
- Dsymbol s2 = isDsymbol(o2);
- Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1));
- Expression e2 = isExpression(o2);
- version (none)
- {
- Tuple v1 = isTuple(o1);
- Tuple v2 = isTuple(o2);
- if (t1)
- printf("t1 = %s\n", t1.toChars());
- if (t2)
- printf("t2 = %s\n", t2.toChars());
- if (e1)
- printf("e1 = %s\n", e1.toChars());
- if (e2)
- printf("e2 = %s\n", e2.toChars());
- if (s1)
- printf("s1 = %s\n", s1.toChars());
- if (s2)
- printf("s2 = %s\n", s2.toChars());
- if (v1)
- printf("v1 = %s\n", v1.toChars());
- if (v2)
- printf("v2 = %s\n", v2.toChars());
- }
-
- if (t1 && t2)
- {
- if (!deduceType(t1, sc, t2, parameters, dedtypes))
- return false;
- }
- else if (e1 && e2)
- {
- Le:
- e1 = e1.ctfeInterpret();
-
- /* If it is one of the template parameters for this template,
- * we should not attempt to interpret it. It already has a value.
- */
- if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter))
- {
- /*
- * (T:Number!(e2), int e2)
- */
- j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters);
- if (j != IDX_NOTFOUND)
- goto L1;
- // The template parameter was not from this template
- // (it may be from a parent template, for example)
- }
-
- e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417
- e2 = e2.ctfeInterpret();
-
- //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty);
- //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty);
- if (!e1.equals(e2))
- {
- if (!e2.implicitConvTo(e1.type))
- return false;
-
- e2 = e2.implicitCastTo(sc, e1.type);
- e2 = e2.ctfeInterpret();
- if (!e1.equals(e2))
- return false;
- }
- }
- else if (e1 && t2 && t2.ty == Tident)
- {
- j = templateParameterLookup(t2, parameters);
- L1:
- if (j == IDX_NOTFOUND)
- {
- t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
- if (e2)
- goto Le;
- return false;
- }
- if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null))
- return false;
- }
- else if (s1 && s2)
- {
- Ls:
- if (!s1.equals(s2))
- return false;
- }
- else if (s1 && t2 && t2.ty == Tident)
- {
- j = templateParameterLookup(t2, parameters);
- if (j == IDX_NOTFOUND)
- {
- t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
- if (s2)
- goto Ls;
- return false;
- }
- if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null))
- return false;
- }
- else
- return false;
- }
- return true;
- }
-
override void visit(TypeStruct t)
{
/* If this struct is a template struct, and we're matching
@@ -4368,7 +4182,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
/* Match things like:
* S!(T).foo
*/
- TypeInstance tpi = cast(TypeInstance)tparam;
+ TypeInstance tpi = tparam.isTypeInstance();
if (tpi.idents.length)
{
RootObject id = tpi.idents[tpi.idents.length - 1];
@@ -4391,7 +4205,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
// Extra check
if (tparam && tparam.ty == Tstruct)
{
- TypeStruct tp = cast(TypeStruct)tparam;
+ TypeStruct tp = tparam.isTypeStruct();
//printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
if (wm && t.deduceWild(tparam, false))
@@ -4410,7 +4224,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
// Extra check
if (tparam && tparam.ty == Tenum)
{
- TypeEnum tp = cast(TypeEnum)tparam;
+ TypeEnum tp = tparam.isTypeEnum();
if (t.sym == tp.sym)
visit(cast(Type)t);
else
@@ -4428,59 +4242,6 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
visit(cast(Type)t);
}
- /* Helper for TypeClass.deduceType().
- * Classes can match with implicit conversion to a base class or interface.
- * This is complicated, because there may be more than one base class which
- * matches. In such cases, one or more parameters remain ambiguous.
- * For example,
- *
- * interface I(X, Y) {}
- * class C : I(uint, double), I(char, double) {}
- * C x;
- * foo(T, U)( I!(T, U) x)
- *
- * deduces that U is double, but T remains ambiguous (could be char or uint).
- *
- * Given a baseclass b, and initial deduced types 'dedtypes', this function
- * tries to match tparam with b, and also tries all base interfaces of b.
- * If a match occurs, numBaseClassMatches is incremented, and the new deduced
- * types are ANDed with the current 'best' estimate for dedtypes.
- */
- static void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, Objects* best, ref int numBaseClassMatches)
- {
- TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null;
- if (parti)
- {
- // Make a temporary copy of dedtypes so we don't destroy it
- auto tmpdedtypes = new Objects(dedtypes.length);
- memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.length * (void*).sizeof);
-
- auto t = new TypeInstance(Loc.initial, parti);
- MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes);
- if (m > MATCH.nomatch)
- {
- // If this is the first ever match, it becomes our best estimate
- if (numBaseClassMatches == 0)
- memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.length * (void*).sizeof);
- else
- for (size_t k = 0; k < tmpdedtypes.length; ++k)
- {
- // If we've found more than one possible type for a parameter,
- // mark it as unknown.
- if ((*tmpdedtypes)[k] != (*best)[k])
- (*best)[k] = (*dedtypes)[k];
- }
- ++numBaseClassMatches;
- }
- }
-
- // Now recursively test the inherited interfaces
- foreach (ref bi; b.baseInterfaces)
- {
- deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
- }
- }
-
override void visit(TypeClass t)
{
//printf("TypeClass.deduceType(this = %s)\n", t.toChars());
@@ -4509,7 +4270,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
/* Match things like:
* S!(T).foo
*/
- TypeInstance tpi = cast(TypeInstance)tparam;
+ TypeInstance tpi = tparam.isTypeInstance();
if (tpi.idents.length)
{
RootObject id = tpi.idents[tpi.idents.length - 1];
@@ -4547,12 +4308,12 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
while (s && s.baseclasses.length > 0)
{
// Test the base class
- deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
+ deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, *best, numBaseClassMatches);
// Test the interfaces inherited by the base class
foreach (b; s.interfaces)
{
- deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
+ deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, *best, numBaseClassMatches);
}
s = (*s.baseclasses)[0].sym;
}
@@ -4572,7 +4333,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
// Extra check
if (tparam && tparam.ty == Tclass)
{
- TypeClass tp = cast(TypeClass)tparam;
+ TypeClass tp = tparam.isTypeClass();
//printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
if (wm && t.deduceWild(tparam, false))
@@ -4589,8 +4350,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
override void visit(Expression e)
{
//printf("Expression.deduceType(e = %s)\n", e.toChars());
- size_t i = templateParameterLookup(tparam, parameters);
- if (i == IDX_NOTFOUND || (cast(TypeIdentifier)tparam).idents.length > 0)
+ size_t i = templateParameterLookup(tparam, ¶meters);
+ if (i == IDX_NOTFOUND || tparam.isTypeIdentifier().idents.length > 0)
{
if (e == emptyArrayElement && tparam.ty == Tarray)
{
@@ -4602,13 +4363,13 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
return;
}
- TemplateTypeParameter tp = (*parameters)[i].isTemplateTypeParameter();
+ TemplateTypeParameter tp = parameters[i].isTemplateTypeParameter();
if (!tp)
return; // nomatch
if (e == emptyArrayElement)
{
- if ((*dedtypes)[i])
+ if (dedtypes[i])
{
result = MATCH.exact;
return;
@@ -4630,14 +4391,14 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
tb.ty == Tstruct && tb.hasPointers();
}
- Type at = cast(Type)(*dedtypes)[i];
+ Type at = cast(Type)dedtypes[i];
Type tt;
if (ubyte wx = deduceWildHelper(e.type, &tt, tparam))
{
*wm |= wx;
result = MATCH.constant;
}
- else if (MATCH m = deduceTypeHelper(e.type, &tt, tparam))
+ else if (MATCH m = deduceTypeHelper(e.type, tt, tparam))
{
result = m;
}
@@ -4658,7 +4419,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
// expression vs (none)
if (!at)
{
- (*dedtypes)[i] = new TypeDeduced(tt, e, tparam);
+ dedtypes[i] = new TypeDeduced(tt, e, tparam);
return;
}
@@ -4716,7 +4477,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
if (xt)
xt.update(tt, e, tparam);
else
- (*dedtypes)[i] = tt;
+ dedtypes[i] = tt;
result = match1;
return;
}
@@ -4736,7 +4497,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
if (xt)
xt.update(t, e, tparam);
else
- (*dedtypes)[i] = t;
+ dedtypes[i] = t;
pt = tt.addMod(tparam.mod);
if (*wm)
@@ -4870,7 +4631,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
// Parameter types inference from 'tof'
assert(e.td._scope);
- TypeFunction tf = cast(TypeFunction)e.fd.type;
+ TypeFunction tf = e.fd.type.isTypeFunction();
//printf("\ttof = %s\n", tof.toChars());
//printf("\ttf = %s\n", tf.toChars());
const dim = tf.parameterList.length;
@@ -4895,7 +4656,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
if (!pto)
break;
Type t = pto.type.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774
- if (reliesOnTemplateParameters(t, (*parameters)[inferStart .. parameters.length]))
+ if (reliesOnTemplateParameters(t, parameters[inferStart .. parameters.length]))
return;
t = t.typeSemantic(e.loc, sc);
if (t.ty == Terror)
@@ -4929,7 +4690,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
// Allow conversion from implicit function pointer to delegate
if (e.tok == TOK.reserved && t.ty == Tpointer && tparam.ty == Tdelegate)
{
- TypeFunction tf = cast(TypeFunction)t.nextOf();
+ TypeFunction tf = t.nextOf().isTypeFunction();
t = (new TypeDelegate(tf)).merge();
}
//printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars());
@@ -4959,7 +4720,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
}
}
- scope DeduceType v = new DeduceType(sc, tparam, parameters, dedtypes, wm, inferStart, ignoreAliasThis);
+ scope DeduceType v = new DeduceType();
if (Type t = isType(o))
t.accept(v);
else if (Expression e = isExpression(o))
@@ -4972,6 +4733,254 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
return v.result;
}
+
+/* Helper for TypeClass.deduceType().
+ * Classes can match with implicit conversion to a base class or interface.
+ * This is complicated, because there may be more than one base class which
+ * matches. In such cases, one or more parameters remain ambiguous.
+ * For example,
+ *
+ * interface I(X, Y) {}
+ * class C : I(uint, double), I(char, double) {}
+ * C x;
+ * foo(T, U)( I!(T, U) x)
+ *
+ * deduces that U is double, but T remains ambiguous (could be char or uint).
+ *
+ * Given a baseclass b, and initial deduced types 'dedtypes', this function
+ * tries to match tparam with b, and also tries all base interfaces of b.
+ * If a match occurs, numBaseClassMatches is incremented, and the new deduced
+ * types are ANDed with the current 'best' estimate for dedtypes.
+ */
+private void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, ref TemplateParameters parameters, ref Objects dedtypes, ref Objects best, ref int numBaseClassMatches)
+{
+ TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null;
+ if (parti)
+ {
+ // Make a temporary copy of dedtypes so we don't destroy it
+ auto tmpdedtypes = new Objects(dedtypes.length);
+ memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.length * (void*).sizeof);
+
+ auto t = new TypeInstance(Loc.initial, parti);
+ MATCH m = deduceType(t, sc, tparam, parameters, *tmpdedtypes);
+ if (m > MATCH.nomatch)
+ {
+ // If this is the first ever match, it becomes our best estimate
+ if (numBaseClassMatches == 0)
+ memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.length * (void*).sizeof);
+ else
+ for (size_t k = 0; k < tmpdedtypes.length; ++k)
+ {
+ // If we've found more than one possible type for a parameter,
+ // mark it as unknown.
+ if ((*tmpdedtypes)[k] != best[k])
+ best[k] = dedtypes[k];
+ }
+ ++numBaseClassMatches;
+ }
+ }
+
+ // Now recursively test the inherited interfaces
+ foreach (ref bi; b.baseInterfaces)
+ {
+ deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
+ }
+}
+
+/********************
+ * Match template `parameters` to the target template instance.
+ * Example:
+ * struct Temp(U, int Z) {}
+ * void foo(T)(Temp!(T, 3));
+ * foo(Temp!(int, 3)());
+ * Input:
+ * sc = context
+ * parameters = template params of foo -> [T]
+ * tiargs = <Temp!(int, 3)>.tiargs -> [int, 3]
+ * tdtypes = <Temp!(int, 3)>.tdtypes -> [int, 3]
+ * tempdecl = <struct Temp!(T, int Z)> -> [T, Z]
+ * tp = <Temp!(T, 3)>
+ * Output:
+ * dedtypes = deduced params of `foo(Temp!(int, 3)())` -> [int]
+ */
+private bool resolveTemplateInstantiation(Scope* sc, TemplateParameters* parameters, Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes)
+{
+ for (size_t i = 0; 1; i++)
+ {
+ //printf("\ttest: tempinst.tiargs[%zu]\n", i);
+ RootObject o1 = null;
+ if (i < tiargs.length)
+ o1 = (*tiargs)[i];
+ else if (i < tdtypes.length && i < tp.tempinst.tiargs.length)
+ {
+ // Pick up default arg
+ o1 = (*tdtypes)[i];
+ }
+ else if (i >= tp.tempinst.tiargs.length)
+ break;
+ //printf("\ttest: o1 = %s\n", o1.toChars());
+ if (i >= tp.tempinst.tiargs.length)
+ {
+ size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0);
+ while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg()))
+ {
+ i++;
+ }
+ if (i >= dim)
+ break; // match if all remained parameters are dependent
+ return false;
+ }
+
+ RootObject o2 = (*tp.tempinst.tiargs)[i];
+ Type t2 = isType(o2);
+ //printf("\ttest: o2 = %s\n", o2.toChars());
+ size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1)
+ ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND;
+ if (j != IDX_NOTFOUND && j == parameters.length - 1 &&
+ (*parameters)[j].isTemplateTupleParameter())
+ {
+ /* Given:
+ * struct A(B...) {}
+ * alias A!(int, float) X;
+ * static if (is(X Y == A!(Z), Z...)) {}
+ * deduce that Z is a tuple(int, float)
+ */
+
+ /* Create tuple from remaining args
+ */
+ size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i;
+ auto vt = new Tuple(vtdim);
+ for (size_t k = 0; k < vtdim; k++)
+ {
+ RootObject o;
+ if (k < tiargs.length)
+ o = (*tiargs)[i + k];
+ else // Pick up default arg
+ o = (*tdtypes)[i + k];
+ vt.objects[k] = o;
+ }
+
+ Tuple v = cast(Tuple)(*dedtypes)[j];
+ if (v)
+ {
+ if (!match(v, vt))
+ return false;
+ }
+ else
+ (*dedtypes)[j] = vt;
+ break;
+ }
+ else if (!o1)
+ break;
+
+ Type t1 = isType(o1);
+ Dsymbol s1 = isDsymbol(o1);
+ Dsymbol s2 = isDsymbol(o2);
+ Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1));
+ Expression e2 = isExpression(o2);
+ version (none)
+ {
+ Tuple v1 = isTuple(o1);
+ Tuple v2 = isTuple(o2);
+ if (t1)
+ printf("t1 = %s\n", t1.toChars());
+ if (t2)
+ printf("t2 = %s\n", t2.toChars());
+ if (e1)
+ printf("e1 = %s\n", e1.toChars());
+ if (e2)
+ printf("e2 = %s\n", e2.toChars());
+ if (s1)
+ printf("s1 = %s\n", s1.toChars());
+ if (s2)
+ printf("s2 = %s\n", s2.toChars());
+ if (v1)
+ printf("v1 = %s\n", v1.toChars());
+ if (v2)
+ printf("v2 = %s\n", v2.toChars());
+ }
+
+ if (t1 && t2)
+ {
+ if (!deduceType(t1, sc, t2, *parameters, *dedtypes))
+ return false;
+ }
+ else if (e1 && e2)
+ {
+ Le:
+ e1 = e1.ctfeInterpret();
+
+ /* If it is one of the template parameters for this template,
+ * we should not attempt to interpret it. It already has a value.
+ */
+ if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter))
+ {
+ /*
+ * (T:Number!(e2), int e2)
+ */
+ j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters);
+ if (j != IDX_NOTFOUND)
+ goto L1;
+ // The template parameter was not from this template
+ // (it may be from a parent template, for example)
+ }
+
+ e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417
+ e2 = e2.ctfeInterpret();
+
+ //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty);
+ //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty);
+ if (!e1.equals(e2))
+ {
+ if (!e2.implicitConvTo(e1.type))
+ return false;
+
+ e2 = e2.implicitCastTo(sc, e1.type);
+ e2 = e2.ctfeInterpret();
+ if (!e1.equals(e2))
+ return false;
+ }
+ }
+ else if (e1 && t2 && t2.ty == Tident)
+ {
+ j = templateParameterLookup(t2, parameters);
+ L1:
+ if (j == IDX_NOTFOUND)
+ {
+ t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
+ if (e2)
+ goto Le;
+ return false;
+ }
+ if (!(*parameters)[j].matchArg(sc, e1, j, parameters, *dedtypes, null))
+ return false;
+ }
+ else if (s1 && s2)
+ {
+ Ls:
+ if (!s1.equals(s2))
+ return false;
+ }
+ else if (s1 && t2 && t2.ty == Tident)
+ {
+ j = templateParameterLookup(t2, parameters);
+ if (j == IDX_NOTFOUND)
+ {
+ t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
+ if (s2)
+ goto Ls;
+ return false;
+ }
+ if (!(*parameters)[j].matchArg(sc, s1, j, parameters, *dedtypes, null))
+ return false;
+ }
+ else
+ return false;
+ }
+ return true;
+}
+
+
/***********************************************************
* Check whether the type t representation relies on one or more the template parameters.
* Params:
@@ -5625,7 +5634,11 @@ extern (C++) final class TemplateValueParameter : TemplateParameter
if (e)
{
e = e.syntaxCopy();
- if ((e = e.expressionSemantic(sc)) is null)
+ Scope* sc2 = sc.push();
+ sc2.inDefaultArg = true;
+ e = e.expressionSemantic(sc2);
+ sc2.pop();
+ if (e is null)
return null;
if (auto te = e.isTemplateExp())
{
@@ -6176,7 +6189,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
}
//printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars());
- if (!arrayObjectMatch(&tdtypes, &ti.tdtypes))
+ if (!arrayObjectMatch(tdtypes, ti.tdtypes))
goto Lnotequals;
/* Template functions may have different instantiations based on
@@ -6221,7 +6234,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
if (!hash)
{
hash = cast(size_t)cast(void*)enclosing;
- hash += arrayObjectHash(&tdtypes);
+ hash += arrayObjectHash(tdtypes);
hash += hash == 0;
}
return hash;
@@ -6691,6 +6704,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol
if (!tiargs)
return true;
bool err = false;
+
+ // The arguments are not treated as part of a default argument,
+ // because they are evaluated at compile time.
+ sc = sc.push();
+ sc.inDefaultArg = false;
+
for (size_t j = 0; j < tiargs.length; j++)
{
RootObject o = (*tiargs)[j];
@@ -6716,10 +6735,9 @@ extern (C++) class TemplateInstance : ScopeDsymbol
}
Ltype:
- if (ta.ty == Ttuple)
+ if (TypeTuple tt = ta.isTypeTuple())
{
// Expand tuple
- TypeTuple tt = cast(TypeTuple)ta;
size_t dim = tt.arguments.length;
tiargs.remove(j);
if (dim)
@@ -6923,6 +6941,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
}
//printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]);
}
+ sc.pop();
version (none)
{
printf("-TemplateInstance.semanticTiargs()\n");
@@ -6982,7 +7001,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
assert(tempdecl._scope);
// Deduce tdtypes
tdtypes.setDim(tempdecl.parameters.length);
- if (!tempdecl.matchWithInstance(sc, this, &tdtypes, argumentList, 2))
+ if (!tempdecl.matchWithInstance(sc, this, tdtypes, argumentList, 2))
{
.error(loc, "%s `%s` incompatible arguments for template instantiation", kind, toPrettyChars);
return false;
@@ -7032,7 +7051,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
dedtypes.zero();
assert(td.semanticRun != PASS.initial);
- MATCH m = td.matchWithInstance(sc, this, &dedtypes, argumentList, 0);
+ MATCH m = td.matchWithInstance(sc, this, dedtypes, argumentList, 0);
//printf("matchWithInstance = %d\n", m);
if (m == MATCH.nomatch) // no match at all
return 0;
@@ -7158,7 +7177,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
// print additional information, e.g. `foo` is not a type
foreach (i, param; *tdecl.parameters)
{
- MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, &dedtypes, null);
+ MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, dedtypes, null);
auto arg = (*tiargs)[i];
auto sym = arg.isDsymbol;
auto exp = arg.isExpression;
@@ -7262,7 +7281,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
* to instantiate the template.
*/
//printf("tp = %p, td.parameters.length = %d, tiargs.length = %d\n", tp, td.parameters.length, tiargs.length);
- auto tf = cast(TypeFunction)fd.type;
+ auto tf = fd.type.isTypeFunction();
if (tf.parameterList.length)
{
auto tp = td.isVariadic();
@@ -7308,7 +7327,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
return 1;
}
}
- MATCH m = td.matchWithInstance(sc, this, &dedtypes, ArgumentList(), 0);
+ MATCH m = td.matchWithInstance(sc, this, dedtypes, ArgumentList(), 0);
if (m == MATCH.nomatch)
return 0;
}
@@ -7992,7 +8011,7 @@ struct TemplateInstanceBox
* dedtypes[] deduced arguments to template instance
* *psparam set to symbol declared and initialized to dedtypes[i]
*/
-MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam)
+MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam)
{
MATCH matchArgNoMatch()
{
@@ -8015,7 +8034,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si
{
assert(i < dedtypes.length);
// It might have already been deduced
- oarg = (*dedtypes)[i];
+ oarg = dedtypes[i];
if (!oarg)
return matchArgNoMatch();
}
@@ -8031,7 +8050,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si
assert(i + 1 == dedtypes.length); // must be the last one
Tuple ovar;
- if (Tuple u = isTuple((*dedtypes)[i]))
+ if (Tuple u = isTuple(dedtypes[i]))
{
// It has already been deduced
ovar = u;
@@ -8059,7 +8078,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si
return matchArgParameter();
}
-MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam)
+MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam)
{
MATCH matchArgNoMatch()
{
@@ -8087,7 +8106,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
return matchArgNoMatch();
//printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), ttp.specType.toChars());
- MATCH m2 = deduceType(ta, sc, ttp.specType, parameters, dedtypes);
+ MATCH m2 = deduceType(ta, sc, ttp.specType, *parameters, dedtypes);
if (m2 == MATCH.nomatch)
{
//printf("\tfailed deduceType\n");
@@ -8096,9 +8115,9 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
if (m2 < m)
m = m2;
- if ((*dedtypes)[i])
+ if (dedtypes[i])
{
- Type t = cast(Type)(*dedtypes)[i];
+ Type t = cast(Type)dedtypes[i];
if (ttp.dependent && !t.equals(ta)) // https://issues.dlang.org/show_bug.cgi?id=14357
return matchArgNoMatch();
@@ -8113,10 +8132,10 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
}
else
{
- if ((*dedtypes)[i])
+ if (dedtypes[i])
{
// Must match already deduced type
- Type t = cast(Type)(*dedtypes)[i];
+ Type t = cast(Type)dedtypes[i];
if (!t.equals(ta))
{
@@ -8130,7 +8149,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
m = MATCH.convert;
}
}
- (*dedtypes)[i] = ta;
+ dedtypes[i] = ta;
if (psparam)
*psparam = new AliasDeclaration(ttp.loc, ttp.ident, ta);
@@ -8235,15 +8254,15 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
}
else
{
- if ((*dedtypes)[i])
+ if (dedtypes[i])
{
// Must match already deduced value
- Expression e = cast(Expression)(*dedtypes)[i];
+ Expression e = cast(Expression)dedtypes[i];
if (!ei || !ei.equals(e))
return matchArgNoMatch();
}
}
- (*dedtypes)[i] = ei;
+ dedtypes[i] = ei;
if (psparam)
{
@@ -8354,7 +8373,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
return matchArgNoMatch();
Type t = new TypeInstance(Loc.initial, ti);
- MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes);
+ MATCH m2 = deduceType(t, sc, talias, *parameters, dedtypes);
if (m2 == MATCH.nomatch)
return matchArgNoMatch();
}
@@ -8375,14 +8394,14 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
}
}
}
- else if ((*dedtypes)[i])
+ else if (dedtypes[i])
{
// Must match already deduced symbol
- RootObject si = (*dedtypes)[i];
+ RootObject si = dedtypes[i];
if (!sa || si != sa)
return matchArgNoMatch();
}
- (*dedtypes)[i] = sa;
+ dedtypes[i] = sa;
if (psparam)
{
@@ -8415,15 +8434,15 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
Tuple ovar = isTuple(oarg);
if (!ovar)
return MATCH.nomatch;
- if ((*dedtypes)[i])
+ if (dedtypes[i])
{
- Tuple tup = isTuple((*dedtypes)[i]);
+ Tuple tup = isTuple(dedtypes[i]);
if (!tup)
return MATCH.nomatch;
if (!match(tup, ovar))
return MATCH.nomatch;
}
- (*dedtypes)[i] = ovar;
+ dedtypes[i] = ovar;
if (psparam)
*psparam = new TupleDeclaration(ttp.loc, ttp.ident, &ovar.objects);
@@ -8457,21 +8476,24 @@ struct TemplateStats
/*******************************
* Add this instance
+ * Params:
+ * td = template declaration
+ * ti = instance of td
+ * listInstances = keep track of instances of templates
*/
static void incInstance(const TemplateDeclaration td,
- const TemplateInstance ti)
+ const TemplateInstance ti,
+ bool listInstances)
{
void log(ref TemplateStats ts)
{
if (ts.allInstances is null)
ts.allInstances = new TemplateInstances();
- if (global.params.v.templatesListInstances)
+ if (listInstances)
ts.allInstances.push(cast() ti);
}
- // message(ti.loc, "incInstance %p %p", td, ti);
- if (!global.params.v.templates)
- return;
+ // message(ti.loc, "incInstance %p %p", td, ti);
if (!td)
return;
assert(ti);
@@ -8494,8 +8516,6 @@ struct TemplateStats
const TemplateInstance ti)
{
// message(ti.loc, "incUnique %p %p", td, ti);
- if (!global.params.v.templates)
- return;
if (!td)
return;
assert(ti);
@@ -8506,7 +8526,13 @@ struct TemplateStats
}
}
-extern (C++) void printTemplateStats()
+/********************************
+ * Print informational statistics on template instantiations.
+ * Params:
+ * listInstances = list instances of templates
+ * eSink = where the print is sent
+ */
+extern (C++) void printTemplateStats(bool listInstances, ErrorSink eSink)
{
static struct TemplateDeclarationStats
{
@@ -8523,11 +8549,12 @@ extern (C++) void printTemplateStats()
}
}
- if (!global.params.v.templates)
- return;
+ const stats_length = TemplateStats.stats.length;
+ if (!stats_length)
+ return; // nothing to report
Array!(TemplateDeclarationStats) sortedStats;
- sortedStats.reserve(TemplateStats.stats.length);
+ sortedStats.reserve(stats_length);
foreach (td_, ref ts; TemplateStats.stats)
{
sortedStats.push(TemplateDeclarationStats(cast(TemplateDeclaration) td_, ts));
@@ -8537,10 +8564,9 @@ extern (C++) void printTemplateStats()
foreach (const ref ss; sortedStats[])
{
- if (global.params.v.templatesListInstances &&
- ss.ts.allInstances)
+ if (listInstances && ss.ts.allInstances)
{
- message(ss.td.loc,
+ eSink.message(ss.td.loc,
"vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:",
ss.ts.numInstantiations,
ss.ts.uniqueInstantiations,
@@ -8548,14 +8574,14 @@ extern (C++) void printTemplateStats()
foreach (const ti; (*ss.ts.allInstances)[])
{
if (ti.tinst) // if has enclosing instance
- message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars());
+ eSink.message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars());
else
- message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars());
+ eSink.message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars());
}
}
else
{
- message(ss.td.loc,
+ eSink.message(ss.td.loc,
"vtemplate: %u (%u distinct) instantiation(s) of template `%s` found",
ss.ts.numInstantiations,
ss.ts.uniqueInstantiations,
@@ -779,6 +779,17 @@ public:
}
}
+ if (tf && tf.next)
+ {
+ // Ensure return type is declared before a function that returns that is declared.
+ if (auto sty = tf.next.isTypeStruct())
+ ensureDeclared(sty.sym);
+ //else if (auto cty = tf.next.isTypeClass())
+ // includeSymbol(cty.sym); // classes are returned by pointer only need to forward declare
+ //else if (auto ety = tf.next.isTypeEnum())
+ // ensureDeclared(ety.sym);
+ }
+
writeProtection(fd.visibility.kind);
if (tf && tf.linkage == LINK.c)
@@ -34,6 +34,7 @@ import dmd.mtype;
import dmd.printast;
import dmd.rootobject;
import dmd.tokens;
+import dmd.typesem : hasPointers, parameterStorageClass;
import dmd.visitor;
import dmd.arraytypes;
@@ -189,39 +189,6 @@ extern (C++) void expandTuples(Expressions* exps, Identifiers* names = null)
}
}
-/****************************************
- * Expand alias this tuples.
- */
-TupleDeclaration isAliasThisTuple(Expression e)
-{
- if (!e.type)
- return null;
-
- Type t = e.type.toBasetype();
- while (true)
- {
- if (Dsymbol s = t.toDsymbol(null))
- {
- if (auto ad = s.isAggregateDeclaration())
- {
- s = ad.aliasthis ? ad.aliasthis.sym : null;
- if (s && s.isVarDeclaration())
- {
- TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration();
- if (td && td.isexp)
- return td;
- }
- if (Type att = t.aliasthisOf())
- {
- t = att;
- continue;
- }
- }
- }
- return null;
- }
-}
-
/****************************************
* If `s` is a function template, i.e. the only member of a template
* and that member is a function, return that template.
@@ -384,7 +384,6 @@ private Expression reorderSettingAAElem(BinExp exp, Scope* sc)
return Expression.combine(e0, be);
}
-
private Expression checkOpAssignTypes(BinExp binExp, Scope* sc)
{
auto e1 = binExp.e1;
@@ -563,6 +562,39 @@ private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
return e0;
}
+/****************************************
+ * Expand alias this tuples.
+ */
+TupleDeclaration isAliasThisTuple(Expression e)
+{
+ if (!e.type)
+ return null;
+
+ Type t = e.type.toBasetype();
+ while (true)
+ {
+ if (Dsymbol s = t.toDsymbol(null))
+ {
+ if (auto ad = s.isAggregateDeclaration())
+ {
+ s = ad.aliasthis ? ad.aliasthis.sym : null;
+ if (s && s.isVarDeclaration())
+ {
+ TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration();
+ if (td && td.isexp)
+ return td;
+ }
+ if (Type att = t.aliasthisOf())
+ {
+ t = att;
+ continue;
+ }
+ }
+ }
+ return null;
+ }
+}
+
/**************************************
* Runs semantic on ae.arguments. Declares temporary variables
* if '$' was used.
@@ -5115,7 +5147,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
tb = tb.isTypeDArray().next.toBasetype();
}
- if (global.params.betterC || !sc.needsCodegen())
+ if (!global.params.useGC && sc.needsCodegen())
+ {
+ version(IN_GCC)
+ error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-fno-rtti`", exp.toChars());
+ else
+ error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-betterC`", exp.toChars());
+ return setError();
+ }
+
+ if (!sc.needsCodegen())
goto LskipNewArrayLowering;
/* Class types may inherit base classes that have errors.
@@ -6432,8 +6473,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
return setError();
}
- const(char)* failMessage;
- if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
+ void errorHelper(const(char)* failMessage) scope
{
OutBuffer buf;
buf.writeByte('(');
@@ -6447,8 +6487,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
if (failMessage)
errorSupplemental(exp.loc, "%s", failMessage);
- return setError();
}
+
+ if (tf.callMatch(null, exp.argumentList, 0, &errorHelper, sc) == MATCH.nomatch)
+ return setError();
+
// Purity and safety check should run after testing arguments matching
if (exp.f)
{
@@ -6505,8 +6548,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
exp.f = exp.f.toAliasFunc();
TypeFunction tf = cast(TypeFunction)exp.f.type;
- const(char)* failMessage;
- if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
+
+ void errorHelper2(const(char)* failMessage) scope
{
OutBuffer buf;
buf.writeByte('(');
@@ -6527,6 +6570,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
errorSupplemental(exp.loc, "%s", failMessage);
exp.f = null;
}
+
+ if (tf.callMatch(null, exp.argumentList, 0, &errorHelper2, sc) == MATCH.nomatch)
+ exp.f = null;
}
if (!exp.f || exp.f.errors)
return setError();
@@ -7041,7 +7087,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
sc2.tinst = null;
sc2.minst = null;
sc2.flags |= SCOPE.fullinst;
- Type t = e.targ.trySemantic(e.loc, sc2);
+ Type t = dmd.typesem.trySemantic(e.targ, e.loc, sc2);
sc2.pop();
if (!t) // errors, so condition is false
return no();
@@ -7271,7 +7317,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
Objects dedtypes = Objects(e.parameters.length);
dedtypes.zero();
- MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal);
+ MATCH m = deduceType(e.targ, sc, e.tspec, *e.parameters, dedtypes, null, 0, e.tok == TOK.equal);
if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal))
{
@@ -7292,7 +7338,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
TemplateParameter tp = (*e.parameters)[i];
Declaration s = null;
- m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s);
+ m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, dedtypes, &s);
if (m == MATCH.nomatch)
return no();
s.dsymbolSemantic(sc);
@@ -7437,7 +7483,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
result = (cast(BinExp)e).reorderSettingAAElem(sc);
}
- private Expression compileIt(MixinExp exp)
+ private Expression compileIt(MixinExp exp, Scope *sc)
{
OutBuffer buf;
if (expressionsToString(buf, sc, exp.exps))
@@ -7478,7 +7524,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
printf("MixinExp::semantic('%s')\n", exp.toChars());
}
- auto e = compileIt(exp);
+ // The expression is not treated as part of a default argument,
+ // because it is evaluated at compile time.
+ Scope* sc2 = sc.push();
+ sc2.inDefaultArg = false;
+
+ auto e = compileIt(exp, sc2);
+ sc2.pop();
if (!e)
return setError();
result = e.expressionSemantic(sc);
@@ -7575,7 +7627,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
auto fileName = FileName(resolvedNamez);
- if (auto fmResult = global.fileManager.lookup(fileName))
+ if (auto fmResult = global.fileManager.getFileContents(fileName))
{
se = new StringExp(e.loc, fmResult);
}
@@ -7721,7 +7773,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
// if the assert condition is a mixin expression, try to compile it
if (auto ce = exp.e1.isMixinExp())
{
- if (auto e1 = compileIt(ce))
+ if (auto e1 = compileIt(ce, sc))
exp.e1 = e1;
}
@@ -13924,45 +13976,34 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
{
//printf("FileInitExp::semantic()\n");
e.type = Type.tstring;
- result = e;
+ result = e.resolveLoc(e.loc, sc);
}
override void visit(LineInitExp e)
{
e.type = Type.tint32;
- result = e;
+ result = e.resolveLoc(e.loc, sc);
}
override void visit(ModuleInitExp e)
{
//printf("ModuleInitExp::semantic()\n");
e.type = Type.tstring;
- result = e;
+ result = e.resolveLoc(e.loc, sc);
}
override void visit(FuncInitExp e)
{
//printf("FuncInitExp::semantic()\n");
e.type = Type.tstring;
- if (sc.func)
- {
- result = e.resolveLoc(Loc.initial, sc);
- return;
- }
- result = e;
+ result = e.resolveLoc(e.loc, sc);
}
override void visit(PrettyFuncInitExp e)
{
//printf("PrettyFuncInitExp::semantic()\n");
e.type = Type.tstring;
- if (sc.func)
- {
- result = e.resolveLoc(Loc.initial, sc);
- return;
- }
-
- result = e;
+ result = e.resolveLoc(e.loc, sc);
}
}
@@ -15047,10 +15088,21 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
*/
Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
{
+ // Don't replace the special keywords, while we are inside a default
+ // argument. They are replaced later when copied to the call site.
+ if (sc.inDefaultArg)
+ return exp;
+
exp.loc = loc;
Expression visit(Expression exp)
{
+ if (auto binExp = exp.isBinExp())
+ {
+ binExp.e1 = binExp.e1.resolveLoc(loc, sc);
+ binExp.e2 = binExp.e2.resolveLoc(loc, sc);
+ return binExp;
+ }
if (auto unaExp = exp.isUnaExp())
{
unaExp.e1 = unaExp.e1.resolveLoc(loc, sc);
@@ -15059,10 +15111,121 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
return exp;
}
+ Expression visitCond(CondExp exp)
+ {
+ exp.e1 = exp.e1.resolveLoc(loc, sc);
+ exp.e2 = exp.e2.resolveLoc(loc, sc);
+ exp.econd = exp.econd.resolveLoc(loc, sc);
+ return exp;
+ }
+
Expression visitCat(CatExp exp)
{
exp.e1 = exp.e1.resolveLoc(loc, sc);
exp.e2 = exp.e2.resolveLoc(loc, sc);
+ if (exp.lowering)
+ exp.lowering = exp.lowering.resolveLoc(loc, sc);
+ return exp;
+ }
+
+ Expression visitStructLiteral(StructLiteralExp exp)
+ {
+ foreach (ref element; *exp.elements)
+ {
+ if (element)
+ element = element.resolveLoc(loc, sc);
+ }
+
+ return exp;
+ }
+
+ Expression visitNew(NewExp exp)
+ {
+ if (exp.thisexp)
+ exp.thisexp = exp.thisexp.resolveLoc(loc, sc);
+ if (exp.argprefix)
+ exp.argprefix = exp.argprefix.resolveLoc(loc, sc);
+ if (exp.lowering)
+ exp.lowering = exp.lowering.resolveLoc(loc, sc);
+
+ foreach (ref element; *exp.arguments)
+ {
+ if (element)
+ element = element.resolveLoc(loc, sc);
+ }
+
+ return exp;
+ }
+
+ Expression visitCall(CallExp exp)
+ {
+ foreach (ref element; *exp.arguments)
+ {
+ if (element)
+ element = element.resolveLoc(loc, sc);
+ }
+
+ return exp;
+ }
+
+ Expression visitArray(ArrayExp exp)
+ {
+ exp.e1 = exp.e1.resolveLoc(loc, sc);
+
+ foreach (ref element; *exp.arguments)
+ {
+ if (element)
+ element = element.resolveLoc(loc, sc);
+ }
+
+ return exp;
+ }
+
+ Expression visitSlice(SliceExp exp)
+ {
+ exp.e1 = exp.e1.resolveLoc(loc, sc);
+ exp.lwr = exp.lwr.resolveLoc(loc, sc);
+ exp.upr = exp.upr.resolveLoc(loc, sc);
+
+ return exp;
+ }
+
+ Expression visitInterval(IntervalExp exp)
+ {
+ exp.lwr = exp.lwr.resolveLoc(loc, sc);
+ exp.upr = exp.upr.resolveLoc(loc, sc);
+
+ return exp;
+ }
+
+ Expression visitArrayLiteral(ArrayLiteralExp exp)
+ {
+ if (exp.basis)
+ exp.basis = exp.basis.resolveLoc(loc, sc);
+
+ foreach (ref element; *exp.elements)
+ {
+ if (element)
+ element = element.resolveLoc(loc, sc);
+ }
+
+ return exp;
+ }
+
+ Expression visitAssocArrayLiteral(AssocArrayLiteralExp exp)
+ {
+ foreach (ref element; *exp.keys)
+ {
+ if (element)
+ element = element.resolveLoc(loc, sc);
+ }
+
+ foreach (ref element; *exp.values)
+ {
+ if (element)
+ element = element.resolveLoc(loc, sc);
+ }
+
return exp;
}
@@ -15079,20 +15242,20 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
return e.expressionSemantic(sc);
}
- Expression visitLineInit(LineInitExp _)
+ Expression visitLineInit(LineInitExp exp)
{
Expression e = new IntegerExp(loc, loc.linnum, Type.tint32);
return e.expressionSemantic(sc);
}
- Expression visitModuleInit(ModuleInitExp _)
+ Expression visitModuleInit(ModuleInitExp exp)
{
const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString();
Expression e = new StringExp(loc, s);
return e.expressionSemantic(sc);
}
- Expression visitFuncInit(FuncInitExp _)
+ Expression visitFuncInit(FuncInitExp exp)
{
const(char)* s;
if (sc.callsc && sc.callsc.func)
@@ -15105,7 +15268,7 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
return e.expressionSemantic(sc);
}
- Expression visitPrettyFunc(PrettyFuncInitExp _)
+ Expression visitPrettyFunc(PrettyFuncInitExp exp)
{
FuncDeclaration fd = (sc.callsc && sc.callsc.func)
? sc.callsc.func
@@ -15133,7 +15296,16 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
switch(exp.op)
{
default: return visit(exp);
+ case EXP.structLiteral: return visitStructLiteral(exp.isStructLiteralExp());
+ case EXP.new_: return visitNew(exp.isNewExp());
case EXP.concatenate: return visitCat(exp.isCatExp());
+ case EXP.call: return visitCall(exp.isCallExp());
+ case EXP.question: return visitCond(exp.isCondExp());
+ case EXP.array: return visitArray(exp.isArrayExp());
+ case EXP.slice: return visitSlice(exp.isSliceExp());
+ case EXP.interval: return visitInterval(exp.isIntervalExp());
+ case EXP.arrayLiteral: return visitArrayLiteral(exp.isArrayLiteralExp());
+ case EXP.assocArrayLiteral: return visitAssocArrayLiteral(exp.isAssocArrayLiteralExp());
case EXP.file:
case EXP.fileFullPath: return visitFileInit(exp.isFileInitExp());
case EXP.line: return visitLineInit(exp.isLineInitExp);
@@ -16193,7 +16365,10 @@ Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
em.checkDisabled(loc, sc);
if (em.depdecl && !em.depdecl._scope)
+ {
em.depdecl._scope = sc;
+ em.depdecl._scope.setNoFree();
+ }
em.checkDeprecated(loc, sc);
if (em.errors)
@@ -72,7 +72,7 @@ private struct PathStack
final class FileManager
{
- private StringTable!(const(ubyte)[]) files;
+ private StringTable!(const(ubyte)[]) files; // contents of files indexed by file name
private StringTable!(bool) packageStatus;
// check if the package path of the given path exists. The input path is
@@ -247,35 +247,37 @@ nothrow:
}
/**
- * Looks up the given filename from the internal file buffer table.
- * If the file does not already exist within the table, it will be read from the filesystem.
- * If it has been read before,
- *
- * Returns: the loaded source file if it was found in memory,
- * otherwise `null`
+ * Retrieve the cached contents of the file given by `filename`.
+ * If the file has not been read before, read it and add the contents
+ * to the file cache.
+ * Params:
+ * filename = the name of the file
+ * Returns:
+ * the contents of the file, or `null` if it could not be read or was empty
*/
- const(ubyte)[] lookup(FileName filename)
+ const(ubyte)[] getFileContents(FileName filename)
{
const name = filename.toString;
- if (auto val = files.lookup(name))
- return val.value;
+ if (auto val = files.lookup(name)) // if `name` is cached
+ return val.value; // return its contents
- if (name == "__stdin.d")
+ if (name == "__stdin.d") // special name for reading from stdin
{
- auto buffer = readFromStdin().extractSlice();
+ const ubyte[] buffer = readFromStdin().extractSlice();
if (this.files.insert(name, buffer) is null)
+ // this.files already contains the name
assert(0, "stdin: Insert after lookup failure should never return `null`");
return buffer;
}
- if (FileName.exists(name) != 1)
+ if (FileName.exists(name) != 1) // if not an ordinary file
return null;
auto readResult = File.read(name);
if (!readResult.success)
return null;
- auto fb = readResult.extractSlice();
+ const ubyte[] fb = readResult.extractSlice();
if (files.insert(name, fb) is null)
assert(0, "Insert after lookup failure should never return `null`");
@@ -1195,7 +1195,7 @@ extern (C++) class FuncDeclaration : Declaration
*
* Returns: the `LabelDsymbol` for `ident`
*/
- final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc = Loc.initial)
+ final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc)
{
Dsymbol s;
if (!labtab)
@@ -1471,6 +1471,9 @@ extern (C++) class FuncDeclaration : Declaration
final PURE isPure()
{
//printf("FuncDeclaration::isPure() '%s'\n", toChars());
+
+ import dmd.typesem : purityLevel;
+
TypeFunction tf = type.toTypeFunction();
if (purityInprocess)
setImpure();
@@ -1782,6 +1785,7 @@ extern (C++) class FuncDeclaration : Declaration
case Tstruct:
/* Drill down and check the struct's fields
*/
+ import dmd.typesem : toDsymbol;
auto sym = t.toDsymbol(null).isStructDeclaration();
const tName = t.toChars.toDString;
const entry = parentTypes.insert(tName, t);
@@ -1863,6 +1867,7 @@ extern (C++) class FuncDeclaration : Declaration
case Tstruct:
/* Drill down and check the struct's fields
*/
+ import dmd.typesem : toDsymbol;
auto sym = tp.toDsymbol(null).isStructDeclaration();
foreach (v; sym.fields)
{
@@ -2727,6 +2732,7 @@ extern (C++) class FuncDeclaration : Declaration
{
Type t1 = fdv.type.nextOf().toBasetype();
Type t2 = this.type.nextOf().toBasetype();
+ import dmd.typesem : isBaseOf;
if (t1.isBaseOf(t2, null))
{
/* Making temporary reference variable is necessary
@@ -3294,7 +3300,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null");
}
- if (tiargs && arrayObjectIsError(tiargs))
+ if (tiargs && arrayObjectIsError(*tiargs))
return null;
if (fargs !is null)
foreach (arg; *fargs)
@@ -3441,17 +3447,20 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
return null;
}
- const(char)* failMessage;
- functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage);
- if (failMessage)
+ bool calledHelper;
+ void errorHelper(const(char)* failMessage) scope
{
.error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
tf.modToChars(), fargsBuf.peekChars());
errorSupplemental(loc, failMessage);
- return null;
+ calledHelper = true;
}
+ functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper);
+ if (calledHelper)
+ return null;
+
if (fd.isCtorDeclaration())
.error(loc, "%s%s `%s` cannot construct a %sobject",
funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars());
@@ -3505,10 +3514,13 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
}
}
}
- const(char)* failMessage;
- functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage);
- if (failMessage)
+
+ void errorHelper2(const(char)* failMessage) scope
+ {
errorSupplemental(loc, failMessage);
+ }
+
+ functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper2);
}
return null;
}
@@ -3624,6 +3636,7 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
*/
Type getIndirection(Type t)
{
+ import dmd.typesem : hasPointers;
t = t.baseElemOf();
if (t.ty == Tarray || t.ty == Tpointer)
return t.nextOf().toBasetype();
@@ -3670,6 +3683,7 @@ private bool traverseIndirections(Type ta, Type tb)
static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
{
+ import dmd.typesem : hasPointers;
//printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
ta = ta.baseElemOf();
tb = tb.baseElemOf();
@@ -3706,6 +3720,7 @@ private bool traverseIndirections(Type ta, Type tb)
else
*found = true;
+ import dmd.typesem : toDsymbol;
AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
foreach (v; sym.fields)
{
@@ -15,7 +15,9 @@ import core.stdc.stdio;
import core.stdc.stdint;
import core.stdc.string;
+import dmd.astenums;
import dmd.root.array;
+import dmd.root.file;
import dmd.root.filename;
import dmd.common.outbuffer;
import dmd.errorsink;
@@ -308,7 +310,7 @@ extern (C++) struct Global
ErrorSink errorSink; /// where the error messages go
ErrorSink errorSinkNull; /// where the error messages are ignored
- extern (C++) FileName function(FileName, ref const Loc, out bool, OutBuffer*) preprocess;
+ extern (C++) DArray!ubyte function(FileName, ref const Loc, ref OutBuffer) preprocess;
nothrow:
@@ -307,7 +307,7 @@ struct Global
ErrorSink* errorSink; // where the error messages go
ErrorSink* errorSinkNull; // where the error messages disappear
- FileName (*preprocess)(FileName, const Loc&, bool&, OutBuffer&);
+ DArray<unsigned char> (*preprocess)(FileName, const Loc&, OutBuffer&);
/* Start gagging. Return the current number of gagged errors
*/
@@ -21,16 +21,11 @@ import dmd.aggregate;
import dmd.arraytypes;
import dmd.astenums;
import dmd.ast_node;
-import dmd.gluelayer;
import dmd.dclass;
-import dmd.dcast;
import dmd.declaration;
import dmd.denum;
-import dmd.dmangle;
-import dmd.dscope;
import dmd.dstruct;
import dmd.dsymbol;
-import dmd.dsymbolsem;
import dmd.dtemplate;
import dmd.errors;
import dmd.expression;
@@ -39,9 +34,7 @@ import dmd.globals;
import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
-import dmd.init;
import dmd.location;
-import dmd.opover;
import dmd.root.ctfloat;
import dmd.common.outbuffer;
import dmd.root.rmem;
@@ -256,57 +249,6 @@ bool isSomeChar(TY ty) pure nothrow @nogc @safe
return ty == Tchar || ty == Twchar || ty == Tdchar;
}
-/************************************
- * Determine mutability of indirections in (ref) t.
- *
- * Returns: When the type has any mutable indirections, returns 0.
- * When all indirections are immutable, returns 2.
- * Otherwise, when the type has const/inout indirections, returns 1.
- *
- * Params:
- * isref = if true, check `ref t`; otherwise, check just `t`
- * t = the type that is being checked
- */
-int mutabilityOfType(bool isref, Type t)
-{
- if (isref)
- {
- if (t.mod & MODFlags.immutable_)
- return 2;
- if (t.mod & (MODFlags.const_ | MODFlags.wild))
- return 1;
- return 0;
- }
-
- t = t.baseElemOf();
-
- if (!t.hasPointers() || t.mod & MODFlags.immutable_)
- return 2;
-
- /* Accept immutable(T)[] and immutable(T)* as being strongly pure
- */
- if (t.ty == Tarray || t.ty == Tpointer)
- {
- Type tn = t.nextOf().toBasetype();
- if (tn.mod & MODFlags.immutable_)
- return 2;
- if (tn.mod & (MODFlags.const_ | MODFlags.wild))
- return 1;
- }
-
- /* The rest of this is too strict; fix later.
- * For example, the only pointer members of a struct may be immutable,
- * which would maintain strong purity.
- * (Just like for dynamic arrays and pointers above.)
- */
- if (t.mod & (MODFlags.const_ | MODFlags.wild))
- return 1;
-
- /* Should catch delegates and function pointers, and fold in their purity
- */
- return 0;
-}
-
/****************
* dotExp() bit flags
*/
@@ -363,7 +305,7 @@ extern (C++) abstract class Type : ASTNode
TypeInfoDeclaration vtinfo; // TypeInfo object for this Type
- type* ctype; // for back end
+ void* ctype; // for back end
extern (C++) __gshared Type tvoid;
extern (C++) __gshared Type tint8;
@@ -659,31 +601,6 @@ extern (C++) abstract class Type : ASTNode
return cast(uint)size(Loc.initial);
}
- final Type trySemantic(const ref Loc loc, Scope* sc)
- {
- //printf("+trySemantic(%s) %d\n", toChars(), global.errors);
-
- // Needed to display any deprecations that were gagged
- auto tcopy = this.syntaxCopy();
-
- const errors = global.startGagging();
- Type t = typeSemantic(this, loc, sc);
- if (global.endGagging(errors) || t.ty == Terror) // if any errors happened
- {
- t = null;
- }
- else
- {
- // If `typeSemantic` succeeded, there may have been deprecations that
- // were gagged due the `startGagging` above. Run again to display
- // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107
- if (global.gaggedWarnings > 0)
- typeSemantic(tcopy, loc, sc);
- }
- //printf("-trySemantic(%s) %d\n", toChars(), global.errors);
- return t;
- }
-
/*************************************
* This version does a merge even if the deco is already computed.
* Necessary for types that have a deco, but are not merged.
@@ -1907,11 +1824,6 @@ extern (C++) abstract class Type : ASTNode
return t;
}
- Dsymbol toDsymbol(Scope* sc)
- {
- return null;
- }
-
/*******************************
* If this is a shell around another type,
* get that other type.
@@ -1925,11 +1837,6 @@ extern (C++) abstract class Type : ASTNode
return ((te = isTypeEnum()) !is null) ? te.toBasetype2() : this;
}
- bool isBaseOf(Type t, int* poffset)
- {
- return 0; // assume not
- }
-
/********************************
* Determine if 'this' can be implicitly converted
* to type 'to'.
@@ -2155,32 +2062,6 @@ extern (C++) abstract class Type : ASTNode
return false; // assume not
}
- final Identifier getTypeInfoIdent()
- {
- // _init_10TypeInfo_%s
- OutBuffer buf;
- buf.reserve(32);
- mangleToBuffer(this, buf);
-
- const slice = buf[];
-
- // Allocate buffer on stack, fail over to using malloc()
- char[128] namebuf;
- const namelen = 19 + size_t.sizeof * 3 + slice.length + 1;
- auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen));
-
- const length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ",
- cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr);
- //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name);
- assert(0 < length && length < namelen); // don't overflow the buffer
-
- auto id = Identifier.idPool(name[0 .. length]);
-
- if (name != namebuf.ptr)
- free(name);
- return id;
- }
-
/***************************************
* Return !=0 if the type or any of its subtypes is wild.
*/
@@ -2189,16 +2070,6 @@ extern (C++) abstract class Type : ASTNode
return mod & MODFlags.wild;
}
- /***************************************
- * Return !=0 if type has pointers that need to
- * be scanned by the GC during a collection cycle.
- */
- bool hasPointers()
- {
- //printf("Type::hasPointers() %s, %d\n", toChars(), ty);
- return false;
- }
-
/*************************************
* Detect if type has pointer fields that are initialized to void.
* Local stack variables with such void fields can remain uninitialized,
@@ -2340,76 +2211,6 @@ extern (C++) abstract class Type : ASTNode
return false;
}
- /*************************************
- * https://issues.dlang.org/show_bug.cgi?id=14488
- * Check if the inner most base type is complex or imaginary.
- * Should only give alerts when set to emit transitional messages.
- * Params:
- * loc = The source location.
- * sc = scope of the type
- */
- extern (D) final bool checkComplexTransition(const ref Loc loc, Scope* sc)
- {
- if (sc.isDeprecated())
- return false;
- // Don't complain if we're inside a template constraint
- // https://issues.dlang.org/show_bug.cgi?id=21831
- if (sc.flags & SCOPE.constraint)
- return false;
-
- Type t = baseElemOf();
- while (t.ty == Tpointer || t.ty == Tarray)
- t = t.nextOf().baseElemOf();
-
- // Basetype is an opaque enum, nothing to check.
- if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype)
- return false;
-
- if (t.isimaginary() || t.iscomplex())
- {
- if (sc.flags & SCOPE.Cfile)
- return true; // complex/imaginary not deprecated in C code
- Type rt;
- switch (t.ty)
- {
- case Tcomplex32:
- case Timaginary32:
- rt = Type.tfloat32;
- break;
-
- case Tcomplex64:
- case Timaginary64:
- rt = Type.tfloat64;
- break;
-
- case Tcomplex80:
- case Timaginary80:
- rt = Type.tfloat80;
- break;
-
- default:
- assert(0);
- }
- // @@@DEPRECATED_2.117@@@
- // Deprecated in 2.097 - Can be made an error from 2.117.
- // The deprecation period is longer than usual as `cfloat`,
- // `cdouble`, and `creal` were quite widely used.
- if (t.iscomplex())
- {
- deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead",
- toChars(), rt.toChars());
- return true;
- }
- else
- {
- deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead",
- toChars(), rt.toChars());
- return true;
- }
- }
- return false;
- }
-
// For eliminating dynamic_cast
TypeBasic isTypeBasic()
{
@@ -3531,24 +3332,6 @@ extern (C++) final class TypeSArray : TypeArray
return ae;
}
- override bool hasPointers()
- {
- /* Don't want to do this, because:
- * struct S { T* array[0]; }
- * may be a variable length struct.
- */
- //if (dim.toInteger() == 0)
- // return false;
-
- if (next.ty == Tvoid)
- {
- // Arrays of void contain arbitrary data, which may include pointers
- return true;
- }
- else
- return next.hasPointers();
- }
-
override bool hasSystemFields()
{
return next.hasSystemFields();
@@ -3673,11 +3456,6 @@ extern (C++) final class TypeDArray : TypeArray
return Type.implicitConvTo(to);
}
- override bool hasPointers()
- {
- return true;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -3734,11 +3512,6 @@ extern (C++) final class TypeAArray : TypeArray
return true;
}
- override bool hasPointers()
- {
- return true;
- }
-
override MATCH implicitConvTo(Type to)
{
//printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
@@ -3877,11 +3650,6 @@ extern (C++) final class TypePointer : TypeNext
return true;
}
- override bool hasPointers()
- {
- return true;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -4058,39 +3826,6 @@ extern (C++) final class TypeFunction : TypeNext
return t;
}
- /********************************************
- * Set 'purity' field of 'this'.
- * Do this lazily, as the parameter types might be forward referenced.
- */
- void purityLevel()
- {
- TypeFunction tf = this;
- if (tf.purity != PURE.fwdref)
- return;
-
- purity = PURE.const_; // assume strong until something weakens it
-
- /* Evaluate what kind of purity based on the modifiers for the parameters
- */
- foreach (i, fparam; tf.parameterList)
- {
- Type t = fparam.type;
- if (!t)
- continue;
-
- if (fparam.storageClass & (STC.lazy_ | STC.out_))
- {
- purity = PURE.weak;
- break;
- }
- const pref = (fparam.storageClass & STC.ref_) != 0;
- if (mutabilityOfType(pref, t) == 0)
- purity = PURE.weak;
- }
-
- tf.purity = purity;
- }
-
/********************************************
* Return true if there are lazy parameters.
*/
@@ -4115,122 +3850,6 @@ extern (C++) final class TypeFunction : TypeNext
return linkage == LINK.d && parameterList.varargs == VarArg.variadic;
}
- /************************************
- * Take the specified storage class for p,
- * and use the function signature to infer whether
- * STC.scope_ and STC.return_ should be OR'd in.
- * (This will not affect the name mangling.)
- * Params:
- * tthis = type of `this` parameter, null if none
- * p = parameter to this function
- * outerVars = context variables p could escape into, if any
- * indirect = is this for an indirect or virtual function call?
- * Returns:
- * storage class with STC.scope_ or STC.return_ OR'd in
- */
- StorageClass parameterStorageClass(Type tthis, Parameter p, VarDeclarations* outerVars = null,
- bool indirect = false)
- {
- //printf("parameterStorageClass(p: %s)\n", p.toChars());
- auto stc = p.storageClass;
-
- // When the preview switch is enable, `in` parameters are `scope`
- if (stc & STC.constscoperef)
- return stc | STC.scope_;
-
- if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || purity == PURE.impure)
- return stc;
-
- /* If haven't inferred the return type yet, can't infer storage classes
- */
- if (!nextOf() || !isnothrow())
- return stc;
-
- purityLevel();
-
- static bool mayHavePointers(Type t)
- {
- if (auto ts = t.isTypeStruct())
- {
- auto sym = ts.sym;
- if (sym.members && !sym.determineFields() && sym.type != Type.terror)
- // struct is forward referenced, so "may have" pointers
- return true;
- }
- return t.hasPointers();
- }
-
- // See if p can escape via any of the other parameters
- if (purity == PURE.weak)
- {
- /*
- * Indirect calls may escape p through a nested context
- * See:
- * https://issues.dlang.org/show_bug.cgi?id=24212
- * https://issues.dlang.org/show_bug.cgi?id=24213
- */
- if (indirect)
- return stc;
-
- // Check escaping through parameters
- foreach (i, fparam; parameterList)
- {
- Type t = fparam.type;
- if (!t)
- continue;
- t = t.baseElemOf(); // punch thru static arrays
- if (t.isMutable() && t.hasPointers())
- {
- if (fparam.isReference() && fparam != p)
- return stc;
-
- if (t.ty == Tdelegate)
- return stc; // could escape thru delegate
-
- if (t.ty == Tclass)
- return stc;
-
- /* if t is a pointer to mutable pointer
- */
- if (auto tn = t.nextOf())
- {
- if (tn.isMutable() && mayHavePointers(tn))
- return stc; // escape through pointers
- }
- }
- }
-
- // Check escaping through `this`
- if (tthis && tthis.isMutable())
- {
- foreach (VarDeclaration v; isAggregate(tthis).fields)
- {
- if (v.hasPointers())
- return stc;
- }
- }
-
- // Check escaping through nested context
- if (outerVars && this.isMutable())
- {
- foreach (VarDeclaration v; *outerVars)
- {
- if (v.hasPointers())
- return stc;
- }
- }
- }
-
- // Check escaping through return value
- Type tret = nextOf().toBasetype();
- if (isref || tret.hasPointers())
- {
- return stc | STC.scope_ | STC.return_ | STC.returnScope;
- }
- else
- return stc | STC.scope_;
- }
-
override Type addStorageClass(StorageClass stc)
{
//printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0);
@@ -4631,11 +4250,6 @@ extern (C++) final class TypeDelegate : TypeNext
return true;
}
- override bool hasPointers()
- {
- return true;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -4676,20 +4290,6 @@ extern (C++) final class TypeTraits : Type
return tt;
}
- override Dsymbol toDsymbol(Scope* sc)
- {
- Type t;
- Expression e;
- Dsymbol s;
- resolve(this, loc, sc, e, t, s);
- if (t && t.ty != Terror)
- s = t.toDsymbol(sc);
- else if (e)
- s = getDsymbol(e);
-
- return s;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -4729,20 +4329,6 @@ extern (C++) final class TypeMixin : Type
return new TypeMixin(loc, Expression.arraySyntaxCopy(exps));
}
- override Dsymbol toDsymbol(Scope* sc)
- {
- Type t;
- Expression e;
- Dsymbol s;
- resolve(this, loc, sc, e, t, s);
- if (t)
- s = t.toDsymbol(sc);
- else if (e)
- s = getDsymbol(e);
-
- return s;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -4867,28 +4453,6 @@ extern (C++) final class TypeIdentifier : TypeQualified
return t;
}
- /*****************************************
- * See if type resolves to a symbol, if so,
- * return that symbol.
- */
- override Dsymbol toDsymbol(Scope* sc)
- {
- //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
- if (!sc)
- return null;
-
- Type t;
- Expression e;
- Dsymbol s;
- resolve(this, loc, sc, e, t, s);
- if (t && t.ty != Tident)
- s = t.toDsymbol(sc);
- if (e)
- s = getDsymbol(e);
-
- return s;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -4922,18 +4486,6 @@ extern (C++) final class TypeInstance : TypeQualified
return t;
}
- override Dsymbol toDsymbol(Scope* sc)
- {
- Type t;
- Expression e;
- Dsymbol s;
- //printf("TypeInstance::semantic(%s)\n", toChars());
- resolve(this, loc, sc, e, t, s);
- if (t && t.ty != Tinstance)
- s = t.toDsymbol(sc);
- return s;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -4967,16 +4519,6 @@ extern (C++) final class TypeTypeof : TypeQualified
return t;
}
- override Dsymbol toDsymbol(Scope* sc)
- {
- //printf("TypeTypeof::toDsymbol('%s')\n", toChars());
- Expression e;
- Type t;
- Dsymbol s;
- resolve(this, loc, sc, e, t, s);
- return s;
- }
-
override uinteger_t size(const ref Loc loc)
{
if (exp.type)
@@ -5013,15 +4555,6 @@ extern (C++) final class TypeReturn : TypeQualified
return t;
}
- override Dsymbol toDsymbol(Scope* sc)
- {
- Expression e;
- Type t;
- Dsymbol s;
- resolve(this, loc, sc, e, t, s);
- return s;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -5068,11 +4601,6 @@ extern (C++) final class TypeStruct : Type
return this;
}
- override Dsymbol toDsymbol(Scope* sc)
- {
- return sym;
- }
-
override structalign_t alignment()
{
if (sym.alignment.isUnknown())
@@ -5214,15 +4742,6 @@ extern (C++) final class TypeStruct : Type
return false;
}
- override bool hasPointers()
- {
- if (sym.members && !sym.determineFields() && sym.type != Type.terror)
- error(sym.loc, "no size because of forward references");
-
- sym.determineTypeProperties();
- return sym.hasPointerField;
- }
-
override bool hasVoidInitPointers()
{
sym.size(Loc.initial); // give error for forward references
@@ -5393,9 +4912,9 @@ extern (C++) final class TypeEnum : Type
return sym.getMemtype(loc).size(loc);
}
- Type memType(const ref Loc loc = Loc.initial)
+ Type memType()
{
- return sym.getMemtype(loc);
+ return sym.getMemtype(Loc.initial);
}
override uint alignsize()
@@ -5406,11 +4925,6 @@ extern (C++) final class TypeEnum : Type
return t.alignsize();
}
- override Dsymbol toDsymbol(Scope* sc)
- {
- return sym;
- }
-
override bool isintegral()
{
return memType().isintegral();
@@ -5511,11 +5025,6 @@ extern (C++) final class TypeEnum : Type
return sym.getDefaultValue(loc).toBool().hasValue(false);
}
- override bool hasPointers()
- {
- return memType().hasPointers();
- }
-
override bool hasVoidInitPointers()
{
return memType().hasVoidInitPointers();
@@ -5571,44 +5080,14 @@ extern (C++) final class TypeClass : Type
return this;
}
- override Dsymbol toDsymbol(Scope* sc)
- {
- return sym;
- }
-
override inout(ClassDeclaration) isClassHandle() inout
{
return sym;
}
- override bool isBaseOf(Type t, int* poffset)
- {
- if (t && t.ty == Tclass)
- {
- ClassDeclaration cd = (cast(TypeClass)t).sym;
- if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
- cd.dsymbolSemantic(null);
- if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete())
- sym.dsymbolSemantic(null);
-
- if (sym.isBaseOf(cd, poffset))
- return true;
- }
- return false;
- }
-
extern (D) MATCH implicitConvToWithoutAliasThis(Type to)
{
- // Run semantic before checking whether class is convertible
ClassDeclaration cdto = to.isClassHandle();
- if (cdto)
- {
- //printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to.toChars(), toChars(), cdto.isBaseInfoComplete(), sym.isBaseInfoComplete());
- if (cdto.semanticRun < PASS.semanticdone && !cdto.isBaseInfoComplete())
- cdto.dsymbolSemantic(null);
- if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete())
- sym.dsymbolSemantic(null);
- }
MATCH m = constConv(to);
if (m > MATCH.nomatch)
return m;
@@ -5706,11 +5185,6 @@ extern (C++) final class TypeClass : Type
return true;
}
- override bool hasPointers()
- {
- return true;
- }
-
override void accept(Visitor v)
{
v.visit(this);
@@ -5952,14 +5426,6 @@ extern (C++) final class TypeNull : Type
return MATCH.nomatch;
}
- override bool hasPointers()
- {
- /* Although null isn't dereferencable, treat it as a pointer type for
- * attribute inference, generic code, etc.
- */
- return true;
- }
-
override bool isBoolean()
{
return true;
@@ -6633,39 +6099,6 @@ bool isIndexableNonAggregate(Type t)
t.ty == Ttuple || t.ty == Tvector);
}
-/***************************************************
- * Determine if type t is copyable.
- * Params:
- * t = type to check
- * Returns:
- * true if we can copy it
- */
-bool isCopyable(Type t)
-{
- //printf("isCopyable() %s\n", t.toChars());
- if (auto ts = t.isTypeStruct())
- {
- if (ts.sym.postblit &&
- ts.sym.postblit.storage_class & STC.disable)
- return false;
- if (ts.sym.hasCopyCtor)
- {
- // check if there is a matching overload of the copy constructor and whether it is disabled or not
- // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575
- Dsymbol ctor = search_function(ts.sym, Id.ctor);
- assert(ctor);
- scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue
- el.type = cast() ts;
- Expressions* args = new Expressions();
- args.push(el);
- FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet);
- if (!f || f.storage_class & STC.disable)
- return false;
- }
- }
- return true;
-}
-
/***************************************
* Computes how a parameter may be returned.
* Shrinking the representation is necessary because StorageClass is so wide
@@ -233,7 +233,6 @@ public:
uinteger_t size();
virtual uinteger_t size(const Loc &loc);
virtual unsigned alignsize();
- Type *trySemantic(const Loc &loc, Scope *sc);
Type *merge2();
void modToBuffer(OutBuffer& buf) const;
char *modToChars() const;
@@ -287,9 +286,7 @@ public:
virtual Type *makeSharedWild();
virtual Type *makeSharedWildConst();
virtual Type *makeMutable();
- virtual Dsymbol *toDsymbol(Scope *sc);
Type *toBasetype();
- virtual bool isBaseOf(Type *t, int *poffset);
virtual MATCH implicitConvTo(Type *to);
virtual MATCH constConv(Type *to);
virtual unsigned char deduceWild(Type *t, bool isRef);
@@ -302,9 +299,7 @@ public:
virtual structalign_t alignment();
virtual Expression *defaultInitLiteral(const Loc &loc);
virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0
- Identifier *getTypeInfoIdent();
virtual int hasWild() const;
- virtual bool hasPointers();
virtual bool hasVoidInitPointers();
virtual bool hasSystemFields();
virtual bool hasInvariant();
@@ -451,7 +446,6 @@ public:
MATCH constConv(Type *to) override;
MATCH implicitConvTo(Type *to) override;
Expression *defaultInitLiteral(const Loc &loc) override;
- bool hasPointers() override;
bool hasSystemFields() override;
bool hasVoidInitPointers() override;
bool hasInvariant() override;
@@ -474,7 +468,6 @@ public:
bool isZeroInit(const Loc &loc) override;
bool isBoolean() override;
MATCH implicitConvTo(Type *to) override;
- bool hasPointers() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -491,7 +484,6 @@ public:
uinteger_t size(const Loc &loc) override;
bool isZeroInit(const Loc &loc) override;
bool isBoolean() override;
- bool hasPointers() override;
MATCH implicitConvTo(Type *to) override;
MATCH constConv(Type *to) override;
@@ -509,7 +501,6 @@ public:
MATCH constConv(Type *to) override;
bool isscalar() override;
bool isZeroInit(const Loc &loc) override;
- bool hasPointers() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -605,10 +596,8 @@ public:
static TypeFunction *create(Parameters *parameters, Type *treturn, VarArg varargs, LINK linkage, StorageClass stc = 0);
const char *kind() override;
TypeFunction *syntaxCopy() override;
- void purityLevel();
bool hasLazyParameters();
bool isDstyleVariadic() const;
- StorageClass parameterStorageClass(Type* tthis, Parameter *p, VarDeclarations* outerVars = nullptr, bool indirect = false);
Type *addStorageClass(StorageClass stc) override;
Type *substWildTo(unsigned mod) override;
@@ -659,7 +648,6 @@ public:
MATCH implicitConvTo(Type *to) override;
bool isZeroInit(const Loc &loc) override;
bool isBoolean() override;
- bool hasPointers() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -675,7 +663,6 @@ class TypeTraits final : public Type
const char *kind() override;
TypeTraits *syntaxCopy() override;
uinteger_t size(const Loc &loc) override;
- Dsymbol *toDsymbol(Scope *sc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -687,7 +674,6 @@ class TypeMixin final : public Type
const char *kind() override;
TypeMixin *syntaxCopy() override;
- Dsymbol *toDsymbol(Scope *sc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -713,7 +699,6 @@ public:
static TypeIdentifier *create(const Loc &loc, Identifier *ident);
const char *kind() override;
TypeIdentifier *syntaxCopy() override;
- Dsymbol *toDsymbol(Scope *sc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -726,7 +711,6 @@ public:
const char *kind() override;
TypeInstance *syntaxCopy() override;
- Dsymbol *toDsymbol(Scope *sc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -738,7 +722,6 @@ public:
const char *kind() override;
TypeTypeof *syntaxCopy() override;
- Dsymbol *toDsymbol(Scope *sc) override;
uinteger_t size(const Loc &loc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -748,7 +731,6 @@ class TypeReturn final : public TypeQualified
public:
const char *kind() override;
TypeReturn *syntaxCopy() override;
- Dsymbol *toDsymbol(Scope *sc) override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -776,7 +758,6 @@ public:
uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
TypeStruct *syntaxCopy() override;
- Dsymbol *toDsymbol(Scope *sc) override;
structalign_t alignment() override;
Expression *defaultInitLiteral(const Loc &loc) override;
bool isZeroInit(const Loc &loc) override;
@@ -785,7 +766,6 @@ public:
bool needsDestruction() override;
bool needsCopyOrPostblit() override;
bool needsNested() override;
- bool hasPointers() override;
bool hasVoidInitPointers() override;
bool hasSystemFields() override;
bool hasInvariant() override;
@@ -806,8 +786,7 @@ public:
TypeEnum *syntaxCopy() override;
uinteger_t size(const Loc &loc) override;
unsigned alignsize() override;
- Type *memType(const Loc &loc = Loc());
- Dsymbol *toDsymbol(Scope *sc) override;
+ Type *memType(const Loc &loc);
bool isintegral() override;
bool isfloating() override;
bool isreal() override;
@@ -824,7 +803,6 @@ public:
MATCH implicitConvTo(Type *to) override;
MATCH constConv(Type *to) override;
bool isZeroInit(const Loc &loc) override;
- bool hasPointers() override;
bool hasVoidInitPointers() override;
bool hasSystemFields() override;
bool hasInvariant() override;
@@ -843,9 +821,7 @@ public:
const char *kind() override;
uinteger_t size(const Loc &loc) override;
TypeClass *syntaxCopy() override;
- Dsymbol *toDsymbol(Scope *sc) override;
ClassDeclaration *isClassHandle() override;
- bool isBaseOf(Type *t, int *poffset) override;
MATCH implicitConvTo(Type *to) override;
MATCH constConv(Type *to) override;
unsigned char deduceWild(Type *t, bool isRef) override;
@@ -853,7 +829,6 @@ public:
bool isZeroInit(const Loc &loc) override;
bool isscope() override;
bool isBoolean() override;
- bool hasPointers() override;
void accept(Visitor *v) override { v->visit(this); }
};
@@ -894,7 +869,6 @@ public:
TypeNull *syntaxCopy() override;
MATCH implicitConvTo(Type *to) override;
- bool hasPointers() override;
bool isBoolean() override;
uinteger_t size(const Loc &loc) override;
@@ -925,6 +899,13 @@ public:
/**************************************************************/
+
// If the type is a class or struct, returns the symbol for it, else null.
AggregateDeclaration *isAggregate(Type *t);
+bool hasPointers(Type *t);
+// return the symbol to which type t resolves
+Dsymbol *toDsymbol(Type *t, Scope *sc);
Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false);
+bool isBaseOf(Type *tthis, Type *t, int *poffset);
+Type *trySemantic(Type *type, const Loc &loc, Scope *sc);
+void purityLevel(TypeFunction *type);
@@ -31,6 +31,7 @@ import dmd.location;
bool checkMustUse(Expression e, Scope* sc)
{
import dmd.id : Id;
+ import dmd.typesem : toDsymbol;
assert(e.type);
if (auto sym = e.type.toDsymbol(sc))
@@ -2566,6 +2566,7 @@ void checkObErrors(ref ObState obstate)
//printf("%s: ", obstate.vars[i].toChars()); pvs.print(obstate.vars[]);
if (pvs.state == PtrState.Owner)
{
+ import dmd.typesem : hasPointers;
auto v = obstate.vars[i];
if (v.type.hasPointers())
.error(v.loc, "%s `%s` is not disposed of before return", v.kind, v.toPrettyChars);
@@ -1675,7 +1675,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (token.value == TOK.assign) // = CondExpression
{
nextToken();
- tp_defaultvalue = parseDefaultInitExp();
+ tp_defaultvalue = parseAssignExp();
}
tp = new AST.TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
}
@@ -2969,7 +2969,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
if (token.value == TOK.assign) // = defaultArg
{
nextToken();
- ae = parseDefaultInitExp();
+ ae = parseAssignExp();
}
auto param = new AST.Parameter(loc, storageClass | STC.parameter, at, ai, ae, null);
if (udas)
@@ -6949,33 +6949,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
}
}
- /*****************************************
- * Parses default argument initializer expression that is an assign expression,
- * with special handling for __FILE__, __FILE_DIR__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
- */
- private AST.Expression parseDefaultInitExp()
- {
- AST.Expression e = null;
- const tv = peekNext();
- if (tv == TOK.comma || tv == TOK.rightParenthesis)
- {
- switch (token.value)
- {
- case TOK.file: e = new AST.FileInitExp(token.loc, EXP.file); break;
- case TOK.fileFullPath: e = new AST.FileInitExp(token.loc, EXP.fileFullPath); break;
- case TOK.line: e = new AST.LineInitExp(token.loc); break;
- case TOK.moduleString: e = new AST.ModuleInitExp(token.loc); break;
- case TOK.functionString: e = new AST.FuncInitExp(token.loc); break;
- case TOK.prettyFunction: e = new AST.PrettyFuncInitExp(token.loc); break;
- default: goto LExp;
- }
- nextToken();
- return e;
- }
- LExp:
- return parseAssignExp();
- }
-
/********************
* Parse inline assembler block.
* Enters with token on the `asm`.
@@ -8152,33 +8125,23 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
break;
case TOK.file:
- {
- const(char)* s = loc.filename ? loc.filename : mod.ident.toChars();
- e = new AST.StringExp(loc, s.toDString());
- nextToken();
- break;
- }
+ e = new AST.FileInitExp(loc, EXP.file);
+ nextToken();
+ break;
case TOK.fileFullPath:
- {
- assert(loc.isValid(), "__FILE_FULL_PATH__ does not work with an invalid location");
- const s = FileName.toAbsolute(loc.filename);
- e = new AST.StringExp(loc, s.toDString());
- nextToken();
- break;
- }
+ e = new AST.FileInitExp(loc, EXP.fileFullPath);
+ nextToken();
+ break;
case TOK.line:
- e = new AST.IntegerExp(loc, loc.linnum, AST.Type.tint32);
+ e = new AST.LineInitExp(loc);
nextToken();
break;
case TOK.moduleString:
- {
- const(char)* s = md ? md.toChars() : mod.toChars();
- e = new AST.StringExp(loc, s.toDString());
- nextToken();
- break;
- }
+ e = new AST.ModuleInitExp(loc);
+ nextToken();
+ break;
case TOK.functionString:
e = new AST.FuncInitExp(loc);
nextToken();
@@ -26,6 +26,7 @@ import dmd.identifier;
import dmd.mtype;
import dmd.target;
import dmd.tokens;
+import dmd.typesem : hasPointers;
import dmd.func : setUnsafe, setUnsafePreview;
/*************************************************************
@@ -87,6 +87,7 @@ struct Scope
Dsymbol *inunion; // !=null if processing members of a union
d_bool nofree; // true if shouldn't free it
d_bool inLoop; // true if inside a loop (where constructor calls aren't allowed)
+ d_bool inDefaultArg; // true if inside a default argument (where __FILE__, etc are evaluated at the call site)
int intypeof; // in typeof(exp)
VarDeclaration *lastVar; // Previous symbol used to prevent goto-skips-init
ErrorSink *eSink; // sink for error messages
@@ -231,8 +231,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
if (sc.flags & SCOPE.Cfile && funcdecl.isCMain() && f.next.ty == Tint32)
return true;
- return f.next.ty == Tvoid &&
- (funcdecl.isMain() || global.params.betterC && funcdecl.isCMain());
+ return f.next.ty == Tvoid && (funcdecl.isMain() || funcdecl.isCMain());
}
VarDeclaration _arguments = null;
@@ -346,6 +345,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
sc2.tf = null;
sc2.os = null;
sc2.inLoop = false;
+ sc2.inDefaultArg = false;
sc2.userAttribDecl = null;
if (sc2.intypeof == 1)
sc2.intypeof = 2;
@@ -570,7 +570,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
if ((needEnsure && global.params.useOut == CHECKENABLE.on) || fpostinv)
{
- funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel);
+ funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel, Loc.initial);
}
// scope of out contract (need for vresult.semantic)
@@ -24,6 +24,7 @@ import dmd.init;
import dmd.mtype;
import dmd.postordervisitor;
import dmd.tokens;
+import dmd.typesem;
import dmd.visitor;
/**************************************************
@@ -3753,7 +3753,10 @@ public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc)
{
if (!global.params.useExceptions)
{
- loc.error("cannot use `throw` statements with %s", global.params.betterC ? "-betterC".ptr : "-nothrow".ptr);
+ version (IN_GCC)
+ loc.error("cannot use `throw` statements with `-fno-exceptions`");
+ else
+ loc.error("cannot use `throw` statements with %s", global.params.betterC ? "-betterC".ptr : "-nothrow".ptr);
return false;
}
@@ -324,4 +324,4 @@ Tuple *isTuple(RootObject *o);
Parameter *isParameter(RootObject *o);
TemplateParameter *isTemplateParameter(RootObject *o);
bool isError(const RootObject *const o);
-void printTemplateStats();
+void printTemplateStats(bool listInstances, ErrorSink* eSink);
@@ -430,6 +430,123 @@ private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject i
return sm;
}
+/***************************************************
+ * Determine if type t is copyable.
+ * Params:
+ * t = type to check
+ * Returns:
+ * true if we can copy it
+ */
+bool isCopyable(Type t)
+{
+ //printf("isCopyable() %s\n", t.toChars());
+ if (auto ts = t.isTypeStruct())
+ {
+ if (ts.sym.postblit &&
+ ts.sym.postblit.storage_class & STC.disable)
+ return false;
+ if (ts.sym.hasCopyCtor)
+ {
+ // check if there is a matching overload of the copy constructor and whether it is disabled or not
+ // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575
+ Dsymbol ctor = search_function(ts.sym, Id.ctor);
+ assert(ctor);
+ scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue
+ el.type = cast() ts;
+ Expressions* args = new Expressions();
+ args.push(el);
+ FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet);
+ if (!f || f.storage_class & STC.disable)
+ return false;
+ }
+ }
+ return true;
+}
+
+/************************************
+ * Determine mutability of indirections in (ref) t.
+ *
+ * Returns: When the type has any mutable indirections, returns 0.
+ * When all indirections are immutable, returns 2.
+ * Otherwise, when the type has const/inout indirections, returns 1.
+ *
+ * Params:
+ * isref = if true, check `ref t`; otherwise, check just `t`
+ * t = the type that is being checked
+ */
+int mutabilityOfType(bool isref, Type t)
+{
+ if (isref)
+ {
+ if (t.mod & MODFlags.immutable_)
+ return 2;
+ if (t.mod & (MODFlags.const_ | MODFlags.wild))
+ return 1;
+ return 0;
+ }
+
+ t = t.baseElemOf();
+
+ if (!t.hasPointers() || t.mod & MODFlags.immutable_)
+ return 2;
+
+ /* Accept immutable(T)[] and immutable(T)* as being strongly pure
+ */
+ if (t.ty == Tarray || t.ty == Tpointer)
+ {
+ Type tn = t.nextOf().toBasetype();
+ if (tn.mod & MODFlags.immutable_)
+ return 2;
+ if (tn.mod & (MODFlags.const_ | MODFlags.wild))
+ return 1;
+ }
+
+ /* The rest of this is too strict; fix later.
+ * For example, the only pointer members of a struct may be immutable,
+ * which would maintain strong purity.
+ * (Just like for dynamic arrays and pointers above.)
+ */
+ if (t.mod & (MODFlags.const_ | MODFlags.wild))
+ return 1;
+
+ /* Should catch delegates and function pointers, and fold in their purity
+ */
+ return 0;
+}
+
+/********************************************
+ * Set 'purity' field of 'typeFunction'.
+ * Do this lazily, as the parameter types might be forward referenced.
+ */
+extern(C++) void purityLevel(TypeFunction typeFunction)
+{
+ TypeFunction tf = typeFunction;
+ if (tf.purity != PURE.fwdref)
+ return;
+
+ typeFunction.purity = PURE.const_; // assume strong until something weakens it
+
+ /* Evaluate what kind of purity based on the modifiers for the parameters
+ */
+ foreach (i, fparam; tf.parameterList)
+ {
+ Type t = fparam.type;
+ if (!t)
+ continue;
+
+ if (fparam.storageClass & (STC.lazy_ | STC.out_))
+ {
+ typeFunction.purity = PURE.weak;
+ break;
+ }
+ const pref = (fparam.storageClass & STC.ref_) != 0;
+ if (mutabilityOfType(pref, t) == 0)
+ typeFunction.purity = PURE.weak;
+ }
+
+ tf.purity = typeFunction.purity;
+}
+
/******************************************
* We've mistakenly parsed `t` as a type.
* Redo `t` as an Expression only if there are no type modifiers.
@@ -486,6 +603,77 @@ Expression typeToExpression(Type t)
}
}
+/*************************************
+ * https://issues.dlang.org/show_bug.cgi?id=14488
+ * Check if the inner most base type is complex or imaginary.
+ * Should only give alerts when set to emit transitional messages.
+ * Params:
+ * type = type to check
+ * loc = The source location.
+ * sc = scope of the type
+ */
+extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc)
+{
+ if (sc.isDeprecated())
+ return false;
+ // Don't complain if we're inside a template constraint
+ // https://issues.dlang.org/show_bug.cgi?id=21831
+ if (sc.flags & SCOPE.constraint)
+ return false;
+
+ Type t = type.baseElemOf();
+ while (t.ty == Tpointer || t.ty == Tarray)
+ t = t.nextOf().baseElemOf();
+
+ // Basetype is an opaque enum, nothing to check.
+ if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype)
+ return false;
+
+ if (t.isimaginary() || t.iscomplex())
+ {
+ if (sc.flags & SCOPE.Cfile)
+ return true; // complex/imaginary not deprecated in C code
+ Type rt;
+ switch (t.ty)
+ {
+ case Tcomplex32:
+ case Timaginary32:
+ rt = Type.tfloat32;
+ break;
+
+ case Tcomplex64:
+ case Timaginary64:
+ rt = Type.tfloat64;
+ break;
+
+ case Tcomplex80:
+ case Timaginary80:
+ rt = Type.tfloat80;
+ break;
+
+ default:
+ assert(0);
+ }
+ // @@@DEPRECATED_2.117@@@
+ // Deprecated in 2.097 - Can be made an error from 2.117.
+ // The deprecation period is longer than usual as `cfloat`,
+ // `cdouble`, and `creal` were quite widely used.
+ if (t.iscomplex())
+ {
+ deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead",
+ type.toChars(), rt.toChars());
+ return true;
+ }
+ else
+ {
+ deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead",
+ type.toChars(), rt.toChars());
+ return true;
+ }
+ }
+ return false;
+}
+
/********************************
* 'args' are being matched to function type 'tf'
* Determine match level.
@@ -494,12 +682,12 @@ Expression typeToExpression(Type t)
* tthis = type of `this` pointer, null if not member function
* argumentList = arguments to function call
* flag = 1: performing a partial ordering match
- * pMessage = address to store error message, or null
+ * errorHelper = delegate to call for error messages
* sc = context
* Returns:
* MATCHxxxx
*/
-extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null)
+extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, void delegate(const(char)*) scope errorHelper = null, Scope* sc = null)
{
//printf("TypeFunction::callMatch() %s\n", tf.toChars());
MATCH match = MATCH.exact; // assume exact match
@@ -542,7 +730,7 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
{
// suppress early exit if an error message is wanted,
// so we can check any matching args are valid
- if (!pMessage)
+ if (!errorHelper)
return MATCH.nomatch;
}
// too many args; no match
@@ -552,18 +740,25 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
// https://issues.dlang.org/show_bug.cgi?id=22997
if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs)
{
- OutBuffer buf;
- buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length);
- if (pMessage)
- *pMessage = buf.extractChars();
+ if (errorHelper)
+ {
+ OutBuffer buf;
+ buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length);
+ errorHelper(buf.peekChars());
+ }
return MATCH.nomatch;
}
+ const(char)* failMessage;
+ const(char)** pMessage = errorHelper ? &failMessage : null;
auto resolvedArgs = tf.resolveNamedArgs(argumentList, pMessage);
Expression[] args;
if (!resolvedArgs)
{
- if (!pMessage || *pMessage)
+ if (failMessage)
+ {
+ errorHelper(failMessage);
return MATCH.nomatch;
+ }
// if no message was provided, it was because of overflow which will be diagnosed below
match = MATCH.nomatch;
@@ -642,6 +837,8 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage))
return vmatch < match ? vmatch : match;
// Error message was already generated in `matchTypeSafeVarArgs`
+ if (failMessage)
+ errorHelper(failMessage);
return MATCH.nomatch;
}
if (pMessage && u >= args.length)
@@ -651,16 +848,18 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
else if (pMessage && !*pMessage)
*pMessage = tf.getParamError(args[u], p);
+ if (errorHelper)
+ errorHelper(*pMessage);
return MATCH.nomatch;
}
if (m < match)
match = m; // pick worst match
}
- if (pMessage && !parameterList.varargs && args.length > nparams)
+ if (errorHelper && !parameterList.varargs && args.length > nparams)
{
// all parameters had a match, but there are surplus args
- *pMessage = tf.getMatchError("expected %d argument(s), not %d", nparams, args.length);
+ errorHelper(tf.getMatchError("expected %d argument(s), not %d", nparams, args.length));
return MATCH.nomatch;
}
//printf("match = %d\n", match);
@@ -687,7 +886,7 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
Expression e = new DotIdExp(arg.loc, ve, Id.ctor);
e = new CallExp(arg.loc, e, arg);
//printf("e = %s\n", e.toChars());
- if (.trySemantic(e, sc))
+ if (dmd.expressionsem.trySemantic(e, sc))
return true;
if (pMessage)
@@ -1017,6 +1216,70 @@ private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p,
}
}
+/***************************************
+ * Return !=0 if type has pointers that need to
+ * be scanned by the GC during a collection cycle.
+ */
+extern(C++) bool hasPointers(Type t)
+{
+ bool visitType(Type _) { return false; }
+ bool visitDArray(TypeDArray _) { return true; }
+ bool visitAArray(TypeAArray _) { return true; }
+ bool visitPointer(TypePointer _) { return true; }
+ bool visitDelegate(TypeDelegate _) { return true; }
+ bool visitClass(TypeClass _) { return true; }
+ bool visitEnum(TypeEnum t) { return t.memType().hasPointers(); }
+
+ /* Although null isn't dereferencable, treat it as a pointer type for
+ * attribute inference, generic code, etc.
+ */
+ bool visitNull(TypeNull _) { return true; }
+
+ bool visitSArray(TypeSArray t)
+ {
+ /* Don't want to do this, because:
+ * struct S { T* array[0]; }
+ * may be a variable length struct.
+ */
+ //if (dim.toInteger() == 0)
+ // return false;
+
+ if (t.next.ty == Tvoid)
+ {
+ // Arrays of void contain arbitrary data, which may include pointers
+ return true;
+ }
+ else
+ return t.next.hasPointers();
+ }
+
+ bool visitStruct(TypeStruct t)
+ {
+ StructDeclaration sym = t.sym;
+
+ if (sym.members && !sym.determineFields() && sym.type != Type.terror)
+ error(sym.loc, "no size because of forward references");
+
+ sym.determineTypeProperties();
+ return sym.hasPointerField;
+ }
+
+
+ switch(t.ty)
+ {
+ default: return visitType(t);
+ case Tsarray: return visitSArray(t.isTypeSArray());
+ case Tarray: return visitDArray(t.isTypeDArray());
+ case Taarray: return visitAArray(t.isTypeAArray());
+ case Tpointer: return visitPointer(t.isTypePointer());
+ case Tdelegate: return visitDelegate(t.isTypeDelegate());
+ case Tstruct: return visitStruct(t.isTypeStruct());
+ case Tenum: return visitEnum(t.isTypeEnum());
+ case Tclass: return visitClass(t.isTypeClass());
+ case Tnull: return visitNull(t.isTypeNull());
+ }
+}
+
/******************************************
* Perform semantic analysis on a type.
* Params:
@@ -1661,9 +1924,12 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
else
{
e = inferType(e, fparam.type);
+ Scope* sc2 = sc.push();
+ sc2.inDefaultArg = true;
Initializer iz = new ExpInitializer(e.loc, e);
- iz = iz.initializerSemantic(sc, fparam.type, INITnointerpret);
+ iz = iz.initializerSemantic(sc2, fparam.type, INITnointerpret);
e = iz.initializerToExpression();
+ sc2.pop();
}
if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820
{
@@ -2553,6 +2819,31 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
}
}
+extern(C++) Type trySemantic(Type type, const ref Loc loc, Scope* sc)
+{
+ //printf("+trySemantic(%s) %d\n", toChars(), global.errors);
+
+ // Needed to display any deprecations that were gagged
+ auto tcopy = type.syntaxCopy();
+
+ const errors = global.startGagging();
+ Type t = typeSemantic(type, loc, sc);
+ if (global.endGagging(errors) || t.ty == Terror) // if any errors happened
+ {
+ t = null;
+ }
+ else
+ {
+ // If `typeSemantic` succeeded, there may have been deprecations that
+ // were gagged due the `startGagging` above. Run again to display
+ // those deprecations. https://issues.dlang.org/show_bug.cgi?id=19107
+ if (global.gaggedWarnings > 0)
+ typeSemantic(tcopy, loc, sc);
+ }
+ //printf("-trySemantic(%s) %d\n", toChars(), global.errors);
+ return t;
+}
+
/************************************
* If an identical type to `type` is in `type.stringtable`, return
* the latter one. Otherwise, add it to `type.stringtable`.
@@ -5216,6 +5507,117 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi
}
}
+/*
+If `type` resolves to a dsymbol, then that
+dsymbol is returned.
+
+Params:
+ type = the type that is checked
+ sc = the scope where the type is used
+
+Returns:
+ The dsymbol to which the type resolve or `null`
+ if the type does resolve to any symbol (for example,
+ in the case of basic types).
+*/
+extern(C++) Dsymbol toDsymbol(Type type, Scope* sc)
+{
+ Dsymbol visitType(Type _) { return null; }
+ Dsymbol visitStruct(TypeStruct type) { return type.sym; }
+ Dsymbol visitEnum(TypeEnum type) { return type.sym; }
+ Dsymbol visitClass(TypeClass type) { return type.sym; }
+
+ Dsymbol visitTraits(TypeTraits type)
+ {
+ Type t;
+ Expression e;
+ Dsymbol s;
+ resolve(type, type.loc, sc, e, t, s);
+ if (t && t.ty != Terror)
+ s = t.toDsymbol(sc);
+ else if (e)
+ s = getDsymbol(e);
+
+ return s;
+ }
+
+ Dsymbol visitMixin(TypeMixin type)
+ {
+ Type t;
+ Expression e;
+ Dsymbol s;
+ resolve(type, type.loc, sc, e, t, s);
+ if (t)
+ s = t.toDsymbol(sc);
+ else if (e)
+ s = getDsymbol(e);
+
+ return s;
+ }
+
+ Dsymbol visitIdentifier(TypeIdentifier type)
+ {
+ //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
+ if (!sc)
+ return null;
+
+ Type t;
+ Expression e;
+ Dsymbol s;
+ resolve(type, type.loc, sc, e, t, s);
+ if (t && t.ty != Tident)
+ s = t.toDsymbol(sc);
+ if (e)
+ s = getDsymbol(e);
+
+ return s;
+ }
+
+ Dsymbol visitInstance(TypeInstance type)
+ {
+ Type t;
+ Expression e;
+ Dsymbol s;
+ //printf("TypeInstance::semantic(%s)\n", toChars());
+ resolve(type, type.loc, sc, e, t, s);
+ if (t && t.ty != Tinstance)
+ s = t.toDsymbol(sc);
+ return s;
+ }
+
+ Dsymbol visitTypeof(TypeTypeof type)
+ {
+ //printf("TypeTypeof::toDsymbol('%s')\n", toChars());
+ Expression e;
+ Type t;
+ Dsymbol s;
+ resolve(type, type.loc, sc, e, t, s);
+ return s;
+ }
+
+ Dsymbol visitReturn(TypeReturn type)
+ {
+ Expression e;
+ Type t;
+ Dsymbol s;
+ resolve(type, type.loc, sc, e, t, s);
+ return s;
+ }
+
+ switch(type.ty)
+ {
+ default: return visitType(type);
+ case Ttraits: return visitTraits(type.isTypeTraits());
+ case Tmixin: return visitMixin(type.isTypeMixin());
+ case Tident: return visitIdentifier(type.isTypeIdentifier());
+ case Tinstance: return visitInstance(type.isTypeInstance());
+ case Ttypeof: return visitTypeof(type.isTypeTypeof());
+ case Treturn: return visitReturn(type.isTypeReturn());
+ case Tstruct: return visitStruct(type.isTypeStruct());
+ case Tenum: return visitEnum(type.isTypeEnum());
+ case Tclass: return visitClass(type.isTypeClass());
+ }
+}
/**********************************************
* Extract complex type from core.stdc.config
@@ -5541,6 +5943,144 @@ Lnotcovariant:
return Covariant.no;
}
+/************************************
+ * Take the specified storage class for p,
+ * and use the function signature to infer whether
+ * STC.scope_ and STC.return_ should be OR'd in.
+ * (This will not affect the name mangling.)
+ * Params:
+ * tf = TypeFunction to use to get the signature from
+ * tthis = type of `this` parameter, null if none
+ * p = parameter to this function
+ * outerVars = context variables p could escape into, if any
+ * indirect = is this for an indirect or virtual function call?
+ * Returns:
+ * storage class with STC.scope_ or STC.return_ OR'd in
+ */
+StorageClass parameterStorageClass(TypeFunction tf, Type tthis, Parameter p, VarDeclarations* outerVars = null,
+ bool indirect = false)
+{
+ //printf("parameterStorageClass(p: %s)\n", p.toChars());
+ auto stc = p.storageClass;
+
+ // When the preview switch is enable, `in` parameters are `scope`
+ if (stc & STC.constscoperef)
+ return stc | STC.scope_;
+
+ if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || tf.purity == PURE.impure)
+ return stc;
+
+ /* If haven't inferred the return type yet, can't infer storage classes
+ */
+ if (!tf.nextOf() || !tf.isnothrow())
+ return stc;
+
+ tf.purityLevel();
+
+ static bool mayHavePointers(Type t)
+ {
+ if (auto ts = t.isTypeStruct())
+ {
+ auto sym = ts.sym;
+ if (sym.members && !sym.determineFields() && sym.type != Type.terror)
+ // struct is forward referenced, so "may have" pointers
+ return true;
+ }
+ return t.hasPointers();
+ }
+
+ // See if p can escape via any of the other parameters
+ if (tf.purity == PURE.weak)
+ {
+ /*
+ * Indirect calls may escape p through a nested context
+ * See:
+ * https://issues.dlang.org/show_bug.cgi?id=24212
+ * https://issues.dlang.org/show_bug.cgi?id=24213
+ */
+ if (indirect)
+ return stc;
+
+ // Check escaping through parameters
+ foreach (i, fparam; tf.parameterList)
+ {
+ Type t = fparam.type;
+ if (!t)
+ continue;
+ t = t.baseElemOf(); // punch thru static arrays
+ if (t.isMutable() && t.hasPointers())
+ {
+ if (fparam.isReference() && fparam != p)
+ return stc;
+
+ if (t.ty == Tdelegate)
+ return stc; // could escape thru delegate
+
+ if (t.ty == Tclass)
+ return stc;
+
+ /* if t is a pointer to mutable pointer
+ */
+ if (auto tn = t.nextOf())
+ {
+ if (tn.isMutable() && mayHavePointers(tn))
+ return stc; // escape through pointers
+ }
+ }
+ }
+
+ // Check escaping through `this`
+ if (tthis && tthis.isMutable())
+ {
+ foreach (VarDeclaration v; isAggregate(tthis).fields)
+ {
+ if (v.hasPointers())
+ return stc;
+ }
+ }
+
+ // Check escaping through nested context
+ if (outerVars && tf.isMutable())
+ {
+ foreach (VarDeclaration v; *outerVars)
+ {
+ if (v.hasPointers())
+ return stc;
+ }
+ }
+ }
+
+ // Check escaping through return value
+ Type tret = tf.nextOf().toBasetype();
+ if (tf.isref || tret.hasPointers())
+ {
+ return stc | STC.scope_ | STC.return_ | STC.returnScope;
+ }
+ else
+ return stc | STC.scope_;
+}
+
+extern(C++) bool isBaseOf(Type tthis, Type t, int* poffset)
+{
+ auto tc = tthis.isTypeClass();
+ if (!tc)
+ return false;
+
+ if (!t || t.ty != Tclass)
+ return false;
+
+ ClassDeclaration cd = t.isTypeClass().sym;
+ if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
+ cd.dsymbolSemantic(null);
+ if (tc.sym.semanticRun < PASS.semanticdone && !tc.sym.isBaseInfoComplete())
+ tc.sym.dsymbolSemantic(null);
+
+ if (tc.sym.isBaseOf(cd, poffset))
+ return true;
+
+ return false;
+}
+
/******************************* Private *****************************************/
private:
@@ -204,6 +204,22 @@ binop_assignment (tree_code code, Expression *e1, Expression *e2)
return compound_expr (lexpr, expr);
}
+/* Compile the function literal body. */
+
+static void
+build_lambda_tree (FuncLiteralDeclaration *fld, Type *type = NULL)
+{
+ /* This check is for lambda's, remove `vthis' as function isn't nested. */
+ if (fld->tok == TOK::reserved && (type == NULL || type->ty == TY::Tpointer))
+ {
+ fld->tok = TOK::function_;
+ fld->vthis = NULL;
+ }
+
+ /* Compile the function literal body. */
+ build_decl_tree (fld);
+}
+
/* Implements the visitor interface to build the GCC trees of all Expression
AST classes emitted from the D Front-end.
All visit methods accept one parameter E, which holds the frontend AST
@@ -2012,17 +2028,8 @@ public:
void visit (FuncExp *e) final override
{
- Type *ftype = e->type->toBasetype ();
-
- /* This check is for lambda's, remove `vthis' as function isn't nested. */
- if (e->fd->tok == TOK::reserved && ftype->ty == TY::Tpointer)
- {
- e->fd->tok = TOK::function_;
- e->fd->vthis = NULL;
- }
-
- /* Compile the function literal body. */
- build_decl_tree (e->fd);
+ /* Compile the declaration. */
+ build_lambda_tree (e->fd, e->type->toBasetype ());
/* If nested, this will be a trampoline. */
if (e->fd->isNested ())
@@ -2071,6 +2078,10 @@ public:
if (e->var->isFuncDeclaration ())
result = maybe_reject_intrinsic (result);
+ /* Emit lambdas, same as is done in FuncExp. */
+ if (FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ())
+ build_lambda_tree (fld);
+
if (declaration_reference_p (e->var))
gcc_assert (POINTER_TYPE_P (TREE_TYPE (result)));
else
@@ -2105,19 +2116,9 @@ public:
return;
}
- /* This check is same as is done in FuncExp for lambdas. */
- FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ();
- if (fld != NULL)
- {
- if (fld->tok == TOK::reserved)
- {
- fld->tok = TOK::function_;
- fld->vthis = NULL;
- }
-
- /* Compiler the function literal body. */
- build_decl_tree (fld);
- }
+ /* Emit lambdas, same as is done in FuncExp. */
+ if (FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ())
+ build_lambda_tree (fld);
if (this->constp_)
{
@@ -259,7 +259,8 @@ create_tinfo_types (Module *mod)
array_type_node, array_type_node, array_type_node,
array_type_node, ptr_type_node, ptr_type_node,
ptr_type_node, d_uint_type, ptr_type_node,
- array_type_node, ptr_type_node, ptr_type_node, NULL);
+ array_type_node, ptr_type_node, d_ulong_type,
+ d_ulong_type, ptr_type_node, NULL);
object_module = mod;
}
@@ -814,6 +815,7 @@ public:
void *deallocator;
OffsetTypeInfo[] m_offTi;
void function(Object) defaultConstructor;
+ ulong[2] nameSig
immutable(void)* m_RTInfo;
Information relating to interfaces, and their vtables are laid out
@@ -932,6 +934,10 @@ public:
else
this->layout_field (null_pointer_node);
+ /* ulong[2] nameSig; */
+ this->layout_field (build_zero_cst (d_ulong_type));
+ this->layout_field (build_zero_cst (d_ulong_type));
+
/* immutable(void)* m_RTInfo; */
if (cd->getRTInfo)
this->layout_field (build_expr (cd->getRTInfo, true));
@@ -979,6 +985,10 @@ public:
this->layout_field (null_array_node);
this->layout_field (null_pointer_node);
+ /* ulong[2] nameSig; */
+ this->layout_field (build_zero_cst (d_ulong_type));
+ this->layout_field (build_zero_cst (d_ulong_type));
+
/* immutable(void)* m_RTInfo; */
if (cd->getRTInfo)
this->layout_field (build_expr (cd->getRTInfo, true));
@@ -1084,7 +1094,7 @@ public:
/* StructFlags m_flags; */
int m_flags = StructFlags::none;
- if (ti->hasPointers ())
+ if (hasPointers (ti))
m_flags |= StructFlags::hasPointers;
this->layout_field (build_integer_cst (m_flags, d_uint_type));
@@ -7,7 +7,7 @@ class Object { }
class TypeInfo { }
class TypeInfo_Class : TypeInfo
{
- version(D_LP64) { ubyte[136] _x; } else { ubyte[68] _x; }
+ version(D_LP64) { ubyte[136+16] _x; } else { ubyte[68+16] _x; }
}
class Throwable { }
new file mode 100644
@@ -0,0 +1,13 @@
+struct S
+{
+ int i;
+}
+
+int f(immutable S *s)
+{
+ return s.i;
+}
+
+immutable S globalS = S(5);
+
+static assert (f(&globalS) == 5);
new file mode 100644
@@ -0,0 +1,13 @@
+// REQUIRED_ARGS: -betterC
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test24295.d(12): Error: expression `new int[](1$?:32=u|64=LU$)` allocates with the GC and cannot be used with switch `-betterC`
+---
+*/
+
+void f()
+{
+ int[] overlaps = new int[1];
+}
new file mode 100644
@@ -0,0 +1,250 @@
+module imports.issue18919b;
+
+import core.stdc.stdio;
+
+// Remove directories from paths. Used to make the output platform-independent.
+string baseName(string path)
+{
+ foreach_reverse (i, char c; path)
+ {
+ if (c == '/' || c == '\\')
+ return path[i + 1 .. $];
+ }
+ return path;
+}
+const(char)* baseName(const(char)* path)
+{
+ for (const(char)* ptr = path; *ptr; ptr++)
+ {
+ if (*ptr == '/' || *ptr == '\\')
+ path = ptr + 1;
+ }
+ return path;
+}
+
+void func1(string file = __FILE__, size_t line = __LINE__,
+ string func = __FUNCTION__,
+ string pfunc = __PRETTY_FUNCTION__,
+ string mod = __MODULE__)
+{
+ file = baseName(file);
+ printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr,
+ cast(int) file.length, file.ptr, cast(int) line,
+ cast(int) func.length, func.ptr,
+ cast(int) pfunc.length, pfunc.ptr,
+ cast(int) mod.length, mod.ptr);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=21211
+void func2(const(char)* file = __FILE__.ptr, size_t line = __LINE__,
+ const(char)* func = __FUNCTION__.ptr,
+ const(char)* pfunc = __PRETTY_FUNCTION__.ptr,
+ const(char)* mod = __MODULE__.ptr)
+{
+ file = baseName(file);
+ printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr,
+ file, cast(int) line, func, pfunc, mod);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=18919
+struct Loc3
+{
+ string file;
+ size_t line;
+ string func;
+ string pfunc;
+ string mod;
+}
+void func3(Loc3 loc = Loc3(__FILE__, __LINE__,
+ __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__))
+{
+ loc.file = baseName(loc.file);
+ printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr,
+ cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line,
+ cast(int) loc.func.length, loc.func.ptr,
+ cast(int) loc.pfunc.length, loc.pfunc.ptr,
+ cast(int) loc.mod.length, loc.mod.ptr);
+}
+Loc3 defaultLoc3(string file = __FILE__, size_t line = __LINE__,
+ string func = __FUNCTION__,
+ string pfunc = __PRETTY_FUNCTION__,
+ string mod = __MODULE__)
+{
+ return Loc3(file, line, func, pfunc, mod);
+}
+void func3b(Loc3 loc = defaultLoc3)
+{
+ loc.file = baseName(loc.file);
+ printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr,
+ cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line,
+ cast(int) loc.func.length, loc.func.ptr,
+ cast(int) loc.pfunc.length, loc.pfunc.ptr,
+ cast(int) loc.mod.length, loc.mod.ptr);
+}
+enum Loc3Mixin = q{Loc3(__FILE__, __LINE__,
+ __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)};
+void func3c(Loc3 loc = mixin(Loc3Mixin))
+{
+ loc.file = baseName(loc.file);
+ printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr,
+ cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line,
+ cast(int) loc.func.length, loc.func.ptr,
+ cast(int) loc.pfunc.length, loc.pfunc.ptr,
+ cast(int) loc.mod.length, loc.mod.ptr);
+}
+void func3d(Loc3* loc = new Loc3(__FILE__, __LINE__,
+ __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__))
+{
+ loc.file = baseName(loc.file);
+ printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr,
+ cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line,
+ cast(int) loc.func.length, loc.func.ptr,
+ cast(int) loc.pfunc.length, loc.pfunc.ptr,
+ cast(int) loc.mod.length, loc.mod.ptr);
+}
+
+struct Loc4
+{
+ const(char)* file;
+ size_t line;
+ const(char)* func;
+ const(char)* pfunc;
+ const(char)* mod;
+}
+void func4(Loc4 loc = Loc4(__FILE__.ptr, __LINE__,
+ __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr))
+{
+ loc.file = baseName(loc.file);
+ printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr,
+ loc.file, cast(int) loc.line,
+ loc.func,
+ loc.pfunc,
+ loc.mod);
+}
+Loc4 defaultLoc4(const(char)* file = __FILE__.ptr, size_t line = __LINE__,
+ const(char)* func = __FUNCTION__.ptr,
+ const(char)* pfunc = __PRETTY_FUNCTION__.ptr,
+ const(char)* mod = __MODULE__.ptr)
+{
+ return Loc4(file, line, func, pfunc, mod);
+}
+void func4b(Loc4 loc = defaultLoc4)
+{
+ loc.file = baseName(loc.file);
+ printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr,
+ loc.file, cast(int) loc.line,
+ loc.func,
+ loc.pfunc,
+ loc.mod);
+}
+enum Loc4Mixin = q{Loc4(__FILE__.ptr, __LINE__,
+ __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr)};
+void func4c(Loc4 loc = mixin(Loc4Mixin))
+{
+ loc.file = baseName(loc.file);
+ printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr,
+ loc.file, cast(int) loc.line,
+ loc.func,
+ loc.pfunc,
+ loc.mod);
+}
+void func4d(Loc4* loc = new Loc4(__FILE__.ptr, __LINE__,
+ __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr))
+{
+ loc.file = baseName(loc.file);
+ printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr,
+ loc.file, cast(int) loc.line,
+ loc.func,
+ loc.pfunc,
+ loc.mod);
+}
+
+void func5(string file = baseName(__FILE__), int line = __LINE__,
+ string func = __FUNCTION__,
+ string pfunc = __PRETTY_FUNCTION__,
+ string mod = __MODULE__)()
+{
+ printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr,
+ cast(int) file.length, file.ptr, line,
+ cast(int) func.length, func.ptr,
+ cast(int) pfunc.length, pfunc.ptr,
+ cast(int) mod.length, mod.ptr);
+}
+
+void func6(string file = baseName(__FILE__), int line = __LINE__,
+ const(char)* func = __FUNCTION__.ptr,
+ const(char)* pfunc = __PRETTY_FUNCTION__.ptr,
+ const(char)* mod = __MODULE__.ptr)()
+{
+ printf("%s: %.*s:%d %s %s %s\n", __FUNCTION__.ptr,
+ cast(int) file.length, file.ptr, line, func, pfunc, mod);
+}
+
+void func7(int expr1 = 1000 + __LINE__ * 2,
+ string expr2 = "file=" ~ baseName(__FILE__) ~ " func=" ~ __FUNCTION__,
+ int expr3 = __LINE__ > 5 ? 1 : 2)
+{
+ printf("%s: expr1=%d, %.*s, expr3=%d\n", __FUNCTION__.ptr, expr1, cast(int) expr2.length, expr2.ptr, expr3);
+}
+
+immutable string[2] constants = ["constant1", "constant2"];
+void func8(int[] expr1 = [__LINE__, __LINE__ + 1000],
+ int[string] expr2 = [baseName(__FILE__): __LINE__],
+ string expr3 = constants[__LINE__ > 5],
+ string expr4 = __FILE__[0 .. __FILE__.length - 2])
+{
+ expr4 = baseName(expr4);
+ printf("%s: expr1=[", __FUNCTION__.ptr);
+ foreach (i, x; expr1)
+ printf("%d, ", x);
+ printf("], expr2=[");
+ foreach (k, v; expr2)
+ printf("%.*s: %d, ", cast(int) k.length, k.ptr, v);
+ printf("], expr3=%.*s", cast(int) expr3.length, expr3.ptr);
+ printf(", expr4=%.*s\n", cast(int) expr4.length, expr4.ptr);
+}
+
+void func9(void function(string file = __FILE__, size_t line = __LINE__, string mod = __MODULE__)
+ fp = (string file, size_t line, string mod)
+ {
+ file = baseName(file);
+ printf("imports.issue18919b.func9.fp: %.*s:%d %.*s\n",
+ cast(int) file.length, file.ptr, cast(int) line,
+ cast(int) mod.length, mod.ptr);
+ })
+{
+ fp();
+}
+
+void func10(string expr1 = mixin(() { return "\"expr1=" ~ __MODULE__ ~ "\""; } ()),
+ string expr2 = mixin("\"expr2=" ~ __MODULE__ ~ "\""))
+{
+ printf("%s: %.*s, %.*s\n", __FUNCTION__.ptr,
+ cast(int) expr1.length, expr1.ptr,
+ cast(int) expr2.length, expr2.ptr);
+}
+
+template ctLoc3(string file, int line,
+ string func, string pfunc, string mod)
+{
+ enum Loc3 ctLoc3 = Loc3(file, line, func, pfunc, mod);
+}
+
+void func11(Loc3 loc = ctLoc3!(baseName(__FILE__), __LINE__,
+ __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__))
+{
+ printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr,
+ cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line,
+ cast(int) loc.func.length, loc.func.ptr,
+ cast(int) loc.pfunc.length, loc.pfunc.ptr,
+ cast(int) loc.mod.length, loc.mod.ptr);
+}
+
+void func12(const(char)*[] args = [baseName(__FILE__.ptr),
+ __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr])
+{
+ printf("%s:", __FUNCTION__.ptr);
+ foreach (arg; args)
+ printf(" %s", arg);
+ printf("\n");
+}
new file mode 100644
@@ -0,0 +1,47 @@
+/*
+EXTRA_SOURCES: imports/issue18919b.d
+RUN_OUTPUT:
+---
+imports.issue18919b.func1: issue18919.d:29 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func2: issue18919.d:30 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func3: issue18919.d:31 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func3b: issue18919.d:32 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func3c: issue18919.d:33 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func3d: issue18919.d:34 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func4: issue18919.d:35 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func4b: issue18919.d:36 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func4c: issue18919.d:37 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func4d: issue18919.d:38 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func5!("issue18919.d", 39, "issue18919.main", "void issue18919.main()", "issue18919").func5: issue18919.d:39 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func6!("issue18919.d", 40, "issue18919.main", "void issue18919.main()", "issue18919").func6: issue18919.d:40 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func7: expr1=1082, file=issue18919.d func=issue18919.main, expr3=1
+imports.issue18919b.func8: expr1=[42, 1042, ], expr2=[issue18919.d: 42, ], expr3=constant2, expr4=issue18919
+imports.issue18919b.func9.fp: issue18919b.d:216 imports.issue18919b
+imports.issue18919b.func10: expr1=imports.issue18919b, expr2=imports.issue18919b
+imports.issue18919b.func11: issue18919b.d:233 imports.issue18919b
+imports.issue18919b.func12: issue18919.d issue18919.main void issue18919.main() issue18919
+---
+*/
+import imports.issue18919b;
+
+void main()
+{
+ func1();
+ func2();
+ func3();
+ func3b();
+ func3c();
+ func3d();
+ func4();
+ func4b();
+ func4c();
+ func4d();
+ func5();
+ func6();
+ func7();
+ func8();
+ func9();
+ func10();
+ func11();
+ func12();
+}
@@ -11,9 +11,9 @@ struct Line
void foo(Line line1 = __LINE__, int line2 = __LINE__, int line3 = int(__LINE__))
{
- assert(line1 == 12);
+ assert(line1 == 21);
assert(line2 == 21);
- assert(line3 == 12);
+ assert(line3 == 21);
}
void main()
@@ -3,6 +3,7 @@ version(CRuntime_Microsoft)
{
extern(C)
{
+ extern __gshared void* __ImageBase;
extern __gshared uint _DP_beg;
extern __gshared uint _DP_end;
extern __gshared uint _TP_beg;
@@ -18,8 +19,8 @@ version(CRuntime_Microsoft)
{
import core.internal.traits : externDFunc;
alias findImageSection = externDFunc!("rt.sections_win64.findImageSection",
- void[] function(string name) nothrow @nogc);
- dataSection = findImageSection(".data");
+ void[] function(void* handle, string name) nothrow @nogc);
+ dataSection = findImageSection(&__ImageBase, ".data");
}
void[] tlsRange;
@@ -179,7 +179,7 @@ void test7()
void foo8(int n1 = __LINE__ + 0, int n2 = __LINE__, string s = __FILE__)
{
- assert(n1 < n2);
+ assert(n1 == n2);
printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, cast(int)s.length, s.ptr);
}
@@ -192,7 +192,7 @@ void test8()
void foo9(int n1 = __LINE__ + 0, int n2 = __LINE__, string s = __FILE__)()
{
- assert(n1 < n2);
+ assert(n1 == n2);
printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, cast(int)s.length, s.ptr);
}
@@ -8031,6 +8031,29 @@ void test18232()
assert(u.method() == Canary.init);
}
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=24332
+
+void test24332()
+{
+ class A {}
+ final class B : A {}
+
+ auto foo(A a) {
+ return cast(B) a;
+ }
+
+ auto a = new A();
+ auto n = cast(B) a;
+ assert(n is null);
+ auto b = cast(A) new B();
+ auto c = cast(B) b;
+ assert(c);
+ B e;
+ auto d = cast(B) cast(A) e;
+ assert(d is null);
+}
+
/***************************************************/
int main()
@@ -8352,6 +8375,7 @@ int main()
test17349();
test17915();
test18232();
+ test24332();
printf("Success\n");
return 0;
@@ -1,4 +1,4 @@
-d8e3976a58d6aef7c2c9371028a2ca4460b5b2ce
+bce5c1f7b521d22dcf1ea4e2bc3f76d9d28274fa
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
@@ -697,17 +697,17 @@ else
* Throws:
* $(LREF OutOfMemoryError).
*/
- extern (C) noreturn onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
+ extern (C) noreturn onOutOfMemoryError(void* pretend_sideffect = null, string file = __FILE__, size_t line = __LINE__) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
{
// NOTE: Since an out of memory condition exists, no allocation must occur
// while generating this object.
- throw staticError!OutOfMemoryError();
+ throw staticError!OutOfMemoryError(file, line);
}
- extern (C) noreturn onOutOfMemoryErrorNoGC() @trusted nothrow @nogc
+ extern (C) noreturn onOutOfMemoryErrorNoGC(string file = __FILE__, size_t line = __LINE__) @trusted nothrow @nogc
{
// suppress stacktrace until they are @nogc
- throw staticError!OutOfMemoryError(false);
+ throw staticError!OutOfMemoryError(false, file, line);
}
}
@@ -718,11 +718,11 @@ else
* Throws:
* $(LREF InvalidMemoryOperationError).
*/
-extern (C) noreturn onInvalidMemoryOperationError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
+extern (C) noreturn onInvalidMemoryOperationError(void* pretend_sideffect = null, string file = __FILE__, size_t line = __LINE__) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
{
// The same restriction applies as for onOutOfMemoryError. The GC is in an
// undefined state, thus no allocation must occur while generating this object.
- throw staticError!InvalidMemoryOperationError();
+ throw staticError!InvalidMemoryOperationError(file, line);
}
@@ -9,7 +9,7 @@ module core.internal.container.array;
static import common = core.internal.container.common;
-import core.exception : onOutOfMemoryErrorNoGC;
+import core.exception : onOutOfMemoryError;
struct Array(T)
{
@@ -47,7 +47,7 @@ nothrow:
_length = nlength;
}
else
- onOutOfMemoryErrorNoGC();
+ onOutOfMemoryError();
}
@@ -103,7 +103,7 @@ nothrow:
back = val;
}
else
- onOutOfMemoryErrorNoGC();
+ onOutOfMemoryError();
}
void popBack()
@@ -18,7 +18,7 @@ void* xrealloc(void* ptr, size_t sz) nothrow @nogc
if (!sz) { .free(ptr); return null; }
if (auto nptr = .realloc(ptr, sz)) return nptr;
- .free(ptr); onOutOfMemoryErrorNoGC();
+ .free(ptr); onOutOfMemoryError();
assert(0);
}
@@ -27,7 +27,7 @@ void* xmalloc(size_t sz) nothrow @nogc
import core.exception;
if (auto nptr = .malloc(sz))
return nptr;
- onOutOfMemoryErrorNoGC();
+ onOutOfMemoryError();
assert(0);
}
@@ -180,6 +180,8 @@ private string miniFormat(V)(const scope ref V v)
/// `shared` values are formatted as their base type
static if (is(V == shared T, T))
{
+ import core.atomic : atomicLoad;
+
// Use atomics to avoid race conditions whenever possible
static if (__traits(compiles, atomicLoad(v)))
{
@@ -472,11 +474,6 @@ private bool[] calcFieldOverlap(const scope size_t[] offsets)
return overlaps;
}
-// This should be a local import in miniFormat but fails with a cyclic dependency error
-// core.thread.osthread -> core.time -> object -> core.internal.array.capacity
-// -> core.atomic -> core.thread -> core.thread.osthread
-import core.atomic : atomicLoad;
-
/// Negates a comparison token, e.g. `==` is mapped to `!=`
private string invertCompToken(scope string comp) pure nothrow @nogc @safe
{
@@ -94,8 +94,8 @@ private
// Declared as an extern instead of importing core.exception
// to avoid inlining - see https://issues.dlang.org/show_bug.cgi?id=13725.
- void onInvalidMemoryOperationError(void* pretend_sideffect = null) @trusted pure nothrow @nogc;
- void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc;
+ void onInvalidMemoryOperationError(void* pretend_sideffect = null, string file = __FILE__, size_t line = __LINE__) @trusted pure nothrow @nogc;
+ void onOutOfMemoryError(void* pretend_sideffect = null, string file = __FILE__, size_t line = __LINE__) @trusted nothrow @nogc;
version (COLLECT_FORK)
version (OSX)
@@ -141,7 +141,7 @@ private GC initialize()
auto gc = cast(ConservativeGC) cstdlib.malloc(__traits(classInstanceSize, ConservativeGC));
if (!gc)
- onOutOfMemoryErrorNoGC();
+ onOutOfMemoryError();
return emplace(gc);
}
@@ -160,7 +160,7 @@ class ConservativeGC : GC
Gcx *gcx; // implementation
- static gcLock = shared(AlignedSpinLock)(SpinLock.Contention.lengthy);
+ static gcLock = shared(AlignedSpinLock)(SpinLock.Contention.brief);
static bool _inFinalizer;
__gshared bool isPrecise = false;
@@ -188,7 +188,7 @@ class ConservativeGC : GC
gcx = cast(Gcx*)cstdlib.calloc(1, Gcx.sizeof);
if (!gcx)
- onOutOfMemoryErrorNoGC();
+ onOutOfMemoryError();
gcx.initialize();
if (config.initReserve)
@@ -509,7 +509,7 @@ class ConservativeGC : GC
auto p = gcx.alloc(size + SENTINEL_EXTRA, alloc_size, bits, ti);
if (!p)
- onOutOfMemoryErrorNoGC();
+ onOutOfMemoryError();
debug (SENTINEL)
{
@@ -1968,7 +1968,7 @@ struct Gcx
// tryAlloc will succeed if a new pool was allocated above, if it fails allocate a new pool now
if (!tryAlloc() && (!newPool(1, false) || !tryAlloc()))
// out of luck or memory
- onOutOfMemoryErrorNoGC();
+ onOutOfMemoryError();
}
assert(p !is null);
L_hasBin:
@@ -2008,7 +2008,7 @@ struct Gcx
size_t pn;
immutable npages = LargeObjectPool.numPages(size);
if (npages == size_t.max)
- onOutOfMemoryErrorNoGC(); // size just below size_t.max requested
+ onOutOfMemoryError(); // size just below size_t.max requested
bool tryAlloc() nothrow
{
@@ -2248,7 +2248,7 @@ struct Gcx
enum initSize = 64 * 1024; // Windows VirtualAlloc granularity
immutable ncap = _cap ? 2 * _cap : initSize / RANGE.sizeof;
auto p = cast(RANGE*)os_mem_map(ncap * RANGE.sizeof);
- if (p is null) onOutOfMemoryErrorNoGC();
+ if (p is null) onOutOfMemoryError();
debug (VALGRIND) makeMemUndefined(p[0..ncap]);
if (_p !is null)
{
@@ -3394,7 +3394,7 @@ Lmark:
scanThreadData = cast(ScanThreadData*) cstdlib.calloc(numScanThreads, ScanThreadData.sizeof);
if (!scanThreadData)
- onOutOfMemoryErrorNoGC();
+ onOutOfMemoryError();
evStart.initialize(false, false);
evDone.initialize(false, false);
@@ -3610,7 +3610,7 @@ struct Pool
{
rtinfo = cast(immutable(size_t)**)cstdlib.malloc(npages * (size_t*).sizeof);
if (!rtinfo)
- onOutOfMemoryErrorNoGC();
+ onOutOfMemoryError();
memset(rtinfo, 0, npages * (size_t*).sizeof);
}
else
@@ -3633,13 +3633,13 @@ struct Pool
pagetable = cast(Bins*)cstdlib.malloc(npages * Bins.sizeof);
if (!pagetable)
- onOutOfMemoryErrorNoGC();
+ onOutOfMemoryError();
if (npages > 0)
{
bPageOffsets = cast(uint*)cstdlib.malloc(npages * uint.sizeof);
if (!bPageOffsets)
- onOutOfMemoryErrorNoGC();
+ onOutOfMemoryError();
if (isLargeObject)
{
@@ -4643,14 +4643,14 @@ debug (LOGGING)
{
data = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof);
if (!data && allocdim)
- onOutOfMemoryErrorNoGC();
+ onOutOfMemoryError();
}
else
{ Log *newdata;
newdata = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof);
if (!newdata && allocdim)
- onOutOfMemoryErrorNoGC();
+ onOutOfMemoryError();
memcpy(newdata, data, dim * Log.sizeof);
cstdlib.free(data);
data = newdata;
@@ -4989,8 +4989,8 @@ version (D_LP64) unittest
// only run if the system has enough physical memory
size_t sz = 2L^^32;
//import core.stdc.stdio;
- //printf("availphys = %lld", os_physical_mem());
- if (os_physical_mem() > sz)
+ //printf("availphys = %lld", os_physical_mem(true));
+ if (os_physical_mem(true) > sz)
{
import core.memory;
GC.collect();
@@ -254,23 +254,26 @@ bool isLowOnMem(size_t mapped) nothrow @nogc
/**
Get the size of available physical memory
+ Params:
+ avail = if supported on the current platform, return the currently unused memory
+ rather than the installed physical memory
Returns:
size of installed physical RAM
*/
version (Windows)
{
- ulong os_physical_mem() nothrow @nogc
+ ulong os_physical_mem(bool avail) nothrow @nogc
{
import core.sys.windows.winbase : GlobalMemoryStatus, MEMORYSTATUS;
MEMORYSTATUS stat;
GlobalMemoryStatus(&stat);
- return stat.dwTotalPhys; // limited to 4GB for Win32
+ return avail ? stat.dwAvailPhys : stat.dwTotalPhys; // limited to 4GB for Win32
}
}
else version (Darwin)
{
extern (C) int sysctl(const int* name, uint namelen, void* oldp, size_t* oldlenp, const void* newp, size_t newlen) @nogc nothrow;
- ulong os_physical_mem() nothrow @nogc
+ ulong os_physical_mem(bool avail) nothrow @nogc
{
enum
{
@@ -287,11 +290,15 @@ else version (Darwin)
}
else version (Posix)
{
- ulong os_physical_mem() nothrow @nogc
+ ulong os_physical_mem(bool avail) nothrow @nogc
{
- import core.sys.posix.unistd : sysconf, _SC_PAGESIZE, _SC_PHYS_PAGES;
+ import core.sys.posix.unistd;
const pageSize = sysconf(_SC_PAGESIZE);
- const pages = sysconf(_SC_PHYS_PAGES);
+ static if (__traits(compiles, _SC_AVPHYS_PAGES)) // not available on all platforms
+ const sc = avail ? _SC_AVPHYS_PAGES : _SC_PHYS_PAGES;
+ else
+ const sc = _SC_PHYS_PAGES;
+ const pages = sysconf(sc);
return pageSize * pages;
}
}
@@ -53,9 +53,9 @@ shared struct SpinLock
import core.time;
if (k < pauseThresh)
return core.atomic.pause();
- else if (k < 32)
+ else // if (k < 32)
return Thread.yield();
- Thread.sleep(1.msecs);
+ // Thread.sleep(1.msecs);
}
private:
@@ -266,8 +266,8 @@ extern(C):
/**
* Enables automatic garbage collection behavior if collections have
- * previously been suspended by a call to disable. This function is
- * reentrant, and must be called once for every call to disable before
+ * previously been suspended by a call to `GC.disable()`. This function is
+ * reentrant, and must be called once for every call to `GC.disable()` before
* automatic collections are enabled.
*/
pragma(mangle, "gc_enable") static void enable() @safe nothrow pure;
@@ -278,7 +278,12 @@ extern(C):
* process footprint. Collections may continue to occur in instances
* where the implementation deems necessary for correct program behavior,
* such as during an out of memory condition. This function is reentrant,
- * but enable must be called once for each call to disable.
+ * but `GC.enable()` must be called once for each call to `GC.disable()`.
+ * Unlike the
+ * $(LINK2 https://dlang.org/spec/function.html#nogc-functions, `@nogc` attribute),
+ * `GC.disable()` halts
+ * collections across all threads, yet still allows GC allocations.
+ * Disabling collections eliminates GC pauses.
*/
pragma(mangle, "gc_disable") static void disable() @safe nothrow pure;
@@ -113,6 +113,15 @@ else version (CRuntime_Musl)
*/
noreturn __assert_fail(const(char)* exp, const(char)* file, uint line, const(char)* func);
}
+else version (CRuntime_Newlib)
+{
+ /***
+ * Assert failure function in the Newlib library.
+ */
+ noreturn __assert(const(char)* file, int line, const(char)* exp);
+ ///
+ noreturn __assert_func(const(char)* file, int line, const(char)* func, const(char)* exp);
+}
else version (CRuntime_UClibc)
{
noreturn __assert(const(char)* exp, const(char)* file, uint line, const(char)* func);
@@ -75,6 +75,14 @@ else version (CRuntime_Musl)
alias errno = __errno_location;
}
}
+else version (CRuntime_Newlib)
+{
+ extern (C)
+ {
+ ref int __errno();
+ alias errno = __errno;
+ }
+}
else version (OpenBSD)
{
// https://github.com/openbsd/src/blob/master/include/errno.h
@@ -164,7 +172,7 @@ else
extern (C):
-version (Windows)
+version (CRuntime_DigitalMars)
{
enum EPERM = 1; /// Operation not permitted
enum ENOENT = 2; /// No such file or directory
@@ -250,6 +258,230 @@ version (Windows)
enum ETXTBSY = 139;
enum EWOULDBLOCK = 140;
}
+else version (CRuntime_Microsoft)
+{
+ enum EPERM = 1; /// Operation not permitted
+ enum ENOENT = 2; /// No such file or directory
+ enum ESRCH = 3; /// No such process
+ enum EINTR = 4; /// Interrupted system call
+ enum EIO = 5; /// I/O error
+ enum ENXIO = 6; /// No such device or address
+ enum E2BIG = 7; /// Argument list too long
+ enum ENOEXEC = 8; /// Exec format error
+ enum EBADF = 9; /// Bad file number
+ enum ECHILD = 10; /// No child processes
+ enum EAGAIN = 11; /// Try again
+ enum ENOMEM = 12; /// Out of memory
+ enum EACCES = 13; /// Permission denied
+ enum EFAULT = 14; /// Bad address
+ enum EBUSY = 16; /// Device or resource busy
+ enum EEXIST = 17; /// File exists
+ enum EXDEV = 18; /// Cross-device link
+ enum ENODEV = 19; /// No such device
+ enum ENOTDIR = 20; /// Not a directory
+ enum EISDIR = 21; /// Is a directory
+ enum EINVAL = 22; /// Invalid argument
+ enum ENFILE = 23; /// File table overflow
+ enum EMFILE = 24; /// Too many open files
+ enum ENOTTY = 25; /// Not a typewriter
+ enum EFBIG = 27; /// File too large
+ enum ENOSPC = 28; /// No space left on device
+ enum ESPIPE = 29; /// Illegal seek
+ enum EROFS = 30; /// Read-only file system
+ enum EMLINK = 31; /// Too many links
+ enum EPIPE = 32; /// Broken pipe
+ enum EDOM = 33; /// Math argument out of domain of func
+ enum ERANGE = 34; /// Math result not representable
+ enum EDEADLK = 36; /// Resource deadlock would occur
+ enum ENAMETOOLONG = 38; /// File name too long
+ enum ENOLCK = 39; /// No record locks available
+ enum ENOSYS = 40; /// Function not implemented
+ enum ENOTEMPTY = 41; /// Directory not empty
+ enum EILSEQ = 42; /// Illegal byte sequence
+ enum EDEADLOCK = EDEADLK; /// Resource deadlock would occur
+
+ // POSIX compatibility
+ // See_Also: https://docs.microsoft.com/en-us/cpp/c-runtime-library/errno-constants
+ enum EADDRINUSE = 100;
+ enum EADDRNOTAVAIL = 101;
+ enum EAFNOSUPPORT = 102;
+ enum EALREADY = 103;
+ enum EBADMSG = 104;
+ enum ECANCELED = 105;
+ enum ECONNABORTED = 106;
+ enum ECONNREFUSED = 107;
+ enum ECONNRESET = 108;
+ enum EDESTADDRREQ = 109;
+ enum EHOSTUNREACH = 110;
+ enum EIDRM = 111;
+ enum EINPROGRESS = 112;
+ enum EISCONN = 113;
+ enum ELOOP = 114;
+ enum EMSGSIZE = 115;
+ enum ENETDOWN = 116;
+ enum ENETRESET = 117;
+ enum ENETUNREACH = 118;
+ enum ENOBUFS = 119;
+ enum ENODATA = 120;
+ enum ENOLINK = 121;
+ enum ENOMSG = 122;
+ enum ENOPROTOOPT = 123;
+ enum ENOSR = 124;
+ enum ENOSTR = 125;
+ enum ENOTCONN = 126;
+ enum ENOTRECOVERABLE = 127;
+ enum ENOTSOCK = 128;
+ enum ENOTSUP = 129;
+ enum EOPNOTSUPP = 130;
+ enum EOTHER = 131;
+ enum EOVERFLOW = 132;
+ enum EOWNERDEAD = 133;
+ enum EPROTO = 134;
+ enum EPROTONOSUPPORT = 135;
+ enum EPROTOTYPE = 136;
+ enum ETIME = 137;
+ enum ETIMEDOUT = 138;
+ enum ETXTBSY = 139;
+ enum EWOULDBLOCK = 140;
+}
+else version (CRuntime_Newlib)
+{
+ enum EPERM = 1;
+ enum ENOENT = 2;
+ enum ESRCH = 3;
+ enum EINTR = 4;
+ enum EIO = 5;
+ enum ENXIO = 6;
+ enum E2BIG = 7;
+ enum ENOEXEC = 8;
+ enum EBADF = 9;
+ enum ECHILD = 10;
+ enum EAGAIN = 11;
+ enum ENOMEM = 12;
+ enum EACCES = 13;
+ enum EFAULT = 14;
+ enum EBUSY = 16;
+ enum EEXIST = 17;
+ enum EXDEV = 18;
+ enum ENODEV = 19;
+ enum ENOTDIR = 20;
+ enum EISDIR = 21;
+ enum EINVAL = 22;
+ enum ENFILE = 23;
+ enum EMFILE = 24;
+ enum ENOTTY = 25;
+ enum ETXTBSY = 26;
+ enum EFBIG = 27;
+ enum ENOSPC = 28;
+ enum ESPIPE = 29;
+ enum EROFS = 30;
+ enum EMLINK = 31;
+ enum EPIPE = 32;
+ enum EDOM = 33;
+ enum ERANGE = 34;
+ enum ENOMSG = 35;
+ enum EIDRM = 36;
+ enum EDEADLK = 45;
+ enum ENOLCK = 46;
+ enum ENOSTR = 60;
+ enum ENODATA = 61;
+ enum ETIME = 62;
+ enum ENOSR = 63;
+ enum ENOLINK = 67;
+ enum EPROTO = 71;
+ enum EMULTIHOP = 74;
+ enum EBADMSG = 77;
+ enum EFTYPE = 79;
+ enum ENOSYS = 88;
+ enum ENOTEMPTY = 90;
+ enum ENAMETOOLONG = 91;
+ enum ELOOP = 92;
+ enum EOPNOTSUPP = 95;
+ enum EPFNOSUPPORT = 96;
+ enum ECONNRESET = 104;
+ enum ENOBUFS = 105;
+ enum EAFNOSUPPORT = 106;
+ enum EPROTOTYPE = 107;
+ enum ENOTSOCK = 108;
+ enum ENOPROTOOPT = 109;
+ enum ECONNREFUSED = 111;
+ enum EADDRINUSE = 112;
+ enum ECONNABORTED = 113;
+ enum ENETUNREACH = 114;
+ enum ENETDOWN = 115;
+ enum ETIMEDOUT = 116;
+ enum EHOSTDOWN = 117;
+ enum EHOSTUNREACH = 118;
+ enum EINPROGRESS = 119;
+ enum EALREADY = 120;
+ enum EDESTADDRREQ = 121;
+ enum EMSGSIZE = 122;
+ enum EPROTONOSUPPORT = 123;
+ enum EADDRNOTAVAIL = 125;
+ enum ENETRESET = 126;
+ enum EISCONN = 127;
+ enum ENOTCONN = 128;
+ enum ETOOMANYREFS = 129;
+ enum EDQUOT = 132;
+ enum ESTALE = 133;
+ enum ENOTSUP = 134;
+ enum EILSEQ = 138;
+ enum EOVERFLOW = 139;
+ enum ECANCELED = 140;
+ enum ENOTRECOVERABLE = 141;
+ enum EOWNERDEAD = 142;
+
+ enum EWOULDBLOCK = EAGAIN;
+
+ enum __ELASTERROR = 2000;
+
+ // Linux errno extensions
+ version (Cygwin)
+ {
+ enum ENOTBLK = 15;
+ enum ECHRNG = 37;
+ enum EL2NSYNC = 38;
+ enum EL3HLT = 39;
+ enum EL3RST = 40;
+ enum ELNRNG = 41;
+ enum EUNATCH = 42;
+ enum ENOCSI = 43;
+ enum EL2HLT = 44;
+ enum EBADE = 50;
+ enum EBADR = 51;
+ enum EXFULL = 52;
+ enum ENOANO = 53;
+ enum EBADRQC = 54;
+ enum EBADSLT = 55;
+ enum EDEADLOCK = 56;
+ enum EBFONT = 57;
+ enum ENONET = 64;
+ enum ENOPKG = 65;
+ enum EREMOTE = 66;
+ enum EADV = 68;
+ enum ESRMNT = 69;
+ enum ECOMM = 70;
+ enum ELBIN = 75;
+ enum EDOTDOT = 76;
+ enum ENOTUNIQ = 80;
+ enum EBADFD = 81;
+ enum EREMCHG = 82;
+ enum ELIBACC = 83;
+ enum ELIBBAD = 84;
+ enum ELIBSCN = 85;
+ enum ELIBMAX = 86;
+ enum ELIBEXEC = 87;
+ enum ENMFILE = 89;
+ enum ESHUTDOWN = 110;
+ enum ESOCKTNOSUPPORT = 124;
+ enum EPROCLIM = 130;
+ enum EUSERS = 131;
+ enum ENOMEDIUM = 135;
+ enum ENOSHARE = 136;
+ enum ECASECLASH = 137;
+ enum ESTRPIPE = 143;
+ }
+}
else version (linux)
{
enum EPERM = 1; ///
@@ -448,6 +448,49 @@ else version (CRuntime_Musl)
static assert(false, "Architecture not supported.");
}
}
+else version (CRuntime_Newlib)
+{
+ version (AArch64)
+ {
+ alias fenv_t = ulong;
+ alias fexcept_t = ulong;
+ }
+ else version (RISCV_Any)
+ {
+ alias fenv_t = size_t;
+ alias fexcept_t = size_t;
+ }
+ else version (X86_Any)
+ {
+ struct fenv_t
+ {
+ uint _fpu_cw;
+ uint _fpu_sw;
+ uint _fpu_tagw;
+ uint _fpu_ipoff;
+ uint _fpu_ipsel;
+ uint _fpu_opoff;
+ uint _fpu_opsel;
+ uint _sse_mxcsr;
+ }
+ alias fexcept_t = uint;
+ }
+ else version (SPARC64)
+ {
+ alias fenv_t = ulong;
+ alias fexcept_t = ulong;
+ }
+ else version (SPARC)
+ {
+ alias fenv_t = uint;
+ alias fexcept_t = uint;
+ }
+ else
+ {
+ alias fenv_t = int;
+ alias fexcept_t = int;
+ }
+}
else version (CRuntime_UClibc)
{
version (X86)
@@ -252,6 +252,23 @@ else version (CRuntime_Musl)
///
enum LC_ALL = 6;
}
+else version (CRuntime_Newlib)
+{
+ ///
+ enum LC_ALL = 0;
+ ///
+ enum LC_COLLATE = 1;
+ ///
+ enum LC_CTYPE = 2;
+ ///
+ enum LC_MONETARY = 3;
+ ///
+ enum LC_NUMERIC = 4;
+ ///
+ enum LC_TIME = 5;
+ ///
+ enum LC_MESSAGES = 6;
+}
else version (CRuntime_UClibc)
{
///
@@ -328,6 +328,30 @@ else version (CRuntime_Bionic)
int _size;
}
}
+else version (CRuntime_Newlib)
+{
+ enum
+ {
+ ///
+ BUFSIZ = 1024,
+ ///
+ EOF = -1,
+ ///
+ FOPEN_MAX = 20,
+ ///
+ FILENAME_MAX = 1024,
+ ///
+ TMP_MAX = 26,
+ ///
+ L_tmpnam = 1024
+ }
+
+ struct __sbuf
+ {
+ ubyte* _base;
+ int _size;
+ }
+}
else version (CRuntime_UClibc)
{
enum
@@ -769,6 +793,57 @@ else version (CRuntime_Bionic)
///
alias shared(__sFILE) FILE;
}
+else version (CRuntime_Newlib)
+{
+ import core.sys.posix.sys.types : ssize_t;
+ import core.stdc.wchar_ : mbstate_t;
+
+ ///
+ alias fpos_t = c_long;
+
+ ///
+ struct __sFILE
+ {
+ ubyte* _p;
+ int _r;
+ int _w;
+ short _flags;
+ short _file;
+ __sbuf _bf;
+ int _lbfsize;
+
+ void* _data;
+ void* _cookie;
+
+ ssize_t function(void*, void*, scope char*, size_t) _read;
+ ssize_t function(void*, void*, scope const char*, size_t) _write;
+ fpos_t function(void*, void*, fpos_t, int) _seek;
+ int function(void*, void*) _close;
+
+ __sbuf _ub;
+ ubyte* _up;
+ int _ur;
+
+ ubyte[3] _ubuf;
+ ubyte[1] _nbuf;
+
+ __sbuf _lb;
+
+ int _blksize;
+ int _flags2;
+
+ long _offset;
+ void* _unused;
+
+ void* _lock;
+ mbstate_t _mbstate;
+ }
+
+ ///
+ alias __sFILE _iobuf; // needed for phobos
+ ///
+ alias shared(__sFILE) FILE;
+}
else version (CRuntime_UClibc)
{
import core.stdc.wchar_ : mbstate_t;
@@ -1137,6 +1212,40 @@ else version (CRuntime_Musl)
_IONBF = 2,
}
}
+else version (CRuntime_Newlib)
+{
+ enum
+ {
+ ///
+ _IOFBF = 0,
+ ///
+ _IOLBF = 1,
+ ///
+ _IONBF = 2,
+ }
+
+ private
+ {
+ shared struct _reent
+ {
+ int _errno;
+ __sFILE* _stdin;
+ __sFILE* _stdout;
+ __sFILE* _stderr;
+ }
+ _reent* __getreent();
+ }
+
+ pragma(inline, true)
+ {
+ ///
+ @property auto stdin()() { return __getreent()._stdin; }
+ ///
+ @property auto stdout()() { return __getreent()._stdout; }
+ ///
+ @property auto stderr()() { return __getreent()._stderr; }
+ }
+}
else version (CRuntime_UClibc)
{
enum
@@ -1869,6 +1978,47 @@ else version (CRuntime_Musl)
pragma(printf)
int vsnprintf(scope char* s, size_t n, scope const char* format, va_list arg);
}
+else version (CRuntime_Newlib)
+{
+ // No unsafe pointer manipulation.
+ @trusted
+ {
+ ///
+ void rewind(FILE* stream);
+ ///
+ pure void clearerr(FILE* stream);
+ ///
+ pure int feof(FILE* stream);
+ ///
+ pure int ferror(FILE* stream);
+ ///
+ int fileno(FILE *);
+ }
+
+ ///
+ pragma(printf)
+ int snprintf(scope char* s, size_t n, scope const char* format, scope const ...);
+ ///
+ pragma(printf)
+ int vsnprintf(scope char* s, size_t n, scope const char* format, va_list arg);
+
+ //
+ // Gnu under-the-hood C I/O functions. Uses _iobuf* for the unshared
+ // version of FILE*, usable when the FILE is locked.
+ // See http://gnu.org/software/libc/manual/html_node/I_002fO-on-Streams.html
+ //
+ import core.stdc.wchar_ : wint_t;
+ import core.stdc.stddef : wchar_t;
+
+ ///
+ int fputc_unlocked(int c, _iobuf* stream);
+ ///
+ int fgetc_unlocked(_iobuf* stream);
+ ///
+ wint_t fputwc_unlocked(wchar_t wc, _iobuf* stream);
+ ///
+ wint_t fgetwc_unlocked(_iobuf* stream);
+}
else version (CRuntime_UClibc)
{
// No unsafe pointer manipulation.
@@ -28,6 +28,8 @@ else version (WatchOS)
version (CRuntime_Glibc)
version = AlignedAllocSupported;
+else version (CRuntime_Newlib)
+ version = AlignedAllocSupported;
else {}
extern (C):
@@ -97,6 +99,7 @@ else version (DragonFlyBSD) enum RAND_MAX = 0x7fffffff;
else version (Solaris) enum RAND_MAX = 0x7fff;
else version (CRuntime_Bionic) enum RAND_MAX = 0x7fffffff;
else version (CRuntime_Musl) enum RAND_MAX = 0x7fffffff;
+else version (CRuntime_Newlib) enum RAND_MAX = 0x7fffffff;
else version (CRuntime_UClibc) enum RAND_MAX = 0x7fffffff;
else version (WASI) enum RAND_MAX = 0x7fffffff;
else static assert( false, "Unsupported platform" );
@@ -72,8 +72,15 @@ version (ReturnStrerrorR)
const(char)* strerror_r(int errnum, return scope char* buf, size_t buflen);
}
// This one is
+else version (CRuntime_Newlib)
+{
+ ///
+ pragma(mangle, "__xpg_strerror_r")
+ int strerror_r(int errnum, scope char* buf, size_t buflen);
+}
else
{
+ ///
int strerror_r(int errnum, scope char* buf, size_t buflen);
}
///
@@ -106,6 +106,20 @@ else version (Solaris)
///
alias mbstate_t = __mbstate_t;
}
+else version (CRuntime_Newlib)
+{
+ ///
+ struct mbstate_t
+ {
+ int __count;
+ union ___value
+ {
+ wint_t __wch = 0;
+ char[4] __wchb;
+ }
+ ___value __value;
+ }
+}
else version (CRuntime_UClibc)
{
///
@@ -15,9 +15,6 @@ version (Windows):
// import.
alias HANDLE = void*;
-package template DECLARE_HANDLE(string name, base = HANDLE) {
- mixin ("alias " ~ base.stringof ~ " " ~ name ~ ";");
-}
alias HANDLE* PHANDLE, LPHANDLE;
// helper for aligned structs
@@ -1740,8 +1740,8 @@ enum {
I_CHILDRENCALLBACK = -1
}
-mixin DECLARE_HANDLE!("HTREEITEM");
-mixin DECLARE_HANDLE!("HIMAGELIST");
+alias HTREEITEM = HANDLE;
+alias HIMAGELIST = HANDLE;
version (Win64)
{
@@ -4482,8 +4482,8 @@ static if (_WIN32_IE >= 0x400) {
alias RBHITTESTINFO* LPRBHITTESTINFO;
}
-mixin DECLARE_HANDLE!("HDSA");
-mixin DECLARE_HANDLE!("HDPA");
+alias HDSA = HANDLE;
+alias HDPA = HANDLE;
version (Unicode) {
alias HDITEMW HDITEM;
@@ -15,10 +15,10 @@ pragma(lib, "user32");
import core.sys.windows.basetsd, core.sys.windows.windef, core.sys.windows.winnt;
-mixin DECLARE_HANDLE!("HCONVLIST");
-mixin DECLARE_HANDLE!("HCONV");
-mixin DECLARE_HANDLE!("HSZ");
-mixin DECLARE_HANDLE!("HDDEDATA");
+alias HCONVLIST = HANDLE;
+alias HCONV = HANDLE;
+alias HSZ = HANDLE;
+alias HDDEDATA = HANDLE;
enum : int {
CP_WINANSI = 1004,
@@ -487,10 +487,20 @@ bool dll_process_attach( HINSTANCE hInstance, bool attach_threads,
}, null );
}
-/** same as above, but only usable if druntime is linked statically
+version (Shared) version (DigitalMars) private extern(C) extern __gshared void* __ImageBase;
+
+/** same as above, but checking for shared runtime
*/
+pragma(inline, false) // version (Shared) only set when compiling druntime
bool dll_process_attach( HINSTANCE hInstance, bool attach_threads = true )
{
+ version (Shared) version (DigitalMars)
+ {
+ // cannot declare rt_initSharedModule globally as it then conflicts with the definition in sections_win64.d
+ pragma(mangle, "rt_initSharedModule") extern(C) bool rt_initSharedModule( void* handle );
+ if ( hInstance != &__ImageBase )
+ return rt_initSharedModule( hInstance );
+ }
version (Win64)
{
return dll_process_attach( hInstance, attach_threads,
@@ -506,8 +516,16 @@ bool dll_process_attach( HINSTANCE hInstance, bool attach_threads = true )
/**
* to be called from DllMain with reason DLL_PROCESS_DETACH
*/
+pragma(inline, false) // version (Shared) only set when compiling druntime
void dll_process_detach( HINSTANCE hInstance, bool detach_threads = true )
{
+ version (Shared) version (DigitalMars)
+ {
+ // cannot declare rt_termSharedModule globally as it then conflicts with the definition in sections_win64.d
+ pragma(mangle, "rt_termSharedModule") extern(C) bool rt_termSharedModule( void* handle );
+ if ( hInstance != &__ImageBase )
+ return cast(void) rt_termSharedModule( hInstance );
+ }
// notify core.thread.joinLowLevelThread that the DLL is about to be unloaded
thread_DLLProcessDetaching = true;
@@ -531,6 +549,21 @@ void dll_process_detach( HINSTANCE hInstance, bool detach_threads = true )
Runtime.terminate();
}
+/*****************************
+* Check whether the D runtime is built as a DLL or linked statically
+*
+* Returns:
+* true = DLL, false = static library
+*/
+pragma(inline, false) // version (Shared) only set when compiling druntime
+bool isSharedDRuntime()
+{
+ version (Shared)
+ return true;
+ else
+ return false;
+}
+
/* Make sure that tlsCtorRun is itself a tls variable
*/
static bool tlsCtorRun;
@@ -542,8 +575,15 @@ static ~this() { tlsCtorRun = false; }
* Returns:
* true for success, false for failure
*/
-bool dll_thread_attach( bool attach_thread = true, bool initTls = true )
+pragma(inline, false) // version (Shared) only set when compiling druntime
+bool dll_thread_attach( bool attach_thread = true, bool initTls = true, HINSTANCE hInstance = null )
{
+ version (Shared) version (DigitalMars)
+ {
+ if ( hInstance && hInstance != &__ImageBase )
+ return true;
+ }
+
// if the OS has not prepared TLS for us, don't attach to the thread
// (happened when running under x64 OS)
auto tid = GetCurrentThreadId();
@@ -565,8 +605,15 @@ bool dll_thread_attach( bool attach_thread = true, bool initTls = true )
* Returns:
* true for success, false for failure
*/
-bool dll_thread_detach( bool detach_thread = true, bool exitTls = true )
+pragma(inline, false) // version (Shared) only set when compiling druntime
+bool dll_thread_detach( bool detach_thread = true, bool exitTls = true, HINSTANCE hInstance = null )
{
+ version (Shared) version (DigitalMars)
+ {
+ if ( hInstance && hInstance != &__ImageBase )
+ return true;
+ }
+
// if the OS has not prepared TLS for us, we did not attach to the thread
if ( !GetTlsDataAddress( GetCurrentThreadId() ) )
return false;
@@ -613,10 +660,10 @@ mixin template SimpleDllMain()
return true;
case DLL_THREAD_ATTACH:
- return dll_thread_attach( true, true );
+ return dll_thread_attach( true, true, hInstance );
case DLL_THREAD_DETACH:
- return dll_thread_detach( true, true );
+ return dll_thread_detach( true, true, hInstance );
}
}
}
@@ -19,7 +19,7 @@ version (Windows):
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*/
-import core.sys.windows.basetsd /+: DECLARE_HANDLE, HANDLE+/;
+import core.sys.windows.basetsd /+: HANDLE+/;
import core.sys.windows.windef /+: BOOL, CHAR, DWORD, LPBYTE, LPDWORD+/;
import core.sys.windows.winnt /+: LPCSTR, LPSTR, LPVOID, PVOID, VOID+/;
@@ -47,7 +47,7 @@ enum {
HSE_IO_SEND_HEADERS = 0x00000008
}
-mixin DECLARE_HANDLE!("HCONN");
+alias HCONN = HANDLE;
struct HSE_VERSION_INFO {
DWORD dwExtensionVersion;
@@ -275,7 +275,7 @@ struct IMAGEHLP_DUPLICATE_SYMBOL {
}
alias IMAGEHLP_DUPLICATE_SYMBOL* PIMAGEHLP_DUPLICATE_SYMBOL;
-mixin DECLARE_HANDLE!("DIGEST_HANDLE");
+alias DIGEST_HANDLE = HANDLE;
extern (Windows) {
alias BOOL function(IMAGEHLP_STATUS_REASON, LPSTR, LPSTR, ULONG_PTR, ULONG_PTR)
@@ -14,8 +14,8 @@ version (ANSI) {} else version = Unicode;
import core.sys.windows.basetsd, core.sys.windows.mmsystem, core.sys.windows.windef;
-mixin DECLARE_HANDLE!("HACMDRIVERID");
-mixin DECLARE_HANDLE!("HACMDRIVER");
+alias HACMDRIVERID = HANDLE;
+alias HACMDRIVER = HANDLE;
alias HACMDRIVER* LPHACMDRIVER;
enum size_t
@@ -666,7 +666,7 @@ struct POLICY_DOMAIN_KERBEROS_TICKET_INFO {
}
alias POLICY_DOMAIN_KERBEROS_TICKET_INFO* PPOLICY_DOMAIN_KERBEROS_TICKET_INFO;
-mixin DECLARE_HANDLE!("LSA_HANDLE");
+alias LSA_HANDLE = HANDLE;
alias LSA_HANDLE* PLSA_HANDLE;
struct TRUSTED_DOMAIN_NAME_INFO {
@@ -155,7 +155,7 @@ enum OLEOPT_UPDATE {
// #endif
}
-mixin DECLARE_HANDLE!("HOBJECT");
+alias HOBJECT = HANDLE;
alias LONG_PTR LHSERVER, LHCLIENTDOC, LHSERVERDOC;
struct OLEOBJECTVTBL {
@@ -247,7 +247,7 @@ struct PROPSHEETPAGEW {
alias PROPSHEETPAGEW* LPPROPSHEETPAGEW;
alias const(PROPSHEETPAGEW)* LPCPROPSHEETPAGEW;
-mixin DECLARE_HANDLE!("HPROPSHEETPAGE");
+alias HPROPSHEETPAGE = HANDLE;
struct PROPSHEETHEADERA {
DWORD dwSize = PROPSHEETHEADERA.sizeof;
@@ -160,8 +160,8 @@ struct RPC_IF_ID_VECTOR {
uint Count;
RPC_IF_ID*[1] IfId;
}
-mixin DECLARE_HANDLE!("RPC_AUTH_IDENTITY_HANDLE");
-mixin DECLARE_HANDLE!("RPC_AUTHZ_HANDLE");
+alias RPC_AUTH_IDENTITY_HANDLE = HANDLE;
+alias RPC_AUTHZ_HANDLE = HANDLE;
struct RPC_SECURITY_QOS {
uint Version;
@@ -15,7 +15,7 @@ import core.sys.windows.basetyps;
import core.sys.windows.w32api;
import core.sys.windows.windef;
-mixin DECLARE_HANDLE!("I_RPC_HANDLE");
+alias I_RPC_HANDLE = HANDLE;
alias long RPC_STATUS;
enum RPC_NCA_FLAGS_DEFAULT=0;
@@ -18,7 +18,7 @@ import core.sys.windows.basetyps, core.sys.windows.rpcdcep, core.sys.windows.rpc
core.sys.windows.w32api;
import core.sys.windows.windef; // for HANDLE
-mixin DECLARE_HANDLE!("RPC_NS_HANDLE");
+alias RPC_NS_HANDLE = HANDLE;
enum RPC_C_NS_SYNTAX_DEFAULT=0;
enum RPC_C_NS_SYNTAX_DCE=3;
@@ -858,7 +858,7 @@ enum : DWORD {
alias PVOID HINF;
alias PVOID HDSKSPC;
-mixin DECLARE_HANDLE!("HDEVINFO");
+alias HDEVINFO = HANDLE;
alias PVOID HSPFILEQ;
alias PVOID HSPFILELOG;
@@ -188,7 +188,7 @@ enum SHERB_NOPROGRESSUI = 2;
enum SHERB_NOSOUND = 4;
alias WORD FILEOP_FLAGS, PRINTEROP_FLAGS;
-mixin DECLARE_HANDLE!("HDROP");
+alias HDROP = HANDLE;
//align(2): // 1 in Win32, default in Win64
@@ -120,7 +120,7 @@ enum URLIS
URLIS_HASQUERY
}
-mixin DECLARE_HANDLE!("HUSKEY");
+alias HUSKEY = HANDLE;
alias HUSKEY* PHUSKEY;
extern (Windows)
@@ -106,7 +106,7 @@ struct STRING {
alias STRING* PSTRING;
+/
-mixin DECLARE_HANDLE!("SAM_HANDLE");
+alias SAM_HANDLE = HANDLE;
alias SAM_HANDLE* PSAM_HANDLE;
struct OLD_LARGE_INTEGER {
@@ -678,7 +678,7 @@ extern (Windows) {
void ICCompressorFree(PCOMPVARS pc);
}
-mixin DECLARE_HANDLE!("HDRAWDIB");
+alias HDRAWDIB = HANDLE;
enum {
DDF_0001 = 0x0001,
@@ -74,43 +74,43 @@ alias const(void)* PCVOID, LPCVOID;
alias UINT_PTR WPARAM;
alias LONG_PTR LPARAM, LRESULT;
-mixin DECLARE_HANDLE!("HHOOK");
-mixin DECLARE_HANDLE!("HGLOBAL");
-mixin DECLARE_HANDLE!("HLOCAL");
-mixin DECLARE_HANDLE!("GLOBALHANDLE");
-mixin DECLARE_HANDLE!("LOCALHANDLE");
-mixin DECLARE_HANDLE!("HGDIOBJ");
-mixin DECLARE_HANDLE!("HACCEL");
-mixin DECLARE_HANDLE!("HBITMAP", HGDIOBJ);
-mixin DECLARE_HANDLE!("HBRUSH", HGDIOBJ);
-mixin DECLARE_HANDLE!("HCOLORSPACE");
-mixin DECLARE_HANDLE!("HDC");
-mixin DECLARE_HANDLE!("HGLRC");
-mixin DECLARE_HANDLE!("HDESK");
-mixin DECLARE_HANDLE!("HENHMETAFILE");
-mixin DECLARE_HANDLE!("HFONT", HGDIOBJ);
-mixin DECLARE_HANDLE!("HICON");
-mixin DECLARE_HANDLE!("HINSTANCE");
-mixin DECLARE_HANDLE!("HKEY");
-mixin DECLARE_HANDLE!("HMENU");
-mixin DECLARE_HANDLE!("HMETAFILE");
-mixin DECLARE_HANDLE!("HMODULE");
-mixin DECLARE_HANDLE!("HMONITOR");
-mixin DECLARE_HANDLE!("HPALETTE");
-mixin DECLARE_HANDLE!("HPEN", HGDIOBJ);
-mixin DECLARE_HANDLE!("HRGN", HGDIOBJ);
-mixin DECLARE_HANDLE!("HRSRC");
-mixin DECLARE_HANDLE!("HSTR");
-mixin DECLARE_HANDLE!("HTASK");
-mixin DECLARE_HANDLE!("HWND");
-mixin DECLARE_HANDLE!("HWINSTA");
-mixin DECLARE_HANDLE!("HKL");
-mixin DECLARE_HANDLE!("HCURSOR");
+alias HHOOK = HANDLE;
+alias HGLOBAL = HANDLE;
+alias HLOCAL = HANDLE;
+alias GLOBALHANDLE = HANDLE;
+alias LOCALHANDLE = HANDLE;
+alias HGDIOBJ = HANDLE;
+alias HACCEL = HANDLE;
+alias HBITMAP = HGDIOBJ;
+alias HBRUSH = HGDIOBJ;
+alias HCOLORSPACE = HANDLE;
+alias HDC = HANDLE;
+alias HGLRC = HANDLE;
+alias HDESK = HANDLE;
+alias HENHMETAFILE = HANDLE;
+alias HFONT = HGDIOBJ;
+alias HICON = HANDLE;
+alias HINSTANCE = HANDLE;
+alias HKEY = HANDLE;
+alias HMENU = HANDLE;
+alias HMETAFILE = HANDLE;
+alias HMODULE = HANDLE;
+alias HMONITOR = HANDLE;
+alias HPALETTE = HANDLE;
+alias HPEN = HGDIOBJ;
+alias HRGN = HGDIOBJ;
+alias HRSRC = HANDLE;
+alias HSTR = HANDLE;
+alias HTASK = HANDLE;
+alias HWND = HANDLE;
+alias HWINSTA = HANDLE;
+alias HKL = HANDLE;
+alias HCURSOR = HANDLE;
alias HKEY* PHKEY;
static if (_WIN32_WINNT >= 0x500) {
- mixin DECLARE_HANDLE!("HTERMINAL");
- mixin DECLARE_HANDLE!("HWINEVENTHOOK");
+ alias HTERMINAL = HANDLE;
+ alias HWINEVENTHOOK = HANDLE;
}
alias extern (Windows) INT_PTR function() nothrow FARPROC, NEARPROC, PROC;
@@ -740,7 +740,8 @@ enum {
INTERNET_CACHE_GROUP_REMOVE = 1
}
-mixin DECLARE_HANDLE!("HINTERNET"); // doesn't work - bug
+alias HINTERNET = HANDLE;
+// mixin DECLARE_HANDLE!("HINTERNET"); // doesn't work - bug
/*struct HINTERNET {
HANDLE h;
alias h this;
@@ -184,10 +184,10 @@ struct SERVICE_TABLE_ENTRYW {
}
alias SERVICE_TABLE_ENTRYW* LPSERVICE_TABLE_ENTRYW;
-mixin DECLARE_HANDLE!("SC_HANDLE");
+alias SC_HANDLE = HANDLE;
alias SC_HANDLE* LPSC_HANDLE;
alias void* SC_LOCK;
-mixin DECLARE_HANDLE!("SERVICE_STATUS_HANDLE");
+alias SERVICE_STATUS_HANDLE = HANDLE;
extern (Windows) {
alias void function(DWORD) LPHANDLER_FUNCTION;
@@ -2495,8 +2495,8 @@ extern (Windows) nothrow {
alias NAMEENUMPROCW WINSTAENUMPROCW;
}
-mixin DECLARE_HANDLE!("HDWP");
-mixin DECLARE_HANDLE!("HDEVNOTIFY");
+alias HDWP = HANDLE;
+alias HDEVNOTIFY = HANDLE;
struct MENUGETOBJECTINFO {
DWORD dwFlags;
@@ -96,8 +96,8 @@ alias OLECHAR* BSTR;
alias FLAGGED_WORD_BLOB* wireBSTR;
alias BSTR* LPBSTR;
//alias LONG SCODE; // also in winerror
-mixin DECLARE_HANDLE!("HCONTEXT");
-mixin DECLARE_HANDLE!("HMETAFILEPICT");
+alias HCONTEXT = HANDLE;
+alias HMETAFILEPICT = HANDLE;
union CY {
struct {
@@ -1646,10 +1646,10 @@ class TypeInfo_Class : TypeInfo
string name; /// class name
void*[] vtbl; /// virtual function pointer table
Interface[] interfaces; /// interfaces this class implements
- TypeInfo_Class base; /// base class
+ TypeInfo_Class base; /// base class
void* destructor;
void function(Object) classInvariant;
- enum ClassFlags : uint
+ enum ClassFlags : ushort
{
isCOMclass = 0x1,
noPointers = 0x2,
@@ -1660,11 +1660,14 @@ class TypeInfo_Class : TypeInfo
isAbstract = 0x40,
isCPPclass = 0x80,
hasDtor = 0x100,
+ hasNameSig = 0x200,
}
ClassFlags m_flags;
- void* deallocator;
+ ushort depth; /// inheritance distance from Object
+ void* deallocator;
OffsetTypeInfo[] m_offTi;
void function(Object) defaultConstructor; // default Constructor
+ ulong[2] nameSig; /// unique signature for `name`
immutable(void)* m_RTInfo; // data for precise GC
override @property immutable(void)* rtInfo() const { return m_RTInfo; }
@@ -23,10 +23,12 @@ pure:
// but we are trying to implement dynamic cast.
extern (D) private bool areClassInfosEqual(scope const ClassInfo a, scope const ClassInfo b) @safe
{
- if (a is b)
- return true;
- // take care of potential duplicates across binaries
- return a.name == b.name;
+ // same class if signatures match, works with potential duplicates across binaries
+ return a is b ||
+ (a.m_flags & TypeInfo_Class.ClassFlags.hasNameSig
+ ? (a.nameSig[0] == b.nameSig[0] &&
+ a.nameSig[1] == b.nameSig[1]) // new fast way
+ : (a is b || a.name == b.name)); // old slow way for temporary binary compatibility
}
/******************************************
@@ -58,7 +60,7 @@ Object _d_toObject(return scope void* p)
}
/*************************************
- * Attempts to cast Object o to class c.
+ * Attempts to cast interface Object o to class c.
* Returns o if successful, null if not.
*/
void* _d_interface_cast(void* p, ClassInfo c)
@@ -70,9 +72,26 @@ void* _d_interface_cast(void* p, ClassInfo c)
Interface* pi = **cast(Interface***) p;
debug(cast_) printf("\tpi.offset = %d\n", pi.offset);
- return _d_dynamic_cast(cast(Object)(p - pi.offset), c);
+ Object o2 = cast(Object)(p - pi.offset);
+ void* res = null;
+ size_t offset = 0;
+ if (o2 && _d_isbaseof2(typeid(o2), c, offset))
+ {
+ debug(cast_) printf("\toffset = %d\n", offset);
+ res = cast(void*) o2 + offset;
+ }
+ debug(cast_) printf("\tresult = %p\n", res);
+ return res;
}
+/*****
+ * Dynamic cast from a class object `o` to class or interface `c`, where `c` is a subtype of `o`.
+ * Params:
+ * o = instance of class
+ * c = a subclass of o
+ * Returns:
+ * null if o is null or c is not a subclass of o. Otherwise, return o.
+ */
void* _d_dynamic_cast(Object o, ClassInfo c)
{
debug(cast_) printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name);
@@ -88,6 +107,64 @@ void* _d_dynamic_cast(Object o, ClassInfo c)
return res;
}
+/*****
+ * Dynamic cast from a class object o to class c, where c is a subclass of o.
+ * Params:
+ * o = instance of class
+ * c = a subclass of o
+ * Returns:
+ * null if o is null or c is not a subclass of o. Otherwise, return o.
+ */
+void* _d_class_cast(Object o, ClassInfo c)
+{
+ debug(cast_) printf("_d_cast_cast(o = %p, c = '%.*s', level %d)\n", o, c.name, level);
+
+ if (!o)
+ return null;
+
+ ClassInfo oc = typeid(o);
+ int delta = oc.depth;
+
+ if (delta && c.depth)
+ {
+ delta -= c.depth;
+ if (delta < 0)
+ return null;
+
+ while (delta--)
+ oc = oc.base;
+ if (areClassInfosEqual(oc, c))
+ return cast(void*)o;
+ return null;
+ }
+
+ // no depth data - support the old way
+ do
+ {
+ if (areClassInfosEqual(oc, c))
+ return cast(void*)o;
+ oc = oc.base;
+ } while (oc);
+ return null;
+}
+
+/**
+ * Dynamic cast `o` to final class `c` only one level down
+ * Params:
+ * o = object that is instance of a class
+ * c = class to cast it to
+ * Returns:
+ * o if it succeeds, null if it fails
+ */
+void* _d_paint_cast(Object o, ClassInfo c)
+{
+ /* If o is really an instance of c, just do a paint
+ */
+ auto p = (o && cast(void*)(areClassInfosEqual(typeid(o), c)) ? o : null);
+ debug assert(cast(void*)p is cast(void*)_d_dynamic_cast(o, c));
+ return cast(void*)p;
+}
+
int _d_isbaseof2(scope ClassInfo oc, scope const ClassInfo c, scope ref size_t offset) @safe
{
if (areClassInfosEqual(oc, c))
@@ -496,6 +496,13 @@ private extern (C) int _d_run_main2(char[][] args, size_t totalArgsLength, MainF
{
if (rt_init())
{
+ version(Shared) version(CRuntime_Microsoft) version (DigitalMars)
+ {
+ auto exeHandle = handleForAddr(mainFunc);
+ if (exeHandle)
+ if (!rt_initSharedModule(exeHandle))
+ exeHandle = null;
+ }
auto utResult = runModuleUnitTests();
assert(utResult.passed <= utResult.executed);
if (utResult.passed == utResult.executed)
@@ -521,6 +528,11 @@ private extern (C) int _d_run_main2(char[][] args, size_t totalArgsLength, MainF
cast(int)utResult.executed);
result = EXIT_FAILURE;
}
+ version(Shared) version(CRuntime_Microsoft) version (DigitalMars)
+ {
+ if (exeHandle)
+ rt_termSharedModule(exeHandle);
+ }
}
else
result = EXIT_FAILURE;
@@ -1,4 +1,4 @@
-7a6e9568862f5a0d9eb34707d85dcf7ff889c26f
+e4d0dd5136be3c539a02cc2f1618cb989a685837
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
@@ -279,10 +279,8 @@ See_Also: $(REF BitFlags, std,typecons)
*/
string bitfields(T...)()
{
- import std.conv : to;
-
static assert(T.length % 3 == 0,
- "Wrong number of arguments (" ~ to!string(T.length) ~ "): Must be a multiple of 3");
+ "Wrong number of arguments (" ~ T.length.stringof ~ "): Must be a multiple of 3");
static foreach (i, ARG; T)
{
@@ -1892,7 +1892,7 @@ Complex!T pow(T)(const T x, Complex!T n) @trusted pure nothrow @nogc
@safe pure nothrow @nogc unittest
{
import std.meta : AliasSeq;
- import std.math : RealFormat, floatTraits;
+ import std.math.traits : floatTraits, RealFormat;
static foreach (T; AliasSeq!(float, double, real))
{{
static if (floatTraits!T.realFormat == RealFormat.ibmExtended)
@@ -1804,7 +1804,7 @@ if (!is(S : T) && isAssociativeArray!S &&
}
static void testFloatingToIntegral(Floating, Integral)()
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
bool convFails(Source, Target, E)(Source src)
{
@@ -3430,7 +3430,7 @@ if (isFloatingPoint!Target && !is(Target == enum) &&
Target result = cast(Target) (sign ? -ldval : ldval);
// if overflow occurred
- import std.math : isFinite;
+ import std.math.traits : isFinite;
enforce(isFinite(result), new ConvException("Range error"));
advanceSource();
@@ -3598,7 +3598,7 @@ if (isFloatingPoint!Target && !is(Target == enum) &&
@system unittest
{
// @system because strtod is not @safe.
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
static if (floatTraits!real.realFormat == RealFormat.ieeeDouble)
{
@@ -3682,7 +3682,7 @@ if (isFloatingPoint!Target && !is(Target == enum) &&
{
import core.stdc.errno;
import core.stdc.stdlib;
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
errno = 0; // In case it was set by another unittest in a different module.
struct longdouble
@@ -1632,6 +1632,9 @@ class ErrnoException : Exception
/// Operating system error code.
final @property uint errno() nothrow pure scope @nogc @safe { return _errno; }
private uint _errno;
+ /// Localized error message generated through $(REF strerror_r, core,stdc,string) or $(REF strerror, core,stdc,string).
+ final @property string errnoMsg() nothrow pure scope @nogc @safe { return _errnoMsg; }
+ private string _errnoMsg;
/// Constructor which takes an error message. The current global $(REF errno, core,stdc,errno) value is used as error code.
this(string msg, string file = null, size_t line = 0) @safe
{
@@ -1642,7 +1645,8 @@ class ErrnoException : Exception
this(string msg, int errno, string file = null, size_t line = 0) @safe
{
_errno = errno;
- super(msg ~ " (" ~ errnoString(errno) ~ ")", file, line);
+ _errnoMsg = errnoString(errno);
+ super(msg ~ " (" ~ errnoMsg ~ ")", file, line);
}
}
@@ -28,6 +28,15 @@ if (is(T == float) || is(T == double)
return w.data;
}
+/// Returns: whether `c` is a supported format specifier for floats
+package(std.format) bool isFloatSpec(char c) nothrow @nogc pure @safe
+{
+ return c == 'a' || c == 'A'
+ || c == 'e' || c == 'E'
+ || c == 'f' || c == 'F'
+ || c == 'g' || c == 'G';
+}
+
package(std.format) void printFloat(Writer, T, Char)(auto ref Writer w, const(T) val, FormatSpec!Char f)
if (is(T == float) || is(T == double)
|| (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
@@ -43,10 +52,7 @@ if (is(T == float) || is(T == double)
if (sgn == "" && f.flPlus) sgn = "+";
if (sgn == "" && f.flSpace) sgn = " ";
- assert(f.spec == 'a' || f.spec == 'A'
- || f.spec == 'e' || f.spec == 'E'
- || f.spec == 'f' || f.spec == 'F'
- || f.spec == 'g' || f.spec == 'G', "unsupported format specifier");
+ assert(isFloatSpec(f.spec), "unsupported format specifier");
bool is_upper = f.spec == 'A' || f.spec == 'E' || f.spec=='F' || f.spec=='G';
// special treatment for nan and inf
@@ -570,9 +570,9 @@ void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj,
scope const ref FormatSpec!Char f)
if (is(FloatingPointTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
{
- import std.algorithm.searching : find;
import std.format : enforceFmt;
import std.range.primitives : put;
+ import std.format.internal.floats : printFloat, isFloatSpec;
FloatingPointTypeOf!T val = obj;
const char spec = f.spec;
@@ -597,11 +597,9 @@ if (is(FloatingPointTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
return;
}
- enforceFmt(find("fgFGaAeEs", spec).length,
- "incompatible format character for floating point argument: %" ~ spec);
-
FormatSpec!Char fs = f; // fs is copy for change its values.
fs.spec = spec == 's' ? 'g' : spec;
+ enforceFmt(isFloatSpec(fs.spec), "incompatible format character for floating point argument: %" ~ spec);
static if (is(T == float) || is(T == double)
|| (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
@@ -631,7 +629,6 @@ if (is(FloatingPointTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
tval = -doubleLowest;
}
- import std.format.internal.floats : printFloat;
printFloat(w, tval, fs);
}
@@ -308,7 +308,7 @@ if (isFloatingPoint!T)
// If both are huge, avoid overflow by scaling by 2^^-N.
// If both are tiny, avoid underflow by scaling by 2^^N.
import core.math : fabs, sqrt;
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
alias F = floatTraits!T;
@@ -1002,8 +1002,7 @@ float exp(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) exp(ca
private T expImpl(T)(T x) @safe pure nothrow @nogc
{
- import std.math : floatTraits, RealFormat;
- import std.math.traits : isNaN;
+ import std.math.traits : floatTraits, RealFormat, isNaN;
import std.math.rounding : floor;
import std.math.algebraic : poly;
import std.math.constants : LOG2E;
@@ -1143,7 +1142,7 @@ private T expImpl(T)(T x) @safe pure nothrow @nogc
@safe @nogc nothrow unittest
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
import std.math.operations : NaN, feqrel, isClose;
import std.math.constants : E;
import std.math.traits : isIdentical;
@@ -1517,7 +1516,7 @@ L_largenegative:
private T expm1Impl(T)(T x) @safe pure nothrow @nogc
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
import std.math.rounding : floor;
import std.math.algebraic : poly;
import std.math.constants : LN2;
@@ -1909,8 +1908,7 @@ L_was_nan:
private T exp2Impl(T)(T x) @nogc @safe pure nothrow
{
- import std.math : floatTraits, RealFormat;
- import std.math.traits : isNaN;
+ import std.math.traits : floatTraits, RealFormat, isNaN;
import std.math.rounding : floor;
import std.math.algebraic : poly;
@@ -2098,8 +2096,7 @@ private T exp2Impl(T)(T x) @nogc @safe pure nothrow
T frexp(T)(const T value, out int exp) @trusted pure nothrow @nogc
if (isFloatingPoint!T)
{
- import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
- import std.math.traits : isSubnormal;
+ import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB, isSubnormal;
if (__ctfe)
{
@@ -2353,8 +2350,7 @@ if (isFloatingPoint!T)
@safe unittest
{
- import std.math : floatTraits, RealFormat;
- import std.math.traits : isIdentical;
+ import std.math.traits : floatTraits, RealFormat, isIdentical;
import std.meta : AliasSeq;
import std.typecons : tuple, Tuple;
@@ -2486,7 +2482,7 @@ if (isFloatingPoint!T)
int ilogb(T)(const T x) @trusted pure nothrow @nogc
if (isFloatingPoint!T)
{
- import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
+ import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
import core.bitop : bsr;
alias F = floatTraits!T;
@@ -2681,7 +2677,7 @@ alias FP_ILOGBNAN = core.stdc.math.FP_ILOGBNAN;
@safe nothrow @nogc unittest
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
import std.math.operations : nextUp;
import std.meta : AliasSeq;
import std.typecons : Tuple;
@@ -2778,7 +2774,7 @@ float ldexp(float n, int exp) @safe pure nothrow @nogc { return core.math.ldex
@safe pure nothrow @nogc unittest
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended ||
floatTraits!(real).realFormat == RealFormat.ieeeExtended53 ||
@@ -2866,7 +2862,7 @@ private
// Coefficients shared across log(), log2(), log10(), log1p().
template LogCoeffs(T)
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
static if (floatTraits!T.realFormat == RealFormat.ieeeQuadruple)
{
@@ -3179,8 +3175,7 @@ private T logImpl(T, bool LOG1P = false)(T x) @safe pure nothrow @nogc
{
import std.math.constants : SQRT1_2;
import std.math.algebraic : poly;
- import std.math.traits : isInfinity, isNaN, signbit;
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : isInfinity, isNaN, signbit, floatTraits, RealFormat;
alias coeffs = LogCoeffs!T;
alias F = floatTraits!T;
@@ -3306,7 +3301,7 @@ private T logImpl(T, bool LOG1P = false)(T x) @safe pure nothrow @nogc
@safe @nogc nothrow unittest
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
import std.meta : AliasSeq;
static void testLog(T)(T[2][] vals)
@@ -3452,8 +3447,7 @@ private T log10Impl(T)(T x) @safe pure nothrow @nogc
{
import std.math.constants : SQRT1_2;
import std.math.algebraic : poly;
- import std.math.traits : isNaN, isInfinity, signbit;
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : isNaN, isInfinity, signbit, floatTraits, RealFormat;
alias coeffs = LogCoeffs!T;
alias F = floatTraits!T;
@@ -3558,7 +3552,7 @@ Ldone:
@safe @nogc nothrow unittest
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
import std.meta : AliasSeq;
static void testLog10(T)(T[2][] vals)
@@ -3710,7 +3704,7 @@ private T log1pImpl(T)(T x) @safe pure nothrow @nogc
import std.math.traits : isNaN, isInfinity, signbit;
import std.math.algebraic : poly;
import std.math.constants : SQRT1_2, SQRT2;
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
// Special cases.
if (isNaN(x) || x == 0.0)
@@ -3746,7 +3740,7 @@ private T log1pImpl(T)(T x) @safe pure nothrow @nogc
@safe @nogc nothrow unittest
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
import std.meta : AliasSeq;
static void testLog1p(T)(T[2][] vals)
@@ -3891,7 +3885,7 @@ private T log2Impl(T)(T x) @safe pure nothrow @nogc
import std.math.traits : isNaN, isInfinity, signbit;
import std.math.constants : SQRT1_2, LOG2E;
import std.math.algebraic : poly;
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
alias coeffs = LogCoeffs!T;
alias F = floatTraits!T;
@@ -3972,7 +3966,7 @@ Ldone:
@safe @nogc nothrow unittest
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
import std.meta : AliasSeq;
static void testLog2(T)(T[2][] vals)
@@ -4172,7 +4166,7 @@ private T logbImpl(T)(T x) @trusted pure nothrow @nogc
@safe @nogc nothrow unittest
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
import std.meta : AliasSeq;
static void testLogb(T)(T[2][] vals)
@@ -210,14 +210,12 @@ private:
}
else version (RISCV_Any)
{
- mixin(`
uint result = void;
asm pure nothrow @nogc
{
"frflags %0" : "=r" (result);
}
return result;
- `);
}
else version (LoongArch_Any)
{
@@ -307,13 +305,11 @@ private:
}
else version (RISCV_Any)
{
- mixin(`
uint newValues = 0x0;
asm pure nothrow @nogc
{
"fsflags %0" : : "r" (newValues);
}
- `);
}
else version (LoongArch_Any)
{
@@ -1039,14 +1035,12 @@ private:
}
else version (RISCV_Any)
{
- mixin(`
ControlState cont;
asm pure nothrow @nogc
{
"frcsr %0" : "=r" (cont);
}
return cont;
- `);
}
else version (LoongArch_Any)
{
@@ -1163,12 +1157,10 @@ private:
}
else version (RISCV_Any)
{
- mixin(`
asm pure nothrow @nogc
{
"fscsr %0" : : "r" (newState);
}
- `);
}
else version (LoongArch_Any)
{
@@ -44,7 +44,7 @@ import std.traits : CommonType, isFloatingPoint, isIntegral, Unqual;
*/
real NaN(ulong payload) @trusted pure nothrow @nogc
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
alias F = floatTraits!(real);
static if (F.realFormat == RealFormat.ieeeExtended ||
@@ -136,7 +136,7 @@ real NaN(ulong payload) @trusted pure nothrow @nogc
@system pure nothrow @nogc unittest // not @safe because taking address of local.
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble)
{
@@ -159,7 +159,7 @@ real NaN(ulong payload) @trusted pure nothrow @nogc
*/
ulong getNaNPayload(real x) @trusted pure nothrow @nogc
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
// assert(isNaN(x));
alias F = floatTraits!(real);
@@ -283,7 +283,7 @@ debug(UnitTest)
*/
real nextUp(real x) @trusted pure nothrow @nogc
{
- import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
+ import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
alias F = floatTraits!(real);
static if (F.realFormat != RealFormat.ieeeDouble)
@@ -522,8 +522,7 @@ float nextDown(float x) @safe pure nothrow @nogc
@safe pure nothrow @nogc unittest
{
- import std.math : floatTraits, RealFormat;
- import std.math.traits : isIdentical;
+ import std.math.traits : floatTraits, RealFormat, isIdentical;
static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended ||
floatTraits!(real).realFormat == RealFormat.ieeeDouble ||
@@ -865,7 +864,7 @@ real fma(real x, real y, real z) @safe pure nothrow @nogc { return (x * y) + z;
int feqrel(X)(const X x, const X y) @trusted pure nothrow @nogc
if (isFloatingPoint!(X))
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
import core.math : fabs;
/* Public Domain. Author: Don Clugston, 18 Aug 2005.
@@ -1495,7 +1494,7 @@ private template FloatingPointBaseType(T)
int cmp(T)(const(T) x, const(T) y) @nogc @trusted pure nothrow
if (isFloatingPoint!T)
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
alias F = floatTraits!T;
@@ -1723,7 +1722,7 @@ if (isFloatingPoint!T)
FloatingPointBitpattern!T extractBitpattern(T)(const(T) value) @trusted
if (isFloatingPoint!T)
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
T val = value;
FloatingPointBitpattern!T ret;
@@ -1895,7 +1894,7 @@ if (isFloatingPoint!T)
@safe pure unittest
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
alias F = floatTraits!real;
static if (F.realFormat == RealFormat.ieeeExtended)
@@ -1946,7 +1945,7 @@ if (isFloatingPoint!T)
@safe pure unittest
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
import std.math.exponential : log2;
alias F = floatTraits!real;
@@ -321,169 +321,3 @@ else
static assert(real.mant_dig == 53 || real.mant_dig == 113,
"Only 64-bit and 128-bit reals are supported for BigEndian CPUs.");
}
-
-// Underlying format exposed through floatTraits
-enum RealFormat
-{
- ieeeHalf,
- ieeeSingle,
- ieeeDouble,
- ieeeExtended, // x87 80-bit real
- ieeeExtended53, // x87 real rounded to precision of double.
- ibmExtended, // IBM 128-bit extended
- ieeeQuadruple,
-}
-
-// Constants used for extracting the components of the representation.
-// They supplement the built-in floating point properties.
-template floatTraits(T)
-{
- import std.traits : Unqual;
-
- // EXPMASK is a ushort mask to select the exponent portion (without sign)
- // EXPSHIFT is the number of bits the exponent is left-shifted by in its ushort
- // EXPBIAS is the exponent bias - 1 (exp == EXPBIAS yields ×2^-1).
- // EXPPOS_SHORT is the index of the exponent when represented as a ushort array.
- // SIGNPOS_BYTE is the index of the sign when represented as a ubyte array.
- // RECIP_EPSILON is the value such that (smallest_subnormal) * RECIP_EPSILON == T.min_normal
- enum Unqual!T RECIP_EPSILON = (1/T.epsilon);
- static if (T.mant_dig == 24)
- {
- // Single precision float
- enum ushort EXPMASK = 0x7F80;
- enum ushort EXPSHIFT = 7;
- enum ushort EXPBIAS = 0x3F00;
- enum uint EXPMASK_INT = 0x7F80_0000;
- enum uint MANTISSAMASK_INT = 0x007F_FFFF;
- enum realFormat = RealFormat.ieeeSingle;
- version (LittleEndian)
- {
- enum EXPPOS_SHORT = 1;
- enum SIGNPOS_BYTE = 3;
- }
- else
- {
- enum EXPPOS_SHORT = 0;
- enum SIGNPOS_BYTE = 0;
- }
- }
- else static if (T.mant_dig == 53)
- {
- static if (T.sizeof == 8)
- {
- // Double precision float, or real == double
- enum ushort EXPMASK = 0x7FF0;
- enum ushort EXPSHIFT = 4;
- enum ushort EXPBIAS = 0x3FE0;
- enum uint EXPMASK_INT = 0x7FF0_0000;
- enum uint MANTISSAMASK_INT = 0x000F_FFFF; // for the MSB only
- enum ulong MANTISSAMASK_LONG = 0x000F_FFFF_FFFF_FFFF;
- enum realFormat = RealFormat.ieeeDouble;
- version (LittleEndian)
- {
- enum EXPPOS_SHORT = 3;
- enum SIGNPOS_BYTE = 7;
- }
- else
- {
- enum EXPPOS_SHORT = 0;
- enum SIGNPOS_BYTE = 0;
- }
- }
- else static if (T.sizeof == 12)
- {
- // Intel extended real80 rounded to double
- enum ushort EXPMASK = 0x7FFF;
- enum ushort EXPSHIFT = 0;
- enum ushort EXPBIAS = 0x3FFE;
- enum realFormat = RealFormat.ieeeExtended53;
- version (LittleEndian)
- {
- enum EXPPOS_SHORT = 4;
- enum SIGNPOS_BYTE = 9;
- }
- else
- {
- enum EXPPOS_SHORT = 0;
- enum SIGNPOS_BYTE = 0;
- }
- }
- else
- static assert(false, "No traits support for " ~ T.stringof);
- }
- else static if (T.mant_dig == 64)
- {
- // Intel extended real80
- enum ushort EXPMASK = 0x7FFF;
- enum ushort EXPSHIFT = 0;
- enum ushort EXPBIAS = 0x3FFE;
- enum realFormat = RealFormat.ieeeExtended;
- version (LittleEndian)
- {
- enum EXPPOS_SHORT = 4;
- enum SIGNPOS_BYTE = 9;
- }
- else
- {
- enum EXPPOS_SHORT = 0;
- enum SIGNPOS_BYTE = 0;
- }
- }
- else static if (T.mant_dig == 113)
- {
- // Quadruple precision float
- enum ushort EXPMASK = 0x7FFF;
- enum ushort EXPSHIFT = 0;
- enum ushort EXPBIAS = 0x3FFE;
- enum realFormat = RealFormat.ieeeQuadruple;
- version (LittleEndian)
- {
- enum EXPPOS_SHORT = 7;
- enum SIGNPOS_BYTE = 15;
- }
- else
- {
- enum EXPPOS_SHORT = 0;
- enum SIGNPOS_BYTE = 0;
- }
- }
- else static if (T.mant_dig == 106)
- {
- // IBM Extended doubledouble
- enum ushort EXPMASK = 0x7FF0;
- enum ushort EXPSHIFT = 4;
- enum realFormat = RealFormat.ibmExtended;
-
- // For IBM doubledouble the larger magnitude double comes first.
- // It's really a double[2] and arrays don't index differently
- // between little and big-endian targets.
- enum DOUBLEPAIR_MSB = 0;
- enum DOUBLEPAIR_LSB = 1;
-
- // The exponent/sign byte is for most significant part.
- version (LittleEndian)
- {
- enum EXPPOS_SHORT = 3;
- enum SIGNPOS_BYTE = 7;
- }
- else
- {
- enum EXPPOS_SHORT = 0;
- enum SIGNPOS_BYTE = 0;
- }
- }
- else
- static assert(false, "No traits support for " ~ T.stringof);
-}
-
-// These apply to all floating-point types
-version (LittleEndian)
-{
- enum MANTISSA_LSB = 0;
- enum MANTISSA_MSB = 1;
-}
-else
-{
- enum MANTISSA_LSB = 1;
- enum MANTISSA_MSB = 0;
-}
@@ -551,7 +551,7 @@ long lrint(real x) @trusted pure nothrow @nogc
}
else
{
- import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
+ import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
alias F = floatTraits!(real);
static if (F.realFormat == RealFormat.ieeeDouble)
@@ -896,7 +896,7 @@ long rndtol(float x) @safe pure nothrow @nogc { return rndtol(cast(real) x); }
// Helper for floor/ceil
T floorImpl(T)(const T x) @trusted pure nothrow @nogc
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
alias F = floatTraits!(T);
// Take care not to trigger library calls from the compiler,
@@ -137,7 +137,7 @@ if (isFloatingPoint!(X))
*/
bool isFinite(X)(X x) @trusted pure nothrow @nogc
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
static if (__traits(isFloating, X))
if (__ctfe)
@@ -202,7 +202,7 @@ bool isFinite(X)(X x) @trusted pure nothrow @nogc
*/
bool isNormal(X)(X x) @trusted pure nothrow @nogc
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
static if (__traits(isFloating, X))
if (__ctfe)
@@ -264,7 +264,7 @@ bool isNormal(X)(X x) @trusted pure nothrow @nogc
*/
bool isSubnormal(X)(X x) @trusted pure nothrow @nogc
{
- import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
+ import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
static if (__traits(isFloating, X))
if (__ctfe)
@@ -344,7 +344,7 @@ bool isSubnormal(X)(X x) @trusted pure nothrow @nogc
bool isInfinity(X)(X x) @nogc @trusted pure nothrow
if (isFloatingPoint!(X))
{
- import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
+ import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
alias F = floatTraits!(X);
static if (F.realFormat == RealFormat.ieeeSingle)
@@ -466,7 +466,7 @@ if (isFloatingPoint!(X))
*/
bool isIdentical(real x, real y) @trusted pure nothrow @nogc
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
// We're doing a bitwise comparison so the endianness is irrelevant.
long* pxs = cast(long *)&x;
@@ -510,7 +510,7 @@ bool isIdentical(real x, real y) @trusted pure nothrow @nogc
*/
int signbit(X)(X x) @nogc @trusted pure nothrow
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
if (__ctfe)
{
@@ -594,7 +594,7 @@ Returns:
R copysign(R, X)(R to, X from) @trusted pure nothrow @nogc
if (isFloatingPoint!(R) && isFloatingPoint!(X))
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
if (__ctfe)
{
@@ -851,3 +851,168 @@ if (isNumeric!X)
}}
}
+// Underlying format exposed through floatTraits
+enum RealFormat
+{
+ ieeeHalf,
+ ieeeSingle,
+ ieeeDouble,
+ ieeeExtended, // x87 80-bit real
+ ieeeExtended53, // x87 real rounded to precision of double.
+ ibmExtended, // IBM 128-bit extended
+ ieeeQuadruple,
+}
+
+// Constants used for extracting the components of the representation.
+// They supplement the built-in floating point properties.
+template floatTraits(T)
+{
+ import std.traits : Unqual;
+
+ // EXPMASK is a ushort mask to select the exponent portion (without sign)
+ // EXPSHIFT is the number of bits the exponent is left-shifted by in its ushort
+ // EXPBIAS is the exponent bias - 1 (exp == EXPBIAS yields ×2^-1).
+ // EXPPOS_SHORT is the index of the exponent when represented as a ushort array.
+ // SIGNPOS_BYTE is the index of the sign when represented as a ubyte array.
+ // RECIP_EPSILON is the value such that (smallest_subnormal) * RECIP_EPSILON == T.min_normal
+ enum Unqual!T RECIP_EPSILON = (1/T.epsilon);
+ static if (T.mant_dig == 24)
+ {
+ // Single precision float
+ enum ushort EXPMASK = 0x7F80;
+ enum ushort EXPSHIFT = 7;
+ enum ushort EXPBIAS = 0x3F00;
+ enum uint EXPMASK_INT = 0x7F80_0000;
+ enum uint MANTISSAMASK_INT = 0x007F_FFFF;
+ enum realFormat = RealFormat.ieeeSingle;
+ version (LittleEndian)
+ {
+ enum EXPPOS_SHORT = 1;
+ enum SIGNPOS_BYTE = 3;
+ }
+ else
+ {
+ enum EXPPOS_SHORT = 0;
+ enum SIGNPOS_BYTE = 0;
+ }
+ }
+ else static if (T.mant_dig == 53)
+ {
+ static if (T.sizeof == 8)
+ {
+ // Double precision float, or real == double
+ enum ushort EXPMASK = 0x7FF0;
+ enum ushort EXPSHIFT = 4;
+ enum ushort EXPBIAS = 0x3FE0;
+ enum uint EXPMASK_INT = 0x7FF0_0000;
+ enum uint MANTISSAMASK_INT = 0x000F_FFFF; // for the MSB only
+ enum ulong MANTISSAMASK_LONG = 0x000F_FFFF_FFFF_FFFF;
+ enum realFormat = RealFormat.ieeeDouble;
+ version (LittleEndian)
+ {
+ enum EXPPOS_SHORT = 3;
+ enum SIGNPOS_BYTE = 7;
+ }
+ else
+ {
+ enum EXPPOS_SHORT = 0;
+ enum SIGNPOS_BYTE = 0;
+ }
+ }
+ else static if (T.sizeof == 12)
+ {
+ // Intel extended real80 rounded to double
+ enum ushort EXPMASK = 0x7FFF;
+ enum ushort EXPSHIFT = 0;
+ enum ushort EXPBIAS = 0x3FFE;
+ enum realFormat = RealFormat.ieeeExtended53;
+ version (LittleEndian)
+ {
+ enum EXPPOS_SHORT = 4;
+ enum SIGNPOS_BYTE = 9;
+ }
+ else
+ {
+ enum EXPPOS_SHORT = 0;
+ enum SIGNPOS_BYTE = 0;
+ }
+ }
+ else
+ static assert(false, "No traits support for " ~ T.stringof);
+ }
+ else static if (T.mant_dig == 64)
+ {
+ // Intel extended real80
+ enum ushort EXPMASK = 0x7FFF;
+ enum ushort EXPSHIFT = 0;
+ enum ushort EXPBIAS = 0x3FFE;
+ enum realFormat = RealFormat.ieeeExtended;
+ version (LittleEndian)
+ {
+ enum EXPPOS_SHORT = 4;
+ enum SIGNPOS_BYTE = 9;
+ }
+ else
+ {
+ enum EXPPOS_SHORT = 0;
+ enum SIGNPOS_BYTE = 0;
+ }
+ }
+ else static if (T.mant_dig == 113)
+ {
+ // Quadruple precision float
+ enum ushort EXPMASK = 0x7FFF;
+ enum ushort EXPSHIFT = 0;
+ enum ushort EXPBIAS = 0x3FFE;
+ enum realFormat = RealFormat.ieeeQuadruple;
+ version (LittleEndian)
+ {
+ enum EXPPOS_SHORT = 7;
+ enum SIGNPOS_BYTE = 15;
+ }
+ else
+ {
+ enum EXPPOS_SHORT = 0;
+ enum SIGNPOS_BYTE = 0;
+ }
+ }
+ else static if (T.mant_dig == 106)
+ {
+ // IBM Extended doubledouble
+ enum ushort EXPMASK = 0x7FF0;
+ enum ushort EXPSHIFT = 4;
+ enum realFormat = RealFormat.ibmExtended;
+
+ // For IBM doubledouble the larger magnitude double comes first.
+ // It's really a double[2] and arrays don't index differently
+ // between little and big-endian targets.
+ enum DOUBLEPAIR_MSB = 0;
+ enum DOUBLEPAIR_LSB = 1;
+
+ // The exponent/sign byte is for most significant part.
+ version (LittleEndian)
+ {
+ enum EXPPOS_SHORT = 3;
+ enum SIGNPOS_BYTE = 7;
+ }
+ else
+ {
+ enum EXPPOS_SHORT = 0;
+ enum SIGNPOS_BYTE = 0;
+ }
+ }
+ else
+ static assert(false, "No traits support for " ~ T.stringof);
+}
+
+// These apply to all floating-point types
+version (LittleEndian)
+{
+ enum MANTISSA_LSB = 0;
+ enum MANTISSA_MSB = 1;
+}
+else
+{
+ enum MANTISSA_LSB = 1;
+ enum MANTISSA_MSB = 0;
+}
@@ -307,7 +307,7 @@ Lret:
private T tanImpl(T)(T x) @safe pure nothrow @nogc
{
- import std.math : floatTraits, RealFormat;
+ import std.math.traits : floatTraits, RealFormat;
import std.math.constants : PI, PI_4;
import std.math.rounding : floor;
import std.math.algebraic : poly;
@@ -675,8 +675,7 @@ float atan(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) atan(
private T atanImpl(T)(T x) @safe pure nothrow @nogc
{
- import std.math : floatTraits, RealFormat;
- import std.math.traits : copysign, isInfinity, signbit;
+ import std.math.traits : floatTraits, RealFormat, copysign, isInfinity, signbit;
import std.math.constants : PI_2, PI_4;
import std.math.algebraic : poly;
@@ -2,10 +2,22 @@
/**
* Read and write memory mapped files.
+ *
+ * Memory mapped files are a mechanism in operating systems that allows
+ * file access through virtual memory. After opening a file with `MmFile`,
+ * the contents can be read from or written to with standard slice / pointer operations.
+ * Changes to the memory are automatically reflected in the underlying file.
+ *
+ * Memory mapping can increase I/O performance of large files, compared to buffered
+ * read / write operations from `std.file` and `std.stdio`. However, I/O errors are
+ * not handled as safely: when for example the disk that the file is on gets removed,
+ * reading from it may result in a segfault.
+ *
* Copyright: Copyright The D Language Foundation 2004 - 2009.
* License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
* Authors: $(HTTP digitalmars.com, Walter Bright),
* Matthew Wilson
+ * References: $(LINK https://en.wikipedia.org/wiki/Memory-mapped_file)
* Source: $(PHOBOSSRC std/mmfile.d)
*
* $(SCRIPT inhibitQuickIndex = 1;)
@@ -612,23 +624,47 @@ private:
{
static assert(0);
}
+}
+
+/// Read an existing file
+@system unittest
+{
+ import std.file;
+ std.file.write(deleteme, "hello"); // deleteme is a temporary filename
+ scope(exit) remove(deleteme);
+
+ // Use a scope class so the file will be closed at the end of this function
+ scope mmfile = new MmFile(deleteme);
+
+ assert(mmfile.length == "hello".length);
+
+ // Access file contents with the slice operator
+ // This is typed as `void[]`, so cast to `char[]` or `ubyte[]` to use it
+ const data = cast(const(char)[]) mmfile[];
+
+ // At this point, the file content may not have been read yet.
+ // In that case, the following memory access will intentionally
+ // trigger a page fault, causing the kernel to load the file contents
+ assert(data[0 .. 5] == "hello");
+}
+
+/// Write a new file
+@system unittest
+{
+ import std.file;
+ scope(exit) remove(deleteme);
+
+ scope mmfile = new MmFile(deleteme, MmFile.Mode.readWriteNew, 5, null);
+ assert(mmfile.length == 5);
+
+ auto data = cast(ubyte[]) mmfile[];
+
+ // This write to memory will be reflected in the file contents
+ data[] = '\n';
+
+ mmfile.flush();
- // Report error, where errno gives the error number
- // void errNo()
- // {
- // version (Windows)
- // {
- // throw new FileException(filename, GetLastError());
- // }
- // else version (linux)
- // {
- // throw new FileException(filename, errno);
- // }
- // else
- // {
- // static assert(0);
- // }
- // }
+ assert(std.file.read(deleteme) == "\n\n\n\n\n");
}
@system unittest
@@ -682,7 +682,7 @@ final:
while (prevStack()) {}
return re.ir[pc].data;
default:
- debug printBytecode(re.ir[0..$]);
+ debug(std_regex_debug) printBytecode(re.ir[0..$]);
assert(0);
L_backtrack:
if (!popState())
@@ -403,7 +403,7 @@ struct Group(DataIndex)
}
//debugging tool, prints out instruction along with opcodes
-@trusted string disassemble(in Bytecode[] irb, uint pc, in NamedGroup[] dict=[])
+debug(std_regex_parser) @trusted string disassemble(in Bytecode[] irb, uint pc, in NamedGroup[] dict=[])
{
import std.array : appender;
import std.format.write : formattedWrite;
@@ -467,7 +467,7 @@ struct Group(DataIndex)
}
//disassemble the whole chunk
-@trusted void printBytecode()(in Bytecode[] slice, in NamedGroup[] dict=[])
+debug(std_regex_parser) @trusted void printBytecode()(in Bytecode[] slice, in NamedGroup[] dict=[])
{
import std.stdio : writeln;
for (uint pc=0; pc<slice.length; pc += slice[pc].length)
@@ -3256,11 +3256,19 @@ struct Nullable(T)
* Params:
* value = The value to initialize this `Nullable` with.
*/
- this(inout T value) inout
- {
- _value.payload = value;
- _isNull = false;
- }
+ static if (isCopyable!T)
+ this(inout T value) inout
+ {
+ _value.payload = value;
+ _isNull = false;
+ }
+ else
+ this(T value) inout
+ {
+ import std.algorithm.mutation : move;
+ _value.payload = move(value);
+ _isNull = false;
+ }
static if (hasElaborateDestructor!T)
{
@@ -3273,6 +3281,9 @@ struct Nullable(T)
}
}
+ static if (!isCopyable!T)
+ @disable this(this);
+ else
static if (__traits(hasPostblit, T))
{
this(this)
@@ -3511,22 +3522,18 @@ struct Nullable(T)
* Params:
* value = A value of type `T` to assign to this `Nullable`.
*/
- Nullable opAssign()(T value)
+ ref Nullable opAssign()(T value) return
{
import std.algorithm.mutation : moveEmplace, move;
- // the lifetime of the value in copy shall be managed by
- // this Nullable, so we must avoid calling its destructor.
- auto copy = DontCallDestructorT(value);
-
if (_isNull)
{
// trusted since payload is known to be uninitialized.
- () @trusted { moveEmplace(copy.payload, _value.payload); }();
+ () @trusted { moveEmplace(value, _value.payload); }();
}
else
{
- move(copy.payload, _value.payload);
+ move(value, _value.payload);
}
_isNull = false;
return this;
@@ -3604,12 +3611,14 @@ struct Nullable(T)
alias back = front;
/// ditto
+ static if (isCopyable!T)
@property inout(typeof(this)) save() inout
{
return this;
}
/// ditto
+ static if (isCopyable!T)
inout(typeof(this)) opIndex(size_t[2] dim) inout
in (dim[0] <= length && dim[1] <= length && dim[1] >= dim[0])
{
@@ -4088,16 +4097,12 @@ auto nullable(T)(T t)
struct Test
{
- bool b;
-
- nothrow invariant { assert(b == true); }
-
SysTime _st;
static bool destroyed;
@disable this();
- this(bool b) { this.b = b; }
+ this(int _dummy) {}
~this() @safe { destroyed = true; }
// mustn't call opAssign on Test.init in Nullable!Test, because the invariant
@@ -4109,7 +4114,7 @@ auto nullable(T)(T t)
{
Nullable!Test nt;
- nt = Test(true);
+ nt = Test(1);
// destroy value
Test.destroyed = false;
@@ -10676,6 +10681,21 @@ unittest
assert(s2.get().b == 3);
}
+// https://issues.dlang.org/show_bug.cgi?id=24318
+@system unittest
+{
+ static struct S
+ {
+ @disable this(this);
+ int i;
+ }
+
+ Nullable!S s = S(1);
+ assert(s.get().i == 1);
+ s = S(2);
+ assert(s.get().i == 2);
+}
+
/// The old version of $(LREF SafeRefCounted), before $(LREF borrow) existed.
/// Old code may be relying on `@safe`ty of some of the member functions which
/// cannot be safe in the new scheme, and