On Thu, Dec 11, 2025 at 07:55:38PM +0700, Jason Merrill wrote:
> On 12/11/25 5:17 AM, Marek Polacek wrote:
> > On Fri, Dec 05, 2025 at 10:18:34PM +0530, Jason Merrill wrote:
> > > > + /* Nope. Well then, maybe it's a type-id. */
> > > > + cp_parser_parse_tentatively (parser);
> > > > +
> > > > + /* Unfortunately we need to distinguish in
> > > > + template <typename> struct cls_tmpl {};
> > > > + template <typename T> using cls_tmpl_alias = const cls_tmpl <T>;
> > > > +
> > > > + ^^cls_tmpl_alias <int> which is a type alias from
> > > > + ^^const cls_tmpl_alias <int>
> > > > + ^^cls_tmpl_alias <int> const
> > > > + ^^cls_tmpl_alias <int> *
> > > > + etc. which are just types, not type aliases. Parse tentatively
> > > > + type specifiers and check that there is just ds_type_spec
> > > > specified
> > > > + and it is a specialization of a template alias, in that case later
> > > > + on if cp_parser_type_id parses the same tokens don't strip
> > > > typedefs. */
> > > > + if (!talias)
> > > > + {
> > > > + cp_decl_specifier_seq type_specifier_seq;
> > > > +
> > > > + /* Parse the type-specifier-seq. */
> > > > + cp_parser_type_specifier_seq (parser, CP_PARSER_FLAGS_NONE,
> > > > + /*is_declaration=*/false, false,
> > > > + &type_specifier_seq);
> > > > + if (is_typedef_decl (type_specifier_seq.type)
> > > > + && TYPE_ALIAS_TEMPLATE_INFO (TREE_TYPE
> > > > (type_specifier_seq.type)))
> > > > + {
> > > > + int i;
> > > > + for (i = ds_first; i < ds_last; ++i)
> > > > + if (i != ds_type_spec && type_specifier_seq.locations[i])
> > > > + break;
> > > > + if (i == ds_last)
> > > > + {
> > > > + talias = type_specifier_seq.type;
> > > > + next = cp_lexer_peek_token (parser->lexer);
> > > > + }
> > > > + }
> > > > + cp_parser_abort_tentative_parse (parser);
> > > > + cp_parser_parse_tentatively (parser);
> > > > + }
> > > > +
> > > > + t = cp_parser_type_id (parser);
> > > > + if (cp_parser_parse_definitely (parser))
> > > > + {
> > > > + if (TYPE_P (t))
> > > > + {
> > > > + /* With using A = int; ^^A is a type alias but
> > > > + ^^const A or ^^A & or ^^A const is not.
> > > > + With template <typename T> using B = C <T>;
> > > > + ^^B <int> is a type alias though. */
> > > > + if (talias == NULL_TREE
> > > > + || cp_lexer_peek_token (parser->lexer) != next)
> > > > + t = strip_typedefs (t);
> > > > + }
> > > > + return get_reflection (loc, t);
> > > > + }
> > >
> > > I think it would be simpler to handle more of this in cp_parser_type_id_1,
> > > which already handles other special cases, rather than parsing the
> > > type-specifiers twice?
> >
> > I took a crack at this in
> > <https://forge.sourceware.org/marek/gcc/commit/e2a9ca89a628d54897ffe30054191b0e14dfd1c4>
> > and it seemed to work.
>
> Looks good, except I think I'd rather call _type_id_1 directly rather than
> add a special-case parameter to _type_id.
Done:
<https://forge.sourceware.org/marek/gcc/commit/90552c882ab38ff7270dc900fab786bab53f5435>
> > > > @@ -3437,9 +3444,24 @@ finish_class_member_access_expr (cp_expr object,
> > > > tree name, bool template_p,
> > > > return error_mark_node;
> > > > }
> > > > + /* For OBJECT.[:S::fn:] the BASELINK can be inside a SCOPE_REF.
> > > > + This happens, but, until Reflection, not for a class member
> > > > access. */
> > > > + if (TREE_CODE (name) == SCOPE_REF && BASELINK_P (TREE_OPERAND (name,
> > > > 1)))
> > > > + name = TREE_OPERAND (name, 1);
> > >
> > > Why does this happen? Why isn't the SCOPE_REF folded into the BASELINK?
> >
> > Happens in:
> >
> > struct S {
> > void foo () {}
> > };
> >
> > template <typename T>
> > void qux ()
> > {
> > S s {};
> > s.[:(T) ^^S::foo:] ();
> > }
> >
> > void
> > corge ()
> > {
> > qux <decltype (^^int)> ();
> > }
> >
> > In cp_parser_postfix_dot_deref_expression:
> > * cp_parser_splice_expression gives us a SPLICE_EXPR (~it's dependent)
>
> Yes.
>
> > * since parser->scope is S, we create a SCOPE_REF in build_qualified_name
>
> As discussed in _dot_deref, parser->scope shouldn't be set by the time we
> get back there, so I guess fixing that should make this hunk unnecessary.
OK. I'm going to look at this now.
> > * need to tsubst, so tsubst_expr/SCOPE_REF does tsubst_scope + tsubst_name,
> > then build_qualified_name creates a new SCOPE_REF
> > * tsubst_expr calls finish_class_member_access_expr with that SCOPE_REF
Marek