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
