aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/CodeGen/CodeGenModule.cpp27
-rw-r--r--test/CodeGen/function-attributes.c3
-rw-r--r--test/CodeGen/inline.c10
3 files changed, 24 insertions, 16 deletions
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 5ef57ffdcc..c771461704 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -482,18 +482,23 @@ bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
if (FD->hasAttr<ConstructorAttr>() || FD->hasAttr<DestructorAttr>())
return false;
- // FIXME: What about inline, and/or extern inline?
- if (FD->getStorageClass() != FunctionDecl::Static)
- return false;
- } else {
- const VarDecl *VD = cast<VarDecl>(Global);
- assert(VD->isFileVarDecl() && "Invalid decl");
-
- if (VD->getStorageClass() != VarDecl::Static)
- return false;
+ GVALinkage Linkage = GetLinkageForFunctionOrMethodDecl(FD);
+
+ // static, static inline, always_inline, and extern inline functions can
+ // always be deferred.
+ if (Linkage == GVA_Internal || Linkage == GVA_ExternInline)
+ return true;
+
+ // inline functions can be deferred unless we're in C89 mode.
+ if (Linkage == GVA_Inline && (Features.C99 || Features.CPlusPlus))
+ return true;
+
+ return false;
}
-
- return true;
+
+ const VarDecl *VD = cast<VarDecl>(Global);
+ assert(VD->isFileVarDecl() && "Invalid decl");
+ return VD->getStorageClass() == VarDecl::Static;
}
void CodeGenModule::EmitGlobal(const ValueDecl *Global) {
diff --git a/test/CodeGen/function-attributes.c b/test/CodeGen/function-attributes.c
index a12111ec94..3269f98a56 100644
--- a/test/CodeGen/function-attributes.c
+++ b/test/CodeGen/function-attributes.c
@@ -7,7 +7,6 @@
// RUN: grep 'define zeroext i16 @f5(i32 %x) nounwind' %t &&
// RUN: grep 'define void @f6(i16 signext %x) nounwind' %t &&
// RUN: grep 'define void @f7(i16 zeroext %x) nounwind' %t &&
-// RUN: grep 'define void @f8() nounwind alwaysinline' %t &&
signed char f0(int x) { return x; }
@@ -25,6 +24,8 @@ void f6(signed short x) { }
void f7(unsigned short x) { }
+// F8 is dead so it should not be emitted.
+// RUN: not grep '@f8' %t &&
void __attribute__((always_inline)) f8(void) { }
// RUN: grep 'call void @f9_t() noreturn' %t &&
diff --git a/test/CodeGen/inline.c b/test/CodeGen/inline.c
index 8360896f36..fa2794780b 100644
--- a/test/CodeGen/inline.c
+++ b/test/CodeGen/inline.c
@@ -2,19 +2,20 @@
// 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: grep "define void @unreferenced1()" %t &&
+// RUN: not grep unreferenced2 %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: not grep 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
+// RUN: not grep unreferenced %t
extern inline int ei() { return 123; }
@@ -25,5 +26,6 @@ inline int foo() {
int bar() { return foo(); }
-inline void unreferenced() {}
+inline void unreferenced1() {}
+extern inline void unreferenced2() {}