================
@@ -165,6 +165,58 @@ bool BugSuppression::isSuppressed(const BugReport &R) {
isSuppressed(UniqueingLocation, DeclWithIssue, {});
}
+// For template specializations, returns the primary template definition or
+// partial specialization that was used to instantiate the specialization.
+// This ensures suppression attributes on templates apply to their
+// specializations.
+//
+// For example, given:
+// template <typename T> class [[clang::suppress]] Wrapper { ... };
+// Wrapper<int> w; // instantiates ClassTemplateSpecializationDecl
+//
+// When analyzing code in Wrapper<int>, this function maps the specialization
+// back to the primary template definition, allowing us to find the suppression
+// attribute.
+//
+// The function handles two cases:
+// 1. Instantiation from a class template - searches redeclarations to find
+// the definition (not just a forward declaration).
+// 2. Instantiation from a partial specialization - returns it directly.
+//
+// For non-template-specialization decls, returns the input unchanged.
+static const Decl *
+preferTemplateDefinitionForTemplateSpecializations(const Decl *D) {
+ const auto *SpecializationDecl =
dyn_cast<ClassTemplateSpecializationDecl>(D);
+ if (!SpecializationDecl)
+ return D;
+
+ auto InstantiatedFrom = SpecializationDecl->getInstantiatedFrom();
+ if (!InstantiatedFrom)
+ return D;
+
+ // This might be a class template.
+ if (const auto *Tmpl = InstantiatedFrom.dyn_cast<ClassTemplateDecl *>()) {
+ // Interestingly, the source template might be a forward declaration, so we
+ // need to find the definition redeclaration.
+ for (const auto *Redecl : Tmpl->redecls()) {
+ if (cast<ClassTemplateDecl>(Redecl)->isThisDeclarationADefinition()) {
+ return Redecl;
+ }
+ }
+ assert(false &&
+ "This class template must have a redecl that is a definition");
+ return D;
+ }
+
+ // It might be a partial specialization.
+ const auto *PartialSpecialization =
+ InstantiatedFrom.dyn_cast<ClassTemplatePartialSpecializationDecl *>();
----------------
steakhal wrote:
I believe that this is safe.
`InstantiatedFrom` was checked and it holds something. Now that means that it
can be either a `ClassTemplateDecl` or a
`ClassTemplatePartialSpecializationDecl`.
Since the `ClassTemplateDecl` case was handled above, what is left is this one.
Note that there is no `cast` member function and I believe the free-standing
LLVM cast mechanisms don't work on a `llvm::PointerUnion< ClassTemplateDecl *,
ClassTemplatePartialSpecializationDecl *>`
Now that I'm looking more closely, it does have a `get` method that does what
`cast` should.
That said, I might come back to this code because the semantics of it is not
quite correct. No UB, it just doesn't seem to cover all the cases we need to.
See #182659
https://github.com/llvm/llvm-project/pull/178441
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits