diff options
author | Ted Kremenek <kremenek@apple.com> | 2009-04-10 00:01:14 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2009-04-10 00:01:14 +0000 |
commit | b725232b46e92f3e36b03a32a6fc75748c312122 (patch) | |
tree | 4d9adc37e8bf8da2272db69b7d09242c93081345 | |
parent | 2cf2634ffdb4f7c8d46cef3f8e60a55993f1c57a (diff) |
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
-rw-r--r-- | include/clang/AST/Attr.h | 12 | ||||
-rw-r--r-- | include/clang/Parse/AttributeList.h | 1 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/AttributeList.cpp | 1 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 24 | ||||
-rw-r--r-- | test/Analysis/misc-ps.m | 20 |
6 files changed, 54 insertions, 6 deletions
diff --git a/include/clang/AST/Attr.h b/include/clang/AST/Attr.h index 28f7ec2db6..9deed40d4c 100644 --- a/include/clang/AST/Attr.h +++ b/include/clang/AST/Attr.h @@ -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: diff --git a/include/clang/Parse/AttributeList.h b/include/clang/Parse/AttributeList.h index 2113965bee..751d370dda 100644 --- a/include/clang/Parse/AttributeList.h +++ b/include/clang/Parse/AttributeList.h @@ -49,6 +49,7 @@ public: AT_alias, AT_aligned, AT_always_inline, + AT_analyzer_noreturn, AT_annotate, AT_blocks, AT_cleanup, diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index c7ff0aec27..1d1100a55a 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -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. diff --git a/lib/Parse/AttributeList.cpp b/lib/Parse/AttributeList.cpp index cd192c92ef..14011e5b6f 100644 --- a/lib/Parse/AttributeList.cpp +++ b/lib/Parse/AttributeList.cpp @@ -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; diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index f3f04f0774..bcc17e7eae 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -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; diff --git a/test/Analysis/misc-ps.m b/test/Analysis/misc-ps.m index fede2a2d13..777784aabc 100644 --- a/test/Analysis/misc-ps.m +++ b/test/Analysis/misc-ps.m @@ -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}} +} + |