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.

llvm-svn: 68746
This commit is contained in:
Ted Kremenek 2009-04-10 00:01:14 +00:00
parent fe56c25065
commit 40f4ee74fd
6 changed files with 54 additions and 6 deletions

View 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:

View File

@ -49,6 +49,7 @@ public:
AT_alias,
AT_aligned,
AT_always_inline,
AT_analyzer_noreturn,
AT_annotate,
AT_blocks,
AT_cleanup,

View 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.

View 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;

View 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;

View 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}}
}