-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[Clang] Partial implementation of support for P3074 (trivial unions) #146815
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
base: main
Are you sure you want to change the base?
Changes from 10 commits
40290a9
59b0649
e7cc4ec
5eb68c5
80e2476
9972d7e
c2f3a05
1283ddb
eed0988
64babbc
23bf694
8aebb45
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| // RUN: %clang_cc1 -fsyntax-only -verify %s -std=c++11 | ||
| // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx11-23 %s -std=c++11 | ||
| // RUN: %clang_cc1 -fsyntax-only -verify=expected,cxx26 %s -std=c++26 | ||
|
|
||
| // Implicitly-defined default constructors are constexpr if the implicit | ||
| // definition would be. | ||
|
|
@@ -15,8 +16,9 @@ constexpr NonConstexpr2a nc2a = NonConstexpr2a(); // ok, does not call construct | |
| constexpr int nc2_a = NonConstexpr2().nl.a; // ok | ||
| constexpr int nc2a_a = NonConstexpr2a().a; // ok | ||
| struct Helper { | ||
| friend constexpr NonConstexpr1::NonConstexpr1(); // expected-error {{follows non-constexpr declaration}} | ||
| friend constexpr NonConstexpr2::NonConstexpr2(); // expected-error {{follows non-constexpr declaration}} | ||
| friend constexpr NonConstexpr1::NonConstexpr1(); // cxx11-23-error {{follows non-constexpr declaration}} cxx26-error {{missing exception specification}} | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That ‘is missing exception specification 'noexcept'’ error is weird; I’m also getting that before C++26 and only Clang errors on this; GCC, MSVC, and EDG seem to be fine with it. I don’t think that has anything to do w/ this patch but it’s still strange. |
||
| friend constexpr NonConstexpr2::NonConstexpr2(); // cxx11-23-error {{follows non-constexpr declaration}} cxx26-error {{missing exception specification}} | ||
|
|
||
| }; | ||
|
|
||
| struct Constexpr1 {}; | ||
|
|
@@ -31,14 +33,14 @@ constexpr Constexpr2 c2 = Constexpr2(); // ok | |
|
|
||
| int n; | ||
| struct Member { | ||
| Member() : a(n) {} | ||
| Member() : a(n) {} // cxx26-note {{here}} | ||
| constexpr Member(int&a) : a(a) {} | ||
| int &a; | ||
| }; | ||
| struct NonConstexpr4 { // expected-note {{here}} | ||
| struct NonConstexpr4 { // cxx11-23-note {{here}} cxx26-note {{non-constexpr constructor}} | ||
| Member m; | ||
| }; | ||
| constexpr NonConstexpr4 nc4 = NonConstexpr4(); // expected-error {{constant expression}} expected-note {{non-constexpr constructor 'NonConstexpr4'}} | ||
| constexpr NonConstexpr4 nc4 = NonConstexpr4(); // expected-error {{constant expression}} cxx11-23-note {{non-constexpr constructor 'NonConstexpr4'}} cxx26-note {{in call to}} | ||
| struct Constexpr3 { | ||
| constexpr Constexpr3() : m(n) {} | ||
| Member m; | ||
|
|
@@ -53,11 +55,11 @@ constexpr Constexpr4 c4 = Constexpr4(); // ok | |
| // This rule breaks some legal C++98 programs! | ||
| struct A {}; // expected-note {{here}} | ||
| struct B { | ||
| friend A::A(); // expected-error {{non-constexpr declaration of 'A' follows constexpr declaration}} | ||
| friend A::A(); // cxx11-23-error {{non-constexpr declaration of 'A' follows constexpr declaration}} cxx26-error {{missing exception specification}} | ||
| }; | ||
|
|
||
| namespace UnionCtors { | ||
| union A { // expected-note {{here}} | ||
| union A { // cxx11-23-note {{here}} | ||
| int a; | ||
| int b; | ||
| }; | ||
|
|
@@ -79,19 +81,19 @@ namespace UnionCtors { | |
| int d = 5; | ||
| }; | ||
| }; | ||
| struct E { // expected-note {{here}} | ||
| struct E { // cxx11-23-note {{here}} | ||
| union { | ||
| int a; | ||
| int b; | ||
| }; | ||
| }; | ||
|
|
||
| struct Test { | ||
| friend constexpr A::A() noexcept; // expected-error {{follows non-constexpr declaration}} | ||
| friend constexpr A::A() noexcept; // cxx11-23-error {{follows non-constexpr declaration}} | ||
| friend constexpr B::B() noexcept; | ||
| friend constexpr C::C() noexcept; | ||
| friend constexpr D::D() noexcept; | ||
| friend constexpr E::E() noexcept; // expected-error {{follows non-constexpr declaration}} | ||
| friend constexpr E::E() noexcept; // cxx11-23-error {{follows non-constexpr declaration}} | ||
| }; | ||
| } | ||
|
|
||
|
|
@@ -122,6 +124,6 @@ namespace PR48763 { | |
|
|
||
| struct G { G(); }; | ||
| struct H : D { using D::D; H(int); G g; }; | ||
| union V { H h; }; // expected-note {{field 'h' has a non-trivial default constructor}} | ||
| V v; // expected-error {{deleted}} | ||
| union V { H h; }; // cxx11-23-note {{field 'h' has a non-trivial default constructor}} | ||
| V v; // cxx11-23-error {{deleted}} | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| // RUN: %clang_cc1 -verify -std=c++26 %s -Wno-defaulted-function-deleted -triple x86_64-linux-gnu | ||
|
|
||
| struct NonTrivial { | ||
brevzin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| int i; | ||
| constexpr NonTrivial(int i) :i(i) { } | ||
| constexpr ~NonTrivial() { } | ||
| }; | ||
|
|
||
| union U0 { | ||
| NonTrivial nt; | ||
| int i; | ||
| }; | ||
| U0 u0; | ||
|
|
||
| // check for constant evaluation failure | ||
| constexpr NonTrivial make() { | ||
| U0 u0; | ||
| return u0.nt; | ||
| } | ||
| constexpr NonTrivial nt = make(); // expected-error {{must be initialized by a constant expression}}} | ||
| // expected-note@-3 {{union with no active member}} | ||
| // expected-note@-4 {{in call to 'NonTrivial(u0.nt)'}} | ||
| // expected-note@-3 {{in call to 'make()'}} | ||
|
|
||
| // overload resolution to select a constructor to default-initialize an object of type X either fails | ||
| union U1 { | ||
| U1(int); | ||
| NonTrivial nt; // #1 | ||
| }; | ||
| U1 u1(1); // expected-error {{deleted function}} expected-note@#1 {{non-trivial destructor}} | ||
|
|
||
| // or selects a constructor that is either deleted or not trivial, or | ||
| union U2 { | ||
| U2() : nt(2) { } | ||
| NonTrivial nt; // #2 | ||
| }; | ||
| U2 u2; // expected-error {{deleted function}} expected-note@#2 {{non-trivial destructor}} | ||
|
|
||
| union U3 { | ||
| U3() = delete; | ||
| U3(int); | ||
| NonTrivial nt; // #3 | ||
| }; | ||
| U3 u3(1); // expected-error {{deleted function}} expected-note@#3 {{non-trivial destructor}} | ||
|
|
||
| // or X has a variant member V of class type M (or possibly multi-dimensional array thereof) where V has a default member initializer and M has a destructor that is non-trivial, | ||
brevzin marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| union U4 { | ||
| NonTrivial nt = 1; // #4 | ||
| }; | ||
| U4 u4; // expected-error {{deleted function}} expected-note@#4 {{non-trivial destructor}} | ||
|
|
||
| union U5 { | ||
| NonTrivial nt; | ||
| U5* next = nullptr; | ||
| }; | ||
| U5 u5; | ||
|
|
||
| union U6 { | ||
| U6() = default; | ||
| NonTrivial nt; | ||
| U6* next = nullptr; | ||
| }; | ||
| U6 u6; | ||
|
|
||
|
|
||
| struct DeletedDtor { | ||
| ~DeletedDtor() = delete; // expected-note 2 {{deleted here}} | ||
| }; | ||
| union B1 { | ||
| B1(); | ||
| DeletedDtor a; // expected-note {{because field 'a' has a deleted destructor}} | ||
| }; | ||
| B1 b1; // expected-error {{deleted function}} | ||
| union B2 { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Some more cases: union A {
struct {
NonTrivial x; // W/ and w/o a default member initialiser.
};
};
A a;
struct B {
union {
NonTrivial x; // as above
};
};
B b;
union {
struct {
union {
struct {
union {
NonTrivial x; // as above
};
};
};
};
} c;
struct {
union {
struct {
union {
struct {
NonTrivial x; // as above
};
};
};
};
} d;
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alright I'm not handling this case correctly, but I can't figure out why: union U9 {
struct {
NonTrivial x = 1; // #6
};
} u9; // expected-error {{deleted function}}
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, at a glance nothing jumps out to me; we do create a I did spot a fixme about anonymous unions inside anonymous unions, so er, here’s another gross test case I suppose: union {
union {
NonTrivial x;
};
} a; |
||
| B2(); | ||
| union { // expected-note {{deleted destructor}} | ||
| DeletedDtor a; // expected-note {{because field 'a' has a deleted destructor}} | ||
| }; | ||
| }; | ||
| B2 b2; // expected-error {{deleted function}} | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit (we typically don’t use top-level const for local vars)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not? I see a lot of them btw.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought it was in our coding standards because I’m used to people pointing this out all the time but https://llvm.org/docs/CodingStandards.html doesn’t seem to have anything to say about it.