On Sat, Jul 05, 2025 at 08:46:31AM -0400, Jason Merrill wrote:
> I think we want these diagnostics enabled by default; I don't feel strongly
> about unconditional pedwarn vs. permerror.

So like this then?

2025-07-05  Jakub Jelinek  <ja...@redhat.com>

        PR c++/84009
        * parser.cc (cp_parser_decomposition_declaration): Pedwarn
        on thread_local, __thread or static in decl_specifiers for
        for-range-declaration.
        (cp_parser_init_declarator): Likewise, and also for extern
        or register.

        * g++.dg/cpp0x/range-for40.C: New test.
        * g++.dg/cpp0x/range-for41.C: New test.
        * g++.dg/cpp0x/range-for42.C: New test.
        * g++.dg/cpp0x/range-for43.C: New test.

--- gcc/cp/parser.cc.jj 2025-07-04 19:49:14.702864248 +0200
+++ gcc/cp/parser.cc    2025-07-05 18:41:28.248664302 +0200
@@ -16919,6 +16919,15 @@ cp_parser_decomposition_declaration (cp_
       /* Ensure DECL_VALUE_EXPR is created for all the decls but
         the underlying DECL.  */
       cp_finish_decomp (decl, &decomp);
+      if (decl_spec_seq_has_spec_p (decl_specifiers, ds_thread))
+       pedwarn (decl_specifiers->locations[ds_thread],
+                0, "for-range-declaration cannot be %qs",
+                decl_specifiers->gnu_thread_keyword_p
+                ? "__thread" : "thread_local");
+      else if (decl_specifiers->storage_class == sc_static)
+       pedwarn (decl_specifiers->locations[ds_storage_class],
+                0, "for-range-declaration cannot be %qs",
+                "static");
     }
 
   if (pushed_scope)
@@ -24162,7 +24171,26 @@ cp_parser_init_declarator (cp_parser* pa
          && token->type != CPP_SEMICOLON)
        {
          if (maybe_range_for_decl && *maybe_range_for_decl != error_mark_node)
-           range_for_decl_p = true;
+           {
+             range_for_decl_p = true;
+             if (decl_spec_seq_has_spec_p (decl_specifiers, ds_thread))
+               pedwarn (decl_specifiers->locations[ds_thread],
+                        0, "for-range-declaration cannot be %qs",
+                        decl_specifiers->gnu_thread_keyword_p
+                        ? "__thread" : "thread_local");
+             else if (decl_specifiers->storage_class == sc_static)
+               pedwarn (decl_specifiers->locations[ds_storage_class],
+                        0, "for-range-declaration cannot be %qs",
+                        "static");
+             else if (decl_specifiers->storage_class == sc_extern)
+               pedwarn (decl_specifiers->locations[ds_storage_class],
+                        0, "for-range-declaration cannot be %qs",
+                        "extern");
+             else if (decl_specifiers->storage_class == sc_register)
+               pedwarn (decl_specifiers->locations[ds_storage_class],
+                        0, "for-range-declaration cannot be %qs",
+                        "register");
+           }
          else
            {
              if (!maybe_range_for_decl)
--- gcc/testsuite/g++.dg/cpp0x/range-for40.C.jj 2025-07-04 21:03:00.951729318 
+0200
+++ gcc/testsuite/g++.dg/cpp0x/range-for40.C    2025-07-04 21:11:29.426240713 
+0200
@@ -0,0 +1,41 @@
+// PR c++/84009
+// { dg-do compile { target c++11 } }
+
+int z[64];
+
+void
+foo ()
+{
+  for (static auto a : z)              // { dg-error "for-range-declaration 
cannot be 'static'" }
+    ;
+  for (thread_local auto a : z)                // { dg-error 
"for-range-declaration cannot be 'thread_local'" }
+    ;
+  for (__thread auto a : z)            // { dg-error "for-range-declaration 
cannot be '__thread'" }
+    ;                                  // { dg-error "function-scope 'a' 
implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+  for (register auto a : z)            // { dg-error "for-range-declaration 
cannot be 'register'" }
+    ;                                  // { dg-error "does not allow 
'register' storage class specifier" "" { target c++17 } .-1 }
+  for (extern auto a : z)              // { dg-error "for-range-declaration 
cannot be 'extern'" }
+    ;                                  // { dg-error "'a' has both 'extern' 
and initializer" "" { target *-*-* } .-1 }
+  for (mutable auto a : z)             // { dg-error "non-member 'a' cannot be 
declared 'mutable'" }
+    ;
+  for (virtual auto a : z)             // { dg-error "'virtual' outside class 
declaration" }
+    ;
+  for (explicit auto a : z)            // { dg-error "'explicit' outside class 
declaration" }
+    ;
+  for (friend auto a : z)              // { dg-error "'friend' used outside of 
class" }
+    ;
+  for (typedef auto a : z)             // { dg-error "typedef declared 'auto'" 
}
+    ;                                  // { dg-error "typedef 'a' is 
initialized \\\(use 'decltype' instead\\\)" "" { target *-*-* } .-1 }
+#if __cplusplus >= 202002L
+  for (consteval auto a : z)           // { dg-error "a variable cannot be 
declared 'consteval'" "" { target c++20 } }
+    ;
+  for (constinit auto a : z)           // { dg-error "'constinit' can only be 
applied to a variable with static or thread storage duration" "" { target c++20 
} }
+    ;
+#endif
+  for (inline auto a : z)              // { dg-error "'inline' specifier 
invalid for variable 'a' declared at block scope" }
+    ;
+  for (struct S { int a; } a : z)      // { dg-error "types may not be defined 
in a for-range-declaration" }
+    ;                                  // { dg-error "conversion from 'int' to 
non-scalar type 'foo\\\(\\\)::S' requested" "" { target *-*-* } .-1 }
+  for (enum E { E0 } a : z)            // { dg-error "types may not be defined 
in a for-range-declaration" }
+    ;                                  // { dg-error "invalid conversion from 
'int' to 'foo\\\(\\\)::E'" "" { target *-*-* } .-1 }
+}
--- gcc/testsuite/g++.dg/cpp0x/range-for41.C.jj 2025-07-04 21:12:17.765623538 
+0200
+++ gcc/testsuite/g++.dg/cpp0x/range-for41.C    2025-07-05 18:46:51.010565550 
+0200
@@ -0,0 +1,42 @@
+// PR c++/84009
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+int z[64];
+
+void
+foo ()
+{
+  for (static auto a : z)              // { dg-warning "for-range-declaration 
cannot be 'static'" }
+    ;
+  for (thread_local auto a : z)                // { dg-warning 
"for-range-declaration cannot be 'thread_local'" }
+    ;
+  for (__thread auto a : z)            // { dg-warning "for-range-declaration 
cannot be '__thread'" }
+    ;                                  // { dg-warning "function-scope 'a' 
implicitly auto and declared '__thread'" "" { target *-*-* } .-1 }
+  for (register auto a : z)            // { dg-warning "for-range-declaration 
cannot be 'register'" }
+    ;                                  // { dg-warning "does not allow 
'register' storage class specifier" "" { target c++17 } .-1 }
+  for (extern auto a : z)              // { dg-warning "for-range-declaration 
cannot be 'extern'" }
+    ;                                  // { dg-error "'a' has both 'extern' 
and initializer" "" { target *-*-* } .-1 }
+  for (mutable auto a : z)             // { dg-error "non-member 'a' cannot be 
declared 'mutable'" }
+    ;
+  for (virtual auto a : z)             // { dg-error "'virtual' outside class 
declaration" }
+    ;
+  for (explicit auto a : z)            // { dg-error "'explicit' outside class 
declaration" }
+    ;
+  for (friend auto a : z)              // { dg-error "'friend' used outside of 
class" }
+    ;
+  for (typedef auto a : z)             // { dg-error "typedef declared 'auto'" 
}
+    ;                                  // { dg-error "typedef 'a' is 
initialized \\\(use 'decltype' instead\\\)" "" { target *-*-* } .-1 }
+#if __cplusplus >= 202002L
+  for (consteval auto a : z)           // { dg-error "a variable cannot be 
declared 'consteval'" "" { target c++20 } }
+    ;
+  for (constinit auto a : z)           // { dg-error "'constinit' can only be 
applied to a variable with static or thread storage duration" "" { target c++20 
} }
+    ;
+#endif
+  for (inline auto a : z)              // { dg-error "'inline' specifier 
invalid for variable 'a' declared at block scope" }
+    ;
+  for (struct S { int a; } a : z)      // { dg-error "types may not be defined 
in a for-range-declaration" }
+    ;                                  // { dg-error "conversion from 'int' to 
non-scalar type 'foo\\\(\\\)::S' requested" "" { target *-*-* } .-1 }
+  for (enum E { E0 } a : z)            // { dg-error "types may not be defined 
in a for-range-declaration" }
+    ;                                  // { dg-error "invalid conversion from 
'int' to 'foo\\\(\\\)::E'" "" { target *-*-* } .-1 }
+}
--- gcc/testsuite/g++.dg/cpp0x/range-for42.C.jj 2025-07-04 21:18:01.921229498 
+0200
+++ gcc/testsuite/g++.dg/cpp0x/range-for42.C    2025-07-04 21:56:40.358626480 
+0200
@@ -0,0 +1,41 @@
+// PR c++/84009
+// { dg-do compile { target c++11 } }
+
+struct S { int y; } z[64];
+
+void
+foo ()
+{
+  for (static auto [ a ] : z)          // { dg-error "for-range-declaration 
cannot be 'static'" }
+    ;                                  // { dg-error "structured binding 
declaration can be 'static' only in" "" { target c++17_down } .-1 }
+                                       // { dg-error "structured bindings only 
available with" "" { target c++14_down } .-2 }
+  for (thread_local auto [ a ] : z)    // { dg-error "for-range-declaration 
cannot be 'thread_local'" }
+    ;                                  // { dg-error "structured binding 
declaration can be 'thread_local' only in" "" { target c++17_down } .-1 }
+                                       // { dg-error "structured bindings only 
available with" "" { target c++14_down } .-2 }
+  for (__thread auto [ a ] : z)                // { dg-error 
"for-range-declaration cannot be '__thread'" }
+    ;                                  // { dg-error "function-scope 
'structured binding' implicitly auto and declared '__thread'" "" { target *-*-* 
} .-1 }
+                                       // { dg-error "structured binding 
declaration can be '__thread' only in" "" { target c++17_down } .-2 }
+                                       // { dg-error "structured bindings only 
available with" "" { target c++14_down } .-3 }
+  for (register auto [ a ] : z)                // { dg-error "structured 
binding declaration cannot be 'register'" }
+    ;                                  // { dg-error "structured bindings only 
available with" "" { target c++14_down } .-1 }
+  for (extern auto [ a ] : z)          // { dg-error "structured binding 
declaration cannot be 'extern'" }
+    ;                                  // { dg-error "structured bindings only 
available with" "" { target c++14_down } .-1 }
+  for (mutable auto [ a ] : z)         // { dg-error "structured binding 
declaration cannot be 'mutable'" }
+    ;                                  // { dg-error "structured bindings only 
available with" "" { target c++14_down } .-1 }
+  for (virtual auto [ a ] : z)         // { dg-error "'virtual' outside class 
declaration" }
+    ;                                  // { dg-error "structured bindings only 
available with" "" { target c++14_down } .-1 }
+  for (explicit auto [ a ] : z)                // { dg-error "'explicit' 
outside class declaration" }
+    ;                                  // { dg-error "structured bindings only 
available with" "" { target c++14_down } .-1 }
+  for (friend auto [ a ] : z)          // { dg-error "'friend' used outside of 
class" }
+    ;                                  // { dg-error "structured bindings only 
available with" "" { target c++14_down } .-1 }
+  for (typedef auto [ a ] : z)         // { dg-error "structured binding 
declaration cannot be 'typedef'" }
+    ;                                  // { dg-error "structured bindings only 
available with" "" { target c++14_down } .-1 }
+#if __cplusplus >= 202002L
+  for (consteval auto [ a ] : z)       // { dg-error "structured binding 
declaration cannot be 'consteval'" "" { target c++20 } }
+    ;
+  for (constinit auto [ a ] : z)       // { dg-error "'constinit' can only be 
applied to a variable with static or thread storage duration" "" { target c++20 
} }
+    ;
+#endif
+  for (inline auto [ a ] : z)          // { dg-error "structured binding 
declaration cannot be 'inline'" }
+    ;                                  // { dg-error "structured bindings only 
available with" "" { target c++14_down } .-1 }
+}
--- gcc/testsuite/g++.dg/cpp0x/range-for43.C.jj 2025-07-04 21:56:56.615418951 
+0200
+++ gcc/testsuite/g++.dg/cpp0x/range-for43.C    2025-07-05 18:50:07.529069890 
+0200
@@ -0,0 +1,42 @@
+// PR c++/84009
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct S { int y; } z[64];
+
+void
+foo ()
+{
+  for (static auto [ a ] : z)          // { dg-warning "for-range-declaration 
cannot be 'static'" }
+    ;                                  // { dg-warning "structured binding 
declaration can be 'static' only in" "" { target c++17_down } .-1 }
+                                       // { dg-warning "structured bindings 
only available with" "" { target c++14_down } .-2 }
+  for (thread_local auto [ a ] : z)    // { dg-warning "for-range-declaration 
cannot be 'thread_local'" }
+    ;                                  // { dg-warning "structured binding 
declaration can be 'thread_local' only in" "" { target c++17_down } .-1 }
+                                       // { dg-warning "structured bindings 
only available with" "" { target c++14_down } .-2 }
+  for (__thread auto [ a ] : z)                // { dg-warning 
"for-range-declaration cannot be '__thread'" }
+    ;                                  // { dg-warning "function-scope 
'structured binding' implicitly auto and declared '__thread'" "" { target *-*-* 
} .-1 }
+                                       // { dg-warning "structured binding 
declaration can be '__thread' only in" "" { target c++17_down } .-2 }
+                                       // { dg-warning "structured bindings 
only available with" "" { target c++14_down } .-3 }
+  for (register auto [ a ] : z)                // { dg-error "structured 
binding declaration cannot be 'register'" }
+    ;                                  // { dg-warning "structured bindings 
only available with" "" { target c++14_down } .-1 }
+  for (extern auto [ a ] : z)          // { dg-error "structured binding 
declaration cannot be 'extern'" }
+    ;                                  // { dg-warning "structured bindings 
only available with" "" { target c++14_down } .-1 }
+  for (mutable auto [ a ] : z)         // { dg-error "structured binding 
declaration cannot be 'mutable'" }
+    ;                                  // { dg-warning "structured bindings 
only available with" "" { target c++14_down } .-1 }
+  for (virtual auto [ a ] : z)         // { dg-error "'virtual' outside class 
declaration" }
+    ;                                  // { dg-warning "structured bindings 
only available with" "" { target c++14_down } .-1 }
+  for (explicit auto [ a ] : z)                // { dg-error "'explicit' 
outside class declaration" }
+    ;                                  // { dg-warning "structured bindings 
only available with" "" { target c++14_down } .-1 }
+  for (friend auto [ a ] : z)          // { dg-error "'friend' used outside of 
class" }
+    ;                                  // { dg-warning "structured bindings 
only available with" "" { target c++14_down } .-1 }
+  for (typedef auto [ a ] : z)         // { dg-error "structured binding 
declaration cannot be 'typedef'" }
+    ;                                  // { dg-warning "structured bindings 
only available with" "" { target c++14_down } .-1 }
+#if __cplusplus >= 202002L
+  for (consteval auto [ a ] : z)       // { dg-error "structured binding 
declaration cannot be 'consteval'" "" { target c++20 } }
+    ;
+  for (constinit auto [ a ] : z)       // { dg-error "'constinit' can only be 
applied to a variable with static or thread storage duration" "" { target c++20 
} }
+    ;
+#endif
+  for (inline auto [ a ] : z)          // { dg-error "structured binding 
declaration cannot be 'inline'" }
+    ;                                  // { dg-warning "structured bindings 
only available with" "" { target c++14_down } .-1 }
+}


        Jakub

Reply via email to