[cfe-commits] r143296 - in /cfe/trunk: include/clang/AST/APValue.h lib/AST/APValue.cpp lib/AST/ExprConstant.cpp test/SemaCXX/constant-expression-cxx11.cpp

Richard Smith richard-llvm at metafoo.co.uk
Sat Oct 29 13:57:56 PDT 2011


Author: rsmith
Date: Sat Oct 29 15:57:55 2011
New Revision: 143296

URL: http://llvm.org/viewvc/llvm-project?rev=143296&view=rev
Log:
constexpr function substitution:
Track the function invocation where an lvalue referring to a constexpr function
parameter originated from, and use it to substitute the correct argument and to
determine whether such an argument's lifetime has ended.

Modified:
    cfe/trunk/include/clang/AST/APValue.h
    cfe/trunk/lib/AST/APValue.cpp
    cfe/trunk/lib/AST/ExprConstant.cpp
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp

Modified: cfe/trunk/include/clang/AST/APValue.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/APValue.h?rev=143296&r1=143295&r2=143296&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/APValue.h (original)
+++ cfe/trunk/include/clang/AST/APValue.h Sat Oct 29 15:57:55 2011
@@ -170,7 +170,10 @@
   }
 
   const Expr* getLValueBase() const;
-  CharUnits getLValueOffset() const;
+  CharUnits &getLValueOffset();
+  const CharUnits &getLValueOffset() const {
+    return const_cast<APValue*>(this)->getLValueOffset();
+  }
 
   void setInt(const APSInt &I) {
     assert(isInt() && "Invalid accessor");

Modified: cfe/trunk/lib/AST/APValue.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/APValue.cpp?rev=143296&r1=143295&r2=143296&view=diff
==============================================================================
--- cfe/trunk/lib/AST/APValue.cpp (original)
+++ cfe/trunk/lib/AST/APValue.cpp Sat Oct 29 15:57:55 2011
@@ -169,9 +169,9 @@
   return ((const LV*)(const void*)Data)->Base;
 }
 
-CharUnits APValue::getLValueOffset() const {
-    assert(isLValue() && "Invalid accessor");
-    return ((const LV*)(const void*)Data)->Offset;
+CharUnits &APValue::getLValueOffset() {
+  assert(isLValue() && "Invalid accessor");
+  return ((LV*)(void*)Data)->Offset;
 }
 
 void APValue::setLValue(const Expr *B, const CharUnits &O) {
@@ -185,4 +185,3 @@
   new ((void*)(char*)Data) LV();
   Kind = LValue;
 }
-

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=143296&r1=143295&r2=143296&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Sat Oct 29 15:57:55 2011
@@ -28,6 +28,8 @@
 using llvm::APSInt;
 using llvm::APFloat;
 
+static bool IsParamLValue(const Expr *E);
+
 /// EvalInfo - This is a private struct used by the evaluator to capture
 /// information about a subexpression as it is folded.  It retains information
 /// about the AST context, but also maintains information about the folded
@@ -45,6 +47,35 @@
 namespace {
   struct CallStackFrame;
 
+  /// A core constant value. This can be the value of any constant expression,
+  /// or a pointer or reference to a non-static object or function parameter.
+  class CCValue : public APValue {
+    typedef llvm::APSInt APSInt;
+    typedef llvm::APFloat APFloat;
+    /// If the value is a DeclRefExpr lvalue referring to a ParmVarDecl, this is
+    /// the index of the corresponding function call.
+    unsigned CallIndex;
+  public:
+    CCValue() {}
+    explicit CCValue(const APSInt &I) : APValue(I) {}
+    explicit CCValue(const APFloat &F) : APValue(F) {}
+    CCValue(const APValue *E, unsigned N) : APValue(E, N) {}
+    CCValue(const APSInt &R, const APSInt &I) : APValue(R, I) {}
+    CCValue(const APFloat &R, const APFloat &I) : APValue(R, I) {}
+    CCValue(const CCValue &V) : APValue(V), CallIndex(V.CallIndex) {}
+    CCValue(const Expr *B, const CharUnits &O, unsigned I) :
+      APValue(B, O), CallIndex(I) {}
+    CCValue(const APValue &V, unsigned CallIndex) :
+      APValue(V), CallIndex(CallIndex) {}
+
+    enum { NoCallIndex = (unsigned)-1 };
+
+    unsigned getLValueCallIndex() const {
+      assert(getKind() == LValue);
+      return CallIndex;
+    }
+  };
+
   struct EvalInfo {
     const ASTContext &Ctx;
 
@@ -60,14 +91,17 @@
     /// CallStackDepth - The number of calls in the call stack right now.
     unsigned CallStackDepth;
 
-    typedef llvm::DenseMap<const OpaqueValueExpr*, APValue> MapTy;
+    typedef llvm::DenseMap<const OpaqueValueExpr*, CCValue> MapTy;
     MapTy OpaqueValues;
-    const APValue *getOpaqueValue(const OpaqueValueExpr *e) const {
+    const CCValue *getOpaqueValue(const OpaqueValueExpr *e) const {
       MapTy::const_iterator i = OpaqueValues.find(e);
       if (i == OpaqueValues.end()) return 0;
       return &i->second;
     }
 
+    unsigned getCurrentCallIndex() const;
+    const CCValue *getCallValue(unsigned CallIndex, unsigned ArgIndex) const;
+
     EvalInfo(const ASTContext &C, Expr::EvalStatus &S)
       : Ctx(C), EvalStatus(S), CurrentCall(0), NumCalls(0), CallStackDepth(0) {}
 
@@ -83,14 +117,14 @@
 
     /// ParmBindings - Parameter bindings for this function call, indexed by
     /// parameters' function scope indices.
-    const APValue *Arguments;
+    const CCValue *Arguments;
 
     /// CallIndex - The index of the current call. This is used to match lvalues
     /// referring to parameters up with the corresponding stack frame, and to
     /// detect when the parameter is no longer in scope.
     unsigned CallIndex;
 
-    CallStackFrame(EvalInfo &Info, const APValue *Arguments)
+    CallStackFrame(EvalInfo &Info, const CCValue *Arguments)
         : Info(Info), Caller(Info.CurrentCall), Arguments(Arguments),
           CallIndex(Info.NumCalls++) {
       Info.CurrentCall = this;
@@ -103,6 +137,19 @@
     }
   };
 
+  unsigned EvalInfo::getCurrentCallIndex() const {
+    return CurrentCall ? CurrentCall->CallIndex : CCValue::NoCallIndex;
+  }
+
+  const CCValue *EvalInfo::getCallValue(unsigned CallIndex,
+                                        unsigned ArgIndex) const {
+    for (const CallStackFrame *Frame = CurrentCall;
+         Frame && Frame->CallIndex >= CallIndex; Frame = Frame->Caller)
+      if (Frame->CallIndex == CallIndex)
+        return Frame->Arguments + ArgIndex;
+    return 0;
+  }
+
   struct ComplexValue {
   private:
     bool IsInt;
@@ -123,13 +170,13 @@
     APSInt &getComplexIntReal() { return IntReal; }
     APSInt &getComplexIntImag() { return IntImag; }
 
-    void moveInto(APValue &v) const {
+    void moveInto(CCValue &v) const {
       if (isComplexFloat())
-        v = APValue(FloatReal, FloatImag);
+        v = CCValue(FloatReal, FloatImag);
       else
-        v = APValue(IntReal, IntImag);
+        v = CCValue(IntReal, IntImag);
     }
-    void setFrom(const APValue &v) {
+    void setFrom(const CCValue &v) {
       assert(v.isComplexFloat() || v.isComplexInt());
       if (v.isComplexFloat()) {
         makeComplexFloat();
@@ -146,26 +193,29 @@
   struct LValue {
     const Expr *Base;
     CharUnits Offset;
+    unsigned CallIndex;
 
     const Expr *getLValueBase() { return Base; }
-    CharUnits getLValueOffset() { return Offset; }
+    CharUnits &getLValueOffset() { return Offset; }
+    unsigned getLValueCallIndex() { return CallIndex; }
 
-    void moveInto(APValue &v) const {
-      v = APValue(Base, Offset);
+    void moveInto(CCValue &V) const {
+      V = CCValue(Base, Offset, CallIndex);
     }
-    void setFrom(const APValue &v) {
-      assert(v.isLValue());
-      Base = v.getLValueBase();
-      Offset = v.getLValueOffset();
+    void setFrom(const CCValue &V) {
+      assert(V.isLValue());
+      Base = V.getLValueBase();
+      Offset = V.getLValueOffset();
+      CallIndex = V.getLValueCallIndex();
     }
   };
 }
 
-static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E);
+static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E);
 static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
 static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info);
 static bool EvaluateInteger(const Expr *E, APSInt  &Result, EvalInfo &Info);
-static bool EvaluateIntegerOrLValue(const Expr *E, APValue  &Result,
+static bool EvaluateIntegerOrLValue(const Expr *E, CCValue &Result,
                                     EvalInfo &Info);
 static bool EvaluateFloat(const Expr *E, APFloat &Result, EvalInfo &Info);
 static bool EvaluateComplex(const Expr *E, ComplexValue &Res, EvalInfo &Info);
@@ -194,6 +244,18 @@
   return true;
 }
 
+static bool IsParamLValue(const Expr *E) {
+  if (const DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E))
+    return isa<ParmVarDecl>(DRE->getDecl());
+  return false;
+}
+
+/// Check that this core constant expression value is a valid value for a
+/// constant expression.
+static bool CheckConstantExpression(const CCValue &Value) {
+  return !Value.isLValue() || IsGlobalLValue(Value.getLValueBase());
+}
+
 static bool EvalPointerValueAsBool(const LValue &Value, bool &Result) {
   const Expr* Base = Value.Base;
 
@@ -205,6 +267,7 @@
   }
 
   // Require the base expression to be a global l-value.
+  // FIXME: C++11 requires such conversions. Remove this check.
   if (!IsGlobalLValue(Base)) return false;
 
   // We have a non-null base expression.  These are generally known to
@@ -226,7 +289,7 @@
   return true;
 }
 
-static bool HandleConversionToBool(const APValue &Val, bool &Result) {
+static bool HandleConversionToBool(const CCValue &Val, bool &Result) {
   switch (Val.getKind()) {
   case APValue::Uninitialized:
     return false;
@@ -244,12 +307,11 @@
     Result = !Val.getComplexFloatReal().isZero() ||
              !Val.getComplexFloatImag().isZero();
     return true;
-  case APValue::LValue:
-    {
-      LValue PointerResult;
-      PointerResult.setFrom(Val);
-      return EvalPointerValueAsBool(PointerResult, Result);
-    }
+  case APValue::LValue: {
+    LValue PointerResult;
+    PointerResult.setFrom(Val);
+    return EvalPointerValueAsBool(PointerResult, Result);
+  }
   case APValue::Vector:
     return false;
   }
@@ -260,7 +322,7 @@
 static bool EvaluateAsBooleanCondition(const Expr *E, bool &Result,
                                        EvalInfo &Info) {
   assert(E->isRValue() && "missing lvalue-to-rvalue conv in bool condition");
-  APValue Val;
+  CCValue Val;
   if (!Evaluate(Val, Info, E))
     return false;
   return HandleConversionToBool(Val, Result);
@@ -309,40 +371,44 @@
 }
 
 /// Try to evaluate the initializer for a variable declaration.
-static const APValue *EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD) {
+static bool EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD,
+                                unsigned CallIndex, CCValue &Result) {
   // If this is a parameter to an active constexpr function call, perform
   // argument substitution.
   if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) {
-    // FIXME This assumes that all parameters must be parameters of the current
-    // call. Add the CallIndex to the LValue representation and use that to
-    // check.
-    if (Info.CurrentCall)
-      return &Info.CurrentCall->Arguments[PVD->getFunctionScopeIndex()];
-    return 0;
+    if (const CCValue *ArgValue =
+          Info.getCallValue(CallIndex, PVD->getFunctionScopeIndex())) {
+      Result = *ArgValue;
+      return true;
+    }
+    return false;
   }
 
   const Expr *Init = VD->getAnyInitializer();
   if (!Init)
-    return 0;
+    return false;
 
-  if (APValue *V = VD->getEvaluatedValue())
-    return V;
+  if (APValue *V = VD->getEvaluatedValue()) {
+    Result = CCValue(*V, CCValue::NoCallIndex);
+    return !Result.isUninit();
+  }
 
   if (VD->isEvaluatingValue())
-    return 0;
+    return false;
 
   VD->setEvaluatingValue();
 
-  Expr::EvalResult EResult;
-  EvalInfo InitInfo(Info.Ctx, EResult);
+  Expr::EvalStatus EStatus;
+  EvalInfo InitInfo(Info.Ctx, EStatus);
   // 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
+  if (!Evaluate(Result, InitInfo, Init) || !CheckConstantExpression(Result)) {
     VD->setEvaluatedValue(APValue());
+    return false;
+  }
 
-  return VD->getEvaluatedValue();
+  VD->setEvaluatedValue(Result);
+  return true;
 }
 
 static bool IsConstNonVolatile(QualType T) {
@@ -351,7 +417,7 @@
 }
 
 bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type,
-                                    const LValue &LVal, APValue &RVal) {
+                                    const LValue &LVal, CCValue &RVal) {
   const Expr *Base = LVal.Base;
 
   // FIXME: Indirection through a null pointer deserves a diagnostic.
@@ -401,26 +467,21 @@
     // them are not permitted.
     const VarDecl *VD = dyn_cast<VarDecl>(D);
     if (!VD || !(IsConstNonVolatile(VD->getType()) || isa<ParmVarDecl>(VD)) ||
-        !(Type->isIntegralOrEnumerationType() || Type->isRealFloatingType()))
+        !(Type->isIntegralOrEnumerationType() || Type->isRealFloatingType()) ||
+        !EvaluateVarDeclInit(Info, VD, LVal.CallIndex, RVal))
       return false;
 
-    const APValue *V = EvaluateVarDeclInit(Info, VD);
-    if (!V || V->isUninit())
-      return false;
-
-    if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue()) {
-      RVal = *V;
+    if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue())
       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())
+    if (!RVal.getLValueOffset().isZero())
       return false;
+    Base = RVal.getLValueBase();
   }
 
   // FIXME: C++11: Support MaterializeTemporaryExpr in LValueExprEvaluator and
@@ -449,7 +510,7 @@
 }
 
 // Evaluate a statement.
-static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
+static EvalStmtResult EvaluateStmt(CCValue &Result, EvalInfo &Info,
                                    const Stmt *S) {
   switch (S->getStmtClass()) {
   default:
@@ -479,12 +540,12 @@
 
 /// Evaluate a function call.
 static bool HandleFunctionCall(ArrayRef<const Expr*> Args, const Stmt *Body,
-                               EvalInfo &Info, APValue &Result) {
+                               EvalInfo &Info, CCValue &Result) {
   // FIXME: Implement a proper call limit, along with a command-line flag.
   if (Info.NumCalls >= 1000000 || Info.CallStackDepth >= 512)
     return false;
 
-  SmallVector<APValue, 16> ArgValues(Args.size());
+  SmallVector<CCValue, 16> ArgValues(Args.size());
   // FIXME: Deal with default arguments and 'this'.
   for (ArrayRef<const Expr*>::iterator I = Args.begin(), E = Args.end();
        I != E; ++I)
@@ -609,7 +670,7 @@
 class ExprEvaluatorBase
   : public ConstStmtVisitor<Derived, RetTy> {
 private:
-  RetTy DerivedSuccess(const APValue &V, const Expr *E) {
+  RetTy DerivedSuccess(const CCValue &V, const Expr *E) {
     return static_cast<Derived*>(this)->Success(V, E);
   }
   RetTy DerivedError(const Expr *E) {
@@ -671,11 +732,11 @@
   }
 
   RetTy VisitOpaqueValueExpr(const OpaqueValueExpr *E) {
-    const APValue *value = Info.getOpaqueValue(E);
-    if (!value)
+    const CCValue *Value = Info.getOpaqueValue(E);
+    if (!Value)
       return (E->getSourceExpr() ? StmtVisitorTy::Visit(E->getSourceExpr())
                                  : DerivedError(E));
-    return DerivedSuccess(*value, E);
+    return DerivedSuccess(*Value, E);
   }
 
   RetTy VisitCallExpr(const CallExpr *E) {
@@ -690,7 +751,7 @@
     if (!CalleeType->isFunctionType() && !CalleeType->isFunctionPointerType())
       return DerivedError(E);
 
-    APValue Call;
+    CCValue Call;
     if (!Evaluate(Call, Info, Callee) || !Call.isLValue() ||
         !Call.getLValueBase() || !Call.getLValueOffset().isZero())
       return DerivedError(Callee);
@@ -709,7 +770,7 @@
 
     const FunctionDecl *Definition;
     Stmt *Body = FD->getBody(Definition);
-    APValue Result;
+    CCValue Result;
     llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
 
     if (Body && Definition->isConstexpr() && !Definition->isInvalidDecl() &&
@@ -749,7 +810,7 @@
     case CK_LValueToRValue: {
       LValue LVal;
       if (EvaluateLValue(E->getSubExpr(), LVal, Info)) {
-        APValue RVal;
+        CCValue RVal;
         if (HandleLValueToRValueConversion(Info, E->getType(), LVal, RVal))
           return DerivedSuccess(RVal, E);
       }
@@ -762,7 +823,7 @@
 
   /// Visit a value which is evaluated, but whose value is ignored.
   void VisitIgnoredValue(const Expr *E) {
-    APValue Scratch;
+    CCValue Scratch;
     if (!Evaluate(Scratch, Info, E))
       Info.EvalStatus.HasSideEffects = true;
   }
@@ -799,6 +860,7 @@
   bool Success(const Expr *E) {
     Result.Base = E;
     Result.Offset = CharUnits::Zero();
+    Result.CallIndex = Info.getCurrentCallIndex();
     return true;
   }
 public:
@@ -806,7 +868,7 @@
   LValueExprEvaluator(EvalInfo &info, LValue &Result) :
     ExprEvaluatorBaseTy(info), Result(Result), PrevDecl(0) {}
 
-  bool Success(const APValue &V, const Expr *E) {
+  bool Success(const CCValue &V, const Expr *E) {
     Result.setFrom(V);
     return true;
   }
@@ -867,9 +929,9 @@
   if (!VD->getType()->isReferenceType())
     return Success(E);
 
-  const APValue *V = EvaluateVarDeclInit(Info, VD);
-  if (V && !V->isUninit())
-    return Success(*V, E);
+  CCValue V;
+  if (EvaluateVarDeclInit(Info, VD, Info.getCurrentCallIndex(), V))
+    return Success(V, E);
 
   return Error(E);
 }
@@ -956,6 +1018,7 @@
   bool Success(const Expr *E) {
     Result.Base = E;
     Result.Offset = CharUnits::Zero();
+    Result.CallIndex = Info.getCurrentCallIndex();
     return true;
   }
 public:
@@ -963,7 +1026,7 @@
   PointerExprEvaluator(EvalInfo &info, LValue &Result)
     : ExprEvaluatorBaseTy(info), Result(Result) {}
 
-  bool Success(const APValue &V, const Expr *E) {
+  bool Success(const CCValue &V, const Expr *E) {
     Result.setFrom(V);
     return true;
   }
@@ -1059,8 +1122,7 @@
 
   case CK_DerivedToBase:
   case CK_UncheckedDerivedToBase: {
-    LValue BaseLV;
-    if (!EvaluatePointer(E->getSubExpr(), BaseLV, Info))
+    if (!EvaluatePointer(E->getSubExpr(), Result, Info))
       return false;
 
     // Now figure out the necessary offset to add to the baseLV to get from
@@ -1083,35 +1145,31 @@
       const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl();
       const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl);
 
-      Offset += Layout.getBaseClassOffset(BaseDecl);
+      Result.getLValueOffset() += Layout.getBaseClassOffset(BaseDecl);
       DerivedDecl = BaseDecl;
     }
 
-    Result.Base = BaseLV.getLValueBase();
-    Result.Offset = BaseLV.getLValueOffset() + Offset;
     return true;
   }
 
-  case CK_NullToPointer: {
-    Result.Base = 0;
-    Result.Offset = CharUnits::Zero();
-    return true;
-  }
+  case CK_NullToPointer:
+    return ValueInitialization(E);
 
   case CK_IntegralToPointer: {
-    APValue Value;
+    CCValue Value;
     if (!EvaluateIntegerOrLValue(SubExpr, Value, Info))
       break;
 
     if (Value.isInt()) {
-      Value.getInt() = Value.getInt().extOrTrunc((unsigned)Info.Ctx.getTypeSize(E->getType()));
+      unsigned Size = Info.Ctx.getTypeSize(E->getType());
+      uint64_t N = Value.getInt().extOrTrunc(Size).getZExtValue();
       Result.Base = 0;
-      Result.Offset = CharUnits::fromQuantity(Value.getInt().getZExtValue());
+      Result.Offset = CharUnits::fromQuantity(N);
+      Result.CallIndex = CCValue::NoCallIndex;
       return true;
     } else {
       // Cast is of an lvalue, no need to change value.
-      Result.Base = Value.getLValueBase();
-      Result.Offset = Value.getLValueOffset();
+      Result.setFrom(Value);
       return true;
     }
   }
@@ -1331,9 +1389,9 @@
 namespace {
 class IntExprEvaluator
   : public ExprEvaluatorBase<IntExprEvaluator, bool> {
-  APValue &Result;
+  CCValue &Result;
 public:
-  IntExprEvaluator(EvalInfo &info, APValue &result)
+  IntExprEvaluator(EvalInfo &info, CCValue &result)
     : ExprEvaluatorBaseTy(info), Result(result) {}
 
   bool Success(const llvm::APSInt &SI, const Expr *E) {
@@ -1343,7 +1401,7 @@
            "Invalid evaluation result.");
     assert(SI.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) &&
            "Invalid evaluation result.");
-    Result = APValue(SI);
+    Result = CCValue(SI);
     return true;
   }
 
@@ -1352,7 +1410,7 @@
            "Invalid evaluation result.");
     assert(I.getBitWidth() == Info.Ctx.getIntWidth(E->getType()) &&
            "Invalid evaluation result.");
-    Result = APValue(APSInt(I));
+    Result = CCValue(APSInt(I));
     Result.getInt().setIsUnsigned(
                             E->getType()->isUnsignedIntegerOrEnumerationType());
     return true;
@@ -1361,7 +1419,7 @@
   bool Success(uint64_t Value, const Expr *E) {
     assert(E->getType()->isIntegralOrEnumerationType() && 
            "Invalid evaluation result.");
-    Result = APValue(Info.Ctx.MakeIntValue(Value, E->getType()));
+    Result = CCValue(Info.Ctx.MakeIntValue(Value, E->getType()));
     return true;
   }
 
@@ -1380,7 +1438,7 @@
     return false;
   }
 
-  bool Success(const APValue &V, const Expr *E) {
+  bool Success(const CCValue &V, const Expr *E) {
     return Success(V.getInt(), E);
   }
   bool Error(const Expr *E) {
@@ -1472,13 +1530,14 @@
 /// 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) {
+static bool EvaluateIntegerOrLValue(const Expr* E, CCValue &Result,
+                                    EvalInfo &Info) {
   assert(E->isRValue() && E->getType()->isIntegralOrEnumerationType());
   return IntExprEvaluator(Info, Result).Visit(E);
 }
 
 static bool EvaluateInteger(const Expr* E, APSInt &Result, EvalInfo &Info) {
-  APValue Val;
+  CCValue Val;
   if (!EvaluateIntegerOrLValue(E, Val, Info) || !Val.isInt())
     return false;
   Result = Val.getInt();
@@ -1890,33 +1949,32 @@
   }
 
   // The LHS of a constant expr is always evaluated and needed.
-  APValue LHSVal;
+  CCValue LHSVal;
   if (!EvaluateIntegerOrLValue(E->getLHS(), LHSVal, Info))
     return false; // error in subexpression.
 
   if (!Visit(E->getRHS()))
     return false;
-  APValue &RHSVal = Result;
+  CCValue &RHSVal = Result;
 
   // Handle cases like (unsigned long)&a + 4.
   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;
+      LHSVal.getLValueOffset() += AdditionalOffset;
     else
-      Offset -= AdditionalOffset;
-    Result = APValue(LHSVal.getLValueBase(), Offset);
+      LHSVal.getLValueOffset() -= AdditionalOffset;
+    Result = LHSVal;
     return true;
   }
 
   // Handle cases like 4 + (unsigned long)&a
   if (E->getOpcode() == BO_Add &&
         RHSVal.isLValue() && LHSVal.isInt()) {
-    CharUnits Offset = RHSVal.getLValueOffset();
-    Offset += CharUnits::fromQuantity(LHSVal.getInt().getZExtValue());
-    Result = APValue(RHSVal.getLValueBase(), Offset);
+    RHSVal.getLValueOffset() += CharUnits::fromQuantity(
+                                    LHSVal.getInt().getZExtValue());
+    // Note that RHSVal is Result.
     return true;
   }
 
@@ -2145,7 +2203,7 @@
     return false;
 
   // Get the operand value.
-  APValue Val;
+  CCValue Val;
   if (!Evaluate(Val, Info, E->getSubExpr()))
     return false;
 
@@ -2330,7 +2388,7 @@
   FloatExprEvaluator(EvalInfo &info, APFloat &result)
     : ExprEvaluatorBaseTy(info), Result(result) {}
 
-  bool Success(const APValue &V, const Expr *e) {
+  bool Success(const CCValue &V, const Expr *e) {
     Result = V.getFloat();
     return true;
   }
@@ -2575,7 +2633,7 @@
   ComplexExprEvaluator(EvalInfo &info, ComplexValue &Result)
     : ExprEvaluatorBaseTy(info), Result(Result) {}
 
-  bool Success(const APValue &V, const Expr *e) {
+  bool Success(const CCValue &V, const Expr *e) {
     Result.setFrom(V);
     return true;
   }
@@ -2915,7 +2973,7 @@
 // Top level Expr::EvaluateAsRValue method.
 //===----------------------------------------------------------------------===//
 
-static bool Evaluate(APValue &Result, EvalInfo &Info, const Expr *E) {
+static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E) {
   // In C, function designators are not lvalues, but we evaluate them as if they
   // are.
   if (E->isGLValue() || E->getType()->isFunctionType()) {
@@ -2938,7 +2996,7 @@
     llvm::APFloat F(0.0);
     if (!EvaluateFloat(E, F, Info))
       return false;
-    Result = APValue(F);
+    Result = CCValue(F);
   } else if (E->getType()->isAnyComplexType()) {
     ComplexValue C;
     if (!EvaluateComplex(E, C, Info))
@@ -2959,25 +3017,31 @@
 bool Expr::EvaluateAsRValue(EvalResult &Result, const ASTContext &Ctx) const {
   EvalInfo Info(Ctx, Result);
 
-  if (!::Evaluate(Result.Val, Info, this))
+  CCValue Value;
+  if (!::Evaluate(Value, Info, this))
     return false;
 
   if (isGLValue()) {
     LValue LV;
-    LV.setFrom(Result.Val);
-    return HandleLValueToRValueConversion(Info, getType(), LV, Result.Val);
+    LV.setFrom(Value);
+    if (!HandleLValueToRValueConversion(Info, getType(), LV, Value))
+      return false;
   }
 
-  // FIXME: We don't allow expressions to fold to pointers to locals. Code which
-  // calls EvaluateAsRValue() isn't ready for that yet.
-  return !Result.Val.isLValue() || IsGlobalLValue(Result.Val.getLValueBase());
+  // Check this core constant expression is a constant expression, and if so,
+  // slice it down to one.
+  if (!CheckConstantExpression(Value))
+    return false;
+  Result.Val = Value;
+  return true;
 }
 
 bool Expr::EvaluateAsBooleanCondition(bool &Result,
                                       const ASTContext &Ctx) const {
   EvalResult Scratch;
   return EvaluateAsRValue(Scratch, Ctx) &&
-         HandleConversionToBool(Scratch.Val, Result);
+         HandleConversionToBool(CCValue(Scratch.Val, CCValue::NoCallIndex),
+                                Result);
 }
 
 bool Expr::EvaluateAsInt(APSInt &Result, const ASTContext &Ctx) const {
@@ -2996,7 +3060,7 @@
   LValue LV;
   if (EvaluateLValue(this, LV, Info) && !Result.HasSideEffects &&
       IsGlobalLValue(LV.Base)) {
-    LV.moveInto(Result.Val);
+    Result.Val = APValue(LV.Base, LV.Offset);
     return true;
   }
   return false;
@@ -3007,8 +3071,10 @@
   EvalInfo Info(Ctx, Result);
 
   LValue LV;
-  if (EvaluateLValue(this, LV, Info)) {
-    LV.moveInto(Result.Val);
+  // Don't allow references to out-of-scope function parameters to escape.
+  if (EvaluateLValue(this, LV, Info) &&
+      (!IsParamLValue(LV.Base) || LV.CallIndex == CCValue::NoCallIndex)) {
+    Result.Val = APValue(LV.Base, LV.Offset);
     return true;
   }
   return false;

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=143296&r1=143295&r2=143296&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Sat Oct 29 15:57:55 2011
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
+// RUN: %clang_cc1 -triple i686-linux -fsyntax-only -verify -std=c++11 %s
 
 // FIXME: support const T& parameters here.
 //template<typename T> constexpr T id(const T &t) { return t; }
@@ -10,8 +10,8 @@
 //template<typename T> constexpr T max(const T &a, const T &b) {
 //  return a < b ? b : a;
 //}
-constexpr int min(int a, int b) { return a < b ? a : b; }
-constexpr int max(int a, int b) { return a < b ? b : a; }
+constexpr int min(const int &a, const int &b) { return a < b ? a : b; }
+constexpr int max(const int &a, const int &b) { return a < b ? b : a; }
 
 struct MemberZero {
   constexpr int zero() { return 0; }
@@ -91,3 +91,31 @@
   using check_static_call = int[s.f(19)];
   using check_static_call = int[800];
 }
+
+namespace ParameterScopes {
+
+  const int k = 42;
+  constexpr const int &ObscureTheTruth(const int &a) { return a; }
+  constexpr const int &MaybeReturnJunk(bool b, const int a) {
+    return ObscureTheTruth(b ? a : k);
+  }
+  constexpr int n1 = MaybeReturnJunk(false, 0); // ok
+  constexpr int n2 = MaybeReturnJunk(true, 0); // expected-error {{must be initialized by a constant expression}}
+
+  constexpr int InternalReturnJunk(int n) {
+    // FIXME: We should reject this: it never produces a constant expression.
+    return MaybeReturnJunk(true, n);
+  }
+  constexpr int n3 = InternalReturnJunk(0); // expected-error {{must be initialized by a constant expression}}
+
+  constexpr int LToR(int &n) { return n; }
+  constexpr int GrabCallersArgument(bool which, int a, int b) {
+    return LToR(which ? b : a);
+  }
+  constexpr int n4 = GrabCallersArgument(false, 1, 2);
+  constexpr int n5 = GrabCallersArgument(true, 4, 8);
+  // FIXME: this isn't an ICE yet.
+  using check_value = int[n4 + n5];
+  using check_value = int[9];
+
+}





More information about the cfe-commits mailing list