aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-02-15 02:18:13 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-02-15 02:18:13 +0000
commit83587db1bda97f45d2b5a4189e584e2a18be511a (patch)
treece60b67476bb535994126ecd8ff1ba2a85f00000
parent1d6cc6a44182ef03a373ecd61505042eca3af906 (diff)
Implement DR1454. This allows all intermediate results in constant expressions
to be core constant expressions (including pointers and references to temporaries), and makes constexpr calculations Turing-complete. A Turing machine simulator is included as a testcase. This opens up the possibilty of removing CCValue entirely, and removing some copies from the constant evaluator in the process, but that cleanup is not part of this change. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@150557 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/AST/APValue.h15
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td8
-rw-r--r--lib/AST/APValue.cpp19
-rw-r--r--lib/AST/ExprConstant.cpp414
-rw-r--r--test/CXX/expr/expr.const/p2-0x.cpp26
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp39
-rw-r--r--test/SemaCXX/constexpr-turing.cpp55
7 files changed, 373 insertions, 203 deletions
diff --git a/include/clang/AST/APValue.h b/include/clang/AST/APValue.h
index f361f0f5c8..f687fb7beb 100644
--- a/include/clang/AST/APValue.h
+++ b/include/clang/AST/APValue.h
@@ -138,14 +138,14 @@ public:
APValue(const APValue &RHS) : Kind(Uninitialized) {
*this = RHS;
}
- APValue(LValueBase B, const CharUnits &O, NoLValuePath N)
+ APValue(LValueBase B, const CharUnits &O, NoLValuePath N, unsigned CallIndex)
: Kind(Uninitialized) {
- MakeLValue(); setLValue(B, O, N);
+ MakeLValue(); setLValue(B, O, N, CallIndex);
}
APValue(LValueBase B, const CharUnits &O, ArrayRef<LValuePathEntry> Path,
- bool OnePastTheEnd)
+ bool OnePastTheEnd, unsigned CallIndex)
: Kind(Uninitialized) {
- MakeLValue(); setLValue(B, O, Path, OnePastTheEnd);
+ MakeLValue(); setLValue(B, O, Path, OnePastTheEnd, CallIndex);
}
APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(Uninitialized) {
MakeArray(InitElts, Size);
@@ -246,6 +246,7 @@ public:
bool isLValueOnePastTheEnd() const;
bool hasLValuePath() const;
ArrayRef<LValuePathEntry> getLValuePath() const;
+ unsigned getLValueCallIndex() const;
APValue &getVectorElt(unsigned I) {
assert(isVector() && "Invalid accessor");
@@ -365,9 +366,11 @@ public:
((ComplexAPFloat*)(char*)Data)->Real = R;
((ComplexAPFloat*)(char*)Data)->Imag = I;
}
- void setLValue(LValueBase B, const CharUnits &O, NoLValuePath);
+ void setLValue(LValueBase B, const CharUnits &O, NoLValuePath,
+ unsigned CallIndex);
void setLValue(LValueBase B, const CharUnits &O,
- ArrayRef<LValuePathEntry> Path, bool OnePastTheEnd);
+ ArrayRef<LValuePathEntry> Path, bool OnePastTheEnd,
+ unsigned CallIndex);
void setUnion(const FieldDecl *Field, const APValue &Value) {
assert(isUnion() && "Invalid accessor");
((UnionData*)(char*)Data)->Field = Field;
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index f2154fb4e9..2d6e498fbb 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -35,9 +35,7 @@ def note_constexpr_nonliteral : Note<
"non-literal type %0 cannot be used in a constant expression">;
def note_constexpr_non_global : Note<
"%select{pointer|reference}0 to %select{|subobject of }1"
- "%select{temporary|%4}2 %select{is not a constant expression|"
- "cannot be returned from a constexpr function|"
- "cannot be used to initialize a member in a constant expression}3">;
+ "%select{temporary|%3}2 is not a constant expression">;
def note_constexpr_array_index : Note<"cannot refer to element %0 of "
"%select{array of %2 elements|non-array object}1 in a constant expression">;
def note_constexpr_float_arithmetic : Note<
@@ -76,6 +74,10 @@ def note_constexpr_void_comparison : Note<
def note_constexpr_temporary_here : Note<"temporary created here">;
def note_constexpr_depth_limit_exceeded : Note<
"constexpr evaluation exceeded maximum depth of %0 calls">;
+def note_constexpr_call_limit_exceeded : Note<
+ "constexpr evaluation hit maximum call limit">;
+def note_constexpr_lifetime_ended : Note<
+ "read of %select{temporary|variable}0 whose lifetime has ended">;
def note_constexpr_ltor_volatile_type : Note<
"read of volatile-qualified type %0 is not allowed in a constant expression">;
def note_constexpr_ltor_volatile_obj : Note<
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp
index b8942c3310..4e17d3b69e 100644
--- a/lib/AST/APValue.cpp
+++ b/lib/AST/APValue.cpp
@@ -28,6 +28,7 @@ namespace {
llvm::PointerIntPair<APValue::LValueBase, 1, bool> BaseAndIsOnePastTheEnd;
CharUnits Offset;
unsigned PathLength;
+ unsigned CallIndex;
};
}
@@ -166,9 +167,10 @@ const APValue &APValue::operator=(const APValue &RHS) {
else if (isLValue()) {
if (RHS.hasLValuePath())
setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), RHS.getLValuePath(),
- RHS.isLValueOnePastTheEnd());
+ RHS.isLValueOnePastTheEnd(), RHS.getLValueCallIndex());
else
- setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath());
+ setLValue(RHS.getLValueBase(), RHS.getLValueOffset(), NoLValuePath(),
+ RHS.getLValueCallIndex());
} else if (isArray()) {
for (unsigned I = 0, N = RHS.getArrayInitializedElts(); I != N; ++I)
getArrayInitializedElt(I) = RHS.getArrayInitializedElt(I);
@@ -525,22 +527,31 @@ ArrayRef<APValue::LValuePathEntry> APValue::getLValuePath() const {
return ArrayRef<LValuePathEntry>(LVal.getPath(), LVal.PathLength);
}
-void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath) {
+unsigned APValue::getLValueCallIndex() const {
+ assert(isLValue() && "Invalid accessor");
+ return ((const LV*)(const char*)Data)->CallIndex;
+}
+
+void APValue::setLValue(LValueBase B, const CharUnits &O, NoLValuePath,
+ unsigned CallIndex) {
assert(isLValue() && "Invalid accessor");
LV &LVal = *((LV*)(char*)Data);
LVal.BaseAndIsOnePastTheEnd.setPointer(B);
LVal.BaseAndIsOnePastTheEnd.setInt(false);
LVal.Offset = O;
+ LVal.CallIndex = CallIndex;
LVal.resizePath((unsigned)-1);
}
void APValue::setLValue(LValueBase B, const CharUnits &O,
- ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd) {
+ ArrayRef<LValuePathEntry> Path, bool IsOnePastTheEnd,
+ unsigned CallIndex) {
assert(isLValue() && "Invalid accessor");
LV &LVal = *((LV*)(char*)Data);
LVal.BaseAndIsOnePastTheEnd.setPointer(B);
LVal.BaseAndIsOnePastTheEnd.setInt(IsOnePastTheEnd);
LVal.Offset = O;
+ LVal.CallIndex = CallIndex;
LVal.resizePath(Path.size());
memcpy(LVal.getPath(), Path.data(), Path.size() * sizeof(LValuePathEntry));
}
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 6ad9938906..9454895c75 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -51,26 +51,14 @@ using namespace clang;
using llvm::APSInt;
using llvm::APFloat;
-/// 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
-/// expression.
-///
-/// If an expression could be evaluated, it is still possible it is not a C
-/// "integer constant expression" or constant expression. If not, this struct
-/// captures information about how and why not.
-///
-/// One bit of information passed *into* the request for constant folding
-/// indicates whether the subexpression is "evaluated" or not according to C
-/// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
-/// evaluate the expression regardless of what the RHS is, but C only allows
-/// certain things in certain situations.
+static bool IsGlobalLValue(APValue::LValueBase B);
+
namespace {
struct LValue;
struct CallStackFrame;
struct EvalInfo;
- QualType getType(APValue::LValueBase B) {
+ static QualType getType(APValue::LValueBase B) {
if (!B) return QualType();
if (const ValueDecl *D = B.dyn_cast<const ValueDecl*>())
return D->getType();
@@ -79,6 +67,7 @@ namespace {
/// Get an LValue path entry, which is known to not be an array index, as a
/// field or base class.
+ static
APValue::BaseOrMemberType getAsBaseOrMember(APValue::LValuePathEntry E) {
APValue::BaseOrMemberType Value;
Value.setFromOpaqueValue(E.BaseOrMember);
@@ -87,17 +76,17 @@ namespace {
/// Get an LValue path entry, which is known to not be an array index, as a
/// field declaration.
- const FieldDecl *getAsField(APValue::LValuePathEntry E) {
+ static const FieldDecl *getAsField(APValue::LValuePathEntry E) {
return dyn_cast<FieldDecl>(getAsBaseOrMember(E).getPointer());
}
/// Get an LValue path entry, which is known to not be an array index, as a
/// base class declaration.
- const CXXRecordDecl *getAsBaseClass(APValue::LValuePathEntry E) {
+ static const CXXRecordDecl *getAsBaseClass(APValue::LValuePathEntry E) {
return dyn_cast<CXXRecordDecl>(getAsBaseOrMember(E).getPointer());
}
/// Determine whether this LValue path entry for a base class names a virtual
/// base class.
- bool isVirtualBaseClass(APValue::LValuePathEntry E) {
+ static bool isVirtualBaseClass(APValue::LValuePathEntry E) {
return getAsBaseOrMember(E).getInt();
}
@@ -267,9 +256,6 @@ namespace {
class CCValue : public APValue {
typedef llvm::APSInt APSInt;
typedef llvm::APFloat APFloat;
- /// If the value is a reference or pointer into a parameter or temporary,
- /// this is the corresponding call stack frame.
- CallStackFrame *CallFrame;
/// If the value is a reference or pointer, this is a description of how the
/// subobject was specified.
SubobjectDesignator Designator;
@@ -282,22 +268,19 @@ namespace {
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), CallFrame(V.CallFrame) {}
- CCValue(LValueBase B, const CharUnits &O, CallStackFrame *F,
+ CCValue(const CCValue &V) : APValue(V), Designator(V.Designator) {}
+ CCValue(LValueBase B, const CharUnits &O, unsigned I,
const SubobjectDesignator &D) :
- APValue(B, O, APValue::NoLValuePath()), CallFrame(F), Designator(D) {}
+ APValue(B, O, APValue::NoLValuePath(), I), Designator(D) {}
CCValue(ASTContext &Ctx, const APValue &V, GlobalValue) :
- APValue(V), CallFrame(0), Designator(Ctx, V) {}
+ APValue(V), Designator(Ctx, V) {
+ }
CCValue(const ValueDecl *D, bool IsDerivedMember,
ArrayRef<const CXXRecordDecl*> Path) :
APValue(D, IsDerivedMember, Path) {}
CCValue(const AddrLabelExpr* LHSExpr, const AddrLabelExpr* RHSExpr) :
APValue(LHSExpr, RHSExpr) {}
- CallStackFrame *getLValueFrame() const {
- assert(getKind() == LValue);
- return CallFrame;
- }
SubobjectDesignator &getLValueDesignator() {
assert(getKind() == LValue);
return Designator;
@@ -305,6 +288,21 @@ namespace {
const SubobjectDesignator &getLValueDesignator() const {
return const_cast<CCValue*>(this)->getLValueDesignator();
}
+ APValue toAPValue() const {
+ if (!isLValue())
+ return *this;
+
+ if (Designator.Invalid) {
+ // This is not a core constant expression. An appropriate diagnostic
+ // will have already been produced.
+ return APValue(getLValueBase(), getLValueOffset(),
+ APValue::NoLValuePath(), getLValueCallIndex());
+ }
+
+ return APValue(getLValueBase(), getLValueOffset(),
+ Designator.Entries, Designator.IsOnePastTheEnd,
+ getLValueCallIndex());
+ }
};
/// A stack frame in the constexpr call stack.
@@ -320,6 +318,9 @@ namespace {
/// Callee - The function which was called.
const FunctionDecl *Callee;
+ /// Index - The call index of this call.
+ unsigned Index;
+
/// This - The binding for the this pointer in this call, if any.
const LValue *This;
@@ -372,6 +373,20 @@ namespace {
}
};
+ /// 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
+ /// expression.
+ ///
+ /// If an expression could be evaluated, it is still possible it is not a C
+ /// "integer constant expression" or constant expression. If not, this struct
+ /// captures information about how and why not.
+ ///
+ /// One bit of information passed *into* the request for constant folding
+ /// indicates whether the subexpression is "evaluated" or not according to C
+ /// rules. For example, the RHS of (0 && foo()) is not evaluated. We can
+ /// evaluate the expression regardless of what the RHS is, but C only allows
+ /// certain things in certain situations.
struct EvalInfo {
ASTContext &Ctx;
@@ -384,6 +399,9 @@ namespace {
/// CallStackDepth - The number of calls in the call stack right now.
unsigned CallStackDepth;
+ /// NextCallIndex - The next call index to assign.
+ unsigned NextCallIndex;
+
typedef llvm::DenseMap<const OpaqueValueExpr*, CCValue> MapTy;
/// OpaqueValues - Values used as the common expression in a
/// BinaryConditionalOperator.
@@ -413,7 +431,8 @@ namespace {
EvalInfo(const ASTContext &C, Expr::EvalStatus &S)
: Ctx(const_cast<ASTContext&>(C)), EvalStatus(S), CurrentCall(0),
- CallStackDepth(0), BottomFrame(*this, SourceLocation(), 0, 0, 0),
+ CallStackDepth(0), NextCallIndex(1),
+ BottomFrame(*this, SourceLocation(), 0, 0, 0),
EvaluatingDecl(0), EvaluatingDeclValue(0), HasActiveDiagnostic(false),
CheckingPotentialConstantExpression(false) {}
@@ -435,6 +454,11 @@ namespace {
// when checking a potential constant expression.
if (CheckingPotentialConstantExpression && CallStackDepth > 1)
return false;
+ if (NextCallIndex == 0) {
+ // NextCallIndex has wrapped around.
+ Diag(Loc, diag::note_constexpr_call_limit_exceeded);
+ return false;
+ }
if (CallStackDepth <= getLangOpts().ConstexprCallDepth)
return true;
Diag(Loc, diag::note_constexpr_depth_limit_exceeded)
@@ -442,6 +466,16 @@ namespace {
return false;
}
+ CallStackFrame *getCallFrame(unsigned CallIndex) {
+ assert(CallIndex && "no call index in getCallFrame");
+ // We will eventually hit BottomFrame, which has Index 1, so Frame can't
+ // be null in this loop.
+ CallStackFrame *Frame = CurrentCall;
+ while (Frame->Index > CallIndex)
+ Frame = Frame->Caller;
+ return (Frame->Index == CallIndex) ? Frame : 0;
+ }
+
private:
/// Add a diagnostic to the diagnostics list.
PartialDiagnostic &addDiag(SourceLocation Loc, diag::kind DiagId) {
@@ -560,7 +594,7 @@ CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
const FunctionDecl *Callee, const LValue *This,
const CCValue *Arguments)
: Info(Info), Caller(Info.CurrentCall), CallLoc(CallLoc), Callee(Callee),
- This(This), Arguments(Arguments) {
+ Index(Info.NextCallIndex++), This(This), Arguments(Arguments) {
Info.CurrentCall = this;
++Info.CallStackDepth;
}
@@ -591,10 +625,11 @@ static void describeCall(CallStackFrame *Frame, llvm::raw_ostream &Out) {
if (!Arg.isLValue() || Arg.getLValueDesignator().Invalid)
Arg.printPretty(Out, Frame->Info.Ctx, Param->getType());
else {
- // Deliberately slice off the frame to form an APValue we can print.
+ // Convert the CCValue to an APValue without checking for constantness.
APValue Value(Arg.getLValueBase(), Arg.getLValueOffset(),
Arg.getLValueDesignator().Entries,
- Arg.getLValueDesignator().IsOnePastTheEnd);
+ Arg.getLValueDesignator().IsOnePastTheEnd,
+ Arg.getLValueCallIndex());
Value.printPretty(Out, Frame->Info.Ctx, Param->getType());
}
@@ -679,31 +714,31 @@ namespace {
struct LValue {
APValue::LValueBase Base;
CharUnits Offset;
- CallStackFrame *Frame;
+ unsigned CallIndex;
SubobjectDesignator Designator;
const APValue::LValueBase getLValueBase() const { return Base; }
CharUnits &getLValueOffset() { return Offset; }
const CharUnits &getLValueOffset() const { return Offset; }
- CallStackFrame *getLValueFrame() const { return Frame; }
+ unsigned getLValueCallIndex() const { return CallIndex; }
SubobjectDesignator &getLValueDesignator() { return Designator; }
const SubobjectDesignator &getLValueDesignator() const { return Designator;}
void moveInto(CCValue &V) const {
- V = CCValue(Base, Offset, Frame, Designator);
+ V = CCValue(Base, Offset, CallIndex, Designator);
}
void setFrom(const CCValue &V) {
assert(V.isLValue());
Base = V.getLValueBase();
Offset = V.getLValueOffset();
- Frame = V.getLValueFrame();
+ CallIndex = V.getLValueCallIndex();
Designator = V.getLValueDesignator();
}
- void set(APValue::LValueBase B, CallStackFrame *F = 0) {
+ void set(APValue::LValueBase B, unsigned I = 0) {
Base = B;
Offset = CharUnits::Zero();
- Frame = F;
+ CallIndex = I;
Designator = SubobjectDesignator(getType(B));
}
@@ -852,11 +887,10 @@ namespace {
}
static bool Evaluate(CCValue &Result, EvalInfo &Info, const Expr *E);
-static bool EvaluateConstantExpression(APValue &Result, EvalInfo &Info,
- const LValue &This, const Expr *E,
- CheckConstantExpressionKind CCEK
- = CCEK_Constant,
- bool AllowNonLiteralTypes = false);
+static bool EvaluateInPlace(APValue &Result, EvalInfo &Info,
+ const LValue &This, const Expr *E,
+ CheckConstantExpressionKind CCEK = CCEK_Constant,
+ bool AllowNonLiteralTypes = false);
static bool EvaluateLValue(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluatePointer(const Expr *E, LValue &Result, EvalInfo &Info);
static bool EvaluateMemberPointer(const Expr *E, MemberPtr &Result,
@@ -928,47 +962,43 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
}
}
+static void NoteLValueLocation(EvalInfo &Info, APValue::LValueBase Base) {
+ assert(Base && "no location for a null lvalue");
+ const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
+ if (VD)
+ Info.Note(VD->getLocation(), diag::note_declared_at);
+ else
+ Info.Note(Base.dyn_cast<const Expr*>()->getExprLoc(),
+ diag::note_constexpr_temporary_here);
+}
+
/// Check that this reference or pointer core constant expression is a valid
/// value for an address or reference constant expression. Type T should be
/// either LValue or CCValue. Return true if we can fold this expression,
/// whether or not it's a constant expression.
-template<typename T>
-static bool CheckLValueConstantExpression(EvalInfo &Info, const Expr *E,
- const T &LVal, APValue &Value,
- CheckConstantExpressionKind CCEK) {
+static bool CheckLValueConstantExpression(EvalInfo &Info, SourceLocation Loc,
+ QualType Type, const LValue &LVal) {
+ bool IsReferenceType = Type->isReferenceType();
+
APValue::LValueBase Base = LVal.getLValueBase();
const SubobjectDesignator &Designator = LVal.getLValueDesignator();
if (!IsGlobalLValue(Base)) {
if (Info.getLangOpts().CPlusPlus0x) {
const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
- Info.Diag(E->getExprLoc(), diag::note_constexpr_non_global, 1)
- << E->isGLValue() << !Designator.Entries.empty()
- << !!VD << CCEK << VD;
- if (VD)
- Info.Note(VD->getLocation(), diag::note_declared_at);
- else
- Info.Note(Base.dyn_cast<const Expr*>()->getExprLoc(),
- diag::note_constexpr_temporary_here);
+ Info.Diag(Loc, diag::note_constexpr_non_global, 1)
+ << IsReferenceType << !Designator.Entries.empty()
+ << !!VD << VD;
+ NoteLValueLocation(Info, Base);
} else {
- Info.Diag(E->getExprLoc());
+ Info.Diag(Loc);
}
// Don't allow references to temporaries to escape.
return false;
}
-
- bool IsReferenceType = E->isGLValue();
-
- if (Designator.Invalid) {
- // This is not a core constant expression. An appropriate diagnostic will
- // have already been produced.
- Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
- APValue::NoLValuePath());
- return true;
- }
-
- Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
- Designator.Entries, Designator.IsOnePastTheEnd);
+ assert((Info.CheckingPotentialConstantExpression ||
+ LVal.getLValueCallIndex() == 0) &&
+ "have call index for global lvalue");
// Allow address constant expressions to be past-the-end pointers. This is
// an extension: the standard requires them to point to an object.
@@ -978,20 +1008,16 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, const Expr *E,
// A reference constant expression must refer to an object.
if (!Base) {
// FIXME: diagnostic
- Info.CCEDiag(E->getExprLoc());
+ Info.CCEDiag(Loc);
return true;
}
// Does this refer one past the end of some object?
if (Designator.isOnePastTheEnd()) {
const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
- Info.Diag(E->getExprLoc(), diag::note_constexpr_past_end, 1)
+ Info.Diag(Loc, diag::note_constexpr_past_end, 1)
<< !Designator.Entries.empty() << !!VD << VD;
- if (VD)
- Info.Note(VD->getLocation(), diag::note_declared_at);
- else
- Info.Note(Base.dyn_cast<const Expr*>()->getExprLoc(),
- diag::note_constexpr_temporary_here);
+ NoteLValueLocation(Info, Base);
}
return true;
@@ -1013,18 +1039,58 @@ static bool CheckLiteralType(EvalInfo &Info, const Expr *E) {
}
/// Check that this core constant expression value is a valid value for a
-/// constant expression, and if it is, produce the corresponding constant value.
-/// If not, report an appropriate diagnostic. Does not check that the expression
-/// is of literal type.
-static bool CheckConstantExpression(EvalInfo &Info, const Expr *E,
- const CCValue &CCValue, APValue &Value,
- CheckConstantExpressionKind CCEK
- = CCEK_Constant) {
- if (!CCValue.isLValue()) {
- Value = CCValue;
- return true;
+/// constant expression. If not, report an appropriate diagnostic. Does not
+/// check that the expression is of literal type.
+static bool CheckConstantExpression(EvalInfo &Info, SourceLocation DiagLoc,
+ QualType Type, const APValue &Value) {
+ // Core issue 1454: For a literal constant expression of array or class type,
+ // each subobject of its value shall have been initialized by a constant
+ // expression.
+ if (Value.isArray()) {
+ QualType EltTy = Type->castAsArrayTypeUnsafe()->getElementType();
+ for (unsigned I = 0, N = Value.getArrayInitializedElts(); I != N; ++I) {
+ if (!CheckConstantExpression(Info, DiagLoc, EltTy,
+ Value.getArrayInitializedElt(I)))
+ return false;
+ }
+ if (!Value.hasArrayFiller())
+ return true;
+ return CheckConstantExpression(Info, DiagLoc, EltTy,
+ Value.getArrayFiller());
+ }
+ if (Value.isUnion() && Value.getUnionField()) {
+ return CheckConstantExpression(Info, DiagLoc,
+ Value.getUnionField()->getType(),
+ Value.getUnionValue());
+ }
+ if (Value.isStruct()) {
+ RecordDecl *RD = Type->castAs<RecordType>()->getDecl();
+ if (const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD)) {
+ unsigned BaseIndex = 0;
+ for (CXXRecordDecl::base_class_const_iterator I = CD->bases_begin(),
+ End = CD->bases_end(); I != End; ++I, ++BaseIndex) {
+ if (!CheckConstantExpression(Info, DiagLoc, I->getType(),
+ Value.getStructBase(BaseIndex)))
+ return false;
+ }
+ }
+ for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
+ I != E; ++I) {
+ if (!CheckConstantExpression(Info, DiagLoc, (*I)->getType(),
+ Value.getStructField((*I)->getFieldIndex())))
+ return false;
+ }
+ }
+
+ if (Value.isLValue()) {
+ CCValue Val(Info.Ctx, Value, CCValue::GlobalValue());
+ LValue LVal;
+ LVal.setFrom(Val);
+ return CheckLValueConstantExpression(Info, DiagLoc, Type, LVal);
}
- return CheckLValueConstantExpression(Info, E, CCValue, Value, CCEK);
+
+ // Everything else is fine.
+ return true;
}
const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
@@ -1032,7 +1098,7 @@ const ValueDecl *GetLValueBaseDecl(const LValue &LVal) {
}
static bool IsLiteralLValue(const LValue &Value) {
- return Value.Base.dyn_cast<const Expr*>() && !Value.Frame;
+ return Value.Base.dyn_cast<const Expr*>() && !Value.CallIndex;
}
static bool IsWeakLValue(const LValue &Value) {
@@ -1583,7 +1649,6 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
return false;
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
- CallStackFrame *Frame = LVal.Frame;
SourceLocation Loc = Conv->getExprLoc();
if (!LVal.Base) {
@@ -1592,6 +1657,16 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
return false;
}
+ CallStackFrame *Frame = 0;
+ if (LVal.CallIndex) {
+ Frame = Info.getCallFrame(LVal.CallIndex);
+ if (!Frame) {
+ Info.Diag(Loc, diag::note_constexpr_lifetime_ended, 1) << !Base;
+ NoteLValueLocation(Info, LVal.Base);
+ return false;
+ }
+ }
+
// C++11 DR1311: An lvalue-to-rvalue conversion on a volatile-qualified type
// is not a constant expression (even if the object is non-volatile). We also
// apply this rule to C++98, in order to conform to the expected 'volatile'
@@ -1680,7 +1755,17 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
assert(RVal.getLValueOffset().isZero() &&
"offset for lvalue init of non-reference");
Base = RVal.getLValueBase().get<const Expr*>();
- Frame = RVal.getLValueFrame();
+
+ if (unsigned CallIndex = RVal.getLValueCallIndex()) {
+ Frame = Info.getCallFrame(CallIndex);
+ if (!Frame) {
+ Info.Diag(Loc, diag::note_constexpr_lifetime_ended, 1) << !Base;
+ NoteLValueLocation(Info, RVal.getLValueBase());
+ return false;
+ }
+ } else {
+ Frame = 0;
+ }
}
// Volatile temporary objects cannot be read in constant expressions.
@@ -1896,7 +1981,7 @@ enum EvalStmtResult {
}
// Evaluate a statement.
-static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
+static EvalStmtResult EvaluateStmt(CCValue &Result, EvalInfo &Info,
const Stmt *S) {
switch (S->getStmtClass()) {
default:
@@ -1907,11 +1992,8 @@ static EvalStmtResult EvaluateStmt(APValue &Result, EvalInfo &Info,
return ESR_Succeeded;
case Stmt::ReturnStmtClass: {
- CCValue CCResult;
const Expr *RetExpr = cast<ReturnStmt>(S)->getRetValue();
- if (!Evaluate(CCResult, Info, RetExpr) ||
- !CheckConstantExpression(Info, RetExpr, CCResult, Result,
- CCEK_ReturnValue))
+ if (!Evaluate(Result, Info, RetExpr))
return ESR_Failed;
return ESR_Returned;
}
@@ -2010,7 +2092,7 @@ static bool EvaluateArgs(ArrayRef<const Expr*> Args, ArgVector &ArgValues,
static bool HandleFunctionCall(SourceLocation CallLoc,
const FunctionDecl *Callee, const LValue *This,
ArrayRef<const Expr*> Args, const Stmt *Body,
- EvalInfo &Info, APValue &Result) {
+ EvalInfo &Info, CCValue &Result) {
ArgVector ArgValues(Args.size());
if (!EvaluateArgs(Args, ArgValues, Info))
return false;
@@ -2045,7 +2127,7 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
// If it's a delegating constructor, just delegate.
if (Definition->isDelegatingConstructor()) {
CXXConstructorDecl::init_const_iterator I = Definition->init_begin();
- return EvaluateConstantExpression(Result, Info, This, (*I)->getInit());
+ return EvaluateInPlace(Result, Info, This, (*I)->getInit());
}
// For a trivial copy or move constructor, perform an APValue copy. This is
@@ -2137,8 +2219,8 @@ static bool HandleConstructorCall(SourceLocation CallLoc, const LValue &This,
llvm_unreachable("unknown base initializer kind");
}
- if (!EvaluateConstantExpression(*Value, Info, Subobject, (*I)->getInit(),
- (*I)->isBaseInitializer()
+ if (!EvaluateInPlace(*Value, Info, Subobject, (*I)->getInit(),
+ (*I)->isBaseInitializer()
? CCEK_Constant : CCEK_MemberInit)) {
// If we're checking for a potential constant expression, evaluate all
// initializers even if some of them fail.
@@ -2488,14 +2570,14 @@ public:
const FunctionDecl *Definition = 0;
Stmt *Body = FD->getBody(Definition);
- APValue Result;
+ CCValue Result;
if (!CheckConstexprFunction(Info, E->getExprLoc(), FD, Definition) ||
!HandleFunctionCall(E->getExprLoc(), Definition, This, Args, Body,
Info, Result))
return false;
- return DerivedSuccess(CCValue(Info.Ctx, Result, CCValue::GlobalValue()), E);
+ return DerivedSuccess(Result, E);
}
RetTy VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
@@ -2706,8 +2788,8 @@ public:
// * BlockExpr
// * CallExpr for a MakeStringConstant builtin
// - Locals and temporaries
-// * Any Expr, with a Frame indicating the function in which the temporary was
-// evaluated.
+// * Any Expr, with a CallIndex indicating the function in which the temporary
+// was evaluated.
// plus an offset in bytes.
//===----------------------------------------------------------------------===//
namespace {
@@ -2777,7 +2859,7 @@ bool LValueExprEvaluator::VisitDeclRefExpr(const DeclRefExpr *E) {
bool LValueExprEvaluator::VisitVarDecl(const Expr *E, const VarDecl *VD) {
if (!VD->getType()->isReferenceType()) {
if (isa<ParmVarDecl>(VD)) {
- Result.set(VD, Info.CurrentCall);
+ Result.set(VD, Info.CurrentCall->Index);
return true;
}
return Success(VD);
@@ -2795,9 +2877,9 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
if (E->getType()->isRecordType())
return EvaluateTemporary(E->GetTemporaryExpr(), Result, Info);
- Result.set(E, Info.CurrentCall);
- return EvaluateConstantExpression(Info.CurrentCall->Temporaries[E], Info,
- Result, E->GetTemporaryExpr());
+ Result.set(E, Info.CurrentCall->Index);
+ return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info,
+ Result, E->GetTemporaryExpr());
}
// Materialization of an lvalue temporary occurs when we need to force a copy
@@ -2808,7 +2890,7 @@ bool LValueExprEvaluator::VisitMaterializeTemporaryExpr(
if (!HandleLValueToRValueConversion(Info, E, E->getType(), Result,
Info.CurrentCall->Temporaries[E]))
return false;
- Result.set(E, Info.CurrentCall);
+ Result.set(E, Info.CurrentCall->Index);
return true;
}
@@ -3032,7 +3114,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
uint64_t N = Value.getInt().extOrTrunc(Size).getZExtValue();
Result.Base = (Expr*)0;
Result.Offset = CharUnits::fromQuantity(N);
- Result.Frame = 0;
+ Result.CallIndex = 0;
Result.Designator.setInvalid();
return true;
} else {
@@ -3046,9 +3128,9 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
if (!EvaluateLValue(SubExpr, Result, Info))
return false;
} else {
- Result.set(SubExpr, Info.CurrentCall);
- if (!EvaluateConstantExpression(Info.CurrentCall->Temporaries[SubExpr],
- Info, Result, SubExpr))
+ Result.set(SubExpr, Info.CurrentCall->Index);
+ if (!EvaluateInPlace(Info.CurrentCall->Temporaries[SubExpr],
+ Info, Result, SubExpr))
return false;
}
// The result is a pointer to the first element of the array.
@@ -3175,7 +3257,8 @@ namespace {
: ExprEvaluatorBaseTy(info), This(This), Result(Result) {}
bool Success(const CCValue &V, const Expr *E) {
- return CheckConstantExpression(Info, E, V, Result);
+ Result = V;
+ return true;
}
bool ZeroInitialization(const Expr *E);
@@ -3225,7 +3308,7 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
HandleLValueMember(Info, E, Subobject, *I, &Layout);
ImplicitValueInitExpr VIE((*I)->getType());
- if (!EvaluateConstantExpression(
+ if (!EvaluateInPlace(
Result.getStructField((*I)->getFieldIndex()), Info, Subobject, &VIE))
return false;
}
@@ -3248,8 +3331,7 @@ bool RecordExprEvaluator::ZeroInitialization(const Expr *E) {
HandleLValueMember(Info, E, Subobject, *I);
Result = APValue(*I);
ImplicitValueInitExpr VIE((*I)->getType());
- return EvaluateConstantExpression(Result.getUnionValue(), Info,
- Subobject, &VIE);
+ return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, &VIE);
}
return HandleClassZeroInitialization(Info, E, RD, This, Result);
@@ -3304,8 +3386,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
LValue Subobject = This;
HandleLValueMember(Info, InitExpr, Subobject, Field, &Layout);
- return EvaluateConstantExpression(Result.getUnionValue(), Info,
- Subobject, InitExpr);
+ return EvaluateInPlace(Result.getUnionValue(), Info, Subobject, InitExpr);
}
assert((!isa<CXXRecordDecl>(RD) || !cast<CXXRecordDecl>(RD)->getNumBases()) &&
@@ -3334,7 +3415,7 @@ bool RecordExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
// the initializer list.
ImplicitValueInitExpr VIE(HaveInit ? Info.Ctx.IntTy : Field->getType());
- if (!EvaluateConstantExpression(
+ if (!EvaluateInPlace(
Result.getStructField((*Field)->getFieldIndex()),
Info, Subobject, HaveInit ? E->getInit(ElementNo++) : &VIE)) {
if (!Info.keepEvaluatingAfterFailure())
@@ -3410,9 +3491,8 @@ public:
/// Visit an expression which constructs the value of this temporary.
bool VisitConstructExpr(const Expr *E) {
- Result.set(E, Info.CurrentCall);
- return EvaluateConstantExpression(Info.CurrentCall->Temporaries[E], Info,
- Result, E);
+ Result.set(E, Info.CurrentCall->Index);
+ return EvaluateInPlace(Info.CurrentCall->Temporaries[E], Info, Result, E);
}
bool VisitCastExpr(const CastExpr *E) {
@@ -3658,8 +3738,7 @@ namespace {
LValue Subobject = This;
Subobject.addArray(Info, E, CAT);
ImplicitValueInitExpr VIE(CAT->getElementType());
- return EvaluateConstantExpression(Result.getArrayFiller(), Info,
- Subobject, &VIE);
+ return EvaluateInPlace(Result.getArrayFiller(), Info, Subobject, &VIE);
}
bool VisitInitListExpr(const InitListExpr *E);
@@ -3693,10 +3772,10 @@ bool ArrayExprEvaluator::VisitInitListExpr(const InitListExpr *E) {
for (uint64_t I = 0; I < NumElements; ++I) {
CCValue Char;
if (!HandleLValueToRValueConversion(Info, E->getInit(0),