bool ImplicitInlineCXX20 = !getLangOpts().CPlusPlusModules ||
!NewFD->getOwningModule() ||
NewFD->getOwningModule()->isGlobalModule() ||
- NewFD->getOwningModule()->isModuleMapModule();
+ NewFD->getOwningModule()->isHeaderLikeModule();
bool isInline = D.getDeclSpec().isInlineSpecified();
bool isVirtual = D.getDeclSpec().isVirtualSpecified();
bool hasExplicit = D.getDeclSpec().hasExplicitSpecifier();
--- /dev/null
+// Tests that the friend function with-in an class definition in the header unit is still implicit inline.
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple -xc++-user-header -emit-header-unit %t/foo.h -o %t/foo.pcm
+// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple -fmodule-file=%t/foo.pcm %t/user.cpp \
+// RUN: -S -emit-llvm -disable-llvm-passes -o - | FileCheck %t/user.cpp
+
+//--- foo.h
+class foo {
+ int value;
+public:
+ foo(int v) : value(v) {}
+
+ friend int getFooValue(foo f) {
+ return f.value;
+ }
+};
+
+//--- user.cpp
+import "foo.h";
+int use() {
+ foo f(43);
+ return getFooValue(f);
+}
+
+// CHECK: define{{.*}}linkonce_odr{{.*}}@_Z11getFooValue3foo
--- /dev/null
+// Tests that the member function with-in an class definition in the header unit is still implicit inline.
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple -xc++-user-header -emit-header-unit %t/foo.h -o %t/foo.pcm
+// RUN: %clang_cc1 -std=c++20 -triple %itanium_abi_triple -fmodule-file=%t/foo.pcm %t/user.cpp \
+// RUN: -S -emit-llvm -disable-llvm-passes -o - | FileCheck %t/user.cpp
+
+//--- foo.h
+class foo {
+public:
+ int getValue() {
+ return 43;
+ }
+};
+
+//--- user.cpp
+import "foo.h";
+int use() {
+ foo f;
+ return f.getValue();
+}
+
+// CHECK: define{{.*}}linkonce_odr{{.*}}@_ZN3foo8getValueEv
EXPECT_TRUE(bar->isInlined());
}
+TEST(Decl, MemberFunctionInHeaderUnit) {
+ llvm::Annotations Code(R"(
+ class foo {
+ public:
+ int memFn() {
+ return 43;
+ }
+ };
+ )");
+
+ auto AST = tooling::buildASTFromCodeWithArgs(
+ Code.code(), {"-std=c++20", " -xc++-user-header ", "-emit-header-unit"});
+ ASTContext &Ctx = AST->getASTContext();
+
+ auto *memFn = selectFirst<FunctionDecl>(
+ "memFn", match(functionDecl(hasName("memFn")).bind("memFn"), Ctx));
+
+ EXPECT_TRUE(memFn->isInlined());
+}
+
+TEST(Decl, FriendFunctionWithinClassInHeaderUnit) {
+ llvm::Annotations Code(R"(
+ class foo {
+ int value;
+ public:
+ foo(int v) : value(v) {}
+
+ friend int getFooValue(foo f) {
+ return f.value;
+ }
+ };
+ )");
+
+ auto AST = tooling::buildASTFromCodeWithArgs(
+ Code.code(), {"-std=c++20", " -xc++-user-header ", "-emit-header-unit"});
+ ASTContext &Ctx = AST->getASTContext();
+
+ auto *getFooValue = selectFirst<FunctionDecl>(
+ "getFooValue",
+ match(functionDecl(hasName("getFooValue")).bind("getFooValue"), Ctx));
+
+ EXPECT_TRUE(getFooValue->isInlined());
+}