]> granicus.if.org Git - clang/commitdiff
Implement attribute "analyzer_noreturn" (<rdar://problem/6777003>). This allows
authorTed Kremenek <kremenek@apple.com>
Fri, 10 Apr 2009 00:01:14 +0000 (00:01 +0000)
committerTed Kremenek <kremenek@apple.com>
Fri, 10 Apr 2009 00:01:14 +0000 (00:01 +0000)
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

include/clang/AST/Attr.h
include/clang/Parse/AttributeList.h
lib/Analysis/GRExprEngine.cpp
lib/Parse/AttributeList.cpp
lib/Sema/SemaDeclAttr.cpp
test/Analysis/misc-ps.m

index 28f7ec2db6ce933f57fa8d444d3d86fa79e7133b..9deed40d4c5bbaeeb0545a6cb1552379686ae527 100644 (file)
@@ -29,6 +29,7 @@ public:
     Alias,
     Aligned,
     AlwaysInline,
+    AnalyzerNoReturn, // Clang-specific.
     Annotate,
     AsmLabel, // Represent GCC asm label extension.
     Blocks,
@@ -238,6 +239,17 @@ public:
   static bool classof(const Attr *A) { return A->getKind() == NoReturn; }  
   static bool classof(const NoReturnAttr *A) { return true; }
 };
+  
+class AnalyzerNoReturnAttr : public Attr {
+public:
+  AnalyzerNoReturnAttr() : Attr(AnalyzerNoReturn) {}
+    
+  // Implement isa/cast/dyncast/etc.
+  static bool classof(const Attr *A) {
+      return A->getKind() == AnalyzerNoReturn;
+  }  
+  static bool classof(const AnalyzerNoReturnAttr *A) { return true; }
+};
 
 class DeprecatedAttr : public Attr {
 public:
index 2113965bee94b62785aac2478ff9e4a2141b66d7..751d370dda6e017bf8a55312a07d2edc6a85d66d 100644 (file)
@@ -49,6 +49,7 @@ public:
     AT_alias,
     AT_aligned,
     AT_always_inline,
+    AT_analyzer_noreturn,
     AT_annotate,
     AT_blocks,
     AT_cleanup,
index c7ff0aec27ff7ca34dde9eb6967a67af93f54879..1d1100a55ad61df8b72c73f93b0dc9ff6936b634 100644 (file)
@@ -1292,7 +1292,7 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, NodeTy* Pred,
       
       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.
index cd192c92ef06285a16842bb01b3c7b5a22836335..14011e5b6f15c2b2955efd85580fa42746887dd7 100644 (file)
@@ -126,6 +126,7 @@ AttributeList::Kind AttributeList::getKind(const IdentifierInfo *Name) {
     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;
index f3f04f077426dd25041fcf1ed44355940be401a6..bcc17e7eae7c4b525efb8ff8b81aa8bc2d63e2f7 100644 (file)
@@ -400,20 +400,32 @@ static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
   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 @@ static void ProcessDeclAttribute(Decl *D, const AttributeList &Attr, Sema &S) {
   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;
index fede2a2d136a1b2eb88274fba198a2895e8a2110..777784aabcbe55077629c8bd4a2e779cbeb5659b 100644 (file)
@@ -225,3 +225,23 @@ void pr6708148_test(void) {
   pr6708148_use(x); // no-warning
 }
 
+// Handle both kinds of noreturn attributes for pruning paths.
+void rdar_6777003_noret() __attribute__((noreturn));
+void rdar_6777003_analyzer_noret() __attribute__((analyzer_noreturn));
+
+void rdar_6777003(int x) {
+  int *p = 0;
+  
+  if (x == 1) {
+    rdar_6777003_noret();
+    *p = 1; // no-warning;    
+  }
+  
+  if (x == 2) {
+    rdar_6777003_analyzer_noret();
+    *p = 1; // no-warning;
+  }
+  
+  *p = 1; // expected-warning{{Dereference of null pointer}}  
+}
+