c++: fix template parm count leak
authorNathan Sidwell <nathan@acm.org>
Tue, 4 Aug 2020 16:24:02 +0000 (09:24 -0700)
committerNathan Sidwell <nathan@acm.org>
Tue, 4 Aug 2020 16:32:18 +0000 (09:32 -0700)
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
gcc/testsuite/g++.dg/template/pr39425.C
gcc/testsuite/g++.old-deja/g++.pt/spec20.C

index 7657145..1e7cd19 100644 (file)
@@ -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;
 }
index d55f547..cd30489 100644 (file)
@@ -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" }
index 610e6c7..51bc269 100644 (file)
@@ -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
 };