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 } } }
 }
