Several related changes: 
1) implement parser and sema support for reading and verifying attribute(warnunusedresult).
2) rename hasLocalSideEffect to isUnusedResultAWarning, inverting the sense
   of its result.
3) extend isUnusedResultAWarning to directly return the loc and range 
   info that should be reported to the user.  Make it substantially more
   precise in some cases than what was previously reported.
4) teach isUnusedResultAWarning about CallExpr to decls that are 
   pure/const/warnunusedresult, fixing a fixme.
5) change warn_attribute_wrong_decl_type to not pass in english strings, instead,
   pass in integers and use %select.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@64543 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 3ea2b50..347d8f5 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -298,7 +298,7 @@
   // prototypes, so we ignore it as well
   if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << "nonnull" << "function";
+      << "nonnull" << 0 /*function*/;
     return;
   }
   
@@ -408,7 +408,7 @@
 
   if (!isFunctionOrMethod(d)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << "noreturn" << "function";
+      << "noreturn" << 0 /*function*/;
     return;
   }
   
@@ -424,7 +424,7 @@
   
   if (!isa<VarDecl>(d) && !isFunctionOrMethod(d)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << "unused" << "variable and function";
+      << "unused" << 2 /*variable and function*/;
     return;
   }
   
@@ -445,7 +445,7 @@
     }
   } else if (!isFunctionOrMethod(d)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << "used" << "variable and function";
+      << "used" << 2 /*variable and function*/;
     return;
   }
   
@@ -475,7 +475,7 @@
   FunctionDecl *Fn = dyn_cast<FunctionDecl>(d);
   if (!Fn) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << "constructor" << "function";
+      << "constructor" << 0 /*function*/;
     return;
   }
 
@@ -504,7 +504,7 @@
   
   if (!isa<FunctionDecl>(d)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << "destructor" << "function";
+      << "destructor" << 0 /*function*/;
     return;
   }
 
@@ -712,24 +712,42 @@
     }    
   } else {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << "sentinel" << "function or method";
+      << "sentinel" << 3 /*function or method*/;
     return;
   }
   
   // FIXME: Actually create the attribute.
 }
 
-static void HandleWeakAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S) {
+  // check the attribute arguments.
+  if (Attr.getNumArgs() != 0) {
+    S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
+    return;
+  }
+
+  // TODO: could also be applied to methods?
+  FunctionDecl *Fn = dyn_cast<FunctionDecl>(D);
+  if (!Fn) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+    << "warn_unused_result" << 0 /*function*/;
+    return;
+  }
+  
+  Fn->addAttr(new WarnUnusedResultAttr());
+}
+
+static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) {
   // check the attribute arguments.
   if (Attr.getNumArgs() != 0) {
     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
     return;
   }
   
-  d->addAttr(new WeakAttr());
+  D->addAttr(new WeakAttr());
 }
 
-static void HandleDLLImportAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
   // check the attribute arguments.
   if (Attr.getNumArgs() != 0) {
     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
@@ -737,15 +755,15 @@
   }
 
   // Attribute can be applied only to functions or variables.
-  if (isa<VarDecl>(d)) {
-    d->addAttr(new DLLImportAttr());
+  if (isa<VarDecl>(D)) {
+    D->addAttr(new DLLImportAttr());
     return;
   }
 
-  FunctionDecl *FD = dyn_cast<FunctionDecl>(d);
+  FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
   if (!FD) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << "dllimport" << "function or variable";
+      << "dllimport" << 2 /*variable and function*/;
     return;
   }
 
@@ -766,15 +784,15 @@
     }
   }
 
-  if (d->getAttr<DLLExportAttr>()) {
+  if (D->getAttr<DLLExportAttr>()) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << "dllimport";
     return;
   }
 
-  d->addAttr(new DLLImportAttr());
+  D->addAttr(new DLLImportAttr());
 }
 
-static void HandleDLLExportAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
   // check the attribute arguments.
   if (Attr.getNumArgs() != 0) {
     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
@@ -782,15 +800,15 @@
   }
 
   // Attribute can be applied only to functions or variables.
-  if (isa<VarDecl>(d)) {
-    d->addAttr(new DLLExportAttr());
+  if (isa<VarDecl>(D)) {
+    D->addAttr(new DLLExportAttr());
     return;
   }
 
-  FunctionDecl *FD = dyn_cast<FunctionDecl>(d);
+  FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
   if (!FD) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << "dllexport" << "function or variable";
+      << "dllexport" << 2 /*variable and function*/;
     return;
   }
 
@@ -802,10 +820,10 @@
     return;
   }
 
-  d->addAttr(new DLLExportAttr());
+  D->addAttr(new DLLExportAttr());
 }
 
-static void HandleSectionAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static void HandleSectionAttr(Decl *D, const AttributeList &Attr, Sema &S) {
   // Attribute has no arguments.
   if (Attr.getNumArgs() != 1) {
     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 1;
@@ -821,7 +839,7 @@
     S.Diag(Attr.getLoc(), diag::err_attribute_annotate_no_string);
     return;
   }
-  d->addAttr(new SectionAttr(std::string(SE->getStrData(),
+  D->addAttr(new SectionAttr(std::string(SE->getStrData(),
                                          SE->getByteLength())));
 }
 
@@ -835,7 +853,7 @@
   // Attribute can be applied only to functions.
   if (!isa<FunctionDecl>(d)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << "stdcall" << "function";
+      << "stdcall" << 0 /*function*/;
     return;
   }
 
@@ -858,7 +876,7 @@
 
   if (!isa<FunctionDecl>(d)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << "fastcall" << "function";
+      << "fastcall" << 0 /*function*/;
     return;
   }
 
@@ -977,7 +995,7 @@
 
   if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << "format" << "function";
+      << "format" << 0 /*function*/;
     return;
   }
 
@@ -1116,7 +1134,7 @@
   TypedefDecl *TD = dyn_cast<TypedefDecl>(d);
   if (!TD || !TD->getUnderlyingType()->isUnionType()) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << "transparent_union" << "union";
+      << "transparent_union" << 1 /*union*/;
     return;
   }
 
@@ -1334,7 +1352,7 @@
 
   if (!isa<FunctionDecl>(d)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << "nodebug" << "function";
+      << "nodebug" << 0 /*function*/;
     return;
   }
   
@@ -1381,6 +1399,8 @@
   case AttributeList::AT_used:        HandleUsedAttr      (D, Attr, S); break;
   case AttributeList::AT_vector_size: HandleVectorSizeAttr(D, Attr, S); break;
   case AttributeList::AT_visibility:  HandleVisibilityAttr(D, Attr, S); break;
+  case AttributeList::AT_warn_unused_result: HandleWarnUnusedResult(D,Attr,S);
+    break;
   case AttributeList::AT_weak:        HandleWeakAttr      (D, Attr, S); break;
   case AttributeList::AT_transparent_union:
     HandleTransparentUnionAttr(D, Attr, S);
diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp
index bfa1c5e..c2c1a0f 100644
--- a/lib/Sema/SemaStmt.cpp
+++ b/lib/Sema/SemaStmt.cpp
@@ -95,25 +95,17 @@
     Expr *E = dyn_cast<Expr>(Elts[i]);
     if (!E) continue;
     
-    // Warn about expressions with unused results.
-    if (E->hasLocalSideEffect() || E->getType()->isVoidType())
+    // Warn about expressions with unused results if they are non-void and if
+    // this not the last stmt in a stmt expr.
+    if (E->getType()->isVoidType() || (isStmtExpr && i == NumElts-1))
       continue;
     
-    // The last expr in a stmt expr really is used.
-    if (isStmtExpr && i == NumElts-1)
+    SourceLocation Loc;
+    SourceRange R1, R2;
+    if (!E->isUnusedResultAWarning(Loc, R1, R2))
       continue;
-    
-    /// DiagnoseDeadExpr - This expression is side-effect free and evaluated in
-    /// a context where the result is unused.  Emit a diagnostic to warn about
-    /// this.
-    if (const BinaryOperator *BO = dyn_cast<BinaryOperator>(E))
-      Diag(BO->getOperatorLoc(), diag::warn_unused_expr)
-        << BO->getLHS()->getSourceRange() << BO->getRHS()->getSourceRange();
-    else if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E))
-      Diag(UO->getOperatorLoc(), diag::warn_unused_expr)
-        << UO->getSubExpr()->getSourceRange();
-    else
-      Diag(E->getExprLoc(), diag::warn_unused_expr) << E->getSourceRange();
+
+    Diag(Loc, diag::warn_unused_expr) << R1 << R2;
   }
 
   return Owned(new (Context) CompoundStmt(Context, Elts, NumElts, L, R));