]> granicus.if.org Git - clang/commitdiff
Added sema support for the nonnull attribute. Will add test cases soon.
authorTed Kremenek <kremenek@apple.com>
Mon, 21 Jul 2008 21:53:04 +0000 (21:53 +0000)
committerTed Kremenek <kremenek@apple.com>
Mon, 21 Jul 2008 21:53:04 +0000 (21:53 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@53881 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/AST/Attr.h
include/clang/Basic/DiagnosticKinds.def
include/clang/Parse/AttributeList.h
lib/Sema/SemaDeclAttr.cpp

index c659454b8320b5176703045b53c022c7153f7b41..0f80f238829d0edeb2dadf67e1b5e4fb6ee3695d 100644 (file)
@@ -16,6 +16,7 @@
 
 #include <cassert>
 #include <string>
+#include <algorithm>
 
 namespace clang {
 
@@ -27,6 +28,7 @@ public:
     Aligned,
     Packed,
     Annotate,
+    NonNull,
     NoReturn,
     Deprecated,
     Weak,
@@ -173,6 +175,32 @@ public:
   static bool classof(const Attr *A) { return A->getKind() == NoThrow; }
   static bool classof(const NoThrowAttr *A) { return true; }
 };
+  
+class NonNullAttr : public Attr {
+  unsigned* ArgNums;
+  unsigned Size;
+public:
+  NonNullAttr(unsigned* arg_nums = 0, unsigned size = 0) : Attr(NonNull) {
+    if (size) {
+      assert (arg_nums);
+      ArgNums = new unsigned[size];
+      Size = size;
+      memcpy(ArgNums, arg_nums, sizeof(*ArgNums)*size);
+    }
+    else {
+      ArgNums = 0;
+      Size = 0;
+    }    
+  }
+  
+  virtual ~NonNullAttr() {
+    delete [] ArgNums;
+  }
+  
+  bool isNonNull(unsigned arg) {
+    return ArgNums ? std::binary_search(ArgNums, ArgNums+Size, arg) : true;
+  }  
+};
 
 class FormatAttr : public Attr {
   std::string Type;
index a7c750a27589f81c6a1c1a64bcf9bd94670cea74..c9178ab441139c7dc72a573cd1e37d8664231d98 100644 (file)
@@ -626,6 +626,8 @@ DIAG(err_attribute_argument_n_not_string, ERROR,
      "'%0' attribute requires parameter %1 to be a string")
 DIAG(err_attribute_argument_out_of_bounds, ERROR,
      "'%0' attribute parameter %1 is out of bounds")
+DIAG(err_nonnull_pointers_only, ERROR,
+    "nonnull attribute only applies to pointer arguments")
 DIAG(err_format_strftime_third_parameter, ERROR,
      "strftime format attribute requires 3rd parameter to be 0")
 DIAG(err_format_attribute_requires_variadic, ERROR,
index 18a26163a37b36b111ef861270c747fd84041e97..202e499f061e1b69f2b15592918ec0b245ec9813 100644 (file)
@@ -99,6 +99,44 @@ public:
     assert(Arg < NumArgs && "Arg access out of range!");
     return Args[Arg];
   }
+  
+  class arg_iterator {
+    Action::ExprTy** X;
+    unsigned Idx;
+  public:
+    arg_iterator(Action::ExprTy** x, unsigned idx) : X(x), Idx(idx) {}    
+
+    arg_iterator& operator++() {
+      ++Idx;
+      return *this;
+    }
+    
+    bool operator==(const arg_iterator& I) const {
+      assert (X == I.X &&
+              "compared arg_iterators are for different argument lists");
+      return Idx == I.Idx;
+    }
+    
+    bool operator!=(const arg_iterator& I) const {
+      return !operator==(I);
+    }
+    
+    Action::ExprTy* operator*() const {
+      return X[Idx];
+    }
+    
+    unsigned getArgNum() const {
+      return Idx+1;
+    }
+  };
+  
+  arg_iterator arg_begin() const {
+    return arg_iterator(Args, 0);
+  }
+
+  arg_iterator arg_end() const {
+    return arg_iterator(Args, NumArgs);
+  }
 };
 
 }  // end namespace clang
index f8217b362f214a0ef0340805aca54b32c4a4c8e4..3800fa3568178fc7c2c2572c5d2b92d86005438c 100644 (file)
@@ -233,6 +233,65 @@ static void HandleIBOutletAttr(Decl *d, const AttributeList &Attr, Sema &S) {
     S.Diag(Attr.getLoc(), diag::err_attribute_iboutlet_non_ivar);
 }
 
+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) {
+    S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type,
+           "nonnull", "function");
+    return;
+  }
+  
+  unsigned NumArgs = proto->getNumArgs();
+
+  // The nonnull attribute only applies to pointers.
+  llvm::SmallVector<unsigned, 10> NonNullArgs;
+  
+  for (AttributeList::arg_iterator I=Attr.arg_begin(),
+                                   E=Attr.arg_end(); I!=E; ++I) {
+    
+    
+    // The argument must be an integer constant expression.
+    Expr *Ex = static_cast<Expr *>(Attr.getArg(0));
+    llvm::APSInt ArgNum(32);
+    if (!Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int,
+             "nonnull", Ex->getSourceRange());
+      return;
+    }
+    
+    unsigned x = (unsigned) ArgNum.getZExtValue();
+        
+    if (x < 1 || x > NumArgs) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds,
+             "nonnull", Ex->getSourceRange());
+      return;
+    }
+
+    // Is the function argument a pointer type?
+    if (!proto->getArgType(x).getCanonicalType()->isPointerType()) {
+      // FIXME: Should also highlight argument in decl.
+      S.Diag(Attr.getLoc(), diag::err_nonnull_pointers_only,
+             "nonnull", Ex->getSourceRange());
+      return;    
+    }
+    
+    NonNullArgs.push_back(x);
+  }
+  
+  if (!NonNullArgs.empty()) {
+    unsigned* start = &NonNullArgs[0];
+    unsigned size = NonNullArgs.size();
+    std::sort(start, start + size);
+    d->addAttr(new NonNullAttr(start, size));
+  }
+  else
+    d->addAttr(new NonNullAttr());
+}
+
 static void HandleAliasAttr(Decl *d, const AttributeList &Attr, Sema &S) {
   // check the attribute arguments.
   if (Attr.getNumArgs() != 1) {
@@ -762,7 +821,8 @@ static void ProcessDeclAttribute(Decl *D, const AttributeList &Attr, Sema &S) {
   case AttributeList::AT_annotate:    HandleAnnotateAttr  (D, Attr, S); break;
   case AttributeList::AT_noreturn:    HandleNoReturnAttr  (D, Attr, S); break;
   case AttributeList::AT_format:      HandleFormatAttr    (D, Attr, S); break;
-  case AttributeList::AT_IBOutlet:    HandleIBOutletAttr  (D, Attr, S); break;    
+  case AttributeList::AT_IBOutlet:    HandleIBOutletAttr  (D, Attr, S); break;
+  case AttributeList::AT_nonnull:     HandleNonNullAttr   (D, Attr, S); break;
   case AttributeList::AT_transparent_union:
     HandleTransparentUnionAttr(D, Attr, S);
     break;