Support non-type constrained-type-specifiers.
authorJason Merrill <jason@redhat.com>
Fri, 6 Nov 2015 16:21:29 +0000 (11:21 -0500)
committerJason Merrill <jason@gcc.gnu.org>
Fri, 6 Nov 2015 16:21:29 +0000 (11:21 -0500)
* parser.c (check_type_concept): Remove.
(cp_parser_maybe_constrained_type_specifier): Don't call it.
(synthesize_implicit_template_parm): Handle non-type and template
template parameters.  Also compare extra args.  Return the decl.
(cp_parser_template_argument): Handle constrained-type-specifiers for
non-type template parameters.
(finish_constrained_template_template_parm): Split out from
cp_parser_constrained_template_template_parm.
(cp_parser_nonclass_name): Move some logic into
cp_parser_maybe_concept_name.
(cp_parser_init_declarator): Fix error recovery.
(get_concept_from_constraint): Remove.
(cp_parser_simple_type_specifier): Adjust for
synthesize_implicit_template_parm returning the decl.
* constraint.cc (placeholder_extract_concept_and_args)
(equivalent_placeholder_constraints): Also handle TYPE_DECL
constrained parms.

From-SVN: r229860

gcc/cp/ChangeLog
gcc/cp/constraint.cc
gcc/cp/parser.c
gcc/testsuite/g++.dg/concepts/generic-fn-err.C
gcc/testsuite/g++.dg/concepts/placeholder6.C [new file with mode: 0644]

index fbbb6cb8d0d2309c40b6b9dcf04ca67d502c42a3..ce8a81f6a1e983db4f0ecbfb3562fb46a111e1eb 100644 (file)
@@ -1,5 +1,24 @@
 2015-11-06  Jason Merrill  <jason@redhat.com>
 
+       Support non-type constrained-type-specifiers.
+       * parser.c (check_type_concept): Remove.
+       (cp_parser_maybe_constrained_type_specifier): Don't call it.
+       (synthesize_implicit_template_parm): Handle non-type and template
+       template parameters.  Also compare extra args.  Return the decl.
+       (cp_parser_template_argument): Handle constrained-type-specifiers for
+       non-type template parameters.
+       (finish_constrained_template_template_parm): Split out from
+       cp_parser_constrained_template_template_parm.
+       (cp_parser_nonclass_name): Move some logic into
+       cp_parser_maybe_concept_name.
+       (cp_parser_init_declarator): Fix error recovery.
+       (get_concept_from_constraint): Remove.
+       (cp_parser_simple_type_specifier): Adjust for
+       synthesize_implicit_template_parm returning the decl.
+       * constraint.cc (placeholder_extract_concept_and_args)
+       (equivalent_placeholder_constraints): Also handle TYPE_DECL
+       constrained parms.
+
        * pt.c (push_inline_template_parms_recursive): Don't recreate the
        CONST_DECL.
 
index a1fbf174ee85cfee8e4326323bf54ae4f68c6f2b..c6eaf7546068900801b4fef5bbda3f748afb5212 100644 (file)
@@ -1379,12 +1379,21 @@ make_constrained_auto (tree con, tree args)
   return decl;
 }
 
-/* Given the predicate constraint T from a placeholder type, extract its
-   TMPL and ARGS.  */
+/* Given the predicate constraint T from a constrained-type-specifier, extract
+   its TMPL and ARGS.  FIXME why do we need two different forms of
+   constrained-type-specifier?  */
 
 void
 placeholder_extract_concept_and_args (tree t, tree &tmpl, tree &args)
 {
+  if (TREE_CODE (t) == TYPE_DECL)
+    {
+      /* A constrained parameter.  */
+      tmpl = DECL_TI_TEMPLATE (CONSTRAINED_PARM_CONCEPT (t));
+      args = CONSTRAINED_PARM_EXTRA_ARGS (t);
+      return;
+    }
+
   gcc_assert (TREE_CODE (t) == PRED_CONSTR);
   t = PRED_CONSTR_EXPR (t);
   gcc_assert (TREE_CODE (t) == CALL_EXPR
@@ -1418,9 +1427,10 @@ placeholder_extract_concept_and_args (tree t, tree &tmpl, tree &args)
 bool
 equivalent_placeholder_constraints (tree c1, tree c2)
 {
-  if (TREE_CODE (c1) == TEMPLATE_TYPE_PARM)
+  if (c1 && TREE_CODE (c1) == TEMPLATE_TYPE_PARM)
+    /* A constrained auto.  */
     c1 = PLACEHOLDER_TYPE_CONSTRAINTS (c1);
-  if (TREE_CODE (c2) == TEMPLATE_TYPE_PARM)
+  if (c2 && TREE_CODE (c2) == TEMPLATE_TYPE_PARM)
     c2 = PLACEHOLDER_TYPE_CONSTRAINTS (c2);
 
   if (c1 == c2)
@@ -1434,14 +1444,21 @@ equivalent_placeholder_constraints (tree c1, tree c2)
 
   if (t1 != t2)
     return false;
-  int len = TREE_VEC_LENGTH (a1);
-  if (len != TREE_VEC_LENGTH (a2))
-    return false;
+
   /* Skip the first argument to avoid infinite recursion on the
      placeholder auto itself.  */
-  for (int i = len-1; i > 0; --i)
-    if (!cp_tree_equal (TREE_VEC_ELT (a1, i),
-                       TREE_VEC_ELT (a2, i)))
+  bool skip1 = (TREE_CODE (c1) == PRED_CONSTR);
+  bool skip2 = (TREE_CODE (c2) == PRED_CONSTR);
+
+  int len1 = (a1 ? TREE_VEC_LENGTH (a1) : 0) - skip1;
+  int len2 = (a2 ? TREE_VEC_LENGTH (a2) : 0) - skip2;
+
+  if (len1 != len2)
+    return false;
+
+  for (int i = 0; i < len1; ++i)
+    if (!cp_tree_equal (TREE_VEC_ELT (a1, i + skip1),
+                       TREE_VEC_ELT (a2, i + skip2)))
       return false;
   return true;
 }
index c6f57297e72bbd02a06bed6a76022064d9331e60..d1f4970f1eb1967b2e9fad7fa8a7dc15e1eb031c 100644 (file)
@@ -13871,18 +13871,9 @@ cp_parser_constrained_type_template_parm (cp_parser *parser,
     return error_mark_node;
 }
 
-/* Finish parsing/processing a template template parameter by borrowing
-   the template parameter list from the prototype parameter.  */
-
 static tree
-cp_parser_constrained_template_template_parm (cp_parser *parser,
-                                              tree proto,
-                                              tree id,
-                                              cp_parameter_declarator *parmdecl)
+finish_constrained_template_template_parm (tree proto, tree id)
 {
-  if (!cp_parser_check_constrained_type_parm (parser, parmdecl))
-    return error_mark_node;
-
   /* FIXME: This should probably be copied, and we may need to adjust
      the template parameter depths.  */
   tree saved_parms = current_template_parms;
@@ -13896,6 +13887,20 @@ cp_parser_constrained_template_template_parm (cp_parser *parser,
   return parm;
 }
 
+/* Finish parsing/processing a template template parameter by borrowing
+   the template parameter list from the prototype parameter.  */
+
+static tree
+cp_parser_constrained_template_template_parm (cp_parser *parser,
+                                              tree proto,
+                                              tree id,
+                                              cp_parameter_declarator *parmdecl)
+{
+  if (!cp_parser_check_constrained_type_parm (parser, parmdecl))
+    return error_mark_node;
+  return finish_constrained_template_template_parm (proto, id);
+}
+
 /* Create a new non-type template parameter from the given PARM
    declarator.  */
 
@@ -14950,8 +14955,12 @@ cp_parser_template_argument (cp_parser* parser)
                                          /*check_dependency=*/true,
                                          /*ambiguous_decls=*/NULL,
                                          argument_start_token->location);
-      if (TREE_CODE (argument) != TEMPLATE_DECL
-         && TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE)
+      /* Handle a constrained-type-specifier for a non-type template
+        parameter.  */
+      if (tree decl = cp_parser_maybe_concept_name (parser, argument))
+       argument = decl;
+      else if (TREE_CODE (argument) != TEMPLATE_DECL
+              && TREE_CODE (argument) != UNBOUND_CLASS_TEMPLATE)
        cp_parser_error (parser, "expected template-name");
     }
   if (cp_parser_parse_definitely (parser))
@@ -15630,7 +15639,10 @@ cp_parser_simple_type_specifier (cp_parser* parser,
            }
 
          if (cxx_dialect >= cxx14)
-           type = synthesize_implicit_template_parm (parser, NULL_TREE);
+           {
+             type = synthesize_implicit_template_parm (parser, NULL_TREE);
+             type = TREE_TYPE (type);
+           }
          else
            type = error_mark_node;
 
@@ -15949,19 +15961,6 @@ cp_parser_type_name (cp_parser* parser, bool typename_keyword_p)
   return type_decl;
 }
 
-/* Returns true if proto is a type parameter, but not a template
-   template parameter.  */
-static bool
-check_type_concept (tree fn, tree proto)
-{
-  if (TREE_CODE (proto) != TYPE_DECL)
-    {
-      error ("invalid use of non-type concept %qD", fn);
-      return false;
-    }
-  return true;
-}
-
 /*  Check if DECL and ARGS can form a constrained-type-specifier.
     If ARGS is non-null, we try to form a concept check of the
     form DECL<?, ARGS> where ? is a wildcard that matches any
@@ -16009,13 +16008,6 @@ cp_parser_maybe_constrained_type_specifier (cp_parser *parser,
   if (processing_template_parmlist)
     return build_constrained_parameter (conc, proto, args);
 
-  /* In any other context, a concept must be a type concept.
-
-     FIXME: A constrained-type-specifier can be a placeholder
-     of any kind.  */
-  if (!check_type_concept (conc, proto))
-    return error_mark_node;
-
   /* In a parameter-declaration-clause, constrained-type
      specifiers result in invented template parameters.  */
   if (parser->auto_is_implicit_function_template_parm_p)
@@ -16046,7 +16038,13 @@ cp_parser_maybe_constrained_type_specifier (cp_parser *parser,
 static tree
 cp_parser_maybe_concept_name (cp_parser* parser, tree decl)
 {
-  return cp_parser_maybe_constrained_type_specifier (parser, decl, NULL_TREE);
+  if (flag_concepts
+      && (TREE_CODE (decl) == OVERLOAD
+         || BASELINK_P (decl)
+         || variable_concept_p (decl)))
+    return cp_parser_maybe_constrained_type_specifier (parser, decl, NULL_TREE);
+  else
+    return NULL_TREE;
 }
 
 /* Check if DECL and ARGS form a partial-concept-id.  If so,
@@ -16093,15 +16091,8 @@ cp_parser_nonclass_name (cp_parser* parser)
   type_decl = strip_using_decl (type_decl);
   
   /* If we found an overload set, then it may refer to a concept-name. */
-  if (flag_concepts
-      && (TREE_CODE (type_decl) == OVERLOAD
-         || BASELINK_P (type_decl)
-         || variable_concept_p (type_decl)))
-  {
-    /* Determine whether the overload refers to a concept. */
-    if (tree decl = cp_parser_maybe_concept_name (parser, type_decl))
-      return decl;
-  }
+  if (tree decl = cp_parser_maybe_concept_name (parser, type_decl))
+    type_decl = decl;
 
   if (TREE_CODE (type_decl) != TYPE_DECL
       && (objc_is_id (identifier) || objc_is_class_name (identifier)))
@@ -18183,7 +18174,7 @@ cp_parser_init_declarator (cp_parser* parser,
               "attributes after parenthesized initializer ignored");
 
   /* And now complain about a non-function implicit template.  */
-  if (bogus_implicit_tmpl)
+  if (bogus_implicit_tmpl && decl != error_mark_node)
     error_at (DECL_SOURCE_LOCATION (decl),
              "non-function %qD declared as implicit template", decl);
 
@@ -36681,17 +36672,6 @@ tree_type_is_auto_or_concept (const_tree t)
   return TREE_TYPE (t) && is_auto_or_concept (TREE_TYPE (t));
 }
 
-/* Returns the template declaration being called or evaluated as
-   part of the constraint check. Note that T must be a predicate
-   constraint (it can't be any other kind of constraint). */
-static tree
-get_concept_from_constraint (tree t)
-{
-  tree tmpl, args;
-  placeholder_extract_concept_and_args (t, tmpl, args);
-  return DECL_TEMPLATE_RESULT (tmpl);
-}
-
 /* Add an implicit template type parameter to the CURRENT_TEMPLATE_PARMS
    (creating a new template parameter list if necessary).  Returns the newly
    created template type parm.  */
@@ -36711,9 +36691,14 @@ synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
       tree t = parser->implicit_template_parms;
       while (t)
         {
-          tree c = get_concept_from_constraint (TREE_TYPE (t));
-          if (c == CONSTRAINED_PARM_CONCEPT (constr))
-            return TREE_VALUE (t);
+          if (equivalent_placeholder_constraints (TREE_TYPE (t), constr))
+           {
+             tree d = TREE_VALUE (t);
+             if (TREE_CODE (d) == PARM_DECL)
+               /* Return the TEMPLATE_PARM_INDEX.  */
+               d = DECL_INITIAL (d);
+             return d;
+           }
           t = TREE_CHAIN (t);
         }
     }
@@ -36823,9 +36808,23 @@ synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
   /* Synthesize a new template parameter and track the current template
      parameter chain with implicit_template_parms.  */
 
+  tree proto = constr ? DECL_INITIAL (constr) : NULL_TREE;
   tree synth_id = make_generic_type_name ();
-  tree synth_tmpl_parm = finish_template_type_parm (class_type_node,
-                                                   synth_id);
+  tree synth_tmpl_parm;
+  bool non_type = false;
+
+  if (proto == NULL_TREE || TREE_CODE (proto) == TYPE_DECL)
+    synth_tmpl_parm
+      = finish_template_type_parm (class_type_node, synth_id);
+  else if (TREE_CODE (proto) == TEMPLATE_DECL)
+    synth_tmpl_parm
+      = finish_constrained_template_template_parm (proto, synth_id);
+  else
+    {
+      synth_tmpl_parm = copy_decl (proto);
+      DECL_NAME (synth_tmpl_parm) = synth_id;
+      non_type = true;
+    }
 
   // Attach the constraint to the parm before processing.
   tree node = build_tree_list (NULL_TREE, synth_tmpl_parm);
@@ -36834,7 +36833,7 @@ synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
     = process_template_parm (parser->implicit_template_parms,
                             input_location,
                             node,
-                            /*non_type=*/false,
+                            /*non_type=*/non_type,
                             /*param_pack=*/false);
 
   // Chain the new parameter to the list of implicit parameters.
@@ -36844,7 +36843,10 @@ synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
   else
     parser->implicit_template_parms = new_parm;
 
-  tree new_type = TREE_TYPE (getdecls ());
+  tree new_decl = getdecls ();
+  if (non_type)
+    /* Return the TEMPLATE_PARM_INDEX, not the PARM_DECL.  */
+    new_decl = DECL_INITIAL (new_decl);
 
   /* If creating a fully implicit function template, start the new implicit
      template parameter list with this synthesized type, otherwise grow the
@@ -36878,7 +36880,7 @@ synthesize_implicit_template_parm  (cp_parser *parser, tree constr)
 
   current_binding_level = entry_scope;
 
-  return new_type;
+  return new_decl;
 }
 
 /* Finish the declaration of a fully implicit function template.  Such a
index c6b74571954ee419de83993bb235573e78ddb88f..1e975108257b5c3c75c234ac5c322a0fe4fb49b6 100644 (file)
@@ -11,8 +11,8 @@ template<template<typename> class X>
 
 struct S { };
 
-void f1(Int) { }      // { dg-error "invalid" }
-void f2(Template) { } // { dg-error "invalid" }
+void f1(Int) { }      // { dg-error "" }
+void f2(Template) { } // { dg-error "" }
 
 struct S1 {
   void f1(auto x) { }
diff --git a/gcc/testsuite/g++.dg/concepts/placeholder6.C b/gcc/testsuite/g++.dg/concepts/placeholder6.C
new file mode 100644 (file)
index 0000000..7f2e67a
--- /dev/null
@@ -0,0 +1,10 @@
+// { dg-options -std=c++1z }
+
+template <int I> struct B { static const int i = I; };
+template <int I> concept bool Few = I < 10;
+
+constexpr int g(B<Few> b) { return b.i; }
+
+#define SA(X) static_assert((X),#X)
+SA(g(B<2>{}) == 2);
+SA(g(B<10>{}) == 10);          // { dg-error "" }