| commit 9083d0a40d980928f2f45236a4616528a7ab19ce |
| Author: einvbri <vince.a.bridgers@ericsson.com> |
| Date: Mon Feb 8 06:38:31 2021 -0600 |
| |
| Revert "[Sema] Fix -Warray-bounds false negative when casting an out-of-bounds array item" |
| |
| This reverts commit e48f444751cf781c42934b242b81f549da77bad0. |
| |
| thakis noticed false reports, so reverting this change for now until |
| those can be sorted out. |
| |
| See https://reviews.llvm.org/D71714 |
| |
| diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h |
| index 68420fcbb85f..8b5619945865 100644 |
| --- a/clang/include/clang/Sema/Sema.h |
| +++ b/clang/include/clang/Sema/Sema.h |
| @@ -12313,7 +12313,7 @@ private: |
| void CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, |
| const ArraySubscriptExpr *ASE=nullptr, |
| bool AllowOnePastEnd=true, bool IndexNegated=false); |
| - void CheckArrayAccess(const Expr *E, int AllowOnePastEnd = 0); |
| + void CheckArrayAccess(const Expr *E); |
| // Used to grab the relevant information from a FormatAttr and a |
| // FunctionDeclaration. |
| struct FormatStringInfo { |
| diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp |
| index 17dd5c9e8d99..2d3d36f4adad 100644 |
| --- a/clang/lib/Sema/SemaChecking.cpp |
| +++ b/clang/lib/Sema/SemaChecking.cpp |
| @@ -14387,63 +14387,62 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, |
| PDiag(diag::note_array_declared_here) << ND); |
| } |
| |
| -void Sema::CheckArrayAccess(const Expr *expr, int AllowOnePastEnd) { |
| - if (!expr) |
| - return; |
| - |
| - expr = expr->IgnoreParenCasts(); |
| - switch (expr->getStmtClass()) { |
| - case Stmt::ArraySubscriptExprClass: { |
| - const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(expr); |
| - CheckArrayAccess(ASE->getBase(), ASE->getIdx(), ASE, AllowOnePastEnd > 0); |
| - CheckArrayAccess(ASE->getBase(), AllowOnePastEnd); |
| - return; |
| - } |
| - case Stmt::MemberExprClass: { |
| - expr = cast<MemberExpr>(expr)->getBase(); |
| - CheckArrayAccess(expr, /*AllowOnePastEnd=*/0); |
| - return; |
| - } |
| - case Stmt::OMPArraySectionExprClass: { |
| - const OMPArraySectionExpr *ASE = cast<OMPArraySectionExpr>(expr); |
| - if (ASE->getLowerBound()) |
| - CheckArrayAccess(ASE->getBase(), ASE->getLowerBound(), |
| - /*ASE=*/nullptr, AllowOnePastEnd > 0); |
| - return; |
| - } |
| - case Stmt::UnaryOperatorClass: { |
| - // Only unwrap the * and & unary operators |
| - const UnaryOperator *UO = cast<UnaryOperator>(expr); |
| - expr = UO->getSubExpr(); |
| - switch (UO->getOpcode()) { |
| - case UO_AddrOf: |
| - AllowOnePastEnd++; |
| - break; |
| - case UO_Deref: |
| - AllowOnePastEnd--; |
| - break; |
| - default: |
| - return; |
| +void Sema::CheckArrayAccess(const Expr *expr) { |
| + int AllowOnePastEnd = 0; |
| + while (expr) { |
| + expr = expr->IgnoreParenImpCasts(); |
| + switch (expr->getStmtClass()) { |
| + case Stmt::ArraySubscriptExprClass: { |
| + const ArraySubscriptExpr *ASE = cast<ArraySubscriptExpr>(expr); |
| + CheckArrayAccess(ASE->getBase(), ASE->getIdx(), ASE, |
| + AllowOnePastEnd > 0); |
| + expr = ASE->getBase(); |
| + break; |
| + } |
| + case Stmt::MemberExprClass: { |
| + expr = cast<MemberExpr>(expr)->getBase(); |
| + break; |
| + } |
| + case Stmt::OMPArraySectionExprClass: { |
| + const OMPArraySectionExpr *ASE = cast<OMPArraySectionExpr>(expr); |
| + if (ASE->getLowerBound()) |
| + CheckArrayAccess(ASE->getBase(), ASE->getLowerBound(), |
| + /*ASE=*/nullptr, AllowOnePastEnd > 0); |
| + return; |
| + } |
| + case Stmt::UnaryOperatorClass: { |
| + // Only unwrap the * and & unary operators |
| + const UnaryOperator *UO = cast<UnaryOperator>(expr); |
| + expr = UO->getSubExpr(); |
| + switch (UO->getOpcode()) { |
| + case UO_AddrOf: |
| + AllowOnePastEnd++; |
| + break; |
| + case UO_Deref: |
| + AllowOnePastEnd--; |
| + break; |
| + default: |
| + return; |
| + } |
| + break; |
| + } |
| + case Stmt::ConditionalOperatorClass: { |
| + const ConditionalOperator *cond = cast<ConditionalOperator>(expr); |
| + if (const Expr *lhs = cond->getLHS()) |
| + CheckArrayAccess(lhs); |
| + if (const Expr *rhs = cond->getRHS()) |
| + CheckArrayAccess(rhs); |
| + return; |
| + } |
| + case Stmt::CXXOperatorCallExprClass: { |
| + const auto *OCE = cast<CXXOperatorCallExpr>(expr); |
| + for (const auto *Arg : OCE->arguments()) |
| + CheckArrayAccess(Arg); |
| + return; |
| + } |
| + default: |
| + return; |
| } |
| - CheckArrayAccess(expr, AllowOnePastEnd); |
| - return; |
| - } |
| - case Stmt::ConditionalOperatorClass: { |
| - const ConditionalOperator *cond = cast<ConditionalOperator>(expr); |
| - if (const Expr *lhs = cond->getLHS()) |
| - CheckArrayAccess(lhs, AllowOnePastEnd); |
| - if (const Expr *rhs = cond->getRHS()) |
| - CheckArrayAccess(rhs, AllowOnePastEnd); |
| - return; |
| - } |
| - case Stmt::CXXOperatorCallExprClass: { |
| - const auto *OCE = cast<CXXOperatorCallExpr>(expr); |
| - for (const auto *Arg : OCE->arguments()) |
| - CheckArrayAccess(Arg); |
| - return; |
| - } |
| - default: |
| - return; |
| } |
| } |
| |
| diff --git a/clang/test/Parser/cxx-ambig-decl-expr.cpp b/clang/test/Parser/cxx-ambig-decl-expr.cpp |
| index 373fe250c6b5..6203db2fbd22 100644 |
| --- a/clang/test/Parser/cxx-ambig-decl-expr.cpp |
| +++ b/clang/test/Parser/cxx-ambig-decl-expr.cpp |
| @@ -24,7 +24,7 @@ void arr() { |
| |
| // This is array indexing not an array declarator because a comma expression |
| // is not syntactically a constant-expression. |
| - int(x[1,0]); // expected-warning 2{{unused}} |
| + int(x[1,1]); // expected-warning 2{{unused}} |
| |
| // This is array indexing not an array declaration because a braced-init-list |
| // is not syntactically a constant-expression. |
| diff --git a/clang/test/SemaCXX/array-bounds.cpp b/clang/test/SemaCXX/array-bounds.cpp |
| index 837175014fe5..47be6c2423dc 100644 |
| --- a/clang/test/SemaCXX/array-bounds.cpp |
| +++ b/clang/test/SemaCXX/array-bounds.cpp |
| @@ -27,7 +27,7 @@ template <char *sz> class Qux { |
| }; |
| |
| void f1(int a[1]) { |
| - int val = a[3]; // no warning for function argument |
| + int val = a[3]; // no warning for function argumnet |
| } |
| |
| void f2(const int (&a)[2]) { // expected-note {{declared here}} |
| @@ -133,7 +133,7 @@ int test_pr9296() { |
| |
| int test_sizeof_as_condition(int flag) { |
| int arr[2] = { 0, 0 }; // expected-note {{array 'arr' declared here}} |
| - if (flag) |
| + if (flag) |
| return sizeof(char) != sizeof(char) ? arr[2] : arr[1]; |
| return sizeof(char) == sizeof(char) ? arr[2] : arr[1]; // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}} |
| } |
| @@ -241,7 +241,7 @@ void test_pr10771() { |
| } |
| |
| int test_pr11007_aux(const char * restrict, ...); |
| - |
| + |
| // Test checking with varargs. |
| void test_pr11007() { |
| double a[5]; // expected-note {{array 'a' declared here}} |
| @@ -320,33 +320,3 @@ void test() { |
| arr<float>[1] = 0; // expected-warning {{array index 1 is past the end of the array (which contains 1 element)}} |
| } |
| } // namespace var_template_array |
| - |
| -namespace PR44343 { |
| - const unsigned int array[2] = {0, 1}; // expected-note 5{{array 'array' declared here}} |
| - |
| - const int i1 = (const int)array[2]; // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}} |
| - const int i2 = static_cast<const int>(array[2]); // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}} |
| - const int &i3 = reinterpret_cast<const int&>(array[2]); // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}} |
| - unsigned int &i4 = const_cast<unsigned int&>(array[2]); // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}} |
| - int i5 = int(array[2]); // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}} |
| - const unsigned int *i6 = &(1 > 0 ? array[2] : array[1]); // no warning for one-past-end element's address retrieval |
| - |
| - // Test dynamic cast |
| - struct Base { |
| - virtual ~Base(); |
| - }; |
| - struct Derived : Base { |
| - }; |
| - Base baseArr[2]; // expected-note {{array 'baseArr' declared here}} |
| - Derived *d1 = dynamic_cast<Derived *>(&baseArr[2]); // FIXME: Should actually warn because dynamic_cast accesses the vptr |
| - Derived &d2 = dynamic_cast<Derived &>(baseArr[2]); // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}} |
| - |
| - // Test operator `&` in combination with operators `.` and `->` |
| - struct A { |
| - int n; |
| - }; |
| - A a[2]; // expected-note {{array 'a' declared here}} |
| - int *n = &a[2].n; // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}} |
| - A *aPtr[2]; // expected-note {{array 'aPtr' declared here}} |
| - int *n2 = &aPtr[2]->n; // expected-warning {{array index 2 is past the end of the array (which contains 2 elements)}} |
| -} |