forked from OSchip/llvm-project
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:
parent
fe56c25065
commit
40f4ee74fd
|
@ -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:
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
AT_alias,
|
||||
AT_aligned,
|
||||
AT_always_inline,
|
||||
AT_analyzer_noreturn,
|
||||
AT_annotate,
|
||||
AT_blocks,
|
||||
AT_cleanup,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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}}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue