Patchwork Implement N4051 - Allow typename in a template template parameter

login
register
mail settings
Submitter Ed Smith-Rowland
Date July 22, 2014, 12:53 p.m.
Message ID <53CE5EB2.2090209@verizon.net>
Download mbox | patch
Permalink /patch/372459/
State New
Headers show

Comments

Ed Smith-Rowland - July 22, 2014, 12:53 p.m.
On 07/22/2014 01:56 AM, Ville Voutilainen wrote:
> +/* Parse a type-parameter-key.
> +
> +   type-parameter-key:
> +     class
> +     typedef
> +
> +   Returns the kind of type-parameter-key specified, or none_type to indicate
> +   error.  */
> +
>
> Typo above, should be typename, not typedef.
>
Thanks!

New patch..

OK?
cp/

2014-07-22  Edward Smith-Rowland  <3dw4rd@verizon.net>

	Implement N4051 - Allow typename in a template template parameter
	* parser.c (enum required_token): Add RT_TYPE_PARAMETER_KEY;
	(cp_parser_type_parameter_key): New funtion;
	(cp_parser_token_is_type_parameter_key): Ditto;
	(cp_parser_type_parameter): Look for type-parameter-key for cxx1z or
	or greater; (cp_parser_required_error): Error for RT_TYPE_PARAMETER_KEY.


testsuite/

2014-07-22  Edward Smith-Rowland  <3dw4rd@verizon.net>

	Implement N4051 - Allow typename in a template template parameter
	* g++.dg/cpp1z/typename-tmpl-tmpl-parm.C: New.
ville - July 22, 2014, 4:56 p.m.
On 22 July 2014 15:53, Ed Smith-Rowland <3dw4rd@verizon.net> wrote:
> On 07/22/2014 01:56 AM, Ville Voutilainen wrote:
>>
>> +/* Parse a type-parameter-key.
>> +
>> +   type-parameter-key:
>> +     class
>> +     typedef
>> +
>> +   Returns the kind of type-parameter-key specified, or none_type to
>> indicate
>> +   error.  */
>> +
>>
>> Typo above, should be typename, not typedef.
>>
> Thanks!
>
> New patch..
>
> OK?


Just my 2 cents - the test in the patch doesn't seem to test the error
diagnostics. The patch
amends some of those diagnostics, so I don't think existing tests cover those.
Jason Merrill - July 23, 2014, 10:05 a.m.
On 07/22/2014 01:53 PM, Ed Smith-Rowland wrote:
> +	if (cxx_dialect < cxx1z)
> +	  {
> +	    /* Look for the `class' keyword.  */
> +	    cp_parser_require_keyword (parser, RID_CLASS, RT_CLASS);
> +	  }
> +	else
> +	  {
> +	    /* Look for the `class' or 'typename' keywords.  */
> +	    enum tag_types tag_type = cp_parser_type_parameter_key (parser);
> +	    if (tag_type == none_type)
> +	      return error_mark_node;
> +	  }

Let's encapsulate this in cp_parser_type_parameter_key.  And also accept 
'typename' in lower dialects with a pedwarn.

Jason

Patch

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 178114d..dd5ddac 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -177,6 +177,7 @@  typedef enum required_token {
   RT_INTERATION, /* iteration-statement */
   RT_JUMP, /* jump-statement */
   RT_CLASS_KEY, /* class-key */
+  RT_TYPE_PARAMETER_KEY, /* type-parameter-key */
   RT_CLASS_TYPENAME_TEMPLATE, /* class, typename, or template */
   RT_TRANSACTION_ATOMIC, /* __transaction_atomic */
   RT_TRANSACTION_RELAXED, /* __transaction_relaxed */
@@ -2151,6 +2152,8 @@  static tree cp_parser_class_head
   (cp_parser *, bool *);
 static enum tag_types cp_parser_class_key
   (cp_parser *);
+static enum tag_types cp_parser_type_parameter_key
+  (cp_parser* parser);
 static void cp_parser_member_specification_opt
   (cp_parser *);
 static void cp_parser_member_declaration
@@ -2409,6 +2412,8 @@  static bool cp_parser_nth_token_starts_template_argument_list_p
   (cp_parser *, size_t);
 static enum tag_types cp_parser_token_is_class_key
   (cp_token *);
+static enum tag_types cp_parser_token_is_type_parameter_key
+  (cp_token *);
 static void cp_parser_check_class_key
   (enum tag_types, tree type);
 static void cp_parser_check_access_in_redeclaration
@@ -13375,8 +13380,18 @@  cp_parser_type_parameter (cp_parser* parser, bool *is_parameter_pack)
 	cp_parser_template_parameter_list (parser);
 	/* Look for the `>'.  */
 	cp_parser_require (parser, CPP_GREATER, RT_GREATER);
-	/* Look for the `class' keyword.  */
-	cp_parser_require_keyword (parser, RID_CLASS, RT_CLASS);
+	if (cxx_dialect < cxx1z)
+	  {
+	    /* Look for the `class' keyword.  */
+	    cp_parser_require_keyword (parser, RID_CLASS, RT_CLASS);
+	  }
+	else
+	  {
+	    /* Look for the `class' or 'typename' keywords.  */
+	    enum tag_types tag_type = cp_parser_type_parameter_key (parser);
+	    if (tag_type == none_type)
+	      return error_mark_node;
+	  }
         /* If the next token is an ellipsis, we have a template
            argument pack. */
         if (cp_lexer_next_token_is (parser->lexer, CPP_ELLIPSIS))
@@ -20258,6 +20273,33 @@  cp_parser_class_key (cp_parser* parser)
   return tag_type;
 }
 
+/* Parse a type-parameter-key.
+
+   type-parameter-key:
+     class
+     typename
+
+   Returns the kind of type-parameter-key specified, or none_type to indicate
+   error.  */
+
+static enum tag_types
+cp_parser_type_parameter_key (cp_parser* parser)
+{
+  cp_token *token;
+  enum tag_types tag_type;
+
+  /* Look for the type-parameter-key.  */
+  token = cp_parser_require (parser, CPP_KEYWORD, RT_TYPE_PARAMETER_KEY);
+  if (!token)
+    return none_type;
+
+  /* Check to see if the TOKEN is a type-parameter-key.  */
+  tag_type = cp_parser_token_is_type_parameter_key (token);
+  if (!tag_type)
+    cp_parser_error (parser, "expected type-parameter-key");
+  return tag_type;
+}
+
 /* Parse an (optional) member-specification.
 
    member-specification:
@@ -24543,6 +24585,9 @@  cp_parser_required_error (cp_parser *parser,
 	  case RT_CLASS_KEY:
 	    cp_parser_error (parser, "expected class-key");
 	    return;
+	  case RT_TYPE_PARAMETER_KEY:
+	    cp_parser_error (parser, "expected %<class%> or %<typename%>");
+	    return;
 	  case RT_CLASS_TYPENAME_TEMPLATE:
 	    cp_parser_error (parser,
 	  	 "expected %<class%>, %<typename%>, or %<template%>");
@@ -24776,6 +24821,24 @@  cp_parser_token_is_class_key (cp_token* token)
     }
 }
 
+/* Returns the kind of tag indicated by TOKEN, if it is a type-parameter-key,
+   or none_type otherwise.  */
+
+static enum tag_types
+cp_parser_token_is_type_parameter_key (cp_token* token)
+{
+  switch (token->keyword)
+    {
+    case RID_CLASS:
+      return class_type;
+    case RID_TYPENAME:
+      return typename_type;
+
+    default:
+      return none_type;
+    }
+}
+
 /* Issue an error message if the CLASS_KEY does not match the TYPE.  */
 
 static void
diff --git a/gcc/testsuite/g++.dg/cpp1z/typename-tmpl-tmpl-parm.C b/gcc/testsuite/g++.dg/cpp1z/typename-tmpl-tmpl-parm.C
new file mode 100644
index 0000000..0a4e26f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/typename-tmpl-tmpl-parm.C
@@ -0,0 +1,21 @@ 
+// { dg-options "-std=c++1z" }
+
+template<typename T>
+  struct A {};
+
+template<typename T>
+  using B = int;
+
+template<template<typename> class X>
+  struct C {};
+
+C<A> ca;
+
+C<B> cb;
+
+template<template<typename> typename X>
+  struct D {};
+
+D<A> da;
+
+D<B> db;