diff mbox

C++ PATCH for c++/71604 (type definition in range for)

Message ID CADzB+2n0OkCmj33-7hrQH0_1WcT78ukKjEte_jqtD9NRPa_E2A@mail.gmail.com
State New
Headers show

Commit Message

Jason Merrill July 15, 2016, 4:54 p.m. UTC
This was crashing because the binding hijinks we do to handle the
range-for-declaration weren't dealing well with a class definition.
This patch fixes that, and also adds a diagnostic since that turns out
to be ill-formed.

Tested x86_64-pc-linux-gnu, applying to trunk.
commit adb66c0085a034eddcb7d7467af372331c8db1be
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Jul 14 00:50:14 2016 -0400

    	PR c++/71604 - type definition in range-based for
    
    	PR c++/54430
    	* parser.c (cp_parser_range_for): Modify IDENTIFIER_BINDING directly.
    	(cp_parser_simple_declaration): Diagnose type definition in
    	for-range-declaration.
diff mbox

Patch

diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index ef35aa9..69fb060 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -11187,11 +11187,17 @@  cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
 		     bool ivdep)
 {
   tree stmt, range_expr;
+  cxx_binding *binding = NULL;
+  tree name = NULL_TREE;
 
   /* Get the range declaration momentarily out of the way so that
      the range expression doesn't clash with it. */
   if (range_decl != error_mark_node)
-    pop_binding (DECL_NAME (range_decl), range_decl);
+    {
+      name = DECL_NAME (range_decl);
+      binding = IDENTIFIER_BINDING (name);
+      IDENTIFIER_BINDING (name) = binding->previous;
+    }
 
   if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
     {
@@ -11203,7 +11209,10 @@  cp_parser_range_for (cp_parser *parser, tree scope, tree init, tree range_decl,
 
   /* Put the range declaration back into scope. */
   if (range_decl != error_mark_node)
-    push_binding (DECL_NAME (range_decl), range_decl, current_binding_level);
+    {
+      binding->previous = IDENTIFIER_BINDING (name);
+      IDENTIFIER_BINDING (name) = binding;
+    }
 
   /* If in template, STMT is converted to a normal for-statement
      at instantiation. If not, it is done just ahead. */
@@ -12437,8 +12446,15 @@  cp_parser_simple_declaration (cp_parser* parser,
       if (token->type == CPP_COMMA)
 	/* will be consumed next time around */;
       /* If it's a `;', we are done.  */
-      else if (token->type == CPP_SEMICOLON || maybe_range_for_decl)
+      else if (token->type == CPP_SEMICOLON)
 	break;
+      else if (maybe_range_for_decl)
+	{
+	  if (declares_class_or_enum && token->type == CPP_COLON)
+	    permerror (decl_specifiers.locations[ds_type_spec],
+		       "types may not be defined in a for-range-declaration");
+	  break;
+	}
       /* Anything else is an error.  */
       else
 	{
diff --git a/gcc/testsuite/g++.dg/cpp0x/range-for31.C b/gcc/testsuite/g++.dg/cpp0x/range-for31.C
new file mode 100644
index 0000000..833f510
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/range-for31.C
@@ -0,0 +1,9 @@ 
+// PR c++/71604
+// { dg-do compile { target c++11 } }
+
+void foo ()
+{
+  int a[2] = { 1, 2 }; 
+  for (struct S { S (int) {} } S : a) // { dg-error "types may not be defined" }
+    ;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/range-for8.C b/gcc/testsuite/g++.dg/cpp0x/range-for8.C
index a389f66..38fe456 100644
--- a/gcc/testsuite/g++.dg/cpp0x/range-for8.C
+++ b/gcc/testsuite/g++.dg/cpp0x/range-for8.C
@@ -7,9 +7,9 @@ 
 
 void test()
 {
-    for (struct S { } *x : { (S*)0, (S*)0 } )
+    for (struct S { } *x : { (S*)0, (S*)0 } ) // { dg-error "types may not be defined" }
         ;
 
-    for (struct S { } x : { S(), S() } )
+    for (struct S { } x : { S(), S() } ) // { dg-error "types may not be defined" }
         ;
 }