[cfe-commits] r103237 - in /cfe/trunk/lib/AST: Expr.cpp ExprConstant.cpp

John McCall rjmccall at apple.com
Thu May 6 22:32:02 PDT 2010


Author: rjmccall
Date: Fri May  7 00:32:02 2010
New Revision: 103237

URL: http://llvm.org/viewvc/llvm-project?rev=103237&view=rev
Log:
Move CheckICE and isIntegerConstantExpr to ExprConstant.cpp because it seemed
like a good idea at the time.


Modified:
    cfe/trunk/lib/AST/Expr.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp

Modified: cfe/trunk/lib/AST/Expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Expr.cpp?rev=103237&r1=103236&r2=103237&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Expr.cpp (original)
+++ cfe/trunk/lib/AST/Expr.cpp Fri May  7 00:32:02 2010
@@ -1769,385 +1769,6 @@
   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*.

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=103237&r1=103236&r2=103237&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Fri May  7 00:32:02 2010
@@ -2159,3 +2159,382 @@
 
   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;
+}





More information about the cfe-commits mailing list