[clang] [clang] [Sema] Simplify Expr::isUnusedResultAWarning for CXXConstructExpr (PR #153116)
via cfe-commits
cfe-commits at lists.llvm.org
Mon Aug 11 20:15:02 PDT 2025
https://github.com/halbi2 updated https://github.com/llvm/llvm-project/pull/153116
>From ca3213a6e252919fe6eb19ed2a6d6cd6de539bca Mon Sep 17 00:00:00 2001
From: halbi2 <hehiralbi at gmail.com>
Date: Mon, 11 Aug 2025 21:29:46 -0400
Subject: [PATCH 1/2] [clang] [Sema] Simplify Expr::isUnusedResultAWarning for
CXXConstructExpr
Two tests have new warnings because `warn_unused_result` is now respected for constructor
temporaries. These tests were newly added in #112521 last year. This is good because the
new behavior is better than the old.
---
clang/lib/AST/Expr.cpp | 33 ++++++-------------
.../dcl.attr/dcl.attr.nodiscard/p2.cpp | 2 +-
clang/test/SemaCXX/warn-unused-result.cpp | 4 +--
3 files changed, 13 insertions(+), 26 deletions(-)
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 7cac655ef151c..e3a746069cd3f 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -2805,32 +2805,19 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
case CXXTemporaryObjectExprClass:
case CXXConstructExprClass: {
- if (const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl()) {
- const auto *WarnURAttr = Type->getAttr<WarnUnusedResultAttr>();
- if (Type->hasAttr<WarnUnusedAttr>() ||
- (WarnURAttr && WarnURAttr->IsCXX11NoDiscard())) {
- WarnE = this;
- Loc = getBeginLoc();
- R1 = getSourceRange();
- return true;
- }
- }
-
const auto *CE = cast<CXXConstructExpr>(this);
- if (const CXXConstructorDecl *Ctor = CE->getConstructor()) {
- const auto *WarnURAttr = Ctor->getAttr<WarnUnusedResultAttr>();
- if (WarnURAttr && WarnURAttr->IsCXX11NoDiscard()) {
- WarnE = this;
- Loc = getBeginLoc();
- R1 = getSourceRange();
+ const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl();
- if (unsigned NumArgs = CE->getNumArgs())
- R2 = SourceRange(CE->getArg(0)->getBeginLoc(),
- CE->getArg(NumArgs - 1)->getEndLoc());
- return true;
- }
- }
+ if ((Type && Type->hasAttr<WarnUnusedAttr>()) || 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/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp
index 0012ab976baa5..7f933a4dcc6b2 100644
--- a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp
@@ -115,7 +115,7 @@ void usage() {
S(); // expected-warning {{ignoring temporary created by a constructor declared with 'nodiscard' attribute}}
S('A'); // expected-warning {{ignoring temporary created by a constructor declared with 'nodiscard' attribute: Don't let that S-Char go!}}
S(1);
- S(2.2);
+ S(2.2); // expected-warning {{ignoring temporary created by a constructor declared with 'gnu::warn_unused_result' attribute}}
Y(); // expected-warning {{ignoring temporary of type 'Y' declared with 'nodiscard' attribute: Don't throw me away either!}}
S s;
ConvertTo{}; // expected-warning {{ignoring return value of type 'ConvertTo' declared with 'nodiscard' attribute: Don't throw me away!}}
diff --git a/clang/test/SemaCXX/warn-unused-result.cpp b/clang/test/SemaCXX/warn-unused-result.cpp
index 447654eccd563..1f7913f1aa994 100644
--- a/clang/test/SemaCXX/warn-unused-result.cpp
+++ b/clang/test/SemaCXX/warn-unused-result.cpp
@@ -309,7 +309,7 @@ void use() {
S<double>(2); // no warning
S<int>(2); // expected-warning {{ignoring temporary of type 'S<int>' declared with 'nodiscard'}}
- S<const char>(2); // no warning (warn_unused_result does not diagnose constructor temporaries)
+ S<const char>(2); // expected-warning {{ignoring temporary of type 'S<const char>' declared with 'clang::warn_unused_result' attribute}}
// function should take precedence over type
obtain2(1.0); // expected-warning {{ignoring return value of function declared with 'nodiscard'}}
@@ -336,7 +336,7 @@ struct [[nodiscard]] G {
void use2() {
H{2}; // no warning
H(2.0); // expected-warning {{ignoring temporary created by a constructor declared with 'nodiscard'}}
- H("Hello"); // no warning (warn_unused_result does not diagnose constructor temporaries)
+ H("Hello"); // expected-warning {{ignoring temporary created by a constructor declared with 'warn_unused_result' attribute}}
// no warning for explicit cast to void
(void)H(2);
>From 426d6d765a59c5a4dc356848b8a3b1db23a2d3c1 Mon Sep 17 00:00:00 2001
From: halbi2 <hehiralbi at gmail.com>
Date: Mon, 11 Aug 2025 23:14:35 -0400
Subject: [PATCH 2/2] fix clang-format
---
clang/lib/AST/Expr.cpp | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index e3a746069cd3f..e14cff552c922 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -2808,7 +2808,8 @@ bool Expr::isUnusedResultAWarning(const Expr *&WarnE, SourceLocation &Loc,
const auto *CE = cast<CXXConstructExpr>(this);
const CXXRecordDecl *Type = getType()->getAsCXXRecordDecl();
- if ((Type && Type->hasAttr<WarnUnusedAttr>()) || CE->hasUnusedResultAttr(Ctx)) {
+ if ((Type && Type->hasAttr<WarnUnusedAttr>()) ||
+ CE->hasUnusedResultAttr(Ctx)) {
WarnE = this;
Loc = getBeginLoc();
R1 = getSourceRange();
More information about the cfe-commits
mailing list