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
/// 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);
}
}
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();
+ }
}
};
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) {}
};
}
+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)
// 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());
}
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);
}
};
}
/// 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,
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;
return false;
}
- Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
- Designator.Entries, Designator.OnePastTheEnd);
return true;
}
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);
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)
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.
if (!Type->isConstantSizeType()) {
// sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
+ // FIXME: Diagnostic.
return false;
}
/// 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;
}
// 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();
}
Info.addNotes(Notes);
}
- Result = CCValue(*VD->getEvaluatedValue(), CCValue::GlobalValue());
+ Result = CCValue(Info.Ctx, *VD->getEvaluatedValue(), CCValue::GlobalValue());
return true;
}
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);
}
}
- Obj = CCValue(*O, CCValue::GlobalValue());
+ Obj = CCValue(Info.Ctx, *O, CCValue::GlobalValue());
return true;
}
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();
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 =
}
// 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() +
// 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.
// 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();
/// 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 {
++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,
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*>());
!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) {
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);
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;
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
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;
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.
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();
case CK_BaseToDerived:
if (!Visit(E->getSubExpr()))
return false;
- if (!CheckValidLValue())
- return false;
return HandleBaseToDerivedCast(Info, E, Result);
}
}
= 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);
}
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) {
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();
}
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:
/// -- 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);
if (CD) {
unsigned Index = 0;
for (CXXRecordDecl::base_class_const_iterator I = CD->bases_begin(),
- E = CD->bases_end(); I != E; ++I, ++Index) {
+ End = CD->bases_end(); I != End; ++I, ++Index) {
const CXXRecordDecl *Base = I->getType()->getAsCXXRecordDecl();
LValue Subobject = This;
- HandleLValueDirectBase(Info, Subobject, CD, Base, &Layout);
- if (!HandleClassZeroInitialization(Info, Base, Subobject,
+ HandleLValueDirectBase(Info, E, Subobject, CD, Base, &Layout);
+ if (!HandleClassZeroInitialization(Info, E, Base, Subobject,
Result.getStructBase(Index)))
return false;
}
}
- for (RecordDecl::field_iterator I = RD->field_begin(), E = RD->field_end();
- I != E; ++I) {
+ for (RecordDecl::field_iterator I = RD->field_begin(), End = RD->field_end();
+ I != End; ++I) {
// -- if T is a reference type, no initialization is performed.
if ((*I)->getType()->isReferenceType())
continue;
LValue Subobject = This;
- HandleLValueMember(Info, Subobject, *I, &Layout);
+ HandleLValueMember(Info, E, Subobject, *I, &Layout);
ImplicitValueInitExpr VIE((*I)->getType());
if (!EvaluateConstantExpression(
}
LValue Subobject = This;
- HandleLValueMember(Info, Subobject, *I);
+ HandleLValueMember(Info, E, Subobject, *I);
Result = APValue(*I);
ImplicitValueInitExpr VIE((*I)->getType());
return EvaluateConstantExpression(Result.getUnionValue(), Info,
Subobject, &VIE);
}
- return HandleClassZeroInitialization(Info, RD, This, Result);
+ return HandleClassZeroInitialization(Info, E, RD, This, Result);
}
bool RecordExprEvaluator::VisitCastExpr(const CastExpr *E) {
if (!E->getNumInits())
return true;
LValue Subobject = This;
- HandleLValueMember(Info, Subobject, E->getInitializedFieldInUnion(),
- &Layout);
+ HandleLValueMember(Info, E->getInit(0), Subobject,
+ E->getInitializedFieldInUnion(), &Layout);
return EvaluateConstantExpression(Result.getUnionValue(), Info,
Subobject, E->getInit(0));
}
continue;
LValue Subobject = This;
- HandleLValueMember(Info, Subobject, *Field, &Layout);
if (ElementNo < E->getNumInits()) {
+ HandleLValueMember(Info, E->getInit(ElementNo), Subobject, *Field,
+ &Layout);
if (!EvaluateConstantExpression(
Result.getStructField((*Field)->getFieldIndex()),
Info, Subobject, E->getInit(ElementNo++)))
} else {
// Perform an implicit value-initialization for members beyond the end of
// the initializer list.
+ HandleLValueMember(Info, E, Subobject, *Field, &Layout);
ImplicitValueInitExpr VIE(Field->getType());
if (!EvaluateConstantExpression(
Result.getStructField((*Field)->getFieldIndex()),
// Zero-initialize all elements.
LValue Subobject = This;
- Subobject.Designator.addIndex(0);
+ Subobject.addArray(Info, E, CAT);
ImplicitValueInitExpr VIE(CAT->getElementType());
return EvaluateConstantExpression(Result.getArrayFiller(), Info,
Subobject, &VIE);
Result = APValue(APValue::UninitArray(), NumElements, NumElements);
// Copy the string literal into the array. FIXME: Do this better.
- LV.Designator.addIndex(0);
+ LV.addArray(Info, E, CAT);
for (uint64_t I = 0; I < NumElements; ++I) {
CCValue Char;
if (!HandleLValueToRValueConversion(Info, E->getInit(0),
if (!CheckConstantExpression(Info, E->getInit(0), Char,
Result.getArrayInitializedElt(I)))
return false;
- if (!HandleLValueArrayAdjustment(Info, LV, CAT->getElementType(), 1))
+ if (!HandleLValueArrayAdjustment(Info, E->getInit(0), LV,
+ CAT->getElementType(), 1))
return false;
}
return true;
Result = APValue(APValue::UninitArray(), E->getNumInits(),
CAT->getSize().getZExtValue());
LValue Subobject = This;
- Subobject.Designator.addIndex(0);
+ Subobject.addArray(Info, E, CAT);
unsigned Index = 0;
for (InitListExpr::const_iterator I = E->begin(), End = E->end();
I != End; ++I, ++Index) {
if (!EvaluateConstantExpression(Result.getArrayInitializedElt(Index),
Info, Subobject, cast<Expr>(*I)))
return false;
- if (!HandleLValueArrayAdjustment(Info, Subobject, CAT->getElementType(), 1))
+ if (!HandleLValueArrayAdjustment(Info, cast<Expr>(*I), Subobject,
+ CAT->getElementType(), 1))
return false;
}
if (CheckTrivialDefaultConstructor(Info, E->getExprLoc(), FD, ZeroInit)) {
if (ZeroInit) {
LValue Subobject = This;
- Subobject.Designator.addIndex(0);
+ Subobject.addArray(Info, E, CAT);
ImplicitValueInitExpr VIE(CAT->getElementType());
return EvaluateConstantExpression(Result.getArrayFiller(), Info,
Subobject, &VIE);
// struct S { constexpr S() : p(&p) {} void *p; };
// S s[10];
LValue Subobject = This;
- Subobject.Designator.addIndex(0);
+ Subobject.addArray(Info, E, CAT);
if (ZeroInit) {
ImplicitValueInitExpr VIE(CAT->getElementType());
const ASTContext &Ctx) const {
EvalResult Scratch;
return EvaluateAsRValue(Scratch, Ctx) &&
- HandleConversionToBool(CCValue(Scratch.Val, CCValue::GlobalValue()),
+ HandleConversionToBool(CCValue(const_cast<ASTContext&>(Ctx),
+ Scratch.Val, CCValue::GlobalValue()),
Result);
}