Fix constrained alias template transparency.
authorJason Merrill <jason@redhat.com>
Wed, 27 Nov 2019 22:05:47 +0000 (17:05 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Wed, 27 Nov 2019 22:05:47 +0000 (17:05 -0500)
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.

From-SVN: r278785

gcc/cp/ChangeLog
gcc/cp/constraint.cc
gcc/cp/cp-tree.h
gcc/cp/cxx-pretty-print.c
gcc/cp/parser.c
gcc/cp/pt.c
gcc/testsuite/g++.dg/cpp2a/concepts-alias.C
gcc/testsuite/g++.dg/cpp2a/concepts-alias3.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp2a/concepts-alias4.C [new file with mode: 0644]

index 0f26009b2be9fbd66a1a465ed86bf56708a2dfc6..9dbc61c2151f4a5eff0c1694509df9fe50bd43a2 100644 (file)
@@ -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.
index fadbe7c8ac0a221662be4e24c3d45a13f0cbe6de..0d1c27a6d1699880bedd2db03e87499c20d663f0 100644 (file)
@@ -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
 ---------------------------------------------------------------------------*/
index d8e12e99ba3c5283915304ebbd0f2dd7417fc6cd..fd3be60d407fa8ebb41c9a6d6c3a6a3851665a4c 100644 (file)
@@ -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);
index 8ece11d276e31d48ead7ccf9b4cccc75a0ce4506..909b2a4ef1d4110157a78380185077ecdfbbfe7e 100644 (file)
@@ -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;
index 27318d3aeed9c321950809354306e8f56d13911f..c08b7b32a329e2c106c5c366393c866614a89715 100644 (file)
@@ -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)
index 244eb7d4ff355dd2dc6bc5d6abe32cf3092e1dae..6e712bdb4e10f88adc36cb2d95464e20b0122326 100644 (file)
@@ -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 ();
 
index 6b2ab0d80467de33116e47e0a4eb499c932a9f0a..862879169fb763e9b95ccc2a4b6c94d4abc581cc 100644 (file)
@@ -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 (file)
index 0000000..02e960a
--- /dev/null
@@ -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 (file)
index 0000000..d37ce6a
--- /dev/null
@@ -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;