4

Given the following example code

struct S;

template<typename>
class C
{
public:
   void f(bool b)
   {
      if (b)
        g();
   }

   void g()
   {
     S{};
   }
};

int main()
{
   C<int>{}.f(false);
}

GCC correctly reports the following:

example.cpp: In instantiation of 'void C< <template-parameter-1-1> >::g() [with <template-parameter-1-1> = int]':
10 : required from 'void C< <template-parameter-1-1> >::f(bool) [with <template-parameter-1-1> = int]'
21 : required from here
15 : error: invalid use of incomplete type 'struct S'

My question now is: Is this guaranteed behaviour which has some ruling in the standard or any other documents?

To be more precise about my question:

C is a template class, whose members f() and g() are only instantiated when they are being referenced. f() is referenced in main(). If I do not reference g() (which internally tries to use an incomplete type), the code would compile. But g() is being referenced within an if-branch inside f(). This branch is deterministically never being executed. So the compiler could potentially ignore/remove this dead code branch and thus avoid the instantiation of g() (and with that the error of trying to use the incomplete type). However, this is not happening (on the compilers I tried at least).

I understand that allowing this would turn illegal code into legal code by merely adjusting the optimization settings of a compiler, but still my question is if this code example is guaranteed to fail due to some rules (e.g. order of optimization vs. template passes) which can be read about somewhere.

Thanks for any insights.

Torben L.
  • 191
  • 1
  • 6
  • 1
    The C++ standard never guarantees failure. It only requires that correct programs produce a result consistent with the execution model. It does require diagnostic messages in some cases; I don't think this is such a case but I could be wrong. – rici Aug 04 '16 at 22:40
  • Your question asks the opposite of the title lol – Lightness Races in Orbit Aug 04 '16 at 22:50

2 Answers2

3

Can inlining and dead code removal optimizations prevent template instantiations?

No.

Dead code removal is an optimisation that can be performed to remove code that isn't "used" according to the rules of the optimiser. Such optimisations may not violate the "as-if" rule as long as the implementation wishes to remain fully compliant.

This program is ill-formed anyway. The instantiation of C<int> is required, in full, by the call found within main… and it is impossible. If this instantiation had succeeded then the unused parts of it may have been optimised away, but that's a step "later". You can only remove unused parts of a program that was physically capable of "existing" in the first place.

It might be interesting to ask whether an implementation is required to prevent compilation of such an ill-formed program, if it's likely to later remove the offending code anyway. We could answer this easily by quoting whatever passage of the standard defines "ill-formed". But that's both a different question and, in my opinion, by-the-by.

If you're interested, we cannot respond to this question in the affirmative in the general case, as some cases of ill-formity are qualified with the phrase "no diagnostic required". Off the top of my head, though, if that phrase is not present, a diagnostic is required. (Don't hold me to that.)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • In regards to your second paragraph: If I remove the call to `g()`, the program is not ill-formed, even though `g()`'s ill-formed implementation is still present in `C`. As I understand it, instantiation of `C` does not require the entirety of it to be valid, it only requires the referenced members of it to be. This is what my question is based upon: Since `g()` is only referenced in an unused part of the code, does the compiler still need to check its theoretical validity, even though it's a template class member function? – Torben L. Aug 05 '16 at 06:37
  • I see that the "as-if" rule and the standard's definitions of "ill-formed" are basically the answer to this, and I will do some research in these regards. Thank you. – Torben L. Aug 05 '16 at 06:49
  • _"instantiation of C does not require the entirety of it to be valid"_ I thought it did. – Lightness Races in Orbit Aug 05 '16 at 09:30
2

Optimization is something the compiler is allowed to apply to a valid program. Since S is undefined, it cannot be instantiated, and your program is invalid. It is too late for the optimizer to come in make the program valid.

nate
  • 1,771
  • 12
  • 17
  • Buttttt, to be complete, it may well build and run happily. I realise that's not what was asked for. – Lightness Races in Orbit Aug 04 '16 at 22:48
  • A valid program, and one that runs well are two different things. Many program rely on *predictable* undefined behavior. (think uninitialized variable that has no ill effects 99.9999% of the time) These programs are not valid, and the compiler is free to do what ever it pleases, including format your hard drive, but in practice they "run well". – nate Aug 04 '16 at 23:00