Open stripe2933 opened 4 days ago
@llvm/issue-subscribers-clang-modules
Author: LEE KYOUNGHEON (stripe2933)
I haven't figured it out completely. But it shows we can workaround it by:
export module ranges;
import std;
#define FWD(...) static_cast<decltype(__VA_ARGS__)&&>(__VA_ARGS__)
namespace ranges::views {
+ export inline constexpr auto deref = std::views::transform([](auto &&x) { return *FWD(x); });
- export constexpr auto deref = std::views::transform([](auto &&x) { return *FWD(x); });
}
Sadly this tends to be an ABI issue. According to https://itanium-cxx-abi.github.io/cxx-abi/abi.html:
5.1.8 Closure Types (Lambdas) In the following contexts, however, the one-definition rule requires closure types in different translation units to "correspond":
- ...
- the initializers of inline or templated variables
So that according to the Itanium C++ ABI spec, we only set lambda numbering for the cases listed above (including the initializers of inline variables, this is why the above workaround works). However, this is not true for modules clearly. The lambda is not unique to the translation units if they are used in initializers of varaibles in modules.
I am not sure if we can change the behavior of the compiler before the above proposed wording get approved in Itanium C++ ABI. Otherwise we can only wait for the action of Itanium C++ group, which may take a longer time.
CC @AaronBallman @erichkeane @cor3ntin @mizvekov for the policy issues.
The straight conversion of this example using preprocessor includes, without modules, doesn't work as well, so I tend to think this is not a bug, the user should have used inline
as you suggested.
Wouldn't this be an ODR violation anyway, and the real problem here is that we miss diagnosing that?
The straight conversion of this example using preprocessor includes, without modules, doesn't work as well
What's the example? In the single TU form, https://godbolt.org/z/1zre9eMjb, it works well. Do you mean split the definition of deref
in other TUs? Then I think it wouldn't work well naturally.
Wouldn't this be an ODR violation anyway, and the real problem here is that we miss diagnosing that?
Then this is why I think this is an ABI issue. If we add a clause to https://itanium-cxx-abi.github.io/cxx-abi/abi.html#closure-types:
In the following contexts, however, the one-definition rule requires closure types in different translation units to "correspond":
- ...
- attached to named modules
it wouldn't be an ODR violation.
I don't see how it relates to ODR. In the given modules case, there is only a single definition, and the entity has module linkage.
Anyway I think this is something more fundamental. It can be reduced to:
// mod.cppm
export module mod;
namespace mod {
export constexpr auto lambda = [](auto &&x) { return x; };
}
// main.cpp
import std;
import mod;
constexpr auto local_lambda = [](auto &&x) { return x; };
int main() {
auto vals = std::array{ 1, 2 };
std::views::transform(local_lambda)(vals); // ok
std::views::transform(mod::lambda)(vals); // error
}
And indeed further, to:
// main.cpp
import mod;
constexpr auto local_lambda = [](auto &&x) { return x; };
auto a = local_lambda;
auto b = mod::lambda; // error
And now I see that it's the same issue as #59513, and also that you already realized that, @ChuanqiXu9. Anyway I'll leave this reduction here just in case it's useful.
Following code works with Clang 19 + libc++.
main.cpp
But this does not:
main.cpp
ranges.cppm
Even if I removed
-fexperimental-modules-reduced-bmi
argument, it still throws errors.