On 07/24/2014 11:32 AM, Jason Merrill wrote:
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
OK, here is another round..
Error handling collapsed. Got rid of RT_TYPE_PARAMETER_KEY and uses
altogether.
Built and tested clean on x86_64-linux. OK?
Ed
cp/
2014-07-25 Edward Smith-Rowland <3dw...@verizon.net>
Implement N4051 - Allow typename in a template template parameter
* parser.c (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 all versions
but pedwarn for less than cxx1z.
testsuite/
2014-07-25 Edward Smith-Rowland <3dw...@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.
Index: cp/parser.c
===================================================================
--- cp/parser.c (revision 212967)
+++ cp/parser.c (working copy)
@@ -2151,6 +2151,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 +2411,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 +13379,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 +20262,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. */
+ enum tag_types tag_type = none_type;
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ if ((tag_type = cp_parser_token_is_type_parameter_key (token)) != none_type)
+ {
+ cp_lexer_consume_token (parser->lexer);
+ 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;"
+ " use -std=c++1z or -std=gnu++1z");
+ }
+ else
+ cp_parser_error (parser, "expected %<class%> or %<typename%>");
+
+ return;
+}
+
/* Parse an (optional) member-specification.
member-specification:
@@ -24776,6 +24809,27 @@
}
}
+/* Returns the kind of tag indicated by TOKEN, if it is a type-parameter-key,
+ or none_type otherwise or if the token is null. */
+
+static enum tag_types
+cp_parser_token_is_type_parameter_key (cp_token* token)
+{
+ if (!token)
+ return none_type;
+
+ 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,11 @@
+// { dg-do compile }
+// { dg-options "" }
+
+template<template<typename> struct X> // { dg-error "expected .class. or
.typename. before" }
+ struct D {};
+
+template<template<typename> X> // { dg-error "expected .class. or .typename.
before" }
+ struct E {};
+
+// { dg-error "expected identifier" "expected" { target *-*-* } 4 }
+// { dg-error "expected .>." "expected" { target *-*-* } 4 }
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