if (global.params.useAssert == CHECKENABLEon)
VersionCondition::addPredefinedGlobalIdent ("assert");
+ if (global.params.useIn == CHECKENABLEon)
+ VersionCondition::addPredefinedGlobalIdent("D_PreConditions");
+
+ if (global.params.useOut == CHECKENABLEon)
+ VersionCondition::addPredefinedGlobalIdent("D_PostConditions");
+
+ if (global.params.useInvariants == CHECKENABLEon)
+ VersionCondition::addPredefinedGlobalIdent("D_Invariants");
+
if (global.params.useArrayBounds == CHECKENABLEoff)
VersionCondition::addPredefinedGlobalIdent ("D_NoBoundsChecks");
build_address (targ));
}
- /* Type `noreturn` is a terminator, as no other arguments can possibly
- be evaluated after it. */
- if (TREE_TYPE (targ) == noreturn_type_node)
+ /* Type `noreturn` is a terminator, as no other arguments can possibly
+ be evaluated after it. */
+ if (TREE_TYPE (targ) == noreturn_type_node)
noreturn_call = true;
vec_safe_push (args, targ);
DECL_NONADDRESSABLE_P (field) = !TREE_ADDRESSABLE (vsym);
TREE_THIS_VOLATILE (field) = TREE_THIS_VOLATILE (vsym);
- /* Can't do nrvo if the variable is put in a frame. */
- if (fd->nrvo_can && fd->nrvo_var == v)
- fd->nrvo_can = 0;
+ if (DECL_LANG_NRVO (vsym))
+ {
+ /* Store the nrvo variable in the frame by reference. */
+ TREE_TYPE (field) = build_reference_type (TREE_TYPE (field));
+
+ /* Can't do nrvo if the variable is put in a closure, since what the
+ return slot points to may no longer exist. */
+ gcc_assert (!FRAMEINFO_IS_CLOSURE (ffi));
+ }
if (FRAMEINFO_IS_CLOSURE (ffi))
{
for (size_t i = 0; i < fd->closureVars.length; i++)
{
VarDeclaration *v = fd->closureVars[i];
+ tree vsym = get_symbol_decl (v);
- if (!v->isParameter ())
+ if (TREE_CODE (vsym) != PARM_DECL && !DECL_LANG_NRVO (vsym))
continue;
- tree vsym = get_symbol_decl (v);
-
tree field = component_ref (decl_ref, DECL_LANG_FRAME_FIELD (vsym));
+
+ /* Variable is an alias for the NRVO slot, store the reference. */
+ if (DECL_LANG_NRVO (vsym))
+ vsym = build_address (DECL_LANG_NRVO (vsym));
+
tree expr = modify_expr (field, vsym);
add_stmt (expr);
}
/* True if the decl comes from a template instance. */
#define DECL_INSTANTIATED(NODE) \
- (DECL_LANG_FLAG_1 (VAR_OR_FUNCTION_DECL_CHECK (NODE)))
+ (DECL_LANG_FLAG_2 (VAR_OR_FUNCTION_DECL_CHECK (NODE)))
enum d_tree_index
{
extern tree build_bounds_slice_condition (SliceExp *, tree, tree, tree);
extern bool array_bounds_check (void);
extern bool checkaction_trap_p (void);
-extern tree bind_expr (tree, tree);
extern TypeFunction *get_function_type (Type *);
extern bool call_by_alias_p (FuncDeclaration *, FuncDeclaration *);
extern tree d_build_call_expr (FuncDeclaration *, tree, Expressions *);
return;
}
- if (d->semantic3Errors)
+ if (d->hasSemantic3Errors ())
return;
if (d->isNested ())
break;
/* Parent failed to compile, but errors were gagged. */
- if (fdp->semantic3Errors)
+ if (fdp->hasSemantic3Errors ())
return;
}
}
}
}
- /* May change cfun->static_chain. */
- build_closure (d);
-
- if (d->vresult)
- declare_local_var (d->vresult);
-
- if (d->v_argptr)
- push_stmt_list ();
-
/* Named return value optimisation support for D.
Implemented by overriding all the RETURN_EXPRs and replacing all
occurrences of VAR with the RESULT_DECL for the function.
else
d->shidden = resdecl;
- if (d->nrvo_can && d->nrvo_var)
+ if (d->isNRVO () && d->nrvo_var)
{
tree var = get_symbol_decl (d->nrvo_var);
}
}
+ /* May change cfun->static_chain. */
+ build_closure (d);
+
+ if (d->vresult)
+ declare_local_var (d->vresult);
+
+ if (d->v_argptr)
+ push_stmt_list ();
+
build_function_body (d);
/* Initialize the _argptr variable. */
/* In [pragma/crtctor], Annotates a function so it is run after the C
runtime library is initialized and before the D runtime library is
initialized. */
- if (fd->isCrtCtorDtor == 1)
+ if (fd->isCrtCtor ())
{
DECL_STATIC_CONSTRUCTOR (decl->csym) = 1;
decl_init_priority_insert (decl->csym, DEFAULT_INIT_PRIORITY);
}
- else if (fd->isCrtCtorDtor == 2)
+ else if (fd->isCrtDtor ())
{
DECL_STATIC_DESTRUCTOR (decl->csym) = 1;
decl_fini_priority_insert (decl->csym, DEFAULT_INIT_PRIORITY);
- }
+ }
/* Function was declared `naked'. */
- if (fd->naked)
+ if (fd->isNaked ())
{
insert_decl_attribute (decl->csym, "naked");
DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl->csym) = 1;
}
/* Mark compiler generated functions as artificial. */
- if (fd->generated)
+ if (fd->isGenerated ())
DECL_ARTIFICIAL (decl->csym) = 1;
/* Ensure and require contracts are lexically nested in the function they
if (vd == NULL || fd == NULL)
return t;
- /* Get the named return value. */
- if (DECL_LANG_NRVO (t))
- return DECL_LANG_NRVO (t);
-
/* Get the closure holding the var decl. */
if (DECL_LANG_FRAME_FIELD (t))
{
FuncDeclaration *parent = vd->toParent2 ()->isFuncDeclaration ();
tree frame_ref = get_framedecl (fd, parent);
- return component_ref (build_deref (frame_ref),
- DECL_LANG_FRAME_FIELD (t));
+ tree field = component_ref (build_deref (frame_ref),
+ DECL_LANG_FRAME_FIELD (t));
+ /* Frame field can also be a reference to the DECL_RESULT of a function.
+ Dereference it to get the value. */
+ if (DECL_LANG_NRVO (t))
+ field = build_deref (field);
+
+ return field;
}
+ /* Get the named return value. */
+ if (DECL_LANG_NRVO (t))
+ return DECL_LANG_NRVO (t);
+
/* Get the non-local `this' value by going through parent link
of nested classes, this routine pretty much undoes what
getRightThis in the frontend removes from codegen. */
-2503f17e5767bc4fcd0cf3889c90fa0415b0edaa
+47871363d804f54b29ccfd444b082c19716c2301
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
-v2.099.0
+v2.099.1-beta.1
if (overflow) assert(0);
// Skip no-op for noreturn without custom aligment
- if (memsize != 0 || !alignment.isDefault())
+ if (memalignsize != 0 || !alignment.isDefault())
alignmember(alignment, memalignsize, &ofs);
uint memoffset = ofs;
* definitions exposed some issues in their TypeInfo generation in DMD.
* Related PR: https://github.com/dlang/dmd/pull/13312
*/
- if (semanticRun == PASS.init && !isInterfaceDeclaration())
+ if (semanticRun == PASS.initial && !isInterfaceDeclaration())
{
auto stc = storage_class;
if (_scope)
extern (C++) static int fp(Dsymbol s, void* ctxt)
{
auto f = s.isCtorDeclaration();
- if (f && f.semanticRun == PASS.init)
+ if (f && f.semanticRun == PASS.initial)
f.dsymbolSemantic(null);
return 0;
}
if (tthis && ad.aliasthis.sym.needThis())
{
- if (e.op == EXP.variable)
+ if (auto ve = e.isVarExp())
{
- if (auto fd = (cast(VarExp)e).var.isFuncDeclaration())
+ if (auto fd = ve.var.isFuncDeclaration())
{
// https://issues.dlang.org/show_bug.cgi?id=13009
// Support better match for the overloaded alias this.
{
if (isUnaArrayOp(e.op))
{
- return isArrayOpValid((cast(UnaExp)e).e1);
+ return isArrayOpValid(e.isUnaExp().e1);
}
if (isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || e.op == EXP.assign)
{
- BinExp be = cast(BinExp)e;
+ BinExp be = e.isBinExp();
return isArrayOpValid(be.e1) && isArrayOpValid(be.e2);
}
if (e.op == EXP.construct)
{
- BinExp be = cast(BinExp)e;
+ BinExp be = e.isBinExp();
return be.e1.op == EXP.slice && isArrayOpValid(be.e2);
}
// if (e.op == EXP.call)
bool isNonAssignmentArrayOp(Expression e)
{
if (e.op == EXP.slice)
- return isNonAssignmentArrayOp((cast(SliceExp)e).e1);
+ return isNonAssignmentArrayOp(e.isSliceExp().e1);
Type tb = e.type.toBasetype();
if (tb.ty == Tarray || tb.ty == Tsarray)
return e.e1.modifiableLvalue(sc, e.e1);
}
- return arrayOp(cast(BinExp)e, sc);
+ return arrayOp(e.isBinExp(), sc);
}
/******************************************
alias Ensures = Array!(Ensure);
alias Designators = Array!(Designator);
alias DesigInits = Array!(DesigInit);
-
typedef Array<struct Designator> Designators;
typedef Array<struct DesigInit> DesigInits;
-
result = BE.halt;
return;
}
- if (s.exp.op == EXP.assert_)
+ if (AssertExp a = s.exp.isAssertExp())
{
- AssertExp a = cast(AssertExp)s.exp;
if (a.e1.toBool().hasValue(false)) // if it's an assert(0)
{
result = BE.halt;
if (!(s.stc & STC.nothrow_))
{
if (mustNotThrow && !(s.stc & STC.nothrow_))
- s.deprecation("`asm` statement is assumed to throw - mark it with `nothrow` if it does not");
+ s.error("`asm` statement is assumed to throw - mark it with `nothrow` if it does not");
else
result |= BE.throw_;
}
auto tf = new TypeFunction(ParameterList(fparams), sd.handleType(), LINK.d, stc | STC.ref_);
auto fop = new FuncDeclaration(declLoc, Loc.initial, Id.assign, stc, tf);
fop.storage_class |= STC.inference;
- fop.generated = true;
+ fop.flags |= FUNCFLAG.generated;
Expression e;
if (stc & STC.disable)
{
tf = tf.addSTC(STC.const_).toTypeFunction();
Identifier id = Id.xopEquals;
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf);
- fop.generated = true;
+ fop.flags |= FUNCFLAG.generated;
fop.parent = sd;
Expression e1 = new IdentifierExp(loc, Id.This);
Expression e2 = new IdentifierExp(loc, Id.p);
switch (e.op)
{
case EXP.overloadSet:
- s = (cast(OverExp)e).vars;
+ s = e.isOverExp().vars;
break;
case EXP.scope_:
- s = (cast(ScopeExp)e).sds;
+ s = e.isScopeExp().sds;
break;
case EXP.variable:
- s = (cast(VarExp)e).var;
+ s = e.isVarExp().var;
break;
default:
break;
tf = tf.addSTC(STC.const_).toTypeFunction();
Identifier id = Id.xopCmp;
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf);
- fop.generated = true;
+ fop.flags |= FUNCFLAG.generated;
fop.parent = sd;
Expression e1 = new IdentifierExp(loc, Id.This);
Expression e2 = new IdentifierExp(loc, Id.p);
auto tf = new TypeFunction(ParameterList(parameters), Type.thash_t, LINK.d, STC.nothrow_ | STC.trusted);
Identifier id = Id.xtoHash;
auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf);
- fop.generated = true;
+ fop.flags |= FUNCFLAG.generated;
/* Do memberwise hashing.
*
if (stc & STC.safe)
stc = (stc & ~STC.safe) | STC.trusted;
- ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t),
+ SliceExp se = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type.tsize_t),
new IntegerExp(loc, n, Type.tsize_t));
// Prevent redundant bounds check
- (cast(SliceExp)ex).upperIsInBounds = true;
- (cast(SliceExp)ex).lowerIsLessThanUpper = true;
+ se.upperIsInBounds = true;
+ se.lowerIsLessThanUpper = true;
- ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), ex);
+ ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se);
}
e = Expression.combine(ex, e); // combine in reverse order
}
{
//printf("Building __fieldDtor(), %s\n", e.toChars());
auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__fieldDtor);
- dd.generated = true;
+ dd.flags |= FUNCFLAG.generated;
dd.storage_class |= STC.inference;
dd.fbody = new ExpStatement(loc, e);
ad.members.push(dd);
e = Expression.combine(e, ce);
}
auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__aggrDtor);
- dd.generated = true;
+ dd.flags |= FUNCFLAG.generated;
dd.storage_class |= STC.inference;
dd.fbody = new ExpStatement(loc, e);
ad.members.push(dd);
stmts.push(new ExpStatement(loc, call));
stmts.push(new ReturnStatement(loc, new CastExp(loc, new ThisExp(loc), Type.tvoidptr)));
func.fbody = new CompoundStatement(loc, stmts);
- func.generated = true;
+ func.flags |= FUNCFLAG.generated;
auto sc2 = sc.push();
sc2.stc &= ~STC.static_; // not a static destructor
auto call = new CallExp(dtor.loc, dtor, null);
call.directcall = true; // non-virtual call Class.__dtor();
func.fbody = new ExpStatement(dtor.loc, call);
- func.generated = true;
+ func.flags |= FUNCFLAG.generated;
func.storage_class |= STC.inference;
auto sc2 = sc.push();
//printf("Building __fieldPostBlit()\n");
checkShared();
auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__fieldPostblit);
- dd.generated = true;
+ dd.flags |= FUNCFLAG.generated;
dd.storage_class |= STC.inference | STC.scope_;
dd.fbody = (stc & STC.disable) ? null : new CompoundStatement(loc, postblitCalls);
sd.postblits.shift(dd);
checkShared();
auto dd = new PostBlitDeclaration(declLoc, Loc.initial, stc, Id.__aggrPostblit);
- dd.generated = true;
+ dd.flags |= FUNCFLAG.generated;
dd.storage_class |= STC.inference;
dd.fbody = new ExpStatement(loc, e);
sd.members.push(dd);
auto ccd = new CtorDeclaration(sd.loc, Loc.initial, STC.ref_, tf, true);
ccd.storage_class |= funcStc;
ccd.storage_class |= STC.inference;
- ccd.generated = true;
+ ccd.flags |= FUNCFLAG.generated;
return ccd;
}
}
return true;
}
-
-
}
emplaceExp!(ComplexExp)(&ue, loc, v, type);
}
- else if (e1.op == EXP.symbolOffset)
+ else if (SymOffExp soe = e1.isSymOffExp())
{
- SymOffExp soe = cast(SymOffExp)e1;
emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e2.toInteger());
ue.exp().type = type;
}
- else if (e2.op == EXP.symbolOffset)
+ else if (SymOffExp soe = e2.isSymOffExp())
{
- SymOffExp soe = cast(SymOffExp)e2;
emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger());
ue.exp().type = type;
}
}
emplaceExp!(ComplexExp)(&ue, loc, v, type);
}
- else if (e1.op == EXP.symbolOffset)
+ else if (SymOffExp soe = e1.isSymOffExp())
{
- SymOffExp soe = cast(SymOffExp)e1;
emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset - e2.toInteger());
ue.exp().type = type;
}
{
if (e2.op == EXP.null_)
cmp = 1;
- else if (e2.op == EXP.string_)
+ else if (StringExp es2 = e2.isStringExp())
{
- StringExp es2 = cast(StringExp)e2;
cmp = (0 == es2.len);
}
- else if (e2.op == EXP.arrayLiteral)
+ else if (ArrayLiteralExp es2 = e2.isArrayLiteralExp())
{
- ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
cmp = !es2.elements || (0 == es2.elements.dim);
}
else
}
else if (e2.op == EXP.null_)
{
- if (e1.op == EXP.string_)
+ if (StringExp es1 = e1.isStringExp())
{
- StringExp es1 = cast(StringExp)e1;
cmp = (0 == es1.len);
}
- else if (e1.op == EXP.arrayLiteral)
+ else if (ArrayLiteralExp es1 = e1.isArrayLiteralExp())
{
- ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
cmp = !es1.elements || (0 == es1.elements.dim);
}
else
}
else if (e1.op == EXP.string_ && e2.op == EXP.string_)
{
- StringExp es1 = cast(StringExp)e1;
- StringExp es2 = cast(StringExp)e2;
+ StringExp es1 = e1.isStringExp();
+ StringExp es2 = e2.isStringExp();
if (es1.sz != es2.sz)
{
assert(global.errors);
}
else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral)
{
- ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
- ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
+ ArrayLiteralExp es1 = e1.isArrayLiteralExp();
+ ArrayLiteralExp es2 = e2.isArrayLiteralExp();
if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim))
cmp = 1; // both arrays are empty
else if (!es1.elements || !es2.elements)
else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral)
{
Lsa:
- StringExp es1 = cast(StringExp)e1;
- ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
+ StringExp es1 = e1.isStringExp();
+ ArrayLiteralExp es2 = e2.isArrayLiteralExp();
size_t dim1 = es1.len;
size_t dim2 = es2.elements ? es2.elements.dim : 0;
if (dim1 != dim2)
}
else if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
{
- StructLiteralExp es1 = cast(StructLiteralExp)e1;
- StructLiteralExp es2 = cast(StructLiteralExp)e2;
+ StructLiteralExp es1 = e1.isStructLiteralExp();
+ StructLiteralExp es2 = e2.isStructLiteralExp();
if (es1.sd != es2.sd)
cmp = 0;
else if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim))
}
else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
{
- SymOffExp es1 = cast(SymOffExp)e1;
- SymOffExp es2 = cast(SymOffExp)e2;
+ SymOffExp es1 = e1.isSymOffExp();
+ SymOffExp es2 = e2.isSymOffExp();
cmp = (es1.var == es2.var && es1.offset == es2.offset);
}
else
//printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
if (e1.op == EXP.string_ && e2.op == EXP.string_)
{
- StringExp es1 = cast(StringExp)e1;
- StringExp es2 = cast(StringExp)e2;
+ StringExp es1 = e1.isStringExp();
+ StringExp es2 = e2.isStringExp();
size_t sz = es1.sz;
assert(sz == es2.sz);
size_t len = es1.len;
}
if (e1.op == EXP.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to))
{
- Expression ex = (cast(VectorExp)e1).e1;
+ Expression ex = e1.isVectorExp().e1;
emplaceExp!(UnionExp)(&ue, ex);
return ue;
}
{
UnionExp ue = void;
Loc loc = e1.loc;
- if (e1.op == EXP.string_)
+ if (StringExp es1 = e1.isStringExp())
{
- StringExp es1 = cast(StringExp)e1;
emplaceExp!(IntegerExp)(&ue, loc, es1.len, type);
}
- else if (e1.op == EXP.arrayLiteral)
+ else if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
{
- ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
size_t dim = ale.elements ? ale.elements.dim : 0;
emplaceExp!(IntegerExp)(&ue, loc, dim, type);
}
- else if (e1.op == EXP.assocArrayLiteral)
+ else if (AssocArrayLiteralExp ale = e1.isAssocArrayLiteralExp)
{
- AssocArrayLiteralExp ale = cast(AssocArrayLiteralExp)e1;
size_t dim = ale.keys.dim;
emplaceExp!(IntegerExp)(&ue, loc, dim, type);
}
assert(e1.type);
if (e1.op == EXP.string_ && e2.op == EXP.int64)
{
- StringExp es1 = cast(StringExp)e1;
+ StringExp es1 = e1.isStringExp();
uinteger_t i = e2.toInteger();
if (i >= es1.len)
{
e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length);
emplaceExp!(ErrorExp)(&ue);
}
- else if (e1.op == EXP.arrayLiteral)
+ else if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
{
- ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
auto e = ale[cast(size_t)i];
e.type = type;
e.loc = loc;
else if (e1.type.toBasetype().ty == Tarray && e2.op == EXP.int64)
{
uinteger_t i = e2.toInteger();
- if (e1.op == EXP.arrayLiteral)
+ if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
{
- ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
if (i >= ale.elements.dim)
{
e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), cast(ulong) ale.elements.dim);
else
cantExp(ue);
}
- else if (e1.op == EXP.assocArrayLiteral)
+ else if (AssocArrayLiteralExp ae = e1.isAssocArrayLiteralExp())
{
- AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e1;
/* Search the keys backwards, in case there are duplicate keys
*/
for (size_t i = ae.keys.dim; i;)
if (e1.op == EXP.string_ && lwr.op == EXP.int64 && upr.op == EXP.int64)
{
- StringExp es1 = cast(StringExp)e1;
+ StringExp es1 = e1.isStringExp();
const uinteger_t ilwr = lwr.toInteger();
const uinteger_t iupr = upr.toInteger();
if (sliceBoundsCheck(0, es1.len, ilwr, iupr))
const data1 = es1.peekData();
memcpy(s, data1.ptr + ilwr * sz, len * sz);
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz, es1.postfix);
- StringExp es = cast(StringExp)ue.exp();
+ StringExp es = ue.exp().isStringExp();
es.committed = es1.committed;
es.type = type;
}
}
else if (e1.op == EXP.arrayLiteral && lwr.op == EXP.int64 && upr.op == EXP.int64 && !hasSideEffect(e1))
{
- ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
+ ArrayLiteralExp es1 = e1.isArrayLiteralExp();
const uinteger_t ilwr = lwr.toInteger();
const uinteger_t iupr = upr.toInteger();
if (sliceBoundsCheck(0, es1.elements.dim, ilwr, iupr))
}
}
- if (e1.op == EXP.arrayLiteral)
- append(cast(ArrayLiteralExp)e1);
+ if (auto ale = e1.isArrayLiteralExp())
+ append(ale);
else
elems.push(e1);
if (e2)
{
- if (e2.op == EXP.arrayLiteral)
- append(cast(ArrayLiteralExp)e2);
+ if (auto ale = e2.isArrayLiteralExp())
+ append(ale);
else
elems.push(e2);
}
else
utf_encode(sz, s, cast(dchar)v);
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
- StringExp es = cast(StringExp)ue.exp();
+ StringExp es = ue.exp().isStringExp();
es.type = type;
es.committed = 1;
}
else if (e1.op == EXP.string_ && e2.op == EXP.string_)
{
// Concatenate the strings
- StringExp es1 = cast(StringExp)e1;
- StringExp es2 = cast(StringExp)e2;
+ StringExp es1 = e1.isStringExp();
+ StringExp es2 = e2.isStringExp();
size_t len = es1.len + es2.len;
ubyte sz = es1.sz;
if (sz != es2.sz)
memcpy(cast(char*)s, data1.ptr, es1.len * sz);
memcpy(cast(char*)s + es1.len * sz, data2.ptr, es2.len * sz);
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
- StringExp es = cast(StringExp)ue.exp();
+ StringExp es = ue.exp().isStringExp();
es.committed = es1.committed | es2.committed;
es.type = type;
assert(ue.exp().type);
else if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
{
// [chars] ~ string --> [chars]
- StringExp es = cast(StringExp)e2;
- ArrayLiteralExp ea = cast(ArrayLiteralExp)e1;
+ StringExp es = e2.isStringExp();
+ ArrayLiteralExp ea = e1.isArrayLiteralExp();
size_t len = es.len + ea.elements.dim;
auto elems = new Expressions(len);
for (size_t i = 0; i < ea.elements.dim; ++i)
(*elems)[i] = ea[i];
}
emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
- ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp();
+ ArrayLiteralExp dest = ue.exp().isArrayLiteralExp();
sliceAssignArrayLiteralFromString(dest, es, ea.elements.dim);
assert(ue.exp().type);
return ue;
else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral())
{
// string ~ [chars] --> [chars]
- StringExp es = cast(StringExp)e1;
- ArrayLiteralExp ea = cast(ArrayLiteralExp)e2;
+ StringExp es = e1.isStringExp();
+ ArrayLiteralExp ea = e2.isArrayLiteralExp();
size_t len = es.len + ea.elements.dim;
auto elems = new Expressions(len);
for (size_t i = 0; i < ea.elements.dim; ++i)
(*elems)[es.len + i] = ea[i];
}
emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
- ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp();
+ ArrayLiteralExp dest = ue.exp().isArrayLiteralExp();
sliceAssignArrayLiteralFromString(dest, es, 0);
assert(ue.exp().type);
return ue;
else if (e1.op == EXP.string_ && e2.op == EXP.int64)
{
// string ~ char --> string
- StringExp es1 = cast(StringExp)e1;
+ StringExp es1 = e1.isStringExp();
StringExp es;
const sz = es1.sz;
dinteger_t v = e2.toInteger();
else
utf_encode(sz, cast(char*)s + (sz * es1.len), cast(dchar)v);
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
- es = cast(StringExp)ue.exp();
+ es = ue.exp().isStringExp();
es.committed = es1.committed;
es.type = type;
assert(ue.exp().type);
// [w|d]?char ~ string --> string
// We assume that we only ever prepend one char of the same type
// (wchar,dchar) as the string's characters.
- StringExp es2 = cast(StringExp)e2;
+ StringExp es2 = e2.isStringExp();
const len = 1 + es2.len;
const sz = es2.sz;
dinteger_t v = e1.toInteger();
const data2 = es2.peekData();
memcpy(cast(char*)s + sz, data2.ptr, data2.length);
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
- StringExp es = cast(StringExp)ue.exp();
+ StringExp es = ue.exp().isStringExp();
es.sz = sz;
es.committed = es2.committed;
es.type = type;
}
if (!e.type.equals(type))
{
- StringExp se = cast(StringExp)e.copy();
+ StringExp se = e.copy().isStringExp();
e = se.castTo(null, type);
emplaceExp!(UnionExp)(&ue, e);
e = ue.exp();
{
//printf("Ptr(e1 = %s)\n", e1.toChars());
UnionExp ue = void;
- if (e1.op == EXP.add)
+ if (AddExp ae = e1.isAddExp())
{
- AddExp ae = cast(AddExp)e1;
- if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
+ if (AddrExp ade = ae.e1.isAddrExp())
{
- AddrExp ade = cast(AddrExp)ae.e1;
- if (ade.e1.op == EXP.structLiteral)
- {
- StructLiteralExp se = cast(StructLiteralExp)ade.e1;
- uint offset = cast(uint)ae.e2.toInteger();
- Expression e = se.getField(type, offset);
- if (e)
+ if (ae.e2.op == EXP.int64)
+ if (StructLiteralExp se = ade.e1.isStructLiteralExp())
{
- emplaceExp!(UnionExp)(&ue, e);
- return ue;
+ uint offset = cast(uint)ae.e2.toInteger();
+ Expression e = se.getField(type, offset);
+ if (e)
+ {
+ emplaceExp!(UnionExp)(&ue, e);
+ return ue;
+ }
}
- }
}
}
cantExp(ue);
e = new AST.DotIdExp(loc, e, Id.__sizeof);
break;
}
+ // must be an expression
+ e = cparsePrimaryExp();
+ e = new AST.DotIdExp(loc, e, Id.__sizeof);
+ break;
}
+
e = cparseUnaryExp();
e = new AST.DotIdExp(loc, e, Id.__sizeof);
break;
{
if (token.value == TOK.leftParenthesis)
{
+ //printf("cparseCastExp()\n");
auto tk = peek(&token);
- if (tk.value == TOK.identifier &&
- !isTypedef(tk.ident) &&
- peek(tk).value == TOK.rightParenthesis)
+ bool iscast;
+ bool isexp;
+ if (tk.value == TOK.identifier)
+ {
+ iscast = isTypedef(tk.ident);
+ isexp = !iscast;
+ }
+ if (isexp)
{
// ( identifier ) is an expression
return cparseUnaryExp();
auto ce = new AST.CompoundLiteralExp(loc, t, ci);
return cparsePostfixOperators(ce);
}
- else if (t.isTypeIdentifier() &&
- token.value == TOK.leftParenthesis &&
- !isCastExpression(pt))
+
+ if (iscast)
+ {
+ // ( type-name ) cast-expression
+ auto ce = cparseCastExp();
+ return new AST.CastExp(loc, ce, t);
+ }
+
+ if (t.isTypeIdentifier() &&
+ isexp &&
+ token.value == TOK.leftParenthesis &&
+ !isCastExpression(pt))
{
/* (t)(...)... might be a cast expression or a function call,
* with different grammars: a cast would be cparseCastExp(),
AST.Expression e = new AST.CallExp(loc, ie, cparseArguments());
return cparsePostfixOperators(e);
}
- else
- {
- // ( type-name ) cast-expression
- auto ce = cparseCastExp();
- return new AST.CastExp(loc, ce, t);
- }
+
+ // ( type-name ) cast-expression
+ auto ce = cparseCastExp();
+ return new AST.CastExp(loc, ce, t);
}
}
return cparseUnaryExp();
symbols.push(stag);
if (tt.tok == TOK.enum_)
{
- if (!stag.members)
- error(tt.loc, "`enum %s` has no members", stag.toChars());
isalias = false;
s = new AST.AliasDeclaration(token.loc, id, stag);
}
const idx = previd.toString();
if (idx.length > 2 && idx[0] == '_' && idx[1] == '_') // leading double underscore
importBuiltins = true; // probably one of those compiler extensions
- t = new AST.TypeIdentifier(loc, previd);
+ t = null;
+ if (scw & SCW.xtypedef)
+ {
+ /* Punch through to what the typedef is, to support things like:
+ * typedef T* T;
+ */
+ auto pt = lookupTypedef(previd);
+ if (pt && *pt) // if previd is a known typedef
+ t = *pt;
+ }
+
+ if (!t)
+ t = new AST.TypeIdentifier(loc, previd);
break;
}
scan(&n);
if (n.value == TOK.identifier && n.ident == Id.pack)
return pragmaPack(loc);
- skipToNextLine();
+ if (n.value != TOK.endOfLine)
+ skipToNextLine();
}
/*********
if (n.value != TOK.leftParenthesis)
{
error(loc, "left parenthesis expected to follow `#pragma pack`");
- skipToNextLine();
+ if (n.value != TOK.endOfLine)
+ skipToNextLine();
return;
}
{
error(loc, "right parenthesis expected to close `#pragma pack(`");
}
- skipToNextLine();
+ if (n.value != TOK.endOfLine)
+ skipToNextLine();
}
void setPackAlign(ref const Token t)
}
error(loc, "unrecognized `#pragma pack(%s)`", n.toChars());
- skipToNextLine();
+ if (n.value != TOK.endOfLine)
+ skipToNextLine();
}
//}
switch (e.op)
{
case EXP.arrayLiteral:
- return (cast(ArrayLiteralExp)e).ownedByCtfe == OwnedBy.code;
+ return e.isArrayLiteralExp().ownedByCtfe == OwnedBy.code;
case EXP.assocArrayLiteral:
- return (cast(AssocArrayLiteralExp)e).ownedByCtfe == OwnedBy.code;
+ return e.isAssocArrayLiteralExp().ownedByCtfe == OwnedBy.code;
case EXP.structLiteral:
- return (cast(StructLiteralExp)e).ownedByCtfe == OwnedBy.code;
+ return e.isStructLiteralExp().ownedByCtfe == OwnedBy.code;
case EXP.string_:
case EXP.this_:
case EXP.variable:
case EXP.dotVariable:
case EXP.slice:
case EXP.cast_:
- e = (cast(UnaExp)e).e1;
+ e = e.isUnaExp().e1;
continue;
case EXP.concatenate:
- return needToCopyLiteral((cast(BinExp)e).e1) || needToCopyLiteral((cast(BinExp)e).e2);
+ return needToCopyLiteral(e.isBinExp().e1) || needToCopyLiteral(e.isBinExp().e2);
case EXP.concatenateAssign:
case EXP.concatenateElemAssign:
case EXP.concatenateDcharAssign:
- e = (cast(BinExp)e).e2;
+ e = e.isBinExp().e2;
continue;
default:
return false;
const slice = se.peekData();
memcpy(s, slice.ptr, slice.length);
emplaceExp!(StringExp)(&ue, se.loc, s[0 .. se.len * se.sz], se.len, se.sz);
- StringExp se2 = cast(StringExp)ue.exp();
+ StringExp se2 = ue.exp().isStringExp();
se2.committed = se.committed;
se2.postfix = se.postfix;
se2.type = se.type;
emplaceExp!(ArrayLiteralExp)(&ue, e.loc, e.type, elements);
- ArrayLiteralExp r = cast(ArrayLiteralExp)ue.exp();
+ ArrayLiteralExp r = ue.exp().isArrayLiteralExp();
r.ownedByCtfe = OwnedBy.ctfe;
return ue;
}
if (auto aae = e.isAssocArrayLiteralExp())
{
emplaceExp!(AssocArrayLiteralExp)(&ue, e.loc, copyLiteralArray(aae.keys), copyLiteralArray(aae.values));
- AssocArrayLiteralExp r = cast(AssocArrayLiteralExp)ue.exp();
+ AssocArrayLiteralExp r = ue.exp().isAssocArrayLiteralExp();
r.type = e.type;
r.ownedByCtfe = OwnedBy.ctfe;
return ue;
// just a ref to the keys and values.
OwnedBy wasOwned = aae.ownedByCtfe;
emplaceExp!(AssocArrayLiteralExp)(&ue, lit.loc, aae.keys, aae.values);
- aae = cast(AssocArrayLiteralExp)ue.exp();
+ aae = ue.exp().isAssocArrayLiteralExp();
aae.ownedByCtfe = wasOwned;
}
else
* It's very wasteful to resolve the slice when we only
* need the length.
*/
-uinteger_t resolveArrayLength(const Expression e)
+uinteger_t resolveArrayLength(Expression e)
{
switch (e.op)
{
case EXP.slice:
{
- auto se = cast(SliceExp)e;
+ auto se = e.isSliceExp();
const ilo = se.lwr.toInteger();
const iup = se.upr.toInteger();
return iup - ilo;
*ofs = soe.offset;
if (auto dve = e.isDotVarExp())
{
- const ex = dve.e1;
+ auto ex = dve.e1;
const v = dve.var.isVarDeclaration();
assert(v);
StructLiteralExp se = (ex.op == EXP.classReference)
- ? (cast(ClassReferenceExp)ex).value
- : cast(StructLiteralExp)ex;
+ ? ex.isClassReferenceExp().value
+ : ex.isStructLiteralExp();
// We can't use getField, because it makes a copy
const i = (ex.op == EXP.classReference)
- ? (cast(ClassReferenceExp)ex).getFieldIndex(e.type, v.offset)
+ ? ex.isClassReferenceExp().getFieldIndex(e.type, v.offset)
: se.getFieldIndex(e.type, v.offset);
e = (*se.elements)[i];
}
}
// Note that type painting can occur with VarExp, so we
// must compare the variables being pointed to.
- if (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)
+ if (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var)
{
return true;
}
- if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var)
+ if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && agg1.isSymOffExp().var == agg2.isSymOffExp().var)
{
return true;
}
emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
}
else if (agg1.op == EXP.string_ && agg2.op == EXP.string_ &&
- (cast(StringExp)agg1).peekString().ptr == (cast(StringExp)agg2).peekString().ptr)
+ agg1.isStringExp().peekString().ptr == agg2.isStringExp().peekString().ptr)
{
Type pointee = (cast(TypePointer)agg1.type).next;
const sz = pointee.size();
emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
}
else if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset &&
- (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var)
+ agg1.isSymOffExp().var == agg2.isSymOffExp().var)
{
emplaceExp!(IntegerExp)(pue, loc, ofs1 - ofs2, type);
}
return pue.exp();
}
if (eptr.op == EXP.address)
- eptr = (cast(AddrExp)eptr).e1;
+ eptr = eptr.isAddrExp().e1;
dinteger_t ofs1;
Expression agg1 = getAggregateFromPointer(eptr, &ofs1);
if (agg1.op == EXP.symbolOffset)
{
- if ((cast(SymOffExp)agg1).var.type.ty != Tsarray)
+ if (agg1.isSymOffExp().var.type.ty != Tsarray)
{
error(loc, "cannot perform pointer arithmetic on arrays of unknown length at compile time");
goto Lcant;
if (agg1.op == EXP.symbolOffset)
{
indx = ofs1 / sz;
- len = (cast(TypeSArray)(cast(SymOffExp)agg1).var.type).dim.toInteger();
+ len = (cast(TypeSArray)agg1.isSymOffExp().var.type).dim.toInteger();
}
else
{
}
if (agg1.op == EXP.symbolOffset)
{
- emplaceExp!(SymOffExp)(pue, loc, (cast(SymOffExp)agg1).var, indx * sz);
- SymOffExp se = cast(SymOffExp)pue.exp();
+ emplaceExp!(SymOffExp)(pue, loc, agg1.isSymOffExp().var, indx * sz);
+ SymOffExp se = pue.exp().isSymOffExp();
se.type = type;
return pue.exp();
}
bool isCtfeComparable(Expression e)
{
if (e.op == EXP.slice)
- e = (cast(SliceExp)e).e1;
+ e = e.isSliceExp().e1;
if (e.isConst() != 1)
{
if (e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.function_ || e.op == EXP.delegate_ || e.op == EXP.arrayLiteral || e.op == EXP.structLiteral || e.op == EXP.assocArrayLiteral || e.op == EXP.classReference)
if (e1.op == EXP.classReference || e2.op == EXP.classReference)
{
if (e1.op == EXP.classReference && e2.op == EXP.classReference &&
- (cast(ClassReferenceExp)e1).value == (cast(ClassReferenceExp)e2).value)
+ e1.isClassReferenceExp().value == e2.isClassReferenceExp().value)
return 0;
return 1;
}
{
// printf("e1: %s\n", e1.toChars());
// printf("e2: %s\n", e2.toChars());
- Type t1 = isType((cast(TypeidExp)e1).obj);
- Type t2 = isType((cast(TypeidExp)e2).obj);
+ Type t1 = isType(e1.isTypeidExp().obj);
+ Type t2 = isType(e2.isTypeidExp().obj);
assert(t1);
assert(t2);
return t1 != t2;
dinteger_t ofs1, ofs2;
Expression agg1 = getAggregateFromPointer(e1, &ofs1);
Expression agg2 = getAggregateFromPointer(e2, &ofs2);
- if ((agg1 == agg2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var))
+ if ((agg1 == agg2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var))
{
if (ofs1 == ofs2)
return 0;
return 0;
assert(e1.op == EXP.delegate_ && e2.op == EXP.delegate_);
// Same .funcptr. Do they have the same .ptr?
- Expression ptr1 = (cast(DelegateExp)e1).e1;
- Expression ptr2 = (cast(DelegateExp)e2).e1;
+ Expression ptr1 = e1.isDelegateExp().e1;
+ Expression ptr2 = e2.isDelegateExp().e1;
dinteger_t ofs1, ofs2;
Expression agg1 = getAggregateFromPointer(ptr1, &ofs1);
Expression agg2 = getAggregateFromPointer(ptr2, &ofs2);
// If they are EXP.variable, it means they are FuncDeclarations
- if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var))
+ if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && agg1.isVarExp().var == agg2.isVarExp().var))
{
return 0;
}
}
if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
{
- StructLiteralExp es1 = cast(StructLiteralExp)e1;
- StructLiteralExp es2 = cast(StructLiteralExp)e2;
+ StructLiteralExp es1 = e1.isStructLiteralExp();
+ StructLiteralExp es2 = e2.isStructLiteralExp();
// For structs, we only need to return 0 or 1 (< and > aren't legal).
if (es1.sd != es2.sd)
return 1;
}
if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.assocArrayLiteral)
{
- AssocArrayLiteralExp es1 = cast(AssocArrayLiteralExp)e1;
- AssocArrayLiteralExp es2 = cast(AssocArrayLiteralExp)e2;
+ AssocArrayLiteralExp es1 = e1.isAssocArrayLiteralExp();
+ AssocArrayLiteralExp es2 = e2.isAssocArrayLiteralExp();
size_t dim = es1.keys.dim;
if (es2.keys.dim != dim)
return 1;
}
else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
{
- SymOffExp es1 = cast(SymOffExp)e1;
- SymOffExp es2 = cast(SymOffExp)e2;
+ SymOffExp es1 = e1.isSymOffExp();
+ SymOffExp es2 = e2.isSymOffExp();
cmp = (es1.var == es2.var && es1.offset == es2.offset);
}
else if (e1.type.isreal())
if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
{
// [chars] ~ string => string (only valid for CTFE)
- StringExp es1 = cast(StringExp)e2;
- ArrayLiteralExp es2 = cast(ArrayLiteralExp)e1;
+ StringExp es1 = e2.isStringExp();
+ ArrayLiteralExp es2 = e1.isArrayLiteralExp();
const len = es1.len + es2.elements.dim;
const sz = es1.sz;
void* s = mem.xmalloc((len + 1) * sz);
// Add terminating 0
memset(cast(char*)s + len * sz, 0, sz);
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
- StringExp es = cast(StringExp)ue.exp();
+ StringExp es = ue.exp().isStringExp();
es.committed = 0;
es.type = type;
return ue;
{
// string ~ [chars] => string (only valid for CTFE)
// Concatenate the strings
- StringExp es1 = cast(StringExp)e1;
- ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
+ StringExp es1 = e1.isStringExp();
+ ArrayLiteralExp es2 = e2.isArrayLiteralExp();
const len = es1.len + es2.elements.dim;
const sz = es1.sz;
void* s = mem.xmalloc((len + 1) * sz);
// Add terminating 0
memset(cast(char*)s + len * sz, 0, sz);
emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
- StringExp es = cast(StringExp)ue.exp();
+ StringExp es = ue.exp().isStringExp();
es.sz = sz;
es.committed = 0; //es1.committed;
es.type = type;
if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
{
// [ e1 ] ~ [ e2 ] ---> [ e1, e2 ]
- ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
- ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
+ ArrayLiteralExp es1 = e1.isArrayLiteralExp();
+ ArrayLiteralExp es2 = e2.isArrayLiteralExp();
emplaceExp!(ArrayLiteralExp)(&ue, es1.loc, type, copyLiteralArray(es1.elements));
- es1 = cast(ArrayLiteralExp)ue.exp();
+ es1 = ue.exp().isArrayLiteralExp();
es1.elements.insert(es1.elements.dim, copyLiteralArray(es2.elements));
return ue;
}
// Disallow reinterpreting class casts. Do this by ensuring that
// the original class can implicitly convert to the target class.
// Also do not check 'alias this' for explicit cast expressions.
- auto tclass = (cast(ClassReferenceExp)e).originalClass().type.isTypeClass();
+ auto tclass = e.isClassReferenceExp().originalClass().type.isTypeClass();
auto match = explicitCast ? tclass.implicitConvToWithoutAliasThis(to.mutableOf())
: tclass.implicitConvTo(to.mutableOf());
if (match)
if (dest.op == EXP.structLiteral)
{
assert(dest.op == src.op);
- oldelems = (cast(StructLiteralExp)dest).elements;
- newelems = (cast(StructLiteralExp)src).elements;
- auto sd = (cast(StructLiteralExp)dest).sd;
+ oldelems = dest.isStructLiteralExp().elements;
+ newelems = src.isStructLiteralExp().elements;
+ auto sd = dest.isStructLiteralExp().sd;
const nfields = sd.nonHiddenFields();
const nvthis = sd.fields.dim - nfields;
if (nvthis && oldelems.dim >= nfields && oldelems.dim < newelems.dim)
}
else if (dest.op == EXP.arrayLiteral && src.op == EXP.arrayLiteral)
{
- oldelems = (cast(ArrayLiteralExp)dest).elements;
- newelems = (cast(ArrayLiteralExp)src).elements;
+ oldelems = dest.isArrayLiteralExp().elements;
+ newelems = src.isArrayLiteralExp().elements;
}
else if (dest.op == EXP.string_ && src.op == EXP.string_)
{
- sliceAssignStringFromString(cast(StringExp)dest, cast(StringExp)src, 0);
+ sliceAssignStringFromString(dest.isStringExp(), src.isStringExp(), 0);
return;
}
else if (dest.op == EXP.arrayLiteral && src.op == EXP.string_)
{
- sliceAssignArrayLiteralFromString(cast(ArrayLiteralExp)dest, cast(StringExp)src, 0);
+ sliceAssignArrayLiteralFromString(dest.isArrayLiteralExp(), src.isStringExp(), 0);
return;
}
else if (src.op == EXP.arrayLiteral && dest.op == EXP.string_)
{
- sliceAssignStringFromArrayLiteral(cast(StringExp)dest, cast(ArrayLiteralExp)src, 0);
+ sliceAssignStringFromArrayLiteral(dest.isStringExp(), src.isArrayLiteralExp(), 0);
return;
}
else
size_t indxlo = 0;
if (oldval.op == EXP.slice)
{
- indxlo = cast(size_t)(cast(SliceExp)oldval).lwr.toInteger();
- oldval = (cast(SliceExp)oldval).e1;
+ indxlo = cast(size_t)oldval.isSliceExp().lwr.toInteger();
+ oldval = oldval.isSliceExp().e1;
}
size_t copylen = oldlen < newlen ? oldlen : newlen;
if (oldval.op == EXP.string_)
{
- StringExp oldse = cast(StringExp)oldval;
+ StringExp oldse = oldval.isStringExp();
void* s = mem.xcalloc(newlen + 1, oldse.sz);
const data = oldse.peekData();
memcpy(s, data.ptr, copylen * oldse.sz);
}
}
emplaceExp!(StringExp)(pue, loc, s[0 .. newlen * oldse.sz], newlen, oldse.sz);
- StringExp se = cast(StringExp)pue.exp();
+ StringExp se = pue.exp().isStringExp();
se.type = arrayType;
se.sz = oldse.sz;
se.committed = oldse.committed;
if (oldlen != 0)
{
assert(oldval.op == EXP.arrayLiteral);
- ArrayLiteralExp ae = cast(ArrayLiteralExp)oldval;
+ ArrayLiteralExp ae = oldval.isArrayLiteralExp();
foreach (size_t i; 0 .. copylen)
(*elements)[i] = (*ae.elements)[indxlo + i];
}
(*elements)[i] = defaultElem;
}
emplaceExp!(ArrayLiteralExp)(pue, loc, arrayType, elements);
- ArrayLiteralExp aae = cast(ArrayLiteralExp)pue.exp();
+ ArrayLiteralExp aae = pue.exp().isArrayLiteralExp();
aae.ownedByCtfe = OwnedBy.ctfe;
}
return pue.exp();
{
// &struct.func or &clasinst.func
// &nestedfunc
- Expression ethis = (cast(DelegateExp)newval).e1;
- return (ethis.op == EXP.structLiteral || ethis.op == EXP.classReference || ethis.op == EXP.variable && (cast(VarExp)ethis).var == (cast(DelegateExp)newval).func);
+ Expression ethis = newval.isDelegateExp().e1;
+ return (ethis.op == EXP.structLiteral || ethis.op == EXP.classReference || ethis.op == EXP.variable && ethis.isVarExp().var == newval.isDelegateExp().func);
}
case EXP.symbolOffset:
{
// function pointer, or pointer to static variable
- Declaration d = (cast(SymOffExp)newval).var;
+ Declaration d = newval.isSymOffExp().var;
return d.isFuncDeclaration() || d.isDataseg();
}
case EXP.address:
{
// e1 should be a CTFE reference
- Expression e1 = (cast(AddrExp)newval).e1;
+ Expression e1 = newval.isAddrExp().e1;
return tb.ty == Tpointer &&
(
(e1.op == EXP.structLiteral || e1.op == EXP.arrayLiteral) && isCtfeValueValid(e1) ||
case EXP.slice:
{
// e1 should be an array aggregate
- const SliceExp se = cast(SliceExp)newval;
+ const SliceExp se = newval.isSliceExp();
assert(se.lwr && se.lwr.op == EXP.int64);
assert(se.upr && se.upr.op == EXP.int64);
return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral);
case EXP.variable:
{
- const VarDeclaration v = (cast(VarExp)newval).var.isVarDeclaration();
+ const VarDeclaration v = newval.isVarExp().var.isVarDeclaration();
assert(v);
// Must not be a reference to a reference
return true;
case EXP.index:
{
- const Expression eagg = (cast(IndexExp)newval).e1;
+ const Expression eagg = newval.isIndexExp().e1;
return eagg.op == EXP.string_ || eagg.op == EXP.arrayLiteral || eagg.op == EXP.assocArrayLiteral;
}
case EXP.dotVariable:
{
- Expression eagg = (cast(DotVarExp)newval).e1;
+ Expression eagg = newval.isDotVarExp().e1;
return (eagg.op == EXP.structLiteral || eagg.op == EXP.classReference) && isCtfeValueValid(eagg);
}
ClassDeclaration cd = null;
if (e.op == EXP.structLiteral)
{
- elements = (cast(StructLiteralExp)e).elements;
- sd = (cast(StructLiteralExp)e).sd;
+ elements = e.isStructLiteralExp().elements;
+ sd = e.isStructLiteralExp().sd;
printf("STRUCT type = %s %p:\n", e.type.toChars(), e);
}
else if (e.op == EXP.classReference)
{
- elements = (cast(ClassReferenceExp)e).value.elements;
- cd = (cast(ClassReferenceExp)e).originalClass();
- printf("CLASS type = %s %p:\n", e.type.toChars(), (cast(ClassReferenceExp)e).value);
+ elements = e.isClassReferenceExp().value.elements;
+ cd = e.isClassReferenceExp().originalClass();
+ printf("CLASS type = %s %p:\n", e.type.toChars(), e.isClassReferenceExp().value);
}
else if (e.op == EXP.arrayLiteral)
{
- elements = (cast(ArrayLiteralExp)e).elements;
+ elements = e.isArrayLiteralExp().elements;
printf("ARRAY LITERAL type=%s %p:\n", e.type.toChars(), e);
}
else if (e.op == EXP.assocArrayLiteral)
else if (e.op == EXP.slice)
{
printf("SLICE %p: %s\n", e, e.toChars());
- showCtfeExpr((cast(SliceExp)e).e1, level + 1);
+ showCtfeExpr(e.isSliceExp().e1, level + 1);
}
else if (e.op == EXP.variable)
{
printf("VAR %p %s\n", e, e.toChars());
- VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
+ VarDeclaration v = e.isVarExp().var.isVarDeclaration();
if (v && getValue(v))
showCtfeExpr(getValue(v), level + 1);
}
else if (e.op == EXP.address)
{
// This is potentially recursive. We mustn't try to print the thing we're pointing to.
- printf("POINTER %p to %p: %s\n", e, (cast(AddrExp)e).e1, e.toChars());
+ printf("POINTER %p to %p: %s\n", e, e.isAddrExp().e1, e.toChars());
}
else
printf("VALUE %p: %s\n", e, e.toChars());
(*elements)[i] = elem;
}
emplaceExp!(ArrayLiteralExp)(&ue, var.loc, tsa, elements);
- ArrayLiteralExp ae = cast(ArrayLiteralExp)ue.exp();
+ ArrayLiteralExp ae = ue.exp().isArrayLiteralExp();
ae.ownedByCtfe = OwnedBy.ctfe;
}
else if (t.ty == Tstruct)
(*exps)[i] = voidInitLiteral(ts.sym.fields[i].type, ts.sym.fields[i]).copy();
}
emplaceExp!(StructLiteralExp)(&ue, var.loc, ts.sym, exps);
- StructLiteralExp se = cast(StructLiteralExp)ue.exp();
+ StructLiteralExp se = ue.exp().isStructLiteralExp();
se.type = ts;
se.ownedByCtfe = OwnedBy.ctfe;
}
case EXP.negate : return visitNeg(e.isNegExp());
}
}
-
* postblit. Print the first field that has
* a disabled postblit.
*/
- if (postblit.generated)
+ if (postblit.isGenerated())
{
auto sd = p.isStructDeclaration();
assert(sd);
if (auto ctor = isCtorDeclaration())
{
- if (ctor.isCpCtor && ctor.generated)
+ if (ctor.isCpCtor && ctor.isGenerated())
{
.error(loc, "Generating an `inout` copy constructor for `struct %s` failed, therefore instances of it are uncopyable", parent.toPrettyChars());
return true;
enum AdrOnStackNone = ~0u;
uint ctfeAdrOnStack;
- bool isargptr; // if parameter that _argptr points to
- bool ctorinit; // it has been initialized in a ctor
- bool iscatchvar; // this is the exception object variable in catch() clause
- bool isowner; // this is an Owner, despite it being `scope`
- bool setInCtorOnly; // field can only be set in a constructor, as it is const or immutable
+ // `bool` fields that are compacted into bit fields in a string mixin
+ private extern (D) static struct BitFields
+ {
+ bool isargptr; /// if parameter that _argptr points to
+ bool ctorinit; /// it has been initialized in a ctor
+ bool iscatchvar; /// this is the exception object variable in catch() clause
+ bool isowner; /// this is an Owner, despite it being `scope`
+ bool setInCtorOnly; /// field can only be set in a constructor, as it is const or immutable
+
+ /// It is a class that was allocated on the stack
+ ///
+ /// This means the var is not rebindable once assigned,
+ /// and the destructor gets run when it goes out of scope
+ bool onstack;
- // Both these mean the var is not rebindable once assigned,
- // and the destructor gets run when it goes out of scope
- bool onstack; // it is a class that was allocated on the stack
+ bool overlapped; /// if it is a field and has overlapping
+ bool overlapUnsafe; /// if it is an overlapping field and the overlaps are unsafe
+ bool doNotInferScope; /// do not infer 'scope' for this variable
+ bool doNotInferReturn; /// do not infer 'return' for this variable
+
+ bool isArgDtorVar; /// temporary created to handle scope destruction of a function argument
+ }
+ private ushort bitFields; // stores multiple booleans for BitFields
byte canassign; // it can be assigned to
- bool overlapped; // if it is a field and has overlapping
- bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe
- bool doNotInferScope; // do not infer 'scope' for this variable
- bool doNotInferReturn; // do not infer 'return' for this variable
ubyte isdataseg; // private data for isDataseg 0 unset, 1 true, 2 false
- bool isArgDtorVar; // temporary created to handle scope destruction of a function argument
+ // Generate getter and setter functions for `bitFields`
+ extern (D) mixin(() {
+ string result = "extern (C++) pure nothrow @nogc @safe final {";
+ foreach (size_t i, mem; __traits(allMembers, BitFields))
+ {
+ result ~= "
+ /// set or get the corresponding BitFields member
+ bool "~mem~"() const { return !!(bitFields & (1 << "~i.stringof~")); }
+ /// ditto
+ bool "~mem~"(bool v)
+ {
+ v ? (bitFields |= (1 << "~i.stringof~")) : (bitFields &= ~(1 << "~i.stringof~"));
+ return v;
+ }";
+ }
+ return result ~ "}";
+ }());
+
final extern (D) this(const ref Loc loc, Type type, Identifier ident, Initializer _init, StorageClass storage_class = STC.undefined_)
in
{
v.visit(this);
}
-
- /**********************************
- * Determine if `this` has a lifetime that lasts past
- * the destruction of `v`
- * Params:
- * v = variable to test against
- * Returns:
- * true if it does
- */
- final bool enclosesLifetimeOf(VarDeclaration v) const pure
- {
- // VarDeclaration's with these STC's need special treatment
- enum special = STC.temp | STC.foreach_;
-
- // Sequence numbers work when there are no special VarDeclaration's involved
- if (!((this.storage_class | v.storage_class) & special))
- {
- assert(this.sequenceNumber != this.sequenceNumber.init);
- assert(v.sequenceNumber != v.sequenceNumber.init);
-
- return (this.sequenceNumber < v.sequenceNumber);
- }
-
- // Assume that semantic produces temporaries according to their lifetime
- // (It won't create a temporary before the actual content)
- if ((this.storage_class & special) && (v.storage_class & special))
- return this.sequenceNumber < v.sequenceNumber;
-
- // Fall back to lexical order
- assert(this.loc != Loc.initial);
- assert(v.loc != Loc.initial);
-
- if (this.loc.linnum != v.loc.linnum)
- return this.loc.linnum < v.loc.linnum;
-
- if (this.loc.charnum != v.loc.charnum)
- return this.loc.charnum < v.loc.charnum;
-
- // Default fallback
- return this.sequenceNumber < v.sequenceNumber;
- }
-
- /***************************************
- * Add variable to maybes[].
- * When a maybescope variable `v` is assigned to a maybescope variable `this`,
- * we cannot determine if `this` is actually scope until the semantic
- * analysis for the function is completed. Thus, we save the data
- * until then.
- * Params:
- * v = an STC.maybescope variable that was assigned to `this`
- */
- final void addMaybe(VarDeclaration v)
- {
- //printf("add %s to %s's list of dependencies\n", v.toChars(), toChars());
- if (!maybes)
- maybes = new VarDeclarations();
- maybes.push(v);
- }
}
/*******************************************************
// When interpreting, these point to the value (NULL if value not determinable)
// The index of this variable on the CTFE stack, ~0u if not allocated
unsigned ctfeAdrOnStack;
-
- bool isargptr; // if parameter that _argptr points to
- bool ctorinit; // it has been initialized in a ctor
- bool iscatchvar; // this is the exception object variable in catch() clause
- bool isowner; // this is an Owner, despite it being `scope`
- bool setInCtorOnly; // field can only be set in a constructor, as it is const or immutable
- bool onstack; // it is a class that was allocated on the stack
- char canassign; // it can be assigned to
- bool overlapped; // if it is a field and has overlapping
- bool overlapUnsafe; // if it is an overlapping field and the overlaps are unsafe
- bool doNotInferScope; // do not infer 'scope' for this variable
- bool doNotInferReturn; // do not infer 'return' for this variable
- unsigned char isdataseg; // private data for isDataseg
- bool isArgDtorVar; // temporary created to handle scope destruction of a function argument
-
-public:
+private:
+ uint16_t bitFields;
+public:
+ int8_t canassign; // // it can be assigned to
+ uint8_t isdataseg; // private data for isDataseg
+ bool isargptr() const; // if parameter that _argptr points to
+ bool isargptr(bool v);
+ bool ctorinit() const; // it has been initialized in a ctor
+ bool ctorinit(bool v);
+ bool iscatchvar() const; // this is the exception object variable in catch() clause
+ bool iscatchvar(bool v);
+ bool isowner() const; // this is an Owner, despite it being `scope`
+ bool isowner(bool v);
+ bool setInCtorOnly() const; // field can only be set in a constructor, as it is const or immutable
+ bool setInCtorOnly(bool v);
+ bool onstack() const; // it is a class that was allocated on the stack
+ bool onstack(bool v);
+ bool overlapped() const; // if it is a field and has overlapping
+ bool overlapped(bool v);
+ bool overlapUnsafe() const; // if it is an overlapping field and the overlaps are unsafe
+ bool overlapUnsafe(bool v);
+ bool doNotInferScope() const; // do not infer 'scope' for this variable
+ bool doNotInferScope(bool v);
+ bool doNotInferReturn() const; // do not infer 'return' for this variable
+ bool doNotInferReturn(bool v);
+ bool isArgDtorVar() const; // temporary created to handle scope destruction of a function argument
+ bool isArgDtorVar(bool v);
static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined);
VarDeclaration *syntaxCopy(Dsymbol *);
void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
bool hasPointers();
bool canTakeAddressOf();
bool needsScopeDtor();
- bool enclosesLifetimeOf(VarDeclaration *v) const;
void checkCtorConstInit();
Dsymbol *toAlias();
// Eliminate need for dynamic_cast
// scopes from having the same name
DsymbolTable *localsymtab;
VarDeclaration *vthis; // 'this' parameter (member and nested)
- bool isThis2; // has a dual-context 'this' parameter
VarDeclaration *v_arguments; // '_arguments' parameter
VarDeclaration *v_argptr; // '_argptr' variable
FuncDeclaration *overnext0; // next in overload list (only used during IFTI)
Loc endloc; // location of closing curly bracket
int vtblIndex; // for member functions, index into vtbl[]
- bool naked; // true if naked
- bool generated; // true if function was generated by the compiler rather than
- // supplied by the user
- bool hasAlwaysInlines; // contains references to functions that must be inlined
- unsigned char isCrtCtorDtor; // has attribute pragma(crt_constructor(1)/crt_destructor(2))
- // not set before the glue layer
+
ILS inlineStatusStmt;
ILS inlineStatusExp;
PINLINE inlining;
int inlineNest; // !=0 if nested inline
- bool eh_none; /// true if no exception unwinding is needed
// true if errors in semantic3 this function's frame ptr
- bool semantic3Errors;
ForeachStatement *fes; // if foreach body, this is the foreach
BaseClass* interfaceVirtual; // if virtual, but only appears in interface vtbl[]
- bool introducing; // true if 'introducing' function
// if !=NULL, then this is the type
// of the 'introducing' function
// this one is overriding
Type *tintro;
- bool inferRetType; // true if return type is to be inferred
StorageClass storage_class2; // storage class for template onemember's
// Things that should really go into Scope
// 16 if there are multiple return statements
int hasReturnExp;
- // Support for NRVO (named return value optimization)
- bool nrvo_can; // true means we can do it
VarDeclaration *nrvo_var; // variable to replace with shidden
Symbol *shidden; // hidden pointer passed to function
bool isNogc();
bool isNogcBypassingInference();
+ bool isNRVO() const;
+ void isNRVO(bool v);
+ bool isNaked() const;
+ bool isGenerated() const;
+ void isGenerated(bool v);
+ bool isIntroducing() const;
+ bool hasSemantic3Errors() const;
+ bool hasNoEH() const;
+ bool inferRetType() const;
+ bool hasDualContext() const;
+ bool hasAlwaysInlines() const;
+ bool isCrtCtor() const;
+ bool isCrtDtor() const;
virtual bool isNested() const;
AggregateDeclaration *isThis();
override void setScope(Scope* sc)
{
- if (semanticRun > PASS.init)
+ if (semanticRun > PASS.initial)
return;
ScopeDsymbol.setScope(sc);
}
if (defaultval)
return defaultval;
+ if (isCsymbol())
+ return memtype.defaultInit(loc, true);
+
if (_scope)
dsymbolSemantic(this, _scope);
if (errors)
istatex.caller = istate;
istatex.fd = fd;
- if (fd.isThis2)
+ if (fd.hasDualContext())
{
Expression arg0 = thisarg;
if (arg0 && arg0.type.ty == Tstruct)
e = CTFEExp.voidexp;
if (tf.isref && e.op == EXP.variable && e.isVarExp().var == fd.vthis)
e = thisarg;
- if (tf.isref && fd.isThis2 && e.op == EXP.index)
+ if (tf.isref && fd.hasDualContext() && e.op == EXP.index)
{
auto ie = e.isIndexExp();
auto pe = ie.e1.isPtrExp();
if (auto eaddr = e.isAddrExp())
x = eaddr.e1;
VarDeclaration v;
- while (x.op == EXP.variable && (v = (cast(VarExp)x).var.isVarDeclaration()) !is null)
+ while (x.op == EXP.variable && (v = x.isVarExp().var.isVarDeclaration()) !is null)
{
if (v.storage_class & STC.ref_)
{
}
while ((*boss.value.elements)[next].op == EXP.classReference)
{
- boss = cast(ClassReferenceExp)(*boss.value.elements)[next];
+ boss = (*boss.value.elements)[next].isClassReferenceExp();
}
(*boss.value.elements)[next] = collateral;
return oldest;
if (istate && istate.fd.vthis)
{
result = ctfeEmplaceExp!VarExp(e.loc, istate.fd.vthis);
- if (istate.fd.isThis2)
+ if (istate.fd.hasDualContext())
{
result = ctfeEmplaceExp!PtrExp(e.loc, result);
result.type = Type.tvoidptr.sarrayOf(2);
result = ctfeGlobals.stack.getThis();
if (result)
{
- if (istate && istate.fd.isThis2)
+ if (istate && istate.fd.hasDualContext())
{
assert(result.op == EXP.address);
- result = (cast(AddrExp)result).e1;
+ result = result.isAddrExp().e1;
assert(result.op == EXP.arrayLiteral);
- result = (*(cast(ArrayLiteralExp)result).elements)[0];
+ result = (*result.isArrayLiteralExp().elements)[0];
if (e.type.ty == Tstruct)
{
- result = (cast(AddrExp)result).e1;
+ result = result.isAddrExp().e1;
}
return;
}
{
fromType = (cast(TypeArray)e.var.type).next;
}
- if (e.var.isDataseg() && ((e.offset == 0 && isSafePointerCast(e.var.type, pointee)) || (fromType && isSafePointerCast(fromType, pointee))))
+ if (e.var.isDataseg() && ((e.offset == 0 && isSafePointerCast(e.var.type, pointee)) ||
+ (fromType && isSafePointerCast(fromType, pointee)) ||
+ (e.var.isCsymbol() && e.offset + pointee.size() <= e.var.type.size())))
{
result = e;
return;
if (decl.isDataseg()) {
// Normally this is already done by optimize()
// Do it here in case optimize(WANTvalue) wasn't run before CTFE
- emplaceExp!(SymOffExp)(pue, e.loc, (cast(VarExp)e.e1).var, 0);
+ emplaceExp!(SymOffExp)(pue, e.loc, e.e1.isVarExp().var, 0);
result = pue.exp();
result.type = e.type;
return;
return;
}
- ClassDeclaration cd = (cast(ClassReferenceExp)result).originalClass();
+ ClassDeclaration cd = result.isClassReferenceExp().originalClass();
assert(cd);
emplaceExp!(TypeidExp)(pue, e.loc, cd.type);
else
{
// segfault bug 6250
- assert(exp.op != EXP.index || (cast(IndexExp)exp).e1 != e);
+ assert(exp.op != EXP.index || exp.isIndexExp().e1 != e);
ex = interpretRegion(exp, istate);
if (exceptionOrCant(ex))
return;
}
emplaceExp!(ArrayLiteralExp)(pue, e.loc, e.type, basis, expsx);
- auto ale = cast(ArrayLiteralExp)pue.exp();
+ auto ale = pue.exp().isArrayLiteralExp();
ale.ownedByCtfe = OwnedBy.ctfe;
result = ale;
}
return;
}
emplaceExp!(StructLiteralExp)(pue, e.loc, e.sd, expsx);
- auto sle = cast(StructLiteralExp)pue.exp();
+ auto sle = pue.exp().isStructLiteralExp();
sle.type = e.type;
sle.ownedByCtfe = OwnedBy.ctfe;
sle.origin = e.origin;
foreach (ref element; *elements)
element = copyLiteral(elem).copy();
emplaceExp!(ArrayLiteralExp)(pue, loc, newtype, elements);
- auto ae = cast(ArrayLiteralExp)pue.exp();
+ auto ae = pue.exp().isArrayLiteralExp();
ae.ownedByCtfe = OwnedBy.ctfe;
return ae;
}
result = e; // optimize: reuse this CTFE reference
else
{
- auto edt = cast(DotTypeExp)e.copy();
+ auto edt = e.copy().isDotTypeExp();
edt.e1 = (e1 == ue.exp()) ? e1.copy() : e1; // don't return pointer to ue
result = edt;
}
if (exceptionOrCant(newval))
return;
- VarDeclaration v = (cast(VarExp)e1).var.isVarDeclaration();
+ VarDeclaration v = e1.isVarExp().var.isVarDeclaration();
setValue(v, newval);
// Get the value to return. Note that 'newval' is an Lvalue,
{
while (e1.op == EXP.cast_)
{
- CastExp ce = cast(CastExp)e1;
+ CastExp ce = e1.isCastExp();
e1 = ce.e1;
}
}
AssocArrayLiteralExp existingAA = null;
Expression lastIndex = null;
Expression oldval = null;
- if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
+ if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
{
// ---------------------------------------
// Deal with AA index assignment
* (2) If the ultimate AA is null, no insertion happens at all. Instead,
* we create nested AA literals, and change it into a assignment.
*/
- IndexExp ie = cast(IndexExp)e1;
+ IndexExp ie = e1.isIndexExp();
int depth = 0; // how many nested AA indices are there?
- while (ie.e1.op == EXP.index && (cast(IndexExp)ie.e1).e1.type.toBasetype().ty == Taarray)
+ while (ie.e1.op == EXP.index && ie.e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
{
assert(ie.modifiable);
- ie = cast(IndexExp)ie.e1;
+ ie = ie.e1.isIndexExp();
++depth;
}
// Normal case, ultimate parent AA already exists
// We need to walk from the deepest index up, checking that an AA literal
// already exists on each level.
- lastIndex = interpretRegion((cast(IndexExp)e1).e2, istate);
+ lastIndex = interpretRegion(e1.isIndexExp().e2, istate);
lastIndex = resolveSlice(lastIndex); // only happens with AA assignment
if (exceptionOrCant(lastIndex))
return;
while (depth > 0)
{
// Walk the syntax tree to find the indexExp at this depth
- IndexExp xe = cast(IndexExp)e1;
+ IndexExp xe = e1.isIndexExp();
foreach (d; 0 .. depth)
- xe = cast(IndexExp)xe.e1;
+ xe = xe.e1.isIndexExp();
Expression ekey = interpretRegion(xe.e2, istate);
if (exceptionOrCant(ekey))
oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
Expression newaae = oldval;
- while (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
+ while (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
{
- Expression ekey = interpretRegion((cast(IndexExp)e1).e2, istate);
+ Expression ekey = interpretRegion(e1.isIndexExp().e2, istate);
if (exceptionOrCant(ekey))
return;
ekey = resolveSlice(ekey); // only happens with AA assignment
valuesx.push(newaae);
auto aae = ctfeEmplaceExp!AssocArrayLiteralExp(e.loc, keysx, valuesx);
- aae.type = (cast(IndexExp)e1).e1.type;
+ aae.type = e1.isIndexExp().e1.type;
aae.ownedByCtfe = OwnedBy.ctfe;
if (!existingAA)
{
lastIndex = ekey;
}
newaae = aae;
- e1 = (cast(IndexExp)e1).e1;
+ e1 = e1.isIndexExp().e1;
}
// We must set to aggregate with newaae
if (exceptionOrCant(e1))
return;
- if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
+ if (e1.op == EXP.index && e1.isIndexExp().e1.type.toBasetype().ty == Taarray)
{
- IndexExp ie = cast(IndexExp)e1;
+ IndexExp ie = e1.isIndexExp();
assert(ie.e1.op == EXP.assocArrayLiteral);
- existingAA = cast(AssocArrayLiteralExp)ie.e1;
+ existingAA = ie.e1.isAssocArrayLiteralExp();
lastIndex = ie.e2;
}
}
// We have changed it into a reference assignment
// Note that returnValue is still the new length.
- e1 = (cast(ArrayLengthExp)e1).e1;
+ e1 = e1.isArrayLengthExp().e1;
Type t = e1.type.toBasetype();
if (t.ty != Tarray)
{
if (auto dve = e1x.isDotVarExp())
{
auto ex = dve.e1;
- auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex)
- : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value
+ auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp()
+ : ex.op == EXP.classReference ? ex.isClassReferenceExp().value
: null;
auto v = dve.var.isVarDeclaration();
if (!sle || !v)
* e.v = newval
*/
auto ex = dve.e1;
- auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex)
- : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value
+ auto sle = ex.op == EXP.structLiteral ? ex.isStructLiteralExp()
+ : ex.op == EXP.classReference ? ex.isClassReferenceExp().value
: null;
- auto v = (cast(DotVarExp)e1).var.isVarDeclaration();
+ auto v = e1.isDotVarExp().var.isVarDeclaration();
if (!sle || !v)
{
e.error("CTFE internal error: dotvar assignment");
}
int fieldi = ex.op == EXP.structLiteral ? findFieldIndexByName(sle.sd, v)
- : (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
+ : ex.isClassReferenceExp().findFieldIndexByName(v);
if (fieldi == -1)
{
e.error("CTFE internal error: cannot find field `%s` in `%s`", v.toChars(), ex.toChars());
return CTFEExp.cantexp;
}
- ArrayLiteralExp existingAE = cast(ArrayLiteralExp)aggregate;
+ ArrayLiteralExp existingAE = aggregate.isArrayLiteralExp();
if (existingAE.ownedByCtfe != OwnedBy.ctfe)
{
e.error("cannot modify read-only constant `%s`", existingAE.toChars());
assert(oldval.op == EXP.arrayLiteral);
assert(newval.op == EXP.arrayLiteral);
- Expressions* oldelems = (cast(ArrayLiteralExp)oldval).elements;
- Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
+ Expressions* oldelems = oldval.isArrayLiteralExp().elements;
+ Expressions* newelems = newval.isArrayLiteralExp().elements;
assert(oldelems.dim == newelems.dim);
Type elemtype = oldval.type.nextOf();
if (newval.op == EXP.slice && !isBlockAssignment)
{
- auto se = cast(SliceExp)newval;
+ auto se = newval.isSliceExp();
auto aggr2 = se.e1;
const srclower = se.lwr.toInteger();
const srcupper = se.upr.toInteger();
// https://issues.dlang.org/show_bug.cgi?id=14024
assert(aggr2.op == EXP.arrayLiteral);
Expressions* oldelems = existingAE.elements;
- Expressions* newelems = (cast(ArrayLiteralExp)aggr2).elements;
+ Expressions* newelems = aggr2.isArrayLiteralExp().elements;
Type elemtype = aggregate.type.nextOf();
bool needsPostblit = e.e2.isLvalue();
/* Mixed slice: it was initialized as an array literal of chars/integers.
* Now a slice of it is being set with a string.
*/
- sliceAssignArrayLiteralFromString(existingAE, cast(StringExp)newval, cast(size_t)firstIndex);
+ sliceAssignArrayLiteralFromString(existingAE, newval.isStringExp(), cast(size_t)firstIndex);
return newval;
}
if (newval.op == EXP.arrayLiteral && !isBlockAssignment)
{
Expressions* oldelems = existingAE.elements;
- Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
+ Expressions* newelems = newval.isArrayLiteralExp().elements;
Type elemtype = existingAE.type.nextOf();
bool needsPostblit = e.op != EXP.blit && e.e2.isLvalue();
foreach (j, newelem; *newelems)
if (!directblk && (*w)[k].op == EXP.arrayLiteral)
{
// Multidimensional array block assign
- if (Expression ex = assignTo(cast(ArrayLiteralExp)(*w)[k]))
+ if (Expression ex = assignTo((*w)[k].isArrayLiteralExp()))
return ex;
}
else if (refCopy)
while (e.op == EXP.not)
{
ret *= -1;
- e = (cast(NotExp)e).e1;
+ e = e.isNotExp().e1;
}
switch (e.op)
{
goto case; /+ fall through +/
case EXP.greaterThan:
case EXP.greaterOrEqual:
- *p1 = (cast(BinExp)e).e1;
- *p2 = (cast(BinExp)e).e2;
+ *p1 = e.isBinExp().e1;
+ *p2 = e.isBinExp().e2;
if (!(isPointer((*p1).type) && isPointer((*p2).type)))
ret = 0;
break;
}
}
- if (fd && fd.semanticRun >= PASS.semantic3done && fd.semantic3Errors)
+ if (fd && fd.semanticRun >= PASS.semantic3done && fd.hasSemantic3Errors())
{
e.error("CTFE failed because of previous errors in `%s`", fd.toChars());
result = CTFEExp.cantexp;
// Pointer to a non-array variable
if (agg.op == EXP.symbolOffset)
{
- e.error("mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), (cast(SymOffExp)agg).var.toChars());
+ e.error("mutable variable `%s` cannot be %s at compile time, even through a pointer", cast(char*)(modify ? "modified" : "read"), agg.isSymOffExp().var.toChars());
return false;
}
e.error("index %llu exceeds array length %llu", index, iupr - ilwr);
return false;
}
- *pagg = (cast(SliceExp)e1).e1;
+ *pagg = e1.isSliceExp().e1;
*pidx = index + ilwr;
}
else
assert(e1.op == EXP.assocArrayLiteral);
UnionExp e2tmp = void;
e2 = resolveSlice(e2, &e2tmp);
- result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e1, e2);
+ result = findKeyInAA(e.loc, e1.isAssocArrayLiteralExp(), e2);
if (!result)
{
e.error("key `%s` not found in associative array `%s`", e2.toChars(), e.e1.toChars());
}
e1 = resolveSlice(e1);
- result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e2, e1);
+ result = findKeyInAA(e.loc, e2.isAssocArrayLiteralExp(), e1);
if (exceptionOrCant(result))
return;
if (!result)
return;
}
- auto cre = cast(ClassReferenceExp)result;
+ auto cre = result.isClassReferenceExp();
auto cd = cre.originalClass();
// Find dtor(s) in inheritance chain
result = pue.exp();
return;
}
- if (e1.op == EXP.index && !(cast(IndexExp)e1).e1.type.equals(e1.type))
+ if (e1.op == EXP.index && !e1.isIndexExp().e1.type.equals(e1.type))
{
// type painting operation
- IndexExp ie = cast(IndexExp)e1;
+ IndexExp ie = e1.isIndexExp();
if (castBackFromVoid)
{
// get the original type. For strings, it's just the type...
// ..but for arrays of type void*, it's the type of the element
if (ie.e1.op == EXP.arrayLiteral && ie.e2.op == EXP.int64)
{
- ArrayLiteralExp ale = cast(ArrayLiteralExp)ie.e1;
+ ArrayLiteralExp ale = ie.e1.isArrayLiteralExp();
const indx = cast(size_t)ie.e2.toInteger();
if (indx < ale.elements.dim)
{
{
// &val[idx]
dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger();
- IndexExp ie = cast(IndexExp)ae.e1;
+ IndexExp ie = ae.e1.isIndexExp();
Expression lwr = ie.e2;
Expression upr = ctfeEmplaceExp!IntegerExp(ie.e2.loc, ie.e2.toInteger() + dim, Type.tsize_t);
if (auto ve = e1.isVarExp())
emplaceExp!(VarExp)(pue, e.loc, ve.var);
else
- emplaceExp!(SymOffExp)(pue, e.loc, (cast(SymOffExp)e1).var, (cast(SymOffExp)e1).offset);
+ emplaceExp!(SymOffExp)(pue, e.loc, e1.isSymOffExp().var, e1.isSymOffExp().offset);
result = pue.exp();
result.type = e.to;
return;
{
// Note that the slice may be void[], so when checking for dangerous
// casts, we need to use the original type, which is se.e1.
- SliceExp se = cast(SliceExp)e1;
+ SliceExp se = e1.isSliceExp();
if (!isSafePointerCast(se.e1.type.nextOf(), e.to.nextOf()))
{
e.error("array cast from `%s` to `%s` is not supported at compile time", se.e1.type.toChars(), e.to.toChars());
{
if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
{
- AddrExp ade = cast(AddrExp)ae.e1;
+ AddrExp ade = ae.e1.isAddrExp();
Expression ex = interpretRegion(ade.e1, istate);
if (exceptionOrCant(ex))
return;
}
// *(&x) ==> x
- result = (cast(AddrExp)result).e1;
+ result = result.isAddrExp().e1;
if (result.op == EXP.slice && e.type.toBasetype().ty == Tsarray)
{
// We can't use getField, because it makes a copy
if (ex.op == EXP.classReference)
{
- se = (cast(ClassReferenceExp)ex).value;
- i = (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
+ se = ex.isClassReferenceExp().value;
+ i = ex.isClassReferenceExp().findFieldIndexByName(v);
}
else if (ex.op == EXP.typeid_)
{
}
else
{
- se = cast(StructLiteralExp)ex;
+ se = ex.isStructLiteralExp();
i = findFieldIndexByName(se.sd, v);
}
if (i == -1)
if (e.op == EXP.classReference)
{
- StructLiteralExp sle = (cast(ClassReferenceExp)e).value;
+ StructLiteralExp sle = e.isClassReferenceExp().value;
if (auto ex = scrubSE(sle))
return ex;
}
if (e.op == EXP.classReference)
{
- if (auto ex = scrubSE((cast(ClassReferenceExp)e).value))
+ if (auto ex = scrubSE(e.isClassReferenceExp().value))
return ex;
}
else if (auto sle = e.isStructLiteralExp())
case EXP.vector:
case EXP.dotVariable:
{
- UnaExp ue = cast(UnaExp)e;
+ UnaExp ue = e.isUnaExp();
ue.e1 = copyRegionExp(ue.e1);
break;
}
case EXP.index:
{
- BinExp be = cast(BinExp)e;
+ BinExp be = e.isBinExp();
be.e1 = copyRegionExp(be.e1);
be.e2 = copyRegionExp(be.e2);
break;
Expressions args = Expressions(numParams);
- AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)aa;
+ AssocArrayLiteralExp ae = aa.isAssocArrayLiteralExp();
if (!ae.keys || ae.keys.dim == 0)
return ctfeEmplaceExp!IntegerExp(deleg.loc, 0, Type.tsize_t);
Expression eresult;
{
// At present, the constructors just copy their arguments into the struct.
// But we might need some magic if stack tracing gets added to druntime.
- StructLiteralExp se = (cast(ClassReferenceExp)pthis).value;
+ StructLiteralExp se = pthis.isClassReferenceExp().value;
assert(arguments.dim <= se.elements.dim);
foreach (i, arg; *arguments)
{
if (stc & STC.returninferred)
stc &= ~(STC.return_ | STC.returninferred);
- // 'return inout ref' is the same as 'inout ref'
- if ((stc & (STC.return_ | STC.wild)) == (STC.return_ | STC.wild))
- stc &= ~STC.return_;
-
// much like hdrgen.stcToBuffer()
string rrs;
const isout = (stc & STC.out_) != 0;
}
return null;
}
-
-
return true; // already read
//printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars());
- if (auto result = FileManager.fileManager.lookup(srcfile))
+ if (auto result = global.fileManager.lookup(srcfile))
{
this.src = result.data;
if (global.params.emitMakeDeps)
return null;
}
+ /********************************************
+ * Find the lexically enclosing function (if any).
+ *
+ * This function skips through generated FuncDeclarations,
+ * e.g. rewritten foreach bodies.
+ *
+ * Returns: the function or null
+ */
+ inout(FuncDeclaration) getEnclosingFunction() inout
+ {
+ if (!this.func)
+ return null;
+
+ auto fd = cast(FuncDeclaration) this.func;
+
+ // Look through foreach bodies rewritten as delegates
+ while (fd.fes)
+ {
+ assert(fd.fes.func);
+ fd = fd.fes.func;
+ }
+
+ return cast(inout(FuncDeclaration)) fd;
+ }
+
/*******************************************
* For TemplateDeclarations, we need to remember the Scope
* where it was declared. So mark the Scope as not
enum PASS : ubyte
{
- init, // initial state
+ initial, // initial state
semantic, // semantic() started
semanticdone, // semantic() done
semantic2, // semantic2() started
Scope* _scope; // !=null means context to use for semantic()
const(char)* prettystring; // cached value of toPrettyChars()
bool errors; // this symbol failed to pass semantic()
- PASS semanticRun = PASS.init;
+ PASS semanticRun = PASS.initial;
ushort localNum; /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
DeprecatedDeclaration depdecl; // customized deprecation message
static bool has2This(Dsymbol s)
{
if (auto f = s.isFuncDeclaration())
- return f.isThis2;
+ return f.hasDualContext();
if (auto ad = s.isAggregateDeclaration())
return ad.vthis2 !is null;
return false;
{
enum log = false;
if (log) printf("handleTagSymbols('%s') add %p existing %p\n", s.toChars(), s, s2);
+ if (log) printf(" add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
auto sd = s.isScopeDsymbol(); // new declaration
auto sd2 = s2.isScopeDsymbol(); // existing declaration
sc._module.tagSymTab[cast(void*)s] = s2;
return s;
}
+ // neither s2 nor s is a tag
if (log) printf(" collision\n");
return null;
}
{
enum log = false;
if (log) printf("handleSymbolRedeclarations('%s')\n", s.toChars());
+ if (log) printf(" add %s %s, existing %s %s\n", s.kind(), s.toChars(), s2.kind(), s2.toChars());
static Dsymbol collision()
{
if (fd.fbody) // fd is the definition
{
+ if (log) printf(" replace existing with new\n");
sds.symtab.update(fd); // replace fd2 in symbol table with fd
fd.overnext = fd2;
+
+ /* If fd2 is covering a tag symbol, then fd has to cover the same one
+ */
+ auto ps = cast(void*)fd2 in sc._module.tagSymTab;
+ if (ps)
+ sc._module.tagSymTab[cast(void*)fd] = *ps;
+
return fd;
}
*/
enum class PASS : uint8_t
{
- init, // initial state
+ initial, // initial state
semantic, // semantic() started
semanticdone, // semantic() done
semantic2, // semantic2() started
override void visit(AliasThis dsym)
{
- if (dsym.semanticRun != PASS.init)
+ if (dsym.semanticRun != PASS.initial)
return;
if (dsym._scope)
printf("linkage = %d\n", dsym.linkage);
//if (strcmp(toChars(), "mul") == 0) assert(0);
}
- //if (semanticRun > PASS.init)
+ //if (semanticRun > PASS.initial)
// return;
//semanticRun = PSSsemantic;
}
//printf("inferring type for %s with init %s\n", dsym.toChars(), dsym._init.toChars());
dsym._init = dsym._init.inferType(sc);
- dsym.type = dsym._init.initializerToExpression().type;
+ dsym.type = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0).type;
if (needctfe)
sc = sc.endCTFE();
* and add those.
*/
size_t nelems = Parameter.dim(tt.arguments);
- Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression() : null;
+ Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0) : null;
if (ie)
ie = ie.expressionSemantic(sc);
if (nelems > 0 && ie)
if (ai && tb.ty == Taarray)
e = ai.toAssocArrayLiteral();
else
- e = dsym._init.initializerToExpression();
+ e = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0);
if (!e)
{
// Run semantic, but don't need to interpret
dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITnointerpret);
- e = dsym._init.initializerToExpression();
+ e = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0);
if (!e)
{
dsym.error("is not a static and cannot have static initializer");
dsym.edtor = dsym.callScopeDtor(sc);
if (dsym.edtor)
{
- /* If dsym is a local variable, who's type is a struct with a scope destructor,
- * then make dsym scope, too.
- */
- if (global.params.useDIP1000 == FeatureState.enabled &&
- !(dsym.storage_class & (STC.parameter | STC.temp | STC.field | STC.in_ | STC.foreach_ | STC.result | STC.manifest)) &&
- !dsym.isDataseg() &&
- !dsym.doNotInferScope &&
- dsym.type.hasPointers())
- {
- auto tv = dsym.type.baseElemOf();
- if (tv.ty == Tstruct &&
- tv.isTypeStruct().sym.dtor.storage_class & STC.scope_)
- {
- dsym.storage_class |= STC.scope_;
- }
- }
-
if (sc.func && dsym.storage_class & (STC.static_ | STC.gshared))
dsym.edtor = dsym.edtor.expressionSemantic(sc._module._scope);
else
override void visit(Import imp)
{
//printf("Import::semantic('%s') %s\n", toPrettyChars(), id.toChars());
- if (imp.semanticRun > PASS.init)
+ if (imp.semanticRun > PASS.initial)
return;
if (imp._scope)
void attribSemantic(AttribDeclaration ad)
{
- if (ad.semanticRun != PASS.init)
+ if (ad.semanticRun != PASS.initial)
return;
ad.semanticRun = PASS.semantic;
Dsymbols* d = ad.include(sc);
}
else if (auto f = s.isFuncDeclaration())
{
- f.isCrtCtorDtor |= isCtor ? 1 : 2;
+ f.flags |= isCtor ? FUNCFLAG.CRTCtor : FUNCFLAG.CRTDtor;
return 1;
}
else
override void visit(Module m)
{
- if (m.semanticRun != PASS.init)
+ if (m.semanticRun != PASS.initial)
return;
//printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
m.semanticRun = PASS.semantic;
deferDsymbolSemantic(ed, scx);
Module.dprogress = dprogress_save;
//printf("\tdeferring %s\n", toChars());
- ed.semanticRun = PASS.init;
+ ed.semanticRun = PASS.initial;
return;
}
else
printf("sc.stc = %llx\n", sc.stc);
printf("sc.module = %s\n", sc._module.toChars());
}
- if (tempdecl.semanticRun != PASS.init)
+ if (tempdecl.semanticRun != PASS.initial)
return; // semantic() already run
if (tempdecl._scope)
printf("+TemplateMixin.dsymbolSemantic('%s', this=%p)\n", tm.toChars(), tm);
fflush(stdout);
}
- if (tm.semanticRun != PASS.init)
+ if (tm.semanticRun != PASS.initial)
{
// When a class/struct contains mixin members, and is done over
// because of forward references, never reach here so semanticRun
- // has been reset to PASS.init.
+ // has been reset to PASS.initial.
static if (LOG)
{
printf("\tsemantic done\n");
*/
if (!tm.findTempDecl(sc) || !tm.semanticTiargs(sc) || !tm.findBestMatch(sc, null))
{
- if (tm.semanticRun == PASS.init) // forward reference had occurred
+ if (tm.semanticRun == PASS.initial) // forward reference had occurred
{
//printf("forward reference - deferring\n");
return deferDsymbolSemantic(tm, scx);
override void visit(Nspace ns)
{
- if (ns.semanticRun != PASS.init)
+ if (ns.semanticRun != PASS.initial)
return;
static if (LOG)
{
printf("type: %p, %s\n", funcdecl.type, funcdecl.type.toChars());
}
- if (funcdecl.semanticRun != PASS.init && funcdecl.isFuncLiteralDeclaration())
+ if (funcdecl.semanticRun != PASS.initial && funcdecl.isFuncLiteralDeclaration())
{
/* Member functions that have return types that are
* forward references can have semantic() run more than
AggregateDeclaration ad = funcdecl.isThis();
// Don't nest structs b/c of generated methods which should not access the outer scopes.
// https://issues.dlang.org/show_bug.cgi?id=16627
- if (ad && !funcdecl.generated)
+ if (ad && !funcdecl.isGenerated())
{
funcdecl.storage_class |= ad.storage_class & (STC.TYPECTOR | STC.synchronized_);
ad.makeNested();
funcdecl.inlining = pragmadecl.evalPragmaInline(sc);
// check pragma(crt_constructor)
- if (funcdecl.isCrtCtorDtor)
+ if (funcdecl.flags & (FUNCFLAG.CRTCtor | FUNCFLAG.CRTDtor))
{
if (funcdecl.linkage != LINK.c)
{
funcdecl.error("must be `extern(C)` for `pragma(%s)`",
- funcdecl.isCrtCtorDtor == 1 ? "crt_constructor".ptr : "crt_destructor".ptr);
+ (funcdecl.flags & FUNCFLAG.CRTCtor) ? "crt_constructor".ptr : "crt_destructor".ptr);
}
}
if (sc.scopesym && sc.scopesym.isAggregateDeclaration())
funcdecl.error("`static` member has no `this` to which `return` can apply");
else
- error(funcdecl.loc, "Top-level function `%s` has no `this` to which `return` can apply", funcdecl.toChars());
+ error(funcdecl.loc, "top-level function `%s` has no `this` to which `return` can apply", funcdecl.toChars());
}
if (funcdecl.isAbstract() && !funcdecl.isVirtual())
else
{
//printf("\tintroducing function %s\n", funcdecl.toChars());
- funcdecl.introducing = 1;
+ funcdecl.flags |= FUNCFLAG.introducing;
if (cd.classKind == ClassKind.cpp && target.cpp.reverseOverloads)
{
/* Overloaded functions with same name are grouped and in reverse order.
}
}
- if (funcdecl.isMain())
- funcdecl.checkDmain(); // Check main() parameters and return type
+ funcdecl.checkMain(); // Check main() parameters and return type
/* Purity and safety can be inferred for some functions by examining
* the function body.
if (sd.errors)
sd.type = Type.terror;
- if (sd.semanticRun == PASS.init)
+ if (sd.semanticRun == PASS.initial)
sd.type = sd.type.addSTC(sc.stc | sd.storage_class);
sd.type = sd.type.typeSemantic(sd.loc, sc);
if (auto ts = sd.type.isTypeStruct())
// Ungag errors when not speculative
Ungag ungag = sd.ungagSpeculative();
- if (sd.semanticRun == PASS.init)
+ if (sd.semanticRun == PASS.initial)
{
sd.visibility = sc.visibility;
if (cldec.errors)
cldec.type = Type.terror;
- if (cldec.semanticRun == PASS.init)
+ if (cldec.semanticRun == PASS.initial)
cldec.type = cldec.type.addSTC(sc.stc | cldec.storage_class);
cldec.type = cldec.type.typeSemantic(cldec.loc, sc);
if (auto tc = cldec.type.isTypeClass())
// Ungag errors when not speculative
Ungag ungag = cldec.ungagSpeculative();
- if (cldec.semanticRun == PASS.init)
+ if (cldec.semanticRun == PASS.initial)
{
cldec.visibility = sc.visibility;
auto ctor = new CtorDeclaration(cldec.loc, Loc.initial, 0, tf);
ctor.storage_class |= STC.inference;
- ctor.generated = true;
+ ctor.flags |= FUNCFLAG.generated;
ctor.fbody = new CompoundStatement(Loc.initial, new Statements());
cldec.members.push(ctor);
// Ungag errors when not speculative
Ungag ungag = idec.ungagSpeculative();
- if (idec.semanticRun == PASS.init)
+ if (idec.semanticRun == PASS.initial)
{
idec.visibility = sc.visibility;
}
return;
}
- if (tempinst.semanticRun != PASS.init)
+ if (tempinst.semanticRun != PASS.initial)
{
static if (LOG)
{
global.gag = 0;
tempinst.error(tempinst.loc, "recursive template expansion");
if (tempinst.gagged)
- tempinst.semanticRun = PASS.init;
+ tempinst.semanticRun = PASS.initial;
else
tempinst.inst = tempinst;
tempinst.errors = true;
{
// https://issues.dlang.org/show_bug.cgi?id=13220
// Roll back status for later semantic re-running
- tempinst.semanticRun = PASS.init;
+ tempinst.semanticRun = PASS.initial;
}
else
tempinst.inst = tempinst;
// Create our own scope for the template parameters
Scope* _scope = tempdecl._scope;
- if (tempdecl.semanticRun == PASS.init)
+ if (tempdecl.semanticRun == PASS.initial)
{
tempinst.error("template instantiation `%s` forward references template declaration `%s`", tempinst.toChars(), tempdecl.toChars());
return;
target_symbol_list.remove(target_symbol_list_idx);
tempinst.memberOf = null; // no longer a member
}
- tempinst.semanticRun = PASS.init;
+ tempinst.semanticRun = PASS.initial;
tempinst.inst = null;
tempinst.symtab = null;
}
// Ungag errors when not instantiated DeclDefs scope alias
auto ungag = Ungag(global.gag);
- //printf("%s parent = %s, gag = %d, instantiated = %d\n", toChars(), parent, global.gag, isInstantiated());
- if (ds.parent && global.gag && !ds.isInstantiated() && !ds.toParent2().isFuncDeclaration())
+ //printf("%s parent = %s, gag = %d, instantiated = %d\n", ds.toChars(), ds.parent.toChars(), global.gag, ds.isInstantiated() !is null);
+ if (ds.parent && global.gag && !ds.isInstantiated() && !ds.toParent2().isFuncDeclaration() && (sc.minst || sc.tinst))
{
- //printf("%s type = %s\n", toPrettyChars(), type.toChars());
+ //printf("%s type = %s\n", ds.toPrettyChars(), ds.type.toChars());
global.gag = 0;
}
}
if (s) // it's a symbolic alias
{
- //printf("alias %s resolved to %s %s\n", toChars(), s.kind(), s.toChars());
+ //printf("alias %s resolved to %s %s\n", ds.toChars(), s.kind(), s.toChars());
ds.type = null;
ds.aliassym = s;
}
else // it's a type alias
{
- //printf("alias %s resolved to type %s\n", toChars(), type.toChars());
+ //printf("alias %s resolved to type %s\n", ds.toChars(), ds.type.toChars());
ds.type = ds.type.typeSemantic(ds.loc, sc);
ds.aliassym = null;
}
fd = new FuncDeclaration(fd.loc, fd.endloc, fd.ident, fd.storage_class, tf);
fd.parent = ti;
- fd.inferRetType = true;
+ fd.flags |= FUNCFLAG.inferRetType;
// Shouldn't run semantic on default arguments and return type.
foreach (ref param; *tf.parameterList.parameters)
if (!sc)
sc = td._scope; // workaround for Type.aliasthisOf
- if (td.semanticRun == PASS.init && td._scope)
+ if (td.semanticRun == PASS.initial && td._scope)
{
// Try to fix forward reference. Ungag errors while doing so.
Ungag ungag = td.ungagSpeculative();
td.dsymbolSemantic(td._scope);
}
- if (td.semanticRun == PASS.init)
+ if (td.semanticRun == PASS.initial)
{
.error(loc, "forward reference to template `%s`", td.toChars());
Lerror:
tiargs = new Objects();
auto ti = new TemplateInstance(loc, td, tiargs);
Objects dedtypes = Objects(td.parameters.dim);
- assert(td.semanticRun != PASS.init);
+ assert(td.semanticRun != PASS.initial);
MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, fargs, 0);
//printf("matchWithInstance = %d\n", mta);
if (mta == MATCH.nomatch || mta < ta_last) // no match or less match
if (!td)
return 0;
- if (td.semanticRun == PASS.init)
+ if (td.semanticRun == PASS.initial)
{
if (td._scope)
{
Ungag ungag = td.ungagSpeculative();
td.dsymbolSemantic(td._scope);
}
- if (td.semanticRun == PASS.init)
+ if (td.semanticRun == PASS.initial)
{
error("`%s` forward references template declaration `%s`",
toChars(), td.toChars());
(*tiargs)[j] = sa;
TemplateDeclaration td = sa.isTemplateDeclaration();
- if (td && td.semanticRun == PASS.init && td.literal)
+ if (td && td.semanticRun == PASS.initial && td.literal)
{
td.dsymbolSemantic(sc);
}
dedtypes.setDim(td.parameters.dim);
dedtypes.zero();
- assert(td.semanticRun != PASS.init);
+ assert(td.semanticRun != PASS.initial);
MATCH m = td.matchWithInstance(sc, this, &dedtypes, fargs, 0);
//printf("matchWithInstance = %d\n", m);
extern (D) final bool needsTypeInference(Scope* sc, int flag = 0)
{
//printf("TemplateInstance.needsTypeInference() %s\n", toChars());
- if (semanticRun != PASS.init)
+ if (semanticRun != PASS.initial)
return false;
uint olderrs = global.errors;
*/
dedtypes.setDim(td.parameters.dim);
dedtypes.zero();
- if (td.semanticRun == PASS.init)
+ if (td.semanticRun == PASS.initial)
{
if (td._scope)
{
Ungag ungag = td.ungagSpeculative();
td.dsymbolSemantic(td._scope);
}
- if (td.semanticRun == PASS.init)
+ if (td.semanticRun == PASS.initial)
{
error("`%s` forward references template declaration `%s`", toChars(), td.toChars());
return 1;
if (!td)
return 0;
- if (td.semanticRun == PASS.init)
+ if (td.semanticRun == PASS.initial)
{
if (td._scope)
td.dsymbolSemantic(td._scope);
else
{
- semanticRun = PASS.init;
+ semanticRun = PASS.initial;
return 1;
}
}
*/
private void writeIdentifier(const AST.Dsymbol s, const bool canFix = false)
{
+ if (const mn = getMangleOverride(s))
+ return buf.writestring(mn);
+
writeIdentifier(s.ident, s.loc, s.kind(), canFix);
}
visited[cast(void*)fd] = true;
// silently ignore non-user-defined destructors
- if (fd.generated && fd.isDtorDeclaration())
+ if (fd.isGenerated && fd.isDtorDeclaration())
return;
// Note that tf might be null for templated (member) functions
auto tf = cast(AST.TypeFunction)fd.type;
- if ((tf && tf.linkage != LINK.c && tf.linkage != LINK.cpp) || (!tf && fd.isPostBlitDeclaration()))
+ if ((tf && (tf.linkage != LINK.c || adparent) && tf.linkage != LINK.cpp) || (!tf && fd.isPostBlitDeclaration()))
{
ignored("function %s because of linkage", fd.toPrettyChars());
- return checkVirtualFunction(fd);
+ return checkFunctionNeedsPlaceholder(fd);
+ }
+ if (fd.mangleOverride && tf && tf.linkage != LINK.c)
+ {
+ ignored("function %s because C++ doesn't support explicit mangling", fd.toPrettyChars());
+ return checkFunctionNeedsPlaceholder(fd);
}
if (!adparent && !fd.fbody)
{
if (tf && !isSupportedType(tf.next))
{
ignored("function %s because its return type cannot be mapped to C++", fd.toPrettyChars());
- return checkVirtualFunction(fd);
+ return checkFunctionNeedsPlaceholder(fd);
}
if (tf) foreach (i, fparam; tf.parameterList)
{
{
ignored("function %s because one of its parameters has type `%s` which cannot be mapped to C++",
fd.toPrettyChars(), fparam.type.toChars());
- return checkVirtualFunction(fd);
+ return checkFunctionNeedsPlaceholder(fd);
}
}
}
- /// Checks whether `fd` is a virtual function and emits a dummy declaration
- /// if required to ensure proper vtable layout
- private void checkVirtualFunction(AST.FuncDeclaration fd)
+ /++
+ + Checks whether `fd` is a function that requires a dummy declaration
+ + instead of simply emitting the declaration (because it would cause
+ + ABI / behaviour issues). This includes:
+ +
+ + - virtual functions to ensure proper vtable layout
+ + - destructors that would break RAII
+ +/
+ private void checkFunctionNeedsPlaceholder(AST.FuncDeclaration fd)
{
// Omit redundant declarations - the slot was already
// reserved in the base class
- if (fd.isVirtual() && fd.introducing)
+ if (fd.isVirtual() && fd.isIntroducing())
{
// Hide placeholders because they are not ABI compatible
writeProtection(AST.Visibility.Kind.private_);
buf.printf("virtual void __vtable_slot_%u();", counter++);
buf.writenl();
}
+ else if (fd.isDtorDeclaration())
+ {
+ // Create inaccessible dtor to prevent code from keeping instances that
+ // need to be destroyed on the C++ side (but cannot call the dtor)
+ writeProtection(AST.Visibility.Kind.private_);
+ buf.writeByte('~');
+ buf.writestring(adparent.ident.toString());
+ buf.writestringln("();");
+ }
}
override void visit(AST.UnitTestDeclaration utd)
ignored("variable %s because of linkage", vd.toPrettyChars());
return;
}
+ if (vd.mangleOverride && vd.linkage != LINK.c)
+ {
+ ignored("variable %s because C++ doesn't support explicit mangling", vd.toPrettyChars());
+ return;
+ }
if (!isSupportedType(type))
{
ignored("variable %s because its type cannot be mapped to C++", vd.toPrettyChars());
auto fd = ad.aliassym.isFuncDeclaration();
- if (fd && (fd.generated || fd.isDtorDeclaration()))
+ if (fd && (fd.isGenerated() || fd.isDtorDeclaration()))
{
// Ignore. It's taken care of while visiting FuncDeclaration
return;
// Print prefix of the base class if this function originates from a superclass
// because alias might be resolved through multiple classes, e.g.
// e.g. for alias visit = typeof(super).visit in the visitors
- if (!fd.introducing)
+ if (!fd.isIntroducing())
printPrefix(ad.toParent().isClassDeclaration().baseClass);
else
printPrefix(pd);
scope(exit) printf("[typeToBuffer(AST.Type, AST.Dsymbol) exit] %s sym %s\n", t.toChars(), s.toChars());
}
- this.ident = s.ident;
+ // The context pointer (represented as `ThisDeclaration`) is named
+ // `this` but accessible via `outer`
+ if (auto td = s.isThisDeclaration())
+ {
+ import dmd.id;
+ this.ident = Id.outer;
+ }
+ else
+ this.ident = s.ident;
+
auto type = origType !is null ? origType : t;
AST.Dsymbol customLength;
if (this.ident)
{
buf.writeByte(' ');
- writeIdentifier(s, canFixup);
+ // Custom identifier doesn't need further checks
+ if (this.ident !is s.ident)
+ buf.writestring(this.ident.toString());
+ else
+ writeIdentifier(s, canFixup);
+
}
this.ident = null;
scope(exit) printf("[writeFullName exit] %s\n", sym.toPrettyChars());
}
+ // Explicit `pragma(mangle, "<some string>` overrides the declared name
+ if (auto mn = getMangleOverride(sym))
+ return buf.writestring(mn);
+
/// Checks whether `sym` is nested in `par` and hence doesn't need the FQN
static bool isNestedIn(AST.Dsymbol sym, AST.Dsymbol par)
{
else
buf.writestring(sym.ident.toString());
}
+
+ /// Returns: Explicit mangling for `sym` if present
+ extern(D) static const(char)[] getMangleOverride(const AST.Dsymbol sym)
+ {
+ if (auto decl = sym.isDeclaration())
+ return decl.mangleOverride;
+
+ return null;
+ }
}
/// Namespace for identifiers used to represent special enums in C++
/// Writes `#define <content>` into the supplied buffer
void hashDefine(ref OutBuffer buf, string content)
{
- buf.writestring("# define ");
+ buf.writestring("#define ");
buf.writestringln(content);
}
// If va's lifetime encloses v's, then error
if (va && !va.isDataseg() &&
- (va.enclosesLifetimeOf(v) && !(v.storage_class & STC.temp) ||
- vaIsRef ||
- va.isReference() && !(v.storage_class & (STC.parameter | STC.temp))) &&
+ ((va.enclosesLifetimeOf(v) && !(v.storage_class & STC.temp)) || vaIsRef) &&
fd.setUnsafe())
{
if (!gag)
// If va's lifetime encloses v's, then error
if (va &&
- (va.enclosesLifetimeOf(v) || (va.isRef() && !(va.storage_class & STC.temp)) || va.isDataseg()) &&
+ (va.enclosesLifetimeOf(v) || (va.isReference() && !(va.storage_class & STC.temp)) || va.isDataseg()) &&
fd.setUnsafe())
{
if (!gag)
{
if (!gag)
{
- const(char)* msg, supplemental;
- if (v.storage_class & STC.parameter &&
- (v.type.hasPointers() || v.storage_class & STC.ref_))
- {
- msg = "returning `%s` escapes a reference to parameter `%s`";
- supplemental = vsr == ScopeRef.Ref_ReturnScope
- ? "perhaps remove `scope` parameter annotation so `return` applies to `ref`"
- : v.ident is Id.This
- ? "perhaps annotate the function with `return`"
- : "perhaps annotate the parameter with `return`";
- }
- else
+ const(char)* varKind = v.isParameter() ? "parameter" : "local variable";
+ previewErrorFunc(sc.isDeprecated(), featureState)(e.loc,
+ "returning `%s` escapes a reference to %s `%s`", e.toChars(), varKind, v.toChars());
+
+ if (v.isParameter() && v.isReference())
{
- msg = "returning `%s` escapes a reference to local variable `%s`";
- if (v.ident is Id.This)
- supplemental = "perhaps annotate the function with `return`";
+ if (v.storage_class & STC.returnScope)
+ {
+ previewSupplementalFunc(sc.isDeprecated(), featureState)(v.loc,
+ "perhaps change the `return scope` into `scope return`");
+ }
+ else
+ {
+ const(char)* annotateKind = (v.ident is Id.This) ? "function" : "parameter";
+ previewSupplementalFunc(sc.isDeprecated(), featureState)(v.loc,
+ "perhaps annotate the %s with `return`", annotateKind);
+ }
}
-
- previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, msg, e.toChars(), v.toChars());
- if (supplemental)
- previewSupplementalFunc(sc.isDeprecated(), featureState)(e.loc, supplemental);
}
result = true;
}
override void visit(ThisExp e)
{
- if (e.var && e.var.toParent2().isFuncDeclaration().isThis2)
+ if (e.var && e.var.toParent2().isFuncDeclaration().hasDualContext())
escapeByValue(e, er, live);
else if (e.var)
er.byref.push(e.var);
}
return isReferenceToMutable(p.type);
}
+
+/**********************************
+* Determine if `va` has a lifetime that lasts past
+* the destruction of `v`
+* Params:
+* va = variable assigned to
+* v = variable being assigned
+* Returns:
+* true if it does
+*/
+private bool enclosesLifetimeOf(const VarDeclaration va, const VarDeclaration v) pure
+{
+ assert(va.sequenceNumber != va.sequenceNumber.init);
+ assert(v.sequenceNumber != v.sequenceNumber.init);
+ return va.sequenceNumber < v.sequenceNumber;
+}
+
+/***************************************
+ * Add variable `v` to maybes[]
+ *
+ * When a maybescope variable `v` is assigned to a maybescope variable `va`,
+ * we cannot determine if `this` is actually scope until the semantic
+ * analysis for the function is completed. Thus, we save the data
+ * until then.
+ * Params:
+ * v = an `STC.maybescope` variable that was assigned to `this`
+ */
+private void addMaybe(VarDeclaration va, VarDeclaration v)
+{
+ //printf("add %s to %s's list of dependencies\n", v.toChars(), toChars());
+ if (!va.maybes)
+ va.maybes = new VarDeclarations();
+ va.maybes.push(v);
+}
{
return null;
}
- if (!fd.isNested() || fd.isThis() || (fd.isThis2 && fd.isMember2()))
+ if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2()))
break;
Dsymbol parent = fd.parent;
fd = parent.isFuncDeclaration();
}
- if (!fd.isThis() && !(fd.isThis2 && fd.isMember2()))
+ if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2()))
{
return null;
}
scope bool function(DtorDeclaration) check, const string checkName
) {
auto dd = f.isDtorDeclaration();
- if (!dd || !dd.generated)
+ if (!dd || !dd.isGenerated())
return;
// DtorDeclaration without parents should fail at an earlier stage
}
dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
- dd.generated ? "generated " : "".ptr,
+ dd.isGenerated() ? "generated " : "".ptr,
ad.toChars,
cast(int) checkName.length, checkName.ptr);
{
field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars());
- if (fieldSd.dtor.generated)
+ if (fieldSd.dtor.isGenerated())
checkOverridenDtor(sc, fieldSd.dtor, check, checkName);
else
fieldSd.dtor.loc.errorSupplemental(" %.*s `%s.~this` is declared here",
return false; // magic variable never violates pure and safe
if (v.isImmutable())
return false; // always safe and pure to access immutables...
- if (v.isConst() && !v.isRef() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf()))
+ if (v.isConst() && !v.isReference() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf()))
return false; // or const global/parameter values which have no mutable indirections
if (v.storage_class & STC.manifest)
return false; // ...or manifest constants
//assert(ti.needsTypeInference(sc));
if (ti.tempdecl &&
ti.semantictiargsdone &&
- ti.semanticRun == PASS.init)
+ ti.semanticRun == PASS.initial)
{
error("partial %s `%s` has no type", sds.kind(), toChars());
return true;
{
if (td)
return new FuncExp(loc, td.syntaxCopy(null));
- else if (fd.semanticRun == PASS.init)
+ else if (fd.semanticRun == PASS.initial)
return new FuncExp(loc, fd.syntaxCopy(null));
else // https://issues.dlang.org/show_bug.cgi?id=13481
// Prevent multiple semantic analysis of lambda body.
// Same logic as ScopeExp.checkType()
if (ti.tempdecl &&
ti.semantictiargsdone &&
- ti.semanticRun == PASS.init)
+ ti.semanticRun == PASS.initial)
{
error("partial %s `%s` has no type", ti.kind(), toChars());
return true;
{
if (ti.tempdecl &&
ti.semantictiargsdone &&
- ti.semanticRun == PASS.init)
+ ti.semanticRun == PASS.initial)
error("partial %s `%s` has no value", ti.kind(), toChars());
else
if (e1.op == EXP.this_)
{
FuncDeclaration f = hasThis(sc);
- if (f && f.isThis2)
+ if (f && f.hasDualContext())
{
if (f.followInstantiationContext(ad))
{
Expression ex = condexp.expressionSemantic(sc);
if (ex.op == EXP.error)
e = ex;
- else if (e.op == EXP.function_ || e.op == EXP.delegate_)
- {
- // https://issues.dlang.org/show_bug.cgi?id=21285
- // Functions and delegates don't convert correctly with castTo below
- exps[i] = condexp.e1;
- e = condexp.e2;
- }
else
{
// Convert to common type
if (sc._module)
sc._module.hasAlwaysInlines = true;
if (sc.func)
- sc.func.hasAlwaysInlines = true;
+ sc.func.flags |= FUNCFLAG.hasAlwaysInline;
}
const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration();
return setError();
}
- if (sd.hasRegularCtor() && nargs)
+ // https://issues.dlang.org/show_bug.cgi?id=22639
+ // If the new expression has arguments, we either should call a
+ // regular constructor of a copy constructor if the first argument
+ // is the same type as the struct
+ if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf())))
{
FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard);
if (!f || f.errors)
Type tthis = null;
Expression e1org = exp.e1;
- if (exp.e1.op == EXP.comma)
+ if (auto ce = exp.e1.isCommaExp())
{
/* Rewrite (a,b)(args) as (a,(b(args)))
*/
- auto ce = cast(CommaExp)exp.e1;
exp.e1 = ce.e2;
ce.e2 = exp;
result = ce.expressionSemantic(sc);
return;
}
- if (exp.e1.op == EXP.delegate_)
+ if (DelegateExp de = exp.e1.isDelegateExp())
{
- DelegateExp de = cast(DelegateExp)exp.e1;
exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads);
visit(exp);
return;
}
- if (exp.e1.op == EXP.function_)
+ if (FuncExp fe = exp.e1.isFuncExp())
{
if (arrayExpressionSemantic(exp.arguments, sc) || preFunctionParameters(sc, exp.arguments))
return setError();
// Run e1 semantic even if arguments have any errors
- FuncExp fe = cast(FuncExp)exp.e1;
exp.e1 = callExpSemantic(fe, sc, exp.arguments);
if (exp.e1.op == EXP.error)
{
/* This recognizes:
* foo!(tiargs)(funcargs)
*/
- if (exp.e1.op == EXP.scope_)
+ if (ScopeExp se = exp.e1.isScopeExp())
{
- ScopeExp se = cast(ScopeExp)exp.e1;
TemplateInstance ti = se.sds.isTemplateInstance();
if (ti)
{
* expr.foo!(tiargs)(funcargs)
*/
Ldotti:
- if (exp.e1.op == EXP.dotTemplateInstance)
+ if (DotTemplateInstanceExp se = exp.e1.isDotTemplateInstanceExp())
{
- DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)exp.e1;
TemplateInstance ti = se.ti;
{
/* Attempt to instantiate ti. If that works, go with it.
}
else
{
- if (exp.e1.op == EXP.dotIdentifier)
+ if (DotIdExp die = exp.e1.isDotIdExp())
{
- DotIdExp die = cast(DotIdExp)exp.e1;
exp.e1 = die.expressionSemantic(sc);
/* Look for e1 having been rewritten to expr.opDispatch!(string)
* We handle such earlier, so go back.
/* Look for e1 being a lazy parameter
*/
- if (exp.e1.op == EXP.variable)
+ if (VarExp ve = exp.e1.isVarExp())
{
- VarExp ve = cast(VarExp)exp.e1;
if (ve.var.storage_class & STC.lazy_)
{
// lazy parameters can be called without violating purity and safety
exp.e1 = new VarExp(se.loc, se.var, true);
exp.e1 = exp.e1.expressionSemantic(sc);
}
- else if (exp.e1.op == EXP.dot)
+ else if (DotExp de = exp.e1.isDotExp())
{
- DotExp de = cast(DotExp)exp.e1;
-
if (de.e2.op == EXP.overloadSet)
{
ethis = de.e1;
if (sd.ctor)
{
auto ctor = sd.ctor.isCtorDeclaration();
- if (ctor && ctor.isCpCtor && ctor.generated)
+ if (ctor && ctor.isCpCtor && ctor.isGenerated())
sd.ctor = null;
}
If all constructors are copy constructors, then
try default construction.
*/
- if (!sd.hasRegularCtor)
+ if (!sd.hasRegularCtor &&
+ // https://issues.dlang.org/show_bug.cgi?id=22639
+ // we might still have a copy constructor that could be called
+ (*exp.arguments)[0].type.mutableOf != sd.type.mutableOf())
goto Lx;
auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type);
return setError();
}
}
- else if (exp.e1.op == EXP.overloadSet)
+ else if (auto oe = exp.e1.isOverExp())
{
- auto os = (cast(OverExp)exp.e1).vars;
- exp.f = resolveOverloadSet(exp.loc, sc, os, tiargs, tthis, exp.arguments);
+ exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.arguments);
if (!exp.f)
return setError();
if (ethis)
const(char)* p;
Dsymbol s;
exp.f = null;
- if (exp.e1.op == EXP.function_)
+ if (auto fe = exp.e1.isFuncExp())
{
// function literal that direct called is always inferred.
- assert((cast(FuncExp)exp.e1).fd);
- exp.f = (cast(FuncExp)exp.e1).fd;
+ assert(fe.fd);
+ exp.f = fe.fd;
tf = cast(TypeFunction)exp.f.type;
p = "function literal";
}
}
t1 = tf;
}
- else if (exp.e1.op == EXP.variable)
+ else if (VarExp ve = exp.e1.isVarExp())
{
// Do overload resolution
- VarExp ve = cast(VarExp)exp.e1;
-
exp.f = ve.var.isFuncDeclaration();
assert(exp.f);
tiargs = null;
}
// declare dual-context container
- if (exp.f && exp.f.isThis2 && !sc.intypeof && sc.func)
+ if (exp.f && exp.f.hasDualContext() && !sc.intypeof && sc.func)
{
// check access to second `this`
if (AggregateDeclaration ad2 = exp.f.isMember2())
{
auto fileName = FileName(name.toDString);
- if (auto fmResult = FileManager.fileManager.lookup(fileName))
+ if (auto fmResult = global.fileManager.lookup(fileName))
{
se = new StringExp(e.loc, fmResult.data);
}
else
{
- auto readResult = File.read(name);
+ auto readResult = File.read(name.toDString);
if (!readResult.success)
{
e.error("cannot read file `%s`", name);
auto data = readResult.extractSlice();
se = new StringExp(e.loc, data);
- FileBuffer* fileBuffer = FileBuffer.create();
- fileBuffer.data = data;
- FileManager.fileManager.add(fileName, fileBuffer);
+ FileBuffer* fileBuffer = new FileBuffer(data);
+ global.fileManager.add(fileName, fileBuffer);
}
}
}
const op = exp.e1.op;
bool isEqualsCallExpression;
- if (op == EXP.call)
+ if (const callExp = exp.e1.isCallExp())
{
- const callExp = cast(CallExp) exp.e1;
-
// https://issues.dlang.org/show_bug.cgi?id=20331
// callExp.f may be null if the assert contains a call to
// a function pointer or literal
}
else if (t)
{
- result = new IntegerExp(exp.loc, t.alignsize, Type.tsize_t);
+ // Note similarity to getProperty() implementation of __xalignof
+ const explicitAlignment = t.alignment();
+ const naturalAlignment = t.alignsize();
+ const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
+ result = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
}
else if (s)
{
}
if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238
- (!v.needThis() && v.semanticRun > PASS.init))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
+ (!v.needThis() && v.semanticRun > PASS.initial))) // fix https://issues.dlang.org/show_bug.cgi?id=17258
{
// (e1, v)
checkAccess(exp.loc, sc, exp.e1, v);
}
result = e;
// declare dual-context container
- if (f.isThis2 && !sc.intypeof && sc.func)
+ if (f.hasDualContext() && !sc.intypeof && sc.func)
{
// check access to second `this`
if (AggregateDeclaration ad2 = f.isMember2())
if (checkNonAssignmentArrayOp(e.e1))
return setError();
- e.type = Type.tbool;
+ e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
result = e;
}
// 3. Removal of keyword, "delete" can be used for other identities
if (!exp.isRAII)
{
- error(exp.loc, "The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.");
+ error(exp.loc, "the `delete` keyword is obsolete");
+ errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
return setError();
}
*/
if (VarDeclaration v = expToVariable(exp.e1))
{
- if (exp.e1.op == EXP.dotVariable)
+ if (DotVarExp dve = exp.e1.isDotVarExp())
{
- DotVarExp dve = cast(DotVarExp)exp.e1;
+
if ((dve.e1.op == EXP.this_ || dve.e1.op == EXP.super_) &&
!(v.storage_class & STC.ref_))
{
result = exp.e2;
return;
}
- if (exp.e2.op == EXP.template_)
+ if (auto te = exp.e2.isTemplateExp())
{
- auto td = (cast(TemplateExp)exp.e2).td;
- Expression e = new DotTemplateExp(exp.loc, exp.e1, td);
+ Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td);
result = e.expressionSemantic(sc);
return;
}
e.e2 = e.e2.arrayFuncConv(sc);
e.type = e.e2.type;
+ result = e;
+
+ if (sc.flags & SCOPE.Cfile)
+ return;
+
if (e.type is Type.tvoid)
discardValue(e.e1);
- else if (!e.allowCommaExp && !e.isGenerated && !(sc.flags & SCOPE.Cfile))
+ else if (!e.allowCommaExp && !e.isGenerated)
e.error("Using the result of a comma expression is not allowed");
- result = e;
}
override void visit(IntervalExp e)
// OR it in, because it might already be set for C array indexing
exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
}
+ else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray)
+ {
+ if (auto ve = exp.e1.isVarExp())
+ {
+ /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
+ */
+ auto vp = ve.castTo(sc, t1b.isTypeSArray().next.pointerTo());
+ auto e = new AddExp(exp.loc, vp, exp.e2);
+ auto pe = new PtrExp(exp.loc, e);
+ result = pe.expressionSemantic(sc).optimize(WANTvalue);
+ return;
+ }
+ }
}
}
return;
}
- if (exp.e1.op == EXP.slice)
+ if (SliceExp se = exp.e1.isSliceExp())
{
- SliceExp se = cast(SliceExp)exp.e1;
if (se.e1.type.toBasetype().ty == Tsarray)
{
exp.error("cannot append to static array `%s`", se.e1.type.toChars());
e1x = e1x.optimize(WANTvalue);
if (e1x.toBool().hasValue(exp.op == EXP.orOr))
{
- result = IntegerExp.createBool(exp.op == EXP.orOr);
+ if (sc.flags & SCOPE.Cfile)
+ result = new IntegerExp(exp.op == EXP.orOr);
+ else
+ result = IntegerExp.createBool(exp.op == EXP.orOr);
return;
}
}
if (e2x.type.ty == Tvoid)
exp.type = Type.tvoid;
else
- exp.type = Type.tbool;
+ exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
exp.e1 = e1x;
exp.e2 = e2x;
if (f1 || f2)
return setError();
- exp.type = Type.tbool;
+ exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
// Special handling for array comparisons
Expression arrayLowering = null;
if (f1 || f2)
return setError();
- exp.type = Type.tbool;
+ exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
if (!isArrayComparison)
{
return;
}
- if (exp.econd.op == EXP.dotIdentifier)
- (cast(DotIdExp)exp.econd).noderef = true;
+ if (auto die = exp.econd.isDotIdExp())
+ die.noderef = true;
Expression ec = exp.econd.expressionSemantic(sc);
ec = resolveProperties(sc, ec);
if (e.op == EXP.error)
return e;
- if (e.op == EXP.dotVariable)
+ if (DotVarExp dve = e.isDotVarExp())
{
- DotVarExp dve = cast(DotVarExp)e;
if (FuncDeclaration fd = dve.var.isFuncDeclaration())
{
if (TemplateDeclaration td = fd.findTemplateDeclRoot())
}
}
- if (e.op == EXP.dotTemplateDeclaration)
+ if (DotTemplateExp dte = e.isDotTemplateExp())
{
- DotTemplateExp dte = cast(DotTemplateExp)e;
exp.e1 = dte.e1; // pull semantic() result
exp.ti.tempdecl = dte.td;
return new ScopeExp(exp.loc, exp.ti)
.expressionSemantic(sc);
}
- else if (e.op == EXP.dot)
+ else if (DotExp de = e.isDotExp())
{
- DotExp de = cast(DotExp)e;
-
if (de.e2.op == EXP.overloadSet)
{
if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc))
.expressionSemantic(sc);
}
}
- else if (e.op == EXP.overloadSet)
+ else if (OverExp oe = e.isOverExp())
{
- OverExp oe = cast(OverExp)e;
exp.ti.tempdecl = oe.vars;
return new ScopeExp(exp.loc, exp.ti)
.expressionSemantic(sc);
{
n++;
e1 = new VarExp(loc, f.vthis);
- if (f.isThis2)
+ if (f.hasDualContext())
{
// (*__this)[i]
if (n > 1)
default:
// Default is 'yes' - do nothing
- Expression e = exp;
- Type t = exp.type;
+ Expression e = arrayFuncConv(exp, sc);
+ Type t = e.type;
Type tb = t.toBasetype();
Type att = null;
enum package_d = "package." ~ mars_ext;
enum package_di = "package." ~ hdr_ext;
-struct FileManager
+final class FileManager
{
private StringTable!(FileBuffer*) files;
- private __gshared bool initialized = false;
+
+ ///
+ public this () nothrow
+ {
+ this.files._init();
+ }
nothrow:
/********************************************
*/
const(FileBuffer)* lookup(FileName filename)
{
- if (!initialized)
- FileManager._init();
-
const name = filename.toString;
if (auto val = files.lookup(name))
return val.value;
*/
const(char)[][] getLines(FileName file)
{
- if (!initialized)
- FileManager._init();
-
const(char)[][] lines;
if (const buffer = lookup(file))
{
*/
FileBuffer* add(FileName filename, FileBuffer* filebuffer)
{
- if (!initialized)
- FileManager._init();
-
auto val = files.insert(filename.toString, filebuffer);
return val == null ? null : val.value;
}
-
- __gshared fileManager = FileManager();
-
- // Initialize the global FileManager singleton
- private void _init()
- {
- if (!initialized)
- {
- fileManager.initialize();
- initialized = true;
- }
- }
-
- void initialize()
- {
- files._init();
- }
}
private FileBuffer readFromStdin() nothrow
override void visit(TryFinallyStatement s)
{
DtorExpStatement des;
- if (fd.nrvo_can && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
+ if (fd.isNRVO() && s.finalbody && (des = s.finalbody.isDtorExpStatement()) !is null &&
fd.nrvo_var == des.var)
{
if (!(global.params.useExceptions && ClassDeclaration.throwable))
catches.push(ctch);
Statement s2 = new TryCatchStatement(Loc.initial, s._body, catches);
- fd.eh_none = false;
+ fd.flags &= ~FUNCFLAG.noEH;
replaceCurrent(s2);
s2.accept(this);
}
printf = 0x200, /// is a printf-like function
scanf = 0x400, /// is a scanf-like function
noreturn = 0x800, /// the function does not return
+ NRVO = 0x1000, /// Support for named return value optimization
+ naked = 0x2000, /// The function is 'naked' (see inline ASM)
+ generated = 0x4000, /// The function is compiler generated (e.g. `opCmp`)
+ introducing = 0x8000, /// If this function introduces the overload set
+ semantic3Errors = 0x10000, /// If errors in semantic3 this function's frame ptr
+ noEH = 0x20000, /// No exception unwinding is needed
+ inferRetType = 0x40000, /// Return type is to be inferred
+ dualContext = 0x80000, /// has a dual-context 'this' parameter
+ hasAlwaysInline = 0x100000, /// Contains references to functions that must be inlined
+ CRTCtor = 0x200000, /// Has attribute pragma(crt_constructor)
+ CRTDtor = 0x400000, /// Has attribute pragma(crt_destructor)
}
/***********************************************************
// scopes from having the same name
DsymbolTable localsymtab;
VarDeclaration vthis; /// 'this' parameter (member and nested)
- bool isThis2; /// has a dual-context 'this' parameter
VarDeclaration v_arguments; /// '_arguments' parameter
VarDeclaration v_argptr; /// '_argptr' variable
FuncDeclaration overnext0; /// next in overload list (only used during IFTI)
Loc endloc; /// location of closing curly bracket
int vtblIndex = -1; /// for member functions, index into vtbl[]
- bool naked; /// true if naked
- bool generated; /// true if function was generated by the compiler rather than
- /// supplied by the user
- bool hasAlwaysInlines; /// contains references to functions that must be inlined
- ubyte isCrtCtorDtor; /// has attribute pragma(crt_constructor(1)/crt_destructor(2))
- /// not set before the glue layer
ILS inlineStatusStmt = ILS.uninitialized;
ILS inlineStatusExp = ILS.uninitialized;
PINLINE inlining = PINLINE.default_;
int inlineNest; /// !=0 if nested inline
- bool eh_none; /// true if no exception unwinding is needed
- bool semantic3Errors; /// true if errors in semantic3 this function's frame ptr
ForeachStatement fes; /// if foreach body, this is the foreach
BaseClass* interfaceVirtual; /// if virtual, but only appears in base interface vtbl[]
- bool introducing; /// true if 'introducing' function
/** if !=NULL, then this is the type
of the 'introducing' function
this one is overriding
*/
Type tintro;
- bool inferRetType; /// true if return type is to be inferred
StorageClass storage_class2; /// storage class for template onemember's
// Things that should really go into Scope
/// 16 if there are multiple return statements
int hasReturnExp;
- // Support for NRVO (named return value optimization)
- bool nrvo_can = true; /// true means we can do NRVO
VarDeclaration nrvo_var; /// variable to replace with shidden
Symbol* shidden; /// hidden pointer passed to function
FuncDeclarations *inlinedNestedCallees;
- uint flags; /// FUNCFLAG.xxxxx
+ /// Function flags: A collection of boolean packed for memory efficiency
+ /// See the `FUNCFLAG` enum
+ uint flags = FUNCFLAG.NRVO;
/**
* Data for a function declaration that is needed for the Objective-C
/* The type given for "infer the return type" is a TypeFunction with
* NULL for the return type.
*/
- inferRetType = (type && type.nextOf() is null);
+ if (type && type.nextOf() is null)
+ this.flags |= FUNCFLAG.inferRetType;
}
static FuncDeclaration create(const ref Loc loc, const ref Loc endloc, Identifier id, StorageClass storage_class, Type type, bool noreturn = false)
return false;
}
- return !errors && !semantic3Errors;
+ return !errors && !this.hasSemantic3Errors();
}
/****************************************************
*/
extern (D) final void declareThis(Scope* sc)
{
- isThis2 = toParent2() != toParentLocal();
+ const bool dualCtx = (toParent2() != toParentLocal());
+ if (dualCtx)
+ this.flags |= FUNCFLAG.dualContext;
auto ad = isThis();
- if (!isThis2 && !ad && !isNested())
+ if (!dualCtx && !ad && !isNested())
{
vthis = null;
objc.selectorParameter = null;
return t.addMod(type.mod).addStorageClass(storage_class);
}
- if (isThis2 || isNested())
+ if (dualCtx || isNested())
{
/* The 'this' for a nested function is the link to the
* enclosing function's stack frame.
* Note that nested functions and member functions are disjoint.
*/
- Type tthis = addModStc(isThis2 ?
+ Type tthis = addModStc(dualCtx ?
Type.tvoidptr.sarrayOf(2).pointerTo() :
Type.tvoid.pointerTo());
- vthis = new VarDeclaration(loc, tthis, isThis2 ? Id.this2 : Id.capture, null);
+ vthis = new VarDeclaration(loc, tthis, dualCtx ? Id.this2 : Id.capture, null);
vthis.storage_class |= STC.parameter | STC.nodtor;
}
else if (ad)
if (thandle.ty == Tstruct)
{
vthis.storage_class |= STC.ref_;
-
- /* if member function is marked 'inout', then 'this' is 'return ref'
- * The same thing is done for `ref inout` parameters in TypeFunction's semantic routine.
- */
- if (auto tf = type.isTypeFunction())
- {
- /* This feature was a mistake, but existing code relies on it.
- * So only disable it in @safe code and DIP1000 code
- */
- if (!(global.params.useDIP1000 == FeatureState.enabled &&
- tf.trust == TRUST.safe))
- {
- if (tf.isInOutQual())
- vthis.storage_class |= STC.return_;
- }
- }
}
}
vthis.storage_class |= STC.return_;
if (tf.isScopeQual)
vthis.storage_class |= STC.scope_;
-
- /* Add STC.returnScope like typesem.d does for TypeFunction parameters,
- * at least it should be the same. At the moment, we'll just
- * do existing practice. But we should examine how TypeFunction does
- * it, for consistency.
- */
- if (global.params.useDIP1000 != FeatureState.enabled &&
- !tf.isref && isRefReturnScope(vthis.storage_class))
- {
- /* if `ref return scope`, evaluate to `ref` `return scope`
- */
+ if (tf.isreturnscope)
vthis.storage_class |= STC.returnScope;
- }
}
if (flags & FUNCFLAG.inferScope && !(vthis.storage_class & STC.scope_))
vthis.storage_class |= STC.maybescope;
if (!tf.isnogc)
flags |= FUNCFLAG.nogcInprocess;
- if (!isVirtual() || introducing)
+ if (!isVirtual() || this.isIntroducing())
flags |= FUNCFLAG.returnInprocess;
// Initialize for inferring STC.scope_
return !(flags & FUNCFLAG.nogcInprocess) && isNogc();
}
+ final bool isNRVO() const scope @safe pure nothrow @nogc
+ {
+ return !!(this.flags & FUNCFLAG.NRVO);
+ }
+
+ final void isNRVO(bool v) pure nothrow @safe @nogc
+ {
+ if (v) this.flags |= FUNCFLAG.NRVO;
+ else this.flags &= ~FUNCFLAG.NRVO;
+ }
+
+ final bool isNaked() const scope @safe pure nothrow @nogc
+ {
+ return !!(this.flags & FUNCFLAG.naked);
+ }
+
+ final bool isGenerated() const scope @safe pure nothrow @nogc
+ {
+ return !!(this.flags & FUNCFLAG.generated);
+ }
+
+ final void isGenerated(bool v) pure nothrow @safe @nogc
+ {
+ if (v) this.flags |= FUNCFLAG.generated;
+ else this.flags &= ~FUNCFLAG.generated;
+ }
+
+ final bool isIntroducing() const scope @safe pure nothrow @nogc
+ {
+ return !!(this.flags & FUNCFLAG.introducing);
+ }
+
+ final bool hasSemantic3Errors() const scope @safe pure nothrow @nogc
+ {
+ return !!(this.flags & FUNCFLAG.semantic3Errors);
+ }
+
+ final bool hasNoEH() const scope @safe pure nothrow @nogc
+ {
+ return !!(this.flags & FUNCFLAG.noEH);
+ }
+
+ final bool inferRetType() const scope @safe pure nothrow @nogc
+ {
+ return !!(this.flags & FUNCFLAG.inferRetType);
+ }
+
+ final bool hasDualContext() const scope @safe pure nothrow @nogc
+ {
+ return !!(this.flags & FUNCFLAG.dualContext);
+ }
+
+ final bool hasAlwaysInlines() const scope @safe pure nothrow @nogc
+ {
+ return !!(this.flags & FUNCFLAG.hasAlwaysInline);
+ }
+
+ final bool isCrtCtor() const scope @safe pure nothrow @nogc
+ {
+ return !!(this.flags & FUNCFLAG.CRTCtor);
+ }
+
+ final bool isCrtDtor() const scope @safe pure nothrow @nogc
+ {
+ return !!(this.flags & FUNCFLAG.CRTDtor);
+ }
+
/**************************************
* The function is doing something that may allocate with the GC,
* so mark it as not nogc (not no-how).
{
auto ad = isThis();
ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
- return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !naked);
+ return (ad && !(cd && cd.isCPPclass()) && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !this.isNaked());
}
bool addPostInvariant()
{
auto ad = isThis();
ClassDeclaration cd = ad ? ad.isClassDeclaration() : null;
- return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !naked);
+ return (ad && !(cd && cd.isCPPclass()) && ad.inv && global.params.useInvariants == CHECKENABLE.on && (visibility.kind == Visibility.Kind.protected_ || visibility.kind == Visibility.Kind.public_ || visibility.kind == Visibility.Kind.export_) && !this.isNaked());
}
override const(char)* kind() const
{
- return generated ? "generated function" : "function";
+ return this.isGenerated() ? "generated function" : "function";
}
/********************************************
vresult.parent = this;
}
- if (sc && vresult.semanticRun == PASS.init)
+ if (sc && vresult.semanticRun == PASS.initial)
{
TypeFunction tf = type.toTypeFunction();
if (tf.isref)
return fd;
}
- /******************
- * Check parameters and return type of D main() function.
- * Issue error messages.
- */
- extern (D) final void checkDmain()
- {
+ /+
+ + Checks the parameter and return types iff this is a `main` function.
+ +
+ + The following signatures are allowed for a `D main`:
+ + - Either no or a single parameter of type `string[]`
+ + - Return type is either `void`, `int` or `noreturn`
+ +
+ + The following signatures are standard C:
+ + - `int main()`
+ + - `int main(int, char**)`
+ +
+ + This function accepts the following non-standard extensions:
+ + - `char** envp` as a third parameter
+ + - `void` / `noreturn` as return type
+ +
+ + This function will issue errors for unexpected arguments / return types.
+ +/
+ extern (D) final void checkMain()
+ {
+ if (ident != Id.main || isMember() || isNested())
+ return; // Not a main function
+
TypeFunction tf = type.toTypeFunction();
+
+ Type retType = tf.nextOf();
+ if (!retType)
+ {
+ // auto main(), check after semantic
+ assert(this.inferRetType);
+ return;
+ }
+
+ /// Checks whether `t` is equivalent to `char**`
+ /// Ignores qualifiers and treats enums according to their base type
+ static bool isCharPtrPtr(Type t)
+ {
+ auto tp = t.toBasetype().isTypePointer();
+ if (!tp)
+ return false;
+
+ tp = tp.next.toBasetype().isTypePointer();
+ if (!tp)
+ return false;
+
+ return tp.next.toBasetype().ty == Tchar;
+ }
+
+ // Neither of these qualifiers is allowed because they affect the ABI
+ enum invalidSTC = STC.out_ | STC.ref_ | STC.lazy_;
+
const nparams = tf.parameterList.length;
bool argerr;
- if (nparams == 1)
+
+ if (linkage == LINK.d)
{
- auto fparam0 = tf.parameterList[0];
- auto t = fparam0.type.toBasetype();
- if (t.ty != Tarray ||
- t.nextOf().ty != Tarray ||
- t.nextOf().nextOf().ty != Tchar ||
- fparam0.storageClass & (STC.out_ | STC.ref_ | STC.lazy_))
+ if (nparams == 1)
{
- argerr = true;
+ auto fparam0 = tf.parameterList[0];
+ auto t = fparam0.type.toBasetype();
+ if (t.ty != Tarray ||
+ t.nextOf().ty != Tarray ||
+ t.nextOf().nextOf().ty != Tchar ||
+ fparam0.storageClass & invalidSTC)
+ {
+ argerr = true;
+ }
}
+
+ if (tf.parameterList.varargs || nparams >= 2 || argerr)
+ error("parameter list must be empty or accept one parameter of type `string[]`");
}
- if (!tf.nextOf())
- // auto main(), check after semantic
- assert(this.inferRetType);
- else if (tf.nextOf().ty != Tint32 && tf.nextOf().ty != Tvoid && tf.nextOf().ty != Tnoreturn)
+ else if (linkage == LINK.c)
+ {
+ if (nparams == 2 || nparams == 3)
+ {
+ // Argument count must be int
+ auto argCount = tf.parameterList[0];
+ argerr |= !!(argCount.storageClass & invalidSTC);
+ argerr |= argCount.type.toBasetype().ty != Tint32;
+
+ // Argument pointer must be char**
+ auto argPtr = tf.parameterList[1];
+ argerr |= !!(argPtr.storageClass & invalidSTC);
+ argerr |= !isCharPtrPtr(argPtr.type);
+
+ // `char** environ` is a common extension, see J.5.1 of the C standard
+ if (nparams == 3)
+ {
+ auto envPtr = tf.parameterList[2];
+ argerr |= !!(envPtr.storageClass & invalidSTC);
+ argerr |= !isCharPtrPtr(envPtr.type);
+ }
+ }
+ else
+ argerr = nparams != 0;
+
+ // Disallow variadic main() - except for K&R declarations in C files.
+ // E.g. int main(), int main(argc, argv) int argc, char** argc { ... }
+ if (tf.parameterList.varargs && (!this.isCsymbol() || (!tf.parameterList.hasIdentifierList && nparams)))
+ argerr |= true;
+
+ if (argerr)
+ {
+ error("parameters must match one of the following signatures");
+ loc.errorSupplemental("`main()`");
+ loc.errorSupplemental("`main(int argc, char** argv)`");
+ loc.errorSupplemental("`main(int argc, char** argv, char** environ)` [POSIX extension]");
+ }
+ }
+ else
+ return; // Neither C nor D main, ignore (should probably be an error)
+
+ // Allow enums with appropriate base types (same ABI)
+ retType = retType.toBasetype();
+
+ if (retType.ty != Tint32 && retType.ty != Tvoid && retType.ty != Tnoreturn)
error("must return `int`, `void` or `noreturn`, not `%s`", tf.nextOf().toChars());
- else if (tf.parameterList.varargs || nparams >= 2 || argerr)
- error("parameters must be `main()` or `main(string[] args)`");
}
/***********************************************
*/
final bool checkNRVO()
{
- if (!nrvo_can || returns is null)
+ if (!isNRVO() || returns is null)
return false;
auto tf = type.toTypeFunction();
if (auto ve = rs.exp.isVarExp())
{
auto v = ve.var.isVarDeclaration();
- if (!v || v.isOut() || v.isRef())
+ if (!v || v.isReference())
return false;
else if (nrvo_var is null)
{
// parameters and closure variables cannot be NRVOed.
if (v.isDataseg() || v.isParameter() || v.toParent2() != this)
return false;
+ if (v.nestedrefs.length && needsClosure())
+ return false;
// The variable type needs to be equivalent to the return type.
if (!v.type.equivalent(tf.next))
return false;
import dmd.root.array;
import dmd.root.filename;
import dmd.common.outbuffer;
+import dmd.file_manager;
import dmd.identifier;
/// Defines a setting for how compiler warnings and deprecations are handled
bool hasMainFunction; /// Whether a main function has already been compiled in (for -main switch)
uint varSequenceNumber = 1; /// Relative lifetime of `VarDeclaration` within a function, used for `scope` checks
+ /// Cache files read from disk
+ FileManager fileManager;
+
enum recursionLimit = 500; /// number of recursive template expansions before abort
nothrow:
extern (C++) void _init()
{
+ this.fileManager = new FileManager();
version (MARS)
{
vendor = "Digital Mars D";
// Can't include arraytypes.h here, need to declare these directly.
template <typename TYPE> struct Array;
+class FileManager;
+
typedef unsigned char Diagnostic;
enum
{
bool hasMainFunction;
unsigned varSequenceNumber;
+ FileManager* fileManager;
+
/* Start gagging. Return the current number of gagged errors
*/
unsigned startGagging();
t = te.sym.memtype;
goto L1;
}
+ case Tchar:
case Twchar:
- // BUG: need to cast(wchar)
case Tdchar:
- // BUG: need to cast(dchar)
- if (cast(uinteger_t)v > 0xFF)
- {
- buf.printf("'\\U%08llx'", cast(long)v);
- break;
- }
- goto case;
- case Tchar:
{
- size_t o = buf.length;
- if (v == '\'')
- buf.writestring("'\\''");
- else if (isprint(cast(int)v) && v != '\\')
- buf.printf("'%c'", cast(int)v);
- else
- buf.printf("'\\x%02x'", cast(int)v);
+ const o = buf.length;
+ writeSingleCharLiteral(*buf, cast(dchar) v);
if (hgs.ddoc)
escapeDdocString(buf, o);
break;
bool result = false;
if (stc & STC.scopeinferred)
+ {
+ //buf.writestring("scope-inferred ");
stc &= ~(STC.scope_ | STC.scopeinferred);
+ }
if (stc & STC.returninferred)
+ {
+ //buf.writestring("return-inferred ");
stc &= ~(STC.return_ | STC.returninferred);
+ }
/* Put scope ref return into a standard order
*/
if (tf1.parameterList.length == 0 && tf2.parameterList.length == 0)
return true;
- if (!tf1.nextOf().equals(tf2.nextOf()))
+ if (!cTypeEquivalence(tf1.next, tf2.next))
return false; // function return types don't match
if (tf1.parameterList.length != tf2.parameterList.length)
//printf("t2: %s\n", tf2.toChars());
return true;
}
+
+/*******************************
+ * Types haven't been merged yet, because we haven't done
+ * semantic() yet.
+ * But we still need to see if t1 and t2 are the same type.
+ * Params:
+ * t1 = first type
+ * t2 = second type
+ * Returns:
+ * true if they are equivalent types
+ */
+bool cTypeEquivalence(Type t1, Type t2)
+{
+ if (t1.equals(t2))
+ return true; // that was easy
+
+ if (t1.ty != t2.ty || t1.mod != t2.mod)
+ return false;
+
+ if (auto tp = t1.isTypePointer())
+ return cTypeEquivalence(tp.next, t2.nextOf());
+
+ if (auto ta = t1.isTypeSArray())
+ // Bug: should check array dimension
+ return cTypeEquivalence(ta.next, t2.nextOf());
+
+ if (auto ts = t1.isTypeStruct())
+ return ts.sym is t2.isTypeStruct().sym;
+
+ if (auto te = t1.isTypeEnum())
+ return te.sym is t2.isTypeEnum().sym;
+
+ if (auto tf = t1.isTypeFunction())
+ return cFuncEquivalence(tf, tf.isTypeFunction());
+
+ return false;
+}
void accept(Visitor *v) { v->visit(this); }
};
-Expression *initializerToExpression(Initializer *init, Type *t = NULL);
+Expression *initializerToExpression(Initializer *init, Type *t = NULL, const bool isCfile = false);
* Params:
* init = `Initializer` AST node
* itype = if not `null`, type to coerce expression to
+ * isCfile = default initializers are different with C
* Returns:
* `Expression` created, `null` if cannot, `ErrorExp` for other errors
*/
-extern (C++) Expression initializerToExpression(Initializer init, Type itype = null)
+extern (C++) Expression initializerToExpression(Initializer init, Type itype = null, const bool isCfile = false)
{
Expression visitVoid(VoidInitializer)
{
if (!init.type) // don't know what type to use
return null;
if (!defaultInit)
- defaultInit = (cast(TypeNext)t).next.defaultInit(Loc.initial);
+ defaultInit = (cast(TypeNext)t).next.defaultInit(Loc.initial, isCfile);
element = defaultInit;
}
}
bool doDocComment; // collect doc comment information
bool anyToken; // seen at least one token
bool commentToken; // comments are TOK.comment's
+ bool tokenizeNewlines; // newlines are turned into TOK.endOfLine's
version (DMDLIB)
{
line = p;
this.doDocComment = doDocComment;
this.commentToken = commentToken;
+ this.tokenizeNewlines = false;
this.inTokenStringConstant = 0;
this.lastDocLine = 0;
//initKeywords();
/****************************
* Turn next token in buffer into a token.
+ * Params:
+ * t = the token to set the resulting Token to
*/
final void scan(Token* t)
{
case '\r':
p++;
if (*p != '\n') // if CR stands by itself
+ {
endOfLine();
+ if (tokenizeNewlines)
+ {
+ t.value = TOK.endOfLine;
+ tokenizeNewlines = false;
+ return;
+ }
+ }
version (DMDLIB)
{
if (whitespaceToken)
case '\n':
p++;
endOfLine();
+ if (tokenizeNewlines)
+ {
+ t.value = TOK.endOfLine;
+ tokenizeNewlines = false;
+ return;
+ }
version (DMDLIB)
{
if (whitespaceToken)
return;
case '#':
{
+ // https://issues.dlang.org/show_bug.cgi?id=22825
+ // Special token sequences are terminated by newlines,
+ // and should not be skipped over.
+ this.tokenizeNewlines = true;
p++;
if (parseSpecialTokenSequence())
continue;
{
endOfLine();
p++;
+ if (tokenizeNewlines)
+ {
+ t.value = TOK.endOfLine;
+ tokenizeNewlines = false;
+ return;
+ }
continue;
}
}
{
auto linnum = this.scanloc.linnum;
const(char)* filespec = null;
- const loc = this.loc();
bool flags;
if (!linemarker)
scan(&tok);
if (tok.value == TOK.int32Literal || tok.value == TOK.int64Literal)
{
- const lin = cast(int)(tok.unsvalue - 1);
- if (lin != tok.unsvalue - 1)
- error("line number `%lld` out of range", cast(ulong)tok.unsvalue);
+ const lin = cast(int)(tok.unsvalue);
+ if (lin != tok.unsvalue)
+ {
+ error(tok.loc, "line number `%lld` out of range", cast(ulong)tok.unsvalue);
+ skipToNextLine();
+ return;
+ }
else
linnum = lin;
}
{
}
else
- goto Lerr;
+ {
+ error(tok.loc, "positive integer argument expected following `#line`");
+ if (tok.value != TOK.endOfLine)
+ skipToNextLine();
+ return;
+ }
while (1)
{
- switch (*p)
+ scan(&tok);
+ switch (tok.value)
{
- case 0:
- case 0x1A:
- case '\n':
- Lnewline:
+ case TOK.endOfFile:
+ case TOK.endOfLine:
if (!inTokenStringConstant)
{
this.scanloc.linnum = linnum;
this.scanloc.filename = filespec;
}
return;
- case '\r':
- p++;
- if (*p != '\n')
- {
- p--;
- goto Lnewline;
- }
- continue;
- case ' ':
- case '\t':
- case '\v':
- case '\f':
- p++;
- continue; // skip white space
- case '_':
+ case TOK.file:
if (filespec || flags)
goto Lerr;
- if (memcmp(p, "__FILE__".ptr, 8) == 0)
- {
- p += 8;
- filespec = mem.xstrdup(scanloc.filename);
- continue;
- }
- goto Lerr;
- case '"':
+ filespec = mem.xstrdup(scanloc.filename);
+ continue;
+ case TOK.string_:
if (filespec || flags)
goto Lerr;
- stringbuffer.setsize(0);
- p++;
- while (1)
- {
- uint c;
- c = *p;
- switch (c)
- {
- case '\n':
- case '\r':
- case 0:
- case 0x1A:
- goto Lerr;
- case '"':
- stringbuffer.writeByte(0);
- filespec = mem.xstrdup(cast(const(char)*)stringbuffer[].ptr);
- p++;
- break;
- default:
- if (c & 0x80)
- {
- uint u = decodeUTF();
- if (u == PS || u == LS)
- goto Lerr;
- }
- stringbuffer.writeByte(c);
- p++;
- continue;
- }
- break;
- }
- continue;
-
- case '1':
- case '2':
- case '3':
- case '4':
- if (!linemarker)
+ if (tok.ptr[0] != '"' || tok.postfix != 0)
goto Lerr;
- flags = true; // linemarker flags seen
- ++p;
- if ('0' <= *p && *p <= '9')
- goto Lerr; // only one digit allowed
+ filespec = tok.ustring;
continue;
-
- default:
- if (*p & 0x80)
+ case TOK.int32Literal:
+ if (!filespec)
+ goto Lerr;
+ if (linemarker && tok.unsvalue >= 1 && tok.unsvalue <= 4)
{
- uint u = decodeUTF();
- if (u == PS || u == LS)
- goto Lnewline;
+ flags = true; // linemarker flags seen
+ continue;
}
goto Lerr;
+ default:
+ goto Lerr;
}
}
Lerr:
- if (linemarker)
- error(loc, "# integer [\"filespec\"] { 1 | 2 | 3 | 4 }\\n expected");
- else
- error(loc, "#line integer [\"filespec\"]\\n expected");
+ if (filespec is null)
+ error(tok.loc, "invalid filename for `#line` directive");
+ else if (linemarker)
+ error(tok.loc, "invalid flag for line marker directive");
+ else if (!Ccompile)
+ error(tok.loc, "found `%s` when expecting new line following `#line` directive", tok.toChars());
+ if (tok.value != TOK.endOfLine)
+ skipToNextLine();
}
/***************************************
break;
}
endOfLine();
+ tokenizeNewlines = false;
}
/********************************************
if (auto p = getenv("SOURCE_DATE_EPOCH"))
{
if (!ct.parseDigits(p.toDString()))
- error(loc, "Value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p);
+ error(loc, "value of environment variable `SOURCE_DATE_EPOCH` should be a valid UNIX timestamp, not: `%s`", p);
}
else
.time(&ct);
ParameterList parameterList; // function parameters
+ // These flags can be accessed like `bool` properties,
+ // getters and setters are generated for them
private enum FunctionFlag : uint
{
none = 0,
isproperty = 0x0004, // can be called without parentheses
isref = 0x0008, // returns a reference
isreturn = 0x0010, // 'this' is returned by ref
- isscope = 0x0020, // 'this' is scope
+ isScopeQual = 0x0020, // 'this' is scope
isreturninferred= 0x0040, // 'this' is return from inference
isscopeinferred = 0x0080, // 'this' is scope from inference
islive = 0x0100, // is @live
incomplete = 0x0200, // return type or default arguments removed
- inoutParam = 0x0400, // inout on the parameters
- inoutQual = 0x0800, // inout on the qualifier
+ isInOutParam = 0x0400, // inout on the parameters
+ isInOutQual = 0x0800, // inout on the qualifier
isctor = 0x1000, // the function is a constructor
isreturnscope = 0x2000, // `this` is returned by value
}
{
// Check escaping through return value
Type tret = nextOf().toBasetype();
- if (isref || tret.hasPointers())
+ if (isref || tret.hasPointers() || !isnothrow())
{
return stc;
}
return false;
}
- /// set or get if the function has the `nothrow` attribute
- bool isnothrow() const pure nothrow @safe @nogc
- {
- return (funcFlags & FunctionFlag.isnothrow) != 0;
- }
- /// ditto
- void isnothrow(bool v) pure nothrow @safe @nogc
- {
- if (v) funcFlags |= FunctionFlag.isnothrow;
- else funcFlags &= ~FunctionFlag.isnothrow;
- }
-
- /// set or get if the function has the `@nogc` attribute
- bool isnogc() const pure nothrow @safe @nogc
- {
- return (funcFlags & FunctionFlag.isnogc) != 0;
- }
- /// ditto
- void isnogc(bool v) pure nothrow @safe @nogc
- {
- if (v) funcFlags |= FunctionFlag.isnogc;
- else funcFlags &= ~FunctionFlag.isnogc;
- }
-
- /// set or get if the function has the `@property` attribute
- bool isproperty() const pure nothrow @safe @nogc
- {
- return (funcFlags & FunctionFlag.isproperty) != 0;
- }
- /// ditto
- void isproperty(bool v) pure nothrow @safe @nogc
- {
- if (v) funcFlags |= FunctionFlag.isproperty;
- else funcFlags &= ~FunctionFlag.isproperty;
- }
-
- /// set or get if the function has the `ref` attribute
- bool isref() const pure nothrow @safe @nogc
- {
- return (funcFlags & FunctionFlag.isref) != 0;
- }
- /// ditto
- void isref(bool v) pure nothrow @safe @nogc
- {
- if (v) funcFlags |= FunctionFlag.isref;
- else funcFlags &= ~FunctionFlag.isref;
- }
-
- /// set or get if the function has the `return` attribute
- bool isreturn() const pure nothrow @safe @nogc
- {
- return (funcFlags & FunctionFlag.isreturn) != 0;
- }
- /// ditto
- void isreturn(bool v) pure nothrow @safe @nogc
- {
- if (v) funcFlags |= FunctionFlag.isreturn;
- else funcFlags &= ~FunctionFlag.isreturn;
- }
-
- /// set or get if the function has the `returnscope` attribute
- bool isreturnscope() const pure nothrow @safe @nogc
- {
- return (funcFlags & FunctionFlag.isreturnscope) != 0;
- }
- /// ditto
- void isreturnscope(bool v) pure nothrow @safe @nogc
- {
- if (v) funcFlags |= FunctionFlag.isreturnscope;
- else funcFlags &= ~FunctionFlag.isreturnscope;
- }
-
- /// set or get if the function has the `scope` attribute
- bool isScopeQual() const pure nothrow @safe @nogc
- {
- return (funcFlags & FunctionFlag.isscope) != 0;
- }
- /// ditto
- void isScopeQual(bool v) pure nothrow @safe @nogc
- {
- if (v) funcFlags |= FunctionFlag.isscope;
- else funcFlags &= ~FunctionFlag.isscope;
- }
-
- /// set or get if the function has the `return` attribute inferred
- bool isreturninferred() const pure nothrow @safe @nogc
- {
- return (funcFlags & FunctionFlag.isreturninferred) != 0;
- }
- /// ditto
- void isreturninferred(bool v) pure nothrow @safe @nogc
- {
- if (v) funcFlags |= FunctionFlag.isreturninferred;
- else funcFlags &= ~FunctionFlag.isreturninferred;
- }
-
- /// set or get if the function has the `scope` attribute inferred
- bool isscopeinferred() const pure nothrow @safe @nogc
- {
- return (funcFlags & FunctionFlag.isscopeinferred) != 0;
- }
- /// ditoo
- void isscopeinferred(bool v) pure nothrow @safe @nogc
- {
- if (v) funcFlags |= FunctionFlag.isscopeinferred;
- else funcFlags &= ~FunctionFlag.isscopeinferred;
- }
-
- /// set or get if the function has the `@live` attribute
- bool islive() const pure nothrow @safe @nogc
- {
- return (funcFlags & FunctionFlag.islive) != 0;
- }
- /// ditto
- void islive(bool v) pure nothrow @safe @nogc
- {
- if (v) funcFlags |= FunctionFlag.islive;
- else funcFlags &= ~FunctionFlag.islive;
- }
-
- /// set or get if the return type or the default arguments are removed
- bool incomplete() const pure nothrow @safe @nogc
- {
- return (funcFlags & FunctionFlag.incomplete) != 0;
- }
- /// ditto
- void incomplete(bool v) pure nothrow @safe @nogc
- {
- if (v) funcFlags |= FunctionFlag.incomplete;
- else funcFlags &= ~FunctionFlag.incomplete;
- }
-
- /// set or get if the function has the `inout` on the parameters
- bool isInOutParam() const pure nothrow @safe @nogc
- {
- return (funcFlags & FunctionFlag.inoutParam) != 0;
- }
- /// ditto
- void isInOutParam(bool v) pure nothrow @safe @nogc
- {
- if (v) funcFlags |= FunctionFlag.inoutParam;
- else funcFlags &= ~FunctionFlag.inoutParam;
- }
+ // Generate getter / setter functions for `FunctionFlag` members so they can be
+ // treated like regular `bool` fields, instead of requiring bit twiddling to read/write
+ extern (D) mixin(() {
+ string result = "extern(C++) pure nothrow @safe @nogc {";
+ foreach (string mem; __traits(allMembers, FunctionFlag))
+ {
+ result ~= "
+ /// set or get if the function has the FunctionFlag attribute of the same name
+ bool "~mem~"() const { return (funcFlags & FunctionFlag."~mem~") != 0; }
+ /// ditto
+ void "~mem~"(bool v)
+ {
+ if (v) funcFlags |= FunctionFlag."~mem~";
+ else funcFlags &= ~FunctionFlag."~mem~";
+ }";
+ }
+ return result ~ "}\n";
+ }());
- /// set or get if the function has the `inout` on the parameters
- bool isInOutQual() const pure nothrow @safe @nogc
- {
- return (funcFlags & FunctionFlag.inoutQual) != 0;
- }
- /// ditto
- void isInOutQual(bool v) pure nothrow @safe @nogc
- {
- if (v) funcFlags |= FunctionFlag.inoutQual;
- else funcFlags &= ~FunctionFlag.inoutQual;
- }
/// Returns: `true` the function is `isInOutQual` or `isInOutParam` ,`false` otherwise.
bool iswild() const pure nothrow @safe @nogc
{
- return (funcFlags & (FunctionFlag.inoutParam | FunctionFlag.inoutQual)) != 0;
- }
-
- /// set or get if the function is a constructor
- bool isctor() const pure nothrow @safe @nogc
- {
- return (funcFlags & FunctionFlag.isctor) != 0;
- }
- /// ditto
- void isctor(bool v) pure nothrow @safe @nogc
- {
- if (v) funcFlags |= FunctionFlag.isctor;
- else funcFlags &= ~FunctionFlag.isctor;
+ return (funcFlags & (FunctionFlag.isInOutParam | FunctionFlag.isInOutQual)) != 0;
}
/// Returns: whether `this` function type has the same attributes (`@safe`,...) as `other`
override MOD deduceWild(Type t, bool isRef)
{
- // If sym is forward referenced:
- if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete())
- sym.dsymbolSemantic(null);
ClassDeclaration cd = t.isClassHandle();
if (cd && (sym == cd || cd.isBaseOf(sym, null)))
return Type.deduceWild(t, isRef);
extern (D) private static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe
{
+ // Workaround for failing covariance when finding a common type of delegates,
+ // some of which have parameters with inferred scope
+ // https://issues.dlang.org/show_bug.cgi?id=21285
+ // The root cause is that scopeinferred is not part of the mangle, and mangle
+ // is used for type equality checks
+ if (to & STC.returninferred)
+ to &= ~STC.return_;
+ // note: f(return int* x) currently 'infers' scope without inferring `return`, in that case keep STC.scope
+ if (to & STC.scopeinferred && !(to & STC.return_))
+ to &= ~STC.scope_;
+
if (from == to)
return true;
override void visit(DeleteExp e)
{
- if (e.e1.op == EXP.variable)
+ if (VarExp ve = e.e1.isVarExp())
{
- VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration();
+ VarDeclaration v = ve.var.isVarDeclaration();
if (v && v.onstack)
return; // delete for scope allocated class object
}
*/
auto t = v.type;
- if (v.isRef())
+ if (v.isReference())
{
return t.hasMutableFields() ? PtrState.Borrowed : PtrState.Readonly;
}
{
foreach (v; ts.sym.fields)
{
- if (v.isRef())
+ if (v.isReference())
{
if (v.type.hasMutableFields())
return true;
else if (isReadonlyPtr(v))
pvs.state = PtrState.Readonly;
else
+ {
+ if (pvs.state == PtrState.Owner && v.type.hasPointersToMutableFields())
+ v.error(e.loc, "assigning to Owner without disposing of owned value");
+
pvs.state = PtrState.Owner;
+ }
pvs.deps.zero();
EscapeByResults er;
if (s)
{
functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
- if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+ if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
{
return ErrorExp.get();
}
if (s_r)
{
functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1);
- if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+ if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
{
return ErrorExp.get();
}
if (s_r)
{
functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, &args2);
- if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+ if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
{
return ErrorExp.get();
}
if (s)
{
functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, &args1);
- if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+ if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
{
return ErrorExp.get();
}
if (s)
{
functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
- if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+ if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
{
return ErrorExp.get();
}
if (s)
{
functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
- if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+ if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
return ErrorExp.get();
}
FuncDeclaration lastf = m.lastf;
if (s_r)
{
functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1);
- if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
+ if (m.lastf && (m.lastf.errors || m.lastf.hasSemantic3Errors()))
return ErrorExp.get();
}
if (m.count > 1)
{
eint = ei;
}
+ else if (auto se = ep.e1.isSymOffExp())
+ {
+ if (!se.var.isReference() &&
+ !se.var.isImportedSymbol() &&
+ se.var.isDataseg())
+ {
+ var = se.var.isVarDeclaration();
+ offset += se.offset;
+ }
+ }
}
return false;
}
if (auto ae = e.e1.isIndexExp())
{
// Convert &array[n] to &array+n
- if (ae.e2.op == EXP.int64 && ae.e1.isVarExp())
+ if (ae.e2.isIntegerExp() && ae.e1.isVarExp())
{
sinteger_t index = ae.e2.toInteger();
VarExp ve = ae.e1.isVarExp();
sinteger_t dim = ts.dim.toInteger();
if (index < 0 || index >= dim)
{
- e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
- return error();
+ /* 0 for C static arrays means size is unknown, no need to check
+ */
+ if (!(dim == 0 && ve.var.isCsymbol()))
+ {
+ e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
+ return error();
+ }
}
import core.checkedint : mulu;
return;
}
}
+ // Convert &((a.b)[n]) to (&a.b)+n
+ else if (ae.e2.isIntegerExp() && ae.e1.isDotVarExp())
+ {
+ sinteger_t index = ae.e2.toInteger();
+ DotVarExp ve = ae.e1.isDotVarExp();
+ if (ve.type.isTypeSArray() && ve.var.isField() && ve.e1.isPtrExp())
+ {
+ TypeSArray ts = ve.type.isTypeSArray();
+ sinteger_t dim = ts.dim.toInteger();
+ if (index < 0 || index >= dim)
+ {
+ /* 0 for C static arrays means size is unknown, no need to check
+ */
+ if (!(dim == 0 && ve.var.isCsymbol()))
+ {
+ e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
+ return error();
+ }
+ }
+
+ auto pe = new AddrExp(e.loc, ve);
+ pe.type = e.type;
+ ret = new AddExp(e.loc, pe, ae.e2);
+ ret.type = e.type;
+ return;
+ }
+ }
}
}
case TOK.traits:
if (AST.TraitsExp te = cast(AST.TraitsExp) parsePrimaryExp())
- if (te.ident && te.args)
+ if (te.ident)
{
t = new AST.TypeTraits(token.loc, te);
break;
putc(' ', stdout);
}
}
-
-
return a ^ (a >> 7) ^ (a >> 4);
}
-struct KeyValueTemplate(K,V)
+private struct KeyValueTemplate(K,V)
{
K key;
V value;
alias KeyValue = KeyValueTemplate!(Key, Value);
-struct aaA
+private struct aaA
{
+private:
aaA* next;
KeyValue keyValue;
alias keyValue this;
}
-struct AA
+private struct AA
{
+private:
aaA** b;
size_t b_length;
size_t nodes; // total number of aaA nodes
return data.ptr[--length];
}
};
-
a = b;
assert(a == b);
}
-
-
-
data = null;
return result;
}
-
- extern (C++) static FileBuffer* create() pure nothrow @safe
- {
- return new FileBuffer();
- }
}
///
nothrow:
/// Read the full content of a file.
- extern (C++) static ReadResult read(const(char)* name)
- {
- return read(name.toDString());
- }
-
- /// Ditto
static ReadResult read(const(char)[] name)
{
ReadResult result;
}
/// Write a file, returning `true` on success.
- extern (D) static bool write(const(char)* name, const void[] data)
+ static bool write(const(char)* name, const void[] data)
{
import dmd.common.file : writeFile;
return writeFile(name, data);
}
///ditto
- extern(D) static bool write(const(char)[] name, const void[] data)
+ static bool write(const(char)[] name, const void[] data)
{
return name.toCStringThen!((fname) => write(fname.ptr, data));
}
- /// ditto
- extern (C++) static bool write(const(char)* name, const(void)* data, size_t size)
- {
- return write(name, data[0 .. size]);
- }
-
/// Delete a file.
extern (C++) static void remove(const(char)* name)
{
* Returns:
* `true` on success
*/
- extern (D) static bool update(const(char)* namez, const void[] data)
+ static bool update(const(char)* namez, const void[] data)
{
enum log = false;
if (log) printf("update %s\n", namez);
}
///ditto
- extern(D) static bool update(const(char)[] name, const void[] data)
+ static bool update(const(char)[] name, const void[] data)
{
return name.toCStringThen!(fname => update(fname.ptr, data));
}
- /// ditto
- extern (C++) static bool update(const(char)* name, const(void)* data, size_t size)
- {
- return update(name, data[0 .. size]);
- }
-
/// Size of a file in bytes.
/// Params: namez = null-terminated filename
/// Returns: `ulong.max` on any error, the length otherwise.
}
/// ditto
- extern(D) int opApply(scope int delegate(const(StringValue!T)*) nothrow dg) nothrow
+ int opApply(scope int delegate(const(StringValue!T)*) nothrow dg) nothrow
{
foreach (const se; table)
{
doCond(s.statement) || applyTo(s);
}
}
-
// Disable generated opAssign, because some members forbid identity assignment.
funcdecl.storage_class |= STC.disable;
funcdecl.fbody = null; // remove fbody which contains the error
- funcdecl.semantic3Errors = false;
+ funcdecl.flags &= ~FUNCFLAG.semantic3Errors;
}
return;
}
if (funcdecl.semanticRun >= PASS.semantic3)
return;
funcdecl.semanticRun = PASS.semantic3;
- funcdecl.semantic3Errors = false;
+ funcdecl.flags &= ~FUNCFLAG.semantic3Errors;
if (!funcdecl.type || funcdecl.type.ty != Tfunction)
return;
// functions may be widely used by dmd-compiled projects.
// It also gives more time for the implementation of dual-context
// functions to be reworked as a frontend-only feature.
- if (funcdecl.isThis2)
+ if (funcdecl.hasDualContext())
{
funcdecl.deprecation("function requires a dual-context, which is deprecated");
if (auto ti = sc2.parent ? sc2.parent.isInstantiated() : null)
if (!funcdecl.fbody)
funcdecl.fbody = new CompoundStatement(Loc.initial, new Statements());
- if (funcdecl.naked)
+ if (funcdecl.isNaked())
{
fpreinv = null; // can't accommodate with no stack frame
fpostinv = null;
f.next = Type.tvoid;
if (f.checkRetType(funcdecl.loc))
funcdecl.fbody = new ErrorStatement();
- else if (funcdecl.isMain())
- funcdecl.checkDmain(); // Check main() parameters and return type
+ else
+ funcdecl.checkMain(); // Check main() parameters and return type
}
if (f.next !is null)
// handle NRVO
if (!target.isReturnOnStack(f, funcdecl.needThis()) || !funcdecl.checkNRVO())
- funcdecl.nrvo_can = 0;
+ funcdecl.flags &= ~FUNCFLAG.NRVO;
if (funcdecl.fbody.isErrorStatement())
{
/* Don't generate unwind tables for this function
* https://issues.dlang.org/show_bug.cgi?id=17997
*/
- funcdecl.eh_none = true;
+ funcdecl.flags |= FUNCFLAG.noEH;
}
if (funcdecl.flags & FUNCFLAG.nothrowInprocess)
/* https://issues.dlang.org/show_bug.cgi?id=10789
* If NRVO is not possible, all returned lvalues should call their postblits.
*/
- if (!funcdecl.nrvo_can)
+ if (!funcdecl.isNRVO())
exp = doCopyOrMove(sc2, exp, f.next);
if (tret.hasPointers())
freq = freq.statementSemantic(sc2);
freq.blockExit(funcdecl, false);
- funcdecl.eh_none = false;
+ funcdecl.flags &= ~FUNCFLAG.noEH;
sc2 = sc2.pop();
fens = fens.statementSemantic(sc2);
fens.blockExit(funcdecl, false);
- funcdecl.eh_none = false;
+ funcdecl.flags &= ~FUNCFLAG.noEH;
sc2 = sc2.pop();
const blockexit = s.blockExit(funcdecl, isnothrow);
if (blockexit & BE.throw_)
{
- funcdecl.eh_none = false;
+ funcdecl.flags &= ~FUNCFLAG.noEH;
if (isnothrow)
error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
else if (funcdecl.flags & FUNCFLAG.nothrowInprocess)
{
// 'this' is the monitor
vsync = new VarExp(funcdecl.loc, funcdecl.vthis);
- if (funcdecl.isThis2)
+ if (funcdecl.hasDualContext())
{
vsync = new PtrExp(funcdecl.loc, vsync);
vsync = new IndexExp(funcdecl.loc, vsync, IntegerExp.literal!0);
}
// Fix up forward-referenced gotos
- if (funcdecl.gotos)
+ if (funcdecl.gotos && !funcdecl.isCsymbol())
{
for (size_t i = 0; i < funcdecl.gotos.dim; ++i)
{
}
}
- if (funcdecl.naked && (funcdecl.fensures || funcdecl.frequires))
+ if (funcdecl.isNaked() && (funcdecl.fensures || funcdecl.frequires))
funcdecl.error("naked assembly functions with contracts are not supported");
sc2.ctorflow.callSuper = CSX.none;
* Otherwise, error gagging should be temporarily ungagged by functionSemantic3.
*/
funcdecl.semanticRun = PASS.semantic3done;
- funcdecl.semantic3Errors = (global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement());
+ if ((global.errors != oldErrors) || (funcdecl.fbody && funcdecl.fbody.isErrorStatement()))
+ funcdecl.flags |= FUNCFLAG.semantic3Errors;
+ else
+ funcdecl.flags &= ~FUNCFLAG.semantic3Errors;
if (funcdecl.type.ty == Terror)
funcdecl.errors = true;
//printf("-FuncDeclaration::semantic3('%s.%s', sc = %p, loc = %s)\n", parent.toChars(), toChars(), sc, loc.toChars());
return new GotoStatement(loc, ident);
}
+ /**************
+ * Returns: true for error
+ */
extern (D) bool checkLabel()
{
if (!label.statement)
if (f.checkForwardRef(s.exp.loc))
s.exp = ErrorExp.get();
}
- if (discardValue(s.exp))
+
+ if (!(sc.flags & SCOPE.Cfile) && discardValue(s.exp))
s.exp = ErrorExp.get();
s.exp = s.exp.optimize(WANTvalue);
Dsymbol sapply = null; // the inferred opApply() or front() function
if (!inferForeachAggregate(sc, fs.op == TOK.foreach_, fs.aggr, sapply))
{
- const(char)* msg = "";
- if (fs.aggr.type && isAggregate(fs.aggr.type))
- {
- msg = ", define `opApply()`, range primitives, or use `.tupleof`";
- }
- fs.error("invalid `foreach` aggregate `%s`%s", oaggr.toChars(), msg);
+ assert(oaggr.type);
+
+ fs.error("invalid `foreach` aggregate `%s` of type `%s`", oaggr.toChars(), oaggr.type.toPrettyChars());
+ if (isAggregate(fs.aggr.type))
+ fs.loc.errorSupplemental("maybe define `opApply()`, range primitives, or use `.tupleof`");
+
return setError();
}
needswitcherror = true;
}
- if (!sc.sw.sdefault && !(sc.flags & SCOPE.Cfile) &&
+ if (!sc.sw.sdefault &&
(!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on))
{
ss.hasNoDefault = 1;
- if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement()))
+ if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement()) && !(sc.flags & SCOPE.Cfile))
ss.error("`switch` statement without a `default`; use `final switch` or add `default: assert(0);` or add `default: break;`");
// Generate runtime error if the default is hit
CompoundStatement cs;
Statement s;
- if (global.params.useSwitchError == CHECKENABLE.on &&
+ if (sc.flags & SCOPE.Cfile)
+ {
+ s = new BreakStatement(ss.loc, null); // default for C is `default: break;`
+ }
+ else if (global.params.useSwitchError == CHECKENABLE.on &&
global.params.checkAction != CHECKACTION.halt)
{
if (global.params.checkAction == CHECKACTION.C)
ss._body = cs;
}
- if (ss.checkLabel())
+ if (!(sc.flags & SCOPE.Cfile) && ss.checkLabel())
{
sc.pop();
return setError();
fd.gotos = new GotoStatements();
fd.gotos.push(gs);
}
- else if (gs.checkLabel())
+ else if (!(sc.flags & SCOPE.Cfile) && gs.checkLabel())
return setError();
result = gs;
}
assert(sc.func);
- // use setImpure/setGC when the deprecation cycle is over
- PURE purity;
- if (!(cas.stc & STC.pure_) && (purity = sc.func.isPureBypassingInference()) != PURE.impure && purity != PURE.fwdref)
- cas.deprecation("`asm` statement is assumed to be impure - mark it with `pure` if it is not");
- if (!(cas.stc & STC.nogc) && sc.func.isNogcBypassingInference())
- cas.deprecation("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not");
+ if (!(cas.stc & STC.pure_) && sc.func.setImpure())
+ cas.error("`asm` statement is assumed to be impure - mark it with `pure` if it is not");
+ if (!(cas.stc & STC.nogc) && sc.func.setGC())
+ cas.error("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not");
if (!(cas.stc & (STC.trusted | STC.safe)) && sc.func.setUnsafe())
cas.error("`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not");
arrow, // ->
colonColon, // ::
wchar_tLiteral,
+ endOfLine, // \n, \r, \u2028, \u2029
whitespace,
// C only keywords
TOK.wcharLiteral: "wcharv",
TOK.dcharLiteral: "dcharv",
TOK.wchar_tLiteral: "wchar_tv",
+ TOK.endOfLine: "\\n",
TOK.whitespace: "whitespace",
// C only keywords
sprintf(&buffer[0], "%d", cast(int)intvalue);
break;
case TOK.uns32Literal:
- case TOK.wcharLiteral:
- case TOK.dcharLiteral:
case TOK.wchar_tLiteral:
sprintf(&buffer[0], "%uU", cast(uint)unsvalue);
break;
+ case TOK.wcharLiteral:
+ case TOK.dcharLiteral:
case TOK.charLiteral:
- {
- const v = cast(int)intvalue;
- if (v >= ' ' && v <= '~')
- sprintf(&buffer[0], "'%c'", v);
- else
- sprintf(&buffer[0], "'\\x%02x'", v);
+ {
+ OutBuffer buf;
+ buf.writeSingleCharLiteral(cast(dchar) intvalue);
+ buf.writeByte('\0');
+ p = buf.extractSlice().ptr;
+ }
break;
- }
case TOK.int64Literal:
sprintf(&buffer[0], "%lldL", cast(long)intvalue);
break;
buf.writeByte('\\');
goto default;
default:
- if (c <= 0x7F)
+ if (c <= 0xFF)
{
if (isprint(c))
buf.writeByte(c);
}
assert(buf.extractSlice() == `a\n\r\t\b\f\0\x11\u7233\U00017233`);
}
+
+/**
+ * Write a single-quoted character literal
+ *
+ * Useful for printing '' char literals in e.g. error messages, ddoc, or the `.stringof` property
+ *
+ * Params:
+ * buf = buffer to append character in
+ * c = code point to write
+ */
+nothrow
+void writeSingleCharLiteral(ref OutBuffer buf, dchar c)
+{
+ buf.writeByte('\'');
+ if (c == '\'')
+ buf.writeByte('\\');
+
+ if (c == '"')
+ buf.writeByte('"');
+ else
+ writeCharLiteral(buf, c);
+
+ buf.writeByte('\'');
+}
+
+unittest
+{
+ OutBuffer buf;
+ writeSingleCharLiteral(buf, '\'');
+ assert(buf.extractSlice() == `'\''`);
+ buf.reset();
+ writeSingleCharLiteral(buf, '"');
+ assert(buf.extractSlice() == `'"'`);
+ buf.reset();
+ writeSingleCharLiteral(buf, '\n');
+ assert(buf.extractSlice() == `'\n'`);
+}
arrow, // ->
colonColon, // ::
wchar_tLiteral,
+ endOfLine, // \n, \r, \u2028, \u2029
whitespace,
// C only keywords
{
if (auto e = isExpression(oarg))
{
- if (e.op == EXP.dotVariable)
- return (cast(DotVarExp)e).var;
- if (e.op == EXP.dotTemplateDeclaration)
- return (cast(DotTemplateExp)e).td;
+ if (auto dve = e.isDotVarExp())
+ return dve.var;
+ if (auto dte = e.isDotTemplateExp())
+ return dte.td;
}
return getDsymbol(oarg);
}
e.error("argument `%s` has no visibility", o.toChars());
return ErrorExp.get();
}
- if (s.semanticRun == PASS.init)
+ if (s.semanticRun == PASS.initial)
s.dsymbolSemantic(null);
auto protName = visibilityToString(s.visible().kind); // TODO: How about package(names)
}
else if (e.ident == Id.getMember)
{
- if (ex.op == EXP.dotIdentifier)
+ if (auto die = ex.isDotIdExp())
// Prevent semantic() from replacing Symbol with its initializer
- (cast(DotIdExp)ex).wantsym = true;
+ die.wantsym = true;
ex = ex.expressionSemantic(scx);
return ex;
}
return ErrorExp.get();
}
- if (sc.func is null)
+ auto fd = sc.getEnclosingFunction();
+ if (!fd)
{
e.error("`__traits(parameters)` may only be used inside a function");
return ErrorExp.get();
}
- assert(sc.func && sc.parent.isFuncDeclaration());
- auto tf = sc.parent.isFuncDeclaration.type.isTypeFunction();
+
+ auto tf = fd.type.isTypeFunction();
assert(tf);
auto exps = new Expressions(0);
int addParameterDG(size_t idx, Parameter x)
{
if (ea.op == EXP.function_)
{
- if (auto fe = cast(FuncExp)ea)
+ if (auto fe = ea.isFuncExp())
return fe.fd;
}
}
// duplicate a part of StructDeclaration::semanticTypeInfoMembers
//printf("AA = %s, key: xeq = %p, xerreq = %p xhash = %p\n", toChars(), sd.xeq, sd.xerreq, sd.xhash);
- if (sd.xeq && sd.xeq.generated && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done)
+ if (sd.xeq && sd.xeq.isGenerated() && sd.xeq._scope && sd.xeq.semanticRun < PASS.semantic3done)
{
uint errors = global.startGagging();
sd.xeq.semantic3(sd.xeq._scope);
errors = true;
}
- if ((fparam.storageClass & (STC.ref_ | STC.wild)) == (STC.ref_ | STC.wild))
- {
- // 'ref inout' implies 'return'
- fparam.storageClass |= STC.return_;
- }
-
if (fparam.storageClass & STC.return_)
{
if (fparam.isReference())
mtype.exp.ident != Id.derivedMembers &&
mtype.exp.ident != Id.getMember &&
mtype.exp.ident != Id.parent &&
+ mtype.exp.ident != Id.parameters &&
mtype.exp.ident != Id.child &&
mtype.exp.ident != Id.toType &&
mtype.exp.ident != Id.getOverloads &&
//static int nest; if (++nest == 50) *(char*)0=0;
if (sc is null)
{
- error(loc, "Invalid scope.");
+ error(loc, "invalid scope");
return returnError();
}
if (mt.inuse)
return e.expressionSemantic(sc);
}
}
- if (d.semanticRun == PASS.init)
+ if (d.semanticRun == PASS.initial)
d.dsymbolSemantic(null);
checkAccess(e.loc, sc, e, d);
auto ve = new VarExp(e.loc, d);
if (ident == Id.outer && mt.sym.vthis)
{
- if (mt.sym.vthis.semanticRun == PASS.init)
+ if (mt.sym.vthis.semanticRun == PASS.initial)
mt.sym.vthis.dsymbolSemantic(null);
if (auto cdp = mt.sym.toParentLocal().isClassDeclaration())
Expression e1;
Type t;
/* returns: true to continue, false to return */
- if (f.isThis2)
+ if (f.hasDualContext())
{
if (f.followInstantiationContext(ad))
{
}
}
//printf("e = %s, d = %s\n", e.toChars(), d.toChars());
- if (d.semanticRun == PASS.init)
+ if (d.semanticRun == PASS.initial)
d.dsymbolSemantic(null);
// If static function, get the most visible overload.
auto result = File.read(filename);
if (!result.success)
{
- error(loc, "Error reading file `%.*s`", cast(int)filename.length, filename.ptr);
+ error(loc, "error reading file `%.*s`", cast(int)filename.length, filename.ptr);
fatal();
}
return FileBuffer(result.extractSlice());
gcc_assert (e->e1->op == EXP::variable);
VarDeclaration *v = e->e1->isVarExp ()->var->isVarDeclaration ();
- gcc_assert (v && v->onstack);
+ gcc_assert (v && v->onstack ());
libcall_fn libcall = tb1->isClassHandle ()->isInterfaceDeclaration ()
? LIBCALL_CALLINTERFACEFINALIZER : LIBCALL_CALLFINALIZER;
FuncDeclaration *fd = FuncDeclaration::genCfunc (NULL, Type::tvoid,
Identifier::idPool (name));
- fd->generated = true;
+ fd->isGenerated (true);
fd->loc = Loc (mod->srcfile.toChars (), 1, 0);
fd->parent = mod;
fd->visibility = visibility;
/* If returning via NRVO, just refer to the DECL_RESULT; this differs
from using NULL_TREE in that it indicates that we care about the
value of the DECL_RESULT. */
- if (this->func_->nrvo_can && this->func_->nrvo_var)
+ if (this->func_->isNRVO () && this->func_->nrvo_var)
{
add_stmt (return_expr (decl));
return;
--- /dev/null
+// { dg-do compile }
+// { dg-additional-options "-fpreview=dip1000" }
+ThreadInfo* ptr;
+
+ThreadInfo receiveOnly()
+{
+ ThreadInfo ret;
+
+ get({ptr = &ret;});
+ return ret;
+}
+
+struct ThreadInfo
+{
+ ThreadInfo* next;
+}
+
+bool get(T)(T)
+{
+ return false;
+}
+
+void main()
+{
+ auto t = receiveOnly();
+ assert(&t == ptr);
+}
alias fooFuns = AliasSeq!(__traits(getOverloads, S, "foo"));
static assert(fooFuns.length == 1);
-static assert(fooFuns[0]("") == 2);
\ No newline at end of file
+static assert(fooFuns[0]("") == 2);
static assert(TK2[0] == 3);
static assert(is(TK2[1] == const(uint)));
static assert(is(TK2[2] == int));
-
// REQUIRED_ARGS: -unittest
+// PERMUTE_ARGS: -preview=dip1000
// Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master).
unittest
{
static assert(is(typeof(a[0]) == dg));
static assert(is(typeof(ab[0]) == fn));
}
+
+int f(string s) { throw new Exception(""); }
+void main()
+{
+ string path;
+ int bank, preset;
+ void delegate(string value)[string] aa = [
+ "path": (string arg) {
+ path = arg;
+ },
+ "bank": (string arg) {
+ bank = f(arg);
+ },
+ "preset": (string arg) {
+ preset = f(arg);
+ },
+ ];
+
+ string delegate(string value)[string] aa2 = [
+ "path": (string arg) {
+ path = arg;
+ return arg;
+ },
+ "bank": (string arg) {
+ bank = f(arg);
+ return arg;
+ },
+ "preset": (string arg) {
+ preset = f(arg);
+ return arg;
+ },
+ ];
+}
{
return find( "123" );
}
-
auto a = find!((a){return match(e);})(map!regex(noRemoveStr));
}
}
-
f(s1.s.tupleof); // OK
f((s1.s).tupleof); // Error: need 'this' to access member s
}
-
import core.stdc.stdio;
-extern (C) int main(char** argv, int argc) {
+extern (C) int main()
+{
printf("hello world\n");
int[3] a;
foo(a[], 3);
import core.stdc.stdio;
-extern (C) int main(char** argv, int argc) {
+extern (C) int main()
+{
printf("hello world\n");
foo(3);
return 0;
bool test_ne(double x, double y) { return x != y; }
bool test_ge(double x, double y) { return x >= y; }
bool test_gt(double x, double y) { return x > y; }
-
static assert(6.0i % 2.0i == 0);
static assert(6.0i % 3.0i == 0);
static assert(6.0i % 4.0i == 2i);
-
-
* argulid = the argument
* u = the other argument
*/
-int foo(char c, int argulid, char u);
+int foo(char c, int argulid, char u = '\'', wchar v = '\u7233', dchar y = '\U00017233');
int barr() { return 3; } /// doc for barr()
void test1()
{
}
-
-
-
-
-
void test()(string[] args) if (args[$])
{
}
-
1__a $(BR)
2__b
*/
-int i;
\ No newline at end of file
+int i;
auto mAutoTemplateSuffix(alias T)(ref T t) pure nothrow { return p; } /// 9
pure nothrow:
V mColon(lazy P p) {} /// 10
-
-
-
/********** stars ***************/
int stars;
}
-
alias staticIndexOf IndexOf;
void main() { }
-
/********** stars ***************/
int stars;
}
-
C:\code\d\bugs>dmd -D -o- 148_1.d
148_1.d(6): Error: static if conditional cannot be at global scope
+/
-
/// test
void bug6491a(int a = ddoc6491.c6491, string b = core.cpuid.vendor);
-
-
/// Some doc
abstract void foo();
}
-
---
*/
void foo() { }
-
-
-
{
int32_t y;
double z;
- extern "C" void foo();
void bar();
};
struct
int32_t a;
C* c;
virtual void foo();
- extern "C" virtual void bar();
+private:
+ virtual void __vtable_slot_0();
+public:
virtual void baz(int32_t x = 42);
struct
{
{
public:
int32_t x;
- A* this;
+ A* outer;
};
typedef Inner I;
class Parent
{
- virtual void __vtable_slot_0();
virtual void __vtable_slot_1();
+ virtual void __vtable_slot_2();
public:
virtual void foo();
};
int32_t b;
int64_t c;
_d_dynamicArray< int32_t > arr;
+private:
+ ~S();
+public:
S() :
a(),
b(),
int32_t a;
int32_t b;
int64_t c;
- extern "C" S3(int32_t a);
S3() :
a(42),
b(),
{
int32_t a;
S s;
- extern "C" void bar();
void baz(int32_t x = 42);
struct
{
int b;
long c;
int[] arr;
+ extern(D) ~this() {}
}
extern (C++) struct S2
};
#endif
#if !defined(_d_real)
-# define _d_real long double
+#define _d_real long double
#endif
extern "C" int32_t z;
};
#endif
#if !defined(_d_real)
-# define _d_real long double
+#define _d_real long double
#endif
class ClassFromStruct final
};
#endif
#if !defined(_d_real)
-# define _d_real long double
+#define _d_real long double
#endif
class WithImaginary
--- /dev/null
+/++
+REQUIRED_ARGS: -HC=verbose
+TEST_OUTPUT:
+---
+// Automatically generated by Digital Mars D Compiler v$n$
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <math.h>
+
+#ifdef CUSTOM_D_ARRAY_TYPE
+#define _d_dynamicArray CUSTOM_D_ARRAY_TYPE
+#else
+/// Represents a D [] array
+template<typename T>
+struct _d_dynamicArray final
+{
+ size_t length;
+ T *ptr;
+
+ _d_dynamicArray() : length(0), ptr(NULL) { }
+
+ _d_dynamicArray(size_t length_in, T *ptr_in)
+ : length(length_in), ptr(ptr_in) { }
+
+ T& operator[](const size_t idx) {
+ assert(idx < length);
+ return ptr[idx];
+ }
+
+ const T& operator[](const size_t idx) const {
+ assert(idx < length);
+ return ptr[idx];
+ }
+};
+#endif
+
+extern "C" int32_t freeC();
+
+// Ignored function dtoh_mangling.bar because C++ doesn't support explicit mangling
+struct Data final
+{
+ // Ignored function dtoh_mangling.Data.foo because of linkage
+ // Ignored function dtoh_mangling.Data.bar because C++ doesn't support explicit mangling
+ Data()
+ {
+ }
+};
+
+extern void accept(Data data);
+
+extern "C" void hasDefault(int32_t i = freeC());
+
+extern "C" void hasDefaultMember(int32_t i = memberC());
+
+extern "C" int32_t someVarC;
+
+// Ignored variable dtoh_mangling.var2 because C++ doesn't support explicit mangling
+struct HasMangleMember final
+{
+ int32_t someAttrC;
+ int32_t someAttrCpp;
+ void hasDefaultVar(int32_t i = someAttrC);
+ HasMangleMember()
+ {
+ }
+};
+
+extern "C" void hasDefaultVar(int32_t i = someVarC);
+---
+++/
+
+extern(C):
+
+pragma(mangle, "freeC")
+int foo() { return 0; }
+
+pragma(mangle, "freeCpp")
+extern (C++) void bar() {}
+
+pragma(mangle, "Aggregate")
+struct Data
+{
+ pragma(mangle, "memberC")
+ static int foo() { return 0; }
+
+ pragma(mangle, "memberCpp")
+ extern (C++) void bar() {}
+}
+
+extern(C++)
+void accept(Data data) {}
+
+void hasDefault(int i = foo()) {}
+
+void hasDefaultMember(int i = Data.foo()) {}
+
+pragma(mangle, "someVarC")
+__gshared int var;
+
+pragma(mangle, "someVarCpp")
+extern(C++) __gshared int var2;
+
+struct HasMangleMember
+{
+ pragma(mangle, "someAttrC")
+ int var;
+
+ pragma(mangle, "someAttrCpp")
+ extern(C++) int var2;
+
+ extern(C++) void hasDefaultVar(int i = var) {}
+}
+
+void hasDefaultVar(int i = var) {}
ref SafeS foo3() return scope
{
- return this;
+ static SafeS s;
+ return s;
}
int* p;
TypeTuple!(int, long) T;
printf( "%u\n", cast(uint)IndexOf!(long, T) );
}
-
{
alias aaa = DOMImplementation!string;
}
-
S result;
return result.foo();
}
-
struct G {}
struct F(T) { void f(ref T) {} }
pragma(msg, F!G().f(G.init));
-
return x;
}
static assert(echoPlusOne(1) == 2);
+
+void nesting(double d, int i)
+{
+ alias EXP = AliasSeq!(d, i);
+
+ if (d)
+ {
+ static assert(__traits(isSame, __traits(parameters), EXP));
+
+ while (d)
+ {
+ static assert(__traits(isSame, __traits(parameters), EXP));
+ switch (i)
+ {
+ static assert(__traits(isSame, __traits(parameters), EXP));
+ case 1:
+ static assert(__traits(isSame, __traits(parameters), EXP));
+ break;
+
+ default:
+ static assert(__traits(isSame, __traits(parameters), EXP));
+ break;
+ }
+ }
+ }
+}
+
class Tree {
int opApply(int delegate(size_t, Tree) dg) {
if (dg(0, this)) return 1;
}
foreach(idx, elem; top)
{
- static assert(is(typeof(__traits(parameters)) == AliasSeq!(size_t, Tree)));
+ static assert(is(typeof(__traits(parameters)) == AliasSeq!(Tree, int)));
+ }
+
+ foreach(idx, elem; top)
+ {
+ foreach (idx2, elem2; elem)
+ static assert(is(typeof(__traits(parameters)) == AliasSeq!(Tree, int)));
+ }
+
+ foreach(idx, elem; top)
+ {
+ static void foo(char[] text)
+ {
+ foreach (const char c; text)
+ static assert(is(typeof(__traits(parameters)) == AliasSeq!(char[])));
+ }
}
}
class Test
static assert(testTemplate!long(420) == 0);
+void qualifiers(immutable int a, const bool b)
+{
+ static assert(is(typeof(__traits(parameters)) == AliasSeq!(immutable int, const bool)));
+}
+
+int makeAggregate(int a, bool b)
+{
+ struct S
+ {
+ typeof(__traits(parameters)) members;
+ }
+
+ S s = S(__traits(parameters));
+ assert(s.members[0] == a);
+ assert(s.members[1] == b);
+ return 1;
+}
+
+static assert(makeAggregate(5, true));
+
+int makeAlias(int a, bool b)
+{
+ alias Params = __traits(parameters);
+ assert(Params[0] == 3);
+ assert(Params[1] == true);
+ return 1;
+}
+
+static assert(makeAlias(3, true));
+
+
+mixin template nestedCheckParameters(int unique)
+{
+ alias NestedNames = __traits(parameters);
+ version (Fixed)
+ alias Types = typeof(Names);
+}
+
+mixin template checkParameters(int unique)
+{
+ mixin nestedCheckParameters!unique;
+
+ alias Names = __traits(parameters);
+ alias Types = typeof(Names);
+}
+
+int makeAggregateMixin(immutable int a, const bool b)
+{
+ mixin checkParameters!0;
+
+ struct S
+ {
+ mixin checkParameters!1;
+ typeof(Names) members;
+ }
+
+ S s = S(Names);
+ assert(s.members[0] == a);
+ assert(s.members[1] == b);
+ return 1;
+}
{
static assert(is(T == void));
}
-
Vector!(wchar) str;
return 0;
}
-
return find_!(char).fn( buf );
}
}
-
-
-
import a3682;
alias Tuple!(int) tint;
-
struct A() {
static immutable A a;
}
-
/// Used to test is(x == module)
module imports.plainpackage.plainmodule;
-
enum moduleName = "--error--";
}
}
-
void to(string units, D)(D td) { }
-
void to(T, D)(D td) { }
-
import imports.typecons4003;
Tuple!(string) t;
-
class Foo {
protected int a;
}
-
alias int ListHead;
Queue2.ListHead mqueue;
}
-
}
alias T!() instance;
-
-
class Expression : Node
{
}
-
module imports.test9276parser;
public import imports.test9276expr, imports.test9276decl;
-
class OverloadableDecl : Declaration
{
}
-
class BasicType : Type
{
}
-
{
enum x = _dgliteral!T;
}
-
module its.a.floorwax.wax16798;
pragma(msg, "it's a floor wax");
-
static assert(__traits(isReturnOnStack, test1) == false);
static assert(__traits(isReturnOnStack, test2) == true);
-
enum foo_bug = foo.bug;
Foo15478!int[foo_bug] baz; // OK
}
-
OS os = defaultTargetOS();
@property isPOSIX() scope @nogc { }
}
-
ref SafeS foo3() return scope
{
- return this;
+ static SafeS s; return s;
}
int* p;
static assert(__LINE__ == 201);
static assert(__FILE__ == "newfile.d");
static assert(__FILE_FULL_PATH__[$ - 9 .. $] == "newfile.d");
-
-
enum getStuff = q{ __traits(getMember,sb,"fieldb") };
auto b = Foo4!(mixin(getStuff));
}
-
static assert(Fun.stringof == "void function() @safe");
alias Del = void delegate() @safe;
static assert(Del.stringof == "void delegate() @safe");
-
bindFunc();
bindFunc(); /* 100 */
}
-
{
static Object o = void;
}
-
{
class Y { test15389_x.ns.X b; }
}
-
{
issue15464!C15464();
}
-
-
alias X2 = X;
extern (C++, ns) struct X {}
-
j = 0; // works as expected
k = 0; // Error: variable foo.ns.k is private
}
-
auto d = cast(const(ubyte)[]) c;
auto e = cast(const(Windows1252Char)[]) c;
}
-
addAssignSimple(resultHigh[1..$], newscratchbuff[0..y1.length]);
}
-
// https://issues.dlang.org/show_bug.cgi?id=16080
import imp16080;
-
return ((cast(ubyte*)&y)[1]);
}
}
-
import its.a.floorwax.wax16798;
import its.a.dessert.topping;
-
{
static assert([__traits(allMembers, LeClass)] == ["toString", "toHash", "opCmp", "opEquals", "Monitor", "factory"]);
}
-
static assert(__traits(getFunctionVariadicStyle, (int[] a...) {}) == "typesafe");
static assert(__traits(getFunctionVariadicStyle, typeof(cstyle)) == "stdarg");
-
}
}
const S CONST_S = S("/tmp".ptr);
-
enum B = AliasSeq!(2);
enum C = AliasSeq!();
-
t.opCmp(t);
}
-alias bugi = bug!(typeof(new class{}));
\ No newline at end of file
+alias bugi = bug!(typeof(new class{}));
struct tmp(alias fns) {
alias fun = fns!int;
}
-
static assert(!hasPopBack!Bar);
static assert( hasPopBack!Foo && !hasPopBack!Bar);
}
-
static assert(T.init is T.init);
static assert(T.init != T.init);
}
-
scope fp = (){ n = 10; }; // no closure
fp();
}
-
-
{
assert(myFunc!int() == 0);
}
-
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=20717
+
+/*
+TEST_OUTPUT:
+---
+false
+---
+*/
+
+pragma(msg, is(typeof({
+ struct S
+ {
+ struct Foo {}
+ struct Bar() {}
+ alias Bar = Foo;
+ }
+})));
int d = !x ? 1 : 1 / x;
return a | b | c;
}
-
assert(ptr);
*ptr = 42;
}
-
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=22639
+
+struct A
+{
+ this(ref return scope A rhs) inout {}
+ this(ref return scope const A rhs, int b = 7) inout
+ {
+ if (b != 7) {
+ this.b = b;
+ }
+ }
+
+ this(this) @disable;
+
+ int a=4;
+ int b=3;
+}
+
+void main()
+{
+ A a = A();
+ A c = A(a, 10);
+ A d = void;
+ d.__ctor(a, 200);
+ A* b = new A(a, 10);
+}
{
return E.A; // with qualification, it is an enum
}
-
-
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=22825
+#line /*
+ multi-line comment
+*/ 42
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=22859
+private struct __InoutWorkaroundStruct {}
+@property T rvalueOf(T)(T val) { return val; }
+@property T rvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init);
+@property ref T lvalueOf(T)(inout __InoutWorkaroundStruct = __InoutWorkaroundStruct.init);
+
+// taken from std.traits.isAssignable
+template isAssignable(Lhs, Rhs = Lhs)
+{
+ enum isAssignable = __traits(compiles, lvalueOf!Lhs = rvalueOf!Rhs) && __traits(compiles, lvalueOf!Lhs = lvalueOf!Rhs);
+}
+
+// taken from std.meta.allSatisfy
+template allSatisfy(alias F, T...)
+{
+ static foreach (Ti; T)
+ {
+ static if (!is(typeof(allSatisfy) == bool) && // not yet defined
+ !F!(Ti))
+ {
+ enum allSatisfy = false;
+ }
+ }
+ static if (!is(typeof(allSatisfy) == bool)) // if not yet defined
+ {
+ enum allSatisfy = true;
+ }
+}
+
+struct None{}
+
+class C1
+{
+ static if(allSatisfy!(isAssignable, None, C2)) {}
+}
+
+class C2
+{
+ static if(allSatisfy!(isAssignable, None, C1, C2)) {}
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=22860
+class C1
+{
+ SumType!(C1, C2) field;
+}
+
+class C2
+{
+ SumType!(SumType!(C1, C2)) field;
+}
+
+alias AliasSeq(TList...) = TList;
+
+template allSatisfy(alias F, T...)
+{
+ static foreach (Ti; T)
+ {
+ static if (!F!Ti)
+ enum allSatisfy = false;
+ }
+}
+
+struct This {}
+
+enum isAssignableTo(T) = isAssignable!T;
+enum isHashable(T) = __traits(compiles, { T.init; });
+
+struct SumType(Types...)
+{
+ alias Types = AliasSeq!(ReplaceTypeUnless!(isSumTypeInstance, This, typeof(this), TemplateArgsOf!SumType));
+
+ static foreach (T; Types)
+ {
+ static if (isAssignableTo!T)
+ {
+ }
+ }
+
+ static if (allSatisfy!(isAssignableTo, Types))
+ {
+ }
+
+ static if (allSatisfy!(isHashable, Types))
+ size_t toHash;
+}
+
+bool isSumTypeInstance;
+
+alias TemplateArgsOf(T : Base!Args, alias Base, Args...) = Args;
+enum isAssignable(Lhs, Rhs = Lhs) = isRvalueAssignable!(Lhs, Rhs) ;
+enum isRvalueAssignable(Lhs, Rhs ) = __traits(compiles, { lvalueOf!Lhs = Rhs; });
+
+struct __InoutWorkaroundStruct{}
+T lvalueOf(T)(__InoutWorkaroundStruct );
+
+template ReplaceTypeUnless(alias pred, From, To, T...)
+{
+ static if (T.length == 1)
+ alias ReplaceTypeUnless = T;
+ static if (T.length > 1)
+ alias ReplaceTypeUnless = AliasSeq!(ReplaceTypeUnless!(pred, From, To, T[1 ]));
+}
--- /dev/null
+// REQUIRED_ARGS: -checkaction=context -preview=dip1000
+
+// Issue 22919 - [dip1000] -checkaction=context gives "assigned to `__assertOp2` with longer lifetime" (
+// https://issues.dlang.org/show_bug.cgi?id=22919
+
+@safe:
+struct S
+{
+ int* p;
+ ref S get() scope return {return this;}
+}
+
+void main()
+{
+ scope S arr = S();
+ assert(arr == arr.get());
+}
}
static assert(cast(int)Bug3775.byLine == 1);
-
-
import imports.stdio4003;
void main(){}
-
class Bar : Foo {
alias typeof(Foo.tupleof) Bleh;
}
-
-
enum fmaf = fma(-3.2f, 5.2f, 3.8f); //pragma(msg, fmaf);
enum fmad = fma(-3.2 , 5.2 , 3.8 ); //pragma(msg, fmad);
enum fmar = fma(-3.2L, 5.2L, 3.8L); pragma(msg, fmar);
-
-
{
extern int[1][1] foo;
}
-
private import imports.test63a;
const int SIZE = 7;
-
// https://issues.dlang.org/show_bug.cgi?id=6395
import c6395;
-
// https://issues.dlang.org/show_bug.cgi?id=7400
static assert(!is(typeof({import non_existing_file;})));
-
void main(string[] args)
{
auto foo = new Foo();
-}
\ No newline at end of file
+}
enum x = __traits(parent, imports.bug8922).stringof;
static assert(x == "package imports");
}
-
enum x = __traits(parent, imports.bug8922).stringof;
static assert(x == "package imports");
}
-
import imp9057_2;
Bug9057!(BugInt) xxx;
}
-
-
// EXTRA_SOURCES: imports/test9436interp.d
// EXTRA_FILES: imports/test9436aggr.d imports/test9436node.d imports/test9436type.d
// this is a dummy module for test 9436.
-
return aliasthis; // Line 20
}
}
-
}
// Add more tests regarding inferences later.
-
"lala", "lala", "lala", "lala");
}
-
static assert (() {
Panzer p = new Tiger(); return classname(p);
} () == "Tiger");
-
else
{
static assert(0);
-}
\ No newline at end of file
+}
void ft2(T)(S, T){}
ft2(y, 1);
}
-
const int q10280 = foo10280();
int foo10280() { return q10280; }
-
}
static assert(test11467c());
static assert(test11467d());
-
---
*/
enum xstr = x"60";
-
{
deprecated override bool opEquals(Object);
}
-
scObj.scFunc();
scObj.wFunc(); // ng
}
-
class Baz { int a; }
class Test : Foo, Bar, Baz, int {}
-
alias g a;
alias g a;
}
-
TEST_OUTPUT:
---
fail_compilation/dip25.d(17): Deprecation: returning `this.buffer[]` escapes a reference to parameter `this`
-fail_compilation/dip25.d(17): perhaps annotate the function with `return`
-fail_compilation/dip25.d(22): Error: returning `identity(x)` escapes a reference to local variable `x`
+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): Deprecation: returning `identity(x)` escapes a reference to parameter `x`
fail_compilation/dip25.d(23): perhaps annotate the parameter with `return`
---
immutable a = foo();
pragma(msg, a);
}
-
/*
TEST_OUTPUT:
---
-fail_compilation/fail118.d(26): Error: invalid `foreach` aggregate `Iter`, define `opApply()`, range primitives, or use `.tupleof`
-fail_compilation/fail118.d(27): Error: invalid `foreach` aggregate `Iter`, define `opApply()`, range primitives, or use `.tupleof`
+fail_compilation/fail118.d(43): Error: invalid `foreach` aggregate `Iter` of type `Iter`
+fail_compilation/fail118.d(43): maybe define `opApply()`, range primitives, or use `.tupleof`
+fail_compilation/fail118.d(44): Error: invalid `foreach` aggregate `Iter` of type `Iter`
+fail_compilation/fail118.d(44): maybe define `opApply()`, range primitives, or use `.tupleof`
+fail_compilation/fail118.d(47): Error: invalid `foreach` aggregate `s` of type `S*`
+fail_compilation/fail118.d(49): Error: undefined identifier `unknown`
+fail_compilation/fail118.d(37): Error: undefined identifier `doesNotExist`
+fail_compilation/fail118.d(51): Error: template instance `fail118.error!()` error instantiating
+fail_compilation/fail118.d(51): Error: invalid `foreach` aggregate `error()` of type `void`
---
*/
mixin opHackedApply!() oldIterMix;
}
+struct S
+{
+ int opApply(scope int delegate(const int) dg);
+}
+
+auto error()()
+{
+ doesNotExist();
+}
+
void main()
{
Foo f = new Foo;
foreach (int i; f.oldIterMix.Iter) {}
foreach ( i; f.oldIterMix.Iter) {}
+
+ S* s;
+ foreach (const i; s) {}
+
+ foreach(const i; unknown) {}
+
+ foreach (const i; error()) {}
}
mixin Foo!(y);
assert(abc() == 8);
}
-
/*
TEST_OUTPUT:
---
-fail_compilation/fail131.d(8): Error: function `D main` parameters must be `main()` or `main(string[] args)`
+fail_compilation/fail131.d(8): Error: function `D main` parameter list must be empty or accept one parameter of type `string[]`
---
*/
TEST_OUTPUT:
---
fail_compilation/fail13902.d(88): Error: Using the result of a comma expression is not allowed
-fail_compilation/fail13902.d(75): Error: returning `& x` escapes a reference to local variable `x`
-fail_compilation/fail13902.d(76): Error: returning `&s1.v` escapes a reference to local variable `s1`
-fail_compilation/fail13902.d(81): Error: returning `& sa1` escapes a reference to local variable `sa1`
-fail_compilation/fail13902.d(82): Error: returning `&sa2[0][0]` escapes a reference to local variable `sa2`
-fail_compilation/fail13902.d(83): Error: returning `& x` escapes a reference to local variable `x`
-fail_compilation/fail13902.d(84): Error: returning `(& x+4)` escapes a reference to local variable `x`
-fail_compilation/fail13902.d(85): Error: returning `& x + cast(long)x * 4L` escapes a reference to local variable `x`
-fail_compilation/fail13902.d(88): Error: returning `& y` escapes a reference to local variable `y`
+fail_compilation/fail13902.d(75): Error: returning `& x` escapes a reference to parameter `x`
+fail_compilation/fail13902.d(76): Error: returning `&s1.v` escapes a reference to parameter `s1`
+fail_compilation/fail13902.d(81): Error: returning `& sa1` escapes a reference to parameter `sa1`
+fail_compilation/fail13902.d(82): Error: returning `&sa2[0][0]` escapes a reference to parameter `sa2`
+fail_compilation/fail13902.d(83): Error: returning `& x` escapes a reference to parameter `x`
+fail_compilation/fail13902.d(84): Error: returning `(& x+4)` escapes a reference to parameter `x`
+fail_compilation/fail13902.d(85): Error: returning `& x + cast(long)x * 4L` escapes a reference to parameter `x`
+fail_compilation/fail13902.d(88): Error: returning `& y` escapes a reference to parameter `y`
---
*/
int* testEscape2(
/*
TEST_OUTPUT:
---
-fail_compilation/fail13902.d(150): Error: returning `cast(int[])sa1` escapes a reference to local variable `sa1`
-fail_compilation/fail13902.d(151): Error: returning `cast(int[])sa1` escapes a reference to local variable `sa1`
-fail_compilation/fail13902.d(152): Error: returning `sa1[]` escapes a reference to local variable `sa1`
+fail_compilation/fail13902.d(150): Error: returning `cast(int[])sa1` escapes a reference to parameter `sa1`
+fail_compilation/fail13902.d(151): Error: returning `cast(int[])sa1` escapes a reference to parameter `sa1`
+fail_compilation/fail13902.d(152): Error: returning `sa1[]` escapes a reference to parameter `sa1`
fail_compilation/fail13902.d(155): Error: returning `cast(int[])sa2` escapes a reference to local variable `sa2`
fail_compilation/fail13902.d(156): Error: returning `cast(int[])sa2` escapes a reference to local variable `sa2`
fail_compilation/fail13902.d(157): Error: returning `sa2[]` escapes a reference to local variable `sa2`
/*
TEST_OUTPUT:
---
-fail_compilation/fail13902.d(240): Error: returning `x` escapes a reference to local variable `x`
-fail_compilation/fail13902.d(241): Error: returning `s1.v` escapes a reference to local variable `s1`
-fail_compilation/fail13902.d(245): Error: returning `sa1[0]` escapes a reference to local variable `sa1`
-fail_compilation/fail13902.d(246): Error: returning `sa2[0][0]` escapes a reference to local variable `sa2`
-fail_compilation/fail13902.d(247): Error: returning `x = 1` escapes a reference to local variable `x`
-fail_compilation/fail13902.d(248): Error: returning `x += 1` escapes a reference to local variable `x`
-fail_compilation/fail13902.d(249): Error: returning `s1.v = 1` escapes a reference to local variable `s1`
-fail_compilation/fail13902.d(250): Error: returning `s1.v += 1` escapes a reference to local variable `s1`
+fail_compilation/fail13902.d(240): Error: returning `x` escapes a reference to parameter `x`
+fail_compilation/fail13902.d(241): Error: returning `s1.v` escapes a reference to parameter `s1`
+fail_compilation/fail13902.d(245): Error: returning `sa1[0]` escapes a reference to parameter `sa1`
+fail_compilation/fail13902.d(246): Error: returning `sa2[0][0]` escapes a reference to parameter `sa2`
+fail_compilation/fail13902.d(247): Error: returning `x = 1` escapes a reference to parameter `x`
+fail_compilation/fail13902.d(248): Error: returning `x += 1` escapes a reference to parameter `x`
+fail_compilation/fail13902.d(249): Error: returning `s1.v = 1` escapes a reference to parameter `s1`
+fail_compilation/fail13902.d(250): Error: returning `s1.v += 1` escapes a reference to parameter `s1`
---
*/
ref int testEscapeRef2(
TEST_OUTPUT:
---
fail_compilation/fail13902.d(324): Error: returning `vda[0]` escapes a reference to parameter `vda`
-fail_compilation/fail13902.d(324): perhaps annotate the parameter with `return`
---
+
*/
ref int testDynamicArrayVariadic1(int[] vda...) { return vda[0]; }
@safe int[] testDynamicArrayVariadic2(int[] vda...) { return vda[]; }
/*
TEST_OUTPUT:
---
-fail_compilation/fail13902.d(335): Error: returning `vsa[0]` escapes a reference to local variable `vsa`
+fail_compilation/fail13902.d(335): Error: returning `vsa[0]` escapes a reference to parameter `vsa`
fail_compilation/fail13902.d(336): Error: returning `vsa[]` escapes a reference to variadic parameter `vsa`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail14486.d(35): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(36): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(41): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(42): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(47): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(48): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(53): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(54): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(59): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(60): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(65): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(66): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail14486.d(47): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(47): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(48): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(48): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(53): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(53): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(54): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(54): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(59): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(59): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(60): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(60): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(65): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(65): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(66): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(66): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(71): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(71): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(72): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(72): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(77): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(77): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/fail14486.d(78): Error: the `delete` keyword is obsolete
+fail_compilation/fail14486.d(78): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
---
*/
mixin Test!() xs;
bool x = xs[false];
}
-
-
bc: 4, // line 20
};
}
-
-
auto fail = () => {};
auto ok = () => () {};
}
-
auto a = const(S)("abc");
assert(a.i == 2);
}
-
-
DSO* _pdso;
void[] _tlsRange;
}
-
enum s = __traits(getLinkage, 8 * 8);
enum t = __traits(getLinkage, 8, 8);
-
static assert(__traits(getFunctionVariadicStyle, 1) == "none");
static assert(__traits(getFunctionVariadicStyle, x) == "none");
-
array ~= arr;
return array[0];
}
-
-
// REQUIRED_ARGS: -de
/* TEST_OUTPUT:
---
-fail_compilation/fail17906.d(11): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail17906.d(12): Error: the `delete` keyword is obsolete
+fail_compilation/fail17906.d(12): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
---
*/
// https://issues.dlang.org/show_bug.cgi?id=18647
struct String {
const(char)* mem1() const scope @safe { return ptr; }
-
- inout(char)* mem2() inout scope @safe { return ptr; } // no error because `ref inout` implies `return`
+ // https://issues.dlang.org/show_bug.cgi?id=22027
+ inout(char)* mem2() inout scope @safe { return ptr; }
char* ptr;
}
const(char)* foo1(scope const(char)* ptr) @safe { return ptr; }
inout(char)* foo2(scope inout(char)* ptr) @safe { return ptr; }
-
assert(wrap[0].s.test()); // failure
}
}
-
/*
TEST_OUTPUT:
---
-fail_compilation/fail19744.d(8): Error: Top-level function `test` has no `this` to which `return` can apply
+fail_compilation/fail19744.d(8): Error: top-level function `test` has no `this` to which `return` can apply
---
*/
foreach (i; 0 .. n)
cast(void)n;
}
-
foreach (i; m .. n)
cast(void)n;
}
-
Object o;
auto ti = typeid(o);
}
-
Object o;
auto ti = o.classinfo;
}
-
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/fail20084.d(109): Error: returning `v.front()` escapes a reference to local variable `v`
+fail_compilation/fail20084.d(109): Error: returning `v.front()` escapes a reference to parameter `v`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail20448.d(16): Error: returning `p.x` escapes a reference to local variable `p`
+fail_compilation/fail20448.d(16): Error: returning `p.x` escapes a reference to parameter `p`
fail_compilation/fail20448.d(22): Error: template instance `fail20448.member!"x"` error instantiating
---
*/
auto m2 = new immutable(Message)(2);
m2.notifier = 3;
}
-
TEST_OUTPUT:
---
fail_compilation/fail21868b.d(19): Error: returning `&s.x` escapes a reference to parameter `s`
-fail_compilation/fail21868b.d(19): perhaps remove `scope` parameter annotation so `return` applies to `ref`
+fail_compilation/fail21868b.d(17): perhaps change the `return scope` into `scope return`
---
*/
{
return &s.x;
}
-
-
v.a = arg; // this should not
}
}
-
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=22825
+/* TEST_OUTPUT:
+---
+fail_compilation/fail22825a.d(10): Error: positive integer argument expected following `#line`
+fail_compilation/fail22825a.d(11): Error: declaration expected, not `42`
+---
+*/
+#line /*
+ multi-line comment
+*/
+42
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=22825
+/* TEST_OUTPUT:
+---
+fail_compilation/fail22825b.d(7): Error: declaration expected, not `#`
+---
+*/
+#
+ line
+
+
+
+
+12
/*
TEST_OUTPUT:
---
-fail_compilation/fail2361.d(13): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail2361.d(14): Error: the `delete` keyword is obsolete
+fail_compilation/fail2361.d(14): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail249.d(16): Error: invalid `foreach` aggregate `bar()`
+fail_compilation/fail249.d(16): Error: invalid `foreach` aggregate `bar()` of type `void`
---
*/
final
override void foo(){}
}
-
/*
TEST_OUTPUT:
---
-fail_compilation/fail261.d(18): Error: invalid `foreach` aggregate `range`, define `opApply()`, range primitives, or use `.tupleof`
+fail_compilation/fail261.d(19): Error: invalid `foreach` aggregate `range` of type `MyRange`
+fail_compilation/fail261.d(19): maybe define `opApply()`, range primitives, or use `.tupleof`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail359.d(8): Error: #line integer ["filespec"]\n expected
-fail_compilation/fail359.d(9): Error: no identifier for declarator `_BOOM`
+fail_compilation/fail359.d(7): Error: invalid filename for `#line` directive
---
*/
#line 5 _BOOM
void main() { }
-
float[] otherStuff;
otherStuff ~= stuff;
}
-
B blah;
void foo(B b){}
}
-
B blah;
void foo(B b){}
}
-
B blah;
void foo(B b){}
}
-
assert(77);
while (false);
}
-
struct G1 {}
else
struct G2 {}
-
struct G3 {}
else
struct G4 {}
-
struct G1 {}
else
struct G2 {}
-
class G5 {}
else
class G6 {}
-
void G10(){}
else
void G11(){}
-
assert(sp == -1);
return 0;
}
-
mixin populate!(.contents);
}
public mixin populate!int;
-
{
Contract* r; if (r.empty) {}
}
-
int a;
invariant() { a += 5; }
}
-
@property int g()() { return 0; }
void test() immutable { int f = g; }
}
-
@property int g()() immutable { return 0; }
void test() const { int f = g; }
}
-
@property int g()() immutable { return 0; }
void test() { int f = g; }
}
-
@property int g()() shared { return 0; }
void test() { int f = g; }
}
-
@property int g()() { return 0; }
void test() shared { int f = g; }
}
-
@property int g()() { return 0; }
void test() inout { int f = g; }
}
-
@property int g()() immutable { return 0; }
void test() inout { int f = g; }
}
-
REQUIRED_ARGS: -o-
TEST_OUTPUT:
----
-fail_compilation/fail7524a.d(10): Error: #line integer ["filespec"]\n expected
-fail_compilation/fail7524a.d(10): Error: declaration expected, not `"$r:\w+ +\d+ \d+$"`
+fail_compilation/fail7524a.d(9): Error: invalid filename for `#line` directive
----
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail7524b.d(10): Error: #line integer ["filespec"]\n expected
-fail_compilation/fail7524b.d(10): Error: declaration expected, not `$n$L`
+fail_compilation/fail7524b.d(9): Error: invalid filename for `#line` directive
---
*/
ub[] = cast(ubyte[4]) &i;
//ub[] = (cast(ubyte*) &i)[0..4];
}
-
auto yd = ft * 3;
auto ft = inch * 12;
-
}
enum C = B.nonexistent;
-
*/
void filter(R)(scope bool delegate(ref BAD!R) func) { }
void main() { filter(r => r); }
-
void main() {
foo(cast(int[2][1])[1, 2]);
}
-
enum x1 = fun1(0);
enum x2 = fun2(0);
-
static void fsc() shared const {}
static void fsw() shared inout {}
}
-
/*
TEST_OUTPUT:
---
-fail_compilation/fail92.d(15): Error: invalid `foreach` aggregate `t`
+fail_compilation/fail92.d(15): Error: invalid `foreach` aggregate `t` of type `typeof(null)`
fail_compilation/fail92.d(23): Error: template instance `fail92.crash!(typeof(null))` error instantiating
---
*/
A(i);
assert(i == 2);
}
-
static assert(__traits(compiles, v = 1)); // multiple initialization
}
}
-
void* dg2ptr(void delegate() dg) {
return cast(void*) dg;
}
-
fail_compilation/fail_arrayop2.d(272): Error: array operation `[1] * 6` without destination memory not allowed
fail_compilation/fail_arrayop2.d(275): Error: `([1] * 6)[0..2]` is not an lvalue and cannot be modified
fail_compilation/fail_arrayop2.d(278): Error: can only `*` a pointer, not a `int[]`
-fail_compilation/fail_arrayop2.d(281): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail_arrayop2.d(281): Error: the `delete` keyword is obsolete
+fail_compilation/fail_arrayop2.d(281): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
fail_compilation/fail_arrayop2.d(284): Error: array operation `da[] * 6` without destination memory not allowed
fail_compilation/fail_arrayop2.d(287): Error: array operation `da[] * 6` without destination memory not allowed
fail_compilation/fail_arrayop2.d(290): Error: `[1] * 6` is not an lvalue and cannot be modified
fail_compilation/fail_arrayop2.d(321): Error: array operation `[1] * 6` without destination memory not allowed
---
*/
-
// Test all expressions, which can take arrays as their operands but cannot be a part of array operation.
void test15407exp()
{
enum : int (int function() bode T);
}
-
/*
TEST_OUTPUT:
---
-fail_compilation/faildeleteaa.d(11): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/faildeleteaa.d(12): Error: the `delete` keyword is obsolete
+fail_compilation/faildeleteaa.d(12): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
---
*/
/* REQUIRED_ARGS: -preview=dip1000
TEST_OUTPUT:
---
-fail_compilation/fix18575.d(27): Error: returning `s.foo()` escapes a reference to local variable `s`
-fail_compilation/fix18575.d(31): Error: returning `s.foo()` escapes a reference to local variable `s`
-fail_compilation/fix18575.d(35): Error: returning `s.abc()` escapes a reference to local variable `s`
-fail_compilation/fix18575.d(39): Error: returning `s.ghi(t)` escapes a reference to local variable `t`
+fail_compilation/fix18575.d(27): Error: returning `s.foo()` escapes a reference to parameter `s`
+fail_compilation/fix18575.d(31): Error: returning `s.foo()` escapes a reference to parameter `s`
+fail_compilation/fix18575.d(35): Error: returning `s.abc()` escapes a reference to parameter `s`
+fail_compilation/fix18575.d(39): Error: returning `s.ghi(t)` escapes a reference to parameter `t`
---
*/
auto j(S s, S t) {
return s.ghi(t);
}
-
alias T2 = Type!(__traits(toType, int));
alias T3 = Type!(__traits(toType, 1));
alias T4 = Type!(__traits(toType, "hello betty"));
-
/* TEST_OUTPUT:
---
+fail_compilation/fob1.d(204): Error: variable `fob1.foo2.p` assigning to Owner without disposing of owned value
fail_compilation/fob1.d(203): Error: variable `fob1.foo2.p` is left dangling at return
---
*/
free7(p);
}
+/* TEST_OUTPUT:
+---
+fail_compilation/fob2.d(807): Error: variable `fob2.test8.p` assigning to Owner without disposing of owned value
+---
+*/
+
+#line 800
+
+int* malloc8();
+void free8(int*);
+
+@live void test8()
+{
+ int* p = malloc8();
+ p = malloc8(); // error here
+ free8(p);
+}
pragma(printf) extern (C) int vprintf5(const(char)*, va_list);
pragma(printf) extern (C) int vprintf6(immutable(char)*, va_list);
pragma(printf) extern (C) int vprintf7(char*, va_list);
-
TEST_OUTPUT:
---
fail_compilation/imports/foo10727a.d(34): Error: undefined identifier `Frop`
-fail_compilation/imports/foo10727a.d(26): Error: template instance `foo10727a.CirBuff!(Foo)` error instantiating
-fail_compilation/imports/foo10727a.d(31): instantiated from here: `Bar!(Foo)`
---
*/
TEST_OUTPUT:
---
fail_compilation/imports/foo10727b.d(25): Error: undefined identifier `Frop`
-fail_compilation/imports/foo10727b.d(17): Error: template instance `foo10727b.CirBuff!(Foo)` error instantiating
-fail_compilation/imports/foo10727b.d(22): instantiated from here: `Bar!(Foo)`
---
*/
/*
TEST_OUTPUT:
----
-fail_compilation/ice11968.d(8): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/ice11968.d(9): Error: the `delete` keyword is obsolete
+fail_compilation/ice11968.d(9): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
----
*/
auto d = new D();
d.foo();
}
-
fail_compilation/ice9254a.d(15): Error: Using the result of a comma expression is not allowed
fail_compilation/ice9254a.d(15): Error: Using the result of a comma expression is not allowed
fail_compilation/ice9254a.d(15): Error: Using the result of a comma expression is not allowed
-fail_compilation/ice9254a.d(15): Error: invalid `foreach` aggregate `false`
+fail_compilation/ice9254a.d(15): Error: invalid `foreach` aggregate `false` of type `bool`
---
*/
fail_compilation/ice9254b.d(17): Error: Using the result of a comma expression is not allowed
fail_compilation/ice9254b.d(17): Error: Using the result of a comma expression is not allowed
fail_compilation/ice9254b.d(17): Error: Using the result of a comma expression is not allowed
-fail_compilation/ice9254b.d(17): Error: invalid `foreach` aggregate `false`
+fail_compilation/ice9254b.d(17): Error: invalid `foreach` aggregate `false` of type `bool`
---
*/
fail_compilation/ice9254c.d(15): Error: Using the result of a comma expression is not allowed
fail_compilation/ice9254c.d(15): Error: Using the result of a comma expression is not allowed
fail_compilation/ice9254c.d(15): Error: Using the result of a comma expression is not allowed
-fail_compilation/ice9254c.d(15): Error: invalid `foreach` aggregate `false`
+fail_compilation/ice9254c.d(15): Error: invalid `foreach` aggregate `false` of type `bool`
---
*/
struct S { private enum string c = "qwerty"; }
class C { private enum string d = "qwerty"; }
-
return _input[0];
}
}
-
-
{
}
-class SomeClass {}
\ No newline at end of file
+class SomeClass {}
"Cannot put a "~E.stringof~" into a "~R.stringof);
}
}
-
{
return Complex!real(0, 0);
}
-
public import imports.test18480b : TestTemplate;
alias TestTemplate = TestTemplate;
-
import imports.test21164c;
enum N = O();
alias Q = R!(N, S);
-
struct R(O U, int W)
{
}
-
module imports;
const char[] file1 = "File1";
-
p = (*cp)[].ptr;
p = (*e)[].ptr;
}
-
/* TEST_OUTPUT:
---
-fail_compilation/issue22826.d(7): Error: #line integer ["filespec"]\n expected
-fail_compilation/issue22826.d(7): Error: declaration expected, not `3`
+fail_compilation/issue22826.d(6): Error: found `3` when expecting new line following `#line` directive
---
*/
#line 12 "issue22826.d" 3
fail_compilation/lexer1.d(36): Error: declaration expected, not `0.1fi`
fail_compilation/lexer1.d(37): Error: declaration expected, not `0.1Li`
fail_compilation/lexer1.d(38): Error: declaration expected, not `' '`
-fail_compilation/lexer1.d(39): Error: declaration expected, not `55295U`
-fail_compilation/lexer1.d(40): Error: declaration expected, not `65536U`
+fail_compilation/lexer1.d(39): Error: declaration expected, not `'\ud7ff'`
+fail_compilation/lexer1.d(40): Error: declaration expected, not `'\U00010000'`
fail_compilation/lexer1.d(41): Error: declaration expected, not `"ab\\c\"\u1234a\U00011100a\0ab"d`
fail_compilation/lexer1.d(43): Error: declaration expected, not `module`
fail_compilation/lexer1.d(45): Error: escape hex sequence has 1 hex digits instead of 2
fail_compilation/lexer4.d(31): Error: lower case integer suffix 'l' is not allowed. Please use 'L' instead
fail_compilation/lexer4.d(32): Error: use 'i' suffix instead of 'I'
fail_compilation/lexer4.d(34): Error: line number `1234567891234567879` out of range
-fail_compilation/lexer4.d(36): Error: #line integer ["filespec"]\n expected
-fail_compilation/lexer4.d(19): Error: #line integer ["filespec"]\n expected
-fail_compilation/lexer4.d(19): Error: declaration expected, not `"file"`
+fail_compilation/lexer4.d(36): Error: positive integer argument expected following `#line`
+fail_compilation/lexer4.d(19): Error: found `"file"` when expecting new line following `#line` directive
---
*/
+
static c1 = '
;
static c2 = '';
//\xff chars
__gshared pragma(mangle, "test\xff9") ubyte test9_6;
__gshared extern pragma(mangle, "test\xff9") ubyte test9_6_e;
-
int i;
auto ti = typeid(i);
}
-
/*
TEST_OUTPUT:
---
-fail_compilation/nogc1.d(73): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/nogc1.d(74): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/nogc1.d(75): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/nogc1.d(76): Error: the `delete` keyword is obsolete
+fail_compilation/nogc1.d(76): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/nogc1.d(77): Error: the `delete` keyword is obsolete
+fail_compilation/nogc1.d(77): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
+fail_compilation/nogc1.d(78): Error: the `delete` keyword is obsolete
+fail_compilation/nogc1.d(78): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
---
*/
@nogc void testDelete(int* p, Object o, S1* s)
pragma(inline, 1,2,3) void bar();
pragma(inline, "string") void baz(); // works now
-
{
pragma(unrecognized, "string");
}
-
-
fail_compilation/reserved_version.d(218): Error: version identifier `D_PreConditions` is reserved and cannot be set
fail_compilation/reserved_version.d(219): Error: version identifier `D_PostConditions` is reserved and cannot be set
fail_compilation/reserved_version.d(220): Error: version identifier `D_ProfileGC` is reserved and cannot be set
+fail_compilation/reserved_version.d(221): Error: version identifier `D_Invariants` is reserved and cannot be set
---
*/
version = D_PreConditions;
version = D_PostConditions;
version = D_ProfileGC;
+version = D_Invariants;
// This should work though
debug = DigitalMars;
// REQUIRED_ARGS: -version=D_PreConditions
// REQUIRED_ARGS: -version=D_PostConditions
// REQUIRED_ARGS: -version=D_ProfileGC
+// REQUIRED_ARGS: -version=D_Invariants
// REQUIRED_ARGS: -debug=DigitalMars
// REQUIRED_ARGS: -debug=GNU
// REQUIRED_ARGS: -debug=LDC
// REQUIRED_ARGS: -debug=D_PreConditions
// REQUIRED_ARGS: -debug=D_PostConditions
// REQUIRED_ARGS: -debug=D_ProfileGC
+// REQUIRED_ARGS: -debug=D_Invariants
/*
TEST_OUTPUT:
---
Error: version identifier `D_PreConditions` is reserved and cannot be set
Error: version identifier `D_PostConditions` is reserved and cannot be set
Error: version identifier `D_ProfileGC` is reserved and cannot be set
+Error: version identifier `D_Invariants` is reserved and cannot be set
---
*/
int* oops;
// this(int* p) @safe { oops = p; }
}
-
/*
TEST_OUTPUT:
---
-fail_compilation/retscope3.d(3027): Error: scope variable `l` assigned to `elem` with longer lifetime
----
-*/
-
-#line 3000
-
-struct List
-{
- Elem front() @safe return scope;
-
- ~this() @trusted scope;
-
- @disable this(this);
-
- void* data;
-}
-
-struct Elem
-{
- void* data;
-}
-
-List list() @trusted
-{
- return List();
-}
-
-void test3000() @safe
-{
- Elem elem;
- {
- auto l = list(); // inferred as scope
- elem = l.front; // escapes, b/c l isn't scoped
- }
-}
-
-/**********************************************/
-
-/*
-TEST_OUTPUT:
----
fail_compilation/retscope3.d(4003): Error: copying `u[]` into allocated memory escapes a reference to variadic parameter `u`
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
p = &t.a; // should not compile
}
}
-
int x = 42;
return escape_c_20150(&x);
}
+
+/* TEST_OUTPUT:
+---
+fail_compilation/retscope6.d(13010): Error: reference to local variable `str` assigned to non-scope parameter `x` calling retscope6.f_throw
+---
+*/
+
+#line 13000
+// https://issues.dlang.org/show_bug.cgi?id=22221
+
+void f_throw(string x) @safe pure
+{
+ throw new Exception(x);
+}
+
+void escape_throw_20150() @safe
+{
+ immutable(char)[4] str;
+ f_throw(str[]);
+}
fail_compilation/shared.d(2202): Error: direct access to shared `c` is not allowed, see `core.atomic`
fail_compilation/shared.d(2206): Error: function `shared.test_inference_2` function returns `shared` but cannot be inferred `ref`
fail_compilation/shared.d(2208): Error: returning `c` escapes a reference to parameter `c`
-fail_compilation/shared.d(2208): perhaps annotate the parameter with `return`
fail_compilation/shared.d(2214): Error: function `shared.test_inference_3` function returns `shared` but cannot be inferred `ref`
fail_compilation/shared.d(2216): return value `getSharedObject()` is not an lvalue
fail_compilation/shared.d(2222): Error: direct access to shared `a` is not allowed, see `core.atomic`
fail_compilation/shared.d(2222): Error: cannot implicitly convert expression `a` of type `shared(const(Object))` to `object.Object`
---
*/
+
#line 2100
// Derived from https://issues.dlang.org/show_bug.cgi?id=20908
ref shared(int) test20908()
__traits(getAttributes, foo);
__traits(getAttributes, foo)[0];
}
-
-
@safe ubyte oops(ubyte[3] b) {
return *b.ptr;
}
-
u.sysDg = &s.sysMethod;
u.safeDg();
}
-
@safe:
void abc(ref int x) { }
void def(const ref int x) { }
-
Bar bar;
Baz baz;
}
-
-
-
@safe void bar(ref int*);
@safe void cbar(ref const int*);
@safe void sinister(out int*);
-
dg = &bar; // Error
auto dg2 = &bar;
}
-
-
void[] v;
immutable x = f(v);
}
-
{
return cast(T[])[];
}
-
-
const(ubyte)[] a;
auto b = cast(const(uint[])) a;
}
-
arr1[] = arr2[]; // overwrites pointers with arbitrary ints
}
-
enum c = new C();
enum pi = new int(3);
}
-
}
struct WhereField(FieldType) {}
-
/*
* TEST_OUTPUT:
---
-fail_compilation/test16195.d(13): Error: The `delete` keyword is obsolete. Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/test16195.d(14): Error: the `delete` keyword is obsolete
+fail_compilation/test16195.d(14): use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
---
*/
{
float g = foo().ptr[0];
}
-
TEST_OUTPUT:
---
fail_compilation/test16589.d(26): Error: returning `&this.data` escapes a reference to parameter `this`
-fail_compilation/test16589.d(26): perhaps annotate the function with `return`
+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): perhaps annotate the function with `return`
+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): perhaps annotate the parameter with `return`
+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): perhaps annotate the parameter with `return`
-fail_compilation/test16589.d(47): Error: returning `&s.data` escapes a reference to local variable `s`
-fail_compilation/test16589.d(52): Error: returning `& s` escapes a reference to local variable `s`
+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`
---
*/
}
pragma(msg, typeof(func!U));
-
enum a3 = __traits(getParameterStorageClasses, foo, int);
enum a4 = __traits(getParameterStorageClasses, foo, 0, 1);
-
TEST_OUTPUT:
---
fail_compilation/test17450.d(17): Error: returning `&s.bar` escapes a reference to parameter `s`
-fail_compilation/test17450.d(17): perhaps annotate the parameter with `return`
+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): perhaps annotate the function with `return`
+fail_compilation/test17450.d(19): perhaps annotate the function with `return`
---
*/
// https://issues.dlang.org/show_bug.cgi?id=17450
{
return S().bar(); // error
}
-
ref int foo() { return i; }
return foo();
}
-
-
super(msg, file, line);
}
}
-
-
imports.imp21353.P();
with (imports.imp21353) { P(); } // fixed
}
-
/*
TEST_OUTPUT:
---
-fail_compilation/test21927.d(17): Error: invalid `foreach` aggregate `this.T2(Args2...)`
-fail_compilation/test21927.d(18): Error: invalid `foreach` aggregate `this.T2!()`
+fail_compilation/test21927.d(17): Error: invalid `foreach` aggregate `this.T2(Args2...)` of type `void`
+fail_compilation/test21927.d(18): Error: invalid `foreach` aggregate `this.T2!()` of type `void`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/test21939.d(9): Error: invalid `foreach` aggregate `Object`, define `opApply()`, range primitives, or use `.tupleof`
+fail_compilation/test21939.d(10): Error: invalid `foreach` aggregate `Object` of type `Object`
+fail_compilation/test21939.d(10): maybe define `opApply()`, range primitives, or use `.tupleof`
---
*/
TEST_OUTPUT:
---
fail_compilation/test22541.d(104): Error: returning `i` escapes a reference to parameter `i`
-fail_compilation/test22541.d(104): perhaps annotate the parameter with `return`
+fail_compilation/test22541.d(102): perhaps annotate the parameter with `return`
---
*/
--- /dev/null
+/* REQUIRED_ARGS: -preview=dip1000
+ * TEST_OUTPUT:
+---
+fail_compilation/test22840.d(25): Error: returning `sb.slice()` escapes a reference to local variable `sb`
+---
+*/
+
+// inout method with inferred @safe escapes local data
+// https://issues.dlang.org/show_bug.cgi?id=22840
+
+// See also: https://issues.dlang.org/show_bug.cgi?id=20149
+
+struct S
+{
+ int buf;
+ auto slice() inout
+ {
+ return &buf;
+ }
+}
+
+int* fun() @safe
+{
+ S sb;
+ return sb.slice(); // should error
+}
--- /dev/null
+/* 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(15): perhaps change the `return scope` into `scope return`
+---
+*/
+@safe:
+
+struct S
+{
+ int val;
+ int* ptr;
+
+ int* retScope() return scope
+ {
+ return &this.val;
+ }
+}
static foreach (a, b, c)
{
}
-
-
//writefln(file1);
return 0;
}
-
int printf(const(char)*, const scope shared return ...);
int printf(const(char)*, ref out scope immutable shared return ...);
-
finally foo();
int x = 1;
}
-
-
auto num = removeIf( "abcdef".dup, ( char c ) { return c == 'c'; } );
assert(num == 5);
}
-
assert(i == 1); // this fails
}
}
-
printf("Success\n");
return 0;
}
-
return new Enumerator!(int)();
}
}
-
mixin GoodMixin;
mixin BadMixin;
}
-
return removeIf_!(ElemTypeOf!(Buf), Pred).fn( buf, pred );
}
}
-
void afn1() {}
void afn2() {}
-
public import imports.c22a : afn1;
void bfn1() {}
-
// extreme test of bug 4820
void nextis(W)(void delegate() dg = {}) {}
-
-
}
//A aFunc( A function() f );
-
funcC!(bool)(1.0);
foo!int(0);
}
-
import test11039;
static anotherGlobalField = SomeStruct!string("Hello Again!");
-
assert(pairA == pairB);
printf("Pair tests passed!\r\n");
}
-
Variant b = Variant(v);
}
}
-
private import imports.test29b;
deprecated alias imports.test29b.qwert qwert;
-
template Baz() {
private void privfunc(){ }
}
-
int f(){
return S.sizeof; // OK
}
-
return removeIf_!(ElemTypeOf!(Buf), Pred).fn( buf, pred );
}
}
-
printf("context.func>\n");
}
}
-
{
assert(false, "Blah");
}
-
printf("bar(t)\n");
return 3;
}
-
printf("bar(t,i)\n");
return 4;
}
-
private C!(char) c;
this() { c = new C!(char); }
}
-
{
alias Foo!(int) bar;
}
-
// doesn't work
void foo() { C!(int) x; }
-
-
module imports.test57b;
class C(T) { struct X {} }
-
long[] a;
a[] = -a[];
}
-
printf("AA\n");
aa = 1;
}
-
printf("BB\n");
bb = 1;
}
-
void bar3() {
Foo!(int) w;
}
-
}
/*************************************/
-
-
assert(a(10, 1, -1, -1, 1, 0) == -67);
return 0;
}
-
--- /dev/null
+/***************************************************/
+
+struct S1
+{
+ int x;
+ ~this() {}
+}
+
+__gshared S1* s1ptr;
+
+S1 test1a()
+{
+ auto result = S1(123);
+ (() @trusted { result.x++; s1ptr = &result; })();
+ return result;
+}
+
+void test1()
+{
+ auto r = test1a();
+ assert(r.x == 124);
+ assert(&r == s1ptr);
+}
+
+/***************************************************/
+
+void main()
+{
+ test1();
+}
return false;
return true;
}
-
-
-
int inner()() { return p; }
alias inner!() finner;
}
-
mixin(getEnum(1087));
void main() { }
-
printf("Success\n");
return 0;
}
-
-
globalField.getInnerField();
anotherGlobalField.getInnerField();
}
-
printf("Success\n");
return 0;
}
-
a.foo(c, null, false);
}
-
res ~= value;
assert(res == [1, 2, 3]);
}
-
ulog("point(1.2)\n");
return 0;
}
-
auto bar = genBar(args.length == 0);
return 0;
}
-
{
assert(test1(1) == test2(1));
}
-
foreach(p; px)
assert(p && *p == 7);
}
-
assert(temp!int() == 5);
}
}
-
TA!(int) variable;
return 0;
}
-
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=22175
+
+struct Struct
+{
+ short a = 24, b = 25, c = 26, d = 27;
+ ubyte e = 28;
+}
+
+Struct foo() { Struct s; s.a = 60; s.b = 61; s.c = 62, s.d = 63; s.e = 64; return s; }
+
+Struct test(int i) {
+ Struct var = i ? Struct() : foo();
+ Struct nest() { return var; }
+ return nest();
+}
+
+int main()
+{
+ auto s = test(0);
+ assert(s.a == 60);
+ assert(s.b == 61);
+ assert(s.c == 62);
+ assert(s.d == 63);
+ assert(s.e == 64);
+ s = test(1);
+ assert(s.a == 24);
+ assert(s.b == 25);
+ assert(s.c == 26);
+ assert(s.d == 27);
+ assert(s.e == 28);
+ return 0;
+}
--- /dev/null
+/*
+REQUIRED_ARGS: -release -check=assert=on
+PERMUTE_ARGS: -check=invariant=on
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=22945
+
+bool hitStruct;
+bool hitClass;
+
+struct S
+{
+ this(int) {}
+ invariant { hitStruct = true; }
+}
+
+class C
+{
+ this() {}
+ invariant { hitClass = true; }
+}
+
+int main()
+{
+ cast(void) S(0);
+ cast(void) new C();
+
+ version(D_Invariants)
+ {
+ assert(hitStruct && hitClass);
+ }
+ else
+ {
+ assert(!hitStruct && !hitClass);
+ }
+
+ return 0;
+}
assert(a.bar == "lolobetty");
return 0;
}
-
{
assert(S.sizeof == int.sizeof);
}
-
printf("Success\n");
}
-
-
void main() {
Bar.foobar();
}
-
import imports.test57a;
void main() {}
-
auto x = new C;
x.f(1);
}
-
{
test9495a();
test9495b();
-}
\ No newline at end of file
+}
// PERMUTE_ARGS: -betterC
void foo() { }
-
void whatever() {}
foo!(whatever)();
}
-
---
foo1 ulong function(return ref int* delegate() return p) ref return
foo2 int function(return ref int delegate() p) ref
-foo3 int function(return ref inout(int*) p) ref
+foo3 int function(ref inout(int*) p) ref
foo4 int function(return ref inout(int*) p) ref
---
*/
// Test scope mangling
assert(SS.foo1.mangleof == "_D10testscope22SS4foo1MFNcNjNkKDFNjZPiZm");
assert(SS.foo2.mangleof == "_D10testscope22SS4foo2MFNcNkKDFZiZi");
- assert(SS.foo3.mangleof == "_D10testscope22SS4foo3MFNcNkKNgPiZi");
+ assert(SS.foo3.mangleof == "_D10testscope22SS4foo3MFNcKNgPiZi");
assert(SS.foo4.mangleof == "_D10testscope22SS4foo4MFNcNkKNgPiZi");
// Test scope pretty-printing
assert(typeof(SS.foo1).stringof == "ref ulong(return ref int* delegate() return p) return");
assert(typeof(SS.foo2).stringof == "ref int(return ref int delegate() p)");
- assert(typeof(SS.foo3).stringof == "ref int(return ref inout(int*) p)");
+ assert(typeof(SS.foo3).stringof == "ref int(ref inout(int*) p)");
assert(typeof(SS.foo4).stringof == "ref int(return ref inout(int*) p)");
}
}
printf("Success\n");
return 0;
}
-
printf("Success\n");
return 0;
}
-
assert(stuff1.num == 1);
return 0;
}
-
#if __cplusplus
}
#endif
-
{
assert(magic == 12345);
return 0;
-}
\ No newline at end of file
+}
-26b581670ef6e2643d74078f200d1cd21fa40e90
+c52e28b723ccfbe845a95e8e7b528e3cc0b9d790
The first line of this file holds the git revision number of the last
merge done from the dlang/druntime repository.
DRUNTIME_DSOURCES_OPENBSD = core/sys/openbsd/dlfcn.d \
core/sys/openbsd/err.d core/sys/openbsd/execinfo.d \
- core/sys/openbsd/pthread_np.d core/sys/openbsd/stdlib.d \
- core/sys/openbsd/string.d core/sys/openbsd/sys/cdefs.d \
- core/sys/openbsd/sys/elf.d core/sys/openbsd/sys/elf32.d \
- core/sys/openbsd/sys/elf64.d core/sys/openbsd/sys/elf_common.d \
- core/sys/openbsd/sys/link_elf.d core/sys/openbsd/sys/mman.d \
- core/sys/openbsd/sys/sysctl.d core/sys/openbsd/time.d \
- core/sys/openbsd/unistd.d
+ core/sys/openbsd/pthread_np.d core/sys/openbsd/pwd.d \
+ core/sys/openbsd/stdlib.d core/sys/openbsd/string.d \
+ core/sys/openbsd/sys/cdefs.d core/sys/openbsd/sys/elf.d \
+ core/sys/openbsd/sys/elf32.d core/sys/openbsd/sys/elf64.d \
+ core/sys/openbsd/sys/elf_common.d core/sys/openbsd/sys/link_elf.d \
+ core/sys/openbsd/sys/mman.d core/sys/openbsd/sys/sysctl.d \
+ core/sys/openbsd/time.d core/sys/openbsd/unistd.d
DRUNTIME_DSOURCES_POSIX = core/sys/posix/aio.d \
core/sys/posix/arpa/inet.d core/sys/posix/config.d \
@DRUNTIME_OS_NETBSD_TRUE@am__objects_15 = $(am__objects_14)
am__objects_16 = core/sys/openbsd/dlfcn.lo core/sys/openbsd/err.lo \
core/sys/openbsd/execinfo.lo core/sys/openbsd/pthread_np.lo \
- core/sys/openbsd/stdlib.lo core/sys/openbsd/string.lo \
- core/sys/openbsd/sys/cdefs.lo core/sys/openbsd/sys/elf.lo \
- core/sys/openbsd/sys/elf32.lo core/sys/openbsd/sys/elf64.lo \
+ core/sys/openbsd/pwd.lo core/sys/openbsd/stdlib.lo \
+ core/sys/openbsd/string.lo core/sys/openbsd/sys/cdefs.lo \
+ core/sys/openbsd/sys/elf.lo core/sys/openbsd/sys/elf32.lo \
+ core/sys/openbsd/sys/elf64.lo \
core/sys/openbsd/sys/elf_common.lo \
core/sys/openbsd/sys/link_elf.lo core/sys/openbsd/sys/mman.lo \
core/sys/openbsd/sys/sysctl.lo core/sys/openbsd/time.lo \
DRUNTIME_DSOURCES_OPENBSD = core/sys/openbsd/dlfcn.d \
core/sys/openbsd/err.d core/sys/openbsd/execinfo.d \
- core/sys/openbsd/pthread_np.d core/sys/openbsd/stdlib.d \
- core/sys/openbsd/string.d core/sys/openbsd/sys/cdefs.d \
- core/sys/openbsd/sys/elf.d core/sys/openbsd/sys/elf32.d \
- core/sys/openbsd/sys/elf64.d core/sys/openbsd/sys/elf_common.d \
- core/sys/openbsd/sys/link_elf.d core/sys/openbsd/sys/mman.d \
- core/sys/openbsd/sys/sysctl.d core/sys/openbsd/time.d \
- core/sys/openbsd/unistd.d
+ core/sys/openbsd/pthread_np.d core/sys/openbsd/pwd.d \
+ core/sys/openbsd/stdlib.d core/sys/openbsd/string.d \
+ core/sys/openbsd/sys/cdefs.d core/sys/openbsd/sys/elf.d \
+ core/sys/openbsd/sys/elf32.d core/sys/openbsd/sys/elf64.d \
+ core/sys/openbsd/sys/elf_common.d core/sys/openbsd/sys/link_elf.d \
+ core/sys/openbsd/sys/mman.d core/sys/openbsd/sys/sysctl.d \
+ core/sys/openbsd/time.d core/sys/openbsd/unistd.d
DRUNTIME_DSOURCES_POSIX = core/sys/posix/aio.d \
core/sys/posix/arpa/inet.d core/sys/posix/config.d \
core/sys/openbsd/err.lo: core/sys/openbsd/$(am__dirstamp)
core/sys/openbsd/execinfo.lo: core/sys/openbsd/$(am__dirstamp)
core/sys/openbsd/pthread_np.lo: core/sys/openbsd/$(am__dirstamp)
+core/sys/openbsd/pwd.lo: core/sys/openbsd/$(am__dirstamp)
core/sys/openbsd/stdlib.lo: core/sys/openbsd/$(am__dirstamp)
core/sys/openbsd/string.lo: core/sys/openbsd/$(am__dirstamp)
core/sys/openbsd/sys/$(am__dirstamp):
in (atomicPtrIsProperlyAligned(here), "Argument `here` is not properly aligned")
{
// resolve implicit conversions
- T arg1 = ifThis;
+ const T arg1 = ifThis;
T arg2 = writeThis;
static if (__traits(isFloating, T))
shared NoIndirections n;
static assert(is(typeof(atomicLoad(n)) == NoIndirections));
}
+
+ unittest // Issue 21631
+ {
+ shared uint si1 = 45;
+ shared uint si2 = 38;
+ shared uint* psi = &si1;
+
+ assert((&psi).cas(cast(const) psi, &si2));
+ }
}
TypeFunction:
CallConvention FuncAttrs Arguments ArgClose Type
*/
- char[] parseTypeFunction( char[] name = null, IsDelegate isdg = IsDelegate.no ) return
+ char[] parseTypeFunction( char[] name = null, IsDelegate isdg = IsDelegate.no ) return scope
{
debug(trace) printf( "parseTypeFunction+\n" );
debug(trace) scope(success) printf( "parseTypeFunction-\n" );
bloat.
Params:
- fromType = name of the type being cast from
- fromSize = total size in bytes of the array being cast from
- toType = name of the type being cast o
- toSize = total size in bytes of the array being cast to
+ fromType = name of the type being cast from
+ fromSize = total size in bytes of the array being cast from
+ fromLength = length of array being cast from
+ toType = name of the type being cast to
+ toElemSize = element size of array being cast to
*/
-private void onArrayCastError()(string fromType, size_t fromSize, string toType, size_t toSize) @trusted
+private void onArrayCastError()(string fromType, size_t fromSize, size_t fromLength, string toType, size_t toElemSize) @trusted
{
import core.internal.string : unsignedToTempString;
import core.memory : pureMalloc;
index += N;
}
- add("An array of size ");
- auto s = unsignedToTempString(fromSize);
+ add("`");
+ add(fromType);
+ add("[]` of length ");
+ auto s = unsignedToTempString(fromLength);
add(s[]);
- add(" does not align on an array of size ");
- s = unsignedToTempString(toSize);
+ add(" cannot be cast to `");
+ add(toType);
+ add("[]` as its length in bytes (");
+ s = unsignedToTempString(fromSize);
add(s[]);
- add(", so `");
- add(fromType);
- add("` cannot be cast to `");
+ add(") is not a multiple of `");
add(toType);
- add("`");
+ add(".sizeof` (");
+ s = unsignedToTempString(toElemSize);
+ add(s[]);
+ add(").");
msg[index] = '\0'; // null-termination
// first argument must evaluate to `false` at compile-time to maintain memory safety in release builds
/**
The compiler lowers expressions of `cast(TTo[])TFrom[]` to
-this implementation.
+this implementation. Note that this does not detect alignment problems.
Params:
from = the array to reinterpret-cast
if ((fromSize % TTo.sizeof) != 0)
{
- onArrayCastError(TFrom.stringof, fromSize, TTo.stringof, toLength * TTo.sizeof);
+ onArrayCastError(TFrom.stringof, fromSize, from.length, TTo.stringof, TTo.sizeof);
}
struct Array
foreach (v; s)
assert(v == cast(short) 0xabab);
}
+
+@system nothrow unittest
+{
+ string msg;
+ try
+ {
+ auto str = "hello";
+ auto wstr = cast(wstring) str;
+ }
+ catch (Throwable t)
+ msg = t.msg;
+
+ static immutable expected = "`immutable(char)[]` of length 5 cannot be cast to `immutable(wchar)[]` as " ~
+ "its length in bytes (5) is not a multiple of `immutable(wchar).sizeof` (2).";
+
+ if (msg != expected)
+ {
+ import core.stdc.stdio;
+ printf("Expected: |%.*s|\n", cast(int) expected.length, expected.ptr);
+ printf("Actual : |%.*s|\n", cast(int) msg.length, msg.ptr);
+ assert(false);
+ }
+}
else version (linux)
{
// clone() fits better as we don't want to do anything but scanning in the child process.
- // no fork-handlera are called, so we can avoid deadlocks due to malloc locks. Probably related:
+ // no fork-handlers are called, so we can avoid deadlocks due to malloc locks. Probably related:
// https://sourceware.org/bugzilla/show_bug.cgi?id=4737
import core.sys.linux.sched : clone;
import core.sys.posix.signal : SIGCHLD;
- enum CLONE_CHILD_CLEARTID = 0x00200000; /* Register exit futex and memory */
- const flags = CLONE_CHILD_CLEARTID | SIGCHLD; // child thread id not needed
+ const flags = SIGCHLD; // exit signal
scope int delegate() scope dg = &child_mark;
extern(C) static int wrap_delegate(void* arg)
{
auto dg = cast(int delegate() scope*)arg;
return (*dg)();
}
- char[256] stackbuf; // enough stack space for clone() to place some info for the child without stomping the parent stack
+ ubyte[256] stackbuf; // enough stack space for clone() to place some info for the child without stomping the parent stack
auto stack = stackbuf.ptr + (isStackGrowingDown ? stackbuf.length : 0);
auto pid = clone(&wrap_delegate, stack, flags, &dg);
}
auto pid = fork();
fork_needs_lock = true;
}
- assert(pid != -1);
switch (pid)
{
case -1: // fork() failed, retry without forking
//printf("\tpool address range = %p .. %p\n", minAddr, maxAddr);
version (COLLECT_FORK)
- bool doFork = shouldFork;
+ alias doFork = shouldFork;
else
enum doFork = false;
final switch (forkResult)
{
case ChildStatus.error:
+ // fork() failed, retry without forking
disableFork();
goto Lmark;
case ChildStatus.running:
///
struct ldiv_t
{
- int quot,
- rem;
+ c_long quot,
+ rem;
}
///
///
inout(T)* data() inout @safe { return _Get_data()._Myptr; }
///
- inout(T)[] as_array() return scope inout nothrow @trusted { return _Get_data()._Myptr[0 .. _Get_data()._Mysize]; }
+ inout(T)[] as_array() scope return inout nothrow @trusted { return _Get_data()._Myptr[0 .. _Get_data()._Mysize]; }
///
ref inout(T) at(size_type i) inout nothrow @trusted { return _Get_data()._Myptr[0 .. _Get_data()._Mysize][i]; }
///
inout(T)* data() inout @safe { return __get_pointer(); }
///
- inout(T)[] as_array() return scope inout nothrow @trusted { return __get_pointer()[0 .. size()]; }
+ inout(T)[] as_array() scope return inout nothrow @trusted { return __get_pointer()[0 .. size()]; }
///
ref inout(T) at(size_type i) inout nothrow @trusted { return __get_pointer()[0 .. size()][i]; }
--- /dev/null
+/**
+ * D header file for OpenBSD pwd.h.
+ *
+ * Copyright: Copyright © 2022, The D Language Foundation
+ * License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
+ * Authors: Brian Callahan
+ */
+module core.sys.openbsd.pwd;
+
+version (OpenBSD):
+extern (C):
+nothrow:
+@nogc:
+
+public import core.sys.posix.pwd;
+import core.sys.posix.sys.types : uid_t;
+
+passwd* getpwnam_shadow(scope const char*);
+passwd* getpwuid_shadow(uid_t);
* $(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/package.d)
+ * Source: $(DRUNTIMESRC core/thread/context.d)
*/
module core.thread.context;
void sink(in char[] buf) scope nothrow
{
- fprintf(stderr, "%.*s", cast(int)buf.length, buf.ptr);
+ fwrite(buf.ptr, char.sizeof, buf.length, stderr);
}
formatThrowable(t, &sink);
}
-a74fa63e6775d626850d8ebd854d9803c7ffb97d
+99e9c1b7741e0f4e6f2a8c14883c4828d092701d
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
static if (isNarrowString!Source)
{
import std.string : representation;
- auto s = source.representation;
+ scope s = source.representation;
}
else
{
}
static if (isNarrowString!Source)
- source = cast(Source) s;
+ source = source[$ - s.length .. $];
static if (doCount)
{
* A $(LREF ConvException) if `source` is empty, if no number could be
* parsed, or if an overflow occurred.
*/
-auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref scope Source source)
+auto parse(Target, Source, Flag!"doCount" doCount = No.doCount)(ref Source source)
if (isInputRange!Source && isSomeChar!(ElementType!Source) && !is(Source == enum) &&
isFloatingPoint!Target && !is(Target == enum))
{
static if (isNarrowString!Source)
{
import std.string : representation;
- auto p = source.representation;
+ scope p = source.representation;
}
else
{
alias p = source;
}
- void advanceSource() @trusted
+ void advanceSource()
{
- // p is assigned from source.representation above so the cast is valid
static if (isNarrowString!Source)
- source = cast(Source) p;
+ source = source[$ - p.length .. $];
}
static immutable real[14] negtab =
}
}
}
+
+// Converts an unsigned integer to a compile-time string constant.
+package enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
+
+// Check that .stringof does what we expect, since it's not guaranteed by the
+// language spec.
+@safe /*@betterC*/ unittest
+{
+ assert(toCtString!0 == "0");
+ assert(toCtString!123456 == "123456");
+}
hnsecsToUnixEpoch;
}
}
+ else version (Hurd)
+ {
+ static if (clockType == ClockType.second)
+ return unixTimeToStdTime(core.stdc.time.time(null));
+ else
+ {
+ import core.sys.hurd.time : CLOCK_REALTIME_COARSE;
+ import core.sys.posix.time : clock_gettime, CLOCK_REALTIME;
+ static if (clockType == ClockType.coarse) alias clockArg = CLOCK_REALTIME_COARSE;
+ else static if (clockType == ClockType.normal) alias clockArg = CLOCK_REALTIME;
+ else static if (clockType == ClockType.precise) alias clockArg = CLOCK_REALTIME;
+ else static assert(0, "Previous static if is wrong.");
+ timespec ts = void;
+ immutable error = clock_gettime(clockArg, &ts);
+ // Posix clock_gettime called with a valid address and valid clock_id is only
+ // permitted to fail if the number of seconds does not fit in time_t. If tv_sec
+ // is long or larger overflow won't happen before 292 billion years A.D.
+ static if (ts.tv_sec.max < long.max)
+ {
+ if (error)
+ throw new TimeException("Call to clock_gettime() failed");
+ }
+ return convert!("seconds", "hnsecs")(ts.tv_sec) +
+ ts.tv_nsec / 100 +
+ hnsecsToUnixEpoch;
+ }
+ }
else static assert(0, "Unsupported OS");
}
else static assert(0, "Unsupported OS");
Returns: The `this` of this `SysTime`.
+/
- ref SysTime opAssign()(auto ref const(SysTime) rhs) return scope @safe pure nothrow
+ ref SysTime opAssign()(auto ref const(SysTime) rhs) scope return @safe pure nothrow
{
_stdTime = rhs._stdTime;
_timezone = rhs._timezone;
import std.concurrency : initOnce;
initOnce!stdSharedDefaultLogger({
auto buffer = cast(ubyte[]) _buffer;
- return emplace!FileLogger(buffer, stderr, LogLevel.warning);
+ return emplace!FileLogger(buffer, stderr, LogLevel.info);
}());
return stdSharedDefaultLogger;
}
/** This property sets and gets the default `Logger`. Unless set to another
-logger by the user, the default logger's log level is LogLevel.warning.
+logger by the user, the default logger's log level is LogLevel.info.
Example:
-------------
auto oldunspecificLogger = sharedLog;
- assert(oldunspecificLogger.logLevel == LogLevel.warning,
+ assert(oldunspecificLogger.logLevel == LogLevel.info,
to!string(oldunspecificLogger.logLevel));
assert(l.logLevel == LogLevel.all);
{
auto dl = cast(FileLogger) sharedLog;
assert(dl !is null);
- assert(dl.logLevel == LogLevel.warning);
+ assert(dl.logLevel == LogLevel.info);
assert(globalLogLevel == LogLevel.all);
auto tl = cast(StdForwardLogger) stdThreadLocalLog;
{
auto dl = cast(FileLogger) sharedLog;
assert(dl !is null);
- assert(dl.logLevel == LogLevel.warning);
+ assert(dl.logLevel == LogLevel.info);
assert(globalLogLevel == LogLevel.all);
auto tl = cast(StdForwardLogger) stdThreadLocalLog;
{
auto dl = cast(FileLogger) sharedLog;
assert(dl !is null);
- assert(dl.logLevel == LogLevel.warning);
+ assert(dl.logLevel == LogLevel.info);
assert(globalLogLevel == LogLevel.all);
auto tl = cast(StdForwardLogger) stdThreadLocalLog;
string file = __FILE__,
size_t line = __LINE__) @safe
{
- this(name, sysErrorString(errno), file, line, errno);
+ this(name, generateSysErrorMsg(errno), file, line, errno);
}
else version (Posix) this(scope const(char)[] name,
uint errno = .errno,
while (true)
{
auto len = GetModuleFileNameW(null, buffer.ptr, cast(DWORD) buffer.length);
- enforce(len, sysErrorString(GetLastError()));
+ wenforce(len);
if (len != buffer.length)
return to!(string)(buffer[0 .. len]);
buffer.length *= 2;
// Only Solaris 10 and later
return readLink(format("/proc/%d/path/a.out", getpid()));
}
+ else version (Hurd)
+ {
+ return readLink("/proc/self/exe");
+ }
else
static assert(0, "thisExePath is not supported on this platform");
}
enum hasToString = HasToStringResult.none;
}
else static if (is(typeof(
- {
- T val = void;
+ (T val) {
const FormatSpec!Char f;
static struct S {void put(scope Char s){}}
S s;
enum hasToString = HasToStringResult.customPutWriterFormatSpec;
}
else static if (is(typeof(
- {
- T val = void;
+ (T val) {
static struct S {void put(scope Char s){}}
S s;
val.toString(s);
{
enum hasToString = HasToStringResult.customPutWriter;
}
- else static if (is(typeof({ T val = void; FormatSpec!Char f; val.toString((scope const(char)[] s){}, f); })))
+ else static if (is(typeof((T val) { FormatSpec!Char f; val.toString((scope const(char)[] s){}, f); })))
{
enum hasToString = HasToStringResult.constCharSinkFormatSpec;
}
- else static if (is(typeof({ T val = void; val.toString((scope const(char)[] s){}, "%s"); })))
+ else static if (is(typeof((T val) { val.toString((scope const(char)[] s){}, "%s"); })))
{
enum hasToString = HasToStringResult.constCharSinkFormatString;
}
- else static if (is(typeof({ T val = void; val.toString((scope const(char)[] s){}); })))
+ else static if (is(typeof((T val) { val.toString((scope const(char)[] s){}); })))
{
enum hasToString = HasToStringResult.constCharSink;
}
else static if (hasPreviewIn &&
- is(typeof({ T val = void; FormatSpec!Char f; val.toString((in char[] s){}, f); })))
+ is(typeof((T val) { FormatSpec!Char f; val.toString((in char[] s){}, f); })))
{
enum hasToString = HasToStringResult.inCharSinkFormatSpec;
}
else static if (hasPreviewIn &&
- is(typeof({ T val = void; val.toString((in char[] s){}, "%s"); })))
+ is(typeof((T val) { val.toString((in char[] s){}, "%s"); })))
{
enum hasToString = HasToStringResult.inCharSinkFormatString;
}
else static if (hasPreviewIn &&
- is(typeof({ T val = void; val.toString((in char[] s){}); })))
+ is(typeof((T val) { val.toString((in char[] s){}); })))
{
enum hasToString = HasToStringResult.inCharSink;
}
- else static if (is(typeof({ T val = void; return val.toString(); }()) S) && isSomeString!S)
+ else static if (is(ReturnType!((T val) { return val.toString(); }) S) && isSomeString!S)
{
enum hasToString = HasToStringResult.hasSomeToString;
}
}
}
+// const toString methods
+@safe unittest
+{
+ import std.range.primitives : isOutputRange;
+
+ static struct A
+ {
+ void toString(Writer)(ref Writer w) const
+ if (isOutputRange!(Writer, string))
+ {}
+ }
+ static struct B
+ {
+ void toString(scope void delegate(scope const(char)[]) sink, scope FormatSpec!char fmt) const {}
+ }
+ static struct C
+ {
+ void toString(scope void delegate(scope const(char)[]) sink, string fmt) const {}
+ }
+ static struct D
+ {
+ void toString(scope void delegate(scope const(char)[]) sink) const {}
+ }
+ static struct E
+ {
+ string toString() const {return "";}
+ }
+ static struct F
+ {
+ void toString(Writer)(ref Writer w, scope const ref FormatSpec!char fmt) const
+ if (isOutputRange!(Writer, string))
+ {}
+ }
+ static struct G
+ {
+ string toString() const {return "";}
+ void toString(Writer)(ref Writer w) const if (isOutputRange!(Writer, string)) {}
+ }
+ static struct H
+ {
+ string toString() const {return "";}
+ void toString(Writer)(ref Writer w, scope const ref FormatSpec!char fmt) const
+ if (isOutputRange!(Writer, string))
+ {}
+ }
+ static struct I
+ {
+ void toString(Writer)(ref Writer w) const if (isOutputRange!(Writer, string)) {}
+ void toString(Writer)(ref Writer w, scope const ref FormatSpec!char fmt) const
+ if (isOutputRange!(Writer, string))
+ {}
+ }
+ static struct J
+ {
+ string toString() const {return "";}
+ void toString(Writer)(ref Writer w, scope ref FormatSpec!char fmt) const
+ if (isOutputRange!(Writer, string))
+ {}
+ }
+ static struct K
+ {
+ void toString(Writer)(Writer w, scope const ref FormatSpec!char fmt) const
+ if (isOutputRange!(Writer, string))
+ {}
+ }
+ static struct L
+ {
+ void toString(Writer)(ref Writer w, scope const FormatSpec!char fmt) const
+ if (isOutputRange!(Writer, string))
+ {}
+ }
+ static struct M
+ {
+ void toString(scope void delegate(in char[]) sink, in FormatSpec!char fmt) const {}
+ }
+ static struct N
+ {
+ void toString(scope void delegate(in char[]) sink, string fmt) const {}
+ }
+ static struct O
+ {
+ void toString(scope void delegate(in char[]) sink) const {}
+ }
+
+ with(HasToStringResult)
+ {
+ static assert(hasToString!(A, char) == customPutWriter);
+ static assert(hasToString!(B, char) == constCharSinkFormatSpec);
+ static assert(hasToString!(C, char) == constCharSinkFormatString);
+ static assert(hasToString!(D, char) == constCharSink);
+ static assert(hasToString!(E, char) == hasSomeToString);
+ static assert(hasToString!(F, char) == customPutWriterFormatSpec);
+ static assert(hasToString!(G, char) == customPutWriter);
+ static assert(hasToString!(H, char) == customPutWriterFormatSpec);
+ static assert(hasToString!(I, char) == customPutWriterFormatSpec);
+ static assert(hasToString!(J, char) == hasSomeToString);
+ static assert(hasToString!(K, char) == constCharSinkFormatSpec);
+ static assert(hasToString!(L, char) == none);
+ static if (hasPreviewIn)
+ {
+ static assert(hasToString!(M, char) == inCharSinkFormatSpec);
+ static assert(hasToString!(N, char) == inCharSinkFormatString);
+ static assert(hasToString!(O, char) == inCharSink);
+ }
+
+ // https://issues.dlang.org/show_bug.cgi?id=22873
+ static assert(hasToString!(inout(A), char) == customPutWriter);
+ static assert(hasToString!(inout(B), char) == constCharSinkFormatSpec);
+ static assert(hasToString!(inout(C), char) == constCharSinkFormatString);
+ static assert(hasToString!(inout(D), char) == constCharSink);
+ static assert(hasToString!(inout(E), char) == hasSomeToString);
+ static assert(hasToString!(inout(F), char) == customPutWriterFormatSpec);
+ static assert(hasToString!(inout(G), char) == customPutWriter);
+ static assert(hasToString!(inout(H), char) == customPutWriterFormatSpec);
+ static assert(hasToString!(inout(I), char) == customPutWriterFormatSpec);
+ static assert(hasToString!(inout(J), char) == hasSomeToString);
+ static assert(hasToString!(inout(K), char) == constCharSinkFormatSpec);
+ static assert(hasToString!(inout(L), char) == none);
+ static if (hasPreviewIn)
+ {
+ static assert(hasToString!(inout(M), char) == inCharSinkFormatSpec);
+ static assert(hasToString!(inout(N), char) == inCharSinkFormatString);
+ static assert(hasToString!(inout(O), char) == inCharSink);
+ }
+ }
+}
+
// object formatting with toString
private void formatObject(Writer, T, Char)(ref Writer w, ref T val, scope const ref FormatSpec!Char f)
if (hasToString!(T, Char))
if (isSomeString!(typeof(fmt)))
{
alias e = checkFormatException!(fmt, Args);
- static assert(!e, e.msg);
+ static assert(!e, e);
return .sformat(buf, fmt, args);
}
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, Args);
- static assert(!e, e.msg);
+ static assert(!e, e);
return .formattedRead(r, fmt, args);
}
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, Args);
- static assert(!e, e.msg);
+ static assert(!e, e);
return .formattedWrite(w, fmt, args);
}
import std.meta : AliasSeq, Reverse;
import std.traits : isCallable, Parameters;
+import std.conv : toCtString;
import std.internal.attributes : betterC;
}
}
-// Converts an unsigned integer to a compile-time string constant.
-private enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
-
-// Check that .stringof does what we expect, since it's not guaranteed by the
-// language spec.
-@safe unittest
-{
- assert(toCtString!0 == "0");
- assert(toCtString!123456 == "123456");
-}
-
/**
* Passes the fields of a struct as arguments to a function.
*
(*a)[0] = "world"; // segmentation fault
---
*/
- @property ref inout(JSONValue[]) array() return scope inout pure @system
+ @property ref inout(JSONValue[]) array() scope return inout pure @system
{
enforce!JSONException(type == JSONType.array,
"JSONValue is not an array");
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, A);
- static assert(!e, e.msg);
+ static assert(!e, e);
return this.writef(fmt, args);
}
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, A);
- static assert(!e, e.msg);
+ static assert(!e, e);
return this.writefln(fmt, args);
}
import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf;
return cast(uint) sysconf(_SC_NPROCESSORS_ONLN);
}
+ else version (Hurd)
+ {
+ import core.sys.posix.unistd : _SC_NPROCESSORS_ONLN, sysconf;
+ return cast(uint) sysconf(_SC_NPROCESSORS_ONLN);
+ }
else
{
static assert(0, "Don't know how to get N CPUs on this OS.");
}
else version (Windows)
{
- import std.exception : enforce;
- enforce(
+ import std.windows.syserror : wenforce;
+ wenforce(
SetEnvironmentVariableW(name.tempCStringW(), value.tempCStringW()),
- sysErrorString(GetLastError())
);
return value;
}
{
throw new StdioException(
"Failed to make "~which~" stream inheritable by child process ("
- ~sysErrorString(GetLastError()) ~ ')',
+ ~generateSysErrorMsg() ~ ')',
0);
}
}
if (!CreatePipe(&readHandle, &writeHandle, null, 0))
{
throw new StdioException(
- "Error creating pipe (" ~ sysErrorString(GetLastError()) ~ ')',
+ "Error creating pipe (" ~ generateSysErrorMsg() ~ ')',
0);
}
string file = __FILE__,
size_t line = __LINE__)
{
- auto lastMsg = sysErrorString(GetLastError());
+ auto lastMsg = generateSysErrorMsg();
auto msg = customMsg.empty ? lastMsg
: customMsg ~ " (" ~ lastMsg ~ ')';
return new ProcessException(msg, file, line);
else
version (Windows)
{
- return sysErrorString(err);
+ return generateSysErrorMsg(err);
}
else
return "Socket error " ~ to!string(err);
{
version (Windows)
{
- return sysErrorString(err);
+ return generateSysErrorMsg(err);
}
else
{
{
import core.sys.windows.winbase : OVERLAPPED;
import core.sys.windows.winnt : BOOL, ULARGE_INTEGER;
+ import std.windows.syserror : wenforce;
private BOOL lockImpl(alias F, Flags...)(ulong start, ulong length,
Flags flags)
return F(windowsHandle, flags, 0, liLength.LowPart,
liLength.HighPart, &overlapped);
}
-
- private static T wenforce(T)(T cond, lazy string str)
- {
- import core.sys.windows.winbase : GetLastError;
- import std.windows.syserror : sysErrorString;
-
- if (cond) return cond;
- throw new Exception(str ~ ": " ~ sysErrorString(GetLastError()));
- }
}
version (Posix)
{
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, A);
- static assert(!e, e.msg);
+ static assert(!e, e);
return this.writef(fmt, args);
}
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, A);
- static assert(!e, e.msg);
+ static assert(!e, e);
return this.writefln(fmt, args);
}
import std.format : checkFormatException;
alias e = checkFormatException!(format, Data);
- static assert(!e, e.msg);
+ static assert(!e, e);
return this.readf(format, data);
}
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, A);
- static assert(!e, e.msg);
+ static assert(!e, e);
return .writef(fmt, args);
}
import std.format : checkFormatException;
alias e = checkFormatException!(fmt, A);
- static assert(!e, e.msg);
+ static assert(!e, e);
return .writefln(fmt, args);
}
import std.format : checkFormatException;
alias e = checkFormatException!(format, A);
- static assert(!e, e.msg);
+ static assert(!e, e);
return .readf(format, args);
}
import std.traits : CommonType, DeducedParameterType;
import std.typecons : ReplaceTypeUnless;
import std.typecons : Flag;
+import std.conv : toCtString;
/// Placeholder used to refer to the enclosing [SumType].
struct This {}
-// Converts an unsigned integer to a compile-time string constant.
-private enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
-
-// Check that .stringof does what we expect, since it's not guaranteed by the
-// language spec.
-@safe unittest
-{
- assert(toCtString!0 == "0");
- assert(toCtString!123456 == "123456");
-}
-
// True if a variable of type T can appear on the lhs of an assignment
private enum isAssignableTo(T) =
isAssignable!T || (!isCopyable!T && isRvalueAssignable!T);
{
return isNull ? fallback : _value.payload;
}
+
+ /// $(MREF_ALTTEXT Range interface, std, range, primitives) functions.
+ alias empty = isNull;
+
+ /// ditto
+ alias popFront = nullify;
+
+ /// ditto
+ alias popBack = nullify;
+
+ /// ditto
+ @property ref inout(T) front() inout @safe pure nothrow
+ {
+ return get();
+ }
+
+ /// ditto
+ alias back = front;
+
+ /// ditto
+ @property inout(typeof(this)) save() inout
+ {
+ return this;
+ }
+
+ /// ditto
+ inout(typeof(this)) opIndex() inout
+ {
+ return this;
+ }
+
+ /// ditto
+ inout(typeof(this)) opIndex(size_t[2] dim) inout
+ in (dim[0] <= length && dim[1] <= length && dim[1] >= dim[0])
+ {
+ return (dim[0] == 0 && dim[1] == 1) ? this : this.init;
+ }
+ /// ditto
+ size_t[2] opSlice(size_t dim : 0)(size_t from, size_t to) const
+ {
+ return [from, to];
+ }
+
+ /// ditto
+ @property size_t length() const @safe pure nothrow
+ {
+ return !empty;
+ }
+
+ /// ditto
+ alias opDollar(size_t dim : 0) = length;
+
+ /// ditto
+ ref inout(T) opIndex(size_t index) inout @safe pure nothrow
+ in (index < length)
+ {
+ return get();
+ }
}
/// ditto
assert(a.isNull);
assertThrown!Throwable(a.get);
}
+///
+@safe unittest
+{
+ import std.algorithm.iteration : each, joiner;
+ Nullable!int a = 42;
+ Nullable!int b;
+ // Add each value to an array
+ int[] arr;
+ a.each!((n) => arr ~= n);
+ assert(arr == [42]);
+ b.each!((n) => arr ~= n);
+ assert(arr == [42]);
+ // Take first value from an array of Nullables
+ Nullable!int[] c = new Nullable!int[](10);
+ c[7] = Nullable!int(42);
+ assert(c.joiner.front == 42);
+}
@safe unittest
{
auto k = Nullable!int(74);
a = b = c = nullable(5);
}
+// https://issues.dlang.org/show_bug.cgi?id=18374
+@safe pure nothrow unittest
+{
+ import std.algorithm.comparison : equal;
+ import std.range : only, takeNone;
+ import std.range.primitives : hasAssignableElements, hasLength,
+ hasLvalueElements, hasSlicing, hasSwappableElements,
+ isRandomAccessRange;
+ Nullable!int a = 42;
+ assert(!a.empty);
+ assert(a.front == 42);
+ assert(a.back == 42);
+ assert(a[0] == 42);
+ assert(a.equal(only(42)));
+ assert(a[0 .. $].equal(only(42)));
+ a[0] = 43;
+ assert(a.equal(only(43)));
+ --a[0];
+ assert(a.equal(only(42)));
+ Nullable!int b;
+ assert(b.empty);
+ assert(b.equal(takeNone(b)));
+ Nullable!int c = a.save();
+ assert(!c.empty);
+ c.popFront();
+ assert(!a.empty);
+ assert(c.empty);
+
+ assert(isRandomAccessRange!(Nullable!int));
+ assert(hasLength!(Nullable!int));
+ assert(hasSlicing!(Nullable!int));
+ assert(hasAssignableElements!(Nullable!int));
+ assert(hasSwappableElements!(Nullable!int));
+ assert(hasLvalueElements!(Nullable!int));
+}
+
/**
Just like `Nullable!T`, except that the null state is defined as a
particular value. For example, $(D Nullable!(uint, uint.max)) is an
enum isBaseEnumType(T) = is(E == T);
alias Base = OriginalType!E;
Base mValue;
- static struct Negation
- {
- @safe @nogc pure nothrow:
- private:
- Base mValue;
-
- // Prevent non-copy construction outside the module.
- @disable this();
- this(Base value)
- {
- mValue = value;
- }
- }
public:
this(E flag)
return mValue;
}
- Negation opUnary(string op)() const
+ auto opUnary(string op)() const
if (op == "~")
{
- return Negation(~mValue);
+ return BitFlags(cast(E) cast(Base) ~mValue);
}
auto ref opAssign(T...)(T flags)
return this;
}
- auto ref opOpAssign(string op: "&")(Negation negatedFlags)
- {
- mValue &= negatedFlags.mValue;
- return this;
- }
-
auto opBinary(string op)(BitFlags flags) const
if (op == "|" || op == "&")
{
return result;
}
- auto opBinary(string op: "&")(Negation negatedFlags) const
- {
- BitFlags result = this;
- result.opOpAssign!op(negatedFlags);
- return result;
- }
-
auto opBinaryRight(string op)(E flag) const
if (op == "|" || op == "&")
{
assert(flags.A && !flags.B && !flags.C);
}
+// Negation of BitFlags should work with any base type.
+// Double-negation of BitFlags should work.
+@safe @nogc pure nothrow unittest
+{
+ static foreach (alias Base; AliasSeq!(
+ byte,
+ ubyte,
+ short,
+ ushort,
+ int,
+ uint,
+ long,
+ ulong,
+ ))
+ {{
+ enum Enum : Base
+ {
+ A = 1 << 0,
+ B = 1 << 1,
+ C = 1 << 2,
+ }
+
+ auto flags = BitFlags!Enum(Enum.A);
+
+ assert(flags == ~~flags);
+ }}
+}
+
private enum false_(T) = false;
// ReplaceType
Returns:
An array with the same element type as `s`.
+/
-ElementEncodingType!S[] toLower(S)(S s)
-if (isSomeString!S || (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
+ElementEncodingType!S[] toLower(S)(return scope S s) @trusted
+if (isSomeString!S)
{
static import std.ascii;
+ return toCase!(LowerTriple, std.ascii.toLower)(s);
+}
- static if (isSomeString!S)
- return () @trusted { return toCase!(LowerTriple, std.ascii.toLower)(s); } ();
- else
- return toCase!(LowerTriple, std.ascii.toLower)(s);
+/// ditto
+ElementEncodingType!S[] toLower(S)(S s)
+if (!isSomeString!S && (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
+{
+ static import std.ascii;
+ return toCase!(LowerTriple, std.ascii.toLower)(s);
}
// overloads for the most common cases to reduce compile time
@safe pure /*TODO nothrow*/
{
- string toLower(string s)
+ string toLower(return scope string s)
{ return toLower!string(s); }
- wstring toLower(wstring s)
+ wstring toLower(return scope wstring s)
{ return toLower!wstring(s); }
- dstring toLower(dstring s)
+ dstring toLower(return scope dstring s)
{ return toLower!dstring(s); }
@safe unittest
Returns:
An new array with the same element type as `s`.
+/
-ElementEncodingType!S[] toUpper(S)(S s)
-if (isSomeString!S || (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
+ElementEncodingType!S[] toUpper(S)(return scope S s) @trusted
+if (isSomeString!S)
{
static import std.ascii;
+ return toCase!(UpperTriple, std.ascii.toUpper)(s);
+}
- static if (isSomeString!S)
- return () @trusted { return toCase!(UpperTriple, std.ascii.toUpper)(s); } ();
- else
- return toCase!(UpperTriple, std.ascii.toUpper)(s);
+/// ditto
+ElementEncodingType!S[] toUpper(S)(S s)
+if (!isSomeString!S && (isRandomAccessRange!S && hasLength!S && hasSlicing!S && isSomeChar!(ElementType!S)))
+{
+ static import std.ascii;
+ return toCase!(UpperTriple, std.ascii.toUpper)(s);
}
// overloads for the most common cases to reduce compile time
@safe pure /*TODO nothrow*/
{
- string toUpper(string s)
+ string toUpper(return scope string s)
{ return toUpper!string(s); }
- wstring toUpper(wstring s)
+ wstring toUpper(return scope wstring s)
{ return toUpper!wstring(s); }
- dstring toUpper(dstring s)
+ dstring toUpper(return scope dstring s)
{ return toUpper!dstring(s); }
@safe unittest
to!int(result.length), null, null);
}
- if (!readLen || readLen != result.length)
- {
- throw new Exception("Couldn't convert string: " ~
- sysErrorString(GetLastError()));
- }
-
+ wenforce(readLen && readLen == result.length, "Couldn't convert string");
return result.ptr;
}
}
to!int(result.length));
}
- if (!readLen || readLen != result.length)
- {
- throw new Exception("Couldn't convert string: " ~
- sysErrorString(GetLastError()));
- }
+ wenforce(readLen && readLen == result.length, "Couldn't convert string");
return result[0 .. result.length-1].to!string; // omit trailing null
}
}
return s[0 .. c-s]; // string is ASCII, no conversion necessary
}
-
-
{
private alias DWORD = int;
final @property DWORD code(); /// `GetLastError`'s return value.
- this(DWORD code, string str=null, string file = null, size_t line = 0) @trusted;
+ this(DWORD code, string str=null, string file = null, size_t line = 0) nothrow @trusted;
}
/++
version (Windows):
import core.sys.windows.winbase, core.sys.windows.winnt;
-import std.array : appender;
-import std.conv : to;
-import std.format.write : formattedWrite;
+import std.array : appender, Appender;
+import std.conv : to, toTextRange, text;
+import std.exception;
import std.windows.charset;
string sysErrorString(
{
auto buf = appender!string();
- if (!putSysError(errCode, buf, MAKELANGID(langId, subLangId)))
- {
- throw new Exception(
- "failed getting error string for WinAPI error code: " ~
- sysErrorString(GetLastError()));
- }
+ wenforce(
+ // Ignore unlikely UTF decoding errors, always report the actual error (`errCode`)
+ putSysError(errCode, buf, MAKELANGID(langId, subLangId)).ifThrown(false),
+ text("Could not fetch error string for WinAPI code ", errCode)
+ );
return buf.data;
}
+@safe unittest
+{
+ import std.algorithm.searching;
+
+ assert(sysErrorString(ERROR_PATH_NOT_FOUND) !is null);
+
+ const msg = collectExceptionMsg!WindowsException(sysErrorString(DWORD.max));
+ assert(msg.startsWith(`Could not fetch error string for WinAPI code 4294967295: `));
+}
+
bool putSysError(Writer)(DWORD code, Writer w, /*WORD*/int langId = 0)
{
wchar *lpMsgBuf = null;
return false;
}
-
class WindowsException : Exception
{
import core.sys.windows.windef : DWORD;
final @property DWORD code() { return _code; } /// `GetLastError`'s return value.
private DWORD _code;
- this(DWORD code, string str=null, string file = null, size_t line = 0) @trusted
+ this(DWORD code, string str=null, string file = null, size_t line = 0) nothrow @trusted
{
_code = code;
- auto buf = appender!string();
+ auto buf = appender!(char[]);
if (str != null)
{
buf.put(": ");
}
- if (code)
+ if (code && writeErrorMessage(code, buf))
{
- auto success = putSysError(code, buf);
- formattedWrite(buf, success ? " (error %d)" : "Error %d", code);
+ buf.put(" (error ");
+ toTextRange(code, buf);
+ buf.put(')');
}
- super(buf.data, file, line);
+ super(cast(immutable) buf.data, file, line);
}
}
+/// Writes the error string associated to `code` into `buf`.
+/// Writes `Error <code>` when the error message lookup fails
+private bool writeErrorMessage(DWORD code, ref Appender!(char[]) buf) nothrow
+{
+ bool success;
+ try
+ {
+ // Reset the buffer to undo partial changes
+ const len = buf[].length;
+ scope (failure) buf.shrinkTo(len);
-T wenforce(T, S)(T value, lazy S msg = null,
+ success = putSysError(code, buf);
+ }
+ catch (Exception) {}
+
+ // Write the error code instead if we couldn't find the string
+ if (!success)
+ {
+ buf.put("Error ");
+ toTextRange(code, buf);
+ }
+
+ return success;
+}
+
+T wenforce(T, S = string)(T value, lazy S msg = null,
string file = __FILE__, size_t line = __LINE__)
if (isSomeString!S)
{
throw new WindowsException(GetLastError(), names, file, line);
}
-version (Windows)
@system unittest
{
import std.algorithm.searching : startsWith, endsWith;
- import std.exception;
import std.string;
auto e = collectException!WindowsException(
e = new WindowsException(0, "Test");
assert(e.msg == "Test");
}
+
+@safe nothrow unittest
+{
+ import std.algorithm.searching : endsWith;
+
+ auto e = new WindowsException(ERROR_FILE_NOT_FOUND);
+ assert(e.msg.endsWith("(error 2)"));
+
+ e = new WindowsException(DWORD.max);
+ assert(e.msg == "Error 4294967295");
+}
+
+/// Tries to translate an error code from the Windows API to the corresponding
+/// error message. Returns `Error <code>` on failure
+package (std) string generateSysErrorMsg(DWORD errCode = GetLastError()) nothrow @trusted
+{
+ auto buf = appender!(char[]);
+ cast(void) writeErrorMessage(errCode, buf);
+ return cast(immutable) buf[];
+}
+
+nothrow @safe unittest
+{
+ assert(generateSysErrorMsg(ERROR_PATH_NOT_FOUND) !is null);
+ assert(generateSysErrorMsg(DWORD.max) == "Error 4294967295");
+}
--- /dev/null
+// { dg-shouldfail " world!" }
+// { dg-output "object.Exception@.*: hello.*world!" }
+module message_with_null;
+
+void main()
+{
+ throw new Exception("hello\0 world!");
+}