[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
spatel added a comment. In https://reviews.llvm.org/D30806#1248575, @efriedma wrote: > This was merged in https://reviews.llvm.org/rC298491 . But it got reverted soon after due to miscompiles: https://reviews.llvm.org/rL298695 And the functionality hasn't been reimplemented AFAICT. https://reviews.llvm.org/D30806 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
efriedma closed this revision. efriedma added a comment. This was merged in https://reviews.llvm.org/rC298491 . https://reviews.llvm.org/D30806 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
xbolva00 added a comment. Herald added a subscriber: sanjoy. Coming from https://reviews.llvm.org/D50039. This patch was accepted but never merged? https://reviews.llvm.org/D30806 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
hfinkel accepted this revision. hfinkel added a comment. This revision is now accepted and ready to land. LGTM https://reviews.llvm.org/D30806 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
chandlerc updated this revision to Diff 92245. chandlerc added a comment. Update with fixes suggested in review. https://reviews.llvm.org/D30806 Files: include/clang/AST/ASTContext.h include/clang/Basic/Builtins.def lib/AST/ASTContext.cpp lib/CodeGen/CGCall.cpp test/CodeGen/nonnull.c Index: test/CodeGen/nonnull.c === --- test/CodeGen/nonnull.c +++ test/CodeGen/nonnull.c @@ -49,3 +49,87 @@ // CHECK: define void @bar8(i32* nonnull %a, i32* nonnull %b) void bar8(int *a, int *b) __attribute__((nonnull)) __attribute__((nonnull(1))) {} + +// CHECK: declare void @foo_decl(i32* nonnull) +void foo_decl(int *__attribute__((nonnull))); + +// CHECK: declare void @bar_decl(i32* nonnull) +void bar_decl(int *) __attribute__((nonnull(1))); + +// CHECK: declare void @bar2_decl(i32*, i32* nonnull) +void bar2_decl(int *, int *) __attribute__((nonnull(2))); + +// CHECK: declare nonnull i32* @bar3_decl() +int *bar3_decl(void) __attribute__((returns_nonnull)); + +// CHECK: declare i32 @bar4_decl(i32, i32* nonnull) +int bar4_decl(int, int *) __attribute__((nonnull)); + +// CHECK: declare i32 @bar5_decl(i32, i32* nonnull) +int bar5_decl(int, int *) __attribute__((nonnull(1, 2))); + +// CHECK: declare i32 @bar6_decl(i64) +int bar6_decl(TransparentUnion) __attribute__((nonnull(1))); + +// CHECK: declare void @bar7_decl(i32* nonnull, i32* nonnull) +void bar7_decl(int *, int *) +__attribute__((nonnull(1))) __attribute__((nonnull(2))); + +// CHECK: declare void @bar8_decl(i32* nonnull, i32* nonnull) +void bar8_decl(int *, int *) +__attribute__((nonnull)) __attribute__((nonnull(1))); + +// Clang specially disables nonnull attributes on some library builtin +// functions to work around the fact that the standard and some vendors mark +// them as nonnull even though they are frequently called in practice with null +// arguments if a corresponding size argument is zero. + +// CHECK: declare i8* @memcpy(i8*, i8*, i64) +void *memcpy(void *, const void *, unsigned long) +__attribute__((nonnull(1, 2))) __attribute__((returns_nonnull)); + +// CHECK: declare i32 @memcmp(i8*, i8*, i64) +int memcmp(const void *, const void *, unsigned long) __attribute__((nonnull(1, 2))); + +// CHECK: declare i8* @memmove(i8*, i8*, i64) +void *memmove(void *, const void *, unsigned long) +__attribute__((nonnull(1, 2))) __attribute__((returns_nonnull)); + +// CHECK: declare i8* @strncpy(i8*, i8*, i64) +char *strncpy(char *, const char *, unsigned long) +__attribute__((nonnull(1, 2))) __attribute__((returns_nonnull)); + +// CHECK: declare i32 @strncmp(i8*, i8*, i64) +int strncmp(const char *, const char *, unsigned long) __attribute__((nonnull(1, 2))); + +// CHECK: declare nonnull i8* @strncat(i8* nonnull, i8*, i64) +char *strncat(char *, const char *, unsigned long) +__attribute__((nonnull(1, 2))) __attribute__((returns_nonnull)); + +// CHECK: declare i8* @memchr(i8*, i32, i64) +void *memchr(const void *__attribute__((nonnull)), int, unsigned long) +__attribute__((returns_nonnull)); + +// CHECK: declare i8* @memset(i8*, i32, i64) +void *memset(void *__attribute__((nonnull)), int, unsigned long) +__attribute__((returns_nonnull)); + +void use_declarations(int *p, void *volatile *sink) { + foo_decl(p); + bar_decl(p); + bar2_decl(p, p); + (void)bar3_decl(); + bar4_decl(42, p); + bar5_decl(42, p); + bar6_decl(p); + bar7_decl(p, p); + bar8_decl(p, p); + *sink = (void *) + *sink = (void *) + *sink = (void *) + *sink = (void *) + *sink = (void *) + *sink = (void *) + *sink = (void *) + *sink = (void *) +} Index: lib/CodeGen/CGCall.cpp === --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -1759,6 +1759,34 @@ F.addAttributes(llvm::AttributeSet::FunctionIndex, AS); } +/// Returns the attribute (either parameter attribute, or function +/// attribute), which declares argument ArgNo to be non-null. +static const NonNullAttr *getNonNullAttr(const Decl *FD, const ParmVarDecl *PVD, + QualType ArgType, unsigned ArgNo) { + // 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 (!ArgType->isAnyPointerType() && !ArgType->isBlockPointerType()) +return nullptr; + // First, check attribute on parameter itself. + if (PVD) { +if (auto ParmNNAttr = PVD->getAttr()) + return ParmNNAttr; + } + // Check function attributes. + if (!FD) +return nullptr; + for (const auto *NNAttr : FD->specific_attrs()) { +if (NNAttr->isNonNull(ArgNo)) + return NNAttr; + } + return
[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
chandlerc marked an inline comment as done. chandlerc added a comment. Function argument order fixed. https://reviews.llvm.org/D30806 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
hfinkel added inline comments. Comment at: include/clang/AST/ASTContext.h:1868 + bool *OverrideNonnullReturn = nullptr, + unsigned *OverrideNonnullArgs = nullptr, unsigned *IntegerConstantArgs = nullptr) const; chandlerc wrote: > hfinkel wrote: > > It seems like you had to touch more code than necessary because you decided > > to add these parameters before IntegerConstantArgs. Why don't you add them > > afterward instead? > It seemed more natural But I'm happy to change the order. I'm not worreid > about how much code I have to touch, I'd rather just get the options in the > right place. What order would you suggest? I suggest the other order because it is more common to want the IntegerConstantArgs than the nonnull args (which essentially only one caller wants). https://reviews.llvm.org/D30806 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
chandlerc added inline comments. Comment at: include/clang/AST/ASTContext.h:1868 + bool *OverrideNonnullReturn = nullptr, + unsigned *OverrideNonnullArgs = nullptr, unsigned *IntegerConstantArgs = nullptr) const; hfinkel wrote: > It seems like you had to touch more code than necessary because you decided > to add these parameters before IntegerConstantArgs. Why don't you add them > afterward instead? It seemed more natural But I'm happy to change the order. I'm not worreid about how much code I have to touch, I'd rather just get the options in the right place. What order would you suggest? https://reviews.llvm.org/D30806 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
hfinkel added inline comments. Comment at: include/clang/AST/ASTContext.h:1865 /// arguments to the builtin that are required to be integer constant /// expressions. QualType GetBuiltinType(unsigned ID, GetBuiltinTypeError , Please add some description of the new parameters. Comment at: include/clang/AST/ASTContext.h:1868 + bool *OverrideNonnullReturn = nullptr, + unsigned *OverrideNonnullArgs = nullptr, unsigned *IntegerConstantArgs = nullptr) const; It seems like you had to touch more code than necessary because you decided to add these parameters before IntegerConstantArgs. Why don't you add them afterward instead? https://reviews.llvm.org/D30806 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
chandlerc added a comment. Ping? https://reviews.llvm.org/D30806 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
chandlerc updated this revision to Diff 91286. chandlerc added a comment. Update to fix subtle bugs in handling arguments. Thanks to David for the review comments that caused me to see the issue here. https://reviews.llvm.org/D30806 Files: include/clang/AST/ASTContext.h include/clang/Basic/Builtins.def lib/AST/ASTContext.cpp lib/CodeGen/CGBuiltin.cpp lib/CodeGen/CGCall.cpp lib/Sema/SemaChecking.cpp test/CodeGen/nonnull.c Index: test/CodeGen/nonnull.c === --- test/CodeGen/nonnull.c +++ test/CodeGen/nonnull.c @@ -49,3 +49,87 @@ // CHECK: define void @bar8(i32* nonnull %a, i32* nonnull %b) void bar8(int *a, int *b) __attribute__((nonnull)) __attribute__((nonnull(1))) {} + +// CHECK: declare void @foo_decl(i32* nonnull) +void foo_decl(int *__attribute__((nonnull))); + +// CHECK: declare void @bar_decl(i32* nonnull) +void bar_decl(int *) __attribute__((nonnull(1))); + +// CHECK: declare void @bar2_decl(i32*, i32* nonnull) +void bar2_decl(int *, int *) __attribute__((nonnull(2))); + +// CHECK: declare nonnull i32* @bar3_decl() +int *bar3_decl(void) __attribute__((returns_nonnull)); + +// CHECK: declare i32 @bar4_decl(i32, i32* nonnull) +int bar4_decl(int, int *) __attribute__((nonnull)); + +// CHECK: declare i32 @bar5_decl(i32, i32* nonnull) +int bar5_decl(int, int *) __attribute__((nonnull(1, 2))); + +// CHECK: declare i32 @bar6_decl(i64) +int bar6_decl(TransparentUnion) __attribute__((nonnull(1))); + +// CHECK: declare void @bar7_decl(i32* nonnull, i32* nonnull) +void bar7_decl(int *, int *) +__attribute__((nonnull(1))) __attribute__((nonnull(2))); + +// CHECK: declare void @bar8_decl(i32* nonnull, i32* nonnull) +void bar8_decl(int *, int *) +__attribute__((nonnull)) __attribute__((nonnull(1))); + +// Clang specially disables nonnull attributes on some library builtin +// functions to work around the fact that the standard and some vendors mark +// them as nonnull even though they are frequently called in practice with null +// arguments if a corresponding size argument is zero. + +// CHECK: declare i8* @memcpy(i8*, i8*, i64) +void *memcpy(void *, const void *, unsigned long) +__attribute__((nonnull(1, 2))) __attribute__((returns_nonnull)); + +// CHECK: declare i32 @memcmp(i8*, i8*, i64) +int memcmp(const void *, const void *, unsigned long) __attribute__((nonnull(1, 2))); + +// CHECK: declare i8* @memmove(i8*, i8*, i64) +void *memmove(void *, const void *, unsigned long) +__attribute__((nonnull(1, 2))) __attribute__((returns_nonnull)); + +// CHECK: declare i8* @strncpy(i8*, i8*, i64) +char *strncpy(char *, const char *, unsigned long) +__attribute__((nonnull(1, 2))) __attribute__((returns_nonnull)); + +// CHECK: declare i32 @strncmp(i8*, i8*, i64) +int strncmp(const char *, const char *, unsigned long) __attribute__((nonnull(1, 2))); + +// CHECK: declare nonnull i8* @strncat(i8* nonnull, i8*, i64) +char *strncat(char *, const char *, unsigned long) +__attribute__((nonnull(1, 2))) __attribute__((returns_nonnull)); + +// CHECK: declare i8* @memchr(i8*, i32, i64) +void *memchr(const void *__attribute__((nonnull)), int, unsigned long) +__attribute__((returns_nonnull)); + +// CHECK: declare i8* @memset(i8*, i32, i64) +void *memset(void *__attribute__((nonnull)), int, unsigned long) +__attribute__((returns_nonnull)); + +void use_declarations(int *p, void *volatile *sink) { + foo_decl(p); + bar_decl(p); + bar2_decl(p, p); + (void)bar3_decl(); + bar4_decl(42, p); + bar5_decl(42, p); + bar6_decl(p); + bar7_decl(p, p); + bar8_decl(p, p); + *sink = (void *) + *sink = (void *) + *sink = (void *) + *sink = (void *) + *sink = (void *) + *sink = (void *) + *sink = (void *) + *sink = (void *) +} Index: lib/Sema/SemaChecking.cpp === --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -735,7 +735,8 @@ // Find out if any arguments are required to be integer constant expressions. unsigned ICEArguments = 0; ASTContext::GetBuiltinTypeError Error; - Context.GetBuiltinType(BuiltinID, Error, ); + Context.GetBuiltinType(BuiltinID, Error, /*OverrideNonnullReturn=*/nullptr, + /*OverrideNonnullArgs=*/nullptr, ); if (Error != ASTContext::GE_None) ICEArguments = 0; // Don't diagnose previously diagnosed errors. Index: lib/CodeGen/CGCall.cpp === --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -1759,6 +1759,34 @@ F.addAttributes(llvm::AttributeSet::FunctionIndex, AS); } +/// Returns the attribute (either parameter attribute, or function +/// attribute), which declares argument ArgNo to be non-null. +static const NonNullAttr *getNonNullAttr(const Decl *FD, const ParmVarDecl *PVD, + QualType ArgType, unsigned ArgNo) { + // FIXME: __attribute__((nonnull)) can also be
[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
chandlerc added inline comments. Comment at: lib/AST/ASTContext.cpp:8786 +if (OverrideNonnull && OverrideNonnullArgs) + *OverrideNonnullArgs |= 1 << ArgTypes.size(); + majnemer wrote: > `1U` to avoid overflow UB? I'd mildly prefer an assert (or rely on UBSan) that it *doesn't* overflow. Also note that this is the same pattern we use just a few lines down for the ICE argument bitmask -- we have a pretty baked in assumption that all the builtins here don't have more than 31 arguments. Anyways, happy to make whatever change you would prefer here. I just copied the code below, I don't have any strong opinion here. Comment at: lib/CodeGen/CGCall.cpp:2082 + if (getNonNullAttr(FD, PVD, ParamType, PVD->getFunctionScopeIndex()) && + (OverrideNonnullArgs & (1 << ArgNo)) == 0) +Attrs.addAttribute(llvm::Attribute::NonNull); majnemer wrote: > Ditto. See above, I'll keep these in sync. However, this exposes a related bug: we shouldn't be even doing this bit test if the function isn't a builtin. I'll add a check for that. That seems cleaner than relying on the bittest itself failing. https://reviews.llvm.org/D30806 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
majnemer added inline comments. Comment at: lib/AST/ASTContext.cpp:8786 +if (OverrideNonnull && OverrideNonnullArgs) + *OverrideNonnullArgs |= 1 << ArgTypes.size(); + `1U` to avoid overflow UB? Comment at: lib/CodeGen/CGCall.cpp:2082 + if (getNonNullAttr(FD, PVD, ParamType, PVD->getFunctionScopeIndex()) && + (OverrideNonnullArgs & (1 << ArgNo)) == 0) +Attrs.addAttribute(llvm::Attribute::NonNull); Ditto. https://reviews.llvm.org/D30806 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
chandlerc added a comment. In https://reviews.llvm.org/D30806#697372, @ahatanak wrote: > Are users allowed to call these routines with a null pointer and a non-zero > size? Or can we assume that if the size is known to be non-zero at compile > time, the pointers are not null? If the sizes are non-zero, all of these will access memory through the pointer. But we don't currently have any way of easily expressing this in the IR. We could try something fancy like call-side attributes when the size is known, but it is pretty redundant -- we could just teach the same things that look at the attributes to know that these are reads or writes of a constant size... > I'm thinking we might miss optimization opportunities if it's not possible to > mark the pointer parameters as nonnull. Note that currently, *nothing marks these parameters as nonnull*. So in all the years that folks have used Clang and LLVM with libc headers that have an __attribute__((nonnull)), no one has found a performance problem with this as the root cause and fixed it. To me, this indicates that this isn't that important of an optimization *for these libc routines*. If someone ever comes up with a testcase where this is important thing for performance, I think we can cross the bridge of finding a fancier way to analyze things then. https://reviews.llvm.org/D30806 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
ahatanak added a comment. Are users allowed to call these routines with a null pointer and a non-zero size? Or can we assume that if the size is known to be non-zero at compile time, the pointers are not null? I'm thinking we might miss optimization opportunities if it's not possible to mark the pointer parameters as nonnull. https://reviews.llvm.org/D30806 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D30806: [nonnull] Teach Clang to attach the nonnull LLVM attribute to declarations and calls instead of just definitions, and then teach it to *not* attach such attributes even if the source c
chandlerc created this revision. Herald added a subscriber: mcrosier. This follows the design direction discussed on cfe-dev here: http://lists.llvm.org/pipermail/cfe-dev/2017-January/052066.html The idea is that for C standard library builtins, even if the library vendor chooses to annotate their routines with __attribute__((nonnull)), we will ignore those attributes which pertain to pointer arguments that have an associated size. This allows the widespread (and seemingly reasonable) pattern of calling these routines with a null pointer and a zero size. I have only done this for the library builtins currently recognized by Clang, but we can now trivially add to this set. This will be controllable with -fno-builtin if anyone should care to do so. Note that this does *not* change the AST. As a consequence, warnings, static analysis, and source code rewriting are not impacted. This isn't even a regression on any platform as neither Clang nor LLVM have ever put 'nonnull' onto these arguments for declarations. All this patch does is enable it on other declarations while preventing us from ever accidentally enabling it on these libc functions due to a library vendor. https://reviews.llvm.org/D30806 Files: include/clang/AST/ASTContext.h include/clang/Basic/Builtins.def lib/AST/ASTContext.cpp lib/CodeGen/CGBuiltin.cpp lib/CodeGen/CGCall.cpp lib/Sema/SemaChecking.cpp test/CodeGen/nonnull.c Index: test/CodeGen/nonnull.c === --- test/CodeGen/nonnull.c +++ test/CodeGen/nonnull.c @@ -49,3 +49,87 @@ // CHECK: define void @bar8(i32* nonnull %a, i32* nonnull %b) void bar8(int *a, int *b) __attribute__((nonnull)) __attribute__((nonnull(1))) {} + +// CHECK: declare void @foo_decl(i32* nonnull) +void foo_decl(int *__attribute__((nonnull))); + +// CHECK: declare void @bar_decl(i32* nonnull) +void bar_decl(int *) __attribute__((nonnull(1))); + +// CHECK: declare void @bar2_decl(i32*, i32* nonnull) +void bar2_decl(int *, int *) __attribute__((nonnull(2))); + +// CHECK: declare nonnull i32* @bar3_decl() +int *bar3_decl(void) __attribute__((returns_nonnull)); + +// CHECK: declare i32 @bar4_decl(i32, i32* nonnull) +int bar4_decl(int, int *) __attribute__((nonnull)); + +// CHECK: declare i32 @bar5_decl(i32, i32* nonnull) +int bar5_decl(int, int *) __attribute__((nonnull(1, 2))); + +// CHECK: declare i32 @bar6_decl(i64) +int bar6_decl(TransparentUnion) __attribute__((nonnull(1))); + +// CHECK: declare void @bar7_decl(i32* nonnull, i32* nonnull) +void bar7_decl(int *, int *) +__attribute__((nonnull(1))) __attribute__((nonnull(2))); + +// CHECK: declare void @bar8_decl(i32* nonnull, i32* nonnull) +void bar8_decl(int *, int *) +__attribute__((nonnull)) __attribute__((nonnull(1))); + +// Clang specially disables nonnull attributes on some library builtin +// functions to work around the fact that the standard and some vendors mark +// them as nonnull even though they are frequently called in practice with null +// arguments if a corresponding size argument is zero. + +// CHECK: declare i8* @memcpy(i8*, i8*, i64) +void *memcpy(void *, const void *, unsigned long) +__attribute__((nonnull(1, 2))) __attribute__((returns_nonnull)); + +// CHECK: declare i32 @memcmp(i8*, i8*, i64) +int memcmp(const void *, const void *, unsigned long) __attribute__((nonnull(1, 2))); + +// CHECK: declare i8* @memmove(i8*, i8*, i64) +void *memmove(void *, const void *, unsigned long) +__attribute__((nonnull(1, 2))) __attribute__((returns_nonnull)); + +// CHECK: declare i8* @strncpy(i8*, i8*, i64) +char *strncpy(char *, const char *, unsigned long) +__attribute__((nonnull(1, 2))) __attribute__((returns_nonnull)); + +// CHECK: declare i32 @strncmp(i8*, i8*, i64) +int strncmp(const char *, const char *, unsigned long) __attribute__((nonnull(1, 2))); + +// CHECK: declare nonnull i8* @strncat(i8* nonnull, i8*, i64) +char *strncat(char *, const char *, unsigned long) +__attribute__((nonnull(1, 2))) __attribute__((returns_nonnull)); + +// CHECK: declare i8* @memchr(i8*, i32, i64) +void *memchr(const void *__attribute__((nonnull)), int, unsigned long) +__attribute__((returns_nonnull)); + +// CHECK: declare i8* @memset(i8*, i32, i64) +void *memset(void *__attribute__((nonnull)), int, unsigned long) +__attribute__((returns_nonnull)); + +void use_declarations(int *p, void *volatile *sink) { + foo_decl(p); + bar_decl(p); + bar2_decl(p, p); + (void)bar3_decl(); + bar4_decl(42, p); + bar5_decl(42, p); + bar6_decl(p); + bar7_decl(p, p); + bar8_decl(p, p); + *sink = (void *) + *sink = (void *) + *sink = (void *) + *sink = (void *) + *sink = (void *) + *sink = (void *) + *sink = (void *) + *sink = (void *) +} Index: lib/Sema/SemaChecking.cpp === --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -735,7 +735,8 @@ // Find out if any arguments are required to be