]> granicus.if.org Git - clang/commitdiff
Handle nonnull attribute with optional argument number on
authorFariborz Jahanian <fjahanian@apple.com>
Mon, 27 Jun 2011 21:12:03 +0000 (21:12 +0000)
committerFariborz Jahanian <fjahanian@apple.com>
Mon, 27 Jun 2011 21:12:03 +0000 (21:12 +0000)
functions with arguments of transparent unions type.
// rdar://9584012

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@133941 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaDeclAttr.cpp
test/Sema/nonnull.c [new file with mode: 0644]

index 9302277e13bd9d38ff645b078c065c66cd1019d4..f5e80d563060a3d0aacd67cc1e9b2e196c03122b 100644 (file)
@@ -361,6 +361,21 @@ static void HandleIBOutletCollection(Decl *d, const AttributeList &Attr,
                                                       QT));
 }
 
+static void PossibleTransparentUnionPointerType(QualType &T) {
+  if (const RecordType *UT = T->getAsUnionType())
+    if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) {
+      RecordDecl *UD = UT->getDecl();
+      for (RecordDecl::field_iterator it = UD->field_begin(),
+           itend = UD->field_end(); it != itend; ++it) {
+        QualType QT = it->getType();
+        if (QT->isAnyPointerType() || QT->isBlockPointerType()) {
+          T = QT;
+          return;
+        }
+      }
+    }
+}
+
 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
@@ -413,6 +428,8 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
 
     // Is the function argument a pointer type?
     QualType T = getFunctionOrMethodArgType(d, x).getNonReferenceType();
+    PossibleTransparentUnionPointerType(T);
+    
     if (!T->isAnyPointerType() && !T->isBlockPointerType()) {
       // FIXME: Should also highlight argument in decl.
       S.Diag(Attr.getLoc(), diag::warn_nonnull_pointers_only)
@@ -428,21 +445,9 @@ static void HandleNonNullAttr(Decl *d, const AttributeList &Attr, Sema &S) {
   if (NonNullArgs.empty()) {
     for (unsigned I = 0, E = getFunctionOrMethodNumArgs(d); I != E; ++I) {
       QualType T = getFunctionOrMethodArgType(d, I).getNonReferenceType();
+      PossibleTransparentUnionPointerType(T);
       if (T->isAnyPointerType() || T->isBlockPointerType())
         NonNullArgs.push_back(I);
-      else if (const RecordType *UT = T->getAsUnionType()) {
-        if (UT && UT->getDecl()->hasAttr<TransparentUnionAttr>()) {
-          RecordDecl *UD = UT->getDecl();
-          for (RecordDecl::field_iterator it = UD->field_begin(),
-               itend = UD->field_end(); it != itend; ++it) {
-            T = it->getType();
-            if (T->isAnyPointerType() || T->isBlockPointerType()) {
-              NonNullArgs.push_back(I);
-              break;
-            }
-          }
-        }
-      }
     }
 
     // No pointer arguments?
diff --git a/test/Sema/nonnull.c b/test/Sema/nonnull.c
new file mode 100644 (file)
index 0000000..cea8e3d
--- /dev/null
@@ -0,0 +1,21 @@
+// RUN: %clang_cc1 -fsyntax-only %s
+// rdar://9584012
+
+typedef struct {
+       char *str;
+} Class;
+
+typedef union {
+       Class *object;
+} Instance __attribute__((transparent_union));
+
+__attribute__((nonnull(1))) void Class_init(Instance this, char *str) {
+       this.object->str = str;
+}
+
+int main(void) {
+       Class *obj;
+       Class_init(0, "Hello World"); // expected-warning {{null passed to a callee which requires a non-null argument}}
+       Class_init(obj, "Hello World");
+}
+