On Wed, 11 Feb 2026, Marek Polacek wrote:

> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> 
> -- >8 --
> [temp.res.general]/4.4.1 says that a decl-specifier of the
> decl-specifier-seq of a simple-declaration in namespace scope is
> a type-only context.  I think this goes back to P0634R3.  So
> 
>   [: ^^int :] a = 42;
> 
> shouldn't require a 'typename' when in a namespace scope.
> 
> The _diagnose_invalid_type_name change is so that we don't emit extra
> 
>   error: '<expression error>' in '...' does not name a type
> 
> in concepts-return-req4.C, variadic74.C, and variadic-nested3.C.

Looks good.  We get the same useless error without this patch if the
invalid variable declarations were instead variable template
declarations, and the added error_mark_node check will suppress those
too.

And this change doesn't really affect C++20 / non-reflection code since
IIUC before reflection, type/expr ambiguity only arises in a template
context which goes through cp_parser_single_declaration which already
sets CP_PARSER_FLAGS_TYPENAME_OPTIONAL.

> 
>       PR c++/124045
> 
> gcc/cp/ChangeLog:
> 
>       * parser.cc (cp_parser_parse_and_diagnose_invalid_type_name): Also
>       abort the tentative parse when id is error_mark_node.
>       (cp_parser_simple_declaration): Set CP_PARSER_FLAGS_TYPENAME_OPTIONAL
>       when in a namespace scope.
>       (cp_parser_single_declaration): Use cp_parser_flags instead of int.
> 
> gcc/testsuite/ChangeLog:
> 
>       * g++.dg/reflect/type1.C: Don't expect an error for a missing typename
>       in a namespace scope.
> ---
>  gcc/cp/parser.cc                     | 14 +++++++++-----
>  gcc/testsuite/g++.dg/reflect/type1.C |  4 ++--
>  2 files changed, 11 insertions(+), 7 deletions(-)
> 
> diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
> index 8c46b260fff..0f53ff90215 100644
> --- a/gcc/cp/parser.cc
> +++ b/gcc/cp/parser.cc
> @@ -4171,7 +4171,8 @@ cp_parser_parse_and_diagnose_invalid_type_name 
> (cp_parser *parser)
>    /* If the next token is a (, this is a function with no explicit return
>       type, i.e. constructor, destructor or conversion op.  */
>    if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN)
> -      || TREE_CODE (id) == TYPE_DECL)
> +      || TREE_CODE (id) == TYPE_DECL
> +      || id == error_mark_node)
>      {
>        cp_parser_abort_tentative_parse (parser);
>        return false;
> @@ -17924,9 +17925,12 @@ cp_parser_simple_declaration (cp_parser* parser,
>       omitted only when declaring a class or enumeration, that is when
>       the decl-specifier-seq contains either a class-specifier, an
>       elaborated-type-specifier, or an enum-specifier.  */
> -  cp_parser_decl_specifier_seq (parser,
> -                             CP_PARSER_FLAGS_OPTIONAL,
> -                             &decl_specifiers,
> +  cp_parser_flags flags = CP_PARSER_FLAGS_OPTIONAL;
> +  /* [temp.res.general]/4.4.1: a decl-specifier of the decl-specifier-seq
> +     of a simple-declaration in namespace scope is a type-only context.  */
> +  if (at_namespace_scope_p ())
> +    flags |= CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
> +  cp_parser_decl_specifier_seq (parser, flags, &decl_specifiers,
>                               &declares_class_or_enum);
>    /* We no longer need to defer access checks.  */
>    stop_deferring_access_checks ();
> @@ -36481,7 +36485,7 @@ cp_parser_single_declaration (cp_parser* parser,
>        && (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON)
>         || decl_specifiers.type != error_mark_node))
>      {
> -      int flags = CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
> +      cp_parser_flags flags = CP_PARSER_FLAGS_TYPENAME_OPTIONAL;
>        /* FIXME: Delay parsing for all template friends, not just class
>        template scope ones (PR114764).  */
>        if (member_p && (!(friend_p && *friend_p)
> diff --git a/gcc/testsuite/g++.dg/reflect/type1.C 
> b/gcc/testsuite/g++.dg/reflect/type1.C
> index 74bc27282b3..bcdb9d6c122 100644
> --- a/gcc/testsuite/g++.dg/reflect/type1.C
> +++ b/gcc/testsuite/g++.dg/reflect/type1.C
> @@ -21,11 +21,11 @@ constexpr info g7 = ^^T;
>  constexpr info g8 = ^^decltype(^^int);
>  constexpr info g9 = ^^void() const & noexcept;
>  
> -[: g1 :] u1;  // { dg-error "expected unqualified-id" }
> +[: g1 :] u1;
>  typename [: g1 :] u2;
>  
>  namespace N {
> -  [: g1 :] nu1;  // { dg-error "expected unqualified-id" }
> +  [: g1 :] nu1;
>    typename [: g1 :] nu2;
>  }
>  
> 
> base-commit: 560766f6e239a8192c42ac5f009f0a4ee2478a61
> -- 
> 2.53.0
> 
> 

Reply via email to