[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