aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNathan Sidwell <nathan@acm.org>2020-08-04 09:24:02 -0700
committerNathan Sidwell <nathan@acm.org>2020-08-04 09:32:18 -0700
commit0f4f9bc12201c9cda9558295a4fef58fe0246b44 (patch)
tree0fe04fa020cb1b07bb207d25f0ceaac11bec9ef9
parent35ffd4d16d7e3dbba297da788414a673530b7817 (diff)
downloadgcc-0f4f9bc12201c9cda9558295a4fef58fe0246b44.zip
gcc-0f4f9bc12201c9cda9558295a4fef58fe0246b44.tar.gz
gcc-0f4f9bc12201c9cda9558295a4fef58fe0246b44.tar.bz2
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.
-rw-r--r--gcc/cp/parser.c51
-rw-r--r--gcc/testsuite/g++.dg/template/pr39425.C8
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/spec20.C5
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<unsigned int s>
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 <class U> void f(U);
template <> void f<int>(int); // { dg-error "20:template-id .f<int>. in declaration|explicit specialization" }
- template <class V> struct I {}; // { dg-error "template" }
- template <class V> struct I<V*> {}; // { dg-error "template" }
+ template <class V> struct I {};
+ template <class V> struct I<V*> {};
+
template <> struct I<int>; // { dg-error "" } invalid specialization
};