Handle nonnull attribute with optional argument number on
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
diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp
index 9302277..f5e80d5 100644
--- a/lib/Sema/SemaDeclAttr.cpp
+++ b/lib/Sema/SemaDeclAttr.cpp
@@ -361,6 +361,21 @@
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 @@
// 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 @@
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
index 0000000..cea8e3d
--- /dev/null
+++ b/test/Sema/nonnull.c
@@ -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");
+}
+