diff options
author | Patrick Palka <ppalka@redhat.com> | 2021-03-02 07:38:37 -0500 |
---|---|---|
committer | Patrick Palka <ppalka@redhat.com> | 2021-03-02 07:38:37 -0500 |
commit | 04b10596fe2fec1aa6652c15fd389087a78a235f (patch) | |
tree | 9775aca8f0ee0e9d720a87764802a3314f3c9eda /gcc | |
parent | d6378b9785b856785d6649d0f769a25b8bb47c9b (diff) | |
download | gcc-04b10596fe2fec1aa6652c15fd389087a78a235f.zip gcc-04b10596fe2fec1aa6652c15fd389087a78a235f.tar.gz gcc-04b10596fe2fec1aa6652c15fd389087a78a235f.tar.bz2 |
c++: Some preparatory type canonicalization fixes
The patches that follow revealed some latent type canonicalization
issues during normalization/satisfaction, due to normalization of
some constraint-expressions now being performed in different contexts
and more frequently (since the normalization caches get frequently
emptied in a checking compiler). The issues are:
1. In tsubst_parameter_mapping, we canonicalize the arguments of a
substituted TYPE_ARGUMENT_PACK only if the argument we started with
wasn't a TYPE_ARGUMENT_PACK. We should canonicalize a substituted
TYPE_ARGUMENT_PACK regardless of what we started with.
2. We currently set DECL_CONTEXT and CONSTRAINT_VAR_P on each of the
parameters introduced in a requires expression _after_ we're done
processing the requirements. But meanwhile we may have already
built and computed the canonical form of a type that uses one of
these PARM_DECLs (as say an operand to decltype). But the canonical
form depends on the result of cp_tree_equal, which in turn depends on
the value of CONSTRAINT_VAR_P and DECL_CONTEXT. So we must set these
fields earlier, before processing requirements.
3. In do_auto_deduction, we use the result of finish_decltype_type later
as a template argument, so we should canonicalize the result too.
(While we're here, we should pass 'complain' to finish_decltype_type,
which fixes the testcase auto1.C below.)
gcc/cp/ChangeLog:
* constraint.cc (tsubst_parameter_mapping): Canonicalize the
arguments of a substituted TYPE_ARGUMENT_PACK even if we've
started with a TYPE_ARGUMENT_PACK.
(finish_requires_expr): Don't set DECL_CONTEXT and
CONSTRAINT_VAR_P on each of the introduced parameters here.
* parser.c (cp_parser_requirement_parameter_list): Instead set
these fields earlier, here.
* pt.c (do_auto_deduction): Canonicalize the result of
do_auto_deduction. Pass 'complain' to finish_decltype_type.
gcc/testsuite/ChangeLog:
* g++.dg/cpp1z/auto1.C: New test.
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/constraint.cc | 25 | ||||
-rw-r--r-- | gcc/cp/parser.c | 12 | ||||
-rw-r--r-- | gcc/cp/pt.c | 8 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/cpp1z/auto1.C | 13 |
4 files changed, 39 insertions, 19 deletions
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc index 3e599fe..39c9798 100644 --- a/gcc/cp/constraint.cc +++ b/gcc/cp/constraint.cc @@ -2319,15 +2319,15 @@ tsubst_parameter_mapping (tree map, tree args, subst_info info) new_arg = tsubst_template_arg (arg, args, complain, in_decl); if (TYPE_P (new_arg)) new_arg = canonicalize_type_argument (new_arg, complain); - if (TREE_CODE (new_arg) == TYPE_ARGUMENT_PACK) + } + if (TREE_CODE (new_arg) == TYPE_ARGUMENT_PACK) + { + tree pack_args = ARGUMENT_PACK_ARGS (new_arg); + for (int i = 0; i < TREE_VEC_LENGTH (pack_args); i++) { - tree pack_args = ARGUMENT_PACK_ARGS (new_arg); - for (int i = 0; i < TREE_VEC_LENGTH (pack_args); i++) - { - tree& pack_arg = TREE_VEC_ELT (pack_args, i); - if (TYPE_P (pack_arg)) - pack_arg = canonicalize_type_argument (pack_arg, complain); - } + tree& pack_arg = TREE_VEC_ELT (pack_args, i); + if (TYPE_P (pack_arg)) + pack_arg = canonicalize_type_argument (pack_arg, complain); } } if (new_arg == error_mark_node) @@ -3253,15 +3253,6 @@ evaluate_concept_check (tree check, tsubst_flags_t complain) tree finish_requires_expr (location_t loc, tree parms, tree reqs) { - /* Modify the declared parameters by removing their context - so they don't refer to the enclosing scope and explicitly - indicating that they are constraint variables. */ - for (tree parm = parms; parm; parm = DECL_CHAIN (parm)) - { - DECL_CONTEXT (parm) = NULL_TREE; - CONSTRAINT_VAR_P (parm) = true; - } - /* Build the node. */ tree r = build_min (REQUIRES_EXPR, boolean_type_node, parms, reqs, NULL_TREE); TREE_SIDE_EFFECTS (r) = false; diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index bb1499a..92de144 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -28817,6 +28817,18 @@ cp_parser_requirement_parameter_list (cp_parser *parser) if (!parens.require_close (parser)) return error_mark_node; + /* Modify the declared parameters by removing their context + so they don't refer to the enclosing scope and explicitly + indicating that they are constraint variables. */ + for (tree parm = parms; parm; parm = TREE_CHAIN (parm)) + { + if (parm == void_list_node || parm == explicit_void_list_node) + break; + tree decl = TREE_VALUE (parm); + DECL_CONTEXT (decl) = NULL_TREE; + CONSTRAINT_VAR_P (decl) = true; + } + return parms; } diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 6a2c4f3..f324f6a 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -29517,9 +29517,13 @@ do_auto_deduction (tree type, tree init, tree auto_node, || ((TREE_CODE (init) == COMPONENT_REF || TREE_CODE (init) == SCOPE_REF) && !REF_PARENTHESIZED_P (init))); + tree deduced = finish_decltype_type (init, id, complain); + deduced = canonicalize_type_argument (deduced, complain); + if (deduced == error_mark_node) + return error_mark_node; targs = make_tree_vec (1); - TREE_VEC_ELT (targs, 0) - = finish_decltype_type (init, id, tf_warning_or_error); + TREE_VEC_ELT (targs, 0) = deduced; + /* FIXME: These errors ought to be diagnosed at parse time. */ if (type != auto_node) { if (complain & tf_error) diff --git a/gcc/testsuite/g++.dg/cpp1z/auto1.C b/gcc/testsuite/g++.dg/cpp1z/auto1.C new file mode 100644 index 0000000..5cc762a --- /dev/null +++ b/gcc/testsuite/g++.dg/cpp1z/auto1.C @@ -0,0 +1,13 @@ +// Verify that deduction failure of the decltype(auto) template parameter is +// a SFINAE error. +// { dg-do compile { target c++17 } } + +template <class> void f(); +template <class> void f(int); + +template <class T = int, decltype(auto) = &f<T>> void g(); +template <class = int> void g(); + +int main() { + g(); +} |