From 527042b5a97168594d999e08cd1d42901e0ea6c4 Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Fri, 14 Aug 2009 20:49:40 +0000 Subject: [PATCH] Improve Sema's handling of attribute 'malloc' to reject the attribute when attaching to Objective-C methods (which mirrors GCC's behavior) and to allow the return type of the function to be an Objective-C pointer or Block pointer (which GCC also accepts). Along the way, add 'const' to some of the pointer arguments of various utility functions... llvm-svn: 79040 --- clang/lib/Sema/SemaDeclAttr.cpp | 44 ++++++++++++++++++------------- clang/test/SemaObjC/attr-malloc.m | 14 ++++++++++ 2 files changed, 40 insertions(+), 18 deletions(-) create mode 100644 clang/test/SemaObjC/attr-malloc.m diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index d5d3840569bf..4952e629001e 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -24,13 +24,14 @@ using namespace clang; // Helper functions //===----------------------------------------------------------------------===// -static const FunctionType *getFunctionType(Decl *d, bool blocksToo = true) { +static const FunctionType *getFunctionType(const Decl *d, + bool blocksToo = true) { QualType Ty; - if (ValueDecl *decl = dyn_cast(d)) + if (const ValueDecl *decl = dyn_cast(d)) Ty = decl->getType(); - else if (FieldDecl *decl = dyn_cast(d)) + else if (const FieldDecl *decl = dyn_cast(d)) Ty = decl->getType(); - else if (TypedefDecl* decl = dyn_cast(d)) + else if (const TypedefDecl* decl = dyn_cast(d)) Ty = decl->getUnderlyingType(); else return 0; @@ -46,17 +47,23 @@ static const FunctionType *getFunctionType(Decl *d, bool blocksToo = true) { // FIXME: We should provide an abstraction around a method or function // to provide the following bits of information. +/// isFunctionOrMethod - Return true if the given decl has function +/// type (function or function-typed variable). +static bool isFunction(const Decl *d) { + return getFunctionType(d, false) != NULL; +} + /// isFunctionOrMethod - Return true if the given decl has function /// type (function or function-typed variable) or an Objective-C /// method. -static bool isFunctionOrMethod(Decl *d) { - return getFunctionType(d, false) || isa(d); +static bool isFunctionOrMethod(const Decl *d) { + return isFunction(d)|| isa(d); } /// isFunctionOrMethodOrBlock - Return true if the given decl has function /// type (function or function-typed variable) or an Objective-C /// method or a block. -static bool isFunctionOrMethodOrBlock(Decl *d) { +static bool isFunctionOrMethodOrBlock(const Decl *d) { if (isFunctionOrMethod(d)) return true; // check for block is more involved. @@ -70,7 +77,7 @@ static bool isFunctionOrMethodOrBlock(Decl *d) { /// hasFunctionProto - Return true if the given decl has a argument /// information. This decl should have already passed /// isFunctionOrMethod or isFunctionOrMethodOrBlock. -static bool hasFunctionProto(Decl *d) { +static bool hasFunctionProto(const Decl *d) { if (const FunctionType *FnTy = getFunctionType(d)) return isa(FnTy); else { @@ -82,7 +89,7 @@ static bool hasFunctionProto(Decl *d) { /// getFunctionOrMethodNumArgs - Return number of function or method /// arguments. It is an error to call this on a K&R function (use /// hasFunctionProto first). -static unsigned getFunctionOrMethodNumArgs(Decl *d) { +static unsigned getFunctionOrMethodNumArgs(const Decl *d) { if (const FunctionType *FnTy = getFunctionType(d)) return cast(FnTy)->getNumArgs(); if (const BlockDecl *BD = dyn_cast(d)) @@ -90,7 +97,7 @@ static unsigned getFunctionOrMethodNumArgs(Decl *d) { return cast(d)->param_size(); } -static QualType getFunctionOrMethodArgType(Decl *d, unsigned Idx) { +static QualType getFunctionOrMethodArgType(const Decl *d, unsigned Idx) { if (const FunctionType *FnTy = getFunctionType(d)) return cast(FnTy)->getArgType(Idx); if (const BlockDecl *BD = dyn_cast(d)) @@ -99,13 +106,13 @@ static QualType getFunctionOrMethodArgType(Decl *d, unsigned Idx) { return cast(d)->param_begin()[Idx]->getType(); } -static QualType getFunctionOrMethodResultType(Decl *d) { +static QualType getFunctionOrMethodResultType(const Decl *d) { if (const FunctionType *FnTy = getFunctionType(d)) return cast(FnTy)->getResultType(); return cast(d)->getResultType(); } -static bool isFunctionOrMethodVariadic(Decl *d) { +static bool isFunctionOrMethodVariadic(const Decl *d) { if (const FunctionType *FnTy = getFunctionType(d)) { const FunctionProtoType *proto = cast(FnTy); return proto->isVariadic(); @@ -431,17 +438,18 @@ static void HandleMallocAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - if (!isFunctionOrMethod(d)) { + if (!isFunction(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) << Attr.getName() << 0 /*function*/; return; } - if (FunctionDecl *FD = dyn_cast(d)) { - if (!FD->getResultType()->isPointerType()) { - S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only); - return; - } + const FunctionDecl *FD = cast(d); + QualType RetTy = FD->getResultType(); + + if (!(RetTy->isAnyPointerType() || RetTy->isBlockPointerType())) { + S.Diag(Attr.getLoc(), diag::warn_attribute_malloc_pointer_only); + return; } d->addAttr(::new (S.Context) MallocAttr()); diff --git a/clang/test/SemaObjC/attr-malloc.m b/clang/test/SemaObjC/attr-malloc.m new file mode 100644 index 000000000000..14cf5ff5e278 --- /dev/null +++ b/clang/test/SemaObjC/attr-malloc.m @@ -0,0 +1,14 @@ +// RUN: clang-cc -verify -fsyntax-only -fblocks %s + +#include + +@interface TestAttrMallocOnMethods {} +- (id) test1 __attribute((malloc)); // expected-warning{{'malloc' attribute only applies to function types}} +- (int) test2 __attribute((malloc)); // expected-warning{{'malloc' attribute only applies to function types}} +@end + +id bar(void) __attribute((malloc)); // no-warning + +typedef void (^bptr)(void); +bptr baz(void) __attribute((malloc)); // no-warning +