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;
-4d1bfcf142928cf1c097b0a2689485c1b14f4f53
+eb7bee331a13026eeb4dcbf9d43d5d4e744a4d26
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
-v2.099.1
+v2.100.0-beta.1
}
/**
+ * 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.
*/
enum MODFlags : int
{
+ none = 0, // default (mutable)
const_ = 1, // type is const
immutable_ = 4, // type is immutable
shared_ = 2, // type is shared
// 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);
}
}
}
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;
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())
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)
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);
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);
}
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))
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())
{
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;
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;
}
// 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);
}
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;
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;
}
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());
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);
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;
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();
*/
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;
}
}
if (v.isDataseg())
continue;
- if (global.params.useDIP1000 == FeatureState.enabled)
+ if (global.params.useDIP1000 != FeatureState.disabled)
{
if (va && va.isScope() && !v.isReference())
{
{
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;
+ }
}
}
}
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
*/
!(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;
}
}
)
{
// 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;
}
va.maybes = new VarDeclarations();
va.maybes.push(v);
}
+
+
+private bool setUnsafeDIP1000(FuncDeclaration f)
+{
+ return global.params.useDIP1000 == FeatureState.enabled
+ ? f.setUnsafe()
+ : f.isSafeBypassingInference();
+}
return null;
}
- TupleExp toTupleExp()
- {
- return null;
- }
-
/***************************************
* Return !=0 if expression is an lvalue.
*/
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; }
return new TupleExp(loc, exps);
}
- override TupleExp toTupleExp()
- {
- return this;
- }
-
override TupleExp syntaxCopy()
{
return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps));
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);
Expressions *exps;
static TupleExp *create(const Loc &loc, Expressions *exps);
- TupleExp *toTupleExp();
TupleExp *syntaxCopy();
bool equals(const RootObject *o) const;
//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.
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.
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.
*/
}
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());
if (Expression ex = unaSemantic(exp, sc))
return ex;
- if (exp.ident == Id._mangleof)
+ if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
{
// symbol.mangleof
//{ 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.
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)
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();
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;
*/
extern (C++) Expression initializerToExpression(Initializer init, Type itype = null, const bool isCfile = false)
{
+ //printf("initializerToExpression() isCfile: %d\n", isCfile);
+
Expression visitVoid(VoidInitializer)
{
return null;
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;
Expression visitC(CInitializer i)
{
- //printf("CInitializer.initializerToExpression()\n");
+ //printf("CInitializer.initializerToExpression(null, true)\n");
return null;
}
{
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;
}
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
/* If haven't inferred the return type yet, can't infer storage classes
*/
- if (!nextOf())
+ if (!nextOf() || !isnothrow())
return stc;
purityLevel();
}
}
- /* 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)
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;
}
}
*/
enum MODFlags
{
+ MODnone = 0, // default (mutable)
MODconst = 1, // type is const
MODimmutable = 4, // type is immutable
MODshared = 2, // type is shared
void purityLevel();
bool hasLazyParameters();
bool isDstyleVariadic() const;
- bool parameterEscapes(Parameter *p);
StorageClass parameterStorageClass(Parameter *p);
Type *addStorageClass(StorageClass stc);
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();
}
}
+ 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;
}
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;
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();
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
*/
}
/**************************************
+ * 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
*/
private AST.Condition parseVersionCondition()
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;
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;
override void visit(ImportStatement s)
{
}
+
+ override void visit(CaseStatement s)
+ {
+ }
+
+ override void visit(DefaultStatement s)
+ {
+ }
}
scope HasCode hc = new HasCode();
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
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)
{
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
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);
}
{
static if (LOGDEFAULTINIT)
{
- printf("TypeBasic::defaultInit() '%s'\n", mt.toChars());
+ printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt.toChars(), isCfile);
}
dinteger_t value = 0;
{
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);
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();
}
}
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.
A[10] b;
b[] = a[];
}
+
+/**********************************************/
+// https://issues.dlang.org/show_bug.cgi?id=22922
+void issue22922()
+{
+ int[] x = [];
+}
--- /dev/null
+// 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;
+ }
+ }
+}
--- /dev/null
+// 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;
+}
/*
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 `""`
---
*/
{
version = blah;
debug = blah;
+ version = 1;
+ debug = 2;
+ version = "";
+ debug = "";
}
--- /dev/null
+// 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);
+}
--- /dev/null
+// 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;
+}
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:
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; }
/* 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`
---
*/
// 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);
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
+}
--- /dev/null
+/*
+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;
+ }
+}
--- /dev/null
+/*
+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++)
/********************************************/
-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;
-9ba9a6ae2b8f6811cb85107cb56701df04f36ac6
+27834edb5e1613e3abd43e09880c36d9fc961938
The first line of this file holds the git revision number of the last
merge done from the dlang/druntime repository.
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.
*/
*/
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 );
}
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
-{
- // suppress stacktrace until they are @nogc
- throw staticError!OutOfMemoryError(false);
+ // 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
+{
+ /**
+ * 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
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;
* 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;
* 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
-c0cc5e917db105301dd1199b4b3c854626526407
+ac296f80cda437483b743f953dc69cb1271c82df
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
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 \
@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 \
@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 \
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)
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];
alias Base64 = Base64Impl!('+', '/');
///
-@safe unittest
+pure @safe unittest
{
ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f];
assert(Base64.encode(data) == "g9cwegE/");
alias Base64URL = Base64Impl!('-', '_');
///
-@safe unittest
+pure @safe unittest
{
ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f];
assert(Base64URL.encode(data) == "g9cwegE_");
alias Base64URLNoPadding = Base64Impl!('-', '_', Base64.NoPadding);
///
-@safe unittest
+pure @safe unittest
{
ubyte[] data = [0x83, 0xd7, 0x30, 0x7b, 0xef];
assert(Base64URLNoPadding.encode(data) == "g9cwe-8");
* 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)
* 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");
}
///
- @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...
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/");
}
--- /dev/null
+// 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);
+}
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");
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
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.
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.
*/