Hi again,
On 06/03/2018 19:58, Paolo Carlini wrote:
.. grrrr, consider the patch withdrawn in its detailed form, I have a
new testcase which add some random code after that ill-formed class
and it's mishandled, it ICEs again.
The below avoids the idiotic thinko (I added a testcase for that) and is
likewise passing testing.
Thanks,
Paolo.
/////////////////////////
Index: cp/parser.c
===================================================================
--- cp/parser.c (revision 258264)
+++ cp/parser.c (working copy)
@@ -565,6 +565,8 @@ cp_debug_parser (FILE *file, cp_parser *parser)
"local class", parser->in_function_body);
cp_debug_print_flag (file, "Auto correct a colon to a scope operator",
parser->colon_corrects_to_scope_p);
+ cp_debug_print_flag (file, "Error in template parameter list",
+ parser->error_in_template_parameter_list_p);
cp_debug_print_flag (file, "Colon doesn't start a class definition",
parser->colon_doesnt_start_class_def_p);
if (parser->type_definition_forbidden_message)
@@ -3910,6 +3912,9 @@ cp_parser_new (void)
/* We can correct until told otherwise. */
parser->colon_corrects_to_scope_p = true;
+ /* No error so far. */
+ parser->error_in_template_parameter_list_p = false;
+
/* The unparsed function queue is empty. */
push_unparsed_function_queues (parser);
@@ -10151,6 +10156,8 @@ cp_parser_lambda_expression (cp_parser* parser)
/* Inside the class, surrounding template-parameter-lists do not apply. */
unsigned int saved_num_template_parameter_lists
= parser->num_template_parameter_lists;
+ bool saved_error_in_template_parameter_list_p
+ = parser->error_in_template_parameter_list_p;
unsigned char in_statement = parser->in_statement;
bool in_switch_statement_p = parser->in_switch_statement_p;
bool fully_implicit_function_template_p
@@ -10161,6 +10168,7 @@ cp_parser_lambda_expression (cp_parser* parser)
= parser->auto_is_implicit_function_template_parm_p;
parser->num_template_parameter_lists = 0;
+ parser->error_in_template_parameter_list_p = false;
parser->in_statement = 0;
parser->in_switch_statement_p = false;
parser->fully_implicit_function_template_p = false;
@@ -10199,6 +10207,8 @@ cp_parser_lambda_expression (cp_parser* parser)
type = finish_struct (type, /*attributes=*/NULL_TREE);
parser->num_template_parameter_lists = saved_num_template_parameter_lists;
+ parser->error_in_template_parameter_list_p
+ = saved_error_in_template_parameter_list_p;
parser->in_statement = in_statement;
parser->in_switch_statement_p = in_switch_statement_p;
parser->fully_implicit_function_template_p
@@ -10624,7 +10634,8 @@ cp_parser_lambda_declarator_opt (cp_parser* parser
{
fco = finish_member_template_decl (fco);
finish_template_decl (template_param_list);
- --parser->num_template_parameter_lists;
+ if (--parser->num_template_parameter_lists == 0)
+ parser->error_in_template_parameter_list_p = false;
}
else if (parser->fully_implicit_function_template_p)
fco = finish_fully_implicit_template (parser, fco);
@@ -15065,6 +15076,11 @@ cp_parser_template_parameter_list (cp_parser* pars
parameter_list = chainon (parameter_list, err_parm);
}
+ if (parameter == error_mark_node
+ || error_operand_p (TREE_VALUE (parameter))
+ || error_operand_p (TREE_PURPOSE (parameter)))
+ parser->error_in_template_parameter_list_p = true;
+
/* If the next token is not a `,', we're done. */
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
break;
@@ -16673,7 +16689,8 @@ cp_parser_explicit_specialization (cp_parser* pars
if (need_lang_pop)
pop_lang_context ();
/* We're done with this parameter list. */
- --parser->num_template_parameter_lists;
+ if (--parser->num_template_parameter_lists == 0)
+ parser->error_in_template_parameter_list_p = false;
}
/* Parse a type-specifier.
@@ -22438,6 +22455,7 @@ cp_parser_class_specifier_1 (cp_parser* parser)
tree attributes = NULL_TREE;
bool nested_name_specifier_p;
unsigned saved_num_template_parameter_lists;
+ bool saved_error_in_template_parameter_list_p;
bool saved_in_function_body;
unsigned char in_statement;
bool in_switch_statement_p;
@@ -22480,6 +22498,9 @@ cp_parser_class_specifier_1 (cp_parser* parser)
saved_num_template_parameter_lists
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
+ saved_error_in_template_parameter_list_p
+ = parser->error_in_template_parameter_list_p;
+ parser->error_in_template_parameter_list_p = false;
/* We are not in a function body. */
saved_in_function_body = parser->in_function_body;
parser->in_function_body = false;
@@ -22658,8 +22679,13 @@ cp_parser_class_specifier_1 (cp_parser* parser)
struct A::B { void f() { } };
there is no need to delay the parsing of `A::B::f'. */
- if (--parser->num_classes_being_defined == 0)
+ if (saved_error_in_template_parameter_list_p)
{
+ /* Do nothing, we skip the bodies in order to improve error
+ recovery (c++/71169, c++/71832, etc). */;
+ }
+ else if (--parser->num_classes_being_defined == 0)
+ {
tree decl;
tree class_type = NULL_TREE;
tree pushed_scope = NULL_TREE;
@@ -22752,6 +22778,8 @@ cp_parser_class_specifier_1 (cp_parser* parser)
parser->in_function_body = saved_in_function_body;
parser->num_template_parameter_lists
= saved_num_template_parameter_lists;
+ parser->error_in_template_parameter_list_p
+ = saved_error_in_template_parameter_list_p;
parser->in_unbraced_linkage_specification_p
= saved_in_unbraced_linkage_specification_p;
@@ -23253,7 +23281,8 @@ cp_parser_class_head (cp_parser* parser,
if (invalid_explicit_specialization_p)
{
end_specialization ();
- --parser->num_template_parameter_lists;
+ if (--parser->num_template_parameter_lists == 0)
+ parser->error_in_template_parameter_list_p = false;
}
if (type)
@@ -26616,6 +26645,7 @@ cp_parser_constructor_declarator_p (cp_parser *par
tree type;
tree pushed_scope = NULL_TREE;
unsigned saved_num_template_parameter_lists;
+ bool saved_error_in_template_parameter_list_p;
/* Names appearing in the type-specifier should be looked up
in the scope of the class. */
@@ -26642,6 +26672,9 @@ cp_parser_constructor_declarator_p (cp_parser *par
saved_num_template_parameter_lists
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
+ saved_error_in_template_parameter_list_p
+ = parser->error_in_template_parameter_list_p;
+ parser->error_in_template_parameter_list_p = false;
/* Look for the type-specifier. */
cp_parser_type_specifier (parser,
@@ -26653,6 +26686,8 @@ cp_parser_constructor_declarator_p (cp_parser *par
parser->num_template_parameter_lists
= saved_num_template_parameter_lists;
+ parser->error_in_template_parameter_list_p
+ = saved_error_in_template_parameter_list_p;
/* Leave the scope of the class. */
if (pushed_scope)
@@ -26751,6 +26786,7 @@ cp_parser_function_definition_after_declarator (cp
bool saved_in_unbraced_linkage_specification_p;
bool saved_in_function_body;
unsigned saved_num_template_parameter_lists;
+ bool saved_error_in_template_parameter_list_p;
cp_token *token;
bool fully_implicit_function_template_p
= parser->fully_implicit_function_template_p;
@@ -26799,6 +26835,9 @@ cp_parser_function_definition_after_declarator (cp
saved_num_template_parameter_lists
= parser->num_template_parameter_lists;
parser->num_template_parameter_lists = 0;
+ saved_error_in_template_parameter_list_p
+ = parser->error_in_template_parameter_list_p;
+ parser->error_in_template_parameter_list_p = false;
/* If the next token is `try', `__transaction_atomic', or
`__transaction_relaxed`, then we are looking at either function-try-block
@@ -26824,6 +26863,8 @@ cp_parser_function_definition_after_declarator (cp
= saved_in_unbraced_linkage_specification_p;
parser->num_template_parameter_lists
= saved_num_template_parameter_lists;
+ parser->error_in_template_parameter_list_p
+ = saved_error_in_template_parameter_list_p;
parser->in_function_body = saved_in_function_body;
parser->fully_implicit_function_template_p
@@ -26893,7 +26934,8 @@ cp_parser_template_declaration_after_parameters (c
/*complain=*/true);
}
/* We are done with the current parameter list. */
- --parser->num_template_parameter_lists;
+ if (--parser->num_template_parameter_lists == 0)
+ parser->error_in_template_parameter_list_p = false;
pop_deferring_access_checks ();
@@ -39249,7 +39291,8 @@ finish_fully_implicit_template (cp_parser *parser,
end_template_decl ();
parser->fully_implicit_function_template_p = false;
- --parser->num_template_parameter_lists;
+ if (--parser->num_template_parameter_lists == 0)
+ parser->error_in_template_parameter_list_p = false;
return member_decl_opt;
}
Index: cp/parser.h
===================================================================
--- cp/parser.h (revision 258264)
+++ cp/parser.h (working copy)
@@ -346,6 +346,9 @@ struct GTY(()) cp_parser {
is terminated by colon. */
bool colon_doesnt_start_class_def_p;
+ /* TRUE if there was an error in a template parameter list. */
+ bool error_in_template_parameter_list_p;
+
/* If non-NULL, then we are parsing a construct where new type
definitions are not permitted. The string stored here will be
issued as an error message if a type is defined. */
Index: testsuite/g++.dg/cpp0x/pr71169-2.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr71169-2.C (nonexistent)
+++ testsuite/g++.dg/cpp0x/pr71169-2.C (working copy)
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+template <Preconditioner> class A { // { dg-error "declared" }
+ template <class = int> void m_fn1() {
+ m_fn1();
+ }
+};
+
+template<typename>
+struct B
+{
+ int f() { return 0; }
+};
+
+int main()
+{
+ B<int> b;
+ return b.f();
+}
Index: testsuite/g++.dg/cpp0x/pr71169.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr71169.C (nonexistent)
+++ testsuite/g++.dg/cpp0x/pr71169.C (working copy)
@@ -0,0 +1,7 @@
+// { dg-do compile { target c++11 } }
+
+template <Preconditioner> class A { // { dg-error "declared" }
+ template <class = int> void m_fn1() {
+ m_fn1();
+ }
+};
Index: testsuite/g++.dg/cpp0x/pr71832.C
===================================================================
--- testsuite/g++.dg/cpp0x/pr71832.C (nonexistent)
+++ testsuite/g++.dg/cpp0x/pr71832.C (working copy)
@@ -0,0 +1,7 @@
+// { dg-do compile { target c++11 } }
+
+template < typename decltype (0) > struct A // { dg-error "expected|two or
more" }
+{
+ void foo () { baz (); }
+ template < typename ... S > void baz () {}
+};