[clang] 301e0d9 - [Clang][Fortify] drop inline decls when redeclared

via cfe-commits cfe-commits at lists.llvm.org
Fri Apr 8 00:32:05 PDT 2022


Author: serge-sans-paille
Date: 2022-04-08T09:31:51+02:00
New Revision: 301e0d91354b853addb63a35e72e552e8059413e

URL: https://github.com/llvm/llvm-project/commit/301e0d91354b853addb63a35e72e552e8059413e
DIFF: https://github.com/llvm/llvm-project/commit/301e0d91354b853addb63a35e72e552e8059413e.diff

LOG: [Clang][Fortify] drop inline decls when redeclared

When an inline builtin declaration is shadowed by an actual declaration, we must
reference the actual declaration, even if it's not the last, following GCC
behavior.

This fixes #54715

Differential Revision: https://reviews.llvm.org/D123308

Added: 
    clang/test/CodeGen/fread-inline-builtin-late-redecl.c

Modified: 
    clang/lib/CodeGen/CGExpr.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 45059cafabb58..0c1b201037ff1 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4948,6 +4948,16 @@ RValue CodeGenFunction::EmitSimpleCallExpr(const CallExpr *E,
   return EmitCall(E->getCallee()->getType(), Callee, E, ReturnValue);
 }
 
+// Detect the unusual situation where an inline version is shadowed by a
+// non-inline version. In that case we should pick the external one
+// everywhere. That's GCC behavior too.
+static bool OnlyHasInlineBuiltinDeclaration(const FunctionDecl *FD) {
+  for (const FunctionDecl *PD = FD; PD; PD = PD->getPreviousDecl())
+    if (!PD->isInlineBuiltinDeclaration())
+      return false;
+  return true;
+}
+
 static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) {
   const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
 
@@ -4955,8 +4965,8 @@ static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) {
     std::string FDInlineName = (FD->getName() + ".inline").str();
     // When directing calling an inline builtin, call it through it's mangled
     // name to make it clear it's not the actual builtin.
-    if (FD->isInlineBuiltinDeclaration() &&
-        CGF.CurFn->getName() != FDInlineName) {
+    if (CGF.CurFn->getName() != FDInlineName &&
+        OnlyHasInlineBuiltinDeclaration(FD)) {
       llvm::Constant *CalleePtr = EmitFunctionDeclPointer(CGF.CGM, GD);
       llvm::Function *Fn = llvm::cast<llvm::Function>(CalleePtr);
       llvm::Module *M = Fn->getParent();

diff  --git a/clang/test/CodeGen/fread-inline-builtin-late-redecl.c b/clang/test/CodeGen/fread-inline-builtin-late-redecl.c
new file mode 100644
index 0000000000000..bc629fa09f498
--- /dev/null
+++ b/clang/test/CodeGen/fread-inline-builtin-late-redecl.c
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -triple x86_64 -S -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s
+//
+// Verifies that clang-generated *.inline are removed when shadowed by an
+// external definition, even when that definition appears at the end of the
+// file.
+
+// CHECK-NOT: strlen.inline
+
+extern unsigned long strlen(char const *s);
+
+extern __inline __attribute__((__always_inline__)) __attribute__((__gnu_inline__)) unsigned long strlen(char const *s) {
+  return 1;
+}
+
+static unsigned long chesterfield(char const *s) {
+  return strlen(s);
+}
+static unsigned long (*_strlen)(char const *ptr);
+
+unsigned long blutch(char const *s) {
+  return chesterfield(s);
+}
+
+unsigned long strlen(char const *s) {
+  return _strlen(s);
+}


        


More information about the cfe-commits mailing list