diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 3f1d412638ee..ef9404a321bf 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -229,26 +229,32 @@ GetLinkageForFunction(const FunctionDecl *FD, const LangOptions &Features) { return CodeGenModule::GVA_Internal; if (!FD->isInline()) - return CodeGenModule::GVA_Normal; + return CodeGenModule::GVA_StrongExternal; - if (FD->getStorageClass() == FunctionDecl::Extern) - return CodeGenModule::GVA_ExternInline; - // If the inline function explicitly has the GNU inline attribute on it, then - // force to GNUC semantics, regardless of language. + // force to GNUC semantics (which is strong external), regardless of language. if (FD->hasAttr()) - return CodeGenModule::GVA_GNUCInline; - + return CodeGenModule::GVA_StrongExternal; + // 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) + if (Features.CPlusPlus) // inline and extern inline. return CodeGenModule::GVA_CXXInline; + if (FD->getStorageClass() == FunctionDecl::Extern) { + // extern inline in C99 is a strong definition. In C89, it is extern inline. + if (Features.C99) + return CodeGenModule::GVA_StrongExternal; + + // In C89 mode, an 'extern inline' works like a C99 inline function. + return CodeGenModule::GVA_C99Inline; + } + if (Features.C99) return CodeGenModule::GVA_C99Inline; // Otherwise, this is the GNU inline extension in K&R and GNU C89 mode. - return CodeGenModule::GVA_GNUCInline; + return CodeGenModule::GVA_StrongExternal; } /// SetFunctionDefinitionAttributes - Set attributes for a global. @@ -266,10 +272,9 @@ void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D, GV->setLinkage(llvm::Function::DLLExportLinkage); } else if (D->hasAttr() || D->hasAttr()) { 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". + } else if (Linkage == GVA_C99Inline) { + // 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 if (Linkage == GVA_CXXInline) { // In C++, the compiler has to emit a definition in every translation unit @@ -279,16 +284,9 @@ void CodeGenModule::SetFunctionDefinitionAttributes(const FunctionDecl *D, // merged with other definitions. c) C++ has the ODR, so we know the // definition is dependable. GV->setLinkage(llvm::Function::LinkOnceODRLinkage); - } else if (Linkage == GVA_C99Inline) { - // 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 if (Linkage == GVA_GNUCInline) { - // 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); } else { + assert(Linkage == GVA_StrongExternal); + // Otherwise, we have strong external linkage. GV->setLinkage(llvm::Function::ExternalLinkage); } @@ -481,8 +479,8 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) { // static, static inline, always_inline, and extern inline functions can // always be deferred. Normal inline functions can be deferred in C99/C++. - if (Linkage == GVA_Internal || Linkage == GVA_ExternInline || - Linkage == GVA_C99Inline || Linkage == GVA_CXXInline) + if (Linkage == GVA_Internal || Linkage == GVA_C99Inline || + Linkage == GVA_CXXInline) return true; return false; } diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 06118ac13788..ff6c405de034 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -315,10 +315,9 @@ public: enum GVALinkage { GVA_Internal, GVA_ExternInline, - GVA_GNUCInline, GVA_C99Inline, GVA_CXXInline, - GVA_Normal + GVA_StrongExternal }; private: diff --git a/clang/test/CodeGen/inline.c b/clang/test/CodeGen/inline.c index 7ddfd7645d18..8a283059956e 100644 --- a/clang/test/CodeGen/inline.c +++ b/clang/test/CodeGen/inline.c @@ -9,15 +9,16 @@ // RUN: echo "\nC99 tests:" && // RUN: clang %s -emit-llvm -S -o %t -std=c99 && -// RUN: grep "define available_externally i32 @ei()" %t && +// RUN: grep "define i32 @ei()" %t && // RUN: grep "define available_externally i32 @foo()" %t && // RUN: grep "define i32 @bar()" %t && -// RUN: not grep unreferenced %t && +// RUN: not grep unreferenced1 %t && +// RUN: grep "define void @unreferenced2()" %t && // RUN: grep "define void @gnu_inline()" %t && // RUN: echo "\nC++ tests:" && // 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 @_Z2eiv()" %t && // RUN: grep "define linkonce_odr i32 @_Z3foov()" %t && // RUN: grep "define i32 @_Z3barv()" %t && // RUN: not grep unreferenced %t &&