diff options
-rw-r--r-- | gcc/cp/constraint.cc | 10 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 7 | ||||
-rw-r--r-- | gcc/cp/mangle.cc | 369 | ||||
-rw-r--r-- | gcc/cp/pt.cc | 4 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/mangle-concepts1.C | 88 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/mangle-ttp1.C | 27 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/mangle10.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/abi/mangle52.C | 2 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/class-deduction-alias3.C | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp2a/class-deduction-alias8.C | 5 | ||||
-rw-r--r-- | include/demangle.h | 2 | ||||
-rw-r--r-- | libiberty/cp-demangle.c | 88 | ||||
-rw-r--r-- | libiberty/testsuite/demangle-expected | 8 | ||||
-rw-r--r-- | libstdc++-v3/include/std/bit | 2 | ||||
-rw-r--r-- | libstdc++-v3/include/std/variant | 4 |
15 files changed, 551 insertions, 72 deletions
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 64b64e1..d9972d6 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -240,7 +240,9 @@ combine_constraint_expressions (tree lhs, tree rhs) return rhs; if (!rhs) return lhs; - return finish_constraint_and_expr (input_location, lhs, rhs); + /* Use UNKNOWN_LOCATION so write_template_args can tell the difference + between this and a && the user wrote. */ + return finish_constraint_and_expr (UNKNOWN_LOCATION, lhs, rhs); } /* Extract the template-id from a concept check. For standard and variable @@ -1605,9 +1607,11 @@ finish_shorthand_constraint (tree decl, tree constr) check = ovl_make (tmpl); check = build_concept_check (check, arg, args, tf_warning_or_error); - /* Make the check a fold-expression if needed. */ + /* Make the check a fold-expression if needed. + Use UNKNOWN_LOCATION so write_template_args can tell the + difference between this and a fold the user wrote. */ if (apply_to_each_p && declared_pack_p) - check = finish_left_unary_fold_expr (DECL_SOURCE_LOCATION (decl), + check = finish_left_unary_fold_expr (UNKNOWN_LOCATION, check, TRUTH_ANDIF_EXPR); return check; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8809842..b9adc17 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -3799,6 +3799,12 @@ struct GTY(()) lang_decl { : TREE_VEC_LENGTH (INNERMOST_TEMPLATE_ARGS (NODE)) #endif +/* True iff NODE represents the template args for a type-constraint, + in which case the first one represents the constrained type. + Currently only set during mangling. */ +#define TEMPLATE_ARGS_TYPE_CONSTRAINT_P(NODE) \ + TREE_PRIVATE (TREE_VEC_CHECK (NODE)) + /* The list of access checks that were deferred during parsing which need to be performed at template instantiation time. @@ -8509,6 +8515,7 @@ struct processing_constraint_expression_sentinel extern bool processing_constraint_expression_p (); extern tree unpack_concept_check (tree); +extern tree get_concept_check_template (tree); extern tree evaluate_concept_check (tree); extern bool constraints_satisfied_p (tree, tree = NULL_TREE); extern bool* lookup_subsumption_result (tree, tree); diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc index 5137305..8a44b11 100644 --- a/gcc/cp/mangle.cc +++ b/gcc/cp/mangle.cc @@ -221,7 +221,7 @@ static void write_function_type (const tree); static void write_bare_function_type (const tree, const int, const tree); static void write_method_parms (tree, const int, const tree); static void write_class_enum_type (const tree); -static void write_template_args (tree); +static void write_template_args (tree, tree = NULL_TREE); static void write_expression (tree); static void write_template_arg_literal (const tree); static void write_template_arg (tree); @@ -842,6 +842,70 @@ mangle_return_type_p (tree decl) && maybe_template_info (decl)); } +/* <constraint-expression> ::= <expression> */ + +static void +write_constraint_expression (tree expr) +{ + write_expression (expr); +} + +/* Mangle a requires-clause following a template-head, if any. + + Q <constraint_expression> E */ + +static void +write_tparms_constraints (tree constraints) +{ + /* In a declaration with shorthand constraints in the template-head, followed + by a requires-clause, followed by shorthand constraints in the + function-parameter-list, the full constraints will be some && with the + parameter constraints on the RHS, around an && with the requires-clause on + the RHS. Find the requires-clause, if any. + + This logic relies on the && and ... from combine_constraint_expressions, + finish_shorthand_constraint, and convert_generic_types_to_packs having + UNKNOWN_LOCATION. If they need to have an actual location, we could move + to using a TREE_LANG_FLAG. */ + if (constraints && abi_check (19)) + { + tree probe = constraints; + while (probe + && !EXPR_LOCATION (probe) + && TREE_CODE (probe) == TRUTH_ANDIF_EXPR) + { + tree op1 = TREE_OPERAND (probe, 1); + probe = (EXPR_LOCATION (op1) ? op1 + : TREE_OPERAND (probe, 0)); + } + if (probe && EXPR_LOCATION (probe)) + { + write_char ('Q'); + write_constraint_expression (probe); + } + } +} + +/* <type-constraint> ::= <name> */ + +static void +write_type_constraint (tree cnst) +{ + if (!cnst) return; + + cnst = unpack_concept_check (cnst); + gcc_checking_assert (TREE_CODE (cnst) == TEMPLATE_ID_EXPR); + + tree concept_decl = get_concept_check_template (cnst); + write_name (concept_decl, 0); + tree args = TREE_OPERAND (cnst, 1); + if (TREE_VEC_LENGTH (args) > 1) + { + TEMPLATE_ARGS_TYPE_CONSTRAINT_P (args) = true; + write_template_args (args); + } +} + /* <encoding> ::= <function name> <bare-function-type> ::= <data name> */ @@ -886,6 +950,14 @@ write_encoding (const tree decl) mangle_return_type_p (decl), d); + if (tree c = get_trailing_function_requirements (decl)) + if (abi_check (19)) + { + ++G.parm_depth; + write_char ('Q'); + write_constraint_expression (c); + --G.parm_depth; + } } } @@ -1037,7 +1109,13 @@ write_name (tree decl, const int ignore_local_scope) { /* Yes: use <unscoped-template-name>. */ write_unscoped_template_name (TI_TEMPLATE (info)); - write_template_args (TI_ARGS (info)); + /* Pass down the parms of a function template in case we need to + mangle them; we don't mangle the parms of a non-overloadable + template. */ + tree parms = (TREE_CODE (decl) == FUNCTION_DECL + ? DECL_TEMPLATE_PARMS (TI_TEMPLATE (info)) + : NULL_TREE); + write_template_args (TI_ARGS (info), parms); } else /* Everything else gets an <unqualified-name>. */ @@ -1722,10 +1800,136 @@ write_unnamed_type_name (const tree type) write_compact_number (discriminator); } +/* ABI issue #47: if a function template parameter is not "natural" for its + argument we must mangle the parameter. */ + +static bool +template_parm_natural_p (tree arg, tree parm) +{ + tree decl = TREE_VALUE (parm); + + /* A template parameter is "natural" if: */ + + if (template_parameter_pack_p (decl)) + { + tree args = ARGUMENT_PACK_ARGS (arg); + if (TREE_VEC_LENGTH (args) == 0) + { +#if 0 + /* the argument is an empty pack and the parameter is an + unconstrained template type parameter pack; */ + if (TREE_CODE (decl) != TYPE_DECL) + return false; +#else + /* Defer changing the mangling of C++11 code like + template <int i> int max(); + template <int i, int j, int... rest> int max(); */ + return true; +#endif + } + else + /* the argument is a non-empty pack and a non-pack variant of the + parameter would be natural for the first element of the pack; */ + arg = TREE_VEC_ELT (args, 0); + } + + /* the argument is a template and the parameter has the exact + same template head; */ + if (TREE_CODE (decl) == TEMPLATE_DECL) + return template_heads_equivalent_p (arg, decl); + + /* the argument is a type and the parameter is unconstrained; or */ + else if (TREE_CODE (decl) == TYPE_DECL) + return !TEMPLATE_PARM_CONSTRAINTS (parm); + + /* the argument is a non-type template argument and the declared parameter + type neither is instantiation dependent nor contains deduced types. */ + else if (TREE_CODE (decl) == PARM_DECL) + { +#if 0 + return !uses_template_parms (TREE_TYPE (decl)); +#else + /* Defer changing the mangling of C++98 code like + template <class T, T V> .... */ + return !type_uses_auto (TREE_TYPE (decl)); +#endif + } + + gcc_unreachable (); +} + +/* Used for lambda template head and non-natural function template parameters. + + <template-param-decl> ::= Ty # template type parameter + ::= Tk <type-constraint> # constrained type parameter + ::= Tn <type> # template non-type parameter + ::= Tt <template-param-decl>* [Q <constraint-expression] E # ttp + ::= Tp <non-pack template-param-decl> # template parameter pack */ + +static void +write_template_param_decl (tree parm) +{ + tree decl = TREE_VALUE (parm); + + if (template_parameter_pack_p (decl)) + write_string ("Tp"); + + switch (TREE_CODE (decl)) + { + case PARM_DECL: + { + write_string ("Tn"); + + tree type = TREE_TYPE (decl); + if (tree c = (is_auto (type) + ? PLACEHOLDER_TYPE_CONSTRAINTS (type) + : NULL_TREE)) + { + if (AUTO_IS_DECLTYPE (type)) + write_string ("DK"); + else + write_string ("Dk"); + write_type_constraint (c); + } + else + write_type (type); + } + break; + + case TEMPLATE_DECL: + { + write_string ("Tt"); + tree parms = DECL_INNERMOST_TEMPLATE_PARMS (decl); + for (tree node : tree_vec_range (parms)) + write_template_param_decl (node); + write_char ('E'); + } + break; + + case TYPE_DECL: + if (tree c = TEMPLATE_PARM_CONSTRAINTS (parm)) + { + if (TREE_CODE (c) == UNARY_LEFT_FOLD_EXPR) + { + c = FOLD_EXPR_PACK (c); + c = PACK_EXPANSION_PATTERN (c); + } + if (TREE_CODE (decl) == TYPE_DECL) + { + write_string ("Tk"); + write_type_constraint (c); + } + } + else + write_string ("Ty"); + break; + + default: + gcc_unreachable (); + } +} + // A template head, for templated lambdas. -// <template-head> ::= Tp* Ty -// Tp* Tn <type> -// Tp* Tt <template-head> E // New in ABI=18. Returns true iff we emitted anything -- used for ABI // version warning. @@ -1735,50 +1939,26 @@ write_closure_template_head (tree tmpl) bool any = false; // We only need one level of template parms - tree inner = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl)); + tree parms = DECL_TEMPLATE_PARMS (tmpl); + tree inner = INNERMOST_TEMPLATE_PARMS (parms); for (int ix = 0, len = TREE_VEC_LENGTH (inner); ix != len; ix++) { tree parm = TREE_VEC_ELT (inner, ix); if (parm == error_mark_node) continue; - parm = TREE_VALUE (parm); - if (DECL_IMPLICIT_TEMPLATE_PARM_P (parm)) + if (DECL_IMPLICIT_TEMPLATE_PARM_P (TREE_VALUE (parm))) // A synthetic parm, we're done. break; any = true; if (abi_version_at_least (18)) - { - if (TREE_CODE (parm) == PARM_DECL - ? TEMPLATE_PARM_PARAMETER_PACK (DECL_INITIAL (parm)) - : TEMPLATE_TYPE_PARAMETER_PACK (TREE_TYPE (parm))) - write_string ("Tp"); - - switch (TREE_CODE (parm)) - { - default: - gcc_unreachable (); - - case TYPE_DECL: - write_string ("Ty"); - break; - - case PARM_DECL: - write_string ("Tn"); - write_type (TREE_TYPE (parm)); - break; - - case TEMPLATE_DECL: - write_string ("Tt"); - write_closure_template_head (parm); - write_string ("E"); - break; - } - } + write_template_param_decl (parm); } + write_tparms_constraints (TEMPLATE_PARMS_CONSTRAINTS (parms)); + return any; } @@ -2893,13 +3073,84 @@ write_class_enum_type (const tree type) write_name (TYPE_NAME (type), /*ignore_local_scope=*/0); } +/* Mangle a requirement REQ in a requires-expression. */ + +static void +write_requirement (tree req) +{ + tree op = TREE_OPERAND (req, 0); + + switch (tree_code code = TREE_CODE (req)) + { + /* # simple-requirement or compound-requirement + <requirement> ::= X <expression> [ N ] [ R <type-constraint> ] */ + case SIMPLE_REQ: + case COMPOUND_REQ: + write_char ('X'); + write_expression (op); + if (code == SIMPLE_REQ) + break; + if (COMPOUND_REQ_NOEXCEPT_P (req)) + write_char ('N'); + if (tree constr = TREE_OPERAND (req, 1)) + { + write_char ('R'); + write_type_constraint (PLACEHOLDER_TYPE_CONSTRAINTS (constr)); + } + break; + + /* <requirement> ::= T <type> # type-requirement */ + case TYPE_REQ: + write_char ('T'); + write_type (op); + break; + + /* <requirement> ::= Q <constraint-expression> # nested-requirement */ + case NESTED_REQ: + write_char ('Q'); + write_constraint_expression (op); + break; + + default: + gcc_unreachable (); + } +} + +/* # requires { ... } + <expression> ::= rq <requirement>+ E + # requires (...) { ... } + <expression> ::= rQ <bare-function-type> _ <requirement>+ E */ + +static void +write_requires_expr (tree expr) +{ + tree parms = REQUIRES_EXPR_PARMS (expr); + if (parms) + { + write_string ("rQ"); + ++G.parm_depth; + for (; parms; parms = DECL_CHAIN (parms)) + write_type (cv_unqualified (TREE_TYPE (parms))); + --G.parm_depth; + write_char ('_'); + } + else + write_string ("rq"); + + for (tree reqs = REQUIRES_EXPR_REQS (expr); reqs; + reqs = TREE_CHAIN (reqs)) + write_requirement (TREE_VALUE (reqs)); + + write_char ('E'); +} + /* Non-terminal <template-args>. ARGS is a TREE_VEC of template arguments. - <template-args> ::= I <template-arg>* E */ + <template-args> ::= I <template-arg>* [Q <constraint-expr>] E */ static void -write_template_args (tree args) +write_template_args (tree args, tree parms /*= NULL_TREE*/) { int i; int length = 0; @@ -2911,6 +3162,13 @@ write_template_args (tree args) if (args) length = TREE_VEC_LENGTH (args); + tree constraints = NULL_TREE; + if (parms) + { + constraints = TEMPLATE_PARMS_CONSTRAINTS (parms); + parms = INNERMOST_TEMPLATE_PARMS (parms); + } + if (args && length && TREE_CODE (TREE_VEC_ELT (args, 0)) == TREE_VEC) { /* We have nested template args. We want the innermost template @@ -2918,8 +3176,38 @@ write_template_args (tree args) args = TREE_VEC_ELT (args, length - 1); length = TREE_VEC_LENGTH (args); } - for (i = 0; i < length; ++i) - write_template_arg (TREE_VEC_ELT (args, i)); + if (TEMPLATE_ARGS_TYPE_CONSTRAINT_P (args)) + /* Skip the constrained type. */ + i = 1; + else + i = 0; + bool implicit_parm_scope = false; + for (; i < length; ++i) + { + tree arg = TREE_VEC_ELT (args, i); + if (parms) + { + tree parm = TREE_VEC_ELT (parms, i); + tree decl = TREE_VALUE (parm); + if (DECL_IMPLICIT_TEMPLATE_PARM_P (decl) + && !implicit_parm_scope) + { + /* The rest of the template parameters are based on generic + function parameters, so any expressions in their + type-constraints are in parameter scope. */ + implicit_parm_scope = true; + ++G.parm_depth; + } + if (!template_parm_natural_p (arg, parm) + && abi_check (19)) + write_template_param_decl (parm); + } + write_template_arg (arg); + } + if (implicit_parm_scope) + --G.parm_depth; + + write_tparms_constraints (constraints); write_char ('E'); } @@ -3107,6 +3395,7 @@ write_expression (tree expr) write_char ('f'); if (delta != 0) { + gcc_checking_assert (delta > 0); if (abi_check (5)) { /* Let L be the number of function prototype scopes from the @@ -3431,6 +3720,8 @@ write_expression (tree expr) write_type (LAMBDA_EXPR_CLOSURE (expr)); write_char ('E'); } + else if (code == REQUIRES_EXPR) + write_requires_expr (expr); else if (dependent_name (expr)) { tree name = dependent_name (expr); diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc index c54b256..d12d576 100644 --- a/gcc/cp/pt.cc +++ b/gcc/cp/pt.cc @@ -30951,7 +30951,9 @@ convert_generic_types_to_packs (tree parm, int start_idx, int end_idx) { tree id = unpack_concept_check (constr); TREE_VEC_ELT (TREE_OPERAND (id, 1), 0) = t; - location_t loc = DECL_SOURCE_LOCATION (TYPE_NAME (t)); + /* Use UNKNOWN_LOCATION so write_template_args can tell the + difference between this and a fold the user wrote. */ + location_t loc = UNKNOWN_LOCATION; tree fold = finish_left_unary_fold_expr (loc, constr, TRUTH_ANDIF_EXPR); TEMPLATE_PARM_CONSTRAINTS (node) = fold; diff --git a/gcc/testsuite/g++.dg/abi/mangle-concepts1.C b/gcc/testsuite/g++.dg/abi/mangle-concepts1.C new file mode 100644 index 0000000..eac520c --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle-concepts1.C @@ -0,0 +1,88 @@ +// { dg-do compile { target c++20 } } + +template <class T> concept C = true; +template <class T, class U> concept C2 = true; +template <class T> concept D = true; +template <class T> concept E = true; +template <class T> concept F = true; +template <class T> using Ref = T&; + +// { dg-final { scan-assembler "_Z1fIiQ1CIT_EEvv" } } +template <class T> requires C<T> void f() {} +template void f<int>(); + +// { dg-final { scan-assembler "_Z2f2ITk1CiEvv" } } +template <C T> void f2() {} +template void f2<int>(); + +// { dg-final { scan-assembler "_Z2f3IiEvvQ1CIT_E" } } +template <class T> void f3() requires C<T> {} +template void f3<int>(); + +// { dg-final { scan-assembler "_Z2f4ITk1CiEvT_" } } +void f4(C auto c) {} +template void f4(int); + +// ??? The constraints end up out of order in the mangled name, may +// need to change the equivalence rule. +// { dg-final { scan-assembler "_Z2f5ITk1CicTk1EfTk1FsQ1DIT0_EEvT1_T2_" } } +template <C T, class U> requires D<U> void f5(E auto c, F auto f) {} +template void f5<int,char>(float,short); + +// { dg-final { scan-assembler "_Z2f6ITk2C2IiEsEvv" } } +template <C2<int> T> void f6() {} +template void f6<short>(); + +// { dg-final { scan-assembler "_ZN1AIiE1fEvQ1CIT_E" } } +template <class T> struct A { + void f() requires C<T> { }; +}; +template struct A<int>; + +// { dg-final { scan-assembler "_Z1gIiQrqXcvT__ETRS0_Q1CIS0_EXpscvS0__ENR1CEEvv" } } +template <class T> +requires requires { T(); + typename Ref<T>; + requires C<T>; + { +T() } noexcept -> C; +} +void g() {} +template void g<int>(); + +// { dg-final { scan-assembler "_Z1hIiQrQT__Xpsfp_EEvv" } } +template <class T> +requires requires (T t) { +t; } +void h() {} +template void h<int>(); + +// { dg-final { scan-assembler "_Z3fn1IiEvT_QrQS0__XpsfL0p_Xpsfp_E" } } +template <class T> +void fn1(T t1) + requires requires (T t2) { +t1; +t2; } +{} +template void fn1<int>(int); + +// { dg-final { scan-assembler "_Z3fn3IiTk2C2IDtfL0p_EEiEvT_T0_" } } +template<typename T> void fn3(T t, C2<decltype(t)> auto) {} +template void fn3(int, int); + +// { dg-final { scan-assembler "_Z3fn4IiiEvT_T0_Q2C2IS1_FDTcl3fn3fL0p_fp_EES0_EE" } } +template<typename T, typename U> void fn4(T t, U u) + requires C2<U, auto (T u) -> decltype(fn3(t, u))> {} +template void fn4(int, int); + +// { dg-final { scan-assembler "_Z3fn5ITpTk1CJicfEEvDpT_" } } +template<C... T> void fn5(T...) { } +template void fn5(int,char,float); + +// { dg-final { scan-assembler "_ZN2A2IiE1BIiE1fIiiEEvvQ2C2IT_TL1_0_E" } } +template <class T> struct A2 { + template <class X> struct B { + template <class U, class V> void f() requires C2<T,V> {} + }; +}; +template void A2<int>::B<int>::f<int,int>(); + +template<C auto N> void f7() {} +// { dg-final { scan-assembler "_Z2f7ITnDk1CLi5EEvv" } } +template void f7<5>(); diff --git a/gcc/testsuite/g++.dg/abi/mangle-ttp1.C b/gcc/testsuite/g++.dg/abi/mangle-ttp1.C new file mode 100644 index 0000000..2f5878f --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/mangle-ttp1.C @@ -0,0 +1,27 @@ +// ABI #47 "natural" template parameter mangling +// { dg-do compile { target c++17 } } + +template <template <class...> class TT> class A { }; +template <int... T> class B { }; + +template <auto... T> +void f(B<T...> b); + +template <template <auto...> class TT> +void g(TT<42>); + +template <template <int...> class TT> +void h(TT<42>); + +template <class T> struct C { + template <template <T...> class TT> static void j(TT<42>); +}; + +int main() +{ + B<42> b; + f(b); // { dg-final { scan-assembler "_Z1fITpTnDaJLi42EEEv1BIJXspT_EEE" } } + g(b); // { dg-final { scan-assembler "_Z1gITtTpTnDaE1BEvT_IJLi42EEE" } } + h(b); // { dg-final { scan-assembler "_Z1hI1BEvT_IJLi42EEE" } } + C<int>::j(b); // { dg-final { scan-assembler "_ZN1CIiE1jI1BEEvT_IJLi42EEE" } } +} diff --git a/gcc/testsuite/g++.dg/abi/mangle10.C b/gcc/testsuite/g++.dg/abi/mangle10.C index d5782ba..fcbb815 100644 --- a/gcc/testsuite/g++.dg/abi/mangle10.C +++ b/gcc/testsuite/g++.dg/abi/mangle10.C @@ -1,4 +1,4 @@ -// { dg-options "-fabi-version=0" } +// { dg-options "-fabi-version=0 -fabi-compat-version=0" } template <template <typename> class Q> void f (typename Q<int>::X) {} diff --git a/gcc/testsuite/g++.dg/abi/mangle52.C b/gcc/testsuite/g++.dg/abi/mangle52.C index 0b9a72f..1e7eca0 100644 --- a/gcc/testsuite/g++.dg/abi/mangle52.C +++ b/gcc/testsuite/g++.dg/abi/mangle52.C @@ -1,4 +1,4 @@ -// { dg-options "-fabi-version=0 -Wabi=2" } +// { dg-options "-fabi-version=18 -Wabi=2" } template <unsigned int> struct helper {}; // { dg-final { scan-assembler "\n_?_Z6check1IiEvP6helperIXszscT_Li1EEE\[: \t\n\]" } } diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias3.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias3.C index 318d4c9..b43a8c8 100644 --- a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias3.C +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias3.C @@ -1,8 +1,11 @@ // PR c++/95486 // { dg-do compile { target c++20 } } +template <class T> +concept Int = __is_same (T, int); + template<class T, class U> -struct X { X(U) requires __is_same(U, int) {} }; +struct X { X(U) requires Int<U> {} }; template<class U> using Y = X<void, U>; diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias8.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias8.C index ec005956..9de0a72 100644 --- a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias8.C +++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias8.C @@ -1,8 +1,11 @@ // PR c++/95486 // { dg-do compile { target c++20 } } +template <class T> +concept Int = __is_same (T, int); + template<class T, class U> -struct X { X(U) requires __is_same(U, int) {} }; +struct X { X(U) requires Int<U> {} }; template<class U> X(U) -> X<char, U>; diff --git a/include/demangle.h b/include/demangle.h index f062d77..0d3e2bd 100644 --- a/include/demangle.h +++ b/include/demangle.h @@ -466,6 +466,8 @@ enum demangle_component_type DEMANGLE_COMPONENT_TEMPLATE_TEMPLATE_PARM, DEMANGLE_COMPONENT_TEMPLATE_PACK_PARM, + DEMANGLE_COMPONENT_CONSTRAINTS, + /* A builtin type with argument. This holds the builtin type information. */ DEMANGLE_COMPONENT_EXTENDED_BUILTIN_TYPE diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c index 2ce984f..151f2eb 100644 --- a/libiberty/cp-demangle.c +++ b/libiberty/cp-demangle.c @@ -993,6 +993,7 @@ d_make_comp (struct d_info *di, enum demangle_component_type type, case DEMANGLE_COMPONENT_VECTOR_TYPE: case DEMANGLE_COMPONENT_CLONE: case DEMANGLE_COMPONENT_MODULE_ENTITY: + case DEMANGLE_COMPONENT_CONSTRAINTS: if (left == NULL || right == NULL) return NULL; break; @@ -1345,6 +1346,22 @@ is_ctor_dtor_or_conversion (struct demangle_component *dc) } } +/* [ Q <constraint-expression> ] */ + +static struct demangle_component * +d_maybe_constraints (struct d_info *di, struct demangle_component *dc) +{ + if (d_peek_char (di) == 'Q') + { + d_advance (di, 1); + struct demangle_component *expr = d_expression (di); + if (expr == NULL) + return NULL; + dc = d_make_comp (di, DEMANGLE_COMPONENT_CONSTRAINTS, dc, expr); + } + return dc; +} + /* <encoding> ::= <(function) name> <bare-function-type> ::= <(data) name> ::= <special-name> @@ -1398,21 +1415,21 @@ d_encoding (struct d_info *di, int top_level) struct demangle_component *ftype; ftype = d_bare_function_type (di, has_return_type (dc)); - if (ftype) - { - /* If this is a non-top-level local-name, clear the - return type, so it doesn't confuse the user by - being confused with the return type of whaever - this is nested within. */ - if (!top_level && dc->type == DEMANGLE_COMPONENT_LOCAL_NAME - && ftype->type == DEMANGLE_COMPONENT_FUNCTION_TYPE) - d_left (ftype) = NULL; - - dc = d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME, - dc, ftype); - } - else - dc = NULL; + if (!ftype) + return NULL; + + /* If this is a non-top-level local-name, clear the + return type, so it doesn't confuse the user by + being confused with the return type of whaever + this is nested within. */ + if (!top_level && dc->type == DEMANGLE_COMPONENT_LOCAL_NAME + && ftype->type == DEMANGLE_COMPONENT_FUNCTION_TYPE) + d_left (ftype) = NULL; + + ftype = d_maybe_constraints (di, ftype); + + dc = d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME, + dc, ftype); } } } @@ -3023,7 +3040,7 @@ d_parmlist (struct d_info *di) struct demangle_component *type; char peek = d_peek_char (di); - if (peek == '\0' || peek == 'E' || peek == '.') + if (peek == '\0' || peek == 'E' || peek == '.' || peek == 'Q') break; if ((peek == 'R' || peek == 'O') && d_peek_next_char (di) == 'E') @@ -3259,7 +3276,7 @@ d_template_args (struct d_info *di) return d_template_args_1 (di); } -/* <template-arg>* E */ +/* <template-arg>* [Q <constraint-expression>] E */ static struct demangle_component * d_template_args_1 (struct d_info *di) @@ -3295,13 +3312,17 @@ d_template_args_1 (struct d_info *di) return NULL; pal = &d_right (*pal); - if (d_peek_char (di) == 'E') - { - d_advance (di, 1); - break; - } + char peek = d_peek_char (di); + if (peek == 'E' || peek == 'Q') + break; } + al = d_maybe_constraints (di, al); + + if (d_peek_char (di) != 'E') + return NULL; + d_advance (di, 1); + di->last_name = hold_last_name; return al; @@ -4442,6 +4463,7 @@ d_count_templates_scopes (struct d_print_info *dpi, case DEMANGLE_COMPONENT_PACK_EXPANSION: case DEMANGLE_COMPONENT_TAGGED_NAME: case DEMANGLE_COMPONENT_CLONE: + case DEMANGLE_COMPONENT_CONSTRAINTS: recurse_left_right: /* PR 89394 - Check for too much recursion. */ if (dpi->recursion > DEMANGLE_RECURSION_LIMIT) @@ -5201,6 +5223,22 @@ d_print_comp_inner (struct d_print_info *dpi, int options, dpt.next = dpi->templates; dpi->templates = &dpt; dpt.template_decl = typed_name; + + /* Constraints are mangled as part of the template argument list, + so they wrap the _TEMPLATE_ARGLIST. But + d_lookup_template_argument expects the RHS of _TEMPLATE to be + the _ARGLIST, and constraints need to refer to these args. So + move the _CONSTRAINTS out of the _TEMPLATE and onto the type. + This will result in them being printed after the () like a + trailing requires-clause, but that seems like our best option + given that we aren't printing a template-head. */ + struct demangle_component *tnr = d_right (typed_name); + if (tnr->type == DEMANGLE_COMPONENT_CONSTRAINTS) + { + d_right (typed_name) = d_left (tnr); + d_left (tnr) = d_right (dc); + d_right (dc) = tnr; + } } d_print_comp (dpi, options, d_right (dc)); @@ -6248,6 +6286,12 @@ d_print_comp_inner (struct d_print_info *dpi, int options, d_append_string (dpi, "..."); return; + case DEMANGLE_COMPONENT_CONSTRAINTS: + d_print_comp (dpi, options, d_left (dc)); + d_append_string (dpi, " requires "); + d_print_comp (dpi, options, d_right (dc)); + return; + default: d_print_error (dpi); return; diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected index 01ca222..0997e96 100644 --- a/libiberty/testsuite/demangle-expected +++ b/libiberty/testsuite/demangle-expected @@ -1692,3 +1692,11 @@ X<float>::operator Z<int><int>()::y _ZN1SILi1EEF3barIiEEiR4Base int S<1>::bar[friend]<int>(Base&) + +# requires on template-head +_Z1fIiQ1CIT_EEvv +void f<int>() requires C<int> + +# requires after () +_Z1fIiEvvQ1CIT_E +void f<int>() requires C<int> diff --git a/libstdc++-v3/include/std/bit b/libstdc++-v3/include/std/bit index dce61b4..07b8988 100644 --- a/libstdc++-v3/include/std/bit +++ b/libstdc++-v3/include/std/bit @@ -88,7 +88,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION bit_cast(const _From& __from) noexcept #ifdef __cpp_concepts requires (sizeof(_To) == sizeof(_From)) - && __is_trivially_copyable(_To) && __is_trivially_copyable(_From) + && is_trivially_copyable_v<_To> && is_trivially_copyable_v<_From> #endif { return __builtin_bit_cast(_To, __from); diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant index 36bb37c..e31b6e9 100644 --- a/libstdc++-v3/include/std/variant +++ b/libstdc++-v3/include/std/variant @@ -427,8 +427,8 @@ namespace __variant ~_Variadic_union() = default; constexpr ~_Variadic_union() - requires (!__has_trivial_destructor(_First)) - || (!__has_trivial_destructor(_Variadic_union<_Rest...>)) + requires (!is_trivially_destructible_v<_First>) + || (!is_trivially_destructible_v<_Variadic_union<_Rest...>>) { } #endif |