On 6/19/24 9:54 AM, Marek Polacek wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
-- >8 --
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.
---
gcc/cp/class.cc | 3 +-
gcc/cp/tree.cc | 4 +-
gcc/testsuite/g++.dg/ext/is_trivial1.C | 14 ++++++
gcc/testsuite/g++.dg/ext/is_trivial2.C | 17 +++++++
gcc/testsuite/g++.dg/ext/is_trivial3.C | 15 ++++++
gcc/testsuite/g++.dg/ext/is_trivial4.C | 10 ++++
gcc/testsuite/g++.dg/ext/is_trivial5.C | 8 ++++
gcc/testsuite/g++.dg/ext/is_trivial6.C | 49 ++++++++++++++++++++
gcc/testsuite/g++.dg/warn/Wclass-memaccess.C | 2 +
9 files changed, 120 insertions(+), 2 deletions(-)
create mode 100644 gcc/testsuite/g++.dg/ext/is_trivial1.C
create mode 100644 gcc/testsuite/g++.dg/ext/is_trivial2.C
create mode 100644 gcc/testsuite/g++.dg/ext/is_trivial3.C
create mode 100644 gcc/testsuite/g++.dg/ext/is_trivial4.C
create mode 100644 gcc/testsuite/g++.dg/ext/is_trivial5.C
create mode 100644 gcc/testsuite/g++.dg/ext/is_trivial6.C
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index 0ce361eb88e..718601756dd 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -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);
}
diff --git a/gcc/cp/tree.cc b/gcc/cp/tree.cc
index 28648c14c6d..5b837f89e03 100644
--- a/gcc/cp/tree.cc
+++ b/gcc/cp/tree.cc
@@ -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);
diff --git a/gcc/testsuite/g++.dg/ext/is_trivial1.C
b/gcc/testsuite/g++.dg/ext/is_trivial1.C
new file mode 100644
index 00000000000..60ce48edfe9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_trivial1.C
@@ -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>));
diff --git a/gcc/testsuite/g++.dg/ext/is_trivial2.C
b/gcc/testsuite/g++.dg/ext/is_trivial2.C
new file mode 100644
index 00000000000..8a8e554580c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_trivial2.C
@@ -0,0 +1,17 @@
+// PR c++/58074
+// { dg-do compile { target c++11 } }
+
+struct Trivial
+{
+ Trivial() = delete;
+};
+
+struct NonTrivial
+{
+ NonTrivial() = default;
+ NonTrivial(NonTrivial&) = default;
+ NonTrivial& operator=(NonTrivial&) = default;
+};
+
+static_assert(!__is_trivial(Trivial), "Ouch");
+static_assert(__is_trivial(NonTrivial), "Ouch");
Funny that these classes in this testcase are now named backwards, we've
come full circle to the behavior that PR58074 was complaining about.
Maybe add a comment to that effect? OK with that tweak.
Jasnon