[cfe-commits] r143204 - in /cfe/trunk: include/clang/AST/ASTContext.h include/clang/AST/Expr.h lib/AST/ExprConstant.cpp test/CodeGenCXX/static-data-member.cpp test/SemaCXX/constant-expression-cxx11.cpp

Richard Smith richard-llvm at metafoo.co.uk
Fri Oct 28 10:51:58 PDT 2011


Author: rsmith
Date: Fri Oct 28 12:51:58 2011
New Revision: 143204

URL: http://llvm.org/viewvc/llvm-project?rev=143204&view=rev
Log:
Reinstate r142844 (reverted in r142872) now that lvalue-to-rvalue conversions
are present in all the necessary places:

In constant expression evaluation, evaluate lvalues as lvalues and rvalues as
rvalues. Remove special case for caching reference initialization and fix a
cyclic initialization crash in the process.

Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/Expr.h
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/test/CodeGenCXX/static-data-member.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=143204&r1=143203&r2=143204&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Fri Oct 28 12:51:58 2011
@@ -1274,7 +1274,7 @@
   CanQualType getCanonicalParamType(QualType T) const;
 
   /// \brief Determine whether the given types are equivalent.
-  bool hasSameType(QualType T1, QualType T2) {
+  bool hasSameType(QualType T1, QualType T2) const {
     return getCanonicalType(T1) == getCanonicalType(T2);
   }
 
@@ -1294,7 +1294,7 @@
 
   /// \brief Determine whether the given types are equivalent after
   /// cvr-qualifiers have been removed.
-  bool hasSameUnqualifiedType(QualType T1, QualType T2) {
+  bool hasSameUnqualifiedType(QualType T1, QualType T2) const {
     return getCanonicalType(T1).getTypePtr() ==
            getCanonicalType(T2).getTypePtr();
   }

Modified: cfe/trunk/include/clang/AST/Expr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Expr.h?rev=143204&r1=143203&r2=143204&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Expr.h (original)
+++ cfe/trunk/include/clang/AST/Expr.h Fri Oct 28 12:51:58 2011
@@ -465,7 +465,8 @@
   /// Evaluate - Return true if this is a constant which we can fold using
   /// any crazy technique (that has nothing to do with language standards) that
   /// we want to.  If this function returns true, it returns the folded constant
-  /// in Result.
+  /// in Result. If this expression is a glvalue, an lvalue-to-rvalue conversion
+  /// will be applied.
   bool Evaluate(EvalResult &Result, const ASTContext &Ctx) const;
 
   /// EvaluateAsBooleanCondition - Return true if this is a constant

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=143204&r1=143203&r2=143204&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Oct 28 12:51:58 2011
@@ -148,10 +148,13 @@
   if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(E))
     return CLE->isFileScope();
 
+  if (isa<MemberExpr>(E))
+    return false;
+
   return true;
 }
 
-static bool EvalPointerValueAsBool(LValue& Value, bool& Result) {
+static bool EvalPointerValueAsBool(const LValue &Value, bool &Result) {
   const Expr* Base = Value.Base;
 
   // A null base expression indicates a null pointer.  These are always
@@ -183,40 +186,44 @@
   return true;
 }
 
-static bool HandleConversionToBool(const Expr* E, bool& Result,
-                                   EvalInfo &Info) {
-  if (E->getType()->isIntegralOrEnumerationType()) {
-    APSInt IntResult;
-    if (!EvaluateInteger(E, IntResult, Info))
-      return false;
-    Result = IntResult != 0;
+static bool HandleConversionToBool(const APValue &Val, bool &Result) {
+  switch (Val.getKind()) {
+  case APValue::Uninitialized:
+    return false;
+  case APValue::Int:
+    Result = Val.getInt().getBoolValue();
     return true;
-  } else if (E->getType()->isRealFloatingType()) {
-    APFloat FloatResult(0.0);
-    if (!EvaluateFloat(E, FloatResult, Info))
-      return false;
-    Result = !FloatResult.isZero();
+  case APValue::Float:
+    Result = !Val.getFloat().isZero();
     return true;
-  } else if (E->getType()->hasPointerRepresentation()) {
-    LValue PointerResult;
-    if (!EvaluatePointer(E, PointerResult, Info))
-      return false;
-    return EvalPointerValueAsBool(PointerResult, Result);
-  } else if (E->getType()->isAnyComplexType()) {
-    ComplexValue ComplexResult;
-    if (!EvaluateComplex(E, ComplexResult, Info))
-      return false;
-    if (ComplexResult.isComplexFloat()) {
-      Result = !ComplexResult.getComplexFloatReal().isZero() ||
-               !ComplexResult.getComplexFloatImag().isZero();
-    } else {
-      Result = ComplexResult.getComplexIntReal().getBoolValue() ||
-               ComplexResult.getComplexIntImag().getBoolValue();
-    }
+  case APValue::ComplexInt:
+    Result = Val.getComplexIntReal().getBoolValue() ||
+             Val.getComplexIntImag().getBoolValue();
+    return true;
+  case APValue::ComplexFloat:
+    Result = !Val.getComplexFloatReal().isZero() ||
+             !Val.getComplexFloatImag().isZero();
     return true;
+  case APValue::LValue:
+    {
+      LValue PointerResult;
+      PointerResult.setFrom(Val);
+      return EvalPointerValueAsBool(PointerResult, Result);
+    }
+  case APValue::Vector:
+    return false;
   }
 
-  return false;
+  llvm_unreachable("unknown APValue kind");
+}
+
+static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result,
+                                       EvalInfo &Info) {
+  assert(E->isRValue() && "missing lvalue-to-rvalue conv in bool condition");
+  APValue Val;
+  if (!Evaluate(Val, Info, E))
+    return false;
+  return HandleConversionToBool(Val, Result);
 }
 
 static APSInt HandleFloatToIntCast(QualType DestType, QualType SrcType,
@@ -263,6 +270,8 @@
 
 /// Try to evaluate the initializer for a variable declaration.
 static APValue *EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD) {
+  // FIXME: If this is a parameter to an active constexpr function call, perform
+  // substitution now.
   if (isa<ParmVarDecl>(VD))
     return 0;
 
@@ -278,10 +287,11 @@
 
   VD->setEvaluatingValue();
 
-  // FIXME: If the initializer isn't a constant expression, propagate up any
-  // diagnostic explaining why not.
   Expr::EvalResult EResult;
-  if (Init->Evaluate(EResult, Info.Ctx) && !EResult.HasSideEffects)
+  EvalInfo InitInfo(Info.Ctx, EResult);
+  // FIXME: The caller will need to know whether the value was a constant
+  // expression. If not, we should propagate up a diagnostic.
+  if (Evaluate(EResult.Val, InitInfo, Init))
     VD->setEvaluatedValue(EResult.Val);
   else
     VD->setEvaluatedValue(APValue());
@@ -289,11 +299,92 @@
   return VD->getEvaluatedValue();
 }
 
-bool IsConstNonVolatile(QualType T) {
+static bool IsConstNonVolatile(QualType T) {
   Qualifiers Quals = T.getQualifiers();
   return Quals.hasConst() && !Quals.hasVolatile();
 }
 
+bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type,
+                                    const LValue &LVal, APValue &RVal) {
+  const Expr *Base = LVal.Base;
+
+  // FIXME: Indirection through a null pointer deserves a diagnostic.
+  if (!Base)
+    return false;
+
+  // FIXME: Support accessing subobjects of objects of literal types. A simple
+  // byte offset is insufficient for C++11 semantics: we need to know how the
+  // reference was formed (which union member was named, for instance).
+  // FIXME: Support subobjects of StringLiteral and PredefinedExpr.
+  if (!LVal.Offset.isZero())
+    return false;
+
+  const Decl *D = 0;
+
+  if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Base)) {
+    // If the lvalue has been cast to some other type, don't try to read it.
+    // FIXME: Could simulate a bitcast here.
+    if (!Info.Ctx.hasSameUnqualifiedType(Type, DRE->getType()))
+      return false;
+    D = DRE->getDecl();
+  }
+
+  // FIXME: Static data members accessed via a MemberExpr are represented as
+  // that MemberExpr. We should use the Decl directly instead.
+  if (const MemberExpr *ME = dyn_cast<MemberExpr>(Base)) {
+    if (!Info.Ctx.hasSameUnqualifiedType(Type, ME->getType()))
+      return false;
+    D = ME->getMemberDecl();
+    assert(!isa<FieldDecl>(D) && "shouldn't see fields here");
+  }
+
+  if (D) {
+    // In C++98, const, non-volatile integers initialized with ICEs are ICEs.
+    // In C++11, constexpr, non-volatile variables initialized with constant
+    // expressions are constant expressions too.
+    // In C, such things can also be folded, although they are not ICEs.
+    //
+    // FIXME: Allow folding any const variable of literal type initialized with
+    // a constant expression. For now, we only allow variables with integral and
+    // floating types to be folded.
+    const VarDecl *VD = dyn_cast<VarDecl>(D);
+    if (!VD || !IsConstNonVolatile(VD->getType()) ||
+        (!Type->isIntegralOrEnumerationType() && !Type->isRealFloatingType()))
+      return false;
+
+    APValue *V = EvaluateVarDeclInit(Info, VD);
+    if (!V || V->isUninit())
+      return false;
+
+    if (!VD->getAnyInitializer()->isLValue()) {
+      RVal = *V;
+      return true;
+    }
+
+    // The declaration was initialized by an lvalue, with no lvalue-to-rvalue
+    // conversion. This happens when the declaration and the lvalue should be
+    // considered synonymous, for instance when initializing an array of char
+    // from a string literal. Continue as if the initializer lvalue was the
+    // value we were originally given.
+    Base = V->getLValueBase();
+    if (!V->getLValueOffset().isZero())
+      return false;
+  }
+
+  // FIXME: C++11: Support MaterializeTemporaryExpr in LValueExprEvaluator and
+  // here.
+
+  // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the
+  // initializer until now for such expressions. Such an expression can't be
+  // an ICE in C, so this only matters for fold.
+  if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(Base)) {
+    assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?");
+    return Evaluate(RVal, Info, CLE->getInitializer());
+  }
+
+  return false;
+}
+
 namespace {
 class HasSideEffect
   : public ConstStmtVisitor<HasSideEffect, bool> {
@@ -454,7 +545,7 @@
       return DerivedError(E);
 
     bool cond;
-    if (!HandleConversionToBool(E->getCond(), cond, Info))
+    if (!EvaluateAsBooleanCondition(E->getCond(), cond, Info))
       return DerivedError(E);
 
     return StmtVisitorTy::Visit(cond ? E->getTrueExpr() : E->getFalseExpr());
@@ -462,10 +553,10 @@
 
   RetTy VisitConditionalOperator(const ConditionalOperator *E) {
     bool BoolResult;
-    if (!HandleConversionToBool(E->getCond(), BoolResult, Info))
+    if (!EvaluateAsBooleanCondition(E->getCond(), BoolResult, Info))
       return DerivedError(E);
 
-    Expr* EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
+    Expr *EvalExpr = BoolResult ? E->getTrueExpr() : E->getFalseExpr();
     return StmtVisitorTy::Visit(EvalExpr);
   }
 
@@ -477,6 +568,9 @@
     return DerivedSuccess(*value, E);
   }
 
+  RetTy VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
+    return StmtVisitorTy::Visit(E->getInitializer());
+  }
   RetTy VisitInitListExpr(const InitListExpr *E) {
     if (Info.getLangOpts().CPlusPlus0x) {
       if (E->getNumInits() == 0)
@@ -493,6 +587,28 @@
     return DerivedValueInitialization(E);
   }
 
+  RetTy VisitCastExpr(const CastExpr *E) {
+    switch (E->getCastKind()) {
+    default:
+      break;
+
+    case CK_NoOp:
+      return StmtVisitorTy::Visit(E->getSubExpr());
+
+    case CK_LValueToRValue: {
+      LValue LVal;
+      if (EvaluateLValue(E->getSubExpr(), LVal, Info)) {
+        APValue RVal;
+        if (HandleLValueToRValueConversion(Info, E->getType(), LVal, RVal))
+          return DerivedSuccess(RVal, E);
+      }
+      break;
+    }
+    }
+
+    return DerivedError(E);
+  }
+
   /// Visit a value which is evaluated, but whose value is ignored.
   void VisitIgnoredValue(const Expr *E) {
     APValue Scratch;
@@ -505,6 +621,23 @@
 
 //===----------------------------------------------------------------------===//
 // LValue Evaluation
+//
+// This is used for evaluating lvalues (in C and C++), xvalues (in C++11),
+// function designators (in C), decl references to void objects (in C), and
+// temporaries (if building with -Wno-address-of-temporary).
+//
+// LValue evaluation produces values comprising a base expression of one of the
+// following types:
+//  * DeclRefExpr
+//  * MemberExpr for a static member
+//  * CompoundLiteralExpr in C
+//  * StringLiteral
+//  * PredefinedExpr
+//  * ObjCEncodeExpr
+//  * AddrLabelExpr
+//  * BlockExpr
+//  * CallExpr for a MakeStringConstant builtin
+// plus an offset in bytes.
 //===----------------------------------------------------------------------===//
 namespace {
 class LValueExprEvaluator
@@ -530,6 +663,8 @@
     return false;
   }
   
+  bool VisitVarDecl(const Expr *E, const VarDecl *VD);
+
   bool VisitDeclRefExpr(const DeclRefExpr *E);
   bool VisitPredefinedExpr(const PredefinedExpr *E) { return Success(E); }
   bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
@@ -542,13 +677,13 @@
   bool VisitCastExpr(const CastExpr *E) {
     switch (E->getCastKind()) {
     default:
-      return false;
+      return ExprEvaluatorBaseTy::VisitCastExpr(E);
 
-    case CK_NoOp:
     case CK_LValueBitCast:
       return Visit(E->getSubExpr());
 
-    // FIXME: Support CK_DerivedToBase and friends.
+    // FIXME: Support CK_DerivedToBase and CK_UncheckedDerivedToBase.
+    // Reuse PointerExprEvaluator::VisitCastExpr for these.
     }
   }
 
@@ -557,39 +692,52 @@
 };
 } // end anonymous namespace
 
+/// Evaluate an expression as an lvalue. This can be legitimately called on
+/// expressions which are not glvalues, in a few cases:
+///  * function designators in C,
+///  * "extern void" objects,
+///  * temporaries, if building with -Wno-address-of-temporary.
 static bool EvaluateLValue(const Expr* E, LValue& Result, EvalInfo &Info) {
+  assert((E->isGLValue() || E->getType()->isFunctionType() ||
+          E->getType()->isVoidType() || isa<CXXTemporaryObjectExpr>(E)) &&
+         "can't evaluate expression as an lvalue");
   return LValueExprEvaluator(Info, Result).Visit(E);
 }
 
 bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
-  if (isa<FunctionDecl>(E->getDecl())) {
+  if (isa<FunctionDecl>(E->getDecl()))
     return Success(E);
-  } else if (const VarDecl* VD = dyn_cast<VarDecl>(E->getDecl())) {
-    if (!VD->getType()->isReferenceType())
-      return Success(E);
-    // Reference parameters can refer to anything even if they have an
-    // "initializer" in the form of a default argument.
-    if (!isa<ParmVarDecl>(VD)) {
-      // FIXME: Check whether VD might be overridden!
+  if (const VarDecl* VD = dyn_cast<VarDecl>(E->getDecl()))
+    return VisitVarDecl(E, VD);
+  return Error(E);
+}
 
-      // Check for recursive initializers of references.
-      if (PrevDecl == VD)
-        return Error(E);
-      PrevDecl = VD;
-      if (const Expr *Init = VD->getAnyInitializer())
-        return Visit(Init);
-    }
-  }
+bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
+  if (!VD->getType()->isReferenceType())
+    return Success(E);
+
+  APValue *V = EvaluateVarDeclInit(Info, VD);
+  if (V && !V->isUninit())
+    return Success(*V, E);
 
-  return ExprEvaluatorBaseTy::VisitDeclRefExpr(E);
+  return Error(E);
 }
 
 bool
 LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
+  assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?");
+  // Defer visiting the literal until the lvalue-to-rvalue conversion. We can
+  // only see this when folding in C, so there's no standard to follow here.
   return Success(E);
 }
 
 bool LValueExprEvaluator::VisitMemberExpr(const MemberExpr *E) {
+  // Handle static data members.
+  if (const VarDecl *VD = dyn_cast<VarDecl>(E->getMemberDecl())) {
+    VisitIgnoredValue(E->getBase());
+    return VisitVarDecl(E, VD);
+  }
+
   QualType Ty;
   if (E->isArrow()) {
     if (!EvaluatePointer(E->getBase(), Result, Info))
@@ -617,6 +765,10 @@
 }
 
 bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
+  // FIXME: Deal with vectors as array subscript bases.
+  if (E->getBase()->getType()->isVectorType())
+    return false;
+
   if (!EvaluatePointer(E->getBase(), Result, Info))
     return false;
 
@@ -684,7 +836,7 @@
 } // end anonymous namespace
 
 static bool EvaluatePointer(const Expr* E, LValue& Result, EvalInfo &Info) {
-  assert(E->getType()->hasPointerRepresentation());
+  assert(E->isRValue() && E->getType()->hasPointerRepresentation());
   return PointerExprEvaluator(Info, Result).Visit(E);
 }
 
@@ -740,7 +892,6 @@
   default:
     break;
 
-  case CK_NoOp:
   case CK_BitCast:
   case CK_CPointerToObjCPointerCast:
   case CK_BlockPointerToObjCPointerCast:
@@ -810,7 +961,7 @@
     return EvaluateLValue(SubExpr, Result, Info);
   }
 
-  return false;
+  return ExprEvaluatorBaseTy::VisitCastExpr(E);
 }
 
 bool PointerExprEvaluator::VisitCallExpr(const CallExpr *E) {
@@ -852,7 +1003,6 @@
     bool VisitUnaryReal(const UnaryOperator *E)
       { return Visit(E->getSubExpr()); }
     bool VisitCastExpr(const CastExpr* E);
-    bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
     bool VisitInitListExpr(const InitListExpr *E);
     bool VisitUnaryImag(const UnaryOperator *E);
     // FIXME: Missing: unary -, unary ~, binary add/sub/mul/div,
@@ -864,8 +1014,7 @@
 } // end anonymous namespace
 
 static bool EvaluateVector(const Expr* E, APValue& Result, EvalInfo &Info) {
-  if (!E->getType()->isVectorType())
-    return false;
+  assert(E->isRValue() && E->getType()->isVectorType() &&"not a vector rvalue");
   return VectorExprEvaluator(Info, Result).Visit(E);
 }
 
@@ -927,20 +1076,12 @@
     }
     return Success(Elts, E);
   }
-  case CK_LValueToRValue:
-  case CK_NoOp:
-    return Visit(SE);
   default:
-    return Error(E);
+    return ExprEvaluatorBaseTy::VisitCastExpr(E);
   }
 }
 
 bool
-VectorExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
-  return Visit(E->getInitializer());
-}
-
-bool
 VectorExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
   const VectorType *VT = E->getType()->castAs<VectorType>();
   unsigned NumInits = E->getNumInits();
@@ -1022,6 +1163,10 @@
 
 //===----------------------------------------------------------------------===//
 // Integer Evaluation
+//
+// As a GNU extension, we support casting pointers to sufficiently-wide integer
+// types and back in constant folding. Integer values are thus represented
+// either as an integer-valued APValue, or as an lvalue-valued APValue.
 //===----------------------------------------------------------------------===//
 
 namespace {
@@ -1105,8 +1250,7 @@
   }
   bool VisitMemberExpr(const MemberExpr *E) {
     if (CheckReferencedDecl(E, E->getMemberDecl())) {
-      // Conservatively assume a MemberExpr will have side-effects
-      Info.EvalStatus.HasSideEffects = true;
+      VisitIgnoredValue(E->getBase());
       return true;
     }
 
@@ -1161,14 +1305,20 @@
 };
 } // end anonymous namespace
 
+/// EvaluateIntegerOrLValue - Evaluate an rvalue integral-typed expression, and
+/// produce either the integer value or a pointer.
+///
+/// GCC has a heinous extension which folds casts between pointer types and
+/// pointer-sized integral types. We support this by allowing the evaluation of
+/// an integer rvalue to produce a pointer (represented as an lvalue) instead.
+/// Some simple arithmetic on such values is supported (they are treated much
+/// like char*).
 static bool EvaluateIntegerOrLValue(const Expr* E, APValue &Result, EvalInfo &Info) {
-  assert(E->getType()->isIntegralOrEnumerationType());
+  assert(E->isRValue() && E->getType()->isIntegralOrEnumerationType());
   return IntExprEvaluator(Info, Result).Visit(E);
 }
 
 static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) {
-  assert(E->getType()->isIntegralOrEnumerationType());
-
   APValue Val;
   if (!EvaluateIntegerOrLValue(E, Val, Info) || !Val.isInt())
     return false;
@@ -1197,18 +1347,6 @@
       return Success(Val, E);
     }
   }
-
-  // In C++, const, non-volatile integers initialized with ICEs are ICEs.
-  // In C, they can also be folded, although they are not ICEs.
-  if (IsConstNonVolatile(E->getType())) {
-    if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
-      APValue *V = EvaluateVarDeclInit(Info, VD);
-      if (V && V->isInt())
-        return Success(V->getInt(), E);
-    }
-  }
-
-  // Otherwise, random variable references are not constants.
   return false;
 }
 
@@ -1411,6 +1549,9 @@
 }
 
 bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
+  if (E->isAssignmentOp())
+    return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E);
+
   if (E->getOpcode() == BO_Comma) {
     VisitIgnoredValue(E->getLHS());
     return Visit(E->getRHS());
@@ -1421,20 +1562,20 @@
     // necessarily integral
     bool lhsResult, rhsResult;
 
-    if (HandleConversionToBool(E->getLHS(), lhsResult, Info)) {
+    if (EvaluateAsBooleanCondition(E->getLHS(), lhsResult, Info)) {
       // We were able to evaluate the LHS, see if we can get away with not
       // evaluating the RHS: 0 && X -> 0, 1 || X -> 1
       if (lhsResult == (E->getOpcode() == BO_LOr))
         return Success(lhsResult, E);
 
-      if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) {
+      if (EvaluateAsBooleanCondition(E->getRHS(), rhsResult, Info)) {
         if (E->getOpcode() == BO_LOr)
           return Success(lhsResult || rhsResult, E);
         else
           return Success(lhsResult && rhsResult, E);
       }
     } else {
-      if (HandleConversionToBool(E->getRHS(), rhsResult, Info)) {
+      if (EvaluateAsBooleanCondition(E->getRHS(), rhsResult, Info)) {
         // We can't evaluate the LHS; however, sometimes the result
         // is determined by the RHS: X && 0 -> 0, X || 1 -> 1.
         if (rhsResult == (E->getOpcode() == BO_LOr) ||
@@ -1590,58 +1731,60 @@
   }
 
   // The LHS of a constant expr is always evaluated and needed.
-  if (!Visit(E->getLHS()))
+  APValue LHSVal;
+  if (!EvaluateIntegerOrLValue(E->getLHS(), LHSVal, Info))
     return false; // error in subexpression.
 
-  APValue RHSVal;
-  if (!EvaluateIntegerOrLValue(E->getRHS(), RHSVal, Info))
+  if (!Visit(E->getRHS()))
     return false;
+  APValue &RHSVal = Result;
 
   // Handle cases like (unsigned long)&a + 4.
-  if (E->isAdditiveOp() && Result.isLValue() && RHSVal.isInt()) {
-    CharUnits Offset = Result.getLValueOffset();
+  if (E->isAdditiveOp() && LHSVal.isLValue() && RHSVal.isInt()) {
+    CharUnits Offset = LHSVal.getLValueOffset();
     CharUnits AdditionalOffset = CharUnits::fromQuantity(
                                      RHSVal.getInt().getZExtValue());
     if (E->getOpcode() == BO_Add)
       Offset += AdditionalOffset;
     else
       Offset -= AdditionalOffset;
-    Result = APValue(Result.getLValueBase(), Offset);
+    Result = APValue(LHSVal.getLValueBase(), Offset);
     return true;
   }
 
   // Handle cases like 4 + (unsigned long)&a
   if (E->getOpcode() == BO_Add &&
-        RHSVal.isLValue() && Result.isInt()) {
+        RHSVal.isLValue() && LHSVal.isInt()) {
     CharUnits Offset = RHSVal.getLValueOffset();
-    Offset += CharUnits::fromQuantity(Result.getInt().getZExtValue());
+    Offset += CharUnits::fromQuantity(LHSVal.getInt().getZExtValue());
     Result = APValue(RHSVal.getLValueBase(), Offset);
     return true;
   }
 
   // All the following cases expect both operands to be an integer
-  if (!Result.isInt() || !RHSVal.isInt())
+  if (!LHSVal.isInt() || !RHSVal.isInt())
     return false;
 
-  APSInt& RHS = RHSVal.getInt();
+  APSInt &LHS = LHSVal.getInt();
+  APSInt &RHS = RHSVal.getInt();
 
   switch (E->getOpcode()) {
   default:
     return Error(E->getOperatorLoc(), diag::note_invalid_subexpr_in_ice, E);
-  case BO_Mul: return Success(Result.getInt() * RHS, E);
-  case BO_Add: return Success(Result.getInt() + RHS, E);
-  case BO_Sub: return Success(Result.getInt() - RHS, E);
-  case BO_And: return Success(Result.getInt() & RHS, E);
-  case BO_Xor: return Success(Result.getInt() ^ RHS, E);
-  case BO_Or:  return Success(Result.getInt() | RHS, E);
+  case BO_Mul: return Success(LHS * RHS, E);
+  case BO_Add: return Success(LHS + RHS, E);
+  case BO_Sub: return Success(LHS - RHS, E);
+  case BO_And: return Success(LHS & RHS, E);
+  case BO_Xor: return Success(LHS ^ RHS, E);
+  case BO_Or:  return Success(LHS | RHS, E);
   case BO_Div:
     if (RHS == 0)
       return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E);
-    return Success(Result.getInt() / RHS, E);
+    return Success(LHS / RHS, E);
   case BO_Rem:
     if (RHS == 0)
       return Error(E->getOperatorLoc(), diag::note_expr_divide_by_zero, E);
-    return Success(Result.getInt() % RHS, E);
+    return Success(LHS % RHS, E);
   case BO_Shl: {
     // During constant-folding, a negative shift is an opposite shift.
     if (RHS.isSigned() && RHS.isNegative()) {
@@ -1651,8 +1794,8 @@
 
   shift_left:
     unsigned SA
-      = (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1);
-    return Success(Result.getInt() << SA, E);
+      = (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+    return Success(LHS << SA, E);
   }
   case BO_Shr: {
     // During constant-folding, a negative shift is an opposite shift.
@@ -1663,16 +1806,16 @@
 
   shift_right:
     unsigned SA =
-      (unsigned) RHS.getLimitedValue(Result.getInt().getBitWidth()-1);
-    return Success(Result.getInt() >> SA, E);
+      (unsigned) RHS.getLimitedValue(LHS.getBitWidth()-1);
+    return Success(LHS >> SA, E);
   }
 
-  case BO_LT: return Success(Result.getInt() < RHS, E);
-  case BO_GT: return Success(Result.getInt() > RHS, E);
-  case BO_LE: return Success(Result.getInt() <= RHS, E);
-  case BO_GE: return Success(Result.getInt() >= RHS, E);
-  case BO_EQ: return Success(Result.getInt() == RHS, E);
-  case BO_NE: return Success(Result.getInt() != RHS, E);
+  case BO_LT: return Success(LHS < RHS, E);
+  case BO_GT: return Success(LHS > RHS, E);
+  case BO_LE: return Success(LHS <= RHS, E);
+  case BO_GE: return Success(LHS >= RHS, E);
+  case BO_EQ: return Success(LHS == RHS, E);
+  case BO_NE: return Success(LHS != RHS, E);
   }
 }
 
@@ -1833,7 +1976,7 @@
   if (E->getOpcode() == UO_LNot) {
     // LNot's operand isn't necessarily an integer, so we handle it specially.
     bool bres;
-    if (!HandleConversionToBool(E->getSubExpr(), bres, Info))
+    if (!EvaluateAsBooleanCondition(E->getSubExpr(), bres, Info))
       return false;
     return Success(!bres, E);
   }
@@ -1842,8 +1985,9 @@
   if (!E->getSubExpr()->getType()->isIntegralOrEnumerationType())
     return false;
 
-  // Get the operand value into 'Result'.
-  if (!Visit(E->getSubExpr()))
+  // Get the operand value.
+  APValue Val;
+  if (!Evaluate(Val, Info, E->getSubExpr()))
     return false;
 
   switch (E->getOpcode()) {
@@ -1854,16 +1998,16 @@
   case UO_Extension:
     // FIXME: Should extension allow i-c-e extension expressions in its scope?
     // If so, we could clear the diagnostic ID.
-    return true;
+    return Success(Val, E);
   case UO_Plus:
-    // The result is always just the subexpr.
-    return true;
+    // The result is just the value.
+    return Success(Val, E);
   case UO_Minus:
-    if (!Result.isInt()) return false;
-    return Success(-Result.getInt(), E);
+    if (!Val.isInt()) return false;
+    return Success(-Val.getInt(), E);
   case UO_Not:
-    if (!Result.isInt()) return false;
-    return Success(~Result.getInt(), E);
+    if (!Val.isInt()) return false;
+    return Success(~Val.getInt(), E);
   }
 }
 
@@ -1918,7 +2062,7 @@
 
   case CK_LValueToRValue:
   case CK_NoOp:
-    return Visit(E->getSubExpr());
+    return ExprEvaluatorBaseTy::VisitCastExpr(E);
 
   case CK_MemberPointerToBoolean:
   case CK_PointerToBoolean:
@@ -1927,7 +2071,7 @@
   case CK_FloatingComplexToBoolean:
   case CK_IntegralComplexToBoolean: {
     bool BoolResult;
-    if (!HandleConversionToBool(SubExpr, BoolResult, Info))
+    if (!EvaluateAsBooleanCondition(SubExpr, BoolResult, Info))
       return false;
     return Success(BoolResult, E);
   }
@@ -2050,15 +2194,13 @@
   bool VisitUnaryReal(const UnaryOperator *E);
   bool VisitUnaryImag(const UnaryOperator *E);
 
-  bool VisitDeclRefExpr(const DeclRefExpr *E);
-
   // FIXME: Missing: array subscript of vector, member of vector,
   //                 ImplicitValueInitExpr
 };
 } // end anonymous namespace
 
 static bool EvaluateFloat(const Expr* E, APFloat& Result, EvalInfo &Info) {
-  assert(E->getType()->isRealFloatingType());
+  assert(E->isRValue() && E->getType()->isRealFloatingType());
   return FloatExprEvaluator(Info, Result).Visit(E);
 }
 
@@ -2141,21 +2283,6 @@
   }
 }
 
-bool FloatExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
-  if (ExprEvaluatorBaseTy::VisitDeclRefExpr(E))
-    return true;
-
-  const VarDecl *VD = dyn_cast<VarDecl>(E->getDecl());
-  if (VD && IsConstNonVolatile(VD->getType())) {
-    APValue *V = EvaluateVarDeclInit(Info, VD);
-    if (V && V->isFloat()) {
-      Result = V->getFloat();
-      return true;
-    }
-  }
-  return false;
-}
-
 bool FloatExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
   if (E->getSubExpr()->getType()->isAnyComplexType()) {
     ComplexValue CV;
@@ -2245,11 +2372,7 @@
 
   switch (E->getCastKind()) {
   default:
-    return false;
-
-  case CK_LValueToRValue:
-  case CK_NoOp:
-    return Visit(SubExpr);
+    return ExprEvaluatorBaseTy::VisitCastExpr(E);
 
   case CK_IntegralToFloating: {
     APSInt IntResult;
@@ -2317,7 +2440,7 @@
 
 static bool EvaluateComplex(const Expr *E, ComplexValue &Result,
                             EvalInfo &Info) {
-  assert(E->getType()->isAnyComplexType());
+  assert(E->isRValue() && E->getType()->isAnyComplexType());
   return ComplexExprEvaluator(Info, Result).Visit(E);
 }
 
@@ -2390,7 +2513,7 @@
 
   case CK_LValueToRValue:
   case CK_NoOp:
-    return Visit(E->getSubExpr());
+    return ExprEvaluatorBaseTy::VisitCastExpr(E);
 
   case CK_Dependent:
   case CK_GetObjCProperty:
@@ -2634,27 +2757,28 @@
 //===----------------------------------------------------------------------===//
 
 static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
-  if (E->getType()->isVectorType()) {
+  // In C, function designators are not lvalues, but we evaluate them as if they
+  // are.
+  if (E->isGLValue() || E->getType()->isFunctionType()) {
+    LValue LV;
+    if (!EvaluateLValue(E, LV, Info))
+      return false;
+    LV.moveInto(Result);
+  } else if (E->getType()->isVectorType()) {
     if (!EvaluateVector(E, Result, Info))
       return false;
   } else if (E->getType()->isIntegralOrEnumerationType()) {
     if (!IntExprEvaluator(Info, Result).Visit(E))
       return false;
-    if (Result.isLValue() &&
-        !IsGlobalLValue(Result.getLValueBase()))
-      return false;
   } else if (E->getType()->hasPointerRepresentation()) {
     LValue LV;
     if (!EvaluatePointer(E, LV, Info))
       return false;
-    if (!IsGlobalLValue(LV.Base))
-      return false;
     LV.moveInto(Result);
   } else if (E->getType()->isRealFloatingType()) {
     llvm::APFloat F(0.0);
     if (!EvaluateFloat(E, F, Info))
       return false;
-
     Result = APValue(F);
   } else if (E->getType()->isAnyComplexType()) {
     ComplexValue C;
@@ -2667,36 +2791,50 @@
   return true;
 }
 
+
 /// Evaluate - Return true if this is a constant which we can fold using
 /// any crazy technique (that has nothing to do with language standards) that
 /// we want to.  If this function returns true, it returns the folded constant
-/// in Result.
+/// in Result. If this expression is a glvalue, an lvalue-to-rvalue conversion
+/// will be applied to the result.
 bool Expr::Evaluate(EvalResult &Result, const ASTContext &Ctx) const {
   EvalInfo Info(Ctx, Result);
-  return ::Evaluate(Result.Val, Info, this);
+
+  if (!::Evaluate(Result.Val, Info, this))
+    return false;
+
+  if (isGLValue()) {
+    LValue LV;
+    LV.setFrom(Result.Val);
+    return HandleLValueToRValueConversion(Info, getType(), LV, Result.Val);
+  }
+
+  // FIXME: We don't allow expressions to fold to pointers or references to
+  // locals. Code which calls Evaluate() isn't ready for that yet.
+  return !Result.Val.isLValue() || IsGlobalLValue(Result.Val.getLValueBase());
 }
 
 bool Expr::EvaluateAsBooleanCondition(bool &Result,
                                       const ASTContext &Ctx) const {
-  EvalStatus Scratch;
-  EvalInfo Info(Ctx, Scratch);
-
-  return HandleConversionToBool(this, Result, Info);
+  EvalResult Scratch;
+  return Evaluate(Scratch, Ctx) && HandleConversionToBool(Scratch.Val, Result);
 }
 
 bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx) const {
-  EvalStatus Scratch;
-  EvalInfo Info(Ctx, Scratch);
-
-  return EvaluateInteger(this, Result, Info) && !Scratch.HasSideEffects;
+  EvalResult ExprResult;
+  if (!Evaluate(ExprResult, Ctx) || ExprResult.HasSideEffects ||
+      !ExprResult.Val.isInt()) {
+    return false;
+  }
+  Result = ExprResult.Val.getInt();
+  return true;
 }
 
 bool Expr::EvaluateAsLValue(EvalResult &Result, const ASTContext &Ctx) const {
   EvalInfo Info(Ctx, Result);
 
   LValue LV;
-  if (EvaluateLValue(this, LV, Info) &&
-      !Result.HasSideEffects &&
+  if (EvaluateLValue(this, LV, Info) && !Result.HasSideEffects &&
       IsGlobalLValue(LV.Base)) {
     LV.moveInto(Result.Val);
     return true;
@@ -3193,11 +3331,7 @@
     if (Loc) *Loc = d.Loc;
     return false;
   }
-  EvalResult EvalResult;
-  if (!Evaluate(EvalResult, Ctx))
+  if (!EvaluateAsInt(Result, 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;
 }

Modified: cfe/trunk/test/CodeGenCXX/static-data-member.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/static-data-member.cpp?rev=143204&r1=143203&r2=143204&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/static-data-member.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/static-data-member.cpp Fri Oct 28 12:51:58 2011
@@ -64,3 +64,17 @@
   // CHECK-NEXT: br label
   // CHECK:      ret void
 }
+
+// Test that we can fold member lookup expressions which resolve to static data
+// members.
+namespace test4 {
+  struct A {
+    static const int n = 76;
+  };
+
+  int f(A *a) {
+    // CHECK: define i32 @_ZN5test41fEPNS_1AE
+    // CHECK: ret i32 76
+    return a->n;
+  }
+}

Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=143204&r1=143203&r2=143204&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Fri Oct 28 12:51:58 2011
@@ -26,3 +26,17 @@
     }
   }
 }
+
+extern int &Recurse1;
+int &Recurse2 = Recurse1, &Recurse1 = Recurse2;
+constexpr int &Recurse3 = Recurse2; // expected-error {{must be initialized by a constant expression}}
+
+namespace MemberEnum {
+  struct WithMemberEnum {
+    enum E { A = 42 };
+  } wme;
+  // FIXME: b's initializer is not treated as a constant expression yet, but we
+  // can at least fold it.
+  constexpr bool b = wme.A == 42;
+  int n[b];
+}





More information about the cfe-commits mailing list