Search code examples
c++templatesoptimizationdead-codeinlining

Can inlining and dead code removal optimizations prevent template instantiations?


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.


Solution

  • 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.)