From d3f2c10f881311831a84114179342ff4db55e0c3 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Sun, 19 Oct 2008 02:04:16 +0000 Subject: [PATCH] Improve attribute parsing & tests. - Support noreturn on function-typed variables. - Extend isFunctionOrMethod to return true for K&R functions and provide hasFunctionProto to check if a decl has information about its arguments. This code needs some serious cleaning, but works. - Add/improve test cases for noreturn and unused. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@57778 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Sema/SemaDeclAttr.cpp | 68 +++++++++++++++++-------------- test/Sema/attr-noreturn.c | 14 +++++++ test/Sema/attr-unused.c | 12 ++++++ test/SemaObjC/method-attributes.m | 4 +- 4 files changed, 67 insertions(+), 31 deletions(-) create mode 100644 test/Sema/attr-noreturn.c create mode 100644 test/Sema/attr-unused.c diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index 5c04bf0b92..41fe4ed044 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -25,7 +25,7 @@ using namespace clang; // Helper functions //===----------------------------------------------------------------------===// -static const FunctionTypeProto *getFunctionProto(Decl *d) { +static const FunctionType *getFunctionType(Decl *d) { QualType Ty; if (ValueDecl *decl = dyn_cast(d)) Ty = decl->getType(); @@ -38,25 +38,38 @@ static const FunctionTypeProto *getFunctionProto(Decl *d) { if (Ty->isFunctionPointerType()) Ty = Ty->getAsPointerType()->getPointeeType(); - - if (const FunctionType *FnTy = Ty->getAsFunctionType()) - return dyn_cast(FnTy->getAsFunctionType()); - - return 0; + + return Ty->getAsFunctionType(); } // 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 is a (non-K&R) -/// function or an Objective-C method. +/// 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 getFunctionProto(d) || isa(d); - + return getFunctionType(d) || isa(d); } +/// hasFunctionProto - Return true if the given decl has a argument +/// information. This decl should have already passed +/// isFunctionOrMethod. +static bool hasFunctionProto(Decl *d) { + if (const FunctionType *FnTy = getFunctionType(d)) { + return isa(FnTy); + } else { + assert(isa(d)); + return true; + } +} + +/// 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) { - if (const FunctionTypeProto *proto = getFunctionProto(d)) { + if (const FunctionType *FnTy = getFunctionType(d)) { + const FunctionTypeProto *proto = cast(FnTy); return proto->getNumArgs(); } else { return cast(d)->getNumParams(); @@ -64,7 +77,8 @@ static unsigned getFunctionOrMethodNumArgs(Decl *d) { } static QualType getFunctionOrMethodArgType(Decl *d, unsigned Idx) { - if (const FunctionTypeProto *proto = getFunctionProto(d)) { + if (const FunctionType *FnTy = getFunctionType(d)) { + const FunctionTypeProto *proto = cast(FnTy); return proto->getArgType(Idx); } else { return cast(d)->getParamDecl(Idx)->getType(); @@ -72,7 +86,8 @@ static QualType getFunctionOrMethodArgType(Decl *d, unsigned Idx) { } static bool isFunctionOrMethodVariadic(Decl *d) { - if (const FunctionTypeProto *proto = getFunctionProto(d)) { + if (const FunctionType *FnTy = getFunctionType(d)) { + const FunctionTypeProto *proto = cast(FnTy); return proto->isVariadic(); } else { return cast(d)->isVariadic(); @@ -289,17 +304,15 @@ static void HandleIBOutletAttr(Decl *d, const AttributeList &Attr, Sema &S) { } static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { - // GCC ignores the nonnull attribute on K&R style function // prototypes, so we ignore it as well - const FunctionTypeProto *proto = getFunctionProto(d); - if (!proto) { + if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type, "nonnull", "function"); return; } - unsigned NumArgs = proto->getNumArgs(); + unsigned NumArgs = getFunctionOrMethodNumArgs(d); // The nonnull attribute only applies to pointers. llvm::SmallVector NonNullArgs; @@ -328,7 +341,7 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { --x; // Is the function argument a pointer type? - if (!proto->getArgType(x)->isPointerType()) { + if (!getFunctionOrMethodArgType(d, x)->isPointerType()) { // FIXME: Should also highlight argument in decl. S.Diag(Attr.getLoc(), diag::err_nonnull_pointers_only, "nonnull", Ex->getSourceRange()); @@ -341,12 +354,9 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) { // If no arguments were specified to __attribute__((nonnull)) then all // pointer arguments have a nonnull attribute. if (NonNullArgs.empty()) { - unsigned idx = 0; - - for (FunctionTypeProto::arg_type_iterator - I=proto->arg_type_begin(), E=proto->arg_type_end(); I!=E; ++I, ++idx) - if ((*I)->isPointerType()) - NonNullArgs.push_back(idx); + for (unsigned I = 0, E = getFunctionOrMethodNumArgs(d); I != E; ++I) + if (getFunctionOrMethodArgType(d, I)->isPointerType()) + NonNullArgs.push_back(I); if (NonNullArgs.empty()) { S.Diag(Attr.getLoc(), diag::warn_attribute_nonnull_no_pointers); @@ -393,8 +403,8 @@ static void HandleNoReturnAttr(Decl *d, const AttributeList &Attr, Sema &S) { std::string("0")); return; } - - if (!isa(d) && !isa(d)) { + + if (!isFunctionOrMethod(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type, "noreturn", "function"); return; @@ -411,7 +421,7 @@ static void HandleUnusedAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - if (!isa(d) && !getFunctionProto(d)) { + if (!isa(d) && !isFunctionOrMethod(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type, "unused", "variable and function"); return; @@ -755,9 +765,7 @@ static void HandleFormatAttr(Decl *d, const AttributeList &Attr, Sema &S) { return; } - // GCC ignores the format attribute on K&R style function - // prototypes, so we ignore it as well - if (!isFunctionOrMethod(d)) { + if (!isFunctionOrMethod(d) || !hasFunctionProto(d)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type, "format", "function"); return; diff --git a/test/Sema/attr-noreturn.c b/test/Sema/attr-noreturn.c new file mode 100644 index 0000000000..5384eaf832 --- /dev/null +++ b/test/Sema/attr-noreturn.c @@ -0,0 +1,14 @@ +// RUN: clang -verify -fsyntax-only %s + +static void (*fp0)(void) __attribute__((noreturn)); + +static void __attribute__((noreturn)) f0(void) { + fatal(); +} + +// On K&R +int f1() __attribute__((noreturn)); + +int g0 __attribute__((noreturn)); // expected-warning {{'noreturn' attribute only applies to function types}} + +int f2() __attribute__((noreturn(1, 2))); // expected-error {{attribute requires 0 argument(s)}} diff --git a/test/Sema/attr-unused.c b/test/Sema/attr-unused.c new file mode 100644 index 0000000000..87d58572a6 --- /dev/null +++ b/test/Sema/attr-unused.c @@ -0,0 +1,12 @@ +// RUN: clang -verify -fsyntax-only %s + +static void (*fp0)(void) __attribute__((unused)); + +static void __attribute__((unused)) f0(void); + +// On K&R +int f1() __attribute__((unused)); + +int g0 __attribute__((unused)); + +int f2() __attribute__((unused(1, 2))); // expected-error {{attribute requires 0 argument(s)}} diff --git a/test/SemaObjC/method-attributes.m b/test/SemaObjC/method-attributes.m index d16d6ffe78..5b2cab6a39 100644 --- a/test/SemaObjC/method-attributes.m +++ b/test/SemaObjC/method-attributes.m @@ -1,8 +1,10 @@ -// RUN: clang -fsyntax-only %s +// RUN: clang -verify -fsyntax-only %s @class NSString; @interface A -t1 __attribute__((noreturn)); - (NSString *)stringByAppendingFormat:(NSString *)format, ... __attribute__((format(__NSString__, 1, 2))); +-(void) m0 __attribute__((noreturn)); +-(void) m1 __attribute__((unused)); @end