aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Merrill <jason@redhat.com>2019-11-27 22:05:47 +0000
committerJason Merrill <jason@redhat.com>2019-11-27 22:05:47 +0000
commitac1745ae600ec50d9248cc720559167ac10a0ecb (patch)
tree50c06c4b53bf6fd71ab1e834aabdcf0a2c7e4b37
parentb4376ebd2aa393a0e2ac06c579805616287923d1 (diff)
Fix constrained alias template transparency.
A constrained alias template can't be treated as equivalent to its underlying template/type for much the same reason that an alias template like void_t can't; we're relying on checking during substitution. * 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. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@278785 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/cp/ChangeLog10
-rw-r--r--gcc/cp/constraint.cc15
-rw-r--r--gcc/cp/cp-tree.h4
-rw-r--r--gcc/cp/cxx-pretty-print.c6
-rw-r--r--gcc/cp/parser.c8
-rw-r--r--gcc/cp/pt.c53
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-alias.C9
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-alias3.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/concepts-alias4.C10
9 files changed, 97 insertions, 28 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 0f26009b2be..9dbc61c2151 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,13 @@
+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.
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index fadbe7c8ac0..0d1c27a6d16 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -1124,7 +1124,7 @@ static GTY ((cache)) decl_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;
@@ -1134,7 +1134,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
@@ -2966,6 +2966,17 @@ more_constrained (tree d1, tree d2)
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
---------------------------------------------------------------------------*/
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index d8e12e99ba3..fd3be60d407 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -7772,7 +7772,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);
@@ -7834,6 +7835,7 @@ extern bool subsumes_constraints (tree, tree);
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);
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 27318d3aeed..c08b7b32a32 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -19901,14 +19901,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 244eb7d4ff3..6e712bdb4e1 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -215,6 +215,7 @@ static tree listify_autos (tree, tree);
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);
@@ -5989,9 +5990,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
@@ -6350,6 +6360,14 @@ uses_all_template_parms_r (tree t, void *data_)
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);
@@ -6395,7 +6413,7 @@ dependent_alias_template_spec_p (const_tree t, bool transparent_typedefs)
/* 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);
@@ -6430,6 +6448,11 @@ get_underlying_template (tree tmpl)
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;
}
@@ -9679,7 +9702,9 @@ lookup_template_class_1 (tree d1, tree arglist, tree in_decl, tree context,
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)
{
@@ -20499,8 +20524,6 @@ instantiate_alias_template (tree tmpl, tree args, tsubst_flags_t complain)
{
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),
@@ -20508,6 +20531,22 @@ instantiate_alias_template (tree tmpl, tree args, tsubst_flags_t complain)
/*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 ();
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-alias.C b/gcc/testsuite/g++.dg/cpp2a/concepts-alias.C
index 6b2ab0d8046..862879169fb 100644
--- a/gcc/testsuite/g++.dg/cpp2a/concepts-alias.C
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-alias.C
@@ -7,12 +7,8 @@ template<typename T>
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*;
@@ -20,6 +16,5 @@ struct S { };
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
-
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-alias3.C b/gcc/testsuite/g++.dg/cpp2a/concepts-alias3.C
new file mode 100644
index 00000000000..02e960ad40a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-alias3.C
@@ -0,0 +1,10 @@
+// { 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;
diff --git a/gcc/testsuite/g++.dg/cpp2a/concepts-alias4.C b/gcc/testsuite/g++.dg/cpp2a/concepts-alias4.C
new file mode 100644
index 00000000000..d37ce6a51e8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/concepts-alias4.C
@@ -0,0 +1,10 @@
+// { 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;