[cfe-commits] r143335 - in /cfe/trunk: lib/AST/ExprConstant.cpp test/SemaCXX/constant-expression-cxx11.cpp

Richard Smith richard-llvm at metafoo.co.uk
Sun Oct 30 22:52:43 PDT 2011


Author: rsmith
Date: Mon Oct 31 00:52:43 2011
New Revision: 143335

URL: http://llvm.org/viewvc/llvm-project?rev=143335&view=rev
Log:
C++11 generalized constant expression handling: evaluation support for
materialized temporaries.

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

Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=143335&r1=143334&r2=143335&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Mon Oct 31 00:52:43 2011
@@ -46,6 +46,7 @@
 /// certain things in certain situations.
 namespace {
   struct CallStackFrame;
+  struct EvalInfo;
 
   /// 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.
@@ -68,7 +69,7 @@
     CCValue(const APValue &V, unsigned CallIndex) :
       APValue(V), CallIndex(CallIndex) {}
 
-    enum { NoCallIndex = (unsigned)-1 };
+    enum { NoCallIndex = (unsigned)0 };
 
     unsigned getLValueCallIndex() const {
       assert(getKind() == LValue);
@@ -76,6 +77,31 @@
     }
   };
 
+  /// A stack frame in the constexpr call stack.
+  struct CallStackFrame {
+    EvalInfo &Info;
+
+    /// Parent - The caller of this stack frame.
+    CallStackFrame *Caller;
+
+    /// ParmBindings - Parameter bindings for this function call, indexed by
+    /// parameters' function scope indices.
+    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;
+
+    typedef llvm::DenseMap<const Expr*, CCValue> MapTy;
+    typedef MapTy::const_iterator temp_iterator;
+    /// Temporaries - Temporary lvalues materialized within this stack frame.
+    MapTy Temporaries;
+
+    CallStackFrame(EvalInfo &Info, const CCValue *Arguments);
+    ~CallStackFrame();
+  };
+
   struct EvalInfo {
     const ASTContext &Ctx;
 
@@ -83,7 +109,7 @@
     Expr::EvalStatus &EvalStatus;
 
     /// CurrentCall - The top of the constexpr call stack.
-    const CallStackFrame *CurrentCall;
+    CallStackFrame *CurrentCall;
 
     /// NumCalls - The number of calls we've evaluated so far.
     unsigned NumCalls;
@@ -92,61 +118,59 @@
     unsigned CallStackDepth;
 
     typedef llvm::DenseMap<const OpaqueValueExpr*, CCValue> MapTy;
+    /// OpaqueValues - Values used as the common expression in a
+    /// BinaryConditionalOperator.
     MapTy OpaqueValues;
+
+    /// BottomFrame - The frame in which evaluation started. This must be
+    /// initialized last.
+    CallStackFrame BottomFrame;
+
+
+    EvalInfo(const ASTContext &C, Expr::EvalStatus &S)
+      : Ctx(C), EvalStatus(S), CurrentCall(0), NumCalls(0), CallStackDepth(0),
+        BottomFrame(*this, 0) {}
+
+    unsigned getCurrentCallIndex() const { return CurrentCall->CallIndex; }
+    CallStackFrame *getStackFrame(unsigned CallIndex) const;
+    const CCValue *getCallValue(unsigned CallIndex, unsigned ArgIndex) 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) {}
-
     const LangOptions &getLangOpts() { return Ctx.getLangOptions(); }
   };
 
-  /// A stack frame in the constexpr call stack.
-  struct CallStackFrame {
-    EvalInfo &Info;
-
-    /// Parent - The caller of this stack frame.
-    const CallStackFrame *Caller;
-
-    /// ParmBindings - Parameter bindings for this function call, indexed by
-    /// parameters' function scope indices.
-    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::CallStackFrame(EvalInfo &Info, const CCValue *Arguments)
+      : Info(Info), Caller(Info.CurrentCall), Arguments(Arguments),
+        CallIndex(Info.NumCalls++) {
+    Info.CurrentCall = this;
+    ++Info.CallStackDepth;
+  }
 
-    CallStackFrame(EvalInfo &Info, const CCValue *Arguments)
-        : Info(Info), Caller(Info.CurrentCall), Arguments(Arguments),
-          CallIndex(Info.NumCalls++) {
-      Info.CurrentCall = this;
-      ++Info.CallStackDepth;
-    }
-    ~CallStackFrame() {
-      assert(Info.CurrentCall == this && "calls retired out of order");
-      --Info.CallStackDepth;
-      Info.CurrentCall = Caller;
-    }
-  };
+  CallStackFrame::~CallStackFrame() {
+    assert(Info.CurrentCall == this && "calls retired out of order");
+    --Info.CallStackDepth;
+    Info.CurrentCall = Caller;
+  }
 
-  unsigned EvalInfo::getCurrentCallIndex() const {
-    return CurrentCall ? CurrentCall->CallIndex : CCValue::NoCallIndex;
+  CallStackFrame *EvalInfo::getStackFrame(unsigned CallIndex) const {
+    for (CallStackFrame *Frame = CurrentCall;
+         Frame && Frame->CallIndex >= CallIndex; Frame = Frame->Caller)
+      if (Frame->CallIndex == CallIndex)
+        return Frame;
+    return 0;
   }
 
   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;
+    if (CallIndex == 0)
+      return 0;
+    if (CallStackFrame *Frame = getStackFrame(CallIndex))
+      return Frame->Arguments + ArgIndex;
     return 0;
   }
 
@@ -239,7 +263,7 @@
   if (const CompoundLiteralExpr *CLE = dyn_cast<CompoundLiteralExpr>(E))
     return CLE->isFileScope();
 
-  if (isa<MemberExpr>(E))
+  if (isa<MemberExpr>(E) || isa<MaterializeTemporaryExpr>(E))
     return false;
 
   return true;
@@ -277,7 +301,8 @@
 static bool IsLiteralLValue(const LValue &Value) {
   return Value.Base &&
          !isa<DeclRefExpr>(Value.Base) &&
-         !isa<MemberExpr>(Value.Base);
+         !isa<MemberExpr>(Value.Base) &&
+         !isa<MaterializeTemporaryExpr>(Value.Base);
 }
 
 static bool IsWeakLValue(const LValue &Value) {
@@ -441,6 +466,7 @@
 bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type,
                                     const LValue &LVal, CCValue &RVal) {
   const Expr *Base = LVal.Base;
+  unsigned CallIndex = LVal.CallIndex;
 
   // FIXME: Indirection through a null pointer deserves a diagnostic.
   if (!Base)
@@ -473,7 +499,7 @@
     const VarDecl *VD = dyn_cast<VarDecl>(D);
     if (!VD || !(IsConstNonVolatile(VD->getType()) || isa<ParmVarDecl>(VD)) ||
         !Type->isLiteralType() ||
-        !EvaluateVarDeclInit(Info, VD, LVal.CallIndex, RVal))
+        !EvaluateVarDeclInit(Info, VD, CallIndex, RVal))
       return false;
 
     if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue())
@@ -487,10 +513,18 @@
     if (!RVal.getLValueOffset().isZero())
       return false;
     Base = RVal.getLValueBase();
+    CallIndex = RVal.getLValueCallIndex();
   }
 
-  // FIXME: C++11: Support MaterializeTemporaryExpr in LValueExprEvaluator and
-  // here.
+  // If this is an lvalue expression with a nontrivial initializer, grab the
+  // value from the relevant stack frame, if the object is still in scope.
+  if (isa<MaterializeTemporaryExpr>(Base)) {
+    if (CallStackFrame *Frame = Info.getStackFrame(CallIndex)) {
+      RVal = Frame->Temporaries[Base];
+      return true;
+    }
+    return false;
+  }
 
   // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the
   // initializer until now for such expressions. Such an expression can't be
@@ -847,6 +881,7 @@
 // following types:
 //  * DeclRefExpr
 //  * MemberExpr for a static member
+//  * MaterializeTemporaryExpr
 //  * CompoundLiteralExpr in C
 //  * StringLiteral
 //  * PredefinedExpr
@@ -885,6 +920,7 @@
 
   bool VisitDeclRefExpr(const DeclRefExpr *E);
   bool VisitPredefinedExpr(const PredefinedExpr *E) { return Success(E); }
+  bool VisitMaterializeTemporaryExpr(const MaterializeTemporaryExpr *E);
   bool VisitCompoundLiteralExpr(const CompoundLiteralExpr *E);
   bool VisitMemberExpr(const MemberExpr *E);
   bool VisitStringLiteral(const StringLiteral *E) { return Success(E); }
@@ -941,6 +977,13 @@
   return Error(E);
 }
 
+bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
+    const MaterializeTemporaryExpr *E) {
+  if (!Evaluate(Info.CurrentCall->Temporaries[E], Info, E->GetTemporaryExpr()))
+    return false;
+  return Success(E);
+}
+
 bool
 LValueExprEvaluator::VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
   assert(!Info.getLangOpts().CPlusPlus && "lvalue compound literal in c++?");

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=143335&r1=143334&r2=143335&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Mon Oct 31 00:52:43 2011
@@ -203,3 +203,19 @@
 using check = int[2+4+16+128+512+2048+4096+16384+32768];
 
 }
+
+namespace MaterializeTemporary {
+
+constexpr int f(const int &r) { return r; }
+constexpr int n = f(1);
+
+constexpr bool same(const int &a, const int &b) { return &a == &b; }
+constexpr bool sameTemporary(const int &n) { return same(n, n); }
+
+using check_value = int[1];
+using check_value = int[n];
+using check_value = int[!same(4, 4)];
+using check_value = int[same(n, n)];
+using check_value = int[sameTemporary(9)];
+
+}





More information about the cfe-commits mailing list