зеркало из https://github.com/microsoft/clang-1.git
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
This commit is contained in:
Родитель
66a915fbd7
Коммит
d905f5ad54
379
lib/AST/Expr.cpp
379
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<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))
|
||||
return CheckEvalInICE(E, Ctx);
|
||||
return ICEDiag(2, E->getLocStart());
|
||||
}
|
||||
case Expr::DeclRefExprClass:
|
||||
if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
|
||||
return NoDiag();
|
||||
if (Ctx.getLangOptions().CPlusPlus &&
|
||||
E->getType().getCVRQualifiers() == Qualifiers::Const) {
|
||||
const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl();
|
||||
|
||||
// Parameter variables are never constants. Without this check,
|
||||
// getAnyInitializer() can find a default argument, which leads
|
||||
// to chaos.
|
||||
if (isa<ParmVarDecl>(D))
|
||||
return ICEDiag(2, 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)) {
|
||||
Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers();
|
||||
if (Quals.hasVolatile() || !Quals.hasConst())
|
||||
return ICEDiag(2, cast<DeclRefExpr>(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<DeclRefExpr>(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<DeclRefExpr>(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<UnaryOperator>(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<SizeOfAlignOfExpr>(E);
|
||||
if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType())
|
||||
return ICEDiag(2, E->getLocStart());
|
||||
return NoDiag();
|
||||
}
|
||||
case Expr::BinaryOperatorClass: {
|
||||
const BinaryOperator *Exp = cast<BinaryOperator>(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<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>(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<CXXDefaultArgExpr>(E)->getExpr(), Ctx);
|
||||
case Expr::ChooseExprClass: {
|
||||
return CheckICE(cast<ChooseExpr>(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*.
|
||||
|
|
|
@ -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<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))
|
||||
return CheckEvalInICE(E, Ctx);
|
||||
return ICEDiag(2, E->getLocStart());
|
||||
}
|
||||
case Expr::DeclRefExprClass:
|
||||
if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl()))
|
||||
return NoDiag();
|
||||
if (Ctx.getLangOptions().CPlusPlus &&
|
||||
E->getType().getCVRQualifiers() == Qualifiers::Const) {
|
||||
const NamedDecl *D = cast<DeclRefExpr>(E)->getDecl();
|
||||
|
||||
// Parameter variables are never constants. Without this check,
|
||||
// getAnyInitializer() can find a default argument, which leads
|
||||
// to chaos.
|
||||
if (isa<ParmVarDecl>(D))
|
||||
return ICEDiag(2, 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)) {
|
||||
Qualifiers Quals = Ctx.getCanonicalType(Dcl->getType()).getQualifiers();
|
||||
if (Quals.hasVolatile() || !Quals.hasConst())
|
||||
return ICEDiag(2, cast<DeclRefExpr>(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<DeclRefExpr>(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<DeclRefExpr>(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<UnaryOperator>(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<SizeOfAlignOfExpr>(E);
|
||||
if (Exp->isSizeOf() && Exp->getTypeOfArgument()->isVariableArrayType())
|
||||
return ICEDiag(2, E->getLocStart());
|
||||
return NoDiag();
|
||||
}
|
||||
case Expr::BinaryOperatorClass: {
|
||||
const BinaryOperator *Exp = cast<BinaryOperator>(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<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>(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<CXXDefaultArgExpr>(E)->getExpr(), Ctx);
|
||||
case Expr::ChooseExprClass: {
|
||||
return CheckICE(cast<ChooseExpr>(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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче