diff options
| author | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-10-21 23:01:04 +0000 |
|---|---|---|
| committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2014-10-21 23:01:04 +0000 |
| commit | d20f1e6dd3153e2cda30addf79fb9f781a3449aa (patch) | |
| tree | b1f7cfba70b80a77bf894519ee9e408afb70cd6b /clang | |
| parent | 7c93690be029a86d98cdad59ec4cb858c47e284f (diff) | |
| download | bcm5719-llvm-d20f1e6dd3153e2cda30addf79fb9f781a3449aa.tar.gz bcm5719-llvm-d20f1e6dd3153e2cda30addf79fb9f781a3449aa.zip | |
PR21327 / C++ DR1652 / C++ DR73: comparing a past-the-end pointer for one
complete object to a pointer to the start of another complete object does
not evaluate to the constant 'false'. All other comparisons between the
addresses of subobjects of distinct complete objects still do.
llvm-svn: 220343
Diffstat (limited to 'clang')
| -rw-r--r-- | clang/lib/AST/ExprConstant.cpp | 28 | ||||
| -rw-r--r-- | clang/test/CXX/drs/dr0xx.cpp | 2 | ||||
| -rw-r--r-- | clang/test/SemaCXX/constant-expression-cxx11.cpp | 4 |
3 files changed, 33 insertions, 1 deletions
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 532720666bc..78de2578bee 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -6461,6 +6461,27 @@ static bool HasSameBase(const LValue &A, const LValue &B) { A.getLValueCallIndex() == B.getLValueCallIndex(); } +/// \brief Determine whether this is a pointer past the end of the complete +/// object referred to by the lvalue. +static bool isOnePastTheEndOfCompleteObject(const ASTContext &Ctx, + const LValue &LV) { + // A null pointer can be viewed as being "past the end" but we don't + // choose to look at it that way here. + if (!LV.getLValueBase()) + return false; + + // If the designator is valid and refers to a subobject, we're not pointing + // past the end. + if (!LV.getLValueDesignator().Invalid && + !LV.getLValueDesignator().isOnePastTheEnd()) + return false; + + // We're a past-the-end pointer if we point to the byte after the object, + // no matter what our type or path is. + auto Size = Ctx.getTypeSizeInChars(getType(LV.getLValueBase())); + return LV.getLValueOffset() == Size; +} + namespace { /// \brief Data recursive integer evaluator of certain binary operators. @@ -6923,6 +6944,13 @@ bool IntExprEvaluator::VisitBinaryOperator(const BinaryOperator *E) { // object. if (IsWeakLValue(LHSValue) || IsWeakLValue(RHSValue)) return Error(E); + // We can't compare the address of the start of one object with the + // past-the-end address of another object, per C++ DR1652. + if ((LHSValue.Base && LHSValue.Offset.isZero() && + isOnePastTheEndOfCompleteObject(Info.Ctx, RHSValue)) || + (RHSValue.Base && RHSValue.Offset.isZero() && + isOnePastTheEndOfCompleteObject(Info.Ctx, LHSValue))) + return Error(E); // Pointers with different bases cannot represent the same object. // (Note that clang defaults to -fmerge-all-constants, which can // lead to inconsistent results for comparisons involving the address diff --git a/clang/test/CXX/drs/dr0xx.cpp b/clang/test/CXX/drs/dr0xx.cpp index 781c1883ff8..011b4201b0b 100644 --- a/clang/test/CXX/drs/dr0xx.cpp +++ b/clang/test/CXX/drs/dr0xx.cpp @@ -823,7 +823,7 @@ namespace dr70 { // dr70: yes namespace dr73 { // dr73: no // The resolution to dr73 is unworkable. Consider: int a, b; - static_assert(&a + 1 != &b, ""); + static_assert(&a + 1 != &b, ""); // expected-error {{not an integral constant expression}} } #endif diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp index 24a9d670e87..7c938d54ffa 100644 --- a/clang/test/SemaCXX/constant-expression-cxx11.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp @@ -1935,3 +1935,7 @@ namespace PR19010 { }; void test() { constexpr Test t; } } + +void PR21327(int a, int b) { + static_assert(&a + 1 != &b, ""); // expected-error {{constant expression}} +} |

