On 6/26/26 12:17 PM, Marek Polacek wrote:
Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk/16?

-- >8 --
Our meta::is_trivially_copyable_type may give the wrong result when
its argument is a reflection of an uninstantiated template, because
its TYPE_HAS_* flags haven't been properly set.  They are set in
finish_struct_1, called while instantiating the template.  We can't
call complete_type on all reflection arguments, but that's fine because
only eval_is_trivially_copyable_type needs it.

        PR c++/125901

gcc/cp/ChangeLog:

        * reflect.cc (process_metafunction): Complete type before
        calling eval_is_trivially_copyable_type.

Why here rather than in eval_is_trivially_copyable_type?

Perhaps trivially_copyable_p should assert that strip_array_types (type) is complete or void, since it cannot give an accurate answer for an incomplete class.

I would expect that meta::is_trivially_copyable_type should throw on incomplete type. More generally I'd expect check_trait_type failures to translate to throw.

But oddly, the complete-type requirement column in table https://eel.is/c++draft/meta#tab:meta.unary.prop is titled "preconditions" which doesn't translate to throw under https://eel.is/c++draft/meta#reflection.traits-3 . It seems to me that the column should instead be "mandates". Jonathan, what do you think?
gcc/testsuite/ChangeLog:

        * g++.dg/reflect/type_trait16.C: New test.
---
  gcc/cp/reflect.cc                           |  7 ++++
  gcc/testsuite/g++.dg/reflect/type_trait16.C | 37 +++++++++++++++++++++
  2 files changed, 44 insertions(+)
  create mode 100644 gcc/testsuite/g++.dg/reflect/type_trait16.C

diff --git a/gcc/cp/reflect.cc b/gcc/cp/reflect.cc
index 3d6d24eb23a..03079f7c3a7 100644
--- a/gcc/cp/reflect.cc
+++ b/gcc/cp/reflect.cc
@@ -8311,6 +8311,13 @@ process_metafunction (const constexpr_ctx *ctx, tree 
fun, tree call,
      case METAFN_IS_VOLATILE_TYPE:
        return eval_is_volatile_type (h);
      case METAFN_IS_TRIVIALLY_COPYABLE_TYPE:
+      /* Need to complete the type since we will be looking at the TYPE_HAS_*
+        bits.  */
+      if (!complete_type_or_maybe_complain (h, NULL_TREE, tf_warning_or_error))
+       {
+         *non_constant_p = true;
+         return NULL_TREE;
+       }
        return eval_is_trivially_copyable_type (h);
      case METAFN_IS_STANDARD_LAYOUT_TYPE:
        return eval_is_standard_layout_type (h);
diff --git a/gcc/testsuite/g++.dg/reflect/type_trait16.C 
b/gcc/testsuite/g++.dg/reflect/type_trait16.C
new file mode 100644
index 00000000000..5fca8658f1c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/type_trait16.C
@@ -0,0 +1,37 @@
+// PR c++/125901
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+#include <meta>
+
+template<typename T>
+struct S {
+  T t;
+};
+
+static_assert(is_trivially_copyable_type(^^S<int>));
+static_assert(!is_trivially_copyable_type(^^std::vector<int>));
+static_assert(is_standard_layout_type(^^std::vector<int>));
+static_assert(is_default_constructible_type(^^std::vector<int>));
+static_assert(!is_trivially_default_constructible_type(^^std::vector<int>));
+static_assert(!is_trivially_copy_constructible_type(^^std::vector<int>));
+static_assert(!is_trivially_move_constructible_type(^^std::vector<int>));
+static_assert(is_copy_assignable_type(^^std::vector<int>));
+static_assert(!is_implicit_lifetime_type(^^std::vector<int>));
+static_assert(!has_virtual_destructor(^^std::vector<int>));
+static_assert(!has_unique_object_representations(^^std::vector<int>));
+
+const std::vector<int> vec{};
+const S<int> s{};
+
+static_assert(is_trivially_copyable_type(^^S<int>));
+static_assert(!is_trivially_copyable_type(^^std::vector<int>));
+static_assert(is_standard_layout_type(^^std::vector<int>));
+static_assert(is_default_constructible_type(^^std::vector<int>));
+static_assert(!is_trivially_default_constructible_type(^^std::vector<int>));
+static_assert(!is_trivially_copy_constructible_type(^^std::vector<int>));
+static_assert(!is_trivially_move_constructible_type(^^std::vector<int>));
+static_assert(is_copy_assignable_type(^^std::vector<int>));
+static_assert(!is_implicit_lifetime_type(^^std::vector<int>));
+static_assert(!has_virtual_destructor(^^std::vector<int>));
+static_assert(!has_unique_object_representations(^^std::vector<int>));

base-commit: ae80ad655d514d7c275b21f5d1ad155793ae4cc0

Reply via email to