-c57da0cf5945cfb45eed06f1fd820435cda3ee3a
+c7902293d7df9d02546562cb09fc8439004a70d1
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
-v2.110.0-beta.1
+v2.110.0-rc.1
{
foreach (params; pparams)
{
- auto p = aggrfe ? (*aggrfe.parameters)[i] : rangefe.prm;
+ auto p = aggrfe ? (*aggrfe.parameters)[i] : rangefe.param;
params.push(new Parameter(aloc, p.storageClass, p.type, p.ident, null, null));
}
}
*pue = Slice(e.type, se.e1, se.lwr, se.upr);
return pue.exp();
}
- else
- return Slice(e.type, se.e1, se.lwr, se.upr).copy();
+ return Slice(e.type, se.e1, se.lwr, se.upr).copy();
}
/* Determine the array length, without interpreting it.
case Tint16:
if (ty == Tuns64 && value & ~0x7FFFU)
return MATCH.nomatch;
- else if (cast(short)value != value)
+ if (cast(short)value != value)
return MATCH.nomatch;
break;
if (eoff.op == EXP.int64 && eoff.toInteger() == 0)
{
}
- else if (sc.setUnsafe(false, be.loc, "pointer arithmetic not allowed in @safe functions"))
+ else if (sc.setUnsafe(false, be.loc, "pointer arithmetic"))
{
return ErrorExp.get();
}
bool nothrowInprocess(bool v);
bool nogcInprocess() const;
bool nogcInprocess(bool v);
+ bool saferD() const;
+ bool saferD(bool v);
bool scopeInprocess() const;
bool scopeInprocess(bool v);
bool inlineScanned() const;
bool canFree; /// is on free list
bool fullinst; /// fully instantiate templates
bool ctfeBlock; /// inside a `if (__ctfe)` block
- bool dip1000; /// dip1000 errors enabled for this scope
- bool dip25; /// dip25 errors enabled for this scope
+}
+
+/// State of -preview switches
+///
+/// By making them part of a Scope, we reduce reliance on dmd.globals,
+/// and can enable/disable them per module / edition.
+private struct Previews
+{
+ // Run `dmd -preview=h` for the meaning of these switches
+ private extern (D) static struct BitFields
+ {
+ bool bitfields;
+ bool dip1000;
+ bool dip1008;
+ bool dip1021;
+ bool dip25;
+ bool fixAliasThis;
+ bool fixImmutableConv;
+ bool in_;
+ bool inclusiveInContracts;
+ bool noSharedAccess;
+ bool rvalueRefParam;
+ bool safer;
+ FeatureState systemVariables;
+ }
+
+ import dmd.common.bitfields : generateBitFields;
+ mixin(generateBitFields!(BitFields, ushort));
+
+ void setFromParams(ref Param params) @nogc nothrow pure @safe
+ {
+ this.bitfields = params.bitfields;
+ this.dip1000 = params.useDIP1000 == FeatureState.enabled;
+ this.dip1008 = params.ehnogc;
+ this.dip1021 = params.useDIP1021; // == FeatureState.enabled;
+ this.dip25 = params.useDIP25 == FeatureState.enabled;
+ this.fixAliasThis = params.fixAliasThis;
+ this.fixImmutableConv = params.fixImmutableConv;
+ this.in_ = params.previewIn;
+ this.inclusiveInContracts = params.inclusiveInContracts;
+ this.noSharedAccess = params.noSharedAccess == FeatureState.enabled;
+ this.rvalueRefParam = params.rvalueRefParam == FeatureState.enabled;
+ this.safer = params.safer == FeatureState.enabled;
+ this.systemVariables = params.systemVariables;
+ }
}
extern (C++) struct Scope
DeprecatedDeclaration depdecl; /// customized deprecation message
import dmd.common.bitfields : generateBitFields;
- mixin(generateBitFields!(BitFields, uint));
+ mixin(generateBitFields!(BitFields, ushort));
+
+ Previews previews;
// user defined attributes
UserAttributeDeclaration userAttribDecl;
m = m.parent;
m.addMember(null, sc.scopesym);
m.parent = null; // got changed by addMember()
- if (global.params.useDIP1000 == FeatureState.enabled)
- sc.dip1000 = true;
- if (global.params.useDIP25 == FeatureState.enabled)
- sc.dip25 = true;
+ sc.previews.setFromParams(global.params);
+
if (_module.filetype == FileType.c)
sc.inCfile = true;
// Create the module scope underneath the global scope
s.ignoresymbolvisibility = this.ignoresymbolvisibility;
s.inCfile = this.inCfile;
s.ctfeBlock = this.ctfeBlock;
- s.dip1000 = this.dip1000;
- s.dip25 = this.dip25;
-
+ s.previews = this.previews;
s.lastdc = null;
assert(&this != s);
return s;
}
NotFound:
- if (global.params.fixAliasThis)
+ if (sc.previews.fixAliasThis)
{
Expression exp = new ThisExp(loc);
if (Dsymbol aliasSym = checkAliasThis(sc.scopesym.isAggregateDeclaration(), ident, flags, &exp))
/// Returns: whether to raise DIP1000 warnings (FeatureStabe.default) or errors (FeatureState.enabled)
extern (D) FeatureState useDIP1000()
{
- return (this.dip1000 || hasEdition(Edition.v2024)) ? FeatureState.enabled : FeatureState.disabled;
+ return (this.previews.dip1000 || hasEdition(Edition.v2024)) ? FeatureState.enabled : FeatureState.disabled;
}
/// Returns: whether to raise DIP25 warnings (FeatureStabe.default) or errors (FeatureState.enabled)
extern (D) FeatureState useDIP25()
{
- return (this.dip25 || hasEdition(Edition.v2024)) ? FeatureState.enabled : FeatureState.disabled;
+ return (this.previews.dip25 || hasEdition(Edition.v2024)) ? FeatureState.enabled : FeatureState.disabled;
}
/// Returns: whether this scope compiles with `edition` or later
continue;
if (sa == p1)
return true;
- else if (p2 && sa == p2)
+ if (p2 && sa == p2)
return true;
}
outer = ti.tempdecl.toParent();
// Calculate type size + safety checks
if (dsym.storage_class & STC.gshared && !dsym.isMember())
{
- sc.setUnsafe(false, dsym.loc, "__gshared not allowed in safe functions; use shared");
+ sc.setUnsafe(false, dsym.loc, "using `__gshared` instead of `shared`");
}
Dsymbol parent = dsym.toParent();
if (dsym.type.hasPointers()) // also computes type size
sc.setUnsafe(false, dsym.loc,
- "`void` initializers for pointers not allowed in safe functions");
+ "`void` initializing a pointer");
else if (dsym.type.hasInvariant())
sc.setUnsafe(false, dsym.loc,
- "`void` initializers for structs with invariants are not allowed in safe functions");
+ "`void` initializing a struct with an invariant");
else if (dsym.type.toBasetype().ty == Tbool)
sc.setUnsafePreview(global.params.systemVariables, false, dsym.loc,
- "a `bool` must be 0 or 1, so void intializing it is not allowed in safe functions");
+ "void intializing a bool (which must always be 0 or 1)");
else if (dsym.type.hasUnsafeBitpatterns())
sc.setUnsafePreview(global.params.systemVariables, false, dsym.loc,
- "`void` initializers for types with unsafe bit patterns are not allowed in safe functions");
+ "`void` initializing a type with unsafe bit patterns");
}
else if (!dsym._init &&
!(dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field | STC.parameter)) &&
dsym.type.hasVoidInitPointers())
{
- sc.setUnsafe(false, dsym.loc, "`void` initializers for pointers not allowed in safe functions");
+ sc.setUnsafe(false, dsym.loc, "`void` initializers for pointers");
}
}
{
import dmd.escape : setUnsafeDIP1000;
const inSafeFunc = sc.func && sc.func.isSafeBypassingInference(); // isSafeBypassingInference may call setUnsafe().
- if (setUnsafeDIP1000(*sc, false, dsym.loc, "`scope` allocation of `%s` requires that constructor be annotated with `scope`", dsym))
+ if (setUnsafeDIP1000(*sc, false, dsym.loc, "`scope` allocation of `%s` with a non-`scope` constructor", dsym))
errorSupplemental(ne.member.loc, "is the location of the constructor");
}
ne.onstack = 1;
if (dsym.errors)
return;
- if (!(global.params.bitfields || sc.inCfile))
+ if (!(sc.previews.bitfields || sc.inCfile))
{
version (IN_GCC)
.error(dsym.loc, "%s `%s` use `-fpreview=bitfields` for bitfield support", dsym.kind, dsym.toPrettyChars);
// Try to convert Expression to symbol
if (auto ve = ea.isVarExp())
return ve.var;
- else if (auto fe = ea.isFuncExp())
+ if (auto fe = ea.isFuncExp())
return fe.td ? fe.td : fe.fd;
- else if (auto te = ea.isTemplateExp())
+ if (auto te = ea.isTemplateExp())
return te.td;
- else if (auto te = ea.isScopeExp())
+ if (auto te = ea.isScopeExp())
return te.sds;
else
return null;
if (assertmsg)
{
result |= sc.setUnsafeDIP1000(gag, arg.loc,
- desc ~ " `%s` assigned to non-scope parameter calling `assert()`", v);
+ "assigning" ~ desc ~ " `%s` to non-scope parameter calling `assert()`", v);
return;
}
const(char)* msg =
(isThis) ? (desc ~ " `%s` calling non-scope member function `%s.%s()`") :
- (fdc && parId) ? (desc ~ " `%s` assigned to non-scope parameter `%s` calling `%s`") :
- (fdc && !parId) ? (desc ~ " `%s` assigned to non-scope anonymous parameter calling `%s`") :
- (!fdc && parId) ? (desc ~ " `%s` assigned to non-scope parameter `%s`") :
+ (fdc && parId) ? ("assigning " ~ desc ~ " `%s` to non-scope parameter `%s` calling `%s`") :
+ (fdc && !parId) ? ("assigning " ~ desc ~ " `%s` to non-scope anonymous parameter calling `%s`") :
+ (!fdc && parId) ? ("assigning " ~ desc ~ " `%s` to non-scope parameter `%s`") :
(desc ~ " `%s` assigned to non-scope anonymous parameter");
if (isThis ?
if (parStc & STC.scope_)
return;
const(char)* msg = parId ?
- "reference to stack allocated value returned by `%s` assigned to non-scope parameter `%s`" :
- "reference to stack allocated value returned by `%s` assigned to non-scope anonymous parameter";
+ "assigning reference to stack allocated value returned by `%s` to non-scope parameter `%s`" :
+ "assigning reference to stack allocated value returned by `%s` to non-scope anonymous parameter";
result |= sc.setUnsafeDIP1000(gag, ee.loc, msg, ee, parId);
}
{
case EnclosedBy.none: assert(0);
case EnclosedBy.returnScope:
- msg = "scope variable `%s` assigned to return scope `%s`";
+ msg = "assigning scope variable `%s` to return scope `%s`";
break;
case EnclosedBy.longerScope:
- msg = "scope variable `%s` assigned to `%s` with longer lifetime";
+ msg = "assigning scope variable `%s` to `%s` with longer lifetime";
break;
case EnclosedBy.refVar:
- msg = "scope variable `%s` assigned to `ref` variable `%s` with longer lifetime";
+ msg = "assigning scope variable `%s` to `ref` variable `%s` with longer lifetime";
break;
case EnclosedBy.global:
- msg = "scope variable `%s` assigned to global variable `%s`";
+ msg = "assigning scope variable `%s` to global variable `%s`";
break;
}
}
return;
}
- result |= sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to non-scope `%s`", v, e1);
+ result |= sc.setUnsafeDIP1000(gag, ae.loc, "assigning scope variable `%s` to non-scope `%s`", v, e1);
}
else
{
else
{
result |= sc.setUnsafeDIP1000(gag, ae.loc,
- "address of local variable `%s` assigned to return scope `%s`", v, va);
+ "assigning address of local variable `%s` to return scope `%s`", v, va);
}
}
// If va's lifetime encloses v's, then error
if (va && !(vaIsFirstRef && v.isReturn()) && va.enclosesLifetimeOf(v))
{
- if (sc.setUnsafeDIP1000(gag, ae.loc, "address of variable `%s` assigned to `%s` with longer lifetime", v, va))
+ if (sc.setUnsafeDIP1000(gag, ae.loc, "assigning address of variable `%s` to `%s` with longer lifetime", v, va))
{
result = true;
return;
return;
}
- result |= sc.setUnsafeDIP1000(gag, ae.loc, "reference to local variable `%s` assigned to non-scope `%s`", v, e1);
+ result |= sc.setUnsafeDIP1000(gag, ae.loc, "assigning reference to local variable `%s` to non-scope `%s`", v, e1);
}
void onFunc(FuncDeclaration func, bool called)
return;
}
result |= sc.setUnsafeDIP1000(gag, ae.loc,
- "reference to local `%s` assigned to non-scope `%s` in @safe code", v, e1);
+ "assigning reference to local `%s` to non-scope `%s`", v, e1);
}
}
}
const(char)* msg = (ee.op == EXP.structLiteral) ?
- "address of struct literal `%s` assigned to `%s` with longer lifetime" :
- "address of expression temporary returned by `%s` assigned to `%s` with longer lifetime";
+ "assigning address of struct literal `%s` to `%s` with longer lifetime" :
+ "assigning address of expression temporary returned by `%s` to `%s` with longer lifetime";
result |= sc.setUnsafeDIP1000(gag, ee.loc, msg, ee, e1);
}
// despite being `scope`
{
// https://issues.dlang.org/show_bug.cgi?id=17029
- result |= sc.setUnsafeDIP1000(gag, e.loc, "scope variable `%s` may not be thrown", v);
+ result |= sc.setUnsafeDIP1000(gag, e.loc, "throwing scope variable `%s`", v);
return;
}
else
!(p.parent == sc.func))
{
// https://issues.dlang.org/show_bug.cgi?id=20868
- result |= sc.setUnsafeDIP1000(gag, e.loc, "scope variable `%s` may not be copied into allocated memory", v);
+ result |= sc.setUnsafeDIP1000(gag, e.loc, "copying scope variable `%s` into allocated memory", v);
return;
}
}
bool escapingRef(VarDeclaration v, FeatureState fs)
{
const(char)* msg = v.isParameter() ?
- "copying `%s` into allocated memory escapes a reference to parameter `%s`" :
- "copying `%s` into allocated memory escapes a reference to local variable `%s`";
- return setUnsafePreview(&sc, fs, gag, e.loc, msg, e, v);
+ "escaping a reference to parameter `%s` by copying `%s` into allocated memory" :
+ "escaping a reference to local variable `%s` by copying `%s` into allocated memory";
+ return setUnsafePreview(&sc, fs, gag, e.loc, msg, v, e);
}
Dsymbol p = v.toParent2();
{
if (called)
result |= sc.setUnsafeDIP1000(gag, e.loc,
- "nested function `%s` returns `scope` values and escapes them into allocated memory", fd);
+ "escaping a `scope` value returned from nested function `%s` into allocated memory", fd);
}
void onExp(Expression ee, bool retRefTransition)
{
if (log) printf("byexp %s\n", ee.toChars());
if (!gag)
- sc.eSink.error(ee.loc, "storing reference to stack allocated value returned by `%s` into allocated memory causes it to escape",
+ sc.eSink.error(ee.loc, "escaping reference to stack allocated value returned by `%s` into allocated memory",
ee.toChars());
result = true;
}
else
{
// https://issues.dlang.org/show_bug.cgi?id=17029
- result |= sc.setUnsafeDIP1000(gag, e.loc, "scope variable `%s` may not be returned", v);
+ result |= sc.setUnsafeDIP1000(gag, e.loc, "returning scope variable `%s`", v);
return;
}
}
// depending on the flag passed to the CLI for DIP25
void escapingRef(VarDeclaration v, FeatureState featureState)
{
- const(char)* msg = v.isParameter() ?
- "returning `%s` escapes a reference to parameter `%s`" :
- "returning `%s` escapes a reference to local variable `%s`";
-
+ const(char)* safeMsg = v.isParameter() ?
+ "escaping a reference to parameter `%s` by returning `%s`" :
+ "escaping a reference to local variable `%s` by returning `%s` ";
if (v.isParameter() && v.isReference())
{
- if (setUnsafePreview(&sc, featureState, gag, e.loc, msg, e, v) ||
+ if (setUnsafePreview(&sc, featureState, gag, e.loc, safeMsg, v, e) ||
sc.func.isSafeBypassingInference())
{
result = true;
{
if (retRefTransition)
{
- result |= sc.setUnsafeDIP1000(gag, e.loc, msg, e, v);
+ result |= sc.setUnsafeDIP1000(gag, e.loc, safeMsg, v, e);
}
else
{
+ const(char)* msg = v.isParameter() ?
+ "returning `%s` escapes a reference to parameter `%s`" :
+ "returning `%s` escapes a reference to local variable `%s`";
if (!gag)
previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, msg, e.toChars(), v.toChars());
result = true;
// take address of `scope` variable not allowed, requires transitive scope
return sc.setUnsafeDIP1000(gag, e.loc,
- "cannot take address of `scope` variable `%s` since `scope` applies to first indirection only", v);
+ "taking address of `scope` variable `%s` with pointers", v);
}
/****************************
{
if (sd.isSystem())
{
- if (sc.setUnsafePreview(global.params.systemVariables, false, loc,
- "cannot access `@system` variable `%s` in @safe code", sd))
+ if (sc.setUnsafePreview(sc.previews.systemVariables, false, loc,
+ "access `@system` variable `%s`", sd))
{
if (auto v = sd.isVarDeclaration())
{
*/
if (v.storage_class & STC.gshared)
{
- if (sc.setUnsafe(false, loc,
- "`@safe` function `%s` cannot access `__gshared` data `%s`", sc.func, v))
+ if (sc.setUnsafe(false, loc, "accessing `__gshared` data `%s`", v))
{
err = true;
}
}
else if (p.storageClass & STC.ref_)
{
- if (global.params.rvalueRefParam == FeatureState.enabled &&
+ if (sc.previews.rvalueRefParam &&
!arg.isLvalue() &&
targ.isCopyable())
{ /* allow rvalues to be passed to ref parameters by copying
/* Test compliance with DIP1021 Argument Ownership and Function Calls
*/
- if (global.params.useDIP1021 && (tf.trust == TRUST.safe || tf.trust == TRUST.default_) ||
+ if (sc.previews.dip1021 && (tf.trust == TRUST.safe || tf.trust == TRUST.default_) ||
tf.isLive)
err |= checkMutableArguments(*sc, fd, tf, ethis, arguments, false);
}
}
- if (global.params.fixAliasThis)
+ if (sc.previews.fixAliasThis)
{
if (ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol())
{
return;
}
- if (!global.params.fixAliasThis && hasThis(sc))
+ if (!sc.previews.fixAliasThis && hasThis(sc))
{
for (AggregateDeclaration ad = sc.getStructClassScope(); ad;)
{
// When using `@nogc` exception handling, lower `throw new E(args)` to
// `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`.
- if (global.params.ehnogc && exp.thrownew &&
+ if (sc.previews.dip1008 && exp.thrownew &&
!cd.isCOMclass() && !cd.isCPPclass())
{
assert(cd.ctor);
*/
if (1)
{
- if (sc.setUnsafe(false, exp.loc,
- "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func))
+ if (sc.setUnsafe(false, exp.loc, "taking address of lazy parameter `%s`", ve))
{
setError();
return;
}
if (sc.func && !sc.intypeof && !sc.debug_)
{
- sc.setUnsafe(false, exp.loc,
- "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
- f, sc.func);
+ sc.setUnsafe(false, exp.loc, "taking address of member `%s` without `this` reference", f);
}
}
}
if (!isSafeCast(ex, t1b, tob, msg))
{
if (sc.setUnsafe(false, exp.loc,
- "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
+ "cast from `%s` to `%s`", exp.e1.type, exp.to))
{
if (msg.length)
errorSupplemental(exp.loc, "%.*s", msg.fTuple.expand);
else if (msg.length) // deprecated unsafe
{
const err = sc.setUnsafePreview(FeatureState.default_, false, exp.loc,
- "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to);
+ "cast from `%s` to `%s`", exp.e1.type, exp.to);
// if message was printed
if (sc.func && sc.func.isSafeBypassingInference() && !sc.isDeprecated())
deprecationSupplemental(exp.loc, "%.*s", msg.fTuple.expand);
return setError();
}
- if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions"))
+ if (sc.setUnsafe(false, exp.loc, "pointer slicing"))
return setError();
}
else if (t1b.ty == Tarray)
if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0)
{
}
- else if (sc.setUnsafe(false, exp.loc, "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1))
+ else if (sc.setUnsafe(false, exp.loc, "indexing pointer `%s`", exp.e1))
{
return setError();
}
{
if (t2.nextOf().implicitConvTo(t1.nextOf()))
{
- if (sc.setUnsafe(false, exp.loc, "cannot copy `%s` to `%s` in `@safe` code", t2, t1))
+ if (sc.setUnsafe(false, exp.loc, "copying `%s` to `%s`", t2, t1))
return setError();
}
else
{
// copying from non-void to void was overlooked, deprecate
if (sc.setUnsafePreview(FeatureState.default_, false, exp.loc,
- "cannot copy `%s` to `%s` in `@safe` code", t2, t1))
+ "copying `%s` to `%s`", t2, t1))
return setError();
}
- if (global.params.fixImmutableConv && !t2.implicitConvTo(t1))
+ if (sc.previews.fixImmutableConv && !t2.implicitConvTo(t1))
{
error(exp.loc, "cannot copy `%s` to `%s`",
t2.toChars(), t1.toChars());
(exp.e2.implicitConvTo(exp.e1.type) ||
(tb2.nextOf().implicitConvTo(tb1next) &&
// Do not strip const(void)[]
- (!global.params.fixImmutableConv || tb1next.ty != Tvoid) &&
+ (!sc.previews.fixImmutableConv || tb1next.ty != Tvoid) &&
(tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
{
// EXP.concatenateAssign
if (!p1.equivalent(p2))
{
- // Deprecation to remain for at least a year, after which this should be
- // changed to an error
// See https://github.com/dlang/dmd/pull/7332
- deprecation(exp.loc,
- "cannot subtract pointers to different types: `%s` and `%s`.",
+ error(exp.loc, "cannot subtract pointers to different types: `%s` and `%s`.",
t1.toChars(), t2.toChars());
+ return setError();
}
// Need to divide the result by the stride
if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod)
{
// Do not strip const(void)[]
- if (!global.params.fixImmutableConv || tb.nextOf().ty != Tvoid)
+ if (!sc.previews.fixImmutableConv || tb.nextOf().ty != Tvoid)
exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
}
if (Type tbn = tb.nextOf())
*/
bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
{
- if (global.params.noSharedAccess != FeatureState.enabled ||
- !sc ||
+ if (!sc ||
+ !sc.previews.noSharedAccess ||
sc.intypeof ||
sc.ctfe)
{
with (_this)
if (!trusted && !e1.type.pointerTo().implicitConvTo(to.pointerTo()))
sc.setUnsafePreview(FeatureState.default_, false, loc,
- "cast from `%s` to `%s` cannot be used as an lvalue in @safe code",
+ "using the result of a cast from `%s` to `%s` as an lvalue",
e1.type, to);
return _this;
Expression visitDelegatePtr(DelegatePtrExp exp)
{
- if (sc.setUnsafe(false, exp.loc, "cannot modify delegate pointer in `@safe` code `%s`", exp))
+ if (sc.setUnsafe(false, exp.loc, "modifying delegate pointer `%s`", exp))
{
return ErrorExp.get();
}
Expression visitDelegateFuncptr(DelegateFuncptrExp exp)
{
- if (sc.setUnsafe(false, exp.loc, "cannot modify delegate function pointer in `@safe` code `%s`", exp))
+ if (sc.setUnsafe(false, exp.loc, "modifying delegate function pointer `%s`", exp))
{
return ErrorExp.get();
}
{
if (sc.useDIP1000 != FeatureState.enabled &&
!(v.storage_class & STC.temp) &&
- sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func))
+ sc.setUnsafe(false, exp.loc, "taking the address of stack-allocated local variable `%s`", v))
{
return false;
}
if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize ||
(v.offset & (target.ptrsize - 1))) &&
(sc.setUnsafe(false, loc,
- "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v)))
+ "field `%s.%s` assigning to misaligned pointers", sd, v)))
{
return false;
}
bool safetyInprocess; /// working on determining safety
bool nothrowInprocess; /// working on determining nothrow
bool nogcInprocess; /// working on determining @nogc
+ bool saferD; /// do -preview=safer checks if this function has default safety
bool scopeInprocess; /// infer `return` and `scope` for parameters
bool inlineScanned; /// function has been scanned for inline possibilities
bool hasCatches; /// function has try-catch statements
const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
- .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
+ string match = "";
+ final switch (m.last)
+ {
+ case MATCH.convert:
+ match = "after implicit conversions";
+ break;
+ case MATCH.constant:
+ match = "after qualifier conversion";
+ break;
+ case MATCH.exact:
+ match = "exactly";
+ break;
+ case MATCH.nomatch:
+ assert(0);
+ }
+
+ .error(loc, "`%s.%s` called with argument types `%s` matches multiple overloads %.*s:\n%s: `%s%s%s`\nand:\n%s: `%s%s%s`",
s.parent.toPrettyChars(), s.ident.toChars(),
fargsBuf.peekChars(),
+ match.fTuple.expand,
m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, tf1.modToChars(),
m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, tf2.modToChars());
return null;
params.v.color = detectTerminal();
}
+ params.v.errorPrintMode = ErrorPrintMode.printErrorContext; // Enable error context globally by default
compileEnv.versionNumber = parseVersionNumber(versionString());
/* Initialize date, time, and timestamp
{
buf.writestring(Token.toString(s.op));
buf.writestring(" (");
- if (s.prm.type)
- typeToBuffer(s.prm.type, s.prm.ident, buf, hgs);
+ if (s.param.type)
+ typeToBuffer(s.param.type, s.param.ident, buf, hgs);
else
- buf.writestring(s.prm.ident.toString());
+ buf.writestring(s.param.ident.toString());
buf.writestring("; ");
s.lwr.expressionToBuffer(buf, hgs);
buf.writestring(" .. ");
void visitIf(IfStatement s)
{
buf.writestring("if (");
- printConditionAssignment(s.prm, s.condition);
+ printConditionAssignment(s.param, s.condition);
buf.writeByte(')');
buf.writenl();
if (s.ifbody.isScopeStatement())
void foreachRangeWithoutBody(ForeachRangeStatement s)
{
- /* s.op ( prm ; lwr .. upr )
+ /* s.op ( param ; lwr .. upr )
*/
buf.writestring(Token.toString(s.op));
buf.writestring(" (");
- if (s.prm.type)
- typeToBuffer(s.prm.type, s.prm.ident, buf, hgs);
+ if (s.param.type)
+ typeToBuffer(s.param.type, s.param.ident, buf, hgs);
else
- buf.writestring(s.prm.ident.toString());
+ buf.writestring(s.param.ident.toString());
buf.writestring("; ");
s.lwr.expressionToBuffer(buf, hgs);
buf.writestring(" .. ");
(vd.offset & (target.ptrsize - 1))))
{
if (sc.setUnsafe(false, argLoc,
- "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, vd))
+ "field `%s.%s` assigning to misaligned pointers", sd, vd))
{
errors = true;
elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
}
if (value < a.value)
return -1;
- else if (value > a.value)
+ if (value > a.value)
return 1;
else
return 0;
SignExtendedNumber opBinary(string op : "+")(SignExtendedNumber rhs)
{
uinteger_t sum = value + rhs.value;
- bool carry = sum < value && sum < rhs.value;
+ const carry = sum < value && sum < rhs.value;
if (negative != rhs.negative)
return SignExtendedNumber(sum, !carry);
- else if (negative)
+ if (negative)
return SignExtendedNumber(carry ? sum : 0, true);
else
return SignExtendedNumber(carry ? ulong.max : sum, false);
{
if (!negative)
return this;
- else if (rhs.negative)
+ if (rhs.negative)
return max();
else
return rhs.value == 0 ? rhs : this;
// shifts will give huge result.
if (value == 0)
return this;
- else if (rhs.negative)
+ if (rhs.negative)
return extreme(negative);
uinteger_t v = copySign(value, negative);
{
if (rhs.negative || rhs.value > 63)
return negative ? SignExtendedNumber(-1, true) : SignExtendedNumber(0);
- else if (isMinimum())
+ if (isMinimum())
return rhs.value == 0 ? this : SignExtendedNumber(-1UL << (64 - rhs.value), true);
uinteger_t x = value ^ -cast(int)negative;
{
if (!type.isIntegral() || type.toBasetype().isTypeVector())
return this;
- else if (!type.isUnsigned())
+ if (!type.isUnsigned())
return castSigned(type.sizemask());
- else if (type.toBasetype().ty == Tdchar)
+ if (type.toBasetype().ty == Tdchar)
return castDchar();
- else
return castUnsigned(type.sizemask());
}
{
if (!type.isIntegral() || type.toBasetype().isTypeVector())
return castUnsigned(ulong.max);
- else if (type.toBasetype().ty == Tdchar)
+ if (type.toBasetype().ty == Tdchar)
return castDchar();
- else
- return castUnsigned(type.sizemask());
+ return castUnsigned(type.sizemask());
}
bool contains(IntRange a) @safe
{
if (imax.negative)
return this;
- else if (!imin.negative)
+ if (!imin.negative)
return IntRange(-imax, -imin);
- else
- {
- SignExtendedNumber imaxAbsNeg = -imax;
- return IntRange(imaxAbsNeg < imin ? imaxAbsNeg : imin,
- SignExtendedNumber(0));
- }
+ SignExtendedNumber imaxAbsNeg = -imax;
+ return IntRange(imaxAbsNeg < imin ? imaxAbsNeg : imin,
+ SignExtendedNumber(0));
}
IntRange unionWith(const ref IntRange other) const @safe
swap(l, r); // r spans [-1,0]
}
- auto minAndNeg = minAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
- auto minAndPos = minAnd(l, IntRange(SignExtendedNumber(0), r.imax));
- auto maxAndNeg = maxAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
- auto maxAndPos = maxAnd(l, IntRange(SignExtendedNumber(0), r.imax));
+ const minAndNeg = minAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
+ const minAndPos = minAnd(l, IntRange(SignExtendedNumber(0), r.imax));
+ const maxAndNeg = maxAnd(l, IntRange(r.imin, SignExtendedNumber(-1)));
+ const maxAndPos = maxAnd(l, IntRange(SignExtendedNumber(0), r.imax));
- auto min = minAndNeg < minAndPos ? minAndNeg : minAndPos;
- auto max = maxAndNeg > maxAndPos ? maxAndNeg : maxAndPos;
+ const min = minAndNeg < minAndPos ? minAndNeg : minAndPos;
+ const max = maxAndNeg > maxAndPos ? maxAndNeg : maxAndPos;
auto range = IntRange(min, max);
return range;
{
return IntRange(imin / rhs.imax, imax / rhs.imin);
}
- else if (rhs.imin.negative && !rhs.imax.negative) // divisor spans [-1, 0, 1]
+ if (rhs.imin.negative && !rhs.imax.negative) // divisor spans [-1, 0, 1]
{
SignExtendedNumber[4] bdy = [-imin, imin, -imax, imax];
return IntRange.fromNumbers4(bdy.ptr);
}
- else
- {
- // [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
- SignExtendedNumber[4] bdy;
- bdy[0] = imin / rhs.imin;
- bdy[1] = imin / rhs.imax;
- bdy[2] = imax / rhs.imin;
- bdy[3] = imax / rhs.imax;
+ // [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
+ SignExtendedNumber[4] bdy;
+ bdy[0] = imin / rhs.imin;
+ bdy[1] = imin / rhs.imax;
+ bdy[2] = imax / rhs.imin;
+ bdy[3] = imax / rhs.imax;
- return IntRange.fromNumbers4(bdy.ptr);
- }
+ return IntRange.fromNumbers4(bdy.ptr);
}
IntRange opBinary(string op : "%")(IntRange rhs)
// of modules representing their syntax.
json.generateModules(modules);
json.removeComma();
+ return;
}
- else
- {
- // Generate the new format which is an object where each
- // output option is its own field.
- json.objectStart();
- if (global.params.jsonFieldFlags & JsonFieldFlags.compilerInfo)
- {
- json.propertyStart("compilerInfo");
- json.generateCompilerInfo();
- }
- if (global.params.jsonFieldFlags & JsonFieldFlags.buildInfo)
- {
- json.propertyStart("buildInfo");
- json.generateBuildInfo();
- }
- if (global.params.jsonFieldFlags & JsonFieldFlags.modules)
- {
- json.propertyStart("modules");
- json.generateModules(modules);
- }
- if (global.params.jsonFieldFlags & JsonFieldFlags.semantics)
- {
- json.propertyStart("semantics");
- json.generateSemantics();
- }
- json.objectEnd();
+ // Generate the new format which is an object where each
+ // output option is its own field.
+
+ json.objectStart();
+ if (global.params.jsonFieldFlags & JsonFieldFlags.compilerInfo)
+ {
+ json.propertyStart("compilerInfo");
+ json.generateCompilerInfo();
+ }
+ if (global.params.jsonFieldFlags & JsonFieldFlags.buildInfo)
+ {
+ json.propertyStart("buildInfo");
+ json.generateBuildInfo();
+ }
+ if (global.params.jsonFieldFlags & JsonFieldFlags.modules)
+ {
+ json.propertyStart("modules");
+ json.generateModules(modules);
+ }
+ if (global.params.jsonFieldFlags & JsonFieldFlags.semantics)
+ {
+ json.propertyStart("semantics");
+ json.generateSemantics();
}
+ json.objectEnd();
}
/**
* Follows Itanium C++ ABI 1.86 section 5.1
* http://refspecs.linux-foundation.org/cxxabi-1.86.html#mangling
* which is where the grammar comments come from.
- *
- * Bugs:
- * https://issues.dlang.org/query.cgi
- * enter `C++, mangling` as the keywords.
*/
module dmd.mangle.cpp;
FuncDeclaration f;
bool checkOnly; // don't print errors
bool err;
+ bool nogcExceptions; // -preview=dip1008 enabled
extern (D) this(FuncDeclaration f) scope @safe
{
}
if (e.onstack)
return;
- if (global.params.ehnogc && e.thrownew)
+ if (nogcExceptions && e.thrownew)
return; // separate allocator is called for this, not the GC
if (setGC(e, "cannot use `new` in `@nogc` %s `%s`"))
{
scope NOGCVisitor gcv = new NOGCVisitor(f);
gcv.checkOnly = betterC;
+ gcv.nogcExceptions = sc.previews.dip1008;
walkPostorder(e, gcv);
if (gcv.err)
{
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/ob.d, _ob.d)
* Documentation: https://dlang.org/phobos/dmd_escape.html
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/ob.d
- * Bug reports: use 'live' keyword:
- * https://issues.dlang.org/buglist.cgi?bug_status=NEW&bug_status=REOPENED&keywords=live
* References: https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md Argument Ownership and Function Calls
*/
}
/***
- * Parse an assignment condition for if or while statements.
+ * Parse an assignment condition for `if`, `switch` or `while` statements.
*
* Returns:
* The variable that is declared inside the condition
public this(const char[] text)
{
this.text = text;
+ this.index = 0;
+ this.eolIndex = 0;
+ this.nextIndex = 0;
}
- public bool empty() { return index == text.length; }
+ public bool empty() { advance(); return index >= text.length; }
public void popFront() { advance(); index = nextIndex; }
- public const(char)[] front() { advance(); return text[index .. eolIndex]; }
+ public const(char)[] front()
+ {
+ advance();
+ if (index > eolIndex || index >= text.length) {
+ return "";
+ }
+ return text[index .. eolIndex];
+ }
private void advance()
{
if (i + 2 < text.length &&
text[i + 1] == 0x80 &&
(text[i + 2] == 0xA8 || text[i + 2] == 0xA9)
- )
+ )
{
eolIndex = i;
nextIndex = i + 3;
break;
}
}
+
+ // No newline found; set indices to the end of the text
+ eolIndex = text.length;
+ nextIndex = text.length;
}
}
import dmd.aggregate;
import dmd.astenums;
+import dmd.common.outbuffer;
import dmd.dcast : implicitConvTo;
import dmd.dclass;
import dmd.declaration;
if (!ad)
return false;
- import dmd.globals : global;
if (v.isSystem())
{
- if (sc.setUnsafePreview(global.params.systemVariables, !printmsg, e.loc,
- "cannot access `@system` field `%s.%s` in `@safe` code", ad, v))
+ if (sc.setUnsafePreview(sc.previews.systemVariables, !printmsg, e.loc,
+ "accessing `@system` field `%s.%s`", ad, v))
return true;
}
if (v.overlapped)
{
if (sc.func.isSafeBypassingInference() && sc.setUnsafe(!printmsg, e.loc,
- "field `%s.%s` cannot access pointers in `@safe` code that overlap other fields", ad, v))
+ "accessing overlapped field `%s.%s` with pointers", ad, v))
{
return true;
}
// To turn into an error, remove `isSafeBypassingInference` check in the
// above if statement and remove the else branch
sc.setUnsafePreview(FeatureState.default_, !printmsg, e.loc,
- "field `%s.%s` cannot access pointers in `@safe` code that overlap other fields", ad, v);
+ "accessing overlapped field `%s.%s` with pointers", ad, v);
}
}
}
if (v.overlapped)
{
if (sc.setUnsafe(!printmsg, e.loc,
- "field `%s.%s` cannot access structs with invariants in `@safe` code that overlap other fields",
+ "accessing overlapped field `%s.%s` with a structs invariant",
ad, v))
return true;
}
// Should probably be turned into an error in a new edition
if (v.type.hasUnsafeBitpatterns() && v.overlapped && sc.setUnsafePreview(
FeatureState.default_, !printmsg, e.loc,
- "cannot access overlapped field `%s.%s` with unsafe bit patterns in `@safe` code", ad, v)
+ "accessing overlapped field `%s.%s` with unsafe bit patterns", ad, v)
)
{
return true;
(v.offset & (target.ptrsize - 1)))
{
if (sc.setUnsafe(!printmsg, e.loc,
- "field `%s.%s` cannot modify misaligned pointers in `@safe` code", ad, v))
+ "modifying misaligned pointers through field `%s.%s`", ad, v))
return true;
}
}
if (v.overlapUnsafe)
{
if (sc.setUnsafe(!printmsg, e.loc,
- "field `%s.%s` cannot modify fields in `@safe` code that overlap fields with other storage classes",
+ "modifying field `%s.%s` which overlaps with fields with other storage classes",
ad, v))
{
return true;
auto tfromb = tfrom.toBasetype();
auto ttob = tto.toBasetype();
+ // Casting to void* is always safe, https://github.com/dlang/dmd/issues/20514
+ if (ttob.isTypePointer() && ttob.nextOf().toBasetype().ty == Tvoid)
+ return true;
+
if (ttob.ty == Tclass && tfromb.ty == Tclass)
{
ClassDeclaration cdfrom = tfromb.isClassHandle();
if (!(flag & DotExpFlag.noDeref)) // this use is attempting a dereference
{
if (id == Id.ptr)
- return sc.setUnsafe(false, e.loc, "`%s.ptr` cannot be used in `@safe` code, use `&%s[0]` instead", e, e);
+ return sc.setUnsafe(false, e.loc, "using `%s.ptr` (instead of `&%s[0])`", e, e);
else
- return sc.setUnsafe(false, e.loc, "`%s.%s` cannot be used in `@safe` code", e, id);
+ return sc.setUnsafe(false, e.loc, "using `%s.%s`", e, id);
}
return false;
}
*/
bool isSaferD(FuncDeclaration fd)
{
- return fd.type.toTypeFunction().trust == TRUST.default_ &&
- global.params.safer == FeatureState.enabled;
+ return fd.type.toTypeFunction().trust == TRUST.default_ && fd.saferD;
}
bool isSafe(FuncDeclaration fd)
else if (fd.isSafe() || fd.isSaferD())
{
if (!gag && format)
- .error(loc, format, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+ {
+ OutBuffer buf;
+ buf.printf(format, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+ if (fd.isSafe())
+ buf.writestring(" is not allowed in a `@safe` function");
+ else
+ buf.writestring(" is not allowed in a function with default safety with `-preview=safer`");
+ .error(loc, buf.extractChars());
+ }
}
}
{
if (sc.varDecl.storage_class & STC.safe)
{
- .error(loc, format, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+ OutBuffer buf;
+ buf.printf(format, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+ buf.printf(" can't initialize `@safe` variable `%s`", sc.varDecl.toChars());
+ .error(loc, buf.extractChars());
+
return true;
}
else if (!(sc.varDecl.storage_class & STC.trusted))
{
// Message wil be gagged, but still call error() to update global.errors and for
// -verrors=spec
- .error(loc, format, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+ OutBuffer buf;
+ buf.printf(format, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+ buf.writestring(" is not allowed in a `@safe` function");
+ .error(loc, buf.extractChars());
return true;
}
return false;
{
if (!gag && !sc.isDeprecated())
{
- deprecation(loc, format, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+ OutBuffer buf;
+ buf.printf(format, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+ buf.writestring(" will become `@system` in a future release");
+ deprecation(loc, buf.extractChars());
}
}
else if (!sc.func.safetyViolation)
DeprecatedDeclaration *depdecl; // customized deprecation message
- unsigned flags;
+ uint16_t flags;
+ uint16_t previews; // state of preview switches
bool ctor() const;
bool ctor(bool v);
bool fullinst(bool v);
bool ctfeBlock() const;
bool ctfeBlock(bool v);
- bool dip1000() const;
- bool dip1000(bool v);
- bool dip25() const;
- bool dip25(bool v);
UserAttributeDeclaration *userAttribDecl; // user defined attributes
return;
funcdecl.semanticRun = PASS.semantic3;
funcdecl.hasSemantic3Errors = false;
+ funcdecl.saferD = sc.previews.safer;
if (!funcdecl.type || funcdecl.type.ty != Tfunction)
return;
sc2 = sc2.pop();
}
- if (global.params.inclusiveInContracts)
+ if (sc.previews.inclusiveInContracts)
{
funcdecl.frequire = funcdecl.mergeFrequireInclusivePreview(
funcdecl.frequire, funcdecl.fdrequireParams);
}
// Do live analysis
- if (global.params.useDIP1021 && funcdecl.fbody && funcdecl.type.ty != Terror &&
+ if (sc.previews.dip1021 && funcdecl.fbody && funcdecl.type.ty != Terror &&
funcdecl.type.isTypeFunction().isLive)
{
oblive(funcdecl);
extern (C++) final class ForeachRangeStatement : Statement
{
TOK op; // TOK.foreach_ or TOK.foreach_reverse_
- Parameter prm; // loop index variable
+ Parameter param; // loop index variable
Expression lwr;
Expression upr;
Statement _body;
VarDeclaration key;
- extern (D) this(const ref Loc loc, TOK op, Parameter prm, Expression lwr, Expression upr, Statement _body, Loc endloc) @safe
+ extern (D) this(const ref Loc loc, TOK op, Parameter param, Expression lwr, Expression upr, Statement _body, Loc endloc) @safe
{
super(loc, STMT.ForeachRange);
this.op = op;
- this.prm = prm;
+ this.param = param;
this.lwr = lwr;
this.upr = upr;
this._body = _body;
override ForeachRangeStatement syntaxCopy()
{
- return new ForeachRangeStatement(loc, op, prm.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc);
+ return new ForeachRangeStatement(loc, op, param.syntaxCopy(), lwr.syntaxCopy(), upr.syntaxCopy(), _body ? _body.syntaxCopy() : null, endloc);
}
override bool hasBreak() const pure nothrow
*/
extern (C++) final class IfStatement : Statement
{
- Parameter prm;
+ Parameter param;
Expression condition;
Statement ifbody;
Statement elsebody;
VarDeclaration match; // for MatchExpression results
Loc endloc; // location of closing curly bracket
- extern (D) this(const ref Loc loc, Parameter prm, Expression condition, Statement ifbody, Statement elsebody, Loc endloc) @safe
+ extern (D) this(const ref Loc loc, Parameter param, Expression condition, Statement ifbody, Statement elsebody, Loc endloc) @safe
{
super(loc, STMT.If);
- this.prm = prm;
+ this.param = param;
this.condition = condition;
this.ifbody = ifbody;
this.elsebody = elsebody;
override IfStatement syntaxCopy()
{
return new IfStatement(loc,
- prm ? prm.syntaxCopy() : null,
+ param ? param.syntaxCopy() : null,
condition.syntaxCopy(),
ifbody ? ifbody.syntaxCopy() : null,
elsebody ? elsebody.syntaxCopy() : null,
{
public:
TOK op; // TOKforeach or TOKforeach_reverse
- Parameter *prm; // loop index variable
+ Parameter *param; // loop index variable
Expression *lwr;
Expression *upr;
Statement *_body;
class IfStatement final : public Statement
{
public:
- Parameter *prm;
+ Parameter *param;
Expression *condition;
Statement *ifbody;
Statement *elsebody;
return setError();
}
- if (fs.prm.type)
+ if (fs.param.type)
{
- fs.prm.type = fs.prm.type.typeSemantic(loc, sc);
- fs.prm.type = fs.prm.type.addStorageClass(fs.prm.storageClass);
- fs.lwr = fs.lwr.implicitCastTo(sc, fs.prm.type);
+ fs.param.type = fs.param.type.typeSemantic(loc, sc);
+ fs.param.type = fs.param.type.addStorageClass(fs.param.storageClass);
+ fs.lwr = fs.lwr.implicitCastTo(sc, fs.param.type);
- if (fs.upr.implicitConvTo(fs.prm.type) || (fs.prm.storageClass & STC.ref_))
+ if (fs.upr.implicitConvTo(fs.param.type) || (fs.param.storageClass & STC.ref_))
{
- fs.upr = fs.upr.implicitCastTo(sc, fs.prm.type);
+ fs.upr = fs.upr.implicitCastTo(sc, fs.param.type);
}
else
{
- // See if upr-1 fits in prm.type
+ // See if upr-1 fits in param.type
Expression limit = new MinExp(loc, fs.upr, IntegerExp.literal!1);
limit = limit.expressionSemantic(sc);
limit = limit.optimize(WANTvalue);
- if (!limit.implicitConvTo(fs.prm.type))
+ if (!limit.implicitConvTo(fs.param.type))
{
- fs.upr = fs.upr.implicitCastTo(sc, fs.prm.type);
+ fs.upr = fs.upr.implicitCastTo(sc, fs.param.type);
}
}
}
{
/* Just picking the first really isn't good enough.
*/
- fs.prm.type = fs.lwr.type;
+ fs.param.type = fs.lwr.type;
}
else if (fs.lwr.type == fs.upr.type)
{
/* Same logic as CondExp ?lwr:upr
*/
- fs.prm.type = fs.lwr.type;
+ fs.param.type = fs.lwr.type;
}
else
{
scope AddExp ea = new AddExp(loc, fs.lwr, fs.upr);
if (typeCombine(ea, sc))
return setError();
- fs.prm.type = ea.type;
+ fs.param.type = ea.type;
fs.lwr = ea.e1;
fs.upr = ea.e2;
}
- fs.prm.type = fs.prm.type.addStorageClass(fs.prm.storageClass);
+ fs.param.type = fs.param.type.addStorageClass(fs.param.storageClass);
}
- if (fs.prm.type.ty == Terror || fs.lwr.op == EXP.error || fs.upr.op == EXP.error)
+ if (fs.param.type.ty == Terror || fs.lwr.op == EXP.error || fs.upr.op == EXP.error)
{
return setError();
}
if (fs.op == TOK.foreach_reverse_)
{
cond = new PostExp(EXP.minusMinus, loc, new VarExp(loc, fs.key));
- if (fs.prm.type.isScalar())
+ if (fs.param.type.isScalar())
{
// key-- > tmp
cond = new CmpExp(EXP.greaterThan, loc, cond, new VarExp(loc, tmp));
}
else
{
- if (fs.prm.type.isScalar())
+ if (fs.param.type.isScalar())
{
// key < tmp
cond = new CmpExp(EXP.lessThan, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp));
//increment = new AddAssignExp(loc, new VarExp(loc, fs.key), IntegerExp.literal!1);
increment = new PreExp(EXP.prePlusPlus, loc, new VarExp(loc, fs.key));
}
- if ((fs.prm.storageClass & STC.ref_) && fs.prm.type.equals(fs.key.type))
+ if ((fs.param.storageClass & STC.ref_) && fs.param.type.equals(fs.key.type))
{
fs.key.range = null;
- auto v = new AliasDeclaration(loc, fs.prm.ident, fs.key);
+ auto v = new AliasDeclaration(loc, fs.param.ident, fs.key);
fs._body = new CompoundStatement(loc, new ExpStatement(loc, v), fs._body);
}
else
{
- ie = new ExpInitializer(loc, new CastExp(loc, new VarExp(loc, fs.key), fs.prm.type));
- auto v = new VarDeclaration(loc, fs.prm.type, fs.prm.ident, ie);
- v.storage_class |= STC.temp | STC.foreach_ | (fs.prm.storageClass & STC.ref_);
+ ie = new ExpInitializer(loc, new CastExp(loc, new VarExp(loc, fs.key), fs.param.type));
+ auto v = new VarDeclaration(loc, fs.param.type, fs.param.ident, ie);
+ v.storage_class |= STC.temp | STC.foreach_ | (fs.param.storageClass & STC.ref_);
fs._body = new CompoundStatement(loc, new ExpStatement(loc, v), fs._body);
- if (fs.key.range && !fs.prm.type.isMutable())
+ if (fs.key.range && !fs.param.type.isMutable())
{
/* Limit the range of the key to the specified range
*/
v.range = new IntRange(fs.key.range.imin, fs.key.range.imax - SignExtendedNumber(1));
}
}
- if (fs.prm.storageClass & STC.ref_)
+ if (fs.param.storageClass & STC.ref_)
{
- if (fs.key.type.constConv(fs.prm.type) == MATCH.nomatch)
+ if (fs.key.type.constConv(fs.param.type) == MATCH.nomatch)
{
- error(fs.loc, "argument type mismatch, `%s` to `ref %s`", fs.key.type.toChars(), fs.prm.type.toChars());
+ error(fs.loc, "argument type mismatch, `%s` to `ref %s`", fs.key.type.toChars(), fs.param.type.toChars());
return setError();
}
}
sym.parent = sc.scopesym;
sym.endlinnum = ifs.endloc.linnum;
Scope* scd = sc.push(sym);
- if (ifs.prm)
+ if (ifs.param)
{
- /* Declare prm, which we will set to be the
+ /* Declare param, which we will set to be the
* result of condition.
*/
auto ei = new ExpInitializer(ifs.loc, ifs.condition);
- ifs.match = new VarDeclaration(ifs.loc, ifs.prm.type, ifs.prm.ident, ei);
+ ifs.match = new VarDeclaration(ifs.loc, ifs.param.type, ifs.param.ident, ei);
ifs.match.parent = scd.func;
- ifs.match.storage_class |= ifs.prm.storageClass;
+ ifs.match.storage_class |= ifs.param.storageClass;
ifs.match.dsymbolSemantic(scd);
auto de = new DeclarationExp(ifs.loc, ifs.match);
if (checkNonAssignmentArrayOp(ifs.condition))
ifs.condition = ErrorExp.get();
- // Convert to boolean after declaring prm so this works:
- // if (S prm = S()) {}
+ // Convert to boolean after declaring param so this works:
+ // if (S param = S()) {}
// where S is a struct that defines opCast!bool.
ifs.condition = ifs.condition.toBoolean(scd);
// If we previously assumed the function could be ref when
// checking for `shared`, make sure we were right
- if (global.params.noSharedAccess == FeatureState.enabled && rs.exp.type.isShared())
+ if (sc.previews.noSharedAccess && rs.exp.type.isShared())
{
.error(fd.loc, "%s `%s` function returns `shared` but cannot be inferred `ref`", fd.kind, fd.toPrettyChars);
supplemental();
deprecation(cas.loc, "`asm` statement cannot be marked `@safe`, use `@system` or `@trusted` instead");
if (!(cas.stc & (STC.trusted | STC.safe)))
{
- sc.setUnsafe(false, cas.loc, "`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not");
+ sc.setUnsafe(false, cas.loc, "`asm` statement without `@trusted` annotation");
}
sc.pop();
p.type = p.type.addStorageClass(p.storageClass);
if (tfld)
{
- Parameter prm = tfld.parameterList[i];
- //printf("\tprm = %s%s\n", (prm.storageClass&STC.ref_?"ref ":"").ptr, prm.ident.toChars());
- stc = (prm.storageClass & STC.ref_) | (p.storageClass & STC.scope_);
- if ((p.storageClass & STC.ref_) != (prm.storageClass & STC.ref_))
+ Parameter param = tfld.parameterList[i];
+ //printf("\tparam = %s%s\n", (param.storageClass&STC.ref_?"ref ":"").ptr, param.ident.toChars());
+ stc = (param.storageClass & STC.ref_) | (p.storageClass & STC.scope_);
+ if ((p.storageClass & STC.ref_) != (param.storageClass & STC.ref_))
{
- if (!(prm.storageClass & STC.ref_))
+ if (!(param.storageClass & STC.ref_))
{
error(fs.loc, "`foreach`: cannot make `%s` `ref`", p.ident.toChars());
return null;
}
if (!c.internalCatch)
{
- if (sc.setUnsafe(false, c.loc, "cannot catch C++ class objects in `@safe` code"))
+ if (sc.setUnsafe(false, c.loc, "catching C++ class objects"))
c.errors = true;
}
}
else if (!c.internalCatch && ClassDeclaration.exception &&
cd != ClassDeclaration.exception && !ClassDeclaration.exception.isBaseOf(cd, null) &&
sc.setUnsafe(false, c.loc,
- "can only catch class objects derived from `Exception` in `@safe` code, not `%s`", c.type))
+ "catching class objects derived from `%s` instead of `Exception`", c.type))
{
c.errors = true;
}
- else if (global.params.ehnogc)
+ else if (sc.previews.dip1008)
{
stc |= STC.scope_;
}
// DIP1008 requires destruction of the Throwable, even if the user didn't specify an identifier
auto ident = c.ident;
- if (!ident && global.params.ehnogc)
+ if (!ident && sc.previews.dip1008)
ident = Identifier.generateAnonymousId("var");
if (ident)
c.var.dsymbolSemantic(sc);
sc.insert(c.var);
- if (global.params.ehnogc && stc & STC.scope_)
+ if (sc.previews.dip1008 && stc & STC.scope_)
{
/* Add a destructor for c.var
* try { handler } finally { if (!__ctfe) _d_delThrowable(var); }
{
// Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
}
- else if (global.params.rvalueRefParam == FeatureState.enabled)
+ else if (sc.previews.rvalueRefParam)
{
// Allow implicit conversion to ref
}
// Need to make this a rvalue through a temporary
m = MATCH.convert;
}
- else if (global.params.rvalueRefParam != FeatureState.enabled ||
+ else if (!(sc && sc.previews.rvalueRefParam) ||
p.storageClass & STC.out_ ||
!arg.type.isCopyable()) // can't copy to temp for ref parameter
{
// default arg must be an lvalue
if (isRefOrOut && !isAuto &&
- !(fparam.storageClass & STC.constscoperef) &&
- global.params.rvalueRefParam != FeatureState.enabled)
+ !(fparam.storageClass & STC.constscoperef) && !sc.previews.rvalueRefParam)
e = e.toLvalue(sc, "create default argument for `ref` / `out` parameter from");
fparam.defaultArg = e;
override void visit(AST.ForeachRangeStatement s)
{
//printf("Visiting ForeachRangeStatement\n");
- if (s.prm.type)
- visitType(s.prm.type);
+ if (s.param.type)
+ visitType(s.param.type);
s.lwr.accept(this);
s.upr.accept(this);
if (s._body)
override void visit(AST.IfStatement s)
{
//printf("Visiting IfStatement\n");
- if (s.prm && s.prm.type)
- visitType(s.prm.type);
+ if (s.param && s.param.type)
+ visitType(s.param.type);
s.condition.accept(this);
s.ifbody.accept(this);
if (s.elsebody)
void test4() @safe
{
- asm { } // { dg-error "'asm' statement is assumed to be '@system' - mark it with '@trusted' if it is not" }
+ asm { } // { dg-error "'asm' statement without '@trusted' annotation is not allowed in a '@safe' function" }
}
union U { int i; bool b; }
U u;
u.i = 0x81818181;
- assert(array[u.b] == 678); // { dg-warning "cannot access overlapped field" }
- return u.b; // { dg-warning "cannot access overlapped field" }
+ assert(array[u.b] == 678); // { dg-warning "accessing overlapped field" }
+ return u.b; // { dg-warning "accessing overlapped field" }
}
@safe void main()
-/* REQUIRED_ARGS: -m64
+/* REQUIRED_ARGS: -verrors=simple -m64
TEST_OUTPUT:
---
compilable/b16976.d(33): Deprecation: foreach: loop index implicitly converted from `size_t` to `int`
// https://issues.dlang.org/show_bug.cgi?id=20643
// https://issues.dlang.org/show_bug.cgi?id=20644
+// REQUIRED_ARGS: -verrors=simple
/*
TEST_OUTPUT:
----
-compilable/chkformat.d(14): Deprecation: more format specifiers than 0 arguments
+compilable/chkformat.d(15): Deprecation: more format specifiers than 0 arguments
----
*/
import core.stdc.stdio;
// COMPILABLE_MATH_TEST
// PERMUTE_ARGS:
+// REQUIRED_ARGS: -verrors=simple
// EXTRA_FILES: imports/a12506.d
/* TEST_OUTPUT:
---
-compilable/compile1.d(230): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
+compilable/compile1.d(231): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
---
*/
// PERMUTE_ARGS:
-// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -wi -o-
+// REQUIRED_ARGS: -verrors=simple -D -Dd${RESULTS_DIR}/compilable -wi -o-
/*
TEST_OUTPUT:
// PERMUTE_ARGS:
-// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -wi -o-
+// REQUIRED_ARGS: -verrors=simple -D -Dd${RESULTS_DIR}/compilable -wi -o-
/*
TEST_OUTPUT:
// PERMUTE_ARGS:
-// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -wi -o-
+// REQUIRED_ARGS: -verrors=simple -D -Dd${RESULTS_DIR}/compilable -wi -o-
/*
TEST_OUTPUT:
---
// PERMUTE_ARGS:
-// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -wi -o-
+// REQUIRED_ARGS: -verrors=simple -D -Dd${RESULTS_DIR}/compilable -wi -o-
/*
TEST_OUTPUT:
/*
-REQUIRED_ARGS: -dw
+REQUIRED_ARGS: -verrors=simple -dw
TEST_OUTPUT:
---
compilable/depmsg.d(39): Deprecation: struct `depmsg.main.Inner.A` is deprecated - With message!
// https://issues.dlang.org/show_bug.cgi?id=22668
-
+// REQUIRED_ARGS: -verrors=simple
// Overrides with same deprecated'ness are allowed
class SameParent
/*
-REQUIRED_ARGS: -verrors=3
+REQUIRED_ARGS: -verrors=simple -verrors=3
TEST_OUTPUT:
---
compilable/deprecationlimit.d(18): Deprecation: function `deprecationlimit.f` is deprecated
/+
-REQUIRED_ARGS: -HC -c -o- -wi -extern-std=c++20
+REQUIRED_ARGS: -verrors=simple -HC -c -o- -wi -extern-std=c++20
PERMUTE_ARGS:
TEST_OUTPUT:
---
// PERMUTE_ARGS: -inline
+// REQUIRED_ARGS: -verrors=simple
/*
TEST_OUTPUT:
---
-compilable/interpret3.d(6350): Deprecation: identity comparison of static arrays implicitly coerces them to slices, which are compared by reference
+compilable/interpret3.d(6351): Deprecation: identity comparison of static arrays implicitly coerces them to slices, which are compared by reference
---
*/
// PERMUTE_ARGS:
-// REQUIRED_ARGS: -unittest -verrors=0
+// REQUIRED_ARGS: -verrors=simple -unittest -verrors=0
/*
TEST_OUTPUT:
-// REQUIRED_ARGS:
+// REQUIRED_ARGS: -verrors=simple
// EXTRA_FILES: imports/a12567.d
// PERMUTE_ARGS:
/*
// https://issues.dlang.org/show_bug.cgi?id=19227
+// REQUIRED_ARGS: -verrors=simple
/* TEST_OUTPUT:
---
-compilable/test19227.d(16): Deprecation: use of complex type `cfloat` is deprecated, use `std.complex.Complex!(float)` instead
+compilable/test19227.d(17): Deprecation: use of complex type `cfloat` is deprecated, use `std.complex.Complex!(float)` instead
Deprecation: use of complex type `const(cfloat)` is deprecated, use `std.complex.Complex!(float)` instead
---
*/
// https://issues.dlang.org/show_bug.cgi?id=19609
+// REQUIRED_ARGS: -verrors=simple
// EXTRA_FILES: imports/test19609a.d imports/test19609b.d imports/test19609c.d
/*
TEST_OUTPUT:
---
-compilable/test19609.d(11): Deprecation: module `imports.test19609a` is deprecated
-compilable/test19609.d(12): Deprecation: module `imports.test19609b` is deprecated - hello
-compilable/test19609.d(13): Deprecation: module `imports.test19609c` is deprecated
+compilable/test19609.d(12): Deprecation: module `imports.test19609a` is deprecated
+compilable/test19609.d(13): Deprecation: module `imports.test19609b` is deprecated - hello
+compilable/test19609.d(14): Deprecation: module `imports.test19609c` is deprecated
---
*/
import imports.test19609a;
// https://issues.dlang.org/show_bug.cgi?id=21514
+// REQUIRED_ARGS: -verrors=simple
// DISABLED: win32 win64
/* TEST_OUTPUT:
---
-compilable/test21514.d(16): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
-compilable/test21514.d(16): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
-compilable/test21514.d(17): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
-compilable/test21514.d(17): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
-compilable/test21514.d(19): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
-compilable/test21514.d(19): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
-compilable/test21514.d(20): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
-compilable/test21514.d(20): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/test21514.d(17): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
+compilable/test21514.d(17): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
+compilable/test21514.d(18): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/test21514.d(18): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/test21514.d(20): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
+compilable/test21514.d(20): Deprecation: use of complex type `cdouble` is deprecated, use `std.complex.Complex!(double)` instead
+compilable/test21514.d(21): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
+compilable/test21514.d(21): Deprecation: use of complex type `creal` is deprecated, use `std.complex.Complex!(real)` instead
---
*/
/* https://issues.dlang.org/show_bug.cgi?id=23097
-REQUIRED_ARGS: -verrors=spec
+REQUIRED_ARGS: -verrors=simple -verrors=spec
TEST_OUTPUT:
---
(spec:2) compilable/test23097.d(14): Error: `inout` constructor `test23097.S23097.this` creates const object, not mutable
// https://issues.dlang.org/show_bug.cgi?id=9701
+// REQUIRED_ARGS: -verrors=simple
/*
TEST_OUTPUT:
---
-compilable/test9701.d(68): Deprecation: enum member `test9701.Enum.value7` is deprecated
-compilable/test9701.d(68): Deprecation: enum member `test9701.Enum.value8` is deprecated - message
+compilable/test9701.d(69): Deprecation: enum member `test9701.Enum.value7` is deprecated
+compilable/test9701.d(69): Deprecation: enum member `test9701.Enum.value8` is deprecated - message
---
*/
-// REQUIRED_ARGS:
+// REQUIRED_ARGS: -verrors=simple
// PERMUTE_ARGS:
// EXTRA_FILES: imports/udamodule1.d
/*
/*
PERMUTE_ARGS:
-REQUIRED_ARGS: -verrors=spec
+REQUIRED_ARGS: -verrors=simple -verrors=spec
TEST_OUTPUT:
---
(spec:1) compilable/verrors_spec.d(13): Error: cannot implicitly convert expression `& i` of type `int*` to `int`
fail_compilation/attributediagnostic.d(26): which calls `attributediagnostic.layer0`
fail_compilation/attributediagnostic.d(28): which calls `attributediagnostic.system`
fail_compilation/attributediagnostic.d(30): which wasn't inferred `@safe` because of:
-fail_compilation/attributediagnostic.d(30): `asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not
+fail_compilation/attributediagnostic.d(30): `asm` statement without `@trusted` annotation
fail_compilation/attributediagnostic.d(25): `attributediagnostic.layer1` is declared here
fail_compilation/attributediagnostic.d(46): Error: `@safe` function `D main` cannot call `@system` function `attributediagnostic.system1`
fail_compilation/attributediagnostic.d(35): which wasn't inferred `@safe` because of:
-fail_compilation/attributediagnostic.d(35): cast from `uint` to `int*` not allowed in safe code
+fail_compilation/attributediagnostic.d(35): cast from `uint` to `int*`
fail_compilation/attributediagnostic.d(33): `attributediagnostic.system1` is declared here
fail_compilation/attributediagnostic.d(47): Error: `@safe` function `D main` cannot call `@system` function `attributediagnostic.system2`
fail_compilation/attributediagnostic.d(41): which wasn't inferred `@safe` because of:
REQUIRED_ARGS: -de -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/bool_cast.d(17): Deprecation: cast from `ubyte[]` to `bool[]` not allowed in safe code
+fail_compilation/bool_cast.d(17): Deprecation: cast from `ubyte[]` to `bool[]` will become `@system` in a future release
fail_compilation/bool_cast.d(17): Source element may have bytes which are not 0 or 1
-fail_compilation/bool_cast.d(22): Deprecation: cast from `int*` to `bool*` not allowed in safe code
+fail_compilation/bool_cast.d(22): Deprecation: cast from `int*` to `bool*` will become `@system` in a future release
fail_compilation/bool_cast.d(22): Source element may have bytes which are not 0 or 1
-fail_compilation/bool_cast.d(24): Deprecation: cast from `bool*` to `byte*` not allowed in safe code
+fail_compilation/bool_cast.d(24): Deprecation: cast from `bool*` to `byte*` will become `@system` in a future release
fail_compilation/bool_cast.d(24): Target element could be assigned a byte which is not 0 or 1
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/bug19569.d(70): Error: `bug19569.test0` called with argument types `()` matches both:
+fail_compilation/bug19569.d(70): Error: `bug19569.test0` called with argument types `()` matches multiple overloads exactly:
fail_compilation/bug19569.d(56): `bug19569.test0()`
and:
fail_compilation/bug19569.d(57): `bug19569.test0()`
-fail_compilation/bug19569.d(71): Error: `bug19569.test1` called with argument types `()` matches both:
+fail_compilation/bug19569.d(71): Error: `bug19569.test1` called with argument types `()` matches multiple overloads exactly:
fail_compilation/bug19569.d(59): `bug19569.test1()`
and:
fail_compilation/bug19569.d(60): `bug19569.test1()`
-fail_compilation/bug19569.d(72): Error: `bug19569.test2` called with argument types `()` matches both:
+fail_compilation/bug19569.d(72): Error: `bug19569.test2` called with argument types `()` matches multiple overloads exactly:
fail_compilation/bug19569.d(62): `bug19569.test2!().test2()`
and:
fail_compilation/bug19569.d(63): `bug19569.test2!().test2()`
-fail_compilation/bug19569.d(73): Error: `bug19569.test3` called with argument types `()` matches both:
+fail_compilation/bug19569.d(73): Error: `bug19569.test3` called with argument types `()` matches multiple overloads exactly:
fail_compilation/bug19569.d(65): `bug19569.test3!().test3()`
and:
fail_compilation/bug19569.d(66): `bug19569.test3!().test3()`
-fail_compilation/bug19569.d(78): Error: `bug19569.test0` called with argument types `()` matches both:
+fail_compilation/bug19569.d(78): Error: `bug19569.test0` called with argument types `()` matches multiple overloads exactly:
fail_compilation/bug19569.d(56): `bug19569.test0()`
and:
fail_compilation/bug19569.d(57): `bug19569.test0()`
-fail_compilation/bug19569.d(79): Error: `bug19569.test1` called with argument types `()` matches both:
+fail_compilation/bug19569.d(79): Error: `bug19569.test1` called with argument types `()` matches multiple overloads exactly:
fail_compilation/bug19569.d(59): `bug19569.test1()`
and:
fail_compilation/bug19569.d(60): `bug19569.test1()`
-fail_compilation/bug19569.d(80): Error: `bug19569.test2` called with argument types `()` matches both:
+fail_compilation/bug19569.d(80): Error: `bug19569.test2` called with argument types `()` matches multiple overloads exactly:
fail_compilation/bug19569.d(62): `bug19569.test2!().test2()`
and:
fail_compilation/bug19569.d(63): `bug19569.test2!().test2()`
-fail_compilation/bug19569.d(81): Error: `bug19569.test3` called with argument types `()` matches both:
+fail_compilation/bug19569.d(81): Error: `bug19569.test3` called with argument types `()` matches multiple overloads exactly:
fail_compilation/bug19569.d(65): `bug19569.test3!().test3()`
and:
fail_compilation/bug19569.d(66): `bug19569.test3!().test3()`
-fail_compilation/bug19569.d(86): Error: `bug19569.test0` called with argument types `()` matches both:
+fail_compilation/bug19569.d(86): Error: `bug19569.test0` called with argument types `()` matches multiple overloads exactly:
fail_compilation/bug19569.d(56): `bug19569.test0()`
and:
fail_compilation/bug19569.d(57): `bug19569.test0()`
-fail_compilation/bug19569.d(87): Error: `bug19569.test1` called with argument types `()` matches both:
+fail_compilation/bug19569.d(87): Error: `bug19569.test1` called with argument types `()` matches multiple overloads exactly:
fail_compilation/bug19569.d(59): `bug19569.test1()`
and:
fail_compilation/bug19569.d(60): `bug19569.test1()`
-fail_compilation/bug19569.d(88): Error: `bug19569.test2` called with argument types `()` matches both:
+fail_compilation/bug19569.d(88): Error: `bug19569.test2` called with argument types `()` matches multiple overloads exactly:
fail_compilation/bug19569.d(62): `bug19569.test2!().test2()`
and:
fail_compilation/bug19569.d(63): `bug19569.test2!().test2()`
-fail_compilation/bug19569.d(89): Error: `bug19569.test3` called with argument types `()` matches both:
+fail_compilation/bug19569.d(89): Error: `bug19569.test3` called with argument types `()` matches multiple overloads exactly:
fail_compilation/bug19569.d(65): `bug19569.test3!().test3()`
and:
fail_compilation/bug19569.d(66): `bug19569.test3!().test3()`
REQUIRED_ARGS: -preview=dip1000 -de
TEST_OUTPUT:
---
-fail_compilation/cast_qual.d(17): Deprecation: cast from `const(int)` to `int` cannot be used as an lvalue in @safe code
-fail_compilation/cast_qual.d(19): Deprecation: cast from `const(int)` to `int` cannot be used as an lvalue in @safe code
-fail_compilation/cast_qual.d(25): Error: cast from `const(Object)` to `object.Object` not allowed in safe code
+fail_compilation/cast_qual.d(17): Deprecation: using the result of a cast from `const(int)` to `int` as an lvalue will become `@system` in a future release
+fail_compilation/cast_qual.d(19): Deprecation: using the result of a cast from `const(int)` to `int` as an lvalue will become `@system` in a future release
+fail_compilation/cast_qual.d(25): Error: cast from `const(Object)` to `object.Object` is not allowed in a `@safe` function
fail_compilation/cast_qual.d(25): Incompatible type qualifier
---
*/
REQUIRED_ARGS: -de
TEST_OUTPUT:
---
-fail_compilation/cpp_cast.d(19): Error: cast from `cpp_cast.I` to `cpp_cast.C` not allowed in safe code
+fail_compilation/cpp_cast.d(19): Error: cast from `cpp_cast.I` to `cpp_cast.C` is not allowed in a `@safe` function
fail_compilation/cpp_cast.d(19): No dynamic type information for extern(C++) classes
-fail_compilation/cpp_cast.d(21): Deprecation: cast from `cpp_cast.C` to `cpp_cast.D` not allowed in safe code
+fail_compilation/cpp_cast.d(21): Deprecation: cast from `cpp_cast.C` to `cpp_cast.D` will become `@system` in a future release
fail_compilation/cpp_cast.d(21): No dynamic type information for extern(C++) classes
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/cppeh1.d(26): Error: cannot catch C++ class objects in `@safe` code
+fail_compilation/cppeh1.d(26): Error: catching C++ class objects is not allowed in a `@safe` function
---
*/
fail_compilation/diag10319.d(26): `pure` function `diag10319.bar!int.bar` cannot access mutable static data `g`
fail_compilation/diag10319.d(34): Error: `@safe` function `D main` cannot call `@system` function `diag10319.bar!int.bar`
fail_compilation/diag10319.d(27): which wasn't inferred `@safe` because of:
-fail_compilation/diag10319.d(27): cannot take address of local `x` in `@safe` function `bar`
+fail_compilation/diag10319.d(27): taking the address of stack-allocated local variable `x`
fail_compilation/diag10319.d(24): `diag10319.bar!int.bar` is declared here
fail_compilation/diag10319.d(33): Error: function `diag10319.foo` is not `nothrow`
fail_compilation/diag10319.d(34): Error: function `diag10319.bar!int.bar` is not `nothrow`
/*
TEST_OUTPUT:
---
-fail_compilation/diag10359.d(10): Error: pointer slicing not allowed in safe functions
+fail_compilation/diag10359.d(10): Error: pointer slicing is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/diag11769.d(18): Error: `diag11769.foo!string.bar` called with argument types `(string)` matches both:
+fail_compilation/diag11769.d(18): Error: `diag11769.foo!string.bar` called with argument types `(string)` matches multiple overloads after implicit conversions:
fail_compilation/diag11769.d(13): `diag11769.foo!string.bar(wstring __param_0)`
and:
fail_compilation/diag11769.d(14): `diag11769.foo!string.bar(dstring __param_0)`
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/diag23295.d(21): Error: scope variable `x` assigned to non-scope parameter `y` calling `foo`
+fail_compilation/diag23295.d(21): Error: assigning scope variable `x` to non-scope parameter `y` calling `foo` is not allowed in a `@safe` function
fail_compilation/diag23295.d(32): which is assigned to non-scope parameter `z`
fail_compilation/diag23295.d(34): which is not `scope` because of `f = & z`
-fail_compilation/diag23295.d(24): Error: scope variable `ex` assigned to non-scope parameter `e` calling `thro`
+fail_compilation/diag23295.d(24): Error: assigning scope variable `ex` to non-scope parameter `e` calling `thro` is not allowed in a `@safe` function
fail_compilation/diag23295.d(39): which is not `scope` because of `throw e`
---
*/
REQUIRED_ARGS:
TEST_OUTPUT:
---
-fail_compilation/dip25.d(17): Error: returning `this.buffer[]` escapes a reference to parameter `this`
+fail_compilation/dip25.d(17): Error: escaping a reference to parameter `this` by returning `this.buffer[]` is not allowed in a `@safe` function
fail_compilation/dip25.d(15): perhaps annotate the function with `return`
fail_compilation/dip25.d(22): Error: returning `identity(x)` escapes a reference to parameter `x`
-fail_compilation/dip25.d(23): Error: returning `identity(x)` escapes a reference to parameter `x`
+fail_compilation/dip25.d(23): Error: escaping a reference to parameter `x` by returning `identity(x)` is not allowed in a `@safe` function
fail_compilation/dip25.d(23): perhaps annotate the parameter with `return`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail14554.d(28): Error: `fail14554.issue14554_1.foo` called with argument types `(int)` matches both:
+fail_compilation/fail14554.d(28): Error: `fail14554.issue14554_1.foo` called with argument types `(int)` matches multiple overloads exactly:
fail_compilation/fail14554.d(17): `fail14554.issue14554_1.foo!bool.foo(int j)`
and:
fail_compilation/fail14554.d(18): `fail14554.issue14554_1.foo!bool.foo(int j)`
-fail_compilation/fail14554.d(29): Error: `fail14554.issue14554_2.foo` called with argument types `(int)` matches both:
+fail_compilation/fail14554.d(29): Error: `fail14554.issue14554_2.foo` called with argument types `(int)` matches multiple overloads exactly:
fail_compilation/fail14554.d(22): `fail14554.issue14554_2.foo!bool.foo(int j)`
and:
fail_compilation/fail14554.d(23): `fail14554.issue14554_2.foo!bool.foo(int j)`
/* TEST_OUTPUT:
---
-fail_compilation/fail16600.d(22): Error: `fail16600.S.__ctor` called with argument types `(string) const` matches both:
+fail_compilation/fail16600.d(22): Error: `fail16600.S.__ctor` called with argument types `(string) const` matches multiple overloads exactly:
fail_compilation/fail16600.d(16): `fail16600.S.this(string __param_0)`
and:
fail_compilation/fail16600.d(17): `fail16600.S.this(string __param_0) immutable`
/* REQUIRED_ARGS: -preview=dip1000
* TEST_OUTPUT:
---
-fail_compilation/fail17842.d(14): Error: scope variable `p` assigned to non-scope `*q`
-fail_compilation/fail17842.d(23): Error: scope variable `obj` may not be copied into allocated memory
+fail_compilation/fail17842.d(14): Error: assigning scope variable `p` to non-scope `*q` is not allowed in a `@safe` function
+fail_compilation/fail17842.d(23): Error: copying scope variable `obj` into allocated memory is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail19729.d(35): Error: `fail19729.C.__ctor` called with argument types `(string)` matches both:
+fail_compilation/fail19729.d(35): Error: `fail19729.C.__ctor` called with argument types `(string)` matches multiple overloads exactly:
fail_compilation/fail19729.d(18): `fail19729.C.Templ!string.this(string t)`
and:
fail_compilation/fail19729.d(18): `fail19729.C.Templ!string.this(string t)`
-fail_compilation/fail19729.d(36): Error: `fail19729.D.__ctor` called with argument types `(string)` matches both:
+fail_compilation/fail19729.d(36): Error: `fail19729.D.__ctor` called with argument types `(string)` matches multiple overloads after qualifier conversion:
fail_compilation/fail19729.d(18): `fail19729.D.Templ!(const(char)[]).this(const(char)[] t)`
and:
fail_compilation/fail19729.d(18): `fail19729.D.Templ!(const(char)*).this(const(char)* t)`
/* REQUIRED_ARGS: -preview=dip1000
* TEST_OUTPUT:
---
-fail_compilation/fail19881.d(13): Error: address of local variable `local` assigned to return scope `input`
-fail_compilation/fail19881.d(13): Error: address of variable `local` assigned to `input` with longer lifetime
+fail_compilation/fail19881.d(13): Error: assigning address of local variable `local` to return scope `input` is not allowed in a `@safe` function
+fail_compilation/fail19881.d(13): Error: assigning address of variable `local` to `input` with longer lifetime is not allowed in a `@safe` function
---
*/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/fail19965.d(36): Error: address of variable `f` assigned to `a` with longer lifetime
+fail_compilation/fail19965.d(36): Error: assigning address of variable `f` to `a` with longer lifetime is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail20000.d(37): Error: cast from `fail20000.DClass` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(37): Error: cast from `fail20000.DClass` to `fail20000.CppClass` is not allowed in a `@safe` function
fail_compilation/fail20000.d(37): Source object type is incompatible with target type
-fail_compilation/fail20000.d(38): Error: cast from `fail20000.DInterface` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(38): Error: cast from `fail20000.DInterface` to `fail20000.CppClass` is not allowed in a `@safe` function
fail_compilation/fail20000.d(38): Source object type is incompatible with target type
-fail_compilation/fail20000.d(39): Error: cast from `fail20000.CppClass2` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(39): Error: cast from `fail20000.CppClass2` to `fail20000.CppClass` is not allowed in a `@safe` function
fail_compilation/fail20000.d(39): Source object type is incompatible with target type
-fail_compilation/fail20000.d(40): Error: cast from `fail20000.CppInterface2` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(40): Error: cast from `fail20000.CppInterface2` to `fail20000.CppClass` is not allowed in a `@safe` function
fail_compilation/fail20000.d(40): Source object type is incompatible with target type
-fail_compilation/fail20000.d(42): Error: cast from `fail20000.DClass` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(42): Error: cast from `fail20000.DClass` to `fail20000.CppInterface` is not allowed in a `@safe` function
fail_compilation/fail20000.d(42): Source object type is incompatible with target type
-fail_compilation/fail20000.d(43): Error: cast from `fail20000.DInterface` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(43): Error: cast from `fail20000.DInterface` to `fail20000.CppInterface` is not allowed in a `@safe` function
fail_compilation/fail20000.d(43): Source object type is incompatible with target type
-fail_compilation/fail20000.d(44): Error: cast from `fail20000.CppClass2` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(44): Error: cast from `fail20000.CppClass2` to `fail20000.CppInterface` is not allowed in a `@safe` function
fail_compilation/fail20000.d(44): Source object type is incompatible with target type
-fail_compilation/fail20000.d(45): Error: cast from `fail20000.CppInterface2` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(45): Error: cast from `fail20000.CppInterface2` to `fail20000.CppInterface` is not allowed in a `@safe` function
fail_compilation/fail20000.d(45): Source object type is incompatible with target type
-fail_compilation/fail20000.d(47): Error: cast from `fail20000.CppClass` to `fail20000.DClass` not allowed in safe code
+fail_compilation/fail20000.d(47): Error: cast from `fail20000.CppClass` to `fail20000.DClass` is not allowed in a `@safe` function
fail_compilation/fail20000.d(47): Source object type is incompatible with target type
-fail_compilation/fail20000.d(48): Error: cast from `fail20000.CppInterface` to `fail20000.DClass` not allowed in safe code
+fail_compilation/fail20000.d(48): Error: cast from `fail20000.CppInterface` to `fail20000.DClass` is not allowed in a `@safe` function
fail_compilation/fail20000.d(48): Source object type is incompatible with target type
-fail_compilation/fail20000.d(50): Error: cast from `fail20000.CppClass` to `fail20000.DInterface` not allowed in safe code
+fail_compilation/fail20000.d(50): Error: cast from `fail20000.CppClass` to `fail20000.DInterface` is not allowed in a `@safe` function
fail_compilation/fail20000.d(50): Source object type is incompatible with target type
-fail_compilation/fail20000.d(51): Error: cast from `fail20000.CppInterface` to `fail20000.DInterface` not allowed in safe code
+fail_compilation/fail20000.d(51): Error: cast from `fail20000.CppInterface` to `fail20000.DInterface` is not allowed in a `@safe` function
fail_compilation/fail20000.d(51): Source object type is incompatible with target type
---
*/
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/fail20084.d(109): Error: returning `v.front()` escapes a reference to parameter `v`
+fail_compilation/fail20084.d(109): Error: escaping a reference to parameter `v` by returning `v.front()` is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail20108.d(15): Error: address of variable `y` assigned to `x` with longer lifetime
+fail_compilation/fail20108.d(15): Error: assigning address of variable `y` to `x` with longer lifetime is not allowed in a `@safe` function
fail_compilation/fail20108.d(16): Error: scope parameter `x` may not be returned
-fail_compilation/fail20108.d(23): Error: address of variable `y` assigned to `x` with longer lifetime
-fail_compilation/fail20108.d(24): Error: scope variable `x` may not be returned
+fail_compilation/fail20108.d(23): Error: assigning address of variable `y` to `x` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/fail20108.d(24): Error: returning scope variable `x` is not allowed in a `@safe` function
---
*/
fail_compilation/fail20183.d(1016): Error: function `addr` is not callable using argument types `(int)`
fail_compilation/fail20183.d(1016): cannot pass rvalue argument `S(0).i` of type `int` to parameter `return ref int b`
fail_compilation/fail20183.d(1004): `fail20183.addr(return ref int b)` declared here
-fail_compilation/fail20183.d(1017): Error: address of expression temporary returned by `s()` assigned to `q` with longer lifetime
-fail_compilation/fail20183.d(1018): Error: address of struct literal `S(0)` assigned to `r` with longer lifetime
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail20183.d(1107): Error: address of expression temporary returned by `s()` assigned to `this.ptr` with longer lifetime
+fail_compilation/fail20183.d(1017): Error: assigning address of expression temporary returned by `s()` to `q` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/fail20183.d(1018): Error: assigning address of struct literal `S(0)` to `r` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/fail20183.d(1107): Error: assigning address of expression temporary returned by `s()` to `this.ptr` with longer lifetime is not allowed in a `@safe` function
---
*/
#line 1100
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/fail20461.d(106): Error: reference to local variable `buffer` assigned to non-scope parameter calling `assert()`
+fail_compilation/fail20461.d(106): Error: assigningreference to local variable `buffer` to non-scope parameter calling `assert()` is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail20551.d(15): Error: cannot take address of lazy parameter `e` in `@safe` function `opAssign`
+fail_compilation/fail20551.d(15): Error: taking address of lazy parameter `e` is not allowed in a `@safe` function
fail_compilation/fail20551.d(26): Error: template instance `fail20551.LazyStore!int.LazyStore.opAssign!int` error instantiating
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail20658.d(14): Error: field `U.m` cannot modify fields in `@safe` code that overlap fields with other storage classes
+fail_compilation/fail20658.d(14): Error: modifying field `U.m` which overlaps with fields with other storage classes is not allowed in a `@safe` function
---
*/
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/fail20691.d(106): Error: cannot take address of `scope` variable `sa` since `scope` applies to first indirection only
-fail_compilation/fail20691.d(107): Error: cannot take address of `scope` variable `sa` since `scope` applies to first indirection only
-fail_compilation/fail20691.d(108): Error: cannot take address of `scope` variable `sa` since `scope` applies to first indirection only
+fail_compilation/fail20691.d(106): Error: taking address of `scope` variable `sa` with pointers is not allowed in a `@safe` function
+fail_compilation/fail20691.d(107): Error: taking address of `scope` variable `sa` with pointers is not allowed in a `@safe` function
+fail_compilation/fail20691.d(108): Error: taking address of `scope` variable `sa` with pointers is not allowed in a `@safe` function
---
*/
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/fail21868b.d(19): Error: returning `&s.x` escapes a reference to parameter `s`
+fail_compilation/fail21868b.d(19): Error: escaping a reference to parameter `s` by returning `&s.x` is not allowed in a `@safe` function
fail_compilation/fail21868b.d(17): perhaps change the `return scope` into `scope return`
---
*/
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/fail22138.d(107): Error: scope variable `e` may not be returned
+fail_compilation/fail22138.d(107): Error: returning scope variable `e` is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail22157.d(32): Error: `fail22157.S!true.S.foo` called with argument types `()` matches both:
+fail_compilation/fail22157.d(32): Error: `fail22157.S!true.S.foo` called with argument types `()` matches multiple overloads exactly:
fail_compilation/fail22157.d(21): `fail22157.S!true.S.foo()`
and:
fail_compilation/fail22157.d(22): `fail22157.S!true.S.foo()`
-fail_compilation/fail22157.d(33): Error: `fail22157.S!false.S.foo` called with argument types `()` matches both:
+fail_compilation/fail22157.d(33): Error: `fail22157.S!false.S.foo` called with argument types `()` matches multiple overloads exactly:
fail_compilation/fail22157.d(26): `fail22157.S!false.S.foo()`
and:
fail_compilation/fail22157.d(27): `fail22157.S!false.S.foo()`
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/fail22366.d(22): Error: scope variable `s` may not be copied into allocated memory
-fail_compilation/fail22366.d(25): Error: scope variable `s` may not be copied into allocated memory
-fail_compilation/fail22366.d(26): Error: scope variable `s` may not be copied into allocated memory
-fail_compilation/fail22366.d(27): Error: scope variable `s` may not be copied into allocated memory
-fail_compilation/fail22366.d(28): Error: scope variable `s` may not be copied into allocated memory
-fail_compilation/fail22366.d(31): Error: scope variable `s` may not be copied into allocated memory
-fail_compilation/fail22366.d(32): Error: scope variable `s` may not be copied into allocated memory
+fail_compilation/fail22366.d(22): Error: copying scope variable `s` into allocated memory is not allowed in a `@safe` function
+fail_compilation/fail22366.d(25): Error: copying scope variable `s` into allocated memory is not allowed in a `@safe` function
+fail_compilation/fail22366.d(26): Error: copying scope variable `s` into allocated memory is not allowed in a `@safe` function
+fail_compilation/fail22366.d(27): Error: copying scope variable `s` into allocated memory is not allowed in a `@safe` function
+fail_compilation/fail22366.d(28): Error: copying scope variable `s` into allocated memory is not allowed in a `@safe` function
+fail_compilation/fail22366.d(31): Error: copying scope variable `s` into allocated memory is not allowed in a `@safe` function
+fail_compilation/fail22366.d(32): Error: copying scope variable `s` into allocated memory is not allowed in a `@safe` function
---
*/
/* TEST_OUTPUT:
---
-fail_compilation/fail23626b.d(26): Error: `fail23626b.AmbigOpApply.opApply` called with argument types `(int delegate(int i) pure nothrow @nogc @system)` matches both:
+fail_compilation/fail23626b.d(26): Error: `fail23626b.AmbigOpApply.opApply` called with argument types `(int delegate(int i) pure nothrow @nogc @system)` matches multiple overloads after qualifier conversion:
fail_compilation/fail23626b.d(12): `fail23626b.AmbigOpApply.opApply(int delegate(int) dg)`
and:
fail_compilation/fail23626b.d(17): `fail23626b.AmbigOpApply.opApply(int delegate(int) dg)`
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/fail24208.d(19): Error: reference to local variable `n` assigned to non-scope parameter `p` calling `escape`
+fail_compilation/fail24208.d(19): Error: assigning reference to local variable `n` to non-scope parameter `p` calling `escape` is not allowed in a `@safe` function
fail_compilation/fail24208.d(15): which is not `scope` because of `escaped = p`
---
+/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/fail24212.d(29): Error: reference to local variable `n` assigned to non-scope parameter `p` calling `fun`
+fail_compilation/fail24212.d(29): Error: assigning reference to local variable `n` to non-scope parameter `p` calling `fun` is not allowed in a `@safe` function
---
+/
class Base
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/fail24213.d(16): Error: reference to local variable `n` assigned to non-scope parameter `p`
+fail_compilation/fail24213.d(16): Error: assigning reference to local variable `n` to non-scope parameter `p` is not allowed in a `@safe` function
---
+/
alias Dg = void delegate(int* p) @safe pure nothrow;
/*
TEST_OUTPUT:
---
-fail_compilation/fail6497.d(12): Error: cannot take address of local `n` in `@safe` function `main`
-fail_compilation/fail6497.d(12): Error: cannot take address of local `n` in `@safe` function `main`
+fail_compilation/fail6497.d(12): Error: taking the address of stack-allocated local variable `n` is not allowed in a `@safe` function
+fail_compilation/fail6497.d(12): Error: taking the address of stack-allocated local variable `n` is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail8313.d(13): Error: `fail8313.bar` called with argument types `(int)` matches both:
+fail_compilation/fail8313.d(13): Error: `fail8313.bar` called with argument types `(int)` matches multiple overloads exactly:
fail_compilation/fail8313.d(11): `fail8313.bar!().bar(int x)`
and:
fail_compilation/fail8313.d(12): `fail8313.bar!().bar(int x)`
/*
TEST_OUTPUT:
---
-fail_compilation/fail8373.d(21): Error: `fail8373.fun1` called with argument types `(int)` matches both:
+fail_compilation/fail8373.d(21): Error: `fail8373.fun1` called with argument types `(int)` matches multiple overloads exactly:
fail_compilation/fail8373.d(15): `fail8373.fun1!().fun1!int.fun1(int)`
and:
fail_compilation/fail8373.d(16): `fail8373.fun1!int.fun1(int)`
-fail_compilation/fail8373.d(22): Error: `fail8373.fun2` called with argument types `(int)` matches both:
+fail_compilation/fail8373.d(22): Error: `fail8373.fun2` called with argument types `(int)` matches multiple overloads exactly:
fail_compilation/fail8373.d(18): `fail8373.fun2!int.fun2(int)`
and:
fail_compilation/fail8373.d(19): `fail8373.fun2!().fun2!int.fun2(int)`
REQUIRED_ARGS: -verrors=context
TEST_OUTPUT:
---
-fail_compilation/fail_pretty_errors.d(24): Error: undefined identifier `a`
+fail_compilation/fail_pretty_errors.d(27): Error: undefined identifier `a`
a = 1;
^
-fail_compilation/fail_pretty_errors.d-mixin-29(29): Error: undefined identifier `b`
-fail_compilation/fail_pretty_errors.d(34): Error: cannot implicitly convert expression `5` of type `int` to `string`
+fail_compilation/fail_pretty_errors.d-mixin-32(32): Error: undefined identifier `b`
+fail_compilation/fail_pretty_errors.d(37): Error: cannot implicitly convert expression `5` of type `int` to `string`
string x = 5;
^
-fail_compilation/fail_pretty_errors.d(39): Error: mixin `fail_pretty_errors.testMixin2.mixinTemplate!()` error instantiating
+fail_compilation/fail_pretty_errors.d(42): Error: mixin `fail_pretty_errors.testMixin2.mixinTemplate!()` error instantiating
mixin mixinTemplate;
^
-fail_compilation/fail_pretty_errors.d(45): Error: invalid array operation `"" + ""` (possible missing [])
+fail_compilation/fail_pretty_errors.d(48): Error: invalid array operation `"" + ""` (possible missing [])
auto x = ""+"";
^
-fail_compilation/fail_pretty_errors.d(45): did you mean to concatenate (`"" ~ ""`) instead ?
+fail_compilation/fail_pretty_errors.d(48): did you mean to concatenate (`"" ~ ""`) instead ?
+fail_compilation/fail_pretty_errors.d(51): Error: cannot implicitly convert expression `1111` of type `int` to `byte`
+ byte É‘ = 1111;
+ ^
---
*/
{
// check supplemental error doesn't show context
auto x = ""+"";
+
+ // Check correct spacing with the presence of unicode characters and tabs
+ byte É‘ = 1111;
}
---
fail_compilation/fail_scope.d(43): Error: returning `cast(char[])string` escapes a reference to local variable `string`
fail_compilation/fail_scope.d(61): Error: returning `s.bar()` escapes a reference to local variable `s`
-fail_compilation/fail_scope.d(72): Error: `fail_scope.foo8` called with argument types `(int)` matches both:
+fail_compilation/fail_scope.d(72): Error: `fail_scope.foo8` called with argument types `(int)` matches multiple overloads exactly:
fail_compilation/fail_scope.d(66): `fail_scope.foo8(ref int x)`
and:
fail_compilation/fail_scope.d(67): `fail_scope.foo8(return ref int x)`
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/fix22108.d(12): Error: scope variable `p` may not be returned
+fail_compilation/fix22108.d(12): Error: returning scope variable `p` is not allowed in a `@safe` function
---
*/
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/fix5212.d(14): Error: scope variable `args_` assigned to non-scope `this.args`
+fail_compilation/fix5212.d(14): Error: assigning scope variable `args_` to non-scope `this.args` is not allowed in a `@safe` function
---
*/
fail_compilation/named_arguments_overload.d(34): Error: none of the overloads of `snoopy` are callable using argument types `(immutable(T), immutable(S))`
fail_compilation/named_arguments_overload.d(17): Candidates are: `named_arguments_overload.snoopy(S s, int i = 0, T t = T())`
fail_compilation/named_arguments_overload.d(18): `named_arguments_overload.snoopy(T t, int i, S s)`
-fail_compilation/named_arguments_overload.d(35): Error: `named_arguments_overload.snoopy` called with argument types `(immutable(S), immutable(T), immutable(int))` matches both:
+fail_compilation/named_arguments_overload.d(35): Error: `named_arguments_overload.snoopy` called with argument types `(immutable(S), immutable(T), immutable(int))` matches multiple overloads after qualifier conversion:
fail_compilation/named_arguments_overload.d(17): `named_arguments_overload.snoopy(S s, int i = 0, T t = T())`
and:
fail_compilation/named_arguments_overload.d(18): `named_arguments_overload.snoopy(T t, int i, S s)`
fail_compilation/previewin.d(6): Error: function `takeFunction` is not callable using argument types `(void function(ref scope const(real) x) pure nothrow @nogc @safe)`
fail_compilation/previewin.d(6): cannot pass argument `__lambda_L6_C18` of type `void function(ref scope const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
fail_compilation/previewin.d(11): `previewin.takeFunction(void function(in real) f)` declared here
-fail_compilation/previewin.d(15): Error: scope variable `arg` assigned to global variable `myGlobal`
-fail_compilation/previewin.d(16): Error: scope variable `arg` assigned to global variable `myGlobal`
+fail_compilation/previewin.d(15): Error: assigning scope variable `arg` to global variable `myGlobal` is not allowed in a `@safe` function
+fail_compilation/previewin.d(16): Error: assigning scope variable `arg` to global variable `myGlobal` is not allowed in a `@safe` function
fail_compilation/previewin.d(17): Error: scope parameter `arg` may not be returned
-fail_compilation/previewin.d(18): Error: scope variable `arg` assigned to `ref` variable `escape` with longer lifetime
-fail_compilation/previewin.d(22): Error: returning `arg` escapes a reference to parameter `arg`
+fail_compilation/previewin.d(18): Error: assigning scope variable `arg` to `ref` variable `escape` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/previewin.d(22): Error: escaping a reference to parameter `arg` by returning `arg` is not allowed in a `@safe` function
fail_compilation/previewin.d(22): perhaps annotate the parameter with `return`
----
*/
/* TEST_OUTPUT:
---
-fail_compilation/pull12941.d(110): Error: `pull12941.foo` called with argument types `(int*)` matches both:
+fail_compilation/pull12941.d(110): Error: `pull12941.foo` called with argument types `(int*)` matches multiple overloads exactly:
fail_compilation/pull12941.d(101): `pull12941.foo(return ref scope int* p)`
and:
fail_compilation/pull12941.d(102): `pull12941.foo(return out scope int* p)`
TEST_OUTPUT:
---
fail_compilation/retscope.d(22): Error: scope parameter `p` may not be returned
-fail_compilation/retscope.d(32): Error: returning `b ? nested1(& i) : nested2(& j)` escapes a reference to local variable `j`
-fail_compilation/retscope.d(45): Error: scope variable `p` assigned to global variable `q`
-fail_compilation/retscope.d(47): Error: address of variable `i` assigned to `q` with longer lifetime
-fail_compilation/retscope.d(48): Error: scope variable `a` assigned to global variable `b`
-fail_compilation/retscope.d(49): Error: address of expression temporary returned by `(*fp2)()` assigned to `q` with longer lifetime
+fail_compilation/retscope.d(32): Error: escaping a reference to local variable `j` by returning `b ? nested1(& i) : nested2(& j)` is not allowed in a `@safe` function
+fail_compilation/retscope.d(45): Error: assigning scope variable `p` to global variable `q` is not allowed in a `@safe` function
+fail_compilation/retscope.d(47): Error: assigning address of variable `i` to `q` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/retscope.d(48): Error: assigning scope variable `a` to global variable `b` is not allowed in a `@safe` function
+fail_compilation/retscope.d(49): Error: assigning address of expression temporary returned by `(*fp2)()` to `q` with longer lifetime is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(96): Error: reference to local variable `sa` assigned to non-scope parameter `a` calling `bar8`
---
*/
// https://issues.dlang.org/show_bug.cgi?id=8838
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(123): Error: returning `foo9(cast(char[])tmp)` escapes a reference to local variable `tmp`
+fail_compilation/retscope.d(95): Error: assigning reference to local variable `sa` to non-scope parameter `a` calling `bar8` is not allowed in a `@safe` function
+fail_compilation/retscope.d(123): Error: escaping a reference to local variable `tmp` by returning `foo9(cast(char[])tmp)` is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(177): Error: address of variable `i` assigned to `p` with longer lifetime
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(197): Error: scope variable `e` may not be returned
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(212): Error: scope variable `p` assigned to non-scope `e.e`
+fail_compilation/retscope.d(176): Error: assigning address of variable `i` to `p` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/retscope.d(195): Error: returning scope variable `e` is not allowed in a `@safe` function
+fail_compilation/retscope.d(212): Error: assigning scope variable `p` to non-scope `e.e` is not allowed in a `@safe` function
---
*/
struct Escaper3 { void* e; }
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(266): Error: cannot take address of `scope` variable `p` since `scope` applies to first indirection only
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(286): Error: returning `foo6(& b)` escapes a reference to local variable `b`
+fail_compilation/retscope.d(265): Error: taking address of `scope` variable `p` with pointers is not allowed in a `@safe` function
+fail_compilation/retscope.d(286): Error: escaping a reference to local variable `b` by returning `foo6(& b)` is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(335): Error: reference to local variable `i` assigned to non-scope `f`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(358): Error: cannot take address of `scope` variable `aa` since `scope` applies to first indirection only
+fail_compilation/retscope.d(334): Error: assigning reference to local variable `i` to non-scope `f` is not allowed in a `@safe` function
+fail_compilation/retscope.d(358): Error: taking address of `scope` variable `aa` with pointers is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(1103): Error: scope variable `f` may not be returned
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(1205): Error: scope variable `f14` calling non-scope member function `Foo14.foo()`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(1311): Error: scope variable `u2` assigned to `ek` with longer lifetime
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(1405): Error: reference to local variable `buf` assigned to non-scope anonymous parameter calling `myprintf`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope.d(1509): Error: reference to stack allocated value returned by `(*fp15)()` assigned to non-scope anonymous parameter
+fail_compilation/retscope.d(1103): Error: returning scope variable `f` is not allowed in a `@safe` function
+fail_compilation/retscope.d(1205): Error: scope variable `f14` calling non-scope member function `Foo14.foo()` is not allowed in a `@safe` function
+fail_compilation/retscope.d(1311): Error: assigning scope variable `u2` to `ek` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/retscope.d(1405): Error: assigning reference to local variable `buf` to non-scope anonymous parameter calling `myprintf` is not allowed in a `@safe` function
+fail_compilation/retscope.d(1509): Error: assigning reference to stack allocated value returned by `(*fp15)()` to non-scope anonymous parameter is not allowed in a `@safe` function
---
*/
/*********************************************
TEST_OUTPUT:
---
-fail_compilation/retscope.d(1907): Error: scope variable `x` assigned to `ref` variable `this` with longer lifetime
-fail_compilation/retscope.d(1913): Error: scope variable `x` may not be returned
+fail_compilation/retscope.d(1907): Error: assigning scope variable `x` to `ref` variable `this` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/retscope.d(1913): Error: returning scope variable `x` is not allowed in a `@safe` function
---
*/
#line 1900
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/retscope2.d(102): Error: scope variable `s` assigned to `ref` variable `p` with longer lifetime
-fail_compilation/retscope2.d(107): Error: address of variable `s` assigned to `p` with longer lifetime
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope2.d(302): Error: scope variable `a` assigned to return scope `b`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope2.d(403): Error: scope variable `a` assigned to return scope `c`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope2.d(504): Error: scope variable `c` may not be returned
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope2.d(604): Error: scope variable `__param_0` assigned to non-scope anonymous parameter calling `foo600`
-fail_compilation/retscope2.d(604): Error: scope variable `__param_1` assigned to non-scope anonymous parameter calling `foo600`
+fail_compilation/retscope2.d(102): Error: assigning scope variable `s` to `ref` variable `p` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/retscope2.d(107): Error: assigning address of variable `s` to `p` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/retscope2.d(302): Error: assigning scope variable `a` to return scope `b` is not allowed in a `@safe` function
+fail_compilation/retscope2.d(403): Error: assigning scope variable `a` to return scope `c` is not allowed in a `@safe` function
+fail_compilation/retscope2.d(504): Error: returning scope variable `c` is not allowed in a `@safe` function
+fail_compilation/retscope2.d(604): Error: assigning scope variable `__param_0` to non-scope anonymous parameter calling `foo600` is not allowed in a `@safe` function
+fail_compilation/retscope2.d(604): Error: assigning scope variable `__param_1` to non-scope anonymous parameter calling `foo600` is not allowed in a `@safe` function
fail_compilation/retscope2.d(614): Error: template instance `retscope2.test600!(int*, int*)` error instantiating
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope2.d(719): Error: returning `get2(s)` escapes a reference to local variable `s`
-fail_compilation/retscope2.d(721): Error: returning `s.get1()` escapes a reference to local variable `s`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope2.d(804): Error: scope variable `e` may not be thrown
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope2.d(907): Error: address of variable `this` assigned to `p17568` with longer lifetime
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope2.d(1005): Error: scope variable `p` assigned to non-scope `this._p`
-fail_compilation/retscope2.d(1021): Error: scope variable `p` assigned to non-scope `c._p`
-fail_compilation/retscope2.d(1024): Error: scope variable `p` assigned to non-scope `d._p`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope2.d(1107): Error: scope variable `dg` may not be returned
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope2.d(1216): Error: returning `s.foo()` escapes a reference to local variable `s`
-fail_compilation/retscope2.d(1233): Error: returning `t.foo()` escapes a reference to local variable `t`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope2.d(1306): Error: copying `& i` into allocated memory escapes a reference to local variable `i`
+fail_compilation/retscope2.d(719): Error: returning `get2(s)` escapes a reference to local variable `s`
+fail_compilation/retscope2.d(721): Error: returning `s.get1()` escapes a reference to local variable `s`
+fail_compilation/retscope2.d(804): Error: throwing scope variable `e` is not allowed in a `@safe` function
+fail_compilation/retscope2.d(907): Error: assigning address of variable `this` to `p17568` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/retscope2.d(1005): Error: assigning scope variable `p` to non-scope `this._p` is not allowed in a `@safe` function
+fail_compilation/retscope2.d(1021): Error: assigning scope variable `p` to non-scope `c._p` is not allowed in a `@safe` function
+fail_compilation/retscope2.d(1024): Error: assigning scope variable `p` to non-scope `d._p` is not allowed in a `@safe` function
+fail_compilation/retscope2.d(1107): Error: returning scope variable `dg` is not allowed in a `@safe` function
+fail_compilation/retscope2.d(1216): Error: returning `s.foo()` escapes a reference to local variable `s`
+fail_compilation/retscope2.d(1233): Error: returning `t.foo()` escapes a reference to local variable `t`
+fail_compilation/retscope2.d(1306): Error: escaping a reference to local variable `i by copying `& i` into allocated memory is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope3.d(2008): Error: copying `& i` into allocated memory escapes a reference to local variable `i`
-fail_compilation/retscope3.d(2017): Error: copying `S2000(& i)` into allocated memory escapes a reference to local variable `i`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope3.d(4003): Error: copying `u[]` into allocated memory escapes a reference to parameter `u`
+fail_compilation/retscope3.d(2008): Error: escaping a reference to local variable `i by copying `& i` into allocated memory is not allowed in a `@safe` function
+fail_compilation/retscope3.d(2017): Error: escaping a reference to local variable `i by copying `S2000(& i)` into allocated memory is not allowed in a `@safe` function
+fail_compilation/retscope3.d(4003): Error: escaping a reference to parameter `u` by copying `u[]` into allocated memory is not allowed in a `@safe` function
fail_compilation/retscope3.d(4016): Error: storing reference to outer local variable `i` into allocated memory causes it to escape
-fail_compilation/retscope3.d(4025): Error: storing reference to stack allocated value returned by `makeSA()` into allocated memory causes it to escape
+fail_compilation/retscope3.d(4025): Error: escaping reference to stack allocated value returned by `makeSA()` into allocated memory
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope5.d(5010): Error: address of variable `t` assigned to `p` with longer lifetime
+fail_compilation/retscope5.d(5010): Error: assigning address of variable `t` to `p` with longer lifetime is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/retscope6.d(6007): Error: copying `& i` into allocated memory escapes a reference to local variable `i`
+fail_compilation/retscope6.d(6007): Error: escaping a reference to local variable `i by copying `& i` into allocated memory is not allowed in a `@safe` function
---
*/
/* TEST_OUTPUT:
---
-fail_compilation/retscope6.d(7034): Error: address of variable `i` assigned to `s` with longer lifetime
-fail_compilation/retscope6.d(7035): Error: address of variable `i` assigned to `s` with longer lifetime
-fail_compilation/retscope6.d(7025): Error: scope variable `__param_2` assigned to `ref` variable `t` with longer lifetime
+fail_compilation/retscope6.d(7034): Error: assigning address of variable `i` to `s` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/retscope6.d(7035): Error: assigning address of variable `i` to `s` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/retscope6.d(7025): Error: assigning scope variable `__param_2` to `ref` variable `t` with longer lifetime is not allowed in a `@safe` function
fail_compilation/retscope6.d(7037): Error: template instance `retscope6.S.emplace4!(int*)` error instantiating
-fail_compilation/retscope6.d(7037): Error: address of variable `i` assigned to `s` with longer lifetime
+fail_compilation/retscope6.d(7037): Error: assigning address of variable `i` to `s` with longer lifetime is not allowed in a `@safe` function
---
*/
/* TEST_OUTPUT:
---
-fail_compilation/retscope6.d(8016): Error: address of variable `i` assigned to `p` with longer lifetime
-fail_compilation/retscope6.d(8031): Error: reference to local variable `i` assigned to non-scope parameter `p` calling `betty`
-fail_compilation/retscope6.d(8031): Error: reference to local variable `j` assigned to non-scope parameter `q` calling `betty`
+fail_compilation/retscope6.d(8016): Error: assigning address of variable `i` to `p` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/retscope6.d(8031): Error: assigning reference to local variable `i` to non-scope parameter `p` calling `betty` is not allowed in a `@safe` function
+fail_compilation/retscope6.d(8031): Error: assigning reference to local variable `j` to non-scope parameter `q` calling `betty` is not allowed in a `@safe` function
fail_compilation/retscope6.d(8023): which is not `scope` because of `p = q`
-fail_compilation/retscope6.d(8048): Error: reference to local variable `i` assigned to non-scope parameter `p` calling `archie`
+fail_compilation/retscope6.d(8048): Error: assigning reference to local variable `i` to non-scope parameter `p` calling `archie` is not allowed in a `@safe` function
fail_compilation/retscope6.d(8039): which is not `scope` because of `r = p`
-fail_compilation/retscope6.d(8048): Error: reference to local variable `j` assigned to non-scope parameter `q` calling `archie`
+fail_compilation/retscope6.d(8048): Error: assigning reference to local variable `j` to non-scope parameter `q` calling `archie` is not allowed in a `@safe` function
fail_compilation/retscope6.d(8038): which is not `scope` because of `p = q`
---
*/
/* TEST_OUTPUT:
---
-fail_compilation/retscope6.d(9023): Error: returning `fred(& i)` escapes a reference to local variable `i`
+fail_compilation/retscope6.d(9023): Error: escaping a reference to local variable `i` by returning `fred(& i)` is not allowed in a `@safe` function
---
*/
/* TEST_OUTPUT:
---
-fail_compilation/retscope6.d(10003): Error: scope variable `values` assigned to non-scope parameter `values` calling `escape`
+fail_compilation/retscope6.d(10003): Error: assigning scope variable `values` to non-scope parameter `values` calling `escape` is not allowed in a `@safe` function
---
*/
/* TEST_OUTPUT:
---
-fail_compilation/retscope6.d(11004): Error: address of variable `buffer` assigned to `secret` with longer lifetime
+fail_compilation/retscope6.d(11004): Error: assigning address of variable `buffer` to `secret` with longer lifetime is not allowed in a `@safe` function
---
*/
/* TEST_OUTPUT:
---
-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`
+fail_compilation/retscope6.d(12011): Error: escaping a reference to local variable `x` by returning `escape_m_20150(& x)` is not allowed in a `@safe` function
+fail_compilation/retscope6.d(12022): Error: escaping a reference to local variable `x` by returning `escape_c_20150(& x)` is not allowed in a `@safe` function
---
*/
/* TEST_OUTPUT:
---
-fail_compilation/retscope6.d(13010): Error: reference to local variable `str` assigned to non-scope parameter `x` calling `f_throw`
+fail_compilation/retscope6.d(13010): Error: assigning reference to local variable `str` to non-scope parameter `x` calling `f_throw` is not allowed in a `@safe` function
---
*/
/* TEST_OUTPUT:
---
-fail_compilation/retscope6.d(14019): Error: scope variable `scopePtr` assigned to non-scope parameter `x` calling `noInfer23021`
+fail_compilation/retscope6.d(14019): Error: assigning scope variable `scopePtr` to non-scope parameter `x` calling `noInfer23021` is not allowed in a `@safe` function
fail_compilation/retscope6.d(14009): which is not `scope` because of `*escapeHole = cast(const(int)*)x`
-fail_compilation/retscope6.d(14022): Error: scope variable `scopePtr` may not be returned
+fail_compilation/retscope6.d(14022): Error: returning scope variable `scopePtr` is not allowed in a `@safe` function
---
*/
/* TEST_OUTPUT:
---
-fail_compilation/retscope6.d(14050): Error: scope variable `z` assigned to non-scope parameter `y` calling `f23294`
+fail_compilation/retscope6.d(14050): Error: assigning scope variable `z` to non-scope parameter `y` calling `f23294` is not allowed in a `@safe` function
fail_compilation/retscope6.d(14044): which is not `scope` because of `x = y`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/safe_gshared.d(13): Error: `@safe` function `f` cannot access `__gshared` data `x`
-fail_compilation/safe_gshared.d(14): Error: `@safe` function `f` cannot access `__gshared` data `x`
+fail_compilation/safe_gshared.d(13): Error: accessing `__gshared` data `x` is not allowed in a `@safe` function
+fail_compilation/safe_gshared.d(14): Error: accessing `__gshared` data `x` is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/safe_pointer_index.d(11): Error: `@safe` function `f` cannot index pointer `x`
+fail_compilation/safe_pointer_index.d(11): Error: indexing pointer `x` is not allowed in a `@safe` function
---
*/
/* REQUIRED_ARGS: -preview=safer
TEST_OUTPUT:
---
-fail_compilation/safer.d(10): Error: `void` initializers for pointers not allowed in safe functions
+fail_compilation/safer.d(10): Error: `void` initializing a pointer is not allowed in a function with default safety with `-preview=safer`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/shared.d(3004): Error: cast from `void*` to `shared(int*)` not allowed in safe code
+fail_compilation/shared.d(3004): Error: cast from `void*` to `shared(int*)` is not allowed in a `@safe` function
fail_compilation/shared.d(3004): `void` data may contain pointers and target element type is mutable
-fail_compilation/shared.d(3005): Error: cast from `void*` to `shared(const(int*))` not allowed in safe code
+fail_compilation/shared.d(3005): Error: cast from `void*` to `shared(const(int*))` is not allowed in a `@safe` function
fail_compilation/shared.d(3005): Source type is incompatible with target type containing a pointer
-fail_compilation/shared.d(3008): Error: cast from `shared(void*)` to `int*` not allowed in safe code
+fail_compilation/shared.d(3008): Error: cast from `shared(void*)` to `int*` is not allowed in a `@safe` function
fail_compilation/shared.d(3008): `void` data may contain pointers and target element type is mutable
-fail_compilation/shared.d(3009): Error: cast from `shared(void*)` to `shared(const(int*))` not allowed in safe code
+fail_compilation/shared.d(3009): Error: cast from `shared(void*)` to `shared(const(int*))` is not allowed in a `@safe` function
fail_compilation/shared.d(3009): Source type is incompatible with target type containing a pointer
---
*/
REQUIRED_ARGS: -preview=dip1000 -de
TEST_OUTPUT:
---
-fail_compilation/system_ptr_cast.d(20): Deprecation: cast from `S*` to `int*` not allowed in safe code
+fail_compilation/system_ptr_cast.d(20): Deprecation: cast from `S*` to `int*` will become `@system` in a future release
fail_compilation/system_ptr_cast.d(20): Source element type has unsafe bit patterns and target element type is mutable
-fail_compilation/system_ptr_cast.d(24): Deprecation: cast from `int*` to `S*` not allowed in safe code
+fail_compilation/system_ptr_cast.d(24): Deprecation: cast from `int*` to `S*` will become `@system` in a future release
fail_compilation/system_ptr_cast.d(24): Target element type has unsafe bit patterns
---
*/
REQUIRED_ARGS: -preview=systemVariables
TEST_OUTPUT:
---
-fail_compilation/systemvariables.d(39): Error: cannot access `@system` variable `gInt` in @safe code
+fail_compilation/systemvariables.d(39): Error: access `@system` variable `gInt` is not allowed in a `@safe` function
fail_compilation/systemvariables.d(29): `gInt` is declared here
-fail_compilation/systemvariables.d(40): Error: cannot access `@system` variable `gInt` in @safe code
+fail_compilation/systemvariables.d(40): Error: access `@system` variable `gInt` is not allowed in a `@safe` function
fail_compilation/systemvariables.d(29): `gInt` is declared here
-fail_compilation/systemvariables.d(41): Error: cannot access `@system` variable `gArr` in @safe code
+fail_compilation/systemvariables.d(41): Error: access `@system` variable `gArr` is not allowed in a `@safe` function
fail_compilation/systemvariables.d(31): `gArr` is declared here
-fail_compilation/systemvariables.d(42): Error: cannot access `@system` variable `gArr` in @safe code
+fail_compilation/systemvariables.d(42): Error: access `@system` variable `gArr` is not allowed in a `@safe` function
fail_compilation/systemvariables.d(31): `gArr` is declared here
-fail_compilation/systemvariables.d(43): Error: cannot access `@system` variable `gInt` in @safe code
+fail_compilation/systemvariables.d(43): Error: access `@system` variable `gInt` is not allowed in a `@safe` function
fail_compilation/systemvariables.d(29): `gInt` is declared here
-fail_compilation/systemvariables.d(46): Error: cannot access `@system` variable `lSys` in @safe code
+fail_compilation/systemvariables.d(46): Error: access `@system` variable `lSys` is not allowed in a `@safe` function
fail_compilation/systemvariables.d(45): `lSys` is declared here
-fail_compilation/systemvariables.d(47): Error: cannot access `@system` variable `lSys` in @safe code
+fail_compilation/systemvariables.d(47): Error: access `@system` variable `lSys` is not allowed in a `@safe` function
fail_compilation/systemvariables.d(45): `lSys` is declared here
-fail_compilation/systemvariables.d(48): Error: cannot access `@system` variable `lSys` in @safe code
+fail_compilation/systemvariables.d(48): Error: access `@system` variable `lSys` is not allowed in a `@safe` function
fail_compilation/systemvariables.d(45): `lSys` is declared here
-fail_compilation/systemvariables.d(50): Error: cannot access `@system` variable `eInt` in @safe code
+fail_compilation/systemvariables.d(50): Error: access `@system` variable `eInt` is not allowed in a `@safe` function
fail_compilation/systemvariables.d(30): `eInt` is declared here
---
*/
REQUIRED_ARGS: -de
TEST_OUTPUT:
---
-fail_compilation/systemvariables_bool_union.d(21): Deprecation: cannot access overlapped field `Box.b` with unsafe bit patterns in `@safe` code
+fail_compilation/systemvariables_bool_union.d(21): Deprecation: accessing overlapped field `Box.b` with unsafe bit patterns will become `@system` in a future release
---
*/
fail_compilation/systemvariables_deprecation.d(16): Deprecation: `@safe` function `main` calling `middle`
fail_compilation/systemvariables_deprecation.d(21): which calls `systemvariables_deprecation.inferred`
fail_compilation/systemvariables_deprecation.d(27): which wouldn't be `@safe` because of:
-fail_compilation/systemvariables_deprecation.d(27): cannot access `@system` variable `x0` in @safe code
+fail_compilation/systemvariables_deprecation.d(27): access `@system` variable `x0`
---
*/
REQUIRED_ARGS: -preview=systemVariables
TEST_OUTPUT:
---
-fail_compilation/systemvariables_struct.d(31): Error: cannot access `@system` field `S.syst` in `@safe` code
-fail_compilation/systemvariables_struct.d(32): Error: cannot access `@system` field `S.syst` in `@safe` code
-fail_compilation/systemvariables_struct.d(33): Error: cannot access `@system` field `S.syst` in `@safe` code
-fail_compilation/systemvariables_struct.d(36): Error: cannot access `@system` field `S.syst` in `@safe` code
-fail_compilation/systemvariables_struct.d(37): Error: cannot access `@system` field `S.syst` in `@safe` code
-fail_compilation/systemvariables_struct.d(38): Error: cannot access `@system` field `S.syst` in `@safe` code
-fail_compilation/systemvariables_struct.d(54): Error: cannot access `@system` field `S2.syst` in `@safe` code
-fail_compilation/systemvariables_struct.d(55): Error: cannot access `@system` field `S2.syst` in `@safe` code
-fail_compilation/systemvariables_struct.d(56): Error: cannot access `@system` field `S.syst` in `@safe` code
-fail_compilation/systemvariables_struct.d(57): Error: cannot access `@system` field `S.syst` in `@safe` code
+fail_compilation/systemvariables_struct.d(31): Error: accessing `@system` field `S.syst` is not allowed in a `@safe` function
+fail_compilation/systemvariables_struct.d(32): Error: accessing `@system` field `S.syst` is not allowed in a `@safe` function
+fail_compilation/systemvariables_struct.d(33): Error: accessing `@system` field `S.syst` is not allowed in a `@safe` function
+fail_compilation/systemvariables_struct.d(36): Error: accessing `@system` field `S.syst` is not allowed in a `@safe` function
+fail_compilation/systemvariables_struct.d(37): Error: accessing `@system` field `S.syst` is not allowed in a `@safe` function
+fail_compilation/systemvariables_struct.d(38): Error: accessing `@system` field `S.syst` is not allowed in a `@safe` function
+fail_compilation/systemvariables_struct.d(54): Error: accessing `@system` field `S2.syst` is not allowed in a `@safe` function
+fail_compilation/systemvariables_struct.d(55): Error: accessing `@system` field `S2.syst` is not allowed in a `@safe` function
+fail_compilation/systemvariables_struct.d(56): Error: accessing `@system` field `S.syst` is not allowed in a `@safe` function
+fail_compilation/systemvariables_struct.d(57): Error: accessing `@system` field `S.syst` is not allowed in a `@safe` function
---
*/
REQUIRED_ARGS: -preview=systemVariables
TEST_OUTPUT:
---
-fail_compilation/systemvariables_void_init.d(48): Error: `void` initializers for types with unsafe bit patterns are not allowed in safe functions
-fail_compilation/systemvariables_void_init.d(49): Error: `void` initializers for types with unsafe bit patterns are not allowed in safe functions
-fail_compilation/systemvariables_void_init.d(50): Error: `void` initializers for types with unsafe bit patterns are not allowed in safe functions
-fail_compilation/systemvariables_void_init.d(51): Error: a `bool` must be 0 or 1, so void intializing it is not allowed in safe functions
-fail_compilation/systemvariables_void_init.d(52): Error: a `bool` must be 0 or 1, so void intializing it is not allowed in safe functions
-fail_compilation/systemvariables_void_init.d(53): Error: `void` initializers for types with unsafe bit patterns are not allowed in safe functions
-fail_compilation/systemvariables_void_init.d(54): Error: `void` initializers for types with unsafe bit patterns are not allowed in safe functions
+fail_compilation/systemvariables_void_init.d(48): Error: `void` initializing a type with unsafe bit patterns is not allowed in a `@safe` function
+fail_compilation/systemvariables_void_init.d(49): Error: `void` initializing a type with unsafe bit patterns is not allowed in a `@safe` function
+fail_compilation/systemvariables_void_init.d(50): Error: `void` initializing a type with unsafe bit patterns is not allowed in a `@safe` function
+fail_compilation/systemvariables_void_init.d(51): Error: void intializing a bool (which must always be 0 or 1) is not allowed in a `@safe` function
+fail_compilation/systemvariables_void_init.d(52): Error: void intializing a bool (which must always be 0 or 1) is not allowed in a `@safe` function
+fail_compilation/systemvariables_void_init.d(53): Error: `void` initializing a type with unsafe bit patterns is not allowed in a `@safe` function
+fail_compilation/systemvariables_void_init.d(54): Error: `void` initializing a type with unsafe bit patterns is not allowed in a `@safe` function
---
*/
-/* REQUIRED_ARGS: -main -de
- * TEST_OUTPUT:
+/* TEST_OUTPUT:
---
-fail_compilation/test11006.d(10): Deprecation: cannot subtract pointers to different types: `void*` and `int*`.
-fail_compilation/test11006.d(10): while evaluating: `static assert(2L == 2L)`
-fail_compilation/test11006.d(11): Deprecation: cannot subtract pointers to different types: `int*` and `void*`.
-fail_compilation/test11006.d(11): while evaluating: `static assert(8L == 8L)`
+fail_compilation/test11006.d(11): Error: cannot subtract pointers to different types: `void*` and `int*`.
+fail_compilation/test11006.d(11): while evaluating: `static assert(cast(void*)8 - cast(int*)0 == 2L)`
+fail_compilation/test11006.d(12): Error: cannot subtract pointers to different types: `int*` and `void*`.
+fail_compilation/test11006.d(12): while evaluating: `static assert(cast(int*)8 - cast(void*)0 == 8L)`
+fail_compilation/test11006.d(13): Error: cannot subtract pointers to different types: `ushort*` and `ubyte*`.
+fail_compilation/test11006.d(13): while evaluating: `static assert(null - null == 0)`
---
*/
static assert(cast(void*)8 - cast(int*) 0 == 2L);
static assert(cast(int*) 8 - cast(void*)0 == 8L);
+static assert((ushort*).init - (ubyte*).init == 0);
/*
TEST_OUTPUT:
---
-fail_compilation/test11176.d(12): Error: `b.ptr` cannot be used in `@safe` code, use `&b[0]` instead
-fail_compilation/test11176.d(16): Error: `b.ptr` cannot be used in `@safe` code, use `&b[0]` instead
+fail_compilation/test11176.d(12): Error: using `b.ptr` (instead of `&b[0])` is not allowed in a `@safe` function
+fail_compilation/test11176.d(16): Error: using `b.ptr` (instead of `&b[0])` is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/test12822.d(13): Error: cannot modify delegate pointer in `@safe` code `dg.ptr`
-fail_compilation/test12822.d(14): Error: `dg.funcptr` cannot be used in `@safe` code
+fail_compilation/test12822.d(13): Error: modifying delegate pointer `dg.ptr` is not allowed in a `@safe` function
+fail_compilation/test12822.d(14): Error: using `dg.funcptr` is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/test13536.d(22): Error: field `U.sysDg` cannot access pointers in `@safe` code that overlap other fields
-fail_compilation/test13536.d(23): Error: field `U.safeDg` cannot access pointers in `@safe` code that overlap other fields
+fail_compilation/test13536.d(22): Error: accessing overlapped field `U.sysDg` with pointers is not allowed in a `@safe` function
+fail_compilation/test13536.d(23): Error: accessing overlapped field `U.safeDg` with pointers is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/test13537.d(31): Error: field `U.y` cannot modify fields in `@safe` code that overlap fields with other storage classes
-fail_compilation/test13537.d(32): Error: field `U.y` cannot modify fields in `@safe` code that overlap fields with other storage classes
-fail_compilation/test13537.d(33): Error: field `U.z` cannot access pointers in `@safe` code that overlap other fields
-fail_compilation/test13537.d(34): Error: field `U.y` cannot modify fields in `@safe` code that overlap fields with other storage classes
+fail_compilation/test13537.d(31): Error: modifying field `U.y` which overlaps with fields with other storage classes is not allowed in a `@safe` function
+fail_compilation/test13537.d(32): Error: modifying field `U.y` which overlaps with fields with other storage classes is not allowed in a `@safe` function
+fail_compilation/test13537.d(33): Error: accessing overlapped field `U.z` with pointers is not allowed in a `@safe` function
+fail_compilation/test13537.d(34): Error: modifying field `U.y` which overlaps with fields with other storage classes is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/test14496.d(21): Error: `void` initializers for pointers not allowed in safe functions
-fail_compilation/test14496.d(24): Error: `void` initializers for pointers not allowed in safe functions
-fail_compilation/test14496.d(28): Error: `void` initializers for pointers not allowed in safe functions
-fail_compilation/test14496.d(48): Error: `void` initializers for pointers not allowed in safe functions
-fail_compilation/test14496.d(49): Error: `void` initializers for pointers not allowed in safe functions
-fail_compilation/test14496.d(50): Error: `void` initializers for pointers not allowed in safe functions
+fail_compilation/test14496.d(21): Error: `void` initializing a pointer is not allowed in a `@safe` function
+fail_compilation/test14496.d(24): Error: `void` initializing a pointer is not allowed in a `@safe` function
+fail_compilation/test14496.d(28): Error: `void` initializing a pointer is not allowed in a `@safe` function
+fail_compilation/test14496.d(48): Error: `void` initializers for pointers is not allowed in a `@safe` function
+fail_compilation/test14496.d(49): Error: `void` initializers for pointers is not allowed in a `@safe` function
+fail_compilation/test14496.d(50): Error: `void` initializers for pointers is not allowed in a `@safe` function
---
*/
// https://issues.dlang.org/show_bug.cgi?id=14496
fail_compilation/test15191.d(34): Error: returning `&identity(x)` escapes a reference to local variable `x`
fail_compilation/test15191.d(40): Error: returning `&identityPtr(x)` escapes a reference to local variable `x`
fail_compilation/test15191.d(46): Error: returning `&identityPtr(x)` escapes a reference to local variable `x`
-fail_compilation/test15191.d(67): Error: cannot take address of `scope` variable `x` since `scope` applies to first indirection only
-fail_compilation/test15191.d(69): Error: cannot take address of `scope` variable `x` since `scope` applies to first indirection only
+fail_compilation/test15191.d(67): Error: taking address of `scope` variable `x` with pointers is not allowed in a `@safe` function
+fail_compilation/test15191.d(69): Error: taking address of `scope` variable `x` with pointers is not allowed in a `@safe` function
---
*/
/* https://issues.dlang.org/show_bug.cgi?id=15399
TEST_OUTPUT:
---
-fail_compilation/test15399.d(32): Error: field `S1.ptr` cannot modify misaligned pointers in `@safe` code
-fail_compilation/test15399.d(33): Error: field `S2.ptr` cannot modify misaligned pointers in `@safe` code
-fail_compilation/test15399.d(34): Error: field `S1.ptr` cannot modify misaligned pointers in `@safe` code
-fail_compilation/test15399.d(35): Error: field `S2.ptr` cannot modify misaligned pointers in `@safe` code
-fail_compilation/test15399.d(36): Error: field `S1.ptr` cannot modify misaligned pointers in `@safe` code
-fail_compilation/test15399.d(37): Error: field `S2.ptr` cannot modify misaligned pointers in `@safe` code
-fail_compilation/test15399.d(38): Error: field `S1.ptr` cannot modify misaligned pointers in `@safe` code
-fail_compilation/test15399.d(39): Error: field `S2.ptr` cannot modify misaligned pointers in `@safe` code
+fail_compilation/test15399.d(32): Error: modifying misaligned pointers through field `S1.ptr` is not allowed in a `@safe` function
+fail_compilation/test15399.d(33): Error: modifying misaligned pointers through field `S2.ptr` is not allowed in a `@safe` function
+fail_compilation/test15399.d(34): Error: modifying misaligned pointers through field `S1.ptr` is not allowed in a `@safe` function
+fail_compilation/test15399.d(35): Error: modifying misaligned pointers through field `S2.ptr` is not allowed in a `@safe` function
+fail_compilation/test15399.d(36): Error: modifying misaligned pointers through field `S1.ptr` is not allowed in a `@safe` function
+fail_compilation/test15399.d(37): Error: modifying misaligned pointers through field `S2.ptr` is not allowed in a `@safe` function
+fail_compilation/test15399.d(38): Error: modifying misaligned pointers through field `S1.ptr` is not allowed in a `@safe` function
+fail_compilation/test15399.d(39): Error: modifying misaligned pointers through field `S2.ptr` is not allowed in a `@safe` function
---
*/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test15544.d(20): Error: reference to local `this` assigned to non-scope `_del` in @safe code
-fail_compilation/test15544.d(22): Error: reference to local `this` assigned to non-scope `_del` in @safe code
+fail_compilation/test15544.d(20): Error: assigning reference to local `this` to non-scope `_del` is not allowed in a `@safe` function
+fail_compilation/test15544.d(22): Error: assigning reference to local `this` to non-scope `_del` is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/test15544.d(46): Error: reference to local `y` assigned to non-scope `dg` in @safe code
+fail_compilation/test15544.d(46): Error: assigning reference to local `y` to non-scope `dg` is not allowed in a `@safe` function
---
*/
/*
* TEST_OUTPUT:
---
-fail_compilation/test15672.d(17): Error: cast from `void[]` to `byte[]` not allowed in safe code
+fail_compilation/test15672.d(17): Error: cast from `void[]` to `byte[]` is not allowed in a `@safe` function
fail_compilation/test15672.d(17): `void` data may contain pointers and target element type is mutable
-fail_compilation/test15672.d(27): Error: cast from `void*` to `byte*` not allowed in safe code
+fail_compilation/test15672.d(27): Error: cast from `void*` to `byte*` is not allowed in a `@safe` function
fail_compilation/test15672.d(27): `void` data may contain pointers and target element type is mutable
---
*/
REQUIRED_ARGS: -m32
TEST_OUTPUT:
---
-fail_compilation/test15703.d(23): Error: cast from `Object[]` to `uint[]` not allowed in safe code
+fail_compilation/test15703.d(23): Error: cast from `Object[]` to `uint[]` is not allowed in a `@safe` function
fail_compilation/test15703.d(23): Target element type is mutable and source element type contains a pointer
-fail_compilation/test15703.d(25): Error: cast from `object.Object` to `const(uint)*` not allowed in safe code
+fail_compilation/test15703.d(25): Error: cast from `object.Object` to `const(uint)*` is not allowed in a `@safe` function
fail_compilation/test15703.d(25): Source type is incompatible with target type containing a pointer
-fail_compilation/test15703.d(28): Error: cast from `uint[]` to `Object[]` not allowed in safe code
+fail_compilation/test15703.d(28): Error: cast from `uint[]` to `Object[]` is not allowed in a `@safe` function
fail_compilation/test15703.d(28): Target element type contains a pointer
-fail_compilation/test15703.d(44): Error: cast from `int[]` to `S[]` not allowed in safe code
+fail_compilation/test15703.d(44): Error: cast from `int[]` to `S[]` is not allowed in a `@safe` function
fail_compilation/test15703.d(44): Target element type is opaque
-fail_compilation/test15703.d(45): Error: cast from `S[]` to `int[]` not allowed in safe code
+fail_compilation/test15703.d(45): Error: cast from `S[]` to `int[]` is not allowed in a `@safe` function
fail_compilation/test15703.d(45): Source element type is opaque
---
*/
/*
* TEST_OUTPUT:
---
-fail_compilation/test15704.d(17): Error: cannot copy `void[]` to `void[]` in `@safe` code
-fail_compilation/test15704.d(18): Error: cannot copy `const(void)[]` to `void[]` in `@safe` code
-fail_compilation/test15704.d(19): Deprecation: cannot copy `int[]` to `void[]` in `@safe` code
+fail_compilation/test15704.d(17): Error: copying `void[]` to `void[]` is not allowed in a `@safe` function
+fail_compilation/test15704.d(18): Error: copying `const(void)[]` to `void[]` is not allowed in a `@safe` function
+fail_compilation/test15704.d(19): Deprecation: copying `int[]` to `void[]` will become `@system` in a future release
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/test16365.d(20): Error: `this` reference necessary to take address of member `f1` in `@safe` function `main`
+fail_compilation/test16365.d(20): Error: taking address of member `f1` without `this` reference is not allowed in a `@safe` function
fail_compilation/test16365.d(22): Error: cannot implicitly convert expression `&f2` of type `void delegate() pure nothrow @nogc @safe` to `void function() @safe`
-fail_compilation/test16365.d(27): Error: `dg.funcptr` cannot be used in `@safe` code
+fail_compilation/test16365.d(27): Error: using `dg.funcptr` is not allowed in a `@safe` function
---
*/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test16589.d(26): Error: returning `&this.data` escapes a reference to parameter `this`
+fail_compilation/test16589.d(26): Error: escaping a reference to parameter `this` by returning `&this.data` is not allowed in a `@safe` function
fail_compilation/test16589.d(24): perhaps annotate the function with `return`
-fail_compilation/test16589.d(31): Error: returning `&this` escapes a reference to parameter `this`
+fail_compilation/test16589.d(31): Error: escaping a reference to parameter `this` by returning `&this` is not allowed in a `@safe` function
fail_compilation/test16589.d(29): perhaps annotate the function with `return`
-fail_compilation/test16589.d(37): Error: returning `&s.data` escapes a reference to parameter `s`
+fail_compilation/test16589.d(37): Error: escaping a reference to parameter `s` by returning `&s.data` is not allowed in a `@safe` function
fail_compilation/test16589.d(35): perhaps annotate the parameter with `return`
-fail_compilation/test16589.d(42): Error: returning `&s` escapes a reference to parameter `s`
+fail_compilation/test16589.d(42): Error: escaping a reference to parameter `s` by returning `&s` is not allowed in a `@safe` function
fail_compilation/test16589.d(40): perhaps annotate the parameter with `return`
fail_compilation/test16589.d(47): Error: returning `&s.data` escapes a reference to parameter `s`
fail_compilation/test16589.d(52): Error: returning `& s` escapes a reference to parameter `s`
/*
TEST_OUTPUT:
---
-fail_compilation/test17284.d(17): Error: field `U.c` cannot access pointers in `@safe` code that overlap other fields
+fail_compilation/test17284.d(17): Error: accessing overlapped field `U.c` with pointers is not allowed in a `@safe` function
pure nothrow @safe void(U t)
---
REQUIRED_ARGS: -preview=bitfields
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test17422.d(23): Error: scope variable `p` may not be returned
+fail_compilation/test17422.d(23): Error: returning scope variable `p` is not allowed in a `@safe` function
---
*/
struct RC
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test17423.d(27): Error: reference to local `this` assigned to non-scope parameter `dlg` calling `opApply`
+fail_compilation/test17423.d(27): Error: assigning reference to local `this` to non-scope parameter `dlg` calling `opApply` is not allowed in a `@safe` function
fail_compilation/test17423.d(16): which is not `scope` because of `this.myDlg = dlg`
---
*/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test17450.d(17): Error: returning `&s.bar` escapes a reference to parameter `s`
+fail_compilation/test17450.d(17): Error: escaping a reference to parameter `s` by returning `&s.bar` is not allowed in a `@safe` function
fail_compilation/test17450.d(16): perhaps annotate the parameter with `return`
-fail_compilation/test17450.d(20): Error: returning `&this.bar` escapes a reference to parameter `this`
+fail_compilation/test17450.d(20): Error: escaping a reference to parameter `this` by returning `&this.bar` is not allowed in a `@safe` function
fail_compilation/test17450.d(19): perhaps annotate the function with `return`
---
*/
/* REQUIRED_ARGS: -preview=dip1000
* TEST_OUTPUT:
---
-fail_compilation/test17764.d(109): Error: scope variable `c` assigned to global variable `global`
+fail_compilation/test17764.d(109): Error: assigning scope variable `c` to global variable `global` is not allowed in a `@safe` function
---
*/
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test17959.d(18): Error: scope variable `this` assigned to non-scope `this.escape`
-fail_compilation/test17959.d(19): Error: scope variable `this` assigned to non-scope `this.f`
+fail_compilation/test17959.d(18): Error: assigning scope variable `this` to non-scope `this.escape` is not allowed in a `@safe` function
+fail_compilation/test17959.d(19): Error: assigning scope variable `this` to non-scope `this.f` is not allowed in a `@safe` function
---
*/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test17977.d(19): Error: address of variable `__slList3` assigned to `elem` with longer lifetime
+fail_compilation/test17977.d(19): Error: assigning address of variable `__slList3` to `elem` with longer lifetime is not allowed in a `@safe` function
---
*/
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test18282.d(25): Error: scope variable `aa` may not be returned
-fail_compilation/test18282.d(34): Error: copying `& i` into allocated memory escapes a reference to local variable `i`
-fail_compilation/test18282.d(35): Error: copying `& i` into allocated memory escapes a reference to local variable `i`
-fail_compilation/test18282.d(36): Error: scope variable `staa` may not be returned
-fail_compilation/test18282.d(44): Error: copying `S2000(& i)` into allocated memory escapes a reference to local variable `i`
-fail_compilation/test18282.d(53): Error: copying `& i` into allocated memory escapes a reference to local variable `i`
-fail_compilation/test18282.d(53): Error: copying `& c` into allocated memory escapes a reference to local variable `c`
+fail_compilation/test18282.d(25): Error: returning scope variable `aa` is not allowed in a `@safe` function
+fail_compilation/test18282.d(34): Error: escaping a reference to local variable `i by copying `& i` into allocated memory is not allowed in a `@safe` function
+fail_compilation/test18282.d(35): Error: escaping a reference to local variable `i by copying `& i` into allocated memory is not allowed in a `@safe` function
+fail_compilation/test18282.d(36): Error: returning scope variable `staa` is not allowed in a `@safe` function
+fail_compilation/test18282.d(44): Error: escaping a reference to local variable `i by copying `S2000(& i)` into allocated memory is not allowed in a `@safe` function
+fail_compilation/test18282.d(53): Error: escaping a reference to local variable `i by copying `& i` into allocated memory is not allowed in a `@safe` function
+fail_compilation/test18282.d(53): Error: escaping a reference to local variable `c by copying `& c` into allocated memory is not allowed in a `@safe` function
---
*/
/******************************
TEST_OUTPUT:
---
-fail_compilation/test18282.d(1007): Error: copying `& foo` into allocated memory escapes a reference to local variable `foo`
-fail_compilation/test18282.d(1008): Error: copying `& foo` into allocated memory escapes a reference to local variable `foo`
-fail_compilation/test18282.d(1009): Error: copying `& foo` into allocated memory escapes a reference to local variable `foo`
-fail_compilation/test18282.d(1016): Error: copying `&this` into allocated memory escapes a reference to parameter `this`
+fail_compilation/test18282.d(1007): Error: escaping a reference to local variable `foo by copying `& foo` into allocated memory is not allowed in a `@safe` function
+fail_compilation/test18282.d(1008): Error: escaping a reference to local variable `foo by copying `& foo` into allocated memory is not allowed in a `@safe` function
+fail_compilation/test18282.d(1009): Error: escaping a reference to local variable `foo by copying `& foo` into allocated memory is not allowed in a `@safe` function
+fail_compilation/test18282.d(1016): Error: escaping a reference to parameter `this` by copying `&this` into allocated memory is not allowed in a `@safe` function
---
*/
TEST_OUTPUT:
---
-fail_compilation/test18385b.d(13): Error: `test18385b.S.foo` called with argument types `(int)` matches both:
+fail_compilation/test18385b.d(13): Error: `test18385b.S.foo` called with argument types `(int)` matches multiple overloads exactly:
fail_compilation/test18385b.d(8): `test18385b.S.foo(int s)`
and:
fail_compilation/test18385b.d(3): `test18385b.foo(int s)`
-fail_compilation/test18385b.d(102): Error: `test18385b.bar` called with argument types `(int)` matches both:
+fail_compilation/test18385b.d(102): Error: `test18385b.bar` called with argument types `(int)` matches multiple overloads exactly:
fail_compilation/test18385b.d(2): `test18385b.bar(int s)`
and:
fail_compilation/test18385b.d(3): `test18385b.foo(int s)`
/* TEST_OUTPUT:
---
-fail_compilation/test18597.d(24): Error: field `Unaligned.p` cannot modify misaligned pointers in `@safe` code
-fail_compilation/test18597.d(25): Error: field `Unaligned.p` cannot assign to misaligned pointers in `@safe` code
-fail_compilation/test18597.d(26): Error: field `Unaligned.p` cannot assign to misaligned pointers in `@safe` code
+fail_compilation/test18597.d(24): Error: modifying misaligned pointers through field `Unaligned.p` is not allowed in a `@safe` function
+fail_compilation/test18597.d(25): Error: field `Unaligned.p` assigning to misaligned pointers is not allowed in a `@safe` function
+fail_compilation/test18597.d(26): Error: field `Unaligned.p` assigning to misaligned pointers is not allowed in a `@safe` function
---
*/
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test18644.d(15): Error: nested function `foo` returns `scope` values and escapes them into allocated memory
-fail_compilation/test18644.d(16): Error: escaping local variable through nested function `foo`
-fail_compilation/test18644.d(22): Error: escaping local variable through nested function `foo`
+fail_compilation/test18644.d(15): Error: escaping a `scope` value returned from nested function `foo` into allocated memory is not allowed in a `@safe` function
+fail_compilation/test18644.d(16): Error: escaping local variable through nested function `foo` is not allowed in a `@safe` function
+fail_compilation/test18644.d(22): Error: escaping local variable through nested function `foo` is not allowed in a `@safe` function
---
*/
/* REQUIRED_ARGS: -preview=dip1000
* TEST_OUTPUT:
---
-fail_compilation/test19097.d(44): Error: scope variable `s` may not be returned
-fail_compilation/test19097.d(48): Error: scope variable `s1` may not be returned
-fail_compilation/test19097.d(77): Error: scope variable `z` assigned to `ref` variable `refPtr` with longer lifetime
-fail_compilation/test19097.d(108): Error: scope variable `s4` may not be returned
-fail_compilation/test19097.d(126): Error: scope variable `s5c` may not be returned
-fail_compilation/test19097.d(130): Error: scope variable `s5m` may not be returned
-fail_compilation/test19097.d(147): Error: scope variable `s6c` may not be returned
-fail_compilation/test19097.d(151): Error: scope variable `s6m` may not be returned
+fail_compilation/test19097.d(44): Error: returning scope variable `s` is not allowed in a `@safe` function
+fail_compilation/test19097.d(48): Error: returning scope variable `s1` is not allowed in a `@safe` function
+fail_compilation/test19097.d(77): Error: assigning scope variable `z` to `ref` variable `refPtr` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/test19097.d(108): Error: returning scope variable `s4` is not allowed in a `@safe` function
+fail_compilation/test19097.d(126): Error: returning scope variable `s5c` is not allowed in a `@safe` function
+fail_compilation/test19097.d(130): Error: returning scope variable `s5m` is not allowed in a `@safe` function
+fail_compilation/test19097.d(147): Error: returning scope variable `s6c` is not allowed in a `@safe` function
+fail_compilation/test19097.d(151): Error: returning scope variable `s6m` is not allowed in a `@safe` function
---
*/
/* TEST_OUTPUT:
---
-fail_compilation/test19646.d(12): Error: cast from `const(int)*` to `int*` not allowed in safe code
+fail_compilation/test19646.d(12): Error: cast from `const(int)*` to `int*` can't initialize `@safe` variable `y`
fail_compilation/test19646.d(12): Source type is incompatible with target type containing a pointer
fail_compilation/test19646.d(18): Error: `@safe` variable `z` cannot be initialized by calling `@system` function `f`
---
/*
TEST_OUTPUT:
---
-fail_compilation/imports/test20023b.d(8): Error: scope variable `e` may not be returned
+fail_compilation/imports/test20023b.d(8): Error: returning scope variable `e` is not allowed in a `@safe` function
fail_compilation/test20023.d(15): Error: template instance `imports.test20023b.threw!()` error instantiating
---
*/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test20245.d(21): Error: reference to local variable `x` assigned to non-scope parameter `ptr` calling `escape`
-fail_compilation/test20245.d(22): Error: copying `&x` into allocated memory escapes a reference to parameter `x`
-fail_compilation/test20245.d(23): Error: scope variable `a` may not be returned
-fail_compilation/test20245.d(27): Error: cannot take address of `scope` variable `x` since `scope` applies to first indirection only
-fail_compilation/test20245.d(33): Error: reference to local variable `x` assigned to non-scope parameter `ptr` calling `escape`
-fail_compilation/test20245.d(34): Error: copying `&x` into allocated memory escapes a reference to parameter `x`
-fail_compilation/test20245.d(50): Error: reference to local variable `price` assigned to non-scope `this.minPrice`
-fail_compilation/test20245.d(69): Error: reference to local variable `this.content[]` calling non-scope member function `Exception.this()`
-fail_compilation/test20245.d(89): Error: reference to local variable `this` assigned to non-scope parameter `content` calling `listUp`
+fail_compilation/test20245.d(21): Error: assigning reference to local variable `x` to non-scope parameter `ptr` calling `escape` is not allowed in a `@safe` function
+fail_compilation/test20245.d(22): Error: escaping a reference to parameter `x` by copying `&x` into allocated memory is not allowed in a `@safe` function
+fail_compilation/test20245.d(23): Error: returning scope variable `a` is not allowed in a `@safe` function
+fail_compilation/test20245.d(27): Error: taking address of `scope` variable `x` with pointers is not allowed in a `@safe` function
+fail_compilation/test20245.d(33): Error: assigning reference to local variable `x` to non-scope parameter `ptr` calling `escape` is not allowed in a `@safe` function
+fail_compilation/test20245.d(34): Error: escaping a reference to parameter `x` by copying `&x` into allocated memory is not allowed in a `@safe` function
+fail_compilation/test20245.d(50): Error: assigning reference to local variable `price` to non-scope `this.minPrice` is not allowed in a `@safe` function
+fail_compilation/test20245.d(69): Error: reference to local variable `this.content[]` calling non-scope member function `Exception.this()` is not allowed in a `@safe` function
+fail_compilation/test20245.d(89): Error: assigning reference to local variable `this` to non-scope parameter `content` calling `listUp` is not allowed in a `@safe` function
fail_compilation/test20245.d(82): which is not `scope` because of `charPtr = content`
---
*/
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test20569.d(19): Error: cannot take address of `scope` variable `s1` since `scope` applies to first indirection only
-fail_compilation/test20569.d(23): Error: cannot take address of `scope` variable `s2` since `scope` applies to first indirection only
+fail_compilation/test20569.d(19): Error: taking address of `scope` variable `s1` with pointers is not allowed in a `@safe` function
+fail_compilation/test20569.d(23): Error: taking address of `scope` variable `s2` with pointers is not allowed in a `@safe` function
---
*/
---
fail_compilation/test20655.d(29): Deprecation: `@safe` function `g` calling `f1`
fail_compilation/test20655.d(24): which wouldn't be `@safe` because of:
-fail_compilation/test20655.d(24): field `U.s` cannot access pointers in `@safe` code that overlap other fields
+fail_compilation/test20655.d(24): accessing overlapped field `U.s` with pointers
fail_compilation/test20655.d(30): Deprecation: `@safe` function `g` calling `f2`
fail_compilation/test20655.d(25): which wouldn't be `@safe` because of:
-fail_compilation/test20655.d(25): field `U.s` cannot access pointers in `@safe` code that overlap other fields
+fail_compilation/test20655.d(25): accessing overlapped field `U.s` with pointers
fail_compilation/test20655.d(31): Deprecation: `@safe` function `g` calling `f3`
fail_compilation/test20655.d(28): which wouldn't be `@safe` because of:
-fail_compilation/test20655.d(28): field `U.s` cannot access pointers in `@safe` code that overlap other fields
+fail_compilation/test20655.d(28): accessing overlapped field `U.s` with pointers
---
*/
REQUIRED_ARGS:
TEST_OUTPUT:
---
-fail_compilation/test20809.d(114): Error: returning `this.a` escapes a reference to parameter `this`
+fail_compilation/test20809.d(114): Error: escaping a reference to parameter `this` by returning `this.a` is not allowed in a `@safe` function
fail_compilation/test20809.d(112): perhaps annotate the function with `return`
---
*/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test20881.d(20): Error: scope variable `this` may not be returned
-fail_compilation/test20881.d(27): Error: address of variable `s` assigned to `global` with longer lifetime
-fail_compilation/test20881.d(28): Error: address of variable `s` assigned to `global` with longer lifetime
-fail_compilation/test20881.d(29): Error: address of variable `s` assigned to `global` with longer lifetime
+fail_compilation/test20881.d(20): Error: returning scope variable `this` is not allowed in a `@safe` function
+fail_compilation/test20881.d(27): Error: assigning address of variable `s` to `global` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/test20881.d(28): Error: assigning address of variable `s` to `global` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/test20881.d(29): Error: assigning address of variable `s` to `global` with longer lifetime is not allowed in a `@safe` function
---
*/
@safe:
fail_compilation/test20998.d(90): Error: too many initializers for `X3` with 3 fields
X3 x3 = { ptr: null, "a", ptr: 2, 444 };
^
-fail_compilation/test20998.d(98): Error: field `X4.ptr` cannot assign to misaligned pointers in `@safe` code
+fail_compilation/test20998.d(98): Error: field `X4.ptr` assigning to misaligned pointers is not allowed in a `@safe` function
X4 x4 = { ptr: null, "a", 444, ptr: 2, true };
^
fail_compilation/test20998.d(98): Error: cannot implicitly convert expression `"a"` of type `string` to `int`
/* TEST_OUTPUT:
---
-fail_compilation/test21665.d(18): Error: `void` initializers for structs with invariants are not allowed in safe functions
-fail_compilation/test21665.d(30): Error: field `U.s` cannot access structs with invariants in `@safe` code that overlap other fields
+fail_compilation/test21665.d(18): Error: `void` initializing a struct with an invariant is not allowed in a `@safe` function
+fail_compilation/test21665.d(30): Error: accessing overlapped field `U.s` with a structs invariant is not allowed in a `@safe` function
---
*/
/* TEST_OUTPUT:
REQUIRED_ARGS: -preview=dip1000
---
-fail_compilation/test22145.d(115): Error: scope variable `x` assigned to global variable `global`
+fail_compilation/test22145.d(115): Error: assigning scope variable `x` to global variable `global` is not allowed in a `@safe` function
---
*/
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test22227.d(12): Error: scope variable `foo` may not be returned
-fail_compilation/test22227.d(14): Error: scope variable `foo` may not be returned
+fail_compilation/test22227.d(12): Error: returning scope variable `foo` is not allowed in a `@safe` function
+fail_compilation/test22227.d(14): Error: returning scope variable `foo` is not allowed in a `@safe` function
---
*/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test22298.d(18): Error: scope variable `i` assigned to `p` with longer lifetime
-fail_compilation/test22298.d(29): Error: scope variable `y` assigned to `x` with longer lifetime
+fail_compilation/test22298.d(18): Error: assigning scope variable `i` to `p` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/test22298.d(29): Error: assigning scope variable `y` to `x` with longer lifetime is not allowed in a `@safe` function
---
*/
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test22541.d(104): Error: returning `i` escapes a reference to parameter `i`
+fail_compilation/test22541.d(104): Error: escaping a reference to parameter `i` by returning `i` is not allowed in a `@safe` function
fail_compilation/test22541.d(102): perhaps annotate the parameter with `return`
---
*/
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test22680.d(104): Error: scope variable `this` assigned to global variable `c`
+fail_compilation/test22680.d(104): Error: assigning scope variable `this` to global variable `c` is not allowed in a `@safe` function
---
*/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test22709.d(15): Error: address of variable `local` assigned to `arr` with longer lifetime
-fail_compilation/test22709.d(20): Error: address of variable `local` assigned to `arr` with longer lifetime
+fail_compilation/test22709.d(15): Error: assigning address of variable `local` to `arr` with longer lifetime is not allowed in a `@safe` function
+fail_compilation/test22709.d(20): Error: assigning address of variable `local` to `arr` with longer lifetime is not allowed in a `@safe` function
---
*/
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test22910.d(17): Error: returning `&this.val` escapes a reference to parameter `this`
+fail_compilation/test22910.d(17): Error: escaping a reference to parameter `this` by returning `&this.val` is not allowed in a `@safe` function
fail_compilation/test22910.d(15): perhaps change the `return scope` into `scope return`
---
*/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test22977.d(16): Error: escaping local variable through nested function `scfunc`
-fail_compilation/test22977.d(22): Error: escaping local variable through nested function `scfunc2`
+fail_compilation/test22977.d(16): Error: escaping local variable through nested function `scfunc` is not allowed in a `@safe` function
+fail_compilation/test22977.d(22): Error: escaping local variable through nested function `scfunc2` is not allowed in a `@safe` function
---
*/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test23073.d(28): Error: scope variable `c` assigned to non-scope parameter `c` calling `assignNext`
+fail_compilation/test23073.d(28): Error: assigning scope variable `c` to non-scope parameter `c` calling `assignNext` is not allowed in a `@safe` function
fail_compilation/test23073.d(22): which is not `scope` because of `c.next = c`
---
*/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test23491.d(16): Error: reference to local variable `buffer` assigned to non-scope anonymous parameter
-fail_compilation/test23491.d(17): Error: reference to local variable `buffer` assigned to non-scope anonymous parameter calling `sinkF`
-fail_compilation/test23491.d(18): Error: reference to local variable `buffer` assigned to non-scope parameter `buf`
+fail_compilation/test23491.d(16): Error: reference to local variable `buffer` assigned to non-scope anonymous parameter is not allowed in a `@safe` function
+fail_compilation/test23491.d(17): Error: assigning reference to local variable `buffer` to non-scope anonymous parameter calling `sinkF` is not allowed in a `@safe` function
+fail_compilation/test23491.d(18): Error: assigning reference to local variable `buffer` to non-scope parameter `buf` is not allowed in a `@safe` function
---
*/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test23982.d(35): Error: scope variable `a` assigned to non-scope parameter `a` calling `foo2`
+fail_compilation/test23982.d(35): Error: assigning scope variable `a` to non-scope parameter `a` calling `foo2` is not allowed in a `@safe` function
fail_compilation/test23982.d(26): which is not `scope` because of `b = a`
---
*/
/* REQUIRED_ARGS: -preview=dip1000
* TEST_OUTPUT:
---
-fail_compilation/test24015.d(19): Error: scope variable `v` assigned to non-scope parameter `...` calling `jer`
+fail_compilation/test24015.d(19): Error: assigning scope variable `v` to non-scope parameter `...` calling `jer` is not allowed in a `@safe` function
---
*/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test24680.d(19): Error: returning `c.peek(buf[])` escapes a reference to local variable `buf`
+fail_compilation/test24680.d(19): Error: escaping a reference to local variable `buf` by returning `c.peek(buf[])` is not allowed in a `@safe` function
---
*/
REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/test24694.d(25): Error: reference to local variable `x` assigned to non-scope `b.c.p`
+fail_compilation/test24694.d(25): Error: assigning reference to local variable `x` to non-scope `b.c.p` is not allowed in a `@safe` function
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/testInference.d(225): Error: `testInference.test17086` called with argument types `(bool)` matches both:
+fail_compilation/testInference.d(225): Error: `testInference.test17086` called with argument types `(bool)` matches multiple overloads exactly:
fail_compilation/testInference.d(219): `testInference.test17086!(bool, false).test17086(bool x)`
and:
fail_compilation/testInference.d(220): `testInference.test17086!(bool, false).test17086(bool y)`
/+
TEST_OUTPUT:
---
-fail_compilation/testOpApply.d(27): Error: `testOpApply.SameAttr.opApply` called with argument types `(int delegate(int i) pure nothrow @nogc @safe)` matches both:
+fail_compilation/testOpApply.d(27): Error: `testOpApply.SameAttr.opApply` called with argument types `(int delegate(int i) pure nothrow @nogc @safe)` matches multiple overloads after qualifier conversion:
fail_compilation/testOpApply.d(13): `testOpApply.SameAttr.opApply(int delegate(int) @system dg)`
and:
fail_compilation/testOpApply.d(18): `testOpApply.SameAttr.opApply(int delegate(int) @system dg)`
/+
TEST_OUTPUT:
---
-fail_compilation/testOpApply.d(104): Error: `testOpApply.SameAttr.opApply` called with argument types `(int delegate(int i) pure nothrow @nogc @system)` matches both:
+fail_compilation/testOpApply.d(104): Error: `testOpApply.SameAttr.opApply` called with argument types `(int delegate(int i) pure nothrow @nogc @system)` matches multiple overloads after qualifier conversion:
fail_compilation/testOpApply.d(13): `testOpApply.SameAttr.opApply(int delegate(int) @system dg)`
and:
fail_compilation/testOpApply.d(18): `testOpApply.SameAttr.opApply(int delegate(int) @system dg)`
TEST_OUTPUT:
---
-fail_compilation/union_initialization.d(19): Error: field `B.p` cannot access pointers in `@safe` code that overlap other fields
-fail_compilation/union_initialization.d(25): Error: field `B.p` cannot access pointers in `@safe` code that overlap other fields
+fail_compilation/union_initialization.d(19): Error: accessing overlapped field `B.p` with pointers is not allowed in a `@safe` function
+fail_compilation/union_initialization.d(25): Error: accessing overlapped field `B.p` with pointers is not allowed in a `@safe` function
---
*/
/* PERMUTE_ARGS:
+REQUIRED_ARGS: -verrors=simple
TEST_OUTPUT:
---
-runnable/future.d(16): Deprecation: method `future.B.msg` implicitly overrides `@__future` base class method; rename the former
-runnable/future.d(11): base method `future.A.msg` defined here
+runnable/future.d(17): Deprecation: method `future.B.msg` implicitly overrides `@__future` base class method; rename the former
+runnable/future.d(12): base method `future.A.msg` defined here
---
*/
/*
+REQUIRED_ARGS: -verrors=simple
TEST_OUTPUT:
---
-runnable/implicit.d(162): Deprecation: slice of static array temporary returned by `pureMaker3c()` assigned to longer lived variable `z1`
-runnable/implicit.d(163): Deprecation: slice of static array temporary returned by `pureMaker3c()` assigned to longer lived variable `z2`
+runnable/implicit.d(163): Deprecation: slice of static array temporary returned by `pureMaker3c()` assigned to longer lived variable `z1`
+runnable/implicit.d(164): Deprecation: slice of static array temporary returned by `pureMaker3c()` assigned to longer lived variable `z2`
---
RUN_OUTPUT:
-// REQUIRED_ARGS:
+// REQUIRED_ARGS: -verrors=simple
/*
TEST_OUTPUT:
---
/*
+REQUIRED_ARGS: -verrors=simple
TEST_OUTPUT:
---
-runnable/test8.d(261): Deprecation: identity comparison of static arrays implicitly coerces them to slices, which are compared by reference
+runnable/test8.d(262): Deprecation: identity comparison of static arrays implicitly coerces them to slices, which are compared by reference
---
*/
int b;
Object c;
- static assert(!__traits(compiles, cast(void*)a));
- static assert(!__traits(compiles, cast(void*)b));
- static assert(!__traits(compiles, cast(void*)c));
+ static assert(__traits(compiles, cast(void*)a));
+ static assert(__traits(compiles, cast(void*)b));
+ static assert(__traits(compiles, cast(void*)c));
}
@safe
static assert( __traits(compiles, cast(const(void)*)mp));
static assert( __traits(compiles, cast(const(void)*)ip));
- static assert(!__traits(compiles, cast(immutable(void)*)mp));
- static assert(!__traits(compiles, cast(immutable(void)*)cp));
+ static assert(__traits(compiles, cast(immutable(void)*)mp));
+ static assert(__traits(compiles, cast(immutable(void)*)cp));
- static assert(!__traits(compiles, cast(void*)cp));
- static assert(!__traits(compiles, cast(void*)ip));
+ static assert(__traits(compiles, cast(void*)cp));
+ static assert(__traits(compiles, cast(void*)ip));
}
@safe
-c57da0cf5945cfb45eed06f1fd820435cda3ee3a
+c7902293d7df9d02546562cb09fc8439004a70d1
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
core/sync/barrier.d core/sync/condition.d core/sync/config.d \
core/sync/event.d core/sync/exception.d core/sync/mutex.d \
core/sync/package.d core/sync/rwmutex.d core/sync/semaphore.d \
- core/thread/context.d core/thread/fiber.d core/thread/osthread.d \
+ core/thread/context.d core/thread/fiber/base.d \
+ core/thread/fiber/package.d core/thread/osthread.d \
core/thread/package.d core/thread/threadbase.d \
core/thread/threadgroup.d core/thread/types.d core/time.d \
core/vararg.d core/volatile.d etc/valgrind/valgrind.d gcc/attribute.d \
core/sync/condition.lo core/sync/config.lo core/sync/event.lo \
core/sync/exception.lo core/sync/mutex.lo core/sync/package.lo \
core/sync/rwmutex.lo core/sync/semaphore.lo \
- core/thread/context.lo core/thread/fiber.lo \
- core/thread/osthread.lo core/thread/package.lo \
- core/thread/threadbase.lo core/thread/threadgroup.lo \
- core/thread/types.lo core/time.lo core/vararg.lo \
- core/volatile.lo etc/valgrind/valgrind.lo gcc/attribute.lo \
- gcc/attributes.lo gcc/backtrace.lo gcc/builtins.lo gcc/deh.lo \
- gcc/emutls.lo gcc/gthread.lo gcc/sections/common.lo \
- gcc/sections/elf.lo gcc/sections/macho.lo \
- gcc/sections/package.lo gcc/sections/pecoff.lo gcc/simd.lo \
- gcc/unwind/arm.lo gcc/unwind/arm_common.lo gcc/unwind/c6x.lo \
+ core/thread/context.lo core/thread/fiber/base.lo \
+ core/thread/fiber/package.lo core/thread/osthread.lo \
+ core/thread/package.lo core/thread/threadbase.lo \
+ core/thread/threadgroup.lo core/thread/types.lo core/time.lo \
+ core/vararg.lo core/volatile.lo etc/valgrind/valgrind.lo \
+ gcc/attribute.lo gcc/attributes.lo gcc/backtrace.lo \
+ gcc/builtins.lo gcc/deh.lo gcc/emutls.lo gcc/gthread.lo \
+ gcc/sections/common.lo gcc/sections/elf.lo \
+ gcc/sections/macho.lo gcc/sections/package.lo \
+ gcc/sections/pecoff.lo gcc/simd.lo gcc/unwind/arm.lo \
+ gcc/unwind/arm_common.lo gcc/unwind/c6x.lo \
gcc/unwind/generic.lo gcc/unwind/package.lo gcc/unwind/pe.lo \
object.lo rt/aApply.lo rt/aApplyR.lo rt/aaA.lo rt/adi.lo \
rt/arraycat.lo rt/cast_.lo rt/config.lo rt/critical_.lo \
core/sync/barrier.d core/sync/condition.d core/sync/config.d \
core/sync/event.d core/sync/exception.d core/sync/mutex.d \
core/sync/package.d core/sync/rwmutex.d core/sync/semaphore.d \
- core/thread/context.d core/thread/fiber.d core/thread/osthread.d \
+ core/thread/context.d core/thread/fiber/base.d \
+ core/thread/fiber/package.d core/thread/osthread.d \
core/thread/package.d core/thread/threadbase.d \
core/thread/threadgroup.d core/thread/types.d core/time.d \
core/vararg.d core/volatile.d etc/valgrind/valgrind.d gcc/attribute.d \
@$(MKDIR_P) core/thread
@: > core/thread/$(am__dirstamp)
core/thread/context.lo: core/thread/$(am__dirstamp)
-core/thread/fiber.lo: core/thread/$(am__dirstamp)
+core/thread/fiber/$(am__dirstamp):
+ @$(MKDIR_P) core/thread/fiber
+ @: > core/thread/fiber/$(am__dirstamp)
+core/thread/fiber/base.lo: core/thread/fiber/$(am__dirstamp)
+core/thread/fiber/package.lo: core/thread/fiber/$(am__dirstamp)
core/thread/osthread.lo: core/thread/$(am__dirstamp)
core/thread/package.lo: core/thread/$(am__dirstamp)
core/thread/threadbase.lo: core/thread/$(am__dirstamp)
-rm -f core/sys/windows/stdc/*.lo
-rm -f core/thread/*.$(OBJEXT)
-rm -f core/thread/*.lo
+ -rm -f core/thread/fiber/*.$(OBJEXT)
+ -rm -f core/thread/fiber/*.lo
-rm -f etc/valgrind/*.$(OBJEXT)
-rm -f etc/valgrind/*.lo
-rm -f gcc/*.$(OBJEXT)
-rm -rf core/sys/windows/.libs core/sys/windows/_libs
-rm -rf core/sys/windows/stdc/.libs core/sys/windows/stdc/_libs
-rm -rf core/thread/.libs core/thread/_libs
+ -rm -rf core/thread/fiber/.libs core/thread/fiber/_libs
-rm -rf etc/valgrind/.libs etc/valgrind/_libs
-rm -rf gcc/.libs gcc/_libs
-rm -rf gcc/sections/.libs gcc/sections/_libs
-rm -f core/sys/windows/$(am__dirstamp)
-rm -f core/sys/windows/stdc/$(am__dirstamp)
-rm -f core/thread/$(am__dirstamp)
+ -rm -f core/thread/fiber/$(am__dirstamp)
-rm -f etc/valgrind/$(am__dirstamp)
-rm -f gcc/$(am__dirstamp)
-rm -f gcc/sections/$(am__dirstamp)
else version (WatchOS)
version = Darwin;
-debug(trace) import core.stdc.stdio : printf;
-debug(info) import core.stdc.stdio : printf;
+debug (trace) debug = needPrintf;
+debug (info) debug = needPrintf;
+
+debug (needPrintf)
+private int printf(Args...)(scope const char* fmt, scope const Args args)
+ => __ctfe ? 0 : imported!"core.stdc.stdio".printf(fmt, args);
extern (C) alias CXX_DEMANGLER = char* function (const char* mangled_name,
char* output_buffer,
}
name = dst[beg .. nameEnd];
- debug(info) printf( "name (%.*s)\n", cast(int) name.length, name.ptr );
+ debug(info) printf( "name (%.*s)\n", cast(int) name.length, name.getSlice.ptr );
if ( 'M' == front )
popFront(); // has 'this' pointer
// ARRAY FUNCTIONS
/**
- * Get the current used capacity of an array block. Note that this is only
- * needed if you are about to change the array used size and need to deal
- * with the memory that is about to go away. For appending or shrinking
- * arrays that have no destructors, you probably don't need this function.
+ * Get the current used capacity of an array block.
+ *
+ * Note that this is only needed if you are about to change the array used
+ * size and need to deal with the memory that is about to go away. For
+ * appending or shrinking arrays that have no destructors, you probably
+ * don't need this function.
+ *
* Params:
* ptr = The pointer to check. This can be an interior pointer, but if it
* is beyond the end of the used space, the return value may not be
* valid.
- * atomic = If true, the value is fetched atomically (for shared arrays)
- * Returns: Current array slice, or null if the pointer does not point to a
- * valid appendable GC block.
+ * atomic = The value is fetched atomically (for shared arrays)
+ * Returns:
+ * Current array slice, or null if the pointer does not point to a valid
+ * appendable GC block.
*/
void[] getArrayUsed(void *ptr, bool atomic = false) nothrow;
/**
- * Expand the array used size. Used for appending and expanding the length
- * of the array slice. If the operation can be performed without
- * reallocating, the function succeeds. Newly expanded data is not
- * initialized.
+ * Expand the array used size in place.
+ *
+ * Used for appending and expanding the length of the array slice. If the
+ * operation can be performed without reallocating, the function succeeds.
+ * Newly expanded data is not initialized. Slices that do not point at
+ * expandable GC blocks cannot be affected, and this function will always
+ * return false.
*
- * slices that do not point at expandable GC blocks cannot be affected, and
- * this function will always return false.
* Params:
* slice = the slice to attempt expanding in place.
* newUsed = the size that should be stored as used.
bool expandArrayUsed(void[] slice, size_t newUsed, bool atomic = false) nothrow @safe;
/**
- * Expand the array capacity. Used for reserving space that can be used for
- * appending. If the operation can be performed without reallocating, the
- * function succeeds. The used size is not changed.
+ * Expand the array capacity in place.
+ *
+ * Used for reserving space that can be used for appending. If the
+ * operation can be performed without reallocating, the function succeeds.
+ * The used size is not changed. Slices that do not point at expandable GC
+ * blocks cannot be affected, and this function will always return zero.
*
- * slices that do not point at expandable GC blocks cannot be affected, and
- * this function will always return zero.
* Params:
* slice = the slice to attempt reserving capacity for.
* request = the requested size to expand to. Includes the existing data.
* Passing a value less than the current array size will result in no
* changes, but will return the current capacity.
- * atomic = if true, the array may be shared between threads, and this
- * operation should be done atomically.
- * Returns: resulting capacity size, 0 if the operation could not be performed.
+ * atomic = The array may be shared between threads, and this operation
+ * should be done atomically.
+ *
+ * Returns:
+ * Resulting capacity size or 0 if the operation could not be performed.
*/
size_t reserveArrayCapacity(void[] slice, size_t request, bool atomic = false) nothrow @safe;
/**
- * Shrink used space of a slice. Unlike the other array functions, the
- * array slice passed in is the target slice, and the existing used space
- * is passed separately. This is to discourage code that ends up with a
- * slice to dangling valid data.
+ * Shrink used space of a slice in place.
+ *
+ * Unlike the other array functions, the array slice passed in is the
+ * target slice, and the existing used space is passed separately. This is
+ * to discourage code that ends up with a slice to dangling valid data.
+ *
* If slice.ptr[0 .. existingUsed] does not point to the end of a valid GC
* appendable slice, then the operation fails.
+ *
* Params:
* slice = The proposed valid slice data.
* existingUsed = The amount of data in the block (starting at slice.ptr)
* that is currently valid in the array. If this amount does not match
* the current used size, the operation fails.
- * atomic = If true, the slice may be shared between threads, and the
- * operation should be atomic.
+ * atomic = The slice may be shared between threads, and the operation
+ * should be atomic.
* Returns: true if successful.
*/
bool shrinkArrayUsed(void[] slice, size_t existingUsed, bool atomic = false) nothrow;
import core.stdc.stdint : uintptr_t;
debug(PRINTF) import core.stdc.stdio : printf;
- debug(PRINTF) printf("_d_arrayctor(from = %p,%d) size = %d\n", from.ptr, from.length, T.sizeof);
+ debug(PRINTF) printf("_d_arrayctor(from = %p,%zd) size = %zd\n", from.ptr, from.length, T.sizeof);
void[] vFrom = (cast(void*) from.ptr)[0..from.length];
void[] vTo = (cast(void*) to.ptr)[0..to.length];
*/
Tarr _d_newarraymTX(Tarr : U[], T, U)(size_t[] dims, bool isShared=false) @trusted
{
- debug(PRINTF) printf("_d_newarraymTX(dims.length = %d)\n", dims.length);
+ debug(PRINTF) printf("_d_newarraymTX(dims.length = %zd)\n", dims.length);
if (dims.length == 0)
return null;
}
auto result = __allocateInnerArray(dims);
- debug(PRINTF) printf("result = %llx\n", result.ptr);
+ debug(PRINTF) printf("result = %p\n", result.ptr);
return (cast(U*) result.ptr)[0 .. dims[0]];
}
module core.internal.atomic;
-import core.atomic : MemoryOrder, has128BitCAS;
+import core.atomic : has128BitCAS, MemoryOrder;
version (DigitalMars)
{
{
static if (GNU_Thread_Model == ThreadModel.Posix)
{
- import core.sys.posix.pthread;
+ import core.sys.posix.sys.types : pthread_mutex_t, pthread_mutexattr_t;
alias atomicMutexHandle = pthread_mutex_t;
pragma(mangle, "pthread_mutex_init") int fakePureMutexInit(pthread_mutex_t*, pthread_mutexattr_t*);
}
else static if (GNU_Thread_Model == ThreadModel.Win32)
{
- import core.sys.windows.winbase;
+ import core.sys.windows.winbase : CRITICAL_SECTION;
alias atomicMutexHandle = CRITICAL_SECTION;
pragma(mangle, "InitializeCriticalSection") int fakePureMutexInit(CRITICAL_SECTION*);
*
* Copyright: D Language Foundation 2018 - 2020
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/druntime/src/core/internal/dassert.d, _dassert.d)
+ * Source: $(DRUNTIMESRC core/internal/_dassert.d)
* Documentation: https://dlang.org/phobos/core_internal_dassert.html
*/
module core.internal.dassert;
import core.memory;
import core.attribute;
+debug (PRINTF) import core.stdc.stdio : printf;
+
alias BlkInfo = GC.BlkInfo;
alias BlkAttr = GC.BlkAttr;
// called after the mark routine to eliminate block cache data when it
// might be ready to sweep
- debug(PRINTF) printf("processing GC Marks, %x\n", cache);
+ debug(PRINTF) printf("processing GC Marks, %p\n", cache);
debug(PRINTF) foreach (i; 0 .. N_CACHE_BLOCKS)
{
- printf("cache entry %d has base ptr %x\tsize %d\tflags %x\n", i, cache[i].base, cache[i].size, cache[i].attr);
+ printf("cache entry %d has base ptr %p\tsize %zd\tflags %x\n", i, cache[i].base, cache[i].size, cache[i].attr);
}
auto cache_end = cache + N_CACHE_BLOCKS;
for (;cache < cache_end; ++cache)
{
if (cache.base != null && isMarked(cache.base) == IsMarked.no)
{
- debug(PRINTF) printf("clearing cache entry at %x\n", cache.base);
+ debug(PRINTF) printf("clearing cache entry at %p\n", cache.base);
cache.base = null; // clear that data.
}
}
printf("CACHE: \n");
foreach (i; 0 .. N_CACHE_BLOCKS)
{
- printf(" %d\taddr:% .8x\tsize:% .10d\tflags:% .8x\n", i, ptr[i].base, ptr[i].size, ptr[i].attr);
+ printf(" %d\taddr:% .8p\tsize:% .10zd\tflags:% .8x\n", i, ptr[i].base, ptr[i].size, ptr[i].attr);
}
}
}
assert(size != 0);
debug(PRINTF)
- printf("GC::malloc(gcx = %p, size = %d bits = %x, ti = %s)\n", gcx, size, bits, debugTypeName(ti).ptr);
+ printf("GC::malloc(gcx = %p, size = %zd bits = %x, ti = %s)\n", gcx, size, bits, debugTypeName(ti).ptr);
assert(gcx);
//debug(PRINTF) printf("gcx.self = %x, pthread_self() = %x\n", gcx.self, pthread_self());
//
private void freeNoSync(void *p) nothrow @nogc
{
- debug(PRINTF) printf("Freeing %p\n", cast(size_t) p);
+ debug(PRINTF) printf("Freeing %#zx\n", cast(size_t) p);
assert (p);
Pool* pool;
pagenum = pool.pagenumOf(p);
- debug(PRINTF) printf("pool base = %p, PAGENUM = %d of %d, bin = %d\n", pool.baseAddr, pagenum, pool.npages, pool.pagetable[pagenum]);
+ debug(PRINTF) printf("pool base = %p, PAGENUM = %zd of %zd, bin = %d\n", pool.baseAddr, pagenum, pool.npages, pool.pagetable[pagenum]);
debug(PRINTF) if (pool.isLargeObject) printf("Block size = %d\n", pool.bPageOffsets[pagenum]);
bin = pool.pagetable[pagenum];
long apiTime = mallocTime + reallocTime + freeTime + extendTime + otherTime + lockTime;
printf("\tGC API: %lld ms\n", toDuration(apiTime).total!"msecs");
- sprintf(apitxt.ptr, " API%5ld ms", toDuration(apiTime).total!"msecs");
+ sprintf(apitxt.ptr, " API%5lld ms", toDuration(apiTime).total!"msecs");
}
printf("GC summary:%5lld MB,%5lld GC%5lld ms, Pauses%5lld ms <%5lld ms%s\n",
*/
void* bigAlloc(size_t size, ref size_t alloc_size, uint bits, const TypeInfo ti = null) nothrow
{
- debug(PRINTF) printf("In bigAlloc. Size: %d\n", size);
+ debug(PRINTF) printf("In bigAlloc. Size: %zd\n", size);
LargeObjectPool* pool;
size_t pn;
debug(PRINTF) printFreeInfo(&pool.base);
auto p = pool.baseAddr + pn * PAGESIZE;
- debug(PRINTF) printf("Got large alloc: %p, pt = %d, np = %d\n", p, pool.pagetable[pn], npages);
+ debug(PRINTF) printf("Got large alloc: %p, pt = %d, np = %zd\n", p, pool.pagetable[pn], npages);
invalidate(p[0 .. size], 0xF1, true);
alloc_size = npages * PAGESIZE;
//debug(PRINTF) printf("\tp = %p\n", p);
version (Posix)
{
- import core.sys.posix.signal;
+ import core.sys.posix.signal : pthread_sigmask, SIG_BLOCK, SIG_SETMASK, sigfillset, sigset_t;
// block all signals, scanBackground inherits this mask.
// see https://issues.dlang.org/show_bug.cgi?id=20256
sigset_t new_mask, old_mask;
if (atomicLoad(busyThreads) == 0)
return;
- debug(PARALLEL_PRINTF)
+ version (Posix) debug (PARALLEL_PRINTF)
+ {
+ import core.sys.posix.pthread : pthread_self, pthread_t;
pthread_t threadId = pthread_self();
- debug(PARALLEL_PRINTF) printf("scanBackground thread %d start\n", threadId);
+ printf("scanBackground thread %d start\n", threadId);
+ }
ScanRange!precise rng;
alias toscan = scanStack!precise;
busyThreads.atomicOp!"+="(1);
if (toscan.popLocked(rng))
{
- debug(PARALLEL_PRINTF) printf("scanBackground thread %d scanning range [%p,%lld] from stack\n", threadId,
- rng.pbot, cast(long) (rng.ptop - rng.pbot));
+ version (Posix) debug (PARALLEL_PRINTF)
+ {
+ printf("scanBackground thread %d scanning range [%p,%lld] from stack\n",
+ threadId, rng.pbot, cast(long) (rng.ptop - rng.pbot));
+ }
mark!(precise, true, true)(rng);
}
busyThreads.atomicOp!"-="(1);
}
- debug(PARALLEL_PRINTF) printf("scanBackground thread %d done\n", threadId);
+ version (Posix) debug (PARALLEL_PRINTF) printf("scanBackground thread %d done\n", threadId);
}
}
debugTypeName(ti).ptr, p, bitmap, cast(ulong)element_size);
debug(PRINTF)
for (size_t i = 0; i < element_size/((void*).sizeof); i++)
- printf("%d", (bitmap[i/(8*size_t.sizeof)] >> (i%(8*size_t.sizeof))) & 1);
+ printf("%zd", (bitmap[i/(8*size_t.sizeof)] >> (i%(8*size_t.sizeof))) & 1);
debug(PRINTF) printf("\n");
if (tocopy * (void*).sizeof < s) // better safe than sorry: if allocated more, assume pointers inside
{
- debug(PRINTF) printf(" Appending %d pointer bits\n", s/(void*).sizeof - tocopy);
+ debug(PRINTF) printf(" Appending %zd pointer bits\n", s/(void*).sizeof - tocopy);
is_pointer.setRange(offset/(void*).sizeof + tocopy, s/(void*).sizeof - tocopy);
}
}
if (pool.pagetable[i] >= Bins.B_FREE) nReallyFree++;
}
- printf("Pool %p: %d really free, %d supposedly free\n", pool, nReallyFree, pool.freepages);
+ printf("Pool %p: %d really free, %zd supposedly free\n", pool, nReallyFree, pool.freepages);
}
debug(PRINTF)
for (size_t i = 0; i < bits.nwords; i++)
{
if (i % 32 == 0) printf("\n\t");
- printf("%x ", bits.data[i]);
+ printf("%zx ", bits.data[i]);
}
printf("\n");
}
else version (WatchOS)
version = Darwin;
- import core.sys.posix.sys.mman;
import core.stdc.stdlib;
+ import core.sys.posix.sys.mman : MAP_ANON, MAP_FAILED, MAP_PRIVATE, MAP_SHARED, mmap, munmap, PROT_READ, PROT_WRITE;
/// Possible results for the wait_pid() function.
return ChildStatus.done;
}
- public import core.sys.posix.unistd: pid_t, fork;
- import core.sys.posix.sys.wait: waitpid, WNOHANG;
- import core.stdc.errno: errno, EINTR, ECHILD;
+ public import core.sys.posix.unistd : fork, pid_t;
+ import core.stdc.errno : ECHILD, EINTR, errno;
+ import core.sys.posix.sys.wait : waitpid, WNOHANG;
//version = GC_Use_Alloc_MMap;
}
{
ulong os_physical_mem(bool avail) nothrow @nogc
{
- import core.sys.posix.unistd;
+ static import core.sys.posix.unistd;
+ import core.sys.posix.unistd : _SC_PAGESIZE, _SC_PHYS_PAGES, sysconf;
const pageSize = sysconf(_SC_PAGESIZE);
- static if (__traits(compiles, _SC_AVPHYS_PAGES)) // not available on all platforms
+ static if (__traits(compiles, core.sys.posix.unistd._SC_AVPHYS_PAGES)) // not available on all platforms
+ {
+ import core.sys.posix.unistd : _SC_AVPHYS_PAGES;
const sc = avail ? _SC_AVPHYS_PAGES : _SC_PHYS_PAGES;
+ }
else
+ {
const sc = _SC_PHYS_PAGES;
+ }
const pages = sysconf(sc);
return pageSize * pages;
}
License: Distributed under the
$(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
(See accompanying file LICENSE)
- Source: $(DRUNTIMESRC core/_internal/_destruction.d)
+ Source: $(DRUNTIMESRC core/_internal/_postblit.d)
*/
module core.internal.postblit;
import core.stdc.stdlib;
+debug (qsort) import core.stdc.stdio : printf;
+
version (OSX)
version = Darwin;
else version (iOS)
* Copyright: Copyright Sean Kelly 2005 - 2009.
* License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
* Authors: Sean Kelly, Walter Bright
- * Source: $(DRUNTIMESRC rt/util/_string.d)
+ * Source: $(DRUNTIMESRC core/internal/_string.d)
*/
module core.internal.string;
module core.internal.utf;
+debug (utf) import core.stdc.stdio : printf;
+
extern (C) void onUnicodeError( string msg, size_t idx, string file = __FILE__, size_t line = __LINE__ ) @safe pure;
/*******************************
* Copyright: Copyright Sean Kelly 2005 - 2009.
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Authors: Sean Kelly
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/druntime/src/core/runtime.d, _runtime.d)
+ * Source: $(DRUNTIMESRC core/_runtime.d)
* Documentation: https://dlang.org/phobos/core_runtime.html
*/
static if (__traits(compiles, new LibBacktrace(0)))
{
- import core.sys.posix.signal; // segv handler
+ // segv handler
+ import core.sys.posix.signal : SA_RESETHAND, SA_SIGINFO, sigaction, sigaction_t, SIGBUS, sigfillset, siginfo_t,
+ SIGSEGV;
static extern (C) void unittestSegvHandler(int signum, siginfo_t* info, void* ptr)
{
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
* (See accompanying file LICENSE)
* Authors: Sean Kelly, Alex Rønne Petersen
- * Source: https://github.com/dlang/dmd/blob/master/druntime/src/core/stdc/errno.d
+ * Source: $(DRUNTIMESRC core/stdc/_errno.d)
* Standards: ISO/IEC 9899:1999 (E)
*/
* (See accompanying file LICENSE)
* Authors: Sean Kelly,
* Alex Rønne Petersen
- * Source: https://github.com/dlang/dmd/blob/master/druntime/src/core/stdc/stdio.d
+ * Source: $(DRUNTIMESRC core/stdc/_stdio.d)
* Standards: ISO/IEC 9899:1999 (E)
*/
}
else version (Posix)
{
- import core.sync.config;
import core.stdc.errno;
- import core.sys.posix.pthread;
- import core.sys.posix.time;
+ import core.sync.config;
+ import core.sys.posix.pthread : pthread_cond_broadcast, pthread_cond_destroy, pthread_cond_init,
+ pthread_cond_signal, pthread_cond_t, pthread_cond_timedwait, pthread_cond_wait;
+ import core.sys.posix.time : timespec;
}
else
{
{
m_assocMutex = m;
}
- static if ( is( typeof( pthread_condattr_setclock ) ) )
+ static if ( is( typeof( imported!"core.sys.posix.pthread".pthread_condattr_setclock ) ) )
{
+ import core.sys.posix.pthread : pthread_condattr_destroy, pthread_condattr_init,
+ pthread_condattr_setclock;
+ import core.sys.posix.sys.types : pthread_condattr_t;
+ import core.sys.posix.time : CLOCK_MONOTONIC;
() @trusted
{
pthread_condattr_t attr = void;
unittest
{
- import core.thread;
import core.sync.mutex;
import core.sync.semaphore;
+ import core.thread;
void testNotify()
unittest
{
- import core.thread;
import core.sync.mutex;
import core.sync.semaphore;
+ import core.thread;
void testNotify()
version (Posix)
{
- import core.sys.posix.pthread;
- import core.sys.posix.time;
- import core.sys.posix.sys.time;
+ import core.sys.posix.sys.time : gettimeofday, timeval;
+ import core.sys.posix.time : timespec;
import core.time;
void mktspec( ref timespec t ) nothrow @nogc
{
- static if ( is (typeof ( pthread_condattr_setclock ) ) )
+ static if ( is (typeof ( imported!"core.sys.posix.pthread".pthread_condattr_setclock ) ) )
{
+ import core.sys.posix.time : clock_gettime, CLOCK_MONOTONIC;
clock_gettime( CLOCK_MONOTONIC, &t );
}
else
}
else version (Posix)
{
- import core.sys.posix.pthread;
- import core.sys.posix.sys.types;
- import core.sys.posix.time;
+ import core.sys.posix.pthread : pthread_cond_broadcast, pthread_cond_destroy, pthread_cond_init,
+ pthread_cond_timedwait, pthread_cond_wait, pthread_mutex_destroy, pthread_mutex_init, pthread_mutex_lock,
+ pthread_mutex_unlock;
+ import core.sys.posix.sys.types : pthread_cond_t, pthread_mutex_t;
+ import core.sys.posix.time : timespec;
}
else
{
static assert(false, "Platform not supported");
}
-import core.time;
import core.internal.abort : abort;
+import core.time;
/**
* represents an event. Clients of an event are suspended while waiting
return;
pthread_mutex_init(cast(pthread_mutex_t*) &m_mutex, null) == 0 ||
abort("Error: pthread_mutex_init failed.");
- static if ( is( typeof( pthread_condattr_setclock ) ) )
+
+ static if ( is( typeof( imported!"core.sys.posix.pthread".pthread_condattr_setclock ) ) )
{
+ import core.sys.posix.pthread : CLOCK_MONOTONIC, pthread_condattr_destroy, pthread_condattr_init,
+ pthread_condattr_setclock;
+ import core.sys.posix.sys.types : pthread_condattr_t;
+
pthread_condattr_t attr = void;
pthread_condattr_init(&attr) == 0 ||
abort("Error: pthread_condattr_init failed.");
unittest
{
- import core.thread, core.atomic;
+ import core.atomic;
+ import core.thread;
scope event = new Event(true, false);
int numThreads = 10;
}
else version (Posix)
{
- import core.sys.posix.pthread;
+ import core.sys.posix.pthread : pthread_mutex_destroy, pthread_mutex_init, pthread_mutex_lock,
+ PTHREAD_MUTEX_RECURSIVE, pthread_mutex_trylock, pthread_mutex_unlock, pthread_mutexattr_destroy,
+ pthread_mutexattr_init, pthread_mutexattr_settype;
+ import core.sys.posix.sys.types : pthread_mutex_t, pthread_mutexattr_t;
}
else
{
// Test @nogc usage.
@system @nogc nothrow unittest
{
- import core.stdc.stdlib : malloc, free;
import core.lifetime : emplace;
+ import core.stdc.stdlib : free, malloc;
auto mtx = cast(shared Mutex) malloc(__traits(classInstanceSize, Mutex));
emplace(mtx);
import core.sync.mutex;
import core.memory;
-version (Posix)
-{
- import core.sys.posix.pthread;
-}
-
////////////////////////////////////////////////////////////////////////////////
// ReadWriteMutex
}
else version (Darwin)
{
- import core.sync.config;
import core.stdc.errno;
- import core.sys.posix.time;
- import core.sys.darwin.mach.semaphore;
+ import core.sync.config;
+ import core.sys.darwin.mach.kern_return : KERN_ABORTED, KERN_OPERATION_TIMED_OUT;
+ import core.sys.darwin.mach.semaphore : mach_task_self, mach_timespec_t, semaphore_create, semaphore_destroy,
+ semaphore_signal, semaphore_t, semaphore_timedwait, semaphore_wait, SYNC_POLICY_FIFO;
}
else version (Posix)
{
- import core.sync.config;
import core.stdc.errno;
- import core.sys.posix.pthread;
- import core.sys.posix.semaphore;
+ import core.sync.config;
+ import core.sys.posix.semaphore : sem_destroy, sem_init, sem_post, sem_t, sem_timedwait, sem_trywait, sem_wait;
+ import core.sys.posix.time : clock_gettime, CLOCK_REALTIME, timespec;
}
else
{
}
else version (Posix)
{
- import core.sys.posix.time : clock_gettime, CLOCK_REALTIME;
-
timespec t = void;
clock_gettime( CLOCK_REALTIME, &t );
mvtspec( t, period );
unittest
{
- import core.thread, core.atomic;
+ import core.atomic;
+ import core.thread;
void testWait()
{
*
* License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
* Authors: Mathias 'Geod24' Lang
- * Source: $(DRUNTIMESRC core/sys/darwin/mach/_nlist.d)
+ * Source: $(DRUNTIMESRC core/sys/darwin/mach/_stab.d)
*/
module core.sys.darwin.mach.stab;
module core.sys.linux.sys.procfs;
+version (linux):
+
import core.sys.posix.sys.types : pid_t;
-version (linux)
-{
- alias lwpid_t = pid_t;
-}
+alias lwpid_t = pid_t;
* Copyright: Copyright (C) 2018 by The D Language Foundation, All Rights Reserved
* Authors: Petar Kirov
* License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/druntime/src/core/sys/posix/spawn.d, _spawn.d)
+ * Source: $(DRUNTIMESRC core/sys/posix/_spawn.d)
* Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition
*/
module core.sys.posix.spawn;
* (See accompanying file LICENSE)
* Authors: Sean Kelly,
* Alex Rønne Petersen
- * Source: $(DRUNTIMESRC core/stdc/_time.d)
+ * Source: $(DRUNTIMESRC core/sys/posix/stdc/_time.d)
* Standards: ISO/IEC 9899:1999 (E)
*/
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
* (See accompanying file LICENSE)
* Authors: Benjamin Thaut, Sean Kelly
- * Source: $(DRUNTIMESRC core/sys/windows/_stacktrace.d)
+ * Source: $(DRUNTIMESRC core/sys/windows/_dbghelp.d)
*/
module core.sys.windows.dbghelp;
* (See accompanying file LICENSE)
* Authors: Sean Kelly,
* Alex Rønne Petersen
- * Source: $(DRUNTIMESRC core/stdc/_time.d)
+ * Source: $(DRUNTIMESRC core/sys/windows/stdc/_time.d)
* Standards: ISO/IEC 9899:1999 (E)
*/
--- /dev/null
+/**
+ * Base fiber module provides OS-indepedent part of lightweight threads aka fibers.
+ *
+ * Copyright: Copyright Sean Kelly 2005 - 2012.
+ * License: Distributed under the
+ * $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
+ * (See accompanying file LICENSE)
+ * Authors: Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak
+ * Source: $(DRUNTIMESRC core/thread/fiber/base.d)
+ */
+
+/* NOTE: This file has been patched from the original DMD distribution to
+ * work with the GDC compiler.
+ */
+module core.thread.fiber.base;
+
+package:
+version (GNU)
+ import gcc.config;
+
+import core.thread.fiber;
+import core.thread.threadbase;
+import core.thread.threadgroup;
+import core.thread.types;
+import core.thread.context;
+
+import core.memory : pageSize;
+
+package
+{
+ import core.atomic : atomicStore, cas, MemoryOrder;
+ import core.exception : onOutOfMemoryError;
+ import core.stdc.stdlib : abort;
+
+ extern (C) void fiber_entryPoint() nothrow
+ {
+ FiberBase obj = FiberBase.getThis();
+ assert( obj );
+
+ assert( ThreadBase.getThis().m_curr is obj.m_ctxt );
+ atomicStore!(MemoryOrder.raw)(*cast(shared)&ThreadBase.getThis().m_lock, false);
+ obj.m_ctxt.tstack = obj.m_ctxt.bstack;
+ obj.m_state = FiberBase.State.EXEC;
+
+ try
+ {
+ obj.run();
+ }
+ catch ( Throwable t )
+ {
+ obj.m_unhandled = t;
+ }
+
+ static if ( __traits( compiles, ucontext_t ) )
+ obj.m_ucur = &obj.m_utxt;
+
+ obj.m_state = Fiber.State.TERM;
+ obj.switchOut();
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Fiber
+///////////////////////////////////////////////////////////////////////////////
+/*
+ * Documentation of Fiber internals:
+ *
+ * The main routines to implement when porting Fibers to new architectures are
+ * fiber_switchContext and initStack. Some version constants have to be defined
+ * for the new platform as well, search for "Fiber Platform Detection and Memory Allocation".
+ *
+ * Fibers are based on a concept called 'Context'. A Context describes the execution
+ * state of a Fiber or main thread which is fully described by the stack, some
+ * registers and a return address at which the Fiber/Thread should continue executing.
+ * Please note that not only each Fiber has a Context, but each thread also has got a
+ * Context which describes the threads stack and state. If you call Fiber fib; fib.call
+ * the first time in a thread you switch from Threads Context into the Fibers Context.
+ * If you call fib.yield in that Fiber you switch out of the Fibers context and back
+ * into the Thread Context. (However, this is not always the case. You can call a Fiber
+ * from within another Fiber, then you switch Contexts between the Fibers and the Thread
+ * Context is not involved)
+ *
+ * In all current implementations the registers and the return address are actually
+ * saved on a Contexts stack.
+ *
+ * The fiber_switchContext routine has got two parameters:
+ * void** a: This is the _location_ where we have to store the current stack pointer,
+ * the stack pointer of the currently executing Context (Fiber or Thread).
+ * void* b: This is the pointer to the stack of the Context which we want to switch into.
+ * Note that we get the same pointer here as the one we stored into the void** a
+ * in a previous call to fiber_switchContext.
+ *
+ * In the simplest case, a fiber_switchContext rountine looks like this:
+ * fiber_switchContext:
+ * push {return Address}
+ * push {registers}
+ * copy {stack pointer} into {location pointed to by a}
+ * //We have now switch to the stack of a different Context!
+ * copy {b} into {stack pointer}
+ * pop {registers}
+ * pop {return Address}
+ * jump to {return Address}
+ *
+ * The GC uses the value returned in parameter a to scan the Fibers stack. It scans from
+ * the stack base to that value. As the GC dislikes false pointers we can actually optimize
+ * this a little: By storing registers which can not contain references to memory managed
+ * by the GC outside of the region marked by the stack base pointer and the stack pointer
+ * saved in fiber_switchContext we can prevent the GC from scanning them.
+ * Such registers are usually floating point registers and the return address. In order to
+ * implement this, we return a modified stack pointer from fiber_switchContext. However,
+ * we have to remember that when we restore the registers from the stack!
+ *
+ * --------------------------- <= Stack Base
+ * | Frame | <= Many other stack frames
+ * | Frame |
+ * |-------------------------| <= The last stack frame. This one is created by fiber_switchContext
+ * | registers with pointers |
+ * | | <= Stack pointer. GC stops scanning here
+ * | return address |
+ * |floating point registers |
+ * --------------------------- <= Real Stack End
+ *
+ * fiber_switchContext:
+ * push {registers with pointers}
+ * copy {stack pointer} into {location pointed to by a}
+ * push {return Address}
+ * push {Floating point registers}
+ * //We have now switch to the stack of a different Context!
+ * copy {b} into {stack pointer}
+ * //We now have to adjust the stack pointer to point to 'Real Stack End' so we can pop
+ * //the FP registers
+ * //+ or - depends on if your stack grows downwards or upwards
+ * {stack pointer} = {stack pointer} +- ({FPRegisters}.sizeof + {return address}.sizeof}
+ * pop {Floating point registers}
+ * pop {return Address}
+ * pop {registers with pointers}
+ * jump to {return Address}
+ *
+ * So the question now is which registers need to be saved? This depends on the specific
+ * architecture ABI of course, but here are some general guidelines:
+ * - If a register is callee-save (if the callee modifies the register it must saved and
+ * restored by the callee) it needs to be saved/restored in switchContext
+ * - If a register is caller-save it needn't be saved/restored. (Calling fiber_switchContext
+ * is a function call and the compiler therefore already must save these registers before
+ * calling fiber_switchContext)
+ * - Argument registers used for passing parameters to functions needn't be saved/restored
+ * - The return register needn't be saved/restored (fiber_switchContext hasn't got a return type)
+ * - All scratch registers needn't be saved/restored
+ * - The link register usually needn't be saved/restored (but sometimes it must be cleared -
+ * see below for details)
+ * - The frame pointer register - if it exists - is usually callee-save
+ * - All current implementations do not save control registers
+ *
+ * What happens on the first switch into a Fiber? We never saved a state for this fiber before,
+ * but the initial state is prepared in the initStack routine. (This routine will also be called
+ * when a Fiber is being resetted). initStack must produce exactly the same stack layout as the
+ * part of fiber_switchContext which saves the registers. Pay special attention to set the stack
+ * pointer correctly if you use the GC optimization mentioned before. the return Address saved in
+ * initStack must be the address of fiber_entrypoint.
+ *
+ * There's now a small but important difference between the first context switch into a fiber and
+ * further context switches. On the first switch, Fiber.call is used and the returnAddress in
+ * fiber_switchContext will point to fiber_entrypoint. The important thing here is that this jump
+ * is a _function call_, we call fiber_entrypoint by jumping before it's function prologue. On later
+ * calls, the user used yield() in a function, and therefore the return address points into a user
+ * function, after the yield call. So here the jump in fiber_switchContext is a _function return_,
+ * not a function call!
+ *
+ * The most important result of this is that on entering a function, i.e. fiber_entrypoint, we
+ * would have to provide a return address / set the link register once fiber_entrypoint
+ * returns. Now fiber_entrypoint does never return and therefore the actual value of the return
+ * address / link register is never read/used and therefore doesn't matter. When fiber_switchContext
+ * performs a _function return_ the value in the link register doesn't matter either.
+ * However, the link register will still be saved to the stack in fiber_entrypoint and some
+ * exception handling / stack unwinding code might read it from this stack location and crash.
+ * The exact solution depends on your architecture, but see the ARM implementation for a way
+ * to deal with this issue.
+ *
+ * The ARM implementation is meant to be used as a kind of documented example implementation.
+ * Look there for a concrete example.
+ *
+ * FIXME: fiber_entrypoint might benefit from a @noreturn attribute, but D doesn't have one.
+ */
+
+/**
+ * This class provides a cooperative concurrency mechanism integrated with the
+ * threading and garbage collection functionality. Calling a fiber may be
+ * considered a blocking operation that returns when the fiber yields (via
+ * Fiber.yield()). Execution occurs within the context of the calling thread
+ * so synchronization is not necessary to guarantee memory visibility so long
+ * as the same thread calls the fiber each time. Please note that there is no
+ * requirement that a fiber be bound to one specific thread. Rather, fibers
+ * may be freely passed between threads so long as they are not currently
+ * executing. Like threads, a new fiber thread may be created using either
+ * derivation or composition, as in the following example.
+ *
+ * Warning:
+ * Status registers are not saved by the current implementations. This means
+ * floating point exception status bits (overflow, divide by 0), rounding mode
+ * and similar stuff is set per-thread, not per Fiber!
+ *
+ * Warning:
+ * On ARM FPU registers are not saved if druntime was compiled as ARM_SoftFloat.
+ * If such a build is used on a ARM_SoftFP system which actually has got a FPU
+ * and other libraries are using the FPU registers (other code is compiled
+ * as ARM_SoftFP) this can cause problems. Druntime must be compiled as
+ * ARM_SoftFP in this case.
+ *
+ * Authors: Based on a design by Mikola Lysenko.
+ */
+class FiberBase
+{
+ /**
+ * Initializes a fiber object which is associated with a static
+ * D function.
+ *
+ * Params:
+ * fn = The fiber function.
+ * sz = The stack size for this fiber.
+ * guardPageSize = size of the guard page to trap fiber's stack
+ * overflows. Beware that using this will increase
+ * the number of mmaped regions on platforms using mmap
+ * so an OS-imposed limit may be hit.
+ *
+ * In:
+ * fn must not be null.
+ */
+ this( void function() fn, size_t sz, size_t guardPageSize ) nothrow
+ in
+ {
+ assert( fn );
+ }
+ do
+ {
+ allocStack( sz, guardPageSize );
+ reset( fn );
+ }
+
+
+ /**
+ * Initializes a fiber object which is associated with a dynamic
+ * D function.
+ *
+ * Params:
+ * dg = The fiber function.
+ * sz = The stack size for this fiber.
+ * guardPageSize = size of the guard page to trap fiber's stack
+ * overflows. Beware that using this will increase
+ * the number of mmaped regions on platforms using mmap
+ * so an OS-imposed limit may be hit.
+ *
+ * In:
+ * dg must not be null.
+ */
+ this( void delegate() dg, size_t sz, size_t guardPageSize ) nothrow
+ {
+ allocStack( sz, guardPageSize );
+ reset( cast(void delegate() const) dg );
+ }
+
+
+ /**
+ * Cleans up any remaining resources used by this object.
+ */
+ ~this() nothrow @nogc
+ {
+ // NOTE: A live reference to this object will exist on its associated
+ // stack from the first time its call() method has been called
+ // until its execution completes with State.TERM. Thus, the only
+ // times this dtor should be called are either if the fiber has
+ // terminated (and therefore has no active stack) or if the user
+ // explicitly deletes this object. The latter case is an error
+ // but is not easily tested for, since State.HOLD may imply that
+ // the fiber was just created but has never been run. There is
+ // not a compelling case to create a State.INIT just to offer a
+ // means of ensuring the user isn't violating this object's
+ // contract, so for now this requirement will be enforced by
+ // documentation only.
+ freeStack();
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // General Actions
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Transfers execution to this fiber object. The calling context will be
+ * suspended until the fiber calls Fiber.yield() or until it terminates
+ * via an unhandled exception.
+ *
+ * Params:
+ * rethrow = Rethrow any unhandled exception which may have caused this
+ * fiber to terminate.
+ *
+ * In:
+ * This fiber must be in state HOLD.
+ *
+ * Throws:
+ * Any exception not handled by the joined thread.
+ *
+ * Returns:
+ * Any exception not handled by this fiber if rethrow = false, null
+ * otherwise.
+ */
+ // Not marked with any attributes, even though `nothrow @nogc` works
+ // because it calls arbitrary user code. Most of the implementation
+ // is already `@nogc nothrow`, but in order for `Fiber.call` to
+ // propagate the attributes of the user's function, the Fiber
+ // class needs to be templated.
+ final Throwable call( Rethrow rethrow = Rethrow.yes )
+ {
+ return rethrow ? call!(Rethrow.yes)() : call!(Rethrow.no);
+ }
+
+ /// ditto
+ final Throwable call( Rethrow rethrow )()
+ {
+ callImpl();
+ if ( m_unhandled )
+ {
+ Throwable t = m_unhandled;
+ m_unhandled = null;
+ static if ( rethrow )
+ throw t;
+ else
+ return t;
+ }
+ return null;
+ }
+
+ private void callImpl() nothrow @nogc
+ in
+ {
+ assert( m_state == State.HOLD );
+ }
+ do
+ {
+ FiberBase cur = getThis();
+
+ static if ( __traits( compiles, ucontext_t ) )
+ m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt;
+
+ setThis( this );
+ this.switchIn();
+ setThis( cur );
+
+ static if ( __traits( compiles, ucontext_t ) )
+ m_ucur = null;
+
+ // NOTE: If the fiber has terminated then the stack pointers must be
+ // reset. This ensures that the stack for this fiber is not
+ // scanned if the fiber has terminated. This is necessary to
+ // prevent any references lingering on the stack from delaying
+ // the collection of otherwise dead objects. The most notable
+ // being the current object, which is referenced at the top of
+ // fiber_entryPoint.
+ if ( m_state == State.TERM )
+ {
+ m_ctxt.tstack = m_ctxt.bstack;
+ }
+ }
+
+ /// Flag to control rethrow behavior of $(D $(LREF call))
+ enum Rethrow : bool { no, yes }
+
+ /**
+ * Resets this fiber so that it may be re-used, optionally with a
+ * new function/delegate. This routine should only be called for
+ * fibers that have terminated, as doing otherwise could result in
+ * scope-dependent functionality that is not executed.
+ * Stack-based classes, for example, may not be cleaned up
+ * properly if a fiber is reset before it has terminated.
+ *
+ * In:
+ * This fiber must be in state TERM or HOLD.
+ */
+ final void reset() nothrow @nogc
+ in
+ {
+ assert( m_state == State.TERM || m_state == State.HOLD );
+ }
+ do
+ {
+ m_ctxt.tstack = m_ctxt.bstack;
+ m_state = State.HOLD;
+ initStack();
+ m_unhandled = null;
+ }
+
+ /// ditto
+ final void reset( void function() fn ) nothrow @nogc
+ {
+ reset();
+ m_call = fn;
+ }
+
+ /// ditto
+ final void reset( void delegate() dg ) nothrow @nogc
+ {
+ reset();
+ m_call = dg;
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // General Properties
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /// A fiber may occupy one of three states: HOLD, EXEC, and TERM.
+ enum State
+ {
+ /** The HOLD state applies to any fiber that is suspended and ready to
+ be called. */
+ HOLD,
+ /** The EXEC state will be set for any fiber that is currently
+ executing. */
+ EXEC,
+ /** The TERM state is set when a fiber terminates. Once a fiber
+ terminates, it must be reset before it may be called again. */
+ TERM
+ }
+
+
+ /**
+ * Gets the current state of this fiber.
+ *
+ * Returns:
+ * The state of this fiber as an enumerated value.
+ */
+ final @property State state() const @safe pure nothrow @nogc
+ {
+ return m_state;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Actions on Calling Fiber
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Forces a context switch to occur away from the calling fiber.
+ */
+ static void yield() nothrow @nogc
+ {
+ FiberBase cur = getThis();
+ assert( cur, "Fiber.yield() called with no active fiber" );
+ assert( cur.m_state == State.EXEC );
+
+ static if ( __traits( compiles, ucontext_t ) )
+ cur.m_ucur = &cur.m_utxt;
+
+ cur.m_state = State.HOLD;
+ cur.switchOut();
+ cur.m_state = State.EXEC;
+ }
+
+
+ /**
+ * Forces a context switch to occur away from the calling fiber and then
+ * throws obj in the calling fiber.
+ *
+ * Params:
+ * t = The object to throw.
+ *
+ * In:
+ * t must not be null.
+ */
+ static void yieldAndThrow( Throwable t ) nothrow @nogc
+ in
+ {
+ assert( t );
+ }
+ do
+ {
+ FiberBase cur = getThis();
+ assert( cur, "Fiber.yield() called with no active fiber" );
+ assert( cur.m_state == State.EXEC );
+
+ static if ( __traits( compiles, ucontext_t ) )
+ cur.m_ucur = &cur.m_utxt;
+
+ cur.m_unhandled = t;
+ cur.m_state = State.HOLD;
+ cur.switchOut();
+ cur.m_state = State.EXEC;
+ }
+
+
+ ///////////////////////////////////////////////////////////////////////////
+ // Fiber Accessors
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Provides a reference to the calling fiber or null if no fiber is
+ * currently active.
+ *
+ * Returns:
+ * The fiber object representing the calling fiber or null if no fiber
+ * is currently active within this thread. The result of deleting this object is undefined.
+ */
+ static FiberBase getThis() @safe nothrow @nogc
+ {
+ version (GNU) pragma(inline, false);
+ return sm_this;
+ }
+
+
+private:
+
+ //
+ // Fiber entry point. Invokes the function or delegate passed on
+ // construction (if any).
+ //
+ final void run()
+ {
+ m_call();
+ }
+
+ //
+ // Standard fiber data
+ //
+ Callable m_call;
+ bool m_isRunning;
+ Throwable m_unhandled;
+ State m_state;
+
+
+protected:
+ ///////////////////////////////////////////////////////////////////////////
+ // Stack Management
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ //
+ // Allocate a new stack for this fiber.
+ //
+ abstract void allocStack( size_t sz, size_t guardPageSize ) nothrow;
+
+
+ //
+ // Free this fiber's stack.
+ //
+ abstract void freeStack() nothrow @nogc;
+
+
+ //
+ // Initialize the allocated stack.
+ // Look above the definition of 'class Fiber' for some information about the implementation of this routine
+ //
+ abstract void initStack() nothrow @nogc;
+
+
+ StackContext* m_ctxt;
+ size_t m_size;
+ void* m_pmem;
+
+ static if ( __traits( compiles, ucontext_t ) )
+ {
+ // NOTE: The static ucontext instance is used to represent the context
+ // of the executing thread.
+ static ucontext_t sm_utxt = void;
+ ucontext_t m_utxt = void;
+ package ucontext_t* m_ucur = null;
+ }
+ else static if (GNU_Enable_CET)
+ {
+ // When libphobos was built with --enable-cet, these fields need to
+ // always be present in the Fiber class layout.
+ import core.sys.posix.ucontext;
+ static ucontext_t sm_utxt = void;
+ ucontext_t m_utxt = void;
+ package ucontext_t* m_ucur = null;
+ }
+
+
+private:
+ ///////////////////////////////////////////////////////////////////////////
+ // Storage of Active Fiber
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ //
+ // Sets a thread-local reference to the current fiber object.
+ //
+ static void setThis( FiberBase f ) nothrow @nogc
+ {
+ sm_this = f;
+ }
+
+ static FiberBase sm_this;
+
+
+private:
+ ///////////////////////////////////////////////////////////////////////////
+ // Context Switching
+ ///////////////////////////////////////////////////////////////////////////
+
+
+ //
+ // Switches into the stack held by this fiber.
+ //
+ final void switchIn() nothrow @nogc
+ {
+ ThreadBase tobj = ThreadBase.getThis();
+ void** oldp = &tobj.m_curr.tstack;
+ void* newp = m_ctxt.tstack;
+
+ // NOTE: The order of operations here is very important. The current
+ // stack top must be stored before m_lock is set, and pushContext
+ // must not be called until after m_lock is set. This process
+ // is intended to prevent a race condition with the suspend
+ // mechanism used for garbage collection. If it is not followed,
+ // a badly timed collection could cause the GC to scan from the
+ // bottom of one stack to the top of another, or to miss scanning
+ // a stack that still contains valid data. The old stack pointer
+ // oldp will be set again before the context switch to guarantee
+ // that it points to exactly the correct stack location so the
+ // successive pop operations will succeed.
+ *oldp = getStackTop();
+ atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, true);
+ tobj.pushContext( m_ctxt );
+
+ fiber_switchContext( oldp, newp );
+
+ // NOTE: As above, these operations must be performed in a strict order
+ // to prevent Bad Things from happening.
+ tobj.popContext();
+ atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, false);
+ tobj.m_curr.tstack = tobj.m_curr.bstack;
+ }
+
+
+ //
+ // Switches out of the current stack and into the enclosing stack.
+ //
+ final void switchOut() nothrow @nogc
+ {
+ ThreadBase tobj = ThreadBase.getThis();
+ void** oldp = &m_ctxt.tstack;
+ void* newp = tobj.m_curr.within.tstack;
+
+ // NOTE: The order of operations here is very important. The current
+ // stack top must be stored before m_lock is set, and pushContext
+ // must not be called until after m_lock is set. This process
+ // is intended to prevent a race condition with the suspend
+ // mechanism used for garbage collection. If it is not followed,
+ // a badly timed collection could cause the GC to scan from the
+ // bottom of one stack to the top of another, or to miss scanning
+ // a stack that still contains valid data. The old stack pointer
+ // oldp will be set again before the context switch to guarantee
+ // that it points to exactly the correct stack location so the
+ // successive pop operations will succeed.
+ *oldp = getStackTop();
+ atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, true);
+
+ fiber_switchContext( oldp, newp );
+
+ // NOTE: As above, these operations must be performed in a strict order
+ // to prevent Bad Things from happening.
+ // NOTE: If use of this fiber is multiplexed across threads, the thread
+ // executing here may be different from the one above, so get the
+ // current thread handle before unlocking, etc.
+ tobj = ThreadBase.getThis();
+ atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, false);
+ tobj.m_curr.tstack = tobj.m_curr.bstack;
+ }
+}
+
+///
+unittest {
+ int counter;
+
+ class DerivedFiber : Fiber
+ {
+ this()
+ {
+ super( &run );
+ }
+
+ private :
+ void run()
+ {
+ counter += 2;
+ }
+ }
+
+ void fiberFunc()
+ {
+ counter += 4;
+ Fiber.yield();
+ counter += 8;
+ }
+
+ // create instances of each type
+ Fiber derived = new DerivedFiber();
+ Fiber composed = new Fiber( &fiberFunc );
+
+ assert( counter == 0 );
+
+ derived.call();
+ assert( counter == 2, "Derived fiber increment." );
+
+ composed.call();
+ assert( counter == 6, "First composed fiber increment." );
+
+ counter += 16;
+ assert( counter == 22, "Calling context increment." );
+
+ composed.call();
+ assert( counter == 30, "Second composed fiber increment." );
+
+ // since each fiber has run to completion, each should have state TERM
+ assert( derived.state == Fiber.State.TERM );
+ assert( composed.state == Fiber.State.TERM );
+}
+
+version (unittest)
+{
+ import core.thread.fiber: Fiber;
+}
+
+version (CoreUnittest)
+{
+ class TestFiber : Fiber
+ {
+ this()
+ {
+ super(&run);
+ }
+
+ void run()
+ {
+ foreach (i; 0 .. 1000)
+ {
+ sum += i;
+ Fiber.yield();
+ }
+ }
+
+ enum expSum = 1000 * 999 / 2;
+ size_t sum;
+ }
+
+ void runTen()
+ {
+ TestFiber[10] fibs;
+ foreach (ref fib; fibs)
+ fib = new TestFiber();
+
+ bool cont;
+ do {
+ cont = false;
+ foreach (fib; fibs) {
+ if (fib.state == Fiber.State.HOLD)
+ {
+ fib.call();
+ cont |= fib.state != Fiber.State.TERM;
+ }
+ }
+ } while (cont);
+
+ foreach (fib; fibs)
+ {
+ assert(fib.sum == TestFiber.expSum);
+ }
+ }
+}
+
+
+// Single thread running separate fibers
+unittest
+{
+ runTen();
+}
+
+
+// Multiple threads running separate fibers
+unittest
+{
+ auto group = new ThreadGroup();
+ foreach (_; 0 .. 4)
+ {
+ group.create(&runTen);
+ }
+ group.joinAll();
+}
+
+
+// Multiple threads running shared fibers
+version (PPC) version = UnsafeFiberMigration;
+version (PPC64) version = UnsafeFiberMigration;
+version (OSX)
+{
+ version (X86) version = UnsafeFiberMigration;
+ version (X86_64) version = UnsafeFiberMigration;
+ version (AArch64) version = UnsafeFiberMigration;
+}
+
+version (UnsafeFiberMigration)
+{
+ // XBUG: core.thread fibers are supposed to be safe to migrate across
+ // threads, however, there is a problem: GCC always assumes that the
+ // address of thread-local variables don't change while on a given stack.
+ // In consequence, migrating fibers between threads currently is an unsafe
+ // thing to do, and will break on some targets (possibly PR26461).
+}
+else
+{
+ version = FiberMigrationUnittest;
+}
+
+version (FiberMigrationUnittest)
+unittest
+{
+ shared bool[10] locks;
+ TestFiber[10] fibs;
+
+ void runShared()
+ {
+ bool cont;
+ do {
+ cont = false;
+ foreach (idx; 0 .. 10)
+ {
+ if (cas(&locks[idx], false, true))
+ {
+ if (fibs[idx].state == Fiber.State.HOLD)
+ {
+ fibs[idx].call();
+ cont |= fibs[idx].state != Fiber.State.TERM;
+ }
+ locks[idx] = false;
+ }
+ else
+ {
+ cont = true;
+ }
+ }
+ } while (cont);
+ }
+
+ foreach (ref fib; fibs)
+ {
+ fib = new TestFiber();
+ }
+
+ auto group = new ThreadGroup();
+ foreach (_; 0 .. 4)
+ {
+ group.create(&runShared);
+ }
+ group.joinAll();
+
+ foreach (fib; fibs)
+ {
+ assert(fib.sum == TestFiber.expSum);
+ }
+}
+
+
+// Test exception handling inside fibers.
+unittest
+{
+ enum MSG = "Test message.";
+ string caughtMsg;
+ (new Fiber({
+ try
+ {
+ throw new Exception(MSG);
+ }
+ catch (Exception e)
+ {
+ caughtMsg = e.msg;
+ }
+ })).call();
+ assert(caughtMsg == MSG);
+}
+
+
+unittest
+{
+ int x = 0;
+
+ (new Fiber({
+ x++;
+ })).call();
+ assert( x == 1 );
+}
+
+nothrow unittest
+{
+ new Fiber({}).call!(Fiber.Rethrow.no)();
+}
+
+unittest
+{
+ new Fiber({}).call(Fiber.Rethrow.yes);
+ new Fiber({}).call(Fiber.Rethrow.no);
+}
+
+unittest
+{
+ enum MSG = "Test message.";
+
+ try
+ {
+ (new Fiber(function() {
+ throw new Exception( MSG );
+ })).call();
+ assert( false, "Expected rethrown exception." );
+ }
+ catch ( Throwable t )
+ {
+ assert( t.msg == MSG );
+ }
+}
+
+// Test exception chaining when switching contexts in finally blocks.
+unittest
+{
+ static void throwAndYield(string msg) {
+ try {
+ throw new Exception(msg);
+ } finally {
+ Fiber.yield();
+ }
+ }
+
+ static void fiber(string name) {
+ try {
+ try {
+ throwAndYield(name ~ ".1");
+ } finally {
+ throwAndYield(name ~ ".2");
+ }
+ } catch (Exception e) {
+ assert(e.msg == name ~ ".1");
+ assert(e.next);
+ assert(e.next.msg == name ~ ".2");
+ assert(!e.next.next);
+ }
+ }
+
+ auto first = new Fiber(() => fiber("first"));
+ auto second = new Fiber(() => fiber("second"));
+ first.call();
+ second.call();
+ first.call();
+ second.call();
+ first.call();
+ second.call();
+ assert(first.state == Fiber.State.TERM);
+ assert(second.state == Fiber.State.TERM);
+}
+
+// Test Fiber resetting
+unittest
+{
+ static string method;
+
+ static void foo()
+ {
+ method = "foo";
+ }
+
+ void bar()
+ {
+ method = "bar";
+ }
+
+ static void expect(Fiber fib, string s)
+ {
+ assert(fib.state == Fiber.State.HOLD);
+ fib.call();
+ assert(fib.state == Fiber.State.TERM);
+ assert(method == s); method = null;
+ }
+ auto fib = new Fiber(&foo);
+ expect(fib, "foo");
+
+ fib.reset();
+ expect(fib, "foo");
+
+ fib.reset(&foo);
+ expect(fib, "foo");
+
+ fib.reset(&bar);
+ expect(fib, "bar");
+
+ fib.reset(function void(){method = "function";});
+ expect(fib, "function");
+
+ fib.reset(delegate void(){method = "delegate";});
+ expect(fib, "delegate");
+}
+
+// Test unsafe reset in hold state
+unittest
+{
+ auto fib = new Fiber(function {ubyte[2048] buf = void; Fiber.yield();}, 4096);
+ foreach (_; 0 .. 10)
+ {
+ fib.call();
+ assert(fib.state == Fiber.State.HOLD);
+ fib.reset();
+ }
+}
+
+// stress testing GC stack scanning
+unittest
+{
+ import core.memory;
+ import core.thread.osthread : Thread;
+ import core.time : dur;
+
+ static void unreferencedThreadObject()
+ {
+ static void sleep() { Thread.sleep(dur!"msecs"(100)); }
+ auto thread = new Thread(&sleep).start();
+ }
+ unreferencedThreadObject();
+ GC.collect();
+
+ static class Foo
+ {
+ this(int value)
+ {
+ _value = value;
+ }
+
+ int bar()
+ {
+ return _value;
+ }
+
+ int _value;
+ }
+
+ static void collect()
+ {
+ auto foo = new Foo(2);
+ assert(foo.bar() == 2);
+ GC.collect();
+ Fiber.yield();
+ GC.collect();
+ assert(foo.bar() == 2);
+ }
+
+ auto fiber = new Fiber(&collect);
+
+ fiber.call();
+ GC.collect();
+ fiber.call();
+
+ // thread reference
+ auto foo = new Foo(2);
+
+ void collect2()
+ {
+ assert(foo.bar() == 2);
+ GC.collect();
+ Fiber.yield();
+ GC.collect();
+ assert(foo.bar() == 2);
+ }
+
+ fiber = new Fiber(&collect2);
+
+ fiber.call();
+ GC.collect();
+ fiber.call();
+
+ static void recurse(size_t cnt)
+ {
+ --cnt;
+ Fiber.yield();
+ if (cnt)
+ {
+ auto fib = new Fiber(() { recurse(cnt); });
+ fib.call();
+ GC.collect();
+ fib.call();
+ }
+ }
+ fiber = new Fiber(() { recurse(20); });
+ fiber.call();
+}
/**
- * The fiber module provides OS-indepedent lightweight threads aka fibers.
+ * The fiber module provides lightweight threads aka fibers.
*
* Copyright: Copyright Sean Kelly 2005 - 2012.
* License: Distributed under the
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
* (See accompanying file LICENSE)
* Authors: Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak
- * Source: $(DRUNTIMESRC core/thread/fiber.d)
+ * Source: $(DRUNTIMESRC core/thread/fiber/package.d)
*/
/* NOTE: This file has been patched from the original DMD distribution to
*/
module core.thread.fiber;
+import core.thread.context;
+import core.thread.fiber.base : fiber_entryPoint, FiberBase;
import core.thread.threadbase;
import core.thread.threadgroup;
import core.thread.types;
-import core.thread.context;
import core.memory : pageSize;
version (GNU)
{
import gcc.builtins;
- import gcc.config;
version (GNU_StackGrowsDown)
version = StackGrowsDown;
}
version (Windows)
{
- import core.stdc.stdlib : malloc, free;
+ import core.stdc.stdlib : free, malloc;
import core.sys.windows.winbase;
import core.sys.windows.winnt;
}
-private
+package
{
version (D_InlineAsm_X86)
{
// a version identifier. Please note that this is considered
// an obsolescent feature according to the POSIX spec, so a
// custom solution is still preferred.
- import core.sys.posix.ucontext;
+ import core.sys.posix.ucontext : getcontext, makecontext, MINSIGSTKSZ, swapcontext, ucontext_t;
}
}
}
// Fiber Entry Point and Context Switch
///////////////////////////////////////////////////////////////////////////////
-private
+package
{
import core.atomic : atomicStore, cas, MemoryOrder;
import core.exception : onOutOfMemoryError;
import core.stdc.stdlib : abort;
- extern (C) void fiber_entryPoint() nothrow
+ // Look above the definition of 'class Fiber' for some information about the implementation of this routine
+ version (AsmExternal)
{
- Fiber obj = Fiber.getThis();
- assert( obj );
-
- assert( ThreadBase.getThis().m_curr is obj.m_ctxt );
- atomicStore!(MemoryOrder.raw)(*cast(shared)&ThreadBase.getThis().m_lock, false);
- obj.m_ctxt.tstack = obj.m_ctxt.bstack;
- obj.m_state = Fiber.State.EXEC;
-
- try
- {
- obj.run();
- }
- catch ( Throwable t )
- {
- obj.m_unhandled = t;
- }
-
- static if ( __traits( compiles, ucontext_t ) )
- obj.m_ucur = &obj.m_utxt;
-
- obj.m_state = Fiber.State.TERM;
- obj.switchOut();
+ extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow @nogc;
+ version (AArch64)
+ extern (C) void fiber_trampoline() nothrow;
}
-
- // Look above the definition of 'class Fiber' for some information about the implementation of this routine
- version (AsmExternal)
- {
- extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow @nogc;
- version (AArch64)
- extern (C) void fiber_trampoline() nothrow;
- }
- else
+ else
extern (C) void fiber_switchContext( void** oldp, void* newp ) nothrow @nogc
{
// NOTE: The data pushed and popped in this routine must match the
*
* Authors: Based on a design by Mikola Lysenko.
*/
-class Fiber
+class Fiber : FiberBase
{
///////////////////////////////////////////////////////////////////////////
// Initialization
*/
this( void function() fn, size_t sz = pageSize * defaultStackPages,
size_t guardPageSize = pageSize ) nothrow
- in
- {
- assert( fn );
- }
- do
{
- allocStack( sz, guardPageSize );
- reset( fn );
+ super( fn, sz, guardPageSize );
}
this( void delegate() dg, size_t sz = pageSize * defaultStackPages,
size_t guardPageSize = pageSize ) nothrow
{
- allocStack( sz, guardPageSize );
- reset( cast(void delegate() const) dg );
- }
-
-
- /**
- * Cleans up any remaining resources used by this object.
- */
- ~this() nothrow @nogc
- {
- // NOTE: A live reference to this object will exist on its associated
- // stack from the first time its call() method has been called
- // until its execution completes with State.TERM. Thus, the only
- // times this dtor should be called are either if the fiber has
- // terminated (and therefore has no active stack) or if the user
- // explicitly deletes this object. The latter case is an error
- // but is not easily tested for, since State.HOLD may imply that
- // the fiber was just created but has never been run. There is
- // not a compelling case to create a State.INIT just to offer a
- // means of ensuring the user isn't violating this object's
- // contract, so for now this requirement will be enforced by
- // documentation only.
- freeStack();
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // General Actions
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Transfers execution to this fiber object. The calling context will be
- * suspended until the fiber calls Fiber.yield() or until it terminates
- * via an unhandled exception.
- *
- * Params:
- * rethrow = Rethrow any unhandled exception which may have caused this
- * fiber to terminate.
- *
- * In:
- * This fiber must be in state HOLD.
- *
- * Throws:
- * Any exception not handled by the joined thread.
- *
- * Returns:
- * Any exception not handled by this fiber if rethrow = false, null
- * otherwise.
- */
- // Not marked with any attributes, even though `nothrow @nogc` works
- // because it calls arbitrary user code. Most of the implementation
- // is already `@nogc nothrow`, but in order for `Fiber.call` to
- // propagate the attributes of the user's function, the Fiber
- // class needs to be templated.
- final Throwable call( Rethrow rethrow = Rethrow.yes )
- {
- return rethrow ? call!(Rethrow.yes)() : call!(Rethrow.no);
- }
-
- /// ditto
- final Throwable call( Rethrow rethrow )()
- {
- callImpl();
- if ( m_unhandled )
- {
- Throwable t = m_unhandled;
- m_unhandled = null;
- static if ( rethrow )
- throw t;
- else
- return t;
- }
- return null;
- }
-
- private void callImpl() nothrow @nogc
- in
- {
- assert( m_state == State.HOLD );
- }
- do
- {
- Fiber cur = getThis();
-
- static if ( __traits( compiles, ucontext_t ) )
- m_ucur = cur ? &cur.m_utxt : &Fiber.sm_utxt;
-
- setThis( this );
- this.switchIn();
- setThis( cur );
-
- static if ( __traits( compiles, ucontext_t ) )
- m_ucur = null;
-
- // NOTE: If the fiber has terminated then the stack pointers must be
- // reset. This ensures that the stack for this fiber is not
- // scanned if the fiber has terminated. This is necessary to
- // prevent any references lingering on the stack from delaying
- // the collection of otherwise dead objects. The most notable
- // being the current object, which is referenced at the top of
- // fiber_entryPoint.
- if ( m_state == State.TERM )
- {
- m_ctxt.tstack = m_ctxt.bstack;
- }
- }
-
- /// Flag to control rethrow behavior of $(D $(LREF call))
- enum Rethrow : bool { no, yes }
-
- /**
- * Resets this fiber so that it may be re-used, optionally with a
- * new function/delegate. This routine should only be called for
- * fibers that have terminated, as doing otherwise could result in
- * scope-dependent functionality that is not executed.
- * Stack-based classes, for example, may not be cleaned up
- * properly if a fiber is reset before it has terminated.
- *
- * In:
- * This fiber must be in state TERM or HOLD.
- */
- final void reset() nothrow @nogc
- in
- {
- assert( m_state == State.TERM || m_state == State.HOLD );
- }
- do
- {
- m_ctxt.tstack = m_ctxt.bstack;
- m_state = State.HOLD;
- initStack();
- m_unhandled = null;
- }
-
- /// ditto
- final void reset( void function() fn ) nothrow @nogc
- {
- reset();
- m_call = fn;
- }
-
- /// ditto
- final void reset( void delegate() dg ) nothrow @nogc
- {
- reset();
- m_call = dg;
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // General Properties
- ///////////////////////////////////////////////////////////////////////////
-
-
- /// A fiber may occupy one of three states: HOLD, EXEC, and TERM.
- enum State
- {
- /** The HOLD state applies to any fiber that is suspended and ready to
- be called. */
- HOLD,
- /** The EXEC state will be set for any fiber that is currently
- executing. */
- EXEC,
- /** The TERM state is set when a fiber terminates. Once a fiber
- terminates, it must be reset before it may be called again. */
- TERM
- }
-
-
- /**
- * Gets the current state of this fiber.
- *
- * Returns:
- * The state of this fiber as an enumerated value.
- */
- final @property State state() const @safe pure nothrow @nogc
- {
- return m_state;
- }
-
-
- ///////////////////////////////////////////////////////////////////////////
- // Actions on Calling Fiber
- ///////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Forces a context switch to occur away from the calling fiber.
- */
- static void yield() nothrow @nogc
- {
- Fiber cur = getThis();
- assert( cur, "Fiber.yield() called with no active fiber" );
- assert( cur.m_state == State.EXEC );
-
- static if ( __traits( compiles, ucontext_t ) )
- cur.m_ucur = &cur.m_utxt;
-
- cur.m_state = State.HOLD;
- cur.switchOut();
- cur.m_state = State.EXEC;
- }
-
-
- /**
- * Forces a context switch to occur away from the calling fiber and then
- * throws obj in the calling fiber.
- *
- * Params:
- * t = The object to throw.
- *
- * In:
- * t must not be null.
- */
- static void yieldAndThrow( Throwable t ) nothrow @nogc
- in
- {
- assert( t );
- }
- do
- {
- Fiber cur = getThis();
- assert( cur, "Fiber.yield() called with no active fiber" );
- assert( cur.m_state == State.EXEC );
-
- static if ( __traits( compiles, ucontext_t ) )
- cur.m_ucur = &cur.m_utxt;
-
- cur.m_unhandled = t;
- cur.m_state = State.HOLD;
- cur.switchOut();
- cur.m_state = State.EXEC;
+ super( dg, sz, guardPageSize );
}
*/
static Fiber getThis() @safe nothrow @nogc
{
- version (GNU) pragma(inline, false);
- return sm_this;
+ return cast(Fiber) FiberBase.getThis();
}
}
}
-private:
-
- //
- // Fiber entry point. Invokes the function or delegate passed on
- // construction (if any).
- //
- final void run()
- {
- m_call();
- }
-
- //
- // Standard fiber data
- //
- Callable m_call;
- bool m_isRunning;
- Throwable m_unhandled;
- State m_state;
-
-
-private:
+protected:
///////////////////////////////////////////////////////////////////////////
// Stack Management
///////////////////////////////////////////////////////////////////////////
//
// Allocate a new stack for this fiber.
//
- final void allocStack( size_t sz, size_t guardPageSize ) nothrow
+ final override void allocStack( size_t sz, size_t guardPageSize ) nothrow
in
{
assert( !m_pmem && !m_ctxt );
}
else
{
- version (Posix) import core.sys.posix.sys.mman; // mmap, MAP_ANON
+ version (Posix) import core.sys.posix.sys.mman : MAP_ANON, MAP_FAILED, MAP_PRIVATE, mmap,
+ mprotect, PROT_NONE, PROT_READ, PROT_WRITE;
+ version (OpenBSD) import core.sys.posix.sys.mman : MAP_STACK;
static if ( __traits( compiles, ucontext_t ) )
{
//
// Free this fiber's stack.
//
- final void freeStack() nothrow @nogc
+ final override void freeStack() nothrow @nogc
in(m_pmem)
in(m_ctxt)
{
}
else
{
- import core.sys.posix.sys.mman; // munmap
+ import core.sys.posix.sys.mman : mmap, munmap;
static if ( __traits( compiles, mmap ) )
{
// Initialize the allocated stack.
// Look above the definition of 'class Fiber' for some information about the implementation of this routine
//
- final void initStack() nothrow @nogc
+ final override void initStack() nothrow @nogc
in
{
assert( m_ctxt.tstack && m_ctxt.tstack == m_ctxt.bstack );
}
enum sehChainEnd = cast(EXCEPTION_REGISTRATION*) 0xFFFFFFFF;
- __gshared static fp_t finalHandler = null;
+ __gshared fp_t finalHandler = null;
if ( finalHandler is null )
{
static EXCEPTION_REGISTRATION* fs0() nothrow
// Only need to set return address ($r1). Everything else is fine
// zero initialized.
pstack -= size_t.sizeof * 11; // skip past space reserved for $r21-$r31
- push (cast(size_t) &fiber_entryPoint);
+ push(cast(size_t) &fiber_entryPoint);
pstack += size_t.sizeof; // adjust sp (newp) above lr
}
else version (AsmAArch64_Posix)
else
static assert(0, "Not implemented");
}
-
-
- StackContext* m_ctxt;
- size_t m_size;
- void* m_pmem;
-
- static if ( __traits( compiles, ucontext_t ) )
- {
- // NOTE: The static ucontext instance is used to represent the context
- // of the executing thread.
- static ucontext_t sm_utxt = void;
- ucontext_t m_utxt = void;
- ucontext_t* m_ucur = null;
- }
- else static if (GNU_Enable_CET)
- {
- // When libphobos was built with --enable-cet, these fields need to
- // always be present in the Fiber class layout.
- import core.sys.posix.ucontext;
- static ucontext_t sm_utxt = void;
- ucontext_t m_utxt = void;
- ucontext_t* m_ucur = null;
- }
-
-
-private:
- ///////////////////////////////////////////////////////////////////////////
- // Storage of Active Fiber
- ///////////////////////////////////////////////////////////////////////////
-
-
- //
- // Sets a thread-local reference to the current fiber object.
- //
- static void setThis( Fiber f ) nothrow @nogc
- {
- sm_this = f;
- }
-
- static Fiber sm_this;
-
-
-private:
- ///////////////////////////////////////////////////////////////////////////
- // Context Switching
- ///////////////////////////////////////////////////////////////////////////
-
-
- //
- // Switches into the stack held by this fiber.
- //
- final void switchIn() nothrow @nogc
- {
- ThreadBase tobj = ThreadBase.getThis();
- void** oldp = &tobj.m_curr.tstack;
- void* newp = m_ctxt.tstack;
-
- // NOTE: The order of operations here is very important. The current
- // stack top must be stored before m_lock is set, and pushContext
- // must not be called until after m_lock is set. This process
- // is intended to prevent a race condition with the suspend
- // mechanism used for garbage collection. If it is not followed,
- // a badly timed collection could cause the GC to scan from the
- // bottom of one stack to the top of another, or to miss scanning
- // a stack that still contains valid data. The old stack pointer
- // oldp will be set again before the context switch to guarantee
- // that it points to exactly the correct stack location so the
- // successive pop operations will succeed.
- *oldp = getStackTop();
- atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, true);
- tobj.pushContext( m_ctxt );
-
- fiber_switchContext( oldp, newp );
-
- // NOTE: As above, these operations must be performed in a strict order
- // to prevent Bad Things from happening.
- tobj.popContext();
- atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, false);
- tobj.m_curr.tstack = tobj.m_curr.bstack;
- }
-
-
- //
- // Switches out of the current stack and into the enclosing stack.
- //
- final void switchOut() nothrow @nogc
- {
- ThreadBase tobj = ThreadBase.getThis();
- void** oldp = &m_ctxt.tstack;
- void* newp = tobj.m_curr.within.tstack;
-
- // NOTE: The order of operations here is very important. The current
- // stack top must be stored before m_lock is set, and pushContext
- // must not be called until after m_lock is set. This process
- // is intended to prevent a race condition with the suspend
- // mechanism used for garbage collection. If it is not followed,
- // a badly timed collection could cause the GC to scan from the
- // bottom of one stack to the top of another, or to miss scanning
- // a stack that still contains valid data. The old stack pointer
- // oldp will be set again before the context switch to guarantee
- // that it points to exactly the correct stack location so the
- // successive pop operations will succeed.
- *oldp = getStackTop();
- atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, true);
-
- fiber_switchContext( oldp, newp );
-
- // NOTE: As above, these operations must be performed in a strict order
- // to prevent Bad Things from happening.
- // NOTE: If use of this fiber is multiplexed across threads, the thread
- // executing here may be different from the one above, so get the
- // current thread handle before unlocking, etc.
- tobj = ThreadBase.getThis();
- atomicStore!(MemoryOrder.raw)(*cast(shared)&tobj.m_lock, false);
- tobj.m_curr.tstack = tobj.m_curr.bstack;
- }
-}
-
-///
-unittest {
- int counter;
-
- class DerivedFiber : Fiber
- {
- this()
- {
- super( &run );
- }
-
- private :
- void run()
- {
- counter += 2;
- }
- }
-
- void fiberFunc()
- {
- counter += 4;
- Fiber.yield();
- counter += 8;
- }
-
- // create instances of each type
- Fiber derived = new DerivedFiber();
- Fiber composed = new Fiber( &fiberFunc );
-
- assert( counter == 0 );
-
- derived.call();
- assert( counter == 2, "Derived fiber increment." );
-
- composed.call();
- assert( counter == 6, "First composed fiber increment." );
-
- counter += 16;
- assert( counter == 22, "Calling context increment." );
-
- composed.call();
- assert( counter == 30, "Second composed fiber increment." );
-
- // since each fiber has run to completion, each should have state TERM
- assert( derived.state == Fiber.State.TERM );
- assert( composed.state == Fiber.State.TERM );
-}
-
-version (CoreUnittest)
-{
- class TestFiber : Fiber
- {
- this()
- {
- super(&run);
- }
-
- void run()
- {
- foreach (i; 0 .. 1000)
- {
- sum += i;
- Fiber.yield();
- }
- }
-
- enum expSum = 1000 * 999 / 2;
- size_t sum;
- }
-
- void runTen()
- {
- TestFiber[10] fibs;
- foreach (ref fib; fibs)
- fib = new TestFiber();
-
- bool cont;
- do {
- cont = false;
- foreach (fib; fibs) {
- if (fib.state == Fiber.State.HOLD)
- {
- fib.call();
- cont |= fib.state != Fiber.State.TERM;
- }
- }
- } while (cont);
-
- foreach (fib; fibs)
- {
- assert(fib.sum == TestFiber.expSum);
- }
- }
-}
-
-
-// Single thread running separate fibers
-unittest
-{
- runTen();
-}
-
-
-// Multiple threads running separate fibers
-unittest
-{
- auto group = new ThreadGroup();
- foreach (_; 0 .. 4)
- {
- group.create(&runTen);
- }
- group.joinAll();
-}
-
-
-// Multiple threads running shared fibers
-version (PPC) version = UnsafeFiberMigration;
-version (PPC64) version = UnsafeFiberMigration;
-version (OSX)
-{
- version (X86) version = UnsafeFiberMigration;
- version (X86_64) version = UnsafeFiberMigration;
- version (AArch64) version = UnsafeFiberMigration;
-}
-
-version (UnsafeFiberMigration)
-{
- // XBUG: core.thread fibers are supposed to be safe to migrate across
- // threads, however, there is a problem: GCC always assumes that the
- // address of thread-local variables don't change while on a given stack.
- // In consequence, migrating fibers between threads currently is an unsafe
- // thing to do, and will break on some targets (possibly PR26461).
-}
-else
-{
- version = FiberMigrationUnittest;
-}
-
-version (FiberMigrationUnittest)
-unittest
-{
- shared bool[10] locks;
- TestFiber[10] fibs;
-
- void runShared()
- {
- bool cont;
- do {
- cont = false;
- foreach (idx; 0 .. 10)
- {
- if (cas(&locks[idx], false, true))
- {
- if (fibs[idx].state == Fiber.State.HOLD)
- {
- fibs[idx].call();
- cont |= fibs[idx].state != Fiber.State.TERM;
- }
- locks[idx] = false;
- }
- else
- {
- cont = true;
- }
- }
- } while (cont);
- }
-
- foreach (ref fib; fibs)
- {
- fib = new TestFiber();
- }
-
- auto group = new ThreadGroup();
- foreach (_; 0 .. 4)
- {
- group.create(&runShared);
- }
- group.joinAll();
-
- foreach (fib; fibs)
- {
- assert(fib.sum == TestFiber.expSum);
- }
-}
-
-
-// Test exception handling inside fibers.
-unittest
-{
- enum MSG = "Test message.";
- string caughtMsg;
- (new Fiber({
- try
- {
- throw new Exception(MSG);
- }
- catch (Exception e)
- {
- caughtMsg = e.msg;
- }
- })).call();
- assert(caughtMsg == MSG);
-}
-
-
-unittest
-{
- int x = 0;
-
- (new Fiber({
- x++;
- })).call();
- assert( x == 1 );
-}
-
-nothrow unittest
-{
- new Fiber({}).call!(Fiber.Rethrow.no)();
-}
-
-unittest
-{
- new Fiber({}).call(Fiber.Rethrow.yes);
- new Fiber({}).call(Fiber.Rethrow.no);
-}
-
-unittest
-{
- enum MSG = "Test message.";
-
- try
- {
- (new Fiber(function() {
- throw new Exception( MSG );
- })).call();
- assert( false, "Expected rethrown exception." );
- }
- catch ( Throwable t )
- {
- assert( t.msg == MSG );
- }
-}
-
-// Test exception chaining when switching contexts in finally blocks.
-unittest
-{
- static void throwAndYield(string msg) {
- try {
- throw new Exception(msg);
- } finally {
- Fiber.yield();
- }
- }
-
- static void fiber(string name) {
- try {
- try {
- throwAndYield(name ~ ".1");
- } finally {
- throwAndYield(name ~ ".2");
- }
- } catch (Exception e) {
- assert(e.msg == name ~ ".1");
- assert(e.next);
- assert(e.next.msg == name ~ ".2");
- assert(!e.next.next);
- }
- }
-
- auto first = new Fiber(() => fiber("first"));
- auto second = new Fiber(() => fiber("second"));
- first.call();
- second.call();
- first.call();
- second.call();
- first.call();
- second.call();
- assert(first.state == Fiber.State.TERM);
- assert(second.state == Fiber.State.TERM);
-}
-
-// Test Fiber resetting
-unittest
-{
- static string method;
-
- static void foo()
- {
- method = "foo";
- }
-
- void bar()
- {
- method = "bar";
- }
-
- static void expect(Fiber fib, string s)
- {
- assert(fib.state == Fiber.State.HOLD);
- fib.call();
- assert(fib.state == Fiber.State.TERM);
- assert(method == s); method = null;
- }
- auto fib = new Fiber(&foo);
- expect(fib, "foo");
-
- fib.reset();
- expect(fib, "foo");
-
- fib.reset(&foo);
- expect(fib, "foo");
-
- fib.reset(&bar);
- expect(fib, "bar");
-
- fib.reset(function void(){method = "function";});
- expect(fib, "function");
-
- fib.reset(delegate void(){method = "delegate";});
- expect(fib, "delegate");
-}
-
-// Test unsafe reset in hold state
-unittest
-{
- auto fib = new Fiber(function {ubyte[2048] buf = void; Fiber.yield();}, 4096);
- foreach (_; 0 .. 10)
- {
- fib.call();
- assert(fib.state == Fiber.State.HOLD);
- fib.reset();
- }
-}
-
-// stress testing GC stack scanning
-unittest
-{
- import core.memory;
- import core.thread.osthread : Thread;
- import core.time : dur;
-
- static void unreferencedThreadObject()
- {
- static void sleep() { Thread.sleep(dur!"msecs"(100)); }
- auto thread = new Thread(&sleep).start();
- }
- unreferencedThreadObject();
- GC.collect();
-
- static class Foo
- {
- this(int value)
- {
- _value = value;
- }
-
- int bar()
- {
- return _value;
- }
-
- int _value;
- }
-
- static void collect()
- {
- auto foo = new Foo(2);
- assert(foo.bar() == 2);
- GC.collect();
- Fiber.yield();
- GC.collect();
- assert(foo.bar() == 2);
- }
-
- auto fiber = new Fiber(&collect);
-
- fiber.call();
- GC.collect();
- fiber.call();
-
- // thread reference
- auto foo = new Foo(2);
-
- void collect2()
- {
- assert(foo.bar() == 2);
- GC.collect();
- Fiber.yield();
- GC.collect();
- assert(foo.bar() == 2);
- }
-
- fiber = new Fiber(&collect2);
-
- fiber.call();
- GC.collect();
- fiber.call();
-
- static void recurse(size_t cnt)
- {
- --cnt;
- Fiber.yield();
- if (cnt)
- {
- auto fib = new Fiber(() { recurse(cnt); });
- fib.call();
- GC.collect();
- fib.call();
- }
- }
- fiber = new Fiber(() { recurse(20); });
- fiber.call();
}
*/
module core.thread.osthread;
-import core.thread.threadbase;
-import core.thread.context;
-import core.thread.types;
import core.atomic;
-import core.memory : GC, pageSize;
-import core.time;
import core.exception : onOutOfMemoryError;
import core.internal.traits : externDFunc;
-
+import core.memory : GC, pageSize;
+import core.thread.context;
+import core.thread.threadbase;
+import core.thread.types;
+import core.time;
///////////////////////////////////////////////////////////////////////////////
// Platform Detection and Memory Allocation
// a version identifier. Please note that this is considered
// an obsolescent feature according to the POSIX spec, so a
// custom solution is still preferred.
- import core.sys.posix.ucontext;
+ static import core.sys.posix.ucontext;
}
}
}
else version (Posix)
{
+ static import core.sys.posix.pthread;
+ static import core.sys.posix.signal;
import core.stdc.errno;
- import core.sys.posix.semaphore;
- import core.sys.posix.stdlib; // for malloc, valloc, free, atexit
- import core.sys.posix.pthread;
- import core.sys.posix.signal;
- import core.sys.posix.time;
+ import core.sys.posix.pthread : pthread_atfork, pthread_attr_destroy, pthread_attr_getstack, pthread_attr_init,
+ pthread_attr_setstacksize, pthread_create, pthread_detach, pthread_getschedparam, pthread_join, pthread_self,
+ pthread_setschedparam, sched_get_priority_max, sched_get_priority_min, sched_param, sched_yield;
+ import core.sys.posix.semaphore : sem_init, sem_post, sem_t, sem_wait;
+ import core.sys.posix.signal : pthread_kill, sigaction, sigaction_t, sigdelset, sigfillset, sigset_t, sigsuspend,
+ SIGUSR1, stack_t;
+ import core.sys.posix.stdlib : free, malloc, realloc;
+ import core.sys.posix.sys.types : pthread_attr_t, pthread_key_t, pthread_t;
+ import core.sys.posix.time : nanosleep, timespec;
version (Darwin)
{
- import core.sys.darwin.mach.thread_act;
+ import core.sys.darwin.mach.kern_return : KERN_SUCCESS;
+ import core.sys.darwin.mach.port : mach_port_t;
+ import core.sys.darwin.mach.thread_act : mach_msg_type_number_t, thread_get_state, thread_resume,
+ thread_suspend, x86_THREAD_STATE64, x86_THREAD_STATE64_COUNT, x86_thread_state64_t;
import core.sys.darwin.pthread : pthread_mach_thread_np;
}
}
version (Solaris)
{
- import core.sys.solaris.sys.priocntl;
- import core.sys.solaris.sys.types;
import core.sys.posix.sys.wait : idtype_t;
+ import core.sys.solaris.sys.priocntl : PC_CLNULL, PC_GETCLINFO, PC_GETPARMS, PC_SETPARMS, pcinfo_t, pcparms_t, priocntl;
+ import core.sys.solaris.sys.types : P_MYID, pri_t;
}
version (GNU)
}
else version (Posix)
{
- static if (__traits(compiles, pthread_setschedprio))
+ static if (__traits(compiles, core.sys.posix.pthread.pthread_setschedprio))
{
+ import core.sys.posix.pthread : pthread_setschedprio;
+
if (auto err = pthread_setschedprio(m_addr, val))
{
// ignore error if thread is not running => Bugzilla 8960
*/
version (Posix)
{
- import core.sys.posix.unistd;
-
- alias getpid = core.sys.posix.unistd.getpid;
+ alias getpid = imported!"core.sys.posix.unistd".getpid;
}
else version (Windows)
{
- alias getpid = core.sys.windows.winbase.GetCurrentProcessId;
+ alias getpid = imported!"core.sys.windows.winbase".GetCurrentProcessId;
}
extern (C) @nogc nothrow
}
else version (Darwin)
{
- import core.sys.darwin.pthread;
+ import core.sys.darwin.pthread : pthread_get_stackaddr_np;
return pthread_get_stackaddr_np(pthread_self());
}
else version (PThread_Getattr_NP)
enum SIGRTMIN = SIGUSR1;
enum SIGRTMAX = 32;
}
+ else
+ {
+ import core.sys.posix.signal : SIGRTMAX, SIGRTMIN;
+ }
if ( suspendSignalNumber == 0 )
{
// NOTE: SA_RESTART indicates that system calls should restart if they
// are interrupted by a signal, but this is not available on all
// Posix systems, even those that support multithreading.
- static if ( __traits( compiles, SA_RESTART ) )
+ static if (__traits(compiles, core.sys.posix.signal.SA_RESTART))
+ {
+ import core.sys.posix.signal : SA_RESTART;
+
suspend.sa_flags = SA_RESTART;
+ }
suspend.sa_handler = &thread_suspendHandler;
// NOTE: We want to ignore all signals while in this handler, so fill
{
private
{
- import core.stdc.errno;
- import core.sys.posix.semaphore;
- import core.sys.posix.stdlib; // for malloc, valloc, free, atexit
- import core.sys.posix.pthread;
- import core.sys.posix.signal;
- import core.sys.posix.time;
-
- version (Darwin)
- {
- import core.sys.darwin.mach.thread_act;
- import core.sys.darwin.pthread : pthread_mach_thread_np;
- }
-
//
// Entry point for POSIX threads
//
// implementation actually requires default initialization
// then pthread_cleanup should be restructured to maintain
// the current lack of a link dependency.
- static if ( __traits( compiles, pthread_cleanup ) )
+ static if (__traits(compiles, core.sys.posix.pthread.pthread_cleanup))
{
+ import core.sys.posix.pthread : pthread_cleanup;
+
pthread_cleanup cleanup = void;
cleanup.push( &thread_cleanupHandler, cast(void*) obj );
}
- else static if ( __traits( compiles, pthread_cleanup_push ) )
+ else static if (__traits(compiles, core.sys.posix.pthread.pthread_cleanup_push))
{
- pthread_cleanup_push( &thread_cleanupHandler, cast(void*) obj );
+ import core.sys.posix.pthread : pthread_cleanup_push;
+
+ pthread_cleanup_push(&thread_cleanupHandler, cast(void*) obj);
}
else
{
// NOTE: Normal cleanup is handled by scope(exit).
- static if ( __traits( compiles, pthread_cleanup ) )
+ static if (__traits(compiles, core.sys.posix.pthread.pthread_cleanup))
{
cleanup.pop( 0 );
}
- else static if ( __traits( compiles, pthread_cleanup_push ) )
+ else static if (__traits(compiles, core.sys.posix.pthread.pthread_cleanup_push))
{
+ import core.sys.posix.pthread : pthread_cleanup_pop;
+
pthread_cleanup_pop( 0 );
}
// Note: if the DLL is never unloaded, process termination kills all threads
// and signals their handles before unconditionally calling DllMain(DLL_PROCESS_DETACH).
- import core.sys.windows.winbase : FreeLibraryAndExitThread, GetModuleHandleExW,
- GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT;
- import core.sys.windows.windef : HMODULE;
import core.sys.windows.dll : dll_getRefCount;
+ import core.sys.windows.winbase : FreeLibraryAndExitThread, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, GetModuleHandleExW;
+ import core.sys.windows.windef : HMODULE;
version (CRuntime_Microsoft)
extern(C) extern __gshared ubyte msvcUsesUCRT; // from rt/msvc.d
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
* (See accompanying file LICENSE)
* Authors: Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak
- * Source: $(DRUNTIMESRC core/thread/osthread.d)
+ * Source: $(DRUNTIMESRC core/thread/threadbase.d)
*/
/* NOTE: This file has been patched from the original DMD distribution to
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
* (See accompanying file LICENSE)
* Authors: Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak
- * Source: $(DRUNTIMESRC core/thread/osthread.d)
+ * Source: $(DRUNTIMESRC core/thread/threadgroup.d)
*/
module core.thread.threadgroup;
* $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost Software License 1.0).
* (See accompanying file LICENSE)
* Authors: Sean Kelly, Walter Bright, Alex Rønne Petersen, Martin Nowak
- * Source: $(DRUNTIMESRC core/thread/osthread.d)
+ * Source: $(DRUNTIMESRC core/thread/types.d)
*/
module core.thread.types;
else
version (Posix)
{
- import core.sys.posix.pthread;
+ import core.sys.posix.sys.types : pthread_t;
alias ThreadID = pthread_t;
}
{
version (Posix)
{
- import core.sys.posix.unistd;
+ import core.sys.posix.unistd : _SC_THREAD_STACK_MIN, sysconf;
PTHREAD_STACK_MIN = cast(size_t)sysconf(_SC_THREAD_STACK_MIN);
}
module core.time;
import core.exception;
-import core.stdc.time;
-import core.stdc.stdio;
import core.internal.string;
-
-version (Windows)
-{
-import core.sys.windows.winbase /+: QueryPerformanceCounter, QueryPerformanceFrequency+/;
-}
-else version (Posix)
-{
-import core.sys.posix.time;
-import core.sys.posix.sys.time;
-}
+import core.stdc.stdio;
+import core.stdc.time;
version (OSX)
version = Darwin;
else version (WatchOS)
version = Darwin;
+version (Windows)
+{
+ import core.sys.windows.winbase /+: QueryPerformanceCounter, QueryPerformanceFrequency+/;
+}
+else version (Darwin)
+{
+ import core.sys.posix.sys.time : gettimeofday, timeval;
+ import core.sys.posix.time : timespec;
+}
+else version (Posix)
+{
+ import core.sys.posix.sys.time : gettimeofday, timeval;
+ import core.sys.posix.time : clock_getres, clock_gettime, CLOCK_MONOTONIC, timespec;
+}
+
+
//This probably should be moved somewhere else in druntime which
//is Darwin-specific.
version (Darwin)
{
-public import core.sys.darwin.mach.kern_return;
+import core.sys.darwin.mach.kern_return : kern_return_t;
extern(C) nothrow @nogc
{
}
-import core.internal.traits : AliasSeq;
+/+
+ dmd @@@BUG18223@@@
+ A selective import of `AliasSeq` happens to bleed through and causes symbol clashes downstream.
+ +/
+version (none)
+ import core.internal.traits : AliasSeq;
+else
+ import core.internal.traits;
/+ An adjusted copy of std.exception.assertThrown. +/
import core.internal.utf : decode, toUTF8;
+debug (apply) import core.stdc.stdio : printf;
+
/**********************************************/
/* 1 argument versions */
int result;
size_t len = aa.length;
- debug(apply) printf("_aApplycd1(), len = %d\n", len);
+ debug(apply) printf("_aApplycd1(), len = %zd\n", len);
for (size_t i = 0; i < len; )
{
dchar d = aa[i];
int result;
size_t len = aa.length;
- debug(apply) printf("_aApplywd1(), len = %d\n", len);
+ debug(apply) printf("_aApplywd1(), len = %zd\n", len);
for (size_t i = 0; i < len; )
{
dchar d = aa[i];
int result;
size_t len = aa.length;
- debug(apply) printf("_aApplycw1(), len = %d\n", len);
+ debug(apply) printf("_aApplycw1(), len = %zd\n", len);
for (size_t i = 0; i < len; )
{
wchar w = aa[i];
int result;
size_t len = aa.length;
- debug(apply) printf("_aApplywc1(), len = %d\n", len);
+ debug(apply) printf("_aApplywc1(), len = %zd\n", len);
for (size_t i = 0; i < len; )
{
wchar w = aa[i];
{
int result;
- debug(apply) printf("_aApplydc1(), len = %d\n", aa.length);
+ debug(apply) printf("_aApplydc1(), len = %zd\n", aa.length);
foreach (dchar d; aa)
{
if (d & ~0x7F)
{
int result;
- debug(apply) printf("_aApplydw1(), len = %d\n", aa.length);
+ debug(apply) printf("_aApplydw1(), len = %zd\n", aa.length);
foreach (dchar d; aa)
{
wchar w;
int result;
size_t len = aa.length;
- debug(apply) printf("_aApplycd2(), len = %d\n", len);
+ debug(apply) printf("_aApplycd2(), len = %zd\n", len);
size_t n;
for (size_t i = 0; i < len; i += n)
{
int result;
size_t len = aa.length;
- debug(apply) printf("_aApplywd2(), len = %d\n", len);
+ debug(apply) printf("_aApplywd2(), len = %zd\n", len);
size_t n;
for (size_t i = 0; i < len; i += n)
{
int result;
size_t len = aa.length;
- debug(apply) printf("_aApplycw2(), len = %d\n", len);
+ debug(apply) printf("_aApplycw2(), len = %zd\n", len);
size_t n;
for (size_t i = 0; i < len; i += n)
{
int result;
size_t len = aa.length;
- debug(apply) printf("_aApplywc2(), len = %d\n", len);
+ debug(apply) printf("_aApplywc2(), len = %zd\n", len);
size_t n;
for (size_t i = 0; i < len; i += n)
{
int result;
size_t len = aa.length;
- debug(apply) printf("_aApplydc2(), len = %d\n", len);
+ debug(apply) printf("_aApplydc2(), len = %zd\n", len);
for (size_t i = 0; i < len; i++)
{
dchar d = aa[i];
extern (C) int _aApplydw2(scope const(dchar)[] aa, dg2_t dg)
{ int result;
- debug(apply) printf("_aApplydw2(), len = %d\n", aa.length);
+ debug(apply) printf("_aApplydw2(), len = %zd\n", aa.length);
foreach (size_t i, dchar d; aa)
{
wchar w;
import core.internal.utf;
+debug (apply) import core.stdc.stdio : printf;
+
/**********************************************/
/* 1 argument versions */
extern (C) int _aApplyRcd1(scope const(char)[] aa, dg_t dg)
{ int result;
- debug(apply) printf("_aApplyRcd1(), len = %d\n", aa.length);
+ debug(apply) printf("_aApplyRcd1(), len = %zd\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
extern (C) int _aApplyRwd1(scope const(wchar)[] aa, dg_t dg)
{ int result;
- debug(apply) printf("_aApplyRwd1(), len = %d\n", aa.length);
+ debug(apply) printf("_aApplyRwd1(), len = %zd\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
extern (C) int _aApplyRcw1(scope const(char)[] aa, dg_t dg)
{ int result;
- debug(apply) printf("_aApplyRcw1(), len = %d\n", aa.length);
+ debug(apply) printf("_aApplyRcw1(), len = %zd\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
wchar w;
extern (C) int _aApplyRwc1(scope const(wchar)[] aa, dg_t dg)
{ int result;
- debug(apply) printf("_aApplyRwc1(), len = %d\n", aa.length);
+ debug(apply) printf("_aApplyRwc1(), len = %zd\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
char c;
extern (C) int _aApplyRdc1(scope const(dchar)[] aa, dg_t dg)
{ int result;
- debug(apply) printf("_aApplyRdc1(), len = %d\n", aa.length);
+ debug(apply) printf("_aApplyRdc1(), len = %zd\n", aa.length);
for (size_t i = aa.length; i != 0;)
{ dchar d = aa[--i];
char c;
extern (C) int _aApplyRdw1(scope const(dchar)[] aa, dg_t dg)
{ int result;
- debug(apply) printf("_aApplyRdw1(), len = %d\n", aa.length);
+ debug(apply) printf("_aApplyRdw1(), len = %zd\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d = aa[--i];
wchar w;
size_t i;
size_t len = aa.length;
- debug(apply) printf("_aApplyRcd2(), len = %d\n", len);
+ debug(apply) printf("_aApplyRcd2(), len = %zd\n", len);
for (i = len; i != 0; )
{ dchar d;
extern (C) int _aApplyRwd2(scope const(wchar)[] aa, dg2_t dg)
{ int result;
- debug(apply) printf("_aApplyRwd2(), len = %d\n", aa.length);
+ debug(apply) printf("_aApplyRwd2(), len = %zd\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
extern (C) int _aApplyRcw2(scope const(char)[] aa, dg2_t dg)
{ int result;
- debug(apply) printf("_aApplyRcw2(), len = %d\n", aa.length);
+ debug(apply) printf("_aApplyRcw2(), len = %zd\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
wchar w;
extern (C) int _aApplyRwc2(scope const(wchar)[] aa, dg2_t dg)
{ int result;
- debug(apply) printf("_aApplyRwc2(), len = %d\n", aa.length);
+ debug(apply) printf("_aApplyRwc2(), len = %zd\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d;
char c;
extern (C) int _aApplyRdc2(scope const(dchar)[] aa, dg2_t dg)
{ int result;
- debug(apply) printf("_aApplyRdc2(), len = %d\n", aa.length);
+ debug(apply) printf("_aApplyRdc2(), len = %zd\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d = aa[--i];
char c;
extern (C) int _aApplyRdw2(scope const(dchar)[] aa, dg2_t dg)
{ int result;
- debug(apply) printf("_aApplyRdw2(), len = %d\n", aa.length);
+ debug(apply) printf("_aApplyRdw2(), len = %zd\n", aa.length);
for (size_t i = aa.length; i != 0; )
{ dchar d = aa[--i];
wchar w;
extern (C) int _adEq2(void[] a1, void[] a2, TypeInfo ti)
{
- debug(adi) printf("_adEq2(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
+ debug(adi) printf("_adEq2(a1.length = %zd, a2.length = %zd)\n", a1.length, a2.length);
if (a1.length != a2.length)
return 0; // not equal
if (!ti.equals(&a1, &a2))
void[] _d_arraycopy(size_t size, void[] from, void[] to)
{
- debug(PRINTF) printf("f = %p,%d, t = %p,%d, size = %d\n",
+ debug(PRINTF) printf("f = %p,%zd, t = %p,%zd, size = %zd\n",
from.ptr, from.length, to.ptr, to.length, size);
enforceRawArraysConformable("copy", size, from, to);
*/
module rt.cast_;
+debug(cast_) import core.stdc.stdio : printf;
+
extern (C):
@nogc:
nothrow:
*/
if (pi.offset < 0x10000)
{
- debug(cast_) printf("\tpi.offset = %d\n", pi.offset);
+ debug(cast_) printf("\tpi.offset = %zd\n", pi.offset);
return cast(Object)(p - pi.offset);
}
return o;
*/
void* _d_interface_cast(void* p, ClassInfo c)
{
- debug(cast_) printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name);
+ debug(cast_) printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, cast(int) c.name.length, c.name.ptr);
if (!p)
return null;
Interface* pi = **cast(Interface***) p;
- debug(cast_) printf("\tpi.offset = %d\n", pi.offset);
+ debug(cast_) printf("\tpi.offset = %zd\n", pi.offset);
Object o2 = cast(Object)(p - pi.offset);
void* res = null;
size_t offset = 0;
if (o2 && _d_isbaseof2(typeid(o2), c, offset))
{
- debug(cast_) printf("\toffset = %d\n", offset);
+ debug(cast_) printf("\toffset = %zd\n", offset);
res = cast(void*) o2 + offset;
}
debug(cast_) printf("\tresult = %p\n", res);
*/
void* _d_dynamic_cast(Object o, ClassInfo c)
{
- debug(cast_) printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name);
+ debug(cast_) printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, cast(int) c.name.length, c.name.ptr);
void* res = null;
size_t offset = 0;
if (o && _d_isbaseof2(typeid(o), c, offset))
{
- debug(cast_) printf("\toffset = %d\n", offset);
+ debug(cast_) printf("\toffset = %zd\n", offset);
res = cast(void*) o + offset;
}
debug(cast_) printf("\tresult = %p\n", res);
*/
void* _d_class_cast(Object o, ClassInfo c)
{
- debug(cast_) printf("_d_cast_cast(o = %p, c = '%.*s', level %d)\n", o, c.name, level);
+ debug(cast_) printf("_d_cast_cast(o = %p, c = '%.*s')\n", o, cast(int) c.name.length, c.name.ptr);
if (!o)
return null;
*/
extern(C) void _d_arrayshrinkfit(const TypeInfo ti, void[] arr) nothrow
{
- debug(PRINTF) printf("_d_arrayshrinkfit, elemsize = %d, arr.ptr = x%x arr.length = %d\n", ti.next.tsize, arr.ptr, arr.length);
+ debug(PRINTF) printf("_d_arrayshrinkfit, elemsize = %zd, arr.ptr = %p arr.length = %zd\n", ti.next.tsize, arr.ptr, arr.length);
auto tinext = unqualify(ti.next);
auto size = tinext.tsize; // array element size
auto reqsize = arr.length * size;
auto tinext = unqualify(ti.next);
auto size = tinext.tsize;
- debug(PRINTF) printf("_d_newarrayU(length = x%x, size = %d)\n", length, size);
+ debug(PRINTF) printf("_d_newarrayU(length = x%zx, size = %zd)\n", length, size);
if (length == 0 || size == 0)
return null;
{
//printf("_d_arraysetlengthT(p = %p, sizeelem = %d, newlength = %d)\n", p, sizeelem, newlength);
if (p)
- printf("\tp.ptr = %p, p.length = %d\n", (*p).ptr, (*p).length);
+ printf("\tp.ptr = %p, p.length = %zd\n", (*p).ptr, (*p).length);
}
if (newlength <= (*p).length)
assert(0);
}
- debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength);
+ debug(PRINTF) printf("newsize = %zx, newlength = %zx\n", newsize, newlength);
const isshared = typeid(ti) is typeid(TypeInfo_Shared);
{
//printf("_d_arraysetlengthT(p = %p, sizeelem = %d, newlength = %d)\n", p, sizeelem, newlength);
if (p)
- printf("\tp.ptr = %p, p.length = %d\n", (*p).ptr, (*p).length);
+ printf("\tp.ptr = %p, p.length = %zd\n", (*p).ptr, (*p).length);
}
if (newlength <= (*p).length)
assert(0);
}
- debug(PRINTF) printf("newsize = %x, newlength = %x\n", newsize, newlength);
+ debug(PRINTF) printf("newsize = %zx, newlength = %zx\n", newsize, newlength);
const isshared = typeid(ti) is typeid(TypeInfo_Shared);
// ((newlength * mult + 99) / 100) * elemsize
newcap = cast(size_t)((newlength * mult + 127) >> 7) * elemsize;
debug(PRINTF) printf("mult: %2.2f, alloc: %2.2f\n",mult/128.0,newcap / cast(double)elemsize);
- debug(PRINTF) printf("newcap = %d, newlength = %d, elemsize = %d\n", newcap, newlength, elemsize);
+ debug(PRINTF) printf("newcap = %zd, newlength = %zd, elemsize = %zd\n", newcap, newlength, elemsize);
return newcap;
}
auto sizeelem = tinext.tsize; // array element size
void* result;
- debug(PRINTF) printf("_d_arrayliteralTX(sizeelem = %d, length = %d)\n", sizeelem, length);
+ debug(PRINTF) printf("_d_arrayliteralTX(sizeelem = %zd, length = %zd)\n", sizeelem, length);
if (length == 0 || sizeelem == 0)
result = null;
else
}
else version (Posix)
{
- import core.sys.posix.pthread;
+ import core.sys.posix.pthread : pthread_mutex_destroy, pthread_mutex_init, pthread_mutex_lock,
+ PTHREAD_MUTEX_RECURSIVE, pthread_mutex_unlock, pthread_mutexattr_destroy, pthread_mutexattr_init,
+ pthread_mutexattr_settype;
+ import core.sys.posix.sys.types : pthread_mutex_t, pthread_mutexattr_t;
@nogc:
alias Mutex = pthread_mutex_t;
-ad8ee55872a25c93beacfb0ae1cca80dc8115916
+03aeafd2095b563bb66b75342652d2dcea66c9e8
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
`commonPrefix("parakeet", "parachute")` returns `"para"`.)
$(T2 endsWith,
`endsWith("rocks", "ks")` returns `true`.)
+$(T2 extrema, `extrema([2, 1, 3, 5, 4])` returns `[1, 5]`.)
$(T2 find,
`find("hello world", "or")` returns `"orld"` using linear search.
(For binary search refer to $(REF SortedRange, std,range).))
See_Also:
- $(LREF maxElement), $(REF min, std,algorithm,comparison), $(LREF minCount),
+ $(LREF extrema), $(LREF maxElement), $(REF min, std,algorithm,comparison), $(LREF minCount),
$(LREF minIndex), $(LREF minPos)
*/
auto minElement(alias map = (a => a), Range)(Range r)
See_Also:
- $(LREF minElement), $(REF max, std,algorithm,comparison), $(LREF maxCount),
+ $(LREF extrema), $(LREF minElement), $(REF max, std,algorithm,comparison), $(LREF maxCount),
$(LREF maxIndex), $(LREF maxPos)
*/
auto maxElement(alias map = (a => a), Range)(Range r)
assert(maxElement(arr) == S(145));
}
+/** Returns an array of the minimum and maximum element in `r`.
+ * Performs `< 3n/2` comparisons, unlike the naive `< 2n`.
+ * Params:
+ * r = The range to traverse.
+ */
+// TODO alias map = a => a
+ElementType!Range[2] extrema(Range)(Range r)
+if (isInputRange!Range && !isInfinite!Range)
+in (!r.empty)
+{
+ static if (isRandomAccessRange!Range && hasLength!Range)
+ {
+ if (r.length == 1)
+ return [r[0], r[0]];
+
+ typeof(return) result;
+ size_t i;
+ if (r.length & 1) // odd
+ {
+ result = [r[0], r[0]];
+ i = 1;
+ }
+ else
+ {
+ result = (r[0] < r[1]) ? [r[0], r[1]] : [r[1], r[0]];
+ i = 2;
+ }
+ // iterate pairs
+ const imax = r.length;
+ for (; i != imax; i += 2)
+ {
+ // save work
+ if (r[i] < r[i+1])
+ {
+ if (r[i] < result[0])
+ result[0] = r[i];
+ if (r[i+1] > result[1])
+ result[1] = r[i+1];
+ }
+ else
+ {
+ if (r[i+1] < result[0])
+ result[0] = r[i+1];
+ if (r[i] > result[1])
+ result[1] = r[i];
+ }
+ }
+ return result;
+ }
+ else
+ {
+ auto first = r.front;
+ r.popFront;
+ if (r.empty)
+ return [first, first];
+
+ typeof(return) result = (first < r.front) ? [first, r.front] : [r.front, first];
+ // iterate pairs
+ while (true)
+ {
+ r.popFront;
+ if (r.empty)
+ return result;
+ first = r.front;
+ r.popFront;
+ if (r.empty)
+ {
+ if (first < result[0])
+ result[0] = first;
+ else if (first > result[1])
+ result[1] = first;
+ return result;
+ }
+ // save work
+ if (first < r.front)
+ {
+ if (first < result[0])
+ result[0] = first;
+ if (r.front > result[1])
+ result[1] = r.front;
+ }
+ else
+ {
+ if (r.front < result[0])
+ result[0] = r.front;
+ if (first > result[1])
+ result[1] = first;
+ }
+ }
+ }
+}
+
+///
+@safe unittest
+{
+ assert(extrema([5,2,9,4,1]) == [1, 9]);
+}
+
+@safe unittest
+{
+ assert(extrema([8,3,7,4,9]) == [3, 9]);
+ assert(extrema([1,5,3,2]) == [1, 5]);
+ assert(extrema([2,3,3,2]) == [2, 3]);
+
+ import std.range;
+ assert(iota(2, 5).extrema == [2, 4]);
+ assert(iota(3, 7).retro.extrema == [3, 6]);
+
+ import std.internal.test.dummyrange;
+ foreach (DummyType; AllDummyRanges)
+ {
+ DummyType d;
+ assert(d.extrema == [1, 10]);
+ }
+
+ version (StdRandomTests)
+ foreach (i; 0 .. 1000)
+ {
+ import std.random;
+ auto arr = generate!(() => uniform(0, 100)).takeExactly(uniform(1, 10)).array;
+ auto result = arr.extrema;
+ assert(result[0] == arr.minElement);
+ assert(result[1] == arr.maxElement);
+ }
+}
+
// minPos
/**
Computes a subrange of `range` starting at the first occurrence of `range`'s
// POSIX API declarations.
version (Posix)
{
- version (Darwin)
- {
- extern(C) char*** _NSGetEnviron() nothrow;
- const(char**) getEnvironPtr() @trusted
- {
- return *_NSGetEnviron;
- }
- }
- else
- {
- // Made available by the C runtime:
- extern(C) extern __gshared const char** environ;
- const(char**) getEnvironPtr() @trusted
- {
- return environ;
- }
- }
+ import core.sys.posix.unistd : getEnvironPtr = environ;
@system unittest
{
}
// Execute program.
- core.sys.posix.unistd.execve(argz[0], argz.ptr, envz);
+ core.sys.posix.unistd.execve(argz[0], argz.ptr, envz is null ? getEnvironPtr : envz);
// If execution fails, exit as quickly as possible.
abortOnError(forkPipeOut, InternalError.exec, .errno);
// on the form "name=value", optionally adding those of the current process'
// environment strings that are not present in childEnv. If the parent's
// environment should be inherited without modification, this function
-// returns environ directly.
+// returns null.
version (Posix)
private const(char*)* createEnv(const string[string] childEnv,
bool mergeWithParentEnv)
auto environ = getEnvironPtr;
if (mergeWithParentEnv)
{
- if (childEnv.length == 0) return environ;
+ if (childEnv.length == 0) return null;
while (environ[parentEnvLength] != null) ++parentEnvLength;
}
assert(e1 != null && *e1 == null);
auto e2 = createEnv(null, true);
- assert(e2 != null);
- int i = 0;
- auto environ = getEnvironPtr;
- for (; environ[i] != null; ++i)
- {
- assert(e2[i] != null);
- import core.stdc.string : strcmp;
- assert(strcmp(e2[i], environ[i]) == 0);
- }
- assert(e2[i] == null);
+ assert(e2 == null);
auto e3 = createEnv(["foo" : "bar", "hello" : "world"], false);
assert(e3 != null && e3[0] != null && e3[1] != null && e3[2] == null);
private struct ByLineCopy(Char, Terminator)
{
private:
- import std.typecons : SafeRefCounted, RefCountedAutoInitialize;
+ import std.typecons : borrow, RefCountedAutoInitialize, SafeRefCounted;
/* Ref-counting stops the source range's ByLineCopyImpl
* from getting out of sync after the range is copied, e.g.
impl = Impl(f, kt, terminator);
}
- @property bool empty()
+ /* Verifiably `@safe` when built with -preview=DIP1000. */
+ @property bool empty() @trusted
{
- return impl.refCountedPayload.empty;
+ // Using `ref` is actually necessary here.
+ return impl.borrow!((ref i) => i.empty);
}
- @property Char[] front()
+ /* Verifiably `@safe` when built with -preview=DIP1000. */
+ @property Char[] front() @trusted
{
- return impl.refCountedPayload.front;
+ // Using `ref` is likely optional here.
+ return impl.borrow!((ref i) => i.front);
}
- void popFront()
+ /* Verifiably `@safe` when built with -preview=DIP1000. */
+ void popFront() @trusted
{
- impl.refCountedPayload.popFront();
+ impl.borrow!((ref i) => i.popFront());
}
}
assert(!file.isOpen);
}
- @system unittest
+ @safe unittest
{
static import std.file;
auto deleteme = testFilename();
auto myLines = lines(f);
foreach (string line; myLines)
continue;
+ }
+
- auto myByLineCopy = f.byLineCopy; // but cannot safely iterate yet
- /*
- still `@system`:
- - cannot call `@system` function `std.stdio.File.ByLineCopy!(immutable(char), char).ByLineCopy.empty`
- - cannot call `@system` function `std.stdio.File.ByLineCopy!(immutable(char), char).ByLineCopy.popFront`
- - cannot call `@system` function `std.stdio.File.ByLineCopy!(immutable(char), char).ByLineCopy.front`
- */
- //foreach (line; myByLineCopy)
- // continue;
+ {
+ auto f = File(deleteMe, "r");
+ scope(exit) { f.close(); }
+
+ auto myByLineCopy = f.byLineCopy;
+ foreach (line; myByLineCopy)
+ continue;
}
}