From 74fa38297b22d826f53f0b1894a1847eca3503dc Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Wed, 6 Nov 2019 19:50:19 -0500 Subject: [PATCH] Implement D1907R1 "structural type". ISO C++ paper D1907R1 proposes "structural type" as an alternative to the current notion of "strong structural equality", which has various problems. I'm implementing it to give people a chance to try it. The build_base_field changes are to make it easier for structural_type_p to see whether a base is private or protected. * tree.c (structural_type_p): New. * pt.c (invalid_nontype_parm_type_p): Use it. * class.c (build_base_field_1): Take binfo. Copy TREE_PRIVATE. (build_base_field): Pass binfo. From-SVN: r277902 --- gcc/cp/ChangeLog | 6 ++ gcc/cp/class.c | 9 ++- gcc/cp/cp-tree.h | 1 + gcc/cp/pt.c | 18 ++---- gcc/cp/tree.c | 57 +++++++++++++++++++ .../g++.dg/cpp2a/udlit-class-nttp-neg2.C | 2 +- 6 files changed, 77 insertions(+), 16 deletions(-) diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 8f6a71a8b6a..a0b93e77e4d 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,5 +1,11 @@ 2019-11-06 Jason Merrill + Implement D1907R1 "structural type". + * tree.c (structural_type_p): New. + * pt.c (invalid_nontype_parm_type_p): Use it. + * class.c (build_base_field_1): Take binfo. Copy TREE_PRIVATE. + (build_base_field): Pass binfo. + PR c++/92150 - partial specialization with class NTTP. * pt.c (unify): Handle VIEW_CONVERT_EXPR. diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 89ed1c040f6..a9aa5e77171 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -4353,15 +4353,18 @@ layout_empty_base_or_field (record_layout_info rli, tree binfo_or_decl, fields at NEXT_FIELD, and return it. */ static tree -build_base_field_1 (tree t, tree basetype, tree *&next_field) +build_base_field_1 (tree t, tree binfo, tree *&next_field) { /* Create the FIELD_DECL. */ + tree basetype = BINFO_TYPE (binfo); gcc_assert (CLASSTYPE_AS_BASE (basetype)); tree decl = build_decl (input_location, FIELD_DECL, NULL_TREE, CLASSTYPE_AS_BASE (basetype)); DECL_ARTIFICIAL (decl) = 1; DECL_IGNORED_P (decl) = 1; DECL_FIELD_CONTEXT (decl) = t; + TREE_PRIVATE (decl) = TREE_PRIVATE (binfo); + TREE_PROTECTED (decl) = TREE_PROTECTED (binfo); if (is_empty_class (basetype)) /* CLASSTYPE_SIZE is one byte, but the field needs to have size zero. */ DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = size_zero_node; @@ -4414,7 +4417,7 @@ build_base_field (record_layout_info rli, tree binfo, CLASSTYPE_EMPTY_P (t) = 0; /* Create the FIELD_DECL. */ - decl = build_base_field_1 (t, basetype, next_field); + decl = build_base_field_1 (t, binfo, next_field); /* Try to place the field. It may take more than one try if we have a hard time placing the field without putting two @@ -4448,7 +4451,7 @@ build_base_field (record_layout_info rli, tree binfo, aggregate bases. */ if (cxx_dialect >= cxx17 && !BINFO_VIRTUAL_P (binfo)) { - tree decl = build_base_field_1 (t, basetype, next_field); + tree decl = build_base_field_1 (t, binfo, next_field); DECL_FIELD_OFFSET (decl) = BINFO_OFFSET (binfo); DECL_FIELD_BIT_OFFSET (decl) = bitsize_zero_node; SET_DECL_OFFSET_ALIGN (decl, BITS_PER_UNIT); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 2b45d62ce21..adc021b2a5c 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -7302,6 +7302,7 @@ extern bool trivial_type_p (const_tree); extern bool trivially_copyable_p (const_tree); extern bool type_has_unique_obj_representations (const_tree); extern bool scalarish_type_p (const_tree); +extern bool structural_type_p (tree, bool = false); extern bool type_has_nontrivial_default_init (const_tree); extern bool type_has_nontrivial_copy_init (const_tree); extern void maybe_warn_parm_abi (tree, location_t); diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 061a92c9db0..8bacb3952ff 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -25748,21 +25748,15 @@ invalid_nontype_parm_type_p (tree type, tsubst_flags_t complain) return false; if (!complete_type_or_else (type, NULL_TREE)) return true; - if (!literal_type_p (type)) + if (!structural_type_p (type)) { - error ("%qT is not a valid type for a template non-type parameter " - "because it is not literal", type); - explain_non_literal_class (type); - return true; - } - if (cp_has_mutable_p (type)) - { - error ("%qT is not a valid type for a template non-type parameter " - "because it has a mutable member", type); + auto_diagnostic_group d; + if (complain & tf_error) + error ("%qT is not a valid type for a template non-type parameter " + "because it is not structural", type); + structural_type_p (type, true); return true; } - /* FIXME check op<=> and strong structural equality once spaceship is - implemented. */ return false; } diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 5cdeb6a07fe..ba635d4ddbd 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -4378,6 +4378,63 @@ zero_init_p (const_tree t) return 1; } +/* True IFF T is a C++20 structural type (P1907R1) that can be used as a + non-type template parameter. If EXPLAIN, explain why not. */ + +bool +structural_type_p (tree t, bool explain) +{ + t = strip_array_types (t); + if (INTEGRAL_OR_ENUMERATION_TYPE_P (t)) + return true; + if (NULLPTR_TYPE_P (t)) + return true; + if (TYPE_PTR_P (t) || TYPE_PTRMEM_P (t)) + return true; + if (TYPE_REF_P (t) && !TYPE_REF_IS_RVALUE (t)) + return true; + if (!CLASS_TYPE_P (t)) + return false; + if (TREE_CODE (t) == UNION_TYPE) + { + if (explain) + inform (location_of (t), "%qT is a union", t); + return false; + } + if (!literal_type_p (t)) + { + if (explain) + explain_non_literal_class (t); + return false; + } + if (CLASSTYPE_HAS_MUTABLE (t)) + { + if (explain) + inform (location_of (t), "%qT has a mutable member", t); + return false; + } + for (tree m = next_initializable_field (TYPE_FIELDS (t)); m; + m = next_initializable_field (DECL_CHAIN (m))) + { + if (TREE_PRIVATE (m) || TREE_PROTECTED (m)) + { + if (explain) + inform (location_of (m), "%qD is not public", m); + return false; + } + if (!structural_type_p (TREE_TYPE (m))) + { + if (explain) + { + inform (location_of (m), "%qD has a non-structural type", m); + structural_type_p (TREE_TYPE (m), true); + } + return false; + } + } + return true; +} + /* Handle the C++17 [[nodiscard]] attribute, which is similar to the GNU warn_unused_result attribute. */ diff --git a/gcc/testsuite/g++.dg/cpp2a/udlit-class-nttp-neg2.C b/gcc/testsuite/g++.dg/cpp2a/udlit-class-nttp-neg2.C index 2c00c5c6b88..71ba8f981a0 100644 --- a/gcc/testsuite/g++.dg/cpp2a/udlit-class-nttp-neg2.C +++ b/gcc/testsuite/g++.dg/cpp2a/udlit-class-nttp-neg2.C @@ -9,5 +9,5 @@ struct non_literal_class { // auto operator<=> (const non_literal_fixed_string&) = default; }; -template // { dg-error "11:is not a valid type for a template non-type parameter because it is not literal" } +template // { dg-error "11:is not a valid type for a template non-type parameter because it is not structural" } int operator"" _udl(); // { dg-error "5:literal operator template .int operator\"\"_udl\\(\\). has invalid parameter list" } -- 2.30.2