]> granicus.if.org Git - clang/commitdiff
Properly handle multiple nonnull attributes in CodeGen
authorAlexey Samsonov <vonosmas@gmail.com>
Thu, 28 Aug 2014 00:53:20 +0000 (00:53 +0000)
committerAlexey Samsonov <vonosmas@gmail.com>
Thu, 28 Aug 2014 00:53:20 +0000 (00:53 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@216638 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/CGCall.cpp
test/CodeGen/nonnull.c

index c95680ccda6c535707814c0f137f8163cab96697..75713419aa11aaa85b3b1a84a6e7267aa7fdeaf2 100644 (file)
@@ -1419,6 +1419,30 @@ static llvm::Value *emitArgumentDemotion(CodeGenFunction &CGF,
   return CGF.Builder.CreateFPCast(value, varType, "arg.unpromote");
 }
 
+static bool shouldAddNonNullAttr(const Decl *FD, const ParmVarDecl *PVD) {
+  // FIXME: __attribute__((nonnull)) can also be applied to:
+  //   - references to pointers, where the pointee is known to be
+  //     nonnull (apparently a Clang extension)
+  //   - transparent unions containing pointers
+  // In the former case, LLVM IR cannot represent the constraint. In
+  // the latter case, we have no guarantee that the transparent union
+  // is in fact passed as a pointer.
+  if (!PVD->getType()->isAnyPointerType() &&
+      !PVD->getType()->isBlockPointerType())
+    return false;
+  // First, check attribute on parameter itself.
+  if (PVD->hasAttr<NonNullAttr>())
+    return true;
+  // Check function attributes.
+  if (!FD)
+    return false;
+  for (const auto *NNAttr : FD->specific_attrs<NonNullAttr>()) {
+    if (NNAttr->isNonNull(PVD->getFunctionScopeIndex()))
+      return true;
+  }
+  return false;
+}
+
 void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
                                          llvm::Function *Fn,
                                          const FunctionArgList &Args) {
@@ -1463,10 +1487,6 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
                                         llvm::Attribute::NoAlias));
   }
 
-  // Get the function-level nonnull attribute if it exists.
-  const NonNullAttr *NNAtt =
-    CurCodeDecl ? CurCodeDecl->getAttr<NonNullAttr>() : nullptr;
-
   // Track if we received the parameter as a pointer (indirect, byval, or
   // inalloca).  If already have a pointer, EmitParmDecl doesn't need to copy it
   // into a local alloca for us.
@@ -1557,17 +1577,7 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI,
         llvm::Value *V = AI;
 
         if (const ParmVarDecl *PVD = dyn_cast<ParmVarDecl>(Arg)) {
-          // FIXME: __attribute__((nonnull)) can also be applied to:
-          //   - references to pointers, where the pointee is known to be
-          //     nonnull (apparently a Clang extension)
-          //   - transparent unions containing pointers
-          // In the former case, LLVM IR cannot represent the constraint. In
-          // the latter case, we have no guarantee that the transparent union
-          // is in fact passed as a pointer.
-          if (((NNAtt && NNAtt->isNonNull(PVD->getFunctionScopeIndex())) ||
-               PVD->hasAttr<NonNullAttr>()) &&
-              (PVD->getType()->isAnyPointerType() ||
-               PVD->getType()->isBlockPointerType()))
+          if (shouldAddNonNullAttr(CurCodeDecl, PVD))
             AI->addAttr(llvm::AttributeSet::get(getLLVMContext(),
                                                 AI->getArgNo() + 1,
                                                 llvm::Attribute::NonNull));
index e234105d9ad68acb996cad66ffe489a104ded08f..7c33e6329fddff8e07fd98ef03a99b7d9dca70dc 100644 (file)
@@ -41,3 +41,11 @@ typedef union {
 int bar6(TransparentUnion tu) __attribute__((nonnull(1))) {
   return *tu.p;
 }
+
+// CHECK: define void @bar7(i32* nonnull %a, i32* nonnull %b)
+void bar7(int *a, int *b) __attribute__((nonnull(1)))
+__attribute__((nonnull(2))) {}
+
+// CHECK: define void @bar8(i32* nonnull %a, i32* nonnull %b)
+void bar8(int *a, int *b) __attribute__((nonnull))
+__attribute__((nonnull(1))) {}