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 dfd4a3a948b..0e32d908b06 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 +struct S { + S() requires false = default; +}; +static_assert(!__is_trivial(S)); + +template +struct R { + R() requires true = default; +}; +static_assert(__is_trivial(R)); 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..e7ecc74831a --- /dev/null +++ b/gcc/testsuite/g++.dg/ext/is_trivial2.C @@ -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"); 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 +struct A { + A() = delete; + A() requires(sizeof(T) == 1) = default; + A() requires(sizeof(T) != 1) = delete; +}; +static_assert(!__is_trivial(A)); +static_assert(__is_trivial(A)); + +template +struct B { + B() = default; + B() requires(sizeof(T) == 1) = default; + B() requires(sizeof(T) != 1) = delete; +}; +static_assert(__is_trivial(B)); +static_assert(__is_trivial(B)); + +template +struct C { + C() = default; + C() requires(sizeof(T) == 1) = delete; + C() requires(sizeof(T) != 1) = default; +}; +static_assert(__is_trivial(C)); +static_assert(__is_trivial(C)); + +template +struct D { + D() = default; + D(int = 42) {} + D() requires(sizeof(T) == 1) = delete; + D() requires(sizeof(T) != 1) = default; +}; +static_assert(!__is_trivial(D)); +static_assert(!__is_trivial(D)); + + +template +struct E { + E() = delete; + E() requires(sizeof(T) == 1) = default; + E() requires(sizeof(T) != 1) = delete; +}; +static_assert(!__is_trivial(E)); +static_assert(__is_trivial(E)); 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 } } } }