]> granicus.if.org Git - clang/commitdiff
Improve attribute parsing & tests.
authorDaniel Dunbar <daniel@zuster.org>
Sun, 19 Oct 2008 02:04:16 +0000 (02:04 +0000)
committerDaniel Dunbar <daniel@zuster.org>
Sun, 19 Oct 2008 02:04:16 +0000 (02:04 +0000)
 - 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
test/Sema/attr-noreturn.c [new file with mode: 0644]
test/Sema/attr-unused.c [new file with mode: 0644]
test/SemaObjC/method-attributes.m

index 5c04bf0b92235df5a91548f15462ab2d6eff677b..41fe4ed044279c7fe5faa3bc2dbdd97cc0ee08fb 100644 (file)
@@ -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<ValueDecl>(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<FunctionTypeProto>(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<ObjCMethodDecl>(d);
+  return getFunctionType(d) || isa<ObjCMethodDecl>(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<FunctionTypeProto>(FnTy);
+  } else {
+    assert(isa<ObjCMethodDecl>(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<FunctionTypeProto>(FnTy);
     return proto->getNumArgs();
   } else {
     return cast<ObjCMethodDecl>(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<FunctionTypeProto>(FnTy);
     return proto->getArgType(Idx);
   } else {
     return cast<ObjCMethodDecl>(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<FunctionTypeProto>(FnTy);
     return proto->isVariadic();
   } else {
     return cast<ObjCMethodDecl>(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<unsigned, 10> 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<FunctionDecl>(d) && !isa<ObjCMethodDecl>(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<VarDecl>(d) && !getFunctionProto(d)) {
+  if (!isa<VarDecl>(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 (file)
index 0000000..5384eaf
--- /dev/null
@@ -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 (file)
index 0000000..87d5857
--- /dev/null
@@ -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)}}
index d16d6ffe7879a478e7819e658c74906e7f0d95c5..5b2cab6a3910a82d023b64a44b001db077e2a317 100644 (file)
@@ -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