From 0f4f9bc12201c9cda9558295a4fef58fe0246b44 Mon Sep 17 00:00:00 2001 From: Nathan Sidwell Date: Tue, 4 Aug 2020 09:24:02 -0700 Subject: [PATCH] c++: fix template parm count leak I noticed that we could leak parser->num_template_parameter_lists with erroneous specializations. We'd increment, notice a problem and then bail out. This refactors cp_parser_explicit_specialization to avoid that code path. A couple of tests get different diagnostics because of the fix. pr39425 then goes to unbounded template instantiation and exceeds the implementation limit. gcc/cp/ * parser.c (cp_parser_explicit_specialization): Refactor to avoid leak of num_template_parameter_lists value. gcc/testsuite/ * g++.dg/template/pr39425.C: Adjust errors, (unbounded template recursion). * g++.old-deja/g++.pt/spec20.C: Remove fallout diagnostics. --- gcc/cp/parser.c | 51 +++++++++++++++--------------- gcc/testsuite/g++.dg/template/pr39425.C | 8 +++-- gcc/testsuite/g++.old-deja/g++.pt/spec20.C | 5 +-- 3 files changed, 34 insertions(+), 30 deletions(-) diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c index 7657145..1e7cd19 100644 --- a/gcc/cp/parser.c +++ b/gcc/cp/parser.c @@ -17653,7 +17653,6 @@ cp_parser_explicit_instantiation (cp_parser* parser) static void cp_parser_explicit_specialization (cp_parser* parser) { - bool need_lang_pop; cp_token *token = cp_lexer_peek_token (parser->lexer); /* Look for the `template' keyword. */ @@ -17664,52 +17663,54 @@ cp_parser_explicit_specialization (cp_parser* parser) cp_parser_require (parser, CPP_GREATER, RT_GREATER); /* We have processed another parameter list. */ ++parser->num_template_parameter_lists; + /* [temp] A template ... explicit specialization ... shall not have C linkage. */ - if (current_lang_name == lang_name_c) + bool need_lang_pop = current_lang_name == lang_name_c; + if (need_lang_pop) { error_at (token->location, "template specialization with C linkage"); maybe_show_extern_c_location (); + /* Give it C++ linkage to avoid confusing other parts of the front end. */ push_lang_context (lang_name_cplusplus); need_lang_pop = true; } - else - need_lang_pop = false; - /* Let the front end know that we are beginning a specialization. */ - if (!begin_specialization ()) - { - end_specialization (); - return; - } - /* If the next keyword is `template', we need to figure out whether - or not we're looking a template-declaration. */ - if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE)) + /* Let the front end know that we are beginning a specialization. */ + if (begin_specialization ()) { - if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_LESS - && cp_lexer_peek_nth_token (parser->lexer, 3)->type != CPP_GREATER) - cp_parser_template_declaration_after_export (parser, - /*member_p=*/false); + /* If the next keyword is `template', we need to figure out + whether or not we're looking a template-declaration. */ + if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TEMPLATE)) + { + if (cp_lexer_peek_nth_token (parser->lexer, 2)->type == CPP_LESS + && cp_lexer_peek_nth_token (parser->lexer, 3)->type != CPP_GREATER) + cp_parser_template_declaration_after_export (parser, + /*member_p=*/false); + else + cp_parser_explicit_specialization (parser); + } else - cp_parser_explicit_specialization (parser); + /* Parse the dependent declaration. */ + cp_parser_single_declaration (parser, + /*checks=*/NULL, + /*member_p=*/false, + /*explicit_specialization_p=*/true, + /*friend_p=*/NULL); } - else - /* Parse the dependent declaration. */ - cp_parser_single_declaration (parser, - /*checks=*/NULL, - /*member_p=*/false, - /*explicit_specialization_p=*/true, - /*friend_p=*/NULL); + /* We're done with the specialization. */ end_specialization (); + /* For the erroneous case of a template with C linkage, we pushed an implicit C++ linkage scope; exit that scope now. */ if (need_lang_pop) pop_lang_context (); + /* We're done with this parameter list. */ --parser->num_template_parameter_lists; } diff --git a/gcc/testsuite/g++.dg/template/pr39425.C b/gcc/testsuite/g++.dg/template/pr39425.C index d55f547..cd30489 100644 --- a/gcc/testsuite/g++.dg/template/pr39425.C +++ b/gcc/testsuite/g++.dg/template/pr39425.C @@ -5,14 +5,16 @@ class a { template struct _rec { - static const char size = _rec< (s >> 1) >::size; + static const char size = _rec< (s >> 1) >::size; // { dg-error "depth" } }; template<> // { dg-error "explicit" } - struct _rec <0> { + struct _rec <0> { // { dg-error "too few" } static const char size = 0; }; static const unsigned int value = _rec < 1 >::size; -} // { dg-error "after class definition" } +}; + +// { dg-prune-output "compilation terminated" } diff --git a/gcc/testsuite/g++.old-deja/g++.pt/spec20.C b/gcc/testsuite/g++.old-deja/g++.pt/spec20.C index 610e6c7..51bc269 100644 --- a/gcc/testsuite/g++.old-deja/g++.pt/spec20.C +++ b/gcc/testsuite/g++.old-deja/g++.pt/spec20.C @@ -10,7 +10,8 @@ struct S { template void f(U); template <> void f(int); // { dg-error "20:template-id .f. in declaration|explicit specialization" } - template struct I {}; // { dg-error "template" } - template struct I {}; // { dg-error "template" } + template struct I {}; + template struct I {}; + template <> struct I; // { dg-error "" } invalid specialization }; -- 2.7.4