Skip to content

Commit

Permalink
Revert "[Clang] Improve diagnostic on [[nodiscard]] attribute (llvm…
Browse files Browse the repository at this point in the history
…#112521)"

This reverts commit 422a454.

Change-Id: Ic924284ad9180c46f8942300f505d7950dff3c53
  • Loading branch information
ronlieb committed Dec 18, 2024
1 parent 78d6846 commit 113585a
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 159 deletions.
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -672,6 +672,7 @@ Improvements to Clang's diagnostics
getS(); // Now diagnoses "Reason 2", previously diagnoses "Reason 1"
}

- Clang now diagnoses ``= delete("reason")`` extension warnings only in pedantic mode rather than on by default. (#GH109311).

- Clang now diagnoses missing return value in functions containing ``if consteval`` (#GH116485).

Expand Down
8 changes: 3 additions & 5 deletions clang/include/clang/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -3181,14 +3181,12 @@ class CallExpr : public Expr {
QualType getCallReturnType(const ASTContext &Ctx) const;

/// Returns the WarnUnusedResultAttr that is either declared on the called
/// function, or its return type declaration, together with a NamedDecl that
/// refers to the declaration the attribute is attached onto.
std::pair<const NamedDecl *, const Attr *>
getUnusedResultAttr(const ASTContext &Ctx) const;
/// function, or its return type declaration.
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).second != nullptr;
return getUnusedResultAttr(Ctx) != nullptr;
}

SourceLocation getRParenLoc() const { return RParenLoc; }
Expand Down
13 changes: 8 additions & 5 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -9307,11 +9307,11 @@ def warn_unused_container_subscript_expr : Warning<
def warn_unused_call : Warning<
"ignoring return value of function declared with %0 attribute">,
InGroup<UnusedValue>;
def warn_unused_return_type : Warning<
"ignoring %select{return value|temporary}0 of type %2 declared with %1 attribute%select{|: %4}3">,
InGroup<UnusedValue>;
def warn_unused_constructor : Warning<
"ignoring temporary created by a constructor declared with %0 attribute%select{|: %2}1">,
"ignoring temporary created by a constructor declared with %0 attribute">,
InGroup<UnusedValue>;
def warn_unused_constructor_msg : Warning<
"ignoring temporary created by a constructor declared with %0 attribute: %1">,
InGroup<UnusedValue>;
def warn_side_effects_unevaluated_context : Warning<
"expression with side effects has no effect in an unevaluated context">,
Expand All @@ -9320,7 +9320,10 @@ def warn_side_effects_typeid : Warning<
"expression with side effects will be evaluated despite being used as an "
"operand to 'typeid'">, InGroup<PotentiallyEvaluatedExpression>;
def warn_unused_result : Warning<
"ignoring return value of function declared with %0 attribute%select{|: %2}1">,
"ignoring return value of function declared with %0 attribute">,
InGroup<UnusedResult>;
def warn_unused_result_msg : Warning<
"ignoring return value of function declared with %0 attribute: %1">,
InGroup<UnusedResult>;
def warn_unused_result_typedef_unsupported_spelling : Warning<
"'[[%select{nodiscard|gnu::warn_unused_result}0]]' attribute ignored when "
Expand Down
18 changes: 8 additions & 10 deletions clang/lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1615,24 +1615,22 @@ QualType CallExpr::getCallReturnType(const ASTContext &Ctx) const {
return FnType->getReturnType();
}

std::pair<const NamedDecl *, const Attr *>
CallExpr::getUnusedResultAttr(const ASTContext &Ctx) const {
// If the callee is marked nodiscard, return that attribute
const Decl *D = getCalleeDecl();
if (const auto *A = D->getAttr<WarnUnusedResultAttr>())
return {nullptr, A};

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 {TD, A};
return A;

for (const auto *TD = getCallReturnType(Ctx)->getAs<TypedefType>(); TD;
TD = TD->desugar()->getAs<TypedefType>())
if (const auto *A = TD->getDecl()->getAttr<WarnUnusedResultAttr>())
return {TD->getDecl(), A};
return {nullptr, nullptr};
return A;

// Otherwise, see if the callee is marked nodiscard and return that attribute
// instead.
const Decl *D = getCalleeDecl();
return D ? D->getAttr<WarnUnusedResultAttr>() : nullptr;
}

SourceLocation CallExpr::getBeginLoc() const {
Expand Down
47 changes: 17 additions & 30 deletions clang/lib/Sema/SemaStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,30 +200,23 @@ static bool DiagnoseUnusedComparison(Sema &S, const Expr *E) {
return true;
}

static bool DiagnoseNoDiscard(Sema &S, const NamedDecl *OffendingDecl,
const WarnUnusedResultAttr *A, SourceLocation Loc,
SourceRange R1, SourceRange R2, bool IsCtor) {
static bool DiagnoseNoDiscard(Sema &S, const WarnUnusedResultAttr *A,
SourceLocation Loc, SourceRange R1,
SourceRange R2, bool IsCtor) {
if (!A)
return false;
StringRef Msg = A->getMessage();

if (Msg.empty()) {
if (OffendingDecl)
return S.Diag(Loc, diag::warn_unused_return_type)
<< IsCtor << A << OffendingDecl << false << R1 << R2;
if (IsCtor)
return S.Diag(Loc, diag::warn_unused_constructor)
<< A << false << R1 << R2;
return S.Diag(Loc, diag::warn_unused_result) << A << false << R1 << R2;
return S.Diag(Loc, diag::warn_unused_constructor) << A << R1 << R2;
return S.Diag(Loc, diag::warn_unused_result) << A << R1 << R2;
}

if (OffendingDecl)
return S.Diag(Loc, diag::warn_unused_return_type)
<< IsCtor << A << OffendingDecl << true << Msg << R1 << R2;
if (IsCtor)
return S.Diag(Loc, diag::warn_unused_constructor)
<< A << true << Msg << R1 << R2;
return S.Diag(Loc, diag::warn_unused_result) << A << true << Msg << R1 << R2;
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;
}

void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
Expand Down Expand Up @@ -293,10 +286,9 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
if (E->getType()->isVoidType())
return;

auto [OffendingDecl, A] = CE->getUnusedResultAttr(Context);
if (DiagnoseNoDiscard(*this, OffendingDecl,
cast_or_null<WarnUnusedResultAttr>(A), Loc, R1, R2,
/*isCtor=*/false))
if (DiagnoseNoDiscard(*this, cast_or_null<WarnUnusedResultAttr>(
CE->getUnusedResultAttr(Context)),
Loc, R1, R2, /*isCtor=*/false))
return;

// If the callee has attribute pure, const, or warn_unused_result, warn with
Expand All @@ -317,21 +309,16 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
}
} else if (const auto *CE = dyn_cast<CXXConstructExpr>(E)) {
if (const CXXConstructorDecl *Ctor = CE->getConstructor()) {
const NamedDecl *OffendingDecl = nullptr;
const auto *A = Ctor->getAttr<WarnUnusedResultAttr>();
if (!A) {
OffendingDecl = Ctor->getParent();
A = OffendingDecl->getAttr<WarnUnusedResultAttr>();
}
if (DiagnoseNoDiscard(*this, OffendingDecl, A, Loc, R1, R2,
/*isCtor=*/true))
A = A ? A : Ctor->getParent()->getAttr<WarnUnusedResultAttr>();
if (DiagnoseNoDiscard(*this, 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, TD->getAttr<WarnUnusedResultAttr>(), Loc,
R1, R2, /*isCtor=*/false))
if (DiagnoseNoDiscard(*this, TD->getAttr<WarnUnusedResultAttr>(), Loc, R1,
R2, /*isCtor=*/false))
return;
}
} else if (ShouldSuppress)
Expand All @@ -345,8 +332,8 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S, unsigned DiagID) {
}
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (MD) {
if (DiagnoseNoDiscard(*this, nullptr, MD->getAttr<WarnUnusedResultAttr>(),
Loc, R1, R2, /*isCtor=*/false))
if (DiagnoseNoDiscard(*this, MD->getAttr<WarnUnusedResultAttr>(), Loc, R1,
R2, /*isCtor=*/false))
return;
}
} else if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) {
Expand Down
28 changes: 14 additions & 14 deletions clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ E get_e();
// cxx11-warning@-1 {{use of the 'nodiscard' attribute is a C++17 extension}}

void f() {
get_s(); // expected-warning {{ignoring return value of type 'S' declared with 'nodiscard' attribute}}
get_s(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
get_i(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
get_vi(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
get_e(); // expected-warning {{ignoring return value of type 'E' declared with 'nodiscard' attribute}}
get_e(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}

// Okay, warnings are not encouraged
get_s_ref();
Expand Down Expand Up @@ -54,10 +54,10 @@ void f() {
fp3 three;
fp2_alias four;

one(); // expected-warning {{ignoring return value of type 'E' declared with 'nodiscard' attribute}}
two(); // expected-warning {{ignoring return value of type 'S' declared with 'nodiscard' attribute}}
three(); // expected-warning {{ignoring return value of type 'S' declared with 'nodiscard' attribute}}
four(); // expected-warning {{ignoring return value of type 'S' declared with 'nodiscard' attribute}}
one(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
two(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
three(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
four(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}

// These are all okay because of the explicit cast to void.
(void)one();
Expand All @@ -84,8 +84,8 @@ LaterReason get_later_reason();
// cxx11-17-warning@-1 {{use of the 'nodiscard' attribute is a C++20 extension}}

void cxx20_use() {
get_reason(); // expected-warning {{ignoring return value of type 'ReasonStruct' declared with 'nodiscard' attribute: reason}}
get_later_reason(); // expected-warning {{ignoring return value of type 'LaterReason' declared with 'nodiscard' attribute: later reason}}
get_reason(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: reason}}
get_later_reason(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: later reason}}
another_reason(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: another reason}}
conflicting_reason(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: special reason}}
}
Expand Down Expand Up @@ -115,20 +115,20 @@ void usage() {
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);
Y(); // expected-warning {{ignoring temporary of type 'Y' declared with 'nodiscard' attribute: Don't throw me away either!}}
Y(); // expected-warning {{ignoring temporary created by a constructor 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!}}
ConvertTo{}; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: Don't throw me away!}}

// AST is different in C++17 mode. Before, a move ctor for ConvertTo is there
// as well, hence the constructor warning.

// since-cxx17-warning@+2 {{ignoring return value of type 'ConvertTo' declared with 'nodiscard' attribute: Don't throw me away!}}
// cxx11-warning@+1 {{ignoring temporary of type 'ConvertTo' declared with 'nodiscard' attribute: Don't throw me away!}}
// since-cxx17-warning@+2 {{ignoring return value of function declared with 'nodiscard' attribute: Don't throw me away!}}
// cxx11-warning@+1 {{ignoring temporary created by a constructor declared with 'nodiscard' attribute: Don't throw me away!}}
(ConvertTo) s;
(int)s; // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
(S)'c'; // expected-warning {{ignoring temporary created by a constructor declared with 'nodiscard' attribute: Don't let that S-Char go!}}
// since-cxx17-warning@+2 {{ignoring return value of type 'ConvertTo' declared with 'nodiscard' attribute: Don't throw me away!}}
// cxx11-warning@+1 {{ignoring temporary of type 'ConvertTo' declared with 'nodiscard' attribute: Don't throw me away!}}
// since-cxx17-warning@+2 {{ignoring return value of function declared with 'nodiscard' attribute: Don't throw me away!}}
// cxx11-warning@+1 {{ignoring temporary created by a constructor declared with 'nodiscard' attribute: Don't throw me away!}}
static_cast<ConvertTo>(s);
static_cast<int>(s); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
static_cast<double>(s); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: Don't throw away as a double}}
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace std_example {
error_info enable_missile_safety_mode();
void launch_missiles();
void test_missiles() {
enable_missile_safety_mode(); // expected-warning {{ignoring return value of type 'error_info' declared with 'nodiscard'}}
enable_missile_safety_mode(); // expected-warning {{ignoring return value of function declared with 'nodiscard'}}
launch_missiles();
}

Expand Down
8 changes: 4 additions & 4 deletions clang/test/Sema/c2x-nodiscard.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ enum E2 get_e(void);
[[nodiscard]] int get_i(void);

void f2(void) {
get_s(); // expected-warning {{ignoring return value of type 'S4' declared with 'nodiscard' attribute}}
get_s3(); // expected-warning {{ignoring return value of type 'S3' declared with 'nodiscard' attribute: Wrong}}
get_s(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
get_s3(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute: Wrong}}
get_i(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
get_e(); // expected-warning {{ignoring return value of type 'E2' declared with 'nodiscard' attribute}}
get_e(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}

// Okay, warnings are not encouraged
(void)get_s();
Expand All @@ -50,7 +50,7 @@ struct [[nodiscard]] error_info{
struct error_info enable_missile_safety_mode(void);
void launch_missiles(void);
void test_missiles(void) {
enable_missile_safety_mode(); // expected-warning {{ignoring return value of type 'error_info' declared with 'nodiscard'}}
enable_missile_safety_mode(); // expected-warning {{ignoring return value of function declared with 'nodiscard'}}
launch_missiles();
}

Expand Down
Loading

0 comments on commit 113585a

Please sign in to comment.