-
Notifications
You must be signed in to change notification settings - Fork 10.9k
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
Trivially Default Constructible with requires
+ Structure Wrapping
#59206
Comments
@llvm/issue-subscribers-c-20 |
@llvm/issue-subscribers-clang-frontend |
Thanks for reporting, this sounds like the fault of my P0848 patch :) |
So, the problem here is that we mark the trivial constructor as ineligible, because it is less constrained than the template constructor. This is morally wrong because the template constructor wouldn't satisfy the constraints if instantiated. But we can't them because we don't (and shouldn't) instantiate the constructor. Apparently GCC decided to just not compare template to non-template constructors: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=c75ebe76ae12ac4020f20a24f34606a594a40d15. I'd like to be conformant, so this needs a CWG issue (not the minor one linked above). I'll try to write a wording suggestion and then we can proceed with this. |
Funny enough, it appears Clang's the only compiler that got DR1363 'correctly'. We got a bug report about DR1363 a few weeks ago: #58578 but I didn't realize at the time that our behavior deviates from GCC/MSVC. So we also had a divergence for struct A {
A() = default;
template<class... Args>
A(Args&&... args) requires (sizeof...(Args) > 0) {}
};
struct B {
B() = default;
template<class... Args>
B(Args&&... args) requires (sizeof...(Args) == 0) {}
};
struct C {
C() = default;
template<class... Args>
C(Args&&... args) {}
}; |
@erichkeane @zygoloid @hubert-reinterpretcast If you can spare some time, I would appreciate if you have any guidance on how to proceed here. Specifically -
I think my current preference is to align with GCC on this. |
So to answer your second question first: I think that just updating the ClangABI flag to support both versions of the triviality is sufficient here, that is what Richard told me initially when I looked into the triviality. HOWEVER, this is something we should do ONCE. And we should fix ALL the triviality all at once, not just piecemeal. I'd encourage us to wait until after the February C++ standards meeting (where C++23 will be 'finalized') and just implement whatever is there at that point. If CWG fixes things after the fact, than so be it. HOWEVER, all of that is after the Clang16 branch, so the question comes in with what we want to do for Clang 16, particularly with this "Regression". I don't have much of a feeling as to what to do (as I don't completely understand the implications of what I'm saying), but I suspect I'd like us to get back to our previous behavior best-we-can to avoid the extra break. WDYT? |
Sounds reasonable to me! I updated the patch to only fix the eligibility regression - and let's wait with the larger breakage until CWG can spare some time to look at this. |
LGTM! Thanks! |
…nstrained constructor is a template Partially solves #59206: We now mark trivial constructors as eligible even if there's a more constrained templated default constructor. Although technically non-conformant, this solves problems with pretty reasonable uses cases like ``` template<int n> struct Foo { constexpr Foo() = default; template<class... Ts> Foo(Ts... vals) requires(sizeof...(Ts) == n) {} }; ``` where we currently consider the default constructor to be ineligible and therefor inheriting/containing classes have non trivial constructors. This is aligned with GCC: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=c75ebe76ae12ac4020f20a24f34606a594a40d15 This doesn't change `__is_trivial`. Although we're technically standard conformant in this regard, GCC/MSVC exhibit different behaviors that seem to make more sense. An issue has been filed to CWG and we await their response. Reviewed By: erichkeane, #clang-language-wg Differential Revision: https://reviews.llvm.org/D139038
@erichkeane any idea if this was discussed on the reflector or something? Didn't get a response on GitHub, unfortunately. |
@royjacobson I usually sit in core so if you can draft an explanation of the issue and a proposed resolution I can see if I can get it reviewed in core. |
Consider the following semi-minimal example:
The first
static_assert
passes, indicating thatFoo<4>
is trivially default constructible. However, we now wrapFoo<4>
in a classBar
which does nothing, and suddenly the type is no longer trivially default constructible and the secondstatic_assert
fails:I believe that this is incorrect behavior. We can verify that
Foo<4>
is indeed trivially default-constructible per the definition, and of course by thestatic_assert
passing. Even ifFoo<4>
didn't fully constrain the constructors, the non-templated defaulted constructor should be selected preferentially. Next, wrappingFoo<4>
inBar
should do nothing; if anything it should ensure that only the default constructor is accessible. And finally, GCC, MSVC, and even Intel Compiler (now based on LLVM) accept this code without complaint.The tested version:
clang version 16.0.0 (https://github.com/llvm/llvm-project.git 437ccf5af9c2aec915a68a164a95d506fbac2324)
Note that this is a regression. E.g. Clang 15 accepts the code.
The text was updated successfully, but these errors were encountered: