diff options
-rw-r--r-- | include/clang/AST/Expr.h | 3 | ||||
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 3 | ||||
-rw-r--r-- | lib/AST/Expr.cpp | 27 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 19 | ||||
-rw-r--r-- | test/Sema/attr-warn_unused_result.c | 6 | ||||
-rw-r--r-- | test/Sema/unused-expr.c | 8 |
6 files changed, 48 insertions, 18 deletions
diff --git a/include/clang/AST/Expr.h b/include/clang/AST/Expr.h index 5c594cab35..d5dff5065d 100644 --- a/include/clang/AST/Expr.h +++ b/include/clang/AST/Expr.h @@ -991,6 +991,9 @@ public: /// \brief If the callee is a FunctionDecl, return it. Otherwise return 0. FunctionDecl *getDirectCallee(); + const FunctionDecl *getDirectCallee() const { + return const_cast<CallExpr*>(this)->getDirectCallee(); + } /// getNumArgs - Return the number of actual arguments to this call. /// diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 557615bee5..f15c028a53 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1859,6 +1859,9 @@ def warn_unused_expr : Warning<"expression result unused">, def warn_unused_property_expr : Warning< "property access result unused - getters should not have side effects">, InGroup<UnusedValue>; +def warn_unused_call : Warning< + "ignoring return value of function declared with %0 attribute">, + InGroup<UnusedValue>; def err_incomplete_type_used_in_type_trait_expr : Error< "incomplete type %0 used in type trait expression">; diff --git a/lib/AST/Expr.cpp b/lib/AST/Expr.cpp index 98348d6efc..6da11c1cab 100644 --- a/lib/AST/Expr.cpp +++ b/lib/AST/Expr.cpp @@ -692,21 +692,22 @@ bool Expr::isUnusedResultAWarning(SourceLocation &Loc, SourceRange &R1, case CXXMemberCallExprClass: { // If this is a direct call, get the callee. const CallExpr *CE = cast<CallExpr>(this); - const Expr *CalleeExpr = CE->getCallee()->IgnoreParenCasts(); - if (const DeclRefExpr *CalleeDRE = dyn_cast<DeclRefExpr>(CalleeExpr)) { + if (const FunctionDecl *FD = CE->getDirectCallee()) { // If the callee has attribute pure, const, or warn_unused_result, warn // about it. void foo() { strlen("bar"); } should warn. - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(CalleeDRE->getDecl())) - if (FD->getAttr<WarnUnusedResultAttr>() || - FD->getAttr<PureAttr>() || FD->getAttr<ConstAttr>()) { - Loc = CE->getCallee()->getLocStart(); - R1 = CE->getCallee()->getSourceRange(); - - if (unsigned NumArgs = CE->getNumArgs()) - R2 = SourceRange(CE->getArg(0)->getLocStart(), - CE->getArg(NumArgs-1)->getLocEnd()); - return true; - } + // + // Note: If new cases are added here, DiagnoseUnusedExprResult should be + // updated to match for QoI. + if (FD->getAttr<WarnUnusedResultAttr>() || + FD->getAttr<PureAttr>() || FD->getAttr<ConstAttr>()) { + Loc = CE->getCallee()->getLocStart(); + R1 = CE->getCallee()->getSourceRange(); + + if (unsigned NumArgs = CE->getNumArgs()) + R2 = SourceRange(CE->getArg(0)->getLocStart(), + CE->getArg(NumArgs-1)->getLocEnd()); + return true; + } } return false; } diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 2a3b9eeea8..e8cd6b081d 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -80,6 +80,25 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { E = E->IgnoreParens(); if (isa<ObjCImplicitSetterGetterRefExpr>(E)) DiagID = diag::warn_unused_property_expr; + + if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { + // 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 (const FunctionDecl *FD = CE->getDirectCallee()) { + if (FD->getAttr<WarnUnusedResultAttr>()) { + Diag(Loc, diag::warn_unused_call) << R1 << R2 << "warn_unused_result"; + return; + } + if (FD->getAttr<PureAttr>()) { + Diag(Loc, diag::warn_unused_call) << R1 << R2 << "pure"; + return; + } + if (FD->getAttr<ConstAttr>()) { + Diag(Loc, diag::warn_unused_call) << R1 << R2 << "const"; + return; + } + } + } Diag(Loc, DiagID) << R1 << R2; } diff --git a/test/Sema/attr-warn_unused_result.c b/test/Sema/attr-warn_unused_result.c index b4ef1bbeaf..08e95f4f61 100644 --- a/test/Sema/attr-warn_unused_result.c +++ b/test/Sema/attr-warn_unused_result.c @@ -9,9 +9,9 @@ int foo() { if (fn1() < 0 || fn2(2,1) < 0 || fn3(2) < 0) // no warnings return -1; - fn1(); // expected-warning {{expression result unused}} - fn2(92, 21); // expected-warning {{expression result unused}} - fn3(42); // expected-warning {{expression result unused}} + fn1(); // expected-warning {{ignoring return value of function declared with warn_unused_result attribute}} + fn2(92, 21); // expected-warning {{ignoring return value of function declared with pure attribute}} + fn3(42); // expected-warning {{ignoring return value of function declared with const attribute}} return 0; } diff --git a/test/Sema/unused-expr.c b/test/Sema/unused-expr.c index 8b5d156126..f8e7c91474 100644 --- a/test/Sema/unused-expr.c +++ b/test/Sema/unused-expr.c @@ -25,7 +25,7 @@ void bar(volatile int *VP, int *P, int A, __real__ VC; // We know this can't change errno because of -fno-math-errno. - sqrt(A); // expected-warning {{expression result unused}} + sqrt(A); // expected-warning {{ignoring return value of function declared with const attribute}} } extern void t1(); @@ -73,4 +73,8 @@ void t4(int a) { for (;;b == 1) {} // expected-warning{{expression result unused}} } - +// rdar://7186119 +int t5f(void) __attribute__((warn_unused_result)); +void t5() { + t5f(); // expected-warning {{ignoring return value of function declared with warn_unused_result}} +} |