Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -2278,6 +2278,13 @@ bool HasWarnUnusedResultAttr = Func ? Func->hasUnusedResultAttr() : FD->hasAttr(); + // If there is no FunctionDecl for the call, check the return type of the + // callee to see if it was declared with the WarnUnusedResult attribute. + if (!Func && !HasWarnUnusedResultAttr) { + if (const TagDecl *TD = CE->getCallReturnType(Ctx)->getAsTagDecl()) + HasWarnUnusedResultAttr = TD->hasAttr(); + } + // If the callee has attribute pure, const, or warn_unused_result, warn // about it. void foo() { strlen("bar"); } should warn. // Index: lib/Sema/SemaStmt.cpp =================================================================== --- lib/Sema/SemaStmt.cpp +++ lib/Sema/SemaStmt.cpp @@ -270,6 +270,12 @@ Diag(Loc, diag::warn_unused_result) << A << R1 << R2; return; } + if (const TagDecl *TD = CE->getCallReturnType(Context)->getAsTagDecl()) { + if (const Attr *A = TD->getAttr()) { + Diag(Loc, diag::warn_unused_result) << A << R1 << R2; + return; + } + } if (ShouldSuppress) return; if (FD->hasAttr()) { Index: test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp =================================================================== --- test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp +++ test/CXX/dcl.dcl/dcl.attr/dcl.attr.nodiscard/p2.cpp @@ -32,6 +32,35 @@ // OK, warning suppressed. (void)fp(); } + +namespace PR31526 { +typedef E (*fp1)(); +typedef S (*fp2)(); + +typedef S S_alias; +typedef S_alias (*fp3)(); + +typedef fp2 fp2_alias; + +void f() { + fp1 one; + fp2 two; + fp3 three; + fp2_alias four; + + 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(); + (void)two(); + (void)three(); + (void)four(); +} +} // namespace PR31526 + #ifdef EXT // expected-warning@4 {{use of the 'nodiscard' attribute is a C++17 extension}} // expected-warning@8 {{use of the 'nodiscard' attribute is a C++17 extension}}