forked from OSchip/llvm-project
Add some basic type checking for attributes ns_returns_retained and
cf_returns_retained. Currently this attribute can now be applied to any Objective-C method or C function that returns a pointer or Objective-C object type. Modify the tablegen definition of diagnostic 'warn_attribute_wrong_decl_type' to expect that the diagnostics infrastructure will add quotes around the attribute name when appropriate. Alonq with this change, I modified the places where this warning is issued to passed the attribute's IdentifierInfo* instead of having a hard-coded C constant string. llvm-svn: 71718
This commit is contained in:
parent
3181652363
commit
3b204e4c2e
|
@ -415,7 +415,7 @@ def warn_attribute_weak_on_local : Warning<
|
||||||
def warn_attribute_weak_import_invalid_on_definition : Warning<
|
def warn_attribute_weak_import_invalid_on_definition : Warning<
|
||||||
"'weak_import' attribute cannot be specified on a definition">;
|
"'weak_import' attribute cannot be specified on a definition">;
|
||||||
def warn_attribute_wrong_decl_type : Warning<
|
def warn_attribute_wrong_decl_type : Warning<
|
||||||
"'%0' attribute only applies to %select{function|union|"
|
"%0 attribute only applies to %select{function|union|"
|
||||||
"variable and function|function or method|parameter|parameter or Objective-C method}1 types">;
|
"variable and function|function or method|parameter|parameter or Objective-C method}1 types">;
|
||||||
def warn_gnu_inline_attribute_requires_inline : Warning<
|
def warn_gnu_inline_attribute_requires_inline : Warning<
|
||||||
"'gnu_inline' attribute requires function to be marked 'inline',"
|
"'gnu_inline' attribute requires function to be marked 'inline',"
|
||||||
|
@ -491,6 +491,9 @@ def note_attribute_overloadable_prev_overload : Note<
|
||||||
"previous overload of function is here">;
|
"previous overload of function is here">;
|
||||||
def err_attribute_overloadable_no_prototype : Error<
|
def err_attribute_overloadable_no_prototype : Error<
|
||||||
"'overloadable' function %0 must have a prototype">;
|
"'overloadable' function %0 must have a prototype">;
|
||||||
|
def warn_ns_attribute_wrong_return_type : Warning<
|
||||||
|
"%0 attribute only applies to functions or methods that "
|
||||||
|
"return a pointer or Objective-C object">;
|
||||||
|
|
||||||
// Function Parameter Semantic Analysis.
|
// Function Parameter Semantic Analysis.
|
||||||
def err_param_with_void_type : Error<"argument may not have 'void' type">;
|
def err_param_with_void_type : Error<"argument may not have 'void' type">;
|
||||||
|
|
|
@ -295,7 +295,7 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||||
// prototypes, so we ignore it as well
|
// prototypes, so we ignore it as well
|
||||||
if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
|
if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "nonnull" << 0 /*function*/;
|
<< Attr.getName() << 0 /*function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,7 +395,7 @@ static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
|
||||||
|
|
||||||
if (!isa<FunctionDecl>(d)) {
|
if (!isa<FunctionDecl>(d)) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "always_inline" << 0 /*function*/;
|
<< Attr.getName() << 0 /*function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,7 +403,7 @@ static void HandleAlwaysInlineAttr(Decl *d, const AttributeList &Attr,
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
|
static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
|
||||||
Sema &S, const char *attrName) {
|
Sema &S) {
|
||||||
// check the attribute arguments.
|
// check the attribute arguments.
|
||||||
if (Attr.getNumArgs() != 0) {
|
if (Attr.getNumArgs() != 0) {
|
||||||
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) << 0;
|
||||||
|
@ -414,7 +414,7 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
|
||||||
ValueDecl *VD = dyn_cast<ValueDecl>(d);
|
ValueDecl *VD = dyn_cast<ValueDecl>(d);
|
||||||
if (VD == 0 || !VD->getType()->isBlockPointerType()) {
|
if (VD == 0 || !VD->getType()->isBlockPointerType()) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< attrName << 0 /*function*/;
|
<< Attr.getName() << 0 /*function*/;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -423,13 +423,13 @@ static bool HandleCommonNoReturnAttr(Decl *d, const AttributeList &Attr,
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||||
if (HandleCommonNoReturnAttr(d, Attr, S, "noreturn"))
|
if (HandleCommonNoReturnAttr(d, Attr, S))
|
||||||
d->addAttr(::new (S.Context) NoReturnAttr());
|
d->addAttr(::new (S.Context) NoReturnAttr());
|
||||||
}
|
}
|
||||||
|
|
||||||
static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
|
static void HandleAnalyzerNoReturnAttr(Decl *d, const AttributeList &Attr,
|
||||||
Sema &S) {
|
Sema &S) {
|
||||||
if (HandleCommonNoReturnAttr(d, Attr, S, "analyzer_noreturn"))
|
if (HandleCommonNoReturnAttr(d, Attr, S))
|
||||||
d->addAttr(::new (S.Context) AnalyzerNoReturnAttr());
|
d->addAttr(::new (S.Context) AnalyzerNoReturnAttr());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -442,7 +442,7 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||||
|
|
||||||
if (!isa<VarDecl>(d) && !isFunctionOrMethod(d)) {
|
if (!isa<VarDecl>(d) && !isFunctionOrMethod(d)) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "unused" << 2 /*variable and function*/;
|
<< Attr.getName() << 2 /*variable and function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -463,7 +463,7 @@ static void HandleUsedAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||||
}
|
}
|
||||||
} else if (!isFunctionOrMethod(d)) {
|
} else if (!isFunctionOrMethod(d)) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "used" << 2 /*variable and function*/;
|
<< Attr.getName() << 2 /*variable and function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,7 +492,7 @@ static void HandleConstructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||||
|
|
||||||
if (!isa<FunctionDecl>(d)) {
|
if (!isa<FunctionDecl>(d)) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "constructor" << 0 /*function*/;
|
<< Attr.getName() << 0 /*function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,7 +521,7 @@ static void HandleDestructorAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||||
|
|
||||||
if (!isa<FunctionDecl>(d)) {
|
if (!isa<FunctionDecl>(d)) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "destructor" << 0 /*function*/;
|
<< Attr.getName() << 0 /*function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -722,7 +722,7 @@ static void HandleSentinelAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "sentinel" << 3 /*function or method*/;
|
<< Attr.getName() << 3 /*function or method*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -740,7 +740,7 @@ static void HandleWarnUnusedResult(Decl *D, const AttributeList &Attr, Sema &S)
|
||||||
FunctionDecl *Fn = dyn_cast<FunctionDecl>(D);
|
FunctionDecl *Fn = dyn_cast<FunctionDecl>(D);
|
||||||
if (!Fn) {
|
if (!Fn) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "warn_unused_result" << 0 /*function*/;
|
<< Attr.getName() << 0 /*function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -757,7 +757,7 @@ static void HandleWeakAttr(Decl *D, const AttributeList &Attr, Sema &S) {
|
||||||
// TODO: could also be applied to methods?
|
// TODO: could also be applied to methods?
|
||||||
if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) {
|
if (!isa<FunctionDecl>(D) && !isa<VarDecl>(D)) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "weak" << 2 /*variable and function*/;
|
<< Attr.getName() << 2 /*variable and function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -782,7 +782,7 @@ static void HandleWeakImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "weak_import" << 2 /*variable and function*/;
|
<< Attr.getName() << 2 /*variable and function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -813,7 +813,7 @@ static void HandleDLLImportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
|
||||||
FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
|
FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
|
||||||
if (!FD) {
|
if (!FD) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "dllimport" << 2 /*variable and function*/;
|
<< Attr.getName() << 2 /*variable and function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -858,7 +858,7 @@ static void HandleDLLExportAttr(Decl *D, const AttributeList &Attr, Sema &S) {
|
||||||
FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
|
FunctionDecl *FD = dyn_cast<FunctionDecl>(D);
|
||||||
if (!FD) {
|
if (!FD) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "dllexport" << 2 /*variable and function*/;
|
<< Attr.getName() << 2 /*variable and function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -903,7 +903,7 @@ static void HandleStdCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||||
// Attribute can be applied only to functions.
|
// Attribute can be applied only to functions.
|
||||||
if (!isa<FunctionDecl>(d)) {
|
if (!isa<FunctionDecl>(d)) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "stdcall" << 0 /*function*/;
|
<< Attr.getName() << 0 /*function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -926,7 +926,7 @@ static void HandleFastCallAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||||
|
|
||||||
if (!isa<FunctionDecl>(d)) {
|
if (!isa<FunctionDecl>(d)) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "fastcall" << 0 /*function*/;
|
<< Attr.getName() << 0 /*function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1045,7 +1045,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||||
|
|
||||||
if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
|
if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "format" << 0 /*function*/;
|
<< Attr.getName() << 0 /*function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1190,7 +1190,7 @@ static void HandleTransparentUnionAttr(Decl *d, const AttributeList &Attr,
|
||||||
|
|
||||||
if (!RD || !RD->isUnion()) {
|
if (!RD || !RD->isUnion()) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "transparent_union" << 1 /*union*/;
|
<< Attr.getName() << 1 /*union*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1464,7 +1464,7 @@ static void HandleNodebugAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||||
|
|
||||||
if (!isFunctionOrMethod(d)) {
|
if (!isFunctionOrMethod(d)) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "nodebug" << 0 /*function*/;
|
<< Attr.getName() << 0 /*function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1480,7 +1480,7 @@ static void HandleNoinlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||||
|
|
||||||
if (!isa<FunctionDecl>(d)) {
|
if (!isa<FunctionDecl>(d)) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "noinline" << 0 /*function*/;
|
<< Attr.getName() << 0 /*function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1497,7 +1497,7 @@ static void HandleGNUInlineAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||||
FunctionDecl *Fn = dyn_cast<FunctionDecl>(d);
|
FunctionDecl *Fn = dyn_cast<FunctionDecl>(d);
|
||||||
if (Fn == 0) {
|
if (Fn == 0) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "gnu_inline" << 0 /*function*/;
|
<< Attr.getName() << 0 /*function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1518,7 +1518,7 @@ static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||||
|
|
||||||
if (!isFunctionOrMethod(d)) {
|
if (!isFunctionOrMethod(d)) {
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
<< "regparm" << 0 /*function*/;
|
<< Attr.getName() << 0 /*function*/;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1552,24 +1552,24 @@ static void HandleRegparmAttr(Decl *d, const AttributeList &Attr, Sema &S) {
|
||||||
static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
|
static void HandleNSReturnsRetainedAttr(Decl *d, const AttributeList &Attr,
|
||||||
Sema &S) {
|
Sema &S) {
|
||||||
|
|
||||||
if (!isa<ObjCMethodDecl>(d) && !isa<FunctionDecl>(d)) {
|
QualType RetTy;
|
||||||
const char *name;
|
|
||||||
|
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(d))
|
||||||
switch (Attr.getKind()) {
|
RetTy = MD->getResultType();
|
||||||
default:
|
else if (FunctionDecl *FD = dyn_cast<FunctionDecl>(d))
|
||||||
assert(0 && "invalid ownership attribute");
|
RetTy = FD->getResultType();
|
||||||
return;
|
else {
|
||||||
case AttributeList::AT_cf_returns_retained:
|
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
|
||||||
name = "cf_returns_retained"; break;
|
<< Attr.getName() << 3 /* function or method */;
|
||||||
case AttributeList::AT_ns_returns_retained:
|
|
||||||
name = "ns_returns_retained"; break;
|
|
||||||
};
|
|
||||||
|
|
||||||
S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) <<
|
|
||||||
name << 3 /* function or method */;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!(S.Context.isObjCNSObjectType(RetTy) || RetTy->getAsPointerType())) {
|
||||||
|
S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type)
|
||||||
|
<< Attr.getName();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (Attr.getKind()) {
|
switch (Attr.getKind()) {
|
||||||
default:
|
default:
|
||||||
assert(0 && "invalid ownership attribute");
|
assert(0 && "invalid ownership attribute");
|
||||||
|
|
|
@ -596,11 +596,17 @@ int RDar6320065_test() {
|
||||||
// Tests of ownership attributes.
|
// Tests of ownership attributes.
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
typedef NSString* MyStringTy;
|
||||||
|
|
||||||
@interface TestOwnershipAttr : NSObject
|
@interface TestOwnershipAttr : NSObject
|
||||||
- (NSString*) returnsAnOwnedString __attribute__((ns_returns_retained));
|
- (NSString*) returnsAnOwnedString __attribute__((ns_returns_retained)); // no-warning
|
||||||
- (NSString*) returnsAnOwnedCFString __attribute__((cf_returns_retained));
|
- (NSString*) returnsAnOwnedCFString __attribute__((cf_returns_retained)); // no-warning
|
||||||
|
- (MyStringTy) returnsAnOwnedTypedString __attribute__((ns_returns_retained)); // no-warning
|
||||||
|
- (int) returnsAnOwnedInt __attribute__((ns_returns_retained)); // expected-warning{{'ns_returns_retained' attribute only applies to functions or methods that return a pointer or Objective-C object}}
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
static int ownership_attribute_doesnt_go_here __attribute__((ns_returns_retained)); // expected-warning{{'ns_returns_retained' attribute only applies to function or method types}}
|
||||||
|
|
||||||
void test_attr_1(TestOwnershipAttr *X) {
|
void test_attr_1(TestOwnershipAttr *X) {
|
||||||
NSString *str = [X returnsAnOwnedString]; // expected-warning{{leak}}
|
NSString *str = [X returnsAnOwnedString]; // expected-warning{{leak}}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue