void created this revision. void added reviewers: rsmith, shafik. Herald added a subscriber: jfb.
This cleans up the code somewhat and allows us conditionally to act on different types of nodes depending on their context. E.g., if we're checking for an ICE in a constant context. Repository: rC Clang https://reviews.llvm.org/D54356 Files: lib/AST/ExprConstant.cpp
Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -10956,401 +10956,372 @@ static ICEDiag Worst(ICEDiag A, ICEDiag B) { return A.Kind >= B.Kind ? A : B; } -static ICEDiag CheckEvalInICE(const Expr* E, const ASTContext &Ctx) { +static ICEDiag CheckEvalInICE(const Expr *E, const ASTContext &Ctx, + EvalInfo &Info) { Expr::EvalResult EVResult; - if (!E->EvaluateAsRValue(EVResult, Ctx) || EVResult.HasSideEffects || + if (!::EvaluateAsRValue(Info, E, EVResult.Val) || EVResult.HasSideEffects || !EVResult.Val.isInt()) return ICEDiag(IK_NotICE, E->getBeginLoc()); return NoDiag(); } +class ICEChecker + : public ConstStmtVisitor<ICEChecker, ICEDiag> { + const ASTContext &Ctx; + EvalInfo &Info; + + typedef ConstStmtVisitor<ICEChecker, ICEDiag> StmtVisitorTy; + +public: + ICEChecker(const ASTContext &Ctx, EvalInfo &Info) + : Ctx(Ctx), Info(Info) {} + + ICEDiag VisitStmt(const Stmt *S) { + return ICEDiag(IK_NotICE, S->getBeginLoc()); + } + + ICEDiag VisitExpr(const Expr *E); + ICEDiag VisitInitListExpr(const InitListExpr *E); + ICEDiag VisitSubstNonTypeTemplateParmExpr( + const SubstNonTypeTemplateParmExpr *E); + ICEDiag VisitParenExpr(const ParenExpr *E); + ICEDiag VisitGenericSelectionExpr(const GenericSelectionExpr *E); + ICEDiag VisitCallExpr(const CallExpr *E); + ICEDiag VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *E); + ICEDiag VisitDeclRefExpr(const DeclRefExpr *E); + ICEDiag VisitBinaryOperator(const BinaryOperator *E); + ICEDiag VisitUnaryOperator(const UnaryOperator *E); + ICEDiag VisitOffsetOfExpr(const OffsetOfExpr *E); + ICEDiag VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E); + ICEDiag VisitCastExpr(const CastExpr *E); + ICEDiag VisitBinaryConditionalOperator(const BinaryConditionalOperator *E); + ICEDiag VisitConditionalOperator(const ConditionalOperator *E); + ICEDiag VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E); + ICEDiag VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E); + ICEDiag VisitChooseExpr(const ChooseExpr *E); +}; + +ICEDiag ICEChecker::VisitExpr(const Expr *E) { + switch (E->getStmtClass()) { + default: + return ICEDiag(IK_NotICE, E->getBeginLoc()); + case Expr::ArrayTypeTraitExprClass: + case Expr::CharacterLiteralClass: + case Expr::CXXBoolLiteralExprClass: + case Expr::CXXNoexceptExprClass: + case Expr::CXXScalarValueInitExprClass: + case Expr::ExpressionTraitExprClass: + case Expr::FixedPointLiteralClass: + case Expr::GNUNullExprClass: + // GCC considers the GNU __null value to be an integral constant expression. + case Expr::IntegerLiteralClass: + case Expr::ObjCBoolLiteralExprClass: + case Expr::SizeOfPackExprClass: + case Expr::TypeTraitExprClass: + return NoDiag(); + } +} + +ICEDiag ICEChecker::VisitInitListExpr(const InitListExpr *E) { + // C++03 [dcl.init]p13: If T is a scalar type, then a declaration of the form + // "T x = { a };" is equivalent to "T x = a;". + // Unless we're initializing a reference, T is a scalar as it is known to be + // of integral or enumeration type. + if (E->isRValue()) + if (E->getNumInits() == 1) + return StmtVisitorTy::Visit(E->getInit(0)); + return ICEDiag(IK_NotICE, E->getBeginLoc()); +} + +ICEDiag ICEChecker::VisitSubstNonTypeTemplateParmExpr( + const SubstNonTypeTemplateParmExpr *E) { + return StmtVisitorTy::Visit(E->getReplacement()); +} + +ICEDiag ICEChecker::VisitParenExpr(const ParenExpr *E) { + return StmtVisitorTy::Visit(E->getSubExpr()); +} + +ICEDiag ICEChecker::VisitGenericSelectionExpr(const GenericSelectionExpr *E) { + return StmtVisitorTy::Visit(E->getResultExpr()); +} + +ICEDiag ICEChecker::VisitCallExpr(const CallExpr *E) { + // C99 6.6/3 allows function calls within unevaluated subexpressions of + // constant expressions, but they can never be ICEs because an ICE cannot + // contain an operand of (pointer to) function type. + if (E->getBuiltinCallee()) + return CheckEvalInICE(E, Ctx, Info); + return ICEDiag(IK_NotICE, E->getBeginLoc()); +} + +ICEDiag ICEChecker::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *E) { + return VisitCallExpr(E); +} + +ICEDiag ICEChecker::VisitDeclRefExpr(const DeclRefExpr *E) { + if (isa<EnumConstantDecl>(E->getDecl())) + return NoDiag(); + + const ValueDecl *D = E->getDecl(); + if (Ctx.getLangOpts().CPlusPlus && + D && IsConstNonVolatile(D->getType())) { + // Parameter variables are never constants. Without this check, + // getAnyInitializer() can find a default argument, which leads + // to chaos. + if (isa<ParmVarDecl>(D)) + return ICEDiag(IK_NotICE, 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(IK_NotICE, E->getLocation()); + + const VarDecl *VD; + // Look for a declaration of this variable that has an initializer, and + // check whether it is an ICE. + if (Dcl->getAnyInitializer(VD) && VD->checkInitIsICE()) + return NoDiag(); + else + return ICEDiag(IK_NotICE, E->getLocation()); + } + } + return ICEDiag(IK_NotICE, E->getBeginLoc()); +} + +ICEDiag ICEChecker::VisitUnaryOperator(const UnaryOperator *E) { + switch (E->getOpcode()) { + case UO_PostInc: + case UO_PostDec: + case UO_PreInc: + case UO_PreDec: + case UO_AddrOf: + case UO_Deref: + case UO_Coawait: + // 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(IK_NotICE, E->getBeginLoc()); + + case UO_Extension: + case UO_LNot: + case UO_Plus: + case UO_Minus: + case UO_Not: + case UO_Real: + case UO_Imag: + return StmtVisitorTy::Visit(E->getSubExpr()); + } + llvm_unreachable("invalid unary operator class"); +} + +ICEDiag ICEChecker::VisitBinaryOperator(const BinaryOperator *E) { + switch (E->getOpcode()) { + case BO_PtrMemD: + case BO_PtrMemI: + case BO_Assign: + case BO_MulAssign: + case BO_DivAssign: + case BO_RemAssign: + case BO_AddAssign: + case BO_SubAssign: + case BO_ShlAssign: + case BO_ShrAssign: + case BO_AndAssign: + case BO_XorAssign: + case BO_OrAssign: + // 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(IK_NotICE, E->getBeginLoc()); + + case BO_Mul: + case BO_Div: + case BO_Rem: + case BO_Add: + case BO_Sub: + case BO_Shl: + case BO_Shr: + case BO_LT: + case BO_GT: + case BO_LE: + case BO_GE: + case BO_EQ: + case BO_NE: + case BO_And: + case BO_Xor: + case BO_Or: + case BO_Comma: + case BO_Cmp: { + ICEDiag LHSResult = StmtVisitorTy::Visit(E->getLHS()); + ICEDiag RHSResult = StmtVisitorTy::Visit(E->getRHS()); + if (E->getOpcode() == BO_Div || + E->getOpcode() == BO_Rem) { + // EvaluateAsRValue gives an error for undefined Div/Rem, so make sure + // we don't evaluate one. + if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICE) { + llvm::APSInt REval = E->getRHS()->EvaluateKnownConstInt(Ctx); + if (REval == 0) + return ICEDiag(IK_ICEIfUnevaluated, E->getBeginLoc()); + if (REval.isSigned() && REval.isAllOnesValue()) { + llvm::APSInt LEval = E->getLHS()->EvaluateKnownConstInt(Ctx); + if (LEval.isMinSignedValue()) + return ICEDiag(IK_ICEIfUnevaluated, E->getBeginLoc()); + } + } + } + if (E->getOpcode() == BO_Comma) { + 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.Kind == IK_ICE && RHSResult.Kind == IK_ICE) + return ICEDiag(IK_ICEIfUnevaluated, E->getBeginLoc()); + } else { + // In both C89 and C++, commas in ICEs are illegal. + return ICEDiag(IK_NotICE, E->getBeginLoc()); + } + } + return Worst(LHSResult, RHSResult); + } + case BO_LAnd: + case BO_LOr: { + ICEDiag LHSResult = StmtVisitorTy::Visit(E->getLHS()); + ICEDiag RHSResult = StmtVisitorTy::Visit(E->getRHS()); + 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. + if ((E->getOpcode() == BO_LAnd) != + (E->getLHS()->EvaluateKnownConstInt(Ctx) == 0)) + return RHSResult; + return NoDiag(); + } + + return Worst(LHSResult, RHSResult); + } + } + llvm_unreachable("invalid binary operator kind"); +} + +ICEDiag ICEChecker::VisitOffsetOfExpr(const OffsetOfExpr *E) { + // 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, Info); +} + +ICEDiag ICEChecker::VisitUnaryExprOrTypeTraitExpr( + const UnaryExprOrTypeTraitExpr *E) { + if (E->getKind() == UETT_SizeOf && + E->getTypeOfArgument()->isVariableArrayType()) + return ICEDiag(IK_NotICE, E->getBeginLoc()); + return NoDiag(); +} + +ICEDiag ICEChecker::VisitCastExpr(const CastExpr *E) { + const Expr *SubExpr = E->getSubExpr(); + if (isa<ExplicitCastExpr>(E)) { + if (const FloatingLiteral *FL + = dyn_cast<FloatingLiteral>(SubExpr->IgnoreParenImpCasts())) { + unsigned DestWidth = Ctx.getIntWidth(E->getType()); + bool DestSigned = E->getType()->isSignedIntegerOrEnumerationType(); + APSInt IgnoredVal(DestWidth, !DestSigned); + bool Ignored; + // If the value does not fit in the destination type, the behavior is + // undefined, so we are not required to treat it as a constant + // expression. + if (FL->getValue().convertToInteger(IgnoredVal, + llvm::APFloat::rmTowardZero, + &Ignored) & APFloat::opInvalidOp) + return ICEDiag(IK_NotICE, E->getBeginLoc()); + return NoDiag(); + } + } + switch (E->getCastKind()) { + default: + return ICEDiag(IK_NotICE, E->getBeginLoc()); + case CK_LValueToRValue: + case CK_AtomicToNonAtomic: + case CK_NonAtomicToAtomic: + case CK_NoOp: + case CK_IntegralToBoolean: + case CK_IntegralCast: + return StmtVisitorTy::Visit(SubExpr); + } +} + +ICEDiag ICEChecker::VisitBinaryConditionalOperator( + const BinaryConditionalOperator *E) { + ICEDiag CommonResult = StmtVisitorTy::Visit(E->getCommon()); + if (CommonResult.Kind == IK_NotICE) return CommonResult; + ICEDiag FalseResult = StmtVisitorTy::Visit(E->getFalseExpr()); + if (FalseResult.Kind == IK_NotICE) return FalseResult; + if (CommonResult.Kind == IK_ICEIfUnevaluated) return CommonResult; + if (FalseResult.Kind == IK_ICEIfUnevaluated && + E->getCommon()->EvaluateKnownConstInt(Ctx) != 0) return NoDiag(); + return FalseResult; +} + +ICEDiag ICEChecker::VisitConditionalOperator(const 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>(E->getCond()->IgnoreParenCasts())) + if (CallCE->getBuiltinCallee() == Builtin::BI__builtin_constant_p) + return CheckEvalInICE(E, Ctx, Info); + ICEDiag CondResult = StmtVisitorTy::Visit(E->getCond()); + if (CondResult.Kind == IK_NotICE) + return CondResult; + + ICEDiag TrueResult = StmtVisitorTy::Visit(E->getTrueExpr()); + ICEDiag FalseResult = StmtVisitorTy::Visit(E->getFalseExpr()); + + if (TrueResult.Kind == IK_NotICE) + return TrueResult; + if (FalseResult.Kind == IK_NotICE) + return FalseResult; + if (CondResult.Kind == IK_ICEIfUnevaluated) + return CondResult; + 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 (E->getCond()->EvaluateKnownConstInt(Ctx) == 0) + return FalseResult; + return TrueResult; +} + +ICEDiag ICEChecker::VisitCXXDefaultArgExpr(const CXXDefaultArgExpr *E) { + return StmtVisitorTy::Visit(E->getExpr()); +} + +ICEDiag ICEChecker::VisitCXXDefaultInitExpr(const CXXDefaultInitExpr *E) { + return StmtVisitorTy::Visit(E->getExpr()); +} + +ICEDiag ICEChecker::VisitChooseExpr(const ChooseExpr *E) { + return StmtVisitorTy::Visit(E->getChosenSubExpr()); +} + static ICEDiag CheckICE(const Expr* E, const ASTContext &Ctx) { assert(!E->isValueDependent() && "Should not see value dependent exprs!"); if (!E->getType()->isIntegralOrEnumerationType()) return ICEDiag(IK_NotICE, E->getBeginLoc()); - switch (E->getStmtClass()) { -#define ABSTRACT_STMT(Node) -#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::OMPArraySectionExprClass: - case Expr::MemberExprClass: - case Expr::CompoundAssignOperatorClass: - case Expr::CompoundLiteralExprClass: - case Expr::ExtVectorElementExprClass: - case Expr::DesignatedInitExprClass: - case Expr::ArrayInitLoopExprClass: - case Expr::ArrayInitIndexExprClass: - case Expr::NoInitExprClass: - case Expr::DesignatedInitUpdateExprClass: - case Expr::ImplicitValueInitExprClass: - case Expr::ParenListExprClass: - case Expr::VAArgExprClass: - case Expr::AddrLabelExprClass: - case Expr::StmtExprClass: - case Expr::CXXMemberCallExprClass: - case Expr::CUDAKernelCallExprClass: - case Expr::CXXDynamicCastExprClass: - case Expr::CXXTypeidExprClass: - case Expr::CXXUuidofExprClass: - case Expr::MSPropertyRefExprClass: - case Expr::MSPropertySubscriptExprClass: - case Expr::CXXNullPtrLiteralExprClass: - case Expr::UserDefinedLiteralClass: - case Expr::CXXThisExprClass: - case Expr::CXXThrowExprClass: - case Expr::CXXNewExprClass: - case Expr::CXXDeleteExprClass: - case Expr::CXXPseudoDestructorExprClass: - case Expr::UnresolvedLookupExprClass: - case Expr::TypoExprClass: - case Expr::DependentScopeDeclRefExprClass: - case Expr::CXXConstructExprClass: - case Expr::CXXInheritedCtorInitExprClass: - case Expr::CXXStdInitializerListExprClass: - case Expr::CXXBindTemporaryExprClass: - case Expr::ExprWithCleanupsClass: - case Expr::CXXTemporaryObjectExprClass: - case Expr::CXXUnresolvedConstructExprClass: - case Expr::CXXDependentScopeMemberExprClass: - case Expr::UnresolvedMemberExprClass: - case Expr::ObjCStringLiteralClass: - case Expr::ObjCBoxedExprClass: - case Expr::ObjCArrayLiteralClass: - case Expr::ObjCDictionaryLiteralClass: - case Expr::ObjCEncodeExprClass: - case Expr::ObjCMessageExprClass: - case Expr::ObjCSelectorExprClass: - case Expr::ObjCProtocolExprClass: - case Expr::ObjCIvarRefExprClass: - case Expr::ObjCPropertyRefExprClass: - case Expr::ObjCSubscriptRefExprClass: - case Expr::ObjCIsaExprClass: - case Expr::ObjCAvailabilityCheckExprClass: - case Expr::ShuffleVectorExprClass: - case Expr::ConvertVectorExprClass: - case Expr::BlockExprClass: - case Expr::NoStmtClass: - case Expr::OpaqueValueExprClass: - case Expr::PackExpansionExprClass: - case Expr::SubstNonTypeTemplateParmPackExprClass: - case Expr::FunctionParmPackExprClass: - case Expr::AsTypeExprClass: - case Expr::ObjCIndirectCopyRestoreExprClass: - case Expr::MaterializeTemporaryExprClass: - case Expr::PseudoObjectExprClass: - case Expr::AtomicExprClass: - case Expr::LambdaExprClass: - case Expr::CXXFoldExprClass: - case Expr::CoawaitExprClass: - case Expr::DependentCoawaitExprClass: - case Expr::CoyieldExprClass: - return ICEDiag(IK_NotICE, E->getBeginLoc()); - - case Expr::InitListExprClass: { - // C++03 [dcl.init]p13: If T is a scalar type, then a declaration of the - // form "T x = { a };" is equivalent to "T x = a;". - // Unless we're initializing a reference, T is a scalar as it is known to be - // of integral or enumeration type. - if (E->isRValue()) - if (cast<InitListExpr>(E)->getNumInits() == 1) - return CheckICE(cast<InitListExpr>(E)->getInit(0), Ctx); - return ICEDiag(IK_NotICE, E->getBeginLoc()); - } - - case Expr::SizeOfPackExprClass: - case Expr::GNUNullExprClass: - // GCC considers the GNU __null value to be an integral constant expression. - return NoDiag(); - - case Expr::SubstNonTypeTemplateParmExprClass: - return - CheckICE(cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement(), Ctx); - - case Expr::ConstantExprClass: - return CheckICE(cast<ConstantExpr>(E)->getSubExpr(), Ctx); - - case Expr::ParenExprClass: - return CheckICE(cast<ParenExpr>(E)->getSubExpr(), Ctx); - case Expr::GenericSelectionExprClass: - return CheckICE(cast<GenericSelectionExpr>(E)->getResultExpr(), Ctx); - case Expr::IntegerLiteralClass: - case Expr::FixedPointLiteralClass: - case Expr::CharacterLiteralClass: - case Expr::ObjCBoolLiteralExprClass: - case Expr::CXXBoolLiteralExprClass: - case Expr::CXXScalarValueInitExprClass: - case Expr::TypeTraitExprClass: - case Expr::ArrayTypeTraitExprClass: - case Expr::ExpressionTraitExprClass: - case Expr::CXXNoexceptExprClass: - return NoDiag(); - case Expr::CallExprClass: - case Expr::CXXOperatorCallExprClass: { - // C99 6.6/3 allows function calls within unevaluated subexpressions of - // constant expressions, but they can never be ICEs because an ICE cannot - // contain an operand of (pointer to) function type. - const CallExpr *CE = cast<CallExpr>(E); - if (CE->getBuiltinCallee()) - return CheckEvalInICE(E, Ctx); - return ICEDiag(IK_NotICE, E->getBeginLoc()); - } - case Expr::DeclRefExprClass: { - if (isa<EnumConstantDecl>(cast<DeclRefExpr>(E)->getDecl())) - return NoDiag(); - const ValueDecl *D = cast<DeclRefExpr>(E)->getDecl(); - if (Ctx.getLangOpts().CPlusPlus && - D && IsConstNonVolatile(D->getType())) { - // Parameter variables are never constants. Without this check, - // getAnyInitializer() can find a default argument, which leads - // to chaos. - if (isa<ParmVarDecl>(D)) - 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(IK_NotICE, cast<DeclRefExpr>(E)->getLocation()); - - const VarDecl *VD; - // Look for a declaration of this variable that has an initializer, and - // check whether it is an ICE. - if (Dcl->getAnyInitializer(VD) && VD->checkInitIsICE()) - return NoDiag(); - else - return ICEDiag(IK_NotICE, cast<DeclRefExpr>(E)->getLocation()); - } - } - return ICEDiag(IK_NotICE, E->getBeginLoc()); - } - case Expr::UnaryOperatorClass: { - const UnaryOperator *Exp = cast<UnaryOperator>(E); - switch (Exp->getOpcode()) { - case UO_PostInc: - case UO_PostDec: - case UO_PreInc: - case UO_PreDec: - case UO_AddrOf: - case UO_Deref: - case UO_Coawait: - // 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(IK_NotICE, E->getBeginLoc()); - case UO_Extension: - case UO_LNot: - case UO_Plus: - case UO_Minus: - case UO_Not: - case UO_Real: - case UO_Imag: - return CheckICE(Exp->getSubExpr(), Ctx); - } - llvm_unreachable("invalid unary operator class"); - } - 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); - } - case Expr::UnaryExprOrTypeTraitExprClass: { - const UnaryExprOrTypeTraitExpr *Exp = cast<UnaryExprOrTypeTraitExpr>(E); - if ((Exp->getKind() == UETT_SizeOf) && - Exp->getTypeOfArgument()->isVariableArrayType()) - return ICEDiag(IK_NotICE, E->getBeginLoc()); - return NoDiag(); - } - case Expr::BinaryOperatorClass: { - const BinaryOperator *Exp = cast<BinaryOperator>(E); - switch (Exp->getOpcode()) { - case BO_PtrMemD: - case BO_PtrMemI: - case BO_Assign: - case BO_MulAssign: - case BO_DivAssign: - case BO_RemAssign: - case BO_AddAssign: - case BO_SubAssign: - case BO_ShlAssign: - case BO_ShrAssign: - case BO_AndAssign: - case BO_XorAssign: - case BO_OrAssign: - // 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(IK_NotICE, E->getBeginLoc()); - - case BO_Mul: - case BO_Div: - case BO_Rem: - case BO_Add: - case BO_Sub: - case BO_Shl: - case BO_Shr: - case BO_LT: - case BO_GT: - case BO_LE: - case BO_GE: - case BO_EQ: - case BO_NE: - case BO_And: - case BO_Xor: - case BO_Or: - case BO_Comma: - case BO_Cmp: { - ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); - ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); - if (Exp->getOpcode() == BO_Div || - Exp->getOpcode() == BO_Rem) { - // EvaluateAsRValue gives an error for undefined Div/Rem, so make sure - // we don't evaluate one. - if (LHSResult.Kind == IK_ICE && RHSResult.Kind == IK_ICE) { - llvm::APSInt REval = Exp->getRHS()->EvaluateKnownConstInt(Ctx); - if (REval == 0) - return ICEDiag(IK_ICEIfUnevaluated, E->getBeginLoc()); - if (REval.isSigned() && REval.isAllOnesValue()) { - llvm::APSInt LEval = Exp->getLHS()->EvaluateKnownConstInt(Ctx); - if (LEval.isMinSignedValue()) - return ICEDiag(IK_ICEIfUnevaluated, E->getBeginLoc()); - } - } - } - if (Exp->getOpcode() == BO_Comma) { - 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.Kind == IK_ICE && RHSResult.Kind == IK_ICE) - return ICEDiag(IK_ICEIfUnevaluated, E->getBeginLoc()); - } else { - // In both C89 and C++, commas in ICEs are illegal. - return ICEDiag(IK_NotICE, E->getBeginLoc()); - } - } - return Worst(LHSResult, RHSResult); - } - case BO_LAnd: - case BO_LOr: { - ICEDiag LHSResult = CheckICE(Exp->getLHS(), Ctx); - ICEDiag RHSResult = CheckICE(Exp->getRHS(), Ctx); - 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. - if ((Exp->getOpcode() == BO_LAnd) != - (Exp->getLHS()->EvaluateKnownConstInt(Ctx) == 0)) - return RHSResult; - return NoDiag(); - } - - return Worst(LHSResult, RHSResult); - } - } - llvm_unreachable("invalid binary operator kind"); - } - case Expr::ImplicitCastExprClass: - case Expr::CStyleCastExprClass: - case Expr::CXXFunctionalCastExprClass: - case Expr::CXXStaticCastExprClass: - case Expr::CXXReinterpretCastExprClass: - case Expr::CXXConstCastExprClass: - case Expr::ObjCBridgedCastExprClass: { - const Expr *SubExpr = cast<CastExpr>(E)->getSubExpr(); - if (isa<ExplicitCastExpr>(E)) { - if (const FloatingLiteral *FL - = dyn_cast<FloatingLiteral>(SubExpr->IgnoreParenImpCasts())) { - unsigned DestWidth = Ctx.getIntWidth(E->getType()); - bool DestSigned = E->getType()->isSignedIntegerOrEnumerationType(); - APSInt IgnoredVal(DestWidth, !DestSigned); - bool Ignored; - // If the value does not fit in the destination type, the behavior is - // undefined, so we are not required to treat it as a constant - // expression. - if (FL->getValue().convertToInteger(IgnoredVal, - llvm::APFloat::rmTowardZero, - &Ignored) & APFloat::opInvalidOp) - return ICEDiag(IK_NotICE, E->getBeginLoc()); - return NoDiag(); - } - } - switch (cast<CastExpr>(E)->getCastKind()) { - case CK_LValueToRValue: - case CK_AtomicToNonAtomic: - case CK_NonAtomicToAtomic: - case CK_NoOp: - case CK_IntegralToBoolean: - case CK_IntegralCast: - return CheckICE(SubExpr, Ctx); - default: - return ICEDiag(IK_NotICE, E->getBeginLoc()); - } - } - case Expr::BinaryConditionalOperatorClass: { - const BinaryConditionalOperator *Exp = cast<BinaryConditionalOperator>(E); - ICEDiag CommonResult = CheckICE(Exp->getCommon(), Ctx); - if (CommonResult.Kind == IK_NotICE) return CommonResult; - ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx); - 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; - } - 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->getBuiltinCallee() == Builtin::BI__builtin_constant_p) - return CheckEvalInICE(E, Ctx); - ICEDiag CondResult = CheckICE(Exp->getCond(), Ctx); - if (CondResult.Kind == IK_NotICE) - return CondResult; - - ICEDiag TrueResult = CheckICE(Exp->getTrueExpr(), Ctx); - ICEDiag FalseResult = CheckICE(Exp->getFalseExpr(), Ctx); - - if (TrueResult.Kind == IK_NotICE) - return TrueResult; - if (FalseResult.Kind == IK_NotICE) - return FalseResult; - if (CondResult.Kind == IK_ICEIfUnevaluated) - return CondResult; - 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) - return FalseResult; - return TrueResult; - } - case Expr::CXXDefaultArgExprClass: - return CheckICE(cast<CXXDefaultArgExpr>(E)->getExpr(), Ctx); - case Expr::CXXDefaultInitExprClass: - return CheckICE(cast<CXXDefaultInitExpr>(E)->getExpr(), Ctx); - case Expr::ChooseExprClass: { - return CheckICE(cast<ChooseExpr>(E)->getChosenSubExpr(), Ctx); - } - } - - llvm_unreachable("Invalid StmtClass!"); + Expr::EvalStatus Status; + SmallVector<PartialDiagnosticAt, 8> Diags; + Status.Diag = &Diags; + EvalInfo Info(Ctx, Status, EvalInfo::EM_ConstantExpression); + return ICEChecker(Ctx, Info).Visit(E); } /// Evaluate an expression as a C++11 integral constant expression.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits