C++11 generalized constant expression handling: evaluation support for
materialized temporaries.
llvm-svn: 143335
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index f4c9a83..9e1e75d 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -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,44 +77,12 @@
}
};
- struct EvalInfo {
- const ASTContext &Ctx;
-
- /// EvalStatus - Contains information about the evaluation.
- Expr::EvalStatus &EvalStatus;
-
- /// CurrentCall - The top of the constexpr call stack.
- const CallStackFrame *CurrentCall;
-
- /// NumCalls - The number of calls we've evaluated so far.
- unsigned NumCalls;
-
- /// CallStackDepth - The number of calls in the call stack right now.
- unsigned CallStackDepth;
-
- typedef llvm::DenseMap<const OpaqueValueExpr*, CCValue> MapTy;
- MapTy OpaqueValues;
- 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;
+ CallStackFrame *Caller;
/// ParmBindings - Parameter bindings for this function call, indexed by
/// parameters' function scope indices.
@@ -124,29 +93,84 @@
/// detect when the parameter is no longer in scope.
unsigned CallIndex;
- 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;
- }
+ 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();
};
- unsigned EvalInfo::getCurrentCallIndex() const {
- return CurrentCall ? CurrentCall->CallIndex : CCValue::NoCallIndex;
+ struct EvalInfo {
+ const ASTContext &Ctx;
+
+ /// EvalStatus - Contains information about the evaluation.
+ Expr::EvalStatus &EvalStatus;
+
+ /// CurrentCall - The top of the constexpr call stack.
+ CallStackFrame *CurrentCall;
+
+ /// NumCalls - The number of calls we've evaluated so far.
+ unsigned NumCalls;
+
+ /// CallStackDepth - The number of calls in the call stack right now.
+ 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;
+ }
+
+ const LangOptions &getLangOpts() { return Ctx.getLangOptions(); }
+ };
+
+ CallStackFrame::CallStackFrame(EvalInfo &Info, const CCValue *Arguments)
+ : Info(Info), Caller(Info.CurrentCall), Arguments(Arguments),
+ CallIndex(Info.NumCalls++) {
+ Info.CurrentCall = this;
+ ++Info.CallStackDepth;
+ }
+
+ CallStackFrame::~CallStackFrame() {
+ assert(Info.CurrentCall == this && "calls retired out of order");
+ --Info.CallStackDepth;
+ 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 {
- 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++?");