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:
Iain Buclaw 2024-01-18 02:39:20 +01:00
parent 5470a9b176
commit f204359931
105 changed files with 2917 additions and 1768 deletions

View file

@ -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)
{

View file

@ -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)

View file

@ -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);

View file

@ -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.

View file

@ -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;
}

View file

@ -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();

View file

@ -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;

View file

@ -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);

View file

@ -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;

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -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;

View file

@ -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.

View file

@ -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)

View file

@ -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`");

View file

@ -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)
{

View file

@ -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:

View file

@ -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
*/

View file

@ -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

View file

@ -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);

View file

@ -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))

View file

@ -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);

View file

@ -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();

View file

@ -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;
/*************************************************************

View file

@ -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

View file

@ -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)

View file

@ -24,6 +24,7 @@ import dmd.init;
import dmd.mtype;
import dmd.postordervisitor;
import dmd.tokens;
import dmd.typesem;
import dmd.visitor;
/**************************************************

View file

@ -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;
}

View file

@ -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);

View file

@ -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:

View file

@ -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_)
{

View file

@ -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));

View file

@ -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 { }

View 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);

View 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];
}

View 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");
}

View 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();
}

View file

@ -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()

View file

@ -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;

View file

@ -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;

View file

@ -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.

View file

@ -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);
}

View file

@ -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()

View file

@ -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);
}

View file

@ -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
{

View file

@ -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();

View file

@ -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;
}
}

View file

@ -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:

View file

@ -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;

View file

@ -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);

View file

@ -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; ///

View file

@ -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)

View file

@ -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)
{
///

View file

@ -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.

View file

@ -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" );

View file

@ -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);
}
///

View file

@ -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)
{
///

View file

@ -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

View file

@ -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;

View file

@ -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,

View file

@ -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 );
}
}
}

View file

@ -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;

View file

@ -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)

View file

@ -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

View file

@ -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 {

View file

@ -155,7 +155,7 @@ enum OLEOPT_UPDATE {
// #endif
}
mixin DECLARE_HANDLE!("HOBJECT");
alias HOBJECT = HANDLE;
alias LONG_PTR LHSERVER, LHCLIENTDOC, LHSERVERDOC;
struct OLEOBJECTVTBL {

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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

View file

@ -120,7 +120,7 @@ enum URLIS
URLIS_HASQUERY
}
mixin DECLARE_HANDLE!("HUSKEY");
alias HUSKEY = HANDLE;
alias HUSKEY* PHUSKEY;
extern (Windows)

View file

@ -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 {

View file

@ -678,7 +678,7 @@ extern (Windows) {
void ICCompressorFree(PCOMPVARS pc);
}
mixin DECLARE_HANDLE!("HDRAWDIB");
alias HDRAWDIB = HANDLE;
enum {
DDF_0001 = 0x0001,

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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;

View file

@ -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 {

View file

@ -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; }

View file

@ -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))

View file

@ -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;

View file

@ -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.

View file

@ -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)
{

View file

@ -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)

View file

@ -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

View file

@ -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);
}
}

View file

@ -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

View file

@ -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);
}

View file

@ -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;

View file

@ -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)

View file

@ -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)
{

View file

@ -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;

View file

@ -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;
}

View file

@ -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,

View file

@ -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