diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index a6f80e3721db1..fbbd4836e8786 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -69,7 +69,7 @@ Potentially Breaking Changes - `CharTypdefsToIgnore` to `CharTypedefsToIgnore` in :doc:`bugprone-signed-char-misuse ` - + - Modified the custom message format of :doc:`bugprone-unsafe-functions ` by assigning a special meaning to the character ``>`` at the start of the value of the option @@ -394,7 +394,7 @@ Changes in existing checks ` check by adding an additional matcher that generalizes the copy-and-swap idiom pattern detection. - + - Improved :doc:`bugprone-unsafe-functions ` check by hiding the default suffix when the reason starts with the character `>` in the `CustomFunctions` @@ -447,7 +447,8 @@ Changes in existing checks positives when pointers is transferred to non-const references and avoid false positives of function pointer and fix false positives on return of non-const pointer and fix false positives on - pointer-to-member operator. + pointer-to-member operator and avoid false positives when the address + of a variable is taken to be passed to a function. - Improved :doc:`misc-coroutine-hostile-raii ` check by adding the option diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-pointer-as-pointers.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-pointer-as-pointers.cpp index 4c847b58d395c..0cb58c2e83643 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-pointer-as-pointers.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-pointer-as-pointers.cpp @@ -73,3 +73,18 @@ void ignoreNonConstRefOps() { int* p2 {nullptr}; int*& r2 = (int*&)p2; } + +void pointer_to_pointer_param(int**); +void pass_address_to_pointer_to_pointer() { + int i = 0; + int* ip = &i; + // CHECK-NOT: warning + pointer_to_pointer_param(&ip); +} + +void void_pointer_to_pointer_param(void**); +void pass_address_to_void_pointer_to_pointer() { + void* ptr = nullptr; + // CHECK-NOT: warning + void_pointer_to_pointer_param(&ptr); +} diff --git a/clang/lib/Analysis/ExprMutationAnalyzer.cpp b/clang/lib/Analysis/ExprMutationAnalyzer.cpp index 2f40c7e4888e3..86d7dcab807d3 100644 --- a/clang/lib/Analysis/ExprMutationAnalyzer.cpp +++ b/clang/lib/Analysis/ExprMutationAnalyzer.cpp @@ -135,6 +135,11 @@ class ExprPointeeResolve { if (const auto *PE = dyn_cast(E)) return resolveExpr(PE->getSubExpr()); + if (const auto *UO = dyn_cast(E)) { + if (UO->getOpcode() == UO_AddrOf) + return resolveExpr(UO->getSubExpr()); + } + if (const auto *ICE = dyn_cast(E)) { // only implicit cast needs to be treated as resolvable. // explicit cast will be checked in `findPointeeToNonConst` diff --git a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp index 8fc9a66dbda7e..d171d47ac1fef 100644 --- a/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp +++ b/clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp @@ -2091,4 +2091,21 @@ TEST(ExprMutationAnalyzerTest, PointeeMutatedByPointerToMemberOperator) { EXPECT_TRUE(isPointeeMutated(Results, AST.get())); } +TEST(ExprMutationAnalyzerTest, PointeeMutatedByPassAsPointerToPointer) { + { + const std::string Code = "void f(int**); void g() { int* ip; f(&ip); }"; + auto AST = buildASTFromCode(Code); + auto Results = + match(withEnclosingCompound(declRefTo("ip")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } + { + const std::string Code = "void f(void**); void g() { void* ip; f(&ip); }"; + auto AST = buildASTFromCode(Code); + auto Results = + match(withEnclosingCompound(declRefTo("ip")), AST->getASTContext()); + EXPECT_TRUE(isPointeeMutated(Results, AST.get())); + } +} + } // namespace clang