https://github.com/halbi2 updated 
https://github.com/llvm/llvm-project/pull/139651

>From 1efa70c6702f7506580a5b8c49ea3df779d31163 Mon Sep 17 00:00:00 2001
From: halbi2 <hehira...@gmail.com>
Date: Mon, 18 Aug 2025 21:46:47 -0400
Subject: [PATCH 1/2] [clang] [test] Better test coverage for nodiscard
 attributes

---
 clang/test/Sema/c2x-nodiscard.c           | 17 +++++
 clang/test/SemaCXX/warn-unused-result.cpp | 85 +++++++++++++++++++++++
 clang/test/SemaObjC/attr-nodiscard.m      |  9 ++-
 clang/test/SemaObjCXX/attr-nodiscard.mm   |  9 ++-
 4 files changed, 118 insertions(+), 2 deletions(-)

diff --git a/clang/test/Sema/c2x-nodiscard.c b/clang/test/Sema/c2x-nodiscard.c
index e2537bcf1d29d..852c74721693b 100644
--- a/clang/test/Sema/c2x-nodiscard.c
+++ b/clang/test/Sema/c2x-nodiscard.c
@@ -41,6 +41,10 @@ void f2(void) {
   (void)get_s3();
   (void)get_i();
   (void)get_e();
+
+  One; // expected-warning {{expression result unused}}
+  (enum E2)(0); // expected-warning {{expression result unused}}
+  (struct S4){1}; // expected-warning {{expression result unused}}
 }
 
 struct [[nodiscard]] error_info{
@@ -60,3 +64,16 @@ void GH104391() {
 #define M (unsigned int) f3()
   M; // expected-warning {{ignoring return value of function declared with 
'nodiscard' attribute}}
 }
+
+[[nodiscard]] typedef int NoDInt; // expected-warning {{'[[nodiscard]]' 
attribute ignored when applied to a typedef}}
+typedef __attribute__((warn_unused)) int WUInt; // expected-warning 
{{'warn_unused' attribute only applies to structs, unions, and classes}}
+typedef __attribute__((warn_unused_result)) int WURInt;
+NoDInt get_nodint();
+WUInt get_wuint();
+WURInt get_wurint();
+
+void f4(void) {
+  get_nodint(); // no warning because attribute is ignored
+  get_wuint();  // no warning because attribute is ignored
+  get_wurint(); // expected-warning {{ignoring return value of type 'WURInt' 
declared with 'warn_unused_result' attribute}}
+}
diff --git a/clang/test/SemaCXX/warn-unused-result.cpp 
b/clang/test/SemaCXX/warn-unused-result.cpp
index 1f7913f1aa994..bd46fdfd57061 100644
--- a/clang/test/SemaCXX/warn-unused-result.cpp
+++ b/clang/test/SemaCXX/warn-unused-result.cpp
@@ -407,3 +407,88 @@ void doGccThings() {
 }
 
 } // namespace BuildStringOnClangScope
+
+namespace candiscard {
+
+struct [[nodiscard]] NoDiscard {
+  [[nodiscard]] NoDiscard(int);
+  NoDiscard(const char *);
+};
+
+struct [[gnu::warn_unused]] WarnUnused {
+  [[gnu::warn_unused]] WarnUnused(int); // expected-warning 
{{'gnu::warn_unused' attribute only applies to structs, unions, and classes}}
+  WarnUnused(const char*);
+};
+
+struct [[gnu::warn_unused_result]] WarnUnusedResult {
+  [[gnu::warn_unused_result]] WarnUnusedResult(int);
+  WarnUnusedResult(const char*);
+};
+
+NoDiscard return_nodiscard();
+WarnUnused return_warnunused();
+WarnUnusedResult return_warnunusedresult();
+
+NoDiscard (*p_return_nodiscard)();
+WarnUnused (*p_return_warnunused)();
+WarnUnusedResult (*p_return_warnunusedresult)();
+
+NoDiscard (*(*pp_return_nodiscard)())();
+WarnUnused (*(*pp_return_warnunused)())();
+WarnUnusedResult (*(*pp_return_warnunusedresult)())();
+
+template <class T> T from_a_template();
+
+void test() {
+  // Unused but named variables
+  NoDiscard unused_variable1(1);         // no warning
+  NoDiscard unused_variable2("");        // no warning
+  WarnUnused unused_variable3(1);        // no warning
+  WarnUnused unused_variable4("");       // no warning
+  WarnUnusedResult unused_variable5(1);  // no warning
+  WarnUnusedResult unused_variable6(""); // no warning
+
+  // Constructor return values
+  NoDiscard(1);         // expected-warning {{ignoring temporary created by a 
constructor declared with 'nodiscard' attribute}}
+  NoDiscard("");        // expected-warning {{ignoring temporary of type 
'NoDiscard' declared with 'nodiscard' attribute}}
+  WarnUnused(1);        // expected-warning {{expression result unused}}
+  WarnUnused("");       // expected-warning {{expression result unused}}
+  WarnUnusedResult(1);  // expected-warning {{ignoring temporary created by a 
constructor declared with 'gnu::warn_unused_result' attribute}}
+  WarnUnusedResult(""); // expected-warning {{ignoring temporary of type 
'WarnUnusedResult' declared with 'gnu::warn_unused_result' attribute}}
+
+  NoDiscard{1};         // expected-warning {{ignoring temporary created by a 
constructor declared with 'nodiscard' attribute}}
+  NoDiscard{""};        // expected-warning {{ignoring temporary of type 
'NoDiscard' declared with 'nodiscard' attribute}}
+  WarnUnused{1};        // expected-warning {{expression result unused}}
+  WarnUnused{""};       // expected-warning {{expression result unused}}
+  WarnUnusedResult{1};  // expected-warning {{ignoring temporary created by a 
constructor declared with 'gnu::warn_unused_result' attribute}}
+  WarnUnusedResult{""}; // expected-warning {{ignoring temporary of type 
'WarnUnusedResult' declared with 'gnu::warn_unused_result' attribute}}
+
+  static_cast<NoDiscard>(1);         // expected-warning {{ignoring temporary 
created by a constructor declared with 'nodiscard' attribute}}
+  static_cast<NoDiscard>("");        // expected-warning {{ignoring temporary 
of type 'NoDiscard' declared with 'nodiscard' attribute}}
+  static_cast<WarnUnused>(1);        // expected-warning {{expression result 
unused}}
+  static_cast<WarnUnused>("");       // expected-warning {{expression result 
unused}}
+  static_cast<WarnUnusedResult>(1);  // expected-warning {{ignoring temporary 
created by a constructor declared with 'gnu::warn_unused_result' attribute}}
+  static_cast<WarnUnusedResult>(""); // expected-warning {{ignoring temporary 
of type 'WarnUnusedResult' declared with 'gnu::warn_unused_result' attribute}}
+
+  // Function return values
+  return_nodiscard(); // expected-warning {{ignoring return value of type 
'NoDiscard' declared with 'nodiscard' attribute}}
+  return_warnunused(); // no warning
+  return_warnunusedresult(); // expected-warning {{ignoring return value of 
type 'WarnUnusedResult' declared with 'gnu::warn_unused_result' attribute}}
+
+  // Function pointer return values
+  p_return_nodiscard(); // expected-warning {{ignoring return value of type 
'NoDiscard' declared with 'nodiscard' attribute}}
+  p_return_warnunused(); // no warning
+  p_return_warnunusedresult(); // expected-warning {{ignoring return value of 
type 'WarnUnusedResult' declared with 'gnu::warn_unused_result' attribute}}
+
+  // Function pointer expression return values
+  pp_return_nodiscard()(); // no warning: TODO
+  pp_return_warnunused()(); // no warning
+  pp_return_warnunusedresult()(); // no warning: TODO
+
+  // From a template
+  from_a_template<NoDiscard>(); // expected-warning {{ignoring return value of 
type 'NoDiscard' declared with 'nodiscard' attribute}}
+  from_a_template<WarnUnused>(); // no warning
+  from_a_template<WarnUnusedResult>(); // expected-warning {{ignoring return 
value of type 'WarnUnusedResult' declared with 'gnu::warn_unused_result' 
attribute}}
+}
+
+} // namespace candiscard
diff --git a/clang/test/SemaObjC/attr-nodiscard.m 
b/clang/test/SemaObjC/attr-nodiscard.m
index 6d04665da25ca..26bbd247d4a3d 100644
--- a/clang/test/SemaObjC/attr-nodiscard.m
+++ b/clang/test/SemaObjC/attr-nodiscard.m
@@ -4,6 +4,9 @@
 
 typedef struct expected E;
 
+[[nodiscard]] typedef int NI; // expected-warning {{'[[nodiscard]]' attribute 
ignored when applied to a typedef}}
+typedef __attribute__((warn_unused_result)) int WUR;
+
 @interface INTF
 - (int) a [[nodiscard]];
 + (int) b [[nodiscard]];
@@ -12,6 +15,8 @@ + (struct expected) d;
 - (E) e;
 + (E) f;
 - (void) g [[nodiscard]]; // expected-warning {{attribute 'nodiscard' cannot 
be applied to Objective-C method without return value}}
+- (NI) h;
+- (WUR) i;
 @end
 
 void foo(INTF *a) {
@@ -21,5 +26,7 @@ void foo(INTF *a) {
   [INTF d]; // expected-warning {{ignoring return value of type 'expected' 
declared with 'nodiscard' attribute}}
   [a e]; // expected-warning {{ignoring return value of type 'expected' 
declared with 'nodiscard' attribute}}
   [INTF f]; // expected-warning {{ignoring return value of type 'expected' 
declared with 'nodiscard' attribute}}
-  [a g];
+  [a g]; // no warning because g returns void
+  [a h]; // no warning because attribute is ignored when applied to a typedef
+  [a i]; // expected-warning {{ignoring return value of type 'WUR' declared 
with 'warn_unused_result' attribute}}
 }
diff --git a/clang/test/SemaObjCXX/attr-nodiscard.mm 
b/clang/test/SemaObjCXX/attr-nodiscard.mm
index e1eefb74d3961..18d829632e428 100644
--- a/clang/test/SemaObjCXX/attr-nodiscard.mm
+++ b/clang/test/SemaObjCXX/attr-nodiscard.mm
@@ -5,6 +5,9 @@
 
 using E = expected<int>;
 
+using NI [[nodiscard]] = int; // expected-warning {{'[[nodiscard]]' attribute 
ignored when applied to a typedef}}
+using WURI [[clang::warn_unused_result]] = int;
+
 @interface INTF
 - (int) a [[nodiscard]];
 + (int) b [[nodiscard]];
@@ -13,6 +16,8 @@ + (int) b [[nodiscard]];
 - (E) e;
 + (E) f;
 - (void) g [[nodiscard]]; // expected-warning {{attribute 'nodiscard' cannot 
be applied to Objective-C method without return value}}
+- (NI) h;
+- (WURI) i;
 @end
 
 void foo(INTF *a) {
@@ -22,5 +27,7 @@ void foo(INTF *a) {
   [INTF d]; // expected-warning {{ignoring return value of type 
'expected<int>' declared with 'nodiscard' attribute}}
   [a e]; // expected-warning {{ignoring return value of type 'expected<int>' 
declared with 'nodiscard' attribute}}
   [INTF f]; // expected-warning {{ignoring return value of type 
'expected<int>' declared with 'nodiscard' attribute}}
-  [a g];
+  [a g]; // no warning because g returns void
+  [a h]; // no warning because attribute is ignored
+  [a i]; // expected-warning {{ignoring return value of type 'WURI' declared 
with 'clang::warn_unused_result' attribute}}
 }

>From 23c5b44123961f252103d84b6f862242fdf54819 Mon Sep 17 00:00:00 2001
From: halbi2 <hehira...@gmail.com>
Date: Mon, 18 Aug 2025 21:47:32 -0400
Subject: [PATCH 2/2] [clang] [Sema] Enable nodiscard warnings for function
 pointers

A call through a function pointer has no associated FunctionDecl,
but it still might have a nodiscard return type. Ensure there is
a codepath to emit the nodiscard warning in this case.

Fixes #142453
---
 clang/lib/AST/Expr.cpp                    | 10 ++++++++++
 clang/test/SemaCXX/warn-unused-result.cpp |  4 ++--
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index e14cff552c922..36e091915e0c8 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -2794,6 +2794,16 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, 
SourceLocation &Loc,
         return true;
       }
     }
+    if (CE->hasUnusedResultAttr(Ctx)) {
+      WarnE = this;
+      Loc = getBeginLoc();
+      R1 = getSourceRange();
+
+      if (unsigned NumArgs = CE->getNumArgs())
+        R2 = SourceRange(CE->getArg(0)->getBeginLoc(),
+                         CE->getArg(NumArgs - 1)->getEndLoc());
+      return true;
+    }
     return false;
   }
 
diff --git a/clang/test/SemaCXX/warn-unused-result.cpp 
b/clang/test/SemaCXX/warn-unused-result.cpp
index bd46fdfd57061..098817729efb1 100644
--- a/clang/test/SemaCXX/warn-unused-result.cpp
+++ b/clang/test/SemaCXX/warn-unused-result.cpp
@@ -481,9 +481,9 @@ void test() {
   p_return_warnunusedresult(); // expected-warning {{ignoring return value of 
type 'WarnUnusedResult' declared with 'gnu::warn_unused_result' attribute}}
 
   // Function pointer expression return values
-  pp_return_nodiscard()(); // no warning: TODO
+  pp_return_nodiscard()(); // expected-warning {{ignoring return value of type 
'NoDiscard' declared with 'nodiscard' attribute}}
   pp_return_warnunused()(); // no warning
-  pp_return_warnunusedresult()(); // no warning: TODO
+  pp_return_warnunusedresult()(); // expected-warning {{ignoring return value 
of type 'WarnUnusedResult' declared with 'gnu::warn_unused_result' attribute}}
 
   // From a template
   from_a_template<NoDiscard>(); // expected-warning {{ignoring return value of 
type 'NoDiscard' declared with 'nodiscard' attribute}}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to