llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-static-analyzer-1

Author: Balázs Benics (steakhal)

<details>
<summary>Changes</summary>

When a friend function template is defined inline inside a 
[[clang::suppress]]-annotated class but was forward-declared at namespace 
scope, the instantiation's lexical DeclContext was the namespace (from the 
forward-declaration), not the class.
The lexical parent chain walk in BugSuppression::isSuppressed therefore never 
reached the class and suppression did not apply.

Fix by extending preferTemplateDefinitionForTemplateSpecializations to handle 
FunctionDecl instances: calling getTemplateInstantiationPattern() that maps the 
instantiation back to the primary template FunctionDecl, whose lexical DC is 
the class where the friend was defined inline.

So the existing parent-chain walk then finds the suppression attribute.

Assisted-By: claude

---
Full diff: https://github.com/llvm/llvm-project/pull/187043.diff


2 Files Affected:

- (modified) clang/lib/StaticAnalyzer/Core/BugSuppression.cpp (+16) 
- (modified) clang/test/Analysis/clang-suppress/friends.cpp (+4-8) 


``````````diff
diff --git a/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp 
b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
index 0e7b5b77a7e54..9e13c0169e879 100644
--- a/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
+++ b/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp
@@ -232,6 +232,22 @@ template <class T> static const T 
*chooseDefinitionRedecl(const T *Tmpl) {
 // class templates. For any other decl, it returns the input unchagned.
 static const Decl *
 preferTemplateDefinitionForTemplateSpecializations(const Decl *D) {
+  // For function template specializations (including instantiated friend
+  // function templates), map back to the primary template's FunctionDecl so
+  // that the lexical parent chain walk reaches the class where the template
+  // was defined inline.
+  //
+  // This handles the case where a friend function template is defined inline
+  // inside a [[clang::suppress]]-annotated class but was pre-declared at
+  // namespace scope.  In that case the instantiation's lexical DC is the
+  // namespace (from the pre-declaration), not the class.  Walking back to the
+  // primary template FunctionDecl — whose lexical DC IS the class — lets the
+  // existing parent-chain walk find the suppression attribute.
+  if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
+    if (const FunctionDecl *Pattern = FD->getTemplateInstantiationPattern())
+      return Pattern;
+  }
+
   const auto *SpecializationDecl = 
dyn_cast<ClassTemplateSpecializationDecl>(D);
   if (!SpecializationDecl)
     return D;
diff --git a/clang/test/Analysis/clang-suppress/friends.cpp 
b/clang/test/Analysis/clang-suppress/friends.cpp
index acd3193eca0e2..1f89567d399bd 100644
--- a/clang/test/Analysis/clang-suppress/friends.cpp
+++ b/clang/test/Analysis/clang-suppress/friends.cpp
@@ -153,8 +153,7 @@ extern void b3_suppressed(T);
 struct [[clang::suppress]] B3_Suppressed {
   template <typename T>
   friend void b3_suppressed(T) {
-    // FIXME: This should be suppressed.
-    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+    clang_analyzer_warnIfReached(); // no-warning
   }
 };
 template <typename T>
@@ -280,8 +279,7 @@ template <typename T> void e3_multi_redecl(T);
 struct [[clang::suppress]] E3_Suppressed {
   template <typename T>
   friend void e3_multi_redecl(T) {
-    // FIXME: This should be suppressed.
-    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+    clang_analyzer_warnIfReached(); // no-warning
   }
 };
 void test_E3() {
@@ -325,8 +323,7 @@ template <typename U>
 struct [[clang::suppress]] E6_SuppressedTmpl {
   template <typename T>
   friend void e6_combined(T) {
-    // FIXME: This should be suppressed.
-    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+    clang_analyzer_warnIfReached(); // no-warning
   }
 };
 void test_E6() {
@@ -356,8 +353,7 @@ template <typename T> void e8_fwd_multi(T);
 struct [[clang::suppress]] E8_Suppressed {
   template <typename T>
   friend void e8_fwd_multi(T) {
-    // FIXME: This should be suppressed.
-    clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+    clang_analyzer_warnIfReached(); // no-warning
   }
 };
 void test_E8() {

``````````

</details>


https://github.com/llvm/llvm-project/pull/187043
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to