Skip to content

Commit

Permalink
[Clang][Fortify] drop inline decls when redeclared
Browse files Browse the repository at this point in the history
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 llvm#54715

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

(cherry picked from commit 301e0d9)
  • Loading branch information
serge-sans-paille authored and tstellar committed Apr 19, 2022
1 parent 571c7d8 commit 0fbe860
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 2 deletions.
14 changes: 12 additions & 2 deletions clang/lib/CodeGen/CGExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4895,15 +4895,25 @@ 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());

if (auto builtinID = FD->getBuiltinID()) {
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();
Expand Down
26 changes: 26 additions & 0 deletions clang/test/CodeGen/fread-inline-builtin-late-redecl.c
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit 0fbe860

Please sign in to comment.