From d9d049a93c55624908e81cf3927b7905efeba05f Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Tue, 14 Apr 2009 06:27:57 +0000 Subject: [PATCH] set the linkage of an inline function according to its language rules. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69030 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CodeGenModule.cpp | 28 ++++++++++++++++++++++++++-- test/CodeGen/inline.c | 29 +++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 test/CodeGen/inline.c diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 1dafd39b2c..adf5ac2e41 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -262,8 +262,32 @@ void CodeGenModule::SetGlobalValueAttributes(const Decl *D, } } else if (D->hasAttr() || D->hasAttr()) { GV->setLinkage(llvm::Function::WeakAnyLinkage); - } else if (Linkage == GVA_Inline || Linkage == GVA_ExternInline) { - GV->setLinkage(llvm::Function::WeakAnyLinkage); + } else if (Linkage == GVA_ExternInline) { + // "extern inline" always gets available_externally linkage, which is the + // strongest linkage type we can give an inline function: we don't have to + // codegen the definition at all, yet we know that it is "ODR". + GV->setLinkage(llvm::Function::AvailableExternallyLinkage); + } else if (Linkage == GVA_Inline) { + // The definition of inline changes based on the language. Note that we + // have already handled "static inline" above, with the GVA_Internal case. + if (Features.CPlusPlus) { + // In C++, the compiler has to emit a definition in every translation unit + // that references the function. We should use linkonce_odr because + // a) if all references in this translation unit are optimized away, we + // don't need to codegen it. b) if the function persists, it needs to be + // merged with other definitions. c) C++ has the ODR, so we know the + // definition is dependable. + GV->setLinkage(llvm::Function::LinkOnceODRLinkage); + } else if (Features.C99) { + // In C99 mode, 'inline' functions are guaranteed to have a strong + // definition somewhere else, so we can use available_externally linkage. + GV->setLinkage(llvm::Function::AvailableExternallyLinkage); + } else { + // In C89 mode, an 'inline' function may only occur in one translation + // unit in the program, but may be extern'd in others. Give it strong + // external linkage. + GV->setLinkage(llvm::Function::ExternalLinkage); + } } if (ForDefinition) { diff --git a/test/CodeGen/inline.c b/test/CodeGen/inline.c new file mode 100644 index 0000000000..8360896f36 --- /dev/null +++ b/test/CodeGen/inline.c @@ -0,0 +1,29 @@ +// RUN: clang %s -emit-llvm -S -o %t -std=c89 && +// RUN: grep "define available_externally i32 @ei()" %t && +// RUN: grep "define i32 @foo()" %t && +// RUN: grep "define i32 @bar()" %t && +// RUN: grep "define void @unreferenced()" %t && + +// RUN: clang %s -emit-llvm -S -o %t -std=c99 && +// RUN: grep "define available_externally i32 @ei()" %t && +// RUN: grep "define available_externally i32 @foo()" %t && +// RUN: grep "define i32 @bar()" %t && +// RUN: grep "define available_externally void @unreferenced()" %t && + +// RUN: clang %s -emit-llvm -S -o %t -std=c++98 && +// RUN: grep "define available_externally i32 @_Z2eiv()" %t && +// RUN: grep "define linkonce_odr i32 @_Z3foov()" %t && +// RUN: grep "define i32 @_Z3barv()" %t && +// RUN: grep "define linkonce_odr void @_Z12unreferencedv()" %t + +extern inline int ei() { return 123; } + +inline int foo() { + return ei(); +} + +int bar() { return foo(); } + + +inline void unreferenced() {} + -- 2.40.0