[cfe-commits] r143463 - in /cfe/trunk: lib/AST/ExprConstant.cpp test/SemaCXX/constant-expression-cxx11.cpp
Richard Smith
richard-llvm at metafoo.co.uk
Tue Nov 1 09:57:24 PDT 2011
Author: rsmith
Date: Tue Nov 1 11:57:24 2011
New Revision: 143463
URL: http://llvm.org/viewvc/llvm-project?rev=143463&view=rev
Log:
Implement C++11 'constexpr calls must return constant expressions' rule, and
perform the code simplifications this rule allows.
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=143463&r1=143462&r2=143463&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Tue Nov 1 11:57:24 2011
@@ -28,8 +28,6 @@
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
@@ -53,27 +51,27 @@
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;
+ /// If the value is a reference or pointer into a parameter or temporary,
+ /// this is the corresponding call stack frame.
+ CallStackFrame *CallFrame;
public:
+ struct GlobalValue {};
+
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)0 };
+ CCValue(const CCValue &V) : APValue(V), CallFrame(V.CallFrame) {}
+ CCValue(const Expr *B, const CharUnits &O, CallStackFrame *F) :
+ APValue(B, O), CallFrame(F) {}
+ CCValue(const APValue &V, GlobalValue) :
+ APValue(V), CallFrame(0) {}
- unsigned getLValueCallIndex() const {
+ CallStackFrame *getLValueFrame() const {
assert(getKind() == LValue);
- return CallIndex;
+ return CallFrame;
}
};
@@ -88,11 +86,6 @@
/// 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.
@@ -131,10 +124,6 @@
: 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;
@@ -145,8 +134,7 @@
};
CallStackFrame::CallStackFrame(EvalInfo &Info, const CCValue *Arguments)
- : Info(Info), Caller(Info.CurrentCall), Arguments(Arguments),
- CallIndex(Info.NumCalls++) {
+ : Info(Info), Caller(Info.CurrentCall), Arguments(Arguments) {
Info.CurrentCall = this;
++Info.CallStackDepth;
}
@@ -157,23 +145,6 @@
Info.CurrentCall = Caller;
}
- 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 {
- if (CallIndex == 0)
- return 0;
- if (CallStackFrame *Frame = getStackFrame(CallIndex))
- return Frame->Arguments + ArgIndex;
- return 0;
- }
-
struct ComplexValue {
private:
bool IsInt;
@@ -217,21 +188,21 @@
struct LValue {
const Expr *Base;
CharUnits Offset;
- unsigned CallIndex;
+ CallStackFrame *Frame;
const Expr *getLValueBase() const { return Base; }
CharUnits &getLValueOffset() { return Offset; }
const CharUnits &getLValueOffset() const { return Offset; }
- unsigned getLValueCallIndex() const { return CallIndex; }
+ CallStackFrame *getLValueFrame() const { return Frame; }
void moveInto(CCValue &V) const {
- V = CCValue(Base, Offset, CallIndex);
+ V = CCValue(Base, Offset, Frame);
}
void setFrom(const CCValue &V) {
assert(V.isLValue());
Base = V.getLValueBase();
Offset = V.getLValueOffset();
- CallIndex = V.getLValueCallIndex();
+ Frame = V.getLValueFrame();
}
};
}
@@ -269,12 +240,6 @@
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) {
@@ -419,16 +384,14 @@
/// Try to evaluate the initializer for a variable declaration.
static bool EvaluateVarDeclInit(EvalInfo &Info, const VarDecl *VD,
- unsigned CallIndex, CCValue &Result) {
+ CallStackFrame *Frame, CCValue &Result) {
// If this is a parameter to an active constexpr function call, perform
// argument substitution.
if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(VD)) {
- if (const CCValue *ArgValue =
- Info.getCallValue(CallIndex, PVD->getFunctionScopeIndex())) {
- Result = *ArgValue;
- return true;
- }
- return false;
+ if (!Frame || !Frame->Arguments)
+ return false;
+ Result = Frame->Arguments[PVD->getFunctionScopeIndex()];
+ return true;
}
const Expr *Init = VD->getAnyInitializer();
@@ -436,7 +399,7 @@
return false;
if (APValue *V = VD->getEvaluatedValue()) {
- Result = CCValue(*V, CCValue::NoCallIndex);
+ Result = CCValue(*V, CCValue::GlobalValue());
return !Result.isUninit();
}
@@ -466,7 +429,7 @@
bool HandleLValueToRValueConversion(EvalInfo &Info, QualType Type,
const LValue &LVal, CCValue &RVal) {
const Expr *Base = LVal.Base;
- unsigned CallIndex = LVal.CallIndex;
+ CallStackFrame *Frame = LVal.Frame;
// FIXME: Indirection through a null pointer deserves a diagnostic.
if (!Base)
@@ -498,8 +461,7 @@
// them are not permitted.
const VarDecl *VD = dyn_cast<VarDecl>(D);
if (!VD || !(IsConstNonVolatile(VD->getType()) || isa<ParmVarDecl>(VD)) ||
- !Type->isLiteralType() ||
- !EvaluateVarDeclInit(Info, VD, CallIndex, RVal))
+ !Type->isLiteralType() || !EvaluateVarDeclInit(Info, VD, Frame, RVal))
return false;
if (isa<ParmVarDecl>(VD) || !VD->getAnyInitializer()->isLValue())
@@ -513,17 +475,14 @@
if (!RVal.getLValueOffset().isZero())
return false;
Base = RVal.getLValueBase();
- CallIndex = RVal.getLValueCallIndex();
+ Frame = RVal.getLValueFrame();
}
- // 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;
+ // If this is a temporary expression with a nontrivial initializer, grab the
+ // value from the relevant stack frame.
+ if (Frame) {
+ RVal = Frame->Temporaries[Base];
+ return true;
}
// In C99, a CompoundLiteralExpr is an lvalue, and we defer evaluating the
@@ -726,6 +685,14 @@
RetTy ValueInitialization(const Expr *E) { return DerivedError(E); }
+ bool MakeTemporary(const Expr *Key, const Expr *Value, LValue &Result) {
+ if (!Evaluate(Info.CurrentCall->Temporaries[Key], Info, Value))
+ return false;
+ Result.Base = Key;
+ Result.Offset = CharUnits::Zero();
+ Result.Frame = Info.CurrentCall;
+ return true;
+ }
public:
ExprEvaluatorBase(EvalInfo &Info) : Info(Info) {}
@@ -813,7 +780,8 @@
llvm::ArrayRef<const Expr*> Args(E->getArgs(), E->getNumArgs());
if (Body && Definition->isConstexpr() && !Definition->isInvalidDecl() &&
- HandleFunctionCall(Args, Body, Info, Result))
+ HandleFunctionCall(Args, Body, Info, Result) &&
+ CheckConstantExpression(Result))
return DerivedSuccess(Result, E);
return DerivedError(E);
@@ -881,7 +849,6 @@
// following types:
// * DeclRefExpr
// * MemberExpr for a static member
-// * MaterializeTemporaryExpr
// * CompoundLiteralExpr in C
// * StringLiteral
// * PredefinedExpr
@@ -889,7 +856,9 @@
// * AddrLabelExpr
// * BlockExpr
// * CallExpr for a MakeStringConstant builtin
-// plus an offset in bytes.
+// plus an offset in bytes. It can also produce lvalues referring to locals. In
+// that case, the Frame will point to a stack frame, and the Expr is used as a
+// key to find the relevant temporary's value.
//===----------------------------------------------------------------------===//
namespace {
class LValueExprEvaluator
@@ -900,7 +869,7 @@
bool Success(const Expr *E) {
Result.Base = E;
Result.Offset = CharUnits::Zero();
- Result.CallIndex = Info.getCurrentCallIndex();
+ Result.Frame = 0;
return true;
}
public:
@@ -967,11 +936,18 @@
}
bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
- if (!VD->getType()->isReferenceType())
+ if (!VD->getType()->isReferenceType()) {
+ if (isa<ParmVarDecl>(VD)) {
+ Result.Base = E;
+ Result.Offset = CharUnits::Zero();
+ Result.Frame = Info.CurrentCall;
+ return true;
+ }
return Success(E);
+ }
CCValue V;
- if (EvaluateVarDeclInit(Info, VD, Info.getCurrentCallIndex(), V))
+ if (EvaluateVarDeclInit(Info, VD, Info.CurrentCall, V))
return Success(V, E);
return Error(E);
@@ -979,9 +955,7 @@
bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
const MaterializeTemporaryExpr *E) {
- if (!Evaluate(Info.CurrentCall->Temporaries[E], Info, E->GetTemporaryExpr()))
- return false;
- return Success(E);
+ return MakeTemporary(E, E->GetTemporaryExpr(), Result);
}
bool
@@ -1066,7 +1040,7 @@
bool Success(const Expr *E) {
Result.Base = E;
Result.Offset = CharUnits::Zero();
- Result.CallIndex = Info.getCurrentCallIndex();
+ Result.Frame = 0;
return true;
}
public:
@@ -1213,7 +1187,7 @@
uint64_t N = Value.getInt().extOrTrunc(Size).getZExtValue();
Result.Base = 0;
Result.Offset = CharUnits::fromQuantity(N);
- Result.CallIndex = CCValue::NoCallIndex;
+ Result.Frame = 0;
return true;
} else {
// Cast is of an lvalue, no need to change value.
@@ -1839,7 +1813,7 @@
}
return IsGlobalLValue(A.getLValueBase()) ||
- A.getLValueCallIndex() == B.getLValueCallIndex();
+ A.getLValueFrame() == B.getLValueFrame();
}
bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
@@ -3124,7 +3098,7 @@
const ASTContext &Ctx) const {
EvalResult Scratch;
return EvaluateAsRValue(Scratch, Ctx) &&
- HandleConversionToBool(CCValue(Scratch.Val, CCValue::NoCallIndex),
+ HandleConversionToBool(CCValue(Scratch.Val, CCValue::GlobalValue()),
Result);
}
@@ -3155,9 +3129,7 @@
EvalInfo Info(Ctx, Result);
LValue LV;
- // Don't allow references to out-of-scope function parameters to escape.
- if (EvaluateLValue(this, LV, Info) &&
- (!IsParamLValue(LV.Base) || LV.CallIndex == CCValue::NoCallIndex)) {
+ if (EvaluateLValue(this, LV, Info)) {
Result.Val = APValue(LV.Base, LV.Offset);
return true;
}
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=143463&r1=143462&r2=143463&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Tue Nov 1 11:57:24 2011
@@ -102,6 +102,14 @@
constexpr int n1 = MaybeReturnJunk(false, 0); // ok
constexpr int n2 = MaybeReturnJunk(true, 0); // expected-error {{must be initialized by a constant expression}}
+ constexpr const int MaybeReturnNonstaticRef(bool b, const int a) {
+ // If ObscureTheTruth returns a reference to 'a', the result is not a
+ // constant expression even though 'a' is still in scope.
+ return ObscureTheTruth(b ? a : k);
+ }
+ constexpr int n1a = MaybeReturnJunk(false, 0); // ok
+ constexpr int n2a = 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);
More information about the cfe-commits
mailing list