/// FIXME: Pass up a reason why! Invalid operation in i-c-e, division by zero,
/// comma, etc
-///
-/// 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.
// CheckICE - This function does the fundamental ICE checking: the returned
-// ICEDiag contains a Val of 0, 1, or 2, and a possibly null SourceLocation.
+// ICEDiag contains an ICEKind indicating whether the expression is an ICE,
+// and a (possibly null) SourceLocation indicating the location of the problem.
+//
// 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.
-// 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.
namespace {
+enum ICEKind {
+ /// This expression is an ICE.
+ IK_ICE,
+ /// 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, and non-constant subexpressions.
+ IK_ICEIfUnevaluated,
+ /// This expression is not an ICE, and is not a legal subexpression for one.
+ IK_NotICE
+};
+
struct ICEDiag {
- unsigned Val;
+ ICEKind Kind;
SourceLocation Loc;
- public:
- ICEDiag(unsigned v, SourceLocation l) : Val(v), Loc(l) {}
- ICEDiag() : Val(0) {}
+ ICEDiag(ICEKind IK, SourceLocation l) : Kind(IK), Loc(l) {}
};
}
-static ICEDiag NoDiag() { return ICEDiag(); }
+static ICEDiag NoDiag() { return ICEDiag(IK_ICE, SourceLocation()); }
+
+static ICEDiag Worst(ICEDiag A, ICEDiag B) { return A.Kind >= B.Kind ? A : B; }
static ICEDiag CheckEvalInICE(const Expr* E, ASTContext &Ctx) {
Expr::EvalResult EVResult;
if (!E->EvaluateAsRValue(EVResult, Ctx) || EVResult.HasSideEffects ||
- !EVResult.Val.isInt()) {
- return ICEDiag(2, E->getLocStart());
- }
+ !EVResult.Val.isInt())
+ return ICEDiag(IK_NotICE, E->getLocStart());
+
return NoDiag();
}
static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) {
assert(!E->isValueDependent() && "Should not see value dependent exprs!");
- if (!E->getType()->isIntegralOrEnumerationType()) {
- return ICEDiag(2, E->getLocStart());
- }
+ if (!E->getType()->isIntegralOrEnumerationType())
+ return ICEDiag(IK_NotICE, E->getLocStart());
switch (E->getStmtClass()) {
#define ABSTRACT_STMT(Node)
case Expr::AtomicExprClass:
case Expr::InitListExprClass:
case Expr::LambdaExprClass:
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
case Expr::SizeOfPackExprClass:
case Expr::GNUNullExprClass:
const CallExpr *CE = cast<CallExpr>(E);
if (CE->isBuiltinCall())
return CheckEvalInICE(E, Ctx);
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
case Expr::DeclRefExprClass: {
if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
// getAnyInitializer() can find a default argument, which leads
// to chaos.
if (isa<ParmVarDecl>(D))
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+ return ICEDiag(IK_NotICE, cast<DeclRefExpr>(E)->getLocation());
// 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>(D)) {
if (!Dcl->getType()->isIntegralOrEnumerationType())
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+ return ICEDiag(IK_NotICE, cast<DeclRefExpr>(E)->getLocation());
const VarDecl *VD;
// Look for a declaration of this variable that has an initializer, and
if (Dcl->getAnyInitializer(VD) && VD->checkInitIsICE())
return NoDiag();
else
- return ICEDiag(2, cast<DeclRefExpr>(E)->getLocation());
+ return ICEDiag(IK_NotICE, cast<DeclRefExpr>(E)->getLocation());
}
}
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
case Expr::UnaryOperatorClass: {
const UnaryOperator *Exp = cast<UnaryOperator>(E);
// C99 6.6/3 allows increment and decrement within unevaluated
// subexpressions of constant expressions, but they can never be ICEs
// because an ICE cannot contain an lvalue operand.
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
case UO_Extension:
case UO_LNot:
case UO_Plus:
case UO_Imag:
return CheckICE(Exp->getSubExpr(), Ctx);
}
-
+
// OffsetOf falls through here.
}
case Expr::OffsetOfExprClass: {
- // Note that per C99, offsetof must be an ICE. And AFAIK, using
- // EvaluateAsRValue matches the proposed gcc behavior for cases like
- // "offsetof(struct s{int x[4];}, x[1.0])". This doesn't affect
- // compliance: we should warn earlier for offsetof expressions with
- // array subscripts that aren't ICEs, and if the array subscripts
- // are ICEs, the value of the offsetof must be an integer constant.
- return CheckEvalInICE(E, Ctx);
+ // Note that per C99, offsetof must be an ICE. And AFAIK, using
+ // EvaluateAsRValue matches the proposed gcc behavior for cases like
+ // "offsetof(struct s{int x[4];}, x[1.0])". This doesn't affect
+ // compliance: we should warn earlier for offsetof expressions with
+ // array subscripts that aren't ICEs, and if the array subscripts
+ // are ICEs, the value of the offsetof must be an integer constant.
+ return CheckEvalInICE(E, Ctx);
}
case Expr::UnaryExprOrTypeTraitExprClass: {
const UnaryExprOrTypeTraitExpr *Exp = cast<UnaryExprOrTypeTraitExpr>(E);
if ((Exp->getKind() == UETT_SizeOf) &&
Exp->getTypeOfArgument()->isVariableArrayType())
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
return NoDiag();
}
case Expr::BinaryOperatorClass: {
// C99 6.6/3 allows assignments within unevaluated subexpressions of
// constant expressions, but they can never be ICEs because an ICE cannot
// contain an lvalue operand.
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
case BO_Mul:
case BO_Div:
Exp->getOpcode() == BO_Rem) {
// EvaluateAsRValue gives an error for undefined Div/Rem, so make sure
// we don't evaluate one.
- if (LHSResult.Val == 0 && RHSResult.Val == 0) {
+ if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICE) {
llvm::APSInt REval = Exp->getRHS()->EvaluateKnownConstInt(Ctx);
if (REval == 0)
- return ICEDiag(1, E->getLocStart());
+ return ICEDiag(IK_ICEIfUnevaluated, E->getLocStart());
if (REval.isSigned() && REval.isAllOnesValue()) {
llvm::APSInt LEval = Exp->getLHS()->EvaluateKnownConstInt(Ctx);
if (LEval.isMinSignedValue())
- return ICEDiag(1, E->getLocStart());
+ return ICEDiag(IK_ICEIfUnevaluated, E->getLocStart());
}
}
}
if (Ctx.getLangOpts().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.Kind == IK_ICE && RHSResult.Kind == IK_ICE)
+ return ICEDiag(IK_ICEIfUnevaluated, E->getLocStart());
} else {
// In both C89 and C++, commas in ICEs are illegal.
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
}
- if (LHSResult.Val >= RHSResult.Val)
- return LHSResult;
- return RHSResult;
+ return Worst(LHSResult, RHSResult);
}
case BO_LAnd:
case BO_LOr: {
ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx);
ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx);
- if (LHSResult.Val == 0 && RHSResult.Val == 1) {
+ if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICEIfUnevaluated) {
// 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.
return NoDiag();
}
- if (LHSResult.Val >= RHSResult.Val)
- return LHSResult;
- return RHSResult;
+ return Worst(LHSResult, RHSResult);
}
}
}
if (FL->getValue().convertToInteger(IgnoredVal,
llvm::APFloat::rmTowardZero,
&Ignored) & APFloat::opInvalidOp)
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
return NoDiag();
}
}
case CK_IntegralCast:
return CheckICE(SubExpr, Ctx);
default:
- return ICEDiag(2, E->getLocStart());
+ return ICEDiag(IK_NotICE, E->getLocStart());
}
}
case Expr::BinaryConditionalOperatorClass: {
const BinaryConditionalOperator *Exp = cast<BinaryConditionalOperator>(E);
ICEDiag CommonResult = CheckICE(Exp->getCommon(), Ctx);
- if (CommonResult.Val == 2) return CommonResult;
+ if (CommonResult.Kind == IK_NotICE) return CommonResult;
ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
- if (FalseResult.Val == 2) return FalseResult;
- if (CommonResult.Val == 1) return CommonResult;
- if (FalseResult.Val == 1 &&
+ if (FalseResult.Kind == IK_NotICE) return FalseResult;
+ if (CommonResult.Kind == IK_ICEIfUnevaluated) return CommonResult;
+ if (FalseResult.Kind == IK_ICEIfUnevaluated &&
Exp->getCommon()->EvaluateKnownConstInt(Ctx) != 0) return NoDiag();
return FalseResult;
}
if (CallCE->isBuiltinCall() == Builtin::BI__builtin_constant_p)
return CheckEvalInICE(E, Ctx);
ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx);
- if (CondResult.Val == 2)
+ if (CondResult.Kind == IK_NotICE)
return CondResult;
ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx);
ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx);
- if (TrueResult.Val == 2)
+ if (TrueResult.Kind == IK_NotICE)
return TrueResult;
- if (FalseResult.Val == 2)
+ if (FalseResult.Kind == IK_NotICE)
return FalseResult;
- if (CondResult.Val == 1)
+ if (CondResult.Kind == IK_ICEIfUnevaluated)
return CondResult;
- if (TrueResult.Val == 0 && FalseResult.Val == 0)
+ if (TrueResult.Kind == IK_ICE && FalseResult.Kind == IK_ICE)
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.
- if (Exp->getCond()->EvaluateKnownConstInt(Ctx) == 0) {
+ if (Exp->getCond()->EvaluateKnownConstInt(Ctx) == 0)
return FalseResult;
- }
return TrueResult;
}
case Expr::CXXDefaultArgExprClass:
if (Ctx.getLangOpts().CPlusPlus0x)
return EvaluateCPlusPlus11IntegralConstantExpr(Ctx, this, 0, Loc);
- ICEDiag d = CheckICE(this, Ctx);
- if (d.Val != 0) {
- if (Loc) *Loc = d.Loc;
+ ICEDiag D = CheckICE(this, Ctx);
+ if (D.Kind != IK_ICE) {
+ if (Loc) *Loc = D.Loc;
return false;
}
return true;
}
bool Expr::isCXX98IntegralConstantExpr(ASTContext &Ctx) const {
- return CheckICE(this, Ctx).Val == 0;
+ return CheckICE(this, Ctx).Kind == IK_ICE;
}
bool Expr::isCXX11ConstantExpr(ASTContext &Ctx, APValue *Result,