+2019-11-16 Jason Merrill <jason@redhat.com>
+
+ * 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.
+
2019-11-12 Jason Merrill <jason@redhat.com>
PR c++/92206 - ICE with typedef to dependent alias.
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;
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
return winner;
}
+/* Return whether D1 is at least as constrained as D2. */
+
+bool
+at_least_as_constrained (tree d1, tree d2)
+{
+ tree n1 = get_normalized_constraints_from_decl (d1);
+ tree n2 = get_normalized_constraints_from_decl (d2);
+
+ return subsumes (n1, n2);
+}
+
/*---------------------------------------------------------------------------
Constraint diagnostics
---------------------------------------------------------------------------*/
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);
extern bool strictly_subsumes (tree, tree, tree);
extern bool weakly_subsumes (tree, tree, tree);
extern int more_constrained (tree, tree);
+extern bool at_least_as_constrained (tree, tree);
extern bool constraints_equivalent_p (tree, tree);
extern bool atomic_constraints_identical_p (tree, tree);
extern hashval_t iterative_hash_constraint (tree, hashval_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;
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)
static tree tsubst_template_parm (tree, tree, tsubst_flags_t);
static tree instantiate_alias_template (tree, tree, tsubst_flags_t);
static bool complex_alias_template_p (const_tree tmpl);
+static tree get_underlying_template (tree);
static tree tsubst_attributes (tree, tree, tsubst_flags_t, tree);
static tree canonicalize_expr_argument (tree, tsubst_flags_t);
static tree make_argument_pack (tree);
}
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
static bool
complex_alias_template_p (const_tree tmpl)
{
+ /* A renaming alias isn't complex. */
+ if (get_underlying_template (CONST_CAST_TREE (tmpl)) != tmpl)
+ return false;
+
+ /* Any other constrained alias is complex. */
+ 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);
/* Return the number of innermost template parameters in TMPL. */
static int
-num_innermost_template_parms (tree tmpl)
+num_innermost_template_parms (const_tree tmpl)
{
tree parms = INNERMOST_TEMPLATE_PARMS (DECL_TEMPLATE_PARMS (tmpl));
return TREE_VEC_LENGTH (parms);
if (!comp_template_args (TI_ARGS (tinfo), alias_args))
break;
+ /* If TMPL adds or changes any constraints, it isn't equivalent. I think
+ it's appropriate to treat a less-constrained alias as equivalent. */
+ if (!at_least_as_constrained (underlying, tmpl))
+ break;
+
/* Alias is equivalent. Strip it and repeat. */
tmpl = underlying;
}
Note that the check is deferred until after the hash
lookup. This prevents redundant checks on previously
instantiated specializations. */
- if (flag_concepts && !constraints_satisfied_p (gen_tmpl, arglist))
+ if (flag_concepts
+ && !DECL_ALIAS_TEMPLATE_P (gen_tmpl)
+ && !constraints_satisfied_p (gen_tmpl, arglist))
{
if (complain & tf_error)
{
{
if (tmpl == error_mark_node || args == error_mark_node)
return error_mark_node;
- if (!push_tinst_level (tmpl, args))
- return error_mark_node;
args =
coerce_innermost_template_parms (DECL_TEMPLATE_PARMS (tmpl),
/*require_all_args=*/true,
/*use_default_args=*/true);
+ /* FIXME check for satisfaction in check_instantiated_args. */
+ if (flag_concepts
+ && !any_dependent_template_arguments_p (args)
+ && !constraints_satisfied_p (tmpl, args))
+ {
+ if (complain & tf_error)
+ {
+ auto_diagnostic_group d;
+ error ("template constraint failure for %qD", tmpl);
+ diagnose_constraints (input_location, tmpl, args);
+ }
+ return error_mark_node;
+ }
+
+ if (!push_tinst_level (tmpl, args))
+ return error_mark_node;
tree r = instantiate_template (tmpl, args, complain);
pop_tinst_level ();
requires Class<T>
using X = T*;
-// BUG: Alias templates are expanded at the point of use, regardless
-// of whether or not they are dependent. This causes T* to be substituted
-// without acutally checking the constraints. See the declaration of y1
-// below.
template<typename T>
-using Y = X<T>;
+using Y = X<T>; // { dg-error "constraint" }
template<Class T> using Z = T*;
X<S> x1; // OK
X<int> x2; // { dg-error "template constraint failure" }
-Y<int> y1; // { dg-error "" "" { xfail *-*-* } }
+Y<int> y1; // { dg-message "" }
Z<S> z1; // ok
-
--- /dev/null
+// { dg-do compile { target c++2a } }
+
+template <typename T> struct A { };
+template <typename T> concept int_type = __is_same_as (T, int);
+template <int_type T> using intA = A<T>;
+
+template <template <typename T> class TT> struct B {
+ TT<char> tt; // { dg-error "" }
+};
+B<intA> b;
--- /dev/null
+// { dg-do compile { target c++2a } }
+
+template <typename T> struct A { };
+template <typename T> concept int_type = __is_same_as (T, int);
+template <int_type T> using intA = A<T>;
+
+template <class T> struct B {
+ intA<T> a; // { dg-error "" }
+};
+B<char> b;