Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[C++20] [Modules] Clang didn't generate the virtual table to the unit containing the key function #70585

Closed
ChuanqiXu9 opened this issue Oct 29, 2023 · 17 comments · Fixed by #75912
Assignees
Labels
clang:modules C++20 modules and Clang Header Modules

Comments

@ChuanqiXu9
Copy link
Member

Reproducer:

// layer1.cppm
export module foo:layer1;
struct Fruit {
    virtual ~Fruit() = default;
    virtual void eval() = 0;
};
struct Banana : public Fruit {
    Banana() {}
    void eval() override;
};

// layer2.cppm
export module foo:layer2;
import :layer1;
export void layer2_fun() {
    Banana *b = new Banana();
    b->eval();
}
void Banana::eval() {
}

Compiler layer2.cppm with:

clang++ -std=c++20 layer1.cppm --precompile -o foo-layer1.pcm
clang++ -std=c++20 layer2.cppm -fprebuilt-module-path=. -S -emit-llvm -o -

Then we can't see anything about the definition of virtual table. This violates the itanium ABI 5.2.3:

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.

@ChuanqiXu9 ChuanqiXu9 added the clang:modules C++20 modules and Clang Header Modules label Oct 29, 2023
@ChuanqiXu9 ChuanqiXu9 self-assigned this Oct 29, 2023
@llvmbot
Copy link
Member

llvmbot commented Oct 29, 2023

@llvm/issue-subscribers-clang-modules

Author: Chuanqi Xu (ChuanqiXu9)

Reproducer:
// layer1.cppm
export module foo:layer1;
struct Fruit {
    virtual ~Fruit() = default;
    virtual void eval() = 0;
};
struct Banana : public Fruit {
    Banana() {}
    void eval() override;
};

// layer2.cppm
export module foo:layer2;
import :layer1;
export void layer2_fun() {
    Banana *b = new Banana();
    b->eval();
}
void Banana::eval() {
}

Compiler layer2.cppm with:

clang++ -std=c++20 layer1.cppm --precompile -o foo-layer1.pcm
clang++ -std=c++20 layer2.cppm -fprebuilt-module-path=. -S -emit-llvm -o -

Then we can't see anything about the definition of virtual table. This violates the itanium ABI 5.2.3:

> 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.

@iains
Copy link
Contributor

iains commented Oct 29, 2023

I seem to recall we fixed a key function issue not too long ago - is this problem present on earlier branches?

@ChuanqiXu9
Copy link
Member Author

I seem to recall we fixed a key function issue not too long ago - is this problem present on earlier branches?

No, I tested on trunk.

The problem we fixed were about we generate the vtables in too many units to produce duplicated symbols.

But the problem is about we didn't generate the vtable in the targeted unit so that we met undefined symbol.

I am trying to look at it. Probably an oversight.

@ChuanqiXu9
Copy link
Member Author

I took a simple look at the problem and the cause may be a mismatch.

Currently, (maybe there are other paths), when we're generating the constructor of the record decl, we will try to emit the vtable for the record decl if the record decl is a dynamic class.

However, in this example, the constructor won't be generated when we compile layer2.cppm, then here is the problem.

One solution may be, checking if the current emitting function is a key function and if yes, try to generate the vtable.

@rnikander
Copy link

FYI, when I create a similar thing in the old style, with just .cc and .o files, I see things like this:

% nm layer1_b.o | llvm-cxxfilt | grep vtable 
00000000000000a0 S vtable for Fruit
                 U vtable for Banana
                 U vtable for __cxxabiv1::__class_type_info
% nm layer2_b.o | llvm-cxxfilt | grep vtable
0000000000000d68 S vtable for Banana
                 U vtable for __cxxabiv1::__class_type_info
                 U vtable for __cxxabiv1::__si_class_type_info

It's seems it's emitting the vtables in one .o files and resolving undefined U vtable for Banana later during linking.

@davidstone
Copy link
Contributor

Is the concept of a key function necessary with modules? Would anything bad happen if the virtual table were emitted in the object file for the module that defines the class?

@ChuanqiXu9
Copy link
Member Author

Is the concept of a key function necessary with modules? Would anything bad happen if the virtual table were emitted in the object file for the module that defines the class?

Otherwise we're violating the Itanium ABI, which seems not good.

@dwblaikie
Copy link
Collaborator

But modules are a new space for the ABI - we could change/specify the ABI to home any type defined in a module to that modules object file, right? I think that would be a good ABI feature/change/direction for modules - at least at a glance. Perhaps on discussion there might be complications/issues with doing that.

@dwblaikie
Copy link
Collaborator

(I'd want to do/have done similar things with debug info for Clang Header Modules, -fmodules-debuginfo that homes DWARF type definitions to the modular object file - this makes even more sense in a C++ standard modules world where object files are required to be generated from modules)

@ChuanqiXu9
Copy link
Member Author

I filed itanium-cxx-abi/cxx-abi#170. Let's discuss the ABI related issue there.

@ChuanqiXu9
Copy link
Member Author

Sent #75912

ChuanqiXu9 added a commit to ChuanqiXu9/llvm-project that referenced this issue Dec 20, 2023
of dynamic classes

Close llvm#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.
ChuanqiXu9 added a commit to ChuanqiXu9/llvm-project that referenced this issue Jan 8, 2024
of dynamic classes

Close llvm#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.
ChuanqiXu9 added a commit to ChuanqiXu9/llvm-project that referenced this issue Jan 25, 2024
of dynamic classes

Close llvm#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.
ChuanqiXu9 added a commit to ChuanqiXu9/llvm-project that referenced this issue Mar 29, 2024
of dynamic classes

Close llvm#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.
ChuanqiXu9 added a commit to ChuanqiXu9/llvm-project that referenced this issue Jun 4, 2024
of dynamic classes

Close llvm#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.
ChuanqiXu9 added a commit to ChuanqiXu9/llvm-project that referenced this issue Jun 17, 2024
of dynamic classes

Close llvm#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.
ChuanqiXu9 added a commit that referenced this issue Jun 17, 2024
…t of dynamic classes (#75912)

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.
@ChuanqiXu9
Copy link
Member Author

ChuanqiXu9 commented Jul 10, 2024

Reopen due to we reverted #75912

@ChuanqiXu9 ChuanqiXu9 reopened this Jul 10, 2024
ChuanqiXu9 added a commit that referenced this issue Jul 10, 2024
Due to #75912 is reverted and
#70585 is reopened. It looks
riskful to fix the issue correctly before 19. So we provide a workaround
here to help people in this trouble as much as possible.
@ChuanqiXu9
Copy link
Member Author

I add this to the document to provide a method to workaround: https://clang.llvm.org/docs/StandardCPlusPlusModules.html#missing-vtables-for-classes-attached-to-modules

Hope this helps.

aaryanshukla pushed a commit to aaryanshukla/llvm-project that referenced this issue Jul 14, 2024
Due to llvm#75912 is reverted and
llvm#70585 is reopened. It looks
riskful to fix the issue correctly before 19. So we provide a workaround
here to help people in this trouble as much as possible.
@h-vetinari
Copy link
Contributor

Since the xref easily gets lost in a closed PR, noting that #75912 apparently didn't take care of the windows ABI, so a future attempt should also take into account not regressing #97447

@ChuanqiXu9
Copy link
Member Author

Yeah, the current blocking issue is that we're waiting the response from MSVC's devs.

@ChuanqiXu9
Copy link
Member Author

I got the response from MSVC dev: it looks like MSVC will always generate the virtual table on need in the COMDAT section no matter if modules are involved or not.

ChuanqiXu9 added a commit to ChuanqiXu9/llvm-project that referenced this issue Aug 7, 2024
…ule unit of dynamic classes (llvm#75912)

Close llvm#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.
@ChuanqiXu9
Copy link
Member Author

Close since #102287 is landed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:modules C++20 modules and Clang Header Modules
Projects
None yet
7 participants