diff mbox

Implement N4051 - Allow typename in a template template parameter

Message ID 53D06FF0.4080100@verizon.net
State New
Headers show

Commit Message

Ed Smith-Rowland July 24, 2014, 2:31 a.m. UTC
On 07/23/2014 06:05 AM, Jason Merrill wrote:
> 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
>
>
OK,

Here is the latest.  I did the rearranging.
g++ now accepts template<template<typename> typename X> from g++98 on 
with pedwarn.
I also upped the test support lib to support c++1z better (this for 
testing pedwarn for version < cxx1z).

Bootstraps and tests clean on x86_64-linux.

OK?
cp/

2014-07-24  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-24  Edward Smith-Rowland  <3dw4rd@verizon.net>

	Implement N4051 - Allow typename in a template template parameter
	* lib/target-supports.exp (check_effective_target_c++1y): Now
	means C++1y and up.
	(check_effective_target_c++1y_down): New.
	(check_effective_target_c++1z_only): New.
	(check_effective_target_c++1z): New.
	* g++.dg/cpp1z/typename-tmpl-tmpl-parm.C: New.
	* g++.dg/cpp1z/typename-tmpl-tmpl-parm-neg.C: New.
	* g++.dg/cpp1z/typename-tmpl-tmpl-parm-.C: New.

Comments

Jason Merrill July 24, 2014, 3:32 p.m. UTC | #1
On 07/23/2014 10:31 PM, Ed Smith-Rowland wrote:
> +    pedwarn (token->location, OPT_Wpedantic,
> +	     "ISO C++ forbids typename key in template template parameter");

This should mention -std=c++1z.

> +  if (tag_type == none_type)
> +    cp_parser_error (parser, "expected type-parameter-key");
...
> +	  case RT_TYPE_PARAMETER_KEY:
> +	    cp_parser_error (parser, "expected %<class%> or %<typename%>");

It seems unfortunate to have this diagnostic in two places.  I think 
let's not use cp_parser_require here.

Jason
diff mbox

Patch

Index: cp/parser.c
===================================================================
--- cp/parser.c	(revision 212967)
+++ cp/parser.c	(working copy)
@@ -177,6 +177,7 @@ 
   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 @@ 
   (cp_parser *, bool *);
 static enum tag_types cp_parser_class_key
   (cp_parser *);
+static void 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 @@ 
   (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,8 @@ 
 	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);
+	/* Look for the `class' or 'typename' keywords.  */
+	cp_parser_type_parameter_key (parser);
         /* 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 +20263,35 @@ 
   return tag_type;
 }
 
+/* Parse a type-parameter-key.
+
+   type-parameter-key:
+     class
+     typename
+
+ */
+
+static void
+cp_parser_type_parameter_key (cp_parser* parser)
+{
+  /* Look for the type-parameter-key.  */
+  cp_token* token = cp_parser_require (parser, CPP_KEYWORD, RT_TYPE_PARAMETER_KEY);
+  if (!token)
+    return;
+
+  /* Check to see if the TOKEN is a type-parameter-key.  */
+  enum tag_types tag_type = cp_parser_token_is_type_parameter_key (token);
+  if (tag_type == none_type)
+    cp_parser_error (parser, "expected type-parameter-key");
+  else if (pedantic && tag_type == typename_type && cxx_dialect < cxx1z)
+    /* typename is not allowed in a template template parameter
+       by the standard until C++1Z.  */
+    pedwarn (token->location, OPT_Wpedantic, 
+	     "ISO C++ forbids typename key in template template parameter");
+
+  return;
+}
+
 /* Parse an (optional) member-specification.
 
    member-specification:
@@ -24543,6 +24577,9 @@ 
 	  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 +24813,24 @@ 
     }
 }
 
+/* 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
Index: testsuite/lib/target-supports.exp
===================================================================
--- testsuite/lib/target-supports.exp	(revision 212967)
+++ testsuite/lib/target-supports.exp	(working copy)
@@ -5707,8 +5707,17 @@ 
     return [check-flags { { } { } { -std=c++1y -std=gnu++1y -std=c++14 -std=gnu++14 } }]
 }
 proc check_effective_target_c++1y { } {
-    return [check_effective_target_c++1y_only]
+    if [check_effective_target_c++1y_only] {
+	return 1
+    }
+    return [check_effective_target_c++1z]
 }
+proc check_effective_target_c++1y_down { } {
+    if ![check_effective_target_c++] {
+	return 0
+    }
+    return ![check_effective_target_c++1z]
+}
 
 proc check_effective_target_c++98_only { } {
     if ![check_effective_target_c++] {
@@ -5717,6 +5726,16 @@ 
     return ![check_effective_target_c++11]
 }
 
+proc check_effective_target_c++1z_only { } {
+    if ![check_effective_target_c++] {
+	return 0
+    }
+    return [check-flags { { } { } { -std=c++1z -std=gnu++1z } }]
+}
+proc check_effective_target_c++1z { } {
+    return [check_effective_target_c++1z_only]
+}
+
 # Return 1 if expensive testcases should be run.
 
 proc check_effective_target_run_expensive_tests { } {
Index: testsuite/g++.dg/cpp1z/typename-tmpl-tmpl-parm.C
===================================================================
--- testsuite/g++.dg/cpp1z/typename-tmpl-tmpl-parm.C	(revision 0)
+++ testsuite/g++.dg/cpp1z/typename-tmpl-tmpl-parm.C	(working copy)
@@ -0,0 +1,28 @@ 
+// { dg-do compile }
+// { dg-options "" }
+
+template<typename T>
+  struct A {};
+
+#if __cplusplus >= 201103L
+template<typename T>
+  using B = int;
+#endif
+
+template<template<typename> class X>
+  struct C {};
+
+C<A> ca;
+
+#if __cplusplus >= 201103L
+C<B> cb;
+#endif
+
+template<template<typename> typename X>
+  struct D {};
+
+D<A> da;
+
+#if __cplusplus >= 201103L
+D<B> db;
+#endif
Index: testsuite/g++.dg/cpp1z/typename-tmpl-tmpl-parm-neg.C
===================================================================
--- testsuite/g++.dg/cpp1z/typename-tmpl-tmpl-parm-neg.C	(revision 0)
+++ testsuite/g++.dg/cpp1z/typename-tmpl-tmpl-parm-neg.C	(working copy)
@@ -0,0 +1,8 @@ 
+// { dg-do compile }
+// { dg-options "" }
+
+template<template<typename> struct X> // { dg-error "expected type-parameter-key before" }
+  struct D {};
+
+template<template<typename> X> // { dg-error "expected .class. or .typename. before" }
+  struct E {};
Index: testsuite/g++.dg/cpp1z/typename-tmpl-tmpl-parm-ped-neg.C
===================================================================
--- testsuite/g++.dg/cpp1z/typename-tmpl-tmpl-parm-ped-neg.C	(revision 0)
+++ testsuite/g++.dg/cpp1z/typename-tmpl-tmpl-parm-ped-neg.C	(working copy)
@@ -0,0 +1,28 @@ 
+// { dg-do compile { target c++1y_down } }
+// { dg-options "-pedantic" }
+
+template<typename T>
+  struct A {};
+
+#if __cplusplus >= 201103L
+template<typename T>
+  using B = int;
+#endif
+
+template<template<typename> class X>
+  struct C {};
+
+C<A> ca;
+
+#if __cplusplus >= 201103L
+C<B> cb;
+#endif
+
+template<template<typename> typename X> // { dg-warning "ISO C.. forbids typename key in template template parameter" }
+  struct D {};
+
+D<A> da;
+
+#if __cplusplus >= 201103L
+D<B> db;
+#endif