Mercurial > projects > ldc
diff dmd/expression.c @ 875:330f999ade44
Merged DMD 1.038
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 06 Jan 2009 16:33:51 +0100 |
parents | bc982f1ad106 |
children | 27a379f288bf |
line wrap: on
line diff
--- a/dmd/expression.c Tue Jan 06 15:54:48 2009 +0100 +++ b/dmd/expression.c Tue Jan 06 16:33:51 2009 +0100 @@ -12,7 +12,10 @@ #include <stdlib.h> #include <ctype.h> #include <assert.h> +#if _MSC_VER #include <complex> +#else +#endif #include <math.h> #if _WIN32 && __DMC__ @@ -68,6 +71,7 @@ #include "parse.h" Expression *createTypeInfoArray(Scope *sc, Expression *args[], int dim); +Expression *expandVar(int result, VarDeclaration *v); #define LOGSEMANTIC 0 @@ -168,10 +172,20 @@ precedence[TOKue] = PREC_rel; precedence[TOKin] = PREC_rel; +#if 0 precedence[TOKequal] = PREC_equal; precedence[TOKnotequal] = PREC_equal; precedence[TOKidentity] = PREC_equal; precedence[TOKnotidentity] = PREC_equal; +#else + /* Note that we changed precedence, so that < and != have the same + * precedence. This change is in the parser, too. + */ + precedence[TOKequal] = PREC_rel; + precedence[TOKnotequal] = PREC_rel; + precedence[TOKidentity] = PREC_rel; + precedence[TOKnotidentity] = PREC_rel; +#endif precedence[TOKand] = PREC_and; @@ -352,7 +366,7 @@ { Type *t = e->type->toBasetype(); - if (t->ty == Tfunction) + if (t->ty == Tfunction /*|| e->op == TOKoverloadset*/) { e = new CallExp(e->loc, e); e = e->semantic(sc); @@ -539,8 +553,6 @@ void functionArguments(Loc loc, Scope *sc, TypeFunction *tf, Expressions *arguments) { unsigned n; - int done; - Type *tb; //printf("functionArguments()\n"); assert(arguments); @@ -552,7 +564,7 @@ n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) - done = 0; + int done = 0; for (size_t i = 0; i < n; i++) { Expression *arg; @@ -561,6 +573,7 @@ arg = (Expression *)arguments->data[i]; else arg = NULL; + Type *tb; if (i < nparams) { @@ -615,11 +628,8 @@ break; } #endif - static int idn; - char name[10 + sizeof(idn)*3 + 1]; - sprintf(name, "__arrayArg%d", ++idn); - Identifier *id = Lexer::idPool(name); - Type *t = new TypeSArray(tb->next, new IntegerExp(nargs - i)); + Identifier *id = Lexer::uniqueId("__arrayArg"); + Type *t = new TypeSArray(((TypeArray *)tb)->next, new IntegerExp(nargs - i)); t = t->semantic(loc, sc); VarDeclaration *v = new VarDeclaration(loc, t, id, new VoidInitializer(loc)); v->semantic(sc); @@ -631,16 +641,19 @@ for (size_t u = i; u < nargs; u++) { Expression *a = (Expression *)arguments->data[u]; - if (tret && !tb->next->equals(a->type)) + if (tret && !((TypeArray *)tb)->next->equals(a->type)) a = a->toDelegate(sc, tret); Expression *e = new VarExp(loc, v); e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams)); - e = new AssignExp(loc, e, a); + AssignExp *ae = new AssignExp(loc, e, a); +#if DMDV2 + ae->op = TOKconstruct; +#endif if (c) - c = new CommaExp(loc, c, e); + c = new CommaExp(loc, c, ae); else - c = e; + c = ae; } arg = new VarExp(loc, v); if (c) @@ -694,12 +707,50 @@ } #endif +#if DMDV2 + if (tb->ty == Tstruct && !(p->storageClass & (STCref | STCout))) + { + arg = callCpCtor(loc, sc, arg); + } +#endif + // Convert lazy argument to a delegate if (p->storageClass & STClazy) { arg = arg->toDelegate(sc, p->type); } +#if DMDV2 + /* Look for arguments that cannot 'escape' from the called + * function. + */ + if (!tf->parameterEscapes(p)) + { + /* Function literals can only appear once, so if this + * appearance was scoped, there cannot be any others. + */ + if (arg->op == TOKfunction) + { FuncExp *fe = (FuncExp *)arg; + fe->fd->tookAddressOf = 0; + } + + /* 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. + */ + else if (arg->op == TOKdelegate) + { DelegateExp *de = (DelegateExp *)arg; + if (de->e1->op == TOKvar) + { VarExp *ve = (VarExp *)de->e1; + FuncDeclaration *f = ve->var->isFuncDeclaration(); + if (f) + { f->tookAddressOf--; + //printf("tookAddressOf = %d\n", f->tookAddressOf); + } + } + } + } +#endif } else { @@ -778,7 +829,11 @@ void expToCBuffer(OutBuffer *buf, HdrGenState *hgs, Expression *e, enum PREC pr) { //if (precedence[e->op] == 0) e->dump(0); - if (precedence[e->op] < pr) + if (precedence[e->op] < pr || + /* Despite precedence, we don't allow a<b<c expressions. + * They must be parenthesized. + */ + (pr == PREC_rel && precedence[e->op] == pr)) { buf->writeByte('('); e->toCBuffer(buf, hgs); @@ -982,6 +1037,16 @@ error("expression %s is not a valid template value argument", toChars()); } +/*************************************** + * Return !=0 if expression is an lvalue. + */ +#if DMDV2 +int Expression::isLvalue() +{ + return 0; +} +#endif + /******************************* * Give error if we're not an lvalue. * If we can, convert expression to be an lvalue. @@ -1002,6 +1067,10 @@ //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type->toChars()); // See if this expression is a modifiable lvalue (i.e. not const) +#if DMDV2 + if (type && (!type->isMutable() || !type->isAssignable())) + error("%s is not mutable", e->toChars()); +#endif return toLvalue(sc, e); } @@ -1049,6 +1118,15 @@ s->checkDeprecated(loc, sc); } +#if DMDV2 +void Expression::checkPurity(Scope *sc, FuncDeclaration *f) +{ + if (sc->func && sc->func->isPure() && !sc->intypeof && !f->isPure()) + error("pure function '%s' cannot call impure function '%s'\n", + sc->func->toChars(), f->toChars()); +} +#endif + /******************************** * Check for expressions that have no use. * Input: @@ -1175,7 +1253,11 @@ int Expression::canThrow() { +#if DMDV2 + return FALSE; +#else return TRUE; +#endif } @@ -1849,7 +1931,9 @@ // ArrayScopeSymbol::search() doesn't have access to sc. s->semantic(sc); } - // Look to see if f is really a function template + /* If f is really a function template, + * then replace f with the function template declaration. + */ FuncDeclaration *f = s->isFuncDeclaration(); if (f && f->parent) { TemplateInstance *ti = f->parent->isTemplateInstance(); @@ -1891,6 +1975,13 @@ buf->writestring(ident->toChars()); } +#if DMDV2 +int IdentifierExp::isLvalue() +{ + return 1; +} +#endif + Expression *IdentifierExp::toLvalue(Scope *sc, Expression *e) { #if 0 @@ -1954,7 +2045,11 @@ // BUG: This should happen after overload resolution for functions, not before if (s->needThis()) { - if (hasThis(sc) /*&& !s->isFuncDeclaration()*/) + if (hasThis(sc) +#if DMDV2 + && !s->isFuncDeclaration() +#endif + ) { // Supply an implicit 'this', as in // this.ident @@ -2112,6 +2207,13 @@ buf->writestring(s->toChars()); } +#if DMDV2 +int DsymbolExp::isLvalue() +{ + return 1; +} +#endif + Expression *DsymbolExp::toLvalue(Scope *sc, Expression *e) { #if 0 @@ -2214,6 +2316,13 @@ buf->writestring("this"); } +#if DMDV2 +int ThisExp::isLvalue() +{ + return 1; +} +#endif + Expression *ThisExp::toLvalue(Scope *sc, Expression *e) { return this; @@ -2431,7 +2540,7 @@ if (!type) { OutBuffer buffer; size_t newlen = 0; - char *p; + const char *p; size_t u; unsigned c; @@ -2629,7 +2738,7 @@ void StringExp::toMangleBuffer(OutBuffer *buf) { char m; OutBuffer tmp; - char *p; + const char *p; unsigned c; size_t u; unsigned char *q; @@ -2772,6 +2881,13 @@ return result ? (dim != 0) : (dim == 0); } +#if DMDV2 +int ArrayLiteralExp::canThrow() +{ + return 1; // because it can fail allocating memory +} +#endif + void ArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writeByte('['); @@ -2890,6 +3006,13 @@ return result ? (dim != 0) : (dim == 0); } +#if DMDV2 +int AssocArrayLiteralExp::canThrow() +{ + return 1; +} +#endif + void AssocArrayLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writeByte('['); @@ -3074,6 +3197,12 @@ return -1; } +#if DMDV2 +int StructLiteralExp::isLvalue() +{ + return 1; +} +#endif Expression *StructLiteralExp::toLvalue(Scope *sc, Expression *e) { @@ -3096,6 +3225,13 @@ return f; } +#if DMDV2 +int StructLiteralExp::canThrow() +{ + return arrayExpressionCanThrow(elements); +} +#endif + void StructLiteralExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring(sd->toChars()); @@ -3287,6 +3423,8 @@ /********************** NewExp **************************************/ +/* thisexp.new(newargs) newtype(arguments) */ + NewExp::NewExp(Loc loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments) : Expression(loc, TOKnew, sizeof(NewExp)) @@ -3472,17 +3610,14 @@ } if (cd->aggNew) - { Expression *e; - - f = cd->aggNew; - + { // Prepend the uint size argument to newargs[] - e = new IntegerExp(loc, cd->size(loc), Type::tuns32); + Expression *e = new IntegerExp(loc, cd->size(loc), Type::tuns32); if (!newargs) newargs = new Expressions(); newargs->shift(e); - f = f->overloadResolve(loc, newargs); + f = cd->aggNew->overloadResolve(loc, newargs); allocator = f->isNewDeclaration(); assert(allocator); @@ -3494,7 +3629,6 @@ if (newargs && newargs->dim) error("no allocator for %s", cd->toChars()); } - } else if (tb->ty == Tstruct) { @@ -3575,6 +3709,13 @@ return 1; } +#if DMDV2 +int NewExp::canThrow() +{ + return 1; +} +#endif + void NewExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { int i; @@ -3642,6 +3783,13 @@ return 1; } +#if DMDV2 +int NewAnonClassExp::canThrow() +{ + return 1; +} +#endif + void NewAnonClassExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { int i; @@ -3670,6 +3818,18 @@ } } +/********************** SymbolExp **************************************/ + +#if DMDV2 +SymbolExp::SymbolExp(Loc loc, enum TOK op, int size, Declaration *var, int hasOverloads) + : Expression(loc, op, size) +{ + assert(var); + this->var = var; + this->hasOverloads = hasOverloads; +} +#endif + /********************** SymOffExp **************************************/ SymOffExp::SymOffExp(Loc loc, Declaration *var, unsigned offset) @@ -3760,6 +3920,11 @@ } #endif } + /* Fix for 1161 doesn't work because it causes protection + * problems when instantiating imported templates passing private + * variables as alias template parameters. + */ + //accessCheck(loc, sc, NULL, var); VarDeclaration *v = var->isVarDeclaration(); if (v) @@ -3774,6 +3939,13 @@ } } v->checkNestedReference(sc, loc); +#if DMDV2 + if (sc->func && sc->func->isPure() && !sc->intypeof) + { + if (v->isDataseg() && !v->isInvariant()) + error("pure function '%s' cannot access mutable static data '%s'", sc->func->toChars(), v->toChars()); + } +#endif } #if 0 else if ((fd = var->isFuncLiteralDeclaration()) != NULL) @@ -3812,6 +3984,15 @@ } } +#if DMDV2 +int VarExp::isLvalue() +{ + if (var->storage_class & STClazy) + return 0; + return 1; +} +#endif + Expression *VarExp::toLvalue(Scope *sc, Expression *e) { #if 0 @@ -4026,6 +4207,13 @@ return f; } +#if DMDV2 +int TupleExp::canThrow() +{ + return arrayExpressionCanThrow(exps); +} +#endif + void TupleExp::checkEscape() { for (size_t i = 0; i < exps->dim; i++) @@ -4195,6 +4383,18 @@ return 1; } +#if DMDV2 +int DeclarationExp::canThrow() +{ + VarDeclaration *v = declaration->isVarDeclaration(); + if (v && v->init) + { ExpInitializer *ie = v->init->isExpInitializer(); + return ie && ie->exp->canThrow(); + } + return 0; +} +#endif + void DeclarationExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { declaration->toCBuffer(buf, hgs); @@ -4398,6 +4598,7 @@ break; case TOKinvariant: + case TOKimmutable: if (!targ->isInvariant()) goto Lno; tded = targ; @@ -4604,6 +4805,13 @@ return this; } +#if DMDV2 +int UnaExp::canThrow() +{ + return e1->canThrow(); +} +#endif + void UnaExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring(Token::toChars(op)); @@ -4773,6 +4981,13 @@ return e1->type->isunsigned() || e2->type->isunsigned(); } +#if DMDV2 +int BinExp::canThrow() +{ + return e1->canThrow() || e2->canThrow(); +} +#endif + void BinExp::incompatibleTypes() { error("incompatible types for ((%s) %s (%s)): '%s' and '%s'", @@ -4805,6 +5020,7 @@ Parser p(sc->module, (unsigned char *)se->string, se->len, 0); p.loc = loc; p.nextToken(); + //printf("p.loc.linnum = %d\n", p.loc.linnum); Expression *e = p.parseExpression(); if (p.token.value != TOKeof) error("incomplete mixin expression (%s)", se->toChars()); @@ -4877,7 +5093,7 @@ return se->semantic(sc); Lerror: - se = new StringExp(loc, ""); + se = new StringExp(loc, (char *)""); goto Lret; } @@ -4940,6 +5156,13 @@ return 1; } +#if DMDV2 +int AssertExp::canThrow() +{ + return (global.params.useAssert != 0); +} +#endif + void AssertExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("assert("); @@ -5162,6 +5385,13 @@ } return e; } +#if DMDV2 + OverloadSet *o = s->isOverloadSet(); + if (o) + { //printf("'%s' is an overload set\n", o->toChars()); + return new OverExp(o); + } +#endif Type *t = s->getType(); if (t) @@ -5224,6 +5454,29 @@ e->type = ((TypePointer *)e1->type)->next; return e->type->dotExp(sc, e, ident); } +#if DMDV2 + else if (t1b->ty == Tarray || + t1b->ty == Tsarray || + t1b->ty == Taarray) + { /* If ident is not a valid property, rewrite: + * e1.ident + * as: + * .ident(e1) + */ + unsigned errors = global.errors; + global.gag++; + e = e1->type->dotExp(sc, e1, ident); + global.gag--; + if (errors != global.errors) // if failed to find the property + { + global.errors = errors; + e = new DotIdExp(loc, new IdentifierExp(loc, Id::empty), ident); + e = new CallExp(loc, e, e1); + } + e = e->semantic(sc); + return e; + } +#endif else { e = e1->type->dotExp(sc, e1, ident); @@ -5341,6 +5594,13 @@ return this; } +#if DMDV2 +int DotVarExp::isLvalue() +{ + return 1; +} +#endif + Expression *DotVarExp::toLvalue(Scope *sc, Expression *e) { //printf("DotVarExp::toLvalue(%s)\n", toChars()); @@ -5391,6 +5651,20 @@ break; } } +#if DMDV2 + else + { + Type *t1 = e1->type->toBasetype(); + + if (!t1->isMutable() || + (t1->ty == Tpointer && !t1->nextOf()->isMutable()) || + !var->type->isMutable() || + !var->type->isAssignable() || + var->storage_class & STCmanifest + ) + error("cannot modify const/invariant %s", toChars()); + } +#endif return this; } @@ -5713,12 +5987,16 @@ if (!arguments) arguments = new Expressions(); arguments->shift(dotid->e1); +#if DMDV2 + e1 = new DotIdExp(dotid->loc, new IdentifierExp(dotid->loc, Id::empty), dotid->ident); +#else e1 = new IdentifierExp(dotid->loc, dotid->ident); - } - } - } - -#if DMDV2 +#endif + } + } + } + +#if 1 /* This recognizes: * foo!(tiargs)(funcargs) */ @@ -5901,7 +6179,7 @@ if (!arguments) // Should fix deduceFunctionTemplate() so it works on NULL argument arguments = new Expressions(); - f = td->deduceFunctionTemplate(sc, loc, NULL, arguments); + f = td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments); if (!f) { type = Type::terror; return this; @@ -5925,6 +6203,9 @@ } checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); +#endif accessCheck(loc, sc, ue->e1, f); if (!f->needThis()) { @@ -5990,6 +6271,9 @@ f = f->overloadResolve(loc, arguments); checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); +#endif e1 = new DotVarExp(e1->loc, e1, f); e1 = e1->semantic(sc); t1 = e1->type; @@ -6027,6 +6311,9 @@ f = cd->ctor; f = f->overloadResolve(loc, arguments); checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); +#endif e1 = new DotVarExp(e1->loc, e1, f); e1 = e1->semantic(sc); t1 = e1->type; @@ -6062,7 +6349,7 @@ else if (e1->op == TOKtemplate) { TemplateExp *te = (TemplateExp *)e1; - f = te->td->deduceFunctionTemplate(sc, loc, NULL, arguments); + f = te->td->deduceFunctionTemplate(sc, loc, targsi, NULL, arguments); if (!f) { type = Type::terror; return this; @@ -6118,6 +6405,9 @@ f = f->overloadResolve(loc, arguments); checkDeprecated(sc, f); +#if DMDV2 + checkPurity(sc, f); +#endif if (f->needThis() && hasThis(sc)) { @@ -6165,9 +6455,75 @@ int CallExp::checkSideEffect(int flag) { +#if DMDV2 + if (flag != 2) + return 1; + + if (e1->checkSideEffect(2)) + return 1; + + /* If any of the arguments have side effects, this expression does + */ + for (size_t i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + if (e->checkSideEffect(2)) + return 1; + } + + /* If calling a function or delegate that is typed as pure, + * then this expression has no side effects. + */ + Type *t = e1->type->toBasetype(); + if (t->ty == Tfunction && ((TypeFunction *)t)->ispure) + return 0; + if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->ispure) + return 0; +#endif return 1; } +#if DMDV2 +int CallExp::canThrow() +{ + if (e1->canThrow()) + return 1; + + /* If any of the arguments can throw, then this expression can throw + */ + for (size_t i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + if (e->canThrow()) + return 1; + } + + /* If calling a function or delegate that is typed as nothrow, + * then this expression cannot throw. + * Note that pure functions can throw. + */ + Type *t = e1->type->toBasetype(); + if (t->ty == Tfunction && ((TypeFunction *)t)->isnothrow) + return 0; + if (t->ty == Tdelegate && ((TypeFunction *)((TypeDelegate *)t)->next)->isnothrow) + return 0; + + return 1; +} +#endif + +#if DMDV2 +int CallExp::isLvalue() +{ + if (type->toBasetype()->ty == Tstruct) + return 1; + Type *tb = e1->type->toBasetype(); + if (tb->ty == Tfunction && ((TypeFunction *)tb)->isref) + return 1; // function returns a reference + return 0; +} +#endif + Expression *CallExp::toLvalue(Scope *sc, Expression *e) { if (type->toBasetype()->ty == Tstruct) @@ -6309,6 +6665,13 @@ return this; } +#if DMDV2 +int PtrExp::isLvalue() +{ + return 1; +} +#endif + Expression *PtrExp::toLvalue(Scope *sc, Expression *e) { #if 0 @@ -6321,6 +6684,21 @@ return this; } +#if DMDV2 +Expression *PtrExp::modifiableLvalue(Scope *sc, Expression *e) +{ + //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type->toChars()); + + if (e1->op == TOKsymoff) + { SymOffExp *se = (SymOffExp *)e1; + se->var->checkModify(loc, sc, type); + //return toLvalue(sc, e); + } + + return Expression::modifiableLvalue(sc, e); +} +#endif + void PtrExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writeByte('*'); @@ -6553,6 +6931,17 @@ to = t; } +#if DMDV2 +/* For cast(const) and cast(immutable) + */ +CastExp::CastExp(Loc loc, Expression *e, unsigned mod) + : UnaExp(loc, TOKcast, sizeof(CastExp), e) +{ + to = NULL; + this->mod = mod; +} +#endif + Expression *CastExp::syntaxCopy() { return new CastExp(loc, e1->syntaxCopy(), to->syntaxCopy()); @@ -6637,7 +7026,35 @@ void CastExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { buf->writestring("cast("); +#if DMDV1 to->toCBuffer(buf, NULL, hgs); +#else + if (to) + to->toCBuffer(buf, NULL, hgs); + else + { + switch (mod) + { case 0: + break; + case MODconst: + buf->writestring(Token::tochars[TOKconst]); + break; + case MODinvariant: + buf->writestring(Token::tochars[TOKimmutable]); + break; + case MODshared: + buf->writestring(Token::tochars[TOKshared]); + break; + case MODshared | MODconst: + buf->writestring(Token::tochars[TOKshared]); + buf->writeByte(' '); + buf->writestring(Token::tochars[TOKconst]); + break; + default: + assert(0); + } + } +#endif buf->writeByte(')'); expToCBuffer(buf, hgs, e1, precedence[op]); } @@ -6831,6 +7248,13 @@ e1->checkEscape(); } +#if DMDV2 +int SliceExp::isLvalue() +{ + return 1; +} +#endif + Expression *SliceExp::toLvalue(Scope *sc, Expression *e) { return this; @@ -6945,6 +7369,14 @@ return e; } +#if DMDV2 +int ArrayExp::isLvalue() +{ + if (type && type->toBasetype()->ty == Tvoid) + return 0; + return 1; +} +#endif Expression *ArrayExp::toLvalue(Scope *sc, Expression *e) { @@ -7015,6 +7447,13 @@ e2->checkEscape(); } +#if DMDV2 +int CommaExp::isLvalue() +{ + return e2->isLvalue(); +} +#endif + Expression *CommaExp::toLvalue(Scope *sc, Expression *e) { e2 = e2->toLvalue(sc, NULL); @@ -7181,6 +7620,13 @@ return e; } +#if DMDV2 +int IndexExp::isLvalue() +{ + return 1; +} +#endif + Expression *IndexExp::toLvalue(Scope *sc, Expression *e) { // if (type && type->toBasetype()->ty == Tvoid) @@ -9034,9 +9480,21 @@ break; } } +#if 0 + printf("res: %s\n", type->toChars()); + printf("e1 : %s\n", e1->type->toChars()); + printf("e2 : %s\n", e2->type->toChars()); +#endif return this; } +#if DMDV2 +int CondExp::isLvalue() +{ + return e1->isLvalue() && e2->isLvalue(); +} +#endif + Expression *CondExp::toLvalue(Scope *sc, Expression *ex) { PtrExp *e; @@ -9092,6 +9550,13 @@ } } +#if DMDV2 +int CondExp::canThrow() +{ + return econd->canThrow() || e1->canThrow() || e2->canThrow(); +} +#endif + void CondExp::toCBuffer(OutBuffer *buf, HdrGenState *hgs) { expToCBuffer(buf, hgs, econd, PREC_oror);