aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/ExprConstant.cpp
diff options
context:
space:
mode:
authorRichard Smith <richard-llvm@metafoo.co.uk>2012-01-06 16:39:00 +0000
committerRichard Smith <richard-llvm@metafoo.co.uk>2012-01-06 16:39:00 +0000
commitb4e85ed51905fc94378d7b4ff62b06e0d08042b7 (patch)
tree341e01d1fbaa36582a5ae93ff542995cf2fe1af1 /lib/AST/ExprConstant.cpp
parentf143ffc4a9af79ac1d822fea6995af4bf45d17dc (diff)
C++11 generalized constant expressions: implement checking and diagnostics for
pointer-arithmetic-related undefined behavior and unspecified results. We continue to fold such values, but now notice they aren't constant expressions. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@147659 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/AST/ExprConstant.cpp')
-rw-r--r--lib/AST/ExprConstant.cpp546
1 files changed, 317 insertions, 229 deletions
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 949988db1a..1ad17ea376 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -76,24 +76,38 @@ namespace {
return Value.getInt();
}
- /// Determine whether the described subobject is an array element.
- static bool SubobjectIsArrayElement(QualType Base,
- ArrayRef<APValue::LValuePathEntry> Path) {
- bool IsArrayElement = false;
- const Type *T = Base.getTypePtr();
+ /// Find the path length and type of the most-derived subobject in the given
+ /// path, and find the size of the containing array, if any.
+ static
+ unsigned findMostDerivedSubobject(ASTContext &Ctx, QualType Base,
+ ArrayRef<APValue::LValuePathEntry> Path,
+ uint64_t &ArraySize, QualType &Type) {
+ unsigned MostDerivedLength = 0;
+ Type = Base;
for (unsigned I = 0, N = Path.size(); I != N; ++I) {
- IsArrayElement = T && T->isArrayType();
- if (IsArrayElement)
- T = T->getBaseElementTypeUnsafe();
- else if (const FieldDecl *FD = getAsField(Path[I]))
- T = FD->getType().getTypePtr();
- else
+ if (Type->isArrayType()) {
+ const ConstantArrayType *CAT =
+ cast<ConstantArrayType>(Ctx.getAsArrayType(Type));
+ Type = CAT->getElementType();
+ ArraySize = CAT->getSize().getZExtValue();
+ MostDerivedLength = I + 1;
+ } else if (const FieldDecl *FD = getAsField(Path[I])) {
+ Type = FD->getType();
+ ArraySize = 0;
+ MostDerivedLength = I + 1;
+ } else {
// Path[I] describes a base class.
- T = 0;
+ ArraySize = 0;
+ }
}
- return IsArrayElement;
+ return MostDerivedLength;
}
+ // The order of this enum is important for diagnostics.
+ enum CheckSubobjectKind {
+ CSK_Base, CSK_Derived, CSK_Field, CSK_ArrayToPointer, CSK_ArrayIndex
+ };
+
/// A path from a glvalue to a subobject of that glvalue.
struct SubobjectDesignator {
/// True if the subobject was named in a manner not supported by C++11. Such
@@ -101,32 +115,43 @@ namespace {
/// and we cannot perform lvalue-to-rvalue conversions on them.
bool Invalid : 1;
- /// Whether this designates an array element.
- bool ArrayElement : 1;
+ /// Is this a pointer one past the end of an object?
+ bool IsOnePastTheEnd : 1;
+
+ /// The length of the path to the most-derived object of which this is a
+ /// subobject.
+ unsigned MostDerivedPathLength : 30;
+
+ /// The size of the array of which the most-derived object is an element, or
+ /// 0 if the most-derived object is not an array element.
+ uint64_t MostDerivedArraySize;
- /// Whether this designates 'one past the end' of the current subobject.
- bool OnePastTheEnd : 1;
+ /// The type of the most derived object referred to by this address.
+ QualType MostDerivedType;
typedef APValue::LValuePathEntry PathEntry;
/// The entries on the path from the glvalue to the designated subobject.
SmallVector<PathEntry, 8> Entries;
- SubobjectDesignator() :
- Invalid(false), ArrayElement(false), OnePastTheEnd(false) {}
+ SubobjectDesignator() : Invalid(true) {}
- SubobjectDesignator(const APValue &V) :
- Invalid(!V.isLValue() || !V.hasLValuePath()), ArrayElement(false),
- OnePastTheEnd(false) {
+ explicit SubobjectDesignator(QualType T)
+ : Invalid(false), IsOnePastTheEnd(false), MostDerivedPathLength(0),
+ MostDerivedArraySize(0), MostDerivedType(T) {}
+
+ SubobjectDesignator(ASTContext &Ctx, const APValue &V)
+ : Invalid(!V.isLValue() || !V.hasLValuePath()), IsOnePastTheEnd(false),
+ MostDerivedPathLength(0), MostDerivedArraySize(0) {
if (!Invalid) {
+ IsOnePastTheEnd = V.isLValueOnePastTheEnd();
ArrayRef<PathEntry> VEntries = V.getLValuePath();
Entries.insert(Entries.end(), VEntries.begin(), VEntries.end());
if (V.getLValueBase())
- ArrayElement = SubobjectIsArrayElement(getType(V.getLValueBase()),
- V.getLValuePath());
- else
- assert(V.getLValuePath().empty() &&"Null pointer with nonempty path");
- OnePastTheEnd = V.isLValueOnePastTheEnd();
+ MostDerivedPathLength =
+ findMostDerivedSubobject(Ctx, getType(V.getLValueBase()),
+ V.getLValuePath(), MostDerivedArraySize,
+ MostDerivedType);
}
}
@@ -134,46 +159,76 @@ namespace {
Invalid = true;
Entries.clear();
}
- /// Update this designator to refer to the given element within this array.
- void addIndex(uint64_t N) {
- if (Invalid) return;
- if (OnePastTheEnd) {
- setInvalid();
- return;
- }
+
+ /// Determine whether this is a one-past-the-end pointer.
+ bool isOnePastTheEnd() const {
+ if (IsOnePastTheEnd)
+ return true;
+ if (MostDerivedArraySize &&
+ Entries[MostDerivedPathLength - 1].ArrayIndex == MostDerivedArraySize)
+ return true;
+ return false;
+ }
+
+ /// Check that this refers to a valid subobject.
+ bool isValidSubobject() const {
+ if (Invalid)
+ return false;
+ return !isOnePastTheEnd();
+ }
+ /// Check that this refers to a valid subobject, and if not, produce a
+ /// relevant diagnostic and set the designator as invalid.
+ bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK);
+
+ /// Update this designator to refer to the first element within this array.
+ void addArrayUnchecked(const ConstantArrayType *CAT) {
PathEntry Entry;
- Entry.ArrayIndex = N;
+ Entry.ArrayIndex = 0;
Entries.push_back(Entry);
- ArrayElement = true;
+
+ // This is a most-derived object.
+ MostDerivedType = CAT->getElementType();
+ MostDerivedArraySize = CAT->getSize().getZExtValue();
+ MostDerivedPathLength = Entries.size();
}
/// Update this designator to refer to the given base or member of this
/// object.
- void addDecl(const Decl *D, bool Virtual = false) {
- if (Invalid) return;
- if (OnePastTheEnd) {
- setInvalid();
- return;
- }
+ void addDeclUnchecked(const Decl *D, bool Virtual = false) {
PathEntry Entry;
APValue::BaseOrMemberType Value(D, Virtual);
Entry.BaseOrMember = Value.getOpaqueValue();
Entries.push_back(Entry);
- ArrayElement = false;
+
+ // If this isn't a base class, it's a new most-derived object.
+ if (const FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+ MostDerivedType = FD->getType();
+ MostDerivedArraySize = 0;
+ MostDerivedPathLength = Entries.size();
+ }
}
+ void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E, uint64_t N);
/// Add N to the address of this subobject.
- void adjustIndex(uint64_t N) {
+ void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) {
if (Invalid) return;
- if (ArrayElement) {
- // FIXME: Make sure the index stays within bounds, or one past the end.
+ if (MostDerivedPathLength == Entries.size() && MostDerivedArraySize) {
Entries.back().ArrayIndex += N;
+ if (Entries.back().ArrayIndex > MostDerivedArraySize) {
+ diagnosePointerArithmetic(Info, E, Entries.back().ArrayIndex);
+ setInvalid();
+ }
return;
}
- if (OnePastTheEnd && N == (uint64_t)-1)
- OnePastTheEnd = false;
- else if (!OnePastTheEnd && N == 1)
- OnePastTheEnd = true;
- else if (N != 0)
+ // [expr.add]p4: For the purposes of these operators, a pointer to a
+ // nonarray object behaves the same as a pointer to the first element of
+ // an array of length one with the type of the object as its element type.
+ if (IsOnePastTheEnd && N == (uint64_t)-1)
+ IsOnePastTheEnd = false;
+ else if (!IsOnePastTheEnd && N == 1)
+ IsOnePastTheEnd = true;
+ else if (N != 0) {
+ diagnosePointerArithmetic(Info, E, uint64_t(IsOnePastTheEnd) + N);
setInvalid();
+ }
}
};
@@ -205,8 +260,8 @@ namespace {
CCValue(LValueBase B, const CharUnits &O, CallStackFrame *F,
const SubobjectDesignator &D) :
APValue(B, O, APValue::NoLValuePath()), CallFrame(F), Designator(D) {}
- CCValue(const APValue &V, GlobalValue) :
- APValue(V), CallFrame(0), Designator(V) {}
+ CCValue(ASTContext &Ctx, const APValue &V, GlobalValue) :
+ APValue(V), CallFrame(0), Designator(Ctx, V) {}
CCValue(const ValueDecl *D, bool IsDerivedMember,
ArrayRef<const CXXRecordDecl*> Path) :
APValue(D, IsDerivedMember, Path) {}
@@ -397,6 +452,31 @@ namespace {
};
}
+bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
+ CheckSubobjectKind CSK) {
+ if (Invalid)
+ return false;
+ if (isOnePastTheEnd()) {
+ Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_past_end_subobject)
+ << CSK;
+ setInvalid();
+ return false;
+ }
+ return true;
+}
+
+void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info,
+ const Expr *E, uint64_t N) {
+ if (MostDerivedPathLength == Entries.size() && MostDerivedArraySize)
+ Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_array_index)
+ << static_cast<int>(N) << /*array*/ 0
+ << static_cast<unsigned>(MostDerivedArraySize);
+ else
+ Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_array_index)
+ << static_cast<int>(N) << /*non-array*/ 1;
+ setInvalid();
+}
+
CallStackFrame::CallStackFrame(EvalInfo &Info, SourceLocation CallLoc,
const FunctionDecl *Callee, const LValue *This,
const CCValue *Arguments)
@@ -434,7 +514,7 @@ static void describeCall(CallStackFrame *Frame, llvm::raw_ostream &Out) {
// Deliberately slice off the frame to form an APValue we can print.
APValue Value(Arg.getLValueBase(), Arg.getLValueOffset(),
Arg.getLValueDesignator().Entries,
- Arg.getLValueDesignator().OnePastTheEnd);
+ Arg.getLValueDesignator().IsOnePastTheEnd);
Value.printPretty(Out, Frame->Info.Ctx, Param->getType());
}
@@ -544,7 +624,44 @@ namespace {
Base = B;
Offset = CharUnits::Zero();
Frame = F;
- Designator = SubobjectDesignator();
+ Designator = SubobjectDesignator(getType(B));
+ }
+
+ // Check that this LValue is not based on a null pointer. If it is, produce
+ // a diagnostic and mark the designator as invalid.
+ bool checkNullPointer(EvalInfo &Info, const Expr *E,
+ CheckSubobjectKind CSK) {
+ if (Designator.Invalid)
+ return false;
+ if (!Base) {
+ Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_null_subobject)
+ << CSK;
+ Designator.setInvalid();
+ return false;
+ }
+ return true;
+ }
+
+ // Check this LValue refers to an object. If not, set the designator to be
+ // invalid and emit a diagnostic.
+ bool checkSubobject(EvalInfo &Info, const Expr *E, CheckSubobjectKind CSK) {
+ return checkNullPointer(Info, E, CSK) &&
+ Designator.checkSubobject(Info, E, CSK);
+ }
+
+ void addDecl(EvalInfo &Info, const Expr *E,
+ const Decl *D, bool Virtual = false) {
+ checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base);
+ Designator.addDeclUnchecked(D, Virtual);
+ }
+ void addArray(EvalInfo &Info, const Expr *E, const ConstantArrayType *CAT) {
+ checkSubobject(Info, E, CSK_ArrayToPointer);
+ Designator.addArrayUnchecked(CAT);
+ }
+ void adjustIndex(EvalInfo &Info, const Expr *E, uint64_t N) {
+ if (!checkNullPointer(Info, E, CSK_ArrayIndex))
+ return;
+ Designator.adjustIndex(Info, E, N);
}
};
@@ -714,7 +831,8 @@ static bool IsGlobalLValue(APValue::LValueBase B) {
}
/// Check that this reference or pointer core constant expression is a valid
-/// value for a constant expression. Type T should be either LValue or CCValue.
+/// value for an address or reference constant expression. Type T should be
+/// either LValue or CCValue.
template<typename T>
static bool CheckLValueConstantExpression(EvalInfo &Info, const Expr *E,
const T &LVal, APValue &Value,
@@ -739,20 +857,38 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, const Expr *E,
return false;
}
- // A constant expression must refer to an object or be a null pointer.
- if (Designator.Invalid ||
- (!LVal.getLValueBase() && !Designator.Entries.empty())) {
- // FIXME: This is not a core constant expression. We should have already
- // produced a CCE diagnostic.
+ bool IsReferenceType = E->isGLValue();
+
+ if (Designator.Invalid) {
+ // This is not a core constant expression. A diagnostic will have already
+ // been produced.
+ if (IsReferenceType)
+ return false;
+
+ // Allow this for pointers, so we can fold things like integers cast to
+ // pointers.
Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
APValue::NoLValuePath());
return true;
}
+ Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
+ Designator.Entries, Designator.IsOnePastTheEnd);
+
+ // Allow address constant expressions to be past-the-end pointers. This is
+ // an extension: the standard requires them to point to an object.
+ if (!IsReferenceType)
+ return true;
+
+ // A reference constant expression must refer to an object.
+ if (!Base) {
+ // FIXME: diagnostic
+ Info.CCEDiag(E->getExprLoc());
+ return false;
+ }
+
// Does this refer one past the end of some object?
- // This is technically not an address constant expression nor a reference
- // constant expression, but we allow it for address constant expressions.
- if (E->isGLValue() && Base && Designator.OnePastTheEnd) {
+ if (Designator.isOnePastTheEnd()) {
const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>();
Info.Diag(E->getExprLoc(), diag::note_constexpr_past_end, 1)
<< !Designator.Entries.empty() << !!VD << VD;
@@ -764,8 +900,6 @@ static bool CheckLValueConstantExpression(EvalInfo &Info, const Expr *E,
return false;
}
- Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
- Designator.Entries, Designator.OnePastTheEnd);
return true;
}
@@ -980,49 +1114,22 @@ static bool EvalAndBitcastToAPInt(EvalInfo &Info, const Expr *E,
return false;
}
-static bool FindMostDerivedObject(EvalInfo &Info, const LValue &LVal,
- const CXXRecordDecl *&MostDerivedType,
- unsigned &MostDerivedPathLength,
- bool &MostDerivedIsArrayElement) {
- const SubobjectDesignator &D = LVal.Designator;
- if (D.Invalid || !LVal.Base)
- return false;
-
- const Type *T = getType(LVal.Base).getTypePtr();
-
- // Find path prefix which leads to the most-derived subobject.
- MostDerivedType = T->getAsCXXRecordDecl();
- MostDerivedPathLength = 0;
- MostDerivedIsArrayElement = false;
-
- for (unsigned I = 0, N = D.Entries.size(); I != N; ++I) {
- bool IsArray = T && T->isArrayType();
- if (IsArray)
- T = T->getBaseElementTypeUnsafe();
- else if (const FieldDecl *FD = getAsField(D.Entries[I]))
- T = FD->getType().getTypePtr();
- else
- T = 0;
-
- if (T) {
- MostDerivedType = T->getAsCXXRecordDecl();
- MostDerivedPathLength = I + 1;
- MostDerivedIsArrayElement = IsArray;
- }
- }
+/// Cast an lvalue referring to a base subobject to a derived class, by
+/// truncating the lvalue's path to the given length.
+static bool CastToDerivedClass(EvalInfo &Info, const Expr *E, LValue &Result,
+ const RecordDecl *TruncatedType,
+ unsigned TruncatedElements) {
+ SubobjectDesignator &D = Result.Designator;
- // (B*)&d + 1 has no most-derived object.
- if (D.OnePastTheEnd && MostDerivedPathLength != D.Entries.size())
+ // Check we actually point to a derived class object.
+ if (TruncatedElements == D.Entries.size())
+ return true;
+ assert(TruncatedElements >= D.MostDerivedPathLength &&
+ "not casting to a derived class");
+ if (!Result.checkSubobject(Info, E, CSK_Derived))
return false;
- return MostDerivedType != 0;
-}
-
-static void TruncateLValueBasePath(EvalInfo &Info, LValue &Result,
- const RecordDecl *TruncatedType,
- unsigned TruncatedElements,
- bool IsArrayElement) {
- SubobjectDesignator &D = Result.Designator;
+ // Truncate the path to the subobject, and remove any derived-to-base offsets.
const RecordDecl *RD = TruncatedType;
for (unsigned I = TruncatedElements, N = D.Entries.size(); I != N; ++I) {
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(RD);
@@ -1034,58 +1141,47 @@ static void TruncateLValueBasePath(EvalInfo &Info, LValue &Result,
RD = Base;
}
D.Entries.resize(TruncatedElements);
- D.ArrayElement = IsArrayElement;
-}
-
-/// If the given LValue refers to a base subobject of some object, find the most
-/// derived object and the corresponding complete record type. This is necessary
-/// in order to find the offset of a virtual base class.
-static bool ExtractMostDerivedObject(EvalInfo &Info, LValue &Result,
- const CXXRecordDecl *&MostDerivedType) {
- unsigned MostDerivedPathLength;
- bool MostDerivedIsArrayElement;
- if (!FindMostDerivedObject(Info, Result, MostDerivedType,
- MostDerivedPathLength, MostDerivedIsArrayElement))
- return false;
-
- // Remove the trailing base class path entries and their offsets.
- TruncateLValueBasePath(Info, Result, MostDerivedType, MostDerivedPathLength,
- MostDerivedIsArrayElement);
return true;
}
-static void HandleLValueDirectBase(EvalInfo &Info, LValue &Obj,
+static void HandleLValueDirectBase(EvalInfo &Info, const Expr *E, LValue &Obj,
const CXXRecordDecl *Derived,
const CXXRecordDecl *Base,
const ASTRecordLayout *RL = 0) {
if (!RL) RL = &Info.Ctx.getASTRecordLayout(Derived);
Obj.getLValueOffset() += RL->getBaseClassOffset(Base);
- Obj.Designator.addDecl(Base, /*Virtual*/ false);
+ Obj.addDecl(Info, E, Base, /*Virtual*/ false);
}
-static bool HandleLValueBase(EvalInfo &Info, LValue &Obj,
+static bool HandleLValueBase(EvalInfo &Info, const Expr *E, LValue &Obj,
const CXXRecordDecl *DerivedDecl,
const CXXBaseSpecifier *Base) {
const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl();
if (!Base->isVirtual()) {
- HandleLValueDirectBase(Info, Obj, DerivedDecl, BaseDecl);
+ HandleLValueDirectBase(Info, E, Obj, DerivedDecl, BaseDecl);
return true;
}
+ SubobjectDesignator &D = Obj.Designator;
+ if (D.Invalid)
+ return false;
+
// Extract most-derived object and corresponding type.
- if (!ExtractMostDerivedObject(Info, Obj, DerivedDecl))
+ DerivedDecl = D.MostDerivedType->getAsCXXRecordDecl();
+ if (!CastToDerivedClass(Info, E, Obj, DerivedDecl, D.MostDerivedPathLength))
return false;
+ // Find the virtual base class.
const ASTRecordLayout &Layout = Info.Ctx.getASTRecordLayout(DerivedDecl);
Obj.getLValueOffset() += Layout.getVBaseClassOffset(BaseDecl);
- Obj.Designator.addDecl(BaseDecl, /*Virtual*/ true);
+ Obj.addDecl(Info, E, BaseDecl, /*Virtual*/ true);
return true;
}
/// Update LVal to refer to the given field, which must be a member of the type
/// currently described by LVal.
-static void HandleLValueMember(EvalInfo &Info, LValue &LVal,
+static void HandleLValueMember(EvalInfo &Info, const Expr *E, LValue &LVal,
const FieldDecl *FD,
const ASTRecordLayout *RL = 0) {
if (!RL)
@@ -1093,7 +1189,7 @@ static void HandleLValueMember(EvalInfo &Info, LValue &LVal,
unsigned I = FD->getFieldIndex();
LVal.Offset += Info.Ctx.toCharUnitsFromBits(RL->getFieldOffset(I));
- LVal.Designator.addDecl(FD);
+ LVal.addDecl(Info, E, FD);
}
/// Get the size of the given type in char units.
@@ -1107,6 +1203,7 @@ static bool HandleSizeof(EvalInfo &Info, QualType Type, CharUnits &Size) {
if (!Type->isConstantSizeType()) {
// sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
+ // FIXME: Diagnostic.
return false;
}
@@ -1116,18 +1213,20 @@ static bool HandleSizeof(EvalInfo &Info, QualType Type, CharUnits &Size) {
/// Update a pointer value to model pointer arithmetic.
/// \param Info - Information about the ongoing evaluation.
+/// \param E - The expression being evaluated, for diagnostic purposes.
/// \param LVal - The pointer value to be updated.
/// \param EltTy - The pointee type represented by LVal.
/// \param Adjustment - The adjustment, in objects of type EltTy, to add.
-static bool HandleLValueArrayAdjustment(EvalInfo &Info, LValue &LVal,
- QualType EltTy, int64_t Adjustment) {
+static bool HandleLValueArrayAdjustment(EvalInfo &Info, const Expr *E,
+ LValue &LVal, QualType EltTy,
+ int64_t Adjustment) {
CharUnits SizeOfPointee;
if (!HandleSizeof(Info, EltTy, SizeOfPointee))
return false;
// Compute the new offset in the appropriate width.
LVal.Offset += Adjustment * SizeOfPointee;
- LVal.Designator.adjustIndex(Adjustment);
+ LVal.adjustIndex(Info, E, Adjustment);
return true;
}
@@ -1156,7 +1255,8 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E,
// If we're currently evaluating the initializer of this declaration, use that
// in-flight value.
if (Info.EvaluatingDecl == VD) {
- Result = CCValue(*Info.EvaluatingDeclValue, CCValue::GlobalValue());
+ Result = CCValue(Info.Ctx, *Info.EvaluatingDeclValue,
+ CCValue::GlobalValue());
return !Result.isUninit();
}
@@ -1183,7 +1283,7 @@ static bool EvaluateVarDeclInit(EvalInfo &Info, const Expr *E,
Info.addNotes(Notes);
}
- Result = CCValue(*VD->getEvaluatedValue(), CCValue::GlobalValue());
+ Result = CCValue(Info.Ctx, *VD->getEvaluatedValue(), CCValue::GlobalValue());
return true;
}
@@ -1211,11 +1311,10 @@ static unsigned getBaseIndex(const CXXRecordDecl *Derived,
static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
CCValue &Obj, QualType ObjType,
const SubobjectDesignator &Sub, QualType SubType) {
- if (Sub.Invalid) {
- Info.Diag(E->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
+ if (Sub.Invalid)
+ // A diagnostic will have already been produced.
return false;
- }
- if (Sub.OnePastTheEnd) {
+ if (Sub.isOnePastTheEnd()) {
Info.Diag(E->getExprLoc(), Info.getLangOpts().CPlusPlus0x ?
(unsigned)diag::note_constexpr_read_past_end :
(unsigned)diag::note_invalid_subexpr_in_const_expr);
@@ -1288,7 +1387,7 @@ static bool ExtractSubobject(EvalInfo &Info, const Expr *E,
}
}
- Obj = CCValue(*O, CCValue::GlobalValue());
+ Obj = CCValue(Info.Ctx, *O, CCValue::GlobalValue());
return true;
}
@@ -1309,6 +1408,10 @@ static bool HandleLValueToRValueConversion(EvalInfo &Info, const Expr *Conv,
if (!Info.getLangOpts().CPlusPlus)
Info.CCEDiag(Conv->getExprLoc(), diag::note_invalid_subexpr_in_const_expr);
+ if (LVal.Designator.Invalid)
+ // A diagnostic will have already been produced.
+ return false;
+
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
CallStackFrame *Frame = LVal.Frame;
SourceLocation Loc = Conv->getExprLoc();
@@ -1513,16 +1616,9 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
if (MemPtr.isDerivedMember()) {
// This is a member of some derived class. Truncate LV appropriately.
- const CXXRecordDecl *MostDerivedType;
- unsigned MostDerivedPathLength;
- bool MostDerivedIsArrayElement;
- if (!FindMostDerivedObject(Info, LV, MostDerivedType, MostDerivedPathLength,
- MostDerivedIsArrayElement))
- return 0;
-
// The end of the derived-to-base path for the base object must match the
// derived-to-base path for the member pointer.
- if (MostDerivedPathLength + MemPtr.Path.size() >
+ if (LV.Designator.MostDerivedPathLength + MemPtr.Path.size() >
LV.Designator.Entries.size())
return 0;
unsigned PathLengthToMember =
@@ -1536,11 +1632,9 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
}
// Truncate the lvalue to the appropriate derived class.
- bool ResultIsArray = false;
- if (PathLengthToMember == MostDerivedPathLength)
- ResultIsArray = MostDerivedIsArrayElement;
- TruncateLValueBasePath(Info, LV, MemPtr.getContainingRecord(),
- PathLengthToMember, ResultIsArray);
+ if (!CastToDerivedClass(Info, BO, LV, MemPtr.getContainingRecord(),
+ PathLengthToMember))
+ return 0;
} else if (!MemPtr.Path.empty()) {
// Extend the LValue path with the member pointer's path.
LV.Designator.Entries.reserve(LV.Designator.Entries.size() +
@@ -1555,11 +1649,11 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
// The first class in the path is that of the lvalue.
for (unsigned I = 1, N = MemPtr.Path.size(); I != N; ++I) {
const CXXRecordDecl *Base = MemPtr.Path[N - I - 1];
- HandleLValueDirectBase(Info, LV, RD, Base);
+ HandleLValueDirectBase(Info, BO, LV, RD, Base);
RD = Base;
}
// Finally cast to the class containing the member.
- HandleLValueDirectBase(Info, LV, RD, MemPtr.getContainingRecord());
+ HandleLValueDirectBase(Info, BO, LV, RD, MemPtr.getContainingRecord());
}
// Add the member. Note that we cannot build bound member functions here.
@@ -1567,7 +1661,7 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
// FIXME: Deal with IndirectFieldDecls.
const FieldDecl *FD = dyn_cast<FieldDecl>(MemPtr.getDecl());
if (!FD) return 0;
- HandleLValueMember(Info, LV, FD);
+ HandleLValueMember(Info, BO, LV, FD);
}
return MemPtr.getDecl();
@@ -1577,40 +1671,38 @@ static const ValueDecl *HandleMemberPointerAccess(EvalInfo &Info,
/// the provided lvalue, which currently refers to the base object.
static bool HandleBaseToDerivedCast(EvalInfo &Info, const CastExpr *E,
LValue &Result) {
- const CXXRecordDecl *MostDerivedType;
- unsigned MostDerivedPathLength;
- bool MostDerivedIsArrayElement;
-
- // Check this cast doesn't take us outside the object.
- if (!FindMostDerivedObject(Info, Result, MostDerivedType,
- MostDerivedPathLength,
- MostDerivedIsArrayElement))
- return false;
SubobjectDesignator &D = Result.Designator;
- if (MostDerivedPathLength + E->path_size() > D.Entries.size())
+ if (D.Invalid || !Result.checkNullPointer(Info, E, CSK_Derived))
return false;
- // Check the type of the final cast. We don't need to check the path,
- // since a cast can only be formed if the path is unique.
- unsigned NewEntriesSize = D.Entries.size() - E->path_size();
- bool ResultIsArray = false;
QualType TargetQT = E->getType();
if (const PointerType *PT = TargetQT->getAs<PointerType>())
TargetQT = PT->getPointeeType();
+
+ // Check this cast lands within the final derived-to-base subobject path.
+ if (D.MostDerivedPathLength + E->path_size() > D.Entries.size()) {
+ Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_invalid_downcast)
+ << D.MostDerivedType << TargetQT;
+ return false;
+ }
+
+ // Check the type of the final cast. We don't need to check the path,
+ // since a cast can only be formed if the path is unique.
+ unsigned NewEntriesSize = D.Entries.size() - E->path_size();
const CXXRecordDecl *TargetType = TargetQT->getAsCXXRecordDecl();
const CXXRecordDecl *FinalType;
- if (NewEntriesSize == MostDerivedPathLength) {
- ResultIsArray = MostDerivedIsArrayElement;
- FinalType = MostDerivedType;
- } else
+ if (NewEntriesSize == D.MostDerivedPathLength)
+ FinalType = D.MostDerivedType->getAsCXXRecordDecl();
+ else
FinalType = getAsBaseClass(D.Entries[NewEntriesSize - 1]);
- if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl())
+ if (FinalType->getCanonicalDecl() != TargetType->getCanonicalDecl()) {
+ Info.CCEDiag(E->getExprLoc(), diag::note_constexpr_invalid_downcast)
+ << D.MostDerivedType << TargetQT;
return false;
+ }
// Truncate the lvalue to the appropriate derived class.
- TruncateLValueBasePath(Info, Result, TargetType, NewEntriesSize,
- ResultIsArray);
- return true;
+ return CastToDerivedClass(Info, E, Result, TargetType, NewEntriesSize);
}
namespace {
@@ -1787,14 +1879,14 @@ static bool HandleConstructorCall(const Expr *CallExpr, const LValue &This,
++BaseIt;
#endif
LValue Subobject = This;
- HandleLValueDirectBase(Info, Subobject, RD,
+ HandleLValueDirectBase(Info, (*I)->getInit(), Subobject, RD,
BaseType->getAsCXXRecordDecl(), &Layout);
if (!EvaluateConstantExpression(Result.getStructBase(BasesSeen++), Info,
Subobject, (*I)->getInit()))
return false;
} else if (FieldDecl *FD = (*I)->getMember()) {
LValue Subobject = This;
- HandleLValueMember(Info, Subobject, FD, &Layout);
+ HandleLValueMember(Info, (*I)->getInit(), Subobject, FD, &Layout);
if (RD->isUnion()) {
Result = APValue(FD);
if (!EvaluateConstantExpression(Result.getUnionValue(), Info, Subobject,
@@ -2083,11 +2175,11 @@ public:
if (!FD)
return Error(Callee);
} else if (CalleeType->isFunctionPointerType()) {
- CCValue Call;
- if (!Evaluate(Call, Info, Callee))
+ LValue Call;
+ if (!EvaluatePointer(Callee, Call, Info))
return false;
- if (!Call.isLValue() || !Call.getLValueOffset().isZero())
+ if (!Call.getLValueOffset().isZero())
return Error(Callee);
FD = dyn_cast_or_null<FunctionDecl>(
Call.getLValueBase().dyn_cast<const ValueDecl*>());
@@ -2124,7 +2216,7 @@ public:
!HandleFunctionCall(E, Definition, This, Args, Body, Info, Result))
return false;
- return DerivedSuccess(CCValue(Result, CCValue::GlobalValue()), E);
+ return DerivedSuccess(CCValue(Info.Ctx, Result, CCValue::GlobalValue()), E);
}
RetTy VisitCompoundLiteralExpr(const CompoundLiteralExpr *E) {
@@ -2163,8 +2255,8 @@ public:
assert(BaseTy->getAs<RecordType>()->getDecl()->getCanonicalDecl() ==
FD->getParent()->getCanonicalDecl() && "record / field mismatch");
- SubobjectDesignator Designator;
- Designator.addDecl(FD);
+ SubobjectDesignator Designator(BaseTy);
+ Designator.addDeclUnchecked(FD);
return ExtractSubobject(Info, E, Val, BaseTy, Designator, E->getType()) &&
DerivedSuccess(Val, E);
@@ -2228,14 +2320,6 @@ public:
return true;
}
- bool CheckValidLValue() {
- // C++11 [basic.lval]p1: An lvalue designates a function or an object. Hence
- // there are no null references, nor once-past-the-end references.
- // FIXME: Check for one-past-the-end array indices
- return Result.Base && !Result.Designator.Invalid &&
- !Result.Designator.OnePastTheEnd;
- }
-
bool VisitMemberExpr(const MemberExpr *E) {
// Handle non-static data members.
QualType BaseTy;
@@ -2253,7 +2337,6 @@ public:
return false;
BaseTy = E->getBase()->getType();
}
- // FIXME: In C++11, require the result to be a valid lvalue.
const FieldDecl *FD = dyn_cast<FieldDecl>(E->getMemberDecl());
// FIXME: Handle IndirectFieldDecls
@@ -2262,7 +2345,7 @@ public:
FD->getParent()->getCanonicalDecl() && "record / field mismatch");
(void)BaseTy;
- HandleLValueMember(this->Info, Result, FD);
+ HandleLValueMember(this->Info, E, Result, FD);
if (FD->getType()->isReferenceType()) {
CCValue RefValue;
@@ -2294,8 +2377,6 @@ public:
case CK_UncheckedDerivedToBase: {
if (!this->Visit(E->getSubExpr()))
return false;
- if (!CheckValidLValue())
- return false;
// Now figure out the necessary offset to add to the base LV to get from
// the derived class to the base class.
@@ -2303,7 +2384,7 @@ public:
for (CastExpr::path_const_iterator PathI = E->path_begin(),
PathE = E->path_end(); PathI != PathE; ++PathI) {
- if (!HandleLValueBase(this->Info, Result, Type->getAsCXXRecordDecl(),
+ if (!HandleLValueBase(this->Info, E, Result, Type->getAsCXXRecordDecl(),
*PathI))
return false;
Type = (*PathI)->getType();
@@ -2378,8 +2459,6 @@ public:
case CK_BaseToDerived:
if (!Visit(E->getSubExpr()))
return false;
- if (!CheckValidLValue())
- return false;
return HandleBaseToDerivedCast(Info, E, Result);
}
}
@@ -2502,12 +2581,10 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
= Index.isSigned() ? Index.getSExtValue()
: static_cast<int64_t>(Index.getZExtValue());
- // FIXME: In C++11, require the result to be a valid lvalue.
- return HandleLValueArrayAdjustment(Info, Result, E->getType(), IndexValue);
+ return HandleLValueArrayAdjustment(Info, E, Result, E->getType(), IndexValue);
}
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
- // FIXME: In C++11, require the result to be a valid lvalue.
return EvaluatePointer(E->getSubExpr(), Result, Info);
}
@@ -2589,8 +2666,8 @@ bool PointerExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) {
AdditionalOffset = -AdditionalOffset;
QualType Pointee = PExp->getType()->getAs<PointerType>()->getPointeeType();
- // FIXME: In C++11, require the result to be a valid lvalue.
- return HandleLValueArrayAdjustment(Info, Result, Pointee, AdditionalOffset);
+ return HandleLValueArrayAdjustment(Info, E, Result, Pointee,
+ AdditionalOffset);
}
bool PointerExprEvaluator::VisitUnaryAddrOf(const UnaryOperator *E) {
@@ -2637,7 +2714,8 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
for (CastExpr::path_const_iterator PathI = E->path_begin(),
PathE = E->path_end(); PathI != PathE; ++PathI) {
- if (!HandleLValueBase(Info, Result, Type->getAsCXXRecordDecl(), *PathI))
+ if (!HandleLValueBase(Info, E, Result, Type->getAsCXXRecordDecl(),
+ *PathI))
return false;
Type = (*PathI)->getType();
}
@@ -2687,7 +2765,11 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return false;
}
// The result is a pointer to the first element of the array.
- Result.Designator.addIndex(0);
+ if (const ConstantArrayType *CAT
+ = Info.Ctx.getAsConstantArrayType(SubExpr->getType()))
+ Result.addArray(Info, E, CAT);
+ else
+ Result.Designator.setInvalid();
return true;
case CK_FunctionToPointerDecay:
@@ -2823,7 +2905,8 @@ namespace {
/// -- if T is a (possibly cv-qualified) non-union class type,
/// each non-static data member and each base-class subobject is
/// zero-initialized
-static bool HandleClassZeroInitialization(EvalInfo &Info, const RecordDecl *RD,
+static bool HandleClassZeroInitialization(EvalInfo &Info, const Expr *E,
+ const RecordDecl *RD,
const LValue &This, APValue &Result) {
assert(!RD->isUnion() && "Expected non-union class type");
const CXXRecordDecl *CD = dyn_cast<CXXRecordDecl>(RD);
@@ -2835,24 +2918,24 @@ static bool HandleClassZeroInitialization(EvalInfo &Info, const RecordDecl *RD,
if (CD) {
unsigned Index = 0;
for (CXXRecordDecl::base_class_const_iterator I = CD->bases_begin(),
- E = CD->bases_end(); I !