On 12/10/25 8:23 PM, Jakub Jelinek wrote:
On Tue, Dec 09, 2025 at 08:38:26PM +0800, Jason Merrill wrote:
+ [:^^B::fn:]() // do not disable virtual dispatch
+ [:^^B:]::fn() // disable virtual dispatch
+
+ so we check SPLICE_P. */
+ if (parser->scope && !splice_p)
*idk = CP_ID_KIND_QUALIFIED;
Hmm, it seems wrong for parser->scope to still be set in the former case.
So this is tested in reflect/member9.C. I thought that d.[:^^B::fn:]()
should behave just like d.B::fn() which also leaves parser->scope set
to B.
I don't think it should, as above the splice is a separate lookup context.
I agree with the comments and the testcase, but we should be clearing
parser->scope after the splice so we don't need any change here.
I've tried:
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 0d59f6ec5a5..bc31eabf474 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -6120,6 +6120,15 @@ cp_parser_splice_specifier (cp_parser *parser, bool
template_p = false,
return error_mark_node;
}
+if (parser->scope || parser->qualifying_scope || parser->object_scope)
+{
+FILE *f = fopen ("/tmp/splice", "a");
+fprintf (f, "%s %s %d %d %d %d\n",
+main_input_filename ? main_input_filename : "-", current_function_name (),
+2, (int) !!parser->scope, (int) !!parser->qualifying_scope, (int)
!!parser->object_scope);
+fclose (f);
+}
+
tree expr = cp_parser_constant_expression (parser,
/*allow_non_constant_p=*/false,
/*non_constant_p=*/nullptr,
@@ -6215,6 +6224,14 @@ cp_parser_splice_expression (cp_parser *parser, bool
template_p,
if (member_access_p)
push_deferring_access_checks (dk_no_check);
+if (parser->scope || parser->qualifying_scope || parser->object_scope)
+{
+FILE *f = fopen ("/tmp/splice", "a");
+fprintf (f, "%s %s %d %d %d %d\n",
+main_input_filename ? main_input_filename : "-", current_function_name (),
+member_access_p, (int) !!parser->scope, (int) !!parser->qualifying_scope, (int)
!!parser->object_scope);
+fclose (f);
+}
cp_expr expr = cp_parser_splice_specifier (parser, template_p, &targs_p);
if (member_access_p)
and this only triggers on type8.C testcase, reduced to
template<class, class> struct same_type;
template<class T> struct same_type<T, T> {};
struct S {
static const int &&mem();
static int i;
int j;
} s;
same_type<decltype([: ^^S::i :]), int> s5b;
where it seems to be parsing [: ^^S::i :] tentatively, sets
parser->scope and parser->qualifying_scope to S during that
parsing and then when it is parsing it again sees that.
So guess the question is where to clear those 3 (e.g. whether
at the start of cp_parser_splice_expression and also at the end
of those?)
I think so.
and/or if there are some spots where it should be temporarily
and where it should be reset back.
I don't think so.
And then there is also parser->context->object_type, guess for that one
we should save it and restore it, so that it can be taken into account
for s.[: ^^S::foo :] <int> (); etc. parsing.
...
The following WIP patch fixes that.
The reason for saving/restoring rather than just clearing is so that
it can be used for the splice-specialization-specifier case later on
if the splice-specifier is non-dependent.
Why is this needed? The template arguments aren't member-qualified,
e.g. this is properly rejected:
struct A {
static const int i = 42;
template <int I> void f();
};
int main()
{
A().f<i>(); // error, no 'i' in scope
}
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 0d59f6ec5a5..4e10fec64e2 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -6102,6 +6102,7 @@ cp_parser_next_tokens_can_start_splice_scope_spec_p
(cp_parser *parser)
static cp_expr
cp_parser_splice_specifier (cp_parser *parser, bool template_p = false,
+ bool member_access_p = false,
bool *targs_p = nullptr)
{
/* Get the location of the '[:'. */
@@ -6120,11 +6121,22 @@ cp_parser_splice_specifier (cp_parser *parser, bool
template_p = false,
return error_mark_node;
}
+ /* For member_access_p, temporarily clear parser->context->object_type. */
Why conditional on member_access_p?
+ tree save_object_type = NULL_TREE;
+ if (member_access_p)
+ {
+ save_object_type = parser->context->object_type;
+ parser->context->object_type = NULL_TREE;
+ }
+
tree expr = cp_parser_constant_expression (parser,
/*allow_non_constant_p=*/false,
/*non_constant_p=*/nullptr,
/*strict_p=*/true);
+ if (member_access_p)
+ parser->context->object_type = save_object_type;
+
/* Get the location of the ':]'. */
location_t finish_loc = cp_lexer_peek_token (parser->lexer)->location;
@@ -6215,7 +6227,8 @@ cp_parser_splice_expression (cp_parser *parser, bool template_p,
if (member_access_p)
push_deferring_access_checks (dk_no_check);
- cp_expr expr = cp_parser_splice_specifier (parser, template_p, &targs_p);
+ cp_expr expr = cp_parser_splice_specifier (parser, template_p,
+ member_access_p, &targs_p);
if (member_access_p)
pop_deferring_access_checks ();
@@ -6385,7 +6398,8 @@ cp_parser_splice_scope_specifier (cp_parser *parser, bool
typename_p,
bool template_p)
{
bool targs_p = false;
- cp_expr scope = cp_parser_splice_specifier (parser, template_p, &targs_p);
+ cp_expr scope = cp_parser_splice_specifier (parser, template_p, false,
+ &targs_p);
const location_t loc = scope.get_location ();
if (TREE_CODE (scope) == TYPE_DECL)
scope = TREE_TYPE (scope);
diff --git a/gcc/testsuite/g++.dg/reflect/member1.C
b/gcc/testsuite/g++.dg/reflect/member1.C
index c64b39f0938..e9d9a64d0eb 100644
--- a/gcc/testsuite/g++.dg/reflect/member1.C
+++ b/gcc/testsuite/g++.dg/reflect/member1.C
@@ -95,5 +95,5 @@ f ()
s.template [: ^^S::N :].t; // { dg-error "reflection .S::N. not usable in a
template splice" }
S::template [: ^^S::N<int> :] e1; // { dg-error "expected unqualified-id" }
C<int>::template [: ^^S::N<int> :] e2; // { dg-error "expected
unqualified-id" }
- s.template [: ^^var<int> :] = 1; // { dg-error "reflection .S::var<int>. not
usable in a template splice" }
+ s.template [: ^^S::var<int> :] = 1; // { dg-error "reflection .S::var<int>. not
usable in a template splice" }
}
diff --git a/gcc/testsuite/g++.dg/reflect/splice3.C
b/gcc/testsuite/g++.dg/reflect/splice3.C
new file mode 100644
index 00000000000..88434444a2d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/reflect/splice3.C
@@ -0,0 +1,5 @@
+// { dg-do compile { target c++26 } }
+// { dg-additional-options "-freflection" }
+
+struct A { static int x; };
+int q = A ().[: ^^x :]; // { dg-error "'x' has not been declared" }
Jakub