diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 295489f48984..52a158fdf498 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -6673,7 +6673,9 @@ bool ASTContext::DeclMustBeEmitted(const Decl *D) { // always be deferred. Normal inline functions can be deferred in C99/C++. // Implicit template instantiations can also be deferred in C++. if (Linkage == GVA_Internal || Linkage == GVA_C99Inline || - Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation) + Linkage == GVA_CXXInline || + (Linkage == GVA_StrongExternal && FD->isInlineSpecified()) || + Linkage == GVA_TemplateInstantiation) return false; return true; } diff --git a/clang/test/CodeGen/inline.c b/clang/test/CodeGen/inline.c index 6bc583df8c96..140642cdd4b8 100644 --- a/clang/test/CodeGen/inline.c +++ b/clang/test/CodeGen/inline.c @@ -1,10 +1,8 @@ // RUN: echo "GNU89 tests:" // RUN: %clang %s -O1 -emit-llvm -S -o %t -std=gnu89 -// RUN: grep "define available_externally i32 @ei()" %t // RUN: grep "define i32 @foo()" %t // RUN: grep "define i32 @bar()" %t -// RUN: grep "define void @unreferenced1()" %t -// RUN: not grep unreferenced2 %t +// RUN: not grep unreferenced %t // RUN: grep "define void @gnu_inline()" %t // RUN: grep "define available_externally void @gnu_ei_inline()" %t // RUN: grep "define i32 @test1" %t @@ -19,8 +17,7 @@ // RUN: grep "define i32 @ei()" %t // RUN: grep "define available_externally i32 @foo()" %t // RUN: grep "define i32 @bar()" %t -// RUN: not grep unreferenced1 %t -// RUN: grep "define void @unreferenced2()" %t +// RUN: not grep unreferenced %t // RUN: grep "define void @gnu_inline()" %t // RUN: grep "define available_externally void @gnu_ei_inline()" %t // RUN: grep "define i32 @test1" %t @@ -53,6 +50,7 @@ __inline void unreferenced1() {} extern __inline void unreferenced2() {} __inline __attribute((__gnu_inline__)) void gnu_inline() {} +void test_gnu_inline() { gnu_inline(); } // PR3988 extern __inline __attribute__((gnu_inline)) void gnu_ei_inline() {} @@ -71,6 +69,7 @@ void test_test2() { test2(); } // PR3989 extern __inline void test3() __attribute__((gnu_inline)); __inline void __attribute__((gnu_inline)) test3() {} +void test_test3() { test3(); } extern int test4(void); extern __inline __attribute__ ((__gnu_inline__)) int test4(void) @@ -92,11 +91,10 @@ void test_test5() { test5(); } __inline int test6() { return 0; } extern int test6(); +void test_test6() { test6(); } - -// No PR#, but this once crashed clang in C99 mode due to buggy extern inline -// redeclaration detection. -void test7() { } +// PR10657 +extern __inline void test7() {} void test7(); // PR11062; the fact that the function is named strlcpy matters here. diff --git a/clang/test/CodeGen/inline2.c b/clang/test/CodeGen/inline2.c index fca4fff7ca8d..3e5602c99b3c 100644 --- a/clang/test/CodeGen/inline2.c +++ b/clang/test/CodeGen/inline2.c @@ -1,61 +1,63 @@ -// RUN: %clang_cc1 -O1 -std=gnu89 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix GNU89 %s -// RUN: %clang_cc1 -O1 -std=c99 -triple i386-apple-darwin9 -emit-llvm %s -o - | FileCheck -check-prefix C99 %s +// RUN: echo "GNU89 tests:" +// RUN: %clang_cc1 -O1 -triple i386-apple-darwin9 -emit-llvm -o %t -std=gnu89 %s +// RUN: grep "define i32 @f0()" %t +// RUN: grep "define i32 @f1()" %t +// RUN: grep "define i32 @f2()" %t +// RUN: grep "define i32 @f3()" %t +// RUN: grep "define i32 @f5()" %t +// RUN: grep "define i32 @f6()" %t +// RUN: grep "define i32 @f7()" %t +// RUN: grep "define i32 @fA()" %t +// RUN: grep "define available_externally i32 @f4()" %t +// RUN: grep "define available_externally i32 @f8()" %t +// RUN: grep "define available_externally i32 @f9()" %t + +// RUN: echo "C99 tests:" +// RUN: %clang_cc1 -O1 -triple i386-apple-darwin9 -emit-llvm -o %t -std=c99 %s +// RUN: grep "define i32 @f0()" %t +// RUN: grep "define i32 @f1()" %t +// RUN: grep "define i32 @f2()" %t +// RUN: grep "define i32 @f3()" %t +// RUN: grep "define i32 @f5()" %t +// RUN: grep "define i32 @f6()" %t +// RUN: grep "define i32 @f7()" %t +// RUN: grep "define available_externally i32 @fA()" %t +// RUN: grep "define i32 @f4()" %t +// RUN: grep "define i32 @f8()" %t +// RUN: grep "define i32 @f9()" %t -// CHECK-GNU89: define i32 @f0() -// CHECK-C99: define i32 @f0() int f0(void); int f0(void) { return 0; } -// CHECK-GNU89: define i32 @f1() -// CHECK-C99: define i32 @f1() inline int f1(void); int f1(void) { return 0; } -// CHECK-GNU89: define i32 @f2() -// CHECK-C99: define i32 @f2() int f2(void); inline int f2(void) { return 0; } -// CHECK-GNU89: define i32 @f3() -// CHECK-C99: define i32 @f3() extern inline int f3(void); int f3(void) { return 0; } -// CHECK-GNU89: define i32 @f5() -// CHECK-C99: define i32 @f5() extern inline int f5(void); inline int f5(void) { return 0; } -// CHECK-GNU89: define i32 @f6() -// CHECK-C99: define i32 @f6() inline int f6(void); extern inline int f6(void) { return 0; } -// CHECK-GNU89: define i32 @f7() -// CHECK-C99: define i32 @f7() extern inline int f7(void); extern int f7(void) { return 0; } -// CHECK-GNU89: define i32 @fA() inline int fA(void) { return 0; } -// CHECK-GNU89: define available_externally i32 @f4() -// CHECK-C99: define i32 @f4() int f4(void); extern inline int f4(void) { return 0; } -// CHECK-GNU89: define available_externally i32 @f8() -// CHECK-C99: define i32 @f8() extern int f8(void); extern inline int f8(void) { return 0; } -// CHECK-GNU89: define available_externally i32 @f9() -// CHECK-C99: define i32 @f9() extern inline int f9(void); extern inline int f9(void) { return 0; } -// CHECK-C99: define available_externally i32 @fA() - int test_all() { return f0() + f1() + f2() + f3() + f4() + f5() + f6() + f7() + f8() + f9() + fA();