Implement attribute "analyzer_noreturn" (<rdar://problem/6777003>). This allows
clients of the analyzer to designate custom assertion routines as "noreturn"
functions from the analyzer's perspective but not the compiler's.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@68746 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp
index c7ff0ae..1d1100a 100644
--- a/lib/Analysis/GRExprEngine.cpp
+++ b/lib/Analysis/GRExprEngine.cpp
@@ -1292,7 +1292,7 @@
       
       FunctionDecl* FD = cast<loc::FuncVal>(L).getDecl();
       
-      if (FD->getAttr<NoReturnAttr>())
+      if (FD->getAttr<NoReturnAttr>() || FD->getAttr<AnalyzerNoReturnAttr>())
         Builder->BuildSinks = true;
       else {
         // HACK: Some functions are not marked noreturn, and don't return.
diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp
index cd192c9..14011e5 100644
--- a/lib/Parse/AttributeList.cpp
+++ b/lib/Parse/AttributeList.cpp
@@ -126,6 +126,7 @@
     break;
   case 17:
     if (!memcmp(Str, "transparent_union", 17)) return AT_transparent_union;
+    if (!memcmp(Str, "analyzer_noreturn", 17)) return AT_analyzer_noreturn;
     break;
   case 18:
     if (!memcmp(Str, "warn_unused_result", 18)) return AT_warn_unused_result;
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index f3f04f0..bcc17e7 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -400,20 +400,32 @@
   d->addAttr(::new (S.Context) AlwaysInlineAttr());
 }
 
-static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
+                                     Sema &S, const char *attrName) {
   // check the attribute arguments.
   if (Attr.getNumArgs() != 0) {
     S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
-    return;
+    return false;
   }
 
   if (!isFunctionOrMethod(d)) {
     S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
-      << "noreturn" << 0 /*function*/;
-    return;
+      << attrName << 0 /*function*/;
+    return false;
   }
   
-  d->addAttr(::new (S.Context) NoReturnAttr());
+  return true;
+}
+
+static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
+  if (HandleCommonNoReturnAttr(d, Attr, S, "noreturn"))  
+    d->addAttr(::new (S.Context) NoReturnAttr());
+}
+
+static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
+                                       Sema &S) {
+  if (HandleCommonNoReturnAttr(d, Attr, S, "analyzer_noreturn"))  
+    d->addAttr(::new (S.Context) AnalyzerNoReturnAttr());
 }
 
 static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
@@ -1498,6 +1510,8 @@
   case AttributeList::AT_aligned:     HandleAlignedAttr   (D, Attr, S); break;
   case AttributeList::AT_always_inline: 
     HandleAlwaysInlineAttr  (D, Attr, S); break;
+  case AttributeList::AT_analyzer_noreturn:
+    HandleAnalyzerNoReturnAttr  (D, Attr, S); break;  
   case AttributeList::AT_annotate:    HandleAnnotateAttr  (D, Attr, S); break;
   case AttributeList::AT_constructor: HandleConstructorAttr(D, Attr, S); break;
   case AttributeList::AT_deprecated:  HandleDeprecatedAttr(D, Attr, S); break;