c++: Defer -fstrong-eval-order processing to template instantiation time [PR117158]

Since r10-3793-g1a37b6d9a7e57c, we ICE upon the following valid code
with -std=c++17 and above

=== cut here ===
struct Base {
  unsigned int *intarray;
};
template <typename T> struct Sub : public Base {
  bool Get(int i) {
    return (Base::intarray[++i] == 0);
  }
};
=== cut here ===

The problem is that from c++17 on, we use -fstrong-eval-order and need
to wrap the array access expression into a SAVE_EXPR. We do so at
template declaration time, and end up calling contains_placeholder_p
with a SCOPE_REF, that it does not handle well.

This patch fixes this by deferring the wrapping into SAVE_EXPR to
instantiation time for templates, when the SCOPE_REF will have been
turned into a COMPONENT_REF.

	PR c++/117158

gcc/cp/ChangeLog:

	* typeck.cc (cp_build_array_ref): Only wrap array expression
	into a SAVE_EXPR at template instantiation time.

gcc/testsuite/ChangeLog:

	* g++.dg/cpp1z/eval-order13.C: New test.
	* g++.dg/parse/crash77.C: New test.
This commit is contained in:
Simon Martin 2024-11-05 10:07:42 +01:00
parent 5c19ba5251
commit b1d92aeb85
3 changed files with 44 additions and 1 deletions

View file

@ -4092,7 +4092,8 @@ cp_build_array_ref (location_t loc, tree array, tree idx,
tree ar = cp_default_conversion (array, complain);
tree ind = cp_default_conversion (idx, complain);
if (!first && flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (ind))
if (!processing_template_decl
&& !first && flag_strong_eval_order == 2 && TREE_SIDE_EFFECTS (ind))
ar = first = save_expr (ar);
/* Put the integer in IND to simplify error checking. */

View file

@ -0,0 +1,29 @@
// PR c++/117158 - Similar to eval-order7.C, only with templates.
// { dg-do run { target c++11 } }
// { dg-options "-fstrong-eval-order" }
int a[4] = { 1, 2, 3, 4 };
int b[4] = { 5, 6, 7, 8 };
struct Base {
int *intarray;
};
template <typename T>
struct Sub : public Base {
int Get(int i) {
Base::intarray = a;
int r = Base::intarray[(Base::intarray = b, i)];
if (Base::intarray != b)
__builtin_abort ();
return r;
}
};
int
main ()
{
Sub<int> s;
if (s.Get (3) != 4)
__builtin_abort ();
}

View file

@ -0,0 +1,13 @@
// PR c++/117158
// { dg-do "compile" }
struct Base {
unsigned int *intarray;
};
template <typename T>
struct Sub : public Base {
bool Get(int i) {
return (Base::intarray[++i] == 0);
}
};