https://gcc.gnu.org/bugzilla/show_bug.cgi?id=126900

--- Comment #5 from Patrick Palka <ppalka at gcc dot gnu.org> ---
Ah, so the trial constant evaluation performed by r17-3305 can cause a function
to be instantiated immediately instead of deferring that instantiation, which
can lead to different diagnostic context lines if that instantiation is
ill-formed.

template<class T>
constexpr int g() {
  static_assert(sizeof(T) == 1);
  return 0;
}

template<class T>
constexpr bool f() {
  auto x = g<T>(); // With -O, g<int> now instantiated during f<int>
instantiation instead of deferred
  return true;
}

static_assert(f<int>());

With -O we'll now diagnose the failed static_assert during instantiation of
f<int>, specifically during cp_fold_function which enters x's initializer,
which constant evaluates it during which we first instantiate g<int>.

Without -O, instantiation of f<int> doesn't do any such folding, and we instead
first instantiate g<int> during manifestly constant evaluation of f<int>().


$ g++ -O 126900.C
126900.C: In instantiation of ‘constexpr int g() [with T = int]’:
126900.C:9:16:   required from ‘constexpr bool f() [with T = int]’
    9 |   auto x = g<T>();
      |            ~~~~^~
126900.C:13:21:   required from here
   13 | static_assert(f<int>());
      |               ~~~~~~^~
126900.C:3:27: error: static assertion failed
    3 |   static_assert(sizeof(T) == 1);
      |                 ~~~~~~~~~~^~~~
  • the comparison reduces to ‘(4 == 1)’

$ g++ 126900.C
126900.C: In instantiation of ‘constexpr int g() [with T = int]’:
126900.C:9:16:   required from here
    9 |   auto x = g<T>();
      |            ~~~~^~
126900.C:13:21:   in ‘constexpr’ expansion of ‘f<int>()’
   13 | static_assert(f<int>());
      |               ~~~~~~^~
126900.C:3:27: error: static assertion failed
    3 |   static_assert(sizeof(T) == 1);
      |                 ~~~~~~~~~~^~~~
  • the comparison reduces to ‘(4 == 1)’

While it's not ideal that the context lines are different with -O vs without,
I'm not sure it's worth fixing this. We can call maybe_constant_init even
without -O (and just discard the result) so that the instantiation order is
independent of -O, but that'd slow down -O0 which we want to be as fast as
possible.  Or we can make maybe_constant_init not instantiate any
uninstantiated functions when mce_false but that'd make the optimization 
dependent on instantiation order which seems brittle, and would severely
restrict when the optimization would trigger.

Reply via email to