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