d: Merge upstream dmd eb7bee331, druntime 27834edb, phobos ac296f80c.
D front-end changes: - Import dmd v2.100.0-beta.1. - Print deprecation messages for scope violations unless `-frevert=dip1000' is used. - Fixed a missed case of switch case fallthrough not being caught by the compiler. D runtime changes: - Import druntime v2.100.0-beta.1. Phobos changes: - Import phobos v2.100.0-beta.1. gcc/d/ChangeLog: * dmd/MERGE: Merge upstream dmd eb7bee331. * dmd/VERSION: Update version to v2.100.0-beta.1. * d-lang.cc (d_handle_option): Handle OPT_frevert_dip1000. * lang.opt (frevert=dip1000): New option. libphobos/ChangeLog: * libdruntime/MERGE: Merge upstream druntime 27834edb. * src/MERGE: Merge upstream phobos ac296f80c. * src/Makefile.am (PHOBOS_DSOURCES): Add std/int128.d. * src/Makefile.in: Regenerate.
This commit is contained in:
parent
93dd7f36f2
commit
ae56e2da05
50 changed files with 1002 additions and 302 deletions
|
@ -637,12 +637,17 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
|
|||
break;
|
||||
|
||||
case OPT_frevert_all:
|
||||
global.params.useDIP1000 = FeatureState::disabled;
|
||||
global.params.useDIP25 = FeatureState::disabled;
|
||||
global.params.dtorFields = FeatureState::disabled;
|
||||
global.params.fix16997 = !value;
|
||||
global.params.markdown = !value;
|
||||
break;
|
||||
|
||||
case OPT_frevert_dip1000:
|
||||
global.params.useDIP1000 = FeatureState::disabled;
|
||||
break;
|
||||
|
||||
case OPT_frevert_dip25:
|
||||
global.params.useDIP25 = FeatureState::disabled;
|
||||
break;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
4d1bfcf142928cf1c097b0a2689485c1b14f4f53
|
||||
eb7bee331a13026eeb4dcbf9d43d5d4e744a4d26
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/dmd repository.
|
||||
|
|
|
@ -1 +1 @@
|
|||
v2.099.1
|
||||
v2.100.0-beta.1
|
||||
|
|
|
@ -57,6 +57,28 @@ enum ClassKind : ubyte
|
|||
c,
|
||||
}
|
||||
|
||||
/**
|
||||
* Give a nice string for a class kind for error messages
|
||||
* Params:
|
||||
* c = class kind
|
||||
* Returns:
|
||||
* 0-terminated string for `c`
|
||||
*/
|
||||
const(char)* toChars(ClassKind c)
|
||||
{
|
||||
final switch (c)
|
||||
{
|
||||
case ClassKind.d:
|
||||
return "D";
|
||||
case ClassKind.cpp:
|
||||
return "C++";
|
||||
case ClassKind.objc:
|
||||
return "Objective-C";
|
||||
case ClassKind.c:
|
||||
return "C";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If an aggregate has a pargma(mangle, ...) this holds the information
|
||||
* to mangle.
|
||||
|
|
|
@ -28,6 +28,7 @@ enum Baseok : ubyte
|
|||
|
||||
enum MODFlags : int
|
||||
{
|
||||
none = 0, // default (mutable)
|
||||
const_ = 1, // type is const
|
||||
immutable_ = 4, // type is immutable
|
||||
shared_ = 2, // type is shared
|
||||
|
|
|
@ -139,16 +139,21 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
|
|||
// Allow if last case/default was empty
|
||||
CaseStatement sc = slast.isCaseStatement();
|
||||
DefaultStatement sd = slast.isDefaultStatement();
|
||||
if (sc && (!sc.statement.hasCode() || sc.statement.isCaseStatement() || sc.statement.isErrorStatement()))
|
||||
{
|
||||
}
|
||||
else if (sd && (!sd.statement.hasCode() || sd.statement.isCaseStatement() || sd.statement.isErrorStatement()))
|
||||
auto sl = (sc ? sc.statement : (sd ? sd.statement : null));
|
||||
|
||||
if (sl && (!sl.hasCode() || sl.isErrorStatement()))
|
||||
{
|
||||
}
|
||||
else if (func.getModule().filetype != FileType.c)
|
||||
{
|
||||
const(char)* gototype = s.isCaseStatement() ? "case" : "default";
|
||||
s.error("switch case fallthrough - use 'goto %s;' if intended", gototype);
|
||||
// @@@DEPRECATED_2.110@@@ https://issues.dlang.org/show_bug.cgi?id=22999
|
||||
// Deprecated in 2.100
|
||||
// Make an error in 2.110
|
||||
if (sl && sl.isCaseStatement())
|
||||
s.deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype);
|
||||
else
|
||||
s.error("switch case fallthrough - use 'goto %s;' if intended", gototype);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -912,8 +912,8 @@ void buildDtors(AggregateDeclaration ad, Scope* sc)
|
|||
ex = new DotVarExp(loc, ex, v);
|
||||
|
||||
// This is a hack so we can call destructors on const/immutable objects.
|
||||
// Do it as a type 'paint'.
|
||||
ex = new CastExp(loc, ex, v.type.mutableOf());
|
||||
// Do it as a type 'paint', `cast()`
|
||||
ex = new CastExp(loc, ex, MODFlags.none);
|
||||
if (stc & STC.safe)
|
||||
stc = (stc & ~STC.safe) | STC.trusted;
|
||||
|
||||
|
@ -1588,7 +1588,7 @@ private bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor)
|
|||
|
||||
auto tf = ctorDecl.type.toTypeFunction();
|
||||
const dim = tf.parameterList.length;
|
||||
if (dim == 1)
|
||||
if (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))
|
||||
{
|
||||
auto param = tf.parameterList[0];
|
||||
if (param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
|
||||
|
|
|
@ -259,6 +259,7 @@ final class CParser(AST) : Parser!AST
|
|||
case TOK.plusPlus:
|
||||
case TOK.minusMinus:
|
||||
case TOK.sizeof_:
|
||||
case TOK._Generic:
|
||||
Lexp:
|
||||
auto exp = cparseExpression();
|
||||
if (token.value == TOK.identifier && exp.op == EXP.identifier)
|
||||
|
@ -2399,15 +2400,13 @@ final class CParser(AST) : Parser!AST
|
|||
if (idx.length > 2 && idx[0] == '_' && idx[1] == '_') // leading double underscore
|
||||
importBuiltins = true; // probably one of those compiler extensions
|
||||
t = null;
|
||||
if (scw & SCW.xtypedef)
|
||||
{
|
||||
/* Punch through to what the typedef is, to support things like:
|
||||
* typedef T* T;
|
||||
*/
|
||||
auto pt = lookupTypedef(previd);
|
||||
if (pt && *pt) // if previd is a known typedef
|
||||
t = *pt;
|
||||
}
|
||||
|
||||
/* Punch through to what the typedef is, to support things like:
|
||||
* typedef T* T;
|
||||
*/
|
||||
auto pt = lookupTypedef(previd);
|
||||
if (pt && *pt) // if previd is a known typedef
|
||||
t = *pt;
|
||||
|
||||
if (!t)
|
||||
t = new AST.TypeIdentifier(loc, previd);
|
||||
|
@ -2745,6 +2744,11 @@ final class CParser(AST) : Parser!AST
|
|||
Specifier specifier;
|
||||
specifier.packalign.setDefault();
|
||||
auto tspec = cparseSpecifierQualifierList(LVL.global, specifier);
|
||||
if (tspec && specifier.mod & MOD.xconst)
|
||||
{
|
||||
tspec = toConst(tspec);
|
||||
specifier.mod = MOD.xnone; // 'used' it
|
||||
}
|
||||
Identifier id;
|
||||
return cparseDeclarator(DTR.xabstract, tspec, id, specifier);
|
||||
}
|
||||
|
|
|
@ -379,7 +379,7 @@ extern (C++) abstract class Declaration : Dsymbol
|
|||
|
||||
if (e1 && e1.op == EXP.this_ && isField())
|
||||
{
|
||||
VarDeclaration vthis = (cast(ThisExp)e1).var;
|
||||
VarDeclaration vthis = e1.isThisExp().var;
|
||||
for (Scope* scx = sc; scx; scx = scx.enclosing)
|
||||
{
|
||||
if (scx.func == vthis.parent && (scx.flags & SCOPE.contract))
|
||||
|
@ -656,9 +656,8 @@ extern (C++) final class TupleDeclaration : Declaration
|
|||
if (o.dyncast() == DYNCAST.expression)
|
||||
{
|
||||
Expression e = cast(Expression)o;
|
||||
if (e.op == EXP.dSymbol)
|
||||
if (DsymbolExp ve = e.isDsymbolExp())
|
||||
{
|
||||
DsymbolExp ve = cast(DsymbolExp)e;
|
||||
Declaration d = ve.s.isDeclaration();
|
||||
if (d && d.needThis())
|
||||
{
|
||||
|
@ -1143,7 +1142,7 @@ extern (C++) class VarDeclaration : Declaration
|
|||
assert(o.dyncast() == DYNCAST.expression);
|
||||
Expression e = cast(Expression)o;
|
||||
assert(e.op == EXP.dSymbol);
|
||||
DsymbolExp se = cast(DsymbolExp)e;
|
||||
DsymbolExp se = e.isDsymbolExp();
|
||||
se.s.setFieldOffset(ad, fieldState, isunion);
|
||||
}
|
||||
return;
|
||||
|
@ -1441,16 +1440,17 @@ extern (C++) class VarDeclaration : Declaration
|
|||
const sdsz = sd.type.size();
|
||||
assert(sdsz != SIZE_INVALID && sdsz != 0);
|
||||
const n = sz / sdsz;
|
||||
e = new SliceExp(loc, e, new IntegerExp(loc, 0, Type.tsize_t), new IntegerExp(loc, n, Type.tsize_t));
|
||||
SliceExp se = new SliceExp(loc, e, new IntegerExp(loc, 0, Type.tsize_t),
|
||||
new IntegerExp(loc, n, Type.tsize_t));
|
||||
|
||||
// Prevent redundant bounds check
|
||||
(cast(SliceExp)e).upperIsInBounds = true;
|
||||
(cast(SliceExp)e).lowerIsLessThanUpper = true;
|
||||
se.upperIsInBounds = true;
|
||||
se.lowerIsLessThanUpper = true;
|
||||
|
||||
// This is a hack so we can call destructors on const/immutable objects.
|
||||
e.type = sd.type.arrayOf();
|
||||
se.type = sd.type.arrayOf();
|
||||
|
||||
e = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), e);
|
||||
e = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
|
|
@ -1133,8 +1133,10 @@ extern (C++) final class Module : Package
|
|||
// If it isn't there, some compiler rewrites, like
|
||||
// classinst == classinst -> .object.opEquals(classinst, classinst)
|
||||
// would fail inside object.d.
|
||||
if (members.dim == 0 || (*members)[0].ident != Id.object ||
|
||||
(*members)[0].isImport() is null)
|
||||
if (filetype != FileType.c &&
|
||||
(members.dim == 0 ||
|
||||
(*members)[0].ident != Id.object ||
|
||||
(*members)[0].isImport() is null))
|
||||
{
|
||||
auto im = new Import(Loc.initial, null, Id.object, null, 0);
|
||||
members.shift(im);
|
||||
|
|
|
@ -838,7 +838,8 @@ extern (C++) class Dsymbol : ASTNode
|
|||
}
|
||||
if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
|
||||
{
|
||||
if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
|
||||
if (ident == Id.__sizeof ||
|
||||
!(sc && sc.flags & SCOPE.Cfile) && (ident == Id.__xalignof || ident == Id._mangleof))
|
||||
{
|
||||
error("`.%s` property cannot be redefined", ident.toChars());
|
||||
errors = true;
|
||||
|
@ -2523,6 +2524,7 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
|
|||
|
||||
if (i1) // vd is the definition
|
||||
{
|
||||
vd2.storage_class |= STC.extern_; // so toObjFile() won't emit it
|
||||
sds.symtab.update(vd); // replace vd2 with the definition
|
||||
return vd;
|
||||
}
|
||||
|
|
|
@ -2874,7 +2874,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
sc = sc.endCTFE();
|
||||
resolved = resolved.ctfeInterpret();
|
||||
StringExp name = resolved.toStringExp();
|
||||
TupleExp tup = name ? null : resolved.toTupleExp();
|
||||
TupleExp tup = name ? null : resolved.isTupleExp();
|
||||
if (!tup && !name)
|
||||
{
|
||||
error(ns.loc, "expected string expression for namespace name, got `%s`", ns.identExp.toChars());
|
||||
|
@ -4621,7 +4621,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
buildOpAssign(sd, sc2);
|
||||
buildOpEquals(sd, sc2);
|
||||
|
||||
if (global.params.useTypeInfo && Type.dtypeinfo) // these functions are used for TypeInfo
|
||||
if (!(sc2.flags & SCOPE.Cfile) &&
|
||||
global.params.useTypeInfo && Type.dtypeinfo) // these functions are used for TypeInfo
|
||||
{
|
||||
sd.xeq = buildXopEquals(sd, sc2);
|
||||
sd.xcmp = buildXopCmp(sd, sc2);
|
||||
|
@ -5023,6 +5024,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
|
|||
cldec.com = true;
|
||||
if (cldec.baseClass.isCPPclass())
|
||||
cldec.classKind = ClassKind.cpp;
|
||||
if (cldec.classKind != cldec.baseClass.classKind)
|
||||
cldec.error("with %s linkage cannot inherit from class `%s` with %s linkage",
|
||||
cldec.classKind.toChars(), cldec.baseClass.toChars(), cldec.baseClass.classKind.toChars());
|
||||
|
||||
if (cldec.baseClass.stack)
|
||||
cldec.stack = true;
|
||||
cldec.enclosing = cldec.baseClass.enclosing;
|
||||
|
|
|
@ -434,8 +434,20 @@ else
|
|||
pragma(printf) extern (C++) void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap);
|
||||
|
||||
/**
|
||||
* Call this after printing out fatal error messages to clean up and exit
|
||||
* the compiler.
|
||||
* The type of the fatal error handler
|
||||
* Returns: true if error handling is done, false to do exit(EXIT_FAILURE)
|
||||
*/
|
||||
alias FatalErrorHandler = bool delegate();
|
||||
|
||||
/**
|
||||
* The fatal error handler.
|
||||
* If non-null it will be called for every fatal() call issued by the compiler.
|
||||
*/
|
||||
__gshared FatalErrorHandler fatalErrorHandler;
|
||||
|
||||
/**
|
||||
* Call this after printing out fatal error messages to clean up and exit the
|
||||
* compiler. You can also set a fatalErrorHandler to override this behaviour.
|
||||
*/
|
||||
extern (C++) void fatal();
|
||||
|
||||
|
|
|
@ -316,24 +316,27 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp
|
|||
*/
|
||||
void unsafeAssign(VarDeclaration v, const char* desc)
|
||||
{
|
||||
if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe())
|
||||
if (setUnsafeDIP1000(sc.func))
|
||||
{
|
||||
if (!gag)
|
||||
{
|
||||
if (assertmsg)
|
||||
{
|
||||
error(arg.loc, "%s `%s` assigned to non-scope parameter calling `assert()`",
|
||||
previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
|
||||
(arg.loc, "%s `%s` assigned to non-scope parameter calling `assert()`",
|
||||
desc, v.toChars());
|
||||
}
|
||||
else
|
||||
{
|
||||
error(arg.loc, "%s `%s` assigned to non-scope parameter `%s` calling %s",
|
||||
previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
|
||||
(arg.loc, "%s `%s` assigned to non-scope parameter `%s` calling %s",
|
||||
desc, v.toChars(),
|
||||
par ? par.toChars() : "this",
|
||||
fdc ? fdc.toPrettyChars() : "indirectly");
|
||||
}
|
||||
}
|
||||
result = true;
|
||||
if (global.params.useDIP1000 == FeatureState.enabled)
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -774,7 +777,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
|
|||
if (v.isDataseg())
|
||||
continue;
|
||||
|
||||
if (global.params.useDIP1000 == FeatureState.enabled)
|
||||
if (global.params.useDIP1000 != FeatureState.disabled)
|
||||
{
|
||||
if (va && va.isScope() && !v.isReference())
|
||||
{
|
||||
|
@ -782,12 +785,18 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
|
|||
{
|
||||
va.doNotInferReturn = true;
|
||||
}
|
||||
else if (fd.setUnsafe())
|
||||
else if (setUnsafeDIP1000(fd))
|
||||
{
|
||||
if (!gag)
|
||||
error(ae.loc, "address of local variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars());
|
||||
result = true;
|
||||
continue;
|
||||
previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
|
||||
(ae.loc, "address of local variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars());
|
||||
|
||||
|
||||
if (global.params.useDIP1000 == FeatureState.enabled)
|
||||
{
|
||||
result = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -976,12 +985,11 @@ bool checkThrowEscape(Scope* sc, Expression e, bool gag)
|
|||
if (v.isScope() && !v.iscatchvar) // special case: allow catch var to be rethrown
|
||||
// despite being `scope`
|
||||
{
|
||||
if (!gag)
|
||||
previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
|
||||
(e.loc, "scope variable `%s` may not be thrown", v.toChars());
|
||||
if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029
|
||||
{
|
||||
if (!gag)
|
||||
error(e.loc, "scope variable `%s` may not be thrown", v.toChars());
|
||||
result = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
|
@ -1042,13 +1050,16 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
|
|||
*/
|
||||
!(p.parent == sc.func))
|
||||
{
|
||||
if (global.params.useDIP1000 == FeatureState.enabled // https://issues.dlang.org/show_bug.cgi?id=17029
|
||||
&& sc.func.setUnsafe()) // https://issues.dlang.org/show_bug.cgi?id=20868
|
||||
if (setUnsafeDIP1000(sc.func)) // https://issues.dlang.org/show_bug.cgi?id=20868
|
||||
{
|
||||
// Only look for errors if in module listed on command line
|
||||
if (!gag)
|
||||
error(e.loc, "scope variable `%s` may not be copied into allocated memory", v.toChars());
|
||||
result = true;
|
||||
previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
|
||||
(e.loc, "scope variable `%s` may not be copied into allocated memory", v.toChars());
|
||||
if (global.params.useDIP1000 == FeatureState.enabled)
|
||||
result = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -1258,11 +1269,13 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
|
|||
)
|
||||
{
|
||||
// https://issues.dlang.org/show_bug.cgi?id=17029
|
||||
if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe())
|
||||
if (setUnsafeDIP1000(sc.func))
|
||||
{
|
||||
if (!gag)
|
||||
error(e.loc, "scope variable `%s` may not be returned", v.toChars());
|
||||
result = true;
|
||||
previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
|
||||
(e.loc, "scope variable `%s` may not be returned", v.toChars());
|
||||
if (global.params.useDIP1000 == FeatureState.enabled)
|
||||
result = true;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
@ -2341,3 +2354,11 @@ private void addMaybe(VarDeclaration va, VarDeclaration v)
|
|||
va.maybes = new VarDeclarations();
|
||||
va.maybes.push(v);
|
||||
}
|
||||
|
||||
|
||||
private bool setUnsafeDIP1000(FuncDeclaration f)
|
||||
{
|
||||
return global.params.useDIP1000 == FeatureState.enabled
|
||||
? f.setUnsafe()
|
||||
: f.isSafeBypassingInference();
|
||||
}
|
||||
|
|
|
@ -967,11 +967,6 @@ extern (C++) abstract class Expression : ASTNode
|
|||
return null;
|
||||
}
|
||||
|
||||
TupleExp toTupleExp()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Return !=0 if expression is an lvalue.
|
||||
*/
|
||||
|
@ -1746,6 +1741,7 @@ extern (C++) abstract class Expression : ASTNode
|
|||
inout(ModuleInitExp) isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; }
|
||||
inout(FuncInitExp) isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; }
|
||||
inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; }
|
||||
inout(ObjcClassReferenceExp) isObjcClassReferenceExp() { return op == EXP.objcClassReference ? cast(typeof(return))this : null; }
|
||||
inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; }
|
||||
inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; }
|
||||
|
||||
|
@ -2888,11 +2884,6 @@ extern (C++) final class TupleExp : Expression
|
|||
return new TupleExp(loc, exps);
|
||||
}
|
||||
|
||||
override TupleExp toTupleExp()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
override TupleExp syntaxCopy()
|
||||
{
|
||||
return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps));
|
||||
|
|
|
@ -103,7 +103,6 @@ public:
|
|||
virtual real_t toImaginary();
|
||||
virtual complex_t toComplex();
|
||||
virtual StringExp *toStringExp();
|
||||
virtual TupleExp *toTupleExp();
|
||||
virtual bool isLvalue();
|
||||
virtual Expression *toLvalue(Scope *sc, Expression *e);
|
||||
virtual Expression *modifiableLvalue(Scope *sc, Expression *e);
|
||||
|
@ -406,7 +405,6 @@ public:
|
|||
Expressions *exps;
|
||||
|
||||
static TupleExp *create(const Loc &loc, Expressions *exps);
|
||||
TupleExp *toTupleExp();
|
||||
TupleExp *syntaxCopy();
|
||||
bool equals(const RootObject *o) const;
|
||||
|
||||
|
|
|
@ -2028,7 +2028,9 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
|
|||
//printf("type: %s\n", arg.type.toChars());
|
||||
//printf("param: %s\n", p.toChars());
|
||||
|
||||
if (firstArg && p.storageClass & STC.return_)
|
||||
const pStc = tf.parameterStorageClass(tthis, p);
|
||||
|
||||
if (firstArg && (pStc & STC.return_))
|
||||
{
|
||||
/* Argument value can be assigned to firstArg.
|
||||
* Check arg to see if it matters.
|
||||
|
@ -2036,7 +2038,9 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
|
|||
if (global.params.useDIP1000 == FeatureState.enabled)
|
||||
err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
|
||||
}
|
||||
else if (tf.parameterEscapes(tthis, p))
|
||||
// Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
|
||||
// as lazy parameters to the next function, but that isn't escaping.
|
||||
else if (!(pStc & (STC.scope_ | STC.lazy_)))
|
||||
{
|
||||
/* Argument value can escape from the called function.
|
||||
* Check arg to see if it matters.
|
||||
|
@ -2044,7 +2048,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
|
|||
if (global.params.useDIP1000 == FeatureState.enabled)
|
||||
err |= checkParamArgumentEscape(sc, fd, p, arg, false, false);
|
||||
}
|
||||
else if (!(p.storageClass & STC.return_))
|
||||
else if (!(pStc & STC.return_))
|
||||
{
|
||||
/* Argument value cannot escape from the called function.
|
||||
*/
|
||||
|
@ -3229,7 +3233,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
}
|
||||
Type t = cle.type.typeSemantic(cle.loc, sc);
|
||||
auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret);
|
||||
auto e = initializerToExpression(init, t);
|
||||
auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
|
||||
if (!e)
|
||||
{
|
||||
error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars());
|
||||
|
@ -12195,7 +12199,7 @@ Expression semanticX(DotIdExp exp, Scope* sc)
|
|||
if (Expression ex = unaSemantic(exp, sc))
|
||||
return ex;
|
||||
|
||||
if (exp.ident == Id._mangleof)
|
||||
if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
|
||||
{
|
||||
// symbol.mangleof
|
||||
|
||||
|
@ -12304,6 +12308,8 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
|
|||
|
||||
//{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
|
||||
|
||||
const cfile = (sc.flags & SCOPE.Cfile) != 0;
|
||||
|
||||
/* Special case: rewrite this.id and super.id
|
||||
* to be classtype.id and baseclasstype.id
|
||||
* if we have no this pointer.
|
||||
|
@ -12555,7 +12561,16 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
|
|||
exp.error("undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars());
|
||||
return ErrorExp.get();
|
||||
}
|
||||
else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum && exp.ident != Id._init && exp.ident != Id.__sizeof && exp.ident != Id.__xalignof && exp.ident != Id.offsetof && exp.ident != Id._mangleof && exp.ident != Id.stringof)
|
||||
else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum &&
|
||||
!(
|
||||
exp.ident == Id.__sizeof ||
|
||||
exp.ident == Id.__xalignof ||
|
||||
!cfile &&
|
||||
(exp.ident == Id._mangleof ||
|
||||
exp.ident == Id.offsetof ||
|
||||
exp.ident == Id._init ||
|
||||
exp.ident == Id.stringof)
|
||||
))
|
||||
{
|
||||
Type t1bn = t1b.nextOf();
|
||||
if (flag)
|
||||
|
@ -12590,7 +12605,7 @@ Expression semanticY(DotIdExp exp, Scope* sc, int flag)
|
|||
Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
|
||||
return e;
|
||||
}
|
||||
else if (sc.flags & SCOPE.Cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp())
|
||||
else if (cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp())
|
||||
{
|
||||
// Sizeof string literal includes the terminating 0
|
||||
auto se = exp.e1.isStringExp();
|
||||
|
|
|
@ -695,7 +695,7 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
|
|||
assert(sc);
|
||||
auto tm = vd.type.addMod(ts.mod);
|
||||
auto iz = di.initializer.initializerSemantic(sc, tm, needInterpret);
|
||||
auto ex = iz.initializerToExpression();
|
||||
auto ex = iz.initializerToExpression(null, true);
|
||||
if (ex.op == EXP.error)
|
||||
{
|
||||
errors = true;
|
||||
|
@ -1100,6 +1100,8 @@ Initializer inferType(Initializer init, Scope* sc)
|
|||
*/
|
||||
extern (C++) Expression initializerToExpression(Initializer init, Type itype = null, const bool isCfile = false)
|
||||
{
|
||||
//printf("initializerToExpression() isCfile: %d\n", isCfile);
|
||||
|
||||
Expression visitVoid(VoidInitializer)
|
||||
{
|
||||
return null;
|
||||
|
@ -1197,7 +1199,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
|
|||
assert(j < edim);
|
||||
if (Initializer iz = init.value[i])
|
||||
{
|
||||
if (Expression ex = iz.initializerToExpression())
|
||||
if (Expression ex = iz.initializerToExpression(null, isCfile))
|
||||
{
|
||||
(*elements)[j] = ex;
|
||||
++j;
|
||||
|
@ -1285,7 +1287,7 @@ extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
|
|||
|
||||
Expression visitC(CInitializer i)
|
||||
{
|
||||
//printf("CInitializer.initializerToExpression()\n");
|
||||
//printf("CInitializer.initializerToExpression(null, true)\n");
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -1236,28 +1236,47 @@ class Lexer
|
|||
{
|
||||
uint v = 0;
|
||||
int n = 0;
|
||||
while (1)
|
||||
if (Ccompile && ndigits == 2)
|
||||
{
|
||||
if (isdigit(cast(char)c))
|
||||
c -= '0';
|
||||
else if (islower(c))
|
||||
c -= 'a' - 10;
|
||||
else
|
||||
c -= 'A' - 10;
|
||||
v = v * 16 + c;
|
||||
c = *++p;
|
||||
if (++n == ndigits)
|
||||
break;
|
||||
if (!ishex(cast(char)c))
|
||||
/* C11 6.4.4.4-7 one to infinity hex digits
|
||||
*/
|
||||
do
|
||||
{
|
||||
.error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits);
|
||||
break;
|
||||
}
|
||||
if (isdigit(cast(char)c))
|
||||
c -= '0';
|
||||
else if (islower(c))
|
||||
c -= 'a' - 10;
|
||||
else
|
||||
c -= 'A' - 10;
|
||||
v = v * 16 + c;
|
||||
c = *++p;
|
||||
} while (ishex(cast(char)c));
|
||||
}
|
||||
if (ndigits != 2 && !utf_isValidDchar(v))
|
||||
else
|
||||
{
|
||||
.error(loc, "invalid UTF character \\U%08x", v);
|
||||
v = '?'; // recover with valid UTF character
|
||||
while (1)
|
||||
{
|
||||
if (isdigit(cast(char)c))
|
||||
c -= '0';
|
||||
else if (islower(c))
|
||||
c -= 'a' - 10;
|
||||
else
|
||||
c -= 'A' - 10;
|
||||
v = v * 16 + c;
|
||||
c = *++p;
|
||||
if (++n == ndigits)
|
||||
break;
|
||||
if (!ishex(cast(char)c))
|
||||
{
|
||||
.error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ndigits != 2 && !utf_isValidDchar(v))
|
||||
{
|
||||
.error(loc, "invalid UTF character \\U%08x", v);
|
||||
v = '?'; // recover with valid UTF character
|
||||
}
|
||||
}
|
||||
c = v;
|
||||
}
|
||||
|
|
|
@ -4360,29 +4360,6 @@ extern (C++) final class TypeFunction : TypeNext
|
|||
return linkage == LINK.d && parameterList.varargs == VarArg.variadic;
|
||||
}
|
||||
|
||||
/***************************
|
||||
* Examine function signature for parameter p and see if
|
||||
* the value of p can 'escape' the scope of the function.
|
||||
* This is useful to minimize the needed annotations for the parameters.
|
||||
* Params:
|
||||
* tthis = type of `this` parameter, null if none
|
||||
* p = parameter to this function
|
||||
* Returns:
|
||||
* true if escapes via assignment to global or through a parameter
|
||||
*/
|
||||
bool parameterEscapes(Type tthis, Parameter p)
|
||||
{
|
||||
/* Scope parameters do not escape.
|
||||
* Allow 'lazy' to imply 'scope' -
|
||||
* lazy parameters can be passed along
|
||||
* as lazy parameters to the next function, but that isn't
|
||||
* escaping.
|
||||
*/
|
||||
if (parameterStorageClass(tthis, p) & (STC.scope_ | STC.lazy_))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/************************************
|
||||
* Take the specified storage class for p,
|
||||
* and use the function signature to infer whether
|
||||
|
@ -4410,7 +4387,7 @@ extern (C++) final class TypeFunction : TypeNext
|
|||
|
||||
/* If haven't inferred the return type yet, can't infer storage classes
|
||||
*/
|
||||
if (!nextOf())
|
||||
if (!nextOf() || !isnothrow())
|
||||
return stc;
|
||||
|
||||
purityLevel();
|
||||
|
@ -4461,37 +4438,12 @@ extern (C++) final class TypeFunction : TypeNext
|
|||
}
|
||||
}
|
||||
|
||||
/* Inferring STC.return_ here has false positives
|
||||
* for pure functions, producing spurious error messages
|
||||
* about escaping references.
|
||||
* Give up on it for now.
|
||||
*/
|
||||
version (none)
|
||||
{
|
||||
stc |= STC.scope_;
|
||||
|
||||
Type tret = nextOf().toBasetype();
|
||||
if (isref || tret.hasPointers())
|
||||
{
|
||||
/* The result has references, so p could be escaping
|
||||
* that way.
|
||||
*/
|
||||
stc |= STC.return_;
|
||||
}
|
||||
}
|
||||
// Check escaping through return value
|
||||
Type tret = nextOf().toBasetype();
|
||||
if (isref || tret.hasPointers())
|
||||
return stc | STC.scope_ | STC.return_ | STC.returnScope;
|
||||
else
|
||||
{
|
||||
// Check escaping through return value
|
||||
Type tret = nextOf().toBasetype();
|
||||
if (isref || tret.hasPointers() || !isnothrow())
|
||||
{
|
||||
return stc;
|
||||
}
|
||||
|
||||
stc |= STC.scope_;
|
||||
}
|
||||
|
||||
return stc;
|
||||
return stc | STC.scope_;
|
||||
}
|
||||
|
||||
override Type addStorageClass(StorageClass stc)
|
||||
|
@ -4791,14 +4743,40 @@ extern (C++) final class TypeFunction : TypeNext
|
|||
m = MATCH.exact;
|
||||
else
|
||||
{
|
||||
m = MATCH.nomatch;
|
||||
if (pMessage)
|
||||
{
|
||||
/* https://issues.dlang.org/show_bug.cgi?id=22202
|
||||
*
|
||||
* If a function was deduced by semantic on the CallExp,
|
||||
* it means that resolveFuncCall completed succesfully.
|
||||
* Therefore, there exists a callable copy constructor,
|
||||
* however, it cannot be called because scope constraints
|
||||
* such as purity, safety or nogc.
|
||||
*/
|
||||
OutBuffer buf;
|
||||
buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
|
||||
argStruct.toChars(), targ.toChars(), tprm.toChars());
|
||||
auto callExp = e.isCallExp();
|
||||
if (auto f = callExp.f)
|
||||
{
|
||||
char[] s;
|
||||
if (!f.isPure && sc.func.setImpure())
|
||||
s ~= "pure ";
|
||||
if (!f.isSafe() && !f.isTrusted() && sc.func.setUnsafe())
|
||||
s ~= "@safe ";
|
||||
if (!f.isNogc && sc.func.setGC())
|
||||
s ~= "nogc ";
|
||||
s[$-1] = '\0';
|
||||
buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
|
||||
argStruct.toChars(), targ.toChars(), tprm.toChars());
|
||||
}
|
||||
|
||||
*pMessage = buf.extractChars();
|
||||
}
|
||||
m = MATCH.nomatch;
|
||||
goto Nomatch;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@ enum class TY : uint8_t
|
|||
*/
|
||||
enum MODFlags
|
||||
{
|
||||
MODnone = 0, // default (mutable)
|
||||
MODconst = 1, // type is const
|
||||
MODimmutable = 4, // type is immutable
|
||||
MODshared = 2, // type is shared
|
||||
|
@ -608,7 +609,6 @@ public:
|
|||
void purityLevel();
|
||||
bool hasLazyParameters();
|
||||
bool isDstyleVariadic() const;
|
||||
bool parameterEscapes(Parameter *p);
|
||||
StorageClass parameterStorageClass(Parameter *p);
|
||||
Type *addStorageClass(StorageClass stc);
|
||||
|
||||
|
|
|
@ -593,7 +593,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
|||
return;
|
||||
}
|
||||
}
|
||||
// Convert &((a.b)[n]) to (&a.b)+n
|
||||
// Convert &((a.b)[index]) to (&a.b)+index*elementsize
|
||||
else if (ae.e2.isIntegerExp() && ae.e1.isDotVarExp())
|
||||
{
|
||||
sinteger_t index = ae.e2.toInteger();
|
||||
|
@ -614,9 +614,18 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
|
|||
}
|
||||
}
|
||||
|
||||
import core.checkedint : mulu;
|
||||
bool overflow;
|
||||
const offset = mulu(index, ts.nextOf().size(e.loc), overflow); // index*elementsize
|
||||
if (overflow)
|
||||
{
|
||||
e.error("array offset overflow");
|
||||
return error();
|
||||
}
|
||||
|
||||
auto pe = new AddrExp(e.loc, ve);
|
||||
pe.type = e.type;
|
||||
ret = new AddExp(e.loc, pe, ae.e2);
|
||||
ret = new AddExp(e.loc, pe, new IntegerExp(e.loc, offset, Type.tsize_t));
|
||||
ret.type = e.type;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -987,23 +987,9 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
|||
nextToken();
|
||||
if (token.value == TOK.assign)
|
||||
{
|
||||
nextToken();
|
||||
if (token.value == TOK.identifier)
|
||||
s = new AST.DebugSymbol(token.loc, token.ident);
|
||||
else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
|
||||
s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue);
|
||||
else
|
||||
{
|
||||
error("identifier or integer expected, not `%s`", token.toChars());
|
||||
s = null;
|
||||
}
|
||||
nextToken();
|
||||
if (token.value != TOK.semicolon)
|
||||
error("semicolon expected");
|
||||
nextToken();
|
||||
s = parseDebugSpecification();
|
||||
break;
|
||||
}
|
||||
|
||||
condition = parseDebugCondition();
|
||||
goto Lcondition;
|
||||
|
||||
|
@ -1012,20 +998,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
|||
nextToken();
|
||||
if (token.value == TOK.assign)
|
||||
{
|
||||
nextToken();
|
||||
if (token.value == TOK.identifier)
|
||||
s = new AST.VersionSymbol(token.loc, token.ident);
|
||||
else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
|
||||
s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue);
|
||||
else
|
||||
{
|
||||
error("identifier or integer expected, not `%s`", token.toChars());
|
||||
s = null;
|
||||
}
|
||||
nextToken();
|
||||
if (token.value != TOK.semicolon)
|
||||
error("semicolon expected");
|
||||
nextToken();
|
||||
s = parseVersionSpecification();
|
||||
break;
|
||||
}
|
||||
condition = parseVersionCondition();
|
||||
|
@ -2197,6 +2170,26 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
|||
return qualified;
|
||||
}
|
||||
|
||||
private AST.DebugSymbol parseDebugSpecification()
|
||||
{
|
||||
AST.DebugSymbol s;
|
||||
nextToken();
|
||||
if (token.value == TOK.identifier)
|
||||
s = new AST.DebugSymbol(token.loc, token.ident);
|
||||
else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
|
||||
s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue);
|
||||
else
|
||||
{
|
||||
error("identifier or integer expected, not `%s`", token.toChars());
|
||||
s = null;
|
||||
}
|
||||
nextToken();
|
||||
if (token.value != TOK.semicolon)
|
||||
error("semicolon expected");
|
||||
nextToken();
|
||||
return s;
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Parse a debug conditional
|
||||
*/
|
||||
|
@ -2223,6 +2216,29 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
|
|||
return new AST.DebugCondition(loc, mod, level, id);
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Parse a version specification
|
||||
*/
|
||||
private AST.VersionSymbol parseVersionSpecification()
|
||||
{
|
||||
AST.VersionSymbol s;
|
||||
nextToken();
|
||||
if (token.value == TOK.identifier)
|
||||
s = new AST.VersionSymbol(token.loc, token.ident);
|
||||
else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
|
||||
s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue);
|
||||
else
|
||||
{
|
||||
error("identifier or integer expected, not `%s`", token.toChars());
|
||||
s = null;
|
||||
}
|
||||
nextToken();
|
||||
if (token.value != TOK.semicolon)
|
||||
error("semicolon expected");
|
||||
nextToken();
|
||||
return s;
|
||||
}
|
||||
|
||||
/**************************************
|
||||
* Parse a version conditional
|
||||
*/
|
||||
|
@ -6053,10 +6069,14 @@ LagainStc:
|
|||
nextToken();
|
||||
if (token.value == TOK.assign)
|
||||
{
|
||||
error("debug conditions can only be declared at module scope");
|
||||
nextToken();
|
||||
nextToken();
|
||||
goto Lerror;
|
||||
if (auto ds = parseDebugSpecification())
|
||||
{
|
||||
if (ds.ident)
|
||||
ds.error("declaration must be at module level");
|
||||
else
|
||||
ds.error("level declaration must be at module level");
|
||||
}
|
||||
break;
|
||||
}
|
||||
cond = parseDebugCondition();
|
||||
goto Lcondition;
|
||||
|
@ -6065,10 +6085,14 @@ LagainStc:
|
|||
nextToken();
|
||||
if (token.value == TOK.assign)
|
||||
{
|
||||
error("version conditions can only be declared at module scope");
|
||||
nextToken();
|
||||
nextToken();
|
||||
goto Lerror;
|
||||
if (auto vs = parseVersionSpecification())
|
||||
{
|
||||
if (vs.ident)
|
||||
vs.error("declaration must be at module level");
|
||||
else
|
||||
vs.error("level declaration must be at module level");
|
||||
}
|
||||
break;
|
||||
}
|
||||
cond = parseVersionCondition();
|
||||
goto Lcondition;
|
||||
|
|
|
@ -315,6 +315,14 @@ extern (C++) abstract class Statement : ASTNode
|
|||
override void visit(ImportStatement s)
|
||||
{
|
||||
}
|
||||
|
||||
override void visit(CaseStatement s)
|
||||
{
|
||||
}
|
||||
|
||||
override void visit(DefaultStatement s)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
scope HasCode hc = new HasCode();
|
||||
|
|
|
@ -17,7 +17,9 @@ import core.stdc.stdio;
|
|||
extern(C++) class ParseTimeTransitiveVisitor(AST) : PermissiveVisitor!AST
|
||||
{
|
||||
alias visit = PermissiveVisitor!AST.visit;
|
||||
mixin ParseVisitMethods!AST;
|
||||
|
||||
mixin ParseVisitMethods!AST __methods;
|
||||
alias visit = __methods.visit;
|
||||
}
|
||||
|
||||
/* This mixin implements the AST traversal logic for parse time AST nodes. The same code
|
||||
|
|
|
@ -1843,7 +1843,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
|
|||
mtype.sym = e.isScopeExp().sds;
|
||||
break;
|
||||
case EXP.tuple:
|
||||
TupleExp te = e.toTupleExp();
|
||||
TupleExp te = e.isTupleExp();
|
||||
Objects* elems = new Objects(te.exps.dim);
|
||||
foreach (i; 0 .. elems.dim)
|
||||
{
|
||||
|
@ -2306,7 +2306,8 @@ extern (C++) Type merge(Type type)
|
|||
case Tident:
|
||||
case Tinstance:
|
||||
case Tmixin:
|
||||
return type;
|
||||
case Ttag:
|
||||
return type; // don't merge placeholder types
|
||||
|
||||
case Tsarray:
|
||||
// prevents generating the mangle if the array dim is not yet known
|
||||
|
@ -3904,7 +3905,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
|
|||
assert(e.op != EXP.dot);
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=14010
|
||||
if (ident == Id._mangleof)
|
||||
if (!(sc.flags & SCOPE.Cfile) && ident == Id._mangleof)
|
||||
{
|
||||
return mt.getProperty(sc, e.loc, ident, flag & 1);
|
||||
}
|
||||
|
@ -4656,7 +4657,7 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi
|
|||
{
|
||||
static if (LOGDEFAULTINIT)
|
||||
{
|
||||
printf("TypeBasic::defaultInit() '%s'\n", mt.toChars());
|
||||
printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt.toChars(), isCfile);
|
||||
}
|
||||
dinteger_t value = 0;
|
||||
|
||||
|
@ -4714,7 +4715,7 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi
|
|||
{
|
||||
static if (LOGDEFAULTINIT)
|
||||
{
|
||||
printf("TypeSArray::defaultInit() '%s'\n", mt.toChars());
|
||||
printf("TypeSArray::defaultInit() '%s' isCfile %d\n", mt.toChars(), isCfile);
|
||||
}
|
||||
if (mt.next.ty == Tvoid)
|
||||
return mt.tuns8.defaultInit(loc, isCfile);
|
||||
|
|
|
@ -84,7 +84,7 @@ extern (D) void writeFile(Loc loc, const(char)[] filename, const void[] data)
|
|||
ensurePathToNameExists(Loc.initial, filename);
|
||||
if (!File.update(filename, data))
|
||||
{
|
||||
error(loc, "Error writing file '%*.s'", cast(int) filename.length, filename.ptr);
|
||||
error(loc, "Error writing file '%.*s'", cast(int) filename.length, filename.ptr);
|
||||
fatal();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -396,6 +396,10 @@ frevert=all
|
|||
D RejectNegative
|
||||
Turn off all revertable D language features.
|
||||
|
||||
frevert=dip1000
|
||||
D RejectNegative
|
||||
Revert DIP1000: Scoped pointers.
|
||||
|
||||
frevert=dip25
|
||||
D RejectNegative
|
||||
Revert DIP25: Sealed references.
|
||||
|
|
|
@ -26,3 +26,10 @@ void issue19234()
|
|||
A[10] b;
|
||||
b[] = a[];
|
||||
}
|
||||
|
||||
/**********************************************/
|
||||
// https://issues.dlang.org/show_bug.cgi?id=22922
|
||||
void issue22922()
|
||||
{
|
||||
int[] x = [];
|
||||
}
|
||||
|
|
40
gcc/testsuite/gdc.test/compilable/test18216.d
Normal file
40
gcc/testsuite/gdc.test/compilable/test18216.d
Normal file
|
@ -0,0 +1,40 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=18216
|
||||
|
||||
struct Node
|
||||
{
|
||||
mixin Type!();
|
||||
Pointer left;
|
||||
}
|
||||
|
||||
mixin template Type()
|
||||
{
|
||||
alias Base = typeof(this);
|
||||
|
||||
static struct Proxy
|
||||
{
|
||||
struct Node
|
||||
{
|
||||
Base m_payload;
|
||||
}
|
||||
static immutable default_value = Base.init; // just remove this will work
|
||||
}
|
||||
|
||||
alias pNode = shared(Proxy.Node)*;
|
||||
|
||||
static struct Pointer
|
||||
{
|
||||
Base* _ptr;
|
||||
auto ptr()
|
||||
{
|
||||
return cast(pNode) _ptr;
|
||||
}
|
||||
|
||||
void opAssign(ref Pointer other) {} // just remove this will work
|
||||
|
||||
alias getThis this; // just remove this will work
|
||||
ref auto getThis() return
|
||||
{
|
||||
return ptr.m_payload;
|
||||
}
|
||||
}
|
||||
}
|
13
gcc/testsuite/gdc.test/compilable/test22635.d
Normal file
13
gcc/testsuite/gdc.test/compilable/test22635.d
Normal file
|
@ -0,0 +1,13 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=22635
|
||||
// opCast prevent calling destructor for const this
|
||||
|
||||
struct Foo
|
||||
{
|
||||
bool opCast(T : bool)() const { assert(0); }
|
||||
~this() {}
|
||||
}
|
||||
|
||||
struct Bar
|
||||
{
|
||||
const Foo foo;
|
||||
}
|
|
@ -1,8 +1,12 @@
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/diag11198.d(11): Error: version conditions can only be declared at module scope
|
||||
fail_compilation/diag11198.d(12): Error: debug conditions can only be declared at module scope
|
||||
fail_compilation/diag11198.d(15): Error: version `blah` declaration must be at module level
|
||||
fail_compilation/diag11198.d(16): Error: debug `blah` declaration must be at module level
|
||||
fail_compilation/diag11198.d(17): Error: version `1` level declaration must be at module level
|
||||
fail_compilation/diag11198.d(18): Error: debug `2` level declaration must be at module level
|
||||
fail_compilation/diag11198.d(19): Error: identifier or integer expected, not `""`
|
||||
fail_compilation/diag11198.d(20): Error: identifier or integer expected, not `""`
|
||||
---
|
||||
*/
|
||||
|
||||
|
@ -10,4 +14,8 @@ void main()
|
|||
{
|
||||
version = blah;
|
||||
debug = blah;
|
||||
version = 1;
|
||||
debug = 2;
|
||||
version = "";
|
||||
debug = "";
|
||||
}
|
||||
|
|
22
gcc/testsuite/gdc.test/fail_compilation/fail22202.d
Normal file
22
gcc/testsuite/gdc.test/fail_compilation/fail22202.d
Normal file
|
@ -0,0 +1,22 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=22202
|
||||
|
||||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail22202.d(21): Error: function `fail22202.fun(SystemCopy _param_0)` is not callable using argument types `(SystemCopy)`
|
||||
fail_compilation/fail22202.d(21): `inout ref inout(SystemCopy)(ref inout(SystemCopy) other)` copy constructor cannot be called from a `pure @safe nogc` context
|
||||
---
|
||||
*/
|
||||
|
||||
struct SystemCopy
|
||||
{
|
||||
this(ref inout SystemCopy other) inout {}
|
||||
}
|
||||
|
||||
void fun(SystemCopy) @safe pure @nogc {}
|
||||
|
||||
void main() @safe pure @nogc
|
||||
{
|
||||
SystemCopy s;
|
||||
fun(s);
|
||||
}
|
22
gcc/testsuite/gdc.test/fail_compilation/fail23036.d
Normal file
22
gcc/testsuite/gdc.test/fail_compilation/fail23036.d
Normal file
|
@ -0,0 +1,22 @@
|
|||
// https://issues.dlang.org/show_bug.cgi?id=23036
|
||||
|
||||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail23036.d(12): Error: `struct S` may not define both a rvalue constructor and a copy constructor
|
||||
fail_compilation/fail23036.d(15): rvalue constructor defined here
|
||||
fail_compilation/fail23036.d(14): copy constructor defined here
|
||||
---
|
||||
*/
|
||||
|
||||
struct S
|
||||
{
|
||||
this(ref S) {}
|
||||
this(S, int a = 2) {}
|
||||
}
|
||||
|
||||
void main()
|
||||
{
|
||||
S a;
|
||||
S b = a;
|
||||
}
|
|
@ -2,6 +2,13 @@
|
|||
REQUIRED_ARGS:
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/fail_scope.d(29): Deprecation: scope variable `da` may not be returned
|
||||
fail_compilation/fail_scope.d(31): Deprecation: scope variable `o` may not be returned
|
||||
fail_compilation/fail_scope.d(32): Deprecation: scope variable `dg` may not be returned
|
||||
fail_compilation/fail_scope.d(34): Deprecation: scope variable `da` may not be returned
|
||||
fail_compilation/fail_scope.d(36): Deprecation: scope variable `o` may not be returned
|
||||
fail_compilation/fail_scope.d(37): Deprecation: scope variable `dg` may not be returned
|
||||
fail_compilation/fail_scope.d(39): Deprecation: scope variable `p` may not be returned
|
||||
fail_compilation/fail_scope.d(44): Error: returning `cast(char[])string` escapes a reference to local variable `string`
|
||||
fail_compilation/fail_scope.d(62): Error: returning `s.bar()` escapes a reference to local variable `s`
|
||||
fail_compilation/fail_scope.d(73): Error: `fail_scope.foo8` called with argument types `(int)` matches both:
|
||||
|
@ -15,26 +22,19 @@ fail_compilation/fail_scope.d(107): Deprecation: escaping reference to outer loc
|
|||
fail_compilation/fail_scope.d(126): Error: returning `s.bar()` escapes a reference to local variable `s`
|
||||
fail_compilation/fail_scope.d(136): Error: returning `foo16226(i)` escapes a reference to local variable `i`
|
||||
---
|
||||
//fail_compilation/fail_scope.d(30): Error: scope variable `da` may not be returned
|
||||
//fail_compilation/fail_scope.d(32): Error: scope variable `o` may not be returned
|
||||
//fail_compilation/fail_scope.d(33): Error: scope variable `dg` may not be returned
|
||||
//fail_compilation/fail_scope.d(35): Error: scope variable `da` may not be returned
|
||||
//fail_compilation/fail_scope.d(37): Error: scope variable `o` may not be returned
|
||||
//fail_compilation/fail_scope.d(38): Error: scope variable `dg` may not be returned
|
||||
//fail_compilation/fail_scope.d(40): Error: scope variable `p` may not be returned
|
||||
*/
|
||||
|
||||
alias int delegate() dg_t;
|
||||
|
||||
int[] checkEscapeScope1(scope int[] da) { return da; }
|
||||
int[3] checkEscapeScope2(scope int[3] sa) { return sa; }
|
||||
Object checkEscapeScope3(scope Object o) { return o; }
|
||||
dg_t checkEscapeScope4(scope dg_t dg) { return dg; }
|
||||
int[] checkEscapeScope1(scope int[] da) @safe { return da; }
|
||||
int[3] checkEscapeScope2(scope int[3] sa) @safe { return sa; }
|
||||
Object checkEscapeScope3(scope Object o) @safe { return o; }
|
||||
dg_t checkEscapeScope4(scope dg_t dg) @safe { return dg; }
|
||||
|
||||
int[] checkEscapeScope1() { scope int[] da = []; return da; }
|
||||
int[3] checkEscapeScope2() { scope int[3] sa = [1,2,3]; return sa; }
|
||||
Object checkEscapeScope3() { scope Object o = new Object; return o; } // same with fail7294.d
|
||||
dg_t checkEscapeScope4() { scope dg_t dg = () => 1; return dg; }
|
||||
int[] checkEscapeScope1() @safe { scope int[] da = []; return da; }
|
||||
int[3] checkEscapeScope2() @safe { scope int[3] sa = [1,2,3]; return sa; }
|
||||
Object checkEscapeScope3() @safe { scope Object o = new Object; return o; } // same with fail7294.d
|
||||
dg_t checkEscapeScope4() @safe { scope dg_t dg = () => 1; return dg; }
|
||||
|
||||
int* test(scope int* p) @safe { return p; }
|
||||
|
||||
|
|
|
@ -201,8 +201,8 @@ void hmac(scope ubyte[] secret)
|
|||
|
||||
/* TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/retscope6.d(12011): Error: reference to local variable `x` assigned to non-scope parameter `r` calling retscope6.escape_m_20150
|
||||
fail_compilation/retscope6.d(12022): Error: reference to local variable `x` assigned to non-scope parameter `r` calling retscope6.escape_c_20150
|
||||
fail_compilation/retscope6.d(12011): Error: returning `escape_m_20150(& x)` escapes a reference to local variable `x`
|
||||
fail_compilation/retscope6.d(12022): Error: returning `escape_c_20150(& x)` escapes a reference to local variable `x`
|
||||
---
|
||||
*/
|
||||
|
||||
|
@ -210,23 +210,23 @@ fail_compilation/retscope6.d(12022): Error: reference to local variable `x` assi
|
|||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=20150
|
||||
|
||||
int* escape_m_20150(int* r) @safe pure
|
||||
int* escape_m_20150(int* r) @safe pure nothrow
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
int* f_m_20150() @safe
|
||||
int* f_m_20150() @safe nothrow
|
||||
{
|
||||
int x = 42;
|
||||
return escape_m_20150(&x);
|
||||
}
|
||||
|
||||
const(int)* escape_c_20150(const int* r) @safe pure
|
||||
const(int)* escape_c_20150(const int* r) @safe pure nothrow
|
||||
{
|
||||
return r;
|
||||
}
|
||||
|
||||
const(int)* f_c_20150() @safe
|
||||
const(int)* f_c_20150() @safe nothrow
|
||||
{
|
||||
int x = 42;
|
||||
return escape_c_20150(&x);
|
||||
|
@ -251,3 +251,39 @@ void escape_throw_20150() @safe
|
|||
immutable(char)[4] str;
|
||||
f_throw(str[]);
|
||||
}
|
||||
|
||||
/* TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/retscope6.d(14019): Error: scope variable `scopePtr` assigned to non-scope parameter `x` calling retscope6.noInfer23021
|
||||
fail_compilation/retscope6.d(14022): Error: scope variable `scopePtr` may not be returned
|
||||
---
|
||||
*/
|
||||
|
||||
#line 14000
|
||||
// https://issues.dlang.org/show_bug.cgi?id=23021
|
||||
|
||||
ref int infer23021(ref int* x) @safe pure nothrow
|
||||
{
|
||||
return *x;
|
||||
}
|
||||
|
||||
ref int noInfer23021(ref int* x, const(int)** escapeHole = null) @safe pure nothrow
|
||||
{
|
||||
*escapeHole = x;
|
||||
return *x;
|
||||
}
|
||||
|
||||
ref int escape23021() @safe
|
||||
{
|
||||
scope int* scopePtr;
|
||||
int* nonScopePtr = null;
|
||||
|
||||
// don't infer scope
|
||||
cast(void) noInfer23021(scopePtr); // error
|
||||
|
||||
// ensure we infer return scope
|
||||
return infer23021(scopePtr); // error
|
||||
|
||||
// ensure we do not infer return ref
|
||||
return infer23021(nonScopePtr); // no error
|
||||
}
|
||||
|
|
27
gcc/testsuite/gdc.test/fail_compilation/test22999.d
Normal file
27
gcc/testsuite/gdc.test/fail_compilation/test22999.d
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
REQUIRED_ARGS: -de
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/test22999.d(18): Deprecation: switch case fallthrough - use 'goto default;' if intended
|
||||
fail_compilation/test22999.d(25): Deprecation: switch case fallthrough - use 'goto case;' if intended
|
||||
---
|
||||
*/
|
||||
|
||||
// no switch fallthrough error with multi-valued case
|
||||
// https://issues.dlang.org/show_bug.cgi?id=22999
|
||||
void main()
|
||||
{
|
||||
int i;
|
||||
switch (0)
|
||||
{
|
||||
case 0, 1: i = 20;
|
||||
default: assert(0);
|
||||
}
|
||||
|
||||
switch (0)
|
||||
{
|
||||
default:
|
||||
case 0, 1: i = 20;
|
||||
case 2, 3: i = 30;
|
||||
}
|
||||
}
|
20
gcc/testsuite/gdc.test/fail_compilation/test23017.d
Normal file
20
gcc/testsuite/gdc.test/fail_compilation/test23017.d
Normal file
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
TEST_OUTPUT:
|
||||
---
|
||||
fail_compilation/test23017.d(16): Error: class `test23017.CppChildA` with C++ linkage cannot inherit from class `DClass` with D linkage
|
||||
---
|
||||
*/
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=23017
|
||||
// C++ class may not derive from D class
|
||||
extern(D) class DClass {}
|
||||
extern(C++) class CppClass
|
||||
{
|
||||
void foo();
|
||||
}
|
||||
|
||||
extern(C++) class CppChildA : DClass {} // error
|
||||
extern(C++) class CppChildB : CppClass {}
|
||||
|
||||
extern(D) class DChildA : DClass {}
|
||||
extern(D) class DChildB : CppClass {} // automatically made extern(C++)
|
|
@ -242,22 +242,6 @@ void test7435() {
|
|||
|
||||
/********************************************/
|
||||
|
||||
char[] dup12()(char[] a) // although inferred pure, don't infer a is 'return'
|
||||
{
|
||||
char[] res;
|
||||
foreach (ref e; a)
|
||||
{}
|
||||
return res;
|
||||
}
|
||||
|
||||
char[] foo12()
|
||||
{
|
||||
char[10] buf;
|
||||
return dup12(buf);
|
||||
}
|
||||
|
||||
/********************************************/
|
||||
|
||||
void test7049() @safe
|
||||
{
|
||||
int count = 0;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
9ba9a6ae2b8f6811cb85107cb56701df04f36ac6
|
||||
27834edb5e1613e3abd43e09880c36d9fc961938
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/druntime repository.
|
||||
|
|
|
@ -19,29 +19,6 @@ void __switch_errorT()(string file = __FILE__, size_t line = __LINE__) @trusted
|
|||
assert(0, "No appropriate switch clause found");
|
||||
}
|
||||
|
||||
version (D_BetterC)
|
||||
{
|
||||
// When compiling with -betterC we use template functions so if they are
|
||||
// used the bodies are copied into the user's program so there is no need
|
||||
// for the D runtime during linking.
|
||||
|
||||
// In the future we might want to convert all functions in this module to
|
||||
// templates even for ordinary builds instead of providing them as an
|
||||
// extern(C) library.
|
||||
|
||||
void onOutOfMemoryError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
|
||||
{
|
||||
assert(0, "Memory allocation failed");
|
||||
}
|
||||
alias onOutOfMemoryErrorNoGC = onOutOfMemoryError;
|
||||
|
||||
void onInvalidMemoryOperationError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
|
||||
{
|
||||
assert(0, "Invalid memory operation");
|
||||
}
|
||||
}
|
||||
else:
|
||||
|
||||
/**
|
||||
* Thrown on a range error.
|
||||
*/
|
||||
|
@ -218,17 +195,17 @@ private void rangeMsgPut(ref char[] r, scope const(char)[] e) @nogc nothrow pure
|
|||
*/
|
||||
class AssertError : Error
|
||||
{
|
||||
@safe pure nothrow this( string file, size_t line )
|
||||
@safe pure nothrow @nogc this( string file, size_t line )
|
||||
{
|
||||
this(cast(Throwable)null, file, line);
|
||||
}
|
||||
|
||||
@safe pure nothrow this( Throwable next, string file = __FILE__, size_t line = __LINE__ )
|
||||
@safe pure nothrow @nogc this( Throwable next, string file = __FILE__, size_t line = __LINE__ )
|
||||
{
|
||||
this( "Assertion failure", file, line, next);
|
||||
}
|
||||
|
||||
@safe pure nothrow this( string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null )
|
||||
@safe pure nothrow @nogc this( string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null )
|
||||
{
|
||||
super( msg, file, line, next );
|
||||
}
|
||||
|
@ -692,26 +669,49 @@ extern (C) void onFinalizeError( TypeInfo info, Throwable e, string file = __FIL
|
|||
throw staticError!FinalizeError(info, e, file, line);
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback for out of memory errors in D. An $(LREF OutOfMemoryError) will be
|
||||
* thrown.
|
||||
*
|
||||
* Throws:
|
||||
* $(LREF OutOfMemoryError).
|
||||
*/
|
||||
extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
|
||||
version (D_BetterC)
|
||||
{
|
||||
// NOTE: Since an out of memory condition exists, no allocation must occur
|
||||
// while generating this object.
|
||||
throw staticError!OutOfMemoryError();
|
||||
}
|
||||
// When compiling with -betterC we use template functions so if they are
|
||||
// used the bodies are copied into the user's program so there is no need
|
||||
// for the D runtime during linking.
|
||||
|
||||
extern (C) void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc
|
||||
// In the future we might want to convert all functions in this module to
|
||||
// templates even for ordinary builds instead of providing them as an
|
||||
// extern(C) library.
|
||||
|
||||
void onOutOfMemoryError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
|
||||
{
|
||||
assert(0, "Memory allocation failed");
|
||||
}
|
||||
alias onOutOfMemoryErrorNoGC = onOutOfMemoryError;
|
||||
|
||||
void onInvalidMemoryOperationError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
|
||||
{
|
||||
assert(0, "Invalid memory operation");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// suppress stacktrace until they are @nogc
|
||||
throw staticError!OutOfMemoryError(false);
|
||||
}
|
||||
/**
|
||||
* A callback for out of memory errors in D. An $(LREF OutOfMemoryError) will be
|
||||
* thrown.
|
||||
*
|
||||
* Throws:
|
||||
* $(LREF OutOfMemoryError).
|
||||
*/
|
||||
extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @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();
|
||||
}
|
||||
|
||||
extern (C) void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc
|
||||
{
|
||||
// suppress stacktrace until they are @nogc
|
||||
throw staticError!OutOfMemoryError(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback for invalid memory operations in D. An
|
||||
|
|
|
@ -2830,8 +2830,8 @@ extern (C)
|
|||
|
||||
private struct AA { void* impl; }
|
||||
// size_t _aaLen(in AA aa) pure nothrow @nogc;
|
||||
private void* _aaGetY(AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey) pure nothrow;
|
||||
private void* _aaGetX(AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey, out bool found) pure nothrow;
|
||||
private void* _aaGetY(scope AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey) pure nothrow;
|
||||
private void* _aaGetX(scope AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey, out bool found) pure nothrow;
|
||||
// inout(void)* _aaGetRvalueX(inout AA aa, in TypeInfo keyti, in size_t valsz, in void* pkey);
|
||||
inout(void[]) _aaValues(inout AA aa, const size_t keysz, const size_t valsz, const TypeInfo tiValueArray) pure nothrow;
|
||||
inout(void[]) _aaKeys(inout AA aa, const size_t keysz, const TypeInfo tiKeyArray) pure nothrow;
|
||||
|
|
|
@ -504,7 +504,7 @@ extern (C) size_t _aaLen(scope const AA aa) pure nothrow @nogc
|
|||
* If key was not in the aa, a mutable pointer to newly inserted value which
|
||||
* is set to all zeros
|
||||
*/
|
||||
extern (C) void* _aaGetY(AA* paa, const TypeInfo_AssociativeArray ti,
|
||||
extern (C) void* _aaGetY(scope AA* paa, const TypeInfo_AssociativeArray ti,
|
||||
const size_t valsz, scope const void* pkey)
|
||||
{
|
||||
bool found;
|
||||
|
@ -525,7 +525,7 @@ extern (C) void* _aaGetY(AA* paa, const TypeInfo_AssociativeArray ti,
|
|||
* If key was not in the aa, a mutable pointer to newly inserted value which
|
||||
* is set to all zeros
|
||||
*/
|
||||
extern (C) void* _aaGetX(AA* paa, const TypeInfo_AssociativeArray ti,
|
||||
extern (C) void* _aaGetX(scope AA* paa, const TypeInfo_AssociativeArray ti,
|
||||
const size_t valsz, scope const void* pkey, out bool found)
|
||||
{
|
||||
// lazily alloc implementation
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
c0cc5e917db105301dd1199b4b3c854626526407
|
||||
ac296f80cda437483b743f953dc69cb1271c82df
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the dlang/phobos repository.
|
||||
|
|
|
@ -130,7 +130,7 @@ PHOBOS_DSOURCES = etc/c/curl.d etc/c/zlib.d std/algorithm/comparison.d \
|
|||
std/experimental/typecons.d std/file.d std/format/internal/floats.d \
|
||||
std/format/internal/read.d std/format/internal/write.d \
|
||||
std/format/package.d std/format/read.d std/format/spec.d \
|
||||
std/format/write.d std/functional.d std/getopt.d \
|
||||
std/format/write.d std/functional.d std/getopt.d std/int128.d \
|
||||
std/internal/attributes.d std/internal/cstring.d \
|
||||
std/internal/math/biguintcore.d std/internal/math/biguintnoasm.d \
|
||||
std/internal/math/errorfunction.d std/internal/math/gammafunction.d \
|
||||
|
|
|
@ -228,6 +228,7 @@ am__dirstamp = $(am__leading_dot)dirstamp
|
|||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/spec.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/write.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/functional.lo std/getopt.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/int128.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/attributes.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/cstring.lo \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/math/biguintcore.lo \
|
||||
|
@ -591,7 +592,7 @@ libgphobos_la_LINK = $(LIBTOOL) --tag=D $(libgphobos_la_LIBTOOLFLAGS) \
|
|||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/experimental/typecons.d std/file.d std/format/internal/floats.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/internal/read.d std/format/internal/write.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/package.d std/format/read.d std/format/spec.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/write.d std/functional.d std/getopt.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/format/write.d std/functional.d std/getopt.d std/int128.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/attributes.d std/internal/cstring.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/math/biguintcore.d std/internal/math/biguintnoasm.d \
|
||||
@ENABLE_LIBDRUNTIME_ONLY_FALSE@ std/internal/math/errorfunction.d std/internal/math/gammafunction.d \
|
||||
|
@ -846,6 +847,7 @@ std/format/spec.lo: std/format/$(am__dirstamp)
|
|||
std/format/write.lo: std/format/$(am__dirstamp)
|
||||
std/functional.lo: std/$(am__dirstamp)
|
||||
std/getopt.lo: std/$(am__dirstamp)
|
||||
std/int128.lo: std/$(am__dirstamp)
|
||||
std/internal/$(am__dirstamp):
|
||||
@$(MKDIR_P) std/internal
|
||||
@: > std/internal/$(am__dirstamp)
|
||||
|
|
|
@ -63,7 +63,7 @@ import std.range.primitives : empty, front, isInputRange, isOutputRange,
|
|||
import std.traits : isArray;
|
||||
|
||||
// Make sure module header code examples work correctly.
|
||||
@safe unittest
|
||||
pure @safe unittest
|
||||
{
|
||||
ubyte[] data = [0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e];
|
||||
|
||||
|
@ -82,7 +82,7 @@ import std.traits : isArray;
|
|||
alias Base64 = Base64Impl!('+', '/');
|
||||
|
||||
///
|
||||
@safe unittest
|
||||
pure @safe unittest
|
||||
{
|
||||
ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f];
|
||||
assert(Base64.encode(data) == "g9cwegE/");
|
||||
|
@ -98,7 +98,7 @@ alias Base64 = Base64Impl!('+', '/');
|
|||
alias Base64URL = Base64Impl!('-', '_');
|
||||
|
||||
///
|
||||
@safe unittest
|
||||
pure @safe unittest
|
||||
{
|
||||
ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f];
|
||||
assert(Base64URL.encode(data) == "g9cwegE_");
|
||||
|
@ -114,7 +114,7 @@ alias Base64URL = Base64Impl!('-', '_');
|
|||
alias Base64URLNoPadding = Base64Impl!('-', '_', Base64.NoPadding);
|
||||
|
||||
///
|
||||
@safe unittest
|
||||
pure @safe unittest
|
||||
{
|
||||
ubyte[] data = [0x83, 0xd7, 0x30, 0x7b, 0xef];
|
||||
assert(Base64URLNoPadding.encode(data) == "g9cwe-8");
|
||||
|
@ -180,7 +180,7 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
|
|||
* Returns:
|
||||
* The length of a Base64 encoding of an array of the given length.
|
||||
*/
|
||||
@safe
|
||||
@safe @nogc
|
||||
pure nothrow size_t encodeLength(in size_t sourceLength)
|
||||
{
|
||||
static if (Padding == NoPadding)
|
||||
|
@ -218,8 +218,8 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
|
|||
* The slice of $(D_PARAM buffer) that contains the encoded string.
|
||||
*/
|
||||
@trusted
|
||||
pure char[] encode(R1, R2)(in R1 source, return scope R2 buffer) if (isArray!R1 && is(ElementType!R1 : ubyte) &&
|
||||
is(R2 == char[]))
|
||||
pure char[] encode(R1, R2)(const scope R1 source, return scope R2 buffer)
|
||||
if (isArray!R1 && is(ElementType!R1 : ubyte) && is(R2 == char[]))
|
||||
in
|
||||
{
|
||||
assert(buffer.length >= encodeLength(source.length), "Insufficient buffer for encoding");
|
||||
|
@ -277,9 +277,9 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
|
|||
}
|
||||
|
||||
///
|
||||
@safe unittest
|
||||
@nogc nothrow @safe unittest
|
||||
{
|
||||
ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f];
|
||||
ubyte[6] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f];
|
||||
char[32] buffer; // much bigger than necessary
|
||||
|
||||
// Just to be sure...
|
||||
|
@ -287,7 +287,7 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
|
|||
assert(buffer.length >= encodedLength);
|
||||
|
||||
// encode() returns a slice to the provided buffer.
|
||||
auto encoded = Base64.encode(data, buffer[]);
|
||||
auto encoded = Base64.encode(data[], buffer[]);
|
||||
assert(encoded is buffer[0 .. encodedLength]);
|
||||
assert(encoded == "g9cwegE/");
|
||||
}
|
||||
|
|
374
libphobos/src/std/int128.d
Normal file
374
libphobos/src/std/int128.d
Normal file
|
@ -0,0 +1,374 @@
|
|||
// Written in the D programming language
|
||||
/**
|
||||
* Implements a signed 128 bit integer type.
|
||||
*
|
||||
Author: Walter Bright
|
||||
Copyright: Copyright (c) 2022, D Language Foundation
|
||||
License: $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0)
|
||||
Source: $(PHOBOSSRC std/int128.d)
|
||||
*/
|
||||
module std.int128;
|
||||
|
||||
private import core.int128;
|
||||
|
||||
|
||||
/***********************************
|
||||
* 128 bit signed integer type.
|
||||
*/
|
||||
|
||||
public struct Int128
|
||||
{
|
||||
@safe pure nothrow @nogc:
|
||||
|
||||
Cent data; /// core.int128.Cent
|
||||
|
||||
/****************
|
||||
* Construct an `Int128` from a `long` value.
|
||||
* The upper 64 bits are formed by sign extension.
|
||||
* Params:
|
||||
* lo = signed lower 64 bits
|
||||
*/
|
||||
this(long lo)
|
||||
{
|
||||
data.lo = lo;
|
||||
data.hi = lo < 0 ? ~0L : 0;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Construct an `Int128` from a `ulong` value.
|
||||
* The upper 64 bits are set to zero.
|
||||
* Params:
|
||||
* lo = unsigned lower 64 bits
|
||||
*/
|
||||
this(ulong lo)
|
||||
{
|
||||
data.lo = lo;
|
||||
data.hi = 0;
|
||||
}
|
||||
|
||||
/****************
|
||||
* Construct an `Int128` from a `long` value.
|
||||
* Params:
|
||||
* hi = upper 64 bits
|
||||
* lo = lower 64 bits
|
||||
*/
|
||||
this(long hi, long lo)
|
||||
{
|
||||
data.hi = hi;
|
||||
data.lo = lo;
|
||||
}
|
||||
|
||||
/********************
|
||||
* Construct an `Int128` from a `Cent`.
|
||||
* Params:
|
||||
* data = Cent data
|
||||
*/
|
||||
this(Cent data)
|
||||
{
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
/********************
|
||||
* Returns: hash value for Int128
|
||||
*/
|
||||
size_t toHash() const
|
||||
{
|
||||
return cast(size_t)((data.lo & 0xFFFF_FFFF) + (data.hi & 0xFFFF_FFFF) + (data.lo >> 32) + (data.hi >> 32));
|
||||
}
|
||||
|
||||
/************************
|
||||
* Compare for equality
|
||||
* Params: lo = signed value to compare with
|
||||
* Returns: true if Int128 equals value
|
||||
*/
|
||||
bool opEquals(long lo) const
|
||||
{
|
||||
return data.lo == lo && data.hi == (lo >> 63);
|
||||
}
|
||||
|
||||
/************************
|
||||
* Compare for equality
|
||||
* Params: lo = unsigned value to compare with
|
||||
* Returns: true if Int128 equals value
|
||||
*/
|
||||
bool opEquals(ulong lo) const
|
||||
{
|
||||
return data.hi == 0 && data.lo == lo;
|
||||
}
|
||||
|
||||
/************************
|
||||
* Compare for equality
|
||||
* Params: op2 = value to compare with
|
||||
* Returns: true if Int128 equals value
|
||||
*/
|
||||
bool opEquals(Int128 op2) const
|
||||
{
|
||||
return data.hi == op2.data.hi && data.lo == op2.data.lo;
|
||||
}
|
||||
|
||||
/** Support unary arithmentic operator +
|
||||
* Params: op = "+"
|
||||
* Returns: lvalue of result
|
||||
*/
|
||||
Int128 opUnary(string op)() const
|
||||
if (op == "+")
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Support unary arithmentic operator - ~
|
||||
* Params: op = "-", "~"
|
||||
* Returns: lvalue of result
|
||||
*/
|
||||
Int128 opUnary(string op)() const
|
||||
if (op == "-" || op == "~")
|
||||
{
|
||||
static if (op == "-")
|
||||
return Int128(neg(this.data));
|
||||
else static if (op == "~")
|
||||
return Int128(com(this.data));
|
||||
}
|
||||
|
||||
/** Support unary arithmentic operator ++ --
|
||||
* Params: op = "++", "--"
|
||||
* Returns: lvalue of result
|
||||
*/
|
||||
Int128 opUnary(string op)()
|
||||
if (op == "++" || op == "--")
|
||||
{
|
||||
static if (op == "++")
|
||||
this.data = inc(this.data);
|
||||
else static if (op == "--")
|
||||
this.data = dec(this.data);
|
||||
else
|
||||
static assert(0, op);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Support casting to a bool
|
||||
* Params: T = bool
|
||||
* Returns: boolean result
|
||||
*/
|
||||
bool opCast(T : bool)() const
|
||||
{
|
||||
return tst(this.data);
|
||||
}
|
||||
|
||||
/** Support binary arithmetic operators + - * / % & | ^ << >> >>>
|
||||
* Params:
|
||||
* op = one of the arithmetic binary operators
|
||||
* op2 = second operand
|
||||
* Returns: value after the operation is applied
|
||||
*/
|
||||
Int128 opBinary(string op)(Int128 op2) const
|
||||
if (op == "+" || op == "-" ||
|
||||
op == "*" || op == "/" || op == "%" ||
|
||||
op == "&" || op == "|" || op == "^")
|
||||
{
|
||||
static if (op == "+")
|
||||
return Int128(add(this.data, op2.data));
|
||||
else static if (op == "-")
|
||||
return Int128(sub(this.data, op2.data));
|
||||
else static if (op == "*")
|
||||
return Int128(mul(this.data, op2.data));
|
||||
else static if (op == "/")
|
||||
return Int128(div(this.data, op2.data));
|
||||
else static if (op == "%")
|
||||
{
|
||||
Cent modulus;
|
||||
divmod(this.data, op2.data, modulus);
|
||||
return Int128(modulus);
|
||||
}
|
||||
else static if (op == "&")
|
||||
return Int128(and(this.data, op2.data));
|
||||
else static if (op == "|")
|
||||
return Int128(or(this.data, op2.data));
|
||||
else static if (op == "^")
|
||||
return Int128(xor(this.data, op2.data));
|
||||
else
|
||||
static assert(0, "wrong op value");
|
||||
}
|
||||
|
||||
/// ditto
|
||||
Int128 opBinary(string op)(long op2) const
|
||||
if (op == "+" || op == "-" ||
|
||||
op == "*" || op == "/" || op == "%" ||
|
||||
op == "&" || op == "|" || op == "^")
|
||||
{
|
||||
return mixin("this " ~ op ~ " Int128(0, op2)");
|
||||
}
|
||||
|
||||
/// ditto
|
||||
Int128 opBinaryRight(string op)(long op2) const
|
||||
if (op == "+" || op == "-" ||
|
||||
op == "*" || op == "/" || op == "%" ||
|
||||
op == "&" || op == "|" || op == "^")
|
||||
{
|
||||
mixin("return Int128(0, op2) " ~ op ~ " this;");
|
||||
}
|
||||
|
||||
/// ditto
|
||||
Int128 opBinary(string op)(long op2) const
|
||||
if (op == "<<")
|
||||
{
|
||||
return Int128(shl(this.data, cast(uint) op2));
|
||||
}
|
||||
|
||||
/// ditto
|
||||
Int128 opBinary(string op)(long op2) const
|
||||
if (op == ">>")
|
||||
{
|
||||
return Int128(sar(this.data, cast(uint) op2));
|
||||
}
|
||||
|
||||
/// ditto
|
||||
Int128 opBinary(string op)(long op2) const
|
||||
if (op == ">>>")
|
||||
{
|
||||
return Int128(shr(this.data, cast(uint) op2));
|
||||
}
|
||||
|
||||
/** arithmetic assignment operators += -= *= /= %= &= |= ^= <<= >>= >>>=
|
||||
* Params: op = one of +, -, etc.
|
||||
* op2 = second operand
|
||||
* Returns: lvalue of updated left operand
|
||||
*/
|
||||
ref Int128 opOpAssign(string op)(Int128 op2)
|
||||
if (op == "+" || op == "-" ||
|
||||
op == "*" || op == "/" || op == "%" ||
|
||||
op == "&" || op == "|" || op == "^" ||
|
||||
op == "<<" || op == ">>" || op == ">>>")
|
||||
{
|
||||
mixin("this = this " ~ op ~ " op2;");
|
||||
return this;
|
||||
}
|
||||
|
||||
/// ditto
|
||||
ref Int128 opOpAssign(string op)(long op2)
|
||||
if (op == "+" || op == "-" ||
|
||||
op == "*" || op == "/" || op == "%" ||
|
||||
op == "&" || op == "|" || op == "^" ||
|
||||
op == "<<" || op == ">>" || op == ">>>")
|
||||
{
|
||||
mixin("this = this " ~ op ~ " op2;");
|
||||
return this;
|
||||
}
|
||||
|
||||
/** support signed arithmentic comparison operators < <= > >=
|
||||
* Params: op2 = right hand operand
|
||||
* Returns: -1 for less than, 0 for equals, 1 for greater than
|
||||
*/
|
||||
int opCmp(Int128 op2) const
|
||||
{
|
||||
return this == op2 ? 0 : gt(this.data, op2.data) * 2 - 1;
|
||||
}
|
||||
|
||||
/** support signed arithmentic comparison operators < <= > >=
|
||||
* Params: op2 = right hand operand
|
||||
* Returns: -1 for less than, 0 for equals, 1 for greater than
|
||||
*/
|
||||
int opCmp(long op2) const
|
||||
{
|
||||
return opCmp(Int128(0, op2));
|
||||
}
|
||||
|
||||
enum min = Int128(long.min, 0); /// minimum value
|
||||
enum max = Int128(long.max, ulong.max); /// maximum value
|
||||
}
|
||||
|
||||
/********************************************* Tests ************************************/
|
||||
|
||||
version (unittest)
|
||||
{
|
||||
import core.stdc.stdio;
|
||||
|
||||
@trusted void print(Int128 c)
|
||||
{
|
||||
printf("%lld, %lld\n", c.data.hi, c.data.lo);
|
||||
}
|
||||
|
||||
@trusted void printx(Int128 c)
|
||||
{
|
||||
printf("%llx, %llx\n", c.data.hi, c.data.lo);
|
||||
}
|
||||
}
|
||||
|
||||
/// Int128 tests
|
||||
@safe pure nothrow @nogc
|
||||
unittest
|
||||
{
|
||||
Int128 c = Int128(5, 6);
|
||||
assert(c == c);
|
||||
assert(c == +c);
|
||||
assert(c == - -c);
|
||||
assert(~c == Int128(~5, ~6));
|
||||
++c;
|
||||
assert(c == Int128(5, 7));
|
||||
assert(--c == Int128(5, 6));
|
||||
assert(!!c);
|
||||
assert(!Int128());
|
||||
|
||||
assert(c + Int128(10, 20) == Int128(15, 26));
|
||||
assert(c - Int128(1, 2) == Int128(4, 4));
|
||||
assert(c * Int128(100, 2) == Int128(610, 12));
|
||||
assert(c / Int128(3, 2) == Int128(0, 1));
|
||||
assert(c % Int128(3, 2) == Int128(2, 4));
|
||||
assert((c & Int128(3, 2)) == Int128(1, 2));
|
||||
assert((c | Int128(3, 2)) == Int128(7, 6));
|
||||
assert((c ^ Int128(3, 2)) == Int128(6, 4));
|
||||
|
||||
assert(c + 15 == Int128(5, 21));
|
||||
assert(c - 15 == Int128(4, -9));
|
||||
assert(c * 15 == Int128(75, 90));
|
||||
assert(c / 15 == Int128(0, 6148914691236517205));
|
||||
assert(c % 15 == Int128(0, 11));
|
||||
assert((c & 15) == Int128(0, 6));
|
||||
assert((c | 15) == Int128(5, 15));
|
||||
assert((c ^ 15) == Int128(5, 9));
|
||||
|
||||
assert(15 + c == Int128(5, 21));
|
||||
assert(15 - c == Int128(-5, 9));
|
||||
assert(15 * c == Int128(75, 90));
|
||||
assert(15 / c == Int128(0, 0));
|
||||
assert(15 % c == Int128(0, 15));
|
||||
assert((15 & c) == Int128(0, 6));
|
||||
assert((15 | c) == Int128(5, 15));
|
||||
assert((15 ^ c) == Int128(5, 9));
|
||||
|
||||
assert(c << 1 == Int128(10, 12));
|
||||
assert(-c >> 1 == Int128(-3, 9223372036854775805));
|
||||
assert(-c >>> 1 == Int128(9223372036854775805, 9223372036854775805));
|
||||
|
||||
assert((c += 1) == Int128(5, 7));
|
||||
assert((c -= 1) == Int128(5, 6));
|
||||
assert((c += Int128(0, 1)) == Int128(5, 7));
|
||||
assert((c -= Int128(0, 1)) == Int128(5, 6));
|
||||
assert((c *= 2) == Int128(10, 12));
|
||||
assert((c /= 2) == Int128(5, 6));
|
||||
assert((c %= 2) == Int128());
|
||||
c += Int128(5, 6);
|
||||
assert((c *= Int128(10, 20)) == Int128(160, 120));
|
||||
assert((c /= Int128(10, 20)) == Int128(0, 15));
|
||||
c += Int128(72, 0);
|
||||
assert((c %= Int128(10, 20)) == Int128(1, -125));
|
||||
assert((c &= Int128(3, 20)) == Int128(1, 0));
|
||||
assert((c |= Int128(8, 2)) == Int128(9, 2));
|
||||
assert((c ^= Int128(8, 2)) == Int128(1, 0));
|
||||
c |= Int128(10, 5);
|
||||
assert((c <<= 1) == Int128(11 * 2, 5 * 2));
|
||||
assert((c >>>= 1) == Int128(11, 5));
|
||||
c = Int128(long.min, long.min);
|
||||
assert((c >>= 1) == Int128(long.min >> 1, cast(ulong) long.min >> 1));
|
||||
|
||||
assert(-Int128.min == Int128.min);
|
||||
assert(Int128.max + 1 == Int128.min);
|
||||
|
||||
c = Int128(5, 6);
|
||||
assert(c < Int128(6, 5));
|
||||
assert(c > 10);
|
||||
|
||||
c = Int128(-1UL);
|
||||
assert(c == -1UL);
|
||||
c = Int128(-1L);
|
||||
assert(c == -1L);
|
||||
}
|
|
@ -1519,7 +1519,7 @@ if (isSomeChar!C)
|
|||
import std.range;
|
||||
// ir() wraps an array in a plain (i.e. non-forward) input range, so that
|
||||
// we can test both code paths
|
||||
InputRange!(C[]) ir(C)(C[][] p...) { return inputRangeObject(p); }
|
||||
InputRange!(C[]) ir(C)(C[][] p...) { return inputRangeObject(p.dup); }
|
||||
version (Posix)
|
||||
{
|
||||
assert(buildPath("foo") == "foo");
|
||||
|
|
|
@ -1422,6 +1422,11 @@ if (isCallable!func)
|
|||
enum val = "val" ~ (name == "val" ? "_" : "");
|
||||
enum ptr = "ptr" ~ (name == "ptr" ? "_" : "");
|
||||
mixin("
|
||||
enum hasDefaultArg = (PT[i .. i+1] " ~ args ~ ") { return true; };
|
||||
");
|
||||
static if (is(typeof(hasDefaultArg())))
|
||||
{
|
||||
mixin("
|
||||
// workaround scope escape check, see
|
||||
// https://issues.dlang.org/show_bug.cgi?id=16582
|
||||
// should use return scope once available
|
||||
|
@ -1432,10 +1437,9 @@ if (isCallable!func)
|
|||
auto " ~ val ~ " = " ~ args ~ "[0];
|
||||
auto " ~ ptr ~ " = &" ~ val ~ ";
|
||||
return *" ~ ptr ~ ";
|
||||
};
|
||||
");
|
||||
static if (is(typeof(get())))
|
||||
};");
|
||||
enum Get = get();
|
||||
}
|
||||
else
|
||||
alias Get = void;
|
||||
// If default arg doesn't exist, returns void instead.
|
||||
|
@ -1483,6 +1487,17 @@ if (isCallable!func)
|
|||
static foreach (V; Voids) static assert(is(V == void));
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=20182
|
||||
@safe pure nothrow @nogc unittest
|
||||
{
|
||||
struct S
|
||||
{
|
||||
this(ref S) {}
|
||||
}
|
||||
|
||||
static assert(__traits(compiles, ParameterDefaults!(S.__ctor)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Alternate name for $(LREF ParameterDefaults), kept for legacy compatibility.
|
||||
*/
|
||||
|
|
Loading…
Add table
Reference in a new issue