Author: Hans Wennborg Date: 2020-01-17T12:51:06+01:00 New Revision: b28326516ca3ad9d51688532e944f491ce8b7908
URL: https://github.com/llvm/llvm-project/commit/b28326516ca3ad9d51688532e944f491ce8b7908 DIFF: https://github.com/llvm/llvm-project/commit/b28326516ca3ad9d51688532e944f491ce8b7908.diff LOG: Revert 9007f06af0e "Revert "Allow system header to provide their own implementation of some builtin"" This should no longer be necessary after cd4c65f91d5 "Add __warn_memset_zero_len builtin as a workaround for glibc issue" Added: clang/test/CodeGen/memcpy-nobuiltin.c clang/test/CodeGen/memcpy-nobuiltin.inc Modified: clang/include/clang/AST/Decl.h clang/lib/AST/Decl.cpp clang/lib/CodeGen/CGExpr.cpp clang/lib/CodeGen/CodeGenModule.cpp Removed: ################################################################################ diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 620ab4b089db..43c6c7b85db4 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -2309,6 +2309,9 @@ class FunctionDecl : public DeclaratorDecl, /// true through IsAligned. bool isReplaceableGlobalAllocationFunction(bool *IsAligned = nullptr) const; + /// Determine if this function provides an inline implementation of a builtin. + bool isInlineBuiltinDeclaration() const; + /// Determine whether this is a destroying operator delete. bool isDestroyingOperatorDelete() const; diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index be59d88b73f1..0d30f64b992e 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -3046,6 +3046,14 @@ bool FunctionDecl::isReplaceableGlobalAllocationFunction(bool *IsAligned) const return Params == FPT->getNumParams(); } +bool FunctionDecl::isInlineBuiltinDeclaration() const { + if (!getBuiltinID()) + return false; + + const FunctionDecl *Definition; + return hasBody(Definition) && Definition->isInlineSpecified(); +} + bool FunctionDecl::isDestroyingOperatorDelete() const { // C++ P0722: // Within a class C, a single object deallocation function with signature diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index b23d9df5f4ba..8e0604181fb1 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -4621,8 +4621,15 @@ RValue CodeGenFunction::EmitSimpleCallExpr(const CallExpr *E, } static CGCallee EmitDirectCallee(CodeGenFunction &CGF, const FunctionDecl *FD) { + if (auto builtinID = FD->getBuiltinID()) { - return CGCallee::forBuiltin(builtinID, FD); + // Replaceable builtin provide their own implementation of a builtin. Unless + // we are in the builtin implementation itself, don't call the actual + // builtin. If we are in the builtin implementation, avoid trivial infinite + // recursion. + if (!FD->isInlineBuiltinDeclaration() || + CGF.CurFn->getName() == FD->getName()) + return CGCallee::forBuiltin(builtinID, FD); } llvm::Constant *calleePtr = EmitFunctionDeclPointer(CGF.CGM, FD); diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 038078bbe88d..57beda26677c 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1840,6 +1840,11 @@ void CodeGenModule::SetFunctionAttributes(GlobalDecl GD, llvm::Function *F, else if (const auto *SA = FD->getAttr<SectionAttr>()) F->setSection(SA->getName()); + if (FD->isInlineBuiltinDeclaration()) { + F->addAttribute(llvm::AttributeList::FunctionIndex, + llvm::Attribute::NoBuiltin); + } + if (FD->isReplaceableGlobalAllocationFunction()) { // A replaceable global allocation function does not act like a builtin by // default, only if it is invoked by a new-expression or delete-expression. diff --git a/clang/test/CodeGen/memcpy-nobuiltin.c b/clang/test/CodeGen/memcpy-nobuiltin.c new file mode 100644 index 000000000000..fb51d87413a1 --- /dev/null +++ b/clang/test/CodeGen/memcpy-nobuiltin.c @@ -0,0 +1,15 @@ +// RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -DWITH_DECL | FileCheck --check-prefix=CHECK-WITH-DECL %s +// RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -UWITH_DECL | FileCheck --check-prefix=CHECK-NO-DECL %s +// RUN: %clang_cc1 -verify -S -emit-llvm -o- %s -isystem %S -DWITH_SELF_REFERENCE_DECL | FileCheck --check-prefix=CHECK-SELF-REF-DECL %s +// +// CHECK-WITH-DECL-NOT: @llvm.memcpy +// CHECK-NO-DECL: @llvm.memcpy +// CHECK-SELF-REF-DECL: @llvm.memcpy +// +#include <memcpy-nobuiltin.inc> +void test(void *dest, void const *from, size_t n) { + memcpy(dest, from, n); + + static char buffer[1]; + memcpy(buffer, from, 2); // expected-warning {{'memcpy' will always overflow; destination buffer has size 1, but size argument is 2}} +} diff --git a/clang/test/CodeGen/memcpy-nobuiltin.inc b/clang/test/CodeGen/memcpy-nobuiltin.inc new file mode 100644 index 000000000000..25eab0a9ffd0 --- /dev/null +++ b/clang/test/CodeGen/memcpy-nobuiltin.inc @@ -0,0 +1,19 @@ +#include <stddef.h> +extern void *memcpy(void *dest, void const *from, size_t n); + +#ifdef WITH_DECL +inline void *memcpy(void *dest, void const *from, size_t n) { + char const *ifrom = from; + char *idest = dest; + while (n--) + *idest++ = *ifrom++; + return dest; +} +#endif +#ifdef WITH_SELF_REFERENCE_DECL +inline void *memcpy(void *dest, void const *from, size_t n) { + if (n != 0) + memcpy(dest, from, n); + return dest; +} +#endif _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits