diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -225,6 +225,8 @@ - Fix an issue about ``decltype`` in the members of class templates derived from templates with related parameters. (`#58674 `_) +- Fix incorrect deletion of the default constructor of unions in some + cases. (`#48416 `_) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -9158,7 +9158,18 @@ // must be accessible and non-deleted, but need not be trivial. Such a // destructor is never actually called, but is semantically checked as // if it were. - DiagKind = 4; + if (CSM == Sema::CXXDefaultConstructor) { + // [class.default.ctor]p2: + // A defaulted default constructor for class X is defined as deleted if + // - X is a union that has a variant member with a non-trivial default + // constructor and no variant member of X has a default member + // initializer + const auto *RD = cast(Field->getParent()); + if (!RD->hasInClassInitializer()) + DiagKind = 4; + } else { + DiagKind = 4; + } } if (DiagKind == -1) diff --git a/clang/test/CodeGen/union-non-trivial-member.cpp b/clang/test/CodeGen/union-non-trivial-member.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/union-non-trivial-member.cpp @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 --std=c++17 -emit-llvm %s -o - -triple x86_64-unknown-linux-gnu | FileCheck %s + +struct non_trivial_constructor { + constexpr non_trivial_constructor() : x(100) { } + int x; +}; + +union UnionInt { + int a{1000}; + non_trivial_constructor b; +}; + +union UnionNonTrivial { + int a; + non_trivial_constructor b{}; +}; + +void f() { + UnionInt u1; + UnionNonTrivial u2; +} + +// CHECK: define dso_local void @_Z1fv() +// CHECK: call void @_ZN8UnionIntC1Ev +// CHECK-NEXT: call void @_ZN15UnionNonTrivialC1Ev + +// CHECK: define {{.*}}void @_ZN8UnionIntC1Ev +// CHECK: call void @_ZN8UnionIntC2Ev + +// CHECK: define {{.*}}void @_ZN15UnionNonTrivialC1Ev +// CHECK: call void @_ZN15UnionNonTrivialC2Ev + +// CHECK: define {{.*}}void @_ZN8UnionIntC2Ev +// CHECK: store i32 1000 + +// CHECK: define {{.*}}void @_ZN15UnionNonTrivialC2Ev +// CHECK: call void @_ZN23non_trivial_constructorC1Ev diff --git a/clang/test/SemaCXX/cxx0x-nontrivial-union.cpp b/clang/test/SemaCXX/cxx0x-nontrivial-union.cpp --- a/clang/test/SemaCXX/cxx0x-nontrivial-union.cpp +++ b/clang/test/SemaCXX/cxx0x-nontrivial-union.cpp @@ -144,3 +144,47 @@ Test2 t2x; // expected-error {{call to implicitly-deleted default constructor of 'Test2'}} } + +namespace GH48416 { + +struct non_trivial_constructor { + constexpr non_trivial_constructor() : x(100) {} + int x; +}; + + +union U1 { + int a; + non_trivial_constructor b; // expected-note {{has a non-trivial default constructor}} +}; + +union U2 { + int a{1000}; + non_trivial_constructor b; +}; + +union U3 { + int a; + non_trivial_constructor b{}; +}; + +union U4 { + int a{}; // expected-note {{previous initialization is here}} + non_trivial_constructor b{}; // expected-error {{initializing multiple members of union}} +}; + +U1 u1; // expected-error {{call to implicitly-deleted default constructor}} +U2 u2; +U3 u3; +U4 u4; + +static_assert(U2().a == 1000, ""); +static_assert(U3().a == 1000, ""); +// expected-error@-1 {{static assertion expression is not an integral constant expression}} +// expected-note@-2 {{read of member 'a' of union with active member 'b'}} +static_assert(U2().b.x == 100, ""); +// expected-error@-1 {{static assertion expression is not an integral constant expression}} +// expected-note@-2 {{read of member 'b' of union with active member 'a'}} +static_assert(U3().b.x == 100, ""); + +} // namespace GH48416