Ping.

On Wed, Jun 19, 2024 at 09:54:23AM -0400, 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");
> diff --git a/gcc/testsuite/g++.dg/ext/is_trivial3.C 
> b/gcc/testsuite/g++.dg/ext/is_trivial3.C
> new file mode 100644
> index 00000000000..9704a9468d5
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_trivial3.C
> @@ -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), "");
> diff --git a/gcc/testsuite/g++.dg/ext/is_trivial4.C 
> b/gcc/testsuite/g++.dg/ext/is_trivial4.C
> new file mode 100644
> index 00000000000..c26e784b76c
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_trivial4.C
> @@ -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), "");
> diff --git a/gcc/testsuite/g++.dg/ext/is_trivial5.C 
> b/gcc/testsuite/g++.dg/ext/is_trivial5.C
> new file mode 100644
> index 00000000000..5c89e1da6e8
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_trivial5.C
> @@ -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");
> diff --git a/gcc/testsuite/g++.dg/ext/is_trivial6.C 
> b/gcc/testsuite/g++.dg/ext/is_trivial6.C
> new file mode 100644
> index 00000000000..a3a688c5938
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ext/is_trivial6.C
> @@ -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>));
> diff --git a/gcc/testsuite/g++.dg/warn/Wclass-memaccess.C 
> b/gcc/testsuite/g++.dg/warn/Wclass-memaccess.C
> index 87aaa79ceca..636a6e6e1b8 100644
> --- a/gcc/testsuite/g++.dg/warn/Wclass-memaccess.C
> +++ b/gcc/testsuite/g++.dg/warn/Wclass-memaccess.C
> @@ -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 } } }
>  }
> 
> base-commit: be18486825dd24533d320bf840bf95bd083487d1
> -- 
> 2.45.1
> 
Marek

Reply via email to