[cfe-commits] r53881 - in /cfe/trunk: include/clang/AST/Attr.h include/clang/Basic/DiagnosticKinds.def include/clang/Parse/AttributeList.h lib/Sema/SemaDeclAttr.cpp

Ted Kremenek kremenek at apple.com
Mon Jul 21 14:53:05 PDT 2008


Author: kremenek
Date: Mon Jul 21 16:53:04 2008
New Revision: 53881

URL: http://llvm.org/viewvc/llvm-project?rev=53881&view=rev
Log:
Added sema support for the nonnull attribute.  Will add test cases soon.

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

Modified: cfe/trunk/include/clang/AST/Attr.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Attr.h?rev=53881&r1=53880&r2=53881&view=diff

==============================================================================
--- cfe/trunk/include/clang/AST/Attr.h (original)
+++ cfe/trunk/include/clang/AST/Attr.h Mon Jul 21 16:53:04 2008
@@ -16,6 +16,7 @@
 
 #include <cassert>
 #include <string>
+#include <algorithm>
 
 namespace clang {
 
@@ -27,6 +28,7 @@
     Aligned,
     Packed,
     Annotate,
+    NonNull,
     NoReturn,
     Deprecated,
     Weak,
@@ -173,6 +175,32 @@
   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;

Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=53881&r1=53880&r2=53881&view=diff

==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Mon Jul 21 16:53:04 2008
@@ -626,6 +626,8 @@
      "'%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,

Modified: cfe/trunk/include/clang/Parse/AttributeList.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Parse/AttributeList.h?rev=53881&r1=53880&r2=53881&view=diff

==============================================================================
--- cfe/trunk/include/clang/Parse/AttributeList.h (original)
+++ cfe/trunk/include/clang/Parse/AttributeList.h Mon Jul 21 16:53:04 2008
@@ -99,6 +99,44 @@
     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

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=53881&r1=53880&r2=53881&view=diff

==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Mon Jul 21 16:53:04 2008
@@ -233,6 +233,65 @@
     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 @@
   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;





More information about the cfe-commits mailing list