<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>