[clang] [clang] Generate note on declaration for nodiscard-related attributes (PR #112289)
Yihe Li via cfe-commits
cfe-commits at lists.llvm.org
Mon Oct 14 17:25:49 PDT 2024
https://github.com/Mick235711 created https://github.com/llvm/llvm-project/pull/112289
Currently, the following program
```cpp
[[nodiscard]] int fun() { return 1; }
[[deprecated]] int fun2() { return 2; }
int main()
{
fun(); fun2();
}
```
generates the following diagnostics on Clang trunk: ([Compiler Explorer](https://godbolt.org/z/48crWEoYY))
```cpp
<source>:6:5: warning: ignoring return value of function declared with 'nodiscard' attribute [-Wunused-result]
6 | fun(); fun2();
| ^~~
<source>:6:12: warning: 'fun2' is deprecated [-Wdeprecated-declarations]
6 | fun(); fun2();
| ^
<source>:2:3: note: 'fun2' has been explicitly marked deprecated here
2 | [[deprecated]] int fun2() { return 2; }
| ^
2 warnings generated.
```
There seems to exist a discrepancy between `[[deprecated]]` and `[[nodiscard]]`. The former generates a warning on the usage of the function, together with a note on the declaration of the function. In contrast, the latter only generates a warning.
This PR tries to fix this discrepancy by additionally generating a note on the declaration of all `[[nodiscard]]`-related attributes (`nodiscard`, `warn_unused_result`, `pure`, and `const`). All 4 attributes generate a warning on ignoring the return value/constructor result on the trunk, and after this PR, all 4 attributes additionally generate a note. The above program will output the following diagnostics after this PR:
```cpp
test.cpp:6:5: warning: ignoring return value of function declared with 'nodiscard' attribute [-Wunused-result]
6 | fun(); fun2();
| ^~~
test.cpp:1:3: note: 'fun' has been explicitly marked nodiscard here
1 | [[nodiscard]] int fun() { return 1; }
| ^
test.cpp:6:12: warning: 'fun2' is deprecated [-Wdeprecated-declarations]
6 | fun(); fun2();
| ^
test.cpp:2:3: note: 'fun2' has been explicitly marked deprecated here
2 | [[deprecated]] int fun2() { return 2; }
| ^
2 warnings generated.
```
---
FIrst time contributor here who is not very familiar with Clang's infrastructure... Any comments and suggestions are welcome. No new test cases are added, as I felt that adding `expected-note`s on existing test cases already serves as testing for this PR.
>From 05e44dc97dcb351f719a5f2ce553c8af5aacfac7 Mon Sep 17 00:00:00 2001
From: Yihe Li <winmikedows at hotmail.com>
Date: Tue, 15 Oct 2024 08:13:22 +0800
Subject: [PATCH] [clang] Generate note on declaration for nodiscard-related
attributes
---
clang/include/clang/AST/Expr.h | 5 +-
.../clang/Basic/DiagnosticSemaKinds.td | 2 +
clang/lib/AST/Expr.cpp | 10 +--
clang/lib/Sema/SemaStmt.cpp | 63 ++++++++++++-------
.../dcl.attr/dcl.attr.nodiscard/p2.cpp | 29 ++++-----
.../dcl.attr/dcl.attr.nodiscard/p3.cpp | 2 +-
.../test/OpenMP/declare_variant_messages.cpp | 2 +-
clang/test/Sema/c2x-nodiscard.c | 12 ++--
clang/test/Sema/unused-expr.c | 10 +--
clang/test/SemaCXX/coroutines.cpp | 2 +-
clang/test/SemaCXX/warn-unused-result.cpp | 26 ++++----
.../SemaObjC/method-warn-unused-attribute.m | 6 +-
12 files changed, 98 insertions(+), 71 deletions(-)
diff --git a/clang/include/clang/AST/Expr.h b/clang/include/clang/AST/Expr.h
index cbe62411d11bff..8f5679767529fd 100644
--- a/clang/include/clang/AST/Expr.h
+++ b/clang/include/clang/AST/Expr.h
@@ -3182,11 +3182,12 @@ class CallExpr : public Expr {
/// Returns the WarnUnusedResultAttr that is either declared on the called
/// function, or its return type declaration.
- const Attr *getUnusedResultAttr(const ASTContext &Ctx) const;
+ std::pair<const NamedDecl *, const Attr *>
+ getUnusedResultAttr(const ASTContext &Ctx) const;
/// Returns true if this call expression should warn on unused results.
bool hasUnusedResultAttr(const ASTContext &Ctx) const {
- return getUnusedResultAttr(Ctx) != nullptr;
+ return getUnusedResultAttr(Ctx).second != nullptr;
}
SourceLocation getRParenLoc() const { return RParenLoc; }
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index c709795e7b21d8..3f6e4c35146454 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -9290,6 +9290,8 @@ def warn_unused_result_typedef_unsupported_spelling : Warning<
def warn_unused_volatile : Warning<
"expression result unused; assign into a variable to force a volatile load">,
InGroup<DiagGroup<"unused-volatile-lvalue">>;
+def note_nodiscard_specified_here : Note<
+ "%0 has been explicitly marked %1 here">;
def ext_cxx14_attr : Extension<
"use of the %0 attribute is a C++14 extension">, InGroup<CXX14Attrs>;
diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp
index 9ecbf121e3fc0d..b9450d6a61e57c 100644
--- a/clang/lib/AST/Expr.cpp
+++ b/clang/lib/AST/Expr.cpp
@@ -1616,22 +1616,24 @@ QualType CallExpr::getCallReturnType(const ASTContext &Ctx) const {
return FnType->getReturnType();
}
-const Attr *CallExpr::getUnusedResultAttr(const ASTContext &Ctx) const {
+std::pair<const NamedDecl *, const Attr *>
+CallExpr::getUnusedResultAttr(const ASTContext &Ctx) const {
// If the return type is a struct, union, or enum that is marked nodiscard,
// then return the return type attribute.
if (const TagDecl *TD = getCallReturnType(Ctx)->getAsTagDecl())
if (const auto *A = TD->getAttr<WarnUnusedResultAttr>())
- return A;
+ return {TD, A};
for (const auto *TD = getCallReturnType(Ctx)->getAs<TypedefType>(); TD;
TD = TD->desugar()->getAs<TypedefType>())
if (const auto *A = TD->getDecl()->getAttr<WarnUnusedResultAttr>())
- return A;
+ return {TD->getDecl(), A};
// Otherwise, see if the callee is marked nodiscard and return that attribute
// instead.
const Decl *D = getCalleeDecl();
- return D ? D->getAttr<WarnUnusedResultAttr>() : nullptr;
+ return {dyn_cast<NamedDecl>(D),
+ D ? D->getAttr<WarnUnusedResultAttr>() : nullptr};
}
SourceLocation CallExpr::getBeginLoc() const {
diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp
index 9e235a46707cd4..baaa6422b88fd4 100644
--- a/clang/lib/Sema/SemaStmt.cpp
+++ b/clang/lib/Sema/SemaStmt.cpp
@@ -14,6 +14,7 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTDiagnostic.h"
#include "clang/AST/ASTLambda.h"
+#include "clang/AST/Attrs.inc"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/CharUnits.h"
#include "clang/AST/DeclObjC.h"
@@ -204,23 +205,29 @@ static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) {
return true;
}
-static bool DiagnoseNoDiscard(Sema &S, const WarnUnusedResultAttr *A,
- SourceLocation Loc, SourceRange R1,
- SourceRange R2, bool IsCtor) {
+static bool DiagnoseNoDiscard(Sema &S, const NamedDecl *OffendingDecl,
+ const WarnUnusedResultAttr *A, SourceLocation Loc,
+ SourceRange R1, SourceRange R2, bool IsCtor) {
if (!A)
return false;
StringRef Msg = A->getMessage();
+ bool result;
if (Msg.empty()) {
if (IsCtor)
- return S.Diag(Loc, diag::warn_unused_constructor) << A << R1 << R2;
- return S.Diag(Loc, diag::warn_unused_result) << A << R1 << R2;
- }
+ result = S.Diag(Loc, diag::warn_unused_constructor) << A << R1 << R2;
+ else
+ result = S.Diag(Loc, diag::warn_unused_result) << A << R1 << R2;
+ } else if (IsCtor)
+ result = S.Diag(Loc, diag::warn_unused_constructor_msg)
+ << A << Msg << R1 << R2;
+ else
+ result = S.Diag(Loc, diag::warn_unused_result_msg) << A << Msg << R1 << R2;
- if (IsCtor)
- return S.Diag(Loc, diag::warn_unused_constructor_msg) << A << Msg << R1
- << R2;
- return S.Diag(Loc, diag::warn_unused_result_msg) << A << Msg << R1 << R2;
+ if (OffendingDecl)
+ S.Diag(A->getLocation(), diag::note_nodiscard_specified_here)
+ << OffendingDecl << A->getSpelling();
+ return result;
}
void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
@@ -290,9 +297,12 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
if (E->getType()->isVoidType())
return;
- if (DiagnoseNoDiscard(*this, cast_or_null<WarnUnusedResultAttr>(
- CE->getUnusedResultAttr(Context)),
- Loc, R1, R2, /*isCtor=*/false))
+ const NamedDecl *OffendingDecl;
+ const Attr *A;
+ std::tie(OffendingDecl, A) = CE->getUnusedResultAttr(Context);
+ if (DiagnoseNoDiscard(*this, OffendingDecl,
+ cast_or_null<WarnUnusedResultAttr>(A), Loc, R1, R2,
+ /*isCtor=*/false))
return;
// If the callee has attribute pure, const, or warn_unused_result, warn with
@@ -302,27 +312,38 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
if (const Decl *FD = CE->getCalleeDecl()) {
if (ShouldSuppress)
return;
- if (FD->hasAttr<PureAttr>()) {
+ if (const auto *A = FD->getAttr<PureAttr>()) {
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "pure";
+ if (OffendingDecl && !OffendingDecl->getIdentifier()->getBuiltinID())
+ Diag(A->getLocation(), diag::note_nodiscard_specified_here)
+ << OffendingDecl << "pure";
return;
}
- if (FD->hasAttr<ConstAttr>()) {
+ if (const auto *A = FD->getAttr<ConstAttr>()) {
Diag(Loc, diag::warn_unused_call) << R1 << R2 << "const";
+ if (OffendingDecl && !OffendingDecl->getIdentifier()->getBuiltinID())
+ Diag(A->getLocation(), diag::note_nodiscard_specified_here)
+ << OffendingDecl << "const";
return;
}
}
} else if (const auto *CE = dyn_cast<CXXConstructExpr>(E)) {
if (const CXXConstructorDecl *Ctor = CE->getConstructor()) {
+ const NamedDecl *OffendingDecl = Ctor;
const auto *A = Ctor->getAttr<WarnUnusedResultAttr>();
- A = A ? A : Ctor->getParent()->getAttr<WarnUnusedResultAttr>();
- if (DiagnoseNoDiscard(*this, A, Loc, R1, R2, /*isCtor=*/true))
+ if (!A) {
+ OffendingDecl = Ctor->getParent();
+ A = OffendingDecl->getAttr<WarnUnusedResultAttr>();
+ }
+ if (DiagnoseNoDiscard(*this, OffendingDecl, A, Loc, R1, R2,
+ /*isCtor=*/true))
return;
}
} else if (const auto *ILE = dyn_cast<InitListExpr>(E)) {
if (const TagDecl *TD = ILE->getType()->getAsTagDecl()) {
- if (DiagnoseNoDiscard(*this, TD->getAttr<WarnUnusedResultAttr>(), Loc, R1,
- R2, /*isCtor=*/false))
+ if (DiagnoseNoDiscard(*this, TD, TD->getAttr<WarnUnusedResultAttr>(), Loc,
+ R1, R2, /*isCtor=*/false))
return;
}
} else if (ShouldSuppress)
@@ -336,8 +357,8 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
}
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (MD) {
- if (DiagnoseNoDiscard(*this, MD->getAttr<WarnUnusedResultAttr>(), Loc, R1,
- R2, /*isCtor=*/false))
+ if (DiagnoseNoDiscard(*this, MD, MD->getAttr<WarnUnusedResultAttr>(), Loc,
+ R1, R2, /*isCtor=*/false))
return;
}
} else if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
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 693ca29370cf3f..158fbdbd67be34 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
@@ -2,18 +2,18 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify=expected,cxx11-17,since-cxx17 -pedantic %s
// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify=expected,since-cxx17 -pedantic %s
-struct [[nodiscard]] S {};
+struct [[nodiscard]] S {}; // expected-note 4 {{'S' has been explicitly marked nodiscard here}}
// cxx11-warning at -1 {{use of the 'nodiscard' attribute is a C++17 extension}}
S get_s();
S& get_s_ref();
-enum [[nodiscard]] E {};
+enum [[nodiscard]] E {}; // expected-note 2 {{'E' has been explicitly marked nodiscard here}}
// cxx11-warning at -1 {{use of the 'nodiscard' attribute is a C++17 extension}}
E get_e();
-[[nodiscard]] int get_i();
+[[nodiscard]] int get_i(); // expected-note {{'get_i' has been explicitly marked nodiscard here}}
// cxx11-warning at -1 {{use of the 'nodiscard' attribute is a C++17 extension}}
-[[nodiscard]] volatile int &get_vi();
+[[nodiscard]] volatile int &get_vi(); // expected-note {{'get_vi' has been explicitly marked nodiscard here}}
// cxx11-warning at -1 {{use of the 'nodiscard' attribute is a C++17 extension}}
void f() {
@@ -32,6 +32,7 @@ void f() {
[[nodiscard]] volatile char &(*fp)(); // expected-warning {{'nodiscard' attribute only applies to functions, classes, or enumerations}}
// cxx11-warning at -1 {{use of the 'nodiscard' attribute is a C++17 extension}}
+// expected-note at -2 {{'fp' has been explicitly marked nodiscard here}}
void g() {
fp(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
@@ -67,20 +68,20 @@ void f() {
}
} // namespace PR31526
-struct [[nodiscard("reason")]] ReasonStruct {};
+struct [[nodiscard("reason")]] ReasonStruct {}; // expected-note {{'ReasonStruct' has been explicitly marked nodiscard here}}
// cxx11-17-warning at -1 {{use of the 'nodiscard' attribute is a C++20 extension}}
struct LaterReason;
-struct [[nodiscard("later reason")]] LaterReason {};
+struct [[nodiscard("later reason")]] LaterReason {}; // expected-note {{'LaterReason' has been explicitly marked nodiscard here}}
// cxx11-17-warning at -1 {{use of the 'nodiscard' attribute is a C++20 extension}}
ReasonStruct get_reason();
LaterReason get_later_reason();
-[[nodiscard("another reason")]] int another_reason();
+[[nodiscard("another reason")]] int another_reason(); // expected-note {{'another_reason' has been explicitly marked nodiscard here}}
// cxx11-17-warning at -1 {{use of the 'nodiscard' attribute is a C++20 extension}}
[[nodiscard("conflicting reason")]] int conflicting_reason();
// cxx11-17-warning at -1 {{use of the 'nodiscard' attribute is a C++20 extension}}
-[[nodiscard("special reason")]] int conflicting_reason();
+[[nodiscard("special reason")]] int conflicting_reason(); // expected-note {{'conflicting_reason' has been explicitly marked nodiscard here}}
// cxx11-17-warning at -1 {{use of the 'nodiscard' attribute is a C++20 extension}}
void cxx20_use() {
@@ -91,23 +92,23 @@ void cxx20_use() {
}
namespace p1771 {
-struct[[nodiscard("Don't throw me away!")]] ConvertTo{};
+struct[[nodiscard("Don't throw me away!")]] ConvertTo{}; // expected-note 3 {{'ConvertTo' has been explicitly marked nodiscard here}}
// cxx11-17-warning at -1 {{use of the 'nodiscard' attribute is a C++20 extension}}
struct S {
- [[nodiscard]] S();
+ [[nodiscard]] S(); // expected-note {{'S' has been explicitly marked nodiscard here}}
// cxx11-warning at -1 {{use of the 'nodiscard' attribute is a C++17 extension}}
- [[nodiscard("Don't let that S-Char go!")]] S(char);
+ [[nodiscard("Don't let that S-Char go!")]] S(char); // expected-note 2 {{'S' has been explicitly marked nodiscard here}}
// cxx11-17-warning at -1 {{use of the 'nodiscard' attribute is a C++20 extension}}
S(int);
[[gnu::warn_unused_result]] S(double);
operator ConvertTo();
- [[nodiscard]] operator int();
+ [[nodiscard]] operator int(); // expected-note 2 {{'operator int' has been explicitly marked nodiscard here}}
// cxx11-warning at -1 {{use of the 'nodiscard' attribute is a C++17 extension}}
- [[nodiscard("Don't throw away as a double")]] operator double();
+ [[nodiscard("Don't throw away as a double")]] operator double(); // expected-note {{'operator double' has been explicitly marked nodiscard here}}
// cxx11-17-warning at -1 {{use of the 'nodiscard' attribute is a C++20 extension}}
};
-struct[[nodiscard("Don't throw me away either!")]] Y{};
+struct[[nodiscard("Don't throw me away either!")]] Y{}; // expected-note {{'Y' has been explicitly marked nodiscard here}}
// cxx11-17-warning at -1 {{use of the 'nodiscard' attribute is a C++20 extension}}
void usage() {
diff --git a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p3.cpp b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p3.cpp
index a3543cff7d2c92..6df334e1c0b488 100644
--- a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p3.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p3.cpp
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -std=c++1z -verify %s
namespace std_example {
- struct [[nodiscard]] error_info{
+ struct [[nodiscard]] error_info{ // expected-note {{'error_info' has been explicitly marked nodiscard here}}
// ...
};
diff --git a/clang/test/OpenMP/declare_variant_messages.cpp b/clang/test/OpenMP/declare_variant_messages.cpp
index b8a806e7ef75b3..5fe53d70270fbc 100644
--- a/clang/test/OpenMP/declare_variant_messages.cpp
+++ b/clang/test/OpenMP/declare_variant_messages.cpp
@@ -133,7 +133,7 @@ int score_and_cond_const();
template <int C>
int score_and_cond_const_inst();
-__attribute__((pure)) int pure() { return 0; }
+__attribute__((pure)) int pure() { return 0; } // expected-note {{'pure' has been explicitly marked pure here}}
#pragma omp declare variant(pure) match(user = {condition(1)}) // expected-warning {{ignoring return value of function declared with pure attribute}}
int unused_warning_after_specialization() { return foo(); }
diff --git a/clang/test/Sema/c2x-nodiscard.c b/clang/test/Sema/c2x-nodiscard.c
index f8b0567366465d..8865e2f9cd0ca2 100644
--- a/clang/test/Sema/c2x-nodiscard.c
+++ b/clang/test/Sema/c2x-nodiscard.c
@@ -9,7 +9,7 @@ struct [[nodiscard]] S1 { // ok
struct [[nodiscard, nodiscard]] S2 { // ok
int i;
};
-struct [[nodiscard("Wrong")]] S3 {
+struct [[nodiscard("Wrong")]] S3 { // expected-note {{'S3' has been explicitly marked nodiscard here}}
int i;
};
@@ -20,15 +20,15 @@ enum [[nodiscard]] E1 { One };
[[nodiscard]] int i; // expected-warning {{'nodiscard' attribute only applies to Objective-C methods, enums, structs, unions, classes, functions, function pointers, and typedefs}}
-struct [[nodiscard]] S4 {
+struct [[nodiscard]] S4 { // expected-note {{'S4' has been explicitly marked nodiscard here}}
int i;
};
struct S4 get_s(void);
-enum [[nodiscard]] E2 { Two };
+enum [[nodiscard]] E2 { Two }; // expected-note {{'E2' has been explicitly marked nodiscard here}}
enum E2 get_e(void);
-[[nodiscard]] int get_i(void);
+[[nodiscard]] int get_i(void); // expected-note {{'get_i' has been explicitly marked nodiscard here}}
void f2(void) {
get_s(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
@@ -43,7 +43,7 @@ void f2(void) {
(void)get_e();
}
-struct [[nodiscard]] error_info{
+struct [[nodiscard]] error_info{ // expected-note {{'error_info' has been explicitly marked nodiscard here}}
int i;
};
@@ -54,7 +54,7 @@ void test_missiles(void) {
launch_missiles();
}
-[[nodiscard]] int f3();
+[[nodiscard]] int f3(); // expected-note {{'f3' has been explicitly marked nodiscard here}}
void GH104391() {
#define M (unsigned int) f3()
diff --git a/clang/test/Sema/unused-expr.c b/clang/test/Sema/unused-expr.c
index 6723a33cbd4e01..9e444f94d67137 100644
--- a/clang/test/Sema/unused-expr.c
+++ b/clang/test/Sema/unused-expr.c
@@ -73,15 +73,15 @@ void t4(int a) {
for (;;b < 1) {} // expected-warning{{relational comparison result unused}}
}
-int t5f(void) __attribute__((warn_unused_result));
+int t5f(void) __attribute__((warn_unused_result)); // expected-note {{'t5f' has been explicitly marked warn_unused_result here}}
void t5(void) {
t5f(); // expected-warning {{ignoring return value of function declared with 'warn_unused_result' attribute}}
}
-int fn1(void) __attribute__ ((warn_unused_result));
-int fn2() __attribute__ ((pure));
-int fn3() __attribute__ ((__const));
+int fn1(void) __attribute__ ((warn_unused_result)); // expected-note 3 {{'fn1' has been explicitly marked warn_unused_result here}}
+int fn2() __attribute__ ((pure)); // expected-note 2 {{'fn2' has been explicitly marked pure here}}
+int fn3() __attribute__ ((__const)); // expected-note {{'fn3' has been explicitly marked const here}}
int t6(void) {
if (fn1() < 0 || fn2(2,1) < 0 || fn3(2) < 0) // no warnings
return -1;
@@ -97,7 +97,7 @@ int t6(void) {
int t7 __attribute__ ((warn_unused_result)); // expected-warning {{'warn_unused_result' attribute only applies to Objective-C methods, enums, structs, unions, classes, functions, function pointers, and typedefs}}
// PR4010
-int (*fn4)(void) __attribute__ ((warn_unused_result));
+int (*fn4)(void) __attribute__ ((warn_unused_result)); // expected-note {{'fn4' has been explicitly marked warn_unused_result here}}
void t8(void) {
fn4(); // expected-warning {{ignoring return value of function declared with 'warn_unused_result' attribute}}
}
diff --git a/clang/test/SemaCXX/coroutines.cpp b/clang/test/SemaCXX/coroutines.cpp
index 068fdab4bfe384..c9d442a0338121 100644
--- a/clang/test/SemaCXX/coroutines.cpp
+++ b/clang/test/SemaCXX/coroutines.cpp
@@ -1497,7 +1497,7 @@ class awaitable_unused_warn {
using handle_type = std::coroutine_handle<>;
constexpr bool await_ready() noexcept { return false; }
void await_suspend(handle_type) noexcept {}
- [[nodiscard]] int await_resume() noexcept { return 1; }
+ [[nodiscard]] int await_resume() noexcept { return 1; } // expected-note 2 {{'await_resume' has been explicitly marked nodiscard here}}
};
template <class Await>
diff --git a/clang/test/SemaCXX/warn-unused-result.cpp b/clang/test/SemaCXX/warn-unused-result.cpp
index 4b7a2503ecc0dd..247be530274af2 100644
--- a/clang/test/SemaCXX/warn-unused-result.cpp
+++ b/clang/test/SemaCXX/warn-unused-result.cpp
@@ -1,13 +1,13 @@
// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
-int f() __attribute__((warn_unused_result));
+int f() __attribute__((warn_unused_result)); // expected-note 12 {{'f' has been explicitly marked warn_unused_result here}}
struct S {
void t() const;
};
-S g1() __attribute__((warn_unused_result));
-S *g2() __attribute__((warn_unused_result));
-S &g3() __attribute__((warn_unused_result));
+S g1() __attribute__((warn_unused_result)); // expected-note {{'g1' has been explicitly marked warn_unused_result here}}
+S *g2() __attribute__((warn_unused_result)); // expected-note {{'g2' has been explicitly marked warn_unused_result here}}
+S &g3() __attribute__((warn_unused_result)); // expected-note {{'g3' has been explicitly marked warn_unused_result here}}
void test() {
f(); // expected-warning {{ignoring return value}}
@@ -64,7 +64,7 @@ void testSubstmts(int i) {
}
struct X {
- int foo() __attribute__((warn_unused_result));
+ int foo() __attribute__((warn_unused_result)); // expected-note 2 {{'foo' has been explicitly marked warn_unused_result here}}
};
void bah() {
@@ -80,7 +80,7 @@ class Foo {
Status doStuff();
};
-struct [[clang::warn_unused_result]] Status {
+struct [[clang::warn_unused_result]] Status { // expected-note 3 {{'Status' has been explicitly marked warn_unused_result here}}
bool ok() const;
Status& operator=(const Status& x);
inline void Update(const Status& new_status) {
@@ -115,7 +115,7 @@ void lazy() {
}
template <typename T>
-class [[clang::warn_unused_result]] StatusOr {
+class [[clang::warn_unused_result]] StatusOr { // expected-note {{'StatusOr<int>' has been explicitly marked warn_unused_result here}}
};
StatusOr<int> doit();
void test() {
@@ -129,7 +129,7 @@ void test() {
}
namespace PR17587 {
-struct [[clang::warn_unused_result]] Status;
+struct [[clang::warn_unused_result]] Status; // expected-note {{'Status' has been explicitly marked warn_unused_result here}}
struct Foo {
Status Bar();
@@ -193,7 +193,7 @@ void g() {
namespace {
// C++ Methods should warn even in their own class.
-struct [[clang::warn_unused_result]] S {
+struct [[clang::warn_unused_result]] S { // expected-note 5 {{'S' has been explicitly marked warn_unused_result here}}
S DoThing() { return {}; };
S operator++(int) { return {}; };
S operator--(int) { return {}; };
@@ -202,7 +202,7 @@ struct [[clang::warn_unused_result]] S {
S operator--() { return {}; };
};
-struct [[clang::warn_unused_result]] P {
+struct [[clang::warn_unused_result]] P { // expected-note 5 {{'P' has been explicitly marked warn_unused_result here}}
P DoThing() { return {}; };
};
@@ -238,7 +238,7 @@ void f() {
} // namespace
namespace PR39837 {
-[[clang::warn_unused_result]] int f(int);
+[[clang::warn_unused_result]] int f(int); // expected-note {{'f' has been explicitly marked warn_unused_result here}}
void g() {
int a[2];
@@ -256,7 +256,7 @@ void i([[nodiscard]] bool (*fp)()); // expected-warning {{'nodiscard' attribute
}
namespace unused_typedef_result {
-[[clang::warn_unused_result]] typedef void *a;
+[[clang::warn_unused_result]] typedef void *a; // expected-note 3 {{'a' has been explicitly marked warn_unused_result here}}
typedef a indirect;
a af1();
indirect indirectf1();
@@ -276,7 +276,7 @@ void bf2() {
b1f1(); // no warning
b2f1(); // no warning
}
-__attribute__((warn_unused_result)) typedef void *c;
+__attribute__((warn_unused_result)) typedef void *c; // expected-note 2 {{'c' has been explicitly marked warn_unused_result here}}
c cf1();
void cf2() {
cf1(); // expected-warning {{ignoring return value}}
diff --git a/clang/test/SemaObjC/method-warn-unused-attribute.m b/clang/test/SemaObjC/method-warn-unused-attribute.m
index b83dabf3bbdc22..99917b8df94330 100644
--- a/clang/test/SemaObjC/method-warn-unused-attribute.m
+++ b/clang/test/SemaObjC/method-warn-unused-attribute.m
@@ -1,10 +1,10 @@
// RUN: %clang_cc1 -fsyntax-only -Wunused-value -verify %s
@interface INTF
-- (id) foo __attribute__((warn_unused_result));
+- (id) foo __attribute__((warn_unused_result));
- (void) garf __attribute__((warn_unused_result)); // expected-warning {{attribute 'warn_unused_result' cannot be applied to Objective-C method without return value}}
-- (int) fee __attribute__((warn_unused_result));
-+ (int) c __attribute__((warn_unused_result));
+- (int) fee __attribute__((warn_unused_result)); // expected-note {{'fee' has been explicitly marked warn_unused_result here}}
++ (int) c __attribute__((warn_unused_result)); // expected-note {{'c' has been explicitly marked warn_unused_result here}}
@end
void foo(INTF *a) {
More information about the cfe-commits
mailing list