Skip to content

Commit 86caab6

Browse files
committed
c++: Fix up handling of non-dependent subscript with static operator[] [PR108437]
As the following testcases shows, when adding static operator[] support I've missed that the 2 build_min_non_dep_op_overload functions need to be adjusted. The first one we only use for the single index case, but as cp_tree_code_length (ARRAY_REF) is 2, we were running into an assertion there which compared nargs and expected_nargs. For ARRAY_REF, the operator[] is either a non-static member or newly static member, never out of class and for the static member case if user uses single index the operator[] needs to have a single argument as well, but the function is called with 2 - the object it is invoked on and the index. We need to evaluate side-effects of the object and use just a single argument in the call - the index. The other build_min_non_dep_op_overload overload has been added solely for ARRAY_REF - CALL_EXPR is the other operator that accepts variable number of operands but that one goes through different routines. There we asserted it is a METHOD_TYPE, so again we shouldn't assert that but handle the case when it is not one by making sure object's side-effects are evaluated if needed and passing all the index arguments to the static operator[]. 2023-01-19 Jakub Jelinek <[email protected]> PR c++/108437 * cp-tree.h (keep_unused_object_arg): Declare. * call.cc (keep_unused_object_arg): No longer static. * tree.cc (build_min_non_dep_op_overload): Handle ARRAY_REF with overload being static member function. * g++.dg/cpp23/subscript12.C: New test. * g++.dg/cpp23/subscript13.C: New test.
1 parent 9b9a989 commit 86caab6

File tree

5 files changed

+102
-8
lines changed

5 files changed

+102
-8
lines changed

gcc/cp/call.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5187,7 +5187,7 @@ build_operator_new_call (tree fnname, vec<tree, va_gc> **args,
51875187
or static operator(), in which cases the source expression
51885188
would be `obj[...]' or `obj(...)'. */
51895189

5190-
static tree
5190+
tree
51915191
keep_unused_object_arg (tree result, tree obj, tree fn)
51925192
{
51935193
if (result == NULL_TREE

gcc/cp/cp-tree.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6599,6 +6599,7 @@ inline tree build_new_op (const op_location_t &loc, enum tree_code code,
65996599
return build_new_op (loc, code, flags, arg1, arg2, NULL_TREE, NULL_TREE,
66006600
NULL, complain);
66016601
}
6602+
extern tree keep_unused_object_arg (tree, tree, tree);
66026603
extern tree build_op_call (tree, vec<tree, va_gc> **,
66036604
tsubst_flags_t);
66046605
extern tree build_op_subscript (const op_location_t &, tree,

gcc/cp/tree.cc

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3693,14 +3693,20 @@ build_min_non_dep_op_overload (enum tree_code op,
36933693
{
36943694
va_list p;
36953695
int nargs, expected_nargs;
3696-
tree fn, call;
3696+
tree fn, call, obj = NULL_TREE;
36973697

36983698
non_dep = extract_call_expr (non_dep);
36993699

37003700
nargs = call_expr_nargs (non_dep);
37013701

37023702
expected_nargs = cp_tree_code_length (op);
3703-
if (TREE_CODE (TREE_TYPE (overload)) == METHOD_TYPE)
3703+
if (TREE_CODE (TREE_TYPE (overload)) == METHOD_TYPE
3704+
/* For ARRAY_REF, operator[] is either a non-static member or newly
3705+
static member, never out of class and for the static member case
3706+
if user uses single index the operator[] needs to have a single
3707+
argument as well, but the function is called with 2 - the object
3708+
it is invoked on and the index. */
3709+
|| op == ARRAY_REF)
37043710
expected_nargs -= 1;
37053711
if ((op == POSTINCREMENT_EXPR
37063712
|| op == POSTDECREMENT_EXPR)
@@ -3715,6 +3721,8 @@ build_min_non_dep_op_overload (enum tree_code op,
37153721
if (TREE_CODE (TREE_TYPE (overload)) == FUNCTION_TYPE)
37163722
{
37173723
fn = overload;
3724+
if (op == ARRAY_REF)
3725+
obj = va_arg (p, tree);
37183726
for (int i = 0; i < nargs; i++)
37193727
{
37203728
tree arg = va_arg (p, tree);
@@ -3746,6 +3754,8 @@ build_min_non_dep_op_overload (enum tree_code op,
37463754
CALL_EXPR_ORDERED_ARGS (call_expr) = CALL_EXPR_ORDERED_ARGS (non_dep);
37473755
CALL_EXPR_REVERSE_ARGS (call_expr) = CALL_EXPR_REVERSE_ARGS (non_dep);
37483756

3757+
if (obj)
3758+
return keep_unused_object_arg (call, obj, overload);
37493759
return call;
37503760
}
37513761

@@ -3759,11 +3769,15 @@ build_min_non_dep_op_overload (tree non_dep, tree overload, tree object,
37593769
non_dep = extract_call_expr (non_dep);
37603770

37613771
unsigned int nargs = call_expr_nargs (non_dep);
3762-
gcc_assert (TREE_CODE (TREE_TYPE (overload)) == METHOD_TYPE);
3763-
tree binfo = TYPE_BINFO (TREE_TYPE (object));
3764-
tree method = build_baselink (binfo, binfo, overload, NULL_TREE);
3765-
tree fn = build_min (COMPONENT_REF, TREE_TYPE (overload),
3766-
object, method, NULL_TREE);
3772+
tree fn = overload;
3773+
if (TREE_CODE (TREE_TYPE (overload)) == METHOD_TYPE)
3774+
{
3775+
tree binfo = TYPE_BINFO (TREE_TYPE (object));
3776+
tree method = build_baselink (binfo, binfo, overload, NULL_TREE);
3777+
fn = build_min (COMPONENT_REF, TREE_TYPE (overload),
3778+
object, method, NULL_TREE);
3779+
object = NULL_TREE;
3780+
}
37673781
gcc_assert (vec_safe_length (args) == nargs);
37683782

37693783
tree call = build_min_non_dep_call_vec (non_dep, fn, args);
@@ -3774,6 +3788,8 @@ build_min_non_dep_op_overload (tree non_dep, tree overload, tree object,
37743788
CALL_EXPR_ORDERED_ARGS (call_expr) = CALL_EXPR_ORDERED_ARGS (non_dep);
37753789
CALL_EXPR_REVERSE_ARGS (call_expr) = CALL_EXPR_REVERSE_ARGS (non_dep);
37763790

3791+
if (object)
3792+
return keep_unused_object_arg (call, object, overload);
37773793
return call;
37783794
}
37793795

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// PR c++/108437
2+
// { dg-do run { target c++23 } }
3+
4+
struct S { static int &operator[] (int x) { static int a[2]; return a[x]; } };
5+
struct U { static int &operator[] (int x, int y, int z) { static int a[2]; return a[x + y + z]; } };
6+
struct V { static int &operator[] () { static int a; return a; } };
7+
8+
template <class T, class W, class X> void
9+
foo ()
10+
{
11+
S s;
12+
s[0]++;
13+
T t;
14+
t[0]++;
15+
U u;
16+
u[0, 0, 0]++;
17+
V v;
18+
v[]++;
19+
W w;
20+
w[0, 0, 0]++;
21+
X x;
22+
x[]++;
23+
}
24+
25+
int
26+
main ()
27+
{
28+
S::operator[] (0) = 1;
29+
U::operator[] (0, 0, 0) = 2;
30+
V::operator[] () = 3;
31+
foo <S, U, V> ();
32+
if (S::operator[] (0) != 3 || U::operator[] (0, 0, 0) != 4 || V::operator[] () != 5)
33+
__builtin_abort ();
34+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// PR c++/108437
2+
// { dg-do run { target c++23 } }
3+
4+
struct S { static int &operator[] (int x) { static int a[2]; return a[x]; } };
5+
struct U { static int &operator[] (int x, int y, int z) { static int a[2]; return a[x + y + z]; } };
6+
struct V { static int &operator[] () { static int a; return a; } };
7+
int cnt;
8+
9+
template <typename T>
10+
T &
11+
bar (T &x)
12+
{
13+
++cnt;
14+
return x;
15+
}
16+
17+
template <class T, class W, class X> void
18+
foo ()
19+
{
20+
S s;
21+
bar (s)[0]++;
22+
T t;
23+
bar (t)[0]++;
24+
U u;
25+
bar (u)[0, 0, 0]++;
26+
V v;
27+
bar (v)[]++;
28+
W w;
29+
bar (w)[0, 0, 0]++;
30+
X x;
31+
bar (x)[]++;
32+
}
33+
34+
int
35+
main ()
36+
{
37+
S::operator[] (0) = 1;
38+
U::operator[] (0, 0, 0) = 2;
39+
V::operator[] () = 3;
40+
foo <S, U, V> ();
41+
if (S::operator[] (0) != 3 || U::operator[] (0, 0, 0) != 4 || V::operator[] () != 5 || cnt != 6)
42+
__builtin_abort ();
43+
}

0 commit comments

Comments
 (0)