On 7/5/25 1:05 PM, Jakub Jelinek wrote:
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?

OK.

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