-
Notifications
You must be signed in to change notification settings - Fork 10.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ABI] [C++20] [Modules] Don't generate vtable if the class is defined…
… in other module unit Close #61940. The root cause is that clang will generate vtable as strong symbol now even if the corresponding class is defined in other module units. After I check the wording in Itanium ABI, I find this is not inconsistent. Itanium ABI 5.2.3 (https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vague-vtable) says: > The virtual table for a class is emitted in the same object containing > the definition of its key function, i.e. the first non-pure virtual > function that is not inline at the point of class definition. So the current behavior is incorrect. This patch tries to address this. Also I think we need to do a similar change for MSVC ABI. But I don't find the formal wording. So I don't address this in this patch. Reviewed By: rjmccall, iains, dblaikie Differential Revision: https://reviews.llvm.org/D150023
- Loading branch information
1 parent
bd96d7b
commit d8a36b0
Showing
2 changed files
with
104 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
// RUN: rm -rf %t | ||
// RUN: split-file %s %t | ||
// RUN: cd %t | ||
// | ||
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -emit-module-interface \ | ||
// RUN: %t/Mod.cppm -o %t/Mod.pcm | ||
// | ||
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 %t/Mod.pcm \ | ||
// RUN: -emit-llvm -o - | FileCheck %t/Mod.cppm | ||
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fmodule-file=Mod=%t/Mod.pcm \ | ||
// RUN: %t/Use.cpp -emit-llvm -o - | FileCheck %t/Use.cpp | ||
// | ||
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -emit-module-interface \ | ||
// RUN: %t/Mod.cppm -o %t/Mod.pcm -DKEY_FUNCTION_INLINE | ||
// | ||
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 %t/Mod.pcm \ | ||
// RUN: -emit-llvm -o - | FileCheck %t/Mod.cppm -check-prefix=CHECK-INLINE | ||
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fmodule-file=Mod=%t/Mod.pcm \ | ||
// RUN: %t/Use.cpp -emit-llvm -o - | FileCheck %t/Use.cpp -check-prefix=CHECK-INLINE | ||
// | ||
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -emit-module-interface \ | ||
// RUN: %t/M-A.cppm -o %t/M-A.pcm | ||
// RUN: %clang_cc1 -triple %itanium_abi_triple -std=c++20 -fmodule-file=M:A=%t/M-A.pcm \ | ||
// RUN: %t/M-B.cppm -emit-llvm -o - | FileCheck %t/M-B.cppm | ||
|
||
//--- Mod.cppm | ||
export module Mod; | ||
|
||
export class Base { | ||
public: | ||
virtual ~Base(); | ||
}; | ||
#ifdef KEY_FUNCTION_INLINE | ||
inline | ||
#endif | ||
Base::~Base() {} | ||
|
||
// CHECK: @_ZTVW3Mod4Base = unnamed_addr constant | ||
// CHECK: @_ZTSW3Mod4Base = constant | ||
// CHECK: @_ZTIW3Mod4Base = constant | ||
|
||
// CHECK-INLINE: @_ZTVW3Mod4Base = linkonce_odr unnamed_addr constant | ||
// CHECK-INLINE: @_ZTSW3Mod4Base = linkonce_odr constant | ||
// CHECK-INLINE: @_ZTIW3Mod4Base = linkonce_odr constant | ||
|
||
module :private; | ||
int private_use() { | ||
Base base; | ||
return 43; | ||
} | ||
|
||
//--- Use.cpp | ||
import Mod; | ||
int use() { | ||
Base* base = new Base(); | ||
return 43; | ||
} | ||
|
||
// CHECK-NOT: @_ZTSW3Mod4Base = constant | ||
// CHECK-NOT: @_ZTIW3Mod4Base = constant | ||
// CHECK: @_ZTVW3Mod4Base = external unnamed_addr | ||
|
||
// CHECK-INLINE: @_ZTVW3Mod4Base = linkonce_odr unnamed_addr constant | ||
// CHECK-INLINE: @_ZTSW3Mod4Base = linkonce_odr constant | ||
// CHECK-INLINE: @_ZTIW3Mod4Base = linkonce_odr constant | ||
|
||
// Check the case that the declaration of the key function comes from another | ||
// module unit but the definition of the key function comes from the current | ||
// mdoule unit. | ||
|
||
//--- M-A.cppm | ||
export module M:A; | ||
export class C { | ||
public: | ||
virtual ~C(); | ||
}; | ||
|
||
int a_use() { | ||
C c; | ||
return 43; | ||
} | ||
|
||
//--- M-B.cppm | ||
export module M:B; | ||
import :A; | ||
|
||
C::~C() {} | ||
|
||
int b_use() { | ||
C c; | ||
return 43; | ||
} | ||
|
||
// CHECK: @_ZTVW1M1C = unnamed_addr constant | ||
// CHECK: @_ZTSW1M1C = constant | ||
// CHECK: @_ZTIW1M1C = constant |