[cfe-commits] r157360 - in /cfe/trunk: include/clang/Basic/Attr.td include/clang/Basic/DiagnosticSemaKinds.td lib/Sema/SemaDeclAttr.cpp test/Sema/alloc_size.c

Nuno Lopes nunoplopes at sapo.pt
Wed May 23 17:22:01 PDT 2012


Author: nlopes
Date: Wed May 23 19:22:00 2012
New Revision: 157360

URL: http://llvm.org/viewvc/llvm-project?rev=157360&view=rev
Log:
implement Sema support for the alloc_size attribute
Portions of this patch by Xi Wang. Reviewed by Jordy Rose. Thank you both.

Codegen support will follow soon.

Added:
    cfe/trunk/test/Sema/alloc_size.c
Modified:
    cfe/trunk/include/clang/Basic/Attr.td
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/lib/Sema/SemaDeclAttr.cpp

Modified: cfe/trunk/include/clang/Basic/Attr.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Attr.td?rev=157360&r1=157359&r2=157360&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Attr.td (original)
+++ cfe/trunk/include/clang/Basic/Attr.td Wed May 23 19:22:00 2012
@@ -144,6 +144,11 @@
   let SemaHandler = 0;
 }
 
+def AllocSize : Attr {
+  let Spellings = ["alloc_size"];
+  let Args = [VariadicUnsignedArgument<"Args">];
+}
+
 def AlwaysInline : InheritableAttr {
   let Spellings = ["always_inline"];
 }

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=157360&r1=157359&r2=157360&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Wed May 23 19:22:00 2012
@@ -1483,6 +1483,8 @@
 def err_init_priority_object_attr : Error<
   "can only use 'init_priority' attribute on file-scope definitions "
   "of objects of class type">;
+def err_attribute_argument_duplicate: Error<
+  "'%0' attribute parameter %1 is duplicated">;
 def err_attribute_argument_n_not_int : Error<
   "'%0' attribute requires parameter %1 to be an integer constant">;
 def err_attribute_argument_n_not_string : Error<

Modified: cfe/trunk/lib/Sema/SemaDeclAttr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaDeclAttr.cpp?rev=157360&r1=157359&r2=157360&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaDeclAttr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp Wed May 23 19:22:00 2012
@@ -922,6 +922,81 @@
     }
 }
 
+static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+  if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+    return;
+
+  // In C++ the implicit 'this' function parameter also counts, and they are
+  // counted from one.
+  bool HasImplicitThisParam = isInstanceMethod(D);
+  unsigned NumArgs = getFunctionOrMethodNumArgs(D) + HasImplicitThisParam;
+
+  SmallVector<unsigned, 8> SizeArgs;
+
+  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 = *I;
+    llvm::APSInt ArgNum;
+    if (Ex->isTypeDependent() || Ex->isValueDependent() ||
+        !Ex->isIntegerConstantExpr(ArgNum, S.Context)) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+      << "alloc_size" << Ex->getSourceRange();
+      return;
+    }
+
+    uint64_t x = ArgNum.getZExtValue();
+
+    if (x < 1 || x > NumArgs) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+      << "alloc_size" << I.getArgNum() << Ex->getSourceRange();
+      return;
+    }
+
+    --x;
+    if (HasImplicitThisParam) {
+      if (x == 0) {
+        S.Diag(Attr.getLoc(),
+               diag::err_attribute_invalid_implicit_this_argument)
+        << "alloc_size" << Ex->getSourceRange();
+        return;
+      }
+      --x;
+    }
+
+    // check if the function argument is of an integer type
+    QualType T = getFunctionOrMethodArgType(D, x).getNonReferenceType();
+    if (!T->isIntegerType()) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_not_int)
+      << "alloc_size" << Ex->getSourceRange();
+      return;
+    }
+
+    // check if the argument is a duplicate
+    SmallVectorImpl<unsigned>::iterator Pos;
+    Pos = std::find(SizeArgs.begin(), SizeArgs.end(), x);
+    if (Pos != SizeArgs.end()) {
+      S.Diag(Attr.getLoc(), diag::err_attribute_argument_duplicate)
+      << "alloc_size" << I.getArgNum() << Ex->getSourceRange();
+      return;
+    }
+
+    SizeArgs.push_back(x);
+  }
+
+  // check if the function returns a pointer
+  if (!getFunctionType(D)->getResultType()->isAnyPointerType()) {
+    S.Diag(Attr.getLoc(), diag::warn_ns_attribute_wrong_return_type)
+    << "alloc_size" << 0 /*function*/<< 1 /*pointer*/ << D->getSourceRange();
+  }
+
+  unsigned size = SizeArgs.size();
+  unsigned* start = &SizeArgs[0];
+  llvm::array_pod_sort(start, start + size);
+  D->addAttr(::new (S.Context) AllocSizeAttr(Attr.getRange(), S.Context, start,
+                                             size));
+}
+
 static void handleNonNullAttr(Sema &S, Decl *D, const AttributeList &Attr) {
   // GCC ignores the nonnull attribute on K&R style function prototypes, so we
   // ignore it as well
@@ -3844,6 +3919,7 @@
     break;
   case AttributeList::AT_alias:       handleAliasAttr       (S, D, Attr); break;
   case AttributeList::AT_aligned:     handleAlignedAttr     (S, D, Attr); break;
+  case AttributeList::AT_alloc_size:  handleAllocSizeAttr   (S, D, Attr); break;
   case AttributeList::AT_always_inline:
     handleAlwaysInlineAttr  (S, D, Attr); break;
   case AttributeList::AT_analyzer_noreturn:

Added: cfe/trunk/test/Sema/alloc_size.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Sema/alloc_size.c?rev=157360&view=auto
==============================================================================
--- cfe/trunk/test/Sema/alloc_size.c (added)
+++ cfe/trunk/test/Sema/alloc_size.c Wed May 23 19:22:00 2012
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+void* my_malloc(unsigned char) __attribute__((alloc_size(1)));
+void* my_calloc(unsigned char, short) __attribute__((alloc_size(1,2)));
+void* my_realloc(void*, unsigned) __attribute__((alloc_size(2)));
+
+
+void* fn1(int) __attribute__((alloc_size("xpto"))); // expected-error{{attribute requires integer constant}}
+
+void* fn2(void*) __attribute__((alloc_size(1))); // expected-error{{attribute requires integer constant}}
+
+void* fn3(unsigned) __attribute__((alloc_size(0))); // expected-error{{attribute parameter 1 is out of bounds}}
+void* fn4(unsigned) __attribute__((alloc_size(2))); // expected-error{{attribute parameter 1 is out of bounds}}
+
+void fn5(unsigned) __attribute__((alloc_size(1))); // expected-warning{{only applies to functions that return a pointer}}
+char fn6(unsigned) __attribute__((alloc_size(1))); // expected-warning{{only applies to functions that return a pointer}}
+
+void* fn7(unsigned) __attribute__((alloc_size)); // expected-error {{attribute takes at least 1 argument}}
+
+void *fn8(int, int) __attribute__((alloc_size(1, 1))); // expected-error {{attribute parameter 2 is duplicated}}
+
+void* fn9(unsigned) __attribute__((alloc_size(12345678901234567890123))); // expected-warning {{integer constant is too large for its type}} // expected-error {{attribute parameter 1 is out of bounds}}





More information about the cfe-commits mailing list