|  | // RUN: rm -rf %t | 
|  | // RUN: split-file %s %t | 
|  | // | 
|  | // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 %t/M.cppm \ | 
|  | // RUN:    -emit-module-interface -o %t/M.pcm | 
|  | // RUN: %clang_cc1 -std=c++20 %t/Use.cpp -fprebuilt-module-path=%t \ | 
|  | // RUN:    -triple %itanium_abi_triple \ | 
|  | // RUN:    -emit-llvm -o - -disable-llvm-passes \ | 
|  | // RUN:    | FileCheck %t/Use.cpp --check-prefix=CHECK-O0 | 
|  | // | 
|  | // RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -O1 %t/M.cppm \ | 
|  | // RUN:    -emit-module-interface -o %t/M.pcm | 
|  | // RUN: %clang_cc1 -std=c++20 %t/Use.cpp -fprebuilt-module-path=%t -O1 \ | 
|  | // RUN:    -triple %itanium_abi_triple \ | 
|  | // RUN:    -emit-llvm -o - -disable-llvm-passes | \ | 
|  | // RUN:    FileCheck %t/Use.cpp --check-prefix=CHECK-O1 | 
|  |  | 
|  | //--- foo.h | 
|  | int func_in_gmf() { | 
|  | return 43; | 
|  | } | 
|  | int func_in_gmf_not_called() { | 
|  | return 44; | 
|  | } | 
|  |  | 
|  | template <class T> | 
|  | class A { | 
|  | public: | 
|  | __attribute__((always_inline)) | 
|  | inline constexpr int getValue() { | 
|  | return 43; | 
|  | } | 
|  |  | 
|  | inline constexpr int getValue2() { | 
|  | return 43; | 
|  | } | 
|  | }; | 
|  |  | 
|  | extern template class A<char>; | 
|  |  | 
|  | //--- M.cppm | 
|  | module; | 
|  | #include "foo.h" | 
|  | export module M; | 
|  | int non_exported_func() { | 
|  | return 43 + func_in_gmf(); | 
|  | } | 
|  | export int exported_func() { | 
|  | return non_exported_func(); | 
|  | } | 
|  |  | 
|  | int non_exported_func_not_called() { | 
|  | return 44; | 
|  | } | 
|  | export int func_not_called() { | 
|  | return non_exported_func_not_called(); | 
|  | } | 
|  |  | 
|  | export | 
|  | __attribute__((always_inline)) | 
|  | int always_inline_func() { | 
|  | return 45; | 
|  | } | 
|  |  | 
|  | export using ::A; | 
|  |  | 
|  | //--- Use.cpp | 
|  | import M; | 
|  | int use() { | 
|  | A<char> a; | 
|  | return exported_func() + always_inline_func() + | 
|  | a.getValue() + a.getValue2(); | 
|  | } | 
|  |  | 
|  | // CHECK-O0: define{{.*}}_Z3usev( | 
|  | // CHECK-O0: declare{{.*}}_ZW1M13exported_funcv( | 
|  | // CHECK-O0: declare{{.*}}_ZW1M18always_inline_funcv( | 
|  | // CHECK-O0: define{{.*}}@_ZN1AIcE8getValueEv( | 
|  | // CHECK-O0: declare{{.*}}@_ZN1AIcE9getValue2Ev( | 
|  | // CHECK-O0-NOT: func_in_gmf | 
|  | // CHECK-O0-NOT: func_in_gmf_not_called | 
|  | // CHECK-O0-NOT: non_exported_func | 
|  | // CHECK-O0-NOT: non_exported_func_not_called | 
|  | // CHECK-O0-NOT: func_not_called | 
|  |  | 
|  | // Checks that the generated code within optimizations keep the same behavior with | 
|  | // O0 to keep consistent ABI. | 
|  | // CHECK-O1: define{{.*}}_Z3usev( | 
|  | // CHECK-O1: declare{{.*}}_ZW1M13exported_funcv( | 
|  | // CHECK-O1: declare{{.*}}_ZW1M18always_inline_funcv( | 
|  | // CHECK-O1: define{{.*}}@_ZN1AIcE8getValueEv( | 
|  | // CHECK-O1: declare{{.*}}@_ZN1AIcE9getValue2Ev( | 
|  | // CHECK-O1-NOT: func_in_gmf | 
|  | // CHECK-O1-NOT: func_in_gmf_not_called | 
|  | // CHECK-O1-NOT: non_exported_func | 
|  | // CHECK-O1-NOT: non_exported_func_not_called | 
|  | // CHECK-O1-NOT: func_not_called |