Patchwork [C++,RFC] Support named type capture for generic lambdas and generic functions as proposed by N3878

login
register
mail settings
Submitter Adam Butcher
Date March 25, 2014, 7:03 a.m.
Message ID <1395731034-14803-1-git-send-email-adam@jessamine.co.uk>
Download mbox | patch
Permalink /patch/333293/
State New
Headers show

Comments

Adam Butcher - March 25, 2014, 7:03 a.m.
* parser.c (cp_parser_simple_type_specifier): Lookahead for a braced
	identifier after a generic type ('auto') parameter and, if present, use
	that as the type identifier name.  Otherwise generate one with
	make_generic_type_name.  Pass the resulting identifier as the new second
	parameter ...
	(synthesize_implicit_template_parm): ... here.  Synthesize the template
	type parm with the provided name rather than generating one.

	* g++.dg/cpp1y/generic-fn-typeid.C: New testcase.
---
 gcc/cp/parser.c                                | 55 +++++++++++++++++++++-----
 gcc/testsuite/g++.dg/cpp1y/generic-fn-typeid.C | 42 ++++++++++++++++++++
 2 files changed, 88 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp1y/generic-fn-typeid.C
Andrew Sutton - March 25, 2014, 12:49 p.m.
It's not clear that this feature will be part of concepts. It will not
be included in the initial working paper, so the proposal will need to
be re-evaluated.

Andrew


On Tue, Mar 25, 2014 at 3:03 AM, Adam Butcher <adam@jessamine.co.uk> wrote:
>         * parser.c (cp_parser_simple_type_specifier): Lookahead for a braced
>         identifier after a generic type ('auto') parameter and, if present, use
>         that as the type identifier name.  Otherwise generate one with
>         make_generic_type_name.  Pass the resulting identifier as the new second
>         parameter ...
>         (synthesize_implicit_template_parm): ... here.  Synthesize the template
>         type parm with the provided name rather than generating one.
>
>         * g++.dg/cpp1y/generic-fn-typeid.C: New testcase.
> ---
>  gcc/cp/parser.c                                | 55 +++++++++++++++++++++-----
>  gcc/testsuite/g++.dg/cpp1y/generic-fn-typeid.C | 42 ++++++++++++++++++++
>  2 files changed, 88 insertions(+), 9 deletions(-)
>  create mode 100644 gcc/testsuite/g++.dg/cpp1y/generic-fn-typeid.C
>
> diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
> index 49fb731..4d6f8fe 100644
> --- a/gcc/cp/parser.c
> +++ b/gcc/cp/parser.c
> @@ -2128,8 +2128,10 @@ static tree cp_parser_late_parsing_omp_declare_simd
>  static tree cp_parser_late_parsing_cilk_simd_fn_info
>    (cp_parser *, tree);
>
> +static tree make_generic_type_name
> +  ();
>  static tree synthesize_implicit_template_parm
> -  (cp_parser *);
> +  (cp_parser *, tree);
>  static tree finish_fully_implicit_template
>    (cp_parser *, tree);
>
> @@ -14530,23 +14532,58 @@ cp_parser_simple_type_specifier (cp_parser* parser,
>        maybe_warn_cpp0x (CPP0X_AUTO);
>        if (parser->auto_is_implicit_function_template_parm_p)
>         {
> -         type = synthesize_implicit_template_parm (parser);
> +         /* Synthesize an implicit template parameter named as specified by
> +            the IDENTIFIER_NODE of a braced identifier (as proposed by section
> +            2.2 of N3878).  If no braced identifier is present then a name is
> +            generated a via make_generic_type_name.  */
> +
> +         if (cp_lexer_peek_nth_token
> +             (parser->lexer, 2)->type == CPP_OPEN_BRACE)
> +           {
> +             /* The 'auto' has only been peeked and is expected to be consumed
> +                later; parse the braced identifier leaving the closing brace as
> +                the next token.  */
> +
> +             cp_lexer_consume_token (parser->lexer); /* RID_AUTO */
> +             cp_lexer_consume_token (parser->lexer); /* CPP_OPEN_BRACE */
> +
> +             tree synth_id = cp_parser_identifier (parser);
> +             if (synth_id != error_mark_node)
> +               type = synthesize_implicit_template_parm (parser, synth_id);
> +
> +             if (cp_parser_require
> +                 (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE) == 0
> +                 || synth_id == error_mark_node)
> +               {
> +                 error_at (input_location,
> +                    "expected braced identifier for generic type capture");
> +                 return error_mark_node;
> +               }
> +
> +             /* Roll-back one token to allow for consume below.  */
> +             cp_lexer_set_token_position (parser->lexer,
> +                                          cp_lexer_previous_token_position
> +                                          (parser->lexer));
> +           }
> +         else
> +           type = synthesize_implicit_template_parm
> +             (parser, make_generic_type_name ());
>
>           if (current_class_type && LAMBDA_TYPE_P (current_class_type))
>             {
>               if (cxx_dialect < cxx1y)
> -               pedwarn (location_of (type), 0,
> +               pedwarn (token->location, 0,
>                          "use of %<auto%> in lambda parameter declaration "
>                          "only available with "
>                          "-std=c++1y or -std=gnu++1y");
>             }
>           else if (cxx_dialect < cxx1y)
> -           pedwarn (location_of (type), 0,
> +           pedwarn (token->location, 0,
>                      "use of %<auto%> in parameter declaration "
>                      "only available with "
>                      "-std=c++1y or -std=gnu++1y");
>           else
> -           pedwarn (location_of (type), OPT_Wpedantic,
> +           pedwarn (token->location, OPT_Wpedantic,
>                      "ISO C++ forbids use of %<auto%> in parameter "
>                      "declaration");
>         }
> @@ -31957,11 +31994,12 @@ tree_type_is_auto_or_concept (const_tree t)
>  }
>
>  /* 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.  */
> +   (creating a new template parameter list if necessary).  The template type
> +   parameter is given the id SYNTH_ID.  Returns the newly created template type
> +   parm.  */
>
>  tree
> -synthesize_implicit_template_parm  (cp_parser *parser)
> +synthesize_implicit_template_parm  (cp_parser *parser, tree synth_id)
>  {
>    gcc_assert (current_binding_level->kind == sk_function_parms);
>
> @@ -32073,7 +32111,6 @@ synthesize_implicit_template_parm  (cp_parser *parser)
>    /* Synthesize a new template parameter and track the current template
>       parameter chain with implicit_template_parms.  */
>
> -  tree synth_id = make_generic_type_name ();
>    tree synth_tmpl_parm = finish_template_type_parm (class_type_node,
>                                                     synth_id);
>    tree new_parm
> diff --git a/gcc/testsuite/g++.dg/cpp1y/generic-fn-typeid.C b/gcc/testsuite/g++.dg/cpp1y/generic-fn-typeid.C
> new file mode 100644
> index 0000000..ab208a4
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/cpp1y/generic-fn-typeid.C
> @@ -0,0 +1,42 @@
> +// Check braced type capture for generic parameter types (from N3878)
> +// { dg-do compile { target c++1y } }
> +// { dg-options "" }
> +
> +auto f(auto {MyType} a, MyType b)
> +{
> +}
> +auto f2(auto {A} a, auto {B} b)
> +{
> +}
> +auto g(auto {g} x)  // { dg-error "declaration|shadows" }
> +{
> +}
> +auto h(auto {x} x)  // { dg-error "declaration|shadows" }
> +{
> +}
> +auto i(auto {})         // { dg-error "braced identifier|auto" }
> +{                // { dg-error "expected" }
> +}
> +auto j(auto {int})  // { dg-error "braced identifier|auto" }
> +{                   // { dg-error "expected" }
> +}
> +auto k(auto {;})  // { dg-error "braced identifier|auto" }
> +{                 // { dg-error "expected" }
> +}
> +
> +int main()
> +{
> +  auto l = [] (auto {X} x1, X x2) {};
> +
> +  l("a", "b");
> +  f("a", "b");
> +  f2("a", "b");
> +
> +  l(1, 2);
> +  f(1, 2);
> +  f2(1, 2);
> +
> +  l(1, 2.d);  // { dg-error "no match" }
> +  f(1, 2.d);  // { dg-error "no match" }
> +  f2(1, 2.d);
> +}
> --
> 1.9.0
>

Patch

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 49fb731..4d6f8fe 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -2128,8 +2128,10 @@  static tree cp_parser_late_parsing_omp_declare_simd
 static tree cp_parser_late_parsing_cilk_simd_fn_info
   (cp_parser *, tree);
 
+static tree make_generic_type_name
+  ();
 static tree synthesize_implicit_template_parm
-  (cp_parser *);
+  (cp_parser *, tree);
 static tree finish_fully_implicit_template
   (cp_parser *, tree);
 
@@ -14530,23 +14532,58 @@  cp_parser_simple_type_specifier (cp_parser* parser,
       maybe_warn_cpp0x (CPP0X_AUTO);
       if (parser->auto_is_implicit_function_template_parm_p)
 	{
-	  type = synthesize_implicit_template_parm (parser);
+	  /* Synthesize an implicit template parameter named as specified by
+	     the IDENTIFIER_NODE of a braced identifier (as proposed by section
+	     2.2 of N3878).  If no braced identifier is present then a name is
+	     generated a via make_generic_type_name.  */
+
+	  if (cp_lexer_peek_nth_token
+	      (parser->lexer, 2)->type == CPP_OPEN_BRACE)
+	    {
+	      /* The 'auto' has only been peeked and is expected to be consumed
+		 later; parse the braced identifier leaving the closing brace as
+		 the next token.  */
+
+	      cp_lexer_consume_token (parser->lexer); /* RID_AUTO */
+	      cp_lexer_consume_token (parser->lexer); /* CPP_OPEN_BRACE */
+
+	      tree synth_id = cp_parser_identifier (parser);
+	      if (synth_id != error_mark_node)
+		type = synthesize_implicit_template_parm (parser, synth_id);
+
+	      if (cp_parser_require
+		  (parser, CPP_CLOSE_BRACE, RT_CLOSE_BRACE) == 0
+		  || synth_id == error_mark_node)
+		{
+		  error_at (input_location,
+		     "expected braced identifier for generic type capture");
+		  return error_mark_node;
+		}
+
+	      /* Roll-back one token to allow for consume below.  */
+	      cp_lexer_set_token_position (parser->lexer,
+					   cp_lexer_previous_token_position
+					   (parser->lexer));
+	    }
+	  else
+	    type = synthesize_implicit_template_parm
+	      (parser, make_generic_type_name ());
 
 	  if (current_class_type && LAMBDA_TYPE_P (current_class_type))
 	    {
 	      if (cxx_dialect < cxx1y)
-		pedwarn (location_of (type), 0,
+		pedwarn (token->location, 0,
 			 "use of %<auto%> in lambda parameter declaration "
 			 "only available with "
 			 "-std=c++1y or -std=gnu++1y");
 	    }
 	  else if (cxx_dialect < cxx1y)
-	    pedwarn (location_of (type), 0,
+	    pedwarn (token->location, 0,
 		     "use of %<auto%> in parameter declaration "
 		     "only available with "
 		     "-std=c++1y or -std=gnu++1y");
 	  else
-	    pedwarn (location_of (type), OPT_Wpedantic,
+	    pedwarn (token->location, OPT_Wpedantic,
 		     "ISO C++ forbids use of %<auto%> in parameter "
 		     "declaration");
 	}
@@ -31957,11 +31994,12 @@  tree_type_is_auto_or_concept (const_tree t)
 }
 
 /* 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.  */
+   (creating a new template parameter list if necessary).  The template type
+   parameter is given the id SYNTH_ID.  Returns the newly created template type
+   parm.  */
 
 tree
-synthesize_implicit_template_parm  (cp_parser *parser)
+synthesize_implicit_template_parm  (cp_parser *parser, tree synth_id)
 {
   gcc_assert (current_binding_level->kind == sk_function_parms);
 
@@ -32073,7 +32111,6 @@  synthesize_implicit_template_parm  (cp_parser *parser)
   /* Synthesize a new template parameter and track the current template
      parameter chain with implicit_template_parms.  */
 
-  tree synth_id = make_generic_type_name ();
   tree synth_tmpl_parm = finish_template_type_parm (class_type_node,
 						    synth_id);
   tree new_parm
diff --git a/gcc/testsuite/g++.dg/cpp1y/generic-fn-typeid.C b/gcc/testsuite/g++.dg/cpp1y/generic-fn-typeid.C
new file mode 100644
index 0000000..ab208a4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/generic-fn-typeid.C
@@ -0,0 +1,42 @@ 
+// Check braced type capture for generic parameter types (from N3878)
+// { dg-do compile { target c++1y } }
+// { dg-options "" }
+
+auto f(auto {MyType} a, MyType b)
+{
+}
+auto f2(auto {A} a, auto {B} b)
+{
+}
+auto g(auto {g} x)  // { dg-error "declaration|shadows" }
+{
+}
+auto h(auto {x} x)  // { dg-error "declaration|shadows" }
+{
+}
+auto i(auto {})	 // { dg-error "braced identifier|auto" }
+{                // { dg-error "expected" }
+}
+auto j(auto {int})  // { dg-error "braced identifier|auto" }
+{                   // { dg-error "expected" }
+}
+auto k(auto {;})  // { dg-error "braced identifier|auto" }
+{                 // { dg-error "expected" }
+}
+
+int main()
+{
+  auto l = [] (auto {X} x1, X x2) {};
+
+  l("a", "b");
+  f("a", "b");
+  f2("a", "b");
+
+  l(1, 2);
+  f(1, 2);
+  f2(1, 2);
+
+  l(1, 2.d);  // { dg-error "no match" }
+  f(1, 2.d);  // { dg-error "no match" }
+  f2(1, 2.d);
+}