From: John McCall Date: Fri, 7 May 2010 05:32:02 +0000 (+0000) Subject: Move CheckICE and isIntegerConstantExpr to ExprConstant.cpp because it seemed X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d905f5ad540c415d1a21b4f8b7bd715bfb7bb920;p=clang Move CheckICE and isIntegerConstantExpr to ExprConstant.cpp because it seemed like a good idea at the time. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@103237 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 417bc964c8..b2e564834e 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -1769,385 +1769,6 @@ bool Expr::isConstantInitializer(ASTContext &Ctx) const { return isEvaluatable(Ctx); } -/// isIntegerConstantExpr - this recursive routine will test if an expression is -/// an integer constant expression. - -/// 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. -// 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 CheckEvalInICE(const Expr* E, ASTContext &Ctx) { - Expr::EvalResult EVResult; - if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects || - !EVResult.Val.isInt()) { - return ICEDiag(2, E->getLocStart()); - } - return NoDiag(); -} - -static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { - assert(!E->isValueDependent() && "Should not see value dependent exprs!"); - if (!E->getType()->isIntegralType()) { - return ICEDiag(2, E->getLocStart()); - } - - switch (E->getStmtClass()) { -#define STMT(Node, Base) case Expr::Node##Class: -#define EXPR(Node, Base) -#include "clang/AST/StmtNodes.inc" - case Expr::PredefinedExprClass: - case Expr::FloatingLiteralClass: - case Expr::ImaginaryLiteralClass: - case Expr::StringLiteralClass: - case Expr::ArraySubscriptExprClass: - case Expr::MemberExprClass: - case Expr::CompoundAssignOperatorClass: - case Expr::CompoundLiteralExprClass: - case Expr::ExtVectorElementExprClass: - case Expr::InitListExprClass: - case Expr::DesignatedInitExprClass: - case Expr::ImplicitValueInitExprClass: - case Expr::ParenListExprClass: - case Expr::VAArgExprClass: - case Expr::AddrLabelExprClass: - case Expr::StmtExprClass: - case Expr::CXXMemberCallExprClass: - case Expr::CXXDynamicCastExprClass: - case Expr::CXXTypeidExprClass: - case Expr::CXXNullPtrLiteralExprClass: - case Expr::CXXThisExprClass: - case Expr::CXXThrowExprClass: - case Expr::CXXNewExprClass: - case Expr::CXXDeleteExprClass: - case Expr::CXXPseudoDestructorExprClass: - case Expr::UnresolvedLookupExprClass: - case Expr::DependentScopeDeclRefExprClass: - case Expr::CXXConstructExprClass: - case Expr::CXXBindTemporaryExprClass: - case Expr::CXXBindReferenceExprClass: - case Expr::CXXExprWithTemporariesClass: - case Expr::CXXTemporaryObjectExprClass: - case Expr::CXXUnresolvedConstructExprClass: - case Expr::CXXDependentScopeMemberExprClass: - case Expr::UnresolvedMemberExprClass: - case Expr::ObjCStringLiteralClass: - case Expr::ObjCEncodeExprClass: - case Expr::ObjCMessageExprClass: - case Expr::ObjCSelectorExprClass: - case Expr::ObjCProtocolExprClass: - case Expr::ObjCIvarRefExprClass: - case Expr::ObjCPropertyRefExprClass: - case Expr::ObjCImplicitSetterGetterRefExprClass: - case Expr::ObjCSuperExprClass: - case Expr::ObjCIsaExprClass: - case Expr::ShuffleVectorExprClass: - case Expr::BlockExprClass: - case Expr::BlockDeclRefExprClass: - case Expr::NoStmtClass: - return ICEDiag(2, E->getLocStart()); - - case Expr::GNUNullExprClass: - // GCC considers the GNU __null value to be an integral constant expression. - return NoDiag(); - - case Expr::ParenExprClass: - return CheckICE(cast(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(E); - if (CE->isBuiltinCall(Ctx)) - return CheckEvalInICE(E, Ctx); - return ICEDiag(2, E->getLocStart()); - } - case Expr::DeclRefExprClass: - if (isa(cast(E)->getDecl())) - return NoDiag(); - if (Ctx.getLangOptions().CPlusPlus && - E->getType().getCVRQualifiers() == Qualifiers::Const) { - const NamedDecl *D = cast(E)->getDecl(); - - // Parameter variables are never constants. Without this check, - // getAnyInitializer() can find a default argument, which leads - // to chaos. - if (isa(D)) - return ICEDiag(2, cast(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(D)) { - Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers(); - if (Quals.hasVolatile() || !Quals.hasConst()) - return ICEDiag(2, cast(E)->getLocation()); - - // Look for a declaration of this variable that has an initializer. - const VarDecl *ID = 0; - const Expr *Init = Dcl->getAnyInitializer(ID); - if (Init) { - if (ID->isInitKnownICE()) { - // We have already checked whether this subexpression is an - // integral constant expression. - if (ID->isInitICE()) - return NoDiag(); - else - return ICEDiag(2, cast(E)->getLocation()); - } - - // It's an ICE whether or not the definition we found is - // out-of-line. See DR 721 and the discussion in Clang PR - // 6206 for details. - - if (Dcl->isCheckingICE()) { - return ICEDiag(2, cast(E)->getLocation()); - } - - Dcl->setCheckingICE(); - ICEDiag Result = CheckICE(Init, Ctx); - // Cache the result of the ICE test. - Dcl->setInitKnownICE(Result.Val == 0); - return Result; - } - } - } - return ICEDiag(2, E->getLocStart()); - case Expr::UnaryOperatorClass: { - const UnaryOperator *Exp = cast(E); - switch (Exp->getOpcode()) { - case UnaryOperator::PostInc: - case UnaryOperator::PostDec: - case UnaryOperator::PreInc: - case UnaryOperator::PreDec: - case UnaryOperator::AddrOf: - case UnaryOperator::Deref: - return ICEDiag(2, E->getLocStart()); - case UnaryOperator::Extension: - case UnaryOperator::LNot: - case UnaryOperator::Plus: - case UnaryOperator::Minus: - case UnaryOperator::Not: - case UnaryOperator::Real: - case UnaryOperator::Imag: - return CheckICE(Exp->getSubExpr(), Ctx); - case UnaryOperator::OffsetOf: - break; - } - - // OffsetOf falls through here. - } - case Expr::OffsetOfExprClass: { - // Note that per C99, offsetof must be an ICE. And AFAIK, using - // Evaluate matches the proposed gcc behavior for cases like - // "offsetof(struct s{int x[4];}, x[!.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::SizeOfAlignOfExprClass: { - const SizeOfAlignOfExpr *Exp = cast(E); - if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType()) - return ICEDiag(2, E->getLocStart()); - return NoDiag(); - } - case Expr::BinaryOperatorClass: { - const BinaryOperator *Exp = cast(E); - switch (Exp->getOpcode()) { - case BinaryOperator::PtrMemD: - case BinaryOperator::PtrMemI: - case BinaryOperator::Assign: - case BinaryOperator::MulAssign: - case BinaryOperator::DivAssign: - case BinaryOperator::RemAssign: - case BinaryOperator::AddAssign: - case BinaryOperator::SubAssign: - case BinaryOperator::ShlAssign: - case BinaryOperator::ShrAssign: - case BinaryOperator::AndAssign: - case BinaryOperator::XorAssign: - case BinaryOperator::OrAssign: - return ICEDiag(2, E->getLocStart()); - - case BinaryOperator::Mul: - case BinaryOperator::Div: - case BinaryOperator::Rem: - case BinaryOperator::Add: - case BinaryOperator::Sub: - case BinaryOperator::Shl: - case BinaryOperator::Shr: - 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::Div || - Exp->getOpcode() == BinaryOperator::Rem) { - // Evaluate gives an error for undefined Div/Rem, so make sure - // we don't evaluate one. - if (LHSResult.Val != 2 && RHSResult.Val != 2) { - llvm::APSInt REval = Exp->getRHS()->EvaluateAsInt(Ctx); - if (REval == 0) - return ICEDiag(1, E->getLocStart()); - if (REval.isSigned() && REval.isAllOnesValue()) { - llvm::APSInt LEval = Exp->getLHS()->EvaluateAsInt(Ctx); - if (LEval.isMinSignedValue()) - return ICEDiag(1, E->getLocStart()); - } - } - } - if (Exp->getOpcode() == BinaryOperator::Comma) { - if (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()); - } else { - // In both C89 and C++, commas in ICEs are illegal. - return ICEDiag(2, E->getLocStart()); - } - } - if (LHSResult.Val >= RHSResult.Val) - return LHSResult; - return RHSResult; - } - case BinaryOperator::LAnd: - 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. - if ((Exp->getOpcode() == BinaryOperator::LAnd) != - (Exp->getLHS()->EvaluateAsInt(Ctx) == 0)) - return RHSResult; - return NoDiag(); - } - - if (LHSResult.Val >= RHSResult.Val) - return LHSResult; - return RHSResult; - } - } - } - case Expr::ImplicitCastExprClass: - case Expr::CStyleCastExprClass: - case Expr::CXXFunctionalCastExprClass: - case Expr::CXXStaticCastExprClass: - case Expr::CXXReinterpretCastExprClass: - case Expr::CXXConstCastExprClass: { - const Expr *SubExpr = cast(E)->getSubExpr(); - if (SubExpr->getType()->isIntegralType()) - return CheckICE(SubExpr, Ctx); - if (isa(SubExpr->IgnoreParens())) - return NoDiag(); - return ICEDiag(2, E->getLocStart()); - } - case Expr::ConditionalOperatorClass: { - const ConditionalOperator *Exp = cast(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(Exp->getCond()->IgnoreParenCasts())) - if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) { - Expr::EvalResult EVResult; - if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects || - !EVResult.Val.isInt()) { - return ICEDiag(2, E->getLocStart()); - } - return NoDiag(); - } - 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. - if (Exp->getCond()->EvaluateAsInt(Ctx) == 0) { - return FalseResult; - } - return TrueResult; - } - case Expr::CXXDefaultArgExprClass: - return CheckICE(cast(E)->getExpr(), Ctx); - case Expr::ChooseExprClass: { - return CheckICE(cast(E)->getChosenSubExpr(Ctx), Ctx); - } - } - - // Silence a GCC warning - return ICEDiag(2, E->getLocStart()); -} - -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)) - llvm_unreachable("ICE cannot be evaluated!"); - assert(!EvalResult.HasSideEffects && "ICE with side effects!"); - assert(EvalResult.Val.isInt() && "ICE that isn't integer!"); - Result = EvalResult.Val.getInt(); - return true; -} - /// isNullPointerConstant - C99 6.3.2.3p3 - Return true if this is either an /// integer constant expression with the value zero, or if this is one that is /// cast to void*. diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp index c1a42d88ff..f6e0c29d8d 100644 --- a/lib/AST/ExprConstant.cpp +++ b/lib/AST/ExprConstant.cpp @@ -2159,3 +2159,382 @@ APSInt Expr::EvaluateAsInt(ASTContext &Ctx) const { return EvalResult.Val.getInt(); } + +/// isIntegerConstantExpr - this recursive routine will test if an expression is +/// an integer constant expression. + +/// 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. +// 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 CheckEvalInICE(const Expr* E, ASTContext &Ctx) { + Expr::EvalResult EVResult; + if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects || + !EVResult.Val.isInt()) { + return ICEDiag(2, E->getLocStart()); + } + return NoDiag(); +} + +static ICEDiag CheckICE(const Expr* E, ASTContext &Ctx) { + assert(!E->isValueDependent() && "Should not see value dependent exprs!"); + if (!E->getType()->isIntegralType()) { + return ICEDiag(2, E->getLocStart()); + } + + switch (E->getStmtClass()) { +#define STMT(Node, Base) case Expr::Node##Class: +#define EXPR(Node, Base) +#include "clang/AST/StmtNodes.inc" + case Expr::PredefinedExprClass: + case Expr::FloatingLiteralClass: + case Expr::ImaginaryLiteralClass: + case Expr::StringLiteralClass: + case Expr::ArraySubscriptExprClass: + case Expr::MemberExprClass: + case Expr::CompoundAssignOperatorClass: + case Expr::CompoundLiteralExprClass: + case Expr::ExtVectorElementExprClass: + case Expr::InitListExprClass: + case Expr::DesignatedInitExprClass: + case Expr::ImplicitValueInitExprClass: + case Expr::ParenListExprClass: + case Expr::VAArgExprClass: + case Expr::AddrLabelExprClass: + case Expr::StmtExprClass: + case Expr::CXXMemberCallExprClass: + case Expr::CXXDynamicCastExprClass: + case Expr::CXXTypeidExprClass: + case Expr::CXXNullPtrLiteralExprClass: + case Expr::CXXThisExprClass: + case Expr::CXXThrowExprClass: + case Expr::CXXNewExprClass: + case Expr::CXXDeleteExprClass: + case Expr::CXXPseudoDestructorExprClass: + case Expr::UnresolvedLookupExprClass: + case Expr::DependentScopeDeclRefExprClass: + case Expr::CXXConstructExprClass: + case Expr::CXXBindTemporaryExprClass: + case Expr::CXXBindReferenceExprClass: + case Expr::CXXExprWithTemporariesClass: + case Expr::CXXTemporaryObjectExprClass: + case Expr::CXXUnresolvedConstructExprClass: + case Expr::CXXDependentScopeMemberExprClass: + case Expr::UnresolvedMemberExprClass: + case Expr::ObjCStringLiteralClass: + case Expr::ObjCEncodeExprClass: + case Expr::ObjCMessageExprClass: + case Expr::ObjCSelectorExprClass: + case Expr::ObjCProtocolExprClass: + case Expr::ObjCIvarRefExprClass: + case Expr::ObjCPropertyRefExprClass: + case Expr::ObjCImplicitSetterGetterRefExprClass: + case Expr::ObjCSuperExprClass: + case Expr::ObjCIsaExprClass: + case Expr::ShuffleVectorExprClass: + case Expr::BlockExprClass: + case Expr::BlockDeclRefExprClass: + case Expr::NoStmtClass: + return ICEDiag(2, E->getLocStart()); + + case Expr::GNUNullExprClass: + // GCC considers the GNU __null value to be an integral constant expression. + return NoDiag(); + + case Expr::ParenExprClass: + return CheckICE(cast(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(E); + if (CE->isBuiltinCall(Ctx)) + return CheckEvalInICE(E, Ctx); + return ICEDiag(2, E->getLocStart()); + } + case Expr::DeclRefExprClass: + if (isa(cast(E)->getDecl())) + return NoDiag(); + if (Ctx.getLangOptions().CPlusPlus && + E->getType().getCVRQualifiers() == Qualifiers::Const) { + const NamedDecl *D = cast(E)->getDecl(); + + // Parameter variables are never constants. Without this check, + // getAnyInitializer() can find a default argument, which leads + // to chaos. + if (isa(D)) + return ICEDiag(2, cast(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(D)) { + Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers(); + if (Quals.hasVolatile() || !Quals.hasConst()) + return ICEDiag(2, cast(E)->getLocation()); + + // Look for a declaration of this variable that has an initializer. + const VarDecl *ID = 0; + const Expr *Init = Dcl->getAnyInitializer(ID); + if (Init) { + if (ID->isInitKnownICE()) { + // We have already checked whether this subexpression is an + // integral constant expression. + if (ID->isInitICE()) + return NoDiag(); + else + return ICEDiag(2, cast(E)->getLocation()); + } + + // It's an ICE whether or not the definition we found is + // out-of-line. See DR 721 and the discussion in Clang PR + // 6206 for details. + + if (Dcl->isCheckingICE()) { + return ICEDiag(2, cast(E)->getLocation()); + } + + Dcl->setCheckingICE(); + ICEDiag Result = CheckICE(Init, Ctx); + // Cache the result of the ICE test. + Dcl->setInitKnownICE(Result.Val == 0); + return Result; + } + } + } + return ICEDiag(2, E->getLocStart()); + case Expr::UnaryOperatorClass: { + const UnaryOperator *Exp = cast(E); + switch (Exp->getOpcode()) { + case UnaryOperator::PostInc: + case UnaryOperator::PostDec: + case UnaryOperator::PreInc: + case UnaryOperator::PreDec: + case UnaryOperator::AddrOf: + case UnaryOperator::Deref: + return ICEDiag(2, E->getLocStart()); + case UnaryOperator::Extension: + case UnaryOperator::LNot: + case UnaryOperator::Plus: + case UnaryOperator::Minus: + case UnaryOperator::Not: + case UnaryOperator::Real: + case UnaryOperator::Imag: + return CheckICE(Exp->getSubExpr(), Ctx); + case UnaryOperator::OffsetOf: + break; + } + + // OffsetOf falls through here. + } + case Expr::OffsetOfExprClass: { + // Note that per C99, offsetof must be an ICE. And AFAIK, using + // Evaluate matches the proposed gcc behavior for cases like + // "offsetof(struct s{int x[4];}, x[!.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::SizeOfAlignOfExprClass: { + const SizeOfAlignOfExpr *Exp = cast(E); + if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType()) + return ICEDiag(2, E->getLocStart()); + return NoDiag(); + } + case Expr::BinaryOperatorClass: { + const BinaryOperator *Exp = cast(E); + switch (Exp->getOpcode()) { + case BinaryOperator::PtrMemD: + case BinaryOperator::PtrMemI: + case BinaryOperator::Assign: + case BinaryOperator::MulAssign: + case BinaryOperator::DivAssign: + case BinaryOperator::RemAssign: + case BinaryOperator::AddAssign: + case BinaryOperator::SubAssign: + case BinaryOperator::ShlAssign: + case BinaryOperator::ShrAssign: + case BinaryOperator::AndAssign: + case BinaryOperator::XorAssign: + case BinaryOperator::OrAssign: + return ICEDiag(2, E->getLocStart()); + + case BinaryOperator::Mul: + case BinaryOperator::Div: + case BinaryOperator::Rem: + case BinaryOperator::Add: + case BinaryOperator::Sub: + case BinaryOperator::Shl: + case BinaryOperator::Shr: + 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::Div || + Exp->getOpcode() == BinaryOperator::Rem) { + // Evaluate gives an error for undefined Div/Rem, so make sure + // we don't evaluate one. + if (LHSResult.Val != 2 && RHSResult.Val != 2) { + llvm::APSInt REval = Exp->getRHS()->EvaluateAsInt(Ctx); + if (REval == 0) + return ICEDiag(1, E->getLocStart()); + if (REval.isSigned() && REval.isAllOnesValue()) { + llvm::APSInt LEval = Exp->getLHS()->EvaluateAsInt(Ctx); + if (LEval.isMinSignedValue()) + return ICEDiag(1, E->getLocStart()); + } + } + } + if (Exp->getOpcode() == BinaryOperator::Comma) { + if (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()); + } else { + // In both C89 and C++, commas in ICEs are illegal. + return ICEDiag(2, E->getLocStart()); + } + } + if (LHSResult.Val >= RHSResult.Val) + return LHSResult; + return RHSResult; + } + case BinaryOperator::LAnd: + 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. + if ((Exp->getOpcode() == BinaryOperator::LAnd) != + (Exp->getLHS()->EvaluateAsInt(Ctx) == 0)) + return RHSResult; + return NoDiag(); + } + + if (LHSResult.Val >= RHSResult.Val) + return LHSResult; + return RHSResult; + } + } + } + case Expr::ImplicitCastExprClass: + case Expr::CStyleCastExprClass: + case Expr::CXXFunctionalCastExprClass: + case Expr::CXXStaticCastExprClass: + case Expr::CXXReinterpretCastExprClass: + case Expr::CXXConstCastExprClass: { + const Expr *SubExpr = cast(E)->getSubExpr(); + if (SubExpr->getType()->isIntegralType()) + return CheckICE(SubExpr, Ctx); + if (isa(SubExpr->IgnoreParens())) + return NoDiag(); + return ICEDiag(2, E->getLocStart()); + } + case Expr::ConditionalOperatorClass: { + const ConditionalOperator *Exp = cast(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(Exp->getCond()->IgnoreParenCasts())) + if (CallCE->isBuiltinCall(Ctx) == Builtin::BI__builtin_constant_p) { + Expr::EvalResult EVResult; + if (!E->Evaluate(EVResult, Ctx) || EVResult.HasSideEffects || + !EVResult.Val.isInt()) { + return ICEDiag(2, E->getLocStart()); + } + return NoDiag(); + } + 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. + if (Exp->getCond()->EvaluateAsInt(Ctx) == 0) { + return FalseResult; + } + return TrueResult; + } + case Expr::CXXDefaultArgExprClass: + return CheckICE(cast(E)->getExpr(), Ctx); + case Expr::ChooseExprClass: { + return CheckICE(cast(E)->getChosenSubExpr(Ctx), Ctx); + } + } + + // Silence a GCC warning + return ICEDiag(2, E->getLocStart()); +} + +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)) + llvm_unreachable("ICE cannot be evaluated!"); + assert(!EvalResult.HasSideEffects && "ICE with side effects!"); + assert(EvalResult.Val.isInt() && "ICE that isn't integer!"); + Result = EvalResult.Val.getInt(); + return true; +}