diff options
author | Martin Bohme <mboehme@google.com> | 2017-08-30 10:44:46 +0000 |
---|---|---|
committer | Martin Bohme <mboehme@google.com> | 2017-08-30 10:44:46 +0000 |
commit | c259e431a5e80c73ee1df96d1f323defbc796aee (patch) | |
tree | 5aaf4ddae83eae1423403e47341c66b75fa9637d | |
parent | 1bf18299ccace7b34db3a95958e3f80b1fa5ba57 (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.td | 9 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticIDs.h | 2 | ||||
-rw-r--r-- | lib/AST/ExprConstant.cpp | 85 | ||||
-rw-r--r-- | test/SemaCXX/constant-expression-cxx11.cpp | 28 |
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]; }; |