https://github.com/unterumarmung created 
https://github.com/llvm/llvm-project/pull/196661

Do not suggest adding `[[nodiscard]]` to functions returning a class template 
specialization whose primary template is already marked `[[nodiscard]]`.

Class template specializations do not carry the `[[nodiscard]]` attribute on 
their own declarations, so `modernize-use-nodiscard` previously missed this 
case and emitted redundant diagnostics for return types such as:
```cpp
template <class T>
struct [[nodiscard]] Result;

Result<int> f() const;
```
Fixes #163425.

>From ab0507fb6e7dcccaeca11879fd6e70cb93ccacf7 Mon Sep 17 00:00:00 2001
From: Daniil Dudkin <[email protected]>
Date: Sat, 9 May 2026 02:01:17 +0300
Subject: [PATCH] [clang-tidy] Avoid `use-nodiscard` false positives for
 `[[nodiscard]]` class templates

Do not suggest adding `[[nodiscard]]` to functions returning a class template
specialization whose primary template is already marked `[[nodiscard]]`.

Class template specializations do not carry the `[[nodiscard]]` attribute on
their own declarations, so `modernize-use-nodiscard` previously missed this case
and emitted redundant diagnostics for return types such as:

  template <class T>
  struct [[nodiscard]] Result;

  Result<int> f() const;

Fixes #163425.
---
 .../modernize/UseNodiscardCheck.cpp           |  5 +++++
 clang-tools-extra/docs/ReleaseNotes.rst       |  5 +++++
 .../checkers/modernize/use-nodiscard.cpp      | 20 +++++++++++++++++++
 3 files changed, 30 insertions(+)

diff --git a/clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.cpp 
b/clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.cpp
index 4940b5590f803..caa3d8c00681e 100644
--- a/clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.cpp
+++ b/clang-tools-extra/clang-tidy/modernize/UseNodiscardCheck.cpp
@@ -84,6 +84,9 @@ void 
UseNodiscardCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
 void UseNodiscardCheck::registerMatchers(MatchFinder *Finder) {
   auto FunctionObj =
       cxxRecordDecl(hasAnyName("::std::function", "::boost::function"));
+  auto NoDiscardClassTemplateSpecialization =
+      classTemplateSpecializationDecl(hasSpecializedTemplate(classTemplateDecl(
+          has(cxxRecordDecl(hasAttr(attr::WarnUnusedResult))))));
 
   // Find all non-void const methods which have not already been marked to
   // warn on unused result.
@@ -93,6 +96,8 @@ void UseNodiscardCheck::registerMatchers(MatchFinder *Finder) 
{
           unless(anyOf(
               returns(voidType()),
               returns(hasDeclaration(decl(hasAttr(attr::WarnUnusedResult)))),
+              returns(hasUnqualifiedDesugaredType(recordType(
+                  hasDeclaration(NoDiscardClassTemplateSpecialization)))),
               isNoReturn(), isOverloadedOperator(), isVariadic(),
               hasTemplateReturnType(), hasClassMutableFields(),
               isConversionOperator(), hasAttr(attr::WarnUnusedResult),
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index c464be5f6311a..783c919f8ce8e 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -440,6 +440,11 @@ Changes in existing checks
   private deleted functions, if they do not have a public overload or are a
   special member function.
 
+- Improved :doc:`modernize-use-nodiscard
+  <clang-tidy/checks/modernize/use-nodiscard>` check by avoiding false
+  positives on functions returning specializations of class templates marked
+  ``[[nodiscard]]``.
+
 - Improved :doc:`modernize-use-std-format
   <clang-tidy/checks/modernize/use-std-format>` check:
 
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nodiscard.cpp 
b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nodiscard.cpp
index 73ea4e46f76b6..e9097a7b19fdd 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nodiscard.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-nodiscard.cpp
@@ -24,6 +24,12 @@ typedef const unsigned &my_unsigned_const_reference;
 
 struct NO_DISCARD NoDiscardStruct{};
 
+template <typename T>
+struct NO_DISCARD NoDiscardTemplate {};
+
+using NoDiscardTemplateAlias = NoDiscardTemplate<int>;
+typedef NoDiscardTemplate<int> NoDiscardTemplateTypedef;
+
 class Foo {
 public:
     using size_type = unsigned;
@@ -164,6 +170,20 @@ class Foo {
 
     // Do not add ``[[nodiscard]]`` to functions returning types marked 
[[nodiscard]].
     NoDiscardStruct f50() const;
+
+    // Do not add ``[[nodiscard]]`` to functions returning class template
+    // specializations whose primary template is marked [[nodiscard]].
+    NoDiscardTemplate<int> f51() const;
+
+    NoDiscardTemplateAlias f52() const;
+
+    NoDiscardTemplateTypedef f53() const;
+
+    const NoDiscardTemplate<int> f54() const;
+
+    const NoDiscardTemplate<int> &f55() const;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'f55' should be 
marked NO_DISCARD [modernize-use-nodiscard]
+    // CHECK-FIXES: NO_DISCARD const NoDiscardTemplate<int> &f55() const;
 };
 
 // Do not add ``[[nodiscard]]`` to Lambda.

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

Reply via email to