d: Merge dmd, druntime bce5c1f7b5, phobos e4d0dd513.
D front-end changes: - Import latest changes from dmd v2.107.0-beta.1. - Keywords like `__FILE__' are now always evaluated at the callsite. D runtime changes: - Import latest changes from druntime v2.107.0-beta.1. - Added `nameSig' field to TypeInfo_Class in object.d. Phobos changes: - Import latest changes from phobos v2.107.0-beta.1. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd bce5c1f7b5. * d-attribs.cc (build_attributes): Update for new front-end interface. * d-lang.cc (d_parse_file): Likewise. * decl.cc (DeclVisitor::visit (VarDeclaration *)): Likewise. * expr.cc (build_lambda_tree): New function. (ExprVisitor::visit (FuncExp *)): Use build_lambda_tree. (ExprVisitor::visit (SymOffExp *)): Likewise. (ExprVisitor::visit (VarExp *)): Likewise. * typeinfo.cc (create_tinfo_types): Add two ulong fields to internal TypeInfo representation. (TypeInfoVisitor::visit (TypeInfoClassDeclaration *)): Emit stub data for TypeInfo_Class.nameSig. (TypeInfoVisitor::visit (TypeInfoStructDeclaration *)): Update for new front-end interface. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime bce5c1f7b5. * src/MERGE: Merge upstream phobos e4d0dd513.
This commit is contained in:
parent
5470a9b176
commit
f204359931
105 changed files with 2917 additions and 1768 deletions
|
@ -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)
|
||||
// String literals
|
||||
size_t saveindx; // used for reverse iteration
|
||||
|
||||
switch (se.sz)
|
||||
{
|
||||
// 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();
|
||||
|
||||
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
|
||||
{
|
||||
// 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);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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 { }
|
||||
|
|
13
gcc/testsuite/gdc.test/compilable/issue24316.d
Normal file
13
gcc/testsuite/gdc.test/compilable/issue24316.d
Normal file
|
@ -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);
|
13
gcc/testsuite/gdc.test/fail_compilation/test24295.d
Normal file
13
gcc/testsuite/gdc.test/fail_compilation/test24295.d
Normal file
|
@ -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];
|
||||
}
|
250
gcc/testsuite/gdc.test/runnable/imports/issue18919b.d
Normal file
250
gcc/testsuite/gdc.test/runnable/imports/issue18919b.d
Normal file
|
@ -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");
|
||||
}
|
47
gcc/testsuite/gdc.test/runnable/issue18919.d
Normal file
47
gcc/testsuite/gdc.test/runnable/issue18919.d
Normal file
|
@ -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;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue