This patch implements C++20 class template argument deduction for alias
templates, which works by a moderately arcane transformation of the
deduction guides for the underlying class template. When implementing
it, I found that I could simplify the rules in the draft a bit and get
the same effect; I'll be emailing the committee to that effect soon.
While working on this I ran into various shortcomings in our handling of
constrained alias templates (like B in the testcase), and fixed those in
a separate patch.
Tested x86_64-pc-linux-gnu. I'm going to clean this up a bit more
before checking it in, but am sending this functional patch now before
the end of stage 1.
commit dfa6229b66fa6186e67e3602a89a02e4f2b7ad27
Author: Jason Merrill <ja...@redhat.com>
Date: Fri Nov 15 16:24:58 2019 -0500
Implement P1814R0, CTAD for alias templates.
* pt.c (rewrite_tparm_list): Factor out of build_deduction_guide.
(maybe_aggr_guide): Check for copy-init here.
(alias_ctad_tweaks): New.
(deduction_guides_for): Factor out of do_class_deduction.
(ctad_template_p): New.
* parser.c (cp_parser_simple_type_specifier): Use it.
* constraint.cc (append_constraint): New.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index 2a626d6d1ac..e943400d978 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -6820,6 +6820,7 @@ extern tree make_constrained_auto (tree, tree);
extern tree make_constrained_decltype_auto (tree, tree);
extern tree make_template_placeholder (tree);
extern bool template_placeholder_p (tree);
+extern bool ctad_template_p (tree);
extern tree do_auto_deduction (tree, tree, tree,
tsubst_flags_t
= tf_warning_or_error,
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index c973d487245..3fe17f4a6ee 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -1111,6 +1111,20 @@ build_constraints (tree tr, tree dr)
return (tree)ci;
}
+/* Add constraint RHS to the end of CONSTRAINT_INFO ci. */
+
+tree
+append_constraint (tree ci, tree rhs)
+{
+ tree dr = CI_DECLARATOR_REQS (ci);
+ dr = combine_constraint_expressions (dr, rhs);
+ CI_DECLARATOR_REQS (ci) = dr;
+ tree ac = CI_ASSOCIATED_CONSTRAINTS (ci);
+ ac = combine_constraint_expressions (ac, rhs);
+ CI_ASSOCIATED_CONSTRAINTS (ci) = ac;
+ return ci;
+}
+
/* A mapping from declarations to constraint information. */
static GTY ((cache)) tree_cache_map *decl_constraints;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index a80b4c818bb..a109fc17356 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -18072,8 +18072,7 @@ cp_parser_simple_type_specifier (cp_parser* parser,
/*ambiguous_decls=*/NULL,
token->location);
if (tmpl && tmpl != error_mark_node
- && (DECL_CLASS_TEMPLATE_P (tmpl)
- || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl)))
+ && ctad_template_p (tmpl))
type = make_template_placeholder (tmpl);
else if (flag_concepts && tmpl && concept_definition_p (tmpl))
type = cp_parser_placeholder_type_specifier (parser, loc,
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 08b4713035b..75832ceabab 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -27747,6 +27747,29 @@ rewrite_template_parm (tree olddecl, unsigned index, unsigned level,
return newdecl;
}
+/* As rewrite_template_parm, but for the whole TREE_LIST representing a
+ template parameter. */
+
+static tree
+rewrite_tparm_list (tree oldelt, unsigned index, unsigned level,
+ tree targs, unsigned targs_index, tsubst_flags_t complain)
+{
+ tree olddecl = TREE_VALUE (oldelt);
+ tree newdecl = rewrite_template_parm (olddecl, index, level,
+ targs, complain);
+ if (newdecl == error_mark_node)
+ return error_mark_node;
+ tree newdef = tsubst_template_arg (TREE_PURPOSE (oldelt),
+ targs, complain, NULL_TREE);
+ tree list = build_tree_list (newdef, newdecl);
+ TEMPLATE_PARM_CONSTRAINTS (list)
+ = tsubst_constraint_info (TEMPLATE_PARM_CONSTRAINTS (oldelt),
+ targs, complain, NULL_TREE);
+ int depth = TMPL_ARGS_DEPTH (targs);
+ TMPL_ARG (targs, depth, targs_index) = template_parm_to_arg (list);
+ return list;
+}
+
/* Returns a C++17 class deduction guide template based on the constructor
CTOR. As a special case, CTOR can be a RECORD_TYPE for an implicit default
guide, REFERENCE_TYPE for an implicit copy/move guide, or TREE_LIST for an
@@ -27860,19 +27883,12 @@ build_deduction_guide (tree type, tree ctor, tree outer_args, tsubst_flags_t com
unsigned index = i + clen;
unsigned level = 1;
tree oldelt = TREE_VEC_ELT (ftparms, i);
- tree olddecl = TREE_VALUE (oldelt);
- tree newdecl = rewrite_template_parm (olddecl, index, level,
- tsubst_args, complain);
- if (newdecl == error_mark_node)
+ tree newelt
+ = rewrite_tparm_list (oldelt, index, level,
+ tsubst_args, i, complain);
+ if (newelt == error_mark_node)
ok = false;
- tree newdef = tsubst_template_arg (TREE_PURPOSE (oldelt),
- tsubst_args, complain, ctor);
- tree list = build_tree_list (newdef, newdecl);
- TEMPLATE_PARM_CONSTRAINTS (list)
- = tsubst_constraint_info (TEMPLATE_PARM_CONSTRAINTS (oldelt),
- tsubst_args, complain, ctor);
- TREE_VEC_ELT (new_vec, index) = list;
- TMPL_ARG (tsubst_args, depth, i) = template_parm_to_arg (list);
+ TREE_VEC_ELT (new_vec, index) = newelt;
}
/* Now we have a final set of template parms to substitute into the
@@ -27947,20 +27963,48 @@ collect_ctor_idx_types (tree ctor, tree list)
return list;
}
+/* Return whether ETYPE is, or is derived from, a specialization of TMPL. */
+
+static bool
+is_spec_or_derived (tree etype, tree tmpl)
+{
+ if (!etype || !CLASS_TYPE_P (etype))
+ return false;
+
+ tree type = TREE_TYPE (tmpl);
+ tree tparms = (INNERMOST_TEMPLATE_PARMS
+ (DECL_TEMPLATE_PARMS (tmpl)));
+ tree targs = make_tree_vec (TREE_VEC_LENGTH (tparms));
+ int err = unify (tparms, targs, type, etype,
+ UNIFY_ALLOW_DERIVED, /*explain*/false);
+ ggc_free (targs);
+ return !err;
+}
+
/* Return a C++20 aggregate deduction candidate for TYPE initialized from
INIT. */
static tree
-maybe_aggr_guide (tree type, tree init)
+maybe_aggr_guide (tree tmpl, tree init, vec<tree,va_gc> *args)
{
if (cxx_dialect < cxx2a)
return NULL_TREE;
if (init == NULL_TREE)
return NULL_TREE;
+
+ tree type = TREE_TYPE (tmpl);
if (!CP_AGGREGATE_TYPE_P (type))
return NULL_TREE;
+ /* No aggregate candidate for copy-initialization. */
+ if (args->length() == 1)
+ {
+ tree val = (*args)[0];
+ if (is_spec_or_derived (tmpl, TREE_TYPE (val)))
+ return NULL_TREE;
+ }
+
/* If we encounter a problem, we just won't add the candidate. */
tsubst_flags_t complain = tf_none;
@@ -28002,81 +28046,99 @@ maybe_aggr_guide (tree type, tree init)
return NULL_TREE;
}
-/* Return whether ETYPE is, or is derived from, a specialization of TMPL. */
-
-static bool
-is_spec_or_derived (tree etype, tree tmpl)
-{
- if (!etype || !CLASS_TYPE_P (etype))
- return false;
-
- tree type = TREE_TYPE (tmpl);
- tree tparms = (INNERMOST_TEMPLATE_PARMS
- (DECL_TEMPLATE_PARMS (tmpl)));
- tree targs = make_tree_vec (TREE_VEC_LENGTH (tparms));
- int err = unify (tparms, targs, type, etype,
- UNIFY_ALLOW_DERIVED, /*explain*/false);
- ggc_free (targs);
- return !err;
-}
-
-/* Deduce template arguments for the class template placeholder PTYPE for
- template TMPL based on the initializer INIT, and return the resulting
- type. */
-
static tree
-do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
- tsubst_flags_t complain)
+alias_ctad_tweaks (tree tmpl, tree uguides)
{
- if (!DECL_CLASS_TEMPLATE_P (tmpl))
+ tsubst_flags_t complain = tf_warning_or_error;
+ tree aguides = NULL_TREE;
+ tree atparms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
+ tree utype = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl));
+ for (ovl_iterator iter (uguides); iter; ++iter)
{
- /* We should have handled this in the caller. */
- if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))
- return ptype;
- if (complain & tf_error)
- error ("non-class template %qT used without template arguments", tmpl);
- return error_mark_node;
- }
- if (init && TREE_TYPE (init) == ptype)
- /* Using the template parm as its own argument. */
- return ptype;
-
- tree type = TREE_TYPE (tmpl);
-
- bool try_list_ctor = false;
- bool copy_init = false;
-
- releasing_vec rv_args = NULL;
- vec<tree,va_gc> *&args = *&rv_args;
- if (init == NULL_TREE)
- args = make_tree_vector ();
- else if (BRACE_ENCLOSED_INITIALIZER_P (init))
- {
- if (CONSTRUCTOR_NELTS (init) == 1)
+ tree f = *iter;
+ tree in_decl = f;
+ location_t loc = DECL_SOURCE_LOCATION (f);
+ tree ret = TREE_TYPE (TREE_TYPE (f));
+ tree g = f;
+ if (TREE_CODE (f) == TEMPLATE_DECL)
{
- /* As an exception, the first phase in 16.3.1.7 (considering the
- initializer list as a single argument) is omitted if the
- initializer list consists of a single expression of type cv U,
- where U is a specialization of C or a class derived from a
- specialization of C. */
- tree elt = CONSTRUCTOR_ELT (init, 0)->value;
- copy_init = is_spec_or_derived (TREE_TYPE (elt), tmpl);
+ ++processing_template_decl;
+ tree ftparms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (f));
+ unsigned len = TREE_VEC_LENGTH (ftparms);
+ tree targs = make_tree_vec (len);
+ int err = unify (ftparms, targs, ret, utype, UNIFY_ALLOW_NONE, false);
+ gcc_assert (!err);
+
+ unsigned alen = TREE_VEC_LENGTH (atparms);
+ unsigned ndlen = 0;
+ unsigned j;
+ for (unsigned i = 0; i < len; ++i)
+ if (TREE_VEC_ELT (targs, i) == NULL_TREE)
+ ++ndlen;
+
+ tree gtparms = make_tree_vec (alen + ndlen);
+ for (j = 0; j < alen; ++j)
+ TREE_VEC_ELT (gtparms, j) = TREE_VEC_ELT (atparms, j);
+ for (unsigned i = 0; ndlen && i < len; ++i)
+ if (TREE_VEC_ELT (targs, i) == NULL_TREE)
+ {
+ --ndlen;
+ unsigned index = j++;
+ unsigned level = 1;
+ tree oldlist = TREE_VEC_ELT (ftparms, i);
+ tree list = rewrite_tparm_list (oldlist, index, level,
+ targs, i, complain);
+ TREE_VEC_ELT (gtparms, index) = list;
+ }
+ gtparms = build_tree_list (size_one_node, gtparms);
+
+ tree gfn = tsubst_decl (DECL_TEMPLATE_RESULT (f), targs,
+ complain|tf_partial);
+ DECL_USE_TEMPLATE (gfn) = 0;
+ g = build_template_decl (gfn, gtparms, false);
+ DECL_TEMPLATE_RESULT (g) = gfn;
+ TREE_TYPE (g) = TREE_TYPE (gfn);
+ tree gtargs = template_parms_to_args (gtparms);
+ DECL_TEMPLATE_INFO (gfn) = build_template_info (g, gtargs);
+ DECL_PRIMARY_TEMPLATE (g) = g;
+
+ tree atype = TREE_TYPE (tmpl);
+ ret = TREE_TYPE (TREE_TYPE (gfn));
+ tree ci = get_constraints (f);
+ if (ci)
+ ci = tsubst_constraint_info (ci, targs, complain, in_decl);
+ if (!same_type_p (atype, ret)
+ /* FIXME this should mean they don't compare as equivalent. */
+ || dependent_alias_template_spec_p (atype))
+ {
+ tree same = finish_trait_expr (loc, CPTK_IS_SAME_AS, atype, ret);
+ if (ci)
+ append_constraint (same, ci);
+ else
+ ci = build_constraints (NULL_TREE, same);
+ }
+ if (ci)
+ set_constraints (g, ci);
+
+ --processing_template_decl;
}
- try_list_ctor = !copy_init && TYPE_HAS_LIST_CTOR (type);
- if (try_list_ctor || is_std_init_list (type))
- args = make_tree_vector_single (init);
- else
- args = make_tree_vector_from_ctor (init);
+
+ aguides = lookup_add (g, aguides);
}
- else
+ return aguides;
+}
+
+static tree
+deduction_guides_for (tree tmpl, tree init, vec<tree,va_gc> *args,
+ int flags, tsubst_flags_t complain)
+{
+ if (DECL_ALIAS_TEMPLATE_P (tmpl))
{
- if (TREE_CODE (init) == TREE_LIST)
- args = make_tree_vector_from_list (init);
- else
- args = make_tree_vector_single (init);
-
- if (args->length() == 1)
- copy_init = is_spec_or_derived (TREE_TYPE ((*args)[0]), tmpl);
+ tree under = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl));
+ tree tinfo = get_template_info (under);
+ tree uguides = deduction_guides_for (TI_TEMPLATE (tinfo), init, args,
+ flags, complain);
+ return alias_ctad_tweaks (tmpl, uguides);
}
tree dname = dguide_name (tmpl);
@@ -28106,6 +28168,7 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
}
}
+ tree type = TREE_TYPE (tmpl);
tree outer_args = NULL_TREE;
if (DECL_CLASS_SCOPE_P (tmpl)
&& CLASSTYPE_TEMPLATE_INSTANTIATION (DECL_CONTEXT (tmpl)))
@@ -28114,7 +28177,6 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
type = TREE_TYPE (most_general_template (tmpl));
}
- bool saw_ctor = false;
// FIXME cache artificial deduction guides
for (ovl_iterator iter (CLASSTYPE_CONSTRUCTORS (type)); iter; ++iter)
{
@@ -28130,13 +28192,127 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
elided = true;
else
cands = lookup_add (guide, cands);
+ }
+
+ if (tree guide = maybe_aggr_guide (tmpl, init, args))
+ cands = lookup_add (guide, cands);
+
+ /* Maybe generate an implicit deduction guide. */
+ if (args->length () < 2)
+ {
+ tree gtype = NULL_TREE;
+
+ if (args->length () == 1)
+ /* Generate a copy guide. */
+ gtype = build_reference_type (type);
+ else if (!TYPE_HAS_USER_CONSTRUCTOR (type))
+ /* Generate a default guide. */
+ gtype = type;
+
+ if (gtype)
+ {
+ tree guide = build_deduction_guide (type, gtype, outer_args,
+ complain);
+ if (guide == error_mark_node)
+ return error_mark_node;
+ cands = lookup_add (guide, cands);
+ }
+ }
+
+ return cands;
+}
+
+/* Return whether TMPL is a (class template argument-) deducible template. */
+
+bool
+ctad_template_p (tree tmpl)
+{
+ /* A deducible template is either a class template or is an alias template
+ whose defining-type-id is of the form
+
+ typename(opt) nested-name-specifier(opt) template(opt) simple-template-id
+
+ where the nested-name-specifier (if any) is non-dependent and the
+ template-name of the simple-template-id names a deducible template. */
+
+ if (DECL_CLASS_TEMPLATE_P (tmpl)
+ || DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))
+ return true;
+ if (!DECL_ALIAS_TEMPLATE_P (tmpl))
+ return false;
+ tree orig = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl));
+ if (tree tinfo = get_template_info (orig))
+ return ctad_template_p (TI_TEMPLATE (tinfo));
+ return false;
+}
+
+/* Deduce template arguments for the class template placeholder PTYPE for
+ template TMPL based on the initializer INIT, and return the resulting
+ type. */
+
+static tree
+do_class_deduction (tree ptype, tree tmpl, tree init,
+ int flags, tsubst_flags_t complain)
+{
+ /* We should have handled this in the caller. */
+ if (DECL_TEMPLATE_TEMPLATE_PARM_P (tmpl))
+ return ptype;
+
+ /* Look through alias templates that just rename another template. */
+ tmpl = get_underlying_template (tmpl);
+ if (!ctad_template_p (tmpl))
+ {
+ if (complain & tf_error)
+ error ("non-deducible template %qT used without template arguments", tmpl);
+ return error_mark_node;
+ }
+ else if (cxx_dialect < cxx2a && DECL_ALIAS_TEMPLATE_P (tmpl))
+ {
+ /* This doesn't affect conforming C++17 code, so just pedwarn. */
+ if (complain & tf_warning_or_error)
+ pedwarn (input_location, 0, "alias template deduction only available "
+ "with %<-std=c++2a%> or %<-std=gnu++2a%>");
+ }
+
+ if (init && TREE_TYPE (init) == ptype)
+ /* Using the template parm as its own argument. */
+ return ptype;
+
+ tree type = TREE_TYPE (tmpl);
+
+ bool try_list_ctor = false;
- saw_ctor = true;
+ releasing_vec rv_args = NULL;
+ vec<tree,va_gc> *&args = *&rv_args;
+ if (init == NULL_TREE)
+ args = make_tree_vector ();
+ else if (BRACE_ENCLOSED_INITIALIZER_P (init))
+ {
+ try_list_ctor = TYPE_HAS_LIST_CTOR (type);
+ if (try_list_ctor && CONSTRUCTOR_NELTS (init) == 1)
+ {
+ /* As an exception, the first phase in 16.3.1.7 (considering the
+ initializer list as a single argument) is omitted if the
+ initializer list consists of a single expression of type cv U,
+ where U is a specialization of C or a class derived from a
+ specialization of C. */
+ tree elt = CONSTRUCTOR_ELT (init, 0)->value;
+ if (is_spec_or_derived (TREE_TYPE (elt), tmpl))
+ try_list_ctor = false;
+ }
+ if (try_list_ctor || is_std_init_list (type))
+ args = make_tree_vector_single (init);
+ else
+ args = make_tree_vector_from_ctor (init);
}
+ else if (TREE_CODE (init) == TREE_LIST)
+ args = make_tree_vector_from_list (init);
+ else
+ args = make_tree_vector_single (init);
- if (!copy_init)
- if (tree guide = maybe_aggr_guide (type, init))
- cands = lookup_add (guide, cands);
+ tree cands = deduction_guides_for (tmpl, init, args, flags, complain);
+ if (cands == error_mark_node)
+ return error_mark_node;
tree call = error_mark_node;
@@ -28165,39 +28341,15 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
}
}
- /* Maybe generate an implicit deduction guide. */
- if (call == error_mark_node && args->length () < 2)
+ if (!cands && call == error_mark_node)
{
- tree gtype = NULL_TREE;
-
- if (args->length () == 1)
- /* Generate a copy guide. */
- gtype = build_reference_type (type);
- else if (!saw_ctor)
- /* Generate a default guide. */
- gtype = type;
-
- if (gtype)
- {
- tree guide = build_deduction_guide (type, gtype, outer_args,
- complain);
- if (guide == error_mark_node)
- return error_mark_node;
- cands = lookup_add (guide, cands);
- }
- }
-
- if (elided && !cands)
- {
- error ("cannot deduce template arguments for copy-initialization"
- " of %qT, as it has no non-explicit deduction guides or "
- "user-declared constructors", type);
- return error_mark_node;
- }
- else if (!cands && call == error_mark_node)
- {
- error ("cannot deduce template arguments of %qT, as it has no viable "
- "deduction guides", type);
+ if (flags & LOOKUP_ONLYCONVERTING)
+ error ("cannot deduce template arguments for copy-initialization"
+ " of %qT, as it has no viable non-explicit deduction guides",
+ type);
+ else
+ error ("cannot deduce template arguments of %qT, as it has no viable "
+ "deduction guides", type);
return error_mark_node;
}
@@ -28215,10 +28367,6 @@ do_class_deduction (tree ptype, tree tmpl, tree init, int flags,
++cp_unevaluated_operand;
call = build_new_function_call (cands, &args, complain | tf_decltype);
--cp_unevaluated_operand;
-
- if (elided)
- inform (input_location, "explicit deduction guides not considered "
- "for copy-initialization");
}
return cp_build_qualified_type (TREE_TYPE (call), cp_type_quals (ptype));
diff --git a/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias1.C b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias1.C
new file mode 100644
index 00000000000..c1fbdf09113
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/class-deduction-alias1.C
@@ -0,0 +1,27 @@
+// Testcase from P1814R0
+// { dg-do compile { target c++2a } }
+
+template <class T> struct identity { using type = T; };
+template <class T> using identity_t = typename identity<T>::type;
+template <class T> concept Int = __is_same_as (T, int);
+
+template <class T, class U> struct C {
+ C(T, U); // #1
+};
+template<class T, class U>
+C(T, U) -> C<T, identity_t<U>>; // #2
+
+template<class V>
+using A = C<V *, V *>;
+
+template<Int W>
+using B = A<W>;
+
+int i{};
+double d{};
+A a1(&i, &i); // { dg-bogus "" "Deduces A<int>" }
+A a2(i, i); // { dg-error "" "cannot deduce V * from i" }
+A a3(&i, &d); // { dg-error "" } #1: Cannot deduce (V*, V*) from (int *, double *)
+ // #2: Cannot deduce A<V> from C<int *, double *>
+B b1(&i, &i); // { dg-bogus "" "Deduces B<int>" }
+B b2(&d, &d); // { dg-error "" "cannot deduce B<W> from C<double *, double *>" }
commit 3784366a87f21dd0b995c1c952ab681165b99756
Author: Jason Merrill <ja...@redhat.com>
Date: Sat Nov 16 15:43:07 2019 -0500
Fix various issues with constrained alias templates.
* cxx-pretty-print.c (pp_cxx_unqualified_id): Handle alias
template-id.
* pt.c (complex_alias_template_p): True if constraints.
(get_underlying_template, tsubst): Check alias constraints.
(push_template_decl_real): Set alias constraints here.
* parser.c (cp_parser_alias_declaration): Not here.
* constraint.cc (get_constraints): Take const_tree.
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index d6e9357385a..2a626d6d1ac 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7769,7 +7769,8 @@ extern cp_expr finish_constraint_and_expr (location_t, cp_expr, cp_expr);
extern cp_expr finish_constraint_primary_expr (cp_expr);
extern tree finish_concept_definition (cp_expr, tree);
extern tree combine_constraint_expressions (tree, tree);
-extern tree get_constraints (tree);
+extern tree append_constraint (tree, tree);
+extern tree get_constraints (const_tree);
extern void set_constraints (tree, tree);
extern void remove_constraints (tree);
extern tree current_template_constraints (void);
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 00b59a90868..c973d487245 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -1119,7 +1119,7 @@ static GTY ((cache)) tree_cache_map *decl_constraints;
constrained, return NULL_TREE. Note that T must be non-null. */
tree
-get_constraints (tree t)
+get_constraints (const_tree t)
{
if (!flag_concepts)
return NULL_TREE;
@@ -1129,7 +1129,7 @@ get_constraints (tree t)
gcc_assert (DECL_P (t));
if (TREE_CODE (t) == TEMPLATE_DECL)
t = DECL_TEMPLATE_RESULT (t);
- tree* found = decl_constraints->get (t);
+ tree* found = decl_constraints->get (CONST_CAST_TREE (t));
if (found)
return *found;
else
diff --git a/gcc/cp/cxx-pretty-print.c b/gcc/cp/cxx-pretty-print.c
index 8ece11d276e..909b2a4ef1d 100644
--- a/gcc/cp/cxx-pretty-print.c
+++ b/gcc/cp/cxx-pretty-print.c
@@ -172,11 +172,11 @@ pp_cxx_unqualified_id (cxx_pretty_printer *pp, tree t)
case TYPENAME_TYPE:
case UNBOUND_CLASS_TEMPLATE:
pp_cxx_unqualified_id (pp, TYPE_NAME (t));
- if (CLASS_TYPE_P (t) && CLASSTYPE_USE_TEMPLATE (t))
+ if (tree ti = TYPE_TEMPLATE_INFO_MAYBE_ALIAS (t))
{
pp_cxx_begin_template_argument_list (pp);
- pp_cxx_template_argument_list (pp, INNERMOST_TEMPLATE_ARGS
- (CLASSTYPE_TI_ARGS (t)));
+ tree args = INNERMOST_TEMPLATE_ARGS (TI_ARGS (ti));
+ pp_cxx_template_argument_list (pp, args);
pp_cxx_end_template_argument_list (pp);
}
break;
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c473e7fd92f..a80b4c818bb 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -19891,14 +19891,6 @@ cp_parser_alias_declaration (cp_parser* parser)
if (decl == error_mark_node)
return decl;
- /* Attach constraints to the alias declaration. */
- if (flag_concepts && current_template_parms)
- {
- tree reqs = TEMPLATE_PARMS_CONSTRAINTS (current_template_parms);
- tree constr = build_constraints (reqs, NULL_TREE);
- set_constraints (decl, constr);
- }
-
cp_finish_decl (decl, NULL_TREE, 0, NULL_TREE, 0);
if (pushed_scope)
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index 8f7734a7a41..08b4713035b 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -5986,9 +5986,18 @@ push_template_decl_real (tree decl, bool is_friend)
}
if (TREE_CODE (decl) == TYPE_DECL
- && TYPE_DECL_ALIAS_P (decl)
- && complex_alias_template_p (tmpl))
- TEMPLATE_DECL_COMPLEX_ALIAS_P (tmpl) = true;
+ && TYPE_DECL_ALIAS_P (decl))
+ {
+ if (tree constr
+ = TEMPLATE_PARMS_CONSTRAINTS (DECL_TEMPLATE_PARMS (tmpl)))
+ {
+ /* ??? Why don't we do this here for all templates? */
+ constr = build_constraints (constr, NULL_TREE);
+ set_constraints (decl, constr);
+ }
+ if (complex_alias_template_p (tmpl))
+ TEMPLATE_DECL_COMPLEX_ALIAS_P (tmpl) = true;
+ }
}
/* The DECL_TI_ARGS of DECL contains full set of arguments referring
@@ -6335,6 +6344,9 @@ uses_all_template_parms_r (tree t, void *data_)
static bool
complex_alias_template_p (const_tree tmpl)
{
+ if (get_constraints (tmpl))
+ return true;
+
struct uses_all_template_parms_data data;
tree pat = DECL_ORIGINAL_TYPE (DECL_TEMPLATE_RESULT (tmpl));
tree parms = DECL_TEMPLATE_PARMS (tmpl);
@@ -6403,7 +6415,8 @@ get_underlying_template (tree tmpl)
break;
tree alias_args = INNERMOST_TEMPLATE_ARGS (generic_targs_for (tmpl));
- if (!comp_template_args (TI_ARGS (tinfo), alias_args))
+ if (!comp_template_args (TI_ARGS (tinfo), alias_args)
+ || !equivalently_constrained (tmpl, underlying))
break;
/* Alias is equivalent. Strip it and repeat. */
@@ -14896,6 +14909,18 @@ tsubst (tree t, tree args, tsubst_flags_t complain, tree in_decl)
instantiate it. */
tree tmpl = most_general_template (DECL_TI_TEMPLATE (decl));
tree gen_args = tsubst (DECL_TI_ARGS (decl), args, complain, in_decl);
+ /* FIXME check for satisfaction in check_instantiated_args. */
+ if (flag_concepts
+ && !any_dependent_template_arguments_p (gen_args)
+ && !constraints_satisfied_p (tmpl, gen_args))
+ {
+ if (complain & tf_error)
+ {
+ gcc_assert (seen_error ());
+ diagnose_constraints (input_location, tmpl, args);
+ }
+ return error_mark_node;
+ }
r = instantiate_alias_template (tmpl, gen_args, complain);
}
else if (DECL_CLASS_SCOPE_P (decl)