aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/AST/Expr.cpp498
1 files changed, 172 insertions, 326 deletions
diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp
index d551eac300..ed51fbaa68 100644
--- a/lib/AST/Expr.cpp
+++ b/lib/AST/Expr.cpp
@@ -875,383 +875,229 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const {
}
/// isIntegerConstantExpr - this recursive routine will test if an expression is
-/// an integer constant expression. Note: With the introduction of VLA's in
-/// C99 the result of the sizeof operator is no longer always a constant
-/// expression. The generalization of the wording to include any subexpression
-/// that is not evaluated (C99 6.6p3) means that nonconstant subexpressions
-/// can appear as operands to other operators (e.g. &&, ||, ?:). For instance,
-/// "0 || f()" can be treated as a constant expression. In C90 this expression,
-/// occurring in a context requiring a constant, would have been a constraint
-/// violation. FIXME: This routine currently implements C90 semantics.
-/// To properly implement C99 semantics this routine will need to evaluate
-/// expressions involving operators previously mentioned.
+/// an integer constant expression.
/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero,
/// comma, etc
///
-/// FIXME: This should ext-warn on overflow during evaluation! ISO C does not
-/// permit this. This includes things like (int)1e1000
-///
/// FIXME: Handle offsetof. Two things to do: Handle GCC's __builtin_offsetof
/// to support gcc 4.0+ and handle the idiom GCC recognizes with a null pointer
/// cast+dereference.
-bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
- SourceLocation *Loc, bool isEvaluated) const {
- if (!isIntegerConstantExprInternal(Result, Ctx, Loc, isEvaluated))
- return false;
- assert(Result == EvaluateAsInt(Ctx) && "Inconsistent Evaluate() result!");
- return true;
-}
-bool Expr::isIntegerConstantExprInternal(llvm::APSInt &Result, ASTContext &Ctx,
- SourceLocation *Loc, bool isEvaluated) const {
-
- // Pretest for integral type; some parts of the code crash for types that
- // can't be sized.
- if (!getType()->isIntegralType()) {
- if (Loc) *Loc = getLocStart();
- return false;
+// CheckICE - This function does the fundamental ICE checking: the returned
+// ICEDiag contains a Val of 0, 1, or 2, and a possibly null SourceLocation.
+// Note that to reduce code duplication, this helper does no evaluation
+// itself; the caller checks whether the expression is evaluatable, and
+// in the rare cases where CheckICE actually cares about the evaluated
+// value, it calls into Evalute.
+//
+// Meanings of Val:
+// 0: This expression is an ICE if it can be evaluated by Evaluate.
+// 1: This expression is not an ICE, but if it isn't evaluated, it's
+// a legal subexpression for an ICE. This return value is used to handle
+// the comma operator in C99 mode.
+// 2: This expression is not an ICE, and is not a legal subexpression for one.
+
+struct ICEDiag {
+ unsigned Val;
+ SourceLocation Loc;
+
+ public:
+ ICEDiag(unsigned v, SourceLocation l) : Val(v), Loc(l) {}
+ ICEDiag() : Val(0) {}
+};
+
+ICEDiag NoDiag() { return ICEDiag(); }
+
+static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
+ if (!E->getType()->isIntegralType()) {
+ return ICEDiag(2, E->getLocStart());
}
- switch (getStmtClass()) {
+
+ switch (E->getStmtClass()) {
default:
- if (Loc) *Loc = getLocStart();
- return false;
- case ParenExprClass:
- return cast<ParenExpr>(this)->getSubExpr()->
- isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated);
- case IntegerLiteralClass:
- // NOTE: getValue() returns an APInt, we must set sign.
- Result = cast<IntegerLiteral>(this)->getValue();
- Result.setIsUnsigned(getType()->isUnsignedIntegerType());
- break;
- case CharacterLiteralClass: {
- const CharacterLiteral *CL = cast<CharacterLiteral>(this);
- Result = Ctx.MakeIntValue(CL->getValue(), getType());
- break;
- }
- case CXXBoolLiteralExprClass: {
- const CXXBoolLiteralExpr *BL = cast<CXXBoolLiteralExpr>(this);
- Result = Ctx.MakeIntValue(BL->getValue(), getType());
- break;
- }
- case CXXZeroInitValueExprClass:
- Result = Ctx.MakeIntValue(0, getType());
- break;
- case TypesCompatibleExprClass: {
- const TypesCompatibleExpr *TCE = cast<TypesCompatibleExpr>(this);
- // Per gcc docs "this built-in function ignores top level
- // qualifiers". We need to use the canonical version to properly
- // be able to strip CRV qualifiers from the type.
- QualType T0 = Ctx.getCanonicalType(TCE->getArgType1());
- QualType T1 = Ctx.getCanonicalType(TCE->getArgType2());
- Result = Ctx.MakeIntValue(Ctx.typesAreCompatible(T0.getUnqualifiedType(),
- T1.getUnqualifiedType()),
- getType());
- break;
- }
- case CallExprClass:
- case CXXOperatorCallExprClass: {
- const CallExpr *CE = cast<CallExpr>(this);
-
- // If this is a call to a builtin function, constant fold it otherwise
- // reject it.
- if (CE->isBuiltinCall(Ctx)) {
- EvalResult EvalResult;
- if (CE->Evaluate(EvalResult, Ctx)) {
- assert(!EvalResult.HasSideEffects &&
- "Foldable builtin call should not have side effects!");
- Result = EvalResult.Val.getInt();
- break; // It is a constant, expand it.
- }
- }
-
- if (Loc) *Loc = getLocStart();
- return false;
+ return ICEDiag(2, E->getLocStart());
+ case Expr::ParenExprClass:
+ return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx);
+ case Expr::IntegerLiteralClass:
+ case Expr::CharacterLiteralClass:
+ case Expr::CXXBoolLiteralExprClass:
+ case Expr::CXXZeroInitValueExprClass:
+ case Expr::TypesCompatibleExprClass:
+ case Expr::UnaryTypeTraitExprClass:
+ return NoDiag();
+ case Expr::CallExprClass:
+ case Expr::CXXOperatorCallExprClass: {
+ const CallExpr *CE = cast<CallExpr>(E);
+ if (CE->isBuiltinCall(Ctx) && CE->isEvaluatable(Ctx))
+ return NoDiag();
+ return ICEDiag(2, E->getLocStart());
}
- case DeclRefExprClass:
- case QualifiedDeclRefExprClass:
- if (const EnumConstantDecl *D =
- dyn_cast<EnumConstantDecl>(cast<DeclRefExpr>(this)->getDecl())) {
- Result = D->getInitVal();
- break;
- }
+ case Expr::DeclRefExprClass:
+ case Expr::QualifiedDeclRefExprClass:
+ if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
+ return NoDiag();
if (Ctx.getLangOptions().CPlusPlus &&
- getType().getCVRQualifiers() == QualType::Const) {
+ E->getType().getCVRQualifiers() == QualType::Const) {
// C++ 7.1.5.1p2
// A variable of non-volatile const-qualified integral or enumeration
// type initialized by an ICE can be used in ICEs.
if (const VarDecl *Dcl =
- dyn_cast<VarDecl>(cast<DeclRefExpr>(this)->getDecl())) {
+ dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) {
if (const Expr *Init = Dcl->getInit())
- return Init->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated);
+ return CheckICE(Init, Ctx);
}
}
- if (Loc) *Loc = getLocStart();
- return false;
- case UnaryOperatorClass: {
- const UnaryOperator *Exp = cast<UnaryOperator>(this);
-
- // Get the operand value. If this is offsetof, do not evalute the
- // operand. This affects C99 6.6p3.
- if (!Exp->isOffsetOfOp() && !Exp->getSubExpr()->
- isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated))
- return false;
-
+ return ICEDiag(2, E->getLocStart());
+ case Expr::UnaryOperatorClass: {
+ const UnaryOperator *Exp = cast<UnaryOperator>(E);
switch (Exp->getOpcode()) {
- // Address, indirect, pre/post inc/dec, etc are not valid constant exprs.
- // See C99 6.6p3.
default:
- if (Loc) *Loc = Exp->getOperatorLoc();
- return false;
+ return ICEDiag(2, E->getLocStart());
case UnaryOperator::Extension:
- return true; // FIXME: this is wrong.
- case UnaryOperator::LNot: {
- Result = Ctx.MakeIntValue(Result == 0, getType());
- break;
- }
+ case UnaryOperator::LNot:
case UnaryOperator::Plus:
- break;
case UnaryOperator::Minus:
- Result = -Result;
- break;
case UnaryOperator::Not:
- Result = ~Result;
- break;
+ return CheckICE(Exp->getSubExpr(), Ctx);
case UnaryOperator::OffsetOf:
- Result = Ctx.MakeIntValue(Exp->evaluateOffsetOf(Ctx), getType());
- break;
+ // Note that per C99, a non-constant offsetof is illegal.
+ // FIXME: Do we need to check whether this is evaluatable?
+ return NoDiag();
}
- break;
}
- case SizeOfAlignOfExprClass: {
- const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(this);
- QualType ArgTy = Exp->getTypeOfArgument();
-
- // alignof is always an ICE; sizeof is an ICE if and only if
- // the operand isn't a VLA
- if (Exp->isSizeOf() && ArgTy->isVariableArrayType()) {
- if (Loc) *Loc = Exp->getOperatorLoc();
- return false;
- }
-
- // Use the Evaluate logic to calculate the value, since the
- // calculation is non-trivial.
- Result = EvaluateAsInt(Ctx);
- break;
+ case Expr::SizeOfAlignOfExprClass: {
+ const SizeOfAlignOfExpr *Exp = cast<SizeOfAlignOfExpr>(E);
+ if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType())
+ return ICEDiag(2, E->getLocStart());
+ return NoDiag();
}
- case BinaryOperatorClass: {
- const BinaryOperator *Exp = cast<BinaryOperator>(this);
- llvm::APSInt LHS, RHS;
-
- // Initialize result to have correct signedness and width.
- Result = Ctx.MakeIntValue(0, getType());
-
- // The LHS of a constant expr is always evaluated and needed.
- if (!Exp->getLHS()->isIntegerConstantExpr(LHS, Ctx, Loc, isEvaluated))
- return false;
-
- // The short-circuiting &&/|| operators don't necessarily evaluate their
- // RHS. Make sure to pass isEvaluated down correctly.
- if (Exp->isLogicalOp()) {
- bool RHSEval;
- if (Exp->getOpcode() == BinaryOperator::LAnd)
- RHSEval = LHS != 0;
- else {
- assert(Exp->getOpcode() == BinaryOperator::LOr &&"Unexpected logical");
- RHSEval = LHS == 0;
- }
-
- if (!Exp->getRHS()->isIntegerConstantExpr(RHS, Ctx, Loc,
- isEvaluated & RHSEval))
- return false;
- } else {
- if (!Exp->getRHS()->isIntegerConstantExpr(RHS, Ctx, Loc, isEvaluated))
- return false;
- }
-
+ case Expr::BinaryOperatorClass: {
+ const BinaryOperator *Exp = cast<BinaryOperator>(E);
switch (Exp->getOpcode()) {
default:
- if (Loc) *Loc = getLocStart();
- return false;
+ return ICEDiag(2, E->getLocStart());
case BinaryOperator::Mul:
- Result = LHS * RHS;
- break;
case BinaryOperator::Div:
- if (RHS == 0) {
- if (!isEvaluated) break;
- if (Loc) *Loc = getLocStart();
- return false;
- }
- Result = LHS / RHS;
- break;
case BinaryOperator::Rem:
- if (RHS == 0) {
- if (!isEvaluated) break;
- if (Loc) *Loc = getLocStart();
- return false;
- }
- Result = LHS % RHS;
- break;
- case BinaryOperator::Add: Result = LHS + RHS; break;
- case BinaryOperator::Sub: Result = LHS - RHS; break;
+ case BinaryOperator::Add:
+ case BinaryOperator::Sub:
case BinaryOperator::Shl:
- Result = LHS <<
- static_cast<uint32_t>(RHS.getLimitedValue(LHS.getBitWidth()-1));
- break;
case BinaryOperator::Shr:
- Result = LHS >>
- static_cast<uint32_t>(RHS.getLimitedValue(LHS.getBitWidth()-1));
- break;
- case BinaryOperator::LT: Result = LHS < RHS; break;
- case BinaryOperator::GT: Result = LHS > RHS; break;
- case BinaryOperator::LE: Result = LHS <= RHS; break;
- case BinaryOperator::GE: Result = LHS >= RHS; break;
- case BinaryOperator::EQ: Result = LHS == RHS; break;
- case BinaryOperator::NE: Result = LHS != RHS; break;
- case BinaryOperator::And: Result = LHS & RHS; break;
- case BinaryOperator::Xor: Result = LHS ^ RHS; break;
- case BinaryOperator::Or: Result = LHS | RHS; break;
+ case BinaryOperator::LT:
+ case BinaryOperator::GT:
+ case BinaryOperator::LE:
+ case BinaryOperator::GE:
+ case BinaryOperator::EQ:
+ case BinaryOperator::NE:
+ case BinaryOperator::And:
+ case BinaryOperator::Xor:
+ case BinaryOperator::Or:
+ case BinaryOperator::Comma: {
+ ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
+ ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
+ if (Exp->getOpcode() == BinaryOperator::Comma &&
+ Ctx.getLangOptions().C99) {
+ // C99 6.6p3 introduces a strange edge case: comma can be in an ICE
+ // if it isn't evaluated.
+ if (LHSResult.Val == 0 && RHSResult.Val == 0)
+ return ICEDiag(1, E->getLocStart());
+ }
+ if (LHSResult.Val >= RHSResult.Val)
+ return LHSResult;
+ return RHSResult;
+ }
case BinaryOperator::LAnd:
- Result = LHS != 0 && RHS != 0;
- break;
- case BinaryOperator::LOr:
- Result = LHS != 0 || RHS != 0;
- break;
-
- case BinaryOperator::Comma:
- // C99 6.6p3: "shall not contain assignment, ..., or comma operators,
- // *except* when they are contained within a subexpression that is not
- // evaluated". Note that Assignment can never happen due to constraints
- // on the LHS subexpr, so we don't need to check it here.
- if (isEvaluated) {
- if (Loc) *Loc = getLocStart();
- return false;
+ case BinaryOperator::LOr: {
+ ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
+ ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
+ if (LHSResult.Val == 0 && RHSResult.Val == 1) {
+ // Rare case where the RHS has a comma "side-effect"; we need
+ // to actually check the condition to see whether the side
+ // with the comma is evaluated.
+ Expr::EvalResult Result;
+ if (!Exp->getLHS()->Evaluate(Result, Ctx))
+ return ICEDiag(1, E->getLocStart());
+ if ((Exp->getOpcode() == BinaryOperator::LAnd) !=
+ (Result.Val.getInt() == 0))
+ return RHSResult;
+ return NoDiag();
}
- // The result of the constant expr is the RHS.
- Result = RHS;
- break;
+ if (LHSResult.Val >= RHSResult.Val)
+ return LHSResult;
+ return RHSResult;
}
-
- assert(!Exp->isAssignmentOp() && "LHS can't be a constant expr!");
- break;
- }
- case ImplicitCastExprClass:
- case CStyleCastExprClass:
- case CXXFunctionalCastExprClass: {
- const Expr *SubExpr = cast<CastExpr>(this)->getSubExpr();
- SourceLocation CastLoc = getLocStart();
-
- // C99 6.6p6: shall only convert arithmetic types to integer types.
- if (!SubExpr->getType()->isArithmeticType() ||
- !getType()->isIntegerType()) {
- if (Loc) *Loc = SubExpr->getLocStart();
- return false;
- }
-
- uint32_t DestWidth = static_cast<uint32_t>(Ctx.getTypeSize(getType()));
-
- // Handle simple integer->integer casts.
- if (SubExpr->getType()->isIntegerType()) {
- if (!SubExpr->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated))
- return false;
-
- // Figure out if this is a truncate, extend or noop cast.
- // If the input is signed, do a sign extend, noop, or truncate.
- if (getType()->isBooleanType()) {
- // Conversion to bool compares against zero.
- Result = Ctx.MakeIntValue(Result != 0, getType());
- } else if (SubExpr->getType()->isSignedIntegerType()) {
- Result.sextOrTrunc(DestWidth);
- Result.setIsUnsigned(getType()->isUnsignedIntegerType());
- } else { // If the input is unsigned, do a zero extend, noop,
- // or truncate.
- Result.zextOrTrunc(DestWidth);
- Result.setIsUnsigned(getType()->isUnsignedIntegerType());
- }
- break;
}
-
- // Allow floating constants that are the immediate operands of casts or that
- // are parenthesized.
- const Expr *Operand = SubExpr->IgnoreParens();
-
- // If this isn't a floating literal, we can't handle it.
- const FloatingLiteral *FL = dyn_cast<FloatingLiteral>(Operand);
- if (!FL) {
- if (Loc) *Loc = Operand->getLocStart();
- return false;
- }
-
- // If the destination is boolean, compare against zero.
- if (getType()->isBooleanType()) {
- Result = Ctx.MakeIntValue(!FL->getValue().isZero(), getType());
- break;
- }
-
- // Determine whether we are converting to unsigned or signed.
- bool DestSigned = getType()->isSignedIntegerType();
-
- // TODO: Warn on overflow, but probably not here: isIntegerConstantExpr can
- // be called multiple times per AST.
- uint64_t Space[4];
- bool ignored;
- (void)FL->getValue().convertToInteger(Space, DestWidth, DestSigned,
- llvm::APFloat::rmTowardZero,
- &ignored);
- Result = llvm::APInt(DestWidth, 4, Space);
- Result.setIsUnsigned(getType()->isUnsignedIntegerType());
- break;
}
- case ConditionalOperatorClass: {
- const ConditionalOperator *Exp = cast<ConditionalOperator>(this);
-
- const Expr *Cond = Exp->getCond();
-
- if (!Cond->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated))
- return false;
-
- const Expr *TrueExp = Exp->getLHS();
- const Expr *FalseExp = Exp->getRHS();
- if (Result == 0) std::swap(TrueExp, FalseExp);
-
+ case Expr::ImplicitCastExprClass:
+ case Expr::CStyleCastExprClass:
+ case Expr::CXXFunctionalCastExprClass: {
+ const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr();
+ if (SubExpr->getType()->isIntegralType())
+ return CheckICE(SubExpr, Ctx);
+ if (isa<FloatingLiteral>(SubExpr->IgnoreParens()))
+ return NoDiag();
+ return ICEDiag(2, E->getLocStart());
+ }
+ case Expr::ConditionalOperatorClass: {
+ const ConditionalOperator *Exp = cast<ConditionalOperator>(E);
// If the condition (ignoring parens) is a __builtin_constant_p call,
// then only the true side is actually considered in an integer constant
// expression, and it is fully evaluated. This is an important GNU
// extension. See GCC PR38377 for discussion.
- if (const CallExpr *CallCE = dyn_cast<CallExpr>(Cond->IgnoreParenCasts()))
+ if (const CallExpr *CallCE = dyn_cast<CallExpr>(Exp->getCond()->IgnoreParenCasts()))
if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) {
- EvalResult EVResult;
- if (!Evaluate(EVResult, Ctx) || EVResult.HasSideEffects)
- return false;
- assert(EVResult.Val.isInt() && "FP conditional expr not expected");
- Result = EVResult.Val.getInt();
- if (Loc) *Loc = EVResult.DiagLoc;
- return true;
+ Expr::EvalResult EVResult;
+ if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects ||
+ !EVResult.Val.isInt()) {
+ ICEDiag(2, E->getLocStart());
+ }
+ return NoDiag();
}
-
- // Evaluate the false one first, discard the result.
- llvm::APSInt Tmp;
- if (FalseExp && !FalseExp->isIntegerConstantExpr(Tmp, Ctx, Loc, false))
- return false;
- // Evalute the true one, capture the result. Note that if TrueExp
- // is False then this is an instant of the gcc missing LHS
- // extension, and we will just reuse Result.
- if (TrueExp &&
- !TrueExp->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated))
- return false;
- break;
+ ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
+ ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
+ ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
+ if (CondResult.Val == 2)
+ return CondResult;
+ if (TrueResult.Val == 2)
+ return TrueResult;
+ if (FalseResult.Val == 2)
+ return FalseResult;
+ if (CondResult.Val == 1)
+ return CondResult;
+ if (TrueResult.Val == 0 && FalseResult.Val == 0)
+ return NoDiag();
+ // Rare case where the diagnostics depend on which side is evaluated
+ // Note that if we get here, CondResult is 0, and at least one of
+ // TrueResult and FalseResult is non-zero.
+ Expr::EvalResult Result;
+ if (!Exp->getCond()->Evaluate(Result, Ctx))
+ return ICEDiag(1, E->getLocStart());
+ if (Result.Val.getInt() == 0) {
+ return FalseResult;
+ }
+ return TrueResult;
}
- case CXXDefaultArgExprClass:
- return cast<CXXDefaultArgExpr>(this)
- ->isIntegerConstantExpr(Result, Ctx, Loc, isEvaluated);
-
- case UnaryTypeTraitExprClass:
- Result = Ctx.MakeIntValue(cast<UnaryTypeTraitExpr>(this)->EvaluateTrait(),
- getType());
- break;
+ case Expr::CXXDefaultArgExprClass:
+ return CheckICE(cast<CXXDefaultArgExpr>(E)->getExpr(), Ctx);
}
+}
+bool Expr::isIntegerConstantExpr(llvm::APSInt &Result, ASTContext &Ctx,
+ SourceLocation *Loc, bool isEvaluated) const {
+ ICEDiag d = CheckICE(this, Ctx);
+ if (d.Val != 0) {
+ if (Loc) *Loc = d.Loc;
+ return false;
+ }
+ EvalResult EvalResult;
+ if (!Evaluate(EvalResult, Ctx) || EvalResult.HasSideEffects ||
+ !EvalResult.Val.isInt()) {
+ if (Loc) *Loc = EvalResult.DiagLoc;
+ return false;
+ }
+ Result = EvalResult.Val.getInt();
return true;
}