summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Bohme <mboehme@google.com>2017-08-30 10:44:46 +0000
committerMartin Bohme <mboehme@google.com>2017-08-30 10:44:46 +0000
commitc259e431a5e80c73ee1df96d1f323defbc796aee (patch)
tree5aaf4ddae83eae1423403e47341c66b75fa9637d
parent1bf18299ccace7b34db3a95958e3f80b1fa5ba57 (diff)
Revert "Improve constant expression evaluation of arrays of unknown bound."
This reverts commit r311970. Breaks internal tests. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@312108 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/clang/Basic/DiagnosticASTKinds.td9
-rw-r--r--include/clang/Basic/DiagnosticIDs.h2
-rw-r--r--lib/AST/ExprConstant.cpp85
-rw-r--r--test/SemaCXX/constant-expression-cxx11.cpp28
4 files changed, 27 insertions, 97 deletions
diff --git a/include/clang/Basic/DiagnosticASTKinds.td b/include/clang/Basic/DiagnosticASTKinds.td
index 215580b2e9..b3cba2066e 100644
--- a/include/clang/Basic/DiagnosticASTKinds.td
+++ b/include/clang/Basic/DiagnosticASTKinds.td
@@ -127,10 +127,6 @@ def note_constexpr_access_null : Note<
def note_constexpr_access_past_end : Note<
"%select{read of|assignment to|increment of|decrement of}0 "
"dereferenced one-past-the-end pointer is not allowed in a constant expression">;
-def note_constexpr_access_unsized_array : Note<
- "%select{read of|assignment to|increment of|decrement of}0 "
- "pointer to element of array without known bound "
- "is not allowed in a constant expression">;
def note_constexpr_access_inactive_union_member : Note<
"%select{read of|assignment to|increment of|decrement of}0 "
"member %1 of union with %select{active member %3|no active member}2 "
@@ -158,11 +154,6 @@ def note_constexpr_baa_insufficient_alignment : Note<
def note_constexpr_baa_value_insufficient_alignment : Note<
"value of the aligned pointer (%0) is not a multiple of the asserted %1 "
"%plural{1:byte|:bytes}1">;
-def note_constexpr_unsupported_unsized_array : Note<
- "array-to-pointer decay of array member without known bound is not supported">;
-def note_constexpr_unsized_array_indexed : Note<
- "indexing of array without known bound is not allowed "
- "in a constant expression">;
def warn_integer_constant_overflow : Warning<
"overflow in expression; result is %0 with type %1">,
diff --git a/include/clang/Basic/DiagnosticIDs.h b/include/clang/Basic/DiagnosticIDs.h
index 17a9d8a44f..0ec6886626 100644
--- a/include/clang/Basic/DiagnosticIDs.h
+++ b/include/clang/Basic/DiagnosticIDs.h
@@ -34,7 +34,7 @@ namespace clang {
DIAG_SIZE_SERIALIZATION = 120,
DIAG_SIZE_LEX = 400,
DIAG_SIZE_PARSE = 500,
- DIAG_SIZE_AST = 150,
+ DIAG_SIZE_AST = 110,
DIAG_SIZE_COMMENT = 100,
DIAG_SIZE_SEMA = 3500,
DIAG_SIZE_ANALYSIS = 100
diff --git a/lib/AST/ExprConstant.cpp b/lib/AST/ExprConstant.cpp
index 3af64bc09a..be4b3af4d6 100644
--- a/lib/AST/ExprConstant.cpp
+++ b/lib/AST/ExprConstant.cpp
@@ -141,12 +141,6 @@ namespace {
return E && E->getType()->isPointerType() && tryUnwrapAllocSizeCall(E);
}
- /// The bound to claim that an array of unknown bound has.
- /// The value in MostDerivedArraySize is undefined in this case. So, set it
- /// to an arbitrary value that's likely to loudly break things if it's used.
- static const uint64_t AssumedSizeForUnsizedArray =
- std::numeric_limits<uint64_t>::max() / 2;
-
/// Determines if an LValue with the given LValueBase will have an unsized
/// array in its designator.
/// Find the path length and type of the most-derived subobject in the given
@@ -154,8 +148,7 @@ namespace {
static unsigned
findMostDerivedSubobject(ASTContext &Ctx, APValue::LValueBase Base,
ArrayRef<APValue::LValuePathEntry> Path,
- uint64_t &ArraySize, QualType &Type, bool &IsArray,
- bool &FirstEntryIsUnsizedArray) {
+ uint64_t &ArraySize, QualType &Type, bool &IsArray) {
// This only accepts LValueBases from APValues, and APValues don't support
// arrays that lack size info.
assert(!isBaseAnAllocSizeCall(Base) &&
@@ -165,18 +158,12 @@ namespace {
for (unsigned I = 0, N = Path.size(); I != N; ++I) {
if (Type->isArrayType()) {
- const ArrayType *AT = Ctx.getAsArrayType(Type);
- Type = AT->getElementType();
+ const ConstantArrayType *CAT =
+ cast<ConstantArrayType>(Ctx.getAsArrayType(Type));
+ Type = CAT->getElementType();
+ ArraySize = CAT->getSize().getZExtValue();
MostDerivedLength = I + 1;
IsArray = true;
-
- if (auto *CAT = dyn_cast<ConstantArrayType>(AT)) {
- ArraySize = CAT->getSize().getZExtValue();
- } else {
- assert(I == 0 && "unexpected unsized array designator");
- FirstEntryIsUnsizedArray = true;
- ArraySize = AssumedSizeForUnsizedArray;
- }
} else if (Type->isAnyComplexType()) {
const ComplexType *CT = Type->castAs<ComplexType>();
Type = CT->getElementType();
@@ -259,12 +246,10 @@ namespace {
Entries.insert(Entries.end(), VEntries.begin(), VEntries.end());
if (V.getLValueBase()) {
bool IsArray = false;
- bool FirstIsUnsizedArray = false;
MostDerivedPathLength = findMostDerivedSubobject(
Ctx, V.getLValueBase(), V.getLValuePath(), MostDerivedArraySize,
- MostDerivedType, IsArray, FirstIsUnsizedArray);
+ MostDerivedType, IsArray);
MostDerivedIsArrayElement = IsArray;
- FirstEntryIsAnUnsizedArray = FirstIsUnsizedArray;
}
}
}
@@ -333,7 +318,7 @@ namespace {
// The value in MostDerivedArraySize is undefined in this case. So, set it
// to an arbitrary value that's likely to loudly break things if it's
// used.
- MostDerivedArraySize = AssumedSizeForUnsizedArray;
+ MostDerivedArraySize = std::numeric_limits<uint64_t>::max() / 2;
MostDerivedPathLength = Entries.size();
}
/// Update this designator to refer to the given base or member of this
@@ -365,7 +350,6 @@ namespace {
MostDerivedArraySize = 2;
MostDerivedPathLength = Entries.size();
}
- void diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info, const Expr *E);
void diagnosePointerArithmetic(EvalInfo &Info, const Expr *E,
const APSInt &N);
/// Add N to the address of this subobject.
@@ -373,7 +357,6 @@ namespace {
if (Invalid || !N) return;
uint64_t TruncatedN = N.extOrTrunc(64).getZExtValue();
if (isMostDerivedAnUnsizedArray()) {
- diagnoseUnsizedArrayPointerArithmetic(Info, E);
// Can't verify -- trust that the user is doing the right thing (or if
// not, trust that the caller will catch the bad behavior).
// FIXME: Should we reject if this overflows, at least?
@@ -1085,19 +1068,9 @@ bool SubobjectDesignator::checkSubobject(EvalInfo &Info, const Expr *E,
setInvalid();
return false;
}
- // Note, we do not diagnose if isMostDerivedAnUnsizedArray(), because there
- // must actually be at least one array element; even a VLA cannot have a
- // bound of zero. And if our index is nonzero, we already had a CCEDiag.
return true;
}
-void SubobjectDesignator::diagnoseUnsizedArrayPointerArithmetic(EvalInfo &Info,
- const Expr *E) {
- Info.CCEDiag(E, diag::note_constexpr_unsized_array_indexed);
- // Do not set the designator as invalid: we can represent this situation,
- // and correct handling of __builtin_object_size requires us to do so.
-}
-
void SubobjectDesignator::diagnosePointerArithmetic(EvalInfo &Info,
const Expr *E,
const APSInt &N) {
@@ -1241,6 +1214,8 @@ namespace {
IsNullPtr);
else {
assert(!InvalidBase && "APValues can't handle invalid LValue bases");
+ assert(!Designator.FirstEntryIsAnUnsizedArray &&
+ "Unsized array with a valid base?");
V = APValue(Base, Offset, Designator.Entries,
Designator.IsOnePastTheEnd, CallIndex, IsNullPtr);
}
@@ -1313,14 +1288,10 @@ namespace {
if (checkSubobject(Info, E, isa<FieldDecl>(D) ? CSK_Field : CSK_Base))
Designator.addDeclUnchecked(D, Virtual);
}
- void addUnsizedArray(EvalInfo &Info, const Expr *E, QualType ElemTy) {
- if (!Designator.Entries.empty()) {
- Info.CCEDiag(E, diag::note_constexpr_unsupported_unsized_array);
- Designator.setInvalid();
- return;
- }
-
- assert(getType(Base)->isPointerType() || getType(Base)->isArrayType());
+ void addUnsizedArray(EvalInfo &Info, QualType ElemTy) {
+ assert(Designator.Entries.empty() && getType(Base)->isPointerType());
+ assert(isBaseAnAllocSizeCall(Base) &&
+ "Only alloc_size bases can have unsized arrays");
Designator.FirstEntryIsAnUnsizedArray = true;
Designator.addUnsizedArrayUnchecked(ElemTy);
}
@@ -2627,12 +2598,10 @@ findSubobject(EvalInfo &Info, const Expr *E, const CompleteObject &Obj,
if (Sub.Invalid)
// A diagnostic will have already been produced.
return handler.failed();
- if (Sub.isOnePastTheEnd() || Sub.isMostDerivedAnUnsizedArray()) {
+ if (Sub.isOnePastTheEnd()) {
if (Info.getLangOpts().CPlusPlus11)
- Info.FFDiag(E, Sub.isOnePastTheEnd()
- ? diag::note_constexpr_access_past_end
- : diag::note_constexpr_access_unsized_array)
- << handler.AccessKind;
+ Info.FFDiag(E, diag::note_constexpr_access_past_end)
+ << handler.AccessKind;
else
Info.FFDiag(E);
return handler.failed();
@@ -5491,7 +5460,7 @@ static bool evaluateLValueAsAllocSize(EvalInfo &Info, APValue::LValueBase Base,
Result.setInvalid(E);
QualType Pointee = E->getType()->castAs<PointerType>()->getPointeeType();
- Result.addUnsizedArray(Info, E, Pointee);
+ Result.addUnsizedArray(Info, Pointee);
return true;
}
@@ -5701,8 +5670,7 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return true;
}
}
-
- case CK_ArrayToPointerDecay: {
+ case CK_ArrayToPointerDecay:
if (SubExpr->isGLValue()) {
if (!evaluateLValue(SubExpr, Result))
return false;
@@ -5713,13 +5681,12 @@ bool PointerExprEvaluator::VisitCastExpr(const CastExpr* E) {
return false;
}
// The result is a pointer to the first element of the array.
- auto *AT = Info.Ctx.getAsArrayType(SubExpr->getType());
- if (auto *CAT = dyn_cast<ConstantArrayType>(AT))
+ if (const ConstantArrayType *CAT
+ = Info.Ctx.getAsConstantArrayType(SubExpr->getType()))
Result.addArray(Info, E, CAT);
else
- Result.addUnsizedArray(Info, E, AT->getElementType());
+ Result.Designator.setInvalid();
return true;
- }
case CK_FunctionToPointerDecay:
return evaluateLValue(SubExpr, Result);
@@ -5786,7 +5753,7 @@ bool PointerExprEvaluator::visitNonBuiltinCallExpr(const CallExpr *E) {
Result.setInvalid(E);
QualType PointeeTy = E->getType()->castAs<PointerType>()->getPointeeType();
- Result.addUnsizedArray(Info, E, PointeeTy);
+ Result.addUnsizedArray(Info, PointeeTy);
return true;
}
@@ -7347,8 +7314,7 @@ static const Expr *ignorePointerCastsAndParens(const Expr *E) {
/// Please note: this function is specialized for how __builtin_object_size
/// views "objects".
///
-/// If this encounters an invalid RecordDecl or otherwise cannot determine the
-/// correct result, it will always return true.
+/// If this encounters an invalid RecordDecl, it will always return true.
static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
assert(!LVal.Designator.Invalid);
@@ -7379,8 +7345,9 @@ static bool isDesignatorAtObjectEnd(const ASTContext &Ctx, const LValue &LVal) {
unsigned I = 0;
QualType BaseType = getType(Base);
if (LVal.Designator.FirstEntryIsAnUnsizedArray) {
- // If we don't know the array bound, conservatively assume we're looking at
- // the final array element.
+ assert(isBaseAnAllocSizeCall(Base) &&
+ "Unsized array in non-alloc_size call?");
+ // If this is an alloc_size base, we should ignore the initial array index
++I;
BaseType = BaseType->castAs<PointerType>()->getPointeeType();
}
diff --git a/test/SemaCXX/constant-expression-cxx11.cpp b/test/SemaCXX/constant-expression-cxx11.cpp
index 4504a97261..3fda2d0a7f 100644
--- a/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/test/SemaCXX/constant-expression-cxx11.cpp
@@ -604,34 +604,6 @@ static_assert(NATDCArray{}[1][1].n == 0, "");
}
-// FIXME: The rules in this case are unclear, but we conservatively choose to
-// reject any cases where pointer arithmetic is not statically known to be
-// valid.
-namespace ArrayOfUnknownBound {
- extern int arr[];
- constexpr int *a = arr;
- constexpr int *b = &arr[0];
- static_assert(a == b, "");
- constexpr int *c = &arr[1]; // expected-error {{constant}} expected-note {{indexing of array without known bound}}
- constexpr int *d = &a[1]; // expected-error {{constant}} expected-note {{indexing of array without known bound}}
- constexpr int *e = a + 1; // expected-error {{constant}} expected-note {{indexing of array without known bound}}
-
- struct X {
- int a;
- int b[]; // expected-warning {{C99}}
- };
- extern X x;
- constexpr int *xb = x.b; // expected-error {{constant}} expected-note {{not supported}}
-
- struct Y { int a; };
- extern Y yarr[];
- constexpr Y *p = yarr;
- constexpr int *q = &p->a;
-
- extern const int carr[]; // expected-note {{here}}
- constexpr int n = carr[0]; // expected-error {{constant}} expected-note {{non-constexpr variable}}
-}
-
namespace DependentValues {
struct I { int n; typedef I V[10]; };