[clang] [analyzer] Fix [[clang::suppress]] for template instantiations (PR #168954)
Balázs Benics via cfe-commits
cfe-commits at lists.llvm.org
Fri Nov 21 11:45:05 PST 2025
================
@@ -1,4 +1,27 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
+
+void clang_analyzer_warnIfReached();
+
+struct Clazz {
+ template <typename T>
+ static void templated_memfn();
+};
+
+// This must come before the 'templated_memfn' is defined!
+static void instantiate() {
+ Clazz::templated_memfn<int>();
+}
+
+template <typename T>
+void Clazz::templated_memfn() {
+ // When we report a bug in a function, we traverse the lexical decl context
+ // of it while looking for suppression attributes to record what source
----------------
steakhal wrote:
> I'm trying to understand how `BugSuppression` works: The bug is at the `clang_analyzer_warnIfReached()` call so the decl context being visited is the instantiated definition of `Clazz::templated_memfn<int>() {...}`. [...]
You are right. Sharp eyes. I lied a bit because we also swap the decl context to the parent context, which is going to be the class definition itself, that has the template instantiations as child nodes in the AST - including the one where we have the suppression. However, if we skip traversing instantiations then we would not see the suppression.
https://github.com/llvm/llvm-project/blob/main/clang/lib/StaticAnalyzer/Core/BugSuppression.cpp#L175-L189
```c++
} else {
// This is the fast path. However, we should still consider the topmost
// declaration that isn't TranslationUnitDecl, because we should respect
// attributes on the entire declaration chain.
while (true) {
// Use the "lexical" parent. Eg., if the attribute is on a class, suppress
// warnings in inline methods but not in out-of-line methods.
const Decl *Parent =
dyn_cast_or_null<Decl>(DeclWithIssue->getLexicalDeclContext());
if (Parent == nullptr || isa<TranslationUnitDecl>(Parent))
break;
DeclWithIssue = Parent;
}
}
```
> What would happen if I move `[[clang::suppress]]` to line 12: `[[clang::suppress]] Clazz::templated_memfn<int>();`?
I've not tried, but I'm almost certain that having a suppress for a statement (such as your proposed attribute at that CallExpr) would only suppress issues raised within the source range of the effective statement (CallExpr).
Since the bug is raised within the callee of that CallExpr, the bug should not be suppressed by that attribute.
If it would suppress it, than that would be a bug in the suppression algorithm.
https://github.com/llvm/llvm-project/pull/168954
More information about the cfe-commits
mailing list