Skip to content

Commit 908a028

Browse files
committed
[C++20] [Modules] [Itanium ABI] Generate the vtable in the module unit
of dynamic classes Close #70585 and reflect itanium-cxx-abi/cxx-abi#170. The significant change of the patch is: for dynamic classes attached to module units, we generate the vtable to the attached module units directly and the key functions for such classes is meaningless.
1 parent beb2c7f commit 908a028

File tree

4 files changed

+102
-17
lines changed

4 files changed

+102
-17
lines changed

clang/lib/CodeGen/CGVTables.cpp

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,6 +1046,15 @@ CodeGenModule::getVTableLinkage(const CXXRecordDecl *RD) {
10461046
if (!RD->isExternallyVisible())
10471047
return llvm::GlobalVariable::InternalLinkage;
10481048

1049+
// Previously we'll decide the linkage of the vtable by the linkage
1050+
// of the key function. But within modules, the concept of key functions
1051+
// becomes meaningless. So the linkage of the vtable should always be
1052+
// external if the class is externally visible.
1053+
//
1054+
// TODO: How about the case of AppleKext, DLLExportAttr and DLLImportAttr.
1055+
if (Module *M = RD->getOwningModule(); M && M->isNamedModule())
1056+
return llvm::GlobalVariable::ExternalLinkage;
1057+
10491058
// We're at the end of the translation unit, so the current key
10501059
// function is fully correct.
10511060
const CXXMethodDecl *keyFunction = Context.getCurrentKeyFunction(RD);
@@ -1180,6 +1189,21 @@ bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) {
11801189
TSK == TSK_ExplicitInstantiationDefinition)
11811190
return false;
11821191

1192+
// Itanium C++ ABI [5.2.3]:
1193+
// Virtual tables for dynamic classes are emitted as follows:
1194+
//
1195+
// - If the class is templated, the tables are emitted in every object that
1196+
// references any of them.
1197+
// - Otherwise, if the class is attached to a module, the tables are uniquely
1198+
// emitted in the object for the module unit in which it is defined.
1199+
// - Otherwise, if the class has a key function (see below), the tables are
1200+
// emitted in the object for the translation unit containing the definition of
1201+
// the key function. This is unique if the key function is not inline.
1202+
// - Otherwise, the tables are emitted in every object that references any of
1203+
// them.
1204+
if (Module *M = RD->getOwningModule(); M && M->isNamedModule())
1205+
return M != CGM.getContext().getCurrentNamedModule();
1206+
11831207
// Otherwise, if the class doesn't have a key function (possibly
11841208
// anymore), the vtable must be defined here.
11851209
const CXXMethodDecl *keyFunction = CGM.getContext().getCurrentKeyFunction(RD);
@@ -1189,13 +1213,7 @@ bool CodeGenVTables::isVTableExternal(const CXXRecordDecl *RD) {
11891213
const FunctionDecl *Def;
11901214
// Otherwise, if we don't have a definition of the key function, the
11911215
// vtable must be defined somewhere else.
1192-
if (!keyFunction->hasBody(Def))
1193-
return true;
1194-
1195-
assert(Def && "The body of the key function is not assigned to Def?");
1196-
// If the non-inline key function comes from another module unit, the vtable
1197-
// must be defined there.
1198-
return Def->isInAnotherModuleUnit() && !Def->isInlineSpecified();
1216+
return !keyFunction->hasBody(Def);
11991217
}
12001218

12011219
/// Given that we're currently at the end of the translation unit, and

clang/lib/CodeGen/ItaniumCXXABI.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1801,6 +1801,12 @@ void ItaniumCXXABI::emitVTableDefinitions(CodeGenVTables &CGVT,
18011801
if (VTable->hasInitializer())
18021802
return;
18031803

1804+
// If the class are attached to a C++ named module other than the one
1805+
// we're currently compiling, the vtable should be defined there.
1806+
if (Module *M = RD->getOwningModule();
1807+
M && M->isNamedModule() && M != CGM.getContext().getCurrentNamedModule())
1808+
return;
1809+
18041810
ItaniumVTableContext &VTContext = CGM.getItaniumVTableContext();
18051811
const VTableLayout &VTLayout = VTContext.getVTableLayout(RD);
18061812
llvm::GlobalVariable::LinkageTypes Linkage = CGM.getVTableLinkage(RD);

clang/test/CodeGenCXX/modules-vtable.cppm

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
// RUN: %t/M-A.cppm -o %t/M-A.pcm
2525
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fmodule-file=M:A=%t/M-A.pcm \
2626
// RUN: %t/M-B.cppm -emit-llvm -o - | FileCheck %t/M-B.cppm
27+
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 \
28+
// RUN: %t/M-A.pcm -emit-llvm -o - | FileCheck %t/M-A.cppm
2729

2830
//--- Mod.cppm
2931
export module Mod;
@@ -41,9 +43,10 @@ Base::~Base() {}
4143
// CHECK: @_ZTSW3Mod4Base = constant
4244
// CHECK: @_ZTIW3Mod4Base = constant
4345

44-
// CHECK-INLINE: @_ZTVW3Mod4Base = linkonce_odr {{.*}}unnamed_addr constant
45-
// CHECK-INLINE: @_ZTSW3Mod4Base = linkonce_odr {{.*}}constant
46-
// CHECK-INLINE: @_ZTIW3Mod4Base = linkonce_odr {{.*}}constant
46+
// With the new Itanium C++ ABI, the linkage of vtables in modules don't need to be linkonce ODR.
47+
// CHECK-INLINE: @_ZTVW3Mod4Base = {{.*}}unnamed_addr constant
48+
// CHECK-INLINE: @_ZTSW3Mod4Base = {{.*}}constant
49+
// CHECK-INLINE: @_ZTIW3Mod4Base = {{.*}}constant
4750

4851
module :private;
4952
int private_use() {
@@ -60,11 +63,11 @@ int use() {
6063

6164
// CHECK-NOT: @_ZTSW3Mod4Base = constant
6265
// CHECK-NOT: @_ZTIW3Mod4Base = constant
63-
// CHECK: @_ZTVW3Mod4Base = external unnamed_addr
66+
// CHECK: @_ZTVW3Mod4Base = external
6467

65-
// CHECK-INLINE: @_ZTVW3Mod4Base = linkonce_odr {{.*}}unnamed_addr constant
66-
// CHECK-INLINE: @_ZTSW3Mod4Base = linkonce_odr {{.*}}constant
67-
// CHECK-INLINE: @_ZTIW3Mod4Base = linkonce_odr {{.*}}constant
68+
// CHECK-INLINE-NOT: @_ZTSW3Mod4Base = constant
69+
// CHECK-INLINE-NOT: @_ZTIW3Mod4Base = constant
70+
// CHECK-INLINE: @_ZTVW3Mod4Base = external
6871

6972
// Check the case that the declaration of the key function comes from another
7073
// module unit but the definition of the key function comes from the current
@@ -82,6 +85,10 @@ int a_use() {
8285
return 43;
8386
}
8487

88+
// CHECK: @_ZTVW1M1C = unnamed_addr constant
89+
// CHECK: @_ZTSW1M1C = constant
90+
// CHECK: @_ZTIW1M1C = constant
91+
8592
//--- M-B.cppm
8693
export module M:B;
8794
import :A;
@@ -93,6 +100,6 @@ int b_use() {
93100
return 43;
94101
}
95102

96-
// CHECK: @_ZTVW1M1C = unnamed_addr constant
97-
// CHECK: @_ZTSW1M1C = constant
98-
// CHECK: @_ZTIW1M1C = constant
103+
// CHECK: @_ZTVW1M1C = external
104+
// CHECK-NOT: @_ZTSW1M1C = constant
105+
// CHECK-NOT: @_ZTIW1M1C = constant

clang/test/CodeGenCXX/pr70585.cppm

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// REQUIRES: !system-windows
2+
3+
// RUN: rm -rf %t
4+
// RUN: split-file %s %t
5+
// RUN: cd %t
6+
//
7+
// RUN: %clang_cc1 -std=c++20 %t/layer1.cppm -triple %itanium_abi_triple \
8+
// RUN: -emit-module-interface -o %t/foo-layer1.pcm
9+
// RUN: %clang_cc1 -std=c++20 %t/layer2.cppm -triple %itanium_abi_triple \
10+
// RUN: -emit-module-interface -fmodule-file=foo:layer1=%t/foo-layer1.pcm \
11+
// RUN: -o %t/foo-layer2.pcm
12+
// RUN: %clang_cc1 -std=c++20 %t/foo-layer1.pcm -S -emit-llvm -o - | FileCheck %t/layer1.cppm
13+
// RUN: %clang_cc1 -std=c++20 %t/foo-layer2.pcm -S -emit-llvm -o - \
14+
// RUN: -fmodule-file=foo:layer1=%t/foo-layer1.pcm | FileCheck %t/layer2.cppm
15+
16+
//--- layer1.cppm
17+
export module foo:layer1;
18+
struct Fruit {
19+
virtual ~Fruit() = default;
20+
virtual void eval() = 0;
21+
};
22+
struct Banana : public Fruit {
23+
Banana() {}
24+
void eval() override;
25+
};
26+
27+
// CHECK-DAG: @_ZTVW3foo6Banana = unnamed_addr constant
28+
// CHECK-DAG: @_ZTSW3foo6Banana = constant
29+
// CHECK-DAG: @_ZTIW3foo6Banana = constant
30+
//
31+
// CHECK-DAG: @_ZTVW3foo5Fruit = unnamed_addr constant
32+
// CHECK-DAG: @_ZTSW3foo5Fruit = constant
33+
// CHECK-DAG: @_ZTIW3foo5Fruit = constant
34+
35+
// Testing that:
36+
// (1) The use of virtual functions won't produce the vtable.
37+
// (2) The definition of key functions won't produce the vtable.
38+
//
39+
//--- layer2.cppm
40+
export module foo:layer2;
41+
import :layer1;
42+
export void layer2_fun() {
43+
Banana *b = new Banana();
44+
b->eval();
45+
}
46+
void Banana::eval() {
47+
}
48+
49+
// CHECK-NOT: @_ZTVW3foo6Banana
50+
// CHECK-NOT: @_ZTSW3foo6Banana
51+
// CHECK-NOT: @_ZTIW3foo6Banana
52+
// CHECK-NOT: @_ZTVW3foo5Fruit
53+
// CHECK-NOT: @_ZTSW3foo5Fruit
54+
// CHECK-NOT: @_ZTIW3foo5Fruit

0 commit comments

Comments
 (0)