<br><br><div class="gmail_quote">Le 1 novembre 2011 17:57, Richard Smith <span dir="ltr"><<a href="mailto:richard-llvm@metafoo.co.uk">richard-llvm@metafoo.co.uk</a>></span> a écrit :<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
Author: rsmith<br>
Date: Tue Nov  1 11:57:24 2011<br>
New Revision: 143463<br>
<br>
URL: <a href="http://llvm.org/viewvc/llvm-project?rev=143463&view=rev" target="_blank">http://llvm.org/viewvc/llvm-project?rev=143463&view=rev</a><br>
Log:<br>
Implement C++11 'constexpr calls must return constant expressions' rule, and<br>
perform the code simplifications this rule allows.<br>
<br>
Modified:<br>
    cfe/trunk/lib/AST/ExprConstant.cpp<br>
    cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp<br>
<br>
Modified: cfe/trunk/lib/AST/ExprConstant.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=143463&r1=143462&r2=143463&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=143463&r1=143462&r2=143463&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)<br>
+++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Nov  1 11:57:24 2011<br>
@@ -28,8 +28,6 @@<br>
 using llvm::APSInt;<br>
 using llvm::APFloat;<br>
<br>
-static bool IsParamLValue(const Expr *E);<br>
-<br>
 /// EvalInfo - This is a private struct used by the evaluator to capture<br>
 /// information about a subexpression as it is folded.  It retains information<br>
 /// about the AST context, but also maintains information about the folded<br>
@@ -53,27 +51,27 @@<br>
   class CCValue : public APValue {<br>
     typedef llvm::APSInt APSInt;<br>
     typedef llvm::APFloat APFloat;<br>
-    /// If the value is a DeclRefExpr lvalue referring to a ParmVarDecl, this is<br>
-    /// the index of the corresponding function call.<br>
-    unsigned CallIndex;<br>
+    /// If the value is a reference or pointer into a parameter or temporary,<br>
+    /// this is the corresponding call stack frame.<br>
+    CallStackFrame *CallFrame;<br>
   public:<br>
+    struct GlobalValue {};<br>
+<br>
     CCValue() {}<br>
     explicit CCValue(const APSInt &I) : APValue(I) {}<br>
     explicit CCValue(const APFloat &F) : APValue(F) {}<br>
     CCValue(const APValue *E, unsigned N) : APValue(E, N) {}<br>
     CCValue(const APSInt &R, const APSInt &I) : APValue(R, I) {}<br>
     CCValue(const APFloat &R, const APFloat &I) : APValue(R, I) {}<br>
-    CCValue(const CCValue &V) : APValue(V), CallIndex(V.CallIndex) {}<br>
-    CCValue(const Expr *B, const CharUnits &O, unsigned I) :<br>
-      APValue(B, O), CallIndex(I) {}<br>
-    CCValue(const APValue &V, unsigned CallIndex) :<br>
-      APValue(V), CallIndex(CallIndex) {}<br>
-<br>
-    enum { NoCallIndex = (unsigned)0 };<br>
+    CCValue(const CCValue &V) : APValue(V), CallFrame(V.CallFrame) {}<br>
+    CCValue(const Expr *B, const CharUnits &O, CallStackFrame *F) :<br>
+      APValue(B, O), CallFrame(F) {}<br>
+    CCValue(const APValue &V, GlobalValue) :<br>
+      APValue(V), CallFrame(0) {}<br>
<br>
-    unsigned getLValueCallIndex() const {<br>
+    CallStackFrame *getLValueFrame() const {<br>
       assert(getKind() == LValue);<br>
-      return CallIndex;<br>
+      return CallFrame;<br>
     }<br>
   };<br>
<br>
@@ -88,11 +86,6 @@<br>
     /// parameters' function scope indices.<br>
     const CCValue *Arguments;<br>
<br>
-    /// CallIndex - The index of the current call. This is used to match lvalues<br>
-    /// referring to parameters up with the corresponding stack frame, and to<br>
-    /// detect when the parameter is no longer in scope.<br>
-    unsigned CallIndex;<br>
-<br>
     typedef llvm::DenseMap<const Expr*, CCValue> MapTy;<br>
     typedef MapTy::const_iterator temp_iterator;<br>
     /// Temporaries - Temporary lvalues materialized within this stack frame.<br>
@@ -131,10 +124,6 @@<br>
       : Ctx(C), EvalStatus(S), CurrentCall(0), NumCalls(0), CallStackDepth(0),<br>
         BottomFrame(*this, 0) {}<br>
<br>
-    unsigned getCurrentCallIndex() const { return CurrentCall->CallIndex; }<br>
-    CallStackFrame *getStackFrame(unsigned CallIndex) const;<br>
-    const CCValue *getCallValue(unsigned CallIndex, unsigned ArgIndex) const;<br>
-<br>
     const CCValue *getOpaqueValue(const OpaqueValueExpr *e) const {<br>
       MapTy::const_iterator i = OpaqueValues.find(e);<br>
       if (i == OpaqueValues.end()) return 0;<br>
@@ -145,8 +134,7 @@<br>
   };<br>
<br>
   CallStackFrame::CallStackFrame(EvalInfo &Info, const CCValue *Arguments)<br>
-      : Info(Info), Caller(Info.CurrentCall), Arguments(Arguments),<br>
-        CallIndex(Info.NumCalls++) {<br>
+      : Info(Info), Caller(Info.CurrentCall), Arguments(Arguments) {<br>
     Info.CurrentCall = this;<br>
     ++Info.CallStackDepth;<br>
   }<br>
@@ -157,23 +145,6 @@<br>
     Info.CurrentCall = Caller;<br>
   }<br>
<br>
-  CallStackFrame *EvalInfo::getStackFrame(unsigned CallIndex) const {<br>
-    for (CallStackFrame *Frame = CurrentCall;<br>
-         Frame && Frame->CallIndex >= CallIndex; Frame = Frame->Caller)<br>
-      if (Frame->CallIndex == CallIndex)<br>
-        return Frame;<br>
-    return 0;<br>
-  }<br>
-<br>
-  const CCValue *EvalInfo::getCallValue(unsigned CallIndex,<br>
-                                        unsigned ArgIndex) const {<br>
-    if (CallIndex == 0)<br>
-      return 0;<br>
-    if (CallStackFrame *Frame = getStackFrame(CallIndex))<br>
-      return Frame->Arguments + ArgIndex;<br>
-    return 0;<br>
-  }<br>
-<br>
   struct ComplexValue {<br>
   private:<br>
     bool IsInt;<br>
@@ -217,21 +188,21 @@<br>
   struct LValue {<br>
     const Expr *Base;<br>
     CharUnits Offset;<br>
-    unsigned CallIndex;<br>
+    CallStackFrame *Frame;<br>
<br>
     const Expr *getLValueBase() const { return Base; }<br>
     CharUnits &getLValueOffset() { return Offset; }<br>
     const CharUnits &getLValueOffset() const { return Offset; }<br>
-    unsigned getLValueCallIndex() const { return CallIndex; }<br>
+    CallStackFrame *getLValueFrame() const { return Frame; }<br>
<br>
     void moveInto(CCValue &V) const {<br>
-      V = CCValue(Base, Offset, CallIndex);<br>
+      V = CCValue(Base, Offset, Frame);<br>
     }<br>
     void setFrom(const CCValue &V) {<br>
       assert(V.isLValue());<br>
       Base = V.getLValueBase();<br>
       Offset = V.getLValueOffset();<br>
-      CallIndex = V.getLValueCallIndex();<br>
+      Frame = V.getLValueFrame();<br>
     }<br>
   };<br>
 }<br>
@@ -269,12 +240,6 @@<br>
   return true;<br>
 }<br>
<br>
-static bool IsParamLValue(const Expr *E) {<br>
-  if (const DeclRefExpr *DRE = dyn_cast_or_null<DeclRefExpr>(E))<br>
-    return isa<ParmVarDecl>(DRE->getDecl());<br>
-  return false;<br>
-}<br>
-<br>
 /// Check that this core constant expression value is a valid value for a<br>
 /// constant expression.<br>
 static bool CheckConstantExpression(const CCValue &Value) {<br>
@@ -419,16 +384,14 @@<br>
<br>
 /// Try to evaluate the initializer for a variable declaration.<br>
 static bool EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD,<br>
-                                unsigned CallIndex, CCValue &Result) {<br>
+                                CallStackFrame *Frame, CCValue &Result) {<br>
   // If this is a parameter to an active constexpr function call, perform<br>
   // argument substitution.<br>
   if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) {<br>
-    if (const CCValue *ArgValue =<br>
-          Info.getCallValue(CallIndex, PVD->getFunctionScopeIndex())) {<br>
-      Result = *ArgValue;<br>
-      return true;<br>
-    }<br>
-    return false;<br>
+    if (!Frame || !Frame->Arguments)<br>
+      return false;<br>
+    Result = Frame->Arguments[PVD->getFunctionScopeIndex()];<br>
+    return true;<br>
   }<br>
<br>
   const Expr *Init = VD->getAnyInitializer();<br>
@@ -436,7 +399,7 @@<br>
     return false;<br>
<br>
   if (APValue *V = VD->getEvaluatedValue()) {<br>
-    Result = CCValue(*V, CCValue::NoCallIndex);<br>
+    Result = CCValue(*V, CCValue::GlobalValue());<br>
     return !Result.isUninit();<br>
   }<br>
<br>
@@ -466,7 +429,7 @@<br>
 bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type,<br>
                                     const LValue &LVal, CCValue &RVal) {<br>
   const Expr *Base = LVal.Base;<br>
-  unsigned CallIndex = LVal.CallIndex;<br>
+  CallStackFrame *Frame = LVal.Frame;<br>
<br>
   // FIXME: Indirection through a null pointer deserves a diagnostic.<br>
   if (!Base)<br>
@@ -498,8 +461,7 @@<br>
     // them are not permitted.<br>
     const VarDecl *VD = dyn_cast<VarDecl>(D);<br>
     if (!VD || !(IsConstNonVolatile(VD->getType()) || isa<ParmVarDecl>(VD)) ||<br>
-        !Type->isLiteralType() ||<br>
-        !EvaluateVarDeclInit(Info, VD, CallIndex, RVal))<br>
+        !Type->isLiteralType() || !EvaluateVarDeclInit(Info, VD, Frame, RVal))<br>
       return false;<br>
<br>
     if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue())<br>
@@ -513,17 +475,14 @@<br>
     if (!RVal.getLValueOffset().isZero())<br>
       return false;<br>
     Base = RVal.getLValueBase();<br>
-    CallIndex = RVal.getLValueCallIndex();<br>
+    Frame = RVal.getLValueFrame();<br>
   }<br>
<br>
-  // If this is an lvalue expression with a nontrivial initializer, grab the<br>
-  // value from the relevant stack frame, if the object is still in scope.<br>
-  if (isa<MaterializeTemporaryExpr>(Base)) {<br>
-    if (CallStackFrame *Frame = Info.getStackFrame(CallIndex)) {<br>
-      RVal = Frame->Temporaries[Base];<br>
-      return true;<br>
-    }<br>
-    return false;<br>
+  // If this is a temporary expression with a nontrivial initializer, grab the<br>
+  // value from the relevant stack frame.<br>
+  if (Frame) {<br>
+    RVal = Frame->Temporaries[Base];<br>
+    return true;<br>
   }<br>
<br>
   // In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the<br>
@@ -726,6 +685,14 @@<br>
<br>
   RetTy ValueInitialization(const Expr *E) { return DerivedError(E); }<br>
<br>
+  bool MakeTemporary(const Expr *Key, const Expr *Value, LValue &Result) {<br>
+    if (!Evaluate(Info.CurrentCall->Temporaries[Key], Info, Value))<br>
+      return false;<br>
+    Result.Base = Key;<br>
+    Result.Offset = CharUnits::Zero();<br>
+    Result.Frame = Info.CurrentCall;<br>
+    return true;<br>
+  }<br>
 public:<br>
   ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {}<br>
<br>
@@ -813,7 +780,8 @@<br>
     llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());<br>
<br>
     if (Body && Definition->isConstexpr() && !Definition->isInvalidDecl() &&<br>
-        HandleFunctionCall(Args, Body, Info, Result))<br>
+        HandleFunctionCall(Args, Body, Info, Result) &&<br>
+        CheckConstantExpression(Result))<br>
       return DerivedSuccess(Result, E);<br>
<br>
     return DerivedError(E);<br>
@@ -881,7 +849,6 @@<br>
 // following types:<br>
 //  * DeclRefExpr<br>
 //  * MemberExpr for a static member<br>
-//  * MaterializeTemporaryExpr<br>
 //  * CompoundLiteralExpr in C<br>
 //  * StringLiteral<br>
 //  * PredefinedExpr<br>
@@ -889,7 +856,9 @@<br>
 //  * AddrLabelExpr<br>
 //  * BlockExpr<br>
 //  * CallExpr for a MakeStringConstant builtin<br>
-// plus an offset in bytes.<br>
+// plus an offset in bytes. It can also produce lvalues referring to locals. In<br>
+// that case, the Frame will point to a stack frame, and the Expr is used as a<br>
+// key to find the relevant temporary's value.<br>
 //===----------------------------------------------------------------------===//<br>
 namespace {<br>
 class LValueExprEvaluator<br>
@@ -900,7 +869,7 @@<br>
   bool Success(const Expr *E) {<br>
     Result.Base = E;<br>
     Result.Offset = CharUnits::Zero();<br>
-    Result.CallIndex = Info.getCurrentCallIndex();<br>
+    Result.Frame = 0;<br>
     return true;<br>
   }<br>
 public:<br>
@@ -967,11 +936,18 @@<br>
 }<br>
<br>
 bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {<br>
-  if (!VD->getType()->isReferenceType())<br>
+  if (!VD->getType()->isReferenceType()) {<br>
+    if (isa<ParmVarDecl>(VD)) {<br>
+      Result.Base = E;<br>
+      Result.Offset = CharUnits::Zero();<br>
+      Result.Frame = Info.CurrentCall;<br>
+      return true;<br>
+    }<br>
     return Success(E);<br>
+  }<br>
<br>
   CCValue V;<br>
-  if (EvaluateVarDeclInit(Info, VD, Info.getCurrentCallIndex(), V))<br>
+  if (EvaluateVarDeclInit(Info, VD, Info.CurrentCall, V))<br>
     return Success(V, E);<br>
<br>
   return Error(E);<br>
@@ -979,9 +955,7 @@<br>
<br>
 bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(<br>
     const MaterializeTemporaryExpr *E) {<br>
-  if (!Evaluate(Info.CurrentCall->Temporaries[E], Info, E->GetTemporaryExpr()))<br>
-    return false;<br>
-  return Success(E);<br>
+  return MakeTemporary(E, E->GetTemporaryExpr(), Result);<br>
 }<br>
<br>
 bool<br>
@@ -1066,7 +1040,7 @@<br>
   bool Success(const Expr *E) {<br>
     Result.Base = E;<br>
     Result.Offset = CharUnits::Zero();<br>
-    Result.CallIndex = Info.getCurrentCallIndex();<br>
+    Result.Frame = 0;<br>
     return true;<br>
   }<br>
 public:<br>
@@ -1213,7 +1187,7 @@<br>
       uint64_t N = Value.getInt().extOrTrunc(Size).getZExtValue();<br>
       Result.Base = 0;<br>
       Result.Offset = CharUnits::fromQuantity(N);<br>
-      Result.CallIndex = CCValue::NoCallIndex;<br>
+      Result.Frame = 0;<br>
       return true;<br>
     } else {<br>
       // Cast is of an lvalue, no need to change value.<br>
@@ -1839,7 +1813,7 @@<br>
   }<br>
<br>
   return IsGlobalLValue(A.getLValueBase()) ||<br>
-         A.getLValueCallIndex() == B.getLValueCallIndex();<br>
+         A.getLValueFrame() == B.getLValueFrame();<br>
 }<br>
<br>
 bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {<br>
@@ -3124,7 +3098,7 @@<br>
                                       const ASTContext &Ctx) const {<br>
   EvalResult Scratch;<br>
   return EvaluateAsRValue(Scratch, Ctx) &&<br>
-         HandleConversionToBool(CCValue(Scratch.Val, CCValue::NoCallIndex),<br>
+         HandleConversionToBool(CCValue(Scratch.Val, CCValue::GlobalValue()),<br>
                                 Result);<br>
 }<br>
<br>
@@ -3155,9 +3129,7 @@<br>
   EvalInfo Info(Ctx, Result);<br>
<br>
   LValue LV;<br>
-  // Don't allow references to out-of-scope function parameters to escape.<br>
-  if (EvaluateLValue(this, LV, Info) &&<br>
-      (!IsParamLValue(LV.Base) || LV.CallIndex == CCValue::NoCallIndex)) {<br>
+  if (EvaluateLValue(this, LV, Info)) {<br>
     Result.Val = APValue(LV.Base, LV.Offset);<br>
     return true;<br>
   }<br>
<br>
Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp<br>
URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=143463&r1=143462&r2=143463&view=diff" target="_blank">http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=143463&r1=143462&r2=143463&view=diff</a><br>

==============================================================================<br>
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)<br>
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Tue Nov  1 11:57:24 2011<br>
@@ -102,6 +102,14 @@<br>
   constexpr int n1 = MaybeReturnJunk(false, 0); // ok<br>
   constexpr int n2 = MaybeReturnJunk(true, 0); // expected-error {{must be initialized by a constant expression}}<br>
<br>
+  constexpr const int MaybeReturnNonstaticRef(bool b, const int a) {<br>
+    // If ObscureTheTruth returns a reference to 'a', the result is not a<br>
+    // constant expression even though 'a' is still in scope.<br>
+    return ObscureTheTruth(b ? a : k);<br>
+  }<br>
+  constexpr int n1a = MaybeReturnJunk(false, 0); // ok<br>
+  constexpr int n2a = MaybeReturnJunk(true, 0); // expected-error {{must be initialized by a constant expression}}<br>
+<br></blockquote><div><br>
Is it your intention to use  MaybeReturnJunk   and not the newly introduced   MaybeReturnNonstaticRef   here ?<br> </div><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">

   constexpr int InternalReturnJunk(int n) {<br>
     // FIXME: We should reject this: it never produces a constant expression.<br>
     return MaybeReturnJunk(true, n);<br>
<br>
</blockquote></div><br>--Matthieu<br>