getASTContext());
}
- /// Returns the WarnUnusedResultAttr that is either declared on this
- /// function, or its return type declaration.
- const Attr *getUnusedResultAttr() const;
-
- /// Returns true if this function or its return type has the
- /// warn_unused_result attribute.
- bool hasUnusedResultAttr() const { return getUnusedResultAttr() != nullptr; }
-
/// Returns the storage class as written in the source. For the
/// computed linkage of symbol, see getLinkage.
StorageClass getStorageClass() const {
/// type.
QualType getCallReturnType(const ASTContext &Ctx) const;
+ /// Returns the WarnUnusedResultAttr that is either declared on the called
+ /// 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) != nullptr;
+ }
+
SourceLocation getRParenLoc() const { return RParenLoc; }
void setRParenLoc(SourceLocation L) { RParenLoc = L; }
return FTL.getExceptionSpecRange();
}
-const Attr *FunctionDecl::getUnusedResultAttr() const {
- QualType RetType = getReturnType();
- if (const auto *Ret = RetType->getAsRecordDecl()) {
- if (const auto *R = Ret->getAttr<WarnUnusedResultAttr>())
- return R;
- } else if (const auto *ET = RetType->getAs<EnumType>()) {
- if (const EnumDecl *ED = ET->getDecl()) {
- if (const auto *R = ED->getAttr<WarnUnusedResultAttr>())
- return R;
- }
- }
- return getAttr<WarnUnusedResultAttr>();
-}
-
/// For an inline function definition in C, or for a gnu_inline function
/// in C++, determine whether the definition will be externally visible.
///
return FnType->getReturnType();
}
+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;
+
+ // 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 {
if (isa<CXXOperatorCallExpr>(this))
return cast<CXXOperatorCallExpr>(this)->getBeginLoc();
// If this is a direct call, get the callee.
const CallExpr *CE = cast<CallExpr>(this);
if (const Decl *FD = CE->getCalleeDecl()) {
- const FunctionDecl *Func = dyn_cast<FunctionDecl>(FD);
- bool HasWarnUnusedResultAttr = Func ? Func->hasUnusedResultAttr()
- : FD->hasAttr<WarnUnusedResultAttr>();
-
// If the callee has attribute pure, const, or warn_unused_result, warn
// about it. void foo() { strlen("bar"); } should warn.
//
// Note: If new cases are added here, DiagnoseUnusedExprResult should be
// updated to match for QoI.
- if (HasWarnUnusedResultAttr ||
+ if (CE->hasUnusedResultAttr(Ctx) ||
FD->hasAttr<PureAttr>() || FD->hasAttr<ConstAttr>()) {
WarnE = this;
Loc = CE->getCallee()->getBeginLoc();
if (E->getType()->isVoidType())
return;
+ if (const Attr *A = CE->getUnusedResultAttr(Context)) {
+ Diag(Loc, diag::warn_unused_result) << A << R1 << R2;
+ return;
+ }
+
// If the callee has attribute pure, const, or warn_unused_result, warn with
// a more specific message to make it clear what is happening. If the call
// is written in a macro body, only warn if it has the warn_unused_result
// attribute.
if (const Decl *FD = CE->getCalleeDecl()) {
- if (const Attr *A = isa<FunctionDecl>(FD)
- ? cast<FunctionDecl>(FD)->getUnusedResultAttr()
- : FD->getAttr<WarnUnusedResultAttr>()) {
- Diag(Loc, diag::warn_unused_result) << A << R1 << R2;
- return;
- }
if (ShouldSuppress)
return;
if (FD->hasAttr<PureAttr>()) {
// 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}}