itanium-cxx-abi / cxx-abi

C++ ABI Summary
508 stars 96 forks source link

[C++20] [Modules] Exported lambdas is not unique to the TU #186

Open ChuanqiXu9 opened 5 months ago

ChuanqiXu9 commented 5 months ago

Reproducer: https://godbolt.org/z/zG5jKc8ao

export module mod;
export auto f = [] {};
import mod;
int main ()
{
    auto const g = f;
}

And it runs well if we changed the definition of f into export inline auto f = [] {};. Then I realized this may be related to ABI. Itanium C++ ABI 5.1.8 said:

In some contexts, such closure types are unique to the translation unit: This ABI therefore does not specify an encoding for such cases (but an implementation must ensure that any internal encoding does not conflict with this ABI).

In the following contexts, however, the one-definition rule requires closure types in different translation units to "correspond":

  • default arguments appearing in class definitions
  • default member initializers
  • the bodies of inline or templated functions
  • the initializers of inline or templated variables

So in the above example, the two different TU should share the same lambda type and so maybe we need to change the wording here.

ChuanqiXu9 commented 5 months ago

Or maybe all the lambdas in modules can't be considered as unique unless they are in TU-local context? Since we may need to merge them: https://github.com/llvm/llvm-project/commit/2241146752f9260d077a6ac38f43069f945e85b4

@zygoloid

ChuanqiXu9 commented 2 months ago

ping @rjmccall @zygoloid again, we met this again in https://github.com/llvm/llvm-project/issues/110146

zygoloid commented 2 months ago

Presumably we should use the same rule that we use for lambdas in inline variables for lambdas in exported variables. This would be easy to add to #85 assuming we agree it's the right direction.

(See also #157, which is the same thing for lambdas in the initializer of a static data member, and #165, which is the same thing for lambdas in a class body outside of a member function, both of which would be addressed by #85.)

zygoloid commented 2 months ago

Presumably we should use the same rule that we use for lambdas in inline variables for lambdas in exported variables.

I think the same consideration would also apply to lambdas in exported functions -- at least ones with a deduced return type -- even if they're not inline. But it's worth checking the TU-local / exposure rules to make sure that such cases aren't simply ill-formed.

ChuanqiXu9 commented 1 month ago

Presumably we should use the same rule that we use for lambdas in inline variables for lambdas in exported variables.

BTW, should we change the wording to exported or module-linkage variables? Since the variables with module linkage can be accessed by other TUs in the same module.

zygoloid commented 1 month ago

Yeah, I think the only cases left where lambdas don't need a mangling are when they have (effectively) internal linkage or appear in a non-inline function in a non-module translation unit.

ChuanqiXu9 commented 1 month ago

Do the lambdas need a mangling if they are in a non-inline function in a module unit?

zygoloid commented 1 month ago

I think they might in a module interface unit, depending on whether the function has a deduced return type, whether the implementation does inlining of non-inline functions in module interface units, etc.

Actually, maybe the best thing is for the ABI to define a mangling for all lambdas in all functions, classes, and variable initializers, and leave it to the implementation to determine whether the mangling is actually needed, based on their own implementation choices. Implementations might want to use the mangling regardless so that demanglers can produce better results.