From 40f4ee74fdc904dd469db8fd66eb07e33e06eb45 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Fri, 10 Apr 2009 00:01:14 +0000 Subject: [PATCH] Implement attribute "analyzer_noreturn" (). This allows clients of the analyzer to designate custom assertion routines as "noreturn" functions from the analyzer's perspective but not the compiler's. llvm-svn: 68746 --- clang/include/clang/AST/Attr.h | 12 ++++++++++++ clang/include/clang/Parse/AttributeList.h | 1 + clang/lib/Analysis/GRExprEngine.cpp | 2 +- clang/lib/Parse/AttributeList.cpp | 1 + clang/lib/Sema/SemaDeclAttr.cpp | 24 ++++++++++++++++++----- clang/test/Analysis/misc-ps.m | 20 +++++++++++++++++++ 6 files changed, 54 insertions(+), 6 deletions(-) diff --git a/clang/include/clang/AST/Attr.h b/clang/include/clang/AST/Attr.h index 28f7ec2db6ce..9deed40d4c5b 100644 --- a/clang/include/clang/AST/Attr.h +++ b/clang/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/clang/include/clang/Parse/AttributeList.h b/clang/include/clang/Parse/AttributeList.h index 2113965bee94..751d370dda6e 100644 --- a/clang/include/clang/Parse/AttributeList.h +++ b/clang/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/clang/lib/Analysis/GRExprEngine.cpp b/clang/lib/Analysis/GRExprEngine.cpp index c7ff0aec27ff..1d1100a55ad6 100644 --- a/clang/lib/Analysis/GRExprEngine.cpp +++ b/clang/lib/Analysis/GRExprEngine.cpp @@ -1292,7 +1292,7 @@ void GRExprEngine::VisitCallRec(CallExpr* CE, NodeTy* Pred, FunctionDecl* FD = cast(L).getDecl(); - if (FD->getAttr()) + if (FD->getAttr() || FD->getAttr()) Builder->BuildSinks = true; else { // HACK: Some functions are not marked noreturn, and don't return. diff --git a/clang/lib/Parse/AttributeList.cpp b/clang/lib/Parse/AttributeList.cpp index cd192c92ef06..14011e5b6f15 100644 --- a/clang/lib/Parse/AttributeList.cpp +++ b/clang/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/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index f3f04f077426..bcc17e7eae7c 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/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/clang/test/Analysis/misc-ps.m b/clang/test/Analysis/misc-ps.m index fede2a2d136a..777784aabcbe 100644 --- a/clang/test/Analysis/misc-ps.m +++ b/clang/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}} +} +