Bug 85723 - [C++17][DR 1496] __is_trivial intrinsic fails with no trivial non-deleted default c'tor
Summary: [C++17][DR 1496] __is_trivial intrinsic fails with no trivial non-deleted def...
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c++ (show other bugs)
Version: 8.1.0
: P3 normal
Target Milestone: ---
Assignee: Marek Polacek
URL:
Keywords: patch, rejects-valid
Depends on:
Blocks:
 
Reported: 2018-05-09 21:47 UTC by Joe Marino
Modified: 2024-07-18 19:20 UTC (History)
2 users (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2019-02-11 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Joe Marino 2018-05-09 21:47:34 UTC
gcc version 8.1.0 (GCC-Explorer-Build) when compiled with the flags:

-std=c++17 -Wall -Wextra

rejects the following code:

struct NonTrivial { NonTrivial() = delete; };
static_assert(!__is_trivial (NonTrivial), "NonTrivial is trivial");

emitting:

<source>:2:15: error: static assertion failed: NonTrivial is trivial


The assert should pass, as all default constructors of NonTrivial are deleted, which does not meet the requirements in 12 [class] p6:

A trivial class is a class that is trivially copyable and has one or more default constructors (15.1), all of which are either trivial or deleted and **at least one of which is not deleted**.

This wording was introduced by the acceptance of DR 1496.


Full contents of compiling with -v follow:

Using built-in specs.

COLLECT_GCC=/opt/compiler-explorer/gcc-8.1.0/bin/g++

Target: x86_64-linux-gnu

Configured with: ../gcc-8.1.0/configure --prefix=/opt/compiler-explorer/gcc-build/staging --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu --disable-bootstrap --enable-multiarch --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --enable-clocale=gnu --enable-languages=c,c++,fortran --enable-ld=yes --enable-gold=yes --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-linker-build-id --enable-lto --enable-plugins --enable-threads=posix --with-pkgversion=GCC-Explorer-Build

Thread model: posix

gcc version 8.1.0 (GCC-Explorer-Build) 

COLLECT_GCC_OPTIONS='-fdiagnostics-color=always' '-g' '-o' '/tmp/compiler-explorer-compiler11849-52-1aa40zw.lzvg/output.s' '-masm=intel' '-S' '-v' '-std=c++17' '-Wall' '-Wextra' '-shared-libgcc' '-mtune=generic' '-march=x86-64'

 /opt/compiler-explorer/gcc-8.1.0/bin/../libexec/gcc/x86_64-linux-gnu/8.1.0/cc1plus -quiet -v -imultiarch x86_64-linux-gnu -iprefix /opt/compiler-explorer/gcc-8.1.0/bin/../lib/gcc/x86_64-linux-gnu/8.1.0/ -D_GNU_SOURCE <source> -quiet -dumpbase example.cpp -masm=intel -mtune=generic -march=x86-64 -auxbase-strip /tmp/compiler-explorer-compiler11849-52-1aa40zw.lzvg/output.s -g -Wall -Wextra -std=c++17 -version -fdiagnostics-color=always -o /tmp/compiler-explorer-compiler11849-52-1aa40zw.lzvg/output.s

GNU C++17 (GCC-Explorer-Build) version 8.1.0 (x86_64-linux-gnu)

	compiled by GNU C version 5.4.0 20160609, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3, isl version isl-0.18-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072

ignoring nonexistent directory "/opt/compiler-explorer/gcc-8.1.0/bin/../lib/gcc/x86_64-linux-gnu/8.1.0/../../../../x86_64-linux-gnu/include"

ignoring duplicate directory "/opt/compiler-explorer/gcc-8.1.0/bin/../lib/gcc/../../lib/gcc/x86_64-linux-gnu/8.1.0/../../../../include/c++/8.1.0"

ignoring duplicate directory "/opt/compiler-explorer/gcc-8.1.0/bin/../lib/gcc/../../lib/gcc/x86_64-linux-gnu/8.1.0/../../../../include/c++/8.1.0/x86_64-linux-gnu"

ignoring duplicate directory "/opt/compiler-explorer/gcc-8.1.0/bin/../lib/gcc/../../lib/gcc/x86_64-linux-gnu/8.1.0/../../../../include/c++/8.1.0/backward"

ignoring duplicate directory "/opt/compiler-explorer/gcc-8.1.0/bin/../lib/gcc/../../lib/gcc/x86_64-linux-gnu/8.1.0/include"

ignoring nonexistent directory "/usr/local/include/x86_64-linux-gnu"

ignoring duplicate directory "/opt/compiler-explorer/gcc-8.1.0/bin/../lib/gcc/../../lib/gcc/x86_64-linux-gnu/8.1.0/include-fixed"

ignoring nonexistent directory "/opt/compiler-explorer/gcc-8.1.0/bin/../lib/gcc/../../lib/gcc/x86_64-linux-gnu/8.1.0/../../../../x86_64-linux-gnu/include"

ignoring duplicate directory "/usr/include/x86_64-linux-gnu"

#include "..." search starts here:

#include <...> search starts here:

 /usr/include/x86_64-linux-gnu

 /opt/compiler-explorer/gcc-8.1.0/bin/../lib/gcc/x86_64-linux-gnu/8.1.0/../../../../include/c++/8.1.0

 /opt/compiler-explorer/gcc-8.1.0/bin/../lib/gcc/x86_64-linux-gnu/8.1.0/../../../../include/c++/8.1.0/x86_64-linux-gnu

 /opt/compiler-explorer/gcc-8.1.0/bin/../lib/gcc/x86_64-linux-gnu/8.1.0/../../../../include/c++/8.1.0/backward

 /opt/compiler-explorer/gcc-8.1.0/bin/../lib/gcc/x86_64-linux-gnu/8.1.0/include

 /opt/compiler-explorer/gcc-8.1.0/bin/../lib/gcc/x86_64-linux-gnu/8.1.0/include-fixed

 /usr/local/include

 /opt/compiler-explorer/gcc-8.1.0/bin/../lib/gcc/../../include

 /usr/include

End of search list.

GNU C++17 (GCC-Explorer-Build) version 8.1.0 (x86_64-linux-gnu)

	compiled by GNU C version 5.4.0 20160609, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3, isl version isl-0.18-GMP

GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072

Compiler executable checksum: 2a4ed8141a9e6ff21b9c06e24d4e4c1a

<source>:2:15: error: static assertion failed: NonTrivial is trivial

 static_assert(!__is_trivial (NonTrivial), "NonTrivial is trivial");

               ^~~~~~~~~~~~~~~~~~~~~~~~~~

Compiler returned: 1
Comment 1 Jonathan Wakely 2019-02-11 20:52:49 UTC
Confirmed.

We also don't yet implement the earlier change to that wording, from https://wg21.link/cwg1363

struct A {
    A() = default;
    A(int i = 0) { }
};

static_assert(!__is_trivial(A), "");

This fails because G++ considers the class trivial, even though default-initialization would fail as ambiguous.
Comment 2 Marek Polacek 2020-02-12 21:59:06 UTC
This came up again <https://gcc.gnu.org/ml/gcc-patches/2020-02/msg00753.html>.  I think I could take a look at it for GCC 11.
Comment 3 Jonathan Wakely 2024-06-18 12:15:10 UTC
And again, causing PR 115522
Comment 4 Andrew Pinski 2024-06-18 16:54:07 UTC
(In reply to Jonathan Wakely from comment #3)
> And again, causing PR 115522

oh and clang has not implemented this DR either which made me think that was more of a libstdc++ issue :).
Comment 5 Marek Polacek 2024-06-19 13:56:43 UTC
Patch posted:
https://gcc.gnu.org/pipermail/gcc-patches/2024-June/655124.html
Comment 6 GCC Commits 2024-06-21 09:15:42 UTC
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:

https://gcc.gnu.org/g:510ce5eed69ee1bea9c2c696fe3b2301e16d1486

commit r15-1533-g510ce5eed69ee1bea9c2c696fe3b2301e16d1486
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Jun 18 13:27:02 2024 +0100

    libstdc++: Fix std::to_array for trivial-ish types [PR115522]
    
    Due to PR c++/85723 the std::is_trivial trait is true for types with a
    deleted default constructor, so the use of std::is_trivial in
    std::to_array is not sufficient to ensure the type can be trivially
    default constructed then filled using memcpy.
    
    I also forgot that a type with a deleted assignment operator can still
    be trivial, so we also need to check that it's assignable because the
    is_constant_evaluated() path can't use memcpy.
    
    Replace the uses of std::is_trivial with std::is_trivially_copyable
    (needed for memcpy), std::is_trivially_default_constructible (needed so
    that the default construction is valid and does no work) and
    std::is_copy_assignable (needed for the constant evaluation case).
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/115522
            * include/std/array (to_array): Workaround the fact that
            std::is_trivial is not sufficient to check that a type is
            trivially default constructible and assignable.
            * testsuite/23_containers/array/creation/115522.cc: New test.
Comment 7 GCC Commits 2024-07-12 10:19:23 UTC
The releases/gcc-14 branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:

https://gcc.gnu.org/g:21c8708ba638f57cf904c8af3355318d9cf0f9e0

commit r14-10412-g21c8708ba638f57cf904c8af3355318d9cf0f9e0
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Jun 18 13:27:02 2024 +0100

    libstdc++: Fix std::to_array for trivial-ish types [PR115522]
    
    Due to PR c++/85723 the std::is_trivial trait is true for types with a
    deleted default constructor, so the use of std::is_trivial in
    std::to_array is not sufficient to ensure the type can be trivially
    default constructed then filled using memcpy.
    
    I also forgot that a type with a deleted assignment operator can still
    be trivial, so we also need to check that it's assignable because the
    is_constant_evaluated() path can't use memcpy.
    
    Replace the uses of std::is_trivial with std::is_trivially_copyable
    (needed for memcpy), std::is_trivially_default_constructible (needed so
    that the default construction is valid and does no work) and
    std::is_copy_assignable (needed for the constant evaluation case).
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/115522
            * include/std/array (to_array): Workaround the fact that
            std::is_trivial is not sufficient to check that a type is
            trivially default constructible and assignable.
            * testsuite/23_containers/array/creation/115522.cc: New test.
    
    (cherry picked from commit 510ce5eed69ee1bea9c2c696fe3b2301e16d1486)
Comment 8 GCC Commits 2024-07-12 11:11:42 UTC
The releases/gcc-13 branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>:

https://gcc.gnu.org/g:08463348c5cce84dc3c64ac4fbb20e2795ee104f

commit r13-8908-g08463348c5cce84dc3c64ac4fbb20e2795ee104f
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Jun 18 13:27:02 2024 +0100

    libstdc++: Fix std::to_array for trivial-ish types [PR115522]
    
    Due to PR c++/85723 the std::is_trivial trait is true for types with a
    deleted default constructor, so the use of std::is_trivial in
    std::to_array is not sufficient to ensure the type can be trivially
    default constructed then filled using memcpy.
    
    I also forgot that a type with a deleted assignment operator can still
    be trivial, so we also need to check that it's assignable because the
    is_constant_evaluated() path can't use memcpy.
    
    Replace the uses of std::is_trivial with std::is_trivially_copyable
    (needed for memcpy), std::is_trivially_default_constructible (needed so
    that the default construction is valid and does no work) and
    std::is_copy_assignable (needed for the constant evaluation case).
    
    libstdc++-v3/ChangeLog:
    
            PR libstdc++/115522
            * include/std/array (to_array): Workaround the fact that
            std::is_trivial is not sufficient to check that a type is
            trivially default constructible and assignable.
            * testsuite/23_containers/array/creation/115522.cc: New test.
    
    (cherry picked from commit 510ce5eed69ee1bea9c2c696fe3b2301e16d1486)
Comment 9 GCC Commits 2024-07-18 19:15:32 UTC
The trunk branch has been updated by Marek Polacek <mpolacek@gcc.gnu.org>:

https://gcc.gnu.org/g:9690fb3a43e5cf26a5fb853283d4200df312a640

commit r15-2146-g9690fb3a43e5cf26a5fb853283d4200df312a640
Author: Marek Polacek <polacek@redhat.com>
Date:   Tue Jun 18 16:49:24 2024 -0400

    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.
Comment 10 Marek Polacek 2024-07-18 19:20:24 UTC
Fixed for GCC 15.