d/root-filename.o \
d/root-hash.o \
d/root-longdouble.o \
+ d/root-optional.o \
d/root-port.o \
d/root-region.o \
d/root-rmem.o \
continue;
/* Get the result of the attribute if it hasn't already been folded. */
- if (attr->op == TOKcall)
+ if (attr->op == EXP::call)
attr = attr->ctfeInterpret ();
- if (attr->op != TOKstructliteral)
+ if (attr->op != EXP::structLiteral)
{
warning_at (make_location_t (attr->loc), OPT_Wattributes,
"%qE attribute has no effect",
Expressions *elems = attr->isStructLiteralExp ()->elements;
Expression *e0 = (*elems)[0];
- if (e0->op != TOKstring)
+ if (e0->op != EXP::string_)
{
warning_at (make_location_t (attr->loc), OPT_Wattributes,
"unknown attribute %qs", e0->toChars());
{
Lagain:
Expression *arg = (*arguments)[i];
- gcc_assert (arg->op != TOKtuple);
+ gcc_assert (arg->op != EXP::tuple);
- if (arg->op == TOKcomma)
+ if (arg->op == EXP::comma)
{
CommaExp *ce = arg->isCommaExp ();
tree tce = build_expr (ce->e1);
/* Nested structs also have ADDRESSABLE set, but if the type has
neither a copy constructor nor a destructor available, then we
need to take care of copying its value before passing it. */
- if (arg->op == TOKstructliteral || (!sd->postblit && !sd->dtor))
+ if (arg->op == EXP::structLiteral || (!sd->postblit && !sd->dtor))
targ = force_target_expr (targ);
targ = convert (build_reference_type (TREE_TYPE (targ)),
cst = build_integer_cst (expr->toInteger (), build_ctype (expr->type));
else if (expr->type->isfloating ())
cst = build_float_cst (expr->toReal (), expr->type);
- else if (expr->op == TOKarrayliteral)
+ else if (expr->op == EXP::arrayLiteral)
{
/* Build array as VECTOR_CST, assumes EXPR is constant. */
Expressions *elements = expr->isArrayLiteralExp ()->elements;
cst = native_interpret_expr (vectype, buffer, len);
Expression *e = d_eval_constant_expression (expr->loc, cst);
- gcc_assert (e != NULL && e->op == TOKvector);
+ gcc_assert (e != NULL && e->op == EXP::vector);
return e->isVectorExp ()->e1;
}
global.params.inclusiveInContracts = value;
break;
- case OPT_fpreview_intpromote:
- global.params.fix16997 = value;
- break;
-
case OPT_fpreview_nosharedaccess:
global.params.noSharedAccess = value;
break;
case OPT_frevert_all:
global.params.useDIP25 = FeatureState::disabled;
- global.params.markdown = !value;
global.params.dtorFields = FeatureState::disabled;
+ global.params.fix16997 = !value;
+ global.params.markdown = !value;
break;
case OPT_frevert_dip25:
global.params.dtorFields = FeatureState::disabled;
break;
+ case OPT_frevert_intpromote:
+ global.params.fix16997 = !value;
+ break;
+
case OPT_frevert_markdown:
global.params.markdown = !value;
break;
void
Port::valcpy (void *buffer, uint64_t value, size_t sz)
{
+ gcc_assert (((size_t) buffer) % sz == 0);
+
switch (sz)
{
case 1:
Returns true if the operation is supported or type is not a vector. */
bool
-Target::isVectorOpSupported (Type *type, unsigned op, Type *)
+Target::isVectorOpSupported (Type *type, EXP op, Type *)
{
if (type->ty != TY::Tvector)
return true;
/* Don't support if expression cannot be represented. */
switch (op)
{
- case TOKpow:
- case TOKpowass:
+ case EXP::pow:
+ case EXP::powAssign:
/* pow() is lowered as a function call. */
return false;
- case TOKmod:
- case TOKmodass:
+ case EXP::mod:
+ case EXP::modAssign:
/* fmod() is lowered as a function call. */
if (type->isfloating ())
return false;
break;
- case TOKandand:
- case TOKoror:
+ case EXP::andAnd:
+ case EXP::orOr:
/* Logical operators must have a result type of bool. */
return false;
- case TOKle:
- case TOKlt:
- case TOKge:
- case TOKgt:
- case TOKequal:
- case TOKnotequal:
- case TOKidentity:
- case TOKnotidentity:
+ case EXP::lessOrEqual:
+ case EXP::lessThan:
+ case EXP::greaterOrEqual:
+ case EXP::greaterThan:
+ case EXP::equal:
+ case EXP::notEqual:
+ case EXP::identity:
+ case EXP::notIdentity:
/* Comparison operators must have a result type of bool. */
return false;
ne->type = cd->type;
Expression *e = ne->ctfeInterpret ();
- gcc_assert (e->op == TOKclassreference);
+ gcc_assert (e->op == EXP::classReference);
return build_class_instance (e->isClassReferenceExp ());
}
-568496d5b6ed02d577dfa86f73c7bb4edee05813
+3982604c54e8770585985a33577fbf19b9b5c9ce
The first line of this file holds the git revision number of the last
merge done from the dlang/dmd repository.
{
// Do access check
ClassDeclaration cd = tc.sym;
- if (e.op == TOK.super_)
+ if (e.op == EXP.super_)
{
if (ClassDeclaration cd2 = sc.func.toParent().isClassDeclaration())
cd = cd2;
}
foreach (e; *elements)
{
- if (e && e.op == TOK.error)
+ if (e && e.op == EXP.error)
return false;
}
override final Type getType()
{
+ /* Apply storage classes to forward references. (Issue 22254)
+ * Note: Avoid interfaces for now. Implementing qualifiers on interface
+ * definitions exposed some issues in their TypeInfo generation in DMD.
+ * Related PR: https://github.com/dlang/dmd/pull/13312
+ */
+ if (semanticRun == PASS.init && !isInterfaceDeclaration())
+ {
+ auto stc = storage_class;
+ if (_scope)
+ stc |= _scope.stc;
+ type = type.addSTC(stc);
+ }
return type;
}
if (ad.aliasthis)
{
Loc loc = e.loc;
- Type tthis = (e.op == TOK.type ? e.type : null);
+ Type tthis = (e.op == EXP.type ? e.type : null);
const flags = DotExpFlag.noAliasThis | (gag ? DotExpFlag.gag : 0);
uint olderrors = gag ? global.startGagging() : 0;
e = dotExp(e.type, sc, e, ad.aliasthis.ident, flags);
if (tthis && ad.aliasthis.sym.needThis())
{
- if (e.op == TOK.variable)
+ if (e.op == EXP.variable)
{
if (auto fd = (cast(VarExp)e).var.isFuncDeclaration())
{
import dmd.expressionsem;
import dmd.func;
import dmd.globals;
+import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.mtype;
bool isArrayOpValid(Expression e)
{
//printf("isArrayOpValid() %s\n", e.toChars());
- if (e.op == TOK.slice)
+ if (e.op == EXP.slice)
return true;
- if (e.op == TOK.arrayLiteral)
+ if (e.op == EXP.arrayLiteral)
{
Type t = e.type.toBasetype();
while (t.ty == Tarray || t.ty == Tsarray)
{
return isArrayOpValid((cast(UnaExp)e).e1);
}
- if (isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || e.op == TOK.assign)
+ if (isBinArrayOp(e.op) || isBinAssignArrayOp(e.op) || e.op == EXP.assign)
{
BinExp be = cast(BinExp)e;
return isArrayOpValid(be.e1) && isArrayOpValid(be.e2);
}
- if (e.op == TOK.construct)
+ if (e.op == EXP.construct)
{
BinExp be = cast(BinExp)e;
- return be.e1.op == TOK.slice && isArrayOpValid(be.e2);
+ return be.e1.op == EXP.slice && isArrayOpValid(be.e2);
}
- // if (e.op == TOK.call)
+ // if (e.op == EXP.call)
// {
// TODO: Decide if [] is required after arrayop calls.
// }
bool isNonAssignmentArrayOp(Expression e)
{
- if (e.op == TOK.slice)
+ if (e.op == EXP.slice)
return isNonAssignmentArrayOp((cast(SliceExp)e).e1);
Type tb = e.type.toBasetype();
if (tn && (!tn.isMutable() || !tn.isAssignable()))
{
e.error("slice `%s` is not mutable", e.e1.toChars());
- if (e.op == TOK.addAssign)
+ if (e.op == EXP.addAssign)
checkPossibleAddCatError!(AddAssignExp, CatAssignExp)(e.isAddAssignExp);
return ErrorExp.get();
}
- if (e.e1.op == TOK.arrayLiteral)
+ if (e.e1.op == EXP.arrayLiteral)
{
return e.e1.modifiableLvalue(sc, e.e1);
}
// RPN, prefix unary ops with u
OutBuffer buf;
buf.writestring("u");
- buf.writestring(Token.toString(e.op));
+ buf.writestring(EXPtoString(e.op));
e.e1.accept(this);
tiargs.push(new StringExp(Loc.initial, buf.extractSlice()).expressionSemantic(sc));
}
// RPN
e.e1.accept(this);
e.e2.accept(this);
- tiargs.push(new StringExp(Loc.initial, Token.toString(e.op)).expressionSemantic(sc));
+ tiargs.push(new StringExp(Loc.initial, EXPtoString(e.op)).expressionSemantic(sc));
}
}
}
/***********************************************
* Test if expression is a unary array op.
*/
-bool isUnaArrayOp(TOK op)
+bool isUnaArrayOp(EXP op)
{
switch (op)
{
- case TOK.negate:
- case TOK.tilde:
+ case EXP.negate:
+ case EXP.tilde:
return true;
default:
break;
/***********************************************
* Test if expression is a binary array op.
*/
-bool isBinArrayOp(TOK op)
+bool isBinArrayOp(EXP op)
{
switch (op)
{
- case TOK.add:
- case TOK.min:
- case TOK.mul:
- case TOK.div:
- case TOK.mod:
- case TOK.xor:
- case TOK.and:
- case TOK.or:
- case TOK.pow:
+ case EXP.add:
+ case EXP.min:
+ case EXP.mul:
+ case EXP.div:
+ case EXP.mod:
+ case EXP.xor:
+ case EXP.and:
+ case EXP.or:
+ case EXP.pow:
return true;
default:
break;
/***********************************************
* Test if expression is a binary assignment array op.
*/
-bool isBinAssignArrayOp(TOK op)
+bool isBinAssignArrayOp(EXP op)
{
switch (op)
{
- case TOK.addAssign:
- case TOK.minAssign:
- case TOK.mulAssign:
- case TOK.divAssign:
- case TOK.modAssign:
- case TOK.xorAssign:
- case TOK.andAssign:
- case TOK.orAssign:
- case TOK.powAssign:
+ case EXP.addAssign:
+ case EXP.minAssign:
+ case EXP.mulAssign:
+ case EXP.divAssign:
+ case EXP.modAssign:
+ case EXP.xorAssign:
+ case EXP.andAssign:
+ case EXP.orAssign:
+ case EXP.powAssign:
return true;
default:
break;
bool isArrayOpOperand(Expression e)
{
//printf("Expression.isArrayOpOperand() %s\n", e.toChars());
- if (e.op == TOK.slice)
+ if (e.op == EXP.slice)
return true;
- if (e.op == TOK.arrayLiteral)
+ if (e.op == EXP.arrayLiteral)
{
Type t = e.type.toBasetype();
while (t.ty == Tarray || t.ty == Tsarray)
return (isUnaArrayOp(e.op) ||
isBinArrayOp(e.op) ||
isBinAssignArrayOp(e.op) ||
- e.op == TOK.assign);
+ e.op == EXP.assign);
}
return false;
}
ErrorExp arrayOpInvalidError(Expression e)
{
e.error("invalid array operation `%s` (possible missing [])", e.toChars());
- if (e.op == TOK.add)
+ if (e.op == EXP.add)
checkPossibleAddCatError!(AddExp, CatExp)(e.isAddExp());
- else if (e.op == TOK.addAssign)
+ else if (e.op == EXP.addAssign)
checkPossibleAddCatError!(AddAssignExp, CatAssignExp)(e.isAddAssignExp());
return ErrorExp.get();
}
foreach_ = 0x4000, /// variable for foreach loop
variadic = 0x8000, /// the `variadic` parameter in: T foo(T a, U b, V variadic...)
- ctorinit = 0x1_0000, /// can only be set inside constructor
+ // = 0x1_0000,
templateparameter = 0x2_0000, /// template parameter
ref_ = 0x4_0000, /// `ref`
scope_ = 0x8_0000, /// `scope`
returninferred = 0x100_0000, /// `return` has been inferred and should not be part of mangling, `return_` must also be set
immutable_ = 0x200_0000, /// `immutable`
- init = 0x400_0000, /// has explicit initializer
+ // = 0x400_0000,
manifest = 0x800_0000, /// manifest constant
nodtor = 0x1000_0000, /// do not run destructor
(*args)[0] = e;
}
- if (e.isBool(true))
+ const opt = e.toBool();
+ if (opt.isEmpty())
+ return PINLINE.default_;
+ else if (opt.get())
return PINLINE.always;
- else if (e.isBool(false))
- return PINLINE.never;
else
- return PINLINE.default_;
+ return PINLINE.never;
}
override const(char)* kind() const
// expand static foreach
import dmd.statementsem: makeTupleForeach;
- Dsymbols* d = makeTupleForeach!(true,true)(_scope, sfe.aggrfe, decl, sfe.needExpansion).decl;
+ Dsymbols* d = makeTupleForeach(_scope, true, true, sfe.aggrfe, decl, sfe.needExpansion).decl;
if (d) // process generated declarations
{
// Add members lazily.
result = BE.fallthru;
if (s.exp)
{
- if (s.exp.op == TOK.halt)
+ if (s.exp.op == EXP.halt)
{
result = BE.halt;
return;
}
- if (s.exp.op == TOK.assert_)
+ if (s.exp.op == EXP.assert_)
{
AssertExp a = cast(AssertExp)s.exp;
- if (a.e1.isBool(false)) // if it's an assert(0)
+ if (a.e1.toBool().hasValue(false)) // if it's an assert(0)
{
result = BE.halt;
return;
{
if (canThrow(s.condition, func, mustNotThrow))
result |= BE.throw_;
- if (!(result & BE.break_) && s.condition.isBool(true))
+ if (!(result & BE.break_) && s.condition.toBool().hasValue(true))
result &= ~BE.fallthru;
}
result &= ~(BE.break_ | BE.continue_);
{
if (canThrow(s.condition, func, mustNotThrow))
result |= BE.throw_;
- if (s.condition.isBool(true))
+ const opt = s.condition.toBool();
+ if (opt.hasValue(true))
result &= ~BE.fallthru;
- else if (s.condition.isBool(false))
+ else if (opt.hasValue(false))
return;
}
else
result = BE.none;
if (canThrow(s.condition, func, mustNotThrow))
result |= BE.throw_;
- if (s.condition.isBool(true))
+
+ const opt = s.condition.toBool();
+ if (opt.hasValue(true))
{
result |= blockExit(s.ifbody, func, mustNotThrow);
}
- else if (s.condition.isBool(false))
+ else if (opt.hasValue(false))
{
result |= blockExit(s.elsebody, func, mustNotThrow);
}
s.accept(be);
return be.result;
}
-
module dmd.builtin;
-import core.stdc.math;
-import core.stdc.string;
import dmd.arraytypes;
import dmd.expression;
import dmd.func;
override void visit(AssignExp ae)
{
// blit-init cannot throw
- if (ae.op == TOK.blit)
+ if (ae.op == EXP.blit)
return;
/* Element-wise assignment could invoke postblits.
*/
fop.generated = true;
Expression e1 = new IdentifierExp(loc, Id.p);
Expression e2 = new IdentifierExp(loc, Id.q);
- Expression e = new EqualExp(TOK.equal, loc, e1, e2);
+ Expression e = new EqualExp(EXP.equal, loc, e1, e2);
fop.fbody = new ReturnStatement(loc, e);
uint errors = global.startGagging(); // Do not report errors
Scope* sc2 = sc.push();
Dsymbol s = null;
switch (e.op)
{
- case TOK.overloadSet:
+ case EXP.overloadSet:
s = (cast(OverExp)e).vars;
break;
- case TOK.scope_:
+ case EXP.scope_:
s = (cast(ScopeExp)e).sds;
break;
- case TOK.variable:
+ case EXP.variable:
s = (cast(VarExp)e).var;
break;
default:
void reserve(d_size_t nbytes);
void setsize(d_size_t size);
void reset();
- void write(const void *data, size_t nbytes);
+ void write(const void *data, d_size_t nbytes);
void writestring(const char *string);
void prependstring(const char *string);
void writenl(); // write newline
sc = sc.endCTFE();
el = el.optimize(WANTvalue);
el = el.ctfeInterpret();
- if (el.op == TOK.int64)
+ if (el.op == EXP.int64)
{
Expressions *es = void;
if (auto ale = aggr.isArrayLiteralExp())
//printf("Expression::isConst(): %s\n", e.toChars());
switch (e.op)
{
- case TOK.int64:
- case TOK.float64:
- case TOK.complex80:
+ case EXP.int64:
+ case EXP.float64:
+ case EXP.complex80:
return 1;
- case TOK.null_:
+ case EXP.null_:
return 0;
- case TOK.symbolOffset:
+ case EXP.symbolOffset:
return 2;
default:
return 0;
}
/**********************************
- * Initialize a TOK.cantExpression Expression.
+ * Initialize a EXP.cantExpression Expression.
* Params:
* ue = where to write it
*/
void cantExp(out UnionExp ue)
{
- emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
+ emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
}
/* =============================== constFold() ============================== */
{
UnionExp ue = void;
Loc loc = e1.loc;
- emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(false) ? 1 : 0, type);
+ emplaceExp!(IntegerExp)(&ue, loc, e1.toBool().hasValue(false) ? 1 : 0, type);
return ue;
}
{
UnionExp ue = void;
Loc loc = e1.loc;
- emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(true) ? 1 : 0, type);
+ emplaceExp!(IntegerExp)(&ue, loc, e1.toBool().hasValue(true) ? 1 : 0, type);
return ue;
}
}
emplaceExp!(ComplexExp)(&ue, loc, v, type);
}
- else if (e1.op == TOK.symbolOffset)
+ else if (e1.op == EXP.symbolOffset)
{
SymOffExp soe = cast(SymOffExp)e1;
emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e2.toInteger());
ue.exp().type = type;
}
- else if (e2.op == TOK.symbolOffset)
+ else if (e2.op == EXP.symbolOffset)
{
SymOffExp soe = cast(SymOffExp)e2;
emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger());
}
emplaceExp!(ComplexExp)(&ue, loc, v, type);
}
- else if (e1.op == TOK.symbolOffset)
+ else if (e1.op == EXP.symbolOffset)
{
SymOffExp soe = cast(SymOffExp)e1;
emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset - e2.toInteger());
return ue;
}
-/* Also returns TOK.cantExpression if cannot be computed.
+/* Also returns EXP.cantExpression if cannot be computed.
*/
-UnionExp Equal(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
int cmp = 0;
real_t r1 = CTFloat.zero;
real_t r2 = CTFloat.zero;
//printf("Equal(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
- assert(op == TOK.equal || op == TOK.notEqual);
- if (e1.op == TOK.null_)
+ assert(op == EXP.equal || op == EXP.notEqual);
+ if (e1.op == EXP.null_)
{
- if (e2.op == TOK.null_)
+ if (e2.op == EXP.null_)
cmp = 1;
- else if (e2.op == TOK.string_)
+ else if (e2.op == EXP.string_)
{
StringExp es2 = cast(StringExp)e2;
cmp = (0 == es2.len);
}
- else if (e2.op == TOK.arrayLiteral)
+ else if (e2.op == EXP.arrayLiteral)
{
ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
cmp = !es2.elements || (0 == es2.elements.dim);
return ue;
}
}
- else if (e2.op == TOK.null_)
+ else if (e2.op == EXP.null_)
{
- if (e1.op == TOK.string_)
+ if (e1.op == EXP.string_)
{
StringExp es1 = cast(StringExp)e1;
cmp = (0 == es1.len);
}
- else if (e1.op == TOK.arrayLiteral)
+ else if (e1.op == EXP.arrayLiteral)
{
ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
cmp = !es1.elements || (0 == es1.elements.dim);
return ue;
}
}
- else if (e1.op == TOK.string_ && e2.op == TOK.string_)
+ else if (e1.op == EXP.string_ && e2.op == EXP.string_)
{
StringExp es1 = cast(StringExp)e1;
StringExp es2 = cast(StringExp)e2;
else
cmp = 0;
}
- else if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral)
+ else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral)
{
ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
{
auto ee1 = es1[i];
auto ee2 = es2[i];
- ue = Equal(TOK.equal, loc, Type.tint32, ee1, ee2);
+ ue = Equal(EXP.equal, loc, Type.tint32, ee1, ee2);
if (CTFEExp.isCantExp(ue.exp()))
return ue;
cmp = cast(int)ue.exp().toInteger();
}
}
}
- else if (e1.op == TOK.arrayLiteral && e2.op == TOK.string_)
+ else if (e1.op == EXP.arrayLiteral && e2.op == EXP.string_)
{
// Swap operands and use common code
Expression etmp = e1;
e2 = etmp;
goto Lsa;
}
- else if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral)
+ else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral)
{
Lsa:
StringExp es1 = cast(StringExp)e1;
}
}
}
- else if (e1.op == TOK.structLiteral && e2.op == TOK.structLiteral)
+ else if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
{
StructLiteralExp es1 = cast(StructLiteralExp)e1;
StructLiteralExp es2 = cast(StructLiteralExp)e2;
cmp = 0;
break;
}
- ue = Equal(TOK.equal, loc, Type.tint32, ee1, ee2);
- if (ue.exp().op == TOK.cantExpression)
+ ue = Equal(EXP.equal, loc, Type.tint32, ee1, ee2);
+ if (ue.exp().op == EXP.cantExpression)
return ue;
cmp = cast(int)ue.exp().toInteger();
if (cmp == 0)
cantExp(ue);
return ue;
}
- if (op == TOK.notEqual)
+ if (op == EXP.notEqual)
cmp ^= 1;
emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
return ue;
}
-UnionExp Identity(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
int cmp;
- if (e1.op == TOK.null_)
+ if (e1.op == EXP.null_)
{
- cmp = (e2.op == TOK.null_);
+ cmp = (e2.op == EXP.null_);
}
- else if (e2.op == TOK.null_)
+ else if (e2.op == EXP.null_)
{
cmp = 0;
}
- else if (e1.op == TOK.symbolOffset && e2.op == TOK.symbolOffset)
+ else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
{
SymOffExp es1 = cast(SymOffExp)e1;
SymOffExp es2 = cast(SymOffExp)e2;
}
else
{
- ue = Equal((op == TOK.identity) ? TOK.equal : TOK.notEqual, loc, type, e1, e2);
+ ue = Equal((op == EXP.identity) ? EXP.equal : EXP.notEqual, loc, type, e1, e2);
return ue;
}
}
- if (op == TOK.notIdentity)
+ if (op == EXP.notIdentity)
cmp ^= 1;
emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
return ue;
}
-UnionExp Cmp(TOK op, const ref Loc loc, Type type, Expression e1, Expression e2)
+UnionExp Cmp(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
{
UnionExp ue = void;
dinteger_t n;
real_t r1 = CTFloat.zero;
real_t r2 = CTFloat.zero;
//printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
- if (e1.op == TOK.string_ && e2.op == TOK.string_)
+ if (e1.op == EXP.string_ && e2.op == EXP.string_)
{
StringExp es1 = cast(StringExp)e1;
StringExp es2 = cast(StringExp)e2;
return ue;
}
-/* Also returns TOK.cantExpression if cannot be computed.
+/* Also returns EXP.cantExpression if cannot be computed.
* to: type to cast to
* type: type to paint the result
*/
emplaceExp!(UnionExp)(&ue, e1);
return ue;
}
- if (e1.op == TOK.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to))
+ if (e1.op == EXP.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to))
{
Expression ex = (cast(VectorExp)e1).e1;
emplaceExp!(UnionExp)(&ue, ex);
}
/* Allow casting from one string type to another
*/
- if (e1.op == TOK.string_)
+ if (e1.op == EXP.string_)
{
if (tb.ty == Tarray && typeb.ty == Tarray && tb.nextOf().size() == typeb.nextOf().size())
{
goto L1;
}
}
- if (e1.op == TOK.arrayLiteral && typeb == tb)
+ if (e1.op == EXP.arrayLiteral && typeb == tb)
{
L1:
Expression ex = expType(to, e1);
{
cantExp(ue);
}
- else if (tb.ty == Tstruct && e1.op == TOK.int64)
+ else if (tb.ty == Tstruct && e1.op == EXP.int64)
{
// Struct = 0;
StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration();
UnionExp zero;
emplaceExp!(IntegerExp)(&zero, 0);
ue = Cast(loc, v.type, v.type, zero.exp());
- if (ue.exp().op == TOK.cantExpression)
+ if (ue.exp().op == EXP.cantExpression)
return ue;
elements.push(ue.exp().copy());
}
{
UnionExp ue = void;
Loc loc = e1.loc;
- if (e1.op == TOK.string_)
+ if (e1.op == EXP.string_)
{
StringExp es1 = cast(StringExp)e1;
emplaceExp!(IntegerExp)(&ue, loc, es1.len, type);
}
- else if (e1.op == TOK.arrayLiteral)
+ else if (e1.op == EXP.arrayLiteral)
{
ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
size_t dim = ale.elements ? ale.elements.dim : 0;
emplaceExp!(IntegerExp)(&ue, loc, dim, type);
}
- else if (e1.op == TOK.assocArrayLiteral)
+ else if (e1.op == EXP.assocArrayLiteral)
{
AssocArrayLiteralExp ale = cast(AssocArrayLiteralExp)e1;
size_t dim = ale.keys.dim;
return ue;
}
-/* Also return TOK.cantExpression if this fails
+/* Also return EXP.cantExpression if this fails
*/
UnionExp Index(Type type, Expression e1, Expression e2)
{
Loc loc = e1.loc;
//printf("Index(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
assert(e1.type);
- if (e1.op == TOK.string_ && e2.op == TOK.int64)
+ if (e1.op == EXP.string_ && e2.op == EXP.int64)
{
StringExp es1 = cast(StringExp)e1;
uinteger_t i = e2.toInteger();
emplaceExp!(IntegerExp)(&ue, loc, es1.charAt(i), type);
}
}
- else if (e1.type.toBasetype().ty == Tsarray && e2.op == TOK.int64)
+ else if (e1.type.toBasetype().ty == Tsarray && e2.op == EXP.int64)
{
TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype();
uinteger_t length = tsa.dim.toInteger();
e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length);
emplaceExp!(ErrorExp)(&ue);
}
- else if (e1.op == TOK.arrayLiteral)
+ else if (e1.op == EXP.arrayLiteral)
{
ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
auto e = ale[cast(size_t)i];
else
cantExp(ue);
}
- else if (e1.type.toBasetype().ty == Tarray && e2.op == TOK.int64)
+ else if (e1.type.toBasetype().ty == Tarray && e2.op == EXP.int64)
{
uinteger_t i = e2.toInteger();
- if (e1.op == TOK.arrayLiteral)
+ if (e1.op == EXP.arrayLiteral)
{
ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
if (i >= ale.elements.dim)
else
cantExp(ue);
}
- else if (e1.op == TOK.assocArrayLiteral)
+ else if (e1.op == EXP.assocArrayLiteral)
{
AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e1;
/* Search the keys backwards, in case there are duplicate keys
{
i--;
Expression ekey = (*ae.keys)[i];
- ue = Equal(TOK.equal, loc, Type.tbool, ekey, e2);
+ ue = Equal(EXP.equal, loc, Type.tbool, ekey, e2);
if (CTFEExp.isCantExp(ue.exp()))
return ue;
- if (ue.exp().isBool(true))
+ if (ue.exp().toBool().hasValue(true))
{
Expression e = (*ae.values)[i];
e.type = type;
return ue;
}
-/* Also return TOK.cantExpression if this fails
+/* Also return EXP.cantExpression if this fails
*/
UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
{
newupr <= upr);
}
- if (e1.op == TOK.string_ && lwr.op == TOK.int64 && upr.op == TOK.int64)
+ if (e1.op == EXP.string_ && lwr.op == EXP.int64 && upr.op == EXP.int64)
{
StringExp es1 = cast(StringExp)e1;
const uinteger_t ilwr = lwr.toInteger();
es.type = type;
}
}
- else if (e1.op == TOK.arrayLiteral && lwr.op == TOK.int64 && upr.op == TOK.int64 && !hasSideEffect(e1))
+ else if (e1.op == EXP.arrayLiteral && lwr.op == EXP.int64 && upr.op == EXP.int64 && !hasSideEffect(e1))
{
ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
const uinteger_t ilwr = lwr.toInteger();
}
}
- if (e1.op == TOK.arrayLiteral)
+ if (e1.op == EXP.arrayLiteral)
append(cast(ArrayLiteralExp)e1);
else
elems.push(e1);
if (e2)
{
- if (e2.op == TOK.arrayLiteral)
+ if (e2.op == EXP.arrayLiteral)
append(cast(ArrayLiteralExp)e2);
else
elems.push(e2);
return elems;
}
-/* Also return TOK.cantExpression if this fails
+/* Also return EXP.cantExpression if this fails
*/
UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
{
Type t2 = e2.type.toBasetype();
//printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
//printf("\tt1 = %s, t2 = %s, type = %s\n", t1.toChars(), t2.toChars(), type.toChars());
- if (e1.op == TOK.null_ && (e2.op == TOK.int64 || e2.op == TOK.structLiteral))
+ if (e1.op == EXP.null_ && (e2.op == EXP.int64 || e2.op == EXP.structLiteral))
{
e = e2;
t = t1;
goto L2;
}
- else if ((e1.op == TOK.int64 || e1.op == TOK.structLiteral) && e2.op == TOK.null_)
+ else if ((e1.op == EXP.int64 || e1.op == EXP.structLiteral) && e2.op == EXP.null_)
{
e = e1;
t = t2;
assert(ue.exp().type);
return ue;
}
- else if (e1.op == TOK.null_ && e2.op == TOK.null_)
+ else if (e1.op == EXP.null_ && e2.op == EXP.null_)
{
if (type == e1.type)
{
assert(ue.exp().type);
return ue;
}
- else if (e1.op == TOK.string_ && e2.op == TOK.string_)
+ else if (e1.op == EXP.string_ && e2.op == EXP.string_)
{
// Concatenate the strings
StringExp es1 = cast(StringExp)e1;
assert(ue.exp().type);
return ue;
}
- else if (e2.op == TOK.string_ && e1.op == TOK.arrayLiteral && t1.nextOf().isintegral())
+ else if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
{
// [chars] ~ string --> [chars]
StringExp es = cast(StringExp)e2;
assert(ue.exp().type);
return ue;
}
- else if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral && t2.nextOf().isintegral())
+ else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral())
{
// string ~ [chars] --> [chars]
StringExp es = cast(StringExp)e1;
assert(ue.exp().type);
return ue;
}
- else if (e1.op == TOK.string_ && e2.op == TOK.int64)
+ else if (e1.op == EXP.string_ && e2.op == EXP.int64)
{
// string ~ char --> string
StringExp es1 = cast(StringExp)e1;
assert(ue.exp().type);
return ue;
}
- else if (e1.op == TOK.int64 && e2.op == TOK.string_)
+ else if (e1.op == EXP.int64 && e2.op == EXP.string_)
{
// [w|d]?char ~ string --> string
// We assume that we only ever prepend one char of the same type
assert(ue.exp().type);
return ue;
}
- else if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
+ else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
{
// Concatenate the arrays
auto elems = copyElements(e1, e2);
assert(ue.exp().type);
return ue;
}
- else if (e1.op == TOK.arrayLiteral && e2.op == TOK.null_ && t1.nextOf().equals(t2.nextOf()))
+ else if (e1.op == EXP.arrayLiteral && e2.op == EXP.null_ && t1.nextOf().equals(t2.nextOf()))
{
e = e1;
goto L3;
}
- else if (e1.op == TOK.null_ && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
+ else if (e1.op == EXP.null_ && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
{
e = e2;
L3:
assert(ue.exp().type);
return ue;
}
- else if ((e1.op == TOK.arrayLiteral || e1.op == TOK.null_) && e1.type.toBasetype().nextOf() && e1.type.toBasetype().nextOf().equals(e2.type))
+ else if ((e1.op == EXP.arrayLiteral || e1.op == EXP.null_) && e1.type.toBasetype().nextOf() && e1.type.toBasetype().nextOf().equals(e2.type))
{
- auto elems = (e1.op == TOK.arrayLiteral)
+ auto elems = (e1.op == EXP.arrayLiteral)
? copyElements(e1) : new Expressions();
elems.push(e2);
assert(ue.exp().type);
return ue;
}
- else if (e2.op == TOK.arrayLiteral && e2.type.toBasetype().nextOf().equals(e1.type))
+ else if (e2.op == EXP.arrayLiteral && e2.type.toBasetype().nextOf().equals(e1.type))
{
auto elems = copyElements(e1, e2);
assert(ue.exp().type);
return ue;
}
- else if (e1.op == TOK.null_ && e2.op == TOK.string_)
+ else if (e1.op == EXP.null_ && e2.op == EXP.string_)
{
t = e1.type;
e = e2;
goto L1;
}
- else if (e1.op == TOK.string_ && e2.op == TOK.null_)
+ else if (e1.op == EXP.string_ && e2.op == EXP.null_)
{
e = e1;
t = e2.type;
{
//printf("Ptr(e1 = %s)\n", e1.toChars());
UnionExp ue = void;
- if (e1.op == TOK.add)
+ if (e1.op == EXP.add)
{
AddExp ae = cast(AddExp)e1;
- if (ae.e1.op == TOK.address && ae.e2.op == TOK.int64)
+ if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
{
AddrExp ade = cast(AddrExp)ae.e1;
- if (ade.e1.op == TOK.structLiteral)
+ if (ade.e1.op == EXP.structLiteral)
{
StructLiteralExp se = cast(StructLiteralExp)ade.e1;
uint offset = cast(uint)ae.e2.toInteger();
case TOK.sizeof_:
Lexp:
auto exp = cparseExpression();
- if (token.value == TOK.identifier && exp.op == TOK.identifier)
+ if (token.value == TOK.identifier && exp.op == EXP.identifier)
{
error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars());
nextToken();
break;
case TOK.plusPlus:
- e = new AST.PostExp(TOK.plusPlus, loc, e);
+ e = new AST.PostExp(EXP.plusPlus, loc, e);
break;
case TOK.minusMinus:
- e = new AST.PostExp(TOK.minusMinus, loc, e);
+ e = new AST.PostExp(EXP.minusMinus, loc, e);
break;
case TOK.leftParenthesis:
// Parse `++` as an unary operator so that cast expressions only give
// an error for being non-lvalues.
e = cparseCastExp();
- e = new AST.PreExp(TOK.prePlusPlus, loc, e);
+ e = new AST.PreExp(EXP.prePlusPlus, loc, e);
break;
case TOK.minusMinus:
nextToken();
// Parse `--` as an unary operator, same as prefix increment.
e = cparseCastExp();
- e = new AST.PreExp(TOK.preMinusMinus, loc, e);
+ e = new AST.PreExp(EXP.preMinusMinus, loc, e);
break;
case TOK.and:
const loc = token.loc;
auto e = cparseShiftExp();
- TOK op = token.value;
- switch (op)
+ EXP op = EXP.reserved;
+ switch (token.value)
{
- case TOK.lessThan:
- case TOK.lessOrEqual:
- case TOK.greaterThan:
- case TOK.greaterOrEqual:
+ case TOK.lessThan: op = EXP.lessThan; goto Lcmp;
+ case TOK.lessOrEqual: op = EXP.lessOrEqual; goto Lcmp;
+ case TOK.greaterThan: op = EXP.greaterThan; goto Lcmp;
+ case TOK.greaterOrEqual: op = EXP.greaterOrEqual; goto Lcmp;
+ Lcmp:
nextToken();
auto e2 = cparseShiftExp();
e = new AST.CmpExp(op, loc, e, e2);
const loc = token.loc;
auto e = cparseRelationalExp();
- const TOK op = token.value;
- switch (op)
+ EXP op = EXP.reserved;
+ switch (token.value)
{
- case TOK.equal:
- case TOK.notEqual:
+ case TOK.equal: op = EXP.equal; goto Lequal;
+ case TOK.notEqual: op = EXP.notEqual; goto Lequal;
+ Lequal:
nextToken();
auto e2 = cparseRelationalExp();
e = new AST.EqualExp(op, loc, e, e2);
{
nextToken();
auto e2 = cparseOrExp();
- e = new AST.LogicalExp(loc, TOK.andAnd, e, e2);
+ e = new AST.LogicalExp(loc, EXP.andAnd, e, e2);
}
return e;
}
{
nextToken();
auto e2 = cparseAndAndExp();
- e = new AST.LogicalExp(loc, TOK.orOr, e, e2);
+ e = new AST.LogicalExp(loc, EXP.orOr, e, e2);
}
return e;
}
switch (token.value)
{
case TOK.identifier:
- error("missing comma");
+ if (s)
+ {
+ error("missing comma or semicolon after declaration of `%s`, found `%s` instead", s.toChars(), token.toChars());
+ goto Lend;
+ }
goto default;
case TOK.semicolon:
break;
default:
- error("`=`, `;` or `,` expected");
+ error("`=`, `;` or `,` expected to end declaration instead of `%s`", token.toChars());
+ Lend:
while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
nextToken();
nextToken();
mangle_function(d.isFuncDeclaration());
buf.writestring("EE");
}
- else if (e && e.op == TOK.variable && (cast(VarExp)e).var.isVarDeclaration())
+ else if (e && e.op == EXP.variable && (cast(VarExp)e).var.isVarDeclaration())
{
VarDeclaration vd = (cast(VarExp)e).var.isVarDeclaration();
buf.writeByte('L');
extern (D) this(const ref Loc loc, StructLiteralExp lit, Type type)
{
- super(loc, TOK.classReference, __traits(classInstanceSize, ClassReferenceExp));
+ super(loc, EXP.classReference, __traits(classInstanceSize, ClassReferenceExp));
assert(lit && lit.sd && lit.sd.isClassDeclaration());
this.value = lit;
this.type = type;
extern (D) this(const ref Loc loc, ClassReferenceExp victim)
{
- super(loc, TOK.thrownException, __traits(classInstanceSize, ThrownExceptionExp));
+ super(loc, EXP.thrownException, __traits(classInstanceSize, ThrownExceptionExp));
this.thrown = victim;
this.type = victim.type;
}
*/
extern (C++) final class CTFEExp : Expression
{
- extern (D) this(TOK tok)
+ extern (D) this(EXP tok)
{
super(Loc.initial, tok, __traits(classInstanceSize, CTFEExp));
type = Type.tvoid;
{
switch (op)
{
- case TOK.cantExpression:
+ case EXP.cantExpression:
return "<cant>";
- case TOK.voidExpression:
+ case EXP.voidExpression:
return "cast(void)0";
- case TOK.showCtfeContext:
+ case EXP.showCtfeContext:
return "<error>";
- case TOK.break_:
+ case EXP.break_:
return "<break>";
- case TOK.continue_:
+ case EXP.continue_:
return "<continue>";
- case TOK.goto_:
+ case EXP.goto_:
return "<goto>";
default:
assert(0);
extern (D) static bool isCantExp(const Expression e)
{
- return e && e.op == TOK.cantExpression;
+ return e && e.op == EXP.cantExpression;
}
extern (D) static bool isGotoExp(const Expression e)
{
- return e && e.op == TOK.goto_;
+ return e && e.op == EXP.goto_;
}
}
// True if 'e' is CTFEExp::cantexp, or an exception
bool exceptionOrCantInterpret(const Expression e)
{
- return e && (e.op == TOK.cantExpression || e.op == TOK.thrownException || e.op == TOK.showCtfeContext);
+ return e && (e.op == EXP.cantExpression || e.op == EXP.thrownException || e.op == EXP.showCtfeContext);
}
/************** Aggregate literals (AA/string/array/struct) ******************/
{
switch (e.op)
{
- case TOK.arrayLiteral:
+ case EXP.arrayLiteral:
return (cast(ArrayLiteralExp)e).ownedByCtfe == OwnedBy.code;
- case TOK.assocArrayLiteral:
+ case EXP.assocArrayLiteral:
return (cast(AssocArrayLiteralExp)e).ownedByCtfe == OwnedBy.code;
- case TOK.structLiteral:
+ case EXP.structLiteral:
return (cast(StructLiteralExp)e).ownedByCtfe == OwnedBy.code;
- case TOK.string_:
- case TOK.this_:
- case TOK.variable:
+ case EXP.string_:
+ case EXP.this_:
+ case EXP.variable:
return false;
- case TOK.assign:
+ case EXP.assign:
return false;
- case TOK.index:
- case TOK.dotVariable:
- case TOK.slice:
- case TOK.cast_:
+ case EXP.index:
+ case EXP.dotVariable:
+ case EXP.slice:
+ case EXP.cast_:
e = (cast(UnaExp)e).e1;
continue;
- case TOK.concatenate:
+ case EXP.concatenate:
return needToCopyLiteral((cast(BinExp)e).e1) || needToCopyLiteral((cast(BinExp)e).e2);
- case TOK.concatenateAssign:
- case TOK.concatenateElemAssign:
- case TOK.concatenateDcharAssign:
+ case EXP.concatenateAssign:
+ case EXP.concatenateElemAssign:
+ case EXP.concatenateDcharAssign:
e = (cast(BinExp)e).e2;
continue;
default:
r.origin = sle.origin;
return ue;
}
- if (e.op == TOK.function_ || e.op == TOK.delegate_ || e.op == TOK.symbolOffset || e.op == TOK.null_ || e.op == TOK.variable || e.op == TOK.dotVariable || e.op == TOK.int64 || e.op == TOK.float64 || e.op == TOK.char_ || e.op == TOK.complex80 || e.op == TOK.void_ || e.op == TOK.vector || e.op == TOK.typeid_)
+ if (e.op == EXP.function_ || e.op == EXP.delegate_ || e.op == EXP.symbolOffset || e.op == EXP.null_ || e.op == EXP.variable || e.op == EXP.dotVariable || e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.char_ || e.op == EXP.complex80 || e.op == EXP.void_ || e.op == EXP.vector || e.op == EXP.typeid_)
{
// Simple value types
// Keep e1 for DelegateExp and DotVarExp
if (se.type.toBasetype().ty == Tsarray)
{
// same with resolveSlice()
- if (se.e1.op == TOK.null_)
+ if (se.e1.op == EXP.null_)
{
emplaceExp!(NullExp)(&ue, se.loc, se.type);
return ue;
emplaceExp!(ClassReferenceExp)(&ue, e.loc, cre.value, e.type);
return ue;
}
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
{
emplaceExp!(UnionExp)(&ue, e);
return ue;
{
emplaceExp!(IndexExp)(&ue, lit.loc, ie.e1, ie.e2);
}
- else if (lit.op == TOK.arrayLiteral)
+ else if (lit.op == EXP.arrayLiteral)
{
emplaceExp!(SliceExp)(&ue, lit.loc, lit, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy());
}
- else if (lit.op == TOK.string_)
+ else if (lit.op == EXP.string_)
{
// For strings, we need to introduce another level of indirection
emplaceExp!(SliceExp)(&ue, lit.loc, lit, ctfeEmplaceExp!IntegerExp(Loc.initial, 0, Type.tsize_t), ArrayLength(Type.tsize_t, lit).copy());
{
// Can't type paint from struct to struct*; this needs another
// level of indirection
- if (lit.op == TOK.structLiteral && isPointer(type))
+ if (lit.op == EXP.structLiteral && isPointer(type))
lit.error("CTFE internal error: painting `%s`", type.toChars());
ue = copyLiteral(lit);
}
SliceExp se = e.isSliceExp();
if (!se)
return e;
- if (se.e1.op == TOK.null_)
+ if (se.e1.op == EXP.null_)
return se.e1;
if (pue)
{
{
switch (e.op)
{
- case TOK.vector:
+ case EXP.vector:
return e.isVectorExp().dim;
- case TOK.null_:
+ case EXP.null_:
return 0;
- case TOK.slice:
+ case EXP.slice:
{
auto se = cast(SliceExp)e;
const ilo = se.lwr.toInteger();
return iup - ilo;
}
- case TOK.string_:
+ case EXP.string_:
return e.isStringExp().len;
- case TOK.arrayLiteral:
+ case EXP.arrayLiteral:
{
const ale = e.isArrayLiteralExp();
return ale.elements ? ale.elements.dim : 0;
}
- case TOK.assocArrayLiteral:
+ case EXP.assocArrayLiteral:
{
return e.isAssocArrayLiteralExp().keys.dim;
}
// For CTFE only. Returns true if 'e' is true or a non-null pointer.
bool isTrueBool(Expression e)
{
- return e.isBool(true) || ((e.type.ty == Tpointer || e.type.ty == Tclass) && e.op != TOK.null_);
+ return e.toBool().hasValue(true) || ((e.type.ty == Tpointer || e.type.ty == Tclass) && e.op != EXP.null_);
}
/* Is it safe to convert from srcPointee* to destPointee* ?
const ex = dve.e1;
const v = dve.var.isVarDeclaration();
assert(v);
- StructLiteralExp se = (ex.op == TOK.classReference)
+ StructLiteralExp se = (ex.op == EXP.classReference)
? (cast(ClassReferenceExp)ex).value
: cast(StructLiteralExp)ex;
// We can't use getField, because it makes a copy
- const i = (ex.op == TOK.classReference)
+ const i = (ex.op == EXP.classReference)
? (cast(ClassReferenceExp)ex).getFieldIndex(e.type, v.offset)
: se.getFieldIndex(e.type, v.offset);
e = (*se.elements)[i];
if (auto ie = e.isIndexExp())
{
// Note that each AA element is part of its own memory block
- if ((ie.e1.type.ty == Tarray || ie.e1.type.ty == Tsarray || ie.e1.op == TOK.string_ || ie.e1.op == TOK.arrayLiteral) && ie.e2.op == TOK.int64)
+ if ((ie.e1.type.ty == Tarray || ie.e1.type.ty == Tsarray || ie.e1.op == EXP.string_ || ie.e1.op == EXP.arrayLiteral) && ie.e2.op == EXP.int64)
{
*ofs = ie.e2.toInteger();
return ie.e1;
if (auto se = e.isSliceExp())
{
if (se && e.type.toBasetype().ty == Tsarray &&
- (se.e1.type.ty == Tarray || se.e1.type.ty == Tsarray || se.e1.op == TOK.string_ || se.e1.op == TOK.arrayLiteral) && se.lwr.op == TOK.int64)
+ (se.e1.type.ty == Tarray || se.e1.type.ty == Tsarray || se.e1.op == EXP.string_ || se.e1.op == EXP.arrayLiteral) && se.lwr.op == EXP.int64)
{
*ofs = se.lwr.toInteger();
return se.e1;
return true;
// For integers cast to pointers, we regard them as non-comparable
// unless they are identical. (This may be overly strict).
- if (agg1.op == TOK.int64 && agg2.op == TOK.int64 && agg1.toInteger() == agg2.toInteger())
+ if (agg1.op == EXP.int64 && agg2.op == EXP.int64 && agg1.toInteger() == agg2.toInteger())
{
return true;
}
// Note that type painting can occur with VarExp, so we
// must compare the variables being pointed to.
- if (agg1.op == TOK.variable && agg2.op == TOK.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)
+ if (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var)
{
return true;
}
- if (agg1.op == TOK.symbolOffset && agg2.op == TOK.symbolOffset && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var)
+ if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset && (cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var)
{
return true;
}
const sz = pointee.size();
emplaceExp!(IntegerExp)(&ue, loc, (ofs1 - ofs2) * sz, type);
}
- else if (agg1.op == TOK.string_ && agg2.op == TOK.string_ &&
+ else if (agg1.op == EXP.string_ && agg2.op == EXP.string_ &&
(cast(StringExp)agg1).peekString().ptr == (cast(StringExp)agg2).peekString().ptr)
{
Type pointee = (cast(TypePointer)agg1.type).next;
const sz = pointee.size();
emplaceExp!(IntegerExp)(&ue, loc, (ofs1 - ofs2) * sz, type);
}
- else if (agg1.op == TOK.symbolOffset && agg2.op == TOK.symbolOffset &&
+ else if (agg1.op == EXP.symbolOffset && agg2.op == EXP.symbolOffset &&
(cast(SymOffExp)agg1).var == (cast(SymOffExp)agg2).var)
{
emplaceExp!(IntegerExp)(&ue, loc, ofs1 - ofs2, type);
else
{
error(loc, "`%s - %s` cannot be interpreted at compile time: cannot subtract pointers to two different memory blocks", e1.toChars(), e2.toChars());
- emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
+ emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
}
return ue;
}
// Return eptr op e2, where eptr is a pointer, e2 is an integer,
-// and op is TOK.add or TOK.min
-UnionExp pointerArithmetic(const ref Loc loc, TOK op, Type type, Expression eptr, Expression e2)
+// and op is EXP.add or EXP.min
+UnionExp pointerArithmetic(const ref Loc loc, EXP op, Type type, Expression eptr, Expression e2)
{
UnionExp ue;
if (eptr.type.nextOf().ty == Tvoid)
{
error(loc, "cannot perform arithmetic on `void*` pointers at compile time");
Lcant:
- emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
+ emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
return ue;
}
- if (eptr.op == TOK.address)
+ if (eptr.op == EXP.address)
eptr = (cast(AddrExp)eptr).e1;
dinteger_t ofs1;
Expression agg1 = getAggregateFromPointer(eptr, &ofs1);
- if (agg1.op == TOK.symbolOffset)
+ if (agg1.op == EXP.symbolOffset)
{
if ((cast(SymOffExp)agg1).var.type.ty != Tsarray)
{
goto Lcant;
}
}
- else if (agg1.op != TOK.string_ && agg1.op != TOK.arrayLiteral)
+ else if (agg1.op != EXP.string_ && agg1.op != EXP.arrayLiteral)
{
error(loc, "cannot perform pointer arithmetic on non-arrays at compile time");
goto Lcant;
dinteger_t sz = pointee.size();
sinteger_t indx;
dinteger_t len;
- if (agg1.op == TOK.symbolOffset)
+ if (agg1.op == EXP.symbolOffset)
{
indx = ofs1 / sz;
len = (cast(TypeSArray)(cast(SymOffExp)agg1).var.type).dim.toInteger();
indx = ofs1;
len = dollar.toInteger();
}
- if (op == TOK.add || op == TOK.addAssign || op == TOK.plusPlus)
+ if (op == EXP.add || op == EXP.addAssign || op == EXP.plusPlus)
indx += ofs2 / sz;
- else if (op == TOK.min || op == TOK.minAssign || op == TOK.minusMinus)
+ else if (op == EXP.min || op == EXP.minAssign || op == EXP.minusMinus)
indx -= ofs2 / sz;
else
{
error(loc, "cannot assign pointer to index %lld inside memory block `[0..%lld]`", indx, len);
goto Lcant;
}
- if (agg1.op == TOK.symbolOffset)
+ if (agg1.op == EXP.symbolOffset)
{
emplaceExp!(SymOffExp)(&ue, loc, (cast(SymOffExp)agg1).var, indx * sz);
SymOffExp se = cast(SymOffExp)ue.exp();
se.type = type;
return ue;
}
- if (agg1.op != TOK.arrayLiteral && agg1.op != TOK.string_)
+ if (agg1.op != EXP.arrayLiteral && agg1.op != EXP.string_)
{
error(loc, "CTFE internal error: pointer arithmetic `%s`", agg1.toChars());
goto Lcant;
// Return 1 if true, 0 if false
// -1 if comparison is illegal because they point to non-comparable memory blocks
-int comparePointers(TOK op, Expression agg1, dinteger_t ofs1, Expression agg2, dinteger_t ofs2)
+int comparePointers(EXP op, Expression agg1, dinteger_t ofs1, Expression agg2, dinteger_t ofs2)
{
if (pointToSameMemoryBlock(agg1, agg2))
{
int n;
switch (op)
{
- case TOK.lessThan:
+ case EXP.lessThan:
n = (ofs1 < ofs2);
break;
- case TOK.lessOrEqual:
+ case EXP.lessOrEqual:
n = (ofs1 <= ofs2);
break;
- case TOK.greaterThan:
+ case EXP.greaterThan:
n = (ofs1 > ofs2);
break;
- case TOK.greaterOrEqual:
+ case EXP.greaterOrEqual:
n = (ofs1 >= ofs2);
break;
- case TOK.identity:
- case TOK.equal:
+ case EXP.identity:
+ case EXP.equal:
n = (ofs1 == ofs2);
break;
- case TOK.notIdentity:
- case TOK.notEqual:
+ case EXP.notIdentity:
+ case EXP.notEqual:
n = (ofs1 != ofs2);
break;
default:
}
return n;
}
- const null1 = (agg1.op == TOK.null_);
- const null2 = (agg2.op == TOK.null_);
+ const null1 = (agg1.op == EXP.null_);
+ const null2 = (agg2.op == EXP.null_);
int cmp;
if (null1 || null2)
{
switch (op)
{
- case TOK.lessThan:
+ case EXP.lessThan:
cmp = null1 && !null2;
break;
- case TOK.greaterThan:
+ case EXP.greaterThan:
cmp = !null1 && null2;
break;
- case TOK.lessOrEqual:
+ case EXP.lessOrEqual:
cmp = null1;
break;
- case TOK.greaterOrEqual:
+ case EXP.greaterOrEqual:
cmp = null2;
break;
- case TOK.identity:
- case TOK.equal:
- case TOK.notIdentity: // 'cmp' gets inverted below
- case TOK.notEqual:
+ case EXP.identity:
+ case EXP.equal:
+ case EXP.notIdentity: // 'cmp' gets inverted below
+ case EXP.notEqual:
cmp = (null1 == null2);
break;
default:
{
switch (op)
{
- case TOK.identity:
- case TOK.equal:
- case TOK.notIdentity: // 'cmp' gets inverted below
- case TOK.notEqual:
+ case EXP.identity:
+ case EXP.equal:
+ case EXP.notIdentity: // 'cmp' gets inverted below
+ case EXP.notEqual:
cmp = 0;
break;
default:
return -1; // memory blocks are different
}
}
- if (op == TOK.notIdentity || op == TOK.notEqual)
+ if (op == EXP.notIdentity || op == EXP.notEqual)
cmp ^= 1;
return cmp;
}
/// with >,is, ==, etc, using ctfeCmp, ctfeEqual, ctfeIdentity
bool isCtfeComparable(Expression e)
{
- if (e.op == TOK.slice)
+ if (e.op == EXP.slice)
e = (cast(SliceExp)e).e1;
if (e.isConst() != 1)
{
- if (e.op == TOK.null_ || e.op == TOK.string_ || e.op == TOK.function_ || e.op == TOK.delegate_ || e.op == TOK.arrayLiteral || e.op == TOK.structLiteral || e.op == TOK.assocArrayLiteral || e.op == TOK.classReference)
+ 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)
{
return true;
}
// https://issues.dlang.org/show_bug.cgi?id=14123
// TypeInfo object is comparable in CTFE
- if (e.op == TOK.typeid_)
+ if (e.op == EXP.typeid_)
return true;
return false;
}
return true;
}
-/// Map TOK comparison ops
-private bool numCmp(N)(TOK op, N n1, N n2)
+/// Map EXP comparison ops
+private bool numCmp(N)(EXP op, N n1, N n2)
{
switch (op)
{
- case TOK.lessThan:
+ case EXP.lessThan:
return n1 < n2;
- case TOK.lessOrEqual:
+ case EXP.lessOrEqual:
return n1 <= n2;
- case TOK.greaterThan:
+ case EXP.greaterThan:
return n1 > n2;
- case TOK.greaterOrEqual:
+ case EXP.greaterOrEqual:
return n1 >= n2;
default:
}
/// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool specificCmp(TOK op, int rawCmp)
+bool specificCmp(EXP op, int rawCmp)
{
return numCmp!int(op, rawCmp, 0);
}
/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool intUnsignedCmp(TOK op, dinteger_t n1, dinteger_t n2)
+bool intUnsignedCmp(EXP op, dinteger_t n1, dinteger_t n2)
{
return numCmp!dinteger_t(op, n1, n2);
}
/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool intSignedCmp(TOK op, sinteger_t n1, sinteger_t n2)
+bool intSignedCmp(EXP op, sinteger_t n1, sinteger_t n2)
{
return numCmp!sinteger_t(op, n1, n2);
}
/// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool realCmp(TOK op, real_t r1, real_t r2)
+bool realCmp(EXP op, real_t r1, real_t r2)
{
// Don't rely on compiler, handle NAN arguments separately
if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
{
switch (op)
{
- case TOK.lessThan:
- case TOK.lessOrEqual:
- case TOK.greaterThan:
- case TOK.greaterOrEqual:
+ case EXP.lessThan:
+ case EXP.lessOrEqual:
+ case EXP.greaterThan:
+ case EXP.greaterOrEqual:
return false;
default:
auto se2 = x2.isStringExp();
auto ae2 = x2.isArrayLiteralExp();
- // Now both must be either TOK.arrayLiteral or TOK.string_
+ // Now both must be either EXP.arrayLiteral or EXP.string_
if (se1 && se2)
return sliceCmpStringWithString(se1, se2, cast(size_t)lo1, cast(size_t)lo2, cast(size_t)len);
if (se1 && ae2)
return de.func;
if (auto fe = e.isFuncExp())
return fe.fd;
- assert(e.op == TOK.null_);
+ assert(e.op == EXP.null_);
return null;
}
private bool isArray(const Expression e)
{
- return e.op == TOK.arrayLiteral || e.op == TOK.string_ || e.op == TOK.slice || e.op == TOK.null_;
+ return e.op == EXP.arrayLiteral || e.op == EXP.string_ || e.op == EXP.slice || e.op == EXP.null_;
}
/*****
*/
private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool identity = false)
{
- if (e1.op == TOK.classReference || e2.op == TOK.classReference)
+ if (e1.op == EXP.classReference || e2.op == EXP.classReference)
{
- if (e1.op == TOK.classReference && e2.op == TOK.classReference &&
+ if (e1.op == EXP.classReference && e2.op == EXP.classReference &&
(cast(ClassReferenceExp)e1).value == (cast(ClassReferenceExp)e2).value)
return 0;
return 1;
}
- if (e1.op == TOK.typeid_ && e2.op == TOK.typeid_)
+ if (e1.op == EXP.typeid_ && e2.op == EXP.typeid_)
{
// printf("e1: %s\n", e1.toChars());
// printf("e2: %s\n", e2.toChars());
return t1 != t2;
}
// null == null, regardless of type
- if (e1.op == TOK.null_ && e2.op == TOK.null_)
+ if (e1.op == EXP.null_ && e2.op == EXP.null_)
return 0;
if (e1.type.ty == Tpointer && e2.type.ty == Tpointer)
{
dinteger_t ofs1, ofs2;
Expression agg1 = getAggregateFromPointer(e1, &ofs1);
Expression agg2 = getAggregateFromPointer(e2, &ofs2);
- if ((agg1 == agg2) || (agg1.op == TOK.variable && agg2.op == TOK.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var))
+ if ((agg1 == agg2) || (agg1.op == EXP.variable && agg2.op == EXP.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var))
{
if (ofs1 == ofs2)
return 0;
return 1;
// If both are delegate literals, assume they have the
// same closure pointer. TODO: We don't support closures yet!
- if (e1.op == TOK.function_ && e2.op == TOK.function_)
+ if (e1.op == EXP.function_ && e2.op == EXP.function_)
return 0;
- assert(e1.op == TOK.delegate_ && e2.op == TOK.delegate_);
+ 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;
dinteger_t ofs1, ofs2;
Expression agg1 = getAggregateFromPointer(ptr1, &ofs1);
Expression agg2 = getAggregateFromPointer(ptr2, &ofs2);
- // If they are TOK.variable, it means they are FuncDeclarations
- if ((agg1 == agg2 && ofs1 == ofs2) || (agg1.op == TOK.variable && agg2.op == TOK.variable && (cast(VarExp)agg1).var == (cast(VarExp)agg2).var))
+ // 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))
{
return 0;
}
}
return c1 != c2;
}
- if (e1.op == TOK.structLiteral && e2.op == TOK.structLiteral)
+ if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
{
StructLiteralExp es1 = cast(StructLiteralExp)e1;
StructLiteralExp es2 = cast(StructLiteralExp)e2;
Expression ee2 = (*es2.elements)[i];
// https://issues.dlang.org/show_bug.cgi?id=16284
- if (ee1.op == TOK.void_ && ee2.op == TOK.void_) // if both are VoidInitExp
+ if (ee1.op == EXP.void_ && ee2.op == EXP.void_) // if both are VoidInitExp
continue;
if (ee1 == ee2)
return 0; // All elements are equal
}
}
- if (e1.op == TOK.assocArrayLiteral && e2.op == TOK.assocArrayLiteral)
+ if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.assocArrayLiteral)
{
AssocArrayLiteralExp es1 = cast(AssocArrayLiteralExp)e1;
AssocArrayLiteralExp es2 = cast(AssocArrayLiteralExp)e2;
}
/// Evaluate ==, !=. Resolves slices before comparing. Returns 0 or 1
-bool ctfeEqual(const ref Loc loc, TOK op, Expression e1, Expression e2)
+bool ctfeEqual(const ref Loc loc, EXP op, Expression e1, Expression e2)
{
- return !ctfeRawCmp(loc, e1, e2) ^ (op == TOK.notEqual);
+ return !ctfeRawCmp(loc, e1, e2) ^ (op == EXP.notEqual);
}
/// Evaluate is, !is. Resolves slices before comparing. Returns 0 or 1
-bool ctfeIdentity(const ref Loc loc, TOK op, Expression e1, Expression e2)
+bool ctfeIdentity(const ref Loc loc, EXP op, Expression e1, Expression e2)
{
//printf("ctfeIdentity %s %s\n", e1.toChars(), e2.toChars());
- //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", Token::toChars(op),
- // Token::toChars(e1.op), e1.toChars(), Token::toChars(e2.op), e1.toChars());
+ //printf("ctfeIdentity op = '%s', e1 = %s %s, e2 = %s %s\n", EXPtoString(op).ptr,
+ // EXPtoString(e1.op).ptr, e1.toChars(), EXPtoString(e2.op).ptr, e1.toChars());
bool cmp;
- if (e1.op == TOK.null_)
+ if (e1.op == EXP.null_)
{
- cmp = (e2.op == TOK.null_);
+ cmp = (e2.op == EXP.null_);
}
- else if (e2.op == TOK.null_)
+ else if (e2.op == EXP.null_)
{
cmp = false;
}
- else if (e1.op == TOK.symbolOffset && e2.op == TOK.symbolOffset)
+ else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
{
SymOffExp es1 = cast(SymOffExp)e1;
SymOffExp es2 = cast(SymOffExp)e2;
{
cmp = !ctfeRawCmp(loc, e1, e2, true);
}
- if (op == TOK.notIdentity || op == TOK.notEqual)
+ if (op == EXP.notIdentity || op == EXP.notEqual)
cmp ^= true;
return cmp;
}
/// Evaluate >,<=, etc. Resolves slices before comparing. Returns 0 or 1
-bool ctfeCmp(const ref Loc loc, TOK op, Expression e1, Expression e2)
+bool ctfeCmp(const ref Loc loc, EXP op, Expression e1, Expression e2)
{
Type t1 = e1.type.toBasetype();
Type t2 = e2.type.toBasetype();
Type t1 = e1.type.toBasetype();
Type t2 = e2.type.toBasetype();
UnionExp ue;
- if (e2.op == TOK.string_ && e1.op == TOK.arrayLiteral && t1.nextOf().isintegral())
+ if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
{
// [chars] ~ string => string (only valid for CTFE)
StringExp es1 = cast(StringExp)e2;
foreach (size_t i; 0 .. es2.elements.dim)
{
Expression es2e = (*es2.elements)[i];
- if (es2e.op != TOK.int64)
+ if (es2e.op != EXP.int64)
{
- emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
+ emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
return ue;
}
dinteger_t v = es2e.toInteger();
es.type = type;
return ue;
}
- if (e1.op == TOK.string_ && e2.op == TOK.arrayLiteral && t2.nextOf().isintegral())
+ if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral())
{
// string ~ [chars] => string (only valid for CTFE)
// Concatenate the strings
foreach (size_t i; 0 .. es2.elements.dim)
{
Expression es2e = (*es2.elements)[i];
- if (es2e.op != TOK.int64)
+ if (es2e.op != EXP.int64)
{
- emplaceExp!(CTFEExp)(&ue, TOK.cantExpression);
+ emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
return ue;
}
const v = es2e.toInteger();
es.type = type;
return ue;
}
- if (e1.op == TOK.arrayLiteral && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
+ if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
{
// [ e1 ] ~ [ e2 ] ---> [ e1, e2 ]
ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
es1.elements.insert(es1.elements.dim, copyLiteralArray(es2.elements));
return ue;
}
- if (e1.op == TOK.arrayLiteral && e2.op == TOK.null_ && t1.nextOf().equals(t2.nextOf()))
+ if (e1.op == EXP.arrayLiteral && e2.op == EXP.null_ && t1.nextOf().equals(t2.nextOf()))
{
// [ e1 ] ~ null ----> [ e1 ].dup
ue = paintTypeOntoLiteralCopy(type, copyLiteral(e1).copy());
return ue;
}
- if (e1.op == TOK.null_ && e2.op == TOK.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
+ if (e1.op == EXP.null_ && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
{
// null ~ [ e2 ] ----> [ e2 ].dup
ue = paintTypeOntoLiteralCopy(type, copyLiteral(e2).copy());
{
--i;
Expression ekey = (*ae.keys)[i];
- const int eq = ctfeEqual(loc, TOK.equal, ekey, e2);
+ const int eq = ctfeEqual(loc, EXP.equal, ekey, e2);
if (eq)
{
return (*ae.values)[i];
return paintTypeOntoLiteral(pue, to, e);
}
- if (e.op == TOK.null_)
+ if (e.op == EXP.null_)
return paint();
- if (e.op == TOK.classReference)
+ if (e.op == EXP.classReference)
{
// Disallow reinterpreting class casts. Do this by ensuring that
// the original class can implicitly convert to the target class
return paint();
// Allow casting away const for struct literals
- if (e.op == TOK.structLiteral && e.type.toBasetype().castMod(0) == to.toBasetype().castMod(0))
+ if (e.op == EXP.structLiteral && e.type.toBasetype().castMod(0) == to.toBasetype().castMod(0))
return paint();
Expression r;
*/
void assignInPlace(Expression dest, Expression src)
{
- if (!(dest.op == TOK.structLiteral || dest.op == TOK.arrayLiteral || dest.op == TOK.string_))
+ if (!(dest.op == EXP.structLiteral || dest.op == EXP.arrayLiteral || dest.op == EXP.string_))
{
printf("invalid op %d %d\n", src.op, dest.op);
assert(0);
}
Expressions* oldelems;
Expressions* newelems;
- if (dest.op == TOK.structLiteral)
+ if (dest.op == EXP.structLiteral)
{
assert(dest.op == src.op);
oldelems = (cast(StructLiteralExp)dest).elements;
foreach (_; 0 .. newelems.dim - oldelems.dim)
oldelems.push(null);
}
- else if (dest.op == TOK.arrayLiteral && src.op == TOK.arrayLiteral)
+ else if (dest.op == EXP.arrayLiteral && src.op == EXP.arrayLiteral)
{
oldelems = (cast(ArrayLiteralExp)dest).elements;
newelems = (cast(ArrayLiteralExp)src).elements;
}
- else if (dest.op == TOK.string_ && src.op == TOK.string_)
+ else if (dest.op == EXP.string_ && src.op == EXP.string_)
{
sliceAssignStringFromString(cast(StringExp)dest, cast(StringExp)src, 0);
return;
}
- else if (dest.op == TOK.arrayLiteral && src.op == TOK.string_)
+ else if (dest.op == EXP.arrayLiteral && src.op == EXP.string_)
{
sliceAssignArrayLiteralFromString(cast(ArrayLiteralExp)dest, cast(StringExp)src, 0);
return;
}
- else if (src.op == TOK.arrayLiteral && dest.op == TOK.string_)
+ else if (src.op == EXP.arrayLiteral && dest.op == EXP.string_)
{
sliceAssignStringFromArrayLiteral(cast(StringExp)dest, cast(ArrayLiteralExp)src, 0);
return;
{
Expression e = (*newelems)[i];
Expression o = (*oldelems)[i];
- if (e.op == TOK.structLiteral)
+ if (e.op == EXP.structLiteral)
{
assert(o.op == e.op);
assignInPlace(o, e);
}
- else if (e.type.ty == Tsarray && e.op != TOK.void_ && o.type.ty == Tsarray)
+ else if (e.type.ty == Tsarray && e.op != EXP.void_ && o.type.ty == Tsarray)
{
assignInPlace(o, e);
}
{
j--;
Expression ekey = (*aae.keys)[j];
- int eq = ctfeEqual(loc, TOK.equal, ekey, index);
+ int eq = ctfeEqual(loc, EXP.equal, ekey, index);
if (eq)
{
(*valuesx)[j] = newval;
auto elements = new Expressions(newlen);
// Resolve slices
size_t indxlo = 0;
- if (oldval.op == TOK.slice)
+ if (oldval.op == EXP.slice)
{
indxlo = cast(size_t)(cast(SliceExp)oldval).lwr.toInteger();
oldval = (cast(SliceExp)oldval).e1;
}
size_t copylen = oldlen < newlen ? oldlen : newlen;
- if (oldval.op == TOK.string_)
+ if (oldval.op == EXP.string_)
{
StringExp oldse = cast(StringExp)oldval;
void* s = mem.xcalloc(newlen + 1, oldse.sz);
{
if (oldlen != 0)
{
- assert(oldval.op == TOK.arrayLiteral);
+ assert(oldval.op == EXP.arrayLiteral);
ArrayLiteralExp ae = cast(ArrayLiteralExp)oldval;
foreach (size_t i; 0 .. copylen)
(*elements)[i] = (*ae.elements)[indxlo + i];
Type tb = newval.type.toBasetype();
switch (newval.op)
{
- case TOK.int64:
- case TOK.float64:
- case TOK.char_:
- case TOK.complex80:
+ case EXP.int64:
+ case EXP.float64:
+ case EXP.char_:
+ case EXP.complex80:
return tb.isscalar();
- case TOK.null_:
+ case EXP.null_:
return tb.ty == Tnull ||
tb.ty == Tpointer ||
tb.ty == Tarray ||
tb.ty == Tclass ||
tb.ty == Tdelegate;
- case TOK.string_:
+ case EXP.string_:
return true; // CTFE would directly use the StringExp in AST.
- case TOK.arrayLiteral:
+ case EXP.arrayLiteral:
return true; //((ArrayLiteralExp *)newval)->ownedByCtfe;
- case TOK.assocArrayLiteral:
+ case EXP.assocArrayLiteral:
return true; //((AssocArrayLiteralExp *)newval)->ownedByCtfe;
- case TOK.structLiteral:
+ case EXP.structLiteral:
return true; //((StructLiteralExp *)newval)->ownedByCtfe;
- case TOK.classReference:
+ case EXP.classReference:
return true;
- case TOK.type:
+ case EXP.type:
return true;
- case TOK.vector:
+ case EXP.vector:
return true; // vector literal
- case TOK.function_:
+ case EXP.function_:
return true; // function literal or delegate literal
- case TOK.delegate_:
+ case EXP.delegate_:
{
// &struct.func or &clasinst.func
// &nestedfunc
Expression ethis = (cast(DelegateExp)newval).e1;
- return (ethis.op == TOK.structLiteral || ethis.op == TOK.classReference || ethis.op == TOK.variable && (cast(VarExp)ethis).var == (cast(DelegateExp)newval).func);
+ return (ethis.op == EXP.structLiteral || ethis.op == EXP.classReference || ethis.op == EXP.variable && (cast(VarExp)ethis).var == (cast(DelegateExp)newval).func);
}
- case TOK.symbolOffset:
+ case EXP.symbolOffset:
{
// function pointer, or pointer to static variable
Declaration d = (cast(SymOffExp)newval).var;
return d.isFuncDeclaration() || d.isDataseg();
}
- case TOK.typeid_:
+ case EXP.typeid_:
{
// always valid
return true;
}
- case TOK.address:
+ case EXP.address:
{
// e1 should be a CTFE reference
Expression e1 = (cast(AddrExp)newval).e1;
return tb.ty == Tpointer &&
(
- (e1.op == TOK.structLiteral || e1.op == TOK.arrayLiteral) && isCtfeValueValid(e1) ||
- e1.op == TOK.variable ||
- e1.op == TOK.dotVariable && isCtfeReferenceValid(e1) ||
- e1.op == TOK.index && isCtfeReferenceValid(e1) ||
- e1.op == TOK.slice && e1.type.toBasetype().ty == Tsarray
+ (e1.op == EXP.structLiteral || e1.op == EXP.arrayLiteral) && isCtfeValueValid(e1) ||
+ e1.op == EXP.variable ||
+ e1.op == EXP.dotVariable && isCtfeReferenceValid(e1) ||
+ e1.op == EXP.index && isCtfeReferenceValid(e1) ||
+ e1.op == EXP.slice && e1.type.toBasetype().ty == Tsarray
);
}
- case TOK.slice:
+ case EXP.slice:
{
// e1 should be an array aggregate
const SliceExp se = cast(SliceExp)newval;
- assert(se.lwr && se.lwr.op == TOK.int64);
- assert(se.upr && se.upr.op == TOK.int64);
- return (tb.ty == Tarray || tb.ty == Tsarray) && (se.e1.op == TOK.string_ || se.e1.op == TOK.arrayLiteral);
+ 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 TOK.void_:
+ case EXP.void_:
return true; // uninitialized value
default:
{
switch (newval.op)
{
- case TOK.this_:
+ case EXP.this_:
return true;
- case TOK.variable:
+ case EXP.variable:
{
const VarDeclaration v = (cast(VarExp)newval).var.isVarDeclaration();
assert(v);
return true;
}
- case TOK.index:
+ case EXP.index:
{
const Expression eagg = (cast(IndexExp)newval).e1;
- return eagg.op == TOK.string_ || eagg.op == TOK.arrayLiteral || eagg.op == TOK.assocArrayLiteral;
+ return eagg.op == EXP.string_ || eagg.op == EXP.arrayLiteral || eagg.op == EXP.assocArrayLiteral;
}
- case TOK.dotVariable:
+ case EXP.dotVariable:
{
Expression eagg = (cast(DotVarExp)newval).e1;
- return (eagg.op == TOK.structLiteral || eagg.op == TOK.classReference) && isCtfeValueValid(eagg);
+ return (eagg.op == EXP.structLiteral || eagg.op == EXP.classReference) && isCtfeValueValid(eagg);
}
default:
// We need the struct definition to detect block assignment
StructDeclaration sd = null;
ClassDeclaration cd = null;
- if (e.op == TOK.structLiteral)
+ if (e.op == EXP.structLiteral)
{
elements = (cast(StructLiteralExp)e).elements;
sd = (cast(StructLiteralExp)e).sd;
printf("STRUCT type = %s %p:\n", e.type.toChars(), e);
}
- else if (e.op == TOK.classReference)
+ 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);
}
- else if (e.op == TOK.arrayLiteral)
+ else if (e.op == EXP.arrayLiteral)
{
elements = (cast(ArrayLiteralExp)e).elements;
printf("ARRAY LITERAL type=%s %p:\n", e.type.toChars(), e);
}
- else if (e.op == TOK.assocArrayLiteral)
+ else if (e.op == EXP.assocArrayLiteral)
{
printf("AA LITERAL type=%s %p:\n", e.type.toChars(), e);
}
- else if (e.op == TOK.string_)
+ else if (e.op == EXP.string_)
{
printf("STRING %s %p\n", e.toChars(), e.isStringExp.peekString.ptr);
}
- else if (e.op == TOK.slice)
+ else if (e.op == EXP.slice)
{
printf("SLICE %p: %s\n", e, e.toChars());
showCtfeExpr((cast(SliceExp)e).e1, level + 1);
}
- else if (e.op == TOK.variable)
+ else if (e.op == EXP.variable)
{
printf("VAR %p %s\n", e, e.toChars());
VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
if (v && getValue(v))
showCtfeExpr(getValue(v), level + 1);
}
- else if (e.op == TOK.address)
+ 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());
Expression elem = voidInitLiteral(tsa.next, var).copy();
// For aggregate value types (structs, static arrays) we must
// create an a separate copy for each element.
- const mustCopy = (elem.op == TOK.arrayLiteral || elem.op == TOK.structLiteral);
+ const mustCopy = (elem.op == EXP.arrayLiteral || elem.op == EXP.structLiteral);
const d = cast(size_t)tsa.dim.toInteger();
auto elements = new Expressions(d);
foreach (i; 0 .. d)
import dmd.expressionsem;
import dmd.func;
import dmd.globals;
+import dmd.hdrgen;
import dmd.impcnvtab;
import dmd.id;
import dmd.importc;
Type typeb = e.type.toBasetype();
// Look for pointers to functions where the functions are overloaded.
- if (e.e1.op == TOK.overloadSet &&
+ if (e.e1.op == EXP.overloadSet &&
(tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
{
OverExp eo = e.e1.isOverExp();
}
}
- if (e.e1.op == TOK.variable &&
+ if (e.e1.op == EXP.variable &&
typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
tb.ty == Tpointer && tb.nextOf().ty == Tfunction)
{
}
// Enhancement 10724
- if (tb.ty == Tpointer && e.e1.op == TOK.string_)
+ if (tb.ty == Tpointer && e.e1.op == EXP.string_)
e.e1.accept(this);
}
result = e;
return;
}
- if (e.op == TOK.variable)
+ if (e.op == EXP.variable)
{
VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
if (v && v.storage_class & STC.manifest)
}
const fsize = t1b.nextOf().size();
const tsize = tob.nextOf().size();
+ if (fsize == SIZE_INVALID || tsize == SIZE_INVALID)
+ {
+ result = ErrorExp.get();
+ return;
+ }
if (fsize != tsize)
{
const dim = t1b.isTypeSArray().dim.toInteger();
override void visit(StructLiteralExp e)
{
visit(cast(Expression)e);
- if (result.op == TOK.structLiteral)
+ if (result.op == EXP.structLiteral)
(cast(StructLiteralExp)result).stype = t; // commit type
}
}
StringExp se = e;
+
+ void lcast()
+ {
+ result = new CastExp(e.loc, se, t);
+ result.type = t; // so semantic() won't be run on e
+ }
+
if (!e.committed)
{
se = cast(StringExp)e.copy();
se = cast(StringExp)e.copy();
copied = 1;
}
- goto Lcast;
+ return lcast();
}
if (typeb.ty != Tsarray && typeb.ty != Tarray && typeb.ty != Tpointer)
{
se = cast(StringExp)e.copy();
copied = 1;
}
- goto Lcast;
+ return lcast();
}
- if (typeb.nextOf().size() == tb.nextOf().size())
+ const nextSz = typeb.nextOf().size();
+ if (nextSz == SIZE_INVALID)
+ {
+ result = ErrorExp.get();
+ return;
+ }
+ if (nextSz == tb.nextOf().size())
{
if (!copied)
{
}
// Look for pointers to functions where the functions are overloaded.
- if (e.e1.op == TOK.overloadSet &&
+ if (e.e1.op == EXP.overloadSet &&
(tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
{
OverExp eo = cast(OverExp)e.e1;
}
}
- if (e.e1.op == TOK.variable &&
+ if (e.e1.op == EXP.variable &&
typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
tb.ty == Tpointer && tb.nextOf().ty == Tfunction)
{
if (e.e1.implicitConvTo(t1b) > MATCH.nomatch)
{
Expression e1x = e.e1.implicitCastTo(sc, t1b);
- assert(e1x.op != TOK.error);
+ assert(e1x.op != EXP.error);
e = cast(SliceExp)e.copy();
e.e1 = e1x;
e.type = t;
if (t) switch (e.op)
{
- case TOK.arrayLiteral: return visitAle(cast(ArrayLiteralExp) e);
- case TOK.assocArrayLiteral: return visitAar(cast(AssocArrayLiteralExp) e);
- case TOK.function_: return visitFun(cast(FuncExp) e);
- case TOK.question: return visitTer(cast(CondExp) e);
+ case EXP.arrayLiteral: return visitAle(cast(ArrayLiteralExp) e);
+ case EXP.assocArrayLiteral: return visitAar(cast(AssocArrayLiteralExp) e);
+ case EXP.function_: return visitFun(cast(FuncExp) e);
+ case EXP.question: return visitTer(cast(CondExp) e);
default:
}
return e;
if (sc.func && !sc.intypeof)
{
eoff = eoff.optimize(WANTvalue);
- if (eoff.op == TOK.int64 && eoff.toInteger() == 0)
+ if (eoff.op == EXP.int64 && eoff.toInteger() == 0)
{
}
else if (sc.func.setUnsafe())
*/
private bool isVoidArrayLiteral(Expression e, Type other)
{
- while (e.op == TOK.arrayLiteral && e.type.ty == Tarray && ((cast(ArrayLiteralExp)e).elements.dim == 1))
+ while (e.op == EXP.arrayLiteral && e.type.ty == Tarray && ((cast(ArrayLiteralExp)e).elements.dim == 1))
{
auto ale = cast(ArrayLiteralExp)e;
e = ale[0];
if (other.ty != Tsarray && other.ty != Tarray)
return false;
Type t = e.type;
- return (e.op == TOK.arrayLiteral && t.ty == Tarray && t.nextOf().ty == Tvoid && (cast(ArrayLiteralExp)e).elements.dim == 0);
+ return (e.op == EXP.arrayLiteral && t.ty == Tarray && t.nextOf().ty == Tvoid && (cast(ArrayLiteralExp)e).elements.dim == 0);
}
/**
*
* Params:
* sc = Current scope
- * op = Operator such as `e1 op e2`. In practice, either TOK.question
+ * op = Operator such as `e1 op e2`. In practice, either EXP.question
* or one of the binary operator.
* pe1 = The LHS of the operation, will be rewritten
* pe2 = The RHS of the operation, will be rewritten
* Returns:
* The resulting type in case of success, `null` in case of error
*/
-Type typeMerge(Scope* sc, TOK op, ref Expression pe1, ref Expression pe2)
+Type typeMerge(Scope* sc, EXP op, ref Expression pe1, ref Expression pe2)
{
//printf("typeMerge() %s op %s\n", e1.toChars(), e2.toChars());
}
}
- if (op != TOK.question || t1b.ty != t2b.ty && (t1b.isTypeBasic() && t2b.isTypeBasic()))
+ if (op != EXP.question || t1b.ty != t2b.ty && (t1b.isTypeBasic() && t2b.isTypeBasic()))
{
- if (op == TOK.question && t1b.ty.isSomeChar() && t2b.ty.isSomeChar())
+ if (op == EXP.question && t1b.ty.isSomeChar() && t2b.ty.isSomeChar())
{
e1 = e1.castTo(sc, Type.tdchar);
e2 = e2.castTo(sc, Type.tdchar);
return null;
}
- if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == TOK.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == TOK.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && t2.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1)))
+ if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == EXP.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == EXP.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && t2.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1)))
{
/* (T[n] op void*) => T[]
* (T[] op void*) => T[]
return coerce(t1.nextOf().arrayOf());
}
- if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == TOK.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == TOK.arrayLiteral && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && t1.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2)))
+ if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == EXP.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == EXP.arrayLiteral && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && t1.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2)))
{
/* (void* op T[n]) => T[]
* (void* op T[]) => T[]
// Tsarray op [x, y, ...] should to be Tsarray
// https://issues.dlang.org/show_bug.cgi?id=14737
// Tsarray ~ [x, y, ...] should to be Tarray
- if (t1.ty == Tsarray && e2.op == TOK.arrayLiteral && op != TOK.concatenate)
+ if (t1.ty == Tsarray && e2.op == EXP.arrayLiteral && op != EXP.concatenate)
return convert(e2, t1);
- if (m == MATCH.constant && (op == TOK.addAssign || op == TOK.minAssign || op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign || op == TOK.powAssign || op == TOK.andAssign || op == TOK.orAssign || op == TOK.xorAssign))
+ if (m == MATCH.constant && (op == EXP.addAssign || op == EXP.minAssign || op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign || op == EXP.powAssign || op == EXP.andAssign || op == EXP.orAssign || op == EXP.xorAssign))
{
// Don't make the lvalue const
return Lret(t2);
{
// https://issues.dlang.org/show_bug.cgi?id=7285
// https://issues.dlang.org/show_bug.cgi?id=14737
- if (t2.ty == Tsarray && e1.op == TOK.arrayLiteral && op != TOK.concatenate)
+ if (t2.ty == Tsarray && e1.op == EXP.arrayLiteral && op != EXP.concatenate)
return convert(e1, t2);
return convert(e2, t1);
}
Type t1n = t1.nextOf();
Type t2n = t2.nextOf();
ubyte mod;
- if (e1.op == TOK.null_ && e2.op != TOK.null_)
+ if (e1.op == EXP.null_ && e2.op != EXP.null_)
mod = t2n.mod;
- else if (e1.op != TOK.null_ && e2.op == TOK.null_)
+ else if (e1.op != EXP.null_ && e2.op == EXP.null_)
mod = t1n.mod;
else if (!t1n.isImmutable() && !t2n.isImmutable() && t1n.isShared() != t2n.isShared())
return null;
if (t1.mod != t2.mod)
{
ubyte mod;
- if (e1.op == TOK.null_ && e2.op != TOK.null_)
+ if (e1.op == EXP.null_ && e2.op != EXP.null_)
mod = t2.mod;
- else if (e1.op != TOK.null_ && e2.op == TOK.null_)
+ else if (e1.op != EXP.null_ && e2.op == EXP.null_)
mod = t1.mod;
else if (!t1.isImmutable() && !t2.isImmutable() && t1.isShared() != t2.isShared())
return null;
goto Lagain;
}
- if ((e1.op == TOK.string_ || e1.op == TOK.null_) && e1.implicitConvTo(t2))
+ if ((e1.op == EXP.string_ || e1.op == EXP.null_) && e1.implicitConvTo(t2))
return convert(e1, t2);
- if ((e2.op == TOK.string_ || e2.op == TOK.null_) && e2.implicitConvTo(t1))
+ if ((e2.op == EXP.string_ || e2.op == EXP.null_) && e2.implicitConvTo(t1))
return convert(e2, t1);
if (t1.ty == Tsarray && t2.ty == Tsarray && e2.implicitConvTo(t1.nextOf().arrayOf()))
return coerce(t1.nextOf().arrayOf());
if (t1.ty == Tnull && (t2.ty == Tpointer || t2.ty == Taarray || t2.ty == Tarray))
return convert(e1, t2);
+ /// Covers array operations for user-defined types
+ Type checkArrayOpType(Expression e1, Expression e2, EXP op, Scope *sc)
+ {
+ // scalar op scalar - we shouldn't be here
+ if (e1.type.ty != Tarray && e1.type.ty != Tsarray && e2.type.ty != Tarray && e2.type.ty != Tsarray)
+ return null;
+
+ // only supporting slices and array literals
+ if (!e1.isSliceExp() && !e1.isArrayLiteralExp() && !e2.isSliceExp() && !e2.isArrayLiteralExp())
+ return null;
+
+ // start with e1 op e2 and if either one of e1 or e2 is a slice or array literal,
+ // replace it with the first element of the array
+ Expression lhs = e1;
+ Expression rhs = e2;
+
+ // T[x .. y] op ?
+ if (e1.isSliceExp())
+ lhs = new IndexExp(Loc.initial, (cast(UnaExp)e1).e1, IntegerExp.literal!0);
+
+ // [t1, t2, .. t3] op ?
+ if (e1.isArrayLiteralExp())
+ lhs = (cast(ArrayLiteralExp)e1).opIndex(0);
+
+ // ? op U[z .. t]
+ if (e2.isSliceExp())
+ rhs = new IndexExp(Loc.initial, (cast(UnaExp)e2).e1, IntegerExp.literal!0);
+
+ // ? op [u1, u2, .. u3]
+ if (e2.isArrayLiteralExp())
+ rhs = (cast(ArrayLiteralExp)e2).opIndex(0);
+
+ // create a new binary expression with the new lhs and rhs (at this stage, at least
+ // one of lhs/rhs has been replaced with the 0'th element of the array it was before)
+ Expression exp;
+ switch (op)
+ {
+ case EXP.add:
+ exp = new AddExp(Loc.initial, lhs, rhs); break;
+ case EXP.min:
+ exp = new MinExp(Loc.initial, lhs, rhs); break;
+ case EXP.mul:
+ exp = new MulExp(Loc.initial, lhs, rhs); break;
+ case EXP.div:
+ exp = new DivExp(Loc.initial, lhs, rhs); break;
+ case EXP.pow:
+ exp = new PowExp(Loc.initial, lhs, rhs); break;
+ default:
+ exp = null;
+ }
+
+ if (exp)
+ {
+ // if T op U is valid and has type V
+ // then T[] op U and T op U[] should be valid and have type V[]
+ Expression e = exp.trySemantic(sc);
+ if (e && e.type)
+ return e.type.arrayOf;
+ }
+
+ return null;
+ }
+
if (t1.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e1))
{
if (e2.implicitConvTo(t1.nextOf()))
e2 = e2.castTo(sc, t);
return Lret(t);
}
- return null;
}
+
+ t = checkArrayOpType(e1, e2, op, sc);
+ if (t !is null)
+ return Lret(t);
+
return null;
}
else if (t2.ty == Tarray && isBinArrayOp(op) && isArrayOpOperand(e2))
t = e1.type.arrayOf();
}
else
- return null;
+ {
+ t = checkArrayOpType(e1, e2, op, sc);
+ if (t is null)
+ return null;
+ }
- //printf("test %s\n", Token::toChars(op));
+ //printf("test %s\n", EXPtoString(op).ptr);
e1 = e1.optimize(WANTvalue);
if (isCommutative(op) && e1.isConst())
{
/* Swap operands to minimize number of functions generated
*/
- //printf("swap %s\n", Token::toChars(op));
+ //printf("swap %s\n", EXPtoString(op).ptr);
Expression tmp = e1;
e1 = e2;
e2 = tmp;
Expression errorReturn()
{
Expression ex = be.incompatibleTypes();
- if (ex.op == TOK.error)
+ if (ex.op == EXP.error)
return ex;
return ErrorExp.get();
}
Type t1 = be.e1.type.toBasetype();
Type t2 = be.e2.type.toBasetype();
- if (be.op == TOK.min || be.op == TOK.add)
+ if (be.op == EXP.min || be.op == EXP.add)
{
// struct+struct, and class+class are errors
if (t1.ty == Tstruct && t2.ty == Tstruct)
return errorReturn();
// If the types have no value, return an error
- if (be.e1.op == TOK.error)
+ if (be.e1.op == EXP.error)
return be.e1;
- if (be.e2.op == TOK.error)
+ if (be.e2.op == EXP.error)
return be.e2;
return null;
}
case Tchar:
case Twchar:
case Tdchar:
- ue.deprecation("integral promotion not done for `%s`, use '-preview=intpromote' switch or `%scast(int)(%s)`",
- ue.toChars(), Token.toChars(ue.op), ue.e1.toChars());
+ ue.deprecation("integral promotion not done for `%s`, remove '-revert=intpromote' switch or `%scast(int)(%s)`",
+ ue.toChars(), EXPtoString(ue.op).ptr, ue.e1.toChars());
break;
default:
((fd.isCtorDeclaration() && var.isField()) ||
(fd.isStaticCtorDeclaration() && !var.isField())) &&
fd.toParentDecl() == var.toParent2() &&
- (!e1 || e1.op == TOK.this_))
+ (!e1 || e1.op == EXP.this_))
{
bool result = true;
override final d_uns64 size(const ref Loc loc)
{
assert(type);
- return type.size();
+ const sz = type.size();
+ if (sz == SIZE_INVALID)
+ errors = true;
+ return sz;
}
/**
}
}
- if (e1 && e1.op == TOK.this_ && isField())
+ if (e1 && e1.op == EXP.this_ && isField())
{
VarDeclaration vthis = (cast(ThisExp)e1).var;
for (Scope* scx = sc; scx; scx = scx.enclosing)
}
}
- if (v && (isCtorinit() || isField()))
+ if (v && (v.isCtorinit() || isField()))
{
// It's only modifiable if inside the right constructor
if ((storage_class & (STC.foreach_ | STC.ref_)) == (STC.foreach_ | STC.ref_))
return false;
}
- final bool isCtorinit() const pure nothrow @nogc @safe
- {
- return (storage_class & STC.ctorinit) != 0;
- }
-
final bool isFinal() const pure nothrow @nogc @safe
{
return (storage_class & STC.final_) != 0;
if (o.dyncast() == DYNCAST.expression)
{
Expression e = cast(Expression)o;
- if (e.op == TOK.dSymbol)
+ if (e.op == EXP.dSymbol)
{
DsymbolExp ve = cast(DsymbolExp)e;
Declaration d = ve.s.isDeclaration();
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
// Both these mean the var is not rebindable once assigned,
// and the destructor gets run when it goes out of scope
RootObject o = (*v2.objects)[i];
assert(o.dyncast() == DYNCAST.expression);
Expression e = cast(Expression)o;
- assert(e.op == TOK.dSymbol);
+ assert(e.op == EXP.dSymbol);
DsymbolExp se = cast(DsymbolExp)e;
se.s.setFieldOffset(ad, fieldState, isunion);
}
return false;
}
+ final bool isCtorinit() const pure nothrow @nogc @safe
+ {
+ return setInCtorOnly;
+ }
+
/*******************************
* Does symbol go into data segment?
* Includes extern variables.
ExpInitializer ez = _init.isExpInitializer();
assert(ez);
Expression e = ez.exp;
- if (e.op == TOK.construct || e.op == TOK.blit)
+ if (e.op == EXP.construct || e.op == EXP.blit)
e = (cast(AssignExp)e).e2;
return lambdaCheckForNestedRef(e, sc);
}
assert(this.loc != Loc.initial);
assert(v.loc != Loc.initial);
- if (auto ld = this.loc.linnum - v.loc.linnum)
- return ld < 0;
+ if (this.loc.linnum != v.loc.linnum)
+ return this.loc.linnum < v.loc.linnum;
- if (auto cd = this.loc.charnum - v.loc.charnum)
- return cd < 0;
+ if (this.loc.charnum != v.loc.charnum)
+ return this.loc.charnum < v.loc.charnum;
// Default fallback
return this.sequenceNumber < v.sequenceNumber;
*/
extern (C++) final class SymbolDeclaration : Declaration
{
- StructDeclaration dsym;
+ AggregateDeclaration dsym;
- extern (D) this(const ref Loc loc, StructDeclaration dsym)
+ extern (D) this(const ref Loc loc, AggregateDeclaration dsym)
{
super(loc, dsym.ident);
this.dsym = dsym;
#define STCforeach 0x4000ULL /// variable for foreach loop
#define STCvariadic 0x8000ULL /// the `variadic` parameter in: T foo(T a, U b, V variadic...)
- #define STCctorinit 0x10000ULL /// can only be set inside constructor
+ // 0x10000ULL
#define STCtemplateparameter 0x20000ULL /// template parameter
#define STCref 0x40000ULL /// `ref`
#define STCscope 0x80000ULL /// `scope`
#define STCreturninferred 0x1000000ULL /// `return` has been inferred and should not be part of mangling, `return` must also be set
#define STCimmutable 0x2000000ULL /// `immutable`
- #define STCinit 0x4000000ULL /// has explicit initializer
+ // 0x4000000ULL
#define STCmanifest 0x8000000ULL /// manifest constant
#define STCnodtor 0x10000000ULL /// do not run destructor
virtual bool isDataseg();
virtual bool isThreadlocal();
virtual bool isCodeseg() const;
- bool isCtorinit() const { return (storage_class & STCctorinit) != 0; }
bool isFinal() const { return (storage_class & STCfinal) != 0; }
virtual bool isAbstract() { return (storage_class & STCabstract) != 0; }
bool isConst() const { return (storage_class & STCconst) != 0; }
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
bool mynew; // it is a class new'd with custom operator new
char canassign; // it can be assigned to
bool needThis();
bool isExport() const;
bool isImportedSymbol() const;
+ bool isCtorinit() const;
bool isDataseg();
bool isThreadlocal();
bool isCTFE();
class SymbolDeclaration : public Declaration
{
public:
- StructDeclaration *dsym;
+ AggregateDeclaration *dsym;
// Eliminate need for dynamic_cast
SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; }
import dmd.expressionsem;
import dmd.func;
import dmd.globals;
+import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.init;
{
switch (e.op)
{
- case TOK.int64:
- case TOK.float64:
- case TOK.complex80:
- case TOK.null_:
- case TOK.void_:
- case TOK.string_:
- case TOK.this_:
- case TOK.super_:
- case TOK.type:
- case TOK.typeid_:
- case TOK.template_: // non-eponymous template/instance
- case TOK.scope_: // ditto
- case TOK.dotTemplateDeclaration: // ditto, e.e1 doesn't matter here
- case TOK.dotTemplateInstance: // ditto
- case TOK.dot: // ditto
+ case EXP.int64:
+ case EXP.float64:
+ case EXP.complex80:
+ case EXP.null_:
+ case EXP.void_:
+ case EXP.string_:
+ case EXP.this_:
+ case EXP.super_:
+ case EXP.type:
+ case EXP.typeid_:
+ case EXP.template_: // non-eponymous template/instance
+ case EXP.scope_: // ditto
+ case EXP.dotTemplateDeclaration: // ditto, e.e1 doesn't matter here
+ case EXP.dotTemplateInstance: // ditto
+ case EXP.dot: // ditto
if (e.type.ty == Terror)
return ErrorExp.get();
- goto case TOK.error;
+ goto case EXP.error;
- case TOK.error:
+ case EXP.error:
return e;
default:
*/
public Expression ctfeInterpretForPragmaMsg(Expression e)
{
- if (e.op == TOK.error || e.op == TOK.type)
+ if (e.op == EXP.error || e.op == EXP.type)
return e;
// It's also OK for it to be a function declaration (happens only with
* thisarg = 'this', if a needThis() function, NULL if not.
*
* Returns:
- * result expression if successful, TOK.cantExpression if not,
+ * result expression if successful, EXP.cantExpression if not,
* or CTFEExp if function returned void.
*/
private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterState* istate, Expressions* arguments, Expression thisarg)
/* Struct literals are passed by value, but we don't need to
* copy them if they are passed as const
*/
- if (earg.op == TOK.structLiteral && !(fparam.storageClass & (STC.const_ | STC.immutable_)))
+ if (earg.op == EXP.structLiteral && !(fparam.storageClass & (STC.const_ | STC.immutable_)))
earg = copyLiteral(earg).copy();
}
if (auto tee = earg.isThrownExceptionExp())
}
ctfeGlobals.stack.push(v);
- if (fparam.isReference() && earg.op == TOK.variable &&
+ if (fparam.isReference() && earg.op == EXP.variable &&
earg.isVarExp().var.toParent2() == fd)
{
VarDeclaration vx = earg.isVarExp().var.isVarDeclaration();
}
else
{
- assert(!e || (e.op != TOK.continue_ && e.op != TOK.break_));
+ assert(!e || (e.op != EXP.continue_ && e.op != EXP.break_));
break;
}
}
// If fell off the end of a void function, return void
if (!e && tf.next.ty == Tvoid)
e = CTFEExp.voidexp;
- if (tf.isref && e.op == TOK.variable && e.isVarExp().var == fd.vthis)
+ if (tf.isref && e.op == EXP.variable && e.isVarExp().var == fd.vthis)
e = thisarg;
- if (tf.isref && fd.isThis2 && e.op == TOK.index)
+ if (tf.isref && fd.isThis2 && e.op == EXP.index)
{
auto ie = e.isIndexExp();
auto pe = ie.e1.isPtrExp();
this.goal = goal;
}
- // If e is TOK.throw_exception or TOK.cantExpression,
+ // If e is EXP.throw_exception or EXP.cantExpression,
// set it to 'result' and returns true.
bool exceptionOrCant(Expression e)
{
if (exceptionOrCantInterpret(e))
{
// Make sure e is not pointing to a stack temporary
- result = (e.op == TOK.cantExpression) ? CTFEExp.cantexp : e;
+ result = (e.op == EXP.cantExpression) ? CTFEExp.cantexp : e;
return true;
}
return false;
continue;
if (exceptionOrCant(e))
return;
- if (e.op == TOK.break_)
+ if (e.op == EXP.break_)
{
if (istate.gotoTarget && istate.gotoTarget != s)
{
result = null;
return;
}
- if (e.op == TOK.continue_)
+ if (e.op == EXP.continue_)
{
if (istate.gotoTarget && istate.gotoTarget != s)
{
if (isTrueBool(e))
result = interpret(pue, s.ifbody, istate);
- else if (e.isBool(false))
+ else if (e.toBool().hasValue(false))
result = interpret(pue, s.elsebody, istate);
else
{
if (auto eaddr = e.isAddrExp())
x = eaddr.e1;
VarDeclaration v;
- while (x.op == TOK.variable && (v = (cast(VarExp)x).var.isVarDeclaration()) !is null)
+ while (x.op == EXP.variable && (v = (cast(VarExp)x).var.isVarDeclaration()) !is null)
{
if (v.storage_class & STC.ref_)
{
else
break;
}
- // TODO: If it is a TOK.dotVariable or TOK.index, we should check that it is not
+ // TODO: If it is a EXP.dotVariable or EXP.index, we should check that it is not
// pointing to a local struct or static array.
}
if (auto se = e.isStructLiteralExp())
return;
}
- // We need to treat pointers specially, because TOK.symbolOffset can be used to
+ // We need to treat pointers specially, because EXP.symbolOffset can be used to
// return a value OR a pointer
Expression e = interpret(pue, s.exp, istate);
if (exceptionOrCant(e))
if (exceptionOrCant(e))
return;
- if (e && e.op == TOK.break_)
+ if (e && e.op == EXP.break_)
{
if (istate.gotoTarget && istate.gotoTarget != s)
{
istate.gotoTarget = null;
break;
}
- if (e && e.op == TOK.continue_)
+ if (e && e.op == EXP.continue_)
{
if (istate.gotoTarget && istate.gotoTarget != s)
{
result = CTFEExp.cantexp;
return;
}
- if (e.isBool(false))
+ if (e.toBool().hasValue(false))
break;
assert(isTrueBool(e));
}
Expression e = interpret(&ue, s.condition, istate);
if (exceptionOrCant(e))
return;
- if (e.isBool(false))
+ if (e.toBool().hasValue(false))
break;
assert(isTrueBool(e));
}
if (exceptionOrCant(e))
return;
- if (e && e.op == TOK.break_)
+ if (e && e.op == EXP.break_)
{
if (istate.gotoTarget && istate.gotoTarget != s)
{
istate.gotoTarget = null;
break;
}
- if (e && e.op == TOK.continue_)
+ if (e && e.op == EXP.continue_)
{
if (istate.gotoTarget && istate.gotoTarget != s)
{
return;
if (exceptionOrCant(e))
return;
- if (e && e.op == TOK.break_)
+ if (e && e.op == EXP.break_)
{
if (istate.gotoTarget && istate.gotoTarget != s)
{
Expression ecase = interpret(&uecase, cs.exp, istate);
if (exceptionOrCant(ecase))
return;
- if (ctfeEqual(cs.exp.loc, TOK.equal, econdition, ecase))
+ if (ctfeEqual(cs.exp.loc, EXP.equal, econdition, ecase))
{
scase = cs;
break;
istate.start = scase;
Expression e = interpret(pue, s._body, istate);
assert(!istate.start); // jump must not fail
- if (e && e.op == TOK.break_)
+ if (e && e.op == EXP.break_)
{
if (istate.gotoTarget && istate.gotoTarget != s)
{
(*collateral.value.elements)[bypass] = boss;
return newest;
}
- while ((*boss.value.elements)[next].op == TOK.classReference)
+ while ((*boss.value.elements)[next].op == EXP.classReference)
{
boss = cast(ClassReferenceExp)(*boss.value.elements)[next];
}
if (exceptionOrCant(e))
return;
- assert(e.op == TOK.classReference);
+ assert(e.op == EXP.classReference);
result = ctfeEmplaceExp!ThrownExceptionExp(s.loc, e.isClassReferenceExp());
}
}
// If it is with(Enum) {...}, just execute the body.
- if (s.exp.op == TOK.scope_ || s.exp.op == TOK.type)
+ if (s.exp.op == EXP.scope_ || s.exp.op == EXP.type)
{
result = interpret(pue, s._body, istate);
return;
{
debug (LOG)
{
- printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), Token.toChars(e.op), e.toChars());
+ printf("%s Expression::interpret() '%s' %s\n", e.loc.toChars(), EXPtoString(e.op).ptr, e.toChars());
printf("type = %s\n", e.type.toChars());
showCtfeExpr(e);
}
{
if (istate && istate.fd.isThis2)
{
- assert(result.op == TOK.address);
+ assert(result.op == EXP.address);
result = (cast(AddrExp)result).e1;
- assert(result.op == TOK.arrayLiteral);
+ assert(result.op == EXP.arrayLiteral);
result = (*(cast(ArrayLiteralExp)result).elements)[0];
if (e.type.ty == Tstruct)
{
}
return;
}
- assert(result.op == TOK.structLiteral || result.op == TOK.classReference || result.op == TOK.type);
+ assert(result.op == EXP.structLiteral || result.op == EXP.classReference || result.op == EXP.type);
return;
}
e.error("value of `this` is not known at compile time");
dinteger_t indx = e.offset / sz;
assert(sz * indx == e.offset);
Expression aggregate = null;
- if (val.op == TOK.arrayLiteral || val.op == TOK.string_)
+ if (val.op == EXP.arrayLiteral || val.op == EXP.string_)
{
aggregate = val;
}
return CTFEExp.cantexp;
assert(e.type);
- if (e.op == TOK.construct || e.op == TOK.blit)
+ if (e.op == EXP.construct || e.op == EXP.blit)
{
AssignExp ae = cast(AssignExp)e;
e = ae.e2;
}
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
{
// FIXME: Ultimately all errors should be detected in prior semantic analysis stage.
}
}
else if (SymbolDeclaration s = d.isSymbolDeclaration())
{
+ // exclude void[]-typed `__traits(initSymbol)`
+ if (auto ta = s.type.toBasetype().isTypeDArray())
+ {
+ assert(ta.next.ty == Tvoid);
+ error(loc, "cannot determine the address of the initializer symbol during CTFE");
+ return CTFEExp.cantexp;
+ }
+
// Struct static initializers, for example
e = s.dsym.type.defaultInitLiteral(loc);
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
error(loc, "CTFE failed because of previous errors in `%s.init`", s.toChars());
e = e.expressionSemantic(null);
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
e = CTFEExp.cantexp;
else // Convert NULL to CTFEExp
e = interpret(e, istate, goal);
{
// Strip off the nest of ref variables
Expression ev = getValue(v);
- if (ev.op == TOK.variable ||
- ev.op == TOK.index ||
- (ev.op == TOK.slice && ev.type.toBasetype().ty == Tsarray) ||
- ev.op == TOK.dotVariable)
+ if (ev.op == EXP.variable ||
+ ev.op == EXP.index ||
+ (ev.op == EXP.slice && ev.type.toBasetype().ty == Tsarray) ||
+ ev.op == EXP.dotVariable)
{
result = interpret(pue, ev, istate, goal);
return;
if (exceptionOrCant(ex))
return;
- if (result.op == TOK.null_)
+ if (result.op == EXP.null_)
{
e.error("null pointer dereference evaluating typeid. `%s` is `null`", ex.toChars());
result = CTFEExp.cantexp;
return;
}
- if (result.op != TOK.classReference)
+ if (result.op != EXP.classReference)
{
e.error("CTFE internal error: determining classinfo");
result = CTFEExp.cantexp;
// A tuple of assignments can contain void (Bug 5676).
if (goal == CTFEGoal.Nothing)
continue;
- if (ex.op == TOK.voidExpression)
+ if (ex.op == EXP.voidExpression)
{
e.error("CTFE internal error: void element `%s` in tuple", exp.toChars());
assert(0);
else
{
// segfault bug 6250
- assert(exp.op != TOK.index || (cast(IndexExp)exp).e1 != e);
+ assert(exp.op != EXP.index || (cast(IndexExp)exp).e1 != e);
ex = interpretRegion(exp, istate);
if (exceptionOrCant(ex))
for (size_t j = i; j < keysx.dim; j++)
{
auto ekey2 = (*keysx)[j];
- if (!ctfeEqual(e.loc, TOK.equal, ekey, ekey2))
+ if (!ctfeEqual(e.loc, EXP.equal, ekey, ekey2))
continue;
// Remove ekey
return;
switch (e.op)
{
- case TOK.negate:
+ case EXP.negate:
*pue = Neg(e.type, e1);
break;
- case TOK.tilde:
+ case EXP.tilde:
*pue = Com(e.type, e1);
break;
- case TOK.not:
+ case EXP.not:
*pue = Not(e.type, e1);
break;
{
printf("%s BinExp::interpretCommon() %s\n", e.loc.toChars(), e.toChars());
}
- if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer && e.op == TOK.min)
+ if (e.e1.type.ty == Tpointer && e.e2.type.ty == Tpointer && e.op == EXP.min)
{
UnionExp ue1 = void;
Expression e1 = interpret(&ue1, e.e1, istate);
result = (*pue).exp();
return;
}
- if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == TOK.add)
+ if (e.e2.type.ty == Tpointer && e.e1.type.isintegral() && e.op == EXP.add)
{
UnionExp ue1 = void;
Expression e1 = interpret(&ue1, e.e1, istate);
if (!evalOperand(&ue2, e.e2, e2))
return;
- if (e.op == TOK.rightShift || e.op == TOK.leftShift || e.op == TOK.unsignedRightShift)
+ if (e.op == EXP.rightShift || e.op == EXP.leftShift || e.op == EXP.unsignedRightShift)
{
const sinteger_t i2 = e2.toInteger();
const d_uns64 sz = e1.type.size() * 8;
{
// The following should really be an assert()
e1.error("CTFE internal error: non-constant value `%s`", e1.toChars());
- emplaceExp!CTFEExp(&ue, TOK.cantExpression);
+ emplaceExp!CTFEExp(&ue, EXP.cantExpression);
return ue;
}
if (e2.isConst() != 1)
{
e2.error("CTFE internal error: non-constant value `%s`", e2.toChars());
- emplaceExp!CTFEExp(&ue, TOK.cantExpression);
+ emplaceExp!CTFEExp(&ue, EXP.cantExpression);
return ue;
}
const cmp = comparePointers(e.op, agg1, ofs1, agg2, ofs2);
if (cmp == -1)
{
- char dir = (e.op == TOK.greaterThan || e.op == TOK.greaterOrEqual) ? '<' : '>';
+ char dir = (e.op == EXP.greaterThan || e.op == EXP.greaterOrEqual) ? '<' : '>';
e.error("the ordering of pointers to unrelated memory blocks is indeterminate in CTFE. To check if they point to the same memory block, use both `>` and `<` inside `&&` or `||`, eg `%s && %s %c= %s + 1`", e.toChars(), e.e1.toChars(), dir, e.e2.toChars());
result = CTFEExp.cantexp;
return;
{
switch (e.op)
{
- case TOK.add:
+ case EXP.add:
interpretCommon(e, &Add);
return;
- case TOK.min:
+ case EXP.min:
interpretCommon(e, &Min);
return;
- case TOK.mul:
+ case EXP.mul:
interpretCommon(e, &Mul);
return;
- case TOK.div:
+ case EXP.div:
interpretCommon(e, &Div);
return;
- case TOK.mod:
+ case EXP.mod:
interpretCommon(e, &Mod);
return;
- case TOK.leftShift:
+ case EXP.leftShift:
interpretCommon(e, &Shl);
return;
- case TOK.rightShift:
+ case EXP.rightShift:
interpretCommon(e, &Shr);
return;
- case TOK.unsignedRightShift:
+ case EXP.unsignedRightShift:
interpretCommon(e, &Ushr);
return;
- case TOK.and:
+ case EXP.and:
interpretCommon(e, &And);
return;
- case TOK.or:
+ case EXP.or:
interpretCommon(e, &Or);
return;
- case TOK.xor:
+ case EXP.xor:
interpretCommon(e, &Xor);
return;
- case TOK.pow:
+ case EXP.pow:
interpretCommon(e, &Pow);
return;
- case TOK.equal:
- case TOK.notEqual:
+ case EXP.equal:
+ case EXP.notEqual:
interpretCompareCommon(e, &ctfeEqual);
return;
- case TOK.identity:
- case TOK.notIdentity:
+ case EXP.identity:
+ case EXP.notIdentity:
interpretCompareCommon(e, &ctfeIdentity);
return;
- case TOK.lessThan:
- case TOK.lessOrEqual:
- case TOK.greaterThan:
- case TOK.greaterOrEqual:
+ case EXP.lessThan:
+ case EXP.lessOrEqual:
+ case EXP.greaterThan:
+ case EXP.greaterOrEqual:
interpretCompareCommon(e, &ctfeCmp);
return;
default:
- printf("be = '%s' %s at [%s]\n", Token.toChars(e.op), e.toChars(), e.loc.toChars());
+ printf("be = '%s' %s at [%s]\n", EXPtoString(e.op).ptr, e.toChars(), e.loc.toChars());
assert(0);
}
}
* So we need to recurse to determine if it is a block assignment.
*/
bool isBlockAssignment = false;
- if (e1.op == TOK.slice)
+ if (e1.op == EXP.slice)
{
// a[] = e can have const e. So we compare the naked types.
Type tdst = e1.type.toBasetype();
// Deal with reference assignment
// ---------------------------------------
// If it is a construction of a ref variable, it is a ref assignment
- if ((e.op == TOK.construct || e.op == TOK.blit) &&
+ if ((e.op == EXP.construct || e.op == EXP.blit) &&
((cast(AssignExp)e).memset == MemorySet.referenceInit))
{
assert(!fp);
if (fp)
{
- while (e1.op == TOK.cast_)
+ while (e1.op == EXP.cast_)
{
CastExp ce = cast(CastExp)e1;
e1 = ce.e1;
AssocArrayLiteralExp existingAA = null;
Expression lastIndex = null;
Expression oldval = null;
- if (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
+ if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
{
// ---------------------------------------
// Deal with AA index assignment
*/
IndexExp ie = cast(IndexExp)e1;
int depth = 0; // how many nested AA indices are there?
- while (ie.e1.op == TOK.index && (cast(IndexExp)ie.e1).e1.type.toBasetype().ty == Taarray)
+ while (ie.e1.op == EXP.index && (cast(IndexExp)ie.e1).e1.type.toBasetype().ty == Taarray)
{
assert(ie.modifiable);
ie = cast(IndexExp)ie.e1;
oldval = copyLiteral(e.e1.type.defaultInitLiteral(e.loc)).copy();
Expression newaae = oldval;
- while (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
+ while (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
{
Expression ekey = interpretRegion((cast(IndexExp)e1).e2, istate);
if (exceptionOrCant(ekey))
assert(existingAA && lastIndex);
e1 = null; // stomp
}
- else if (e1.op == TOK.arrayLength)
+ else if (e1.op == EXP.arrayLength)
{
oldval = interpretRegion(e1, istate);
if (exceptionOrCant(oldval))
return;
}
- else if (e.op == TOK.construct || e.op == TOK.blit)
+ else if (e.op == EXP.construct || e.op == EXP.blit)
{
// Unless we have a simple var assignment, we're
// only modifying part of the variable. So we need to make sure
if (exceptionOrCant(e1))
return;
- if (e1.op == TOK.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
+ if (e1.op == EXP.index && (cast(IndexExp)e1).e1.type.toBasetype().ty == Taarray)
{
IndexExp ie = cast(IndexExp)e1;
- assert(ie.e1.op == TOK.assocArrayLiteral);
+ assert(ie.e1.op == EXP.assocArrayLiteral);
existingAA = cast(AssocArrayLiteralExp)ie.e1;
lastIndex = ie.e2;
}
Expression newval = interpretRegion(e.e2, istate);
if (exceptionOrCant(newval))
return;
- if (e.op == TOK.blit && newval.op == TOK.int64)
+ if (e.op == EXP.blit && newval.op == EXP.int64)
{
Type tbn = e.type.baseElemOf();
if (tbn.ty == Tstruct)
/* Look for special case of struct being initialized with 0.
*/
newval = e.type.defaultInitLiteral(e.loc);
- if (newval.op == TOK.error)
+ if (newval.op == EXP.error)
{
result = CTFEExp.cantexp;
return;
if (e.e1.type.ty != Tpointer)
{
// ~= can create new values (see bug 6052)
- if (e.op == TOK.concatenateAssign || e.op == TOK.concatenateElemAssign || e.op == TOK.concatenateDcharAssign)
+ if (e.op == EXP.concatenateAssign || e.op == EXP.concatenateElemAssign || e.op == EXP.concatenateDcharAssign)
{
// We need to dup it and repaint the type. For a dynamic array
// we can skip duplication, because it gets copied later anyway.
newval = (*fp)(e.loc, e.type, oldval, newval).copy();
}
else if (e.e2.type.isintegral() &&
- (e.op == TOK.addAssign ||
- e.op == TOK.minAssign ||
- e.op == TOK.plusPlus ||
- e.op == TOK.minusMinus))
+ (e.op == EXP.addAssign ||
+ e.op == EXP.minAssign ||
+ e.op == EXP.plusPlus ||
+ e.op == EXP.minusMinus))
{
newval = pointerArithmetic(e.loc, e.op, e.type, oldval, newval).copy();
}
result = ctfeCast(pue, e.loc, e.type, e.type, fp && post ? oldval : newval);
return;
}
- if (e1.op == TOK.arrayLength)
+ if (e1.op == EXP.arrayLength)
{
/* Change the assignment from:
* arr.length = n;
/* Block assignment or element-wise assignment.
*/
- if (e1.op == TOK.slice ||
- e1.op == TOK.vector ||
- e1.op == TOK.arrayLiteral ||
- e1.op == TOK.string_ ||
- e1.op == TOK.null_ && e1.type.toBasetype().ty == Tarray)
+ if (e1.op == EXP.slice ||
+ e1.op == EXP.vector ||
+ e1.op == EXP.arrayLiteral ||
+ e1.op == EXP.string_ ||
+ e1.op == EXP.null_ && e1.type.toBasetype().ty == Tarray)
{
// Note that slice assignments don't support things like ++, so
// we don't need to remember 'returnValue'.
if (auto dve = e1x.isDotVarExp())
{
auto ex = dve.e1;
- auto sle = ex.op == TOK.structLiteral ? (cast(StructLiteralExp)ex)
- : ex.op == TOK.classReference ? (cast(ClassReferenceExp)ex).value
+ auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex)
+ : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value
: null;
auto v = dve.var.isVarDeclaration();
if (!sle || !v)
if (v is v2 || !v.isOverlappedWith(v2))
continue;
auto e = (*sle.elements)[i];
- if (e.op != TOK.void_)
+ if (e.op != EXP.void_)
(*sle.elements)[i] = voidInitLiteral(e.type, v).copy();
}
}
* e.v = newval
*/
auto ex = dve.e1;
- auto sle = ex.op == TOK.structLiteral ? (cast(StructLiteralExp)ex)
- : ex.op == TOK.classReference ? (cast(ClassReferenceExp)ex).value
+ auto sle = ex.op == EXP.structLiteral ? (cast(StructLiteralExp)ex)
+ : ex.op == EXP.classReference ? (cast(ClassReferenceExp)ex).value
: null;
auto v = (cast(DotVarExp)e1).var.isVarDeclaration();
if (!sle || !v)
return CTFEExp.cantexp;
}
- int fieldi = ex.op == TOK.structLiteral ? findFieldIndexByName(sle.sd, v)
+ int fieldi = ex.op == EXP.structLiteral ? findFieldIndexByName(sle.sd, v)
: (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
if (fieldi == -1)
{
existingSE.setCodeUnit(index, cast(dchar)newval.toInteger());
return null;
}
- if (aggregate.op != TOK.arrayLiteral)
+ if (aggregate.op != EXP.arrayLiteral)
{
e.error("index assignment `%s` is not yet supported in CTFE ", e.toChars());
return CTFEExp.cantexp;
if (auto ve = newval.isVectorExp())
{
// Ensure ve is an array literal, and not a broadcast
- if (ve.e1.op == TOK.int64 || ve.e1.op == TOK.float64) // if broadcast
+ if (ve.e1.op == EXP.int64 || ve.e1.op == EXP.float64) // if broadcast
{
UnionExp ue = void;
Expression ex = interpretVectorToArray(&ue, ve);
}
}
- if (newval.op == TOK.structLiteral && oldval)
+ if (newval.op == EXP.structLiteral && oldval)
{
- assert(oldval.op == TOK.structLiteral || oldval.op == TOK.arrayLiteral || oldval.op == TOK.string_);
+ assert(oldval.op == EXP.structLiteral || oldval.op == EXP.arrayLiteral || oldval.op == EXP.string_);
newval = copyLiteral(newval).copy();
assignInPlace(oldval, newval);
}
- else if (wantCopy && e.op == TOK.assign)
+ else if (wantCopy && e.op == EXP.assign)
{
// Currently postblit/destructor calls on static array are done
// in the druntime internal functions so they don't appear in AST.
return CTFEExp.cantexp;
}
}
- assert(oldval.op == TOK.arrayLiteral);
- assert(newval.op == TOK.arrayLiteral);
+ assert(oldval.op == EXP.arrayLiteral);
+ assert(newval.op == EXP.arrayLiteral);
Expressions* oldelems = (cast(ArrayLiteralExp)oldval).elements;
Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
if (wantCopy)
newval = copyLiteral(newval).copy();
- if (t1b.ty == Tsarray && e.op == TOK.construct && e.e2.isLvalue())
+ if (t1b.ty == Tsarray && e.op == EXP.construct && e.e2.isLvalue())
{
// https://issues.dlang.org/show_bug.cgi?id=9245
if (Expression ex = evaluatePostblit(istate, newval))
*payload = oldval;
// Blit assignment should return the newly created value.
- if (e.op == TOK.blit)
+ if (e.op == EXP.blit)
return oldval;
return null;
* This could be a slice assignment or a block assignment, and
* dest could be either an array literal, or a string.
*
- * Returns TOK.cantExpression on failure. If there are no errors,
+ * Returns EXP.cantExpression on failure. If there are no errors,
* it returns aggregate[low..upp], except that as an optimisation,
* if goal == CTFEGoal.Nothing, it will return NULL
*/
lowerbound = 0;
upperbound = se.len;
}
- else if (e1.op == TOK.null_)
+ else if (e1.op == EXP.null_)
{
lowerbound = 0;
upperbound = 0;
return CTFEExp.cantexp;
}
}
- assert(newval.op != TOK.slice);
+ assert(newval.op != EXP.slice);
}
if (auto se = newval.isStringExp())
{
return CTFEExp.cantexp;
}
- if (newval.op == TOK.slice && !isBlockAssignment)
+ if (newval.op == EXP.slice && !isBlockAssignment)
{
auto se = cast(SliceExp)newval;
auto aggr2 = se.e1;
// Currently overlapping for struct array is allowed.
// The order of elements processing depends on the overlapping.
// https://issues.dlang.org/show_bug.cgi?id=14024
- assert(aggr2.op == TOK.arrayLiteral);
+ assert(aggr2.op == EXP.arrayLiteral);
Expressions* oldelems = existingAE.elements;
Expressions* newelems = (cast(ArrayLiteralExp)aggr2).elements;
}
// no overlapping
//length?
- assert(newval.op != TOK.slice);
+ assert(newval.op != EXP.slice);
}
- if (newval.op == TOK.string_ && !isBlockAssignment)
+ if (newval.op == EXP.string_ && !isBlockAssignment)
{
/* 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);
return newval;
}
- if (newval.op == TOK.arrayLiteral && !isBlockAssignment)
+ if (newval.op == EXP.arrayLiteral && !isBlockAssignment)
{
Expressions* oldelems = existingAE.elements;
Expressions* newelems = (cast(ArrayLiteralExp)newval).elements;
Type elemtype = existingAE.type.nextOf();
- bool needsPostblit = e.op != TOK.blit && e.e2.isLvalue();
+ bool needsPostblit = e.op != EXP.blit && e.e2.isLvalue();
foreach (j, newelem; *newelems)
{
newelem = paintTypeOntoLiteral(elemtype, newelem);
bool directblk = (cast(TypeArray)ae.type).next.equivalent(newval.type);
for (size_t k = lwr; k < upr; k++)
{
- if (!directblk && (*w)[k].op == TOK.arrayLiteral)
+ if (!directblk && (*w)[k].op == EXP.arrayLiteral)
{
// Multidimensional array block assign
if (Expression ex = assignTo(cast(ArrayLiteralExp)(*w)[k]))
Type tn = newval.type.toBasetype();
bool wantRef = (tn.ty == Tarray || isAssocArray(tn) || tn.ty == Tclass);
- bool cow = newval.op != TOK.structLiteral && newval.op != TOK.arrayLiteral && newval.op != TOK.string_;
+ bool cow = newval.op != EXP.structLiteral && newval.op != EXP.arrayLiteral && newval.op != EXP.string_;
Type tb = tn.baseElemOf();
StructDeclaration sd = (tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null);
rb.istate = istate;
rb.newval = newval;
rb.refCopy = wantRef || cow;
- rb.needsPostblit = sd && sd.postblit && e.op != TOK.blit && e.e2.isLvalue();
- rb.needsDtor = sd && sd.dtor && e.op == TOK.assign;
+ rb.needsPostblit = sd && sd.postblit && e.op != EXP.blit && e.e2.isLvalue();
+ rb.needsDtor = sd && sd.dtor && e.op == EXP.assign;
if (Expression ex = rb.assignTo(existingAE, cast(size_t)lowerbound, cast(size_t)upperbound))
return ex;
{
switch (e.op)
{
- case TOK.addAssign:
+ case EXP.addAssign:
interpretAssignCommon(e, &Add);
return;
- case TOK.minAssign:
+ case EXP.minAssign:
interpretAssignCommon(e, &Min);
return;
- case TOK.concatenateAssign:
- case TOK.concatenateElemAssign:
- case TOK.concatenateDcharAssign:
+ case EXP.concatenateAssign:
+ case EXP.concatenateElemAssign:
+ case EXP.concatenateDcharAssign:
interpretAssignCommon(e, &ctfeCat);
return;
- case TOK.mulAssign:
+ case EXP.mulAssign:
interpretAssignCommon(e, &Mul);
return;
- case TOK.divAssign:
+ case EXP.divAssign:
interpretAssignCommon(e, &Div);
return;
- case TOK.modAssign:
+ case EXP.modAssign:
interpretAssignCommon(e, &Mod);
return;
- case TOK.leftShiftAssign:
+ case EXP.leftShiftAssign:
interpretAssignCommon(e, &Shl);
return;
- case TOK.rightShiftAssign:
+ case EXP.rightShiftAssign:
interpretAssignCommon(e, &Shr);
return;
- case TOK.unsignedRightShiftAssign:
+ case EXP.unsignedRightShiftAssign:
interpretAssignCommon(e, &Ushr);
return;
- case TOK.andAssign:
+ case EXP.andAssign:
interpretAssignCommon(e, &And);
return;
- case TOK.orAssign:
+ case EXP.orAssign:
interpretAssignCommon(e, &Or);
return;
- case TOK.xorAssign:
+ case EXP.xorAssign:
interpretAssignCommon(e, &Xor);
return;
- case TOK.powAssign:
+ case EXP.powAssign:
interpretAssignCommon(e, &Pow);
return;
{
printf("%s PostExp::interpret() %s\n", e.loc.toChars(), e.toChars());
}
- if (e.op == TOK.plusPlus)
+ if (e.op == EXP.plusPlus)
interpretAssignCommon(e, &Add, 1);
else
interpretAssignCommon(e, &Min, 1);
static int isPointerCmpExp(Expression e, Expression* p1, Expression* p2)
{
int ret = 1;
- while (e.op == TOK.not)
+ while (e.op == EXP.not)
{
ret *= -1;
e = (cast(NotExp)e).e1;
}
switch (e.op)
{
- case TOK.lessThan:
- case TOK.lessOrEqual:
+ case EXP.lessThan:
+ case EXP.lessOrEqual:
ret *= -1;
goto case; /+ fall through +/
- case TOK.greaterThan:
- case TOK.greaterOrEqual:
+ case EXP.greaterThan:
+ case EXP.greaterOrEqual:
*p1 = (cast(BinExp)e).e1;
*p2 = (cast(BinExp)e).e2;
if (!(isPointer((*p1).type) && isPointer((*p2).type)))
*/
private void interpretFourPointerRelation(UnionExp* pue, BinExp e)
{
- assert(e.op == TOK.andAnd || e.op == TOK.orOr);
+ assert(e.op == EXP.andAnd || e.op == EXP.orOr);
/* It can only be an isInside expression, if both e1 and e2 are
* directional pointer comparisons.
Expression agg1 = getAggregateFromPointer(p1, &ofs1);
Expression agg2 = getAggregateFromPointer(p2, &ofs2);
- if (!pointToSameMemoryBlock(agg1, agg2) && agg1.op != TOK.null_ && agg2.op != TOK.null_)
+ if (!pointToSameMemoryBlock(agg1, agg2) && agg1.op != EXP.null_ && agg2.op != EXP.null_)
{
// Here it is either CANT_INTERPRET,
// or an IsInside comparison returning false.
(dir1 != dir2 && pointToSameMemoryBlock(agg1, agg3) && pointToSameMemoryBlock(agg2, agg4)))
{
// it's a legal two-sided comparison
- emplaceExp!(IntegerExp)(pue, e.loc, (e.op == TOK.andAnd) ? 0 : 1, e.type);
+ emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
result = pue.exp();
return;
}
* Returns:
* negate operator
*/
- static TOK negateRelation(TOK op) pure
+ static EXP negateRelation(EXP op) pure
{
switch (op)
{
- case TOK.greaterOrEqual: op = TOK.lessThan; break;
- case TOK.greaterThan: op = TOK.lessOrEqual; break;
- case TOK.lessOrEqual: op = TOK.greaterThan; break;
- case TOK.lessThan: op = TOK.greaterOrEqual; break;
+ case EXP.greaterOrEqual: op = EXP.lessThan; break;
+ case EXP.greaterThan: op = EXP.lessOrEqual; break;
+ case EXP.lessOrEqual: op = EXP.greaterThan; break;
+ case EXP.lessThan: op = EXP.greaterOrEqual; break;
default: assert(0);
}
return op;
}
- const TOK cmpop = nott ? negateRelation(ex.op) : ex.op;
+ const EXP cmpop = nott ? negateRelation(ex.op) : ex.op;
const cmp = comparePointers(cmpop, agg1, ofs1, agg2, ofs2);
// We already know this is a valid comparison.
assert(cmp >= 0);
- if (e.op == TOK.andAnd && cmp == 1 || e.op == TOK.orOr && cmp == 0)
+ if (e.op == EXP.andAnd && cmp == 1 || e.op == EXP.orOr && cmp == 0)
{
result = interpret(pue, e.e2, istate);
return;
}
- emplaceExp!(IntegerExp)(pue, e.loc, (e.op == TOK.andAnd) ? 0 : 1, e.type);
+ emplaceExp!(IntegerExp)(pue, e.loc, (e.op == EXP.andAnd) ? 0 : 1, e.type);
result = pue.exp();
}
return;
bool res;
- const andand = e.op == TOK.andAnd;
- if (andand ? result.isBool(false) : isTrueBool(result))
+ const andand = e.op == EXP.andAnd;
+ if (andand ? result.toBool().hasValue(false) : isTrueBool(result))
res = !andand;
- else if (andand ? isTrueBool(result) : result.isBool(false))
+ else if (andand ? isTrueBool(result) : result.toBool().hasValue(false))
{
UnionExp ue2 = void;
result = interpret(&ue2, e.e2, istate);
if (exceptionOrCant(result))
return;
- if (result.op == TOK.voidExpression)
+ if (result.op == EXP.voidExpression)
{
assert(e.type.ty == Tvoid);
result = null;
return;
}
- if (result.isBool(false))
+ if (result.toBool().hasValue(false))
res = false;
else if (isTrueBool(result))
res = true;
if (auto ce = ea.isCastExp())
ea = ce.e1;
- // printf("2 ea = %s, %s %s\n", ea.type.toChars(), Token.toChars(ea.op), ea.toChars());
- if (ea.op == TOK.variable || ea.op == TOK.symbolOffset)
+ // printf("2 ea = %s, %s %s\n", ea.type.toChars(), EXPtoString(ea.op).ptr, ea.toChars());
+ if (ea.op == EXP.variable || ea.op == EXP.symbolOffset)
result = getVarExp(e.loc, istate, (cast(SymbolExp)ea).var, CTFEGoal.RValue);
else if (auto ae = ea.isAddrExp())
result = interpretRegion(ae.e1, istate);
result = interpretRegion(ae, istate);
return;
}
+ else if (fd.ident == Id._d_arrayctor || fd.ident == Id._d_arraysetctor)
+ {
+ // In expressionsem.d `T[x] ea = eb;` was lowered to `_d_array{,set}ctor(ea[], eb[]);`.
+ // The following code will rewrite it back to `ea = eb` and then interpret that expression.
+ if (fd.ident == Id._d_arraysetctor)
+ assert(e.arguments.dim == 2);
+ else
+ assert(e.arguments.dim == 3);
+
+ Expression ea = (*e.arguments)[0];
+ if (ea.isCastExp)
+ ea = ea.isCastExp.e1;
+
+ Expression eb = (*e.arguments)[1];
+ if (eb.isCastExp && fd.ident == Id._d_arrayctor)
+ eb = eb.isCastExp.e1;
+
+ ConstructExp ce = new ConstructExp(e.loc, ea, eb);
+ ce.type = ea.type;
+
+ result = interpret(ce, istate);
+ return;
+ }
}
else if (auto soe = ecall.isSymOffExp())
{
// Currently this is satisfied because closure is not yet supported.
assert(!fd.isNested() || fd.needThis());
- if (pthis.op == TOK.typeid_)
+ if (pthis.op == EXP.typeid_)
{
pthis.error("static variable `%s` cannot be read at compile time", pthis.toChars());
result = CTFEExp.cantexp;
}
assert(pthis);
- if (pthis.op == TOK.null_)
+ if (pthis.op == EXP.null_)
{
assert(pthis.type.toBasetype().ty == Tclass);
e.error("function call through null class reference `%s`", pthis.toChars());
return;
}
- assert(pthis.op == TOK.structLiteral || pthis.op == TOK.classReference || pthis.op == TOK.type);
+ assert(pthis.op == EXP.structLiteral || pthis.op == EXP.classReference || pthis.op == EXP.type);
if (fd.isVirtual() && !e.directcall)
{
}
result = interpretFunction(pue, fd, istate, e.arguments, pthis);
- if (result.op == TOK.voidExpression)
+ if (result.op == EXP.voidExpression)
return;
if (!exceptionOrCantInterpret(result))
{
// If it creates a variable, and there's no context for
// the variable to be created in, we need to create one now.
InterState istateComma;
- if (!istate && firstComma(e.e1).op == TOK.declaration)
+ if (!istate && firstComma(e.e1).op == EXP.declaration)
{
ctfeGlobals.stack.startFrame(null);
istate = &istateComma;
// If the comma returns a temporary variable, it needs to be an lvalue
// (this is particularly important for struct constructors)
- if (e.e1.op == TOK.declaration &&
- e.e2.op == TOK.variable &&
+ if (e.e1.op == EXP.declaration &&
+ e.e2.op == EXP.variable &&
e.e1.isDeclarationExp().declaration == e.e2.isVarExp().var &&
e.e2.isVarExp().var.storage_class & STC.ctfe)
{
newval = interpretRegion(newval, istate);
if (exceptionOrCant(newval))
return endTempStackFrame();
- if (newval.op != TOK.voidExpression)
+ if (newval.op != EXP.voidExpression)
{
// v isn't necessarily null.
setValueWithoutChecking(v, copyLiteral(newval).copy());
if (isPointer(e.econd.type))
{
- if (econd.op != TOK.null_)
+ if (econd.op != EXP.null_)
{
econd = IntegerExp.createBool(true);
}
result = interpret(pue, e.e1, istate, goal);
incUsageCtfe(istate, e.e1.loc);
}
- else if (econd.isBool(false))
+ else if (econd.toBool().hasValue(false))
{
result = interpret(pue, e.e2, istate, goal);
incUsageCtfe(istate, e.e2.loc);
assert(e1);
if (exceptionOrCant(e1))
return;
- if (e1.op != TOK.string_ && e1.op != TOK.arrayLiteral && e1.op != TOK.slice && e1.op != TOK.null_)
+ if (e1.op != EXP.string_ && e1.op != EXP.arrayLiteral && e1.op != EXP.slice && e1.op != EXP.null_)
{
e.error("`%s` cannot be evaluated at compile time", e.toChars());
result = CTFEExp.cantexp;
{
if (auto ale = e.e1.isArrayLiteralExp())
return ale; // it's already an array literal
- if (e.e1.op == TOK.int64 || e.e1.op == TOK.float64)
+ if (e.e1.op == EXP.int64 || e.e1.op == EXP.float64)
{
// Convert literal __vector(int) -> __vector([array])
auto elements = new Expressions(e.dim);
assert(e1);
if (exceptionOrCant(e1))
return;
- if (e1.op != TOK.arrayLiteral && e1.op != TOK.int64 && e1.op != TOK.float64)
+ if (e1.op != EXP.arrayLiteral && e1.op != EXP.int64 && e1.op != EXP.float64)
{
e.error("`%s` cannot be evaluated at compile time", e.toChars());
result = CTFEExp.cantexp;
if (auto ve = e1.isVectorExp())
{
result = interpretVectorToArray(pue, ve);
- if (result.op != TOK.vector)
+ if (result.op != EXP.vector)
return;
}
e.error("`%s` cannot be evaluated at compile time", e.toChars());
dinteger_t ofs;
Expression agg = getAggregateFromPointer(e1, &ofs);
- if (agg.op == TOK.null_)
+ if (agg.op == EXP.null_)
{
e.error("cannot index through null pointer `%s`", e.e1.toChars());
return false;
}
- if (agg.op == TOK.int64)
+ if (agg.op == EXP.int64)
{
e.error("cannot index through invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
return false;
}
// Pointer to a non-array variable
- if (agg.op == TOK.symbolOffset)
+ 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());
return false;
}
- if (agg.op == TOK.arrayLiteral || agg.op == TOK.string_)
+ if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
{
dinteger_t len = resolveArrayLength(agg);
if (ofs + indx >= len)
Expression e1 = interpretRegion(e.e1, istate);
if (exceptionOrCantInterpret(e1))
return false;
- if (e1.op == TOK.null_)
+ if (e1.op == EXP.null_)
{
e.error("cannot index null array `%s`", e.e1.toChars());
return false;
// Set the $ variable, and find the array literal to modify
dinteger_t len;
- if (e1.op == TOK.variable && e1.type.toBasetype().ty == Tsarray)
+ if (e1.op == EXP.variable && e1.type.toBasetype().ty == Tsarray)
len = e1.type.toBasetype().isTypeSArray().dim.toInteger();
else
{
- if (e1.op != TOK.arrayLiteral && e1.op != TOK.string_ && e1.op != TOK.slice && e1.op != TOK.vector)
+ if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.slice && e1.op != EXP.vector)
{
e.error("cannot determine length of `%s` at compile time", e.e1.toChars());
return false;
ctfeGlobals.stack.pop(e.lengthVar); // $ is defined only inside []
if (exceptionOrCantInterpret(e2))
return false;
- if (e2.op != TOK.int64)
+ if (e2.op != EXP.int64)
{
e.error("CTFE internal error: non-integral index `[%s]`", e.e2.toChars());
return false;
result = CTFEExp.cantexp;
return;
}
- if (agg.op == TOK.arrayLiteral || agg.op == TOK.string_)
+ if (agg.op == EXP.arrayLiteral || agg.op == EXP.string_)
{
if (goal == CTFEGoal.LValue)
{
Expression e1 = interpretRegion(e.e1, istate);
if (exceptionOrCant(e1))
return;
- if (e1.op == TOK.null_)
+ if (e1.op == EXP.null_)
{
if (goal == CTFEGoal.LValue && e1.type.ty == Taarray && e.modifiable)
{
return;
}
- assert(e1.op == TOK.assocArrayLiteral);
+ assert(e1.op == EXP.assocArrayLiteral);
UnionExp e2tmp = void;
e2 = resolveSlice(e2, &e2tmp);
result = findKeyInAA(e.loc, cast(AssocArrayLiteralExp)e1, e2);
result = ctfeIndex(pue, e.loc, e.type, agg, indexToAccess);
if (exceptionOrCant(result))
return;
- if (result.op == TOK.void_)
+ if (result.op == EXP.void_)
{
e.error("`%s` is used before initialized", e.toChars());
errorSupplemental(result.loc, "originally uninitialized here");
Expression e1 = interpretRegion(e.e1, istate);
if (exceptionOrCant(e1))
return;
- if (e1.op == TOK.int64)
+ if (e1.op == EXP.int64)
{
e.error("cannot slice invalid pointer `%s` of value `%s`", e.e1.toChars(), e1.toChars());
result = CTFEExp.cantexp;
Expression agg = getAggregateFromPointer(e1, &ofs);
ilwr += ofs;
iupr += ofs;
- if (agg.op == TOK.null_)
+ if (agg.op == EXP.null_)
{
if (iupr == ilwr)
{
result = CTFEExp.cantexp;
return;
}
- if (agg.op == TOK.symbolOffset)
+ if (agg.op == EXP.symbolOffset)
{
e.error("slicing pointers to static variables is not supported in CTFE");
result = CTFEExp.cantexp;
return;
}
- if (agg.op != TOK.arrayLiteral && agg.op != TOK.string_)
+ if (agg.op != EXP.arrayLiteral && agg.op != EXP.string_)
{
e.error("pointer `%s` cannot be sliced at compile time (it does not point to an array)", e.e1.toChars());
result = CTFEExp.cantexp;
return;
}
- assert(agg.op == TOK.arrayLiteral || agg.op == TOK.string_);
+ assert(agg.op == EXP.arrayLiteral || agg.op == EXP.string_);
dinteger_t len = ArrayLength(Type.tsize_t, agg).exp().toInteger();
//Type *pointee = ((TypePointer *)agg.type)->next;
if (iupr > (len + 1) || iupr < ilwr)
/* Set dollar to the length of the array
*/
uinteger_t dollar;
- if ((e1.op == TOK.variable || e1.op == TOK.dotVariable) && e1.type.toBasetype().ty == Tsarray)
+ if ((e1.op == EXP.variable || e1.op == EXP.dotVariable) && e1.type.toBasetype().ty == Tsarray)
dollar = e1.type.toBasetype().isTypeSArray().dim.toInteger();
else
{
- if (e1.op != TOK.arrayLiteral && e1.op != TOK.string_ && e1.op != TOK.null_ && e1.op != TOK.slice && e1.op != TOK.vector)
+ if (e1.op != EXP.arrayLiteral && e1.op != EXP.string_ && e1.op != EXP.null_ && e1.op != EXP.slice && e1.op != EXP.vector)
{
e.error("cannot determine length of `%s` at compile time", e1.toChars());
result = CTFEExp.cantexp;
uinteger_t ilwr = lwr.toInteger();
uinteger_t iupr = upr.toInteger();
- if (e1.op == TOK.null_)
+ if (e1.op == EXP.null_)
{
if (ilwr == 0 && iupr == 0)
{
result.type = e.type;
return;
}
- if (e1.op == TOK.arrayLiteral || e1.op == TOK.string_)
+ if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
{
if (iupr < ilwr || dollar < iupr)
{
Expression e2 = interpretRegion(e.e2, istate);
if (exceptionOrCant(e2))
return;
- if (e2.op == TOK.null_)
+ if (e2.op == EXP.null_)
{
emplaceExp!(NullExp)(pue, e.loc, e.type);
result = pue.exp();
return;
}
- if (e2.op != TOK.assocArrayLiteral)
+ if (e2.op != EXP.assocArrayLiteral)
{
e.error("`%s` cannot be interpreted at compile time", e.toChars());
result = CTFEExp.cantexp;
* result in [x,y] and then x or y is on the stack.
* But if they are both strings, we can, because it isn't the x~[y] case.
*/
- if (!(e1.op == TOK.string_ && e2.op == TOK.string_))
+ if (!(e1.op == EXP.string_ && e2.op == EXP.string_))
{
if (e1 == ue1.exp())
e1 = ue1.copy();
if (exceptionOrCant(result))
return;
- if (result.op == TOK.null_)
+ if (result.op == EXP.null_)
{
result = CTFEExp.voidexp;
return;
switch (tb.ty)
{
case Tclass:
- if (result.op != TOK.classReference)
+ if (result.op != EXP.classReference)
{
e.error("`delete` on invalid class reference `%s`", result.toChars());
result = CTFEExp.cantexp;
tb = (cast(TypePointer)tb).next.toBasetype();
if (tb.ty == Tstruct)
{
- if (result.op != TOK.address ||
- (cast(AddrExp)result).e1.op != TOK.structLiteral)
+ if (result.op != EXP.address ||
+ (cast(AddrExp)result).e1.op != EXP.structLiteral)
{
e.error("`delete` on invalid struct pointer `%s`", result.toChars());
result = CTFEExp.cantexp;
auto tv = tb.nextOf().baseElemOf();
if (tv.ty == Tstruct)
{
- if (result.op != TOK.arrayLiteral)
+ if (result.op != EXP.arrayLiteral)
{
e.error("`delete` on invalid struct array `%s`", result.toChars());
result = CTFEExp.cantexp;
result = CTFEExp.voidexp;
return;
}
- if (e.to.ty == Tpointer && e1.op != TOK.null_)
+ if (e.to.ty == Tpointer && e1.op != EXP.null_)
{
Type pointee = (cast(TypePointer)e.type).next;
// Implement special cases of normally-unsafe casts
- if (e1.op == TOK.int64)
+ if (e1.op == EXP.int64)
{
// Happens with Windows HANDLEs, for example.
result = paintTypeOntoLiteral(pue, e.to, e1);
if (auto se = e1.isSliceExp())
{
- if (se.e1.op == TOK.null_)
+ if (se.e1.op == EXP.null_)
{
result = paintTypeOntoLiteral(pue, e.type, se.e1);
return;
result = pue.exp();
return;
}
- if (e1.op == TOK.arrayLiteral || e1.op == TOK.string_)
+ if (e1.op == EXP.arrayLiteral || e1.op == EXP.string_)
{
// Create a CTFE pointer &[1,2,3][0] or &"abc"[0]
auto ei = ctfeEmplaceExp!IndexExp(e.loc, e1, ctfeEmplaceExp!IntegerExp(e.loc, 0, Type.tsize_t));
result = pue.exp();
return;
}
- if (e1.op == TOK.index && !(cast(IndexExp)e1).e1.type.equals(e1.type))
+ if (e1.op == EXP.index && !(cast(IndexExp)e1).e1.type.equals(e1.type))
{
// type painting operation
IndexExp ie = cast(IndexExp)e1;
// get the original type. For strings, it's just the type...
Type origType = ie.e1.type.nextOf();
// ..but for arrays of type void*, it's the type of the element
- if (ie.e1.op == TOK.arrayLiteral && ie.e2.op == TOK.int64)
+ if (ie.e1.op == EXP.arrayLiteral && ie.e2.op == EXP.int64)
{
ArrayLiteralExp ale = cast(ArrayLiteralExp)ie.e1;
const indx = cast(size_t)ie.e2.toInteger();
return;
}
- if (castToSarrayPointer && pointee.toBasetype().ty == Tsarray && ae.e1.op == TOK.index)
+ if (castToSarrayPointer && pointee.toBasetype().ty == Tsarray && ae.e1.op == EXP.index)
{
// &val[idx]
dinteger_t dim = (cast(TypeSArray)pointee.toBasetype()).dim.toInteger();
}
}
- if (e1.op == TOK.variable || e1.op == TOK.symbolOffset)
+ if (e1.op == EXP.variable || e1.op == EXP.symbolOffset)
{
// type painting operation
Type origType = (cast(SymbolExp)e1).var.type;
// Check if we have a null pointer (eg, inside a struct)
e1 = interpretRegion(e1, istate);
- if (e1.op != TOK.null_)
+ if (e1.op != EXP.null_)
{
e.error("pointer cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
result = CTFEExp.cantexp;
e1 = interpretRegion(e.e1, istate);
if (exceptionOrCant(e1))
return;
- assert(e1.op == TOK.vector);
+ assert(e1.op == EXP.vector);
e1 = interpretVectorToArray(pue, e1.isVectorExp());
}
- if (e.to.ty == Tarray && e1.op == TOK.slice)
+ if (e.to.ty == Tarray && e1.op == EXP.slice)
{
// Note that the slice may be void[], so when checking for dangerous
// casts, we need to use the original type, which is se.e1.
auto tobt = e.to.toBasetype();
if (tobt.ty == Tbool && e1.type.ty == Tpointer)
{
- emplaceExp!(IntegerExp)(pue, e.loc, e1.op != TOK.null_, e.to);
+ emplaceExp!(IntegerExp)(pue, e.loc, e1.op != EXP.null_, e.to);
result = pue.exp();
return;
}
- else if (tobt.isTypeBasic() && e1.op == TOK.null_)
+ else if (tobt.isTypeBasic() && e1.op == EXP.null_)
{
if (tobt.isintegral())
emplaceExp!(IntegerExp)(pue, e.loc, 0, e.to);
if (isTrueBool(e1))
{
}
- else if (e1.isBool(false))
+ else if (e1.toBool().hasValue(false))
{
if (e.msg)
{
// Constant fold *(&structliteral + offset)
if (auto ae = e.e1.isAddExp())
{
- if (ae.e1.op == TOK.address && ae.e2.op == TOK.int64)
+ if (ae.e1.op == EXP.address && ae.e2.op == EXP.int64)
{
AddrExp ade = cast(AddrExp)ae.e1;
Expression ex = interpretRegion(ade.e1, istate);
if (exceptionOrCant(result))
return;
- if (result.op == TOK.function_)
+ if (result.op == EXP.function_)
return;
if (auto soe = result.isSymOffExp())
{
if (result.isStringExp())
return;
- if (result.op != TOK.address)
+ if (result.op != EXP.address)
{
- if (result.op == TOK.null_)
+ if (result.op == EXP.null_)
e.error("dereference of null pointer `%s`", e.e1.toChars());
else
e.error("dereference of invalid pointer `%s`", result.toChars());
// *(&x) ==> x
result = (cast(AddrExp)result).e1;
- if (result.op == TOK.slice && e.type.toBasetype().ty == Tsarray)
+ if (result.op == EXP.slice && e.type.toBasetype().ty == Tsarray)
{
/* aggr[lwr..upr]
* upr may exceed the upper boundary of aggr, but the check is deferred
return;
}
- if (ex.op == TOK.null_)
+ if (ex.op == EXP.null_)
{
if (ex.type.toBasetype().ty == Tclass)
e.error("class `%s` is `null` and cannot be dereferenced", e.e1.toChars());
StructLiteralExp se;
int i;
- if (ex.op != TOK.structLiteral && ex.op != TOK.classReference && ex.op != TOK.typeid_)
+ if (ex.op != EXP.structLiteral && ex.op != EXP.classReference && ex.op != EXP.typeid_)
{
return notImplementedYet();
}
// We can't use getField, because it makes a copy
- if (ex.op == TOK.classReference)
+ if (ex.op == EXP.classReference)
{
se = (cast(ClassReferenceExp)ex).value;
i = (cast(ClassReferenceExp)ex).findFieldIndexByName(v);
}
- else if (ex.op == TOK.typeid_)
+ else if (ex.op == EXP.typeid_)
{
if (v.ident == Identifier.idPool("name"))
{
Expression index = interpret(e.e2, istate);
if (exceptionOrCant(index))
return;
- if (agg.op == TOK.null_)
+ if (agg.op == EXP.null_)
{
result = CTFEExp.voidexp;
return;
foreach (j, evalue; *valuesx)
{
Expression ekey = (*keysx)[j];
- int eq = ctfeEqual(e.loc, TOK.equal, ekey, index);
+ int eq = ctfeEqual(e.loc, EXP.equal, ekey, index);
if (eq)
++removed;
else if (removed != 0)
// mimicking UnionExp.copy, but with region allocation
switch (uexp.op)
{
- case TOK.cantExpression: return CTFEExp.cantexp;
- case TOK.voidExpression: return CTFEExp.voidexp;
- case TOK.break_: return CTFEExp.breakexp;
- case TOK.continue_: return CTFEExp.continueexp;
- case TOK.goto_: return CTFEExp.gotoexp;
+ case EXP.cantExpression: return CTFEExp.cantexp;
+ case EXP.voidExpression: return CTFEExp.voidexp;
+ case EXP.break_: return CTFEExp.breakexp;
+ case EXP.continue_: return CTFEExp.continueexp;
+ case EXP.goto_: return CTFEExp.gotoexp;
default: break;
}
auto p = ctfeGlobals.region.malloc(uexp.size);
* istate = context
* Returns:
* NULL continue to next statement
- * TOK.cantExpression cannot interpret statement at compile time
+ * EXP.cantExpression cannot interpret statement at compile time
* !NULL expression from return statement, or thrown exception
*/
Expression interpret(UnionExp* pue, Statement s, InterState* istate)
*/
static bool isVoid(const Expression e, bool checkArrayType = false) pure
{
- if (e.op == TOK.void_)
+ if (e.op == EXP.void_)
return true;
static bool isEntirelyVoid(const Expressions* elems)
else
{
e = scrubReturnValue(loc, e);
- if (CTFEExp.isCantExp(e) || e.op == TOK.error)
+ if (CTFEExp.isCantExp(e) || e.op == EXP.error)
return e;
}
}
return null;
}
- if (e.op == TOK.classReference)
+ if (e.op == EXP.classReference)
{
StructLiteralExp sle = (cast(ClassReferenceExp)e).value;
if (auto ex = scrubSE(sle))
return null;
}
- if (e.op == TOK.classReference)
+ if (e.op == EXP.classReference)
{
if (auto ex = scrubSE((cast(ClassReferenceExp)e).value))
return ex;
switch (e.op)
{
- case TOK.classReference:
+ case EXP.classReference:
{
auto cre = e.isClassReferenceExp();
cre.value = copyRegionExp(cre.value).isStructLiteralExp();
break;
}
- case TOK.structLiteral:
+ case EXP.structLiteral:
{
auto sle = e.isStructLiteralExp();
return slec;
}
- case TOK.arrayLiteral:
+ case EXP.arrayLiteral:
{
auto ale = e.isArrayLiteralExp();
ale.basis = copyRegionExp(ale.basis);
break;
}
- case TOK.assocArrayLiteral:
+ case EXP.assocArrayLiteral:
copyArray(e.isAssocArrayLiteralExp().keys);
copyArray(e.isAssocArrayLiteralExp().values);
break;
- case TOK.slice:
+ case EXP.slice:
{
auto se = e.isSliceExp();
se.e1 = copyRegionExp(se.e1);
break;
}
- case TOK.tuple:
+ case EXP.tuple:
{
auto te = e.isTupleExp();
te.e0 = copyRegionExp(te.e0);
break;
}
- case TOK.address:
- case TOK.delegate_:
- case TOK.vector:
- case TOK.dotVariable:
+ case EXP.address:
+ case EXP.delegate_:
+ case EXP.vector:
+ case EXP.dotVariable:
{
UnaExp ue = cast(UnaExp)e;
ue.e1 = copyRegionExp(ue.e1);
break;
}
- case TOK.index:
+ case EXP.index:
{
BinExp be = cast(BinExp)e;
be.e1 = copyRegionExp(be.e1);
break;
}
- case TOK.this_:
- case TOK.super_:
- case TOK.variable:
- case TOK.type:
- case TOK.function_:
- case TOK.typeid_:
- case TOK.string_:
- case TOK.int64:
- case TOK.error:
- case TOK.float64:
- case TOK.complex80:
- case TOK.null_:
- case TOK.void_:
- case TOK.symbolOffset:
- case TOK.char_:
+ case EXP.this_:
+ case EXP.super_:
+ case EXP.variable:
+ case EXP.type:
+ case EXP.function_:
+ case EXP.typeid_:
+ case EXP.string_:
+ case EXP.int64:
+ case EXP.error:
+ case EXP.float64:
+ case EXP.complex80:
+ case EXP.null_:
+ case EXP.void_:
+ case EXP.symbolOffset:
+ case EXP.char_:
break;
- case TOK.cantExpression:
- case TOK.voidExpression:
- case TOK.showCtfeContext:
+ case EXP.cantExpression:
+ case EXP.voidExpression:
+ case EXP.showCtfeContext:
return e;
default:
- printf("e: %s, %s\n", Token.toChars(e.op), e.toChars());
+ printf("e: %s, %s\n", EXPtoString(e.op).ptr, e.toChars());
assert(0);
}
if (auto aae = earg.isAssocArrayLiteralExp())
len = aae.keys.dim;
else
- assert(earg.op == TOK.null_);
+ assert(earg.op == EXP.null_);
emplaceExp!(IntegerExp)(pue, earg.loc, len, Type.tsize_t);
return pue.exp();
}
earg = interpret(pue, earg, istate);
if (exceptionOrCantInterpret(earg))
return earg;
- if (earg.op == TOK.null_)
+ if (earg.op == EXP.null_)
{
emplaceExp!(NullExp)(pue, earg.loc, earg.type);
return pue.exp();
}
- if (earg.op != TOK.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
+ if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
return null;
AssocArrayLiteralExp aae = earg.isAssocArrayLiteralExp();
auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.keys);
earg = interpret(pue, earg, istate);
if (exceptionOrCantInterpret(earg))
return earg;
- if (earg.op == TOK.null_)
+ if (earg.op == EXP.null_)
{
emplaceExp!(NullExp)(pue, earg.loc, earg.type);
return pue.exp();
}
- if (earg.op != TOK.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
+ if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
return null;
auto aae = earg.isAssocArrayLiteralExp();
auto ae = ctfeEmplaceExp!ArrayLiteralExp(aae.loc, returnType, aae.values);
earg = interpret(pue, earg, istate);
if (exceptionOrCantInterpret(earg))
return earg;
- if (earg.op == TOK.null_)
+ if (earg.op == EXP.null_)
{
emplaceExp!(NullExp)(pue, earg.loc, earg.type);
return pue.exp();
}
- if (earg.op != TOK.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
+ if (earg.op != EXP.assocArrayLiteral && earg.type.toBasetype().ty != Taarray)
return null;
auto aae = copyLiteral(earg).copy().isAssocArrayLiteralExp();
for (size_t i = 0; i < aae.keys.dim; i++)
aa = interpret(aa, istate);
if (exceptionOrCantInterpret(aa))
return aa;
- if (aa.op != TOK.assocArrayLiteral)
+ if (aa.op != EXP.assocArrayLiteral)
{
emplaceExp!(IntegerExp)(pue, deleg.loc, 0, Type.tsize_t);
return pue.exp();
}
if (pthis && !fd.fbody && fd.isCtorDeclaration() && fd.parent && fd.parent.parent && fd.parent.parent.ident == Id.object)
{
- if (pthis.op == TOK.classReference && fd.parent.ident == Id.Throwable)
+ if (pthis.op == EXP.classReference && fd.parent.ident == Id.Throwable)
{
// At present, the constructors just copy their arguments into the struct.
// But we might need some magic if stack tracing gets added to druntime.
}
return null;
}
- if (e.op == TOK.structLiteral)
+ if (e.op == EXP.structLiteral)
{
// e.__postblit()
UnionExp ue = void;
foreach_reverse (elem; *ale.elements)
e = evaluateDtor(istate, elem);
}
- else if (e.op == TOK.structLiteral)
+ else if (e.op == EXP.structLiteral)
{
// e.__dtor()
e = interpretFunction(&ue, sd.dtor, istate, null, e);
goto Lsa;
}
buf.writeByte('V');
- if (ea.op == TOK.tuple)
+ if (ea.op == EXP.tuple)
{
ea.error("tuple is not a valid template value argument");
continue;
// Now that we know it is not an alias, we MUST obtain a value
uint olderr = global.errors;
ea = ea.ctfeInterpret();
- if (ea.op == TOK.error || olderr != global.errors)
+ if (ea.op == EXP.error || olderr != global.errors)
continue;
/* Use type mangling that matches what it would be for a function parameter
{
switch (exp.op)
{
- case TOK.int64:
+ case EXP.int64:
return exp.toInteger() == 0;
- case TOK.null_:
- case TOK.false_:
+ case EXP.null_:
+ case EXP.false_:
return true;
- case TOK.structLiteral:
+ case EXP.structLiteral:
{
auto sle = cast(StructLiteralExp) exp;
foreach (i; 0 .. sle.sd.fields.dim)
return true;
}
- case TOK.arrayLiteral:
+ case EXP.arrayLiteral:
{
auto ale = cast(ArrayLiteralExp)exp;
return true;
}
- case TOK.string_:
+ case EXP.string_:
{
StringExp se = cast(StringExp)exp;
return true;
}
- case TOK.vector:
+ case EXP.vector:
{
auto ve = cast(VectorExp) exp;
return _isZeroInit(ve.e1);
}
- case TOK.float64:
- case TOK.complex80:
+ case EXP.float64:
+ case EXP.complex80:
{
import dmd.root.ctfloat : CTFloat;
return (exp.toReal() is CTFloat.zero) &&
Expression eold = null;
for (Expression e = withstate.exp; e != eold; e = resolveAliasThis(_scope, e))
{
- if (e.op == TOK.scope_)
+ if (e.op == EXP.scope_)
{
s = (cast(ScopeExp)e).sds;
}
- else if (e.op == TOK.type)
+ else if (e.op == EXP.type)
{
s = e.type.toDsymbol(null);
}
extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
{
// either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration.
- // Discriminated using DYNCAST and, for expressions, also TOK
+ // Discriminated using DYNCAST and, for expressions, also EXP
private RootObject arrayContent;
Scope* sc;
extern (D) this(Scope* sc, Expression exp)
{
super(exp.loc, null);
- assert(exp.op == TOK.index || exp.op == TOK.slice || exp.op == TOK.array);
+ assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array);
this.sc = sc;
this.arrayContent = exp;
}
else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass))
{
// Look for opDollar
- assert(exp.op == TOK.array || exp.op == TOK.slice);
+ assert(exp.op == EXP.array || exp.op == EXP.slice);
AggregateDeclaration ad = isAggregate(t);
assert(ad);
Dsymbol s = ad.search(loc, Id.opDollar);
if (TemplateDeclaration td = s.isTemplateDeclaration())
{
dinteger_t dim = 0;
- if (exp.op == TOK.array)
+ if (exp.op == EXP.array)
{
dim = (cast(ArrayExp)exp).currentDimension;
}
- else if (exp.op == TOK.slice)
+ else if (exp.op == EXP.slice)
{
dim = 0; // slices are currently always one-dimensional
}
* Note that it's impossible to have both template & function opDollar,
* because both take no arguments.
*/
- if (exp.op == TOK.array && (cast(ArrayExp)exp).arguments.dim != 1)
+ if (exp.op == EXP.array && (cast(ArrayExp)exp).arguments.dim != 1)
{
exp.error("`%s` only defines opDollar for one dimension", ad.toChars());
return null;
e = e.ctfeInterpret();
exp = e; // could be re-evaluated if exps are assigned to more than one AlignDeclaration by CParser.applySpecifier(),
// e.g. `_Alignas(8) int a, b;`
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
errors = true;
else
{
}
Lnomatch:
- if (ie && ie.op == TOK.tuple)
+ if (ie && ie.op == EXP.tuple)
{
auto te = ie.isTupleExp();
size_t tedim = te.exps.dim;
storage_class |= arg.storageClass;
auto v = new VarDeclaration(dsym.loc, arg.type, id, ti, storage_class);
//printf("declaring field %s of type %s\n", v.toChars(), v.type.toChars());
+ v.overlapped = dsym.overlapped;
+
v.dsymbolSemantic(sc);
if (sc.scopesym)
if ((!dsym._init || dsym._init.isVoidInitializer) && !fd)
{
// If not mutable, initializable by constructor only
- dsym.storage_class |= STC.ctorinit;
+ dsym.setInCtorOnly = true;
}
if (dsym._init)
- dsym.storage_class |= STC.init; // remember we had an explicit initializer
+ { } // remember we had an explicit initializer
else if (dsym.storage_class & STC.manifest)
dsym.error("manifest constants must have initializers");
exp = exp.expressionSemantic(sc);
dsym.canassign--;
exp = exp.optimize(WANTvalue);
- if (exp.op == TOK.error)
+ if (exp.op == EXP.error)
{
dsym._init = new ErrorInitializer();
ei = null;
if (ei && dsym.isScope())
{
Expression ex = ei.exp.lastComma();
- if (ex.op == TOK.blit || ex.op == TOK.construct)
+ if (ex.op == EXP.blit || ex.op == EXP.construct)
ex = (cast(AssignExp)ex).e2;
if (auto ne = ex.isNewExp())
{
// Don't run CTFE for the temporary variables inside typeof
dsym._init = dsym._init.initializerSemantic(sc, dsym.type, sc.intypeof == 1 ? INITnointerpret : INITinterpret);
const init_err = dsym._init.isExpInitializer();
- if (init_err && init_err.exp.op == TOK.showCtfeContext)
+ if (init_err && init_err.exp.op == EXP.showCtfeContext)
{
errorSupplemental(dsym.loc, "compile time context created here");
}
dsym.inuse++;
// Bug 20549. Don't try this on modules or packages, syntaxCopy
// could crash (inf. recursion) on a mod/pkg referencing itself
- if (ei && (ei.exp.op != TOK.scope_ ? true : !ei.exp.isScopeExp().sds.isPackage()))
+ if (ei && (ei.exp.op != EXP.scope_ ? true : !ei.exp.isScopeExp().sds.isPackage()))
{
if (ei.exp.type)
{
width.error("bit-field `%s` has zero width", dsym.toChars());
dsym.errors = true;
}
- const max_width = dsym.type.size() * 8;
+ const sz = dsym.type.size();
+ if (sz == SIZE_INVALID)
+ dsym.errors = true;
+ const max_width = sz * 8;
if (uwidth > max_width)
{
width.error("width `%lld` of bit-field `%s` does not fit in type `%s`", cast(long)uwidth, dsym.toChars(), dsym.type.toChars());
override void visit(AnonDeclaration scd)
{
- //printf("\tAnonDeclaration::semantic %s %p\n", isunion ? "union" : "struct", this);
+ //printf("\tAnonDeclaration::semantic isunion:%d ptr:%p\n", scd.isunion, scd);
assert(sc.parent);
auto p = sc.parent.pastMixin();
auto ad = p.isAggregateDeclaration();
for (size_t i = 0; i < scd.decl.dim; i++)
{
Dsymbol s = (*scd.decl)[i];
+ if (auto var = s.isVarDeclaration)
+ {
+ if (scd.isunion)
+ var.overlapped = true;
+ }
s.dsymbolSemantic(sc);
}
sc = sc.pop();
e = resolveProperties(sc, e);
sc = sc.endCTFE();
e = ctfeInterpretForPragmaMsg(e);
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
{
errorSupplemental(pd.loc, "while evaluating `pragma(msg, %s)`", (*pd.args)[i].toChars());
return;
e = resolveProperties(sc, e);
e = e.integralPromotions(sc);
e = e.ctfeInterpret();
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
return errorReturn(em);
auto ie = e.isIntegerExp();
if (!ie)
e = e.expressionSemantic(sc);
e = resolveProperties(sc, e);
e = e.ctfeInterpret();
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
return errorReturn();
if (first && !em.ed.memtype && !em.ed.isAnonymous())
{
ev = ev.implicitCastTo(sc, em.ed.memtype);
ev = ev.ctfeInterpret();
ev = ev.castTo(sc, em.ed.type);
- if (ev.op == TOK.error)
+ if (ev.op == EXP.error)
em.ed.errors = true;
enm.value = ev;
});
// Set value to (eprev + 1).
// But first check that (eprev != emax)
assert(eprev);
- Expression e = new EqualExp(TOK.equal, em.loc, eprev, emax);
+ Expression e = new EqualExp(EXP.equal, em.loc, eprev, emax);
e = e.expressionSemantic(sc);
e = e.ctfeInterpret();
if (e.toInteger())
e = e.ctfeInterpret();
// save origValue (without cast) for better json output
- if (e.op != TOK.error) // avoid duplicate diagnostics
+ if (e.op != EXP.error) // avoid duplicate diagnostics
{
assert(emprev.origValue);
em.origValue = new AddExp(em.loc, emprev.origValue, IntegerExp.literal!1);
em.origValue = em.origValue.ctfeInterpret();
}
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
return errorReturn();
if (e.type.isfloating())
{
// Check that e != eprev (not always true for floats)
- Expression etest = new EqualExp(TOK.equal, em.loc, e, eprev);
+ Expression etest = new EqualExp(EXP.equal, em.loc, e, eprev);
etest = etest.expressionSemantic(sc);
etest = etest.ctfeInterpret();
if (etest.toInteger())
Expression e = new IdentifierExp(Loc.initial, v.ident);
e = new AddAssignExp(Loc.initial, e, IntegerExp.literal!1);
- e = new EqualExp(TOK.notEqual, Loc.initial, e, IntegerExp.literal!1);
+ e = new EqualExp(EXP.notEqual, Loc.initial, e, IntegerExp.literal!1);
s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial);
sa.push(s);
Expression e = new IdentifierExp(Loc.initial, v.ident);
e = new AddAssignExp(Loc.initial, e, IntegerExp.literal!(-1));
- e = new EqualExp(TOK.notEqual, Loc.initial, e, IntegerExp.literal!0);
+ e = new EqualExp(EXP.notEqual, Loc.initial, e, IntegerExp.literal!0);
s = new IfStatement(Loc.initial, null, e, new ReturnStatement(Loc.initial, null), null, Loc.initial);
sa.push(s);
if (cldec.errors)
cldec.type = Type.terror;
+ if (cldec.semanticRun == PASS.init)
+ cldec.type = cldec.type.addSTC(sc.stc | cldec.storage_class);
cldec.type = cldec.type.typeSemantic(cldec.loc, sc);
if (auto tc = cldec.type.isTypeClass())
if (tc.sym != cldec)
s = getDsymbol(e);
if (!s)
{
- if (e.op != TOK.error)
+ if (e.op != EXP.error)
ds.error("cannot alias an expression `%s`", e.toChars());
return errorRet();
}
s = getDsymbol(e);
if (!s)
{
- if (e.op != TOK.error)
+ if (e.op != EXP.error)
ds.error("cannot alias an expression `%s`", e.toChars());
return errorRet();
}
if (const t = isType(o))
return (t.ty == Terror);
if (const e = isExpression(o))
- return (e.op == TOK.error || !e.type || e.type.ty == Terror);
+ return (e.op == EXP.error || !e.type || e.type.ty == Terror);
if (const v = isTuple(o))
return arrayObjectIsError(&v.objects);
const s = isDsymbol(o);
static if (log)
{
- printf("\te1 = %s '%s' %s\n", e1.type ? e1.type.toChars() : "null", Token.toChars(e1.op), e1.toChars());
- printf("\te2 = %s '%s' %s\n", e2.type ? e2.type.toChars() : "null", Token.toChars(e2.op), e2.toChars());
+ printf("\te1 = %s '%s' %s\n", e1.type ? e1.type.toChars() : "null", EXPtoString(e1.op).ptr, e1.toChars());
+ printf("\te2 = %s '%s' %s\n", e2.type ? e2.type.toChars() : "null", EXPtoString(e2.op).ptr, e2.toChars());
}
// two expressions can be equal although they do not have the same
switch (e.op)
{
- case TOK.int64:
+ case EXP.int64:
return cast(size_t) e.isIntegerExp().getInteger();
- case TOK.float64:
+ case EXP.float64:
return CTFloat.hash(e.isRealExp().value);
- case TOK.complex80:
+ case EXP.complex80:
auto ce = e.isComplexExp();
return mixHash(CTFloat.hash(ce.toReal), CTFloat.hash(ce.toImaginary));
- case TOK.identifier:
+ case EXP.identifier:
return cast(size_t)cast(void*) e.isIdentifierExp().ident;
- case TOK.null_:
+ case EXP.null_:
return cast(size_t)cast(void*) e.isNullExp().type;
- case TOK.string_:
+ case EXP.string_:
return calcHash(e.isStringExp.peekData());
- case TOK.tuple:
+ case EXP.tuple:
{
auto te = e.isTupleExp();
size_t hash = 0;
return hash;
}
- case TOK.arrayLiteral:
+ case EXP.arrayLiteral:
{
auto ae = e.isArrayLiteralExp();
size_t hash;
return hash;
}
- case TOK.assocArrayLiteral:
+ case EXP.assocArrayLiteral:
{
auto ae = e.isAssocArrayLiteralExp();
size_t hash;
return hash;
}
- case TOK.structLiteral:
+ case EXP.structLiteral:
{
auto se = e.isStructLiteralExp();
size_t hash;
return hash;
}
- case TOK.variable:
+ case EXP.variable:
return cast(size_t)cast(void*) e.isVarExp().var;
- case TOK.function_:
+ case EXP.function_:
return cast(size_t)cast(void*) e.isFuncExp().fd;
default:
farg = (*fargs)[argi + i];
// Check invalid arguments to detect errors early.
- if (farg.op == TOK.error || farg.type.ty == Terror)
+ if (farg.op == EXP.error || farg.type.ty == Terror)
return nomatch();
if (!(fparam.storageClass & STC.lazy_) && farg.type.ty == Tvoid)
}
{
// Check invalid arguments to detect errors early.
- if (farg.op == TOK.error || farg.type.ty == Terror)
+ if (farg.op == EXP.error || farg.type.ty == Terror)
return nomatch();
Type att = null;
}
Type argtype = farg.type;
- if (!(fparam.storageClass & STC.lazy_) && argtype.ty == Tvoid && farg.op != TOK.function_)
+ if (!(fparam.storageClass & STC.lazy_) && argtype.ty == Tvoid && farg.op != EXP.function_)
return nomatch();
// https://issues.dlang.org/show_bug.cgi?id=12876
Type taai;
if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.dim == 0))
{
- if (farg.op == TOK.string_)
+ if (farg.op == EXP.string_)
{
StringExp se = cast(StringExp)farg;
argtype = se.type.nextOf().sarrayOf(se.len);
}
- else if (farg.op == TOK.arrayLiteral)
+ else if (farg.op == EXP.arrayLiteral)
{
ArrayLiteralExp ae = cast(ArrayLiteralExp)farg;
argtype = ae.type.nextOf().sarrayOf(ae.elements.dim);
}
- else if (farg.op == TOK.slice)
+ else if (farg.op == EXP.slice)
{
SliceExp se = cast(SliceExp)farg;
if (Type tsa = toStaticArrayType(se))
{
if (!farg.isLvalue())
{
- if ((farg.op == TOK.string_ || farg.op == TOK.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray))
+ if ((farg.op == EXP.string_ || farg.op == EXP.slice) && (prmtype.ty == Tsarray || prmtype.ty == Taarray))
{
// Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
}
Declaration d;
VarDeclaration v = null;
- if (ea && ea.op == TOK.type)
+ if (ea && ea.op == EXP.type)
ta = ea.type;
- else if (ea && ea.op == TOK.scope_)
+ else if (ea && ea.op == EXP.scope_)
sa = (cast(ScopeExp)ea).sds;
- else if (ea && (ea.op == TOK.this_ || ea.op == TOK.super_))
+ else if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_))
sa = (cast(ThisExp)ea).var;
- else if (ea && ea.op == TOK.function_)
+ else if (ea && ea.op == EXP.function_)
{
if ((cast(FuncExp)ea).td)
sa = (cast(FuncExp)ea).td;
if (tparam.ty == Tsarray)
{
TypeSArray tsa = cast(TypeSArray)tparam;
- if (tsa.dim.op == TOK.variable && (cast(VarExp)tsa.dim).var.storage_class & STC.templateparameter)
+ if (tsa.dim.op == EXP.variable && (cast(VarExp)tsa.dim).var.storage_class & STC.templateparameter)
{
Identifier id = (cast(VarExp)tsa.dim).var.ident;
i = templateIdentifierLookup(id, parameters);
/* If it is one of the template parameters for this template,
* we should not attempt to interpret it. It already has a value.
*/
- if (e2.op == TOK.variable && ((cast(VarExp)e2).var.storage_class & STC.templateparameter))
+ if (e2.op == EXP.variable && ((cast(VarExp)e2).var.storage_class & STC.templateparameter))
{
/*
* (T:Number!(e2), int e2)
// Reset inference target for the later re-semantic
e.fd.treq = null;
- if (ex.op == TOK.error)
+ if (ex.op == EXP.error)
return;
- if (ex.op != TOK.function_)
+ if (ex.op != EXP.function_)
return;
visit(ex.type);
return;
else if (ea)
{
Lexpr:
- //printf("+[%d] ea = %s %s\n", j, Token.toChars(ea.op), ea.toChars());
+ //printf("+[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
if (flags & 1) // only used by __traits
{
ea = ea.expressionSemantic(sc);
// must not interpret the args, excepting template parameters
- if (ea.op != TOK.variable || ((cast(VarExp)ea).var.storage_class & STC.templateparameter))
+ if (ea.op != EXP.variable || ((cast(VarExp)ea).var.storage_class & STC.templateparameter))
{
ea = ea.optimize(WANTvalue);
}
ea = ea.expressionSemantic(sc);
sc = sc.endCTFE();
- if (ea.op == TOK.variable)
+ if (ea.op == EXP.variable)
{
/* If the parameter is a function that is not called
* explicitly, i.e. `foo!func` as opposed to `foo!func()`,
ea = ErrorExp.get();
}
}
- //printf("-[%d] ea = %s %s\n", j, Token.toChars(ea.op), ea.toChars());
- if (ea.op == TOK.tuple)
+ //printf("-[%d] ea = %s %s\n", j, EXPtoString(ea.op).ptr, ea.toChars());
+ if (ea.op == EXP.tuple)
{
// Expand tuple
TupleExp te = cast(TupleExp)ea;
j--;
continue;
}
- if (ea.op == TOK.error)
+ if (ea.op == EXP.error)
{
err = true;
continue;
}
(*tiargs)[j] = ea;
- if (ea.op == TOK.type)
+ if (ea.op == EXP.type)
{
ta = ea.type;
goto Ltype;
}
- if (ea.op == TOK.scope_)
+ if (ea.op == EXP.scope_)
{
sa = (cast(ScopeExp)ea).sds;
goto Ldsym;
}
- if (ea.op == TOK.function_)
+ if (ea.op == EXP.function_)
{
FuncExp fe = cast(FuncExp)ea;
/* A function literal, that is passed to template and
//goto Ldsym;
}
}
- if (ea.op == TOK.dotVariable && !(flags & 1))
+ if (ea.op == EXP.dotVariable && !(flags & 1))
{
// translate expression to dsymbol.
sa = (cast(DotVarExp)ea).var;
goto Ldsym;
}
- if (ea.op == TOK.template_)
+ if (ea.op == EXP.template_)
{
sa = (cast(TemplateExp)ea).td;
goto Ldsym;
}
- if (ea.op == TOK.dotTemplateDeclaration && !(flags & 1))
+ if (ea.op == EXP.dotTemplateDeclaration && !(flags & 1))
{
// translate expression to dsymbol.
sa = (cast(DotTemplateExp)ea).td;
goto Ldsym;
}
- if (ea.op == TOK.dot)
+ if (ea.op == EXP.dot)
{
if (auto se = (cast(DotExp)ea).e2.isScopeExp())
{
Tuple va = isTuple(o);
if (ea)
{
- if (ea.op == TOK.variable)
+ if (ea.op == EXP.variable)
{
sa = (cast(VarExp)ea).var;
goto Lsa;
}
- if (ea.op == TOK.this_)
+ if (ea.op == EXP.this_)
{
sa = (cast(ThisExp)ea).var;
goto Lsa;
}
- if (ea.op == TOK.function_)
+ if (ea.op == EXP.function_)
{
if ((cast(FuncExp)ea).td)
sa = (cast(FuncExp)ea).td;
goto Lsa;
}
// Emulate Expression.toMangleBuffer call that had exist in TemplateInstance.genIdent.
- if (ea.op != TOK.int64 && ea.op != TOK.float64 && ea.op != TOK.complex80 && ea.op != TOK.null_ && ea.op != TOK.string_ && ea.op != TOK.arrayLiteral && ea.op != TOK.assocArrayLiteral && ea.op != TOK.structLiteral)
+ if (ea.op != EXP.int64 && ea.op != EXP.float64 && ea.op != EXP.complex80 && ea.op != EXP.null_ && ea.op != EXP.string_ && ea.op != EXP.arrayLiteral && ea.op != EXP.assocArrayLiteral && ea.op != EXP.structLiteral)
{
ea.error("expression `%s` is not a valid template value argument", ea.toChars());
errors = true;
goto L1; // dparent is most nested
}
}
+ //https://issues.dlang.org/show_bug.cgi?id=17870
+ if (dparent.isClassDeclaration() && enclosing.isClassDeclaration())
+ {
+ auto pc = dparent.isClassDeclaration();
+ auto ec = enclosing.isClassDeclaration();
+ if (pc.isBaseOf(ec, null))
+ goto L1;
+ else if (ec.isBaseOf(pc, null))
+ {
+ enclosing = dparent;
+ goto L1;
+ }
+ }
error("`%s` is nested in both `%s` and `%s`", toChars(), enclosing.toChars(), dparent.toChars());
errors = true;
}
bool definitelyValueParameter(Expression e)
{
// None of these can be value parameters
- if (e.op == TOK.tuple || e.op == TOK.scope_ ||
- e.op == TOK.type || e.op == TOK.dotType ||
- e.op == TOK.template_ || e.op == TOK.dotTemplateDeclaration ||
- e.op == TOK.function_ || e.op == TOK.error ||
- e.op == TOK.this_ || e.op == TOK.super_ ||
- e.op == TOK.dot)
+ if (e.op == EXP.tuple || e.op == EXP.scope_ ||
+ e.op == EXP.type || e.op == EXP.dotType ||
+ e.op == EXP.template_ || e.op == EXP.dotTemplateDeclaration ||
+ e.op == EXP.function_ || e.op == EXP.error ||
+ e.op == EXP.this_ || e.op == EXP.super_ ||
+ e.op == EXP.dot)
return false;
- if (e.op != TOK.dotVariable)
+ if (e.op != EXP.dotVariable)
return true;
/* Template instantiations involving a DotVar expression are difficult.
if (f)
return false;
- while (e.op == TOK.dotVariable)
+ while (e.op == EXP.dotVariable)
{
e = (cast(DotVarExp)e).e1;
}
// this.x.y and super.x.y couldn't possibly be valid values.
- if (e.op == TOK.this_ || e.op == TOK.super_)
+ if (e.op == EXP.this_ || e.op == EXP.super_)
return false;
// e.type.x could be an alias
- if (e.op == TOK.dotType)
+ if (e.op == EXP.dotType)
return false;
// var.x.y is the only other possible form of alias
- if (e.op != TOK.variable)
+ if (e.op != EXP.variable)
return true;
VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
uint olderrors = global.startGagging();
ei = resolveProperties(sc, ei);
ei = ei.ctfeInterpret();
- if (global.endGagging(olderrors) || ei.op == TOK.error)
+ if (global.endGagging(olderrors) || ei.op == EXP.error)
return matchArgNoMatch();
/* https://issues.dlang.org/show_bug.cgi?id=14520
m = MATCH.convert;
}
- if (ei && ei.op == TOK.variable)
+ if (ei && ei.op == EXP.variable)
{
// Resolve const variables that we had skipped earlier
ei = ei.ctfeInterpret();
Type ta = isType(oarg);
RootObject sa = ta && !ta.deco ? null : getDsymbol(oarg);
Expression ea = isExpression(oarg);
- if (ea && (ea.op == TOK.this_ || ea.op == TOK.super_))
+ if (ea && (ea.op == EXP.this_ || ea.op == EXP.super_))
sa = (cast(ThisExp)ea).var;
- else if (ea && ea.op == TOK.scope_)
+ else if (ea && ea.op == EXP.scope_)
sa = (cast(ScopeExp)ea).sds;
if (sa)
{
import dmd.dsymbol;
import dmd.errors;
import dmd.globals;
+import dmd.hdrgen;
import dmd.identifier;
import dmd.root.filename;
import dmd.visitor;
{
debug (Debug_DtoH) mixin(traceVisit!e);
- buf.writestring(tokToString(e.op));
+ buf.writestring(expToString(e.op));
e.e1.accept(this);
}
e.e1.accept(this);
buf.writeByte(' ');
- buf.writestring(tokToString(e.op));
+ buf.writestring(expToString(e.op));
buf.writeByte(' ');
e.e2.accept(this);
}
/// Translates operator `op` into the C++ representation
- private extern(D) static string tokToString(const TOK op)
+ private extern(D) static string expToString(const EXP op)
{
- switch (op) with (TOK)
+ switch (op) with (EXP)
{
case identity: return "==";
case notIdentity: return "!=";
default:
- return Token.toString(op);
+ return EXPtoString(op);
}
}
{
enum log = false;
if (log) printf("checkAssignEscape(e: %s)\n", e.toChars());
- if (e.op != TOK.assign && e.op != TOK.blit && e.op != TOK.construct &&
- e.op != TOK.concatenateAssign && e.op != TOK.concatenateElemAssign && e.op != TOK.concatenateDcharAssign)
+ if (e.op != EXP.assign && e.op != EXP.blit && e.op != EXP.construct &&
+ e.op != EXP.concatenateAssign && e.op != EXP.concatenateElemAssign && e.op != EXP.concatenateDcharAssign)
return false;
auto ae = cast(BinExp)e;
Expression e1 = ae.e1;
VarDeclaration va = expToVariable(e1);
- if (va && e.op == TOK.concatenateElemAssign)
+ if (va && e.op == EXP.concatenateElemAssign)
{
/* https://issues.dlang.org/show_bug.cgi?id=17842
* Draw an equivalence between:
FuncDeclaration fd = sc.func;
- // Try to infer 'scope' for va if in a function not marked @system
- bool inferScope = false;
- if (va && fd && fd.type && fd.type.isTypeFunction())
- inferScope = fd.type.isTypeFunction().trust != TRUST.system;
- //printf("inferScope = %d, %d\n", inferScope, (va.storage_class & STCmaybescope) != 0);
// Determine if va is a parameter that is an indirect reference
const bool vaIsRef = va && va.storage_class & STC.parameter &&
if (va.isScope())
continue;
- if (inferScope && !va.doNotInferScope)
+ if (!va.doNotInferScope)
{
if (log) printf("inferring scope for lvalue %s\n", va.toChars());
va.storage_class |= STC.scope_ | STC.scopeinferred;
if (va && !va.isDataseg() && !va.doNotInferScope)
{
- if (!va.isScope() && inferScope)
+ if (!va.isScope())
{ /* v is scope, and va is not scope, so va needs to
* infer scope
*/
{
if (va && !va.isDataseg() && !va.doNotInferScope)
{
- if (!va.isScope() && inferScope)
+ if (!va.isScope())
{ //printf("inferring scope for %s\n", va.toChars());
va.storage_class |= STC.scope_ | STC.scopeinferred;
}
if (va && !va.isDataseg() && !va.doNotInferScope)
{
- if (!va.isScope() && inferScope)
+ if (!va.isScope())
{ //printf("inferring scope for %s\n", va.toChars());
va.storage_class |= STC.scope_ | STC.scopeinferred;
}
va.storage_class |= STC.return_ | STC.returninferred;
continue;
}
- if (e1.op == TOK.structLiteral)
+ if (e1.op == EXP.structLiteral)
continue;
if (fd.setUnsafe())
{
/* Don't infer STC.scope_ for va, because then a closure
* won't be generated for fd.
*/
- //if (!va.isScope() && inferScope)
+ //if (!va.isScope())
//va.storage_class |= STC.scope_ | STC.scopeinferred;
continue;
}
/* Do not allow slicing of a static array returned by a function
*/
- if (ee.op == TOK.call && ee.type.toBasetype().isTypeSArray() && e1.type.toBasetype().isTypeDArray() &&
+ if (ee.op == EXP.call && ee.type.toBasetype().isTypeSArray() && e1.type.toBasetype().isTypeDArray() &&
!(va && va.storage_class & STC.temp))
{
if (!gag)
continue;
}
- if (ee.op == TOK.call && ee.type.toBasetype().isTypeStruct() &&
+ if (ee.op == EXP.call && ee.type.toBasetype().isTypeStruct() &&
(!va || !(va.storage_class & STC.temp)) &&
fd.setUnsafe())
{
continue;
}
- if (ee.op == TOK.structLiteral &&
+ if (ee.op == EXP.structLiteral &&
(!va || !(va.storage_class & STC.temp)) &&
fd.setUnsafe())
{
if (va && !va.isDataseg() && !va.doNotInferScope)
{
- if (!va.isScope() && inferScope)
+ if (!va.isScope())
{ //printf("inferring scope for %s\n", va.toChars());
va.storage_class |= STC.scope_ | STC.scopeinferred;
}
if (v.isScope() && !v.iscatchvar) // special case: allow catch var to be rethrown
// despite being `scope`
{
- if (sc._module && sc._module.isRoot())
+ if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029
{
- // Only look for errors if in module listed on command line
- if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029
- {
- if (!gag)
- error(e.loc, "scope variable `%s` may not be thrown", v.toChars());
- result = true;
- }
- continue;
+ if (!gag)
+ error(e.loc, "scope variable `%s` may not be thrown", v.toChars());
+ result = true;
}
+ continue;
}
else
{
if (v.isScope())
{
- if (sc._module && sc._module.isRoot() &&
+ if (
/* This case comes up when the ReturnStatement of a __foreachbody is
* checked for escapes by the caller of __foreachbody. Skip it.
*
if (!v.isReference())
continue;
- if (!sc._module || !sc._module.isRoot())
- continue;
-
// https://dlang.org/spec/function.html#return-ref-parameters
// Only look for errors if in module listed on command line
if (p == sc.func)
continue;
auto pfunc = p.isFuncDeclaration();
- if (pfunc && sc._module && sc._module.isRoot() &&
+ if (pfunc &&
/* This case comes up when the ReturnStatement of a __foreachbody is
* checked for escapes by the caller of __foreachbody. Skip it.
*
)
{
// Only look for errors if in module listed on command line
- if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029
+ // https://issues.dlang.org/show_bug.cgi?id=17029
+ if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe())
{
if (!gag)
error(e.loc, "scope variable `%s` may not be returned", v.toChars());
{
inferReturn(sc.func, v); // infer addition of 'return'
}
- else if (sc._module && sc._module.isRoot())
+ else
{
// https://dlang.org/spec/function.html#return-ref-parameters
// Only look for errors if in module listed on command line
* allowed, but CTFE can generate one out of a new expression,
* but it'll be placed in static data so no need to check it.
*/
- if (e.e1.op != TOK.structLiteral)
+ if (e.e1.op != EXP.structLiteral)
escapeByRef(e.e1, er, live);
}
}
}
// If 'this' is returned, check it too
- if (e.e1.op == TOK.dotVariable && t1.ty == Tfunction)
+ if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction)
{
DotVarExp dve = e.e1.isDotVarExp();
FuncDeclaration fd = dve.var.isFuncDeclaration();
}
}
// If 'this' is returned by ref, check it too
- if (e.e1.op == TOK.dotVariable && t1.ty == Tfunction)
+ if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction)
{
DotVarExp dve = e.e1.isDotVarExp();
}
}
// If it's a delegate, check it too
- if (e.e1.op == TOK.variable && t1.ty == Tdelegate)
+ if (e.e1.op == EXP.variable && t1.ty == Tdelegate)
{
escapeByValue(e.e1, er, live);
}
import dmd.root.ctfloat;
import dmd.root.filename;
import dmd.common.outbuffer;
+import dmd.root.optional;
import dmd.root.rmem;
import dmd.root.rootobject;
import dmd.root.string;
inout(Expression) firstComma(inout Expression e)
{
Expression ex = cast()e;
- while (ex.op == TOK.comma)
+ while (ex.op == EXP.comma)
ex = (cast(CommaExp)ex).e1;
return cast(inout)ex;
inout(Expression) lastComma(inout Expression e)
{
Expression ex = cast()e;
- while (ex.op == TOK.comma)
+ while (ex.op == EXP.comma)
ex = (cast(CommaExp)ex).e2;
return cast(inout)ex;
}
// Inline expand all the tuples
- while (arg.op == TOK.tuple)
+ while (arg.op == EXP.tuple)
{
TupleExp te = cast(TupleExp)arg;
exps.remove(i); // remove arg
printf("expansion ->\n");
foreach (e; exps)
{
- printf("\texps[%d] e = %s %s\n", i, Token.tochars[e.op], e.toChars());
+ printf("\texps[%d] e = %s %s\n", i, EXPtoString(e.op), e.toChars());
}
}
return cast(int)u;
extern (C++) Expression copy()
{
Expression e = exp();
- //if (e.size > sizeof(u)) printf("%s\n", Token::toChars(e.op));
+ //if (e.size > sizeof(u)) printf("%s\n", EXPtoString(e.op).ptr);
assert(e.size <= u.sizeof);
switch (e.op)
{
- case TOK.cantExpression: return CTFEExp.cantexp;
- case TOK.voidExpression: return CTFEExp.voidexp;
- case TOK.break_: return CTFEExp.breakexp;
- case TOK.continue_: return CTFEExp.continueexp;
- case TOK.goto_: return CTFEExp.gotoexp;
+ case EXP.cantExpression: return CTFEExp.cantexp;
+ case EXP.voidExpression: return CTFEExp.voidexp;
+ case EXP.break_: return CTFEExp.breakexp;
+ case EXP.continue_: return CTFEExp.continueexp;
+ case EXP.goto_: return CTFEExp.gotoexp;
default: return e.copy();
}
}
{
switch (e.op)
{
- case TOK.variable:
+ case EXP.variable:
return (cast(VarExp)e).var.isVarDeclaration();
- case TOK.dotVariable:
+ case EXP.dotVariable:
e = (cast(DotVarExp)e).e1;
continue;
- case TOK.index:
+ case EXP.index:
{
IndexExp ei = cast(IndexExp)e;
e = ei.e1;
return null;
}
- case TOK.slice:
+ case EXP.slice:
{
SliceExp ei = cast(SliceExp)e;
e = ei.e1;
return null;
}
- case TOK.this_:
- case TOK.super_:
+ case EXP.this_:
+ case EXP.super_:
return (cast(ThisExp)e).var.isVarDeclaration();
default:
*/
extern (C++) abstract class Expression : ASTNode
{
- const TOK op; // to minimize use of dynamic_cast
+ const EXP op; // to minimize use of dynamic_cast
ubyte size; // # of bytes in Expression so we can copy() it
ubyte parens; // if this is a parenthesized expression
Type type; // !=null means that semantic() has been run
Loc loc; // file location
- extern (D) this(const ref Loc loc, TOK op, int size)
+ extern (D) this(const ref Loc loc, EXP op, int size)
{
//printf("Expression::Expression(op = %d) this = %p\n", op, this);
this.loc = loc;
static void _init()
{
- CTFEExp.cantexp = new CTFEExp(TOK.cantExpression);
- CTFEExp.voidexp = new CTFEExp(TOK.voidExpression);
- CTFEExp.breakexp = new CTFEExp(TOK.break_);
- CTFEExp.continueexp = new CTFEExp(TOK.continue_);
- CTFEExp.gotoexp = new CTFEExp(TOK.goto_);
- CTFEExp.showcontext = new CTFEExp(TOK.showCtfeContext);
+ CTFEExp.cantexp = new CTFEExp(EXP.cantExpression);
+ CTFEExp.voidexp = new CTFEExp(EXP.voidExpression);
+ CTFEExp.breakexp = new CTFEExp(EXP.break_);
+ CTFEExp.continueexp = new CTFEExp(EXP.continue_);
+ CTFEExp.gotoexp = new CTFEExp(EXP.goto_);
+ CTFEExp.showcontext = new CTFEExp(EXP.showCtfeContext);
}
/**
*/
extern (D) static Expression extractLast(Expression e, out Expression e0)
{
- if (e.op != TOK.comma)
+ if (e.op != EXP.comma)
{
return e;
}
CommaExp ce = cast(CommaExp)e;
- if (ce.e2.op != TOK.comma)
+ if (ce.e2.op != EXP.comma)
{
e0 = ce.e1;
return ce.e2;
e0 = e;
Expression* pce = &ce.e2;
- while ((cast(CommaExp)(*pce)).e2.op == TOK.comma)
+ while ((cast(CommaExp)(*pce)).e2.op == EXP.comma)
{
pce = &(cast(CommaExp)(*pce)).e2;
}
- assert((*pce).op == TOK.comma);
+ assert((*pce).op == EXP.comma);
ce = cast(CommaExp)(*pce);
*pce = ce.e1;
dinteger_t toInteger()
{
- //printf("Expression %s\n", Token::toChars(op));
+ //printf("Expression %s\n", EXPtoString(op).ptr);
error("integer constant expression expected instead of `%s`", toChars());
return 0;
}
uinteger_t toUInteger()
{
- //printf("Expression %s\n", Token::toChars(op));
+ //printf("Expression %s\n", EXPtoString(op).ptr);
return cast(uinteger_t)toInteger();
}
else if (!loc.isValid())
loc = e.loc;
- if (e.op == TOK.type)
+ if (e.op == EXP.type)
error("`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind());
else
error("`%s` is not an lvalue and cannot be modified", e.toChars());
extern (D) final bool checkScalar()
{
- if (op == TOK.error)
+ if (op == EXP.error)
return true;
if (type.toBasetype().ty == Terror)
return true;
extern (D) final bool checkNoBool()
{
- if (op == TOK.error)
+ if (op == EXP.error)
return true;
if (type.toBasetype().ty == Terror)
return true;
extern (D) final bool checkIntegral()
{
- if (op == TOK.error)
+ if (op == EXP.error)
return true;
if (type.toBasetype().ty == Terror)
return true;
extern (D) final bool checkArithmetic()
{
- if (op == TOK.error)
+ if (op == EXP.error)
return true;
if (type.toBasetype().ty == Terror)
return true;
extern (D) final bool checkRightThis(Scope* sc)
{
- if (op == TOK.error)
+ if (op == EXP.error)
return true;
- if (op == TOK.variable && type.ty != Terror)
+ if (op == EXP.variable && type.ty != Terror)
{
VarExp ve = cast(VarExp)this;
if (isNeedThisScope(sc, ve.var))
* ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
* Returns true if error occurs.
*/
- extern (D) final bool checkReadModifyWrite(TOK rmwOp, Expression ex = null)
+ extern (D) final bool checkReadModifyWrite(EXP rmwOp, Expression ex = null)
{
//printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass())
// atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
switch (rmwOp)
{
- case TOK.plusPlus:
- case TOK.prePlusPlus:
- rmwOp = TOK.addAssign;
+ case EXP.plusPlus:
+ case EXP.prePlusPlus:
+ rmwOp = EXP.addAssign;
break;
- case TOK.minusMinus:
- case TOK.preMinusMinus:
- rmwOp = TOK.minAssign;
+ case EXP.minusMinus:
+ case EXP.preMinusMinus:
+ rmwOp = EXP.minAssign;
break;
default:
break;
error("read-modify-write operations are not allowed for `shared` variables");
errorSupplemental("Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead",
- Token.toChars(rmwOp), toChars(), ex ? ex.toChars() : "1");
+ EXPtoString(rmwOp).ptr, toChars(), ex ? ex.toChars() : "1");
return true;
}
//printf("Expression::addressOf()\n");
debug
{
- assert(op == TOK.error || isLvalue());
+ assert(op == EXP.error || isLvalue());
}
Expression e = new AddrExp(loc, this, type.pointerTo());
return e;
return .isConst(this);
}
- /********************************
- * Does this expression statically evaluate to a boolean 'result' (true or false)?
- */
- bool isBool(bool result)
+ /// Statically evaluate this expression to a `bool` if possible
+ /// Returns: an optional thath either contains the value or is empty
+ Optional!bool toBool()
{
- return false;
+ return typeof(return)();
}
bool hasCode()
final pure inout nothrow @nogc @safe
{
- inout(IntegerExp) isIntegerExp() { return op == TOK.int64 ? cast(typeof(return))this : null; }
- inout(ErrorExp) isErrorExp() { return op == TOK.error ? cast(typeof(return))this : null; }
- inout(VoidInitExp) isVoidInitExp() { return op == TOK.void_ ? cast(typeof(return))this : null; }
- inout(RealExp) isRealExp() { return op == TOK.float64 ? cast(typeof(return))this : null; }
- inout(ComplexExp) isComplexExp() { return op == TOK.complex80 ? cast(typeof(return))this : null; }
- inout(IdentifierExp) isIdentifierExp() { return op == TOK.identifier ? cast(typeof(return))this : null; }
- inout(DollarExp) isDollarExp() { return op == TOK.dollar ? cast(typeof(return))this : null; }
- inout(DsymbolExp) isDsymbolExp() { return op == TOK.dSymbol ? cast(typeof(return))this : null; }
- inout(ThisExp) isThisExp() { return op == TOK.this_ ? cast(typeof(return))this : null; }
- inout(SuperExp) isSuperExp() { return op == TOK.super_ ? cast(typeof(return))this : null; }
- inout(NullExp) isNullExp() { return op == TOK.null_ ? cast(typeof(return))this : null; }
- inout(StringExp) isStringExp() { return op == TOK.string_ ? cast(typeof(return))this : null; }
- inout(TupleExp) isTupleExp() { return op == TOK.tuple ? cast(typeof(return))this : null; }
- inout(ArrayLiteralExp) isArrayLiteralExp() { return op == TOK.arrayLiteral ? cast(typeof(return))this : null; }
- inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == TOK.assocArrayLiteral ? cast(typeof(return))this : null; }
- inout(StructLiteralExp) isStructLiteralExp() { return op == TOK.structLiteral ? cast(typeof(return))this : null; }
- inout(CompoundLiteralExp) isCompoundLiteralExp() { return op == TOK.compoundLiteral ? cast(typeof(return))this : null; }
- inout(TypeExp) isTypeExp() { return op == TOK.type ? cast(typeof(return))this : null; }
- inout(ScopeExp) isScopeExp() { return op == TOK.scope_ ? cast(typeof(return))this : null; }
- inout(TemplateExp) isTemplateExp() { return op == TOK.template_ ? cast(typeof(return))this : null; }
- inout(NewExp) isNewExp() { return op == TOK.new_ ? cast(typeof(return))this : null; }
- inout(NewAnonClassExp) isNewAnonClassExp() { return op == TOK.newAnonymousClass ? cast(typeof(return))this : null; }
- inout(SymOffExp) isSymOffExp() { return op == TOK.symbolOffset ? cast(typeof(return))this : null; }
- inout(VarExp) isVarExp() { return op == TOK.variable ? cast(typeof(return))this : null; }
- inout(OverExp) isOverExp() { return op == TOK.overloadSet ? cast(typeof(return))this : null; }
- inout(FuncExp) isFuncExp() { return op == TOK.function_ ? cast(typeof(return))this : null; }
- inout(DeclarationExp) isDeclarationExp() { return op == TOK.declaration ? cast(typeof(return))this : null; }
- inout(TypeidExp) isTypeidExp() { return op == TOK.typeid_ ? cast(typeof(return))this : null; }
- inout(TraitsExp) isTraitsExp() { return op == TOK.traits ? cast(typeof(return))this : null; }
- inout(HaltExp) isHaltExp() { return op == TOK.halt ? cast(typeof(return))this : null; }
- inout(IsExp) isExp() { return op == TOK.is_ ? cast(typeof(return))this : null; }
- inout(MixinExp) isMixinExp() { return op == TOK.mixin_ ? cast(typeof(return))this : null; }
- inout(ImportExp) isImportExp() { return op == TOK.import_ ? cast(typeof(return))this : null; }
- inout(AssertExp) isAssertExp() { return op == TOK.assert_ ? cast(typeof(return))this : null; }
- inout(DotIdExp) isDotIdExp() { return op == TOK.dotIdentifier ? cast(typeof(return))this : null; }
- inout(DotTemplateExp) isDotTemplateExp() { return op == TOK.dotTemplateDeclaration ? cast(typeof(return))this : null; }
- inout(DotVarExp) isDotVarExp() { return op == TOK.dotVariable ? cast(typeof(return))this : null; }
- inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == TOK.dotTemplateInstance ? cast(typeof(return))this : null; }
- inout(DelegateExp) isDelegateExp() { return op == TOK.delegate_ ? cast(typeof(return))this : null; }
- inout(DotTypeExp) isDotTypeExp() { return op == TOK.dotType ? cast(typeof(return))this : null; }
- inout(CallExp) isCallExp() { return op == TOK.call ? cast(typeof(return))this : null; }
- inout(AddrExp) isAddrExp() { return op == TOK.address ? cast(typeof(return))this : null; }
- inout(PtrExp) isPtrExp() { return op == TOK.star ? cast(typeof(return))this : null; }
- inout(NegExp) isNegExp() { return op == TOK.negate ? cast(typeof(return))this : null; }
- inout(UAddExp) isUAddExp() { return op == TOK.uadd ? cast(typeof(return))this : null; }
- inout(ComExp) isComExp() { return op == TOK.tilde ? cast(typeof(return))this : null; }
- inout(NotExp) isNotExp() { return op == TOK.not ? cast(typeof(return))this : null; }
- inout(DeleteExp) isDeleteExp() { return op == TOK.delete_ ? cast(typeof(return))this : null; }
- inout(CastExp) isCastExp() { return op == TOK.cast_ ? cast(typeof(return))this : null; }
- inout(VectorExp) isVectorExp() { return op == TOK.vector ? cast(typeof(return))this : null; }
- inout(VectorArrayExp) isVectorArrayExp() { return op == TOK.vectorArray ? cast(typeof(return))this : null; }
- inout(SliceExp) isSliceExp() { return op == TOK.slice ? cast(typeof(return))this : null; }
- inout(ArrayLengthExp) isArrayLengthExp() { return op == TOK.arrayLength ? cast(typeof(return))this : null; }
- inout(ArrayExp) isArrayExp() { return op == TOK.array ? cast(typeof(return))this : null; }
- inout(DotExp) isDotExp() { return op == TOK.dot ? cast(typeof(return))this : null; }
- inout(CommaExp) isCommaExp() { return op == TOK.comma ? cast(typeof(return))this : null; }
- inout(IntervalExp) isIntervalExp() { return op == TOK.interval ? cast(typeof(return))this : null; }
- inout(DelegatePtrExp) isDelegatePtrExp() { return op == TOK.delegatePointer ? cast(typeof(return))this : null; }
- inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == TOK.delegateFunctionPointer ? cast(typeof(return))this : null; }
- inout(IndexExp) isIndexExp() { return op == TOK.index ? cast(typeof(return))this : null; }
- inout(PostExp) isPostExp() { return (op == TOK.plusPlus || op == TOK.minusMinus) ? cast(typeof(return))this : null; }
- inout(PreExp) isPreExp() { return (op == TOK.prePlusPlus || op == TOK.preMinusMinus) ? cast(typeof(return))this : null; }
- inout(AssignExp) isAssignExp() { return op == TOK.assign ? cast(typeof(return))this : null; }
- inout(ConstructExp) isConstructExp() { return op == TOK.construct ? cast(typeof(return))this : null; }
- inout(BlitExp) isBlitExp() { return op == TOK.blit ? cast(typeof(return))this : null; }
- inout(AddAssignExp) isAddAssignExp() { return op == TOK.addAssign ? cast(typeof(return))this : null; }
- inout(MinAssignExp) isMinAssignExp() { return op == TOK.minAssign ? cast(typeof(return))this : null; }
- inout(MulAssignExp) isMulAssignExp() { return op == TOK.mulAssign ? cast(typeof(return))this : null; }
-
- inout(DivAssignExp) isDivAssignExp() { return op == TOK.divAssign ? cast(typeof(return))this : null; }
- inout(ModAssignExp) isModAssignExp() { return op == TOK.modAssign ? cast(typeof(return))this : null; }
- inout(AndAssignExp) isAndAssignExp() { return op == TOK.andAssign ? cast(typeof(return))this : null; }
- inout(OrAssignExp) isOrAssignExp() { return op == TOK.orAssign ? cast(typeof(return))this : null; }
- inout(XorAssignExp) isXorAssignExp() { return op == TOK.xorAssign ? cast(typeof(return))this : null; }
- inout(PowAssignExp) isPowAssignExp() { return op == TOK.powAssign ? cast(typeof(return))this : null; }
-
- inout(ShlAssignExp) isShlAssignExp() { return op == TOK.leftShiftAssign ? cast(typeof(return))this : null; }
- inout(ShrAssignExp) isShrAssignExp() { return op == TOK.rightShiftAssign ? cast(typeof(return))this : null; }
- inout(UshrAssignExp) isUshrAssignExp() { return op == TOK.unsignedRightShiftAssign ? cast(typeof(return))this : null; }
-
- inout(CatAssignExp) isCatAssignExp() { return op == TOK.concatenateAssign
+ inout(IntegerExp) isIntegerExp() { return op == EXP.int64 ? cast(typeof(return))this : null; }
+ inout(ErrorExp) isErrorExp() { return op == EXP.error ? cast(typeof(return))this : null; }
+ inout(VoidInitExp) isVoidInitExp() { return op == EXP.void_ ? cast(typeof(return))this : null; }
+ inout(RealExp) isRealExp() { return op == EXP.float64 ? cast(typeof(return))this : null; }
+ inout(ComplexExp) isComplexExp() { return op == EXP.complex80 ? cast(typeof(return))this : null; }
+ inout(IdentifierExp) isIdentifierExp() { return op == EXP.identifier ? cast(typeof(return))this : null; }
+ inout(DollarExp) isDollarExp() { return op == EXP.dollar ? cast(typeof(return))this : null; }
+ inout(DsymbolExp) isDsymbolExp() { return op == EXP.dSymbol ? cast(typeof(return))this : null; }
+ inout(ThisExp) isThisExp() { return op == EXP.this_ ? cast(typeof(return))this : null; }
+ inout(SuperExp) isSuperExp() { return op == EXP.super_ ? cast(typeof(return))this : null; }
+ inout(NullExp) isNullExp() { return op == EXP.null_ ? cast(typeof(return))this : null; }
+ inout(StringExp) isStringExp() { return op == EXP.string_ ? cast(typeof(return))this : null; }
+ inout(TupleExp) isTupleExp() { return op == EXP.tuple ? cast(typeof(return))this : null; }
+ inout(ArrayLiteralExp) isArrayLiteralExp() { return op == EXP.arrayLiteral ? cast(typeof(return))this : null; }
+ inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == EXP.assocArrayLiteral ? cast(typeof(return))this : null; }
+ inout(StructLiteralExp) isStructLiteralExp() { return op == EXP.structLiteral ? cast(typeof(return))this : null; }
+ inout(CompoundLiteralExp) isCompoundLiteralExp() { return op == EXP.compoundLiteral ? cast(typeof(return))this : null; }
+ inout(TypeExp) isTypeExp() { return op == EXP.type ? cast(typeof(return))this : null; }
+ inout(ScopeExp) isScopeExp() { return op == EXP.scope_ ? cast(typeof(return))this : null; }
+ inout(TemplateExp) isTemplateExp() { return op == EXP.template_ ? cast(typeof(return))this : null; }
+ inout(NewExp) isNewExp() { return op == EXP.new_ ? cast(typeof(return))this : null; }
+ inout(NewAnonClassExp) isNewAnonClassExp() { return op == EXP.newAnonymousClass ? cast(typeof(return))this : null; }
+ inout(SymOffExp) isSymOffExp() { return op == EXP.symbolOffset ? cast(typeof(return))this : null; }
+ inout(VarExp) isVarExp() { return op == EXP.variable ? cast(typeof(return))this : null; }
+ inout(OverExp) isOverExp() { return op == EXP.overloadSet ? cast(typeof(return))this : null; }
+ inout(FuncExp) isFuncExp() { return op == EXP.function_ ? cast(typeof(return))this : null; }
+ inout(DeclarationExp) isDeclarationExp() { return op == EXP.declaration ? cast(typeof(return))this : null; }
+ inout(TypeidExp) isTypeidExp() { return op == EXP.typeid_ ? cast(typeof(return))this : null; }
+ inout(TraitsExp) isTraitsExp() { return op == EXP.traits ? cast(typeof(return))this : null; }
+ inout(HaltExp) isHaltExp() { return op == EXP.halt ? cast(typeof(return))this : null; }
+ inout(IsExp) isExp() { return op == EXP.is_ ? cast(typeof(return))this : null; }
+ inout(MixinExp) isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; }
+ inout(ImportExp) isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; }
+ inout(AssertExp) isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; }
+ inout(DotIdExp) isDotIdExp() { return op == EXP.dotIdentifier ? cast(typeof(return))this : null; }
+ inout(DotTemplateExp) isDotTemplateExp() { return op == EXP.dotTemplateDeclaration ? cast(typeof(return))this : null; }
+ inout(DotVarExp) isDotVarExp() { return op == EXP.dotVariable ? cast(typeof(return))this : null; }
+ inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == EXP.dotTemplateInstance ? cast(typeof(return))this : null; }
+ inout(DelegateExp) isDelegateExp() { return op == EXP.delegate_ ? cast(typeof(return))this : null; }
+ inout(DotTypeExp) isDotTypeExp() { return op == EXP.dotType ? cast(typeof(return))this : null; }
+ inout(CallExp) isCallExp() { return op == EXP.call ? cast(typeof(return))this : null; }
+ inout(AddrExp) isAddrExp() { return op == EXP.address ? cast(typeof(return))this : null; }
+ inout(PtrExp) isPtrExp() { return op == EXP.star ? cast(typeof(return))this : null; }
+ inout(NegExp) isNegExp() { return op == EXP.negate ? cast(typeof(return))this : null; }
+ inout(UAddExp) isUAddExp() { return op == EXP.uadd ? cast(typeof(return))this : null; }
+ inout(ComExp) isComExp() { return op == EXP.tilde ? cast(typeof(return))this : null; }
+ inout(NotExp) isNotExp() { return op == EXP.not ? cast(typeof(return))this : null; }
+ inout(DeleteExp) isDeleteExp() { return op == EXP.delete_ ? cast(typeof(return))this : null; }
+ inout(CastExp) isCastExp() { return op == EXP.cast_ ? cast(typeof(return))this : null; }
+ inout(VectorExp) isVectorExp() { return op == EXP.vector ? cast(typeof(return))this : null; }
+ inout(VectorArrayExp) isVectorArrayExp() { return op == EXP.vectorArray ? cast(typeof(return))this : null; }
+ inout(SliceExp) isSliceExp() { return op == EXP.slice ? cast(typeof(return))this : null; }
+ inout(ArrayLengthExp) isArrayLengthExp() { return op == EXP.arrayLength ? cast(typeof(return))this : null; }
+ inout(ArrayExp) isArrayExp() { return op == EXP.array ? cast(typeof(return))this : null; }
+ inout(DotExp) isDotExp() { return op == EXP.dot ? cast(typeof(return))this : null; }
+ inout(CommaExp) isCommaExp() { return op == EXP.comma ? cast(typeof(return))this : null; }
+ inout(IntervalExp) isIntervalExp() { return op == EXP.interval ? cast(typeof(return))this : null; }
+ inout(DelegatePtrExp) isDelegatePtrExp() { return op == EXP.delegatePointer ? cast(typeof(return))this : null; }
+ inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == EXP.delegateFunctionPointer ? cast(typeof(return))this : null; }
+ inout(IndexExp) isIndexExp() { return op == EXP.index ? cast(typeof(return))this : null; }
+ inout(PostExp) isPostExp() { return (op == EXP.plusPlus || op == EXP.minusMinus) ? cast(typeof(return))this : null; }
+ inout(PreExp) isPreExp() { return (op == EXP.prePlusPlus || op == EXP.preMinusMinus) ? cast(typeof(return))this : null; }
+ inout(AssignExp) isAssignExp() { return op == EXP.assign ? cast(typeof(return))this : null; }
+ inout(ConstructExp) isConstructExp() { return op == EXP.construct ? cast(typeof(return))this : null; }
+ inout(BlitExp) isBlitExp() { return op == EXP.blit ? cast(typeof(return))this : null; }
+ inout(AddAssignExp) isAddAssignExp() { return op == EXP.addAssign ? cast(typeof(return))this : null; }
+ inout(MinAssignExp) isMinAssignExp() { return op == EXP.minAssign ? cast(typeof(return))this : null; }
+ inout(MulAssignExp) isMulAssignExp() { return op == EXP.mulAssign ? cast(typeof(return))this : null; }
+
+ inout(DivAssignExp) isDivAssignExp() { return op == EXP.divAssign ? cast(typeof(return))this : null; }
+ inout(ModAssignExp) isModAssignExp() { return op == EXP.modAssign ? cast(typeof(return))this : null; }
+ inout(AndAssignExp) isAndAssignExp() { return op == EXP.andAssign ? cast(typeof(return))this : null; }
+ inout(OrAssignExp) isOrAssignExp() { return op == EXP.orAssign ? cast(typeof(return))this : null; }
+ inout(XorAssignExp) isXorAssignExp() { return op == EXP.xorAssign ? cast(typeof(return))this : null; }
+ inout(PowAssignExp) isPowAssignExp() { return op == EXP.powAssign ? cast(typeof(return))this : null; }
+
+ inout(ShlAssignExp) isShlAssignExp() { return op == EXP.leftShiftAssign ? cast(typeof(return))this : null; }
+ inout(ShrAssignExp) isShrAssignExp() { return op == EXP.rightShiftAssign ? cast(typeof(return))this : null; }
+ inout(UshrAssignExp) isUshrAssignExp() { return op == EXP.unsignedRightShiftAssign ? cast(typeof(return))this : null; }
+
+ inout(CatAssignExp) isCatAssignExp() { return op == EXP.concatenateAssign
? cast(typeof(return))this
: null; }
- inout(CatElemAssignExp) isCatElemAssignExp() { return op == TOK.concatenateElemAssign
+ inout(CatElemAssignExp) isCatElemAssignExp() { return op == EXP.concatenateElemAssign
? cast(typeof(return))this
: null; }
- inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == TOK.concatenateDcharAssign
+ inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == EXP.concatenateDcharAssign
? cast(typeof(return))this
: null; }
- inout(AddExp) isAddExp() { return op == TOK.add ? cast(typeof(return))this : null; }
- inout(MinExp) isMinExp() { return op == TOK.min ? cast(typeof(return))this : null; }
- inout(CatExp) isCatExp() { return op == TOK.concatenate ? cast(typeof(return))this : null; }
- inout(MulExp) isMulExp() { return op == TOK.mul ? cast(typeof(return))this : null; }
- inout(DivExp) isDivExp() { return op == TOK.div ? cast(typeof(return))this : null; }
- inout(ModExp) isModExp() { return op == TOK.mod ? cast(typeof(return))this : null; }
- inout(PowExp) isPowExp() { return op == TOK.pow ? cast(typeof(return))this : null; }
- inout(ShlExp) isShlExp() { return op == TOK.leftShift ? cast(typeof(return))this : null; }
- inout(ShrExp) isShrExp() { return op == TOK.rightShift ? cast(typeof(return))this : null; }
- inout(UshrExp) isUshrExp() { return op == TOK.unsignedRightShift ? cast(typeof(return))this : null; }
- inout(AndExp) isAndExp() { return op == TOK.and ? cast(typeof(return))this : null; }
- inout(OrExp) isOrExp() { return op == TOK.or ? cast(typeof(return))this : null; }
- inout(XorExp) isXorExp() { return op == TOK.xor ? cast(typeof(return))this : null; }
- inout(LogicalExp) isLogicalExp() { return (op == TOK.andAnd || op == TOK.orOr) ? cast(typeof(return))this : null; }
- //inout(CmpExp) isCmpExp() { return op == TOK. ? cast(typeof(return))this : null; }
- inout(InExp) isInExp() { return op == TOK.in_ ? cast(typeof(return))this : null; }
- inout(RemoveExp) isRemoveExp() { return op == TOK.remove ? cast(typeof(return))this : null; }
- inout(EqualExp) isEqualExp() { return (op == TOK.equal || op == TOK.notEqual) ? cast(typeof(return))this : null; }
- inout(IdentityExp) isIdentityExp() { return (op == TOK.identity || op == TOK.notIdentity) ? cast(typeof(return))this : null; }
- inout(CondExp) isCondExp() { return op == TOK.question ? cast(typeof(return))this : null; }
- inout(GenericExp) isGenericExp() { return op == TOK._Generic ? cast(typeof(return))this : null; }
+ inout(AddExp) isAddExp() { return op == EXP.add ? cast(typeof(return))this : null; }
+ inout(MinExp) isMinExp() { return op == EXP.min ? cast(typeof(return))this : null; }
+ inout(CatExp) isCatExp() { return op == EXP.concatenate ? cast(typeof(return))this : null; }
+ inout(MulExp) isMulExp() { return op == EXP.mul ? cast(typeof(return))this : null; }
+ inout(DivExp) isDivExp() { return op == EXP.div ? cast(typeof(return))this : null; }
+ inout(ModExp) isModExp() { return op == EXP.mod ? cast(typeof(return))this : null; }
+ inout(PowExp) isPowExp() { return op == EXP.pow ? cast(typeof(return))this : null; }
+ inout(ShlExp) isShlExp() { return op == EXP.leftShift ? cast(typeof(return))this : null; }
+ inout(ShrExp) isShrExp() { return op == EXP.rightShift ? cast(typeof(return))this : null; }
+ inout(UshrExp) isUshrExp() { return op == EXP.unsignedRightShift ? cast(typeof(return))this : null; }
+ inout(AndExp) isAndExp() { return op == EXP.and ? cast(typeof(return))this : null; }
+ inout(OrExp) isOrExp() { return op == EXP.or ? cast(typeof(return))this : null; }
+ inout(XorExp) isXorExp() { return op == EXP.xor ? cast(typeof(return))this : null; }
+ inout(LogicalExp) isLogicalExp() { return (op == EXP.andAnd || op == EXP.orOr) ? cast(typeof(return))this : null; }
+ //inout(CmpExp) isCmpExp() { return op == EXP. ? cast(typeof(return))this : null; }
+ inout(InExp) isInExp() { return op == EXP.in_ ? cast(typeof(return))this : null; }
+ inout(RemoveExp) isRemoveExp() { return op == EXP.remove ? cast(typeof(return))this : null; }
+ inout(EqualExp) isEqualExp() { return (op == EXP.equal || op == EXP.notEqual) ? cast(typeof(return))this : null; }
+ inout(IdentityExp) isIdentityExp() { return (op == EXP.identity || op == EXP.notIdentity) ? cast(typeof(return))this : null; }
+ inout(CondExp) isCondExp() { return op == EXP.question ? cast(typeof(return))this : null; }
+ inout(GenericExp) isGenericExp() { return op == EXP._Generic ? cast(typeof(return))this : null; }
inout(DefaultInitExp) isDefaultInitExp() { return isDefaultInitOp(op) ? cast(typeof(return))this: null; }
- inout(FileInitExp) isFileInitExp() { return (op == TOK.file || op == TOK.fileFullPath) ? cast(typeof(return))this : null; }
- inout(LineInitExp) isLineInitExp() { return op == TOK.line ? cast(typeof(return))this : null; }
- inout(ModuleInitExp) isModuleInitExp() { return op == TOK.moduleString ? cast(typeof(return))this : null; }
- inout(FuncInitExp) isFuncInitExp() { return op == TOK.functionString ? cast(typeof(return))this : null; }
- inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == TOK.prettyFunction ? cast(typeof(return))this : null; }
- inout(ClassReferenceExp) isClassReferenceExp() { return op == TOK.classReference ? cast(typeof(return))this : null; }
- inout(ThrownExceptionExp) isThrownExceptionExp() { return op == TOK.thrownException ? cast(typeof(return))this : null; }
+ inout(FileInitExp) isFileInitExp() { return (op == EXP.file || op == EXP.fileFullPath) ? cast(typeof(return))this : null; }
+ inout(LineInitExp) isLineInitExp() { return op == EXP.line ? cast(typeof(return))this : null; }
+ inout(ModuleInitExp) isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; }
+ inout(FuncInitExp) isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; }
+ inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; }
+ inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; }
+ inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; }
}
inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
extern (D) this(const ref Loc loc, dinteger_t value, Type type)
{
- super(loc, TOK.int64, __traits(classInstanceSize, IntegerExp));
+ super(loc, EXP.int64, __traits(classInstanceSize, IntegerExp));
//printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : "");
assert(type);
if (!type.isscalar())
extern (D) this(dinteger_t value)
{
- super(Loc.initial, TOK.int64, __traits(classInstanceSize, IntegerExp));
+ super(Loc.initial, EXP.int64, __traits(classInstanceSize, IntegerExp));
this.type = Type.tint32;
this.value = cast(d_int32)value;
}
return complex_t(toReal());
}
- override bool isBool(bool result)
+ override Optional!bool toBool()
{
bool r = toInteger() != 0;
- return result ? r : !r;
+ return typeof(return)(r);
}
override Expression toLvalue(Scope* sc, Expression e)
{
private extern (D) this()
{
- super(Loc.initial, TOK.error, __traits(classInstanceSize, ErrorExp));
+ super(Loc.initial, EXP.error, __traits(classInstanceSize, ErrorExp));
type = Type.terror;
}
extern (D) this(VarDeclaration var)
{
- super(var.loc, TOK.void_, __traits(classInstanceSize, VoidInitExp));
+ super(var.loc, EXP.void_, __traits(classInstanceSize, VoidInitExp));
this.var = var;
this.type = var.type;
}
extern (D) this(const ref Loc loc, real_t value, Type type)
{
- super(loc, TOK.float64, __traits(classInstanceSize, RealExp));
+ super(loc, EXP.float64, __traits(classInstanceSize, RealExp));
//printf("RealExp::RealExp(%Lg)\n", value);
this.value = value;
this.type = type;
return complex_t(toReal(), toImaginary());
}
- override bool isBool(bool result)
+ override Optional!bool toBool()
{
- return result ? cast(bool)value : !cast(bool)value;
+ return typeof(return)(!!value);
}
override void accept(Visitor v)
extern (D) this(const ref Loc loc, complex_t value, Type type)
{
- super(loc, TOK.complex80, __traits(classInstanceSize, ComplexExp));
+ super(loc, EXP.complex80, __traits(classInstanceSize, ComplexExp));
this.value = value;
this.type = type;
//printf("ComplexExp::ComplexExp(%s)\n", toChars());
return value;
}
- override bool isBool(bool result)
+ override Optional!bool toBool()
{
- if (result)
- return cast(bool)value;
- else
- return !value;
+ return typeof(return)(!!value);
}
override void accept(Visitor v)
extern (D) this(const ref Loc loc, Identifier ident)
{
- super(loc, TOK.identifier, __traits(classInstanceSize, IdentifierExp));
+ super(loc, EXP.identifier, __traits(classInstanceSize, IdentifierExp));
this.ident = ident;
}
extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true)
{
- super(loc, TOK.dSymbol, __traits(classInstanceSize, DsymbolExp));
+ super(loc, EXP.dSymbol, __traits(classInstanceSize, DsymbolExp));
this.s = s;
this.hasOverloads = hasOverloads;
}
extern (D) this(const ref Loc loc)
{
- super(loc, TOK.this_, __traits(classInstanceSize, ThisExp));
+ super(loc, EXP.this_, __traits(classInstanceSize, ThisExp));
//printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
}
- this(const ref Loc loc, const TOK tok)
+ this(const ref Loc loc, const EXP tok)
{
super(loc, tok, __traits(classInstanceSize, ThisExp));
//printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
return r;
}
- override final bool isBool(bool result)
+ override Optional!bool toBool()
{
- return result;
+ // `this` is never null (what about structs?)
+ return typeof(return)(true);
}
override final bool isLvalue()
{
extern (D) this(const ref Loc loc)
{
- super(loc, TOK.super_);
+ super(loc, EXP.super_);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Type type = null)
{
- super(loc, TOK.null_, __traits(classInstanceSize, NullExp));
+ super(loc, EXP.null_, __traits(classInstanceSize, NullExp));
this.type = type;
}
{
if (auto e = o.isExpression())
{
- if (e.op == TOK.null_ && type.equals(e.type))
+ if (e.op == EXP.null_ && type.equals(e.type))
{
return true;
}
return false;
}
- override bool isBool(bool result)
+ override Optional!bool toBool()
{
- return result ? false : true;
+ // null in any type is false
+ return typeof(return)(false);
}
override StringExp toStringExp()
extern (D) this(const ref Loc loc, const(void)[] string)
{
- super(loc, TOK.string_, __traits(classInstanceSize, StringExp));
+ super(loc, EXP.string_, __traits(classInstanceSize, StringExp));
this.string = cast(char*)string.ptr; // note that this.string should be const
this.len = string.length;
this.sz = 1; // work around LDC bug #1286
extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix)
{
- super(loc, TOK.string_, __traits(classInstanceSize, StringExp));
+ super(loc, EXP.string_, __traits(classInstanceSize, StringExp));
this.string = cast(char*)string.ptr; // note that this.string should be const
this.len = len;
this.sz = sz;
return cast(int)(len1 - len2);
}
- override bool isBool(bool result)
+ override Optional!bool toBool()
{
- return result;
+ // Keep the old behaviour for this refactoring
+ // Should probably match language spec instead and check for length
+ return typeof(return)(true);
}
override bool isLvalue()
extern (D) this(const ref Loc loc, Expression e0, Expressions* exps)
{
- super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp));
+ super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp));
//printf("TupleExp(this = %p)\n", this);
this.e0 = e0;
this.exps = exps;
extern (D) this(const ref Loc loc, Expressions* exps)
{
- super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp));
+ super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp));
//printf("TupleExp(this = %p)\n", this);
this.exps = exps;
}
extern (D) this(const ref Loc loc, TupleDeclaration tup)
{
- super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp));
+ super(loc, EXP.tuple, __traits(classInstanceSize, TupleExp));
this.exps = new Expressions();
this.exps.reserve(tup.objects.dim);
extern (D) this(const ref Loc loc, Type type, Expressions* elements)
{
- super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
+ super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
this.type = type;
this.elements = elements;
}
extern (D) this(const ref Loc loc, Type type, Expression e)
{
- super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
+ super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
this.type = type;
elements = new Expressions();
elements.push(e);
extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements)
{
- super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
+ super(loc, EXP.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
this.type = type;
this.basis = basis;
this.elements = elements;
return el ? el : basis;
}
- override bool isBool(bool result)
+ override Optional!bool toBool()
{
size_t dim = elements ? elements.dim : 0;
- return result ? (dim != 0) : (dim == 0);
+ return typeof(return)(dim != 0);
}
override StringExp toStringExp()
foreach (i; 0 .. elements.dim)
{
auto ch = this[i];
- if (ch.op != TOK.int64)
+ if (ch.op != EXP.int64)
return null;
if (sz == 1)
buf.writeByte(cast(uint)ch.toInteger());
extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values)
{
- super(loc, TOK.assocArrayLiteral, __traits(classInstanceSize, AssocArrayLiteralExp));
+ super(loc, EXP.assocArrayLiteral, __traits(classInstanceSize, AssocArrayLiteralExp));
assert(keys.dim == values.dim);
this.keys = keys;
this.values = values;
return new AssocArrayLiteralExp(loc, arraySyntaxCopy(keys), arraySyntaxCopy(values));
}
- override bool isBool(bool result)
+ override Optional!bool toBool()
{
size_t dim = keys.dim;
- return result ? (dim != 0) : (dim == 0);
+ return typeof(return)(dim != 0);
}
override void accept(Visitor v)
extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null)
{
- super(loc, TOK.structLiteral, __traits(classInstanceSize, StructLiteralExp));
+ super(loc, EXP.structLiteral, __traits(classInstanceSize, StructLiteralExp));
this.sd = sd;
if (!elements)
elements = new Expressions();
*/
if (elements.dim)
{
+ const sz = type.size();
+ if (sz == SIZE_INVALID)
+ return -1;
foreach (i, v; sd.fields)
{
- if (offset == v.offset && type.size() == v.type.size())
+ if (offset == v.offset && sz == v.type.size())
{
/* context fields might not be filled. */
if (i >= sd.nonHiddenFields())
extern (D) this(const ref Loc loc, Type type_name, Initializer initializer)
{
- super(loc, TOK.compoundLiteral, __traits(classInstanceSize, CompoundLiteralExp));
+ super(loc, EXP.compoundLiteral, __traits(classInstanceSize, CompoundLiteralExp));
super.type = type_name;
this.initializer = initializer;
//printf("CompoundLiteralExp::CompoundLiteralExp(%s)\n", toChars());
{
extern (D) this(const ref Loc loc, Type type)
{
- super(loc, TOK.type, __traits(classInstanceSize, TypeExp));
+ super(loc, EXP.type, __traits(classInstanceSize, TypeExp));
//printf("TypeExp::TypeExp(%s)\n", type.toChars());
this.type = type;
}
extern (D) this(const ref Loc loc, ScopeDsymbol sds)
{
- super(loc, TOK.scope_, __traits(classInstanceSize, ScopeExp));
+ super(loc, EXP.scope_, __traits(classInstanceSize, ScopeExp));
//printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars());
//static int count; if (++count == 38) *(char*)0=0;
this.sds = sds;
extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null)
{
- super(loc, TOK.template_, __traits(classInstanceSize, TemplateExp));
+ super(loc, EXP.template_, __traits(classInstanceSize, TemplateExp));
//printf("TemplateExp(): %s\n", td.toChars());
this.td = td;
this.fd = fd;
extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
{
- super(loc, TOK.new_, __traits(classInstanceSize, NewExp));
+ super(loc, EXP.new_, __traits(classInstanceSize, NewExp));
this.thisexp = thisexp;
this.newargs = newargs;
this.newtype = newtype;
extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, ClassDeclaration cd, Expressions* arguments)
{
- super(loc, TOK.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp));
+ super(loc, EXP.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp));
this.thisexp = thisexp;
this.newargs = newargs;
this.cd = cd;
Dsymbol originalScope; // original scope before inlining
bool hasOverloads;
- extern (D) this(const ref Loc loc, TOK op, int size, Declaration var, bool hasOverloads)
+ extern (D) this(const ref Loc loc, EXP op, int size, Declaration var, bool hasOverloads)
{
super(loc, op, size);
assert(var);
.error(loc, "need `this` for address of `%s`", v.toChars());
hasOverloads = false;
}
- super(loc, TOK.symbolOffset, __traits(classInstanceSize, SymOffExp), var, hasOverloads);
+ super(loc, EXP.symbolOffset, __traits(classInstanceSize, SymOffExp), var, hasOverloads);
this.offset = offset;
}
- override bool isBool(bool result)
+ override Optional!bool toBool()
{
- return result ? true : false;
+ return typeof(return)(true);
}
override void accept(Visitor v)
if (var.isVarDeclaration())
hasOverloads = false;
- super(loc, TOK.variable, __traits(classInstanceSize, VarExp), var, hasOverloads);
+ super(loc, EXP.variable, __traits(classInstanceSize, VarExp), var, hasOverloads);
//printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars());
//if (strcmp(var.ident.toChars(), "func") == 0) assert(0);
this.type = var.type;
extern (D) this(const ref Loc loc, OverloadSet s)
{
- super(loc, TOK.overloadSet, __traits(classInstanceSize, OverExp));
+ super(loc, EXP.overloadSet, __traits(classInstanceSize, OverExp));
//printf("OverExp(this = %p, '%s')\n", this, var.toChars());
vars = s;
type = Type.tvoid;
{
FuncLiteralDeclaration fd;
TemplateDeclaration td;
- TOK tok;
+ TOK tok; // TOK.reserved, TOK.delegate_, TOK.function_
extern (D) this(const ref Loc loc, Dsymbol s)
{
- super(loc, TOK.function_, __traits(classInstanceSize, FuncExp));
+ super(loc, EXP.function_, __traits(classInstanceSize, FuncExp));
this.td = s.isTemplateDeclaration();
this.fd = s.isFuncLiteralDeclaration();
if (td)
// Reset inference target for the later re-semantic
fd.treq = null;
- if (ex.op == TOK.error)
+ if (ex.op == EXP.error)
return MATCH.nomatch;
if (auto ef = ex.isFuncExp())
return ef.matchType(to, sc, presult, flag);
extern (D) this(const ref Loc loc, Dsymbol declaration)
{
- super(loc, TOK.declaration, __traits(classInstanceSize, DeclarationExp));
+ super(loc, EXP.declaration, __traits(classInstanceSize, DeclarationExp));
this.declaration = declaration;
}
extern (D) this(const ref Loc loc, RootObject o)
{
- super(loc, TOK.typeid_, __traits(classInstanceSize, TypeidExp));
+ super(loc, EXP.typeid_, __traits(classInstanceSize, TypeidExp));
this.obj = o;
}
extern (D) this(const ref Loc loc, Identifier ident, Objects* args)
{
- super(loc, TOK.traits, __traits(classInstanceSize, TraitsExp));
+ super(loc, EXP.traits, __traits(classInstanceSize, TraitsExp));
this.ident = ident;
this.args = args;
}
{
extern (D) this(const ref Loc loc)
{
- super(loc, TOK.halt, __traits(classInstanceSize, HaltExp));
+ super(loc, EXP.halt, __traits(classInstanceSize, HaltExp));
}
override void accept(Visitor v)
extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters)
{
- super(loc, TOK.is_, __traits(classInstanceSize, IsExp));
+ super(loc, EXP.is_, __traits(classInstanceSize, IsExp));
this.targ = targ;
this.id = id;
this.tok = tok;
Expression e1;
Type att1; // Save alias this type to detect recursion
- extern (D) this(const ref Loc loc, TOK op, int size, Expression e1)
+ extern (D) this(const ref Loc loc, EXP op, int size, Expression e1)
{
super(loc, op, size);
this.e1 = e1;
if (e1.type.toBasetype() == Type.terror)
return e1;
- if (e1.op == TOK.type)
+ if (e1.op == EXP.type)
{
- error("incompatible type for `%s(%s)`: cannot use `%s` with types", Token.toChars(op), e1.toChars(), Token.toChars(op));
+ error("incompatible type for `%s(%s)`: cannot use `%s` with types", EXPtoString(op).ptr, e1.toChars(), EXPtoString(op).ptr);
}
else
{
- error("incompatible type for `%s(%s)`: `%s`", Token.toChars(op), e1.toChars(), e1.type.toChars());
+ error("incompatible type for `%s(%s)`: `%s`", EXPtoString(op).ptr, e1.toChars(), e1.type.toChars());
}
return ErrorExp.get();
}
}
alias fp_t = UnionExp function(const ref Loc loc, Type, Expression, Expression);
-alias fp2_t = bool function(const ref Loc loc, TOK, Expression, Expression);
+alias fp2_t = bool function(const ref Loc loc, EXP, Expression, Expression);
/***********************************************************
*/
Type att1; // Save alias this type to detect recursion
Type att2; // Save alias this type to detect recursion
- extern (D) this(const ref Loc loc, TOK op, int size, Expression e1, Expression e2)
+ extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2)
{
super(loc, op, size);
this.e1 = e1;
return e2;
// CondExp uses 'a ? b : c' but we're comparing 'b : c'
- TOK thisOp = (op == TOK.question) ? TOK.colon : op;
- if (e1.op == TOK.type || e2.op == TOK.type)
+ const(char)* thisOp = (op == EXP.question) ? ":" : EXPtoString(op).ptr;
+ if (e1.op == EXP.type || e2.op == EXP.type)
{
error("incompatible types for `(%s) %s (%s)`: cannot use `%s` with types",
- e1.toChars(), Token.toChars(thisOp), e2.toChars(), Token.toChars(op));
+ e1.toChars(), thisOp, e2.toChars(), EXPtoString(op).ptr);
}
else if (e1.type.equals(e2.type))
{
error("incompatible types for `(%s) %s (%s)`: both operands are of type `%s`",
- e1.toChars(), Token.toChars(thisOp), e2.toChars(), e1.type.toChars());
+ e1.toChars(), thisOp, e2.toChars(), e1.type.toChars());
}
else
{
auto ts = toAutoQualChars(e1.type, e2.type);
error("incompatible types for `(%s) %s (%s)`: `%s` and `%s`",
- e1.toChars(), Token.toChars(thisOp), e2.toChars(), ts[0], ts[1]);
+ e1.toChars(), thisOp, e2.toChars(), ts[0], ts[1]);
}
return ErrorExp.get();
}
// T opAssign floating yields a floating. Prevent truncating conversions (float to int).
// See issue 3841.
// Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
- if (op == TOK.addAssign || op == TOK.minAssign ||
- op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign ||
- op == TOK.powAssign)
+ if (op == EXP.addAssign || op == EXP.minAssign ||
+ op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign ||
+ op == EXP.powAssign)
{
if ((type.isintegral() && t2.isfloating()))
{
- warning("`%s %s %s` is performing truncating conversion", type.toChars(), Token.toChars(op), t2.toChars());
+ warning("`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars());
}
}
// generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
- if (op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign)
+ if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign)
{
// Any multiplication by an imaginary or complex number yields a complex result.
// r *= c, i*=c, r*=i, i*=i are all forbidden operations.
- const(char)* opstr = Token.toChars(op);
+ const(char)* opstr = EXPtoString(op).ptr;
if (t1.isreal() && t2.iscomplex())
{
error("`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
}
// generate an error if this is a nonsensical += or -=, eg real += imaginary
- if (op == TOK.addAssign || op == TOK.minAssign)
+ if (op == EXP.addAssign || op == EXP.minAssign)
{
// Addition or subtraction of a real and an imaginary is a complex result.
// Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
{
- error("`%s %s %s` is undefined (result is complex)", t1.toChars(), Token.toChars(op), t2.toChars());
+ error("`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars());
return ErrorExp.get();
}
if (type.isreal() || type.isimaginary())
e2 = e2.castTo(sc, t1);
}
}
- if (op == TOK.mulAssign)
+ if (op == EXP.mulAssign)
{
if (t2.isfloating())
{
}
}
}
- else if (op == TOK.divAssign)
+ else if (op == EXP.divAssign)
{
if (t2.isimaginary())
{
}
}
}
- else if (op == TOK.modAssign)
+ else if (op == EXP.modAssign)
{
if (t2.iscomplex())
{
*/
extern (C++) class BinAssignExp : BinExp
{
- extern (D) this(const ref Loc loc, TOK op, int size, Expression e1, Expression e2)
+ extern (D) this(const ref Loc loc, EXP op, int size, Expression e1, Expression e2)
{
super(loc, op, size, e1, e2);
}
extern (D) this(const ref Loc loc, Expressions* exps)
{
- super(loc, TOK.mixin_, __traits(classInstanceSize, MixinExp));
+ super(loc, EXP.mixin_, __traits(classInstanceSize, MixinExp));
this.exps = exps;
}
{
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, TOK.import_, __traits(classInstanceSize, ImportExp), e);
+ super(loc, EXP.import_, __traits(classInstanceSize, ImportExp), e);
}
override void accept(Visitor v)
extern (D) this(const ref Loc loc, Expression e, Expression msg = null)
{
- super(loc, TOK.assert_, __traits(classInstanceSize, AssertExp), e);
+ super(loc, EXP.assert_, __traits(classInstanceSize, AssertExp), e);
this.msg = msg;
}
extern (D) this(const ref Loc loc, Expression e, Identifier ident)
{
- super(loc, TOK.dotIdentifier, __traits(classInstanceSize, DotIdExp), e);
+ super(loc, EXP.dotIdentifier, __traits(classInstanceSize, DotIdExp), e);
this.ident = ident;
}
extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td)
{
- super(loc, TOK.dotTemplateDeclaration, __traits(classInstanceSize, DotTemplateExp), e);
+ super(loc, EXP.dotTemplateDeclaration, __traits(classInstanceSize, DotTemplateExp), e);
this.td = td;
}
if (var.isVarDeclaration())
hasOverloads = false;
- super(loc, TOK.dotVariable, __traits(classInstanceSize, DotVarExp), e);
+ super(loc, EXP.dotVariable, __traits(classInstanceSize, DotVarExp), e);
//printf("DotVarExp()\n");
this.var = var;
this.hasOverloads = hasOverloads;
override bool isLvalue()
{
- if (e1.op != TOK.structLiteral)
+ if (e1.op != EXP.structLiteral)
return true;
auto vd = var.isVarDeclaration();
return !(vd && vd.isField());
}
if (!isLvalue())
return Expression.toLvalue(sc, e);
- if (e1.op == TOK.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor))
+ if (e1.op == EXP.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor))
{
if (VarDeclaration vd = var.isVarDeclaration())
{
extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs)
{
- super(loc, TOK.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
+ super(loc, EXP.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
//printf("DotTemplateInstanceExp()\n");
this.ti = new TemplateInstance(loc, name, tiargs);
}
extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti)
{
- super(loc, TOK.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
+ super(loc, EXP.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
this.ti = ti;
}
Expression e = new DotIdExp(loc, e1, ti.name);
e = e.expressionSemantic(sc);
- if (e.op == TOK.dot)
+ if (e.op == EXP.dot)
e = (cast(DotExp)e).e2;
Dsymbol s = null;
switch (e.op)
{
- case TOK.overloadSet:
+ case EXP.overloadSet:
s = (cast(OverExp)e).vars;
break;
- case TOK.dotTemplateDeclaration:
+ case EXP.dotTemplateDeclaration:
s = (cast(DotTemplateExp)e).td;
break;
- case TOK.scope_:
+ case EXP.scope_:
s = (cast(ScopeExp)e).sds;
break;
- case TOK.dotVariable:
+ case EXP.dotVariable:
s = (cast(DotVarExp)e).var;
break;
- case TOK.variable:
+ case EXP.variable:
s = (cast(VarExp)e).var;
break;
extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null)
{
- super(loc, TOK.delegate_, __traits(classInstanceSize, DelegateExp), e);
+ super(loc, EXP.delegate_, __traits(classInstanceSize, DelegateExp), e);
this.func = f;
this.hasOverloads = hasOverloads;
this.vthis2 = vthis2;
extern (D) this(const ref Loc loc, Expression e, Dsymbol s)
{
- super(loc, TOK.dotType, __traits(classInstanceSize, DotTypeExp), e);
+ super(loc, EXP.dotType, __traits(classInstanceSize, DotTypeExp), e);
this.sym = s;
}
extern (D) this(const ref Loc loc, Expression e, Expressions* exps)
{
- super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
+ super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
this.arguments = exps;
}
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
+ super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
}
extern (D) this(const ref Loc loc, Expression e, Expression earg1)
{
- super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
+ super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
this.arguments = new Expressions();
if (earg1)
this.arguments.push(earg1);
extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2)
{
- super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
+ super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
auto arguments = new Expressions(2);
(*arguments)[0] = earg1;
(*arguments)[1] = earg2;
{
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, TOK.address, __traits(classInstanceSize, AddrExp), e);
+ super(loc, EXP.address, __traits(classInstanceSize, AddrExp), e);
}
extern (D) this(const ref Loc loc, Expression e, Type t)
{
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, TOK.star, __traits(classInstanceSize, PtrExp), e);
+ super(loc, EXP.star, __traits(classInstanceSize, PtrExp), e);
//if (e.type)
// type = ((TypePointer *)e.type).next;
}
extern (D) this(const ref Loc loc, Expression e, Type t)
{
- super(loc, TOK.star, __traits(classInstanceSize, PtrExp), e);
+ super(loc, EXP.star, __traits(classInstanceSize, PtrExp), e);
type = t;
}
{
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, TOK.negate, __traits(classInstanceSize, NegExp), e);
+ super(loc, EXP.negate, __traits(classInstanceSize, NegExp), e);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, TOK.uadd, __traits(classInstanceSize, UAddExp), e);
+ super(loc, EXP.uadd, __traits(classInstanceSize, UAddExp), e);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, TOK.tilde, __traits(classInstanceSize, ComExp), e);
+ super(loc, EXP.tilde, __traits(classInstanceSize, ComExp), e);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e)
{
- super(loc, TOK.not, __traits(classInstanceSize, NotExp), e);
+ super(loc, EXP.not, __traits(classInstanceSize, NotExp), e);
}
override void accept(Visitor v)
extern (D) this(const ref Loc loc, Expression e, bool isRAII)
{
- super(loc, TOK.delete_, __traits(classInstanceSize, DeleteExp), e);
+ super(loc, EXP.delete_, __traits(classInstanceSize, DeleteExp), e);
this.isRAII = isRAII;
}
extern (D) this(const ref Loc loc, Expression e, Type t)
{
- super(loc, TOK.cast_, __traits(classInstanceSize, CastExp), e);
+ super(loc, EXP.cast_, __traits(classInstanceSize, CastExp), e);
this.to = t;
}
*/
extern (D) this(const ref Loc loc, Expression e, ubyte mod)
{
- super(loc, TOK.cast_, __traits(classInstanceSize, CastExp), e);
+ super(loc, EXP.cast_, __traits(classInstanceSize, CastExp), e);
this.mod = mod;
}
extern (D) this(const ref Loc loc, Expression e, Type t)
{
- super(loc, TOK.vector, __traits(classInstanceSize, VectorExp), e);
+ super(loc, EXP.vector, __traits(classInstanceSize, VectorExp), e);
assert(t.ty == Tvector);
to = cast(TypeVector)t;
}
{
extern (D) this(const ref Loc loc, Expression e1)
{
- super(loc, TOK.vectorArray, __traits(classInstanceSize, VectorArrayExp), e1);
+ super(loc, EXP.vectorArray, __traits(classInstanceSize, VectorArrayExp), e1);
}
override bool isLvalue()
/************************************************************/
extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie)
{
- super(loc, TOK.slice, __traits(classInstanceSize, SliceExp), e1);
+ super(loc, EXP.slice, __traits(classInstanceSize, SliceExp), e1);
this.upr = ie ? ie.upr : null;
this.lwr = ie ? ie.lwr : null;
}
extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr)
{
- super(loc, TOK.slice, __traits(classInstanceSize, SliceExp), e1);
+ super(loc, EXP.slice, __traits(classInstanceSize, SliceExp), e1);
this.upr = upr;
this.lwr = lwr;
}
return this;
}
- override bool isBool(bool result)
+ override Optional!bool toBool()
{
- return e1.isBool(result);
+ return e1.toBool();
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1)
{
- super(loc, TOK.arrayLength, __traits(classInstanceSize, ArrayLengthExp), e1);
+ super(loc, EXP.arrayLength, __traits(classInstanceSize, ArrayLengthExp), e1);
}
override void accept(Visitor v)
extern (D) this(const ref Loc loc, Expression e1, Expression index = null)
{
- super(loc, TOK.array, __traits(classInstanceSize, ArrayExp), e1);
+ super(loc, EXP.array, __traits(classInstanceSize, ArrayExp), e1);
arguments = new Expressions();
if (index)
arguments.push(index);
extern (D) this(const ref Loc loc, Expression e1, Expressions* args)
{
- super(loc, TOK.array, __traits(classInstanceSize, ArrayExp), e1);
+ super(loc, EXP.array, __traits(classInstanceSize, ArrayExp), e1);
arguments = args;
}
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.dot, __traits(classInstanceSize, DotExp), e1, e2);
+ super(loc, EXP.dot, __traits(classInstanceSize, DotExp), e1, e2);
}
override void accept(Visitor v)
extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true)
{
- super(loc, TOK.comma, __traits(classInstanceSize, CommaExp), e1, e2);
+ super(loc, EXP.comma, __traits(classInstanceSize, CommaExp), e1, e2);
allowCommaExp = isGenerated = generated;
}
return this;
}
- override bool isBool(bool result)
+ override Optional!bool toBool()
{
- return e2.isBool(result);
+ return e2.toBool();
}
override Expression addDtorHook(Scope* sc)
extern (D) this(const ref Loc loc, Expression lwr, Expression upr)
{
- super(loc, TOK.interval, __traits(classInstanceSize, IntervalExp));
+ super(loc, EXP.interval, __traits(classInstanceSize, IntervalExp));
this.lwr = lwr;
this.upr = upr;
}
{
extern (D) this(const ref Loc loc, Expression e1)
{
- super(loc, TOK.delegatePointer, __traits(classInstanceSize, DelegatePtrExp), e1);
+ super(loc, EXP.delegatePointer, __traits(classInstanceSize, DelegatePtrExp), e1);
}
override bool isLvalue()
{
extern (D) this(const ref Loc loc, Expression e1)
{
- super(loc, TOK.delegateFunctionPointer, __traits(classInstanceSize, DelegateFuncptrExp), e1);
+ super(loc, EXP.delegateFunctionPointer, __traits(classInstanceSize, DelegateFuncptrExp), e1);
}
override bool isLvalue()
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.index, __traits(classInstanceSize, IndexExp), e1, e2);
+ super(loc, EXP.index, __traits(classInstanceSize, IndexExp), e1, e2);
//printf("IndexExp::IndexExp('%s')\n", toChars());
}
override bool isLvalue()
{
- if (e1.op == TOK.assocArrayLiteral)
+ if (e1.op == EXP.assocArrayLiteral)
return false;
if (e1.type.ty == Tsarray ||
- (e1.op == TOK.index && e1.type.ty != Tarray))
+ (e1.op == EXP.index && e1.type.ty != Tarray))
{
return e1.isLvalue();
}
{
//printf("IndexExp::modifiableLvalue(%s)\n", toChars());
Expression ex = markSettingAAElem();
- if (ex.op == TOK.error)
+ if (ex.op == EXP.error)
return ex;
return Expression.modifiableLvalue(sc, e);
if (auto ie = e1.isIndexExp())
{
Expression ex = ie.markSettingAAElem();
- if (ex.op == TOK.error)
+ if (ex.op == EXP.error)
return ex;
assert(ex == e1);
}
*/
extern (C++) final class PostExp : BinExp
{
- extern (D) this(TOK op, const ref Loc loc, Expression e)
+ extern (D) this(EXP op, const ref Loc loc, Expression e)
{
super(loc, op, __traits(classInstanceSize, PostExp), e, IntegerExp.literal!1);
- assert(op == TOK.minusMinus || op == TOK.plusPlus);
+ assert(op == EXP.minusMinus || op == EXP.plusPlus);
}
override void accept(Visitor v)
*/
extern (C++) final class PreExp : UnaExp
{
- extern (D) this(TOK op, const ref Loc loc, Expression e)
+ extern (D) this(EXP op, const ref Loc loc, Expression e)
{
super(loc, op, __traits(classInstanceSize, PreExp), e);
- assert(op == TOK.preMinusMinus || op == TOK.prePlusPlus);
+ assert(op == EXP.preMinusMinus || op == EXP.prePlusPlus);
}
override void accept(Visitor v)
MemorySet memset;
/************************************************************/
- /* op can be TOK.assign, TOK.construct, or TOK.blit */
+ /* op can be EXP.assign, EXP.construct, or EXP.blit */
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.assign, __traits(classInstanceSize, AssignExp), e1, e2);
+ super(loc, EXP.assign, __traits(classInstanceSize, AssignExp), e1, e2);
}
- this(const ref Loc loc, TOK tok, Expression e1, Expression e2)
+ this(const ref Loc loc, EXP tok, Expression e1, Expression e2)
{
super(loc, tok, __traits(classInstanceSize, AssignExp), e1, e2);
}
{
// Array-op 'x[] = y[]' should make an rvalue.
// Setting array length 'x.length = v' should make an rvalue.
- if (e1.op == TOK.slice || e1.op == TOK.arrayLength)
+ if (e1.op == EXP.slice || e1.op == EXP.arrayLength)
{
return false;
}
override final Expression toLvalue(Scope* sc, Expression ex)
{
- if (e1.op == TOK.slice || e1.op == TOK.arrayLength)
+ if (e1.op == EXP.slice || e1.op == EXP.arrayLength)
{
return Expression.toLvalue(sc, ex);
}
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.construct, e1, e2);
+ super(loc, EXP.construct, e1, e2);
}
// Internal use only. If `v` is a reference variable, the assignment
auto ve = new VarExp(loc, v);
assert(v.type && ve.type);
- super(loc, TOK.construct, ve, e2);
+ super(loc, EXP.construct, ve, e2);
if (v.isReference())
memset = MemorySet.referenceInit;
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.blit, e1, e2);
+ super(loc, EXP.blit, e1, e2);
}
// Internal use only. If `v` is a reference variable, the assinment
auto ve = new VarExp(loc, v);
assert(v.type && ve.type);
- super(loc, TOK.blit, ve, e2);
+ super(loc, EXP.blit, ve, e2);
if (v.isReference())
memset = MemorySet.referenceInit;
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.addAssign, __traits(classInstanceSize, AddAssignExp), e1, e2);
+ super(loc, EXP.addAssign, __traits(classInstanceSize, AddAssignExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.minAssign, __traits(classInstanceSize, MinAssignExp), e1, e2);
+ super(loc, EXP.minAssign, __traits(classInstanceSize, MinAssignExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.mulAssign, __traits(classInstanceSize, MulAssignExp), e1, e2);
+ super(loc, EXP.mulAssign, __traits(classInstanceSize, MulAssignExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.divAssign, __traits(classInstanceSize, DivAssignExp), e1, e2);
+ super(loc, EXP.divAssign, __traits(classInstanceSize, DivAssignExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.modAssign, __traits(classInstanceSize, ModAssignExp), e1, e2);
+ super(loc, EXP.modAssign, __traits(classInstanceSize, ModAssignExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.andAssign, __traits(classInstanceSize, AndAssignExp), e1, e2);
+ super(loc, EXP.andAssign, __traits(classInstanceSize, AndAssignExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.orAssign, __traits(classInstanceSize, OrAssignExp), e1, e2);
+ super(loc, EXP.orAssign, __traits(classInstanceSize, OrAssignExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.xorAssign, __traits(classInstanceSize, XorAssignExp), e1, e2);
+ super(loc, EXP.xorAssign, __traits(classInstanceSize, XorAssignExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.powAssign, __traits(classInstanceSize, PowAssignExp), e1, e2);
+ super(loc, EXP.powAssign, __traits(classInstanceSize, PowAssignExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.leftShiftAssign, __traits(classInstanceSize, ShlAssignExp), e1, e2);
+ super(loc, EXP.leftShiftAssign, __traits(classInstanceSize, ShlAssignExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.rightShiftAssign, __traits(classInstanceSize, ShrAssignExp), e1, e2);
+ super(loc, EXP.rightShiftAssign, __traits(classInstanceSize, ShrAssignExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.unsignedRightShiftAssign, __traits(classInstanceSize, UshrAssignExp), e1, e2);
+ super(loc, EXP.unsignedRightShiftAssign, __traits(classInstanceSize, UshrAssignExp), e1, e2);
}
override void accept(Visitor v)
/***********************************************************
* The ~= operator. It can have one of the following operators:
*
- * TOK.concatenateAssign - appending T[] to T[]
- * TOK.concatenateElemAssign - appending T to T[]
- * TOK.concatenateDcharAssign - appending dchar to T[]
+ * EXP.concatenateAssign - appending T[] to T[]
+ * EXP.concatenateElemAssign - appending T to T[]
+ * EXP.concatenateDcharAssign - appending dchar to T[]
*
- * The parser initially sets it to TOK.concatenateAssign, and semantic() later decides which
+ * The parser initially sets it to EXP.concatenateAssign, and semantic() later decides which
* of the three it will be set to.
*/
extern (C++) class CatAssignExp : BinAssignExp
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.concatenateAssign, __traits(classInstanceSize, CatAssignExp), e1, e2);
+ super(loc, EXP.concatenateAssign, __traits(classInstanceSize, CatAssignExp), e1, e2);
}
- extern (D) this(const ref Loc loc, TOK tok, Expression e1, Expression e2)
+ extern (D) this(const ref Loc loc, EXP tok, Expression e1, Expression e2)
{
super(loc, tok, __traits(classInstanceSize, CatAssignExp), e1, e2);
}
{
extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
{
- super(loc, TOK.concatenateElemAssign, e1, e2);
+ super(loc, EXP.concatenateElemAssign, e1, e2);
this.type = type;
}
{
extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
{
- super(loc, TOK.concatenateDcharAssign, e1, e2);
+ super(loc, EXP.concatenateDcharAssign, e1, e2);
this.type = type;
}
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.add, __traits(classInstanceSize, AddExp), e1, e2);
+ super(loc, EXP.add, __traits(classInstanceSize, AddExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.min, __traits(classInstanceSize, MinExp), e1, e2);
+ super(loc, EXP.min, __traits(classInstanceSize, MinExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.concatenate, __traits(classInstanceSize, CatExp), e1, e2);
+ super(loc, EXP.concatenate, __traits(classInstanceSize, CatExp), e1, e2);
}
override Expression resolveLoc(const ref Loc loc, Scope* sc)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.mul, __traits(classInstanceSize, MulExp), e1, e2);
+ super(loc, EXP.mul, __traits(classInstanceSize, MulExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.div, __traits(classInstanceSize, DivExp), e1, e2);
+ super(loc, EXP.div, __traits(classInstanceSize, DivExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.mod, __traits(classInstanceSize, ModExp), e1, e2);
+ super(loc, EXP.mod, __traits(classInstanceSize, ModExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.pow, __traits(classInstanceSize, PowExp), e1, e2);
+ super(loc, EXP.pow, __traits(classInstanceSize, PowExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.leftShift, __traits(classInstanceSize, ShlExp), e1, e2);
+ super(loc, EXP.leftShift, __traits(classInstanceSize, ShlExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.rightShift, __traits(classInstanceSize, ShrExp), e1, e2);
+ super(loc, EXP.rightShift, __traits(classInstanceSize, ShrExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.unsignedRightShift, __traits(classInstanceSize, UshrExp), e1, e2);
+ super(loc, EXP.unsignedRightShift, __traits(classInstanceSize, UshrExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.and, __traits(classInstanceSize, AndExp), e1, e2);
+ super(loc, EXP.and, __traits(classInstanceSize, AndExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.or, __traits(classInstanceSize, OrExp), e1, e2);
+ super(loc, EXP.or, __traits(classInstanceSize, OrExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.xor, __traits(classInstanceSize, XorExp), e1, e2);
+ super(loc, EXP.xor, __traits(classInstanceSize, XorExp), e1, e2);
}
override void accept(Visitor v)
*/
extern (C++) final class LogicalExp : BinExp
{
- extern (D) this(const ref Loc loc, TOK op, Expression e1, Expression e2)
+ extern (D) this(const ref Loc loc, EXP op, Expression e1, Expression e2)
{
super(loc, op, __traits(classInstanceSize, LogicalExp), e1, e2);
- assert(op == TOK.andAnd || op == TOK.orOr);
+ assert(op == EXP.andAnd || op == EXP.orOr);
}
override void accept(Visitor v)
/***********************************************************
* `op` is one of:
- * TOK.lessThan, TOK.lessOrEqual, TOK.greaterThan, TOK.greaterOrEqual
+ * EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual
*
* http://dlang.org/spec/expression.html#relation_expressions
*/
extern (C++) final class CmpExp : BinExp
{
- extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2)
+ extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
{
super(loc, op, __traits(classInstanceSize, CmpExp), e1, e2);
- assert(op == TOK.lessThan || op == TOK.lessOrEqual || op == TOK.greaterThan || op == TOK.greaterOrEqual);
+ assert(op == EXP.lessThan || op == EXP.lessOrEqual || op == EXP.greaterThan || op == EXP.greaterOrEqual);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.in_, __traits(classInstanceSize, InExp), e1, e2);
+ super(loc, EXP.in_, __traits(classInstanceSize, InExp), e1, e2);
}
override void accept(Visitor v)
{
extern (D) this(const ref Loc loc, Expression e1, Expression e2)
{
- super(loc, TOK.remove, __traits(classInstanceSize, RemoveExp), e1, e2);
+ super(loc, EXP.remove, __traits(classInstanceSize, RemoveExp), e1, e2);
type = Type.tbool;
}
/***********************************************************
* `==` and `!=`
*
- * TOK.equal and TOK.notEqual
+ * EXP.equal and EXP.notEqual
*
* http://dlang.org/spec/expression.html#equality_expressions
*/
extern (C++) final class EqualExp : BinExp
{
- extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2)
+ extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
{
super(loc, op, __traits(classInstanceSize, EqualExp), e1, e2);
- assert(op == TOK.equal || op == TOK.notEqual);
+ assert(op == EXP.equal || op == EXP.notEqual);
}
override void accept(Visitor v)
/***********************************************************
* `is` and `!is`
*
- * TOK.identity and TOK.notIdentity
+ * EXP.identity and EXP.notIdentity
*
* http://dlang.org/spec/expression.html#identity_expressions
*/
extern (C++) final class IdentityExp : BinExp
{
- extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2)
+ extern (D) this(EXP op, const ref Loc loc, Expression e1, Expression e2)
{
super(loc, op, __traits(classInstanceSize, IdentityExp), e1, e2);
- assert(op == TOK.identity || op == TOK.notIdentity);
+ assert(op == EXP.identity || op == EXP.notIdentity);
}
override void accept(Visitor v)
extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2)
{
- super(loc, TOK.question, __traits(classInstanceSize, CondExp), e1, e2);
+ super(loc, EXP.question, __traits(classInstanceSize, CondExp), e1, e2);
this.econd = econd;
}
//printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
Expression ve = new VarExp(vcond.loc, vcond);
if (isThen)
- v.edtor = new LogicalExp(v.edtor.loc, TOK.andAnd, ve, v.edtor);
+ v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor);
else
- v.edtor = new LogicalExp(v.edtor.loc, TOK.orOr, ve, v.edtor);
+ v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor);
v.edtor = v.edtor.expressionSemantic(sc);
//printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
}
}
/// Returns: if this token is the `op` for a derived `DefaultInitExp` class.
-bool isDefaultInitOp(TOK op) pure nothrow @safe @nogc
+bool isDefaultInitOp(EXP op) pure nothrow @safe @nogc
{
- return op == TOK.prettyFunction || op == TOK.functionString ||
- op == TOK.line || op == TOK.moduleString ||
- op == TOK.file || op == TOK.fileFullPath ;
+ return op == EXP.prettyFunction || op == EXP.functionString ||
+ op == EXP.line || op == EXP.moduleString ||
+ op == EXP.file || op == EXP.fileFullPath ;
}
/***********************************************************
*/
extern (C++) class DefaultInitExp : Expression
{
- extern (D) this(const ref Loc loc, TOK op, int size)
+ extern (D) this(const ref Loc loc, EXP op, int size)
{
super(loc, op, size);
}
*/
extern (C++) final class FileInitExp : DefaultInitExp
{
- extern (D) this(const ref Loc loc, TOK tok)
+ extern (D) this(const ref Loc loc, EXP tok)
{
super(loc, tok, __traits(classInstanceSize, FileInitExp));
}
{
//printf("FileInitExp::resolve() %s\n", toChars());
const(char)* s;
- if (op == TOK.fileFullPath)
+ if (op == EXP.fileFullPath)
s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars());
else
s = loc.isValid() ? loc.filename : sc._module.ident.toChars();
{
extern (D) this(const ref Loc loc)
{
- super(loc, TOK.line, __traits(classInstanceSize, LineInitExp));
+ super(loc, EXP.line, __traits(classInstanceSize, LineInitExp));
}
override Expression resolveLoc(const ref Loc loc, Scope* sc)
{
extern (D) this(const ref Loc loc)
{
- super(loc, TOK.moduleString, __traits(classInstanceSize, ModuleInitExp));
+ super(loc, EXP.moduleString, __traits(classInstanceSize, ModuleInitExp));
}
override Expression resolveLoc(const ref Loc loc, Scope* sc)
{
extern (D) this(const ref Loc loc)
{
- super(loc, TOK.functionString, __traits(classInstanceSize, FuncInitExp));
+ super(loc, EXP.functionString, __traits(classInstanceSize, FuncInitExp));
}
override Expression resolveLoc(const ref Loc loc, Scope* sc)
{
extern (D) this(const ref Loc loc)
{
- super(loc, TOK.prettyFunction, __traits(classInstanceSize, PrettyFuncInitExp));
+ super(loc, EXP.prettyFunction, __traits(classInstanceSize, PrettyFuncInitExp));
}
override Expression resolveLoc(const ref Loc loc, Scope* sc)
extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration)
{
- super(loc, TOK.objcClassReference,
+ super(loc, EXP.objcClassReference,
__traits(classInstanceSize, ObjcClassReferenceExp));
this.classDeclaration = classDeclaration;
type = objc.getRuntimeMetaclass(classDeclaration).getType();
extern (D) this(const ref Loc loc, Expression cntlExp, Types* types, Expressions* exps)
{
- super(loc, TOK._Generic, __traits(classInstanceSize, GenericExp));
+ super(loc, EXP._Generic, __traits(classInstanceSize, GenericExp));
this.cntlExp = cntlExp;
this.types = types;
this.exps = exps;
{
switch(exp.op)
{
- case TOK.variable:
+ case EXP.variable:
auto varExp = cast(VarExp)exp;
//printf("VarExp::checkModifiable %s", varExp.toChars());
assert(varExp.type);
return varExp.var.checkModify(varExp.loc, sc, null, flag);
- case TOK.dotVariable:
+ case EXP.dotVariable:
auto dotVarExp = cast(DotVarExp)exp;
//printf("DotVarExp::checkModifiable %s %s\n", dotVarExp.toChars(), dotVarExp.type.toChars());
- if (dotVarExp.e1.op == TOK.this_)
+ if (dotVarExp.e1.op == EXP.this_)
return dotVarExp.var.checkModify(dotVarExp.loc, sc, dotVarExp.e1, flag);
/* https://issues.dlang.org/show_bug.cgi?id=12764
onlyUnion = false;
// Another DotVarExp left?
- if (!dve.e1 || dve.e1.op != TOK.dotVariable)
+ if (!dve.e1 || dve.e1.op != EXP.dotVariable)
break;
dve = cast(DotVarExp) dve.e1;
}
- if (dve.e1.op == TOK.this_)
+ if (dve.e1.op == EXP.this_)
{
scope v = dve.var.isVarDeclaration();
/* if v is a struct member field with no initializer, no default construction
//printf("\te1 = %s\n", e1.toChars());
return dotVarExp.e1.checkModifiable(sc, flag);
- case TOK.star:
+ case EXP.star:
auto ptrExp = cast(PtrExp)exp;
if (auto se = ptrExp.e1.isSymOffExp())
{
}
return Modifiable.yes;
- case TOK.slice:
+ case EXP.slice:
auto sliceExp = cast(SliceExp)exp;
//printf("SliceExp::checkModifiable %s\n", sliceExp.toChars());
auto e1 = sliceExp.e1;
- if (e1.type.ty == Tsarray || (e1.op == TOK.index && e1.type.ty != Tarray) || e1.op == TOK.slice)
+ if (e1.type.ty == Tsarray || (e1.op == EXP.index && e1.type.ty != Tarray) || e1.op == EXP.slice)
{
return e1.checkModifiable(sc, flag);
}
return Modifiable.yes;
- case TOK.comma:
+ case EXP.comma:
return (cast(CommaExp)exp).e2.checkModifiable(sc, flag);
- case TOK.index:
+ case EXP.index:
auto indexExp = cast(IndexExp)exp;
auto e1 = indexExp.e1;
if (e1.type.ty == Tsarray ||
e1.type.ty == Taarray ||
- (e1.op == TOK.index && e1.type.ty != Tarray) ||
- e1.op == TOK.slice)
+ (e1.op == EXP.index && e1.type.ty != Tarray) ||
+ e1.op == EXP.slice)
{
return e1.checkModifiable(sc, flag);
}
return Modifiable.yes;
- case TOK.question:
+ case EXP.question:
auto condExp = cast(CondExp)exp;
if (condExp.e1.checkModifiable(sc, flag) != Modifiable.no
&& condExp.e2.checkModifiable(sc, flag) != Modifiable.no)
#include "tokens.h"
#include "root/dcompat.h"
+#include "root/optional.h"
class Type;
class TypeVector;
class Expression : public ASTNode
{
public:
- TOK op; // to minimize use of dynamic_cast
+ EXP op; // to minimize use of dynamic_cast
unsigned char size; // # of bytes in Expression so we can copy() it
unsigned char parens; // if this is a parenthesized expression
Type *type; // !=NULL means that semantic() has been run
// A compile-time result is required. Give an error if not possible
Expression *ctfeInterpret();
int isConst();
- virtual bool isBool(bool result);
-
+ virtual Optional<bool> toBool();
virtual bool hasCode()
{
return true;
real_t toReal();
real_t toImaginary();
complex_t toComplex();
- bool isBool(bool result);
+ Optional<bool> toBool();
Expression *toLvalue(Scope *sc, Expression *e);
void accept(Visitor *v) { v->visit(this); }
dinteger_t getInteger() { return value; }
real_t toReal();
real_t toImaginary();
complex_t toComplex();
- bool isBool(bool result);
+ Optional<bool> toBool();
void accept(Visitor *v) { v->visit(this); }
};
real_t toReal();
real_t toImaginary();
complex_t toComplex();
- bool isBool(bool result);
+ Optional<bool> toBool();
void accept(Visitor *v) { v->visit(this); }
};
VarDeclaration *var;
ThisExp *syntaxCopy();
- bool isBool(bool result);
+ Optional<bool> toBool();
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
{
public:
bool equals(const RootObject *o) const;
- bool isBool(bool result);
+ Optional<bool> toBool();
StringExp *toStringExp();
void accept(Visitor *v) { v->visit(this); }
};
bool equals(const RootObject *o) const;
StringExp *toStringExp();
StringExp *toUTF8(Scope *sc);
- bool isBool(bool result);
+ Optional<bool> toBool();
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
bool equals(const RootObject *o) const;
Expression *getElement(d_size_t i); // use opIndex instead
Expression *opIndex(d_size_t i);
- bool isBool(bool result);
+ Optional<bool> toBool();
StringExp *toStringExp();
void accept(Visitor *v) { v->visit(this); }
bool equals(const RootObject *o) const;
AssocArrayLiteralExp *syntaxCopy();
- bool isBool(bool result);
+ Optional<bool> toBool();
void accept(Visitor *v) { v->visit(this); }
};
public:
dinteger_t offset;
- bool isBool(bool result);
+ Optional<bool> toBool();
void accept(Visitor *v) { v->visit(this); }
};
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
- bool isBool(bool result);
+ Optional<bool> toBool();
void accept(Visitor *v) { v->visit(this); }
};
bool isLvalue();
Expression *toLvalue(Scope *sc, Expression *e);
Expression *modifiableLvalue(Scope *sc, Expression *e);
- bool isBool(bool result);
+ Optional<bool> toBool();
Expression *addDtorHook(Scope *sc);
void accept(Visitor *v) { v->visit(this); }
};
// allowed to contain types as well as expressions
auto e4 = ctfeInterpretForPragmaMsg(e3);
- if (!e4 || e4.op == TOK.error)
+ if (!e4 || e4.op == EXP.error)
return true;
// expand tuple
exp = resolveProperties(sc, exp);
sc = sc.endCTFE();
- if (exp.op == TOK.error)
+ if (exp.op == EXP.error)
return null;
auto e = exp;
if (exp.type.isString())
{
e = e.ctfeInterpret();
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
return null;
}
if (i == 0)
*pe0 = extractOpDollarSideEffect(sc, ae);
- if (e.op == TOK.interval && !(slice && slice.isTemplateDeclaration()))
+ if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration()))
{
Lfallback:
if (ae.arguments.dim == 1)
ae.error("`%s` has no value", e.toChars());
e = ErrorExp.get();
}
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
return e;
(*ae.arguments)[i] = e;
if (e)
{
auto e2 = e.expressionSemantic(sc);
- if (e2.op == TOK.error)
+ if (e2.op == EXP.error)
err = true;
- if (preserveErrors || e2.op != TOK.error)
+ if (preserveErrors || e2.op != EXP.error)
e = e2;
}
}
{
if (Expression ey = die.semanticY(sc, 1))
{
- if (ey.op == TOK.error)
+ if (ey.op == EXP.error)
return ey;
ce.e1 = ey;
if (isDotOpDispatch(ey))
Type t = e1.type.toBasetype();
//printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
- if (e1.op == TOK.objcClassReference)
+ if (e1.op == EXP.objcClassReference)
{
// We already have an Objective-C class reference, just use that as 'this'.
return e1;
* class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B`
* class B {int m; inc() { new A().inc!m(); } }
*/
- if (e1.op == TOK.this_)
+ if (e1.op == EXP.this_)
{
FuncDeclaration f = hasThis(sc);
if (f && f.isThis2)
e1 = new PtrExp(loc, e1);
e1 = new IndexExp(loc, e1, IntegerExp.literal!1);
e1 = getThisSkipNestedFuncs(loc, sc, f.toParent2(), ad, e1, t, var);
- if (e1.op == TOK.error)
+ if (e1.op == EXP.error)
return e1;
goto L1;
}
// Skip up over nested functions, and get the enclosing
// class type.
e1 = getThisSkipNestedFuncs(loc, sc, tcd.toParentP(ad), ad, e1, t, var);
- if (e1.op == TOK.error)
+ if (e1.op == EXP.error)
return e1;
goto L1;
}
*/
private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null)
{
- //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", Token.toChars(e1.op), e1.toChars(), e2 ? e2.toChars() : null);
+ //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
Loc loc = e1.loc;
OverloadSet os;
if (e2)
{
e2 = e2.expressionSemantic(sc);
- if (e2.op == TOK.error)
+ if (e2.op == EXP.error)
return ErrorExp.get();
e2 = resolveProperties(sc, e2);
tthis = null;
goto Lfd;
}
- else if (e1.op == TOK.dotVariable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(DotVarExp)e1).var.isOverDeclaration()))
+ else if (e1.op == EXP.dotVariable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(DotVarExp)e1).var.isOverDeclaration()))
{
DotVarExp dve = cast(DotVarExp)e1;
s = dve.var;
tthis = dve.e1.type;
goto Lfd;
}
- else if (sc && sc.flags & SCOPE.Cfile && e1.op == TOK.variable && !e2)
+ else if (sc && sc.flags & SCOPE.Cfile && e1.op == EXP.variable && !e2)
{
// ImportC: do not implicitly call function if no ( ) are present
}
- else if (e1.op == TOK.variable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(VarExp)e1).var.isOverDeclaration()))
+ else if (e1.op == EXP.variable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(VarExp)e1).var.isOverDeclaration()))
{
s = (cast(VarExp)e1).var;
tiargs = null;
if (e2)
{
e2 = e2.expressionSemantic(sc);
- if (e2.op == TOK.error)
+ if (e2.op == EXP.error)
return ErrorExp.get();
e2 = resolveProperties(sc, e2);
if (e2)
goto Leprop;
}
- if (e1.op == TOK.variable)
+ if (e1.op == EXP.variable)
{
VarExp ve = cast(VarExp)e1;
VarDeclaration v = ve.var.isVarDeclaration();
if (e2)
return null;
- if (e1.type && e1.op != TOK.type) // function type is not a property
+ if (e1.type && e1.op != EXP.type) // function type is not a property
{
/* Look for e1 being a lazy parameter; rewrite as delegate call
* only if the symbol wasn't already treated as a delegate
Expression e = new CallExp(loc, e1);
return e.expressionSemantic(sc);
}
- else if (e1.op == TOK.dotVariable)
+ else if (e1.op == EXP.dotVariable)
{
// Check for reading overlapped pointer field in @safe code.
if (checkUnsafeAccess(sc, e1, true, true))
return ErrorExp.get();
}
- else if (e1.op == TOK.call)
+ else if (e1.op == EXP.call)
{
CallExp ce = cast(CallExp)e1;
// Check for reading overlapped pointer field in @safe code.
t0 = Type.terror;
continue;
}
- if (e.op == TOK.type)
+ if (e.op == EXP.type)
{
foundType = true; // do not break immediately, there might be more errors
e.checkValue(); // report an error "type T has no value"
condexp.e2 = e;
condexp.loc = e.loc;
Expression ex = condexp.expressionSemantic(sc);
- if (ex.op == TOK.error)
+ if (ex.op == EXP.error)
e = ex;
- else if (e.op == TOK.function_ || e.op == TOK.delegate_)
+ 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
}
e0 = e;
t0 = e.type;
- if (e.op != TOK.error)
+ if (e.op != EXP.error)
exps[i] = e;
}
continue;
e = e.implicitCastTo(sc, t0);
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
{
/* https://issues.dlang.org/show_bug.cgi?id=13024
* a workaround for the bug in typeMerge -
return t0;
}
-private Expression opAssignToOp(const ref Loc loc, TOK op, Expression e1, Expression e2)
+private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expression e2)
{
Expression e;
switch (op)
{
- case TOK.addAssign:
+ case EXP.addAssign:
e = new AddExp(loc, e1, e2);
break;
- case TOK.minAssign:
+ case EXP.minAssign:
e = new MinExp(loc, e1, e2);
break;
- case TOK.mulAssign:
+ case EXP.mulAssign:
e = new MulExp(loc, e1, e2);
break;
- case TOK.divAssign:
+ case EXP.divAssign:
e = new DivExp(loc, e1, e2);
break;
- case TOK.modAssign:
+ case EXP.modAssign:
e = new ModExp(loc, e1, e2);
break;
- case TOK.andAssign:
+ case EXP.andAssign:
e = new AndExp(loc, e1, e2);
break;
- case TOK.orAssign:
+ case EXP.orAssign:
e = new OrExp(loc, e1, e2);
break;
- case TOK.xorAssign:
+ case EXP.xorAssign:
e = new XorExp(loc, e1, e2);
break;
- case TOK.leftShiftAssign:
+ case EXP.leftShiftAssign:
e = new ShlExp(loc, e1, e2);
break;
- case TOK.rightShiftAssign:
+ case EXP.rightShiftAssign:
e = new ShrExp(loc, e1, e2);
break;
- case TOK.unsignedRightShiftAssign:
+ case EXP.unsignedRightShiftAssign:
e = new UshrExp(loc, e1, e2);
break;
{
Expression e;
- assert(exp.e1.op == TOK.arrayLength);
+ assert(exp.e1.op == EXP.arrayLength);
ArrayLengthExp ale = cast(ArrayLengthExp)exp.e1;
- if (ale.e1.op == TOK.variable)
+ if (ale.e1.op == EXP.variable)
{
e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
e = new AssignExp(exp.loc, ale.syntaxCopy(), e);
Expression arg = (*exps)[i];
arg = resolveProperties(sc, arg);
arg = arg.arrayFuncConv(sc);
- if (arg.op == TOK.type)
+ if (arg.op == EXP.type)
{
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
arg = resolveAliasThis(sc, arg);
- if (arg.op == TOK.type)
+ if (arg.op == EXP.type)
{
if (reportErrors)
{
/* Argument value cannot escape from the called function.
*/
Expression a = arg;
- if (a.op == TOK.cast_)
+ if (a.op == EXP.cast_)
a = (cast(CastExp)a).e1;
ArrayLiteralExp ale;
arg = CommaExp.combine(declareTmp, castToSlice);
arg = arg.expressionSemantic(sc);
}
- else if (a.op == TOK.function_)
+ else if (a.op == EXP.function_)
{
/* Function literals can only appear once, so if this
* appearance was scoped, there cannot be any others.
FuncExp fe = cast(FuncExp)a;
fe.fd.tookAddressOf = 0;
}
- else if (a.op == TOK.delegate_)
+ else if (a.op == EXP.delegate_)
{
/* For passing a delegate to a scoped parameter,
* this doesn't count as taking the address of it.
* We only worry about 'escaping' references to the function.
*/
DelegateExp de = cast(DelegateExp)a;
- if (de.e1.op == TOK.variable)
+ if (de.e1.op == EXP.variable)
{
VarExp ve = cast(VarExp)de.e1;
FuncDeclaration f = ve.var.isFuncDeclaration();
//arg = callCpCtor(sc, arg);
}
// Give error for overloaded function addresses
- if (arg.op == TOK.symbolOffset)
+ if (arg.op == EXP.symbolOffset)
{
SymOffExp se = cast(SymOffExp)arg;
if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
// edtor => (__gate || edtor)
assert(tmp.edtor);
Expression e = tmp.edtor;
- e = new LogicalExp(e.loc, TOK.orOr, new VarExp(e.loc, gate), e);
+ e = new LogicalExp(e.loc, EXP.orOr, new VarExp(e.loc, gate), e);
tmp.edtor = e.expressionSemantic(sc);
//printf("edtor: %s\n", tmp.edtor.toChars());
}
}
}
// Try Type.opDispatch (so the static version)
- else if (ss.withstate.exp && ss.withstate.exp.op == TOK.type)
+ else if (ss.withstate.exp && ss.withstate.exp.op == EXP.type)
{
if (Type t = ss.withstate.exp.isTypeExp().type)
{
exp.error("`%s` has no value", e.toChars());
err = true;
}
- else if (e.op == TOK.error)
+ else if (e.op == EXP.error)
err = true;
else
(*exp.exps)[i] = e;
if (e.basis)
e.basis = e.basis.expressionSemantic(sc);
- if (arrayExpressionSemantic(e.elements, sc) || (e.basis && e.basis.op == TOK.error))
+ if (arrayExpressionSemantic(e.elements, sc) || (e.basis && e.basis.op == EXP.error))
return setError();
expandTuples(e.elements);
if (exp.thisexp)
{
exp.thisexp = exp.thisexp.expressionSemantic(sc);
- if (exp.thisexp.op == TOK.error)
+ if (exp.thisexp.op == EXP.error)
return setError();
cdthis = exp.thisexp.type.isClassHandle();
}
exp.thisexp = exp.thisexp.expressionSemantic(sc);
- if (exp.thisexp.op == TOK.error)
+ if (exp.thisexp.op == EXP.error)
return setError();
cdthis = exp.thisexp.type.isClassHandle();
}
if (AggregateDeclaration ad2 = cd.isMember2())
{
Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
- if (te.op != TOK.error)
+ if (te.op != EXP.error)
te = getRightThis(exp.loc, sc, ad2, te, cd);
- if (te.op == TOK.error)
+ if (te.op == EXP.error)
{
exp.error("need `this` of type `%s` needed to `new` nested class `%s`", ad2.toChars(), cd.toChars());
return setError();
}
}
- if (sd.ctor && nargs)
+ if (sd.hasRegularCtor() && nargs)
{
FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.arguments, FuncResolveFlag.standard);
if (!f || f.errors)
Expression arg = (*exp.arguments)[i];
arg = resolveProperties(sc, arg);
arg = arg.implicitCastTo(sc, Type.tsize_t);
- if (arg.op == TOK.error)
+ if (arg.op == EXP.error)
return setError();
arg = arg.optimize(WANTvalue);
- if (arg.op == TOK.int64 && cast(sinteger_t)arg.toInteger() < 0)
+ if (arg.op == EXP.int64 && cast(sinteger_t)arg.toInteger() < 0)
{
exp.error("negative array index `%s`", arg.toChars());
return setError();
* auto foo(void function() fp) { return 1; }
* assert(foo({}) == 1);
*
- * So, should keep fd.tok == TOKreserve if fd.treq == NULL.
+ * So, should keep fd.tok == TOK.reserve if fd.treq == NULL.
*/
if (exp.fd.treq && exp.fd.treq.ty == Tpointer)
{
for (size_t k = 0; k < arguments.dim; k++)
{
Expression checkarg = (*arguments)[k];
- if (checkarg.op == TOK.error)
+ if (checkarg.op == EXP.error)
return checkarg;
}
Type tthis = null;
Expression e1org = exp.e1;
- if (exp.e1.op == TOK.comma)
+ if (exp.e1.op == EXP.comma)
{
/* Rewrite (a,b)(args) as (a,(b(args)))
*/
result = ce.expressionSemantic(sc);
return;
}
- if (exp.e1.op == TOK.delegate_)
+ if (exp.e1.op == EXP.delegate_)
{
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 == TOK.function_)
+ if (exp.e1.op == EXP.function_)
{
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 == TOK.error)
+ if (exp.e1.op == EXP.error)
{
result = exp.e1;
return;
/* This recognizes:
* foo!(tiargs)(funcargs)
*/
- if (exp.e1.op == TOK.scope_)
+ if (exp.e1.op == EXP.scope_)
{
ScopeExp se = cast(ScopeExp)exp.e1;
TemplateInstance ti = se.sds.isTemplateInstance();
else
{
Expression e1x = exp.e1.expressionSemantic(sc);
- if (e1x.op == TOK.error)
+ if (e1x.op == EXP.error)
{
result = e1x;
return;
* expr.foo!(tiargs)(funcargs)
*/
Ldotti:
- if (exp.e1.op == TOK.dotTemplateInstance)
+ if (exp.e1.op == EXP.dotTemplateInstance)
{
DotTemplateInstanceExp se = cast(DotTemplateInstanceExp)exp.e1;
TemplateInstance ti = se.ti;
else
{
Expression e1x = exp.e1.expressionSemantic(sc);
- if (e1x.op == TOK.error)
+ if (e1x.op == EXP.error)
{
result = e1x;
return;
Lagain:
//printf("Lagain: %s\n", toChars());
exp.f = null;
- if (exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_)
+ if (exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_)
{
// semantic() run later for these
}
else
{
- if (exp.e1.op == TOK.dotIdentifier)
+ if (exp.e1.op == EXP.dotIdentifier)
{
DotIdExp die = cast(DotIdExp)exp.e1;
exp.e1 = die.expressionSemantic(sc);
* We handle such earlier, so go back.
* Note that in the rewrite, we carefully did not run semantic() on e1
*/
- if (exp.e1.op == TOK.dotTemplateInstance)
+ if (exp.e1.op == EXP.dotTemplateInstance)
{
goto Ldotti;
}
/* Look for e1 being a lazy parameter
*/
- if (exp.e1.op == TOK.variable)
+ if (exp.e1.op == EXP.variable)
{
VarExp ve = cast(VarExp)exp.e1;
if (ve.var.storage_class & STC.lazy_)
return setError();
}
- if (exp.e1.op == TOK.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads)
+ if (exp.e1.op == EXP.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads)
{
SymOffExp se = cast(SymOffExp)exp.e1;
exp.e1 = new VarExp(se.loc, se.var, true);
exp.e1 = exp.e1.expressionSemantic(sc);
}
- else if (exp.e1.op == TOK.dot)
+ else if (exp.e1.op == EXP.dot)
{
DotExp de = cast(DotExp)exp.e1;
- if (de.e2.op == TOK.overloadSet)
+ if (de.e2.op == EXP.overloadSet)
{
ethis = de.e1;
tthis = de.e1.type;
exp.e1 = de.e2;
}
}
- else if (exp.e1.op == TOK.star && exp.e1.type.ty == Tfunction)
+ else if (exp.e1.op == EXP.star && exp.e1.type.ty == Tfunction)
{
// Rewrite (*fp)(arguments) to fp(arguments)
exp.e1 = (cast(PtrExp)exp.e1).e1;
}
- else if (exp.e1.op == TOK.type && (sc && sc.flags & SCOPE.Cfile))
+ else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile))
{
const numArgs = exp.arguments ? exp.arguments.length : 0;
if (e1org.parens && numArgs >= 1)
Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null;
- if (exp.e1.op == TOK.error)
+ if (exp.e1.op == EXP.error)
{
result = exp.e1;
return;
}
// First look for constructor
- if (exp.e1.op == TOK.type && sd.ctor)
+ if (exp.e1.op == EXP.type && sd.ctor)
{
if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.dim))
goto Lx;
if (search_function(sd, Id.call))
goto L1;
// overload of opCall, therefore it's a call
- if (exp.e1.op != TOK.type)
+ if (exp.e1.op != EXP.type)
{
if (sd.aliasthis && !isRecursiveAliasThis(exp.att1, exp.e1.type))
{
result = e;
return;
}
- else if (exp.e1.op == TOK.type && t1.isscalar())
+ else if (exp.e1.op == EXP.type && t1.isscalar())
{
Expression e;
}
bool isSuper = false;
- if (exp.e1.op == TOK.dotVariable && t1.ty == Tfunction || exp.e1.op == TOK.dotTemplateDeclaration)
+ if (exp.e1.op == EXP.dotVariable && t1.ty == Tfunction || exp.e1.op == EXP.dotTemplateDeclaration)
{
UnaExp ue = cast(UnaExp)exp.e1;
DotVarExp dve;
DotTemplateExp dte;
Dsymbol s;
- if (exp.e1.op == TOK.dotVariable)
+ if (exp.e1.op == EXP.dotVariable)
{
dve = cast(DotVarExp)exp.e1;
dte = null;
{
AggregateDeclaration ad = exp.f.toParentLocal().isAggregateDeclaration();
ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f);
- if (ue.e1.op == TOK.error)
+ if (ue.e1.op == EXP.error)
{
result = ue.e1;
return;
/* Cannot call public functions from inside invariant
* (because then the invariant would have infinite recursion)
*/
- if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == TOK.this_ && exp.f.addPostInvariant())
+ if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == EXP.this_ && exp.f.addPostInvariant())
{
exp.error("cannot call `public`/`export` function `%s` from invariant", exp.f.toChars());
return setError();
{
if (ue1old.checkRightThis(sc))
return setError();
- if (exp.e1.op == TOK.dotVariable)
+ if (exp.e1.op == EXP.dotVariable)
{
dve.var = exp.f;
exp.e1.type = exp.f.type;
{
exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false);
exp.e1 = exp.e1.expressionSemantic(sc);
- if (exp.e1.op == TOK.error)
+ if (exp.e1.op == EXP.error)
return setError();
ue = cast(UnaExp)exp.e1;
}
ClassDeclaration cd = ue.e1.type.isClassHandle();
if (ad && cd && ad.isClassDeclaration())
{
- if (ue.e1.op == TOK.dotType)
+ if (ue.e1.op == EXP.dotType)
{
ue.e1 = (cast(DotTypeExp)ue.e1).e1;
exp.directcall = true;
}
- else if (ue.e1.op == TOK.super_)
+ else if (ue.e1.op == EXP.super_)
exp.directcall = true;
else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211
exp.directcall = true;
}
t1 = exp.e1.type;
}
- else if (exp.e1.op == TOK.super_ || exp.e1.op == TOK.this_)
+ else if (exp.e1.op == EXP.super_ || exp.e1.op == EXP.this_)
{
auto ad = sc.func ? sc.func.isThis() : null;
auto cd = ad ? ad.isClassDeclaration() : null;
- isSuper = exp.e1.op == TOK.super_;
+ isSuper = exp.e1.op == EXP.super_;
if (isSuper)
{
// Base class constructor call
exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false);
exp.e1 = exp.e1.expressionSemantic(sc);
// https://issues.dlang.org/show_bug.cgi?id=21095
- if (exp.e1.op == TOK.error)
+ if (exp.e1.op == EXP.error)
return setError();
t1 = exp.e1.type;
return setError();
}
}
- else if (exp.e1.op == TOK.overloadSet)
+ else if (exp.e1.op == EXP.overloadSet)
{
auto os = (cast(OverExp)exp.e1).vars;
exp.f = resolveOverloadSet(exp.loc, sc, os, tiargs, tthis, exp.arguments);
const(char)* p;
Dsymbol s;
exp.f = null;
- if (exp.e1.op == TOK.function_)
+ if (exp.e1.op == EXP.function_)
{
// function literal that direct called is always inferred.
assert((cast(FuncExp)exp.e1).fd);
tf = tfx;
p = "function pointer";
}
- else if (exp.e1.op == TOK.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration())
+ else if (exp.e1.op == EXP.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration())
{
DotVarExp dve = cast(DotVarExp)exp.e1;
exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.arguments, FuncResolveFlag.overloadOnly);
result = e.expressionSemantic(sc);
return;
}
- else if (exp.e1.op == TOK.variable && (cast(VarExp)exp.e1).var.isOverDeclaration())
+ else if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.isOverDeclaration())
{
s = (cast(VarExp)exp.e1).var;
goto L2;
}
- else if (exp.e1.op == TOK.template_)
+ else if (exp.e1.op == EXP.template_)
{
s = (cast(TemplateExp)exp.e1).td;
L2:
}
t1 = tf;
}
- else if (exp.e1.op == TOK.variable)
+ else if (exp.e1.op == EXP.variable)
{
// Do overload resolution
VarExp ve = cast(VarExp)exp.e1;
if (AggregateDeclaration ad2 = exp.f.isMember2())
{
Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
- if (te.op != TOK.error)
+ if (te.op != EXP.error)
te = getRightThis(exp.loc, sc, ad2, te, exp.f);
- if (te.op == TOK.error)
+ if (te.op == EXP.error)
{
exp.error("need `this` of type `%s` to call function `%s`", ad2.toChars(), exp.f.toChars());
return setError();
ea = ea.expressionSemantic(sc);
ea = resolveProperties(sc, ea);
ta = ea.type;
- if (ea.op == TOK.type)
+ if (ea.op == EXP.type)
ea = null;
}
/* If one of the default arguments was an error,
don't return an invalid tuple
*/
- if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == TOK.error)
+ if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == EXP.error)
return setError();
args.push(new Parameter(arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl));
}
return;
}
- if (exp.e1.op == TOK.arrayLength)
+ if (exp.e1.op == EXP.arrayLength)
{
// arr.length op= e2;
e = rewriteOpAssign(exp);
result = e;
return;
}
- if (exp.e1.op == TOK.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
+ if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
{
if (checkNonAssignmentArrayOp(exp.e1))
return setError();
- if (exp.e1.op == TOK.slice)
+ if (exp.e1.op == EXP.slice)
(cast(SliceExp)exp.e1).arrayop = true;
// T[] op= ...
exp.e1.checkSharedAccess(sc))
return setError();
- int arith = (exp.op == TOK.addAssign || exp.op == TOK.minAssign || exp.op == TOK.mulAssign || exp.op == TOK.divAssign || exp.op == TOK.modAssign || exp.op == TOK.powAssign);
- int bitwise = (exp.op == TOK.andAssign || exp.op == TOK.orAssign || exp.op == TOK.xorAssign);
- int shift = (exp.op == TOK.leftShiftAssign || exp.op == TOK.rightShiftAssign || exp.op == TOK.unsignedRightShiftAssign);
+ int arith = (exp.op == EXP.addAssign || exp.op == EXP.minAssign || exp.op == EXP.mulAssign || exp.op == EXP.divAssign || exp.op == EXP.modAssign || exp.op == EXP.powAssign);
+ int bitwise = (exp.op == EXP.andAssign || exp.op == EXP.orAssign || exp.op == EXP.xorAssign);
+ int shift = (exp.op == EXP.leftShiftAssign || exp.op == EXP.rightShiftAssign || exp.op == EXP.unsignedRightShiftAssign);
if (bitwise && exp.type.toBasetype().ty == Tbool)
exp.e2 = exp.e2.implicitCastTo(sc, exp.type);
else if (exp.checkNoBool())
return setError();
- if ((exp.op == TOK.addAssign || exp.op == TOK.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral())
+ if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral())
{
result = scaleFactor(exp, sc);
return;
return;
}
- if (exp.e1.op == TOK.error || exp.e2.op == TOK.error)
+ if (exp.e1.op == EXP.error || exp.e2.op == EXP.error)
return setError();
e = exp.checkOpAssignTypes(sc);
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
{
result = e;
return;
}
- assert(e.op == TOK.assign || e == exp);
+ assert(e.op == EXP.assign || e == exp);
result = (cast(BinExp)e).reorderSettingAAElem(sc);
}
Objects* tiargs;
Loc loc = exp.e1.loc;
- const tok = exp.e1.op;
+ const op = exp.e1.op;
bool isEqualsCallExpression;
- if (tok == TOK.call)
+ if (op == EXP.call)
{
const callExp = cast(CallExp) exp.e1;
callExpIdent == Id.eq;
}
}
- if (tok == TOK.equal || tok == TOK.notEqual ||
- tok == TOK.lessThan || tok == TOK.greaterThan ||
- tok == TOK.lessOrEqual || tok == TOK.greaterOrEqual ||
- tok == TOK.identity || tok == TOK.notIdentity ||
- tok == TOK.in_ ||
+ if (op == EXP.equal || op == EXP.notEqual ||
+ op == EXP.lessThan || op == EXP.greaterThan ||
+ op == EXP.lessOrEqual || op == EXP.greaterOrEqual ||
+ op == EXP.identity || op == EXP.notIdentity ||
+ op == EXP.in_ ||
isEqualsCallExpression)
{
es = new Expressions(3);
}
// template args
- Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : Token.toString(exp.e1.op));
+ Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op));
comp = comp.expressionSemantic(sc);
(*es)[0] = comp;
(*tiargs)[0] = (*es)[1].type;
// Format exp.e1 before any additional boolean conversion
// Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
- else if (tok != TOK.andAnd && tok != TOK.orOr)
+ else if (op != EXP.andAnd && op != EXP.orOr)
{
es = new Expressions(2);
tiargs = new Objects(1);
exp.e1 = exp.e1.optimize(WANTvalue);
exp.e1 = exp.e1.toBoolean(sc);
- if (exp.e1.op == TOK.error)
+ if (exp.e1.op == EXP.error)
{
result = exp.e1;
return;
checkParamArgumentEscape(sc, null, null, exp.msg, true, false);
}
- if (exp.msg && exp.msg.op == TOK.error)
+ if (exp.msg && exp.msg.op == EXP.error)
{
result = exp.msg;
return;
if (f1 || f2)
return setError();
- if (exp.e1.isBool(false))
+ if (exp.e1.toBool().hasValue(false))
{
/* This is an `assert(0)` which means halt program execution
*/
AggregateDeclaration ad = f.toParentLocal().isAggregateDeclaration();
if (f.needThis())
e.e1 = getRightThis(e.loc, sc, ad, e.e1, f);
- if (e.e1.op == TOK.error)
+ if (e.e1.op == EXP.error)
return setError();
/* A delegate takes the address of e.e1 in order to set the .ptr field
if (AggregateDeclaration ad2 = f.isMember2())
{
Expression te = new ThisExp(e.loc).expressionSemantic(sc);
- if (te.op != TOK.error)
+ if (te.op != EXP.error)
te = getRightThis(e.loc, sc, ad2, te, f);
- if (te.op == TOK.error)
+ if (te.op == EXP.error)
{
e.error("need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars());
return setError();
}
}
- int wasCond = exp.e1.op == TOK.question;
+ int wasCond = exp.e1.op == EXP.question;
- if (exp.e1.op == TOK.dotTemplateInstance)
+ if (exp.e1.op == EXP.dotTemplateInstance)
{
DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1;
TemplateInstance ti = dti.ti;
}
}
}
- else if (exp.e1.op == TOK.scope_)
+ else if (exp.e1.op == EXP.scope_)
{
TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance();
if (ti)
}
exp.e1 = exp.e1.toLvalue(sc, null);
- if (exp.e1.op == TOK.error)
+ if (exp.e1.op == EXP.error)
{
result = exp.e1;
return;
}
else if (!exp.e1.type.deco)
{
- if (exp.e1.op == TOK.variable)
+ if (exp.e1.op == EXP.variable)
{
VarExp ve = cast(VarExp)exp.e1;
Declaration d = ve.var;
exp.type = exp.e1.type.pointerTo();
// See if this should really be a delegate
- if (exp.e1.op == TOK.dotVariable)
+ if (exp.e1.op == EXP.dotVariable)
{
DotVarExp dve = cast(DotVarExp)exp.e1;
FuncDeclaration f = dve.var.isFuncDeclaration();
}
}
}
- else if (exp.e1.op == TOK.variable)
+ else if (exp.e1.op == EXP.variable)
{
VarExp ve = cast(VarExp)exp.e1;
VarDeclaration v = ve.var.isVarDeclaration();
}
}
}
- else if ((exp.e1.op == TOK.this_ || exp.e1.op == TOK.super_) && global.params.useDIP1000 == FeatureState.enabled)
+ else if ((exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_) && global.params.useDIP1000 == FeatureState.enabled)
{
if (VarDeclaration v = expToVariable(exp.e1))
{
return setError();
}
}
- else if (exp.e1.op == TOK.call)
+ else if (exp.e1.op == EXP.call)
{
CallExp ce = cast(CallExp)exp.e1;
if (ce.e1.type.ty == Tfunction)
{
TypeFunction tf = cast(TypeFunction)ce.e1.type;
- if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
+ if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_)
+ && tf.next.hasPointers() && sc.func.setUnsafe())
{
exp.error("cannot take address of `ref return` of `%s()` in `@safe` function `%s`",
ce.e1.toChars(), sc.func.toChars());
}
}
}
- else if (exp.e1.op == TOK.index)
+ else if (exp.e1.op == EXP.index)
{
/* For:
* int[3] a;
/* a ? b : c was transformed to *(a ? &b : &c), but we still
* need to do safety checks
*/
- assert(exp.e1.op == TOK.star);
+ assert(exp.e1.op == EXP.star);
PtrExp pe = cast(PtrExp)exp.e1;
- assert(pe.e1.op == TOK.question);
+ assert(pe.e1.op == EXP.question);
CondExp ce = cast(CondExp)pe.e1;
- assert(ce.e1.op == TOK.address);
- assert(ce.e2.op == TOK.address);
+ assert(ce.e1.op == EXP.address);
+ assert(ce.e2.op == EXP.address);
// Re-run semantic on the address expressions only
ce.e1.type = null;
}
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (e.e1.op == TOK.type)
+ if (e.e1.op == EXP.type)
e.e1 = resolveAliasThis(sc, e.e1);
e.e1 = resolveProperties(sc, e.e1);
}
exp.e1 = resolveProperties(sc, exp.e1);
exp.e1 = exp.e1.modifiableLvalue(sc, null);
- if (exp.e1.op == TOK.error)
+ if (exp.e1.op == EXP.error)
{
result = exp.e1;
return;
if ((sc && sc.flags & SCOPE.Cfile) &&
exp.to && exp.to.ty == Tident &&
- (exp.e1.op == TOK.address || exp.e1.op == TOK.star ||
- exp.e1.op == TOK.uadd || exp.e1.op == TOK.negate))
+ (exp.e1.op == EXP.address || exp.e1.op == EXP.star ||
+ exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate))
{
/* Ambiguous cases arise from CParser if type-name is just an identifier.
* ( identifier ) cast-expression
}
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (exp.e1.op == TOK.type)
+ if (exp.e1.op == EXP.type)
exp.e1 = resolveAliasThis(sc, exp.e1);
auto e1x = resolveProperties(sc, exp.e1);
- if (e1x.op == TOK.error)
+ if (e1x.op == EXP.error)
{
result = e1x;
return;
}
Expression ex = exp.e1.castTo(sc, exp.to);
- if (ex.op == TOK.error)
+ if (ex.op == EXP.error)
{
result = ex;
return;
}
}
- if(t1b.ty == Tarray && exp.e1.op != TOK.arrayLiteral && (sc.flags & SCOPE.ctfe) == 0)
+ if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && (sc.flags & SCOPE.ctfe) == 0)
{
auto tFrom = t1b.nextOf();
auto tTo = tob.nextOf();
// https://issues.dlang.org/show_bug.cgi?id=20130
- if (exp.e1.op != TOK.string_ || !ex.isStringExp)
+ if (exp.e1.op != EXP.string_ || !ex.isStringExp)
{
const uint fromSize = cast(uint)tFrom.size();
const uint toSize = cast(uint)tTo.size();
+ if (fromSize == SIZE_INVALID || toSize == SIZE_INVALID)
+ return setError();
// If array element sizes do not match, we must adjust the dimensions
if (fromSize != toSize)
exp.e1 = exp.e1.expressionSemantic(sc);
exp.type = exp.to.typeSemantic(exp.loc, sc);
- if (exp.e1.op == TOK.error || exp.type.ty == Terror)
+ if (exp.e1.op == EXP.error || exp.type.ty == Terror)
{
result = exp.e1;
return;
exp.e1 = exp.e1.optimize(WANTvalue);
bool res;
- if (exp.e1.op == TOK.arrayLiteral)
+ if (exp.e1.op == EXP.arrayLiteral)
{
foreach (i; 0 .. exp.dim)
{
unaSemantic(e, sc);
e.e1 = resolveProperties(sc, e.e1);
- if (e.e1.op == TOK.error)
+ if (e.e1.op == EXP.error)
{
result = e.e1;
return;
return;
}
exp.e1 = resolveProperties(sc, exp.e1);
- if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple)
+ if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
{
if (exp.lwr || exp.upr)
{
}
if (!exp.lwr && !exp.upr)
{
- if (exp.e1.op == TOK.arrayLiteral)
+ if (exp.e1.op == EXP.arrayLiteral)
{
// Convert [a,b,c][] to [a,b,c]
Type t1b = exp.e1.type.toBasetype();
result = e;
return;
}
- if (exp.e1.op == TOK.slice)
+ if (exp.e1.op == EXP.slice)
{
// Convert e[][] to e[]
SliceExp se = cast(SliceExp)exp.e1;
return;
}
}
- if (exp.e1.op == TOK.error)
+ if (exp.e1.op == EXP.error)
{
result = exp.e1;
return;
*/
if (VarDeclaration v = expToVariable(exp.e1))
{
- if (exp.e1.op == TOK.dotVariable)
+ if (exp.e1.op == EXP.dotVariable)
{
DotVarExp dve = cast(DotVarExp)exp.e1;
- if ((dve.e1.op == TOK.this_ || dve.e1.op == TOK.super_) &&
+ if ((dve.e1.op == EXP.this_ || dve.e1.op == EXP.super_) &&
!(v.storage_class & STC.ref_))
{
// because it's a class
TupleExp te;
TypeTuple tup;
size_t length;
- if (exp.e1.op == TOK.tuple) // slicing an expression tuple
+ if (exp.e1.op == EXP.tuple) // slicing an expression tuple
{
te = cast(TupleExp)exp.e1;
tup = null;
length = te.exps.dim;
}
- else if (exp.e1.op == TOK.type) // slicing a type tuple
+ else if (exp.e1.op == EXP.type) // slicing a type tuple
{
te = null;
tup = cast(TypeTuple)t1b;
size_t j1 = cast(size_t)i1;
size_t j2 = cast(size_t)i2;
Expression e;
- if (exp.e1.op == TOK.tuple)
+ if (exp.e1.op == EXP.tuple)
{
auto exps = new Expressions(j2 - j1);
for (size_t i = 0; i < j2 - j1; i++)
Expression el = new ArrayLengthExp(exp.loc, exp.e1);
el = el.expressionSemantic(sc);
el = el.optimize(WANTvalue);
- if (el.op == TOK.int64)
+ if (el.op == EXP.int64)
{
// Array length is known at compile-time. Upper is in bounds if it fits length.
dinteger_t length = el.toInteger();
auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length));
exp.upperIsInBounds = bounds.contains(uprRange);
- if (exp.lwr.op == TOK.int64 && exp.upr.op == TOK.int64 && exp.lwr.toInteger() > exp.upr.toInteger())
+ if (exp.lwr.op == EXP.int64 && exp.upr.op == EXP.int64 && exp.lwr.toInteger() > exp.upr.toInteger())
{
exp.error("in slice `%s[%llu .. %llu]`, lower bound is greater than upper bound", exp.e1.toChars, exp.lwr.toInteger(), exp.upr.toInteger());
return setError();
}
- if (exp.upr.op == TOK.int64 && exp.upr.toInteger() > length)
+ if (exp.upr.op == EXP.int64 && exp.upr.toInteger() > length)
{
exp.error("in slice `%s[%llu .. %llu]`, upper bound is greater than array length `%llu`", exp.e1.toChars, exp.lwr.toInteger(), exp.upr.toInteger(), length);
return setError();
}
}
- else if (exp.upr.op == TOK.int64 && exp.upr.toInteger() == 0)
+ else if (exp.upr.op == EXP.int64 && exp.upr.toInteger() == 0)
{
// Upper slice expression is '0'. Value is always in bounds.
exp.upperIsInBounds = true;
}
- else if (exp.upr.op == TOK.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar)
+ else if (exp.upr.op == EXP.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar)
{
// Upper slice expression is '$'. Value is always in bounds.
exp.upperIsInBounds = true;
if (isAggregate(exp.e1.type))
exp.error("no `[]` operator overload for type `%s`", exp.e1.type.toChars());
- else if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple)
+ else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
exp.error("static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars());
else if (isIndexableNonAggregate(exp.e1.type))
exp.error("only one index allowed to index `%s`", exp.e1.type.toChars());
exp.e1 = exp.e1.expressionSemantic(sc);
exp.e2 = exp.e2.expressionSemantic(sc);
- if (exp.e1.op == TOK.type)
+ if (exp.e1.op == EXP.type)
{
result = exp.e2;
return;
}
- if (exp.e2.op == TOK.type)
+ if (exp.e2.op == EXP.type)
{
result = exp.e2;
return;
}
- if (exp.e2.op == TOK.template_)
+ if (exp.e2.op == EXP.template_)
{
auto td = (cast(TemplateExp)exp.e2).td;
Expression e = new DotTemplateExp(exp.loc, exp.e1, td);
ue = ue.expressionSemantic(sc);
ue = resolveProperties(sc, ue);
- if (le.op == TOK.error)
+ if (le.op == EXP.error)
{
result = le;
return;
}
- if (ue.op == TOK.error)
+ if (ue.op == EXP.error)
{
result = ue;
return;
unaSemantic(e, sc);
e.e1 = resolveProperties(sc, e.e1);
- if (e.e1.op == TOK.error)
+ if (e.e1.op == EXP.error)
{
result = e.e1;
return;
{
unaSemantic(e, sc);
e.e1 = resolveProperties(sc, e.e1);
- if (e.e1.op == TOK.error)
+ if (e.e1.op == EXP.error)
{
result = e.e1;
return;
if (!exp.e1.type)
exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
assert(exp.e1.type); // semantic() should already be run on it
- if (exp.e1.op == TOK.type && exp.e1.type.ty != Ttuple)
+ if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
{
exp.e2 = exp.e2.expressionSemantic(sc);
exp.e2 = resolveProperties(sc, exp.e2);
Type nt;
- if (exp.e2.op == TOK.type)
+ if (exp.e2.op == EXP.type)
nt = new TypeAArray(exp.e1.type, exp.e2.type);
else
nt = new TypeSArray(exp.e1.type, exp.e2);
result = e.expressionSemantic(sc);
return;
}
- if (exp.e1.op == TOK.error)
+ if (exp.e1.op == EXP.error)
{
result = exp.e1;
return;
exp.e2 = resolveProperties(sc, exp.e2);
if (t1b.ty == Ttuple)
sc = sc.endCTFE();
- if (exp.e2.op == TOK.tuple)
+ if (exp.e2.op == EXP.tuple)
{
TupleExp te = cast(TupleExp)exp.e2;
if (te.exps && te.exps.dim == 1)
if (exp.e2.type == Type.terror)
return setError();
exp.e2 = exp.e2.optimize(WANTvalue);
- if (exp.e2.op == TOK.int64 && exp.e2.toInteger() == 0)
+ if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0)
{
}
else if (sc.func && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
TupleExp te;
TypeTuple tup;
size_t length;
- if (exp.e1.op == TOK.tuple)
+ if (exp.e1.op == EXP.tuple)
{
te = cast(TupleExp)exp.e1;
tup = null;
length = te.exps.dim;
}
- else if (exp.e1.op == TOK.type)
+ else if (exp.e1.op == EXP.type)
{
te = null;
tup = cast(TypeTuple)t1b;
return setError();
}
Expression e;
- if (exp.e1.op == TOK.tuple)
+ if (exp.e1.op == EXP.tuple)
{
e = (*te.exps)[cast(size_t)index];
e = Expression.combine(te.e0, e);
Expression el = new ArrayLengthExp(exp.loc, exp.e1);
el = el.expressionSemantic(sc);
el = el.optimize(WANTvalue);
- if (el.op == TOK.int64)
+ if (el.op == EXP.int64)
{
exp.e2 = exp.e2.optimize(WANTvalue);
dinteger_t length = el.toInteger();
return;
}
Expression e1x = resolveProperties(sc, exp.e1);
- if (e1x.op == TOK.error)
+ if (e1x.op == EXP.error)
{
result = e1x;
return;
if (exp.e1.checkReadModifyWrite(exp.op))
return setError();
- if (exp.e1.op == TOK.slice)
+ if (exp.e1.op == EXP.slice)
{
- const(char)* s = exp.op == TOK.plusPlus ? "increment" : "decrement";
+ const(char)* s = exp.op == EXP.plusPlus ? "increment" : "decrement";
exp.error("cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s);
return setError();
}
Type t1 = exp.e1.type.toBasetype();
- if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == TOK.arrayLength)
+ if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == EXP.arrayLength)
{
/* Check for operator overloading,
* but rewrite in terms of ++e instead of e++
/* If e1 is not trivial, take a reference to it
*/
Expression de = null;
- if (exp.e1.op != TOK.variable && exp.e1.op != TOK.arrayLength)
+ if (exp.e1.op != EXP.variable && exp.e1.op != EXP.arrayLength)
{
// ref v = e1;
auto v = copyToTemp(STC.ref_, "__postref", exp.e1);
Expression ea = new DeclarationExp(exp.loc, tmp);
Expression eb = exp.e1.syntaxCopy();
- eb = new PreExp(exp.op == TOK.plusPlus ? TOK.prePlusPlus : TOK.preMinusMinus, exp.loc, eb);
+ eb = new PreExp(exp.op == EXP.plusPlus ? EXP.prePlusPlus : EXP.preMinusMinus, exp.loc, eb);
Expression ec = new VarExp(exp.loc, tmp);
}
// Rewrite as e1+=1 or e1-=1
- if (exp.op == TOK.prePlusPlus)
+ if (exp.op == EXP.prePlusPlus)
e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
else
e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
{
printf("AssignExp::semantic('%s')\n", exp.toChars());
}
- //printf("exp.e1.op = %d, '%s'\n", exp.e1.op, Token.toChars(exp.e1.op));
- //printf("exp.e2.op = %d, '%s'\n", exp.e2.op, Token.toChars(exp.e2.op));
+ //printf("exp.e1.op = %d, '%s'\n", exp.e1.op, EXPtoString(exp.e1.op).ptr);
+ //printf("exp.e2.op = %d, '%s'\n", exp.e2.op, EXPtoString(exp.e2.op).ptr);
void setResult(Expression e, int line = __LINE__)
{
const(bool) maybeSlice =
(ae.arguments.dim == 0 ||
- ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval);
+ ae.arguments.dim == 1 && (*ae.arguments)[0].op == EXP.interval);
IntervalExp ie = null;
if (maybeSlice && ae.arguments.dim)
{
- assert((*ae.arguments)[0].op == TOK.interval);
+ assert((*ae.arguments)[0].op == EXP.interval);
ie = cast(IntervalExp)(*ae.arguments)[0];
}
while (true)
{
- if (ae.e1.op == TOK.error)
+ if (ae.e1.op == EXP.error)
return setResult(ae.e1);
Expression e0 = null;
res = resolveOpDollar(sc, ae, &e0);
if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
goto Lfallback;
- if (res.op == TOK.error)
+ if (res.op == EXP.error)
return setResult(res);
res = exp.e2.expressionSemantic(sc);
- if (res.op == TOK.error)
+ if (res.op == EXP.error)
return setResult(res);
exp.e2 = res;
{
// Deal with $
res = resolveOpDollar(sc, ae, ie, &e0);
- if (res.op == TOK.error)
+ if (res.op == EXP.error)
return setResult(res);
res = exp.e2.expressionSemantic(sc);
- if (res.op == TOK.error)
+ if (res.op == EXP.error)
return setResult(res);
exp.e2 = res;
if (!t1.isTypeSArray())
e2x = e2x.arrayFuncConv(sc);
e2x = resolveProperties(sc, e2x);
- if (e2x.op == TOK.type)
+ if (e2x.op == EXP.type)
e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
- if (e2x.op == TOK.error)
+ if (e2x.op == EXP.error)
return setResult(e2x);
// We delay checking the value for structs/classes as these might have
// an opAssign defined.
Expression e2x = exp.e2;
Ltupleassign:
- if (exp.e1.op == TOK.tuple && e2x.op == TOK.tuple)
+ if (exp.e1.op == EXP.tuple && e2x.op == EXP.tuple)
{
TupleExp tup1 = cast(TupleExp)exp.e1;
TupleExp tup2 = cast(TupleExp)e2x;
/* Look for form: e1 = e2.aliasthis.
*/
- if (exp.e1.op == TOK.tuple)
+ if (exp.e1.op == EXP.tuple)
{
TupleDeclaration td = isAliasThisTuple(e2x);
if (!td)
}
e2x = new TupleExp(e2x.loc, e0, iexps);
e2x = e2x.expressionSemantic(sc);
- if (e2x.op == TOK.error)
+ if (e2x.op == EXP.error)
{
result = e2x;
return;
/* Inside constructor, if this is the first assignment of object field,
* rewrite this to initializing the field.
*/
- if (exp.op == TOK.assign
+ if (exp.op == EXP.assign
&& exp.e1.checkModifiable(sc) == Modifiable.initialization)
{
//printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
if (auto ie1 = exp.e1.isIndexExp())
{
Expression e1x = ie1.markSettingAAElem();
- if (e1x.op == TOK.error)
+ if (e1x.op == EXP.error)
{
result = e1x;
return;
}
}
}
- else if (exp.op == TOK.construct && exp.e1.op == TOK.variable &&
+ else if (exp.op == EXP.construct && exp.e1.op == EXP.variable &&
(cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_))
{
exp.memset = MemorySet.referenceInit;
}
- if (exp.op == TOK.assign) // skip TOK.blit and TOK.construct, which are initializations
+ if (exp.op == EXP.assign) // skip EXP.blit and EXP.construct, which are initializations
{
exp.e1.checkSharedAccess(sc);
checkUnsafeAccess(sc, exp.e1, false, true);
auto e2x = exp.e2;
auto sd = (cast(TypeStruct)t1).sym;
- if (exp.op == TOK.construct)
+ if (exp.op == EXP.construct)
{
Type t2 = e2x.type.toBasetype();
if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym)
// Look for the form from last of comma chain.
auto e2y = lastComma(e2x);
- CallExp ce = (e2y.op == TOK.call) ? cast(CallExp)e2y : null;
- DotVarExp dve = (ce && ce.e1.op == TOK.dotVariable)
+ CallExp ce = (e2y.op == EXP.call) ? cast(CallExp)e2y : null;
+ DotVarExp dve = (ce && ce.e1.op == EXP.dotVariable)
? cast(DotVarExp)ce.e1 : null;
if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() &&
// https://issues.dlang.org/show_bug.cgi?id=19389
- dve.e1.op != TOK.dotVariable &&
+ dve.e1.op != EXP.dotVariable &&
e2y.type.implicitConvTo(t1))
{
/* Look for form of constructor call which is:
* initializer
*/
Expression einit = getInitExp(sd, exp.loc, sc, t1);
- if (einit.op == TOK.error)
+ if (einit.op == EXP.error)
{
result = einit;
return;
// a temporary created and an extra destructor call.
// AST will be rewritten to:
// a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
- if (e2x.op == TOK.question)
+ if (e2x.op == EXP.question)
{
/* Rewrite as:
* a ? e1 = b : e1 = c;
* Foo f = new Foo2(0); is a valid expression if Foo has a constructor
* which receives an instance of a Foo2 class
*/
- if (exp.e2.op == TOK.new_)
+ if (exp.e2.op == EXP.new_)
{
auto newExp = cast(NewExp)(exp.e2);
if (newExp.newtype && newExp.newtype == t1)
e2x = e2x.expressionSemantic(sc);
e2x = resolveProperties(sc, e2x);
- if (e2x.op == TOK.error)
+ if (e2x.op == EXP.error)
{
result = e2x;
return;
}
}
}
- else if (exp.op == TOK.assign)
+ else if (exp.op == EXP.assign)
{
- if (e1x.op == TOK.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
+ if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
{
/*
* Rewrite:
*/
// ensure we keep the expr modifiable
Expression esetting = (cast(IndexExp)e1x).markSettingAAElem();
- if (esetting.op == TOK.error)
+ if (esetting.op == EXP.error)
{
result = esetting;
return;
}
- assert(esetting.op == TOK.index);
+ assert(esetting.op == EXP.index);
IndexExp ie = cast(IndexExp) esetting;
Type t2 = e2x.type.toBasetype();
ey = new ConstructExp(exp.loc, ex, ey);
ey = ey.expressionSemantic(sc);
- if (ey.op == TOK.error)
+ if (ey.op == EXP.error)
{
result = ey;
return;
// The whole expression should have the common type
// of opAssign() return and assigned AA entry.
// Even if there's no common type, expression should be typed as void.
- if (!typeMerge(sc, TOK.question, ex, ey))
+ if (!typeMerge(sc, EXP.question, ex, ey))
{
ex = new CastExp(ex.loc, ex, Type.tvoid);
ey = new CastExp(ey.loc, ey, Type.tvoid);
}
}
else
- assert(exp.op == TOK.blit);
+ assert(exp.op == EXP.blit);
if (e2x.checkValue())
return setError();
else if (t1.ty == Tclass)
{
// Disallow assignment operator overloads for same type
- if (exp.op == TOK.assign && !exp.e2.implicitConvTo(exp.e1.type))
+ if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type))
{
Expression e = exp.op_overload(sc);
if (e)
else if (t1.ty == Tsarray)
{
// SliceExp cannot have static array type without context inference.
- assert(exp.e1.op != TOK.slice);
+ assert(exp.e1.op != EXP.slice);
Expression e1x = exp.e1;
Expression e2x = exp.e2;
if (e2x.implicitConvTo(e1x.type))
{
- if (exp.op != TOK.blit && (e2x.op == TOK.slice && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op == TOK.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != TOK.slice && e2x.isLvalue()))
+ if (exp.op != EXP.blit && (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() || e2x.op != EXP.slice && e2x.isLvalue()))
{
if (e1x.checkPostblit(sc, t1))
return setError();
// May be block or element-wise assignment, so
// convert e1 to e1[]
- if (exp.op != TOK.assign)
+ if (exp.op != EXP.assign)
{
// If multidimensional static array, treat as one large array
//
sle.arrayop = true;
e1x = sle.expressionSemantic(sc);
}
- if (e1x.op == TOK.error)
+ if (e1x.op == EXP.error)
return setResult(e1x);
- if (e2x.op == TOK.error)
+ if (e2x.op == EXP.error)
return setResult(e2x);
exp.e1 = e1x;
// e1 is not an lvalue, but we let code generator handle it
auto ale1x = ale.e1.modifiableLvalue(sc, exp.e1);
- if (ale1x.op == TOK.error)
+ if (ale1x.op == EXP.error)
return setResult(ale1x);
ale.e1 = ale1x;
auto lc = lastComma(exp.e2);
lc = lc.optimize(WANTvalue);
// use slice expression when arr.length = 0 to avoid runtime call
- if(lc.op == TOK.int64 && lc.toInteger() == 0)
+ if(lc.op == EXP.int64 && lc.toInteger() == 0)
{
Expression se = new SliceExp(ale.loc, ale.e1, lc, lc);
Expression as = new AssignExp(ale.loc, ale.e1, se);
{
Type tn = se.type.nextOf();
const fun = sc.func;
- if (exp.op == TOK.assign && !tn.isMutable() &&
+ if (exp.op == EXP.assign && !tn.isMutable() &&
// allow modifiation in module ctor, see
// https://issues.dlang.org/show_bug.cgi?id=9884
(!fun || (fun && !fun.isStaticCtorDeclaration())))
return setError();
}
- if (exp.op == TOK.assign && !tn.baseElemOf().isAssignable())
+ if (exp.op == EXP.assign && !tn.baseElemOf().isAssignable())
{
exp.error("slice `%s` is not mutable, struct `%s` has immutable members",
exp.e1.toChars(), tn.baseElemOf().toChars());
}
// For conditional operator, both branches need conversion.
- while (se.e1.op == TOK.slice)
+ while (se.e1.op == EXP.slice)
se = cast(SliceExp)se.e1;
- if (se.e1.op == TOK.question && se.e1.type.toBasetype().ty == Tsarray)
+ if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray)
{
se.e1 = se.e1.modifiableLvalue(sc, exp.e1);
- if (se.e1.op == TOK.error)
+ if (se.e1.op == EXP.error)
return setResult(se.e1);
}
}
else
{
- if (t1.ty == Tsarray && exp.op == TOK.assign)
+ if (t1.ty == Tsarray && exp.op == EXP.assign)
{
Type tn = exp.e1.type.nextOf();
if (tn && !tn.baseElemOf().isAssignable())
// Try to do a decent error message with the expression
// before it gets constant folded
- if (exp.op == TOK.assign)
+ if (exp.op == EXP.assign)
e1x = e1x.modifiableLvalue(sc, e1old);
e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true);
- if (e1x.op == TOK.error)
+ if (e1x.op == EXP.error)
{
result = e1x;
return;
while (telem.ty == Tarray)
telem = telem.nextOf();
- if (exp.e1.op == TOK.slice && t1.nextOf() &&
- (telem.ty != Tvoid || e2x.op == TOK.null_) &&
+ if (exp.e1.op == EXP.slice && t1.nextOf() &&
+ (telem.ty != Tvoid || e2x.op == EXP.null_) &&
e2x.implicitConvTo(t1.nextOf()))
{
// Check for block assignment. If it is of type void[], void[][], etc,
// '= null' is the only allowable block assignment (Bug 7493)
exp.memset = MemorySet.blockAssign; // make it easy for back end to tell what this is
e2x = e2x.implicitCastTo(sc, t1.nextOf());
- if (exp.op != TOK.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf()))
+ if (exp.op != EXP.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf()))
return setError();
}
- else if (exp.e1.op == TOK.slice &&
+ else if (exp.e1.op == EXP.slice &&
(t2.ty == Tarray || t2.ty == Tsarray) &&
t2.nextOf().implicitConvTo(t1.nextOf()))
{
}
}
- if (exp.op != TOK.blit &&
- (e2x.op == TOK.slice && (cast(UnaExp)e2x).e1.isLvalue() ||
- e2x.op == TOK.cast_ && (cast(UnaExp)e2x).e1.isLvalue() ||
- e2x.op != TOK.slice && e2x.isLvalue()))
+ if (exp.op != EXP.blit &&
+ (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() ||
+ e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() ||
+ e2x.op != EXP.slice && e2x.isLvalue()))
{
if (exp.e1.checkPostblit(sc, t1.nextOf()))
return setError();
}
- if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == TOK.assign &&
- e2x.op != TOK.slice && e2x.op != TOK.assign &&
- e2x.op != TOK.arrayLiteral && e2x.op != TOK.string_ &&
- !(e2x.op == TOK.add || e2x.op == TOK.min ||
- e2x.op == TOK.mul || e2x.op == TOK.div ||
- e2x.op == TOK.mod || e2x.op == TOK.xor ||
- e2x.op == TOK.and || e2x.op == TOK.or ||
- e2x.op == TOK.pow ||
- e2x.op == TOK.tilde || e2x.op == TOK.negate))
+ if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign &&
+ e2x.op != EXP.slice && e2x.op != EXP.assign &&
+ e2x.op != EXP.arrayLiteral && e2x.op != EXP.string_ &&
+ !(e2x.op == EXP.add || e2x.op == EXP.min ||
+ e2x.op == EXP.mul || e2x.op == EXP.div ||
+ e2x.op == EXP.mod || e2x.op == EXP.xor ||
+ e2x.op == EXP.and || e2x.op == EXP.or ||
+ e2x.op == EXP.pow ||
+ e2x.op == EXP.tilde || e2x.op == EXP.negate))
{
const(char)* e1str = exp.e1.toChars();
const(char)* e2str = e2x.toChars();
* elements need to be const at best. So we should give a chance
* to change code unit size for polysemous string literal.
*/
- if (e2x.op == TOK.string_)
+ if (e2x.op == EXP.string_)
e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf());
else
e2x = e2x.implicitCastTo(sc, exp.e1.type);
}
else
{
- if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == TOK.assign &&
+ if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign &&
t1.ty == Tarray && t2.ty == Tsarray &&
- e2x.op != TOK.slice &&
+ e2x.op != EXP.slice &&
t2.implicitConvTo(t1))
{
// Disallow ar[] = sa (Converted to ar[] = sa[])
// Disallow da = sa (Converted to da = sa[])
const(char)* e1str = exp.e1.toChars();
const(char)* e2str = e2x.toChars();
- const(char)* atypestr = exp.e1.op == TOK.slice ? "element-wise" : "slice";
+ const(char)* atypestr = exp.e1.op == EXP.slice ? "element-wise" : "slice";
exp.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr, e1str, e2str, e1str, e2str);
}
- if (exp.op == TOK.blit)
+ if (exp.op == EXP.blit)
e2x = e2x.castTo(sc, exp.e1.type);
else
{
// If the implicit cast has failed and the assign expression is
// the initialization of a struct member field
- if (e2x.op == TOK.error && exp.op == TOK.construct && t1.ty == Tstruct)
+ if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct)
{
scope sd = (cast(TypeStruct)t1).sym;
Dsymbol opAssign = search_function(sd, Id.assign);
}
}
}
- if (e2x.op == TOK.error)
+ if (e2x.op == EXP.error)
{
result = e2x;
return;
{
// Look for valid array operations
if (exp.memset != MemorySet.blockAssign &&
- exp.e1.op == TOK.slice &&
+ exp.e1.op == EXP.slice &&
(isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op)))
{
exp.type = exp.e1.type;
- if (exp.op == TOK.construct) // https://issues.dlang.org/show_bug.cgi?id=10282
+ if (exp.op == EXP.construct) // https://issues.dlang.org/show_bug.cgi?id=10282
// tweak mutability of e1 element
exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf();
result = arrayOp(exp, sc);
// Drop invalid array operations in e2
// d = a[] + b[], d = (a[] + b[])[0..2], etc
- if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == TOK.assign))
+ if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == EXP.assign))
return setError();
// Remains valid array assignments
/* Don't allow assignment to classes that were allocated on the stack with:
* scope Class c = new Class();
*/
- if (exp.e1.op == TOK.variable && exp.op == TOK.assign)
+ if (exp.e1.op == EXP.variable && exp.op == EXP.assign)
{
VarExp ve = cast(VarExp)exp.e1;
VarDeclaration vd = ve.var.isVarDeclaration();
}
}
- if (exp.e1.op == TOK.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe)
+ if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe)
{
exp.error("cannot modify compiler-generated variable `__ctfe`");
}
exp.type = exp.e1.type;
assert(exp.type);
- auto res = exp.op == TOK.assign ? exp.reorderSettingAAElem(sc) : exp;
+ auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp;
Expression tmp;
/* https://issues.dlang.org/show_bug.cgi?id=22366
*
* `checkAssignExp` expects only AssignExps.
*/
checkAssignEscape(sc, Expression.extractLast(res, tmp), false);
+
+ if (auto ae = res.isConstructExp())
+ {
+ Type t1b = ae.e1.type.toBasetype();
+ if (t1b.ty != Tsarray && t1b.ty != Tarray)
+ return setResult(res);
+
+ /* Do not lower Rvalues and references, as they need to be moved,
+ * not copied.
+ * Skip the lowering when the RHS is an array literal, as e2ir
+ * already handles such cases more elegantly.
+ */
+ const isArrayCtor =
+ (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) &&
+ ae.e2.isLvalue &&
+ !(ae.e1.isVarExp &&
+ ae.e1.isVarExp.var.isVarDeclaration.isReference) &&
+ (ae.e2.isVarExp ||
+ ae.e2.isSliceExp ||
+ (ae.e2.type.ty == Tsarray && !ae.e2.isArrayLiteralExp)) &&
+ ae.e1.type.nextOf &&
+ ae.e2.type.nextOf &&
+ ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf);
+
+ const isArraySetCtor =
+ (ae.e1.isSliceExp || ae.e1.type.ty == Tsarray) &&
+ ae.e2.isLvalue &&
+ (ae.e2.type.ty == Tstruct || ae.e2.type.ty == Tsarray) &&
+ ae.e1.type.nextOf &&
+ ae.e1.type.nextOf.equivalent(ae.e2.type);
+
+ if (isArrayCtor || isArraySetCtor)
+ {
+ const ts = t1b.nextOf().baseElemOf().isTypeStruct();
+ if (!ts || (!ts.sym.postblit && !ts.sym.dtor))
+ return setResult(res);
+
+ auto func = isArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor;
+ const other = isArrayCtor ? "other array" : "value";
+ if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object))
+ return setError();
+
+ // Lower to object._d_array{,set}ctor(e1, e2)
+ Expression id = new IdentifierExp(exp.loc, Id.empty);
+ id = new DotIdExp(exp.loc, id, Id.object);
+ id = new DotIdExp(exp.loc, id, func);
+ id = id.expressionSemantic(sc);
+
+ auto arguments = new Expressions();
+ arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf).expressionSemantic(sc));
+ if (isArrayCtor)
+ {
+ arguments.push(new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf).expressionSemantic(sc));
+ Expression ce = new CallExp(exp.loc, id, arguments);
+ res = ce.expressionSemantic(sc);
+ }
+ else
+ {
+ Expression e0;
+ // If ae.e2 is not a variable, construct a temp variable, as _d_arraysetctor requires `ref` access
+ if (!ae.e2.isVarExp)
+ {
+ auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2);
+ e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
+ arguments.push(new VarExp(vd.loc, vd).expressionSemantic(sc));
+ }
+ else
+ arguments.push(ae.e2);
+
+ Expression ce = new CallExp(exp.loc, id, arguments);
+ res = Expression.combine(e0, ce).expressionSemantic(sc);
+ }
+
+ if (global.params.verbose)
+ message("lowered %s =>\n %s", exp.toChars(), res.toChars());
+ }
+ }
+
return setResult(res);
}
return setError();
assert(exp.e1.type && exp.e2.type);
- if (exp.e1.op == TOK.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
+ if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
{
if (checkNonAssignmentArrayOp(exp.e1))
return setError();
e = Expression.extractLast(e, e0);
assert(e == exp);
- if (exp.e1.op == TOK.variable)
+ if (exp.e1.op == EXP.variable)
{
// Rewrite: e1 = e1 ^^ e2
e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2);
return;
}
- if (exp.e1.op == TOK.slice)
+ if (exp.e1.op == EXP.slice)
{
SliceExp se = cast(SliceExp)exp.e1;
if (se.e1.type.toBasetype().ty == Tsarray)
}
exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
- if (exp.e1.op == TOK.error)
+ if (exp.e1.op == EXP.error)
{
result = exp.e1;
return;
}
- if (exp.e2.op == TOK.error)
+ if (exp.e2.op == EXP.error)
{
result = exp.e2;
return;
Type tb2 = exp.e2.type.toBasetype();
/* Possibilities:
- * TOK.concatenateAssign: appending T[] to T[]
- * TOK.concatenateElemAssign: appending T to T[]
- * TOK.concatenateDcharAssign: appending dchar to T[]
+ * EXP.concatenateAssign: appending T[] to T[]
+ * EXP.concatenateElemAssign: appending T to T[]
+ * EXP.concatenateDcharAssign: appending dchar to T[]
*/
if ((tb1.ty == Tarray) &&
(tb2.ty == Tarray || tb2.ty == Tsarray) &&
(tb2.nextOf().implicitConvTo(tb1next) &&
(tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
{
- // TOK.concatenateAssign
- assert(exp.op == TOK.concatenateAssign);
+ // EXP.concatenateAssign
+ assert(exp.op == EXP.concatenateAssign);
if (exp.e1.checkPostblit(sc, tb1next))
return setError();
exp.type = exp.e1.type;
auto res = exp.reorderSettingAAElem(sc);
- if ((exp.op == TOK.concatenateElemAssign || exp.op == TOK.concatenateDcharAssign) &&
+ if ((exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign) &&
global.params.useDIP1000 == FeatureState.enabled)
checkAssignEscape(sc, res, false);
result = res;
{
e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t);
}
+ else if (stride == cast(d_int64)SIZE_INVALID)
+ e = ErrorExp.get();
else
{
e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t));
Type tb2next = tb2.nextOf();
// Check for: array ~ array
- if (tb1next && tb2next && (tb1next.implicitConvTo(tb2next) >= MATCH.constant || tb2next.implicitConvTo(tb1next) >= MATCH.constant || exp.e1.op == TOK.arrayLiteral && exp.e1.implicitConvTo(tb2) || exp.e2.op == TOK.arrayLiteral && exp.e2.implicitConvTo(tb1)))
+ if (tb1next && tb2next && (tb1next.implicitConvTo(tb2next) >= MATCH.constant || tb2next.implicitConvTo(tb1next) >= MATCH.constant || exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2) || exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1)))
{
/* https://issues.dlang.org/show_bug.cgi?id=9248
* Here to avoid the case of:
// Check for: array ~ element
if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid)
{
- if (exp.e1.op == TOK.arrayLiteral)
+ if (exp.e1.op == EXP.arrayLiteral)
{
exp.e2 = doCopyOrMove(sc, exp.e2);
// https://issues.dlang.org/show_bug.cgi?id=14686
// Postblit call appears in AST, and this is
// finally translated to an ArrayLiteralExp in below optimize().
}
- else if (exp.e1.op == TOK.string_)
+ else if (exp.e1.op == EXP.string_)
{
// No postblit call exists on character (integer) value.
}
// Postblit call will be done in runtime helper function
}
- if (exp.e1.op == TOK.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf()))
+ if (exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf()))
{
exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf());
exp.type = tb2.arrayOf();
// Check for: element ~ array
if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid)
{
- if (exp.e2.op == TOK.arrayLiteral)
+ if (exp.e2.op == EXP.arrayLiteral)
{
exp.e1 = doCopyOrMove(sc, exp.e1);
}
- else if (exp.e2.op == TOK.string_)
+ else if (exp.e2.op == EXP.string_)
{
}
else
return setError();
}
- if (exp.e2.op == TOK.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf()))
+ if (exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf()))
{
exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf());
exp.type = tb1.arrayOf();
{
Type t1 = tb1next.mutableOf().constOf().arrayOf();
Type t2 = tb2next.mutableOf().constOf().arrayOf();
- if (exp.e1.op == TOK.string_ && !(cast(StringExp)exp.e1).committed)
+ if (exp.e1.op == EXP.string_ && !(cast(StringExp)exp.e1).committed)
exp.e1.type = t1;
else
exp.e1 = exp.e1.castTo(sc, t1);
- if (exp.e2.op == TOK.string_ && !(cast(StringExp)exp.e2).committed)
+ if (exp.e2.op == EXP.string_ && !(cast(StringExp)exp.e2).committed)
exp.e2.type = t2;
else
exp.e2 = exp.e2.castTo(sc, t2);
// First, attempt to fold the expression.
e = exp.optimize(WANTvalue);
- if (e.op != TOK.pow)
+ if (e.op != EXP.pow)
{
e = e.expressionSemantic(sc);
result = e;
}
e = new ScopeExp(exp.loc, mmath);
- if (exp.e2.op == TOK.float64 && exp.e2.toReal() == CTFloat.half)
+ if (exp.e2.op == EXP.float64 && exp.e2.toReal() == CTFloat.half)
{
// Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1);
Expression e1x = exp.e1.expressionSemantic(sc);
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (e1x.op == TOK.type)
+ if (e1x.op == EXP.type)
e1x = resolveAliasThis(sc, e1x);
e1x = resolveProperties(sc, e1x);
/* If in static if, don't evaluate e2 if we don't have to.
*/
e1x = e1x.optimize(WANTvalue);
- if (e1x.isBool(exp.op == TOK.orOr))
+ if (e1x.toBool().hasValue(exp.op == EXP.orOr))
{
- result = IntegerExp.createBool(exp.op == TOK.orOr);
+ result = IntegerExp.createBool(exp.op == EXP.orOr);
return;
}
}
ctorflow.freeFieldinit();
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (e2x.op == TOK.type)
+ if (e2x.op == EXP.type)
e2x = resolveAliasThis(sc, e2x);
e2x = resolveProperties(sc, e2x);
if (e2x.type.ty != Tvoid)
e2x = e2x.toBoolean(sc);
- if (e2x.op == TOK.type || e2x.op == TOK.scope_)
+ if (e2x.op == EXP.type || e2x.op == EXP.scope_)
{
exp.error("`%s` is not an expression", exp.e2.toChars());
return setError();
}
- if (e1x.op == TOK.error || e1x.type.ty == Tnoreturn)
+ if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn)
{
result = e1x;
return;
}
- if (e2x.op == TOK.error)
+ if (e2x.op == EXP.error)
{
result = e2x;
return;
}
Type t1 = exp.e1.type.toBasetype();
Type t2 = exp.e2.type.toBasetype();
- if (t1.ty == Tclass && exp.e2.op == TOK.null_ || t2.ty == Tclass && exp.e1.op == TOK.null_)
+ if (t1.ty == Tclass && exp.e2.op == EXP.null_ || t2.ty == Tclass && exp.e1.op == EXP.null_)
{
exp.error("do not use `null` when comparing class types");
return setError();
}
- TOK cmpop;
+ EXP cmpop;
if (auto e = exp.op_overload(sc, &cmpop))
{
if (!e.type.isscalar() && e.type.equals(exp.e1.type))
exp.error("recursive `opCmp` expansion");
return setError();
}
- if (e.op == TOK.call)
+ if (e.op == EXP.call)
{
e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0);
e = e.expressionSemantic(sc);
}
else if (t1.ty == Taarray || t2.ty == Taarray)
{
- exp.error("`%s` is not defined for associative arrays", Token.toChars(exp.op));
+ exp.error("`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr);
return setError();
}
else if (!target.isVectorOpSupported(t1, exp.op, t2))
result = e;
return;
}
- if (exp.e1.op == TOK.type || exp.e2.op == TOK.type)
+ if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
{
/* https://issues.dlang.org/show_bug.cgi?id=12520
* empty tuples are represented as types so special cases are added
static auto extractTypeTupAndExpTup(Expression e)
{
static struct Result { bool ttEmpty; bool te; }
- auto tt = e.op == TOK.type ? e.isTypeExp().type.isTypeTuple() : null;
+ auto tt = e.op == EXP.type ? e.isTypeExp().type.isTypeTuple() : null;
return Result(tt && (!tt.arguments || !tt.arguments.dim), e.isTupleExp() !is null);
}
auto tups1 = extractTypeTupAndExpTup(exp.e1);
// AliasSeq!() == AliasSeq!(<at least a value>)
if (tups1.ttEmpty && tups2.te)
{
- result = IntegerExp.createBool(exp.op != TOK.equal);
+ result = IntegerExp.createBool(exp.op != EXP.equal);
return;
}
// AliasSeq!(<at least a value>) == AliasSeq!()
else if (tups1.te && tups2.ttEmpty)
{
- result = IntegerExp.createBool(exp.op != TOK.equal);
+ result = IntegerExp.createBool(exp.op != EXP.equal);
return;
}
// AliasSeq!() == AliasSeq!()
else if (tups1.ttEmpty && tups2.ttEmpty)
{
- result = IntegerExp.createBool(exp.op == TOK.equal);
+ result = IntegerExp.createBool(exp.op == EXP.equal);
return;
}
// otherwise, two types are really not comparable
* comparing the addresses of two statics. If so, we can just see
* if they are the same symbol.
*/
- if (exp.e1.op == TOK.address && exp.e2.op == TOK.address)
+ if (exp.e1.op == EXP.address && exp.e2.op == EXP.address)
{
AddrExp ae1 = cast(AddrExp)exp.e1;
AddrExp ae2 = cast(AddrExp)exp.e2;
- if (ae1.e1.op == TOK.variable && ae2.e1.op == TOK.variable)
+ if (ae1.e1.op == EXP.variable && ae2.e1.op == EXP.variable)
{
VarExp ve1 = cast(VarExp)ae1.e1;
VarExp ve2 = cast(VarExp)ae2.e1;
if (ve1.var == ve2.var)
{
// They are the same, result is 'true' for ==, 'false' for !=
- result = IntegerExp.createBool(exp.op == TOK.equal);
+ result = IntegerExp.createBool(exp.op == EXP.equal);
return;
}
}
(*arguments)[1] = exp.e2;
__equals = new CallExp(exp.loc, __equals, arguments);
- if (exp.op == TOK.notEqual)
+ if (exp.op == EXP.notEqual)
{
__equals = new NotExp(exp.loc, __equals);
}
if (f1 || f2)
return setError();
- if (exp.e1.op == TOK.type || exp.e2.op == TOK.type)
+ if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
{
result = exp.incompatibleTypes();
return;
return;
}
- if (exp.e1.op == TOK.call)
+ if (exp.e1.op == EXP.call)
exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc);
- if (exp.e2.op == TOK.call)
+ if (exp.e2.op == EXP.call)
exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc);
if (exp.e1.type.toBasetype().ty == Tsarray ||
return;
}
- if (exp.econd.op == TOK.dotIdentifier)
+ if (exp.econd.op == EXP.dotIdentifier)
(cast(DotIdExp)exp.econd).noderef = true;
Expression ec = exp.econd.expressionSemantic(sc);
sc.merge(exp.loc, ctorflow1);
ctorflow1.freeFieldinit();
- if (ec.op == TOK.error)
+ if (ec.op == EXP.error)
{
result = ec;
return;
return setError();
exp.econd = ec;
- if (e1x.op == TOK.error)
+ if (e1x.op == EXP.error)
{
result = e1x;
return;
return setError();
exp.e1 = e1x;
- if (e2x.op == TOK.error)
+ if (e2x.op == EXP.error)
{
result = e2x;
return;
printf("UnaExp::semantic('%s')\n", e.toChars());
}
Expression e1x = e.e1.expressionSemantic(sc);
- if (e1x.op == TOK.error)
+ if (e1x.op == EXP.error)
return e1x;
e.e1 = e1x;
return null;
Expression e2x = e.e2.expressionSemantic(sc);
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (e1x.op == TOK.type)
+ if (e1x.op == EXP.type)
e1x = resolveAliasThis(sc, e1x);
- if (e2x.op == TOK.type)
+ if (e2x.op == EXP.type)
e2x = resolveAliasThis(sc, e2x);
- if (e1x.op == TOK.error)
+ if (e1x.op == EXP.error)
return e1x;
- if (e2x.op == TOK.error)
+ if (e2x.op == EXP.error)
return e2x;
e.e1 = e1x;
e.e2 = e2x;
return ex;
Expression e1x = resolveProperties(sc, e.e1);
Expression e2x = resolveProperties(sc, e.e2);
- if (e1x.op == TOK.error)
+ if (e1x.op == EXP.error)
return e1x;
- if (e2x.op == TOK.error)
+ if (e2x.op == EXP.error)
return e2x;
e.e1 = e1x;
e.e2 = e2x;
Dsymbol ds;
switch (exp.e1.op)
{
- case TOK.scope_: return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds);
- case TOK.variable: return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var);
- case TOK.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var);
- case TOK.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars);
- case TOK.template_:
+ case EXP.scope_: return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds);
+ case EXP.variable: return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var);
+ case EXP.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var);
+ case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars);
+ case EXP.template_:
{
TemplateExp te = exp.e1.isTemplateExp();
return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td);
}
assert(e);
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
return e;
- if (e.op == TOK.dotVariable)
+ if (e.op == EXP.dotVariable)
{
DotVarExp dve = cast(DotVarExp)e;
if (FuncDeclaration fd = dve.var.isFuncDeclaration())
.expressionSemantic(sc);
}
}
- else if (e.op == TOK.variable)
+ else if (e.op == EXP.variable)
{
VarExp ve = cast(VarExp)e;
if (FuncDeclaration fd = ve.var.isFuncDeclaration())
}
}
- if (e.op == TOK.dotTemplateDeclaration)
+ if (e.op == EXP.dotTemplateDeclaration)
{
DotTemplateExp dte = cast(DotTemplateExp)e;
exp.e1 = dte.e1; // pull semantic() result
return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
.expressionSemantic(sc);
}
- else if (e.op == TOK.template_)
+ else if (e.op == EXP.template_)
{
exp.ti.tempdecl = (cast(TemplateExp)e).td;
return new ScopeExp(exp.loc, exp.ti)
.expressionSemantic(sc);
}
- else if (e.op == TOK.dot)
+ else if (e.op == EXP.dot)
{
DotExp de = cast(DotExp)e;
- if (de.e2.op == TOK.overloadSet)
+ if (de.e2.op == EXP.overloadSet)
{
if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc))
{
.expressionSemantic(sc);
}
}
- else if (e.op == TOK.overloadSet)
+ else if (e.op == EXP.overloadSet)
{
OverExp oe = cast(OverExp)e;
exp.ti.tempdecl = oe.vars;
}
s = s.toParent2();
}
- if (n > 1 || e1.op == TOK.index)
+ if (n > 1 || e1.op == EXP.index)
e1 = e1.expressionSemantic(sc);
if (s && e1.type.equivalent(Type.tvoidptr))
{
e = resolveProperties(sc, e);
if (i >= nfields)
{
- if (i <= sd.fields.dim && e.op == TOK.null_)
+ if (i <= sd.fields.dim && e.op == EXP.null_)
{
// CTFE sometimes creates null as hidden pointer; we'll allow this.
continue;
}
return false;
}
- offset = cast(uint)(v.offset + v.type.size());
+ const vsize = v.type.size();
+ if (vsize == SIZE_INVALID)
+ return false;
+ offset = cast(uint)(v.offset + vsize);
Type t = v.type;
if (stype)
* Allow this by doing an explicit cast, which will lengthen the string
* literal.
*/
- if (e.op == TOK.string_ && tb.ty == Tsarray)
+ if (e.op == EXP.string_ && tb.ty == Tsarray)
{
StringExp se = cast(StringExp)e;
Type typeb = se.type.toBasetype();
e = e.implicitCastTo(sc, t);
L1:
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
return false;
(*elements)[i] = doCopyOrMove(sc, e);
{
switch(exp.op)
{
- case TOK.delete_:
+ case EXP.delete_:
exp.error("`delete` does not give a boolean result");
return ErrorExp.get();
- case TOK.comma:
+ case EXP.comma:
auto ce = exp.isCommaExp();
auto ex2 = ce.e2.toBoolean(sc);
- if (ex2.op == TOK.error)
+ if (ex2.op == EXP.error)
return ex2;
ce.e2 = ex2;
ce.type = ce.e2.type;
return ce;
- case TOK.assign:
- case TOK.construct:
- case TOK.blit:
+ case EXP.assign:
+ case EXP.construct:
+ case EXP.blit:
// Things like:
// if (a = b) ...
// are usually mistakes.
return ErrorExp.get();
//LogicalExp
- case TOK.andAnd:
- case TOK.orOr:
+ case EXP.andAnd:
+ case EXP.orOr:
auto le = exp.isLogicalExp();
auto ex2 = le.e2.toBoolean(sc);
- if (ex2.op == TOK.error)
+ if (ex2.op == EXP.error)
return ex2;
le.e2 = ex2;
return le;
- case TOK.question:
+ case EXP.question:
auto ce = exp.isCondExp();
auto ex1 = ce.e1.toBoolean(sc);
auto ex2 = ce.e2.toBoolean(sc);
- if (ex1.op == TOK.error)
+ if (ex1.op == EXP.error)
return ex1;
- if (ex2.op == TOK.error)
+ if (ex2.op == EXP.error)
return ex2;
ce.e1 = ex1;
ce.e2 = ex2;
void visitWith(WithStatement s)
{
// If it is with(Enum) {...}, just execute the body.
- if (s.exp.op == TOK.scope_ || s.exp.op == TOK.type)
+ if (s.exp.op == EXP.scope_ || s.exp.op == EXP.type)
{
}
else
if (!fbody)
return false;
- if (isVirtualMethod())
+ if (isVirtualMethod() &&
+ /*
+ * https://issues.dlang.org/show_bug.cgi?id=21719
+ *
+ * If we have an auto virtual function we can infer
+ * the attributes.
+ */
+ !(inferRetType && !isCtorDeclaration()))
return false; // since they may be overridden
if (sc.func &&
bool betterC; // be a "better C" compiler; no dependency on D runtime
bool addMain; // add a default main() function
bool allInst; // generate code for all template instantiations
- bool fix16997; // fix integral promotions for unary + - ~ operators
+ bool fix16997 = true; // fix integral promotions for unary + - ~ operators
// https://issues.dlang.org/show_bug.cgi?id=16997
bool fixAliasThis; // if the current scope has an alias this, check it before searching upper scopes
bool inclusiveInContracts; // 'in' contracts of overridden methods must be a superset of parent contract
override void visit(ExpStatement s)
{
- if (s.exp && s.exp.op == TOK.declaration &&
+ if (s.exp && s.exp.op == EXP.declaration &&
(cast(DeclarationExp)s.exp).declaration)
{
// bypass visit(DeclarationExp)
foreach (sx; *s.statements)
{
auto ds = sx ? sx.isExpStatement() : null;
- if (ds && ds.exp.op == TOK.declaration)
+ if (ds && ds.exp.op == EXP.declaration)
{
auto d = (cast(DeclarationExp)ds.exp).declaration;
assert(d.isDeclaration());
{
buf.writestring(" = ");
ExpInitializer ie = vd._init.isExpInitializer();
- if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit))
+ if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit))
(cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs);
else
vd._init.initializerToBuffer(buf, hgs);
{
buf.writestring(" = ");
auto ie = v._init.isExpInitializer();
- if (ie && (ie.exp.op == TOK.construct || ie.exp.op == TOK.blit))
+ if (ie && (ie.exp.op == EXP.construct || ie.exp.op == EXP.blit))
(cast(AssignExp)ie.exp).e2.expressionToBuffer(buf, hgs);
else
v._init.initializerToBuffer(buf, hgs);
buf.writestring("in");
if (auto es = frequire.isExpStatement())
{
- assert(es.exp && es.exp.op == TOK.assert_);
+ assert(es.exp && es.exp.op == EXP.assert_);
buf.writestring(" (");
(cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs);
buf.writeByte(')');
buf.writestring("out");
if (auto es = fensure.ensure.isExpStatement())
{
- assert(es.exp && es.exp.op == TOK.assert_);
+ assert(es.exp && es.exp.op == EXP.assert_);
buf.writestring(" (");
if (fensure.id)
{
buf.writestring("invariant");
if(auto es = d.fbody.isExpStatement())
{
- assert(es.exp && es.exp.op == TOK.assert_);
+ assert(es.exp && es.exp.op == EXP.assert_);
buf.writestring(" (");
(cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs);
buf.writestring(");");
////////////////////////////////////////////////////////////////////////////
override void visit(Expression e)
{
- buf.writestring(Token.toString(e.op));
+ buf.writestring(EXPtoString(e.op));
}
override void visit(IntegerExp e)
override void visit(UnaExp e)
{
- buf.writestring(Token.toString(e.op));
+ buf.writestring(EXPtoString(e.op));
expToBuffer(e.e1, precedence[e.op], buf, hgs);
}
{
expToBuffer(e.e1, precedence[e.op], buf, hgs);
buf.writeByte(' ');
- buf.writestring(Token.toString(e.op));
+ buf.writestring(EXPtoString(e.op));
buf.writeByte(' ');
expToBuffer(e.e2, cast(PREC)(precedence[e.op] + 1), buf, hgs);
}
override void visit(CallExp e)
{
- if (e.e1.op == TOK.type)
+ if (e.e1.op == EXP.type)
{
/* Avoid parens around type to prevent forbidden cast syntax:
* (sometype)(arg1)
override void visit(PostExp e)
{
expToBuffer(e.e1, precedence[e.op], buf, hgs);
- buf.writestring(Token.toString(e.op));
+ buf.writestring(EXPtoString(e.op));
}
override void visit(PreExp e)
{
- buf.writestring(Token.toString(e.op));
+ buf.writestring(EXPtoString(e.op));
expToBuffer(e.e1, precedence[e.op], buf, hgs);
}
override void visit(DefaultInitExp e)
{
- buf.writestring(Token.toString(e.op));
+ buf.writestring(EXPtoString(e.op));
}
override void visit(ClassReferenceExp e)
{
buf.writeByte('@');
- bool isAnonymous = p.userAttribDecl.atts.dim > 0 && (*p.userAttribDecl.atts)[0].op != TOK.call;
+ bool isAnonymous = p.userAttribDecl.atts.dim > 0 && !(*p.userAttribDecl.atts)[0].isCallExp();
if (isAnonymous)
buf.writeByte('(');
{
if (e.type == Type.tsize_t)
{
- Expression ex = (e.op == TOK.cast_ ? (cast(CastExp)e).e1 : e);
+ Expression ex = (e.op == EXP.cast_ ? (cast(CastExp)e).e1 : e);
ex = ex.optimize(WANTvalue);
- const dinteger_t uval = ex.op == TOK.int64 ? ex.toInteger() : cast(dinteger_t)-1;
+ const dinteger_t uval = ex.op == EXP.int64 ? ex.toInteger() : cast(dinteger_t)-1;
if (cast(sinteger_t)uval >= 0)
{
dinteger_t sizemax = void;
debug
{
if (precedence[e.op] == PREC.zero)
- printf("precedence not defined for token '%s'\n", Token.toChars(e.op));
+ printf("precedence not defined for token '%s'\n", EXPtoString(e.op).ptr);
}
if (e.op == 0xFF)
{
}
else if (Expression e = isExpression(oarg))
{
- if (e.op == TOK.int64 || e.op == TOK.float64 || e.op == TOK.null_ || e.op == TOK.string_ || e.op == TOK.this_)
+ if (e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.this_)
{
buf.writestring(e.toChars());
return;
}
else if (auto e = isExpression(oarg))
{
- if (e.op == TOK.variable)
+ if (e.op == EXP.variable)
e = e.optimize(WANTvalue); // added to fix https://issues.dlang.org/show_bug.cgi?id=7375
expToBuffer(e, PREC.assign, buf, hgs);
}
case Ttag: return visitTag(cast(TypeTag)t);
}
}
+
+/****************************************
+ * Convert EXP to char*.
+ */
+
+string EXPtoString(EXP op)
+{
+ static immutable char*[EXP.max + 1] strings =
+ [
+ EXP.type : "type",
+ EXP.error : "error",
+ EXP.objcClassReference : "class",
+
+ EXP.typeof_ : "typeof",
+ EXP.mixin_ : "mixin",
+
+ EXP.import_ : "import",
+ EXP.dotVariable : "dotvar",
+ EXP.scope_ : "scope",
+ EXP.identifier : "identifier",
+ EXP.this_ : "this",
+ EXP.super_ : "super",
+ EXP.int64 : "long",
+ EXP.float64 : "double",
+ EXP.complex80 : "creal",
+ EXP.null_ : "null",
+ EXP.string_ : "string",
+ EXP.arrayLiteral : "arrayliteral",
+ EXP.assocArrayLiteral : "assocarrayliteral",
+ EXP.classReference : "classreference",
+ EXP.file : "__FILE__",
+ EXP.fileFullPath : "__FILE_FULL_PATH__",
+ EXP.line : "__LINE__",
+ EXP.moduleString : "__MODULE__",
+ EXP.functionString : "__FUNCTION__",
+ EXP.prettyFunction : "__PRETTY_FUNCTION__",
+ EXP.typeid_ : "typeid",
+ EXP.is_ : "is",
+ EXP.assert_ : "assert",
+ EXP.halt : "halt",
+ EXP.template_ : "template",
+ EXP.dSymbol : "symbol",
+ EXP.function_ : "function",
+ EXP.variable : "var",
+ EXP.symbolOffset : "symoff",
+ EXP.structLiteral : "structLiteral",
+ EXP.compoundLiteral : "compoundliteral",
+ EXP.arrayLength : "arraylength",
+ EXP.delegatePointer : "delegateptr",
+ EXP.delegateFunctionPointer : "delegatefuncptr",
+ EXP.remove : "remove",
+ EXP.tuple : "tuple",
+ EXP.traits : "__traits",
+ EXP.default_ : "default",
+ EXP.overloadSet : "__overloadset",
+ EXP.void_ : "void",
+ EXP.vectorArray : "vectorarray",
+ EXP._Generic : "_Generic",
+
+ // post
+ EXP.dotTemplateInstance : "dotti",
+ EXP.dotIdentifier : "dotid",
+ EXP.dotTemplateDeclaration : "dottd",
+ EXP.dot : ".",
+ EXP.dotType : "dottype",
+ EXP.plusPlus : "++",
+ EXP.minusMinus : "--",
+ EXP.prePlusPlus : "++",
+ EXP.preMinusMinus : "--",
+ EXP.call : "call",
+ EXP.slice : "..",
+ EXP.array : "[]",
+ EXP.index : "[i]",
+
+ EXP.delegate_ : "delegate",
+ EXP.address : "&",
+ EXP.star : "*",
+ EXP.negate : "-",
+ EXP.uadd : "+",
+ EXP.not : "!",
+ EXP.tilde : "~",
+ EXP.delete_ : "delete",
+ EXP.new_ : "new",
+ EXP.newAnonymousClass : "newanonclass",
+ EXP.cast_ : "cast",
+
+ EXP.vector : "__vector",
+ EXP.pow : "^^",
+
+ EXP.mul : "*",
+ EXP.div : "/",
+ EXP.mod : "%",
+
+ EXP.add : "+",
+ EXP.min : "-",
+ EXP.concatenate : "~",
+
+ EXP.leftShift : "<<",
+ EXP.rightShift : ">>",
+ EXP.unsignedRightShift : ">>>",
+
+ EXP.lessThan : "<",
+ EXP.lessOrEqual : "<=",
+ EXP.greaterThan : ">",
+ EXP.greaterOrEqual : ">=",
+ EXP.in_ : "in",
+
+ EXP.equal : "==",
+ EXP.notEqual : "!=",
+ EXP.identity : "is",
+ EXP.notIdentity : "!is",
+
+ EXP.and : "&",
+ EXP.xor : "^",
+ EXP.or : "|",
+
+ EXP.andAnd : "&&",
+ EXP.orOr : "||",
+
+ EXP.question : "?",
+
+ EXP.assign : "=",
+ EXP.construct : "=",
+ EXP.blit : "=",
+ EXP.addAssign : "+=",
+ EXP.minAssign : "-=",
+ EXP.concatenateAssign : "~=",
+ EXP.concatenateElemAssign : "~=",
+ EXP.concatenateDcharAssign : "~=",
+ EXP.mulAssign : "*=",
+ EXP.divAssign : "/=",
+ EXP.modAssign : "%=",
+ EXP.powAssign : "^^=",
+ EXP.leftShiftAssign : "<<=",
+ EXP.rightShiftAssign : ">>=",
+ EXP.unsignedRightShiftAssign : ">>>=",
+ EXP.andAssign : "&=",
+ EXP.orAssign : "|=",
+ EXP.xorAssign : "^=",
+
+ EXP.comma : ",",
+ EXP.declaration : "declaration",
+
+ EXP.interval : "interval",
+ ];
+ const p = strings[op];
+ if (!p)
+ {
+ printf("error: EXP %d has no string\n", op);
+ return "XXXXX";
+ //assert(0);
+ }
+ assert(p);
+ return p[0 .. strlen(p)];
+}
e = (*s.constraints)[i];
e = e.expressionSemantic(sc);
- assert(e.op == TOK.string_ && (cast(StringExp) e).sz == 1);
+ assert(e.op == EXP.string_ && (cast(StringExp) e).sz == 1);
(*s.constraints)[i] = e;
}
}
{
Expression e = (*s.clobbers)[i];
e = e.expressionSemantic(sc);
- assert(e.op == TOK.string_ && (cast(StringExp) e).sz == 1);
+ assert(e.op == EXP.string_ && (cast(StringExp) e).sz == 1);
(*s.clobbers)[i] = e;
}
}
{ "dup" },
{ "_aaApply" },
{ "_aaApply2" },
+ { "_d_arrayctor" },
+ { "_d_arraysetctor" },
// For pragma's
{ "Pinline", "inline" },
{ "getUnitTests" },
{ "getVirtualIndex" },
{ "getPointerBitmap" },
+ { "initSymbol" },
{ "getCppNamespaces" },
{ "isReturnOnStack" },
{ "isZeroInit" },
auto tm = vd.type.addMod(t.mod);
auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret);
auto ex = iz.initializerToExpression();
- if (ex.op == TOK.error)
+ if (ex.op == EXP.error)
{
errors = true;
elems[fieldi] = ErrorExp.get(); // for better diagnostics on multiple errors
errors = true;
}
length = cast(uint)idxvalue;
- if (idx.op == TOK.error)
+ if (idx.op == EXP.error)
errors = true;
}
Initializer val = i.value[j];
errors = true;
ei = val.isExpInitializer();
// found a tuple, expand it
- if (ei && ei.exp.op == TOK.tuple)
+ if (ei && ei.exp.op == EXP.tuple)
{
TupleExp te = cast(TupleExp)ei.exp;
i.index.remove(j);
return err();
const sz = t.nextOf().size();
+ if (sz == SIZE_INVALID)
+ return err();
bool overflow;
const max = mulu(i.dim, sz, overflow);
if (overflow || max >= amax)
i.exp = resolveProperties(sc, i.exp);
if (needInterpret)
sc = sc.endCTFE();
- if (i.exp.op == TOK.error)
+ if (i.exp.op == EXP.error)
return err();
uint olderrors = global.errors;
*/
i.exp = i.exp.optimize(WANTvalue);
i.exp = i.exp.ctfeInterpret();
- if (i.exp.op == TOK.voidExpression)
+ if (i.exp.op == EXP.voidExpression)
error(i.loc, "variables cannot be initialized with an expression of type `void`. Use `void` initialization instead.");
}
else
i.exp = new TupleExp(i.exp.loc, new Expressions());
i.exp.type = et;
}
- if (i.exp.op == TOK.type)
+ if (i.exp.op == EXP.type)
{
i.exp.error("initializer must be an expression, not `%s`", i.exp.toChars());
return err();
return err();
}
Type ti = i.exp.type.toBasetype();
- if (i.exp.op == TOK.tuple && i.expandTuples && !i.exp.implicitConvTo(t))
+ if (i.exp.op == EXP.tuple && i.expandTuples && !i.exp.implicitConvTo(t))
{
return new ExpInitializer(i.loc, i.exp);
}
* Allow this by doing an explicit cast, which will lengthen the string
* literal.
*/
- if (i.exp.op == TOK.string_ && tb.ty == Tsarray)
+ if (i.exp.op == EXP.string_ && tb.ty == Tsarray)
{
StringExp se = cast(StringExp)i.exp;
Type typeb = se.type.toBasetype();
{
uinteger_t dim1 = (cast(TypeSArray)tb).dim.toInteger();
uinteger_t dim2 = dim1;
- if (i.exp.op == TOK.arrayLiteral)
+ if (i.exp.op == EXP.arrayLiteral)
{
ArrayLiteralExp ale = cast(ArrayLiteralExp)i.exp;
dim2 = ale.elements ? ale.elements.dim : 0;
}
- else if (i.exp.op == TOK.slice)
+ else if (i.exp.op == EXP.slice)
{
Type tx = toStaticArrayType(cast(SliceExp)i.exp);
if (tx)
i.exp = i.exp.implicitCastTo(sc, t);
}
L1:
- if (i.exp.op == TOK.error)
+ if (i.exp.op == EXP.error)
{
return i;
}
auto tm = vd.type.addMod(ts.mod);
auto iz = di.initializer.initializerSemantic(sc, tm, needInterpret);
auto ex = iz.initializerToExpression();
- if (ex.op == TOK.error)
+ if (ex.op == EXP.error)
{
errors = true;
continue;
}
const sz = tn.size(); // element size
+ if (sz == SIZE_INVALID)
+ return err();
bool overflow;
const max = mulu(edim, sz, overflow);
if (overflow || max >= amax)
}
assert(iz.isExpInitializer());
(*values)[i] = (cast(ExpInitializer)iz).exp;
- assert((*values)[i].op != TOK.error);
+ assert(!(*values)[i].isErrorExp());
}
Expression e = new AssocArrayLiteralExp(init.loc, keys, values);
auto ei = new ExpInitializer(init.loc, e);
}
assert(iz.isExpInitializer());
(*elements)[i] = (cast(ExpInitializer)iz).exp;
- assert((*elements)[i].op != TOK.error);
+ assert(!(*elements)[i].isErrorExp());
}
Expression e = new ArrayLiteralExp(init.loc, null, elements);
auto ei = new ExpInitializer(init.loc, e);
init.exp = init.exp.expressionSemantic(sc);
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (init.exp.op == TOK.type)
+ if (init.exp.op == EXP.type)
init.exp = resolveAliasThis(sc, init.exp);
init.exp = resolveProperties(sc, init.exp);
- if (init.exp.op == TOK.scope_)
+ if (init.exp.op == EXP.scope_)
{
ScopeExp se = cast(ScopeExp)init.exp;
TemplateInstance ti = se.sds.isTemplateInstance();
return new ErrorInitializer();
}
}
- if (init.exp.op == TOK.address)
+ if (init.exp.op == EXP.address)
{
AddrExp ae = cast(AddrExp)init.exp;
- if (ae.e1.op == TOK.overloadSet)
+ if (ae.e1.op == EXP.overloadSet)
{
init.exp.error("cannot infer type from overloaded function symbol `%s`", init.exp.toChars());
return new ErrorInitializer();
}
}
- if (init.exp.op == TOK.error)
+ if (init.exp.op == EXP.error)
{
return new ErrorInitializer();
}
{
if (auto e = init.index[i])
{
- if (e.op == TOK.int64)
+ if (e.op == EXP.int64)
{
const uinteger_t idxval = e.toInteger();
if (idxval >= amax)
*/
foreach (e; (*elements)[0 .. edim])
{
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
{
return e;
}
{
//printf("ExpInitializer::toExpression(t = %s) exp = %s\n", itype.toChars(), i.exp.toChars());
Type tb = itype.toBasetype();
- Expression e = (i.exp.op == TOK.construct || i.exp.op == TOK.blit) ? (cast(AssignExp)i.exp).e2 : i.exp;
+ Expression e = (i.exp.op == EXP.construct || i.exp.op == EXP.blit) ? (cast(AssignExp)i.exp).e2 : i.exp;
if (tb.ty == Tsarray && e.implicitConvTo(tb.nextOf()))
{
TypeSArray tsa = cast(TypeSArray)tb;
if (e.type.ty == Terror)
return false;
- if (e.op == TOK.null_)
+ if (e.op == EXP.null_)
return false;
if (auto se = e.isStructLiteralExp())
{
}
if (e.type.ty == Tpointer && !e.type.isPtrToFunction())
{
- if (e.op == TOK.symbolOffset) // address of a global is OK
+ if (e.op == EXP.symbolOffset) // address of a global is OK
return false;
- if (e.op == TOK.int64) // cast(void *)int is OK
+ if (e.op == EXP.int64) // cast(void *)int is OK
return false;
- if (e.op == TOK.string_) // "abc".ptr is OK
+ if (e.op == EXP.string_) // "abc".ptr is OK
return false;
return true;
}
import dmd.expression;
import dmd.func;
import dmd.dmangle;
+import dmd.hdrgen;
import dmd.mtype;
import dmd.common.outbuffer;
import dmd.root.rmem;
return;
buf.writeByte('(');
- buf.writestring(Token.toString(exp.op));
+ buf.writestring(EXPtoString(exp.op));
exp.e1.accept(this);
if (buf.length != 0)
buf.writestring(")_");
return;
buf.writeByte('(');
- buf.writestring(Token.toChars(exp.op));
+ buf.writestring(EXPtoString(exp.op).ptr);
exp.e1.accept(this);
if (buf.length == 0)
// Intentionally not advancing `p`, such that subsequent calls keep returning TOK.endOfFile.
return;
case ' ':
+ // Skip 4 spaces at a time after aligning 'p' to a 4-byte boundary.
+ while ((cast(size_t)p) % uint.sizeof)
+ {
+ if (*p != ' ')
+ goto LendSkipFourSpaces;
+ p++;
+ }
+ while (*(cast(uint*)p) == 0x20202020) // ' ' == 0x20
+ p += 4;
+ // Skip over any remaining space on the line.
+ while (*p == ' ')
+ p++;
+ LendSkipFourSpaces:
+ continue; // skip white space
case '\t':
case '\v':
case '\f':
case '\r':
p++;
if (*p != '\n') // if CR stands by itself
- {
endOfLine();
- goto skipFourSpaces;
- }
continue; // skip white space
case '\n':
p++;
endOfLine();
- skipFourSpaces:
- while (*(cast(uint*)p) == 0x20202020) //' ' == 0x20
- {
- p+=4;
- }
continue; // skip white space
case '0':
if (!isZeroSecond(p[1])) // if numeric literal does not continue
}
else if (tp1.ty == Tdelegate)
{
- if (tp1.implicitConvTo(tp2))
+ if (tp2.implicitConvTo(tp1))
goto Lcov;
}
}
goto Nomatch;
}
- if (arg.op == TOK.string_ && tp.ty == Tsarray)
+ if (arg.op == EXP.string_ && tp.ty == Tsarray)
{
if (ta.ty != Tsarray)
{
ta = tn.sarrayOf(dim);
}
}
- else if (arg.op == TOK.slice && tp.ty == Tsarray)
+ else if (arg.op == EXP.slice && tp.ty == Tsarray)
{
// Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
if (ta.ty != Tsarray)
else if ((p.storageClass & STC.in_) && global.params.previewIn)
{
// Allow converting a literal to an `in` which is `ref`
- if (arg.op == TOK.arrayLiteral && tp.ty == Tsarray)
+ if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray)
{
Type tn = tp.nextOf();
dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
{
assert(to);
- if (this == to)
+ if (this.equals(to))
return MATCH.constant;
if (this.covariant(to) == Covariant.yes)
//printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", this, to);
//printf("from: %s\n", toChars());
//printf("to : %s\n", to.toChars());
- if (this == to)
+ if (this.equals(to))
return MATCH.exact;
if (auto toDg = to.isTypeDelegate())
}
else
e = vd.type.defaultInitLiteral(loc);
- if (e && e.op == TOK.error)
+ if (e && e.op == EXP.error)
return e;
if (e)
offset = vd.offset + cast(uint)vd.type.size();
override bool isZeroInit(const ref Loc loc)
{
- return sym.getDefaultValue(loc).isBool(false);
+ return sym.getDefaultValue(loc).toBool().hasValue(false);
}
override bool hasPointers()
override void visit(DeleteExp e)
{
- if (e.e1.op == TOK.variable)
+ if (e.e1.op == EXP.variable)
{
VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration();
if (v && v.onstack)
override void visit(AssignExp e)
{
- if (e.e1.op == TOK.arrayLength)
+ if (e.e1.op == EXP.arrayLength)
{
if (f.setGC())
{
Expression checkGC(Scope* sc, Expression e)
{
FuncDeclaration f = sc.func;
- if (e && e.op != TOK.error && f && sc.intypeof != 1 && !(sc.flags & SCOPE.ctfe) &&
+ if (e && e.op != EXP.error && f && sc.intypeof != 1 && !(sc.flags & SCOPE.ctfe) &&
(f.type.ty == Tfunction &&
(cast(TypeFunction)f.type).isnogc || (f.flags & FUNCFLAG.nogcInprocess) || global.params.vgc) &&
!(sc.flags & SCOPE.debug_))
override void visit(Expression e)
{
- //printf("[%s] %s: %s\n", e.loc.toChars(), Token.toChars(e.op), e.toChars());
+ //printf("[%s] %s: %s\n", e.loc.toChars(), EXPtoString(e.op).ptr, e.toChars());
//assert(0);
}
* allowed, but CTFE can generate one out of a new expression,
* but it'll be placed in static data so no need to check it.
*/
- if (e.e1.op != TOK.structLiteral)
+ if (e.e1.op != EXP.structLiteral)
e.e1.accept(this);
}
* allowed, but CTFE can generate one out of a new expression,
* but it'll be placed in static data so no need to check it.
*/
- if (e.e1.op != TOK.structLiteral)
+ if (e.e1.op != EXP.structLiteral)
e.e1.accept(this);
}
override void setSelector(FuncDeclaration fd, Scope* sc)
{
foreachUda(fd, sc, (e) {
- if (e.op != TOK.structLiteral)
+ if (!e.isStructLiteralExp())
return 0;
- auto literal = cast(StructLiteralExp) e;
+ auto literal = e.isStructLiteralExp();
assert(literal.sd);
if (!isCoreUda(literal.sd, Id.udaSelector))
int count;
foreachUda(fd, sc, (e) {
- if (e.op != TOK.type)
+ if (!e.isTypeExp())
return 0;
- auto typeExp = cast(TypeExp) e;
+ auto typeExp = e.isTypeExp();
if (typeExp.type.ty != Tenum)
return 0;
arrayExpressionSemantic(udas, sc, true);
return udas.each!((uda) {
- if (uda.op != TOK.tuple)
+ if (!uda.isTupleExp())
return 0;
- auto exps = (cast(TupleExp) uda).exps;
+ auto exps = uda.isTupleExp().exps;
return exps.each!((e) {
assert(e);
import dmd.expressionsem;
import dmd.func;
import dmd.globals;
+import dmd.hdrgen;
import dmd.id;
import dmd.identifier;
import dmd.mtype;
* Determine if operands of binary op can be reversed
* to fit operator overload.
*/
-bool isCommutative(TOK op)
+bool isCommutative(EXP op)
{
switch (op)
{
- case TOK.add:
- case TOK.mul:
- case TOK.and:
- case TOK.or:
- case TOK.xor:
+ case EXP.add:
+ case EXP.mul:
+ case EXP.and:
+ case EXP.or:
+ case EXP.xor:
// EqualExp
- case TOK.equal:
- case TOK.notEqual:
+ case EXP.equal:
+ case EXP.notEqual:
// CmpExp
- case TOK.lessThan:
- case TOK.lessOrEqual:
- case TOK.greaterThan:
- case TOK.greaterOrEqual:
+ case EXP.lessThan:
+ case EXP.lessOrEqual:
+ case EXP.greaterThan:
+ case EXP.greaterOrEqual:
return true;
default:
break;
{
switch (e.op)
{
- case TOK.uadd: return Id.uadd;
- case TOK.negate: return Id.neg;
- case TOK.tilde: return Id.com;
- case TOK.cast_: return Id._cast;
- case TOK.in_: return Id.opIn;
- case TOK.plusPlus: return Id.postinc;
- case TOK.minusMinus: return Id.postdec;
- case TOK.add: return Id.add;
- case TOK.min: return Id.sub;
- case TOK.mul: return Id.mul;
- case TOK.div: return Id.div;
- case TOK.mod: return Id.mod;
- case TOK.pow: return Id.pow;
- case TOK.leftShift: return Id.shl;
- case TOK.rightShift: return Id.shr;
- case TOK.unsignedRightShift: return Id.ushr;
- case TOK.and: return Id.iand;
- case TOK.or: return Id.ior;
- case TOK.xor: return Id.ixor;
- case TOK.concatenate: return Id.cat;
- case TOK.assign: return Id.assign;
- case TOK.addAssign: return Id.addass;
- case TOK.minAssign: return Id.subass;
- case TOK.mulAssign: return Id.mulass;
- case TOK.divAssign: return Id.divass;
- case TOK.modAssign: return Id.modass;
- case TOK.powAssign: return Id.powass;
- case TOK.leftShiftAssign: return Id.shlass;
- case TOK.rightShiftAssign: return Id.shrass;
- case TOK.unsignedRightShiftAssign: return Id.ushrass;
- case TOK.andAssign: return Id.andass;
- case TOK.orAssign: return Id.orass;
- case TOK.xorAssign: return Id.xorass;
- case TOK.concatenateAssign: return Id.catass;
- case TOK.equal: return Id.eq;
- case TOK.lessThan:
- case TOK.lessOrEqual:
- case TOK.greaterThan:
- case TOK.greaterOrEqual: return Id.cmp;
- case TOK.array: return Id.index;
- case TOK.star: return Id.opStar;
+ case EXP.uadd: return Id.uadd;
+ case EXP.negate: return Id.neg;
+ case EXP.tilde: return Id.com;
+ case EXP.cast_: return Id._cast;
+ case EXP.in_: return Id.opIn;
+ case EXP.plusPlus: return Id.postinc;
+ case EXP.minusMinus: return Id.postdec;
+ case EXP.add: return Id.add;
+ case EXP.min: return Id.sub;
+ case EXP.mul: return Id.mul;
+ case EXP.div: return Id.div;
+ case EXP.mod: return Id.mod;
+ case EXP.pow: return Id.pow;
+ case EXP.leftShift: return Id.shl;
+ case EXP.rightShift: return Id.shr;
+ case EXP.unsignedRightShift: return Id.ushr;
+ case EXP.and: return Id.iand;
+ case EXP.or: return Id.ior;
+ case EXP.xor: return Id.ixor;
+ case EXP.concatenate: return Id.cat;
+ case EXP.assign: return Id.assign;
+ case EXP.addAssign: return Id.addass;
+ case EXP.minAssign: return Id.subass;
+ case EXP.mulAssign: return Id.mulass;
+ case EXP.divAssign: return Id.divass;
+ case EXP.modAssign: return Id.modass;
+ case EXP.powAssign: return Id.powass;
+ case EXP.leftShiftAssign: return Id.shlass;
+ case EXP.rightShiftAssign: return Id.shrass;
+ case EXP.unsignedRightShiftAssign: return Id.ushrass;
+ case EXP.andAssign: return Id.andass;
+ case EXP.orAssign: return Id.orass;
+ case EXP.xorAssign: return Id.xorass;
+ case EXP.concatenateAssign: return Id.catass;
+ case EXP.equal: return Id.eq;
+ case EXP.lessThan:
+ case EXP.lessOrEqual:
+ case EXP.greaterThan:
+ case EXP.greaterOrEqual: return Id.cmp;
+ case EXP.array: return Id.index;
+ case EXP.star: return Id.opStar;
default: assert(0);
}
}
{
switch (e.op)
{
- case TOK.in_: return Id.opIn_r;
- case TOK.add: return Id.add_r;
- case TOK.min: return Id.sub_r;
- case TOK.mul: return Id.mul_r;
- case TOK.div: return Id.div_r;
- case TOK.mod: return Id.mod_r;
- case TOK.pow: return Id.pow_r;
- case TOK.leftShift: return Id.shl_r;
- case TOK.rightShift: return Id.shr_r;
- case TOK.unsignedRightShift:return Id.ushr_r;
- case TOK.and: return Id.iand_r;
- case TOK.or: return Id.ior_r;
- case TOK.xor: return Id.ixor_r;
- case TOK.concatenate: return Id.cat_r;
+ case EXP.in_: return Id.opIn_r;
+ case EXP.add: return Id.add_r;
+ case EXP.min: return Id.sub_r;
+ case EXP.mul: return Id.mul_r;
+ case EXP.div: return Id.div_r;
+ case EXP.mod: return Id.mod_r;
+ case EXP.pow: return Id.pow_r;
+ case EXP.leftShift: return Id.shl_r;
+ case EXP.rightShift: return Id.shr_r;
+ case EXP.unsignedRightShift:return Id.ushr_r;
+ case EXP.and: return Id.iand_r;
+ case EXP.or: return Id.ior_r;
+ case EXP.xor: return Id.ixor_r;
+ case EXP.concatenate: return Id.cat_r;
default: return null;
}
}
/*******************************************
* Helper function to turn operator into template argument list
*/
-Objects* opToArg(Scope* sc, TOK op)
+Objects* opToArg(Scope* sc, EXP op)
{
/* Remove the = from op=
*/
switch (op)
{
- case TOK.addAssign:
- op = TOK.add;
+ case EXP.addAssign:
+ op = EXP.add;
break;
- case TOK.minAssign:
- op = TOK.min;
+ case EXP.minAssign:
+ op = EXP.min;
break;
- case TOK.mulAssign:
- op = TOK.mul;
+ case EXP.mulAssign:
+ op = EXP.mul;
break;
- case TOK.divAssign:
- op = TOK.div;
+ case EXP.divAssign:
+ op = EXP.div;
break;
- case TOK.modAssign:
- op = TOK.mod;
+ case EXP.modAssign:
+ op = EXP.mod;
break;
- case TOK.andAssign:
- op = TOK.and;
+ case EXP.andAssign:
+ op = EXP.and;
break;
- case TOK.orAssign:
- op = TOK.or;
+ case EXP.orAssign:
+ op = EXP.or;
break;
- case TOK.xorAssign:
- op = TOK.xor;
+ case EXP.xorAssign:
+ op = EXP.xor;
break;
- case TOK.leftShiftAssign:
- op = TOK.leftShift;
+ case EXP.leftShiftAssign:
+ op = EXP.leftShift;
break;
- case TOK.rightShiftAssign:
- op = TOK.rightShift;
+ case EXP.rightShiftAssign:
+ op = EXP.rightShift;
break;
- case TOK.unsignedRightShiftAssign:
- op = TOK.unsignedRightShift;
+ case EXP.unsignedRightShiftAssign:
+ op = EXP.unsignedRightShift;
break;
- case TOK.concatenateAssign:
- op = TOK.concatenate;
+ case EXP.concatenateAssign:
+ op = EXP.concatenate;
break;
- case TOK.powAssign:
- op = TOK.pow;
+ case EXP.powAssign:
+ op = EXP.pow;
break;
default:
break;
}
- Expression e = new StringExp(Loc.initial, Token.toString(op));
+ Expression e = new StringExp(Loc.initial, EXPtoString(op));
e = e.expressionSemantic(sc);
auto tiargs = new Objects();
tiargs.push(e);
BinExp be = cast(BinExp)e.copy();
// Resolve 'alias this' but in case of assigment don't resolve properties yet
// because 'e1 = e2' could mean 'e1(e2)' or 'e1() = e2'
- bool findOnly = (e.op == TOK.assign);
+ bool findOnly = (e.op == EXP.assign);
be.e1 = resolveAliasThis(sc, e.e1, true, findOnly);
if (!be.e1)
return null;
Expression result;
- if (be.op == TOK.concatenateAssign)
+ if (be.op == EXP.concatenateAssign)
result = be.op_overload(sc);
else
result = be.trySemantic(sc);
return null;
Expression result;
- if (be.op == TOK.concatenateAssign)
+ if (be.op == EXP.concatenateAssign)
result = be.op_overload(sc);
else
result = be.trySemantic(sc);
* `null` if not an operator overload,
* otherwise the lowered expression
*/
-Expression op_overload(Expression e, Scope* sc, TOK* pop = null)
+Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
{
extern (C++) final class OpOverload : Visitor
{
alias visit = Visitor.visit;
public:
Scope* sc;
- TOK* pop;
+ EXP* pop;
Expression result;
- extern (D) this(Scope* sc, TOK* pop)
+ extern (D) this(Scope* sc, EXP* pop)
{
this.sc = sc;
this.pop = pop;
override void visit(UnaExp e)
{
//printf("UnaExp::op_overload() (%s)\n", e.toChars());
- if (e.e1.op == TOK.array)
+ if (e.e1.op == EXP.array)
{
ArrayExp ae = cast(ArrayExp)e.e1;
ae.e1 = ae.e1.expressionSemantic(sc);
ae.e1 = resolveProperties(sc, ae.e1);
Expression ae1old = ae.e1;
- const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval);
+ const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == EXP.interval);
IntervalExp ie = null;
if (maybeSlice && ae.arguments.dim)
{
- assert((*ae.arguments)[0].op == TOK.interval);
+ assert((*ae.arguments)[0].op == EXP.interval);
ie = cast(IntervalExp)(*ae.arguments)[0];
}
while (true)
{
- if (ae.e1.op == TOK.error)
+ if (ae.e1.op == EXP.error)
{
result = ae.e1;
return;
result = resolveOpDollar(sc, ae, &e0);
if (!result) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j)
goto Lfallback;
- if (result.op == TOK.error)
+ if (result.op == EXP.error)
return;
/* Rewrite op(a[arguments]) as:
* a.opIndexUnary!(op)(arguments)
{
// Deal with $
result = resolveOpDollar(sc, ae, ie, &e0);
- if (result.op == TOK.error)
+ if (result.op == EXP.error)
return;
/* Rewrite op(a[i..j]) as:
* a.opSliceUnary!(op)(i, j)
}
e.e1 = e.e1.expressionSemantic(sc);
e.e1 = resolveProperties(sc, e.e1);
- if (e.e1.op == TOK.error)
+ if (e.e1.op == EXP.error)
{
result = e.e1;
return;
return;
}
// D1-style operator overloads, deprecated
- if (e.op != TOK.prePlusPlus && e.op != TOK.preMinusMinus)
+ if (e.op != EXP.prePlusPlus && e.op != EXP.preMinusMinus)
{
auto id = opId(e);
fd = search_function(ad, id);
// @@@DEPRECATED_2.098@@@.
// Deprecated in 2.088
// Make an error in 2.098
- e.deprecation("`%s` is deprecated. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), Token.toChars(e.op));
+ e.deprecation("`%s` is deprecated. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
// Rewrite +e1 as e1.add()
result = build_overload(e.loc, sc, e.e1, null, fd);
return;
/* Rewrite op(e1) as:
* op(e1.aliasthis)
*/
- //printf("att una %s e1 = %s\n", Token::toChars(op), this.e1.type.toChars());
+ //printf("att una %s e1 = %s\n", EXPtoString(op).ptr, this.e1.type.toChars());
Expression e1 = new DotIdExp(e.loc, e.e1, ad.aliasthis.ident);
UnaExp ue = cast(UnaExp)e.copy();
ue.e1 = e1;
ae.e1 = ae.e1.expressionSemantic(sc);
ae.e1 = resolveProperties(sc, ae.e1);
Expression ae1old = ae.e1;
- const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval);
+ const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == EXP.interval);
IntervalExp ie = null;
if (maybeSlice && ae.arguments.dim)
{
- assert((*ae.arguments)[0].op == TOK.interval);
+ assert((*ae.arguments)[0].op == EXP.interval);
ie = cast(IntervalExp)(*ae.arguments)[0];
}
while (true)
{
- if (ae.e1.op == TOK.error)
+ if (ae.e1.op == EXP.error)
{
result = ae.e1;
return;
{
// If the non-aggregate expression ae.e1 is indexable or sliceable,
// convert it to the corresponding concrete expression.
- if (isIndexableNonAggregate(t1b) || ae.e1.op == TOK.type)
+ if (isIndexableNonAggregate(t1b) || ae.e1.op == EXP.type)
{
// Convert to SliceExp
if (maybeSlice)
result = resolveOpDollar(sc, ae, &e0);
if (!result) // a[i..j] might be: a.opSlice(i, j)
goto Lfallback;
- if (result.op == TOK.error)
+ if (result.op == EXP.error)
return;
/* Rewrite e1[arguments] as:
* e1.opIndex(arguments)
}
}
Lfallback:
- if (maybeSlice && ae.e1.op == TOK.type)
+ if (maybeSlice && ae.e1.op == EXP.type)
{
result = new SliceExp(ae.loc, ae.e1, ie);
result = result.expressionSemantic(sc);
{
// Deal with $
result = resolveOpDollar(sc, ae, ie, &e0);
- if (result.op == TOK.error)
+ if (result.op == EXP.error)
return;
/* Rewrite a[i..j] as:
* a.opSlice(i, j)
int argsset = 0;
AggregateDeclaration ad1 = isAggregate(e.e1.type);
AggregateDeclaration ad2 = isAggregate(e.e2.type);
- if (e.op == TOK.assign && ad1 == ad2)
+ if (e.op == EXP.assign && ad1 == ad2)
{
StructDeclaration sd = ad1.isStructDeclaration();
if (sd &&
Dsymbol s = null;
Dsymbol s_r = null;
Objects* tiargs = null;
- if (e.op == TOK.plusPlus || e.op == TOK.minusMinus)
+ if (e.op == EXP.plusPlus || e.op == EXP.minusMinus)
{
// Bug4099 fix
if (ad1 && search_function(ad1, Id.opUnary))
return;
}
- if (e.op != TOK.equal && e.op != TOK.notEqual && e.op != TOK.assign && e.op != TOK.plusPlus && e.op != TOK.minusMinus)
+ if (e.op != EXP.equal && e.op != EXP.notEqual && e.op != EXP.assign && e.op != EXP.plusPlus && e.op != EXP.minusMinus)
{
/* Try opBinary and opBinaryRight
*/
// Deprecated in 2.088
// Make an error in 2.098
if (id == Id.postinc || id == Id.postdec)
- e.deprecation("`%s` is deprecated. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), Token.toChars(e.op));
+ e.deprecation("`%s` is deprecated. Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
else
- e.deprecation("`%s` is deprecated. Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), Token.toChars(e.op));
+ e.deprecation("`%s` is deprecated. Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
}
}
if (ad2 && id_r)
// @@@DEPRECATED_2.098@@@.
// Deprecated in 2.088
// Make an error in 2.098
- e.deprecation("`%s` is deprecated. Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), Token.toChars(e.op));
+ e.deprecation("`%s` is deprecated. Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), EXPtoString(e.op).ptr);
}
}
}
goto L1;
m.lastf = null;
}
- if (e.op == TOK.plusPlus || e.op == TOK.minusMinus)
+ if (e.op == EXP.plusPlus || e.op == EXP.minusMinus)
{
// Kludge because operator overloading regards e++ and e--
// as unary, but it's implemented as a binary.
}
Expression tempResult;
- if (!(e.op == TOK.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
+ if (!(e.op == EXP.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
{
result = checkAliasThisForLhs(ad1, sc, e);
if (result)
* one of the members, hence the `ad1.fields.dim == 2 && ad1.vthis`
* condition.
*/
- if (e.op != TOK.assign || e.e1.op == TOK.type)
+ if (e.op != EXP.assign || e.e1.op == EXP.type)
return;
if (ad1.fields.dim == 1 || (ad1.fields.dim == 2 && ad1.vthis))
tempResult = result;
}
}
- if (!(e.op == TOK.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
+ if (!(e.op == EXP.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
{
result = checkAliasThisForRhs(ad2, sc, e);
if (result)
/* Check for class equality with null literal or typeof(null).
*/
- if (t1.ty == Tclass && e.e2.op == TOK.null_ ||
- t2.ty == Tclass && e.e1.op == TOK.null_)
+ if (t1.ty == Tclass && e.e2.op == EXP.null_ ||
+ t2.ty == Tclass && e.e1.op == EXP.null_)
{
e.error("use `%s` instead of `%s` when comparing with `null`",
- Token.toChars(e.op == TOK.equal ? TOK.identity : TOK.notIdentity),
- Token.toChars(e.op));
+ EXPtoString(e.op == EXP.equal ? EXP.identity : EXP.notIdentity).ptr,
+ EXPtoString(e.op).ptr);
result = ErrorExp.get();
return;
}
result = new DotIdExp(e.loc, result, Id.object);
result = new DotIdExp(e.loc, result, Id.eq);
result = new CallExp(e.loc, result, e1x, e2x);
- if (e.op == TOK.notEqual)
+ if (e.op == EXP.notEqual)
result = new NotExp(e.loc, result);
result = result.expressionSemantic(sc);
return;
result = compare_overload(e, sc, Id.eq, null);
if (result)
{
- if (lastComma(result).op == TOK.call && e.op == TOK.notEqual)
+ if (lastComma(result).op == EXP.call && e.op == EXP.notEqual)
{
result = new NotExp(result.loc, result);
result = result.expressionSemantic(sc);
* This is just a rewriting for deterministic AST representation
* as the backend input.
*/
- auto op2 = e.op == TOK.equal ? TOK.identity : TOK.notIdentity;
+ auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity;
result = new IdentityExp(op2, e.loc, e.e1, e.e2);
result = result.expressionSemantic(sc);
return;
if (!global.params.fieldwise && !needOpEquals(sd))
{
// Use bitwise equality.
- auto op2 = e.op == TOK.equal ? TOK.identity : TOK.notIdentity;
+ auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity;
result = new IdentityExp(op2, e.loc, e.e1, e.e2);
result = result.expressionSemantic(sc);
return;
/* Check for tuple equality.
*/
- if (e.e1.op == TOK.tuple && e.e2.op == TOK.tuple)
+ if (e.e1.op == EXP.tuple && e.e2.op == EXP.tuple)
{
auto tup1 = cast(TupleExp)e.e1;
auto tup2 = cast(TupleExp)e.e2;
if (dim == 0)
{
// zero-length tuple comparison should always return true or false.
- result = IntegerExp.createBool(e.op == TOK.equal);
+ result = IntegerExp.createBool(e.op == EXP.equal);
}
else
{
if (!result)
result = eeq;
- else if (e.op == TOK.equal)
- result = new LogicalExp(e.loc, TOK.andAnd, result, eeq);
+ else if (e.op == EXP.equal)
+ result = new LogicalExp(e.loc, EXP.andAnd, result, eeq);
else
- result = new LogicalExp(e.loc, TOK.orOr, result, eeq);
+ result = new LogicalExp(e.loc, EXP.orOr, result, eeq);
}
assert(result);
}
override void visit(BinAssignExp e)
{
//printf("BinAssignExp::op_overload() (%s)\n", e.toChars());
- if (e.e1.op == TOK.array)
+ if (e.e1.op == EXP.array)
{
ArrayExp ae = cast(ArrayExp)e.e1;
ae.e1 = ae.e1.expressionSemantic(sc);
ae.e1 = resolveProperties(sc, ae.e1);
Expression ae1old = ae.e1;
- const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == TOK.interval);
+ const(bool) maybeSlice = (ae.arguments.dim == 0 || ae.arguments.dim == 1 && (*ae.arguments)[0].op == EXP.interval);
IntervalExp ie = null;
if (maybeSlice && ae.arguments.dim)
{
- assert((*ae.arguments)[0].op == TOK.interval);
+ assert((*ae.arguments)[0].op == EXP.interval);
ie = cast(IntervalExp)(*ae.arguments)[0];
}
while (true)
{
- if (ae.e1.op == TOK.error)
+ if (ae.e1.op == EXP.error)
{
result = ae.e1;
return;
result = resolveOpDollar(sc, ae, &e0);
if (!result) // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j)
goto Lfallback;
- if (result.op == TOK.error)
+ if (result.op == EXP.error)
return;
result = e.e2.expressionSemantic(sc);
- if (result.op == TOK.error)
+ if (result.op == EXP.error)
return;
e.e2 = result;
/* Rewrite a[arguments] op= e2 as:
{
// Deal with $
result = resolveOpDollar(sc, ae, ie, &e0);
- if (result.op == TOK.error)
+ if (result.op == EXP.error)
return;
result = e.e2.expressionSemantic(sc);
- if (result.op == TOK.error)
+ if (result.op == EXP.error)
return;
e.e2 = result;
/* Rewrite (a[i..j] op= e2) as:
// @@@DEPRECATED_2.098@@@.
// Deprecated in 2.088
// Make an error in 2.098
- scope char[] op = Token.toString(e.op).dup;
+ scope char[] op = EXPtoString(e.op).dup;
op[$-1] = '\0'; // remove trailing `=`
e.deprecation("`%s` is deprecated. Use `opOpAssign(string op)(...) if (op == \"%s\")` instead.", id.toChars(), op.ptr);
}
/******************************************
* Common code for overloading of EqualExp and CmpExp
*/
-private Expression compare_overload(BinExp e, Scope* sc, Identifier id, TOK* pop)
+private Expression compare_overload(BinExp e, Scope* sc, Identifier id, EXP* pop)
{
//printf("BinExp::compare_overload(id = %s) %s\n", id.toChars(), e.toChars());
AggregateDeclaration ad1 = isAggregate(e.e1.type);
* at this point, no matching opEquals was found for structs,
* so we should not follow the alias this comparison code.
*/
- if ((e.op == TOK.equal || e.op == TOK.notEqual) && ad1 == ad2)
+ if ((e.op == EXP.equal || e.op == EXP.notEqual) && ad1 == ad2)
return null;
Expression result = checkAliasThisForLhs(ad1, sc, e);
return result ? result : checkAliasThisForRhs(isAggregate(e.e2.type), sc, e);
aggr = aggr.expressionSemantic(sc);
aggr = resolveProperties(sc, aggr);
aggr = aggr.optimize(WANTvalue);
- if (!aggr.type || aggr.op == TOK.error)
+ if (!aggr.type || aggr.op == EXP.error)
return false;
Type tab = aggr.type.toBasetype();
switch (tab.ty)
// opApply aggregate
break;
}
- if (feaggr.op != TOK.type)
+ if (feaggr.op != EXP.type)
{
/* See if rewriting `aggr` to `aggr[]` will work
*/
}
case Tdelegate: // https://dlang.org/spec/statement.html#foreach_over_delegates
- if (aggr.op == TOK.delegate_)
+ if (aggr.op == EXP.delegate_)
{
sapply = (cast(DelegateExp)aggr).func;
}
ethis = fes.aggr;
else
{
- assert(tab.ty == Tdelegate && fes.aggr.op == TOK.delegate_);
+ assert(tab.ty == Tdelegate && fes.aggr.op == EXP.delegate_);
ethis = (cast(DelegateExp)fes.aggr).e1;
}
* Returns:
* reverse of op
*/
-private TOK reverseRelation(TOK op) pure
+private EXP reverseRelation(EXP op) pure
{
switch (op)
{
- case TOK.greaterOrEqual: op = TOK.lessOrEqual; break;
- case TOK.greaterThan: op = TOK.lessThan; break;
- case TOK.lessOrEqual: op = TOK.greaterOrEqual; break;
- case TOK.lessThan: op = TOK.greaterThan; break;
+ case EXP.greaterOrEqual: op = EXP.lessOrEqual; break;
+ case EXP.greaterThan: op = EXP.lessThan; break;
+ case EXP.lessOrEqual: op = EXP.greaterOrEqual; break;
+ case EXP.lessThan: op = EXP.greaterThan; break;
default: break;
}
return op;
}
return nullReturn();
}
- if (ei.op == TOK.construct || ei.op == TOK.blit)
+ if (ei.op == EXP.construct || ei.op == EXP.blit)
{
AssignExp ae = cast(AssignExp)ei;
ei = ae.e2;
if (ei.isConst() == 1)
{
}
- else if (ei.op == TOK.string_)
+ else if (ei.op == EXP.string_)
{
// https://issues.dlang.org/show_bug.cgi?id=14459
// Do not constfold the string literal
}
else if (!(v.storage_class & STC.manifest) &&
ei.isConst() != 1 &&
- ei.op != TOK.string_ &&
- ei.op != TOK.address)
+ ei.op != EXP.string_ &&
+ ei.op != EXP.address)
{
return nullReturn();
}
//printf("fromConstInitializer(result = %x, %s)\n", result, e1.toChars());
//static int xx; if (xx++ == 10) assert(0);
Expression e = e1;
- if (e1.op == TOK.variable)
+ if (auto ve = e1.isVarExp())
{
- VarExp ve = cast(VarExp)e1;
VarDeclaration v = ve.var.isVarDeclaration();
e = expandVar(result, v);
if (e)
// If it is a comma expression involving a declaration, we mustn't
// perform a copy -- we'd get two declarations of the same variable.
// See bugzilla 4465.
- if (e.op == TOK.comma && (cast(CommaExp)e).e1.op == TOK.declaration)
+ if (e.op == EXP.comma && e.isCommaExp().e1.isDeclarationExp())
e = e1;
else if (e.type != e1.type && e1.type && e1.type.ty != Tident)
{
return e;
}
-/* It is possible for constant folding to change an array expression of
+/***
+ * It is possible for constant folding to change an array expression of
* unknown length, into one where the length is known.
* If the expression 'arr' is a literal, set lengthVar to be its length.
+ * Params:
+ * lengthVar = variable declaration for the `.length` property
+ * arr = String, ArrayLiteral, or of TypeSArray
*/
package void setLengthVarIfKnown(VarDeclaration lengthVar, Expression arr)
{
return;
if (lengthVar._init && !lengthVar._init.isVoidInitializer())
return; // we have previously calculated the length
- size_t len;
- if (arr.op == TOK.string_)
- len = (cast(StringExp)arr).len;
- else if (arr.op == TOK.arrayLiteral)
- len = (cast(ArrayLiteralExp)arr).elements.dim;
+ d_uns64 len;
+ if (auto se = arr.isStringExp())
+ len = se.len;
+ else if (auto ale = arr.isArrayLiteralExp())
+ len = ale.elements.dim;
else
{
- Type t = arr.type.toBasetype();
- if (t.ty == Tsarray)
- len = cast(size_t)(cast(TypeSArray)t).dim.toInteger();
- else
+ auto tsa = arr.type.toBasetype().isTypeSArray();
+ if (!tsa)
return; // we don't know the length yet
+ len = tsa.dim.toInteger();
}
Expression dollar = new IntegerExp(Loc.initial, len, Type.tsize_t);
lengthVar._init = new ExpInitializer(Loc.initial, dollar);
lengthVar.storage_class |= STC.static_ | STC.const_;
}
-/* Same as above, but determines the length from 'type'. */
+/***
+ * Same as above, but determines the length from 'type'.
+ * Params:
+ * lengthVar = variable declaration for the `.length` property
+ * type = TypeSArray
+ */
package void setLengthVarIfKnown(VarDeclaration lengthVar, Type type)
{
if (!lengthVar)
return;
if (lengthVar._init && !lengthVar._init.isVoidInitializer())
return; // we have previously calculated the length
- size_t len;
- Type t = type.toBasetype();
- if (t.ty == Tsarray)
- len = cast(size_t)(cast(TypeSArray)t).dim.toInteger();
- else
+ auto tsa = type.toBasetype().isTypeSArray();
+ if (!tsa)
return; // we don't know the length yet
+ d_uns64 len = tsa.dim.toInteger();
Expression dollar = new IntegerExp(Loc.initial, len, Type.tsize_t);
lengthVar._init = new ExpInitializer(Loc.initial, dollar);
lengthVar.storage_class |= STC.static_ | STC.const_;
*/
Expression Expression_optimize(Expression e, int result, bool keepLvalue)
{
- extern (C++) final class OptimizeVisitor : Visitor
- {
- alias visit = Visitor.visit;
-
- Expression ret;
- private const int result;
- private const bool keepLvalue;
+ Expression ret = e;
- extern (D) this(Expression e, int result, bool keepLvalue)
- {
- this.ret = e; // default result is original expression
- this.result = result;
- this.keepLvalue = keepLvalue;
- }
+ void error()
+ {
+ ret = ErrorExp.get();
+ }
- void error()
+ /* Returns: true if error
+ */
+ bool expOptimize(ref Expression e, int flags, bool keepLvalue = false)
+ {
+ if (!e)
+ return false;
+ Expression ex = Expression_optimize(e, flags, keepLvalue);
+ if (ex.op == EXP.error)
{
- ret = ErrorExp.get();
+ ret = ex; // store error result
+ return true;
}
-
- bool expOptimize(ref Expression e, int flags, bool keepLvalue = false)
+ else
{
- if (!e)
- return false;
- Expression ex = Expression_optimize(e, flags, keepLvalue);
- if (ex.op == TOK.error)
- {
- ret = ex; // store error result
- return true;
- }
- else
- {
- e = ex; // modify original
- return false;
- }
+ e = ex; // modify original
+ return false;
}
+ }
- bool unaOptimize(UnaExp e, int flags)
- {
- return expOptimize(e.e1, flags);
- }
+ bool unaOptimize(UnaExp e, int flags)
+ {
+ return expOptimize(e.e1, flags);
+ }
- bool binOptimize(BinExp e, int flags, bool keepLhsLvalue = false)
- {
- expOptimize(e.e1, flags, keepLhsLvalue);
- expOptimize(e.e2, flags);
- return ret.op == TOK.error;
- }
+ bool binOptimize(BinExp e, int flags, bool keepLhsLvalue = false)
+ {
+ return expOptimize(e.e1, flags, keepLhsLvalue) |
+ expOptimize(e.e2, flags);
+ }
- override void visit(Expression e)
- {
- //printf("Expression::optimize(result = x%x) %s\n", result, e.toChars());
- }
+ void visitExp(Expression e)
+ {
+ //printf("Expression::optimize(result = x%x) %s\n", result, e.toChars());
+ }
- override void visit(VarExp e)
- {
- VarDeclaration v = e.var.isVarDeclaration();
+ void visitVar(VarExp e)
+ {
+ VarDeclaration v = e.var.isVarDeclaration();
- if (!(keepLvalue && v && !(v.storage_class & STC.manifest)))
- ret = fromConstInitializer(result, e);
+ if (!(keepLvalue && v && !(v.storage_class & STC.manifest)))
+ ret = fromConstInitializer(result, e);
- // if unoptimized, try to optimize the dtor expression
- // (e.g., might be a LogicalExp with constant lhs)
- if (ret == e && v && v.edtor)
+ // if unoptimized, try to optimize the dtor expression
+ // (e.g., might be a LogicalExp with constant lhs)
+ if (ret == e && v && v.edtor)
+ {
+ // prevent infinite recursion (`<var>.~this()`)
+ if (!v.inuse)
{
- // prevent infinite recursion (`<var>.~this()`)
- if (!v.inuse)
- {
- v.inuse++;
- expOptimize(v.edtor, WANTvalue);
- v.inuse--;
- }
+ v.inuse++;
+ expOptimize(v.edtor, WANTvalue);
+ v.inuse--;
}
}
+ }
- override void visit(TupleExp e)
+ void visitTuple(TupleExp e)
+ {
+ expOptimize(e.e0, WANTvalue);
+ for (size_t i = 0; i < e.exps.dim; i++)
{
- expOptimize(e.e0, WANTvalue);
- for (size_t i = 0; i < e.exps.dim; i++)
- {
- expOptimize((*e.exps)[i], WANTvalue);
- }
+ expOptimize((*e.exps)[i], WANTvalue);
}
+ }
- override void visit(ArrayLiteralExp e)
+ void visitArrayLiteral(ArrayLiteralExp e)
+ {
+ if (e.elements)
{
- if (e.elements)
+ expOptimize(e.basis, result & WANTexpand);
+ for (size_t i = 0; i < e.elements.dim; i++)
{
- expOptimize(e.basis, result & WANTexpand);
- for (size_t i = 0; i < e.elements.dim; i++)
- {
- expOptimize((*e.elements)[i], result & WANTexpand);
- }
+ expOptimize((*e.elements)[i], result & WANTexpand);
}
}
+ }
- override void visit(AssocArrayLiteralExp e)
+ void visitAssocArrayLiteral(AssocArrayLiteralExp e)
+ {
+ assert(e.keys.dim == e.values.dim);
+ for (size_t i = 0; i < e.keys.dim; i++)
{
- assert(e.keys.dim == e.values.dim);
- for (size_t i = 0; i < e.keys.dim; i++)
- {
- expOptimize((*e.keys)[i], result & WANTexpand);
- expOptimize((*e.values)[i], result & WANTexpand);
- }
+ expOptimize((*e.keys)[i], result & WANTexpand);
+ expOptimize((*e.values)[i], result & WANTexpand);
}
+ }
- override void visit(StructLiteralExp e)
+ void visitStructLiteral(StructLiteralExp e)
+ {
+ if (e.stageflags & stageOptimize)
+ return;
+ int old = e.stageflags;
+ e.stageflags |= stageOptimize;
+ if (e.elements)
{
- if (e.stageflags & stageOptimize)
- return;
- int old = e.stageflags;
- e.stageflags |= stageOptimize;
- if (e.elements)
+ for (size_t i = 0; i < e.elements.dim; i++)
{
- for (size_t i = 0; i < e.elements.dim; i++)
- {
- expOptimize((*e.elements)[i], result & WANTexpand);
- }
+ expOptimize((*e.elements)[i], result & WANTexpand);
}
- e.stageflags = old;
}
+ e.stageflags = old;
+ }
- override void visit(UnaExp e)
- {
- //printf("UnaExp::optimize() %s\n", e.toChars());
- if (unaOptimize(e, result))
- return;
- }
+ void visitUna(UnaExp e)
+ {
+ //printf("UnaExp::optimize() %s\n", e.toChars());
+ if (unaOptimize(e, result))
+ return;
+ }
- override void visit(NegExp e)
+ void visitNeg(NegExp e)
+ {
+ if (unaOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1)
{
- if (unaOptimize(e, result))
- return;
- if (e.e1.isConst() == 1)
- {
- ret = Neg(e.type, e.e1).copy();
- }
+ ret = Neg(e.type, e.e1).copy();
}
+ }
- override void visit(ComExp e)
+ void visitCom(ComExp e)
+ {
+ if (unaOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1)
{
- if (unaOptimize(e, result))
- return;
- if (e.e1.isConst() == 1)
- {
- ret = Com(e.type, e.e1).copy();
- }
+ ret = Com(e.type, e.e1).copy();
}
+ }
- override void visit(NotExp e)
+ void visitNop(NotExp e)
+ {
+ if (unaOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1)
{
- if (unaOptimize(e, result))
- return;
- if (e.e1.isConst() == 1)
- {
- ret = Not(e.type, e.e1).copy();
- }
+ ret = Not(e.type, e.e1).copy();
}
+ }
- override void visit(SymOffExp e)
+ void visitSymOff(SymOffExp e)
+ {
+ assert(e.var);
+ }
+
+ void visitAddr(AddrExp e)
+ {
+ //printf("AddrExp::optimize(result = %d) %s\n", result, e.toChars());
+ /* Rewrite &(a,b) as (a,&b)
+ */
+ if (auto ce = e.e1.isCommaExp())
{
- assert(e.var);
+ auto ae = new AddrExp(e.loc, ce.e2, e.type);
+ ret = new CommaExp(ce.loc, ce.e1, ae);
+ ret.type = e.type;
+ return;
}
-
- override void visit(AddrExp e)
+ // Keep lvalue-ness
+ if (expOptimize(e.e1, result, true))
+ return;
+ // Convert &*ex to ex
+ if (auto pe = e.e1.isPtrExp())
{
- //printf("AddrExp::optimize(result = %d) %s\n", result, e.toChars());
- /* Rewrite &(a,b) as (a,&b)
- */
- if (e.e1.op == TOK.comma)
+ Expression ex = pe.e1;
+ if (e.type.equals(ex.type))
+ ret = ex;
+ else if (e.type.toBasetype().equivalent(ex.type.toBasetype()))
{
- CommaExp ce = cast(CommaExp)e.e1;
- auto ae = new AddrExp(e.loc, ce.e2, e.type);
- ret = new CommaExp(ce.loc, ce.e1, ae);
+ ret = ex.copy();
ret.type = e.type;
- return;
- }
- // Keep lvalue-ness
- if (expOptimize(e.e1, result, true))
- return;
- // Convert &*ex to ex
- if (e.e1.op == TOK.star)
- {
- Expression ex = (cast(PtrExp)e.e1).e1;
- if (e.type.equals(ex.type))
- ret = ex;
- else if (e.type.toBasetype().equivalent(ex.type.toBasetype()))
- {
- ret = ex.copy();
- ret.type = e.type;
- }
- return;
- }
- if (e.e1.op == TOK.variable)
- {
- VarExp ve = cast(VarExp)e.e1;
- if (!ve.var.isReference() && !ve.var.isImportedSymbol())
- {
- ret = new SymOffExp(e.loc, ve.var, 0, ve.hasOverloads);
- ret.type = e.type;
- return;
- }
- }
- if (e.e1.op == TOK.index)
- {
- // Convert &array[n] to &array+n
- IndexExp ae = cast(IndexExp)e.e1;
- if (ae.e2.op == TOK.int64 && ae.e1.op == TOK.variable)
- {
- sinteger_t index = ae.e2.toInteger();
- VarExp ve = cast(VarExp)ae.e1;
- if (ve.type.ty == Tsarray && !ve.var.isImportedSymbol())
- {
- TypeSArray ts = cast(TypeSArray)ve.type;
- 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();
- }
-
- import core.checkedint : mulu;
- bool overflow;
- const offset = mulu(index, ts.nextOf().size(e.loc), overflow);
- if (overflow)
- {
- e.error("array offset overflow");
- return error();
- }
-
- ret = new SymOffExp(e.loc, ve.var, offset);
- ret.type = e.type;
- return;
- }
- }
}
+ return;
}
-
- override void visit(PtrExp e)
+ if (auto ve = e.e1.isVarExp())
{
- //printf("PtrExp::optimize(result = x%x) %s\n", result, e.toChars());
- if (expOptimize(e.e1, result))
- return;
- // Convert *&ex to ex
- // But only if there is no type punning involved
- if (e.e1.op == TOK.address)
+ if (!ve.var.isReference() && !ve.var.isImportedSymbol())
{
- Expression ex = (cast(AddrExp)e.e1).e1;
- if (e.type.equals(ex.type))
- ret = ex;
- else if (e.type.toBasetype().equivalent(ex.type.toBasetype()))
- {
- ret = ex.copy();
- ret.type = e.type;
- }
- }
- if (keepLvalue)
+ ret = new SymOffExp(e.loc, ve.var, 0, ve.hasOverloads);
+ ret.type = e.type;
return;
- // Constant fold *(&structliteral + offset)
- if (e.e1.op == TOK.add)
- {
- Expression ex = Ptr(e.type, e.e1).copy();
- if (!CTFEExp.isCantExp(ex))
- {
- ret = ex;
- return;
- }
}
- if (e.e1.op == TOK.symbolOffset)
+ }
+ if (auto ae = e.e1.isIndexExp())
+ {
+ // Convert &array[n] to &array+n
+ if (ae.e2.op == EXP.int64 && ae.e1.isVarExp())
{
- SymOffExp se = cast(SymOffExp)e.e1;
- VarDeclaration v = se.var.isVarDeclaration();
- Expression ex = expandVar(result, v);
- if (ex && ex.op == TOK.structLiteral)
+ sinteger_t index = ae.e2.toInteger();
+ VarExp ve = ae.e1.isVarExp();
+ if (ve.type.isTypeSArray() && !ve.var.isImportedSymbol())
{
- StructLiteralExp sle = cast(StructLiteralExp)ex;
- ex = sle.getField(e.type, cast(uint)se.offset);
- if (ex && !CTFEExp.isCantExp(ex))
+ TypeSArray ts = ve.type.isTypeSArray();
+ sinteger_t dim = ts.dim.toInteger();
+ if (index < 0 || index >= dim)
{
- ret = ex;
- return;
+ e.error("array index %lld is out of bounds `[0..%lld]`", index, dim);
+ return error();
}
- }
- }
- }
- override void visit(DotVarExp e)
- {
- //printf("DotVarExp::optimize(result = x%x) %s\n", result, e.toChars());
- if (expOptimize(e.e1, result))
- return;
- if (keepLvalue)
- return;
- Expression ex = e.e1;
- if (ex.op == TOK.variable)
- {
- VarExp ve = cast(VarExp)ex;
- VarDeclaration v = ve.var.isVarDeclaration();
- ex = expandVar(result, v);
- }
- if (ex && ex.op == TOK.structLiteral)
- {
- StructLiteralExp sle = cast(StructLiteralExp)ex;
- VarDeclaration vf = e.var.isVarDeclaration();
- if (vf && !vf.overlapped)
- {
- /* https://issues.dlang.org/show_bug.cgi?id=13021
- * Prevent optimization if vf has overlapped fields.
- */
- ex = sle.getField(e.type, vf.offset);
- if (ex && !CTFEExp.isCantExp(ex))
+ import core.checkedint : mulu;
+ bool overflow;
+ const offset = mulu(index, ts.nextOf().size(e.loc), overflow);
+ if (overflow)
{
- ret = ex;
- return;
+ e.error("array offset overflow");
+ return error();
}
+
+ ret = new SymOffExp(e.loc, ve.var, offset);
+ ret.type = e.type;
+ return;
}
}
}
+ }
- override void visit(NewExp e)
+ void visitPtr(PtrExp e)
+ {
+ //printf("PtrExp::optimize(result = x%x) %s\n", result, e.toChars());
+ if (expOptimize(e.e1, result))
+ return;
+ // Convert *&ex to ex
+ // But only if there is no type punning involved
+ if (auto ey = e.e1.isAddrExp())
{
- expOptimize(e.thisexp, WANTvalue);
- // Optimize parameters
- if (e.newargs)
+ Expression ex = ey.e1;
+ if (e.type.equals(ex.type))
+ ret = ex;
+ else if (e.type.toBasetype().equivalent(ex.type.toBasetype()))
{
- for (size_t i = 0; i < e.newargs.dim; i++)
- {
- expOptimize((*e.newargs)[i], WANTvalue);
- }
+ ret = ex.copy();
+ ret.type = e.type;
}
- if (e.arguments)
+ }
+ if (keepLvalue)
+ return;
+ // Constant fold *(&structliteral + offset)
+ if (e.e1.op == EXP.add)
+ {
+ Expression ex = Ptr(e.type, e.e1).copy();
+ if (!CTFEExp.isCantExp(ex))
{
- for (size_t i = 0; i < e.arguments.dim; i++)
- {
- expOptimize((*e.arguments)[i], WANTvalue);
- }
+ ret = ex;
+ return;
}
}
-
- override void visit(CallExp e)
+ if (auto se = e.e1.isSymOffExp())
{
- //printf("CallExp::optimize(result = %d) %s\n", result, e.toChars());
- // Optimize parameters with keeping lvalue-ness
- if (expOptimize(e.e1, result))
- return;
- if (e.arguments)
+ VarDeclaration v = se.var.isVarDeclaration();
+ Expression ex = expandVar(result, v);
+ if (ex && ex.isStructLiteralExp())
{
- Type t1 = e.e1.type.toBasetype();
- if (t1.ty == Tdelegate)
- t1 = t1.nextOf();
- // t1 can apparently be void for __ArrayDtor(T) calls
- if (auto tf = t1.isTypeFunction())
+ StructLiteralExp sle = ex.isStructLiteralExp();
+ ex = sle.getField(e.type, cast(uint)se.offset);
+ if (ex && !CTFEExp.isCantExp(ex))
{
- for (size_t i = 0; i < e.arguments.dim; i++)
- {
- Parameter p = tf.parameterList[i];
- bool keep = p && p.isReference();
- expOptimize((*e.arguments)[i], WANTvalue, keep);
- }
+ ret = ex;
+ return;
}
}
}
+ }
- override void visit(CastExp e)
+ void visitDotVar(DotVarExp e)
+ {
+ //printf("DotVarExp::optimize(result = x%x) %s\n", result, e.toChars());
+ if (expOptimize(e.e1, result))
+ return;
+ if (keepLvalue)
+ return;
+ Expression ex = e.e1;
+ if (auto ve = ex.isVarExp())
{
- //printf("CastExp::optimize(result = %d) %s\n", result, e.toChars());
- //printf("from %s to %s\n", e.type.toChars(), e.to.toChars());
- //printf("from %s\n", e.type.toChars());
- //printf("e1.type %s\n", e.e1.type.toChars());
- //printf("type = %p\n", e.type);
- assert(e.type);
- TOK op1 = e.e1.op;
- Expression e1old = e.e1;
- if (expOptimize(e.e1, result, keepLvalue))
- return;
- if (!keepLvalue)
- e.e1 = fromConstInitializer(result, e.e1);
- if (e.e1 == e1old && e.e1.op == TOK.arrayLiteral && e.type.toBasetype().ty == Tpointer && e.e1.type.toBasetype().ty != Tsarray)
- {
- // Casting this will result in the same expression, and
- // infinite loop because of Expression::implicitCastTo()
- return; // no change
- }
- if ((e.e1.op == TOK.string_ || e.e1.op == TOK.arrayLiteral) &&
- (e.type.ty == Tpointer || e.type.ty == Tarray))
+ VarDeclaration v = ve.var.isVarDeclaration();
+ ex = expandVar(result, v);
+ }
+ if (ex && ex.isStructLiteralExp())
+ {
+ StructLiteralExp sle = ex.isStructLiteralExp();
+ VarDeclaration vf = e.var.isVarDeclaration();
+ if (vf && !vf.overlapped)
{
- const esz = e.type.nextOf().size(e.loc);
- const e1sz = e.e1.type.toBasetype().nextOf().size(e.e1.loc);
- if (esz == SIZE_INVALID || e1sz == SIZE_INVALID)
- return error();
-
- if (e1sz == esz)
+ /* https://issues.dlang.org/show_bug.cgi?id=13021
+ * Prevent optimization if vf has overlapped fields.
+ */
+ ex = sle.getField(e.type, vf.offset);
+ if (ex && !CTFEExp.isCantExp(ex))
{
- // https://issues.dlang.org/show_bug.cgi?id=12937
- // If target type is void array, trying to paint
- // e.e1 with that type will cause infinite recursive optimization.
- if (e.type.nextOf().ty == Tvoid)
- return;
- ret = e.e1.castTo(null, e.type);
- //printf(" returning1 %s\n", ret.toChars());
+ ret = ex;
return;
}
}
+ }
+ }
- if (e.e1.op == TOK.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant)
- {
- //printf(" returning2 %s\n", e.e1.toChars());
- L1:
- // Returning e1 with changing its type
- ret = (e1old == e.e1 ? e.e1.copy() : e.e1);
- ret.type = e.type;
- return;
- }
- /* The first test here is to prevent infinite loops
- */
- if (op1 != TOK.arrayLiteral && e.e1.op == TOK.arrayLiteral)
- {
- ret = e.e1.castTo(null, e.to);
- return;
- }
- if (e.e1.op == TOK.null_ && (e.type.ty == Tpointer || e.type.ty == Tclass || e.type.ty == Tarray))
- {
- //printf(" returning3 %s\n", e.e1.toChars());
- goto L1;
- }
- if (e.type.ty == Tclass && e.e1.type.ty == Tclass)
- {
- import dmd.astenums : Sizeok;
-
- // See if we can remove an unnecessary cast
- ClassDeclaration cdfrom = e.e1.type.isClassHandle();
- ClassDeclaration cdto = e.type.isClassHandle();
- if (cdfrom.errors || cdto.errors)
- return error();
- if (cdto == ClassDeclaration.object && !cdfrom.isInterfaceDeclaration())
- goto L1; // can always convert a class to Object
- // Need to determine correct offset before optimizing away the cast.
- // https://issues.dlang.org/show_bug.cgi?id=16980
- cdfrom.size(e.loc);
- assert(cdfrom.sizeok == Sizeok.done);
- assert(cdto.sizeok == Sizeok.done || !cdto.isBaseOf(cdfrom, null));
- int offset;
- if (cdto.isBaseOf(cdfrom, &offset) && offset == 0)
- {
- //printf(" returning4 %s\n", e.e1.toChars());
- goto L1;
- }
- }
- if (e.e1.type.mutableOf().unSharedOf().equals(e.to.mutableOf().unSharedOf()))
+ void visitNew(NewExp e)
+ {
+ expOptimize(e.thisexp, WANTvalue);
+ // Optimize parameters
+ if (e.newargs)
+ {
+ for (size_t i = 0; i < e.newargs.dim; i++)
{
- //printf(" returning5 %s\n", e.e1.toChars());
- goto L1;
+ expOptimize((*e.newargs)[i], WANTvalue);
}
- if (e.e1.isConst())
+ }
+ if (e.arguments)
+ {
+ for (size_t i = 0; i < e.arguments.dim; i++)
{
- if (e.e1.op == TOK.symbolOffset)
- {
- if (e.type.toBasetype().ty != Tsarray)
- {
- const esz = e.type.size(e.loc);
- const e1sz = e.e1.type.size(e.e1.loc);
- if (esz == SIZE_INVALID ||
- e1sz == SIZE_INVALID)
- return error();
-
- if (esz == e1sz)
- goto L1;
- }
- return;
- }
- if (e.to.toBasetype().ty != Tvoid)
- {
- if (e.e1.type.equals(e.type) && e.type.equals(e.to))
- ret = e.e1;
- else
- ret = Cast(e.loc, e.type, e.to, e.e1).copy();
- }
+ expOptimize((*e.arguments)[i], WANTvalue);
}
- //printf(" returning6 %s\n", ret.toChars());
}
+ }
- override void visit(BinAssignExp e)
+ void visitCall(CallExp e)
+ {
+ //printf("CallExp::optimize(result = %d) %s\n", result, e.toChars());
+ // Optimize parameters with keeping lvalue-ness
+ if (expOptimize(e.e1, result))
+ return;
+ if (e.arguments)
{
- //printf("BinAssignExp::optimize(result = %d) %s\n", result, e.toChars());
- if (binOptimize(e, result, /*keepLhsLvalue*/ true))
- return;
- if (e.op == TOK.leftShiftAssign || e.op == TOK.rightShiftAssign || e.op == TOK.unsignedRightShiftAssign)
+ Type t1 = e.e1.type.toBasetype();
+ if (t1.ty == Tdelegate)
+ t1 = t1.nextOf();
+ // t1 can apparently be void for __ArrayDtor(T) calls
+ if (auto tf = t1.isTypeFunction())
{
- if (e.e2.isConst() == 1)
+ for (size_t i = 0; i < e.arguments.dim; i++)
{
- sinteger_t i2 = e.e2.toInteger();
- d_uns64 sz = e.e1.type.size(e.e1.loc);
- assert(sz != SIZE_INVALID);
- sz *= 8;
- if (i2 < 0 || i2 >= sz)
- {
- e.error("shift assign by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1);
- return error();
- }
+ Parameter p = tf.parameterList[i];
+ bool keep = p && p.isReference();
+ expOptimize((*e.arguments)[i], WANTvalue, keep);
}
}
}
+ }
- override void visit(BinExp e)
+ void visitCast(CastExp e)
+ {
+ //printf("CastExp::optimize(result = %d) %s\n", result, e.toChars());
+ //printf("from %s to %s\n", e.type.toChars(), e.to.toChars());
+ //printf("from %s\n", e.type.toChars());
+ //printf("e1.type %s\n", e.e1.type.toChars());
+ //printf("type = %p\n", e.type);
+ assert(e.type);
+ const op1 = e.e1.op;
+ Expression e1old = e.e1;
+ if (expOptimize(e.e1, result, keepLvalue))
+ return;
+ if (!keepLvalue)
+ e.e1 = fromConstInitializer(result, e.e1);
+ if (e.e1 == e1old && e.e1.op == EXP.arrayLiteral && e.type.toBasetype().ty == Tpointer && e.e1.type.toBasetype().ty != Tsarray)
{
- //printf("BinExp::optimize(result = %d) %s\n", result, e.toChars());
- const keepLhsLvalue = e.op == TOK.construct || e.op == TOK.blit || e.op == TOK.assign
- || e.op == TOK.plusPlus || e.op == TOK.minusMinus
- || e.op == TOK.prePlusPlus || e.op == TOK.preMinusMinus;
- binOptimize(e, result, keepLhsLvalue);
+ // Casting this will result in the same expression, and
+ // infinite loop because of Expression::implicitCastTo()
+ return; // no change
}
-
- override void visit(AddExp e)
+ if ((e.e1.op == EXP.string_ || e.e1.op == EXP.arrayLiteral) &&
+ (e.type.ty == Tpointer || e.type.ty == Tarray))
{
- //printf("AddExp::optimize(%s)\n", e.toChars());
- if (binOptimize(e, result))
- return;
- if (e.e1.isConst() && e.e2.isConst())
+ const esz = e.type.nextOf().size(e.loc);
+ const e1sz = e.e1.type.toBasetype().nextOf().size(e.e1.loc);
+ if (esz == SIZE_INVALID || e1sz == SIZE_INVALID)
+ return error();
+
+ if (e1sz == esz)
{
- if (e.e1.op == TOK.symbolOffset && e.e2.op == TOK.symbolOffset)
+ // https://issues.dlang.org/show_bug.cgi?id=12937
+ // If target type is void array, trying to paint
+ // e.e1 with that type will cause infinite recursive optimization.
+ if (e.type.nextOf().ty == Tvoid)
return;
- ret = Add(e.loc, e.type, e.e1, e.e2).copy();
+ ret = e.e1.castTo(null, e.type);
+ //printf(" returning1 %s\n", ret.toChars());
+ return;
}
}
- override void visit(MinExp e)
+ if (e.e1.op == EXP.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant)
{
- if (binOptimize(e, result))
- return;
- if (e.e1.isConst() && e.e2.isConst())
- {
- if (e.e2.op == TOK.symbolOffset)
- return;
- ret = Min(e.loc, e.type, e.e1, e.e2).copy();
- }
+ //printf(" returning2 %s\n", e.e1.toChars());
+ L1:
+ // Returning e1 with changing its type
+ ret = (e1old == e.e1 ? e.e1.copy() : e.e1);
+ ret.type = e.type;
+ return;
}
-
- override void visit(MulExp e)
+ /* The first test here is to prevent infinite loops
+ */
+ if (op1 != EXP.arrayLiteral && e.e1.op == EXP.arrayLiteral)
{
- //printf("MulExp::optimize(result = %d) %s\n", result, e.toChars());
- if (binOptimize(e, result))
- return;
- if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
- {
- ret = Mul(e.loc, e.type, e.e1, e.e2).copy();
- }
+ ret = e.e1.castTo(null, e.to);
+ return;
}
-
- override void visit(DivExp e)
+ if (e.e1.op == EXP.null_ && (e.type.ty == Tpointer || e.type.ty == Tclass || e.type.ty == Tarray))
{
- //printf("DivExp::optimize(%s)\n", e.toChars());
- if (binOptimize(e, result))
- return;
- if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+ //printf(" returning3 %s\n", e.e1.toChars());
+ goto L1;
+ }
+ if (e.type.ty == Tclass && e.e1.type.ty == Tclass)
+ {
+ import dmd.astenums : Sizeok;
+
+ // See if we can remove an unnecessary cast
+ ClassDeclaration cdfrom = e.e1.type.isClassHandle();
+ ClassDeclaration cdto = e.type.isClassHandle();
+ if (cdfrom.errors || cdto.errors)
+ return error();
+ if (cdto == ClassDeclaration.object && !cdfrom.isInterfaceDeclaration())
+ goto L1; // can always convert a class to Object
+ // Need to determine correct offset before optimizing away the cast.
+ // https://issues.dlang.org/show_bug.cgi?id=16980
+ cdfrom.size(e.loc);
+ assert(cdfrom.sizeok == Sizeok.done);
+ assert(cdto.sizeok == Sizeok.done || !cdto.isBaseOf(cdfrom, null));
+ int offset;
+ if (cdto.isBaseOf(cdfrom, &offset) && offset == 0)
{
- ret = Div(e.loc, e.type, e.e1, e.e2).copy();
+ //printf(" returning4 %s\n", e.e1.toChars());
+ goto L1;
}
}
-
- override void visit(ModExp e)
+ if (e.e1.type.mutableOf().unSharedOf().equals(e.to.mutableOf().unSharedOf()))
{
- if (binOptimize(e, result))
+ //printf(" returning5 %s\n", e.e1.toChars());
+ goto L1;
+ }
+ if (e.e1.isConst())
+ {
+ if (e.e1.op == EXP.symbolOffset)
+ {
+ if (e.type.toBasetype().ty != Tsarray)
+ {
+ const esz = e.type.size(e.loc);
+ const e1sz = e.e1.type.size(e.e1.loc);
+ if (esz == SIZE_INVALID ||
+ e1sz == SIZE_INVALID)
+ return error();
+
+ if (esz == e1sz)
+ goto L1;
+ }
return;
- if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+ }
+ if (e.to.toBasetype().ty != Tvoid)
{
- ret = Mod(e.loc, e.type, e.e1, e.e2).copy();
+ if (e.e1.type.equals(e.type) && e.type.equals(e.to))
+ ret = e.e1;
+ else
+ ret = Cast(e.loc, e.type, e.to, e.e1).copy();
}
}
+ //printf(" returning6 %s\n", ret.toChars());
+ }
- extern (D) void shift_optimize(BinExp e, UnionExp function(const ref Loc, Type, Expression, Expression) shift)
+ void visitBinAssign(BinAssignExp e)
+ {
+ //printf("BinAssignExp::optimize(result = %d) %s\n", result, e.toChars());
+ if (binOptimize(e, result, /*keepLhsLvalue*/ true))
+ return;
+ if (e.op == EXP.leftShiftAssign || e.op == EXP.rightShiftAssign || e.op == EXP.unsignedRightShiftAssign)
{
- if (binOptimize(e, result))
- return;
if (e.e2.isConst() == 1)
{
sinteger_t i2 = e.e2.toInteger();
sz *= 8;
if (i2 < 0 || i2 >= sz)
{
- e.error("shift by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1);
+ e.error("shift assign by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1);
return error();
}
- if (e.e1.isConst() == 1)
- ret = (*shift)(e.loc, e.type, e.e1, e.e2).copy();
}
}
+ }
- override void visit(ShlExp e)
- {
- //printf("ShlExp::optimize(result = %d) %s\n", result, e.toChars());
- shift_optimize(e, &Shl);
- }
+ void visitBin(BinExp e)
+ {
+ //printf("BinExp::optimize(result = %d) %s\n", result, e.toChars());
+ const keepLhsLvalue = e.op == EXP.construct || e.op == EXP.blit || e.op == EXP.assign
+ || e.op == EXP.plusPlus || e.op == EXP.minusMinus
+ || e.op == EXP.prePlusPlus || e.op == EXP.preMinusMinus;
+ binOptimize(e, result, keepLhsLvalue);
+ }
- override void visit(ShrExp e)
+ void visitAdd(AddExp e)
+ {
+ //printf("AddExp::optimize(%s)\n", e.toChars());
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() && e.e2.isConst())
{
- //printf("ShrExp::optimize(result = %d) %s\n", result, e.toChars());
- shift_optimize(e, &Shr);
+ if (e.e1.op == EXP.symbolOffset && e.e2.op == EXP.symbolOffset)
+ return;
+ ret = Add(e.loc, e.type, e.e1, e.e2).copy();
}
+ }
- override void visit(UshrExp e)
+ void visitMin(MinExp e)
+ {
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() && e.e2.isConst())
{
- //printf("UshrExp::optimize(result = %d) %s\n", result, toChars());
- shift_optimize(e, &Ushr);
+ if (e.e2.op == EXP.symbolOffset)
+ return;
+ ret = Min(e.loc, e.type, e.e1, e.e2).copy();
}
+ }
- override void visit(AndExp e)
+ void visitMul(MulExp e)
+ {
+ //printf("MulExp::optimize(result = %d) %s\n", result, e.toChars());
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
{
- if (binOptimize(e, result))
- return;
- if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
- ret = And(e.loc, e.type, e.e1, e.e2).copy();
+ ret = Mul(e.loc, e.type, e.e1, e.e2).copy();
}
+ }
- override void visit(OrExp e)
+ void visitDiv(DivExp e)
+ {
+ //printf("DivExp::optimize(%s)\n", e.toChars());
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
{
- if (binOptimize(e, result))
- return;
- if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
- ret = Or(e.loc, e.type, e.e1, e.e2).copy();
+ ret = Div(e.loc, e.type, e.e1, e.e2).copy();
}
+ }
- override void visit(XorExp e)
+ void visitMod(ModExp e)
+ {
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
{
- if (binOptimize(e, result))
- return;
- if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
- ret = Xor(e.loc, e.type, e.e1, e.e2).copy();
+ ret = Mod(e.loc, e.type, e.e1, e.e2).copy();
}
+ }
- override void visit(PowExp e)
+ extern (D) void shift_optimize(BinExp e, UnionExp function(const ref Loc, Type, Expression, Expression) shift)
+ {
+ if (binOptimize(e, result))
+ return;
+ if (e.e2.isConst() == 1)
{
- if (binOptimize(e, result))
- return;
- // All negative integral powers are illegal.
- if (e.e1.type.isintegral() && (e.e2.op == TOK.int64) && cast(sinteger_t)e.e2.toInteger() < 0)
+ sinteger_t i2 = e.e2.toInteger();
+ d_uns64 sz = e.e1.type.size(e.e1.loc);
+ assert(sz != SIZE_INVALID);
+ sz *= 8;
+ if (i2 < 0 || i2 >= sz)
{
- e.error("cannot raise `%s` to a negative integer power. Did you mean `(cast(real)%s)^^%s` ?", e.e1.type.toBasetype().toChars(), e.e1.toChars(), e.e2.toChars());
+ e.error("shift by %lld is outside the range `0..%llu`", i2, cast(ulong)sz - 1);
return error();
}
- // If e2 *could* have been an integer, make it one.
- if (e.e2.op == TOK.float64 && e.e2.toReal() == real_t(cast(sinteger_t)e.e2.toReal()))
- {
- // This only applies to floating point, or positive integral powers.
- if (e.e1.type.isfloating() || cast(sinteger_t)e.e2.toInteger() >= 0)
- e.e2 = new IntegerExp(e.loc, e.e2.toInteger(), Type.tint64);
- }
- if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
- {
- Expression ex = Pow(e.loc, e.type, e.e1, e.e2).copy();
- if (!CTFEExp.isCantExp(ex))
- {
- ret = ex;
- return;
- }
- }
+ if (e.e1.isConst() == 1)
+ ret = (*shift)(e.loc, e.type, e.e1, e.e2).copy();
}
+ }
+
+ void visitShl(ShlExp e)
+ {
+ //printf("ShlExp::optimize(result = %d) %s\n", result, e.toChars());
+ shift_optimize(e, &Shl);
+ }
+
+ void visitShr(ShrExp e)
+ {
+ //printf("ShrExp::optimize(result = %d) %s\n", result, e.toChars());
+ shift_optimize(e, &Shr);
+ }
+
+ void visitUshr(UshrExp e)
+ {
+ //printf("UshrExp::optimize(result = %d) %s\n", result, toChars());
+ shift_optimize(e, &Ushr);
+ }
- override void visit(CommaExp e)
+ void visitAnd(AndExp e)
+ {
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+ ret = And(e.loc, e.type, e.e1, e.e2).copy();
+ }
+
+ void visitOr(OrExp e)
+ {
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+ ret = Or(e.loc, e.type, e.e1, e.e2).copy();
+ }
+
+ void visitXor(XorExp e)
+ {
+ if (binOptimize(e, result))
+ return;
+ if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
+ ret = Xor(e.loc, e.type, e.e1, e.e2).copy();
+ }
+
+ void visitPow(PowExp e)
+ {
+ if (binOptimize(e, result))
+ return;
+ // All negative integral powers are illegal.
+ if (e.e1.type.isintegral() && (e.e2.op == EXP.int64) && cast(sinteger_t)e.e2.toInteger() < 0)
{
- //printf("CommaExp::optimize(result = %d) %s\n", result, e.toChars());
- // Comma needs special treatment, because it may
- // contain compiler-generated declarations. We can interpret them, but
- // otherwise we must NOT attempt to constant-fold them.
- // In particular, if the comma returns a temporary variable, it needs
- // to be an lvalue (this is particularly important for struct constructors)
- expOptimize(e.e1, WANTvalue);
- expOptimize(e.e2, result, keepLvalue);
- if (ret.op == TOK.error)
- return;
- if (!e.e1 || e.e1.op == TOK.int64 || e.e1.op == TOK.float64 || !hasSideEffect(e.e1))
- {
- ret = e.e2;
- if (ret)
- ret.type = e.type;
- }
- //printf("-CommaExp::optimize(result = %d) %s\n", result, e.e.toChars());
+ e.error("cannot raise `%s` to a negative integer power. Did you mean `(cast(real)%s)^^%s` ?", e.e1.type.toBasetype().toChars(), e.e1.toChars(), e.e2.toChars());
+ return error();
}
-
- override void visit(ArrayLengthExp e)
+ // If e2 *could* have been an integer, make it one.
+ if (e.e2.op == EXP.float64 && e.e2.toReal() == real_t(cast(sinteger_t)e.e2.toReal()))
{
- //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, e.toChars());
- if (unaOptimize(e, WANTexpand))
- return;
- // CTFE interpret static immutable arrays (to get better diagnostics)
- if (e.e1.op == TOK.variable)
- {
- VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration();
- if (v && (v.storage_class & STC.static_) && (v.storage_class & STC.immutable_) && v._init)
- {
- if (Expression ci = v.getConstInitializer())
- e.e1 = ci;
- }
- }
- if (e.e1.op == TOK.string_ || e.e1.op == TOK.arrayLiteral || e.e1.op == TOK.assocArrayLiteral || e.e1.type.toBasetype().ty == Tsarray)
- {
- ret = ArrayLength(e.type, e.e1).copy();
- }
+ // This only applies to floating point, or positive integral powers.
+ if (e.e1.type.isfloating() || cast(sinteger_t)e.e2.toInteger() >= 0)
+ e.e2 = new IntegerExp(e.loc, e.e2.toInteger(), Type.tint64);
}
-
- override void visit(EqualExp e)
+ if (e.e1.isConst() == 1 && e.e2.isConst() == 1)
{
- //printf("EqualExp::optimize(result = %x) %s\n", result, e.toChars());
- if (binOptimize(e, WANTvalue))
- return;
- Expression e1 = fromConstInitializer(result, e.e1);
- Expression e2 = fromConstInitializer(result, e.e2);
- if (e1.op == TOK.error)
+ Expression ex = Pow(e.loc, e.type, e.e1, e.e2).copy();
+ if (!CTFEExp.isCantExp(ex))
{
- ret = e1;
+ ret = ex;
return;
}
- if (e2.op == TOK.error)
- {
- ret = e2;
- return;
- }
- ret = Equal(e.op, e.loc, e.type, e1, e2).copy();
- if (CTFEExp.isCantExp(ret))
- ret = e;
}
+ }
- override void visit(IdentityExp e)
+ void visitComma(CommaExp e)
+ {
+ //printf("CommaExp::optimize(result = %d) %s\n", result, e.toChars());
+ // Comma needs special treatment, because it may
+ // contain compiler-generated declarations. We can interpret them, but
+ // otherwise we must NOT attempt to constant-fold them.
+ // In particular, if the comma returns a temporary variable, it needs
+ // to be an lvalue (this is particularly important for struct constructors)
+ expOptimize(e.e1, WANTvalue);
+ expOptimize(e.e2, result, keepLvalue);
+ if (ret.op == EXP.error)
+ return;
+ if (!e.e1 || e.e1.op == EXP.int64 || e.e1.op == EXP.float64 || !hasSideEffect(e.e1))
{
- //printf("IdentityExp::optimize(result = %d) %s\n", result, e.toChars());
- if (binOptimize(e, WANTvalue))
- return;
- if ((e.e1.isConst() && e.e2.isConst()) || (e.e1.op == TOK.null_ && e.e2.op == TOK.null_))
+ ret = e.e2;
+ if (ret)
+ ret.type = e.type;
+ }
+ //printf("-CommaExp::optimize(result = %d) %s\n", result, e.e.toChars());
+ }
+
+ void visitArrayLength(ArrayLengthExp e)
+ {
+ //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, e.toChars());
+ if (unaOptimize(e, WANTexpand))
+ return;
+ // CTFE interpret static immutable arrays (to get better diagnostics)
+ if (auto ve = e.e1.isVarExp())
+ {
+ VarDeclaration v = ve.var.isVarDeclaration();
+ if (v && (v.storage_class & STC.static_) && (v.storage_class & STC.immutable_) && v._init)
{
- ret = Identity(e.op, e.loc, e.type, e.e1, e.e2).copy();
- if (CTFEExp.isCantExp(ret))
- ret = e;
+ if (Expression ci = v.getConstInitializer())
+ e.e1 = ci;
}
}
+ if (e.e1.op == EXP.string_ || e.e1.op == EXP.arrayLiteral || e.e1.op == EXP.assocArrayLiteral || e.e1.type.toBasetype().ty == Tsarray)
+ {
+ ret = ArrayLength(e.type, e.e1).copy();
+ }
+ }
- override void visit(IndexExp e)
+ void visitEqual(EqualExp e)
+ {
+ //printf("EqualExp::optimize(result = %x) %s\n", result, e.toChars());
+ if (binOptimize(e, WANTvalue))
+ return;
+ Expression e1 = fromConstInitializer(result, e.e1);
+ Expression e2 = fromConstInitializer(result, e.e2);
+ if (e1.op == EXP.error)
{
- //printf("IndexExp::optimize(result = %d) %s\n", result, e.toChars());
- if (expOptimize(e.e1, result & WANTexpand))
- return;
- Expression ex = fromConstInitializer(result, e.e1);
- // We might know $ now
- setLengthVarIfKnown(e.lengthVar, ex);
- if (expOptimize(e.e2, WANTvalue))
- return;
- // Don't optimize to an array literal element directly in case an lvalue is requested
- if (keepLvalue && ex.op == TOK.arrayLiteral)
- return;
- ret = Index(e.type, ex, e.e2).copy();
- if (CTFEExp.isCantExp(ret) || (!ret.isErrorExp() && keepLvalue && !ret.isLvalue()))
- ret = e;
+ ret = e1;
+ return;
+ }
+ if (e2.op == EXP.error)
+ {
+ ret = e2;
+ return;
}
+ ret = Equal(e.op, e.loc, e.type, e1, e2).copy();
+ if (CTFEExp.isCantExp(ret))
+ ret = e;
+ }
- override void visit(SliceExp e)
+ void visitIdentity(IdentityExp e)
+ {
+ //printf("IdentityExp::optimize(result = %d) %s\n", result, e.toChars());
+ if (binOptimize(e, WANTvalue))
+ return;
+ if ((e.e1.isConst() && e.e2.isConst()) || (e.e1.op == EXP.null_ && e.e2.op == EXP.null_))
{
- //printf("SliceExp::optimize(result = %d) %s\n", result, e.toChars());
- if (expOptimize(e.e1, result & WANTexpand))
- return;
- if (!e.lwr)
- {
- if (e.e1.op == TOK.string_)
- {
- // Convert slice of string literal into dynamic array
- Type t = e.e1.type.toBasetype();
- if (Type tn = t.nextOf())
- ret = e.e1.castTo(null, tn.arrayOf());
- }
- }
- else
- {
- e.e1 = fromConstInitializer(result, e.e1);
- // We might know $ now
- setLengthVarIfKnown(e.lengthVar, e.e1);
- expOptimize(e.lwr, WANTvalue);
- expOptimize(e.upr, WANTvalue);
- if (ret.op == TOK.error)
- return;
- ret = Slice(e.type, e.e1, e.lwr, e.upr).copy();
- if (CTFEExp.isCantExp(ret))
- ret = e;
- }
- // https://issues.dlang.org/show_bug.cgi?id=14649
- // Leave the slice form so it might be
- // a part of array operation.
- // Assume that the backend codegen will handle the form `e[]`
- // as an equal to `e` itself.
- if (ret.op == TOK.string_)
- {
- e.e1 = ret;
- e.lwr = null;
- e.upr = null;
+ ret = Identity(e.op, e.loc, e.type, e.e1, e.e2).copy();
+ if (CTFEExp.isCantExp(ret))
ret = e;
- }
- //printf("-SliceExp::optimize() %s\n", ret.toChars());
}
+ }
+
+ void visitIndex(IndexExp e)
+ {
+ //printf("IndexExp::optimize(result = %d) %s\n", result, e.toChars());
+ if (expOptimize(e.e1, result & WANTexpand))
+ return;
+ Expression ex = fromConstInitializer(result, e.e1);
+ // We might know $ now
+ setLengthVarIfKnown(e.lengthVar, ex);
+ if (expOptimize(e.e2, WANTvalue))
+ return;
+ // Don't optimize to an array literal element directly in case an lvalue is requested
+ if (keepLvalue && ex.op == EXP.arrayLiteral)
+ return;
+ ret = Index(e.type, ex, e.e2).copy();
+ if (CTFEExp.isCantExp(ret) || (!ret.isErrorExp() && keepLvalue && !ret.isLvalue()))
+ ret = e;
+ }
- override void visit(LogicalExp e)
+ void visitSlice(SliceExp e)
+ {
+ //printf("SliceExp::optimize(result = %d) %s\n", result, e.toChars());
+ if (expOptimize(e.e1, result & WANTexpand))
+ return;
+ if (!e.lwr)
{
- //printf("LogicalExp::optimize(%d) %s\n", result, e.toChars());
- if (expOptimize(e.e1, WANTvalue))
- return;
- const oror = e.op == TOK.orOr;
- if (e.e1.isBool(oror))
- {
- // Replace with (e1, oror)
- ret = IntegerExp.createBool(oror);
- ret = Expression.combine(e.e1, ret);
- if (e.type.toBasetype().ty == Tvoid)
- {
- ret = new CastExp(e.loc, ret, Type.tvoid);
- ret.type = e.type;
- }
- ret = Expression_optimize(ret, result, false);
- return;
- }
- expOptimize(e.e2, WANTvalue);
- if (e.e1.isConst())
+ if (e.e1.op == EXP.string_)
{
- if (e.e2.isConst())
- {
- bool n1 = e.e1.isBool(true);
- bool n2 = e.e2.isBool(true);
- ret = new IntegerExp(e.loc, oror ? (n1 || n2) : (n1 && n2), e.type);
- }
- else if (e.e1.isBool(!oror))
- {
- if (e.type.toBasetype().ty == Tvoid)
- ret = e.e2;
- else
- {
- ret = new CastExp(e.loc, e.e2, e.type);
- ret.type = e.type;
- }
- }
+ // Convert slice of string literal into dynamic array
+ Type t = e.e1.type.toBasetype();
+ if (Type tn = t.nextOf())
+ ret = e.e1.castTo(null, tn.arrayOf());
}
}
-
- override void visit(CmpExp e)
+ else
{
- //printf("CmpExp::optimize() %s\n", e.toChars());
- if (binOptimize(e, WANTvalue))
+ e.e1 = fromConstInitializer(result, e.e1);
+ // We might know $ now
+ setLengthVarIfKnown(e.lengthVar, e.e1);
+ expOptimize(e.lwr, WANTvalue);
+ expOptimize(e.upr, WANTvalue);
+ if (ret.op == EXP.error)
return;
- Expression e1 = fromConstInitializer(result, e.e1);
- Expression e2 = fromConstInitializer(result, e.e2);
- ret = Cmp(e.op, e.loc, e.type, e1, e2).copy();
+ ret = Slice(e.type, e.e1, e.lwr, e.upr).copy();
if (CTFEExp.isCantExp(ret))
ret = e;
}
+ // https://issues.dlang.org/show_bug.cgi?id=14649
+ // Leave the slice form so it might be
+ // a part of array operation.
+ // Assume that the backend codegen will handle the form `e[]`
+ // as an equal to `e` itself.
+ if (ret.op == EXP.string_)
+ {
+ e.e1 = ret;
+ e.lwr = null;
+ e.upr = null;
+ ret = e;
+ }
+ //printf("-SliceExp::optimize() %s\n", ret.toChars());
+ }
- override void visit(CatExp e)
+ void visitLogical(LogicalExp e)
+ {
+ //printf("LogicalExp::optimize(%d) %s\n", result, e.toChars());
+ if (expOptimize(e.e1, WANTvalue))
+ return;
+ const oror = e.op == EXP.orOr;
+ if (e.e1.toBool().hasValue(oror))
{
- //printf("CatExp::optimize(%d) %s\n", result, e.toChars());
- if (binOptimize(e, result))
- return;
- if (e.e1.op == TOK.concatenate)
+ // Replace with (e1, oror)
+ ret = IntegerExp.createBool(oror);
+ ret = Expression.combine(e.e1, ret);
+ if (e.type.toBasetype().ty == Tvoid)
{
- // https://issues.dlang.org/show_bug.cgi?id=12798
- // optimize ((expr ~ str1) ~ str2)
- CatExp ce1 = cast(CatExp)e.e1;
- scope CatExp cex = new CatExp(e.loc, ce1.e2, e.e2);
- cex.type = e.type;
- Expression ex = Expression_optimize(cex, result, false);
- if (ex != cex)
- {
- e.e1 = ce1.e1;
- e.e2 = ex;
- }
+ ret = new CastExp(e.loc, ret, Type.tvoid);
+ ret.type = e.type;
}
- // optimize "str"[] -> "str"
- if (e.e1.op == TOK.slice)
+ ret = Expression_optimize(ret, result, false);
+ return;
+ }
+ expOptimize(e.e2, WANTvalue);
+ if (e.e1.isConst())
+ {
+ const e1Opt = e.e1.toBool();
+ if (e.e2.isConst())
{
- SliceExp se1 = cast(SliceExp)e.e1;
- if (se1.e1.op == TOK.string_ && !se1.lwr)
- e.e1 = se1.e1;
+ bool n1 = e1Opt.hasValue(true);
+ bool n2 = e.e2.toBool().hasValue(true);
+ ret = new IntegerExp(e.loc, oror ? (n1 || n2) : (n1 && n2), e.type);
}
- if (e.e2.op == TOK.slice)
+ else if (e1Opt.hasValue(!oror))
{
- SliceExp se2 = cast(SliceExp)e.e2;
- if (se2.e1.op == TOK.string_ && !se2.lwr)
- e.e2 = se2.e1;
+ if (e.type.toBasetype().ty == Tvoid)
+ ret = e.e2;
+ else
+ {
+ ret = new CastExp(e.loc, e.e2, e.type);
+ ret.type = e.type;
+ }
}
- ret = Cat(e.loc, e.type, e.e1, e.e2).copy();
- if (CTFEExp.isCantExp(ret))
- ret = e;
}
+ }
- override void visit(CondExp e)
+ void visitCmp(CmpExp e)
+ {
+ //printf("CmpExp::optimize() %s\n", e.toChars());
+ if (binOptimize(e, WANTvalue))
+ return;
+ Expression e1 = fromConstInitializer(result, e.e1);
+ Expression e2 = fromConstInitializer(result, e.e2);
+ ret = Cmp(e.op, e.loc, e.type, e1, e2).copy();
+ if (CTFEExp.isCantExp(ret))
+ ret = e;
+ }
+
+ void visitCat(CatExp e)
+ {
+ //printf("CatExp::optimize(%d) %s\n", result, e.toChars());
+ if (binOptimize(e, result))
+ return;
+ if (auto ce1 = e.e1.isCatExp())
{
- if (expOptimize(e.econd, WANTvalue))
- return;
- if (e.econd.isBool(true))
- ret = Expression_optimize(e.e1, result, keepLvalue);
- else if (e.econd.isBool(false))
- ret = Expression_optimize(e.e2, result, keepLvalue);
- else
+ // https://issues.dlang.org/show_bug.cgi?id=12798
+ // optimize ((expr ~ str1) ~ str2)
+ scope CatExp cex = new CatExp(e.loc, ce1.e2, e.e2);
+ cex.type = e.type;
+ Expression ex = Expression_optimize(cex, result, false);
+ if (ex != cex)
{
- expOptimize(e.e1, result, keepLvalue);
- expOptimize(e.e2, result, keepLvalue);
+ e.e1 = ce1.e1;
+ e.e2 = ex;
}
}
+ // optimize "str"[] -> "str"
+ if (auto se1 = e.e1.isSliceExp())
+ {
+ if (se1.e1.op == EXP.string_ && !se1.lwr)
+ e.e1 = se1.e1;
+ }
+ if (auto se2 = e.e2.isSliceExp())
+ {
+ if (se2.e1.op == EXP.string_ && !se2.lwr)
+ e.e2 = se2.e1;
+ }
+ ret = Cat(e.loc, e.type, e.e1, e.e2).copy();
+ if (CTFEExp.isCantExp(ret))
+ ret = e;
}
- scope OptimizeVisitor v = new OptimizeVisitor(e, result, keepLvalue);
+ void visitCond(CondExp e)
+ {
+ if (expOptimize(e.econd, WANTvalue))
+ return;
+ const opt = e.econd.toBool();
+ if (opt.hasValue(true))
+ ret = Expression_optimize(e.e1, result, keepLvalue);
+ else if (opt.hasValue(false))
+ ret = Expression_optimize(e.e2, result, keepLvalue);
+ else
+ {
+ expOptimize(e.e1, result, keepLvalue);
+ expOptimize(e.e2, result, keepLvalue);
+ }
+ }
// Optimize the expression until it can no longer be simplified.
size_t b;
e.error("infinite loop while optimizing expression");
fatal();
}
- auto ex = v.ret;
- ex.accept(v);
- if (ex == v.ret)
+
+ auto ex = ret;
+ switch (ex.op)
+ {
+ case EXP.variable: visitVar(ex.isVarExp()); break;
+ case EXP.tuple: visitTuple(ex.isTupleExp()); break;
+ case EXP.arrayLiteral: visitArrayLiteral(ex.isArrayLiteralExp()); break;
+ case EXP.assocArrayLiteral: visitAssocArrayLiteral(ex.isAssocArrayLiteralExp()); break;
+ case EXP.structLiteral: visitStructLiteral(ex.isStructLiteralExp()); break;
+
+ case EXP.import_:
+ case EXP.assert_:
+ case EXP.dotIdentifier:
+ case EXP.dotTemplateDeclaration:
+ case EXP.dotTemplateInstance:
+ case EXP.delegate_:
+ case EXP.dotType:
+ case EXP.uadd:
+ case EXP.delete_:
+ case EXP.vector:
+ case EXP.vectorArray:
+ case EXP.array:
+ case EXP.delegatePointer:
+ case EXP.delegateFunctionPointer:
+ case EXP.preMinusMinus:
+ case EXP.prePlusPlus: visitUna(cast(UnaExp)ex); break;
+
+ case EXP.negate: visitNeg(ex.isNegExp()); break;
+ case EXP.tilde: visitCom(ex.isComExp()); break;
+ case EXP.not: visitNop(ex.isNotExp()); break;
+ case EXP.symbolOffset: visitSymOff(ex.isSymOffExp()); break;
+ case EXP.address: visitAddr(ex.isAddrExp()); break;
+ case EXP.star: visitPtr(ex.isPtrExp()); break;
+ case EXP.dotVariable: visitDotVar(ex.isDotVarExp()); break;
+ case EXP.new_: visitNew(ex.isNewExp()); break;
+ case EXP.call: visitCall(ex.isCallExp()); break;
+ case EXP.cast_: visitCast(ex.isCastExp()); break;
+
+ case EXP.addAssign:
+ case EXP.minAssign:
+ case EXP.mulAssign:
+ case EXP.divAssign:
+ case EXP.modAssign:
+ case EXP.andAssign:
+ case EXP.orAssign:
+ case EXP.xorAssign:
+ case EXP.powAssign:
+ case EXP.leftShiftAssign:
+ case EXP.rightShiftAssign:
+ case EXP.unsignedRightShiftAssign:
+ case EXP.concatenateElemAssign:
+ case EXP.concatenateDcharAssign:
+ case EXP.concatenateAssign: visitBinAssign(ex.isBinAssignExp()); break;
+
+ case EXP.minusMinus:
+ case EXP.plusPlus:
+ case EXP.assign:
+ case EXP.construct:
+ case EXP.blit:
+ case EXP.in_:
+ case EXP.remove:
+ case EXP.dot: visitBin(cast(BinExp)ex); break;
+
+ case EXP.add: visitAdd(ex.isAddExp()); break;
+ case EXP.min: visitMin(ex.isMinExp()); break;
+ case EXP.mul: visitMul(ex.isMulExp()); break;
+ case EXP.div: visitDiv(ex.isDivExp()); break;
+ case EXP.mod: visitMod(ex.isModExp()); break;
+ case EXP.leftShift: visitShl(ex.isShlExp()); break;
+ case EXP.rightShift: visitShr(ex.isShrExp()); break;
+ case EXP.unsignedRightShift: visitUshr(ex.isUshrExp()); break;
+ case EXP.and: visitAnd(ex.isAndExp()); break;
+ case EXP.or: visitOr(ex.isOrExp()); break;
+ case EXP.xor: visitXor(ex.isXorExp()); break;
+ case EXP.pow: visitPow(ex.isPowExp()); break;
+ case EXP.comma: visitComma(ex.isCommaExp()); break;
+ case EXP.arrayLength: visitArrayLength(ex.isArrayLengthExp()); break;
+ case EXP.notEqual:
+ case EXP.equal: visitEqual(ex.isEqualExp()); break;
+ case EXP.notIdentity:
+ case EXP.identity: visitIdentity(ex.isIdentityExp()); break;
+ case EXP.index: visitIndex(ex.isIndexExp()); break;
+ case EXP.slice: visitSlice(ex.isSliceExp()); break;
+ case EXP.andAnd:
+ case EXP.orOr: visitLogical(ex.isLogicalExp()); break;
+ case EXP.lessThan:
+ case EXP.lessOrEqual:
+ case EXP.greaterThan:
+ case EXP.greaterOrEqual: visitCmp(cast(CmpExp)ex); break;
+ case EXP.concatenate: visitCat(ex.isCatExp()); break;
+ case EXP.question: visitCond(ex.isCondExp()); break;
+
+ default: visitExp(ex); break;
+ }
+
+ if (ex == ret)
break;
}
- return v.ret;
+ return ret;
}
*
* Used by hdrgen
*/
-immutable PREC[TOK.max + 1] precedence =
+immutable PREC[EXP.max + 1] precedence =
[
- TOK.type : PREC.expr,
- TOK.error : PREC.expr,
- TOK.objcClassReference : PREC.expr, // Objective-C class reference, same as TOK.type
-
- TOK.typeof_ : PREC.primary,
- TOK.mixin_ : PREC.primary,
-
- TOK.import_ : PREC.primary,
- TOK.dotVariable : PREC.primary,
- TOK.scope_ : PREC.primary,
- TOK.identifier : PREC.primary,
- TOK.this_ : PREC.primary,
- TOK.super_ : PREC.primary,
- TOK.int64 : PREC.primary,
- TOK.float64 : PREC.primary,
- TOK.complex80 : PREC.primary,
- TOK.null_ : PREC.primary,
- TOK.string_ : PREC.primary,
- TOK.arrayLiteral : PREC.primary,
- TOK.assocArrayLiteral : PREC.primary,
- TOK.classReference : PREC.primary,
- TOK.file : PREC.primary,
- TOK.fileFullPath : PREC.primary,
- TOK.line : PREC.primary,
- TOK.moduleString : PREC.primary,
- TOK.functionString : PREC.primary,
- TOK.prettyFunction : PREC.primary,
- TOK.typeid_ : PREC.primary,
- TOK.is_ : PREC.primary,
- TOK.assert_ : PREC.primary,
- TOK.halt : PREC.primary,
- TOK.template_ : PREC.primary,
- TOK.dSymbol : PREC.primary,
- TOK.function_ : PREC.primary,
- TOK.variable : PREC.primary,
- TOK.symbolOffset : PREC.primary,
- TOK.structLiteral : PREC.primary,
- TOK.compoundLiteral : PREC.primary,
- TOK.arrayLength : PREC.primary,
- TOK.delegatePointer : PREC.primary,
- TOK.delegateFunctionPointer : PREC.primary,
- TOK.remove : PREC.primary,
- TOK.tuple : PREC.primary,
- TOK.traits : PREC.primary,
- TOK.default_ : PREC.primary,
- TOK.overloadSet : PREC.primary,
- TOK.void_ : PREC.primary,
- TOK.vectorArray : PREC.primary,
- TOK._Generic : PREC.primary,
+ EXP.type : PREC.expr,
+ EXP.error : PREC.expr,
+ EXP.objcClassReference : PREC.expr, // Objective-C class reference, same as EXP.type
+
+ EXP.typeof_ : PREC.primary,
+ EXP.mixin_ : PREC.primary,
+
+ EXP.import_ : PREC.primary,
+ EXP.dotVariable : PREC.primary,
+ EXP.scope_ : PREC.primary,
+ EXP.identifier : PREC.primary,
+ EXP.this_ : PREC.primary,
+ EXP.super_ : PREC.primary,
+ EXP.int64 : PREC.primary,
+ EXP.float64 : PREC.primary,
+ EXP.complex80 : PREC.primary,
+ EXP.null_ : PREC.primary,
+ EXP.string_ : PREC.primary,
+ EXP.arrayLiteral : PREC.primary,
+ EXP.assocArrayLiteral : PREC.primary,
+ EXP.classReference : PREC.primary,
+ EXP.file : PREC.primary,
+ EXP.fileFullPath : PREC.primary,
+ EXP.line : PREC.primary,
+ EXP.moduleString : PREC.primary,
+ EXP.functionString : PREC.primary,
+ EXP.prettyFunction : PREC.primary,
+ EXP.typeid_ : PREC.primary,
+ EXP.is_ : PREC.primary,
+ EXP.assert_ : PREC.primary,
+ EXP.halt : PREC.primary,
+ EXP.template_ : PREC.primary,
+ EXP.dSymbol : PREC.primary,
+ EXP.function_ : PREC.primary,
+ EXP.variable : PREC.primary,
+ EXP.symbolOffset : PREC.primary,
+ EXP.structLiteral : PREC.primary,
+ EXP.compoundLiteral : PREC.primary,
+ EXP.arrayLength : PREC.primary,
+ EXP.delegatePointer : PREC.primary,
+ EXP.delegateFunctionPointer : PREC.primary,
+ EXP.remove : PREC.primary,
+ EXP.tuple : PREC.primary,
+ EXP.traits : PREC.primary,
+ EXP.default_ : PREC.primary,
+ EXP.overloadSet : PREC.primary,
+ EXP.void_ : PREC.primary,
+ EXP.vectorArray : PREC.primary,
+ EXP._Generic : PREC.primary,
// post
- TOK.dotTemplateInstance : PREC.primary,
- TOK.dotIdentifier : PREC.primary,
- TOK.dotTemplateDeclaration : PREC.primary,
- TOK.dot : PREC.primary,
- TOK.dotType : PREC.primary,
- TOK.plusPlus : PREC.primary,
- TOK.minusMinus : PREC.primary,
- TOK.prePlusPlus : PREC.primary,
- TOK.preMinusMinus : PREC.primary,
- TOK.call : PREC.primary,
- TOK.slice : PREC.primary,
- TOK.array : PREC.primary,
- TOK.index : PREC.primary,
-
- TOK.delegate_ : PREC.unary,
- TOK.address : PREC.unary,
- TOK.star : PREC.unary,
- TOK.negate : PREC.unary,
- TOK.uadd : PREC.unary,
- TOK.not : PREC.unary,
- TOK.tilde : PREC.unary,
- TOK.delete_ : PREC.unary,
- TOK.new_ : PREC.unary,
- TOK.newAnonymousClass : PREC.unary,
- TOK.cast_ : PREC.unary,
-
- TOK.vector : PREC.unary,
- TOK.pow : PREC.pow,
-
- TOK.mul : PREC.mul,
- TOK.div : PREC.mul,
- TOK.mod : PREC.mul,
-
- TOK.add : PREC.add,
- TOK.min : PREC.add,
- TOK.concatenate : PREC.add,
-
- TOK.leftShift : PREC.shift,
- TOK.rightShift : PREC.shift,
- TOK.unsignedRightShift : PREC.shift,
-
- TOK.lessThan : PREC.rel,
- TOK.lessOrEqual : PREC.rel,
- TOK.greaterThan : PREC.rel,
- TOK.greaterOrEqual : PREC.rel,
- TOK.in_ : PREC.rel,
+ EXP.dotTemplateInstance : PREC.primary,
+ EXP.dotIdentifier : PREC.primary,
+ EXP.dotTemplateDeclaration : PREC.primary,
+ EXP.dot : PREC.primary,
+ EXP.dotType : PREC.primary,
+ EXP.plusPlus : PREC.primary,
+ EXP.minusMinus : PREC.primary,
+ EXP.prePlusPlus : PREC.primary,
+ EXP.preMinusMinus : PREC.primary,
+ EXP.call : PREC.primary,
+ EXP.slice : PREC.primary,
+ EXP.array : PREC.primary,
+ EXP.index : PREC.primary,
+
+ EXP.delegate_ : PREC.unary,
+ EXP.address : PREC.unary,
+ EXP.star : PREC.unary,
+ EXP.negate : PREC.unary,
+ EXP.uadd : PREC.unary,
+ EXP.not : PREC.unary,
+ EXP.tilde : PREC.unary,
+ EXP.delete_ : PREC.unary,
+ EXP.new_ : PREC.unary,
+ EXP.newAnonymousClass : PREC.unary,
+ EXP.cast_ : PREC.unary,
+
+ EXP.vector : PREC.unary,
+ EXP.pow : PREC.pow,
+
+ EXP.mul : PREC.mul,
+ EXP.div : PREC.mul,
+ EXP.mod : PREC.mul,
+
+ EXP.add : PREC.add,
+ EXP.min : PREC.add,
+ EXP.concatenate : PREC.add,
+
+ EXP.leftShift : PREC.shift,
+ EXP.rightShift : PREC.shift,
+ EXP.unsignedRightShift : PREC.shift,
+
+ EXP.lessThan : PREC.rel,
+ EXP.lessOrEqual : PREC.rel,
+ EXP.greaterThan : PREC.rel,
+ EXP.greaterOrEqual : PREC.rel,
+ EXP.in_ : PREC.rel,
/* Note that we changed precedence, so that < and != have the same
* precedence. This change is in the parser, too.
*/
- TOK.equal : PREC.rel,
- TOK.notEqual : PREC.rel,
- TOK.identity : PREC.rel,
- TOK.notIdentity : PREC.rel,
-
- TOK.and : PREC.and,
- TOK.xor : PREC.xor,
- TOK.or : PREC.or,
-
- TOK.andAnd : PREC.andand,
- TOK.orOr : PREC.oror,
-
- TOK.question : PREC.cond,
-
- TOK.assign : PREC.assign,
- TOK.construct : PREC.assign,
- TOK.blit : PREC.assign,
- TOK.addAssign : PREC.assign,
- TOK.minAssign : PREC.assign,
- TOK.concatenateAssign : PREC.assign,
- TOK.concatenateElemAssign : PREC.assign,
- TOK.concatenateDcharAssign : PREC.assign,
- TOK.mulAssign : PREC.assign,
- TOK.divAssign : PREC.assign,
- TOK.modAssign : PREC.assign,
- TOK.powAssign : PREC.assign,
- TOK.leftShiftAssign : PREC.assign,
- TOK.rightShiftAssign : PREC.assign,
- TOK.unsignedRightShiftAssign : PREC.assign,
- TOK.andAssign : PREC.assign,
- TOK.orAssign : PREC.assign,
- TOK.xorAssign : PREC.assign,
-
- TOK.comma : PREC.expr,
- TOK.declaration : PREC.expr,
-
- TOK.interval : PREC.assign,
+ EXP.equal : PREC.rel,
+ EXP.notEqual : PREC.rel,
+ EXP.identity : PREC.rel,
+ EXP.notIdentity : PREC.rel,
+
+ EXP.and : PREC.and,
+ EXP.xor : PREC.xor,
+ EXP.or : PREC.or,
+
+ EXP.andAnd : PREC.andand,
+ EXP.orOr : PREC.oror,
+
+ EXP.question : PREC.cond,
+
+ EXP.assign : PREC.assign,
+ EXP.construct : PREC.assign,
+ EXP.blit : PREC.assign,
+ EXP.addAssign : PREC.assign,
+ EXP.minAssign : PREC.assign,
+ EXP.concatenateAssign : PREC.assign,
+ EXP.concatenateElemAssign : PREC.assign,
+ EXP.concatenateDcharAssign : PREC.assign,
+ EXP.mulAssign : PREC.assign,
+ EXP.divAssign : PREC.assign,
+ EXP.modAssign : PREC.assign,
+ EXP.powAssign : PREC.assign,
+ EXP.leftShiftAssign : PREC.assign,
+ EXP.rightShiftAssign : PREC.assign,
+ EXP.unsignedRightShiftAssign : PREC.assign,
+ EXP.andAssign : PREC.assign,
+ EXP.orAssign : PREC.assign,
+ EXP.xorAssign : PREC.assign,
+
+ EXP.comma : PREC.expr,
+ EXP.declaration : PREC.expr,
+
+ EXP.interval : PREC.assign,
];
enum ParseStatementFlags : int
// Handle delegate declaration:
// t delegate(parameter list) nothrow pure
// t function(parameter list) nothrow pure
- TOK save = token.value;
+ const save = token.value;
nextToken();
auto parameterList = parseParameterList(null);
* Error: found 'foo' when expecting ';' following statement
* becomes Error: found `(` when expecting `;` or `=`, did you mean `Foo foo = 42`?
*/
- if (token.value == TOK.identifier && exp.op == TOK.identifier)
+ if (token.value == TOK.identifier && exp.op == EXP.identifier)
{
error("found `%s` when expecting `;` or `=`, did you mean `%s %s = %s`?", peek(&token).toChars(), exp.toChars(), token.toChars(), peek(peek(&token)).toChars());
nextToken();
// mixin(string)
AST.Expression e = parseAssignExp();
check(TOK.semicolon);
- if (e.op == TOK.mixin_)
+ if (e.op == EXP.mixin_)
{
AST.MixinExp cpe = cast(AST.MixinExp)e;
s = new AST.CompileStatement(loc, cpe.exps);
{
switch (token.value)
{
- case TOK.file: e = new AST.FileInitExp(token.loc, TOK.file); break;
- case TOK.fileFullPath: e = new AST.FileInitExp(token.loc, TOK.fileFullPath); break;
+ case TOK.file: e = new AST.FileInitExp(token.loc, EXP.file); break;
+ case TOK.fileFullPath: e = new AST.FileInitExp(token.loc, EXP.fileFullPath); break;
case TOK.line: e = new AST.LineInitExp(token.loc); break;
case TOK.moduleString: e = new AST.ModuleInitExp(token.loc); break;
case TOK.functionString: e = new AST.FuncInitExp(token.loc); break;
nextToken();
e = parseUnaryExp();
//e = new AddAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
- e = new AST.PreExp(TOK.prePlusPlus, loc, e);
+ e = new AST.PreExp(EXP.prePlusPlus, loc, e);
break;
case TOK.minusMinus:
nextToken();
e = parseUnaryExp();
//e = new MinAssignExp(loc, e, new IntegerExp(loc, 1, Type::tint32));
- e = new AST.PreExp(TOK.preMinusMinus, loc, e);
+ e = new AST.PreExp(EXP.preMinusMinus, loc, e);
break;
case TOK.mul:
break;
case TOK.plusPlus:
- e = new AST.PostExp(TOK.plusPlus, loc, e);
+ e = new AST.PostExp(EXP.plusPlus, loc, e);
break;
case TOK.minusMinus:
- e = new AST.PostExp(TOK.minusMinus, loc, e);
+ e = new AST.PostExp(EXP.minusMinus, loc, e);
break;
case TOK.leftParenthesis:
const loc = token.loc;
auto e = parseShiftExp();
- TOK op = token.value;
+ EXP op = EXP.reserved;
- switch (op)
+ switch (token.value)
{
- case TOK.equal:
- case TOK.notEqual:
+ case TOK.equal: op = EXP.equal; goto Lequal;
+ case TOK.notEqual: op = EXP.notEqual; goto Lequal;
+ Lequal:
nextToken();
auto e2 = parseShiftExp();
e = new AST.EqualExp(op, loc, e, e2);
break;
- case TOK.is_:
- op = TOK.identity;
- goto L1;
-
case TOK.not:
{
// Attempt to identify '!is'
if (tv != TOK.is_)
break;
nextToken();
- op = TOK.notIdentity;
- goto L1;
+ op = EXP.notIdentity;
+ goto Lidentity;
}
- L1:
+ case TOK.is_: op = EXP.identity; goto Lidentity;
+ Lidentity:
nextToken();
auto e2 = parseShiftExp();
e = new AST.IdentityExp(op, loc, e, e2);
break;
- case TOK.lessThan:
- case TOK.lessOrEqual:
- case TOK.greaterThan:
- case TOK.greaterOrEqual:
+ case TOK.lessThan: op = EXP.lessThan; goto Lcmp;
+ case TOK.lessOrEqual: op = EXP.lessOrEqual; goto Lcmp;
+ case TOK.greaterThan: op = EXP.greaterThan; goto Lcmp;
+ case TOK.greaterOrEqual: op = EXP.greaterOrEqual; goto Lcmp;
+ Lcmp:
nextToken();
auto e2 = parseShiftExp();
e = new AST.CmpExp(op, loc, e, e2);
{
nextToken();
auto e2 = parseOrExp();
- e = new AST.LogicalExp(loc, TOK.andAnd, e, e2);
+ e = new AST.LogicalExp(loc, EXP.andAnd, e, e2);
}
return e;
}
{
nextToken();
auto e2 = parseAndAndExp();
- e = new AST.LogicalExp(loc, TOK.orOr, e, e2);
+ e = new AST.LogicalExp(loc, EXP.orOr, e, e2);
}
return e;
}
return e;
// require parens for e.g. `t ? a = 1 : b = 2`
- if (e.op == TOK.question && !e.parens && precedence[token.value] == PREC.assign)
- dmd.errors.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`",
- e.toChars(), Token.toChars(token.value));
+ void checkRequiredParens()
+ {
+ if (e.op == EXP.question && !e.parens)
+ dmd.errors.error(e.loc, "`%s` must be surrounded by parentheses when next to operator `%s`",
+ e.toChars(), Token.toChars(token.value));
+ }
const loc = token.loc;
switch (token.value)
{
case TOK.assign:
+ checkRequiredParens();
nextToken();
auto e2 = parseAssignExp();
e = new AST.AssignExp(loc, e, e2);
break;
case TOK.addAssign:
+ checkRequiredParens();
nextToken();
auto e2 = parseAssignExp();
e = new AST.AddAssignExp(loc, e, e2);
break;
case TOK.minAssign:
+ checkRequiredParens();
nextToken();
auto e2 = parseAssignExp();
e = new AST.MinAssignExp(loc, e, e2);
break;
case TOK.mulAssign:
+ checkRequiredParens();
nextToken();
auto e2 = parseAssignExp();
e = new AST.MulAssignExp(loc, e, e2);
break;
case TOK.divAssign:
+ checkRequiredParens();
nextToken();
auto e2 = parseAssignExp();
e = new AST.DivAssignExp(loc, e, e2);
break;
case TOK.modAssign:
+ checkRequiredParens();
nextToken();
auto e2 = parseAssignExp();
e = new AST.ModAssignExp(loc, e, e2);
break;
case TOK.powAssign:
+ checkRequiredParens();
nextToken();
auto e2 = parseAssignExp();
e = new AST.PowAssignExp(loc, e, e2);
break;
case TOK.andAssign:
+ checkRequiredParens();
nextToken();
auto e2 = parseAssignExp();
e = new AST.AndAssignExp(loc, e, e2);
break;
case TOK.orAssign:
+ checkRequiredParens();
nextToken();
auto e2 = parseAssignExp();
e = new AST.OrAssignExp(loc, e, e2);
break;
case TOK.xorAssign:
+ checkRequiredParens();
nextToken();
auto e2 = parseAssignExp();
e = new AST.XorAssignExp(loc, e, e2);
break;
case TOK.leftShiftAssign:
+ checkRequiredParens();
nextToken();
auto e2 = parseAssignExp();
e = new AST.ShlAssignExp(loc, e, e2);
break;
case TOK.rightShiftAssign:
+ checkRequiredParens();
nextToken();
auto e2 = parseAssignExp();
e = new AST.ShrAssignExp(loc, e, e2);
break;
case TOK.unsignedRightShiftAssign:
+ checkRequiredParens();
nextToken();
auto e2 = parseAssignExp();
e = new AST.UshrAssignExp(loc, e, e2);
break;
case TOK.concatenateAssign:
+ checkRequiredParens();
nextToken();
auto e2 = parseAssignExp();
e = new AST.CatAssignExp(loc, e, e2);
import dmd.expression;
import dmd.tokens;
import dmd.visitor;
+import dmd.hdrgen;
/********************
* Print AST data structure in a nice format.
override void visit(Expression e)
{
printIndent(indent);
- printf("%s %s\n", Token.toChars(e.op), e.type ? e.type.toChars() : "");
+ auto s = EXPtoString(e.op);
+ printf("%.*s %s\n", cast(int)s.length, s.ptr, e.type ? e.type.toChars() : "");
}
override void visit(IntegerExp e)
override void visit(StructLiteralExp e)
{
printIndent(indent);
- printf("%s %s, %s\n", Token.toChars(e.op), e.type ? e.type.toChars() : "", e.toChars());
+ auto s = EXPtoString(e.op);
+ printf("%.*s %s, %s\n", cast(int)s.length, s.ptr, e.type ? e.type.toChars() : "", e.toChars());
}
override void visit(SymbolExp e)
__APPLE__ && __SIZEOF_SIZE_T__ == 8
// DMD versions between 2.079 and 2.081 mapped D ulong to uint64_t on OS X.
typedef uint64_t d_size_t;
+#elif defined(__OpenBSD__) && !defined(__LP64__)
+// size_t is 'unsigned long', which makes it mangle differently than D's 'uint'
+typedef unsigned d_size_t;
#else
typedef size_t d_size_t;
#endif
perror("\tclose error");
goto err;
}
- // Always store a wchar ^Z past end of buffer so scanner has a sentinel
- buffer[size] = 0; // ^Z is obsolete, use 0
- buffer[size + 1] = 0;
- buffer[size + 2] = 0; //add two more so lexer doesnt read pass the buffer
- buffer[size + 3] = 0;
+ // Always store a wchar ^Z past end of buffer so scanner has a
+ // sentinel, although ^Z got obselete, so fill with two 0s and add
+ // two more so lexer doesn't read pass the buffer.
+ buffer[size .. size + 4] = 0;
result.success = true;
result.buffer.data = buffer[0 .. size];
goto err2;
if (!CloseHandle(h))
goto err;
- // Always store a wchar ^Z past end of buffer so scanner has a sentinel
- buffer[size] = 0; // ^Z is obsolete, use 0
- buffer[size + 1] = 0;
- buffer[size + 2] = 0; //add two more so lexer doesnt read pass the buffer
- buffer[size + 3] = 0;
+ // Always store a wchar ^Z past end of buffer so scanner has a
+ // sentinel, although ^Z got obselete, so fill with two 0s and add
+ // two more so lexer doesn't read pass the buffer.
+ buffer[size .. size + 4] = 0;
result.success = true;
result.buffer.data = buffer[0 .. size];
return result;
--- /dev/null
+/**
+ * Optional implementation.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/optional.d, root/_optional.d)
+ * Documentation: https://dlang.org/phobos/dmd_root_optional.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/optional.d
+ */
+module dmd.root.optional;
+
+///
+unittest
+{
+ import core.exception : AssertError;
+
+ Optional!int opt;
+ assert( opt.isEmpty());
+ assert(!opt.isPresent());
+ assert(!opt.hasValue(1));
+ assert(!opt.hasValue(2));
+
+ bool caught;
+ try
+ cast(void) opt.get();
+ catch (AssertError)
+ caught = true;
+ assert(caught);
+
+ opt = Optional!int(1);
+ assert(!opt.isEmpty());
+ assert( opt.isPresent());
+ assert( opt.get() == 1);
+ assert( opt.hasValue(1));
+ assert(!opt.hasValue(2));
+}
+
+/// Optional type that is either `empty` or contains a value of type `T`
+extern (C++) struct Optional(T)
+{
+ /// the value (if present)
+ private T value;
+
+ /// whether `value` is set
+ private bool present;
+
+ /// Creates an `Optional` with the given value
+ this(T value)
+ {
+ this.value = value;
+ this.present = true;
+ }
+
+ // Ctor wrapper for the C++ interface (required by older host compilers)
+ /// ditto
+ static Optional!T create(T val)
+ {
+ return Optional!T(val);
+ }
+
+ /// Returns: Whether this `Optional` contains a value
+ bool isPresent() const
+ {
+ return this.present;
+ }
+
+ /// Returns: Whether this `Optional` does not contain a value
+ bool isEmpty() const
+ {
+ return !this.present;
+ }
+
+ /// Returns: The value if present
+ inout(T) get() inout
+ {
+ assert(present);
+ return value;
+ }
+
+ /// Returns: Whether this `Optional` contains the supplied value
+ bool hasValue(const T exp) const
+ {
+ return present && value == exp;
+ }
+}
--- /dev/null
+#pragma once
+
+/**
+ * Optional implementation.
+ *
+ * Copyright: Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
+ * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/optional.h, root/_optional.h)
+ * Documentation: https://dlang.org/phobos/dmd_root_optional.html
+ * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/optional.h
+ */
+
+/// Optional type that is either `empty` or contains a value of type `T`
+template<typename T>
+struct Optional final
+{
+private:
+ /** the value (if present) **/
+ T value;
+
+ /** whether `value` is set **/
+ bool present;
+
+public:
+ /** Creates an `Optional` with the given value **/
+ Optional(T);
+
+ /** Creates an `Optional` with the given value **/
+ static Optional<T> create(T);
+
+ /** Checks whether this `Optional` contains a value **/
+ bool isPresent() const;
+
+ /** Checks whether this `Optional` does not contain a value **/
+ bool isEmpty() const;
+
+ /** Returns: The value if present **/
+ T get();
+
+ bool hasValue(const T) const;
+};
bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
{
//printf("checkUnsafeAccess(e: '%s', readonly: %d, printmsg: %d)\n", e.toChars(), readonly, printmsg);
- if (e.op != TOK.dotVariable)
+ if (e.op != EXP.dotVariable)
return false;
DotVarExp dve = cast(DotVarExp)e;
if (VarDeclaration v = dve.var.isVarDeclaration())
*/
if (tfromn.ty == Tvoid && ttobn.isMutable())
{
- if (ttob.ty == Tarray && e.op == TOK.arrayLiteral)
+ if (ttob.ty == Tarray && e.op == EXP.arrayLiteral)
return true;
return false;
}
return false;
}
- if (e.op == TOK.classReference)
+ if (e.op == EXP.classReference)
return true;
- if (e.op == TOK.address && (cast(AddrExp)e).e1.op == TOK.structLiteral)
+ if (e.op == EXP.address && (cast(AddrExp)e).e1.op == EXP.structLiteral)
return true;
- if (e.op == TOK.arrayLiteral)
+ if (e.op == EXP.arrayLiteral)
return arrayHasInvalidEnumInitializer((cast(ArrayLiteralExp)e).elements);
- if (e.op == TOK.structLiteral)
+ if (e.op == EXP.structLiteral)
return arrayHasInvalidEnumInitializer((cast(StructLiteralExp)e).elements);
- if (e.op == TOK.assocArrayLiteral)
+ if (e.op == EXP.assocArrayLiteral)
{
AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e;
return arrayHasInvalidEnumInitializer(ae.values) ||
if ((vd.type.ty == Tclass) && vd.type.isMutable() && !vd.type.isShared())
{
ExpInitializer ei = vd._init.isExpInitializer();
- if (ei && ei.exp.op == TOK.classReference)
+ if (ei && ei.exp.op == EXP.classReference)
vd.error("is a thread-local class and cannot have a static initializer. Use `static this()` to initialize instead.");
}
else if (vd.type.ty == Tpointer && vd.type.nextOf().ty == Tstruct && vd.type.nextOf().isMutable() && !vd.type.nextOf().isShared())
{
ExpInitializer ei = vd._init.isExpInitializer();
- if (ei && ei.exp.op == TOK.address && (cast(AddrExp)ei.exp).e1.op == TOK.structLiteral)
+ if (ei && ei.exp.op == EXP.address && (cast(AddrExp)ei.exp).e1.op == EXP.structLiteral)
vd.error("is a thread-local pointer to struct and cannot have a static initializer. Use `static this()` to initialize instead.");
}
}
e = e.expressionSemantic(sc);
if (definitelyValueParameter(e))
e = e.ctfeInterpret();
- if (e.op == TOK.tuple)
+ if (e.op == EXP.tuple)
{
TupleExp te = cast(TupleExp)e;
eval(sc, te.exps, lastTag);
import dmd.dmangle;
// When `@gnuAbiTag` is used, the type will be the UDA, not the struct literal
- if (e.op == TOK.type)
+ if (e.op == EXP.type)
{
e.error("`@%s` at least one argument expected", Id.udaGNUAbiTag.toChars());
return;
for (size_t i = 0; i < funcdecl.returns.dim;)
{
Expression exp = (*funcdecl.returns)[i].exp;
- if (exp.op == TOK.variable && (cast(VarExp)exp).var == funcdecl.vresult)
+ if (exp.op == EXP.variable && (cast(VarExp)exp).var == funcdecl.vresult)
{
if (addReturn0())
exp.type = Type.tint32;
{
ReturnStatement rs = (*funcdecl.returns)[i];
Expression exp = rs.exp;
- if (exp.op == TOK.error)
+ if (exp.op == EXP.error)
continue;
if (tret.ty == Terror)
{
* CallExp is always non trivial expression,
* especially for inlining.
*/
- if (e.op == TOK.call)
+ if (e.op == EXP.call)
{
stop = true;
return;
switch (e.op)
{
// Sort the cases by most frequently used first
- case TOK.assign:
- case TOK.plusPlus:
- case TOK.minusMinus:
- case TOK.declaration:
- case TOK.construct:
- case TOK.blit:
- case TOK.addAssign:
- case TOK.minAssign:
- case TOK.concatenateAssign:
- case TOK.concatenateElemAssign:
- case TOK.concatenateDcharAssign:
- case TOK.mulAssign:
- case TOK.divAssign:
- case TOK.modAssign:
- case TOK.leftShiftAssign:
- case TOK.rightShiftAssign:
- case TOK.unsignedRightShiftAssign:
- case TOK.andAssign:
- case TOK.orAssign:
- case TOK.xorAssign:
- case TOK.powAssign:
- case TOK.in_:
- case TOK.remove:
- case TOK.assert_:
- case TOK.halt:
- case TOK.delete_:
- case TOK.new_:
- case TOK.newAnonymousClass:
+ case EXP.assign:
+ case EXP.plusPlus:
+ case EXP.minusMinus:
+ case EXP.declaration:
+ case EXP.construct:
+ case EXP.blit:
+ case EXP.addAssign:
+ case EXP.minAssign:
+ case EXP.concatenateAssign:
+ case EXP.concatenateElemAssign:
+ case EXP.concatenateDcharAssign:
+ case EXP.mulAssign:
+ case EXP.divAssign:
+ case EXP.modAssign:
+ case EXP.leftShiftAssign:
+ case EXP.rightShiftAssign:
+ case EXP.unsignedRightShiftAssign:
+ case EXP.andAssign:
+ case EXP.orAssign:
+ case EXP.xorAssign:
+ case EXP.powAssign:
+ case EXP.in_:
+ case EXP.remove:
+ case EXP.assert_:
+ case EXP.halt:
+ case EXP.delete_:
+ case EXP.new_:
+ case EXP.newAnonymousClass:
return true;
- case TOK.call:
+ case EXP.call:
{
if (assumeImpureCalls)
return true;
}
break;
}
- case TOK.cast_:
+ case EXP.cast_:
{
CastExp ce = cast(CastExp)e;
/* if:
* cast(classtype)func() // because it may throw
*/
- if (ce.to.ty == Tclass && ce.e1.op == TOK.call && ce.e1.type.ty == Tclass)
+ if (ce.to.ty == Tclass && ce.e1.op == EXP.call && ce.e1.type.ty == Tclass)
return true;
break;
}
return false;
switch (e.op)
{
- case TOK.cast_:
+ case EXP.cast_:
{
CastExp ce = cast(CastExp)e;
if (ce.to.equals(Type.tvoid))
}
break; // complain
}
- case TOK.error:
+ case EXP.error:
return false;
- case TOK.variable:
+ case EXP.variable:
{
VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
if (v && (v.storage_class & STC.temp))
}
break;
}
- case TOK.call:
+ case EXP.call:
/* Issue 3882: */
if (global.params.warnings != DiagnosticReporting.off && !global.gag)
{
const(char)* s;
if (ce.f)
s = ce.f.toPrettyChars();
- else if (ce.e1.op == TOK.star)
+ else if (ce.e1.op == EXP.star)
{
// print 'fp' if ce.e1 is (*fp)
s = (cast(PtrExp)ce.e1).e1.toChars();
}
}
return false;
- case TOK.andAnd:
- case TOK.orOr:
+ case EXP.andAnd:
+ case EXP.orOr:
{
LogicalExp aae = cast(LogicalExp)e;
return discardValue(aae.e2);
}
- case TOK.question:
+ case EXP.question:
{
CondExp ce = cast(CondExp)e;
/* https://issues.dlang.org/show_bug.cgi?id=6178
}
return false;
}
- case TOK.comma:
+ case EXP.comma:
{
CommaExp ce = cast(CommaExp)e;
// Don't complain about compiler-generated comma expressions
// This is concretely done in expressionSemantic, if a CommaExp has Tvoid as type
return discardValue(ce.e2);
}
- case TOK.tuple:
+ case EXP.tuple:
/* Pass without complaint if any of the tuple elements have side effects.
* Ideally any tuple elements with no side effects should raise an error,
* this needs more investigation as to what is the right thing to do.
private Expression checkAssignmentAsCondition(Expression e)
{
auto ec = lastComma(e);
- if (ec.op == TOK.assign)
+ if (ec.op == EXP.assign)
{
ec.error("assignment cannot be used as a condition, perhaps `==` was meant?");
return ErrorExp.get();
s.exp = s.exp.optimize(WANTvalue);
s.exp = checkGC(sc, s.exp);
- if (s.exp.op == TOK.error)
+ if (s.exp.op == EXP.error)
return setError();
result = s;
}
ds._body = ds._body.semanticScope(sc, ds, ds, null);
sc.inLoop = inLoopSave;
- if (ds.condition.op == TOK.dotIdentifier)
+ if (ds.condition.op == EXP.dotIdentifier)
(cast(DotIdExp)ds.condition).noderef = true;
// check in syntax level
ds.condition = ds.condition.toBoolean(sc);
- if (ds.condition.op == TOK.error)
+ if (ds.condition.op == EXP.error)
return setError();
if (ds._body && ds._body.isErrorStatement())
{
if (fs.condition)
{
- if (fs.condition.op == TOK.dotIdentifier)
+ if (fs.condition.op == EXP.dotIdentifier)
(cast(DotIdExp)fs.condition).noderef = true;
// check in syntax level
sc.pop();
- if (fs.condition && fs.condition.op == TOK.error ||
- fs.increment && fs.increment.op == TOK.error ||
+ if (fs.condition && fs.condition.op == EXP.error ||
+ fs.increment && fs.increment.op == EXP.error ||
fs._body && fs._body.isErrorStatement())
return setError();
result = fs;
}
-
- /*******************
- * Type check and unroll `foreach` over an expression tuple as well
- * as `static foreach` statements and `static foreach`
- * declarations. For `static foreach` statements and `static
- * foreach` declarations, the visitor interface is used (and the
- * result is written into the `result` field.) For `static
- * foreach` declarations, the resulting Dsymbols* are returned
- * directly.
- *
- * The unrolled body is wrapped into a
- * - UnrolledLoopStatement, for `foreach` over an expression tuple.
- * - ForwardingStatement, for `static foreach` statements.
- * - ForwardingAttribDeclaration, for `static foreach` declarations.
- *
- * `static foreach` variables are declared as `STC.local`, such
- * that they are inserted into the local symbol tables of the
- * forwarding constructs instead of forwarded. For `static
- * foreach` with multiple foreach loop variables whose aggregate
- * has been lowered into a sequence of tuples, this function
- * expands the tuples into multiple `STC.local` `static foreach`
- * variables.
- */
- auto makeTupleForeach(bool isStatic, bool isDecl)(ForeachStatement fs, Dsymbols* dbody, bool needExpansion)
- {
- // Voldemort return type
- union U
- {
- Statement statement;
- Dsymbols* decl;
- }
-
- U result;
-
- auto returnEarly()
- {
- if (isDecl)
- result.decl = null;
- else
- result.statement = new ErrorStatement();
- return result;
- }
-
- auto loc = fs.loc;
- size_t dim = fs.parameters.dim;
- static if(isStatic) bool skipCheck = needExpansion;
- else enum skipCheck = false;
- if (!skipCheck && (dim < 1 || dim > 2))
- {
- fs.error("only one (value) or two (key,value) arguments for tuple `foreach`");
- setError();
- return returnEarly();
- }
-
- Type paramtype = (*fs.parameters)[dim - 1].type;
- if (paramtype)
- {
- paramtype = paramtype.typeSemantic(loc, sc);
- if (paramtype.ty == Terror)
- {
- setError();
- return returnEarly();
- }
- }
-
- Type tab = fs.aggr.type.toBasetype();
- TypeTuple tuple = cast(TypeTuple)tab;
- static if(!isDecl)
- {
- auto statements = new Statements();
- }
- else
- {
- auto declarations = new Dsymbols();
- }
- //printf("aggr: op = %d, %s\n", fs.aggr.op, fs.aggr.toChars());
- size_t n;
- TupleExp te = null;
- if (fs.aggr.op == TOK.tuple) // expression tuple
- {
- te = cast(TupleExp)fs.aggr;
- n = te.exps.dim;
- }
- else if (fs.aggr.op == TOK.type) // type tuple
- {
- n = Parameter.dim(tuple.arguments);
- }
- else
- assert(0);
- foreach (j; 0 .. n)
- {
- size_t k = (fs.op == TOK.foreach_) ? j : n - 1 - j;
- Expression e = null;
- Type t = null;
- if (te)
- e = (*te.exps)[k];
- else
- t = Parameter.getNth(tuple.arguments, k).type;
- Parameter p = (*fs.parameters)[0];
- static if(!isDecl)
- {
- auto st = new Statements();
- }
- else
- {
- auto st = new Dsymbols();
- }
-
- static if(isStatic) bool skip = needExpansion;
- else enum skip = false;
- if (!skip && dim == 2)
- {
- // Declare key
- if (p.storageClass & (STC.out_ | STC.ref_ | STC.lazy_))
- {
- fs.error("no storage class for key `%s`", p.ident.toChars());
- setError();
- return returnEarly();
- }
- static if(isStatic)
- {
- if(!p.type)
- {
- p.type = Type.tsize_t;
- }
- }
- p.type = p.type.typeSemantic(loc, sc);
-
- if (!p.type.isintegral())
- {
- fs.error("foreach: key cannot be of non-integral type `%s`",
- p.type.toChars());
- setError();
- return returnEarly();
- }
-
- const length = te ? te.exps.length : tuple.arguments.length;
- IntRange dimrange = IntRange(SignExtendedNumber(length))._cast(Type.tsize_t);
- // https://issues.dlang.org/show_bug.cgi?id=12504
- dimrange.imax = SignExtendedNumber(dimrange.imax.value-1);
- if (!IntRange.fromType(p.type).contains(dimrange))
- {
- fs.error("index type `%s` cannot cover index range 0..%llu",
- p.type.toChars(), cast(ulong)length);
- setError();
- return returnEarly();
- }
- Initializer ie = new ExpInitializer(Loc.initial, new IntegerExp(k));
- auto var = new VarDeclaration(loc, p.type, p.ident, ie);
- var.storage_class |= STC.foreach_ | STC.manifest;
- static if(isStatic) var.storage_class |= STC.local;
- static if(!isDecl)
- {
- st.push(new ExpStatement(loc, var));
- }
- else
- {
- st.push(var);
- }
- p = (*fs.parameters)[1]; // value
- }
- /***********************
- * Declares a unrolled `foreach` loop variable or a `static foreach` variable.
- *
- * Params:
- * storageClass = The storage class of the variable.
- * type = The declared type of the variable.
- * ident = The name of the variable.
- * e = The initializer of the variable (i.e. the current element of the looped over aggregate).
- * t = The type of the initializer.
- * Returns:
- * `true` iff the declaration was successful.
- */
- bool declareVariable(StorageClass storageClass, Type type, Identifier ident, Expression e, Type t)
- {
- if (storageClass & (STC.out_ | STC.lazy_) ||
- storageClass & STC.ref_ && !te)
- {
- fs.error("no storage class for value `%s`", ident.toChars());
- setError();
- return false;
- }
- Declaration var;
- if (e)
- {
- Type tb = e.type.toBasetype();
- Dsymbol ds = null;
- if (!(storageClass & STC.manifest))
- {
- if ((isStatic || tb.ty == Tfunction || storageClass&STC.alias_) && e.op == TOK.variable)
- ds = (cast(VarExp)e).var;
- else if (e.op == TOK.template_)
- ds = (cast(TemplateExp)e).td;
- else if (e.op == TOK.scope_)
- ds = (cast(ScopeExp)e).sds;
- else if (e.op == TOK.function_)
- {
- auto fe = cast(FuncExp)e;
- ds = fe.td ? cast(Dsymbol)fe.td : fe.fd;
- }
- else if (e.op == TOK.overloadSet)
- ds = (cast(OverExp)e).vars;
- }
- else if (storageClass & STC.alias_)
- {
- fs.error("`foreach` loop variable cannot be both `enum` and `alias`");
- setError();
- return false;
- }
-
- if (ds)
- {
- var = new AliasDeclaration(loc, ident, ds);
- if (storageClass & STC.ref_)
- {
- fs.error("symbol `%s` cannot be `ref`", ds.toChars());
- setError();
- return false;
- }
- if (paramtype)
- {
- fs.error("cannot specify element type for symbol `%s`", ds.toChars());
- setError();
- return false;
- }
- }
- else if (e.op == TOK.type)
- {
- var = new AliasDeclaration(loc, ident, e.type);
- if (paramtype)
- {
- fs.error("cannot specify element type for type `%s`", e.type.toChars());
- setError();
- return false;
- }
- }
- else
- {
- e = resolveProperties(sc, e);
- Initializer ie = new ExpInitializer(Loc.initial, e);
- auto v = new VarDeclaration(loc, type, ident, ie, storageClass);
- v.storage_class |= STC.foreach_;
- if (storageClass & STC.ref_)
- v.storage_class |= STC.ref_;
- if (isStatic || storageClass&STC.manifest || e.isConst() ||
- e.op == TOK.string_ ||
- e.op == TOK.structLiteral ||
- e.op == TOK.arrayLiteral)
- {
- if (v.storage_class & STC.ref_)
- {
- static if (!isStatic)
- {
- fs.error("constant value `%s` cannot be `ref`", ie.toChars());
- }
- else
- {
- if (!needExpansion)
- {
- fs.error("constant value `%s` cannot be `ref`", ie.toChars());
- }
- else
- {
- fs.error("constant value `%s` cannot be `ref`", ident.toChars());
- }
- }
- setError();
- return false;
- }
- else
- v.storage_class |= STC.manifest;
- }
- var = v;
- }
- }
- else
- {
- var = new AliasDeclaration(loc, ident, t);
- if (paramtype)
- {
- fs.error("cannot specify element type for symbol `%s`", fs.toChars());
- setError();
- return false;
- }
- }
- static if (isStatic)
- {
- var.storage_class |= STC.local;
- }
- static if (!isDecl)
- {
- st.push(new ExpStatement(loc, var));
- }
- else
- {
- st.push(var);
- }
- return true;
- }
- static if (!isStatic)
- {
- // Declare value
- if (!declareVariable(p.storageClass, p.type, p.ident, e, t))
- {
- return returnEarly();
- }
- }
- else
- {
- if (!needExpansion)
- {
- // Declare value
- if (!declareVariable(p.storageClass, p.type, p.ident, e, t))
- {
- return returnEarly();
- }
- }
- else
- { // expand tuples into multiple `static foreach` variables.
- assert(e && !t);
- auto ident = Identifier.generateId("__value");
- declareVariable(0, e.type, ident, e, null);
- import dmd.cond: StaticForeach;
- auto field = Identifier.idPool(StaticForeach.tupleFieldName.ptr,StaticForeach.tupleFieldName.length);
- Expression access = new DotIdExp(loc, e, field);
- access = expressionSemantic(access, sc);
- if (!tuple) return returnEarly();
- //printf("%s\n",tuple.toChars());
- foreach (l; 0 .. dim)
- {
- auto cp = (*fs.parameters)[l];
- Expression init_ = new IndexExp(loc, access, new IntegerExp(loc, l, Type.tsize_t));
- init_ = init_.expressionSemantic(sc);
- assert(init_.type);
- declareVariable(p.storageClass, init_.type, cp.ident, init_, null);
- }
- }
- }
-
- static if (!isDecl)
- {
- if (fs._body) // https://issues.dlang.org/show_bug.cgi?id=17646
- st.push(fs._body.syntaxCopy());
- Statement res = new CompoundStatement(loc, st);
- }
- else
- {
- st.append(Dsymbol.arraySyntaxCopy(dbody));
- }
- static if (!isStatic)
- {
- res = new ScopeStatement(loc, res, fs.endloc);
- }
- else static if (!isDecl)
- {
- auto fwd = new ForwardingStatement(loc, res);
- res = fwd;
- }
- else
- {
- import dmd.attrib: ForwardingAttribDeclaration;
- auto res = new ForwardingAttribDeclaration(st);
- }
- static if (!isDecl)
- {
- statements.push(res);
- }
- else
- {
- declarations.push(res);
- }
- }
-
- static if (!isStatic)
- {
- Statement res = new UnrolledLoopStatement(loc, statements);
- if (LabelStatement ls = checkLabeledLoop(sc, fs))
- ls.gotoTarget = res;
- if (te && te.e0)
- res = new CompoundStatement(loc, new ExpStatement(te.e0.loc, te.e0), res);
- result.statement = res;
- }
- else static if (!isDecl)
- {
- result.statement = new CompoundStatement(loc, statements);
- }
- else
- {
- result.decl = declarations;
- }
- return result;
- }
-
override void visit(ForeachStatement fs)
{
/* https://dlang.org/spec/statement.html#foreach-statement
fs.aggr = fs.aggr.expressionSemantic(sc);
fs.aggr = resolveProperties(sc, fs.aggr);
fs.aggr = fs.aggr.optimize(WANTvalue);
- if (fs.aggr.op == TOK.error)
+ if (fs.aggr.op == EXP.error)
return setError();
Expression oaggr = fs.aggr; // remember original for error messages
if (fs.aggr.type && fs.aggr.type.toBasetype().ty == Tstruct &&
(cast(TypeStruct)(fs.aggr.type.toBasetype())).sym.dtor &&
- fs.aggr.op != TOK.type && !fs.aggr.isLvalue())
+ !fs.aggr.isTypeExp() && !fs.aggr.isLvalue())
{
// https://issues.dlang.org/show_bug.cgi?id=14653
// Extend the life of rvalue aggregate till the end of foreach.
if (tab.ty == Ttuple) // don't generate new scope for tuple loops
{
- Statement s = makeTupleForeach!(false,false)(fs, null, false).statement;
+ Statement s = makeTupleForeach(sc, false, false, fs, null, false).statement;
if (vinit)
s = new CompoundStatement(loc, new ExpStatement(loc, vinit), s);
result = s.statementSemantic(sc);
{
e = new DeclarationExp(loc, vinit);
e = e.expressionSemantic(sc2);
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
return null;
}
if (var.storage_class & STC.ref_)
{
if (fs.aggr.checkModifiable(sc2, ModifyFlags.noError) == Modifiable.initialization)
- var.storage_class |= STC.ctorinit;
+ var.setInCtorOnly = true;
Type t = tab.nextOf();
if (t.constConv(p.type) == MATCH.nomatch)
auto ie = new ExpInitializer(loc, new SliceExp(loc, fs.aggr, null, null));
const valueIsRef = cast(bool) ((*fs.parameters)[dim - 1].storageClass & STC.ref_);
VarDeclaration tmp;
- if (fs.aggr.op == TOK.arrayLiteral && !valueIsRef)
+ if (fs.aggr.op == EXP.arrayLiteral && !valueIsRef)
{
auto ale = cast(ArrayLiteralExp)fs.aggr;
size_t edim = ale.elements ? ale.elements.dim : 0;
// if telem has been specified explicitly,
// converting array literal elements to telem might make it @nogc.
fs.aggr = fs.aggr.implicitCastTo(sc, telem.sarrayOf(edim));
- if (fs.aggr.op == TOK.error)
+ if (fs.aggr.op == EXP.error)
return retError();
// for (T[edim] tmp = a, ...)
if (fs.op == TOK.foreach_reverse_)
{
// key--
- cond = new PostExp(TOK.minusMinus, loc, new VarExp(loc, fs.key));
+ cond = new PostExp(EXP.minusMinus, loc, new VarExp(loc, fs.key));
}
else
{
// key < tmp.length
- cond = new CmpExp(TOK.lessThan, loc, new VarExp(loc, fs.key), tmp_length);
+ cond = new CmpExp(EXP.lessThan, loc, new VarExp(loc, fs.key), tmp_length);
}
Expression increment = null;
*/
VarDeclaration r;
Statement _init;
- if (vinit && fs.aggr.op == TOK.variable && (cast(VarExp)fs.aggr).var == vinit)
+ if (vinit && fs.aggr.op == EXP.variable && (cast(VarExp)fs.aggr).var == vinit)
{
r = vinit;
_init = new ExpStatement(loc, vinit);
ec = new DotIdExp(fs.loc, fs.aggr, sapply.ident);
ec = new CallExp(fs.loc, ec, flde);
ec = ec.expressionSemantic(sc2);
- if (ec.op == TOK.error)
+ if (ec.op == EXP.error)
return null;
if (ec.type != Type.tint32)
{
/* Call:
* aggr(flde)
*/
- if (fs.aggr.op == TOK.delegate_ && (cast(DelegateExp)fs.aggr).func.isNested() &&
+ if (fs.aggr.op == EXP.delegate_ && (cast(DelegateExp)fs.aggr).func.isNested() &&
!(cast(DelegateExp)fs.aggr).func.needThis())
{
// https://issues.dlang.org/show_bug.cgi?id=3560
}
ec = new CallExp(fs.loc, fs.aggr, flde);
ec = ec.expressionSemantic(sc2);
- if (ec.op == TOK.error)
+ if (ec.op == EXP.error)
return null;
if (ec.type != Type.tint32)
{
Expression flde = new FuncExp(fs.loc, fld);
flde = flde.expressionSemantic(sc);
fld.tookAddressOf = 0;
- if (flde.op == TOK.error)
+ if (flde.op == EXP.error)
return null;
return cast(FuncExp)flde;
}
}
fs.prm.type = fs.prm.type.addStorageClass(fs.prm.storageClass);
}
- if (fs.prm.type.ty == Terror || fs.lwr.op == TOK.error || fs.upr.op == TOK.error)
+ if (fs.prm.type.ty == Terror || fs.lwr.op == EXP.error || fs.upr.op == EXP.error)
{
return setError();
}
Expression cond;
if (fs.op == TOK.foreach_reverse_)
{
- cond = new PostExp(TOK.minusMinus, loc, new VarExp(loc, fs.key));
+ cond = new PostExp(EXP.minusMinus, loc, new VarExp(loc, fs.key));
if (fs.prm.type.isscalar())
{
// key-- > tmp
- cond = new CmpExp(TOK.greaterThan, loc, cond, new VarExp(loc, tmp));
+ cond = new CmpExp(EXP.greaterThan, loc, cond, new VarExp(loc, tmp));
}
else
{
// key-- != tmp
- cond = new EqualExp(TOK.notEqual, loc, cond, new VarExp(loc, tmp));
+ cond = new EqualExp(EXP.notEqual, loc, cond, new VarExp(loc, tmp));
}
}
else
if (fs.prm.type.isscalar())
{
// key < tmp
- cond = new CmpExp(TOK.lessThan, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp));
+ cond = new CmpExp(EXP.lessThan, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp));
}
else
{
// key != tmp
- cond = new EqualExp(TOK.notEqual, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp));
+ cond = new EqualExp(EXP.notEqual, loc, new VarExp(loc, fs.key), new VarExp(loc, tmp));
}
}
{
// key += 1
//increment = new AddAssignExp(loc, new VarExp(loc, fs.key), IntegerExp.literal!1);
- increment = new PreExp(TOK.prePlusPlus, loc, new VarExp(loc, fs.key));
+ increment = new PreExp(EXP.prePlusPlus, loc, new VarExp(loc, fs.key));
}
if ((fs.prm.storageClass & STC.ref_) && fs.prm.type.equals(fs.key.type))
{
}
else
{
- if (ifs.condition.op == TOK.dotIdentifier)
+ if (ifs.condition.op == EXP.dotIdentifier)
(cast(DotIdExp)ifs.condition).noderef = true;
ifs.condition = ifs.condition.expressionSemantic(scd);
ctorflow_then.freeFieldinit(); // free extra copy of the data
- if (ifs.condition.op == TOK.error ||
+ if (ifs.condition.op == EXP.error ||
(ifs.ifbody && ifs.ifbody.isErrorStatement()) ||
(ifs.elsebody && ifs.elsebody.isErrorStatement()))
{
// pragma(msg) is allowed to contain types as well as expressions
e = ctfeInterpretForPragmaMsg(e);
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
{
errorSupplemental(ps.loc, "while evaluating `pragma(msg, %s)`", arg.toChars());
return setError();
return setError();
}
- if (e.isBool(true))
+ const opt = e.toBool();
+ if (opt.hasValue(true))
inlining = PINLINE.always;
- else if (e.isBool(false))
+ else if (opt.hasValue(false))
inlining = PINLINE.never;
FuncDeclaration fd = sc.func;
Type att = null;
TypeEnum te = null;
- while (ss.condition.op != TOK.error)
+ while (!ss.condition.isErrorExp())
{
// preserve enum type for final switches
if (ss.condition.type.ty == Tenum)
break;
}
ss.condition = integralPromotions(ss.condition, sc);
- if (ss.condition.op != TOK.error && ss.condition.type.isintegral())
+ if (!ss.condition.isErrorExp() && ss.condition.type.isintegral())
break;
auto ad = isAggregate(ss.condition.type);
}
}
- if (ss.condition.op != TOK.error)
+ if (!ss.condition.isErrorExp())
{
ss.error("`%s` must be of integral or string type, it is a `%s`",
ss.condition.toChars(), ss.condition.type.toChars());
ss.condition = ErrorExp.get();
ss.condition = ss.condition.optimize(WANTvalue);
ss.condition = checkGC(sc, ss.condition);
- if (ss.condition.op == TOK.error)
+ if (ss.condition.op == EXP.error)
conditionError = true;
bool needswitcherror = false;
Expression e = cs.exp;
// Remove all the casts the user and/or implicitCastTo may introduce
// otherwise we'd sometimes fail the check below.
- while (e.op == TOK.cast_)
+ while (e.op == EXP.cast_)
e = (cast(CastExp)e).e1;
/* This is where variables are allowed as case expressions.
*/
- if (e.op == TOK.variable)
+ if (e.op == EXP.variable)
{
VarExp ve = cast(VarExp)e;
VarDeclaration v = ve.var.isVarDeclaration();
if (StringExp se = cs.exp.toStringExp())
cs.exp = se;
- else if (cs.exp.op != TOK.int64 && cs.exp.op != TOK.error)
+ else if (!cs.exp.isIntegerExp() && !cs.exp.isErrorExp())
{
cs.error("`case` must be a `string` or an integral constant, not `%s`", cs.exp.toChars());
errors = true;
result = cs.statement;
return;
}
- if (errors || cs.exp.op == TOK.error)
+ if (errors || cs.exp.op == EXP.error)
return setError();
cs.lastVar = sc.lastVar;
crs.last = crs.last.implicitCastTo(sc, sw.condition.type);
crs.last = crs.last.ctfeInterpret();
- if (crs.first.op == TOK.error || crs.last.op == TOK.error || errors)
+ if (crs.first.op == EXP.error || crs.last.op == EXP.error || errors)
{
if (crs.statement)
crs.statement.statementSemantic(sc);
gcs.exp = gcs.exp.expressionSemantic(sc);
gcs.exp = gcs.exp.implicitCastTo(sc, sc.sw.condition.type);
gcs.exp = gcs.exp.optimize(WANTvalue);
- if (gcs.exp.op == TOK.error)
+ if (gcs.exp.op == EXP.error)
return setError();
}
TypeFunction tf = cast(TypeFunction)fd.type;
assert(tf.ty == Tfunction);
- if (rs.exp && rs.exp.op == TOK.variable && (cast(VarExp)rs.exp).var == fd.vresult)
+ if (rs.exp && rs.exp.op == EXP.variable && (cast(VarExp)rs.exp).var == fd.vresult)
{
// return vresult;
if (sc.fes)
rs.exp.checkSharedAccess(sc, returnSharedRef);
// for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
- if (rs.exp.op == TOK.type)
+ if (rs.exp.op == EXP.type)
rs.exp = resolveAliasThis(sc, rs.exp);
rs.exp = resolveProperties(sc, rs.exp);
// Extract side-effect part
rs.exp = Expression.extractLast(rs.exp, e0);
- if (rs.exp.op == TOK.call)
+ if (rs.exp.op == EXP.call)
rs.exp = valueNoDtor(rs.exp);
if (e0)
else if (m1 && !m2)
{
}
- else if (rs.exp.op != TOK.error)
+ else if (!rs.exp.isErrorExp())
{
rs.error("expected return type of `%s`, not `%s`:",
tret.toChars(),
}
if (e0)
{
- if (e0.op == TOK.declaration || e0.op == TOK.comma)
+ if (e0.op == EXP.declaration || e0.op == EXP.comma)
{
rs.exp = Expression.combine(e0, rs.exp);
}
ss.exp = resolveProperties(sc, ss.exp);
ss.exp = ss.exp.optimize(WANTvalue);
ss.exp = checkGC(sc, ss.exp);
- if (ss.exp.op == TOK.error)
+ if (ss.exp.op == EXP.error)
{
if (ss._body)
ss._body = ss._body.statementSemantic(sc);
ws.exp = resolveProperties(sc, ws.exp);
ws.exp = ws.exp.optimize(WANTvalue);
ws.exp = checkGC(sc, ws.exp);
- if (ws.exp.op == TOK.error)
+ if (ws.exp.op == EXP.error)
return setError();
- if (ws.exp.op == TOK.scope_)
+ if (ws.exp.op == EXP.scope_)
{
sym = new WithScopeSymbol(ws);
sym.parent = sc.scopesym;
sym.endlinnum = ws.endloc.linnum;
}
- else if (ws.exp.op == TOK.type)
+ else if (ws.exp.op == EXP.type)
{
Dsymbol s = (cast(TypeExp)ws.exp).type.toDsymbol(sc);
if (!s || !s.isScopeDsymbol())
FuncDeclaration fd = sc.parent.isFuncDeclaration();
fd.hasReturnExp |= 2;
- if (ts.exp.op == TOK.new_)
+ if (ts.exp.op == EXP.new_)
{
NewExp ne = cast(NewExp)ts.exp;
ne.thrownew = true;
ts.exp = ts.exp.expressionSemantic(sc);
ts.exp = resolveProperties(sc, ts.exp);
ts.exp = checkGC(sc, ts.exp);
- if (ts.exp.op == TOK.error)
+ if (ts.exp.op == EXP.error)
return setError();
checkThrowEscape(sc, ts.exp, false);
{
if (auto es = statement.isExpStatement())
{
- if (es.exp && es.exp.op == TOK.declaration)
+ if (es.exp && es.exp.op == EXP.declaration)
{
auto de = cast(DeclarationExp)es.exp;
auto v = de.declaration.isVarDeclaration();
return statement;
}
-
/*******************
- * See StatementSemanticVisitor.makeTupleForeach. This is a simple
- * wrapper that returns the generated statements/declarations.
+ * Type check and unroll `foreach` over an expression tuple as well
+ * as `static foreach` statements and `static foreach`
+ * declarations. For `static foreach` statements and `static
+ * foreach` declarations, the visitor interface is used (and the
+ * result is written into the `result` field.) For `static
+ * foreach` declarations, the resulting Dsymbols* are returned
+ * directly.
+ *
+ * The unrolled body is wrapped into a
+ * - UnrolledLoopStatement, for `foreach` over an expression tuple.
+ * - ForwardingStatement, for `static foreach` statements.
+ * - ForwardingAttribDeclaration, for `static foreach` declarations.
+ *
+ * `static foreach` variables are declared as `STC.local`, such
+ * that they are inserted into the local symbol tables of the
+ * forwarding constructs instead of forwarded. For `static
+ * foreach` with multiple foreach loop variables whose aggregate
+ * has been lowered into a sequence of tuples, this function
+ * expands the tuples into multiple `STC.local` `static foreach`
+ * variables.
*/
-auto makeTupleForeach(bool isStatic, bool isDecl)(Scope* sc, ForeachStatement fs, Dsymbols* dbody, bool needExpansion)
+public auto makeTupleForeach(Scope* sc, bool isStatic, bool isDecl, ForeachStatement fs, Dsymbols* dbody, bool needExpansion)
{
- scope v = new StatementSemanticVisitor(sc);
- return v.makeTupleForeach!(isStatic, isDecl)(fs, dbody, needExpansion);
+ // Voldemort return type
+ union U
+ {
+ Statement statement;
+ Dsymbols* decl;
+ }
+
+ U result;
+
+ auto returnEarly()
+ {
+ if (isDecl)
+ result.decl = null;
+ else
+ result.statement = new ErrorStatement();
+ return result;
+ }
+
+ auto loc = fs.loc;
+ size_t dim = fs.parameters.dim;
+ const bool skipCheck = isStatic && needExpansion;
+ if (!skipCheck && (dim < 1 || dim > 2))
+ {
+ fs.error("only one (value) or two (key,value) arguments for tuple `foreach`");
+ return returnEarly();
+ }
+
+ Type paramtype = (*fs.parameters)[dim - 1].type;
+ if (paramtype)
+ {
+ paramtype = paramtype.typeSemantic(loc, sc);
+ if (paramtype.ty == Terror)
+ {
+ return returnEarly();
+ }
+ }
+
+ Type tab = fs.aggr.type.toBasetype();
+ TypeTuple tuple = cast(TypeTuple)tab;
+
+ Statements* statements;
+ Dsymbols* declarations;
+ if (isDecl)
+ declarations = new Dsymbols();
+ else
+ statements = new Statements();
+
+ //printf("aggr: op = %d, %s\n", fs.aggr.op, fs.aggr.toChars());
+ size_t n;
+ TupleExp te = null;
+ if (fs.aggr.op == EXP.tuple) // expression tuple
+ {
+ te = cast(TupleExp)fs.aggr;
+ n = te.exps.dim;
+ }
+ else if (fs.aggr.op == EXP.type) // type tuple
+ {
+ n = Parameter.dim(tuple.arguments);
+ }
+ else
+ assert(0);
+ foreach (j; 0 .. n)
+ {
+ size_t k = (fs.op == TOK.foreach_) ? j : n - 1 - j;
+ Expression e = null;
+ Type t = null;
+ if (te)
+ e = (*te.exps)[k];
+ else
+ t = Parameter.getNth(tuple.arguments, k).type;
+ Parameter p = (*fs.parameters)[0];
+
+ Statements* stmts;
+ Dsymbols* decls;
+ if (isDecl)
+ decls = new Dsymbols();
+ else
+ stmts = new Statements();
+
+ const bool skip = isStatic && needExpansion;
+ if (!skip && dim == 2)
+ {
+ // Declare key
+ if (p.storageClass & (STC.out_ | STC.ref_ | STC.lazy_))
+ {
+ fs.error("no storage class for key `%s`", p.ident.toChars());
+ return returnEarly();
+ }
+
+ if (isStatic)
+ {
+ if (!p.type)
+ {
+ p.type = Type.tsize_t;
+ }
+ }
+ p.type = p.type.typeSemantic(loc, sc);
+
+ if (!p.type.isintegral())
+ {
+ fs.error("foreach: key cannot be of non-integral type `%s`",
+ p.type.toChars());
+ return returnEarly();
+ }
+
+ const length = te ? te.exps.length : tuple.arguments.length;
+ IntRange dimrange = IntRange(SignExtendedNumber(length))._cast(Type.tsize_t);
+ // https://issues.dlang.org/show_bug.cgi?id=12504
+ dimrange.imax = SignExtendedNumber(dimrange.imax.value-1);
+ if (!IntRange.fromType(p.type).contains(dimrange))
+ {
+ fs.error("index type `%s` cannot cover index range 0..%llu",
+ p.type.toChars(), cast(ulong)length);
+ return returnEarly();
+ }
+ Initializer ie = new ExpInitializer(Loc.initial, new IntegerExp(k));
+ auto var = new VarDeclaration(loc, p.type, p.ident, ie);
+ var.storage_class |= STC.foreach_ | STC.manifest;
+ if (isStatic)
+ var.storage_class |= STC.local;
+
+ if (isDecl)
+ decls.push(var);
+ else
+ stmts.push(new ExpStatement(loc, var));
+
+ p = (*fs.parameters)[1]; // value
+ }
+ /***********************
+ * Declares a unrolled `foreach` loop variable or a `static foreach` variable.
+ *
+ * Params:
+ * storageClass = The storage class of the variable.
+ * type = The declared type of the variable.
+ * ident = The name of the variable.
+ * e = The initializer of the variable (i.e. the current element of the looped over aggregate).
+ * t = The type of the initializer.
+ * Returns:
+ * `true` iff the declaration was successful.
+ */
+ bool declareVariable(StorageClass storageClass, Type type, Identifier ident, Expression e, Type t)
+ {
+ if (storageClass & (STC.out_ | STC.lazy_) ||
+ storageClass & STC.ref_ && !te)
+ {
+ fs.error("no storage class for value `%s`", ident.toChars());
+ return false;
+ }
+ Declaration var;
+ if (e)
+ {
+ Type tb = e.type.toBasetype();
+ Dsymbol ds = null;
+ if (!(storageClass & STC.manifest))
+ {
+ if ((isStatic || tb.ty == Tfunction || storageClass&STC.alias_) && e.op == EXP.variable)
+ ds = (cast(VarExp)e).var;
+ else if (e.op == EXP.template_)
+ ds = (cast(TemplateExp)e).td;
+ else if (e.op == EXP.scope_)
+ ds = (cast(ScopeExp)e).sds;
+ else if (e.op == EXP.function_)
+ {
+ auto fe = cast(FuncExp)e;
+ ds = fe.td ? cast(Dsymbol)fe.td : fe.fd;
+ }
+ else if (e.op == EXP.overloadSet)
+ ds = (cast(OverExp)e).vars;
+ }
+ else if (storageClass & STC.alias_)
+ {
+ fs.error("`foreach` loop variable cannot be both `enum` and `alias`");
+ return false;
+ }
+
+ if (ds)
+ {
+ var = new AliasDeclaration(loc, ident, ds);
+ if (storageClass & STC.ref_)
+ {
+ fs.error("symbol `%s` cannot be `ref`", ds.toChars());
+ return false;
+ }
+ if (paramtype)
+ {
+ fs.error("cannot specify element type for symbol `%s`", ds.toChars());
+ return false;
+ }
+ }
+ else if (e.op == EXP.type)
+ {
+ var = new AliasDeclaration(loc, ident, e.type);
+ if (paramtype)
+ {
+ fs.error("cannot specify element type for type `%s`", e.type.toChars());
+ return false;
+ }
+ }
+ else
+ {
+ e = resolveProperties(sc, e);
+ Initializer ie = new ExpInitializer(Loc.initial, e);
+ auto v = new VarDeclaration(loc, type, ident, ie, storageClass);
+ v.storage_class |= STC.foreach_;
+ if (storageClass & STC.ref_)
+ v.storage_class |= STC.ref_;
+ if (isStatic || storageClass&STC.manifest || e.isConst() ||
+ e.op == EXP.string_ ||
+ e.op == EXP.structLiteral ||
+ e.op == EXP.arrayLiteral)
+ {
+ if (v.storage_class & STC.ref_)
+ {
+ if (!isStatic)
+ {
+ fs.error("constant value `%s` cannot be `ref`", ie.toChars());
+ }
+ else
+ {
+ if (!needExpansion)
+ {
+ fs.error("constant value `%s` cannot be `ref`", ie.toChars());
+ }
+ else
+ {
+ fs.error("constant value `%s` cannot be `ref`", ident.toChars());
+ }
+ }
+ return false;
+ }
+ else
+ v.storage_class |= STC.manifest;
+ }
+ var = v;
+ }
+ }
+ else
+ {
+ var = new AliasDeclaration(loc, ident, t);
+ if (paramtype)
+ {
+ fs.error("cannot specify element type for symbol `%s`", fs.toChars());
+ return false;
+ }
+ }
+ if (isStatic)
+ {
+ var.storage_class |= STC.local;
+ }
+
+ if (isDecl)
+ decls.push(var);
+ else
+ stmts.push(new ExpStatement(loc, var));
+ return true;
+ }
+
+ if (!isStatic)
+ {
+ // Declare value
+ if (!declareVariable(p.storageClass, p.type, p.ident, e, t))
+ {
+ return returnEarly();
+ }
+ }
+ else
+ {
+ if (!needExpansion)
+ {
+ // Declare value
+ if (!declareVariable(p.storageClass, p.type, p.ident, e, t))
+ {
+ return returnEarly();
+ }
+ }
+ else
+ { // expand tuples into multiple `static foreach` variables.
+ assert(e && !t);
+ auto ident = Identifier.generateId("__value");
+ declareVariable(0, e.type, ident, e, null);
+ import dmd.cond: StaticForeach;
+ auto field = Identifier.idPool(StaticForeach.tupleFieldName.ptr,StaticForeach.tupleFieldName.length);
+ Expression access = new DotIdExp(loc, e, field);
+ access = expressionSemantic(access, sc);
+ if (!tuple) return returnEarly();
+ //printf("%s\n",tuple.toChars());
+ foreach (l; 0 .. dim)
+ {
+ auto cp = (*fs.parameters)[l];
+ Expression init_ = new IndexExp(loc, access, new IntegerExp(loc, l, Type.tsize_t));
+ init_ = init_.expressionSemantic(sc);
+ assert(init_.type);
+ declareVariable(p.storageClass, init_.type, cp.ident, init_, null);
+ }
+ }
+ }
+
+ Statement s;
+ Dsymbol d;
+ if (isDecl)
+ decls.append(Dsymbol.arraySyntaxCopy(dbody));
+ else
+ {
+ if (fs._body) // https://issues.dlang.org/show_bug.cgi?id=17646
+ stmts.push(fs._body.syntaxCopy());
+ s = new CompoundStatement(loc, stmts);
+ }
+
+ if (!isStatic)
+ {
+ s = new ScopeStatement(loc, s, fs.endloc);
+ }
+ else if (isDecl)
+ {
+ import dmd.attrib: ForwardingAttribDeclaration;
+ d = new ForwardingAttribDeclaration(decls);
+ }
+ else
+ {
+ s = new ForwardingStatement(loc, s);
+ }
+
+ if (isDecl)
+ declarations.push(d);
+ else
+ statements.push(s);
+ }
+
+ if (!isStatic)
+ {
+ Statement res = new UnrolledLoopStatement(loc, statements);
+ if (LabelStatement ls = checkLabeledLoop(sc, fs))
+ ls.gotoTarget = res;
+ if (te && te.e0)
+ res = new CompoundStatement(loc, new ExpStatement(te.e0.loc, te.e0), res);
+ result.statement = res;
+ }
+ else if (isDecl)
+ result.decl = declarations;
+ else
+ result.statement = new CompoundStatement(loc, statements);
+
+ return result;
}
/*********************************
* expand template mixin in statement scope
* to handle variable destructors.
*/
- if (!es.exp || es.exp.op != TOK.declaration)
+ if (!es.exp || !es.exp.isDeclarationExp())
return null;
- Dsymbol d = (cast(DeclarationExp)es.exp).declaration;
+ Dsymbol d = es.exp.isDeclarationExp().declaration;
auto tm = d.isTemplateMixin();
if (!tm)
return null;
Expression e = es.exp.expressionSemantic(sc);
- if (e.op == TOK.error || tm.errors)
+ if (e.op == EXP.error || tm.errors)
return errorStatements();
assert(tm.members);
sfs.sfe.prepare(sc);
if (sfs.sfe.ready())
{
- Statement s = makeTupleForeach!(true, false)(sc, sfs.sfe.aggrfe, null, sfs.sfe.needExpansion).statement;
+ Statement s = makeTupleForeach(sc, true, false, sfs.sfe.aggrfe, null, sfs.sfe.needExpansion).statement;
auto result = s.flatten(sc);
if (result)
{
bool impl(Expression e)
{
- if (e.op == TOK.not)
+ if (e.isNotExp())
{
NotExp ne = cast(NotExp)e;
return !impl(ne.e1);
}
- if (e.op == TOK.andAnd || e.op == TOK.orOr)
+ if (e.op == EXP.andAnd || e.op == EXP.orOr)
{
LogicalExp aae = cast(LogicalExp)e;
bool result = impl(aae.e1);
if (errors)
return false;
- if (e.op == TOK.andAnd)
+ if (e.op == EXP.andAnd)
{
if (!result)
return false;
return !errors && result;
}
- if (e.op == TOK.question)
+ if (e.op == EXP.question)
{
CondExp ce = cast(CondExp)e;
bool result = impl(ce.econd);
e = e.optimize(WANTvalue);
if (nerrors != global.errors ||
- e.op == TOK.error ||
+ e.isErrorExp() ||
e.type.toBasetype() == Type.terror)
{
errors = true;
e = e.ctfeInterpret();
- if (e.isBool(true))
+ const opt = e.toBool();
+ if (opt.hasValue(true))
return true;
- else if (e.isBool(false))
+ else if (opt.hasValue(false))
{
if (negatives)
negatives.push(before);
// returns true if satisfied
bool impl(Expression orig, Expression e, bool inverted, bool orOperand, bool unreached)
{
- TOK op = orig.op;
+ EXP op = orig.op;
// lower all 'not' to the bottom
// !(A && B) -> !A || !B
// !(A || B) -> !A && !B
if (inverted)
{
- if (op == TOK.andAnd)
- op = TOK.orOr;
- else if (op == TOK.orOr)
- op = TOK.andAnd;
+ if (op == EXP.andAnd)
+ op = EXP.orOr;
+ else if (op == EXP.orOr)
+ op = EXP.andAnd;
}
- if (op == TOK.not)
+ if (op == EXP.not)
{
NotExp no = cast(NotExp)orig;
NotExp ne = cast(NotExp)e;
assert(ne);
return impl(no.e1, ne.e1, !inverted, orOperand, unreached);
}
- else if (op == TOK.andAnd)
+ else if (op == EXP.andAnd)
{
BinExp bo = cast(BinExp)orig;
BinExp be = cast(BinExp)e;
const r2 = impl(bo.e2, be.e2, inverted, false, unreached || !r1);
return r1 && r2;
}
- else if (op == TOK.orOr)
+ else if (op == EXP.orOr)
{
if (!orOperand) // do not indent A || B || C twice
indent++;
indent--;
return r1 || r2;
}
- else if (op == TOK.question)
+ else if (op == EXP.question)
{
CondExp co = cast(CondExp)orig;
CondExp ce = cast(CondExp)e;
bool impl(Expression orig, Expression e, bool inverted)
{
- TOK op = orig.op;
+ EXP op = orig.op;
if (inverted)
{
- if (op == TOK.andAnd)
- op = TOK.orOr;
- else if (op == TOK.orOr)
- op = TOK.andAnd;
+ if (op == EXP.andAnd)
+ op = EXP.orOr;
+ else if (op == EXP.orOr)
+ op = EXP.andAnd;
}
- if (op == TOK.not)
+ if (op == EXP.not)
{
NotExp no = cast(NotExp)orig;
NotExp ne = cast(NotExp)e;
assert(ne);
return impl(no.e1, ne.e1, !inverted);
}
- else if (op == TOK.andAnd)
+ else if (op == EXP.andAnd)
{
BinExp bo = cast(BinExp)orig;
BinExp be = cast(BinExp)e;
r = r && impl(bo.e2, be.e2, inverted);
return r;
}
- else if (op == TOK.orOr)
+ else if (op == EXP.orOr)
{
BinExp bo = cast(BinExp)orig;
BinExp be = cast(BinExp)e;
stack.setDim(lbefore); // purge added positive items
return r;
}
- else if (op == TOK.question)
+ else if (op == EXP.question)
{
CondExp co = cast(CondExp)orig;
CondExp ce = cast(CondExp)e;
import dmd.globals : Param;
-enum CPU
+enum CPU : ubyte
{
x87,
mmx,
import dmd.mtype : Type, TypeFunction, TypeTuple;
import dmd.root.ctfloat : real_t;
import dmd.statement : Statement;
+ import dmd.tokens : EXP;
/// Bit decoding of the Target.OS
enum OS : ubyte
* Returns:
* true if the operation is supported or type is not a vector
*/
- extern (C++) bool isVectorOpSupported(Type type, uint op, Type t2 = null);
+ extern (C++) bool isVectorOpSupported(Type type, EXP op, Type t2 = null);
/**
* Default system linkage for the target.
class TypeTuple;
class TypeFunction;
-enum class CPU
+enum class CPU : unsigned char
{
x87,
mmx,
unsigned fieldalign(Type *type);
Type *va_listType(const Loc &loc, Scope *sc); // get type of va_list
int isVectorTypeSupported(int sz, Type *type);
- bool isVectorOpSupported(Type *type, unsigned op, Type *t2 = NULL);
+ bool isVectorOpSupported(Type *type, EXP op, Type *t2 = NULL);
// ABI and backend.
LINK systemLinkage();
TypeTuple *toArgTypes(Type *t);
sc = sc.endCTFE();
e = e.implicitCastTo(sc, tvp.valType);
e = e.ctfeInterpret();
- if (e.op == TOK.int64 || e.op == TOK.float64 ||
- e.op == TOK.complex80 || e.op == TOK.null_ || e.op == TOK.string_)
+ if (e.op == EXP.int64 || e.op == EXP.float64 ||
+ e.op == EXP.complex80 || e.op == EXP.null_ || e.op == EXP.string_)
tvp.specValue = e;
}
sc = sc.endCTFE();
e = e.implicitCastTo(sc, tvp.valType);
e = e.ctfeInterpret();
- if (e.op == TOK.int64)
+ if (e.op == EXP.int64)
tvp.defaultValue = e;
}
}
__attribute__,
}
+/// Expression nodes
+enum EXP : ubyte
+{
+ reserved,
+
+ // Other
+ negate,
+ cast_,
+ null_,
+ assert_,
+ true_,
+ false_,
+ array,
+ call,
+ address,
+ type,
+ throw_,
+ new_,
+ delete_,
+ star,
+ symbolOffset,
+ variable,
+ dotVariable,
+ dotIdentifier,
+ dotTemplateInstance,
+ dotType,
+ slice,
+ arrayLength,
+ version_,
+ dollar,
+ template_,
+ dotTemplateDeclaration,
+ declaration,
+ typeof_,
+ pragma_,
+ dSymbol,
+ typeid_,
+ uadd,
+ remove,
+ newAnonymousClass,
+ arrayLiteral,
+ assocArrayLiteral,
+ structLiteral,
+ classReference,
+ thrownException,
+ delegatePointer,
+ delegateFunctionPointer,
+
+ // Operators
+ lessThan,
+ greaterThan,
+ lessOrEqual,
+ greaterOrEqual,
+ equal,
+ notEqual,
+ identity,
+ notIdentity,
+ index,
+ is_,
+
+ leftShift,
+ rightShift,
+ leftShiftAssign,
+ rightShiftAssign,
+ unsignedRightShift,
+ unsignedRightShiftAssign,
+ concatenate,
+ concatenateAssign, // ~=
+ concatenateElemAssign,
+ concatenateDcharAssign,
+ add,
+ min,
+ addAssign,
+ minAssign,
+ mul,
+ div,
+ mod,
+ mulAssign,
+ divAssign,
+ modAssign,
+ and,
+ or,
+ xor,
+ andAssign,
+ orAssign,
+ xorAssign,
+ assign,
+ not,
+ tilde,
+ plusPlus,
+ minusMinus,
+ construct,
+ blit,
+ dot,
+ comma,
+ question,
+ andAnd,
+ orOr,
+ prePlusPlus,
+ preMinusMinus,
+
+ // Leaf operators
+ identifier,
+ string_,
+ this_,
+ super_,
+ halt,
+ tuple,
+ error,
+
+ // Basic types
+ void_,
+ int64,
+ float64,
+ complex80,
+ char_,
+ import_,
+ delegate_,
+ function_,
+ mixin_,
+ in_,
+ default_,
+ break_,
+ continue_,
+ goto_,
+ scope_,
+
+ traits,
+ overloadSet,
+ line,
+ file,
+ fileFullPath,
+ moduleString, // __MODULE__
+ functionString, // __FUNCTION__
+ prettyFunction, // __PRETTY_FUNCTION__
+ shared_,
+ pow,
+ powAssign,
+ vector,
+
+ voidExpression,
+ cantExpression,
+ showCtfeContext,
+ objcClassReference,
+ vectorArray,
+ arrow, // ->
+ compoundLiteral, // ( type-name ) { initializer-list }
+ _Generic,
+ interval,
+}
+
enum FirstCKeyword = TOK.inline;
// Assert that all token enum members have consecutive values and
return p;
}
- static const(char)* toChars(uint value)
+ static const(char)* toChars(TOK value)
{
return toString(value).ptr;
}
- extern (D) static string toString(uint value) pure nothrow @nogc @safe
+ static const(char)* toChars(ushort value)
+ {
+ return toString(cast(TOK)value).ptr;
+ }
+
+ extern (D) static string toString(TOK value) pure nothrow @nogc @safe
{
return tochars[value];
}
? && ||
*/
-typedef unsigned short TOK;
-enum
+enum class TOK : unsigned short
{
- TOKreserved,
-
- // Other
- TOKlparen, TOKrparen,
- TOKlbracket, TOKrbracket,
- TOKlcurly, TOKrcurly,
- TOKcolon, TOKneg,
- TOKsemicolon, TOKdotdotdot,
- TOKeof, TOKcast,
- TOKnull, TOKassert,
- TOKtrue, TOKfalse,
- TOKarray, TOKcall,
- TOKaddress,
- TOKtype, TOKthrow,
- TOKnew, TOKdelete,
- TOKstar, TOKsymoff,
- TOKvar, TOKdotvar,
- TOKdotid, TOKdotti,
- TOKdottype, TOKslice,
- TOKarraylength, TOKversion,
- TOKmodule, TOKdollar,
- TOKtemplate, TOKdottd,
- TOKdeclaration, TOKtypeof,
- TOKpragma, TOKdsymbol,
- TOKtypeid, TOKuadd,
- TOKremove,
- TOKnewanonclass, TOKcomment,
- TOKarrayliteral, TOKassocarrayliteral,
- TOKstructliteral,
- TOKclassreference,
- TOKthrownexception,
- TOKdelegateptr,
- TOKdelegatefuncptr,
-
-// 54
- // Operators
- TOKlt, TOKgt,
- TOKle, TOKge,
- TOKequal, TOKnotequal,
- TOKidentity, TOKnotidentity,
- TOKindex, TOKis,
-
-// 64
- TOKshl, TOKshr,
- TOKshlass, TOKshrass,
- TOKushr, TOKushrass,
- TOKcat, TOKcatass, TOKcatelemass, TOKcatdcharass, // ~ ~=
- TOKadd, TOKmin, TOKaddass, TOKminass,
- TOKmul, TOKdiv, TOKmod,
- TOKmulass, TOKdivass, TOKmodass,
- TOKand, TOKor, TOKxor,
- TOKandass, TOKorass, TOKxorass,
- TOKassign, TOKnot, TOKtilde,
- TOKplusplus, TOKminusminus, TOKconstruct, TOKblit,
- TOKdot, TOKcomma,
- TOKquestion, TOKandand, TOKoror,
- TOKpreplusplus, TOKpreminusminus,
-
-// 105
- // Numeric literals
- TOKint32v, TOKuns32v,
- TOKint64v, TOKuns64v,
- TOKint128v, TOKuns128v,
- TOKfloat32v, TOKfloat64v, TOKfloat80v,
- TOKimaginary32v, TOKimaginary64v, TOKimaginary80v,
-
- // Char constants
- TOKcharv, TOKwcharv, TOKdcharv,
-
- // Leaf operators
- TOKidentifier, TOKstring, TOKxstring,
- TOKthis, TOKsuper,
- TOKhalt, TOKtuple,
- TOKerror,
-
- // Basic types
- TOKvoid,
- TOKint8, TOKuns8,
- TOKint16, TOKuns16,
- TOKint32, TOKuns32,
- TOKint64, TOKuns64,
- TOKint128, TOKuns128,
- TOKfloat32, TOKfloat64, TOKfloat80,
- TOKimaginary32, TOKimaginary64, TOKimaginary80,
- TOKcomplex32, TOKcomplex64, TOKcomplex80,
- TOKchar, TOKwchar, TOKdchar, TOKbool,
-
-// 152
- // Aggregates
- TOKstruct, TOKclass, TOKinterface, TOKunion, TOKenum, TOKimport,
- TOKalias, TOKoverride, TOKdelegate, TOKfunction,
- TOKmixin,
-
- TOKalign, TOKextern, TOKprivate, TOKprotected, TOKpublic, TOKexport,
- TOKstatic, TOKfinal, TOKconst, TOKabstract,
- TOKdebug, TOKdeprecated, TOKin, TOKout, TOKinout, TOKlazy,
- TOKauto, TOKpackage, TOKimmutable,
-
-// 182
- // Statements
- TOKif, TOKelse, TOKwhile, TOKfor, TOKdo, TOKswitch,
- TOKcase, TOKdefault, TOKbreak, TOKcontinue, TOKwith,
- TOKsynchronized, TOKreturn, TOKgoto, TOKtry, TOKcatch, TOKfinally,
- TOKasm, TOKforeach, TOKforeach_reverse,
- TOKscope,
- TOKon_scope_exit, TOKon_scope_failure, TOKon_scope_success,
-
-// 206
- // Contracts
- TOKinvariant,
-
- // Testing
- TOKunittest,
-
- // Added after 1.0
- TOKargTypes,
- TOKref,
- TOKmacro,
-
-// 211
- TOKparameters,
- TOKtraits,
- TOKoverloadset,
- TOKpure,
- TOKnothrow,
- TOKgshared,
- TOKline,
- TOKfile,
- TOKfilefullpath,
- TOKmodulestring,
- TOKfuncstring,
- TOKprettyfunc,
- TOKshared,
- TOKat,
- TOKpow,
- TOKpowass,
- TOKgoesto,
- TOKvector,
- TOKpound,
-
-// 230
- TOKinterval,
- TOKvoidexp,
- TOKcantexp,
- TOKshowctfecontext,
-
- TOKobjc_class_reference,
- TOKvectorarray,
-
- TOKarrow,
- TOKcolonColon,
- TOKwchar_tLiteral,
- TOKcompoundLiteral,
-
- TOKinline,
- TOKregister,
- TOKrestrict,
- TOKsigned,
- TOKsizeof_,
- TOKtypedef_,
- TOKunsigned,
- TOKvolatile,
- TOK_Alignas,
- TOK_Alignof,
- TOK_Atomic,
- TOK_Bool,
- TOK_Complex,
- TOK_Generic,
- TOK_Imaginary,
- TOK_Noreturn,
- TOK_Static_assert,
- TOK_Thread_local,
-
- TOK__cdecl,
- TOK__declspec,
- TOK__attribute__,
-
- TOKMAX
+ reserved,
+
+ // Other
+ leftParenthesis,
+ rightParenthesis,
+ leftBracket,
+ rightBracket,
+ leftCurly,
+ rightCurly,
+ colon,
+ negate,
+ semicolon,
+ dotDotDot,
+ endOfFile,
+ cast_,
+ null_,
+ assert_,
+ true_,
+ false_,
+ array,
+ call,
+ address,
+ type,
+ throw_,
+ new_,
+ delete_,
+ star,
+ symbolOffset,
+ variable,
+ dotVariable,
+ dotIdentifier,
+ dotTemplateInstance,
+ dotType,
+ slice,
+ arrayLength,
+ version_,
+ module_,
+ dollar,
+ template_,
+ dotTemplateDeclaration,
+ declaration,
+ typeof_,
+ pragma_,
+ dSymbol,
+ typeid_,
+ uadd,
+ remove,
+ newAnonymousClass,
+ comment,
+ arrayLiteral,
+ assocArrayLiteral,
+ structLiteral,
+ classReference,
+ thrownException,
+ delegatePointer,
+ delegateFunctionPointer,
+
+ // Operators
+ lessThan, // 54
+ greaterThan,
+ lessOrEqual,
+ greaterOrEqual,
+ equal,
+ notEqual,
+ identity,
+ notIdentity,
+ index,
+ is_,
+
+ leftShift, // 64
+ rightShift,
+ leftShiftAssign,
+ rightShiftAssign,
+ unsignedRightShift,
+ unsignedRightShiftAssign,
+ concatenate,
+ concatenateAssign, // ~=
+ concatenateElemAssign,
+ concatenateDcharAssign,
+ add,
+ min,
+ addAssign,
+ minAssign,
+ mul,
+ div,
+ mod,
+ mulAssign,
+ divAssign,
+ modAssign,
+ and_,
+ or_,
+ xor_,
+ andAssign,
+ orAssign,
+ xorAssign,
+ assign,
+ not_,
+ tilde,
+ plusPlus,
+ minusMinus,
+ construct,
+ blit,
+ dot,
+ comma,
+ question,
+ andAnd,
+ orOr,
+ prePlusPlus,
+ preMinusMinus,
+
+ // Numeric literals
+ int32Literal, // 104,
+ uns32Literal,
+ int64Literal,
+ uns64Literal,
+ int128Literal,
+ uns128Literal,
+ float32Literal,
+ float64Literal,
+ float80Literal,
+ imaginary32Literal,
+ imaginary64Literal,
+ imaginary80Literal,
+
+ // Char constants
+ charLiteral, // 116,
+ wcharLiteral,
+ dcharLiteral,
+
+ // Leaf operators
+ identifier, // 119,
+ string_,
+ hexadecimalString,
+ this_,
+ super_,
+ halt,
+ tuple,
+ error,
+
+ // Basic types
+ void_, // 127
+ int8,
+ uns8,
+ int16,
+ uns16,
+ int32,
+ uns32,
+ int64,
+ uns64,
+ int128,
+ uns128,
+ float32,
+ float64,
+ float80,
+ imaginary32,
+ imaginary64,
+ imaginary80,
+ complex32,
+ complex64,
+ complex80,
+ char_,
+ wchar_,
+ dchar_,
+ bool_,
+
+ // Aggregates
+ struct_, // 151
+ class_,
+ interface_,
+ union_,
+ enum_,
+ import_,
+ alias_,
+ override_,
+ delegate_,
+ function_,
+ mixin_,
+ align_,
+ extern_,
+ private_,
+ protected_,
+ public_,
+ export_,
+ static_,
+ final_,
+ const_,
+ abstract_,
+ debug_,
+ deprecated_,
+ in_,
+ out_,
+ inout_,
+ lazy_,
+ auto_,
+ package_,
+ immutable_,
+
+ // Statements
+ if_, // 181
+ else_,
+ while_,
+ for_,
+ do_,
+ switch_,
+ case_,
+ default_,
+ break_,
+ continue_,
+ with_,
+ synchronized_,
+ return_,
+ goto_,
+ try_,
+ catch_,
+ finally_,
+ asm_,
+ foreach_,
+ foreach_reverse_,
+ scope_,
+ onScopeExit,
+ onScopeFailure,
+ onScopeSuccess,
+
+ // Contracts
+ invariant_, // 205
+
+ // Testing
+ unittest_,
+
+ // Added after 1.0
+ argumentTypes,
+ ref_,
+ macro_,
+
+ parameters, // 210
+ traits,
+ overloadSet,
+ pure_,
+ nothrow_,
+ gshared,
+ line,
+ file,
+ fileFullPath,
+ moduleString, // __MODULE__
+ functionString, // __FUNCTION__
+ prettyFunction, // __PRETTY_FUNCTION__
+ shared_,
+ at,
+ pow,
+ powAssign,
+ goesTo,
+ vector,
+ pound,
+
+ interval, // 229
+ voidExpression,
+ cantExpression,
+ showCtfeContext,
+
+ objcClassReference,
+ vectorArray,
+
+ arrow, // ->
+ colonColon, // ::
+ wchar_tLiteral,
+ compoundLiteral, // ( type-name ) { initializer-list }
+
+ // C only keywords
+ inline_,
+ register_,
+ restrict_,
+ signed_,
+ sizeof_,
+ typedef_,
+ unsigned_,
+ volatile_,
+ _Alignas_,
+ _Alignof_,
+ _Atomic_,
+ _Bool_,
+ _Complex_,
+ _Generic_,
+ _Imaginary_,
+ _Noreturn_,
+ _Static_assert_,
+ _Thread_local_,
+
+ // C only extended keywords
+ cdecl,
+ declspec,
+ attribute__,
+
+ MAX,
+};
+
+enum class EXP : unsigned char
+{
+ reserved,
+
+ // Other
+ negate,
+ cast_,
+ null_,
+ assert_,
+ true_,
+ false_,
+ array,
+ call,
+ address,
+ type,
+ throw_,
+ new_,
+ delete_,
+ star,
+ symbolOffset,
+ variable,
+ dotVariable,
+ dotIdentifier,
+ dotTemplateInstance,
+ dotType,
+ slice,
+ arrayLength,
+ version_,
+ dollar,
+ template_,
+ dotTemplateDeclaration,
+ declaration,
+ typeof_,
+ pragma_,
+ dSymbol,
+ typeid_,
+ uadd,
+ remove,
+ newAnonymousClass,
+ arrayLiteral,
+ assocArrayLiteral,
+ structLiteral,
+ classReference,
+ thrownException,
+ delegatePointer,
+ delegateFunctionPointer,
+
+ // Operators
+ lessThan,
+ greaterThan,
+ lessOrEqual,
+ greaterOrEqual,
+ equal,
+ notEqual,
+ identity,
+ notIdentity,
+ index,
+ is_,
+
+ leftShift,
+ rightShift,
+ leftShiftAssign,
+ rightShiftAssign,
+ unsignedRightShift,
+ unsignedRightShiftAssign,
+ concatenate,
+ concatenateAssign, // ~=
+ concatenateElemAssign,
+ concatenateDcharAssign,
+ add,
+ min,
+ addAssign,
+ minAssign,
+ mul,
+ div,
+ mod,
+ mulAssign,
+ divAssign,
+ modAssign,
+ and_,
+ or_,
+ xor_,
+ andAssign,
+ orAssign,
+ xorAssign,
+ assign,
+ not_,
+ tilde,
+ plusPlus,
+ minusMinus,
+ construct,
+ blit,
+ dot,
+ comma,
+ question,
+ andAnd,
+ orOr,
+ prePlusPlus,
+ preMinusMinus,
+
+ // Leaf operators
+ identifier,
+ string_,
+ this_,
+ super_,
+ halt,
+ tuple,
+ error,
+
+ // Basic types
+ void_,
+ int64,
+ float64,
+ complex80,
+ char_,
+ import_,
+ delegate_,
+ function_,
+ mixin_,
+ in_,
+ default_,
+ break_,
+ continue_,
+ goto_,
+ scope_,
+
+ traits,
+ overloadSet,
+ line,
+ file,
+ fileFullPath,
+ moduleString, // __MODULE__
+ functionString, // __FUNCTION__
+ prettyFunction, // __PRETTY_FUNCTION__
+ shared_,
+ pow,
+ powAssign,
+ vector,
+
+ voidExpression,
+ cantExpression,
+ showCtfeContext,
+ objcClassReference,
+ vectorArray,
+ arrow, // ->
+ compoundLiteral, // ( type-name ) { initializer-list }
+ _Generic_,
+ interval,
+
+ MAX
};
#define TOKwild TOKinout
int isKeyword();
const char *toChars() const;
- static const char *toChars(unsigned value);
+ static const char *toChars(TOK value);
};
#if defined(__GNUC__)
{
if (auto e = isExpression(oarg))
{
- if (e.op == TOK.dotVariable)
+ if (e.op == EXP.dotVariable)
return (cast(DotVarExp)e).var;
- if (e.op == TOK.dotTemplateDeclaration)
+ if (e.op == EXP.dotTemplateDeclaration)
return (cast(DotTemplateExp)e).td;
}
return getDsymbol(oarg);
{
if (global.params.vcomplex)
{
- if (isTypeX(t => t.iscomplex() || t.isimaginary()).isBool(true))
+ if (isTypeX(t => t.iscomplex() || t.isimaginary()).toBool().hasValue(true))
return True();
}
return isDsymX(t => t.isDeprecated());
e.error("`bool` expected as third argument of `__traits(getOverloads)`, not `%s` of type `%s`", b.toChars(), b.type.toChars());
return ErrorExp.get();
}
- includeTemplates = b.isBool(true);
+ includeTemplates = b.toBool().hasValue(true);
}
StringExp se = ex.toStringExp();
}
else if (e.ident == Id.getMember)
{
- if (ex.op == TOK.dotIdentifier)
+ if (ex.op == EXP.dotIdentifier)
// Prevent semantic() from replacing Symbol with its initializer
(cast(DotIdExp)ex).wantsym = true;
ex = ex.expressionSemantic(scx);
{
if (dve.var.isFuncDeclaration() || dve.var.isOverDeclaration())
f = dve.var;
- if (dve.e1.op == TOK.dotType || dve.e1.op == TOK.this_)
+ if (dve.e1.op == EXP.dotType || dve.e1.op == EXP.this_)
ex = null;
else
ex = dve.e1;
if (td && td.funcroot)
f = td.funcroot;
ex = null;
- if (dte.e1.op != TOK.dotType && dte.e1.op != TOK.this_)
+ if (dte.e1.op != EXP.dotType && dte.e1.op != EXP.this_)
ex = dte.e1;
}
bool[string] funcTypeHash;
Expression x = isExpression(o);
Type t = isType(o);
if (x)
- printf("e = %s %s\n", Token.toChars(x.op), x.toChars());
+ printf("e = %s %s\n", EXPtoString(x.op).ptr, x.toChars());
if (t)
printf("t = %d %s\n", t.ty, t.toChars());
}
err |= tf.isnothrow && canThrow(ex, sc2.func, false);
}
ex = checkGC(sc2, ex);
- if (ex.op == TOK.error)
+ if (ex.op == EXP.error)
err = true;
}
}
{
return pointerBitmap(e);
}
+ if (e.ident == Id.initSymbol)
+ {
+ if (dim != 1)
+ return dimError(1);
+
+ auto o = (*e.args)[0];
+ Type t = isType(o);
+ AggregateDeclaration ad = t ? isAggregate(t) : null;
+
+ // Interfaces don't have an init symbol and hence cause linker errors
+ if (!ad || ad.isInterfaceDeclaration())
+ {
+ e.error("struct / class type expected as argument to __traits(initSymbol) instead of `%s`", o.toChars());
+ return ErrorExp.get();
+ }
+
+ Declaration d = new SymbolDeclaration(ad.loc, ad);
+ d.type = Type.tvoid.arrayOf().constOf();
+ d.storage_class |= STC.rvalue;
+ return new VarExp(e.loc, d);
+ }
if (e.ident == Id.isZeroInit)
{
if (dim != 1)
}
else if (auto ea = isExpression(oarg))
{
- if (ea.op == TOK.function_)
+ if (ea.op == EXP.function_)
{
if (auto fe = cast(FuncExp)ea)
return fe.fd;
eindex = semanticLength(sc, tup, eindex);
eindex = eindex.ctfeInterpret();
- if (eindex.op == TOK.error)
+ if (eindex.op == EXP.error)
{
pt = Type.terror;
return;
* enum a = 1; alias b = a;
* template X(alias e){ alias v = e; } alias x = X!(1);
* struct S { int v; alias w = v; }
- * // TypeIdentifier 'a', 'e', and 'v' should be TOK.variable,
+ * // TypeIdentifier 'a', 'e', and 'v' should be EXP.variable,
* // because getDsymbol() need to work in AliasDeclaration::semantic().
*/
if (!v.type ||
*/
Expression typeToExpressionHelper(TypeQualified t, Expression e, size_t i = 0)
{
- //printf("toExpressionHelper(e = %s %s)\n", Token.toChars(e.op), e.toChars());
+ //printf("toExpressionHelper(e = %s %s)\n", EXPtoString(e.op).ptr, e.toChars());
foreach (id; t.idents[i .. t.idents.dim])
{
//printf("\t[%d] e: '%s', id: '%s'\n", i, e.toChars(), id.toChars());
{
mtype.dim = semanticLength(sc, tup, mtype.dim);
mtype.dim = mtype.dim.ctfeInterpret();
- if (mtype.dim.op == TOK.error)
+ if (mtype.dim.op == EXP.error)
return error();
uinteger_t d = mtype.dim.toUInteger();
mtype.dim = mtype.dim.optimize(WANTvalue);
mtype.dim = mtype.dim.ctfeInterpret();
- if (mtype.dim.op == TOK.error)
+ if (mtype.dim.op == EXP.error)
return error();
errors = global.errors;
mtype.dim = mtype.dim.implicitCastTo(sc, Type.tsize_t);
mtype.dim = mtype.dim.optimize(WANTvalue);
- if (mtype.dim.op == TOK.error)
+ if (mtype.dim.op == EXP.error)
return error();
errors = global.errors;
if (errors != global.errors)
return error();
- if (mtype.dim.op == TOK.error)
+ if (mtype.dim.op == EXP.error)
return error();
Type overflowError()
iz = iz.initializerSemantic(sc, fparam.type, INITnointerpret);
e = iz.initializerToExpression();
}
- if (e.op == TOK.function_) // https://issues.dlang.org/show_bug.cgi?id=4820
+ if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820
{
FuncExp fe = cast(FuncExp)e;
// Replace function literal with a function symbol,
e = e.toLvalue(sc, e);
fparam.defaultArg = e;
- return (e.op != TOK.error);
+ return (e.op != EXP.error);
}
ubyte wildparams = 0;
.error(loc, "%s `%s` is used as a type", s.kind, s.toPrettyChars);
//assert(0);
}
- else if (e.op == TOK.variable) // special case: variable is used as a type
+ else if (e.op == EXP.variable) // special case: variable is used as a type
{
Dsymbol varDecl = mtype.toDsymbol(sc);
const(Loc) varDeclLoc = varDecl.getLoc();
{
switch (e.op)
{
- case TOK.dotVariable:
+ case EXP.dotVariable:
mtype.sym = (cast(DotVarExp)e).var;
break;
- case TOK.variable:
+ case EXP.variable:
mtype.sym = (cast(VarExp)e).var;
break;
- case TOK.function_:
+ case EXP.function_:
auto fe = cast(FuncExp)e;
mtype.sym = fe.td ? fe.td : fe.fd;
break;
- case TOK.dotTemplateDeclaration:
+ case EXP.dotTemplateDeclaration:
mtype.sym = (cast(DotTemplateExp)e).td;
break;
- case TOK.dSymbol:
+ case EXP.dSymbol:
mtype.sym = (cast(DsymbolExp)e).s;
break;
- case TOK.template_:
+ case EXP.template_:
mtype.sym = (cast(TemplateExp)e).td;
break;
- case TOK.scope_:
+ case EXP.scope_:
mtype.sym = (cast(ScopeExp)e).sds;
break;
- case TOK.tuple:
+ case EXP.tuple:
TupleExp te = e.toTupleExp();
Objects* elems = new Objects(te.exps.dim);
foreach (i; 0 .. elems.dim)
auto src = (*te.exps)[i];
switch (src.op)
{
- case TOK.type:
+ case EXP.type:
(*elems)[i] = (cast(TypeExp)src).type;
break;
- case TOK.dotType:
+ case EXP.dotType:
(*elems)[i] = (cast(DotTypeExp)src).sym.isType();
break;
- case TOK.overloadSet:
+ case EXP.overloadSet:
(*elems)[i] = (cast(OverExp)src).type;
break;
default:
TupleDeclaration td = new TupleDeclaration(e.loc, Identifier.generateId("__aliastup"), elems);
mtype.sym = td;
break;
- case TOK.dotType:
+ case EXP.dotType:
result = (cast(DotTypeExp)e).sym.isType();
break;
- case TOK.type:
+ case EXP.type:
result = (cast(TypeExp)e).type;
break;
- case TOK.overloadSet:
+ case EXP.overloadSet:
result = (cast(OverExp)e).type;
break;
default:
mtype.upr = semanticLength(sc, tbn, mtype.upr);
mtype.lwr = mtype.lwr.ctfeInterpret();
mtype.upr = mtype.upr.ctfeInterpret();
- if (mtype.lwr.op == TOK.error || mtype.upr.op == TOK.error)
+ if (mtype.lwr.op == EXP.error || mtype.upr.op == EXP.error)
return error();
uinteger_t i1 = mtype.lwr.toUInteger();
{
mt.dim = semanticLength(sc, tup, mt.dim);
mt.dim = mt.dim.ctfeInterpret();
- if (mt.dim.op == TOK.error)
+ if (mt.dim.op == EXP.error)
return returnError();
const d = mt.dim.toUInteger();
if (o.dyncast() == DYNCAST.expression)
{
Expression e = cast(Expression)o;
- if (e.op == TOK.dSymbol)
+ if (e.op == EXP.dSymbol)
return returnSymbol((cast(DsymbolExp)e).s);
else
return returnExp(e);
exp2 = resolvePropertiesOnly(sc2, exp2);
sc2.pop();
- if (exp2.op == TOK.error)
+ if (exp2.op == EXP.error)
{
if (!global.gag)
mt.exp = exp2;
}
mt.exp = exp2;
- if (mt.exp.op == TOK.type ||
- mt.exp.op == TOK.scope_)
+ if (mt.exp.op == EXP.type ||
+ mt.exp.op == EXP.scope_)
{
if (mt.exp.checkType())
goto Lerr;
* template functions.
*/
}
- if (auto f = mt.exp.op == TOK.variable ? (cast( VarExp)mt.exp).var.isFuncDeclaration()
- : mt.exp.op == TOK.dotVariable ? (cast(DotVarExp)mt.exp).var.isFuncDeclaration() : null)
+ if (auto f = mt.exp.op == EXP.variable ? (cast( VarExp)mt.exp).var.isFuncDeclaration()
+ : mt.exp.op == EXP.dotVariable ? (cast(DotVarExp)mt.exp).var.isFuncDeclaration() : null)
{
// f might be a unittest declaration which is incomplete when compiled
// without -unittest. That causes a segfault in checkForwardRef, see
printf("Type::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
}
Expression ex = e.lastComma();
- if (ex.op == TOK.dotVariable)
+ if (ex.op == EXP.dotVariable)
{
DotVarExp dv = cast(DotVarExp)ex;
v = dv.var.isVarDeclaration();
}
- else if (ex.op == TOK.variable)
+ else if (ex.op == EXP.variable)
{
VarExp ve = cast(VarExp)ex;
v = ve.var.isVarDeclaration();
{
printf("TypeVector::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
}
- if (ident == Id.ptr && e.op == TOK.call)
+ if (ident == Id.ptr && e.op == EXP.call)
{
- /* The trouble with TOK.call is the return ABI for float[4] is different from
+ /* The trouble with EXP.call is the return ABI for float[4] is different from
* __vector(float[4]), and a type paint won't do.
*/
e = new AddrExp(e.loc, e);
}
else if (ident == Id.ptr)
{
- if (e.op == TOK.type)
+ if (e.op == EXP.type)
{
e.error("`%s` is not an expression", e.toChars());
return ErrorExp.get();
{
printf("TypeDArray::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
}
- if (e.op == TOK.type && (ident == Id.length || ident == Id.ptr))
+ if (e.op == EXP.type && (ident == Id.length || ident == Id.ptr))
{
e.error("`%s` is not an expression", e.toChars());
return ErrorExp.get();
}
if (ident == Id.length)
{
- if (e.op == TOK.string_)
+ if (e.op == EXP.string_)
{
StringExp se = cast(StringExp)e;
return new IntegerExp(se.loc, se.len, Type.tsize_t);
}
- if (e.op == TOK.null_)
+ if (e.op == EXP.null_)
{
return new IntegerExp(e.loc, 0, Type.tsize_t);
}
if (!gagError)
{
global.endGagging(errors);
- if (exp && exp.op == TOK.error)
+ if (exp && exp.op == EXP.error)
exp = null;
}
{
printf("TypeStruct::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
}
- assert(e.op != TOK.dot);
+ assert(e.op != EXP.dot);
// https://issues.dlang.org/show_bug.cgi?id=14010
if (ident == Id._mangleof)
}
Expression e0;
- Expression ev = e.op == TOK.type ? null : e;
+ Expression ev = e.op == EXP.type ? null : e;
if (ev)
ev = extractSideEffect(sc, "__tup", e0, ev);
TemplateDeclaration td = s.isTemplateDeclaration();
if (td)
{
- if (e.op == TOK.type)
+ if (e.op == EXP.type)
e = new TemplateExp(e.loc, td);
else
e = new DotTemplateExp(e.loc, e, td);
s = ti.inst.toAlias();
if (!s.isTemplateInstance())
goto L1;
- if (e.op == TOK.type)
+ if (e.op == EXP.type)
e = new ScopeExp(e.loc, ti);
else
e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
if (o)
{
auto oe = new OverExp(e.loc, o);
- if (e.op == TOK.type)
+ if (e.op == EXP.type)
{
return oe;
}
return ErrorExp.get();
}
- if (e.op == TOK.type)
+ if (e.op == EXP.type)
{
/* It's:
* Struct.d
return ve;
}
- bool unreal = e.op == TOK.variable && (cast(VarExp)e).var.isField();
+ bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
if (d.isDataseg() || unreal && d.isField())
{
// (e, d)
{
printf("TypeClass::dotExp(e = '%s', ident = '%s')\n", e.toChars(), ident.toChars());
}
- assert(e.op != TOK.dot);
+ assert(e.op != EXP.dot);
// https://issues.dlang.org/show_bug.cgi?id=12543
if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
mt.sym.size(e.loc); // do semantic of type
Expression e0;
- Expression ev = e.op == TOK.type ? null : e;
+ Expression ev = e.op == EXP.type ? null : e;
if (ev)
ev = extractSideEffect(sc, "__tup", e0, ev);
// See if it's a 'this' class or a base class
if (mt.sym.ident == ident)
{
- if (e.op == TOK.type)
+ if (e.op == EXP.type)
{
return mt.Type.getProperty(sc, e.loc, ident, 0);
}
}
if (auto cbase = mt.sym.searchBase(ident))
{
- if (e.op == TOK.type)
+ if (e.op == EXP.type)
{
return mt.Type.getProperty(sc, e.loc, ident, 0);
}
}
Type t = Type.typeinfoclass.type;
- if (e.op == TOK.type || e.op == TOK.dotType)
+ if (e.op == EXP.type || e.op == EXP.dotType)
{
/* For type.classinfo, we know the classinfo
* at compile time.
Expression toTemplateExp(TemplateDeclaration td)
{
- if (e.op == TOK.type)
+ if (e.op == EXP.type)
e = new TemplateExp(e.loc, td);
else
e = new DotTemplateExp(e.loc, e, td);
s = ti.inst.toAlias();
if (!s.isTemplateInstance())
goto L1;
- if (e.op == TOK.type)
+ if (e.op == EXP.type)
e = new ScopeExp(e.loc, ti);
else
e = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
if (o)
{
auto oe = new OverExp(e.loc, o);
- if (e.op == TOK.type)
+ if (e.op == EXP.type)
{
return oe;
}
return ErrorExp.get();
}
- if (e.op == TOK.type)
+ if (e.op == EXP.type)
{
/* It's:
* Class.d
assert(0);
}
- bool unreal = e.op == TOK.variable && (cast(VarExp)e).var.isField();
+ bool unreal = e.op == EXP.variable && (cast(VarExp)e).var.isField();
if (d.isDataseg() || unreal && d.isField())
{
// (e, d)
Parameter p = (*mt.arguments)[i];
assert(p.type);
Expression e = p.type.defaultInitLiteral(loc);
- if (e.op == TOK.error)
+ if (e.op == EXP.error)
{
return e;
}
static Expression pvalToResult(Expression e, const ref Loc loc)
{
- if (e.op != TOK.error)
+ if (e.op != EXP.error)
{
e = e.copy();
e.loc = loc;
* maxval = e;
*/
Expression e = em.value;
- Expression ec = new CmpExp(id == Id.max ? TOK.greaterThan : TOK.lessThan, em.loc, e, *pval);
+ Expression ec = new CmpExp(id == Id.max ? EXP.greaterThan : EXP.lessThan, em.loc, e, *pval);
ed.inuse++;
ec = ec.expressionSemantic(em._scope);
ed.inuse--;
ec = ec.ctfeInterpret();
- if (ec.op == TOK.error)
+ if (ec.op == EXP.error)
{
ed.errors = true;
continue;
if (ce != NULL && ce->e1->isLvalue ())
return true;
- return (e->op != TOKslice && e->isLvalue ());
+ return (e->op != EXP::slice && e->isLvalue ());
}
/* Build an expression of code CODE, data type TYPE, and operands ARG0 and
{
/* Skip casts for lhs assignment. */
Expression *e1b = e1;
- while (e1b->op == TOKcast)
+ while (e1b->op == EXP::cast_)
{
CastExp *ce = e1b->isCastExp ();
gcc_assert (same_type_p (ce->type, ce->to));
void visit (IdentityExp *e)
{
- tree_code code = (e->op == TOKidentity) ? EQ_EXPR : NE_EXPR;
+ tree_code code = (e->op == EXP::identity) ? EQ_EXPR : NE_EXPR;
Type *tb1 = e->e1->type->toBasetype ();
Type *tb2 = e->e2->type->toBasetype ();
{
Type *tb1 = e->e1->type->toBasetype ();
Type *tb2 = e->e2->type->toBasetype ();
- tree_code code = (e->op == TOKequal) ? EQ_EXPR : NE_EXPR;
+ tree_code code = (e->op == EXP::equal) ? EQ_EXPR : NE_EXPR;
if ((tb1->ty == TY::Tsarray || tb1->ty == TY::Tarray)
&& (tb2->ty == TY::Tsarray || tb2->ty == TY::Tarray))
Otherwise for inequality:
(e1.length != 0 && memcmp); */
tree tsizecmp = build_boolop (code, t1len, size_zero_node);
- if (e->op == TOKequal)
+ if (e->op == EXP::equal)
result = build_boolop (TRUTH_ORIF_EXPR, tsizecmp, result);
else
result = build_boolop (TRUTH_ANDIF_EXPR, tsizecmp, result);
else
{
tree tlencmp = build_boolop (code, t1len, t2len);
- if (e->op == TOKequal)
+ if (e->op == EXP::equal)
result = build_boolop (TRUTH_ANDIF_EXPR, tlencmp, result);
else
result = build_boolop (TRUTH_ORIF_EXPR, tlencmp, result);
d_array_convert (e->e2),
build_typeinfo (e->loc, t1array));
- if (e->op == TOKnotequal)
+ if (e->op == EXP::notEqual)
result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result);
this->result_ = result;
build_expr (e->e1),
build_expr (e->e2));
- if (e->op == TOKnotequal)
+ if (e->op == EXP::notEqual)
result = build1 (TRUTH_NOT_EXPR, build_ctype (e->type), result);
this->result_ = result;
switch (e->op)
{
- case TOKle:
+ case EXP::lessOrEqual:
code = LE_EXPR;
break;
- case TOKlt:
+ case EXP::lessThan:
code = LT_EXPR;
break;
- case TOKge:
+ case EXP::greaterOrEqual:
code = GE_EXPR;
break;
- case TOKgt:
+ case EXP::greaterThan:
code = GT_EXPR;
break;
void visit (LogicalExp *e)
{
- tree_code code = (e->op == TOKandand) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR;
+ tree_code code = (e->op == EXP::andAnd) ? TRUTH_ANDIF_EXPR : TRUTH_ORIF_EXPR;
if (e->e2->type->toBasetype ()->ty != TY::Tvoid)
{
tree t2 = build_expr_dtor (e->e2);
/* Invert condition for logical or if expression. */
- if (e->op == TOKoror)
+ if (e->op == EXP::orOr)
t1 = build1 (TRUTH_NOT_EXPR, d_bool_type, t1);
this->result_ = build_condition (build_ctype (e->type),
switch (e->op)
{
- case TOKadd:
- case TOKmin:
+ case EXP::add:
+ case EXP::min:
if ((e->e1->type->isreal () && e->e2->type->isimaginary ())
|| (e->e1->type->isimaginary () && e->e2->type->isreal ()))
{
tree t1 = build_expr (e->e1);
tree t2 = build_expr (e->e2);
- if (e->op == TOKmin)
+ if (e->op == EXP::min)
t2 = build1 (NEGATE_EXPR, TREE_TYPE (t2), t2);
if (e->e1->type->isreal ())
return;
}
else
- code = (e->op == TOKadd)
+ code = (e->op == EXP::add)
? PLUS_EXPR : MINUS_EXPR;
break;
- case TOKmul:
+ case EXP::mul:
code = MULT_EXPR;
break;
- case TOKdiv:
+ case EXP::div:
/* Determine if the div expression is a lowered pointer diff operation.
The front-end rewrites `(p1 - p2)' into `(p1 - p2) / stride'. */
if (MinExp *me = e->e1->isMinExp ())
{
if (me->e1->type->ty == TY::Tpointer
&& me->e2->type->ty == TY::Tpointer
- && e->e2->op == TOKint64)
+ && e->e2->op == EXP::int64)
{
code = EXACT_DIV_EXPR;
break;
? TRUNC_DIV_EXPR : RDIV_EXPR;
break;
- case TOKmod:
+ case EXP::mod:
code = e->e1->type->isfloating ()
? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR;
break;
- case TOKand:
+ case EXP::and_:
code = BIT_AND_EXPR;
break;
- case TOKor:
+ case EXP::or_:
code = BIT_IOR_EXPR;
break;
- case TOKxor:
+ case EXP::xor_:
code = BIT_XOR_EXPR;
break;
- case TOKshl:
+ case EXP::leftShift:
code = LSHIFT_EXPR;
break;
- case TOKshr:
+ case EXP::rightShift:
code = RSHIFT_EXPR;
break;
- case TOKushr:
+ case EXP::unsignedRightShift:
code = UNSIGNED_RSHIFT_EXPR;
break;
tree result;
- if (e->e1->op == TOKcat)
+ if (e->e1->op == EXP::concatenate)
{
/* Flatten multiple concatenations to an array.
So the expression ((a ~ b) ~ c) becomes [a, b, c] */
int ndims = 2;
- for (Expression *ex = e->e1; ex->op == TOKcat;)
+ for (Expression *ex = e->e1; ex->op == EXP::concatenate;)
{
- if (ex->op == TOKcat)
+ if (ex->op == EXP::concatenate)
{
ex = ex->isCatExp ()->e1;
ndims++;
int dim = ndims - 1;
for (Expression *oe = ce->e2; oe != NULL;
- (ce->e1->op != TOKcat
+ (ce->e1->op != EXP::concatenate
? (oe = ce->e1)
: (ce = ce->e1->isCatExp (), oe = ce->e2)))
{
switch (e->op)
{
- case TOKaddass:
+ case EXP::addAssign:
code = PLUS_EXPR;
break;
- case TOKminass:
+ case EXP::minAssign:
code = MINUS_EXPR;
break;
- case TOKmulass:
+ case EXP::mulAssign:
code = MULT_EXPR;
break;
- case TOKdivass:
+ case EXP::divAssign:
code = e->e1->type->isintegral ()
? TRUNC_DIV_EXPR : RDIV_EXPR;
break;
- case TOKmodass:
+ case EXP::modAssign:
code = e->e1->type->isfloating ()
? FLOAT_MOD_EXPR : TRUNC_MOD_EXPR;
break;
- case TOKandass:
+ case EXP::andAssign:
code = BIT_AND_EXPR;
break;
- case TOKorass:
+ case EXP::orAssign:
code = BIT_IOR_EXPR;
break;
- case TOKxorass:
+ case EXP::xorAssign:
code = BIT_XOR_EXPR;
break;
- case TOKpowass:
+ case EXP::powAssign:
gcc_unreachable ();
- case TOKshlass:
+ case EXP::leftShiftAssign:
code = LSHIFT_EXPR;
break;
- case TOKshrass:
- case TOKushrass:
+ case EXP::rightShiftAssign:
+ case EXP::unsignedRightShiftAssign:
/* Use the original lhs type before it was promoted. The left operand
of `>>>=' does not undergo integral promotions before shifting.
Strip off casts just incase anyway. */
- while (e1b->op == TOKcast)
+ while (e1b->op == EXP::cast_)
{
CastExp *ce = e1b->isCastExp ();
gcc_assert (same_type_p (ce->type, ce->to));
e1b = ce->e1;
}
- code = (e->op == TOKshrass) ? RSHIFT_EXPR : UNSIGNED_RSHIFT_EXPR;
+ code = (e->op == EXP::rightShiftAssign) ? RSHIFT_EXPR : UNSIGNED_RSHIFT_EXPR;
break;
default:
/* First, handle special assignment semantics. */
/* Look for array.length = n; */
- if (e->e1->op == TOKarraylength)
+ if (e->e1->op == EXP::arrayLength)
{
/* This case should have been rewritten to `_d_arraysetlengthT` in the
semantic phase. */
}
/* Look for array[] = n; */
- if (e->e1->op == TOKslice)
+ if (e->e1->op == EXP::slice)
{
SliceExp *se = e->e1->isSliceExp ();
Type *stype = se->e1->type->toBasetype ();
tree init = stabilize_expr (&t1);
t1 = d_save_expr (t1);
- if ((postblit || destructor) && e->op != TOKblit)
+ if ((postblit || destructor) && e->op != EXP::blit)
{
- libcall_fn libcall = (e->op == TOKconstruct)
- ? LIBCALL_ARRAYSETCTOR : LIBCALL_ARRAYSETASSIGN;
+ /* Need to call postblit/destructor as part of assignment.
+ Construction has already been handled by the front-end. */
+ gcc_assert (e->op != EXP::construct);
+
/* So we can call postblits on const/immutable objects. */
Type *tm = etype->unSharedOf ()->mutableOf ();
tree ti = build_typeinfo (e->loc, tm);
- result = build_libcall (libcall, Type::tvoid, 4,
+ /* Generate: _d_arraysetassign (t1.ptr, &t2, t1.length, ti); */
+ result = build_libcall (LIBCALL_ARRAYSETASSIGN, Type::tvoid, 4,
d_array_ptr (t1),
build_address (t2),
d_array_length (t1), ti);
this->result_ = compound_expr (result, t1);
}
- else if ((postblit || destructor) && e->op != TOKblit)
+ else if ((postblit || destructor)
+ && e->op != EXP::blit && e->op != EXP::construct)
{
- /* Generate: _d_arrayassign(ti, from, to)
- or: _d_arrayctor(ti, from, to) */
- libcall_fn libcall = (e->op == TOKconstruct)
- ? LIBCALL_ARRAYCTOR : LIBCALL_ARRAYASSIGN;
-
- this->result_ = build_libcall (libcall, e->type, 3,
+ /* Generate: _d_arrayassign(ti, from, to); */
+ this->result_ = build_libcall (LIBCALL_ARRAYASSIGN, e->type, 3,
build_typeinfo (e->loc, etype),
d_array_convert (e->e2),
d_array_convert (e->e1));
/* Look for reference initializations. */
if (e->memset == MemorySet::referenceInit)
{
- gcc_assert (e->op == TOKconstruct || e->op == TOKblit);
- gcc_assert (e->e1->op == TOKvar);
+ gcc_assert (e->op == EXP::construct || e->op == EXP::blit);
+ gcc_assert (e->e1->op == EXP::variable);
Declaration *decl = e->e1->isVarExp ()->var;
if (decl->storage_class & (STCout | STCref))
/* Other types of assignments that may require post construction. */
Type *tb1 = e->e1->type->toBasetype ();
- tree_code modifycode = (e->op == TOKconstruct) ? INIT_EXPR : MODIFY_EXPR;
+ tree_code modifycode = (e->op == EXP::construct) ? INIT_EXPR : MODIFY_EXPR;
/* Look for struct assignment. */
if (tb1->ty == TY::Tstruct)
StructDeclaration *sd = tb1->isTypeStruct ()->sym;
/* Look for struct = 0. */
- if (e->e2->op == TOKint64)
+ if (e->e2->op == EXP::int64)
{
/* Use memset to fill struct. */
- gcc_assert (e->op == TOKblit);
+ gcc_assert (e->op == EXP::blit);
tree result = build_memset_call (t1);
/* Maybe set-up hidden pointer to outer scope context. */
tree init = NULL_TREE;
/* Fill any alignment holes in the struct using memset. */
- if ((e->op == TOKconstruct
- || (e->e2->op == TOKstructliteral && e->op == TOKblit))
+ if ((e->op == EXP::construct
+ || (e->e2->op == EXP::structLiteral && e->op == EXP::blit))
&& (sd->isUnionDeclaration () || !identity_compare_p (sd)))
{
t1 = stabilize_reference (t1);
if (tb1->ty == TY::Tsarray)
{
/* Look for array = 0. */
- if (e->e2->op == TOKint64)
+ if (e->e2->op == EXP::int64)
{
/* Use memset to fill the array. */
- gcc_assert (e->op == TOKblit);
+ gcc_assert (e->op == EXP::blit);
this->result_ = build_memset_call (build_expr (e->e1));
return;
}
gcc_assert (e->e2->type->toBasetype ()->ty == TY::Tsarray);
/* Determine if we need to run postblit. */
- bool postblit = needs_postblit (etype);
- bool destructor = needs_dtor (etype);
- bool lvalue = lvalue_p (e->e2);
+ const bool postblit = needs_postblit (etype);
+ const bool destructor = needs_dtor (etype);
+ const bool lvalue = lvalue_p (e->e2);
/* Optimize static array assignment with array literal. Even if the
elements in rhs are all rvalues and don't have to call postblits,
this assignment should call dtors on old assigned elements. */
if ((!postblit && !destructor)
- || (e->op == TOKconstruct && e->e2->op == TOKarrayliteral)
- || (e->op == TOKconstruct && !lvalue && postblit)
- || (e->op == TOKblit || e->e1->type->size () == 0))
+ || (e->op == EXP::construct && e->e2->op == EXP::arrayLiteral)
+ || (e->op == EXP::construct && !lvalue && postblit)
+ || (e->op == EXP::blit || e->e1->type->size () == 0))
{
tree t1 = build_expr (e->e1);
tree t2 = convert_for_assignment (build_expr (e->e2),
return;
}
+ /* All other kinds of lvalue or rvalue static array assignment.
+ Array construction has already been handled by the front-end. */
+ gcc_assert (e->op != EXP::construct);
+
+ /* Generate: _d_arrayassign_l()
+ or: _d_arrayassign_r() */
+ libcall_fn libcall = (lvalue)
+ ? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R;
+ tree elembuf = build_local_temp (build_ctype (etype));
Type *arrtype = (e->type->ty == TY::Tsarray)
? etype->arrayOf () : e->type;
- tree result;
-
- if (e->op == TOKconstruct)
- {
- /* Generate: _d_arrayctor(ti, from, to) */
- result = build_libcall (LIBCALL_ARRAYCTOR, arrtype, 3,
- build_typeinfo (e->loc, etype),
- d_array_convert (e->e2),
- d_array_convert (e->e1));
- }
- else
- {
- /* Generate: _d_arrayassign_l()
- or: _d_arrayassign_r() */
- libcall_fn libcall = (lvalue)
- ? LIBCALL_ARRAYASSIGN_L : LIBCALL_ARRAYASSIGN_R;
- tree elembuf = build_local_temp (build_ctype (etype));
-
- result = build_libcall (libcall, arrtype, 4,
- build_typeinfo (e->loc, etype),
- d_array_convert (e->e2),
- d_array_convert (e->e1),
- build_address (elembuf));
- }
+ tree result = build_libcall (libcall, arrtype, 4,
+ build_typeinfo (e->loc, etype),
+ d_array_convert (e->e2),
+ d_array_convert (e->e1),
+ build_address (elembuf));
/* Cast the libcall result back to a static array. */
if (e->type->ty == TY::Tsarray)
{
tree result;
- if (e->op == TOKplusplus)
+ if (e->op == EXP::plusPlus)
{
result = build2 (POSTINCREMENT_EXPR, build_ctype (e->type),
build_expr (e->e1), build_expr (e->e2));
}
- else if (e->op == TOKminusminus)
+ else if (e->op == EXP::minusMinus)
{
result = build2 (POSTDECREMENT_EXPR, build_ctype (e->type),
build_expr (e->e1), build_expr (e->e2));
the destructor is called for the object instance. */
libcall_fn libcall;
- if (e->e1->op == TOKvar)
+ if (e->e1->op == EXP::variable)
{
VarDeclaration *v = e->e1->isVarExp ()->var->isVarDeclaration ();
if (v && v->onstack)
size_t offset;
tree result;
- if (e->e1->op == TOKadd)
+ if (e->e1->op == EXP::add)
{
AddExp *ae = e->e1->isAddExp ();
- if (ae->e1->op == TOKaddress
+ if (ae->e1->op == EXP::address
&& ae->e2->isConst () && ae->e2->type->isintegral ())
{
Expression *ex = ae->e1->isAddrExp ()->e1;
offset = ae->e2->toUInteger ();
}
}
- else if (e->e1->op == TOKsymoff)
+ else if (e->e1->op == EXP::symbolOffset)
{
SymOffExp *se = e->e1->isSymOffExp ();
if (!declaration_reference_p (se->var))
/* The frontend optimizer can convert const symbol into a struct literal.
Taking the address of a struct literal is otherwise illegal. */
- if (e->e1->op == TOKstructliteral)
+ if (e->e1->op == EXP::structLiteral)
{
StructLiteralExp *sle = e->e1->isStructLiteralExp ()->origin;
gcc_assert (sle != NULL);
TypeFunction *tf = NULL;
/* Calls to delegates can sometimes look like this. */
- if (e1b->op == TOKcomma)
+ if (e1b->op == EXP::comma)
{
e1b = e1b->isCommaExp ()->e2;
- gcc_assert (e1b->op == TOKvar);
+ gcc_assert (e1b->op == EXP::variable);
Declaration *var = e1b->isVarExp ()->var;
gcc_assert (var->isFuncDeclaration () && !var->needThis ());
}
- if (e1b->op == TOKdotvar && tb->ty != TY::Tdelegate)
+ if (e1b->op == EXP::dotVariable && tb->ty != TY::Tdelegate)
{
DotVarExp *dve = e1b->isDotVarExp ();
/* Don't modify the static initializer for struct literals. */
- if (dve->e1->op == TOKstructliteral)
+ if (dve->e1->op == EXP::structLiteral)
{
StructLiteralExp *sle = dve->e1->isStructLiteralExp ();
sle->useStaticInit = false;
{
/* This could be a delegate expression (TY == Tdelegate), but not
actually a delegate variable. */
- if (e1b->op == TOKdotvar)
+ if (e1b->op == EXP::dotVariable)
{
/* This gets the true function type, getting the function type
from e1->type can sometimes be incorrect, such as when calling
object = delegate_object (callee);
callee = delegate_method (callee);
}
- else if (e1b->op == TOKvar)
+ else if (e1b->op == EXP::variable)
{
FuncDeclaration *fd = e1b->isVarExp ()->var->isFuncDeclaration ();
gcc_assert (fd != NULL);
if (e->func->isNested () && !e->func->isThis ())
{
- if (e->e1->op == TOKnull)
+ if (e->e1->op == EXP::null_)
object = build_expr (e->e1);
else
object = get_frame_for_symbol (e->func);
/* Get pointer to function out of the virtual table. */
if (e->func->isVirtual () && !e->func->isFinalFunc ()
- && e->e1->op != TOKsuper && e->e1->op != TOKdottype)
+ && e->e1->op != EXP::super_ && e->e1->op != EXP::dotType)
{
tree fntype = build_pointer_type (TREE_TYPE (fndecl));
object = d_save_expr (object);
Type *ftype = e->type->toBasetype ();
/* This check is for lambda's, remove `vthis' as function isn't nested. */
- if (e->fd->tok == TOKreserved && ftype->ty == TY::Tpointer)
+ if (e->fd->tok == TOK::reserved && ftype->ty == TY::Tpointer)
{
- e->fd->tok = TOKfunction;
+ e->fd->tok = TOK::function_;
e->fd->vthis = NULL;
}
FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ();
if (fld != NULL)
{
- if (fld->tok == TOKreserved)
+ if (fld->tok == TOK::reserved)
{
- fld->tok = TOKfunction;
+ fld->tok = TOK::function_;
fld->vthis = NULL;
}
{
/* Want the initializer, not the expression. */
VarDeclaration *var = e->var->isVarDeclaration ();
- SymbolDeclaration *sd = e->var->isSymbolDeclaration ();
+ SymbolDeclaration *sdecl = e->var->isSymbolDeclaration ();
tree init = NULL_TREE;
if (var && (var->isConst () || var->isImmutable ())
var->inuse--;
}
}
- else if (sd && sd->dsym)
- init = layout_struct_initializer (sd->dsym);
+ else if (sdecl && sdecl->dsym)
+ {
+ if (StructDeclaration *sd = sdecl->dsym->isStructDeclaration ())
+ init = layout_struct_initializer (sd);
+ else if (ClassDeclaration *cd = sdecl->dsym->isClassDeclaration ())
+ init = layout_class_initializer (cd);
+ else
+ gcc_unreachable ();
+ }
else
error_at (make_location_t (e->loc), "non-constant expression %qs",
e->toChars ());
tree result = get_decl_tree (e->var);
TREE_USED (result) = 1;
+ /* The variable expression generated for `__traits(initSymbol)'. */
+ if (SymbolDeclaration *sd = e->var->isSymbolDeclaration ())
+ {
+ if (e->type->isTypeDArray ())
+ {
+ /* Generate a slice for non-zero initialized aggregates,
+ otherwise create an empty array. */
+ gcc_assert (e->type == Type::tvoid->arrayOf ()->constOf ());
+
+ tree type = build_ctype (e->type);
+ tree length = size_int (sd->dsym->structsize);
+ tree ptr = (sd->dsym->isStructDeclaration ()
+ && sd->dsym->type->isZeroInit (e->loc))
+ ? null_pointer_node : build_address (result);
+
+ this->result_ = d_array_value (type, length, ptr);
+ return;
+ }
+ }
+
/* For variables that are references - currently only out/inout
arguments; objects don't count - evaluating the variable means
we want what it refers to. */
tree type = build_ctype (e->type);
/* First handle array literal expressions. */
- if (e->e1->op == TOKarrayliteral)
+ if (e->e1->op == EXP::arrayLiteral)
{
ArrayLiteralExp *ale = e->e1->isArrayLiteralExp ();
vec <constructor_elt, va_gc> *elms = NULL;
gcc_assert (ti && ti->tiargs && ti->tiargs->length == 2);
Expression *e = isExpression ((*ti->tiargs)[0]);
- gcc_assert (e && e->op == TOKint64);
+ gcc_assert (e && e->op == EXP::int64);
count = build_expr (e, true);
}
D RejectNegative
Implement 'in' contracts of overridden methods to be a superset of parent contract.
-fpreview=intpromote
-D RejectNegative
-Use C-style integral promotion for unary '+', '-' and '~'.
-
fpreview=nosharedaccess
D RejectNegative
Disable access to shared memory objects.
D RejectNegative
Don't destruct fields of partially constructed objects.
+frevert=intpromote
+D RejectNegative
+Use C-style integral promotion for unary '+', '-' and '~'.
+
frevert=markdown
D RejectNegative
Disable Markdown replacements in Ddoc.
DEF_D_RUNTIME (ARRAYSETASSIGN, "_d_arraysetassign", RT(VOIDPTR),
P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0)
-/* Used for constructing a new array from an existing array. The `set' variant
- is for when the constructor value is a single element. */
-DEF_D_RUNTIME (ARRAYCTOR, "_d_arrayctor", RT(ARRAY_VOID),
- P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0)
-DEF_D_RUNTIME (ARRAYSETCTOR, "_d_arraysetctor", RT(VOIDPTR),
- P4(VOIDPTR, VOIDPTR, SIZE_T, CONST_TYPEINFO), 0)
-
/* Used for concatenating two or more arrays together. Then `n' variant is
for when there is more than two arrays to handle. */
DEF_D_RUNTIME (ARRAYCATT, "_d_arraycatT", RT(ARRAY_BYTE),
StructLiteralExp *sle = NULL;
bool using_rvo_p = false;
- if (DotVarExp *dve = (s->exp->op == TOKcall
- && s->exp->isCallExp ()->e1->op == TOKdotvar
+ if (DotVarExp *dve = (s->exp->isCallExp ()
? s->exp->isCallExp ()->e1->isDotVarExp ()
: NULL))
{
RootObject *ro = (*td->objects)[j];
gcc_assert (ro->dyncast () == DYNCAST_EXPRESSION);
Expression *e = (Expression *) ro;
- gcc_assert (e->op == TOKdsymbol);
+ gcc_assert (e->op == EXP::dSymbol);
DsymbolExp *se = e->isDsymbolExp ();
tmembers.push (se->s);
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=21538
+// REQUIRED_ARGS: -preview=dip1000
+
+interface I
+{
+ void f(void delegate() @safe dg) @safe;
+}
+
+class CI : I
+{
+ override void f(void delegate() @system dg) @safe { }
+}
+
+abstract class A
+{
+ void f(void delegate() @safe dg) @safe;
+}
+
+class CA : A
+{
+ override void f(void delegate() @system dg) @safe { }
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=20904
+auto blah(void delegate())
+{
+}
+
+void delegate()[string] r;
+void main()
+{
+ void delegate() nothrow a;
+ r["v"] = a;
+}
--- /dev/null
+// REQUIRED_ARGS: -main -c
+
+void foo() { }
void* a3 = &globalNoreturn;
return a1 < a2 ? a2 : a3;
}
+
+/***************************************************/
+
+noreturn testfn(noreturn function() fn)
+{
+ fn();
+}
+
+noreturn testdg(noreturn delegate() dg)
+{
+ dg();
+}
--- /dev/null
+alias AliasSeq(T...) = T;
+
+class A
+{
+ int z = 3;
+}
+
+class B : A
+{
+ int a = 1;
+}
+
+class C : B
+{
+ int b = 2;
+ alias tup = AliasSeq!(b, a, z);
+}
+
+void main()
+{
+ static const ins = new C;
+ static assert(&ins.tup[0] == &ins.b);
+ static assert(&ins.tup[1] == &ins.a);
+ static assert(&ins.tup[2] == &ins.z);
+ static assert(ins.tup == AliasSeq!(2,1,3));
+}
--- /dev/null
+// PERMUTE_ARGS -preview=dip1000
+// https://issues.dlang.org/show_bug.cgi?id=19873
+int* ed(scope int* x)
+{
+ auto y = x;
+ return y;
+}
+
+int* et(scope int* x) @trusted
+{
+ auto y = x;
+ return y;
+}
+
+int* es(scope int* x) @system
+{
+ auto y = x;
+ return y;
+}
+
+auto ad(scope int* x)
+{
+ auto y = x;
+ return y;
+}
+
+auto at(scope int* x) @trusted
+{
+ auto y = x;
+ return y;
+}
+
+auto as(scope int* x) @system
+{
+ auto y = x;
+ return y;
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=21719
+
+struct S
+{
+ auto f()
+ {
+ } // inferred to be @safe @nogc pure nothrow
+}
+
+class C
+{
+ auto f() // should also infer the same attributes
+ {
+ }
+}
+
+pure @nogc nothrow @safe void test(S s, C c)
+{
+ s.f;
+ c.f;
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=22254
+
+struct Template(T) { T t; }
+
+Template!Bar a;
+Template!Bar b;
+
+immutable struct Bar { }
+
+static assert(is(typeof(a) == typeof(b)));
+static assert(is(typeof(a) == Template!(immutable Bar)));
+
+Template!C c1;
+Template!C c2;
+
+immutable class C { }
+
+static assert(is(typeof(c1) == typeof(c2)));
+static assert(is(typeof(c1) == Template!(immutable C)));
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=22510
+
+struct S
+{
+ int b;
+
+ @disable this(this);
+ this (scope ref inout S) inout
+ {
+ this.b = b;
+ }
+}
+
+void main()
+{
+ auto scoped_s = S(4);
+ auto heap_s = new S(42);
+}
--- /dev/null
+/++
+https://issues.dlang.org/show_bug.cgi?id=21538
+
+TEST_OUTPUT:
+---
+fail_compilation/covariant_override.d(23): Error: function `@safe void covariant_override.CI.f(void delegate() @safe dg)` does not override any function, did you mean to override `@safe void covariant_override.I.f(void delegate() @system dg)`?
+fail_compilation/covariant_override.d(34): Error: function `@safe void covariant_override.CA.f(void delegate() @safe dg)` does not override any function, did you mean to override `@safe void covariant_override.A.f(void delegate() @system dg)`?
+fail_compilation/covariant_override.d(20): Error: class `covariant_override.CI` interface function `void f(void delegate() @system dg) @safe` is not implemented
+---
+++/
+
+static assert(!is(void delegate() @system : void delegate() @safe));
+static assert( is(void delegate() @safe : void delegate() @system));
+
+interface I
+{
+ void f(void delegate() @system dg) @safe;
+}
+
+class CI : I
+{
+ // this overrride should not be legal
+ override void f(void delegate() @safe dg) @safe { }
+}
+
+abstract class A
+{
+ void f(void delegate() @system dg) @safe;
+}
+
+class CA : A
+{
+ // this overrride should not be legal
+ override void f(void delegate() @safe dg) @safe { }
+}
fail_compilation/fail10964.d(29): Error: function `fail10964.S.__postblit` is not `nothrow`
fail_compilation/fail10964.d(30): Error: function `fail10964.S.__postblit` is not `nothrow`
fail_compilation/fail10964.d(33): Error: function `fail10964.S.__postblit` is not `nothrow`
-fail_compilation/fail10964.d(34): Error: function `fail10964.S.__postblit` is not `nothrow`
-fail_compilation/fail10964.d(35): Error: function `fail10964.S.__postblit` is not `nothrow`
+fail_compilation/fail10964.d(34): Error: function `core.internal.array.construction._d_arraysetctor!(S[], S)._d_arraysetctor` is not `nothrow`
+fail_compilation/fail10964.d(35): Error: function `core.internal.array.construction._d_arrayctor!(S[], S)._d_arrayctor` is not `nothrow`
fail_compilation/fail10964.d(22): Error: `nothrow` function `fail10964.foo` may throw
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail10968.d(39): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(39): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here
-fail_compilation/fail10968.d(40): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(40): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here
fail_compilation/fail10968.d(41): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
fail_compilation/fail10968.d(41): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here
-fail_compilation/fail10968.d(44): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(44): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here
-fail_compilation/fail10968.d(45): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(45): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(42): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(42): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(43): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(43): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here
fail_compilation/fail10968.d(46): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
fail_compilation/fail10968.d(46): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
-fail_compilation/fail10968.d(27): `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(47): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(47): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(47): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arraysetctor!(SA[], SA)._d_arraysetctor`
+fail_compilation/fail10968.d(48): Error: `pure` function `fail10968.bar` cannot call impure function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(48): Error: `@safe` function `fail10968.bar` cannot call `@system` function `fail10968.SA.__postblit`
+fail_compilation/fail10968.d(29): `fail10968.SA.__postblit` is declared here
+fail_compilation/fail10968.d(48): Error: `pure` function `fail10968.bar` cannot call impure function `core.internal.array.construction._d_arrayctor!(SA[], SA)._d_arrayctor`
---
*/
/*
TEST_OUTPUT:
---
-fail_compilation/fail10968.d(72): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
-fail_compilation/fail10968.d(73): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
fail_compilation/fail10968.d(74): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
-fail_compilation/fail10968.d(77): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
-fail_compilation/fail10968.d(78): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
+fail_compilation/fail10968.d(75): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
+fail_compilation/fail10968.d(76): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
fail_compilation/fail10968.d(79): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
+fail_compilation/fail10968.d(80): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
+fail_compilation/fail10968.d(81): Error: struct `fail10968.SD` is not copyable because it has a disabled postblit
---
*/
/*
-REQUIRED_ARGS: -de
+REQUIRED_ARGS: -de -revert=intpromote
TEST_OUTPUT:
---
-fail_compilation/fail16997.d(31): Deprecation: integral promotion not done for `~c`, use '-preview=intpromote' switch or `~cast(int)(c)`
-fail_compilation/fail16997.d(32): Deprecation: integral promotion not done for `-c`, use '-preview=intpromote' switch or `-cast(int)(c)`
-fail_compilation/fail16997.d(33): Deprecation: integral promotion not done for `+c`, use '-preview=intpromote' switch or `+cast(int)(c)`
-fail_compilation/fail16997.d(36): Deprecation: integral promotion not done for `~w`, use '-preview=intpromote' switch or `~cast(int)(w)`
-fail_compilation/fail16997.d(37): Deprecation: integral promotion not done for `-w`, use '-preview=intpromote' switch or `-cast(int)(w)`
-fail_compilation/fail16997.d(38): Deprecation: integral promotion not done for `+w`, use '-preview=intpromote' switch or `+cast(int)(w)`
-fail_compilation/fail16997.d(41): Deprecation: integral promotion not done for `~sb`, use '-preview=intpromote' switch or `~cast(int)(sb)`
-fail_compilation/fail16997.d(42): Deprecation: integral promotion not done for `-sb`, use '-preview=intpromote' switch or `-cast(int)(sb)`
-fail_compilation/fail16997.d(43): Deprecation: integral promotion not done for `+sb`, use '-preview=intpromote' switch or `+cast(int)(sb)`
-fail_compilation/fail16997.d(46): Deprecation: integral promotion not done for `~ub`, use '-preview=intpromote' switch or `~cast(int)(ub)`
-fail_compilation/fail16997.d(47): Deprecation: integral promotion not done for `-ub`, use '-preview=intpromote' switch or `-cast(int)(ub)`
-fail_compilation/fail16997.d(48): Deprecation: integral promotion not done for `+ub`, use '-preview=intpromote' switch or `+cast(int)(ub)`
-fail_compilation/fail16997.d(51): Deprecation: integral promotion not done for `~s`, use '-preview=intpromote' switch or `~cast(int)(s)`
-fail_compilation/fail16997.d(52): Deprecation: integral promotion not done for `-s`, use '-preview=intpromote' switch or `-cast(int)(s)`
-fail_compilation/fail16997.d(53): Deprecation: integral promotion not done for `+s`, use '-preview=intpromote' switch or `+cast(int)(s)`
-fail_compilation/fail16997.d(56): Deprecation: integral promotion not done for `~us`, use '-preview=intpromote' switch or `~cast(int)(us)`
-fail_compilation/fail16997.d(57): Deprecation: integral promotion not done for `-us`, use '-preview=intpromote' switch or `-cast(int)(us)`
-fail_compilation/fail16997.d(58): Deprecation: integral promotion not done for `+us`, use '-preview=intpromote' switch or `+cast(int)(us)`
+fail_compilation/fail16997.d(31): Deprecation: integral promotion not done for `~c`, remove '-revert=intpromote' switch or `~cast(int)(c)`
+fail_compilation/fail16997.d(32): Deprecation: integral promotion not done for `-c`, remove '-revert=intpromote' switch or `-cast(int)(c)`
+fail_compilation/fail16997.d(33): Deprecation: integral promotion not done for `+c`, remove '-revert=intpromote' switch or `+cast(int)(c)`
+fail_compilation/fail16997.d(36): Deprecation: integral promotion not done for `~w`, remove '-revert=intpromote' switch or `~cast(int)(w)`
+fail_compilation/fail16997.d(37): Deprecation: integral promotion not done for `-w`, remove '-revert=intpromote' switch or `-cast(int)(w)`
+fail_compilation/fail16997.d(38): Deprecation: integral promotion not done for `+w`, remove '-revert=intpromote' switch or `+cast(int)(w)`
+fail_compilation/fail16997.d(41): Deprecation: integral promotion not done for `~sb`, remove '-revert=intpromote' switch or `~cast(int)(sb)`
+fail_compilation/fail16997.d(42): Deprecation: integral promotion not done for `-sb`, remove '-revert=intpromote' switch or `-cast(int)(sb)`
+fail_compilation/fail16997.d(43): Deprecation: integral promotion not done for `+sb`, remove '-revert=intpromote' switch or `+cast(int)(sb)`
+fail_compilation/fail16997.d(46): Deprecation: integral promotion not done for `~ub`, remove '-revert=intpromote' switch or `~cast(int)(ub)`
+fail_compilation/fail16997.d(47): Deprecation: integral promotion not done for `-ub`, remove '-revert=intpromote' switch or `-cast(int)(ub)`
+fail_compilation/fail16997.d(48): Deprecation: integral promotion not done for `+ub`, remove '-revert=intpromote' switch or `+cast(int)(ub)`
+fail_compilation/fail16997.d(51): Deprecation: integral promotion not done for `~s`, remove '-revert=intpromote' switch or `~cast(int)(s)`
+fail_compilation/fail16997.d(52): Deprecation: integral promotion not done for `-s`, remove '-revert=intpromote' switch or `-cast(int)(s)`
+fail_compilation/fail16997.d(53): Deprecation: integral promotion not done for `+s`, remove '-revert=intpromote' switch or `+cast(int)(s)`
+fail_compilation/fail16997.d(56): Deprecation: integral promotion not done for `~us`, remove '-revert=intpromote' switch or `~cast(int)(us)`
+fail_compilation/fail16997.d(57): Deprecation: integral promotion not done for `-us`, remove '-revert=intpromote' switch or `-cast(int)(us)`
+fail_compilation/fail16997.d(58): Deprecation: integral promotion not done for `+us`, remove '-revert=intpromote' switch or `+cast(int)(us)`
---
*/
+++ /dev/null
-// REQUIRED_ARGS: -preview=dip1000
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail809.d(11): Error: scope variable `dg_` may not be returned
----
-*/
-int delegate() test(lazy int dg)
-{
- int delegate() dg_ = &dg;
- return dg_;
-}
}
-@live void test52()
+@live void test52() @safe
{
int x = 5;
auto p = &x;
--- /dev/null
+module imports.test20023b;
+
+auto threw()() @safe
+{
+ try
+ throw new Exception("Hello");
+ catch (Exception e)
+ return e;
+ assert(0);
+}
-int* foo1(return scope int* p) { return p; } // ok
+int* foo1(return scope int* p) @safe { return p; } // ok
-int* foo2()(scope int* p) { return p; } // ok, 'return' is inferred
+int* foo2()(scope int* p) @safe { return p; } // ok, 'return' is inferred
alias foo2a = foo2!();
-int* foo3(scope int* p) { return p; } // error
+int* foo3(scope int* p) @safe { return p; } // error
-int* foo4(bool b)
+int* foo4(bool b) @safe
{
int i;
int j;
/* TEST_OUTPUT:
+PERMUTE_ARGS -dip1000
---
-fail_compilation/test15191.d(17): Error: cannot take address of `ref return` of `foo()` in `@safe` function `bar`
+fail_compilation/test15191.d(31): Error: returning `&identity(x)` escapes a reference to local variable `x`
+fail_compilation/test15191.d(37): Error: returning `&identityPtr(x)` escapes a reference to local variable `x`
+fail_compilation/test15191.d(43): Error: cannot take address of `ref return` of `identityPtr()` in `@safe` function `addrOfRefTransitive`
+fail_compilation/test15191.d(43): Error: returning `&identityPtr(x)` escapes a reference to local variable `x`
---
*/
-
// https://issues.dlang.org/show_bug.cgi?id=15191
+// https://issues.dlang.org/show_bug.cgi?id=22519
-ref int foo(return ref int s)@safe
+@safe:
+ref int foo(return ref int s)
{
return s;
}
-int* bar(return ref int s) @safe
+int* bar(return ref int s)
{
return &foo(s);
}
+
+ref int identity(ref return int x) {return x;}
+ref int* identityPtr(ref return int* x) {return x;}
+
+int* addrOfRefEscape()
+{
+ int x;
+ return &identity(x);
+}
+
+int** addrOfRefSystem() @system
+{
+ int* x;
+ return &identityPtr(x);
+}
+
+int** addrOfRefTransitive()
+{
+ int* x;
+ return &identityPtr(x);
+}
+
+int gInt;
+ref int getGlobalInt() {return gInt;}
+
+int* addrOfRefGlobal()
+{
+ return &getGlobalInt();
+}
--- /dev/null
+/*
+https://issues.dlang.org/show_bug.cgi?id=15399
+REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/test17977.d(19): Error: address of variable `__slList3` assigned to `elem` with longer lifetime
+---
+*/
+
+@safe:
+struct List {
+ int* data;
+ ~this();
+ int* front() return;
+}
+
+void test()
+{
+ auto elem = List().front;
+}
--- /dev/null
+// REQUIRED_ARGS: -preview=dip1000 -preview=dip1008 -Ifail_compilation/extra-files
+// https://issues.dlang.org/show_bug.cgi?id=20023
+/*
+TEST_OUTPUT:
+---
+fail_compilation/imports/test20023b.d(8): Error: scope variable `e` may not be returned
+fail_compilation/test20023.d(15): Error: template instance `imports.test20023b.threw!()` error instantiating
+---
+*/
+import imports.test20023b;
+
+@safe:
+void main()
+{
+ threw!()();
+}
--- /dev/null
+/********************************************
+TEST_OUTPUT:
+---
+fail_compilation/traits_initSymbol.d(105): Error: struct / class type expected as argument to __traits(initSymbol) instead of `int`
+fail_compilation/traits_initSymbol.d(106): Error: struct / class type expected as argument to __traits(initSymbol) instead of `S[2]`
+fail_compilation/traits_initSymbol.d(107): Error: struct / class type expected as argument to __traits(initSymbol) instead of `123`
+---
+*/
+#line 100
+
+struct S { int i = 4; }
+
+void test1()
+{
+ const void[] initInt = __traits(initSymbol, int);
+ const void[] initArray = __traits(initSymbol, S[2]);
+ const void[] initValue = __traits(initSymbol, 123);
+}
+
+/********************************************
+TEST_OUTPUT:
+---
+fail_compilation/traits_initSymbol.d(203): Error: cannot determine the address of the initializer symbol during CTFE
+fail_compilation/traits_initSymbol.d(203): called from here: `(*function () pure nothrow @nogc @safe => S)()`
+---
+*/
+#line 200
+
+void test2()
+{
+ enum initLen = (() => __traits(initSymbol, S))();
+}
+
+/********************************************
+TEST_OUTPUT:
+---
+fail_compilation/traits_initSymbol.d(305): Error: struct / class type expected as argument to __traits(initSymbol) instead of `traits_initSymbol.Interface`
+---
+*/
+#line 300
+
+interface Interface {}
+
+void test3()
+{
+ const void[] initInterface = __traits(initSymbol, Interface);
+}
+
+/********************************************
+TEST_OUTPUT:
+---
+fail_compilation/traits_initSymbol.d(404): Error: expected 1 arguments for `initSymbol` but had 0
+fail_compilation/traits_initSymbol.d(405): Error: expected 1 arguments for `initSymbol` but had 2
+---
+*/
+#line 400
+
+
+void test4()
+{
+ const void[] tmp = __traits(initSymbol);
+ const void[] tmo = __traits(initSymbol, Interface, S);
+}
--- /dev/null
+alias T = MyStruct!float;
+
+struct MyStruct(U)
+{
+ U x;
+ U y;
+
+ this(U xx, U yy)
+ {
+ x = xx;
+ y = yy;
+ }
+
+ MyStruct!U opBinary(string op)(MyStruct!U z) const
+ {
+ alias C = typeof(return);
+ auto w = C(this.x, this.y);
+ return w.opOpAssign!(op)(z);
+ }
+
+ MyStruct!U opBinaryRight(string op)(MyStruct!U z) const
+ {
+ return opBinary!(op)(z);
+ }
+
+ ref MyStruct opOpAssign(string op, U)(const MyStruct!U z)
+ {
+ mixin ("x "~op~"= z.x;");
+ mixin ("y "~op~"= z.y;");
+ return this;
+ }
+
+ MyStruct!U opBinary(string op, R)(R z) const
+ if (is(R == int) || is(R == float))
+ {
+ alias C = typeof(return);
+ auto w = C(this.x, this.y);
+ return w.opOpAssign!(op)(z);
+ }
+
+ MyStruct!U opBinaryRight(string op, R)(R z) const
+ if (is(R == int) || is(R == float))
+ {
+ return opBinary!(op)(z);
+ }
+
+ ref MyStruct opOpAssign(string op, R)(const R z)
+ if (is(R == int) || is(R == float))
+ {
+ mixin ("x "~op~"= z;");
+ return this;
+ }
+}
+
+void main()
+{
+ T c = MyStruct!float(1.0f, 1.0f);
+ T[] arr = [T(1,1), T(2,2), T(3,3), T(4,4), T(5,5), T(6,6)];
+ T[] result = new T[arr.length];
+
+ // part 2
+
+ result[0] = c * c;
+ assert(result[0] == T(1, 1));
+
+ result[0] = arr[1] * arr[2];
+ assert(result[0] == T(6, 6));
+
+ int[] intarr = [6, 5, 4, 3, 2, 1];
+
+ result[] = arr[] * arr[];
+ assert(result[] == [T(1, 1), T(4, 4), T(9, 9), T(16, 16), T(25, 25), T(36, 36)]);
+
+ result[] = arr[] * 3;
+ assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+ result[] = 3 * arr[];
+ assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+
+ result[] = arr[];
+ result[1..3] = arr[1..3] * 2.0f;
+ assert(result[] == [T(1, 1), T(4, 2), T(6, 3), T(4, 4), T(5, 5), T(6, 6)]);
+ result[1..3] = 2.0f * arr[1..3];
+ assert(result[] == [T(1, 1), T(4, 2), T(6, 3), T(4, 4), T(5, 5), T(6, 6)]);
+
+ result[] = arr[];
+ result[1..$] = arr[1..$] * 2.0f;
+ assert(result[] == [T(1, 1), T(4, 2), T(6, 3), T(8, 4), T(10, 5), T(12, 6)]);
+ result[1..$] = 2.0f * arr[1..$];
+ assert(result[] == [T(1, 1), T(4, 2), T(6, 3), T(8, 4), T(10, 5), T(12, 6)]);
+
+ result[] = intarr[] * arr[];
+ assert(result[] == [T(6, 1), T(10, 2), T(12, 3), T(12, 4), T(10, 5), T(6, 6)]);
+ result[] = arr[] * intarr[];
+ assert(result[] == [T(6, 1), T(10, 2), T(12, 3), T(12, 4), T(10, 5), T(6, 6)]);
+
+ result[] = intarr[] * T(2,3);
+ assert(result[] == [T(12, 3), T(10, 3), T(8, 3), T(6, 3), T(4, 3), T(2, 3)]);
+ result[] = T(2,3) * intarr[];
+ assert(result[] == [T(12, 3), T(10, 3), T(8, 3), T(6, 3), T(4, 3), T(2, 3)]);
+
+ result[] = intarr[] * c;
+ assert(result[] == [T(6, 1), T(5, 1), T(4, 1), T(3, 1), T(2, 1), T(1, 1)]);
+ result[] = c * intarr[];
+ assert(result[] == [T(6, 1), T(5, 1), T(4, 1), T(3, 1), T(2, 1), T(1, 1)]);
+
+ result[] = arr[];
+ result[1..3] = intarr[1..3] * c;
+ assert(result[] == [T(1, 1), T(5, 1), T(4, 1), T(4, 4), T(5, 5), T(6, 6)]);
+ result[1..3] = c * intarr[1..3];
+ assert(result[] == [T(1, 1), T(5, 1), T(4, 1), T(4, 4), T(5, 5), T(6, 6)]);
+
+ result[1..$] = intarr[1..$] * c;
+ assert(result[] == [T(1, 1), T(5, 1), T(4, 1), T(3, 1), T(2, 1), T(1, 1)]);
+ result[1..$] = c * intarr[1..$];
+ assert(result[] == [T(1, 1), T(5, 1), T(4, 1), T(3, 1), T(2, 1), T(1, 1)]);
+
+ result[] = arr[];
+ result[1..3] = intarr[1..3] * arr[1..3];
+ assert(result[] == [T(1, 1), T(10, 2), T(12, 3), T(4, 4), T(5, 5), T(6, 6)]);
+ result[1..3] = arr[1..3] * intarr[1..3];
+ assert(result[] == [T(1, 1), T(10, 2), T(12, 3), T(4, 4), T(5, 5), T(6, 6)]);
+
+ result[] = [1,2,3,4,5,6] * c;
+ assert(result[] == [T(1, 1), T(2, 1), T(3, 1), T(4, 1), T(5, 1), T(6, 1)]);
+ result[] = c * [1,2,3,4,5,6];
+ assert(result[] == [T(1, 1), T(2, 1), T(3, 1), T(4, 1), T(5, 1), T(6, 1)]);
+
+ result[] = arr[] * [1,2,3,4,5,6];
+ assert(result[] == [T(1, 1), T(4, 2), T(9, 3), T(16, 4), T(25, 5), T(36, 6)]);
+ result[] = [1,2,3,4,5,6] * arr[];
+ assert(result[] == [T(1, 1), T(4, 2), T(9, 3), T(16, 4), T(25, 5), T(36, 6)]);
+
+ result[] = [c, 2 * c, 3 * c, 4 * c, 5 * c, 6 * c] * [c, 2 * c, 3 * c, 4 * c, 5 * c, 6 * c];
+ assert(result[] == [T(1, 1), T(4, 1), T(9, 1), T(16, 1), T(25, 1), T(36, 1)]);
+
+ result[] = [c, 2 * c, 3 * c, 4 * c, 5 * c, 6 * c] * [1,2,3,4,5,6];
+ assert(result[] == [T(1, 1), T(4, 1), T(9, 1), T(16, 1), T(25, 1), T(36, 1)]);
+ result[] = [1,2,3,4,5,6] * [c, 2 * c, 3 * c, 4 * c, 5 * c, 6 * c];
+ assert(result[] == [T(1, 1), T(4, 1), T(9, 1), T(16, 1), T(25, 1), T(36, 1)]);
+
+ result[] = arr[] * c;
+ assert(result[] == [T(1, 1), T(2, 2), T(3, 3), T(4, 4), T(5, 5), T(6, 6)]);
+ result[] = c * arr[];
+ assert(result[] == [T(1, 1), T(2, 2), T(3, 3), T(4, 4), T(5, 5), T(6, 6)]);
+
+ result[] = c * 3.0f * arr[];
+ assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+ result[] = 3.0f * c * arr[];
+ assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+
+ result[] = arr[] * 3.0f * c;
+ assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+ // result[] = arr[] * c * 3.0f; //not ok
+ // assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+
+ result[] = 3.0f * arr[] * c;
+ assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+ // result[] = c * arr[] * 3.0f; //not ok
+ // assert(result[] == [T(3, 1), T(6, 2), T(9, 3), T(12, 4), T(15, 5), T(18, 6)]);
+
+ result[] = c * arr[] * c;
+ assert(result[] == [T(1, 1), T(2, 2), T(3, 3), T(4, 4), T(5, 5), T(6, 6)]);
+}
/*
-REQUIRED_ARGS: -mcpu=native -preview=intpromote
+REQUIRED_ARGS: -mcpu=native
PERMUTE_ARGS: -O -inline -release
*/
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=15862
+
+/*
+PERMUTE_ARGS:
+REQUIRED_ARGS: -O -release
+*/
+
+
+int* p() pure nothrow {return new int;}
+int[] a() pure nothrow {return [0];}
+Object o() pure nothrow {return new Object;}
+
+auto pa() pure nothrow {return new int;}
+
+void main()
+{
+ {
+ int* p1 = p();
+ int* p2 = p();
+
+ if (p1 is p2) assert(0);
+
+ int[] a1 = a();
+ int[] a2 = a();
+
+ if (a1 is a2) assert(0);
+
+ Object o1 = o();
+ Object o2 = o();
+
+ if (o1 is o2) assert(0);
+ }
+ {
+ auto p1 = pa();
+ auto p2 = pa();
+
+ if (p1 is p2) assert(0);
+ }
+}
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=21367
+
+string result = "";
+
+struct RCArray(T)
+{
+ T* data;
+ this(this)
+ {
+ result ~= "A";
+ }
+ ~this()
+ {
+ result ~= "B";
+ }
+}
+
+struct Variant(T...)
+{
+ union
+ {
+ T payload;
+ }
+ this(this)
+ {
+ result ~= "C";
+ }
+
+ ~this()
+ {
+ result ~= "D";
+ }
+}
+
+alias Ft = Variant!(RCArray!double, RCArray!int);
+
+void fun(Ft a) {}
+void main()
+{
+ Ft a;
+ Ft b = a;
+}
+
+static ~this()
+{
+ assert(result == "CDD");
+}
--- /dev/null
+// REQUIRED_ARGS: -debug -O -release
+// https://issues.dlang.org/show_bug.cgi?id=22277
+
+bool secret = false;
+
+void free(immutable void* x) pure nothrow
+{
+ debug secret = true;
+}
+
+void main()
+{
+ free(null);
+ if (!secret)
+ assert(0);
+}
-/* PERMUTE_ARGS:
+/* PERMUTE_ARGS: -preview=dip1000
*/
// https://issues.dlang.org/show_bug.cgi?id=15624
}
safe();
}
+
+// https://issues.dlang.org/show_bug.cgi?id=20907
+Lockstep!() lockstep()
+{
+ return Lockstep!()();
+}
+
+struct Lockstep()
+{
+ int opApply(int delegate(int) callback) @system
+ {
+ return 0;
+ }
+
+ int opApply(int delegate(int) pure nothrow @nogc @safe callback) pure nothrow @nogc @safe
+ {
+ return 0;
+ }
+}
+
+void foo0()
+{
+ foreach (x; lockstep()) {}
+}
+
+void foo1()
+{
+ foreach (x; lockstep()) {}
+}
/*
-REQUIRED_ARGS: -mcpu=native -preview=intpromote
+REQUIRED_ARGS: -mcpu=native
PERMUTE_ARGS: -O -inline -release
*/
immutable struct S7038c{ int x; }
static assert(is(S7038c == immutable));
-static assert(!is(C7038 == const));
+// https://issues.dlang.org/show_bug.cgi?id=22515
+// Classes fixed for consistency with structs
+static assert(is(C7038 == const));
const class C7038{ int x; }
-static assert(!is(C7038 == const));
+static assert(is(C7038 == const));
void test7038()
{
static assert(is(typeof(s.x) == const int));
C7038 c;
- static assert(!is(typeof(c) == const));
+ static assert(is(typeof(c) == const));
static assert(is(typeof(c.x) == const int));
}
--- /dev/null
+struct Zero
+{
+ int x;
+}
+
+void testZero()
+{
+ auto zeroInit = __traits(initSymbol, Zero);
+ static assert(is(typeof(zeroInit) == const(void[])));
+
+ assert(zeroInit.ptr is null);
+ assert(zeroInit.length == Zero.sizeof);
+}
+
+struct NonZero
+{
+ long x = 1;
+}
+
+void testNonZero()
+{
+ auto nonZeroInit = __traits(initSymbol, NonZero);
+ static assert(is(typeof(nonZeroInit) == const(void[])));
+
+ assert(nonZeroInit.ptr);
+ assert(nonZeroInit.length == NonZero.sizeof);
+ assert(cast(const(long[])) nonZeroInit == [1L]);
+}
+
+class C
+{
+ short x = 123;
+}
+
+void testClass()
+{
+ auto cInit = __traits(initSymbol, C);
+ static assert(is(typeof(cInit) == const(void[])));
+
+ assert(cInit.ptr);
+ assert(cInit.length == __traits(classInstanceSize, C));
+
+ scope c = new C;
+ assert((cast(void*) c)[0 .. cInit.length] == cInit);
+}
+
+struct AlignedStruct
+{
+ short s = 5;
+ // 2 byte padding
+ align(4) char c = 'c';
+ // 3 byte padding
+ int i = 4;
+ // reduced alignment
+ align(1) long l = 0xDEADBEEF;
+}
+
+void testAlignedStruct()
+{
+ auto init = __traits(initSymbol, AlignedStruct);
+
+ assert(init.ptr);
+ assert(init.length == AlignedStruct.sizeof);
+
+ version (GNU)
+ AlignedStruct exp = AlignedStruct();
+ else
+ AlignedStruct exp;
+ assert(init == (cast(void*) &exp)[0 .. AlignedStruct.sizeof]);
+
+}
+
+class AlignedClass : C
+{
+ short s = 5;
+ // 2 byte padding
+ align(4) char c = 'c';
+ // 3 byte padding
+ int i = 4;
+ // reduced alignment
+ align(1) long l = 0xDEADBEEF;
+}
+
+void testAlignedClass()
+{
+ auto init = __traits(initSymbol, AlignedClass);
+
+ assert(init.ptr);
+ assert(init.length == __traits(classInstanceSize, AlignedClass));
+
+ scope ac = new AlignedClass();
+ assert(init == (cast(void*) ac)[0 .. init.length]);
+}
+
+extern (C++) class ExternCppClass
+{
+ int i = 4;
+}
+
+void testExternCppClass()
+{
+ auto init = __traits(initSymbol, ExternCppClass);
+
+ assert(init.ptr);
+ assert(init.length == __traits(classInstanceSize, ExternCppClass));
+
+ scope ac = new ExternCppClass();
+ assert(init == (cast(void*) ac)[0 .. init.length]);
+}
+
+void main()
+{
+ testZero();
+ testNonZero();
+ testClass();
+ testAlignedStruct();
+ testAlignedClass();
+ testExternCppClass();
+}
class C5933a { auto x() { return 0; } }
-static assert(is(typeof(&(new C5933b()).x) == int delegate()));
+static assert(is(typeof(&(new C5933b()).x) == int delegate() pure nothrow @nogc @safe));
class C5933b { auto x() { return 0; } }
//static assert(is(typeof((new C5933b()).x) == FuncType5933));
{
static struct S
{
- int bar(void delegate(ref int*)) { return 1; }
- int bar(void delegate(ref const int*)) const { return 2; }
+ // Specify attribute inferred for dg1/dg2
+ int bar(void delegate(ref int*) pure nothrow @nogc @safe) { return 1; }
+ int bar(void delegate(ref const int*) pure nothrow @nogc @safe) const { return 2; }
}
void dg1(ref int*) { }
--- /dev/null
+#include <stdarg.h>
+#include <assert.h>
+
+class C1
+{
+public:
+ virtual ~C1();
+
+ int i;
+
+ int f0();
+ int f1(int a);
+ int f2(int a, int b);
+ virtual int f3(int a, int b);
+ int f4(int a, ...);
+};
+
+C1::~C1()
+{
+}
+
+int C1::f0()
+{
+ return i;
+}
+
+int C1::f1(int a)
+{
+ return i + a;
+}
+
+int C1::f2(int a, int b)
+{
+ return i + a + b;
+}
+
+int C1::f3(int a, int b)
+{
+ return i + a + b;
+}
+
+int C1::f4(int a, ...)
+{
+ int r = i + a;
+ int last = a;
+
+ va_list argp;
+ va_start(argp, a);
+ while (last)
+ {
+ last = va_arg(argp, int);
+ r += last;
+ }
+ va_end(argp);
+ return r;
+}
+
+C1 *createC1()
+{
+ return new C1();
+}
+
+class C2
+{
+public:
+ virtual ~C2();
+
+ int i;
+
+ int f0();
+ int f1(int a);
+ int f2(int a, int b);
+ virtual int f3(int a, int b);
+ int f4(int a, ...);
+};
+
+C2 *createC2();
+
+void runCPPTests()
+{
+ C2 *c2 = createC2();
+ c2->i = 100;
+ assert(c2->f0() == 100);
+ assert(c2->f1(1) == 101);
+ assert(c2->f2(20, 3) == 123);
+ assert(c2->f3(20, 3) == 123);
+ assert(c2->f4(20, 3, 0) == 123);
+
+ int (C2::*fp0)() = &C2::f0;
+ int (C2::*fp1)(int) = &C2::f1;
+ int (C2::*fp2)(int, int) = &C2::f2;
+ int (C2::*fp3)(int, int) = &C2::f3;
+#ifndef __DMC__
+ int (C2::*fp4)(int, ...) = &C2::f4;
+#endif
+ assert((c2->*(fp0))() == 100);
+ assert((c2->*(fp1))(1) == 101);
+ assert((c2->*(fp2))(20, 3) == 123);
+ assert((c2->*(fp3))(20, 3) == 123);
+#ifndef __DMC__
+ assert((c2->*(fp4))(20, 3, 0) == 123);
+#endif
+}
--- /dev/null
+// EXTRA_CPP_SOURCES: cpp7925.cpp
+
+/*
+Exclude -O due to a codegen bug on OSX:
+https://issues.dlang.org/show_bug.cgi?id=22556
+
+PERMUTE_ARGS(osx): -inline -release -g
+*/
+
+import core.vararg;
+
+extern(C++) class C1
+{
+public:
+ ~this();
+
+ int i;
+
+ final int f0();
+ final int f1(int a);
+ final int f2(int a, int b);
+ int f3(int a, int b);
+ final int f4(int a, ...);
+};
+
+extern(C++) C1 createC1();
+
+extern(C++) class C2
+{
+public:
+ ~this()
+ {
+ }
+
+ int i;
+
+ final int f0()
+ {
+ return i;
+ }
+
+ final int f1(int a)
+ {
+ return i + a;
+ }
+
+ final int f2(int a, int b)
+ {
+ return i + a + b;
+ }
+
+ int f3(int a, int b)
+ {
+ return i + a + b;
+ }
+
+ final int f4(int a, ...)
+ {
+ int r = i + a;
+ int last = a;
+
+ va_list argp;
+ va_start(argp, a);
+ while (last)
+ {
+ last = va_arg!int(argp);
+ r += last;
+ }
+ va_end(argp);
+ return r;
+ }
+};
+
+extern(C++) C2 createC2()
+{
+ return new C2;
+}
+
+auto callMember(alias F, Params...)(__traits(parent, F) obj, Params params)
+{
+ static if(__traits(getFunctionVariadicStyle, F) == "stdarg")
+ enum varargSuffix = ", ...";
+ else
+ enum varargSuffix = "";
+
+ static if(is(typeof(&F) R == return) && is(typeof(F) P == __parameters))
+ mixin("extern(" ~ __traits(getLinkage, F) ~ ") R delegate(P" ~ varargSuffix ~ ") dg;");
+ dg.funcptr = &F;
+ dg.ptr = cast(void*)obj;
+ return dg(params);
+}
+
+extern(C++) void runCPPTests();
+
+void main()
+{
+ C1 c1 = createC1();
+ c1.i = 100;
+ assert(c1.f0() == 100);
+ assert(c1.f1(1) == 101);
+ assert(c1.f2(20, 3) == 123);
+ assert(c1.f3(20, 3) == 123);
+ assert(c1.f4(20, 3, 0) == 123);
+
+ auto dg0 = &c1.f0;
+ auto dg1 = &c1.f1;
+ auto dg2 = &c1.f2;
+ auto dg3 = &c1.f3;
+ auto dg4 = &c1.f4;
+ assert(dg0() == 100);
+ assert(dg1(1) == 101);
+ assert(dg2(20, 3) == 123);
+ assert(dg3(20, 3) == 123);
+ assert(dg4(20, 3, 0) == 123);
+
+ assert(callMember!(C1.f0)(c1) == 100);
+ assert(callMember!(C1.f1)(c1, 1) == 101);
+ assert(callMember!(C1.f2)(c1, 20, 3) == 123);
+ assert(callMember!(C1.f3)(c1, 20, 3) == 123);
+ assert(callMember!(C1.f4)(c1, 20, 3, 0) == 123);
+
+ int i;
+ extern(C++) void delegate() lamdba1 = () {
+ i = 5;
+ };
+ lamdba1();
+ assert(i == 5);
+
+ extern(C++) int function(int, int) lamdba2 = (int a, int b) {
+ return a + b;
+ };
+ assert(lamdba2(3, 4) == 7);
+
+ extern(C++) void delegate(int, ...) lamdba3 = (int a, ...) {
+ i = a;
+ int last = a;
+
+ va_list argp;
+ va_start(argp, a);
+ while (last)
+ {
+ last = va_arg!int(argp);
+ i += last;
+ }
+ va_end(argp);
+ };
+ lamdba3(1000, 200, 30, 4, 0);
+ assert(i == 1234);
+
+ runCPPTests();
+}
-178c44ff362902af589603767055cfac89215652
+bc58b1e9ea68051af9094651a26313371297b79f
The first line of this file holds the git revision number of the last
merge done from the dlang/druntime repository.
core/sys/linux/sys/procfs.d core/sys/linux/sys/signalfd.d \
core/sys/linux/sys/socket.d core/sys/linux/sys/sysinfo.d \
core/sys/linux/sys/time.d core/sys/linux/sys/xattr.d \
- core/sys/linux/syscalls.d core/sys/linux/termios.d \
- core/sys/linux/time.d core/sys/linux/timerfd.d core/sys/linux/tipc.d \
- core/sys/linux/unistd.d
+ core/sys/linux/termios.d core/sys/linux/time.d \
+ core/sys/linux/timerfd.d core/sys/linux/tipc.d core/sys/linux/unistd.d
DRUNTIME_DSOURCES_NETBSD = core/sys/netbsd/dlfcn.d \
core/sys/netbsd/err.d core/sys/netbsd/execinfo.d \
core/sys/linux/sys/procfs.lo core/sys/linux/sys/signalfd.lo \
core/sys/linux/sys/socket.lo core/sys/linux/sys/sysinfo.lo \
core/sys/linux/sys/time.lo core/sys/linux/sys/xattr.lo \
- core/sys/linux/syscalls.lo core/sys/linux/termios.lo \
- core/sys/linux/time.lo core/sys/linux/timerfd.lo \
- core/sys/linux/tipc.lo core/sys/linux/unistd.lo
+ core/sys/linux/termios.lo core/sys/linux/time.lo \
+ core/sys/linux/timerfd.lo core/sys/linux/tipc.lo \
+ core/sys/linux/unistd.lo
@DRUNTIME_OS_LINUX_TRUE@am__objects_19 = $(am__objects_18)
am__objects_20 = core/sys/windows/accctrl.lo \
core/sys/windows/aclapi.lo core/sys/windows/aclui.lo \
core/sys/linux/sys/procfs.d core/sys/linux/sys/signalfd.d \
core/sys/linux/sys/socket.d core/sys/linux/sys/sysinfo.d \
core/sys/linux/sys/time.d core/sys/linux/sys/xattr.d \
- core/sys/linux/syscalls.d core/sys/linux/termios.d \
- core/sys/linux/time.d core/sys/linux/timerfd.d core/sys/linux/tipc.d \
- core/sys/linux/unistd.d
+ core/sys/linux/termios.d core/sys/linux/time.d \
+ core/sys/linux/timerfd.d core/sys/linux/tipc.d core/sys/linux/unistd.d
DRUNTIME_DSOURCES_NETBSD = core/sys/netbsd/dlfcn.d \
core/sys/netbsd/err.d core/sys/netbsd/execinfo.d \
core/sys/linux/sys/sysinfo.lo: core/sys/linux/sys/$(am__dirstamp)
core/sys/linux/sys/time.lo: core/sys/linux/sys/$(am__dirstamp)
core/sys/linux/sys/xattr.lo: core/sys/linux/sys/$(am__dirstamp)
-core/sys/linux/syscalls.lo: core/sys/linux/$(am__dirstamp)
core/sys/linux/termios.lo: core/sys/linux/$(am__dirstamp)
core/sys/linux/time.lo: core/sys/linux/$(am__dirstamp)
core/sys/linux/timerfd.lo: core/sys/linux/$(am__dirstamp)
enum AddType { no, yes }
- this( return const(char)[] buf_, return char[] dst_ = null )
+ this( return scope const(char)[] buf_, return scope char[] dst_ = null )
{
this( buf_, AddType.yes, dst_ );
}
- this( return const(char)[] buf_, AddType addType_, return char[] dst_ = null )
+ this( return scope const(char)[] buf_, AddType addType_, return scope char[] dst_ = null )
{
buf = buf_;
addType = addType_;
//throw new ParseException( msg );
debug(info) printf( "error: %.*s\n", cast(int) msg.length, msg.ptr );
throw __ctfe ? new ParseException(msg)
- : cast(ParseException) cast(void*) typeid(ParseException).initializer;
+ : cast(ParseException) __traits(initSymbol, ParseException).ptr;
}
//throw new OverflowException( msg );
debug(info) printf( "overflow: %.*s\n", cast(int) msg.length, msg.ptr );
- throw cast(OverflowException) cast(void*) typeid(OverflowException).initializer;
+ throw cast(OverflowException) __traits(initSymbol, OverflowException).ptr;
}
/**
* Does array initialization (not assignment) from another array of the same element type.
* Params:
+ * to = what array to initialize
* from = what data the array should be initialized with
+ * makeWeaklyPure = unused; its purpose is to prevent the function from becoming
+ * strongly pure and risk being optimised out
* Returns:
* The created and initialized array `to`
* Bugs:
* This function template was ported from a much older runtime hook that bypassed safety,
* purity, and throwabilty checks. To prevent breaking existing code, this function template
* is temporarily declared `@trusted` until the implementation can be brought up to modern D expectations.
+ *
+ * The third parameter is never used, but is necessary in order for the
+ * function be treated as weakly pure, instead of strongly pure.
+ * This is needed because constructions such as the one below can be ignored by
+ * the compiler if `_d_arrayctor` is believed to be pure, because purity would
+ * mean the call to `_d_arrayctor` has no effects (no side effects and the
+ * return value is ignored), despite it actually modifying the contents of `a`.
+ * const S[2] b;
+ * const S[2] a = b; // this would get lowered to _d_arrayctor(a, b)
*/
-Tarr1 _d_arrayctor(Tarr1 : T1[], Tarr2 : T2[], T1, T2)(scope Tarr2 from) @trusted
- if (is(Unqual!T1 == Unqual!T2))
+Tarr _d_arrayctor(Tarr : T[], T)(return scope Tarr to, scope Tarr from, char* makeWeaklyPure = null) @trusted
{
pragma(inline, false);
import core.internal.traits : hasElaborateCopyConstructor;
import core.stdc.stdint : uintptr_t;
debug(PRINTF) import core.stdc.stdio : printf;
- debug(PRINTF) printf("_d_arrayctor(to = %p,%d, from = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, T1.tsize);
+ debug(PRINTF) printf("_d_arrayctor(from = %p,%d) size = %d\n", from.ptr, from.length, T.sizeof);
- Tarr1 to = void;
+ void[] vFrom = (cast(void*) from.ptr)[0..from.length];
+ void[] vTo = (cast(void*) to.ptr)[0..to.length];
- void[] vFrom = (cast(void*)from.ptr)[0..from.length];
- void[] vTo = (cast(void*)to.ptr)[0..to.length];
-
- // Force `enforceRawArraysConformable` to be `pure`
+ // Force `enforceRawArraysConformable` to remain weakly `pure`
void enforceRawArraysConformable(const char[] action, const size_t elementSize,
const void[] a1, const void[] a2) @trusted
{
(cast(Type)&enforceRawArraysConformableNogc)(action, elementSize, a1, a2, false);
}
- enforceRawArraysConformable("initialization", T1.sizeof, vFrom, vTo);
+ enforceRawArraysConformable("initialization", T.sizeof, vFrom, vTo);
- static if (hasElaborateCopyConstructor!T1)
+ static if (hasElaborateCopyConstructor!T)
{
size_t i;
try
*/
while (i--)
{
- auto elem = cast(Unqual!T1*)&to[i];
+ auto elem = cast(Unqual!T*) &to[i];
destroy(*elem);
}
else
{
// blit all elements at once
- memcpy(cast(void*) to.ptr, from.ptr, to.length * T1.sizeof);
+ memcpy(cast(void*) to.ptr, from.ptr, to.length * T.sizeof);
}
return to;
S[4] arr1;
S[4] arr2 = [S(0), S(1), S(2), S(3)];
- arr1 = _d_arrayctor!(typeof(arr1))(arr2[]);
+ _d_arrayctor(arr1[], arr2[]);
assert(counter == 4);
assert(arr1 == arr2);
S[4] arr1;
S[4] arr2 = [S(0), S(1), S(2), S(3)];
- arr1 = _d_arrayctor!(typeof(arr1))(arr2[]);
+ _d_arrayctor(arr1[], arr2[]);
assert(counter == 4);
assert(arr1 == arr2);
{
Throw[4] a;
Throw[4] b = [Throw(1), Throw(2), Throw(3), Throw(4)];
- a = _d_arrayctor!(typeof(a))(b[]);
+ _d_arrayctor(a[], b[]);
}
catch (Exception)
{
{
NoThrow[4] a;
NoThrow[4] b = [NoThrow(1), NoThrow(2), NoThrow(3), NoThrow(4)];
- a = _d_arrayctor!(typeof(a))(b[]);
+ _d_arrayctor(a[], b[]);
}
catch (Exception)
{
{
Throw[4] a;
Throw[4] b = [Throw(1), Throw(2), Throw(3), Throw(4)];
- a = _d_arrayctor!(typeof(a))(b[]);
+ _d_arrayctor(a[], b[]);
}
catch (Exception)
{
}
@trusted pure nothrow @nogc
-const(ubyte)[] toUbyte(T)(const ref return scope T val) if (is(T == struct) || is(T == union))
+const(ubyte)[] toUbyte(T)(const return ref scope T val) if (is(T == struct) || is(T == union))
{
if (__ctfe)
{
}
else
{
- return (cast(const(ubyte)*)&val)[0 .. T.sizeof];
+ // We're escaping a reference to `val` here because we cannot express
+ // ref return + scope, it's currently seen as ref + return scope
+ // https://issues.dlang.org/show_bug.cgi?id=22541
+ // Once fixed, the @system lambda should be removed
+ return (() @system => (cast(const(ubyte)*)&val)[0 .. T.sizeof])();
}
}
In contrast to `emplaceRef(chunk)`, there are no checks for disabled default
constructors etc.
+/
-template emplaceInitializer(T)
+void emplaceInitializer(T)(scope ref T chunk) nothrow pure @trusted
if (!is(T == const) && !is(T == immutable) && !is(T == inout))
{
- import core.internal.traits : hasElaborateAssign, Unqual;
+ import core.internal.traits : hasElaborateAssign;
- // Avoid stack allocation by hacking to get to the struct/union init symbol.
- static if (is(T == struct) || is(T == union))
+ static if (__traits(isZeroInit, T))
{
- pragma(mangle, "_D" ~ Unqual!T.mangleof[1..$] ~ "6__initZ")
- __gshared extern immutable T initializer;
+ import core.stdc.string : memset;
+ memset(cast(void*) &chunk, 0, T.sizeof);
}
-
- void emplaceInitializer(scope ref T chunk) nothrow pure @trusted
+ else static if (__traits(isScalar, T) ||
+ T.sizeof <= 16 && !hasElaborateAssign!T && __traits(compiles, (){ T chunk; chunk = T.init; }))
{
- static if (__traits(isZeroInit, T))
- {
- import core.stdc.string : memset;
- memset(cast(void*) &chunk, 0, T.sizeof);
- }
- else static if (__traits(isScalar, T) ||
- T.sizeof <= 16 && !hasElaborateAssign!T && __traits(compiles, (){ T chunk; chunk = T.init; }))
- {
- chunk = T.init;
- }
- else static if (__traits(isStaticArray, T))
- {
- // For static arrays there is no initializer symbol created. Instead, we emplace elements one-by-one.
- foreach (i; 0 .. T.length)
- {
- emplaceInitializer(chunk[i]);
- }
- }
- else
+ chunk = T.init;
+ }
+ else static if (__traits(isStaticArray, T))
+ {
+ // For static arrays there is no initializer symbol created. Instead, we emplace elements one-by-one.
+ foreach (i; 0 .. T.length)
{
- import core.stdc.string : memcpy;
- memcpy(cast(void*)&chunk, &initializer, T.sizeof);
+ emplaceInitializer(chunk[i]);
}
}
+ else
+ {
+ import core.stdc.string : memcpy;
+ const initializer = __traits(initSymbol, T);
+ memcpy(cast(void*)&chunk, initializer.ptr, initializer.length);
+ }
}
@safe unittest
if (neg)
{
// about to do a slice without a bounds check
- auto trustedSlice(return char[] r) @trusted { assert(r.ptr > buf.ptr); return (r.ptr-1)[0..r.length+1]; }
+ auto trustedSlice(return scope char[] r) @trusted { assert(r.ptr > buf.ptr); return (r.ptr-1)[0..r.length+1]; }
r = trustedSlice(r);
r[0] = '-';
}
/* =================== Conversion to UTF8 ======================= */
@safe pure nothrow @nogc
-char[] toUTF8(return char[] buf, dchar c)
+char[] toUTF8(return scope char[] buf, dchar c)
in
{
assert(isValidDchar(c));
* Encodes string s into UTF-8 and returns the encoded string.
*/
@safe pure nothrow
-string toUTF8(return string s)
+string toUTF8(return scope string s)
in
{
validate(s);
/* =================== Conversion to UTF16 ======================= */
@safe pure nothrow @nogc
-wchar[] toUTF16(return wchar[] buf, dchar c)
+wchar[] toUTF16(return scope wchar[] buf, dchar c)
in
{
assert(isValidDchar(c));
/** ditto */
@safe pure nothrow
-wstring toUTF16(return wstring s)
+wstring toUTF16(return scope wstring s)
in
{
validate(s);
/** ditto */
@safe pure nothrow
-dstring toUTF32(return dstring s)
+dstring toUTF32(return scope dstring s)
in
{
validate(s);
" is abstract and it can't be emplaced");
// Initialize the object in its pre-ctor state
- enum classSize = __traits(classInstanceSize, T);
- (() @trusted => (cast(void*) chunk)[0 .. classSize] = typeid(T).initializer[])();
+ const initializer = __traits(initSymbol, T);
+ (() @trusted { (cast(void*) chunk)[0 .. initializer.length] = initializer[]; })();
static if (isInnerClass!T)
{
assert(c.i == 5);
}
+///
+@betterC
+@nogc pure nothrow @system unittest
+{
+ // works with -betterC too:
+
+ static extern (C++) class C
+ {
+ @nogc pure nothrow @safe:
+ int i = 3;
+ this(int i)
+ {
+ assert(this.i == 3);
+ this.i = i;
+ }
+ int virtualGetI() { return i; }
+ }
+
+ import core.internal.traits : classInstanceAlignment;
+
+ align(classInstanceAlignment!C) byte[__traits(classInstanceSize, C)] buffer;
+ C c = emplace!C(buffer[], 42);
+ assert(c.virtualGetI() == 42);
+}
+
@system unittest
{
class Outer
static if (is(T == struct))
{
- // Unsafe when compiling without -dip1000
+ // Unsafe when compiling without -preview=dip1000
if ((() @trusted => &source == &target)()) return;
// Destroy target before overwriting it
static if (hasElaborateDestructor!T) target.__xdtor();
static if (is(T == struct))
{
- // Unsafe when compiling without -dip1000
+ // Unsafe when compiling without -preview=dip1000
assert((() @trusted => &source !is &target)(), "source and target must not be identical");
static if (hasElaborateAssign!T || !isAssignable!T)
static if (__traits(isZeroInit, T))
() @trusted { memset(&source, 0, sz); }();
else
- {
- import core.internal.lifetime : emplaceInitializer;
- ubyte[T.sizeof] init = void;
- emplaceInitializer(*(() @trusted { return cast(T*)init.ptr; }()));
- () @trusted { memcpy(&source, init.ptr, sz); }();
- }
+ () @trusted { memcpy(&source, __traits(initSymbol, T).ptr, sz); }();
}
}
else static if (__traits(isStaticArray, T))
static assert(!__traits(compiles, f(ncarray)));
f(move(ncarray));
}
+
+/**
+ * This is called for a delete statement where the value
+ * being deleted is a pointer to a struct with a destructor
+ * but doesn't have an overloaded delete operator.
+ *
+ * Params:
+ * p = pointer to the value to be deleted
+ */
+void _d_delstruct(T)(ref T *p)
+{
+ if (p)
+ {
+ debug(PRINTF) printf("_d_delstruct(%p)\n", p);
+
+ import core.memory : GC;
+
+ destroy(*p);
+ GC.free(p);
+ p = null;
+ }
+}
+
+@system unittest
+{
+ int dtors = 0;
+ struct S { ~this() { ++dtors; } }
+
+ S *s = new S();
+ _d_delstruct(s);
+
+ assert(s == null);
+ assert(dtors == 1);
+}
+
+@system unittest
+{
+ int innerDtors = 0;
+ int outerDtors = 0;
+
+ struct Inner { ~this() { ++innerDtors; } }
+ struct Outer
+ {
+ Inner *i1;
+ Inner *i2;
+
+ this(int x)
+ {
+ i1 = new Inner();
+ i2 = new Inner();
+ }
+
+ ~this()
+ {
+ ++outerDtors;
+
+ _d_delstruct(i1);
+ assert(i1 == null);
+
+ _d_delstruct(i2);
+ assert(i2 == null);
+ }
+ }
+
+ Outer *o = new Outer(0);
+ _d_delstruct(o);
+
+ assert(o == null);
+ assert(innerDtors == 2);
+ assert(outerDtors == 1);
+}
* reentrant, and must be called once for every call to disable before
* automatic collections are enabled.
*/
- pragma(mangle, "gc_enable") static void enable() nothrow; /* FIXME pure */
+ pragma(mangle, "gc_enable") static void enable() nothrow pure;
/**
* such as during an out of memory condition. This function is reentrant,
* but enable must be called once for each call to disable.
*/
- pragma(mangle, "gc_disable") static void disable() nothrow; /* FIXME pure */
+ pragma(mangle, "gc_disable") static void disable() nothrow pure;
/**
* and then to reclaim free space. This action may need to suspend all
* running threads for at least part of the collection process.
*/
- pragma(mangle, "gc_collect") static void collect() nothrow; /* FIXME pure */
+ pragma(mangle, "gc_collect") static void collect() nothrow pure;
/**
* Indicates that the managed memory space be minimized by returning free
* physical memory to the operating system. The amount of free memory
* returned depends on the allocator design and on program behavior.
*/
- pragma(mangle, "gc_minimize") static void minimize() nothrow; /* FIXME pure */
+ pragma(mangle, "gc_minimize") static void minimize() nothrow pure;
extern(D):
* Throws:
* `OutOfMemoryError` on allocation failure.
*/
- pragma(mangle, "gc_realloc") static void* realloc(return void* p, size_t sz, uint ba = 0, const TypeInfo ti = null) pure nothrow;
+ pragma(mangle, "gc_realloc") static void* realloc(return scope void* p, size_t sz, uint ba = 0, const TypeInfo ti = null) pure nothrow;
// https://issues.dlang.org/show_bug.cgi?id=13111
///
* Returns:
* The actual number of bytes reserved or zero on error.
*/
- pragma(mangle, "gc_reserve") static size_t reserve(size_t sz) nothrow; /* FIXME pure */
+ pragma(mangle, "gc_reserve") static size_t reserve(size_t sz) nothrow pure;
/**
* }
* ---
*/
- pragma(mangle, "gc_addRoot") static void addRoot(const void* p) nothrow @nogc; /* FIXME pure */
+ pragma(mangle, "gc_addRoot") static void addRoot(const void* p) nothrow @nogc pure;
/**
* Params:
* p = A pointer into a GC-managed memory block or null.
*/
- pragma(mangle, "gc_removeRoot") static void removeRoot(const void* p) nothrow @nogc; /* FIXME pure */
+ pragma(mangle, "gc_removeRoot") static void removeRoot(const void* p) nothrow @nogc pure;
/**
* // rawMemory will be recognized on collection.
* ---
*/
- pragma(mangle, "gc_addRange") static void addRange(const void* p, size_t sz, const TypeInfo ti = null) @nogc nothrow; /* FIXME pure */
+ pragma(mangle, "gc_addRange")
+ static void addRange(const void* p, size_t sz, const TypeInfo ti = null) @nogc nothrow pure;
/**
* Params:
* p = A pointer to a valid memory address or to null.
*/
- pragma(mangle, "gc_removeRange") static void removeRange(const void* p) nothrow @nogc; /* FIXME pure */
+ pragma(mangle, "gc_removeRange") static void removeRange(const void* p) nothrow @nogc pure;
/**
else version (WatchOS)
version = Darwin;
+version (CRuntime_Glibc)
+ version = AlignedAllocSupported;
+else {}
+
extern (C):
@system:
///
void free(void* ptr);
+/// since C11
+version (AlignedAllocSupported)
+{
+ void* aligned_alloc(size_t alignment, size_t size);
+}
+
///
noreturn abort() @safe;
///
@nogc:
///
-inout(void)* memchr(return inout void* s, int c, size_t n) pure;
+inout(void)* memchr(return scope inout void* s, int c, size_t n) pure;
///
int memcmp(scope const void* s1, scope const void* s2, size_t n) pure;
///
-void* memcpy(return void* s1, scope const void* s2, size_t n) pure;
+void* memcpy(return scope void* s1, scope const void* s2, size_t n) pure;
version (Windows)
{
///
int memicmp(scope const char* s1, scope const char* s2, size_t n);
}
///
-void* memmove(return void* s1, scope const void* s2, size_t n) pure;
+void* memmove(return scope void* s1, scope const void* s2, size_t n) pure;
///
-void* memset(return void* s, int c, size_t n) pure;
+void* memset(return scope void* s, int c, size_t n) pure;
///
-char* strcat(return char* s1, scope const char* s2) pure;
+char* strcat(return scope char* s1, scope const char* s2) pure;
///
-inout(char)* strchr(return inout(char)* s, int c) pure;
+inout(char)* strchr(return scope inout(char)* s, int c) pure;
///
int strcmp(scope const char* s1, scope const char* s2) pure;
///
int strcoll(scope const char* s1, scope const char* s2);
///
-char* strcpy(return char* s1, scope const char* s2) pure;
+char* strcpy(return scope char* s1, scope const char* s2) pure;
///
size_t strcspn(scope const char* s1, scope const char* s2) pure;
///
version (ReturnStrerrorR)
{
///
- const(char)* strerror_r(int errnum, return char* buf, size_t buflen);
+ const(char)* strerror_r(int errnum, return scope char* buf, size_t buflen);
}
// This one is
else
///
size_t strlen(scope const char* s) pure;
///
-char* strncat(return char* s1, scope const char* s2, size_t n) pure;
+char* strncat(return scope char* s1, scope const char* s2, size_t n) pure;
///
int strncmp(scope const char* s1, scope const char* s2, size_t n) pure;
///
-char* strncpy(return char* s1, scope const char* s2, size_t n) pure;
+char* strncpy(return scope char* s1, scope const char* s2, size_t n) pure;
///
-inout(char)* strpbrk(return inout(char)* s1, scope const char* s2) pure;
+inout(char)* strpbrk(return scope inout(char)* s1, scope const char* s2) pure;
///
-inout(char)* strrchr(return inout(char)* s, int c) pure;
+inout(char)* strrchr(return scope inout(char)* s, int c) pure;
///
size_t strspn(scope const char* s1, scope const char* s2) pure;
///
-inout(char)* strstr(return inout(char)* s1, scope const char* s2) pure;
+inout(char)* strstr(return scope inout(char)* s1, scope const char* s2) pure;
///
-char* strtok(return char* s1, scope const char* s2);
+char* strtok(return scope char* s1, scope const char* s2);
///
size_t strxfrm(scope char* s1, scope const char* s2, size_t n);
ulong wcstoull(const scope wchar_t* nptr, wchar_t** endptr, int base);
///
-pure wchar_t* wcscpy(return wchar_t* s1, scope const wchar_t* s2);
+pure wchar_t* wcscpy(return scope wchar_t* s1, scope const wchar_t* s2);
///
-pure wchar_t* wcsncpy(return wchar_t* s1, scope const wchar_t* s2, size_t n);
+pure wchar_t* wcsncpy(return scope wchar_t* s1, scope const wchar_t* s2, size_t n);
///
-pure wchar_t* wcscat(return wchar_t* s1, scope const wchar_t* s2);
+pure wchar_t* wcscat(return scope wchar_t* s1, scope const wchar_t* s2);
///
-pure wchar_t* wcsncat(return wchar_t* s1, scope const wchar_t* s2, size_t n);
+pure wchar_t* wcsncat(return scope wchar_t* s1, scope const wchar_t* s2, size_t n);
///
pure int wcscmp(scope const wchar_t* s1, scope const wchar_t* s2);
///
///
size_t wcsxfrm(scope wchar_t* s1, scope const wchar_t* s2, size_t n);
///
-pure inout(wchar_t)* wcschr(return inout(wchar_t)* s, wchar_t c);
+pure inout(wchar_t)* wcschr(return scope inout(wchar_t)* s, wchar_t c);
///
pure size_t wcscspn(scope const wchar_t* s1, scope const wchar_t* s2);
///
-pure inout(wchar_t)* wcspbrk(return inout(wchar_t)* s1, scope const wchar_t* s2);
+pure inout(wchar_t)* wcspbrk(return scope inout(wchar_t)* s1, scope const wchar_t* s2);
///
-pure inout(wchar_t)* wcsrchr(return inout(wchar_t)* s, wchar_t c);
+pure inout(wchar_t)* wcsrchr(return scope inout(wchar_t)* s, wchar_t c);
///
pure size_t wcsspn(scope const wchar_t* s1, scope const wchar_t* s2);
///
-pure inout(wchar_t)* wcsstr(return inout(wchar_t)* s1, scope const wchar_t* s2);
+pure inout(wchar_t)* wcsstr(return scope inout(wchar_t)* s1, scope const wchar_t* s2);
///
-wchar_t* wcstok(return wchar_t* s1, scope const wchar_t* s2, wchar_t** ptr);
+wchar_t* wcstok(return scope wchar_t* s1, scope const wchar_t* s2, wchar_t** ptr);
///
pure size_t wcslen(scope const wchar_t* s);
///
-pure inout(wchar_t)* wmemchr(return inout wchar_t* s, wchar_t c, size_t n);
+pure inout(wchar_t)* wmemchr(return scope inout wchar_t* s, wchar_t c, size_t n);
///
pure int wmemcmp(scope const wchar_t* s1, scope const wchar_t* s2, size_t n);
///
-pure wchar_t* wmemcpy(return wchar_t* s1, scope const wchar_t* s2, size_t n);
+pure wchar_t* wmemcpy(return scope wchar_t* s1, scope const wchar_t* s2, size_t n);
///
-pure wchar_t* wmemmove(return wchar_t* s1, scope const wchar_t* s2, size_t n);
+pure wchar_t* wmemmove(return scope wchar_t* s1, scope const wchar_t* s2, size_t n);
///
-pure wchar_t* wmemset(return wchar_t* s, wchar_t c, size_t n);
+pure wchar_t* wmemset(return scope wchar_t* s, wchar_t c, size_t n);
///
size_t wcsftime(wchar_t* s, size_t maxsize, const scope wchar_t* format, const scope tm* timeptr);
version = GenericBaseException;
version (CppRuntime_Clang)
version = GenericBaseException;
+version (CppRuntime_Sun)
+ version = GenericBaseException;
extern (C++, "std"):
@nogc:
if (pthread_mutex_lock(&m_hndl) == 0)
return;
- SyncError syncErr = cast(SyncError) cast(void*) typeid(SyncError).initializer;
+ SyncError syncErr = cast(SyncError) __traits(initSymbol, SyncError).ptr;
syncErr.msg = "Unable to lock mutex.";
throw syncErr;
}
if (pthread_mutex_unlock(&m_hndl) == 0)
return;
- SyncError syncErr = cast(SyncError) cast(void*) typeid(SyncError).initializer;
+ SyncError syncErr = cast(SyncError) __traits(initSymbol, SyncError).ptr;
syncErr.msg = "Unable to unlock mutex.";
throw syncErr;
}
nothrow:
@nogc:
-pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
+pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
*/
ubyte GET_LIBRARY_ORDINAL(uint n_desc) @safe { return ((n_desc) >> 8) & 0xff; }
/// Ditto
-ref ushort SET_LIBRARY_ORDINAL(return scope ref ushort n_desc, uint ordinal) @safe
+ref ushort SET_LIBRARY_ORDINAL(return ref ushort n_desc, uint ordinal) @safe
{
return n_desc = (((n_desc) & 0x00ff) | (((ordinal) & 0xff) << 8));
}
static if (__DARWIN_C_LEVEL >= __DARWIN_C_FULL)
{
// ^ __OSX_AVAILABLE_STARTING(__MAC_10_7, __IPHONE_4_3);
- pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
+ pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
}
static if (__BSD_VISIBLE)
{
- pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
+ pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
}
static if (__BSD_VISIBLE)
{
- pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
+ pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
}
static if (__USE_GNU)
{
- pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
+ pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
}
+++ /dev/null
-module core.sys.linux.syscalls;
-
-version (linux):
-extern (C):
-@system:
-nothrow:
-@nogc:
-
-import core.stdc.config : c_long;
-
-version (CoreDdoc)
-{
- /// Linux system call number from Linux's asm/unistd.h
- enum SystemCall : c_long;
-}
-else version (X86_64)
-{
- // https://github.com/torvalds/linux/blob/v4.14/arch/sh/include/uapi/asm/unistd_64.h
- // https://github.com/torvalds/linux/blob/v4.14/arch/x86/entry/syscalls/syscall_64.tbl
- enum SystemCall : c_long
- {
- read = 0,
- write = 1,
- open = 2,
- close = 3,
- stat = 4,
- fstat = 5,
- lstat = 6,
- poll = 7,
- lseek = 8,
- mmap = 9,
- mprotect = 10,
- munmap = 11,
- brk = 12,
- rt_sigaction = 13,
- rt_sigprocmask = 14,
- rt_sigreturn = 15,
- ioctl = 16,
- pread64 = 17,
- pwrite64 = 18,
- readv = 19,
- writev = 20,
- access = 21,
- pipe = 22,
- select = 23,
- sched_yield = 24,
- mremap = 25,
- msync = 26,
- mincore = 27,
- madvise = 28,
- shmget = 29,
- shmat = 30,
- shmctl = 31,
- dup = 32,
- dup2 = 33,
- pause = 34,
- nanosleep = 35,
- getitimer = 36,
- alarm = 37,
- setitimer = 38,
- getpid = 39,
- sendfile = 40,
- socket = 41,
- connect = 42,
- accept = 43,
- sendto = 44,
- recvfrom = 45,
- sendmsg = 46,
- recvmsg = 47,
- shutdown = 48,
- bind = 49,
- listen = 50,
- getsockname = 51,
- getpeername = 52,
- socketpair = 53,
- setsockopt = 54,
- getsockopt = 55,
- clone = 56,
- fork = 57,
- vfork = 58,
- execve = 59,
- exit = 60,
- wait4 = 61,
- kill = 62,
- uname = 63,
- semget = 64,
- semop = 65,
- semctl = 66,
- shmdt = 67,
- msgget = 68,
- msgsnd = 69,
- msgrcv = 70,
- msgctl = 71,
- fcntl = 72,
- flock = 73,
- fsync = 74,
- fdatasync = 75,
- truncate = 76,
- ftruncate = 77,
- getdents = 78,
- getcwd = 79,
- chdir = 80,
- fchdir = 81,
- rename = 82,
- mkdir = 83,
- rmdir = 84,
- creat = 85,
- link = 86,
- unlink = 87,
- symlink = 88,
- readlink = 89,
- chmod = 90,
- fchmod = 91,
- chown = 92,
- fchown = 93,
- lchown = 94,
- umask = 95,
- gettimeofday = 96,
- getrlimit = 97,
- getrusage = 98,
- sysinfo = 99,
- times = 100,
- ptrace = 101,
- getuid = 102,
- syslog = 103,
- getgid = 104,
- setuid = 105,
- setgid = 106,
- geteuid = 107,
- getegid = 108,
- setpgid = 109,
- getppid = 110,
- getpgrp = 111,
- setsid = 112,
- setreuid = 113,
- setregid = 114,
- getgroups = 115,
- setgroups = 116,
- setresuid = 117,
- getresuid = 118,
- setresgid = 119,
- getresgid = 120,
- getpgid = 121,
- setfsuid = 122,
- setfsgid = 123,
- getsid = 124,
- capget = 125,
- capset = 126,
- rt_sigpending = 127,
- rt_sigtimedwait = 128,
- rt_sigqueueinfo = 129,
- rt_sigsuspend = 130,
- sigaltstack = 131,
- utime = 132,
- mknod = 133,
- uselib = 134,
- personality = 135,
- ustat = 136,
- statfs = 137,
- fstatfs = 138,
- sysfs = 139,
- getpriority = 140,
- setpriority = 141,
- sched_setparam = 142,
- sched_getparam = 143,
- sched_setscheduler = 144,
- sched_getscheduler = 145,
- sched_get_priority_max = 146,
- sched_get_priority_min = 147,
- sched_rr_get_interval = 148,
- mlock = 149,
- munlock = 150,
- mlockall = 151,
- munlockall = 152,
- vhangup = 153,
- modify_ldt = 154,
- pivot_root = 155,
- _sysctl = 156,
- prctl = 157,
- arch_prctl = 158,
- adjtimex = 159,
- setrlimit = 160,
- chroot = 161,
- sync = 162,
- acct = 163,
- settimeofday = 164,
- mount = 165,
- umount2 = 166,
- swapon = 167,
- swapoff = 168,
- reboot = 169,
- sethostname = 170,
- setdomainname = 171,
- iopl = 172,
- ioperm = 173,
- create_module = 174,
- init_module = 175,
- delete_module = 176,
- get_kernel_syms = 177,
- query_module = 178,
- quotactl = 179,
- nfsservctl = 180,
- getpmsg = 181,
- putpmsg = 182,
- afs_syscall = 183,
- tuxcall = 184,
- security = 185,
- gettid = 186,
- readahead = 187,
- setxattr = 188,
- lsetxattr = 189,
- fsetxattr = 190,
- getxattr = 191,
- lgetxattr = 192,
- fgetxattr = 193,
- listxattr = 194,
- llistxattr = 195,
- flistxattr = 196,
- removexattr = 197,
- lremovexattr = 198,
- fremovexattr = 199,
- tkill = 200,
- time = 201,
- futex = 202,
- sched_setaffinity = 203,
- sched_getaffinity = 204,
- set_thread_area = 205,
- io_setup = 206,
- io_destroy = 207,
- io_getevents = 208,
- io_submit = 209,
- io_cancel = 210,
- get_thread_area = 211,
- lookup_dcookie = 212,
- epoll_create = 213,
- epoll_ctl_old = 214,
- epoll_wait_old = 215,
- remap_file_pages = 216,
- getdents64 = 217,
- set_tid_address = 218,
- restart_syscall = 219,
- semtimedop = 220,
- fadvise64 = 221,
- timer_create = 222,
- timer_settime = 223,
- timer_gettime = 224,
- timer_getoverrun = 225,
- timer_delete = 226,
- clock_settime = 227,
- clock_gettime = 228,
- clock_getres = 229,
- clock_nanosleep = 230,
- exit_group = 231,
- epoll_wait = 232,
- epoll_ctl = 233,
- tgkill = 234,
- utimes = 235,
- vserver = 236,
- mbind = 237,
- set_mempolicy = 238,
- get_mempolicy = 239,
- mq_open = 240,
- mq_unlink = 241,
- mq_timedsend = 242,
- mq_timedreceive = 243,
- mq_notify = 244,
- mq_getsetattr = 245,
- kexec_load = 246,
- waitid = 247,
- add_key = 248,
- request_key = 249,
- keyctl = 250,
- ioprio_set = 251,
- ioprio_get = 252,
- inotify_init = 253,
- inotify_add_watch = 254,
- inotify_rm_watch = 255,
- migrate_pages = 256,
- openat = 257,
- mkdirat = 258,
- mknodat = 259,
- fchownat = 260,
- futimesat = 261,
- newfstatat = 262,
- unlinkat = 263,
- renameat = 264,
- linkat = 265,
- symlinkat = 266,
- readlinkat = 267,
- fchmodat = 268,
- faccessat = 269,
- pselect6 = 270,
- ppoll = 271,
- unshare = 272,
- set_robust_list = 273,
- get_robust_list = 274,
- splice = 275,
- tee = 276,
- sync_file_range = 277,
- vmsplice = 278,
- move_pages = 279,
- utimensat = 280,
- epoll_pwait = 281,
- signalfd = 282,
- timerfd_create = 283,
- eventfd = 284,
- fallocate = 285,
- timerfd_settime = 286,
- timerfd_gettime = 287,
- accept4 = 288,
- signalfd4 = 289,
- eventfd2 = 290,
- epoll_create1 = 291,
- dup3 = 292,
- pipe2 = 293,
- inotify_init1 = 294,
- preadv = 295,
- pwritev = 296,
- rt_tgsigqueueinfo = 297,
- perf_event_open = 298,
- recvmmsg = 299,
- fanotify_init = 300,
- fanotify_mark = 301,
- prlimit64 = 302,
- name_to_handle_at = 303,
- open_by_handle_at = 304,
- clock_adjtime = 305,
- syncfs = 306,
- sendmmsg = 307,
- setns = 308,
- getcpu = 309,
- process_vm_readv = 310,
- process_vm_writev = 311,
- kcmp = 312,
- finit_module = 313,
- sched_setattr = 314,
- sched_getattr = 315,
- renameat2 = 316,
- seccomp = 317,
- getrandom = 318,
- memfd_create = 319,
- kexec_file_load = 320,
- bpf = 321,
- execveat = 322,
- userfaultfd = 323,
- membarrier = 324,
- mlock2 = 325,
- copy_file_range = 326,
- preadv2 = 327,
- pwritev2 = 328,
- pkey_mprotect = 329,
- pkey_alloc = 330,
- pkey_free = 331,
- statx = 332,
- }
-}
-else version (X86)
-{
- // https://github.com/torvalds/linux/blob/master/arch/x86/entry/syscalls/syscall_32.tbl
- // https://github.com/torvalds/linux/blob/v4.14/arch/sh/include/uapi/asm/unistd_32.h
- enum SystemCall : c_long
- {
- restart_syscall = 0,
- exit = 1,
- fork = 2,
- read = 3,
- write = 4,
- open = 5,
- close = 6,
- waitpid = 7,
- creat = 8,
- link = 9,
- unlink = 10,
- execve = 11,
- chdir = 12,
- time = 13,
- mknod = 14,
- chmod = 15,
- lchown = 16,
- break_ = 17,
- oldstat = 18,
- lseek = 19,
- getpid = 20,
- mount = 21,
- umount = 22,
- setuid = 23,
- getuid = 24,
- stime = 25,
- ptrace = 26,
- alarm = 27,
- oldfstat = 28,
- pause = 29,
- utime = 30,
- stty = 31,
- gtty = 32,
- access = 33,
- nice = 34,
- ftime = 35,
- sync = 36,
- kill = 37,
- rename = 38,
- mkdir = 39,
- rmdir = 40,
- dup = 41,
- pipe = 42,
- times = 43,
- prof = 44,
- brk = 45,
- setgid = 46,
- getgid = 47,
- signal = 48,
- geteuid = 49,
- getegid = 50,
- acct = 51,
- umount2 = 52,
- lock = 53,
- ioctl = 54,
- fcntl = 55,
- mpx = 56,
- setpgid = 57,
- ulimit = 58,
- oldolduname = 59,
- umask = 60,
- chroot = 61,
- ustat = 62,
- dup2 = 63,
- getppid = 64,
- getpgrp = 65,
- setsid = 66,
- sigaction = 67,
- sgetmask = 68,
- ssetmask = 69,
- setreuid = 70,
- setregid = 71,
- sigsuspend = 72,
- sigpending = 73,
- sethostname = 74,
- setrlimit = 75,
- getrlimit = 76,
- getrusage = 77,
- gettimeofday = 78,
- settimeofday = 79,
- getgroups = 80,
- setgroups = 81,
- select = 82,
- symlink = 83,
- oldlstat = 84,
- readlink = 85,
- uselib = 86,
- swapon = 87,
- reboot = 88,
- readdir = 89,
- mmap = 90,
- munmap = 91,
- truncate = 92,
- ftruncate = 93,
- fchmod = 94,
- fchown = 95,
- getpriority = 96,
- setpriority = 97,
- profil = 98,
- statfs = 99,
- fstatfs = 100,
- ioperm = 101,
- socketcall = 102,
- syslog = 103,
- setitimer = 104,
- getitimer = 105,
- stat = 106,
- lstat = 107,
- fstat = 108,
- olduname = 109,
- iopl = 110,
- vhangup = 111,
- idle = 112,
- vm86old = 113,
- wait4 = 114,
- swapoff = 115,
- sysinfo = 116,
- ipc = 117,
- fsync = 118,
- sigreturn = 119,
- clone = 120,
- setdomainname = 121,
- uname = 122,
- modify_ldt = 123,
- adjtimex = 124,
- mprotect = 125,
- sigprocmask = 126,
- create_module = 127,
- init_module = 128,
- delete_module = 129,
- get_kernel_syms = 130,
- quotactl = 131,
- getpgid = 132,
- fchdir = 133,
- bdflush = 134,
- sysfs = 135,
- personality = 136,
- afs_syscall = 137,
- setfsuid = 138,
- setfsgid = 139,
- _llseek = 140,
- getdents = 141,
- _newselect = 142,
- flock = 143,
- msync = 144,
- readv = 145,
- writev = 146,
- getsid = 147,
- fdatasync = 148,
- _sysctl = 149,
- mlock = 150,
- munlock = 151,
- mlockall = 152,
- munlockall = 153,
- sched_setparam = 154,
- sched_getparam = 155,
- sched_setscheduler = 156,
- sched_getscheduler = 157,
- sched_yield = 158,
- sched_get_priority_max = 159,
- sched_get_priority_min = 160,
- sched_rr_get_interval = 161,
- nanosleep = 162,
- mremap = 163,
- setresuid = 164,
- getresuid = 165,
- vm86 = 166,
- query_module = 167,
- poll = 168,
- nfsservctl = 169,
- setresgid = 170,
- getresgid = 171,
- prctl = 172,
- rt_sigreturn = 173,
- rt_sigaction = 174,
- rt_sigprocmask = 175,
- rt_sigpending = 176,
- rt_sigtimedwait = 177,
- rt_sigqueueinfo = 178,
- rt_sigsuspend = 179,
- pread64 = 180,
- pwrite64 = 181,
- chown = 182,
- getcwd = 183,
- capget = 184,
- capset = 185,
- sigaltstack = 186,
- sendfile = 187,
- getpmsg = 188,
- putpmsg = 189,
- vfork = 190,
- ugetrlimit = 191,
- mmap2 = 192,
- truncate64 = 193,
- ftruncate64 = 194,
- stat64 = 195,
- lstat64 = 196,
- fstat64 = 197,
- lchown32 = 198,
- getuid32 = 199,
- getgid32 = 200,
- geteuid32 = 201,
- getegid32 = 202,
- setreuid32 = 203,
- setregid32 = 204,
- getgroups32 = 205,
- setgroups32 = 206,
- fchown32 = 207,
- setresuid32 = 208,
- getresuid32 = 209,
- setresgid32 = 210,
- getresgid32 = 211,
- chown32 = 212,
- setuid32 = 213,
- setgid32 = 214,
- setfsuid32 = 215,
- setfsgid32 = 216,
- pivot_root = 217,
- mincore = 218,
- madvise = 219,
- getdents64 = 220,
- fcntl64 = 221,
- gettid = 224,
- readahead = 225,
- setxattr = 226,
- lsetxattr = 227,
- fsetxattr = 228,
- getxattr = 229,
- lgetxattr = 230,
- fgetxattr = 231,
- listxattr = 232,
- llistxattr = 233,
- flistxattr = 234,
- removexattr = 235,
- lremovexattr = 236,
- fremovexattr = 237,
- tkill = 238,
- sendfile64 = 239,
- futex = 240,
- sched_setaffinity = 241,
- sched_getaffinity = 242,
- set_thread_area = 243,
- get_thread_area = 244,
- io_setup = 245,
- io_destroy = 246,
- io_getevents = 247,
- io_submit = 248,
- io_cancel = 249,
- fadvise64 = 250,
- exit_group = 252,
- lookup_dcookie = 253,
- epoll_create = 254,
- epoll_ctl = 255,
- epoll_wait = 256,
- remap_file_pages = 257,
- set_tid_address = 258,
- timer_create = 259,
- timer_settime = 260,
- timer_gettime = 261,
- timer_getoverrun = 262,
- timer_delete = 263,
- clock_settime = 264,
- clock_gettime = 265,
- clock_getres = 266,
- clock_nanosleep = 267,
- statfs64 = 268,
- fstatfs64 = 269,
- tgkill = 270,
- utimes = 271,
- fadvise64_64 = 272,
- vserver = 273,
- mbind = 274,
- get_mempolicy = 275,
- set_mempolicy = 276,
- mq_open = 277,
- mq_unlink = 278,
- mq_timedsend = 279,
- mq_timedreceive = 280,
- mq_notify = 281,
- mq_getsetattr = 282,
- kexec_load = 283,
- waitid = 284,
- add_key = 286,
- request_key = 287,
- keyctl = 288,
- ioprio_set = 289,
- ioprio_get = 290,
- inotify_init = 291,
- inotify_add_watch = 292,
- inotify_rm_watch = 293,
- migrate_pages = 294,
- openat = 295,
- mkdirat = 296,
- mknodat = 297,
- fchownat = 298,
- futimesat = 299,
- fstatat64 = 300,
- unlinkat = 301,
- renameat = 302,
- linkat = 303,
- symlinkat = 304,
- readlinkat = 305,
- fchmodat = 306,
- faccessat = 307,
- pselect6 = 308,
- ppoll = 309,
- unshare = 310,
- set_robust_list = 311,
- get_robust_list = 312,
- splice = 313,
- sync_file_range = 314,
- tee = 315,
- vmsplice = 316,
- move_pages = 317,
- getcpu = 318,
- epoll_pwait = 319,
- utimensat = 320,
- signalfd = 321,
- timerfd_create = 322,
- eventfd = 323,
- fallocate = 324,
- timerfd_settime = 325,
- timerfd_gettime = 326,
- signalfd4 = 327,
- eventfd2 = 328,
- epoll_create1 = 329,
- dup3 = 330,
- pipe2 = 331,
- inotify_init1 = 332,
- preadv = 333,
- pwritev = 334,
- rt_tgsigqueueinfo = 335,
- perf_event_open = 336,
- recvmmsg = 337,
- fanotify_init = 338,
- fanotify_mark = 339,
- prlimit64 = 340,
- name_to_handle_at = 341,
- open_by_handle_at = 342,
- clock_adjtime = 343,
- syncfs = 344,
- sendmmsg = 345,
- setns = 346,
- process_vm_readv = 347,
- process_vm_writev = 348,
- kcmp = 349,
- finit_module = 350,
- sched_setattr = 351,
- sched_getattr = 352,
- renameat2 = 353,
- seccomp = 354,
- getrandom = 355,
- memfd_create = 356,
- bpf = 357,
- execveat = 358,
- socket = 359,
- socketpair = 360,
- bind = 361,
- connect = 362,
- listen = 363,
- accept4 = 364,
- getsockopt = 365,
- setsockopt = 366,
- getsockname = 367,
- getpeername = 368,
- sendto = 369,
- sendmsg = 370,
- recvfrom = 371,
- recvmsg = 372,
- shutdown = 373,
- userfaultfd = 374,
- membarrier = 375,
- mlock2 = 376,
- copy_file_range = 377,
- preadv2 = 378,
- pwritev2 = 379,
- pkey_mprotect = 380,
- pkey_alloc = 381,
- pkey_free = 382,
- statx = 383,
- arch_prctl = 384,
- }
-}
module core.sys.linux.unistd;
+public import core.sys.posix.unistd;
+
version (linux):
-extern (C):
+extern(C):
nothrow:
@system:
-@nogc:
-
-public import core.sys.posix.unistd;
-public import core.sys.linux.syscalls : SystemCall;
-import core.stdc.config : c_long;
// Additional seek constants for sparse file handling
// from Linux's unistd.h, stdio.h, and linux/fs.h
// (see http://man7.org/linux/man-pages/man2/lseek.2.html)
-enum
-{
+enum {
/// Offset is relative to the next location containing data
SEEK_DATA = 3,
/// Offset is relative to the next hole (or EOF if file is not sparse)
// Exit all threads in a process
void exit_group(int status);
-
-/**
-Invoke system call specified by number, passing it the remaining arguments.
-This is completely system-dependent, and not often useful.
-
-In Unix, `syscall' sets `errno' for all errors and most calls return -1
-for errors; in many systems you cannot pass arguments or get return
-values for all system calls (`pipe', `fork', and `getppid' typically
-among them).
-
-In Mach, all system calls take normal arguments and always return an
-error code (zero for success).
-*/
-c_long syscall(SystemCall number, ...) @nogc nothrow;
static if (_NETBSD_SOURCE)
{
- pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
+ pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
}
static if (__BSD_VISIBLE)
{
void explicit_bzero(void*, size_t);
- pure void* memmem(return const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
+ pure void* memmem(return scope const void* haystack, size_t haystacklen, scope const void* needle, size_t needlelen);
void* memrchr(scope const void*, int, size_t);
size_t strlcat(char*, scope const char*, size_t);
size_t strlcpy(char*, scope const char*, size_t);
}
else version (Solaris)
{
+ //SIGABRT (defined in core.stdc.signal)
enum SIGALRM = 14;
enum SIGBUS = 10;
enum SIGCHLD = 18;
enum SIGCONT = 25;
+ //SIGFPE (defined in core.stdc.signal)
enum SIGHUP = 1;
+ //SIGILL (defined in core.stdc.signal)
+ //SIGINT (defined in core.stdc.signal)
enum SIGKILL = 9;
enum SIGPIPE = 13;
enum SIGQUIT = 3;
+ //SIGSEGV (defined in core.stdc.signal)
enum SIGSTOP = 23;
+ //SIGTERM (defined in core.stdc.signal)
enum SIGTSTP = 24;
enum SIGTTIN = 26;
enum SIGTTOU = 27;
uint[4] __bits;
}
+ enum SIG_BLOCK = 1;
+ enum SIG_UNBLOCK = 2;
+ enum SIG_SETMASK = 3;
+
struct siginfo_t
{
int si_signo;
___data __data;
}
+ enum SI_NOINFO = 32767;
+ enum SI_DTRACE = 2050;
+ enum SI_RCTL = 2049;
+ enum SI_USER = 0;
+ enum SI_LWP = -1;
+ enum SI_QUEUE = -2;
+ enum SI_TIMER = -3;
+ enum SI_ASYNCIO = -4;
+ enum SI_MESGQ = -5;
+
+ enum SIGIO = SIGPOLL;
+
int kill(pid_t, int);
int sigaction(int, const scope sigaction_t*, sigaction_t*);
int sigaddset(sigset_t*, int);
enum SIGPROF = 29;
enum SIGSYS = 12;
enum SIGTRAP = 5;
- enum SIGVTALRM = 31;
+ enum SIGVTALRM = 28;
enum SIGXCPU = 30;
- enum SIGXFSZ = 25;
+ enum SIGXFSZ = 31;
enum
{
public import core.stdc.string;
/// Copy string until character found
-void* memccpy(return void* dst, scope const void* src, int c, size_t n) pure;
+void* memccpy(return scope void* dst, scope const void* src, int c, size_t n) pure;
/// Copy string (including terminating '\0')
-char* stpcpy(return char* dst, scope const char* src) pure;
+char* stpcpy(return scope char* dst, scope const char* src) pure;
/// Ditto
-char* stpncpy(return char* dst, const char* src, size_t len) pure;
+char* stpncpy(return scope char* dst, const char* src, size_t len) pure;
/// Compare strings according to current collation
int strcoll_l(scope const char* s1, scope const char* s2, locale_t locale);
///
/// System signal messages
const(char)* strsignal(int);
/// Isolate sequential tokens in a null-terminated string
-char* strtok_r(return char* str, scope const char* sep, char** context) pure;
+char* strtok_r(return scope char* str, scope const char* sep, char** context) pure;
/// Transform a string under locale
size_t strxfrm_l(char* s1, scope const char* s2, size_t n, locale_t locale);
}
else
{
- extern (D) inout(ubyte)* CMSG_DATA( return inout(cmsghdr)* cmsg ) pure nothrow @nogc { return cast(ubyte*)( cmsg + 1 ); }
+ extern (D) inout(ubyte)* CMSG_DATA( return scope inout(cmsghdr)* cmsg ) pure nothrow @nogc { return cast(ubyte*)( cmsg + 1 ); }
}
private inout(cmsghdr)* __cmsg_nxthdr(inout(msghdr)*, inout(cmsghdr)*) pure nothrow @nogc;
enum SHF_OS_NONCONFORMING = 0x100;
enum SHF_GROUP = 0x200;
enum SHF_TLS = 0x400;
-
+enum SHF_COMPRESSED = 0x800;
enum SHF_MASKOS = 0x0ff00000;
enum SHF_MASKPROC = 0xf0000000;
enum NT_FDINFO = 22;
enum NT_SPYMASTER = 23;
enum NT_NUM = 23;
+
+enum SHF_ORDERED = 0x40000000;
+enum SHF_EXCLUDE = 0x80000000;
enum ELF_386_MAXPGSZ = 0x10000;
-enum SHF_ORDERED = 0x40000000;
-enum SHF_EXCLUDE = 0x80000000;
-
enum SHN_BEFORE = 0xff00;
enum SHN_AFTER = 0xff01;
enum SHT_SPARC_GOTDATA = 0x70000000;
-enum SHF_ORDERED = 0x40000000;
-enum SHF_EXCLUDE = 0x80000000;
-
enum SHN_BEFORE = 0xff00;
enum SHN_AFTER = 0xff01;
alias BOOL function(HANDLE hProcess, DWORD64 Address, DWORD64 *Displacement, IMAGEHLP_SYMBOLA64 *Symbol) SymGetSymFromAddr64Func;
alias DWORD function(PCSTR DecoratedName, PSTR UnDecoratedName, DWORD UndecoratedLength, DWORD Flags) UnDecorateSymbolNameFunc;
alias DWORD64 function(HANDLE hProcess, HANDLE hFile, PCSTR ImageName, PCSTR ModuleName, DWORD64 BaseOfDll, DWORD SizeOfDll) SymLoadModule64Func;
- alias BOOL function(HANDLE HProcess, PTSTR SearchPath, DWORD SearchPathLength) SymGetSearchPathFunc;
+ alias BOOL function(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength) SymGetSearchPathFunc;
+ alias BOOL function(HANDLE hProcess, PCSTR SearchPath) SymSetSearchPathFunc;
alias BOOL function(HANDLE hProcess, DWORD64 Address) SymUnloadModule64Func;
alias BOOL function(HANDLE hProcess, ULONG ActionCode, ulong CallbackContext, ulong UserContext) PSYMBOL_REGISTERED_CALLBACK64;
alias BOOL function(HANDLE hProcess, PSYMBOL_REGISTERED_CALLBACK64 CallbackFunction, ulong UserContext) SymRegisterCallback64Func;
UnDecorateSymbolNameFunc UnDecorateSymbolName;
SymLoadModule64Func SymLoadModule64;
SymGetSearchPathFunc SymGetSearchPath;
+ SymSetSearchPathFunc SymSetSearchPath;
SymUnloadModule64Func SymUnloadModule64;
SymRegisterCallback64Func SymRegisterCallback64;
ImagehlpApiVersionFunc ImagehlpApiVersion;
sm_inst.UnDecorateSymbolName = cast(UnDecorateSymbolNameFunc) GetProcAddress(sm_hndl,"UnDecorateSymbolName");
sm_inst.SymLoadModule64 = cast(SymLoadModule64Func) GetProcAddress(sm_hndl,"SymLoadModule64");
sm_inst.SymGetSearchPath = cast(SymGetSearchPathFunc) GetProcAddress(sm_hndl,"SymGetSearchPath");
+ sm_inst.SymSetSearchPath = cast(SymSetSearchPathFunc) GetProcAddress(sm_hndl,"SymSetSearchPath");
sm_inst.SymUnloadModule64 = cast(SymUnloadModule64Func) GetProcAddress(sm_hndl,"SymUnloadModule64");
sm_inst.SymRegisterCallback64 = cast(SymRegisterCallback64Func) GetProcAddress(sm_hndl, "SymRegisterCallback64");
sm_inst.ImagehlpApiVersion = cast(ImagehlpApiVersionFunc) GetProcAddress(sm_hndl, "ImagehlpApiVersion");
sm_inst.SymSetOptions && sm_inst.SymFunctionTableAccess64 && sm_inst.SymGetLineFromAddr64 &&
sm_inst.SymGetModuleBase64 && sm_inst.SymGetModuleInfo64 && sm_inst.SymGetSymFromAddr64 &&
sm_inst.UnDecorateSymbolName && sm_inst.SymLoadModule64 && sm_inst.SymGetSearchPath &&
- sm_inst.SymUnloadModule64 && sm_inst.SymRegisterCallback64 && sm_inst.ImagehlpApiVersion);
+ sm_inst.SymSetSearchPath && sm_inst.SymUnloadModule64 && sm_inst.SymRegisterCallback64 &&
+ sm_inst.ImagehlpApiVersion);
return &sm_inst;
}
// the effective maximum.
// maxupri
- result.PRIORITY_MIN = -clinfo[0];
+ result.PRIORITY_MIN = -cast(int)(clinfo[0]);
// by definition
result.PRIORITY_DEFAULT = 0;
}
status = sem_init( &suspendCount, 0, 0 );
assert( status == 0 );
}
- if (typeid(Thread).initializer.ptr)
- _mainThreadStore[] = typeid(Thread).initializer[];
+ _mainThreadStore[] = __traits(initSymbol, Thread)[];
Thread.sm_main = attachThread((cast(Thread)_mainThreadStore.ptr).__ctor());
}
// destruct manually as object.destroy is not @nogc
(cast(ThreadT) cast(void*) ThreadBase.sm_main).__dtor();
_d_monitordelete_nogc(ThreadBase.sm_main);
- if (typeid(ThreadT).initializer.ptr)
- _mainThreadStore[] = typeid(ThreadT).initializer[];
- else
- (cast(ubyte[])_mainThreadStore)[] = 0;
+ _mainThreadStore[] = __traits(initSymbol, ThreadT)[];
ThreadBase.sm_main = null;
assert(ThreadBase.sm_tbeg && ThreadBase.sm_tlen == 1);
// Helper functions
-private inout(TypeInfo) getElement(return inout TypeInfo value) @trusted pure nothrow
+private inout(TypeInfo) getElement(return scope inout TypeInfo value) @trusted pure nothrow
{
TypeInfo element = cast() value;
for (;;)
static if (initialize)
{
- enum classSize = __traits(classInstanceSize, T);
- (cast(void*)obj)[0 .. classSize] = typeid(T).initializer[];
+ const initializer = __traits(initSymbol, T);
+ (cast(void*)obj)[0 .. initializer.length] = initializer[];
}
}
else
public import core.internal.array.construction : _d_arraysetctor;
public import core.internal.array.capacity: _d_arraysetlengthTImpl;
+public import core.lifetime : _d_delstruct;
+
public import core.internal.dassert: _d_assert_fail;
public import core.internal.destruction: __ArrayDtor;
void* p = GC.malloc(sizeti + (2 + rtisize) * (void*).sizeof);
import core.stdc.string : memcpy;
- memcpy(p, typeid(TypeInfo_Struct).initializer().ptr, sizeti);
+ memcpy(p, __traits(initSymbol, TypeInfo_Struct).ptr, sizeti);
auto ti = cast(TypeInfo_Struct) p;
auto extra = cast(TypeInfo*)(p + sizeti);
extern (C) pure nothrow @nogc @safe
{
- Range _aaRange(return AA aa)
+ Range _aaRange(return scope AA aa)
{
if (!aa)
return Range();
* If it is null, return null.
* Else, undefined crash
*/
-Object _d_toObject(return void* p)
+Object _d_toObject(return scope void* p)
{
if (!p)
return null;
{
foreach (a; rt_args)
{
+ if (a == "--")
+ break;
+
if (a.length >= opt.length + 7 && a[0..6] == "--DRT-" &&
a[6 .. 6 + opt.length] == opt && a[6 + opt.length] == '=')
{
}
// strip const/immutable/shared/inout from type info
-inout(TypeInfo) unqualify(return inout(TypeInfo) cti) pure nothrow @nogc
+inout(TypeInfo) unqualify(return scope inout(TypeInfo) cti) pure nothrow @nogc
{
TypeInfo ti = cast() cti;
while (ti)
/**
get the start of the array for the given block
*/
-void *__arrayStart(return BlkInfo info) nothrow pure
+void *__arrayStart(return scope BlkInfo info) nothrow pure
{
return info.base + ((info.size & BIGLENGTHMASK) ? LARGEPREFIX : 0);
}
private:
-@property ref shared(Monitor*) monitor(return Object h) pure nothrow @nogc
+@property ref shared(Monitor*) monitor(return scope Object h) pure nothrow @nogc
{
return *cast(shared Monitor**)&h.__monitor;
}
-574bf883b790340fb753d6542ec48a3ba3e6cb82
+12329adb67fb43891d6e4e543e7257bc34db0aa7
The first line of this file holds the git revision number of the last
merge done from the dlang/phobos repository.
assert(res.equal("cba"));
}
-
/// Ditto
auto joiner(RoR)(RoR r)
if (isInputRange!RoR && isInputRange!(ElementType!RoR))
_currentBack = typeof(_currentBack).init;
}
+ void replaceCurrent(typeof(_current) current) @trusted
+ {
+ import core.lifetime : move;
+
+ current.move(_current);
+ }
+
+ static if (isBidirectional)
+ {
+ void replaceCurrentBack(typeof(_currentBack) currentBack) @trusted
+ {
+ import core.lifetime : move;
+
+ currentBack.move(_currentBack);
+ }
+ }
+
public:
this(RoR r)
{
_items = r;
+ // field _current must be initialized in constructor, because it is nested struct
+ _current = typeof(_current).init;
static if (isBidirectional && hasNested!Result)
_currentBack = typeof(_currentBack).init;
- // field _current must be initialized in constructor, because it is nested struct
mixin(popFrontEmptyElements);
static if (isBidirectional)
mixin(popBackEmptyElements);
// consumed when a .save'd copy of ourselves is iterated over. So
// we need to .save each subrange we traverse.
static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
- _current = _items.front.save;
+ replaceCurrent(_items.front.save);
else
- _current = _items.front;
+ replaceCurrent(_items.front);
}
else
{
- _current = typeof(_current).init;
+ replaceCurrent(typeof(_current).init);
}
};
static if (isBidirectional)
{
static if (is(typeof(null) : typeof(_currentBack)))
- r._currentBack = _currentBack is null ? null : _currentBack.save;
+ r.replaceCurrentBack(_currentBack is null ? null : _currentBack.save);
else
- r._currentBack = _currentBack.save;
+ r.replaceCurrentBack(_currentBack.save);
r.reachedFinalElement = reachedFinalElement;
}
return r;
static if (isForwardRange!RoR && isForwardRange!(ElementType!RoR))
{
if (reachedFinalElement)
- _current = _items.back.save;
+ replaceCurrent(_items.back.save);
else
- _currentBack = _items.back.save;
+ replaceCurrentBack(_items.back.save);
}
else
{
if (reachedFinalElement)
- _current = _items.back;
+ replaceCurrent(_items.back);
else
- _currentBack = _items.back;
+ replaceCurrentBack(_items.back);
}
}
else
{
- _current = typeof(_current).init;
- _currentBack = typeof(_currentBack).init;
+ replaceCurrent(typeof(_current).init);
+ replaceCurrentBack(typeof(_currentBack).init);
}
};
assert([[0]].joiner.save.back == 0);
}
+// https://issues.dlang.org/show_bug.cgi?id=22561
+@safe pure unittest
+{
+ import std.range : only;
+
+ static immutable struct S { int[] array; }
+ assert([only(S(null))].joiner.front == S(null));
+}
+
/++
Implements the homonym function (also known as `accumulate`, $(D
compress), `inject`, or `foldl`) present in various programming
static if (hasElaborateAssign!T)
{
import std.algorithm.internal : addressOf;
- //Elaborate opAssign. Must go the memcpy road.
- //We avoid calling emplace here, because our goal is to initialize to
- //the static state of T.init,
- //So we want to avoid any un-necassarilly CC'ing of T.init
+ //Elaborate opAssign. Must go the memcpy/memset road.
static if (!__traits(isZeroInit, T))
{
- auto p = typeid(T).initializer();
for ( ; !range.empty ; range.popFront() )
{
- static if (__traits(isStaticArray, T))
- {
- // static array initializer only contains initialization
- // for one element of the static array.
- auto elemp = cast(void *) addressOf(range.front);
- auto endp = elemp + T.sizeof;
- while (elemp < endp)
- {
- memcpy(elemp, p.ptr, p.length);
- elemp += p.length;
- }
- }
- else
- {
- memcpy(addressOf(range.front), p.ptr, T.sizeof);
- }
+ import core.internal.lifetime : emplaceInitializer;
+ emplaceInitializer(range.front);
}
}
else
static if (__traits(isZeroInit, T))
() @trusted { memset(&source, 0, sz); }();
else
- {
- auto init = typeid(T).initializer();
- () @trusted { memcpy(&source, init.ptr, sz); }();
- }
+ () @trusted { memcpy(&source, __traits(initSymbol, T).ptr, sz); }();
}
}
else static if (isStaticArray!T)
else
static assert(false, "`transform` returns an unsortable qualified type: " ~ TB.stringof);
- static trustedMalloc(size_t len) @trusted
+ static trustedMalloc()(size_t len) @trusted
{
import core.checkedint : mulu;
- import core.stdc.stdlib : malloc;
+ import core.memory : pureMalloc;
bool overflow;
const nbytes = mulu(len, T.sizeof, overflow);
if (overflow) assert(false, "multiplication overflowed");
- T[] result = (cast(T*) malloc(nbytes))[0 .. len];
+ T[] result = (cast(T*) pureMalloc(nbytes))[0 .. len];
static if (hasIndirections!T)
{
import core.memory : GC;
{
foreach (i; 0 .. length) collectException(destroy(xform1[i]));
}
- static void trustedFree(T[] p) @trusted
+ static void trustedFree()(T[] p) @trusted
{
- import core.stdc.stdlib : free;
+ import core.memory : pureFree;
static if (hasIndirections!T)
{
import core.memory : GC;
GC.removeRange(p.ptr);
}
- free(p.ptr);
+ pureFree(p.ptr);
}
trustedFree(xform1);
}
}
///
-@safe unittest
+@safe pure unittest
{
import std.algorithm.iteration : map;
import std.numeric : entropy;
assert(isSorted!("a > b")(map!(entropy)(arr)));
}
-@safe unittest
+@safe pure unittest
{
import std.algorithm.iteration : map;
import std.numeric : entropy;
assert(isSorted!("a < b")(map!(entropy)(arr)));
}
-@safe unittest
+@safe pure unittest
{
// binary transform function
string[] strings = [ "one", "two", "three" ];
}
// https://issues.dlang.org/show_bug.cgi?id=4909
-@safe unittest
+@safe pure unittest
{
import std.typecons : Tuple;
Tuple!(char)[] chars;
}
// https://issues.dlang.org/show_bug.cgi?id=5924
-@safe unittest
+@safe pure unittest
{
import std.typecons : Tuple;
Tuple!(char)[] chars;
}
// https://issues.dlang.org/show_bug.cgi?id=13965
-@safe unittest
+@safe pure unittest
{
import std.typecons : Tuple;
Tuple!(char)[] chars;
}
// https://issues.dlang.org/show_bug.cgi?id=13965
-@safe unittest
+@safe pure unittest
{
import std.algorithm.iteration : map;
import std.numeric : entropy;
if (msg.convertsTo!(Args))
{
- static if (is(ReturnType!(t) == bool))
+ alias RT = ReturnType!(t);
+ static if (is(RT == bool))
{
return msg.map(op);
}
else
{
msg.map(op);
- return true;
+ static if (!is(immutable RT == immutable noreturn))
+ return true;
}
}
}
if (!atomicLoad!(MemoryOrder.raw)(flag))
{
var = init;
- atomicStore!(MemoryOrder.rel)(flag, true);
+ static if (!is(immutable typeof(var) == immutable noreturn))
+ atomicStore!(MemoryOrder.rel)(flag, true);
}
}
}
immutable expected = Aggregate(42, [1, 2, 3, 4, 5]);
assert(result1 == expected);
}
+
+// Noreturn support
+@system unittest
+{
+ static noreturn foo(int) { throw new Exception(""); }
+
+ if (false) spawn(&foo, 1);
+ if (false) spawnLinked(&foo, 1);
+
+ if (false) receive(&foo);
+ if (false) receiveTimeout(Duration.init, &foo);
+
+ // Wrapped in __traits(compiles) to skip codegen which crashes dmd's backend
+ static assert(__traits(compiles, receiveOnly!noreturn() ));
+ static assert(__traits(compiles, send(Tid.init, noreturn.init) ));
+ static assert(__traits(compiles, prioritySend(Tid.init, noreturn.init) ));
+ static assert(__traits(compiles, yield(noreturn.init) ));
+
+ static assert(__traits(compiles, {
+ __gshared noreturn n;
+ initOnce!n(noreturn.init);
+ }));
+}
T _payload = T.init;
+ this (BaseNode _base, T _payload)
+ {
+ this._base = _base;
+ this._payload = _payload;
+ }
+
inout(BaseNode)* asBaseNode() inout @trusted
{
return &_base;
* Returns:
* true if node was added
*/
- private bool _add(return Elem n)
+ private bool _add(return scope Elem n)
{
Node result;
static if (!allowDuplicates)
}
{
- SysTime stFunc(scope const SysTime st) { return cast(SysTime) st; }
+ SysTime stFunc(scope const SysTime st) { return SysTime.init; }
auto interval = Interval!SysTime(SysTime(DateTime(2010, 7, 4, 12, 1, 7)),
SysTime(DateTime(2012, 1, 7, 14, 0, 0)));
auto ir = IntervalRange!(SysTime, Direction.fwd)(interval, &stFunc);
}
{
- SysTime stFunc(scope const SysTime st) { return cast(SysTime) st; }
+ SysTime stFunc(scope const SysTime st) { return SysTime.init; }
auto posInfInterval = PosInfInterval!SysTime(SysTime(DateTime(2010, 7, 4, 12, 1, 7)));
auto ir = PosInfIntervalRange!SysTime(posInfInterval, &stFunc);
}
}
{
- SysTime stFunc(scope const SysTime st) { return cast(SysTime)(st); }
+ SysTime stFunc(scope const SysTime st) { return SysTime.init; }
auto negInfInterval = NegInfInterval!SysTime(SysTime(DateTime(2012, 1, 7, 14, 0, 0)));
auto ir = NegInfIntervalRange!(SysTime)(negInfInterval, &stFunc);
}
given $(REF DateTime,std,datetime,date) is assumed to
be in the given time zone.
+/
- this(DateTime dateTime, immutable TimeZone tz = null) @safe nothrow
+ this(DateTime dateTime, return scope immutable TimeZone tz = null) return scope @safe nothrow
{
try
this(dateTime, Duration.zero, tz);
$(REF DateTimeException,std,datetime,date) if `fracSecs` is negative or if it's
greater than or equal to one second.
+/
- this(DateTime dateTime, Duration fracSecs, immutable TimeZone tz = null) @safe
+ this(DateTime dateTime, Duration fracSecs, return scope immutable TimeZone tz = null) return scope @safe
{
enforce(fracSecs >= Duration.zero, new DateTimeException("A SysTime cannot have negative fractional seconds."));
enforce(fracSecs < seconds(1), new DateTimeException("Fractional seconds must be less than one second."));
given $(REF Date,std,datetime,date) is assumed to be in the
given time zone.
+/
- this(Date date, immutable TimeZone tz = null) @safe nothrow
+ this(Date date, return scope immutable TimeZone tz = null) return scope @safe nothrow
{
_timezone = tz is null ? LocalTime() : tz;
$(LREF SysTime). If null,
$(REF LocalTime,std,datetime,timezone) will be used.
+/
- this(long stdTime, immutable TimeZone tz = null) @safe pure nothrow
+ this(long stdTime, return scope immutable TimeZone tz = null) return scope @safe pure nothrow
{
_stdTime = stdTime;
_timezone = tz is null ? LocalTime() : tz;
Returns: The `this` of this `SysTime`.
+/
- ref SysTime opAssign()(auto ref const(SysTime) rhs) return @safe pure nothrow scope
+ ref SysTime opAssign()(auto ref const(SysTime) rhs) return scope @safe pure nothrow
{
_stdTime = rhs._stdTime;
_timezone = rhs._timezone;
st = other;
assert(st == other);
+ version (none) // https://issues.dlang.org/show_bug.cgi?id=21175
static void testScope(scope ref SysTime left, const scope SysTime right) @safe
{
left = right;
hours - adjust the time to this $(LREF SysTime)'s time zone before
returning.
+/
- @property immutable(TimeZone) timezone() @safe const pure nothrow scope
+ @property immutable(TimeZone) timezone() @safe const pure nothrow return scope
{
return _timezone;
}
/++
Returns whether DST is in effect for this $(LREF SysTime).
+/
- @property bool dstInEffect() @safe const nothrow scope
+ @property bool dstInEffect() @safe const nothrow return scope
{
return _timezone.dstInEffect(_stdTime);
}
Returns what the offset from UTC is for this $(LREF SysTime).
It includes the DST offset in effect at that time (if any).
+/
- @property Duration utcOffset() @safe const nothrow scope
+ @property Duration utcOffset() @safe const nothrow return scope
{
return _timezone.utcOffsetAt(_stdTime);
}
@property override bool hasDST() @safe const nothrow @nogc { return false; }
- override bool dstInEffect(long stdTime) @safe const nothrow @nogc { return false; }
+ override bool dstInEffect(long stdTime) @safe const scope nothrow @nogc { return false; }
- override long utcToTZ(long stdTime) @safe const nothrow @nogc { return 0; }
+ override long utcToTZ(long stdTime) @safe const scope nothrow @nogc { return 0; }
- override long tzToUTC(long adjTime) @safe const nothrow @nogc { return 0; }
+ override long tzToUTC(long adjTime) @safe const scope nothrow @nogc { return 0; }
- override Duration utcOffsetAt(long stdTime) @safe const nothrow @nogc { return Duration.zero; }
+ override Duration utcOffsetAt(long stdTime) @safe const scope nothrow @nogc { return Duration.zero; }
private:
return _timezoneStorage is null ? InitTimeZone() : _timezoneStorage;
}
- pragma(inline, true) @property void _timezone(immutable TimeZone tz) @safe pure nothrow @nogc scope
+ pragma(inline, true) @property void _timezone(return scope immutable TimeZone tz) @safe pure nothrow @nogc scope
{
_timezoneStorage = tz;
}
However, on Windows, it may be the unabbreviated name (e.g. Pacific
Standard Time). Regardless, it is not the same as name.
+/
- @property string stdName() @safe const nothrow
+ @property string stdName() @safe const scope nothrow
{
return _stdName;
}
However, on Windows, it may be the unabbreviated name (e.g. Pacific
Daylight Time). Regardless, it is not the same as name.
+/
- @property string dstName() @safe const nothrow
+ @property string dstName() @safe const scope nothrow
{
return _dstName;
}
stdTime = The UTC time that needs to be checked for DST in this time
zone.
+/
- abstract bool dstInEffect(long stdTime) @safe const nothrow;
+ abstract bool dstInEffect(long stdTime) @safe const scope nothrow;
/++
stdTime = The UTC time that needs to be adjusted to this time zone's
time.
+/
- abstract long utcToTZ(long stdTime) @safe const nothrow;
+ abstract long utcToTZ(long stdTime) @safe const scope nothrow;
/++
adjTime = The time in this time zone that needs to be adjusted to
UTC time.
+/
- abstract long tzToUTC(long adjTime) @safe const nothrow;
+ abstract long tzToUTC(long adjTime) @safe const scope nothrow;
/++
stdTime = The UTC time for which to get the offset from UTC for this
time zone.
+/
- Duration utcOffsetAt(long stdTime) @safe const nothrow
+ Duration utcOffsetAt(long stdTime) @safe const scope nothrow
{
return dur!"hnsecs"(utcToTZ(stdTime) - stdTime);
}
dynamically rather than it being fixed like it would be with most time
zones.
+/
- @property override string stdName() @trusted const nothrow
+ @property override string stdName() @trusted const scope nothrow
{
version (Posix)
{
dynamically rather than it being fixed like it would be with most time
zones.
+/
- @property override string dstName() @trusted const nothrow
+ @property override string dstName() @trusted const scope nothrow
{
version (Posix)
{
stdTime = The UTC time that needs to be checked for DST in this time
zone.
+/
- override bool dstInEffect(long stdTime) @trusted const nothrow
+ override bool dstInEffect(long stdTime) @trusted const scope nothrow
{
import core.stdc.time : tm;
See_Also:
`TimeZone.utcToTZ`
+/
- override long utcToTZ(long stdTime) @trusted const nothrow
+ override long utcToTZ(long stdTime) @trusted const scope nothrow
{
version (Solaris)
return stdTime + convert!("seconds", "hnsecs")(tm_gmtoff(stdTime));
adjTime = The time in this time zone that needs to be adjusted to
UTC time.
+/
- override long tzToUTC(long adjTime) @trusted const nothrow
+ override long tzToUTC(long adjTime) @trusted const scope nothrow
{
version (Posix)
{
/++
Always returns false.
+/
- override bool dstInEffect(long stdTime) @safe const nothrow
+ override bool dstInEffect(long stdTime) @safe const scope nothrow
{
return false;
}
See_Also:
`TimeZone.utcToTZ`
+/
- override long utcToTZ(long stdTime) @safe const nothrow
+ override long utcToTZ(long stdTime) @safe const scope nothrow
{
return stdTime;
}
adjTime = The time in this time zone that needs to be adjusted to
UTC time.
+/
- override long tzToUTC(long adjTime) @safe const nothrow
+ override long tzToUTC(long adjTime) @safe const scope nothrow
{
return adjTime;
}
stdTime = The UTC time for which to get the offset from UTC for this
time zone.
+/
- override Duration utcOffsetAt(long stdTime) @safe const nothrow
+ override Duration utcOffsetAt(long stdTime) @safe const scope nothrow
{
return dur!"hnsecs"(0);
}
/++
Always returns false.
+/
- override bool dstInEffect(long stdTime) @safe const nothrow
+ override bool dstInEffect(long stdTime) @safe const scope nothrow
{
return false;
}
stdTime = The UTC time that needs to be adjusted to this time zone's
time.
+/
- override long utcToTZ(long stdTime) @safe const nothrow
+ override long utcToTZ(long stdTime) @safe const scope nothrow
{
return stdTime + _utcOffset.total!"hnsecs";
}
adjTime = The time in this time zone that needs to be adjusted to
UTC time.
+/
- override long tzToUTC(long adjTime) @safe const nothrow
+ override long tzToUTC(long adjTime) @safe const scope nothrow
{
return adjTime - _utcOffset.total!"hnsecs";
}
stdTime = The UTC time for which to get the offset from UTC for this
time zone.
+/
- override Duration utcOffsetAt(long stdTime) @safe const nothrow
+ override Duration utcOffsetAt(long stdTime) @safe const scope nothrow
{
return _utcOffset;
}
stdTime = The UTC time that needs to be checked for DST in this time
zone.
+/
- override bool dstInEffect(long stdTime) @safe const nothrow
+ override bool dstInEffect(long stdTime) @safe const scope nothrow
{
assert(!_transitions.empty);
stdTime = The UTC time that needs to be adjusted to this time zone's
time.
+/
- override long utcToTZ(long stdTime) @safe const nothrow
+ override long utcToTZ(long stdTime) @safe const scope nothrow
{
assert(!_transitions.empty);
adjTime = The time in this time zone that needs to be adjusted to
UTC time.
+/
- override long tzToUTC(long adjTime) @safe const nothrow
+ override long tzToUTC(long adjTime) @safe const scope nothrow
{
assert(!_transitions.empty, "UTC offset's not available");
}
- int calculateLeapSeconds(long stdTime) @safe const pure nothrow
+ int calculateLeapSeconds(long stdTime) @safe const scope pure nothrow
{
if (_leapSeconds.empty)
return 0;
current dates but will still return true for `hasDST` because the
time zone did at some point have DST.
+/
- @property override bool hasDST() @safe const nothrow;
+ @property override bool hasDST() @safe const scope nothrow;
/++
stdTime = The UTC time that needs to be checked for DST in this
time zone.
+/
- override bool dstInEffect(long stdTime) @safe const nothrow;
+ override bool dstInEffect(long stdTime) @safe const scope nothrow;
/++
stdTime = The UTC time that needs to be adjusted to this time
zone's time.
+/
- override long utcToTZ(long stdTime) @safe const nothrow;
+ override long utcToTZ(long stdTime) @safe const scope nothrow;
/++
adjTime = The time in this time zone that needs to be adjusted
to UTC time.
+/
- override long tzToUTC(long adjTime) @safe const nothrow;
+ override long tzToUTC(long adjTime) @safe const scope nothrow;
/++
else
alias TIME_ZONE_INFORMATION = void*;
- static bool _dstInEffect(const TIME_ZONE_INFORMATION* tzInfo, long stdTime) nothrow;
- static long _utcToTZ(const TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) nothrow;
- static long _tzToUTC(const TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) nothrow;
+ static bool _dstInEffect(const scope TIME_ZONE_INFORMATION* tzInfo, long stdTime) nothrow;
+ static long _utcToTZ(const scope TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) nothrow;
+ static long _tzToUTC(const scope TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) nothrow;
this() immutable pure
{
public:
- @property override bool hasDST() @safe const nothrow
+ @property override bool hasDST() @safe const scope nothrow
{
return _tzInfo.DaylightDate.wMonth != 0;
}
- override bool dstInEffect(long stdTime) @safe const nothrow
+ override bool dstInEffect(long stdTime) @safe const scope nothrow
{
return _dstInEffect(&_tzInfo, stdTime);
}
- override long utcToTZ(long stdTime) @safe const nothrow
+ override long utcToTZ(long stdTime) @safe const scope nothrow
{
return _utcToTZ(&_tzInfo, stdTime, hasDST);
}
- override long tzToUTC(long adjTime) @safe const nothrow
+ override long tzToUTC(long adjTime) @safe const scope nothrow
{
return _tzToUTC(&_tzInfo, adjTime, hasDST);
}
private:
- static bool _dstInEffect(const TIME_ZONE_INFORMATION* tzInfo, long stdTime) @trusted nothrow
+ static bool _dstInEffect(const scope TIME_ZONE_INFORMATION* tzInfo, long stdTime) @trusted nothrow
{
try
{
}
- static long _utcToTZ(const TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) @safe nothrow
+ static long _utcToTZ(const scope TIME_ZONE_INFORMATION* tzInfo, long stdTime, bool hasDST) @safe nothrow
{
if (hasDST && WindowsTimeZone._dstInEffect(tzInfo, stdTime))
return stdTime - convert!("minutes", "hnsecs")(tzInfo.Bias + tzInfo.DaylightBias);
}
- static long _tzToUTC(const TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) @trusted nothrow
+ static long _tzToUTC(const scope TIME_ZONE_INFORMATION* tzInfo, long adjTime, bool hasDST) @trusted nothrow
{
if (hasDST)
{
}
version (Posix) private extern (C) pragma(mangle, stat.mangleof)
-int trustedStat(const(FSChar)* namez, ref stat_t buf) @nogc nothrow @trusted;
+int trustedStat(scope const(FSChar)* namez, ref stat_t buf) @nogc nothrow @trusted;
/**
Get size of file `name` in bytes.
assert(!f.exists);
}
-private bool existsImpl(const(FSChar)* namez) @trusted nothrow @nogc
+private bool existsImpl(scope const(FSChar)* namez) @trusted nothrow @nogc
{
version (Windows)
{
version (Windows)
{
auto namez = name.tempCString!FSChar();
- static auto trustedGetFileAttributesW(const(FSChar)* namez) @trusted
+ static auto trustedGetFileAttributesW(scope const(FSChar)* namez) @trusted
{
return GetFileAttributesW(namez);
}
version (Windows)
{
auto namez = name.tempCString!FSChar();
- static auto trustedSetFileAttributesW(const(FSChar)* namez, uint dwFileAttributes) @trusted
+ static auto trustedSetFileAttributesW(scope const(FSChar)* namez, uint dwFileAttributes) @trusted
{
return SetFileAttributesW(namez, dwFileAttributes);
}
else version (Posix)
{
auto namez = name.tempCString!FSChar();
- static auto trustedChmod(const(FSChar)* namez, mode_t mode) @trusted
+ static auto trustedChmod(scope const(FSChar)* namez, mode_t mode) @trusted
{
return chmod(namez, mode);
}
version (Windows)
{
- static auto trustedChdir(const(FSChar)* pathz) @trusted
+ static auto trustedChdir(scope const(FSChar)* pathz) @trusted
{
return SetCurrentDirectoryW(pathz);
}
}
else version (Posix)
{
- static auto trustedChdir(const(FSChar)* pathz) @trusted
+ static auto trustedChdir(scope const(FSChar)* pathz) @trusted
{
return core.sys.posix.unistd.chdir(pathz) == 0;
}
version (Windows)
{
- static auto trustedCreateDirectoryW(const(FSChar)* pathz) @trusted
+ static auto trustedCreateDirectoryW(scope const(FSChar)* pathz) @trusted
{
return CreateDirectoryW(pathz, null);
}
{
import std.conv : octal;
- static auto trustedMkdir(const(FSChar)* pathz, mode_t mode) @trusted
+ static auto trustedMkdir(scope const(FSChar)* pathz, mode_t mode) @trusted
{
return core.sys.posix.sys.stat.mkdir(pathz, mode);
}
version (Windows)
{
- static auto trustedRmdir(const(FSChar)* pathz) @trusted
+ static auto trustedRmdir(scope const(FSChar)* pathz) @trusted
{
return RemoveDirectoryW(pathz);
}
}
else version (Posix)
{
- static auto trustedRmdir(const(FSChar)* pathz) @trusted
+ static auto trustedRmdir(scope const(FSChar)* pathz) @trusted
{
return core.sys.posix.unistd.rmdir(pathz) == 0;
}
return _size;
}
- @property SysTime timeCreated() const pure nothrow scope
+ @property SysTime timeCreated() const pure nothrow return scope
{
return cast(SysTime)_timeCreated;
}
- @property SysTime timeLastAccessed() const pure nothrow scope
+ @property SysTime timeLastAccessed() const pure nothrow return scope
{
return cast(SysTime)_timeLastAccessed;
}
- @property SysTime timeLastModified() const pure nothrow scope
+ @property SysTime timeLastModified() const pure nothrow return scope
{
return cast(SysTime)_timeLastModified;
}
@disable this(this);
alias ptr this; /// implicitly covert to raw pointer
- @property inout(To)* buffPtr() inout
+ @property inout(To)* buffPtr() return inout
{
return _ptr == useStack ? _buff.ptr : _ptr;
}
}
// return x / y
- static BigUint divInt(T)(scope return BigUint x, T y_) pure nothrow @safe
+ static BigUint divInt(T)(return scope BigUint x, T y_) pure nothrow @safe
if ( is(immutable T == immutable uint) )
{
uint y = y_;
}
// return x / y
- static BigUint div(scope return BigUint x, scope BigUint y) pure nothrow @safe
+ static BigUint div(return scope BigUint x, scope BigUint y) pure nothrow @safe
{
if (y.data.length > x.data.length)
return BigUint(ZERO);
}
// return x % y
- static BigUint mod(scope return BigUint x, scope BigUint y) pure nothrow @safe
+ static BigUint mod(return scope BigUint x, scope BigUint y) pure nothrow @safe
{
if (y.data.length > x.data.length) return x;
if (y.data.length == 1)
* exponentiation is used.
* Memory allocation is minimized: at most one temporary BigUint is used.
*/
- static BigUint pow(scope return BigUint x, ulong y) pure nothrow @safe
+ static BigUint pow(return scope BigUint x, ulong y) pure nothrow @safe
{
// Deal with the degenerate cases first.
if (y == 0) return BigUint(ONE);
}
// Remove leading zeros from x, to restore the BigUint invariant
-inout(BigDigit) [] removeLeadingZeros(scope return inout(BigDigit) [] x) pure nothrow @safe
+inout(BigDigit) [] removeLeadingZeros(return scope inout(BigDigit) [] x) pure nothrow @safe
{
size_t k = x.length;
while (k>1 && x[k - 1]==0) --k;
// every 8 digits.
// buff.length must be data.length*8 if separator is zero,
// or data.length*9 if separator is non-zero. It will be completely filled.
-char [] biguintToHex(scope return char [] buff, const scope BigDigit [] data, char separator=0,
+char [] biguintToHex(return scope char [] buff, const scope BigDigit [] data, char separator=0,
LetterCase letterCase = LetterCase.upper) pure nothrow @safe
{
int x=0;
return store.str;
}
/// ditto
- @property string str(return string v) pure nothrow @nogc @trusted return // TODO make @safe
+ @property string str(return scope string v) pure nothrow @nogc @trusted return // TODO make @safe
{
assign(v);
return v;
return store.object;
}
/// ditto
- @property JSONValue[string] object(return JSONValue[string] v) pure nothrow @nogc @trusted // TODO make @safe
+ @property JSONValue[string] object(return scope JSONValue[string] v) pure nothrow @nogc @trusted // TODO make @safe
{
assign(v);
return v;
(*a)[0] = "world"; // segmentation fault
---
*/
- @property ref inout(JSONValue[]) array() inout pure @system
+ @property ref inout(JSONValue[]) array() return scope inout pure @system
{
enforce!JSONException(type == JSONType.array,
"JSONValue is not an array");
return store.array;
}
/// ditto
- @property JSONValue[] array(return JSONValue[] v) pure nothrow @nogc @trusted scope // TODO make @safe
+ @property JSONValue[] array(return scope JSONValue[] v) pure nothrow @nogc @trusted scope // TODO make @safe
{
assign(v);
return v;
* Hash syntax for json objects.
* Throws: `JSONException` if `type` is not `JSONType.object`.
*/
- ref inout(JSONValue) opIndex(return string k) inout pure @safe
+ ref inout(JSONValue) opIndex(return scope string k) inout pure @safe
{
auto o = this.objectNoRef;
return *enforce!JSONException(k in o,
so we can return `const(Char)[]` instead of `const(Char)[][]` using a
zero-length string to indicate no match.
+/
-const(Char)[] matchIPSuffix(Char)(return const(Char)[] s) @nogc nothrow pure @safe
+const(Char)[] matchIPSuffix(Char)(return scope const(Char)[] s) @nogc nothrow pure @safe
{
size_t end = s.length;
if (end < 7) return null;
multi-threaded programs. See e.g.
$(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
*/
- inout(char)[] opIndexAssign(return inout char[] value, scope const(char)[] name) @trusted
+ inout(char)[] opIndexAssign(return scope inout char[] value, scope const(char)[] name) @trusted
{
version (Posix)
{
void browse(scope const(char)[] url) nothrow @nogc @safe
{
+ const buffer = url.tempCString(); // Retain buffer until end of scope
const(char)*[3] args;
// Trusted because it's called with a zero-terminated literal
}
}
- const buffer = url.tempCString(); // Retain buffer until end of scope
args[1] = buffer;
args[2] = null;
assert(10.iota.randomSample(3, rnd2).equal([7, 8, 9]));
// Cover all elements in an array in random order
- version (X86_64) // https://issues.dlang.org/show_bug.cgi?id=15147
- assert(10.iota.randomCover(rnd2).equal([7, 4, 2, 0, 1, 6, 8, 3, 9, 5]));
+ version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147
+ assert(10.iota.randomCover(rnd2).equal([7, 4, 2, 0, 1, 6, 8, 3, 9, 5]));
+ else
+ assert(10.iota.randomCover(rnd2).equal([4, 8, 7, 3, 5, 9, 2, 6, 0, 1]));
// Shuffle an array
- version (X86_64) // https://issues.dlang.org/show_bug.cgi?id=15147
- assert([0, 1, 2, 4, 5].randomShuffle(rnd2).equal([2, 0, 4, 5, 1]));
+ version (D_LP64) // https://issues.dlang.org/show_bug.cgi?id=15147
+ assert([0, 1, 2, 4, 5].randomShuffle(rnd2).equal([2, 0, 4, 5, 1]));
+ else
+ assert([0, 1, 2, 4, 5].randomShuffle(rnd2).equal([4, 2, 5, 0, 1]));
}
version (StdUnittest)
auto namez = name.tempCString!FSChar();
auto modez = mode.tempCString!FSChar();
- static _fopenImpl(const(FSChar)* namez, const(FSChar)* modez) @trusted nothrow @nogc
+ static _fopenImpl(scope const(FSChar)* namez, scope const(FSChar)* modez) @trusted nothrow @nogc
{
version (Windows)
{
U stripped;
}
- void opAssign(T another) pure nothrow @nogc
+ void opAssign(return scope T another) pure nothrow @nogc
{
// If `T` defines `opCast` we must infer the safety
static if (hasMember!(T, "opCast"))
opAssign(initializer);
}
- @property inout(T) get() @trusted pure nothrow @nogc inout
+ @property inout(T) get() @trusted pure nothrow @nogc return scope inout
{
return original;
}
}
}
+ this (ref return scope inout Nullable!T rhs) inout
+ {
+ _isNull = rhs._isNull;
+ if (!_isNull)
+ _value.payload = rhs._value.payload;
+ else
+ _value = DontCallDestructorT.init;
+ }
+
/**
* If they are both null, then they are equal. If one is null and the other
* is not, then they are not equal. If they are both non-null, then they are
static struct S2 //inspired from 9404
{
Nullable!int ni;
- this(S2 other)
+ this(ref S2 other)
{
ni = other.ni;
}
- void opAssign(S2 other)
+ void opAssign(ref S2 other)
{
ni = other.ni;
}
assert((a ^ true) == Ternary.no);
assert((a ^ false) == Ternary.yes);
}
+
+// https://issues.dlang.org/show_bug.cgi?id=22511
+@safe unittest
+{
+ static struct S
+ {
+ int b;
+ @disable this(this);
+ this (ref return scope inout S rhs) inout
+ {
+ this.b = rhs.b + 1;
+ }
+ }
+
+ Nullable!S s1 = S(1);
+ Nullable!S s2 = s1;
+ assert(s2.get().b > s1.get().b);
+}
{
return this[0] == val[0] && this[1] == val[1];
}
- @property ref inout(uint) a() inout { return _tuple[0]; }
- @property ref inout(uint) b() inout { return _tuple[1]; }
+ @property ref inout(uint) a() return inout { return _tuple[0]; }
+ @property ref inout(uint) b() return inout { return _tuple[1]; }
}
/**
{
enum Empty = uint.max; // range is empty or just constructed
- this(return R r)
+ this(return scope R r)
{
this.r = r;
}
- this(return R r, uint buff)
+ this(return scope R r, uint buff)
{
this.r = r;
this.buff = buff;
static if (isBidirectionalRange!R)
{
- this(return R r, uint frontBuff, uint backBuff)
+ this(return scope R r, uint frontBuff, uint backBuff)
{
this.r = r;
this.buff = frontBuff;
{
static struct Result
{
- this(return R r)
+ this(return scope R r)
{
this.r = r;
}
- this(return R r, ushort pos, ushort fill, C[4 / C.sizeof] buf)
+ this(return scope R r, ushort pos, ushort fill, C[4 / C.sizeof] buf)
{
this.r = r;
this.pos = pos;
static if (isBidirectionalRange!R)
{
- this(return R r, ushort frontPos, ushort frontFill,
+ this(return scope R r, ushort frontPos, ushort frontFill,
ushort backPos, ushort backFill, C[4 / C.sizeof] buf)
{
this.r = r;
set config_test_list [list \
{ test19433 "--DRT-dont-eat-me" 0 } \
{ test20459 "foo bar -- --DRT-gcopts=profile:1" 0 } \
+ { test22523 "-- --DRT-testmode=run-main" 0 } \
]
# Initialize dg.
--- /dev/null
+// https://issues.dlang.org/show_bug.cgi?id=22523
+
+import core.stdc.stdio;
+
+int main()
+{
+ puts("Executed main although it should be skipped!");
+ return 1;
+}
+
+unittest {}