From cc33d8f124424b71f0de3cf92380a169e118bc79 Mon Sep 17 00:00:00 2001 From: Alexey Samsonov Date: Thu, 28 Aug 2014 00:53:20 +0000 Subject: [PATCH] Properly handle multiple nonnull attributes in CodeGen git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@216638 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGCall.cpp | 40 +++++++++++++++++++++++++--------------- test/CodeGen/nonnull.c | 8 ++++++++ 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index c95680ccda..75713419aa 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -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()) + return true; + // Check function attributes. + if (!FD) + return false; + for (const auto *NNAttr : FD->specific_attrs()) { + 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() : 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(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()) && - (PVD->getType()->isAnyPointerType() || - PVD->getType()->isBlockPointerType())) + if (shouldAddNonNullAttr(CurCodeDecl, PVD)) AI->addAttr(llvm::AttributeSet::get(getLLVMContext(), AI->getArgNo() + 1, llvm::Attribute::NonNull)); diff --git a/test/CodeGen/nonnull.c b/test/CodeGen/nonnull.c index e234105d9a..7c33e6329f 100644 --- a/test/CodeGen/nonnull.c +++ b/test/CodeGen/nonnull.c @@ -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))) {} -- 2.40.0