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:
Iain Buclaw 2022-04-21 14:25:26 +01:00
parent 93dd7f36f2
commit ae56e2da05
50 changed files with 1002 additions and 302 deletions

View file

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

View file

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

View file

@ -1 +1 @@
v2.099.1
v2.100.0-beta.1

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -26,3 +26,10 @@ void issue19234()
A[10] b;
b[] = a[];
}
/**********************************************/
// https://issues.dlang.org/show_bug.cgi?id=22922
void issue22922()
{
int[] x = [];
}

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

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

View file

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

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

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

View file

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

View file

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

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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