c++: implement DR1363 and DR1496 for __is_trivial [PR85723]
is_trivial was introduced in <https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2230.html> which split POD into is_trivial and is_standard_layout. Later came CWG 1363. Since struct A { A() = default; A(int = 42) {} }; cannot be default-initialized, it should not be trivial, so the definition of what is a trivial class changed. Similarly, CWG 1496 concluded that struct B { B() = delete; }: should not be trivial either. P0848 adjusted the definition further to say "eligible". That means that template<typename T> struct C { C() requires false = default; }; should not be trivial, either, since C::C() is not eligible. Bug 85723 reports that we implement none of the CWGs. I chose to fix this by using type_has_non_deleted_trivial_default_ctor which uses locate_ctor which uses build_new_method_call, which would be used by default-initialization as well. With that, all __is_trivial problems I could find in the Bugzilla are fixed, except for PR96288, which may need changes to trivially-copyable, so I'm not messing with that now. I hope this has no ABI implications. There's effort undergoing to remove "trivial class" from the core language as it's not really meaningful. So the impact of this change should be pretty low except to fix a few libstdc++ problems. PR c++/108769 PR c++/58074 PR c++/115522 PR c++/85723 gcc/cp/ChangeLog: * class.cc (type_has_non_deleted_trivial_default_ctor): Fix formatting. * tree.cc (trivial_type_p): Instead of TYPE_HAS_TRIVIAL_DFLT, use type_has_non_deleted_trivial_default_ctor. gcc/testsuite/ChangeLog: * g++.dg/warn/Wclass-memaccess.C: Add dg-warning. * g++.dg/ext/is_trivial1.C: New test. * g++.dg/ext/is_trivial2.C: New test. * g++.dg/ext/is_trivial3.C: New test. * g++.dg/ext/is_trivial4.C: New test. * g++.dg/ext/is_trivial5.C: New test. * g++.dg/ext/is_trivial6.C: New test.
This commit is contained in:
parent
248e8530dd
commit
9690fb3a43
9 changed files with 123 additions and 2 deletions
|
@ -5918,7 +5918,8 @@ type_has_virtual_destructor (tree type)
|
|||
/* True iff class TYPE has a non-deleted trivial default
|
||||
constructor. */
|
||||
|
||||
bool type_has_non_deleted_trivial_default_ctor (tree type)
|
||||
bool
|
||||
type_has_non_deleted_trivial_default_ctor (tree type)
|
||||
{
|
||||
return TYPE_HAS_TRIVIAL_DFLT (type) && locate_ctor (type);
|
||||
}
|
||||
|
|
|
@ -4637,7 +4637,9 @@ trivial_type_p (const_tree t)
|
|||
t = strip_array_types (CONST_CAST_TREE (t));
|
||||
|
||||
if (CLASS_TYPE_P (t))
|
||||
return (TYPE_HAS_TRIVIAL_DFLT (t)
|
||||
/* A trivial class is a class that is trivially copyable and has one or
|
||||
more eligible default constructors, all of which are trivial. */
|
||||
return (type_has_non_deleted_trivial_default_ctor (CONST_CAST_TREE (t))
|
||||
&& trivially_copyable_p (t));
|
||||
else
|
||||
return scalarish_type_p (t);
|
||||
|
|
14
gcc/testsuite/g++.dg/ext/is_trivial1.C
Normal file
14
gcc/testsuite/g++.dg/ext/is_trivial1.C
Normal file
|
@ -0,0 +1,14 @@
|
|||
// PR c++/108769
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
template <class T>
|
||||
struct S {
|
||||
S() requires false = default;
|
||||
};
|
||||
static_assert(!__is_trivial(S<int>));
|
||||
|
||||
template <class T>
|
||||
struct R {
|
||||
R() requires true = default;
|
||||
};
|
||||
static_assert(__is_trivial(R<int>));
|
20
gcc/testsuite/g++.dg/ext/is_trivial2.C
Normal file
20
gcc/testsuite/g++.dg/ext/is_trivial2.C
Normal file
|
@ -0,0 +1,20 @@
|
|||
// PR c++/58074
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct Trivial
|
||||
{
|
||||
Trivial() = delete;
|
||||
};
|
||||
|
||||
struct NonTrivial
|
||||
{
|
||||
NonTrivial() = default;
|
||||
NonTrivial(NonTrivial&) = default;
|
||||
NonTrivial& operator=(NonTrivial&) = default;
|
||||
};
|
||||
|
||||
// As it happens, 58074 was originally asking for the opposite result
|
||||
// of __is_trivial than we're checking here, so what was non-trivial
|
||||
// was supposed to be trivial and vice versa. But here we are.
|
||||
static_assert(!__is_trivial(Trivial), "Ouch");
|
||||
static_assert(__is_trivial(NonTrivial), "Ouch");
|
15
gcc/testsuite/g++.dg/ext/is_trivial3.C
Normal file
15
gcc/testsuite/g++.dg/ext/is_trivial3.C
Normal file
|
@ -0,0 +1,15 @@
|
|||
// PR c++/115522
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
// Not default constructible.
|
||||
struct S {
|
||||
const int i;
|
||||
};
|
||||
|
||||
static_assert(!__is_trivial(S), "");
|
||||
|
||||
struct R {
|
||||
int &r;
|
||||
};
|
||||
|
||||
static_assert(!__is_trivial(R), "");
|
10
gcc/testsuite/g++.dg/ext/is_trivial4.C
Normal file
10
gcc/testsuite/g++.dg/ext/is_trivial4.C
Normal file
|
@ -0,0 +1,10 @@
|
|||
// CWG 1363
|
||||
// PR c++/85723
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct A {
|
||||
A() = default;
|
||||
A(int i = 0) { }
|
||||
};
|
||||
|
||||
static_assert(!__is_trivial(A), "");
|
8
gcc/testsuite/g++.dg/ext/is_trivial5.C
Normal file
8
gcc/testsuite/g++.dg/ext/is_trivial5.C
Normal file
|
@ -0,0 +1,8 @@
|
|||
// CWG 1496
|
||||
// PR c++/85723
|
||||
// { dg-do compile { target c++11 } }
|
||||
|
||||
struct NonTrivial {
|
||||
NonTrivial() = delete;
|
||||
};
|
||||
static_assert(!__is_trivial (NonTrivial), "NonTrivial is trivial");
|
49
gcc/testsuite/g++.dg/ext/is_trivial6.C
Normal file
49
gcc/testsuite/g++.dg/ext/is_trivial6.C
Normal file
|
@ -0,0 +1,49 @@
|
|||
// PR c++/85723
|
||||
// { dg-do compile { target c++20 } }
|
||||
|
||||
template<typename T>
|
||||
struct A {
|
||||
A() = delete;
|
||||
A() requires(sizeof(T) == 1) = default;
|
||||
A() requires(sizeof(T) != 1) = delete;
|
||||
};
|
||||
static_assert(!__is_trivial(A<int>));
|
||||
static_assert(__is_trivial(A<char>));
|
||||
|
||||
template<typename T>
|
||||
struct B {
|
||||
B() = default;
|
||||
B() requires(sizeof(T) == 1) = default;
|
||||
B() requires(sizeof(T) != 1) = delete;
|
||||
};
|
||||
static_assert(__is_trivial(B<int>));
|
||||
static_assert(__is_trivial(B<char>));
|
||||
|
||||
template<typename T>
|
||||
struct C {
|
||||
C() = default;
|
||||
C() requires(sizeof(T) == 1) = delete;
|
||||
C() requires(sizeof(T) != 1) = default;
|
||||
};
|
||||
static_assert(__is_trivial(C<int>));
|
||||
static_assert(__is_trivial(C<char>));
|
||||
|
||||
template<typename T>
|
||||
struct D {
|
||||
D() = default;
|
||||
D(int = 42) {}
|
||||
D() requires(sizeof(T) == 1) = delete;
|
||||
D() requires(sizeof(T) != 1) = default;
|
||||
};
|
||||
static_assert(!__is_trivial(D<int>));
|
||||
static_assert(!__is_trivial(D<char>));
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct E {
|
||||
E() = delete;
|
||||
E() requires(sizeof(T) == 1) = default;
|
||||
E() requires(sizeof(T) != 1) = delete;
|
||||
};
|
||||
static_assert(!__is_trivial(E<int>));
|
||||
static_assert(__is_trivial(E<char>));
|
|
@ -1254,6 +1254,7 @@ void test (HasConstData *p, const HasConstData &x,
|
|||
|
||||
// Reallocating is not diagnosed except in C++ 98 due to a bug.
|
||||
T (q = realloc, (p, 1)); // { dg-warning "moving an object of non-trivially copyable type .struct HasConstData.; use .new. and .delete. instead" "c++98" { target { c++98_only } } }
|
||||
// { dg-warning "moving an object of non-trivial type" "" { target c++11 } .-1 }
|
||||
T (q = realloc, (p, n)); // { dg-warning "realloc" "c++98" { target { c++98_only } } }
|
||||
T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" "c++98" { target { c++98_only } } }
|
||||
}
|
||||
|
@ -1333,6 +1334,7 @@ void test (HasReference *p, const HasReference &x,
|
|||
// in C++ 98 because of a bug, but it seems like it should be
|
||||
// diagnosed in all modes.
|
||||
T (q = realloc, (p, 1)); // { dg-warning "realloc" "c++ 98" { target { c++98_only } } }
|
||||
// { dg-warning "moving an object of non-trivial type" "" { target c++11 } .-1 }
|
||||
T (q = realloc, (p, n)); // { dg-warning "realloc" "c++ 98" { target { c++98_only } } }
|
||||
T (q = realloc, (p, sizeof *p)); // { dg-warning "realloc" "c++ 98" { target { c++98_only } } }
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue