On Thu, Nov 20, 2025 at 10:46:21AM +0530, Jason Merrill wrote:
> > The following testcase shows that range_decl in cp_hide_range_decl is
> > sometimes also NULL_TREE and not just error_mark_node, and the function
> > IMHO should treat both the same, not try to hide anything in that case
> > because it doesn't know what should be hidden. This ICEs during
> > error recovery since something like cp_hide_range_decl has been introduced
> > (earlier it wasn't called that way).
>
> This seems like cp_parser_simple_declaration is violating its comment:
If the intent was a decl or error_mark_node as the comment says, then
it wouldn't start with
if (maybe_range_for_decl)
*maybe_range_for_decl = NULL_TREE;
Furthermore, I think it would be really weird to set *maybe_range_for_decl
to error_mark_node in the non-erroneous cases, the name of the argument
includes maybe_ prefix.
I think it is just fine to set *maybe_range_for_decl to error_mark_node
in the erroneous cases, basically make sure that if it is followed by
CPP_COLON (i.e. when cp_parser_init_statement is going to return true)
then it will never be NULL.
Here is a patch which does that, so far tested with
GXX_TESTSUITE_STDS=98,11,14,17,20,23,26 make -j32 -k check-g++ check-obj-c++
in gcc/ and libstdc++-v3 make check, ok for trunk if it passes full
bootstrap/regtest?
2025-11-20 Jakub Jelinek <[email protected]>
PR c++/122465
* parser.cc (cp_parser_simple_declaration): Adjust function comment.
Set *maybe_range_for_decl to error_mark_node instead of keeping it
NULL_TREE in error cases or when followed by CPP_COLON.
* g++.dg/cpp0x/pr122465.C: New test.
--- gcc/cp/parser.cc.jj 2025-11-20 11:19:13.583211387 +0100
+++ gcc/cp/parser.cc 2025-11-20 12:02:19.051259722 +0100
@@ -17032,8 +17032,9 @@ cp_parser_block_declaration (cp_parser *
If MAYBE_RANGE_FOR_DECL is not NULL, the pointed tree will be set to the
parsed declaration if it is an uninitialized single declarator not followed
- by a `;', or to error_mark_node otherwise. Either way, the trailing `;',
- if present, will not be consumed. */
+ by a `;', or to NULL_TREE when not followed by `:' or to error_mark_node
+ otherwise. Either way, the trailing `;', if present, will not be
+ consumed. */
static void
cp_parser_simple_declaration (cp_parser* parser,
@@ -17085,6 +17086,9 @@ cp_parser_simple_declaration (cp_parser*
&& !decl_specifiers.any_specifiers_p)
{
cp_parser_error (parser, "expected declaration");
+ error_out:
+ if (maybe_range_for_decl && *maybe_range_for_decl == NULL_TREE)
+ *maybe_range_for_decl = error_mark_node;
goto done;
}
@@ -17101,7 +17105,7 @@ cp_parser_simple_declaration (cp_parser*
looking at a declaration. */
cp_parser_commit_to_tentative_parse (parser);
/* Give up. */
- goto done;
+ goto error_out;
}
cp_parser_maybe_commit_to_declaration (parser, &decl_specifiers);
@@ -17126,11 +17130,7 @@ cp_parser_simple_declaration (cp_parser*
if (token->type == CPP_SEMICOLON)
goto finish;
else if (maybe_range_for_decl)
- {
- if (*maybe_range_for_decl == NULL_TREE)
- *maybe_range_for_decl = error_mark_node;
- goto finish;
- }
+ goto finish;
/* Anything else is an error. */
else
{
@@ -17209,7 +17209,7 @@ cp_parser_simple_declaration (cp_parser*
statement is treated as a declaration-statement until proven
otherwise.) */
if (cp_parser_error_occurred (parser))
- goto done;
+ goto error_out;
if (auto_specifier_p && cxx_dialect >= cxx14)
{
@@ -17347,6 +17347,8 @@ cp_parser_simple_declaration (cp_parser*
if (comma_loc != UNKNOWN_LOCATION)
error_at (comma_loc,
"multiple declarations in range-based %<for%> loop");
+ if (*maybe_range_for_decl == NULL_TREE)
+ *maybe_range_for_decl = error_mark_node;
}
done:
--- gcc/testsuite/g++.dg/cpp0x/pr122465.C.jj 2025-11-20 11:19:04.978706617
+0100
+++ gcc/testsuite/g++.dg/cpp0x/pr122465.C 2025-11-20 12:06:11.387942293
+0100
@@ -0,0 +1,10 @@
+// PR c++/122465
+// { dg-do compile { target c++11 } }
+
+void
+foo ()
+{
+ int x = 0;
+ for (const T i = { i } : x) // { dg-error "'T' does not name a type" }
+ ;
+}
Jakub