[cfe-commits] r147659 - in /cfe/trunk: include/clang/Basic/DiagnosticASTKinds.td lib/AST/ExprConstant.cpp test/CXX/expr/expr.const/p2-0x.cpp test/SemaCXX/constant-expression-cxx11.cpp test/SemaCXX/constexpr-backtrace-limit.cpp
Richard Smith
richard-llvm at metafoo.co.uk
Fri Jan 6 08:39:00 PST 2012
Author: rsmith
Date: Fri Jan 6 10:39:00 2012
New Revision: 147659
URL: http://llvm.org/viewvc/llvm-project?rev=147659&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
cfe/trunk/lib/AST/ExprConstant.cpp
cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
cfe/trunk/test/SemaCXX/constexpr-backtrace-limit.cpp
Modified: cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td?rev=147659&r1=147658&r2=147659&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticASTKinds.td Fri Jan 6 10:39:00 2012
@@ -16,6 +16,8 @@
def note_constexpr_invalid_cast : Note<
"%select{reinterpret_cast|dynamic_cast|cast which performs the conversions of"
" a reinterpret_cast|cast from %1}0 is not allowed in a constant expression">;
+def note_constexpr_invalid_downcast : Note<
+ "cannot cast object of dynamic type %0 to type %1">;
def note_constexpr_overflow : Note<
"value %0 is outside the range of representable values of type %1">;
def note_constexpr_invalid_function : Note<
@@ -28,9 +30,20 @@
"%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">;
+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_pointer_arithmetic : Note<
+ "cannot refer to element %0 of non-array object in a constant "
+ "expression">;
def note_constexpr_past_end : Note<
- "dereferenced pointer past the end of %select{|subobject of}0 "
+ "dereferenced pointer past the end of %select{|subobject of }0"
"%select{temporary|%2}1 is not a constant expression">;
+def note_constexpr_past_end_subobject : Note<
+ "cannot access %select{base class|derived class|field|array element}0 of "
+ "pointer past the end of object">;
+def note_constexpr_null_subobject : Note<
+ "cannot %select{access base class of|access derived class of|access field of|"
+ "access array element of|perform pointer arithmetic on}0 null pointer">;
def note_constexpr_var_init_non_constant : Note<
"initializer of %0 is not a constant expression">;
def note_constexpr_typeid_polymorphic : Note<
Modified: cfe/trunk/lib/AST/ExprConstant.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ExprConstant.cpp?rev=147659&r1=147658&r2=147659&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ExprConstant.cpp (original)
+++ cfe/trunk/lib/AST/ExprConstant.cpp Fri Jan 6 10:39:00 2012
@@ -76,24 +76,38 @@
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 @@
/// 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 @@
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 @@
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 @@
};
}
+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 @@
// 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 @@
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 @@
}
/// 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 @@
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 @@
return false;
}
- Value = APValue(LVal.getLValueBase(), LVal.getLValueOffset(),
- Designator.Entries, Designator.OnePastTheEnd);
return true;
}
@@ -980,49 +1114,22 @@
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 @@
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 @@
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 @@
if (!Type->isConstantSizeType()) {
// sizeof(vla) is not a constantexpr: C99 6.5.3.4p2.
+ // FIXME: Diagnostic.
return false;
}
@@ -1116,18 +1213,20 @@
/// 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 @@
// 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 @@
Info.addNotes(Notes);
}
- Result = CCValue(*VD->getEvaluatedValue(), CCValue::GlobalValue());
+ Result = CCValue(Info.Ctx, *VD->getEvaluatedValue(), CCValue::GlobalValue());
return true;
}
@@ -1211,11 +1311,10 @@
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 @@
}
}
- Obj = CCValue(*O, CCValue::GlobalValue());
+ Obj = CCValue(Info.Ctx, *O, CCValue::GlobalValue());
return true;
}
@@ -1309,6 +1408,10 @@
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 @@
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 @@
}
// 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 @@
// 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 @@
// 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 @@
/// 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 @@
++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 @@
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 @@
!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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
case CK_BaseToDerived:
if (!Visit(E->getSubExpr()))
return false;
- if (!CheckValidLValue())
- return false;
return HandleBaseToDerivedCast(Info, E, Result);
}
}
@@ -2502,12 +2581,10 @@
= 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 @@
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 @@
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 @@
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 @@
/// -- 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 @@
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(
@@ -2875,14 +2958,14 @@
}
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) {
@@ -2926,8 +3009,8 @@
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));
}
@@ -2945,9 +3028,10 @@
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++)))
@@ -2955,6 +3039,7 @@
} 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()),
@@ -3274,7 +3359,7 @@
// 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);
@@ -3307,7 +3392,7 @@
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),
@@ -3316,7 +3401,8 @@
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;
@@ -3325,14 +3411,15 @@
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;
}
@@ -3361,7 +3448,7 @@
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);
@@ -3388,7 +3475,7 @@
// 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());
@@ -5284,7 +5371,8 @@
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);
}
Modified: cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp?rev=147659&r1=147658&r2=147659&view=diff
==============================================================================
--- cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp (original)
+++ cfe/trunk/test/CXX/expr/expr.const/p2-0x.cpp Fri Jan 6 10:39:00 2012
@@ -137,6 +137,27 @@
struct T {
int n : f(p); // expected-error {{not an integer constant expression}} expected-note {{in call to 'f(&s.m + 1)'}}
};
+
+ namespace Ptr {
+ struct A {};
+ struct B : A { int n; };
+ B a[3][3];
+ constexpr B *p = a[0] + 4; // expected-error {{constant expression}} expected-note {{element 4 of array of 3 elements}}
+ B b = {};
+ constexpr A *pa = &b + 1; // expected-error {{constant expression}} expected-note {{base class of pointer past the end}}
+ constexpr B *pb = (B*)((A*)&b + 1); // expected-error {{constant expression}} expected-note {{derived class of pointer past the end}}
+ constexpr const int *pn = &(&b + 1)->n; // expected-error {{constant expression}} expected-note {{field of pointer past the end}}
+ constexpr B *parr = &a[3][0]; // expected-error {{constant expression}} expected-note {{array element of pointer past the end}}
+
+ constexpr A *na = nullptr;
+ constexpr B *nb = nullptr;
+ constexpr A &ra = *nb; // expected-error {{constant expression}} expected-note {{cannot access base class of null pointer}}
+ constexpr B &rb = (B&)*na; // expected-error {{constant expression}} expected-note {{cannot access derived class of null pointer}}
+ static_assert((A*)nb == 0, "");
+ static_assert((B*)na == 0, "");
+ constexpr const int &nf = nb->n; // expected-error {{constant expression}} expected-note {{cannot access field of null pointer}}
+ constexpr const int &np = (*(int(*)[4])nullptr)[2]; // expected-error {{constant expression}} expected-note {{cannot access array element of null pointer}}
+ }
}
// - a lambda-expression (5.1.2);
Modified: cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp?rev=147659&r1=147658&r2=147659&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp (original)
+++ cfe/trunk/test/SemaCXX/constant-expression-cxx11.cpp Fri Jan 6 10:39:00 2012
@@ -363,9 +363,8 @@
constexpr char c0 = "nought index"[0];
constexpr char c1 = "nice index"[10];
constexpr char c2 = "nasty index"[12]; // expected-error {{must be initialized by a constant expression}} expected-warning {{is past the end}} expected-note {{read of dereferenced one-past-the-end pointer}}
-// FIXME: block the pointer arithmetic with undefined behavior here
-constexpr char c3 = "negative index"[-1]; // expected-error {{must be initialized by a constant expression}} expected-warning {{is before the beginning}} expected-note {{read of dereferenced one-past-the-end pointer}}
-constexpr char c4 = ((char*)(int*)"no reinterpret_casts allowed")[14]; // expected-error {{must be initialized by a constant expression}}
+constexpr char c3 = "negative index"[-1]; // expected-error {{must be initialized by a constant expression}} expected-warning {{is before the beginning}} expected-note {{cannot refer to element -1 of array of 15 elements}}
+constexpr char c4 = ((char*)(int*)"no reinterpret_casts allowed")[14]; // expected-error {{must be initialized by a constant expression}} expected-note {{cast which performs the conversions of a reinterpret_cast}}
constexpr const char *p = "test" + 2;
static_assert(*p == 's', "");
@@ -443,9 +442,9 @@
constexpr const int *p = xs + 3;
constexpr int xs4 = p[1]; // ok
constexpr int xs5 = p[2]; // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
+constexpr int xs6 = p[3]; // expected-error {{constant expression}} expected-note {{cannot refer to element 6}}
constexpr int xs0 = p[-3]; // ok
-// FIXME: check pointer arithmetic here
-constexpr int xs_1 = p[-4]; // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
+constexpr int xs_1 = p[-4]; // expected-error {{constant expression}} expected-note {{cannot refer to element -1}}
constexpr int zs[2][2][2][2] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
static_assert(zs[0][0][0][0] == 1, "");
@@ -453,12 +452,14 @@
static_assert(zs[0][0][0][2] == 3, ""); // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
static_assert((&zs[0][0][0][2])[-1] == 2, "");
static_assert(**(**(zs + 1) + 1) == 11, "");
-static_assert(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][-1] + 1) == 11, "");
+static_assert(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][-1] + 1) == 11, ""); // expected-error {{constant expression}} expected-note {{cannot refer to element -1 of array of 2 elements in a constant expression}}
+static_assert(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][2] - 2) == 11, "");
+constexpr int err_zs_1_2_0_0 = zs[1][2][0][0]; // expected-error {{constant expression}} expected-note {{cannot access array element of pointer past the end}}
constexpr int fail(const int &p) {
- return (&p)[64]; // expected-note {{read of dereferenced one-past-the-end pointer}}
+ return (&p)[64]; // expected-note {{cannot refer to element 64 of array of 2 elements}}
}
-static_assert(fail(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][-1] + 1)) == 11, ""); // \
+static_assert(fail(*(&(&(*(*&(&zs[2] - 1)[0] + 2 - 2))[2])[-1][2] - 2)) == 11, ""); // \
expected-error {{static_assert expression is not an integral constant expression}} \
expected-note {{in call to 'fail(zs[1][0][1][0])'}}
@@ -598,8 +599,7 @@
static_assert(strcmp_ce(&agg1.c, "hello") == 0, "");
static_assert(agg1.n == 0, "");
static_assert(agg1.d == 0.0, "");
-// FIXME: check pointer arithmetic here.
-static_assert(agg1.arr[-1] == 0, ""); // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end}}
+static_assert(agg1.arr[-1] == 0, ""); // expected-error {{constant expression}} expected-note {{cannot refer to element -1}}
static_assert(agg1.arr[0] == 0, "");
static_assert(agg1.arr[4] == 0, "");
static_assert(agg1.arr[5] == 0, ""); // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end}}
@@ -662,13 +662,13 @@
static_assert(pb1 == &bot1, "");
static_assert(pb2 == &bot2, "");
-constexpr Base2 &fail = (Base2&)bot1; // expected-error {{constant expression}}
-constexpr Base &fail2 = (Base&)*pb2; // expected-error {{constant expression}}
+constexpr Base2 &fail = (Base2&)bot1; // expected-error {{constant expression}} expected-note {{cannot cast object of dynamic type 'const Class::Derived' to type 'Class::Base2'}}
+constexpr Base &fail2 = (Base&)*pb2; // expected-error {{constant expression}} expected-note {{cannot cast object of dynamic type 'const Class::Derived' to type 'Class::Base'}}
constexpr Base2 &ok2 = (Base2&)bot2;
static_assert(&ok2 == &derived, "");
-constexpr Base2 *pfail = (Base2*)pb1; // expected-error {{constant expression}}
-constexpr Base *pfail2 = (Base*)&bot2; // expected-error {{constant expression}}
+constexpr Base2 *pfail = (Base2*)pb1; // expected-error {{constant expression}} expected-note {{cannot cast object of dynamic type 'const Class::Derived' to type 'Class::Base2'}}
+constexpr Base *pfail2 = (Base*)&bot2; // expected-error {{constant expression}} expected-note {{cannot cast object of dynamic type 'const Class::Derived' to type 'Class::Base'}}
constexpr Base2 *pok2 = (Base2*)pb2;
static_assert(pok2 == &derived, "");
static_assert(&ok2 == pok2, "");
@@ -723,7 +723,7 @@
static_assert(u[0].b, ""); // expected-error {{constant expression}} expected-note {{read of member 'b' of union with active member 'a'}}
static_assert(u[1].b == 1, "");
static_assert((&u[1].b)[1] == 2, ""); // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
-static_assert(*(&(u[1].b) + 1 + 1) == 3, ""); // expected-error {{constant expression}} expected-note {{subexpression}}
+static_assert(*(&(u[1].b) + 1 + 1) == 3, ""); // expected-error {{constant expression}} expected-note {{cannot refer to element 2 of non-array object}}
static_assert((&(u[1]) + 1 + 1)->b == 3, "");
}
@@ -798,7 +798,7 @@
constexpr T<5> *p17_5 = &t17;
constexpr T<13> *p17_13 = (T<13>*)p17_5;
- constexpr T<23> *p17_23 = (T<23>*)p17_13; // expected-error {{constant expression}}
+ constexpr T<23> *p17_23 = (T<23>*)p17_13; // expected-error {{constant expression}} expected-note {{cannot cast object of dynamic type 'T<17>' to type 'T<23>'}}
static_assert(&(p17_5->*(int(T<3>::*))deepn) == &t17.n, "");
static_assert(&(p17_13->*deepn) == &t17.n, "");
constexpr int *pbad2 = &(p17_13->*(int(T<9>::*))deepm); // expected-error {{constant expression}}
@@ -832,15 +832,15 @@
// pb3 does not point to an array element.
constexpr Base *pb4 = pb3 + 1; // ok, one-past-the-end pointer.
- constexpr int pb4n = pb4->n; // expected-error {{constant expression}}
- constexpr Base *err_pb5 = pb3 + 2; // FIXME: reject this.
- constexpr int err_pb5n = err_pb5->n; // expected-error {{constant expression}}
- constexpr Base *err_pb2 = pb3 - 1; // FIXME: reject this.
- constexpr int err_pb2n = err_pb2->n; // expected-error {{constant expression}}
+ constexpr int pb4n = pb4->n; // expected-error {{constant expression}} expected-note {{cannot access field of pointer past the end}}
+ constexpr Base *err_pb5 = pb3 + 2; // expected-error {{constant expression}} expected-note {{cannot refer to element 2}} expected-note {{here}}
+ constexpr int err_pb5n = err_pb5->n; // expected-error {{constant expression}} expected-note {{initializer of 'err_pb5' is not a constant expression}}
+ constexpr Base *err_pb2 = pb3 - 1; // expected-error {{constant expression}} expected-note {{cannot refer to element -1}} expected-note {{here}}
+ constexpr int err_pb2n = err_pb2->n; // expected-error {{constant expression}} expected-note {{initializer of 'err_pb2'}}
constexpr Base *pb3a = pb4 - 1;
// pb4 does not point to a Derived.
- constexpr Derived *err_pd4 = (Derived*)pb4; // expected-error {{constant expression}}
+ constexpr Derived *err_pd4 = (Derived*)pb4; // expected-error {{constant expression}} expected-note {{cannot access derived class of pointer past the end}}
constexpr Derived *pd3a = (Derived*)pb3a;
constexpr int pd3n = pd3a->n;
@@ -850,10 +850,9 @@
constexpr Derived *pd9 = pd6 + 3;
constexpr Derived *pd10 = pd6 + 4;
constexpr int pd9n = pd9->n; // ok
- constexpr int err_pd10n = pd10->n; // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
+ constexpr int err_pd10n = pd10->n; // expected-error {{constant expression}} expected-note {{cannot access base class of pointer past the end}}
constexpr int pd0n = pd10[-10].n;
- // FIXME: check pointer arithmetic here.
- constexpr int err_pdminus1n = pd10[-11].n; // expected-error {{constant expression}} expected-note {{read of dereferenced one-past-the-end pointer}}
+ constexpr int err_pdminus1n = pd10[-11].n; // expected-error {{constant expression}} expected-note {{cannot refer to element -1 of}}
constexpr Base *pb9 = pd9;
constexpr const int *(Base::*pfb)() const =
Modified: cfe/trunk/test/SemaCXX/constexpr-backtrace-limit.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/constexpr-backtrace-limit.cpp?rev=147659&r1=147658&r2=147659&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/constexpr-backtrace-limit.cpp (original)
+++ cfe/trunk/test/SemaCXX/constexpr-backtrace-limit.cpp Fri Jan 6 10:39:00 2012
@@ -15,14 +15,14 @@
// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 2 -fconstexpr-depth 8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST3
// TEST3: constant expression
-// TEST3-NEXT: subexpression
+// TEST3-NEXT: reinterpret_cast
// TEST3-NEXT: in call to 'recurse(0)'
// TEST3-NEXT: skipping 4 calls
// TEST3-NEXT: in call to 'recurse(5)'
// RUN: %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit 8 -fconstexpr-depth 8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST4
// TEST4: constant expression
-// TEST4-NEXT: subexpression
+// TEST4-NEXT: reinterpret_cast
// TEST4-NEXT: in call to 'recurse(0)'
// TEST4-NEXT: in call to 'recurse(1)'
// TEST4-NEXT: in call to 'recurse(2)'
More information about the cfe-commits
mailing list