diff mbox series

c++: fix template parm count leak

Message ID 679c10ee-ba72-b1e0-190a-d221afd79b47@acm.org
State New
Headers show
Series c++: fix template parm count leak | expand

Commit Message

Nathan Sidwell Aug. 4, 2020, 4:32 p.m. UTC
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.

pushed,

nathan
diff mbox series

Patch

diff --git i/gcc/cp/parser.c w/gcc/cp/parser.c
index ab088874ba7..9946acdb42f 100644
--- i/gcc/cp/parser.c
+++ w/gcc/cp/parser.c
@@ -17640,7 +17640,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.  */
@@ -17651,52 +17650,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 i/gcc/testsuite/g++.dg/template/pr39425.C w/gcc/testsuite/g++.dg/template/pr39425.C
index d55f547e253..cd304896a61 100644
--- i/gcc/testsuite/g++.dg/template/pr39425.C
+++ w/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 i/gcc/testsuite/g++.old-deja/g++.pt/spec20.C w/gcc/testsuite/g++.old-deja/g++.pt/spec20.C
index 610e6c73371..51bc26906eb 100644
--- i/gcc/testsuite/g++.old-deja/g++.pt/spec20.C
+++ w/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
 };