3

I must be missing something really obvious here. Consider two examples below:

struct Test;

int bar()
{
    return sizeof(Test);   // (1), compilation error: Test is incomplete
}

struct Test
{
    char x[123456];
};

The first example cannot be compiled for obvious reason: struct Test is incomplete at line marked (1) and hence any expression that requires complete type would fail. That's understandable.

template <typename T>
int foo()
{
    return sizeof(T);
}

struct Test;

int bar()
{
    return foo<Test>();    // (2): no error.
}

struct Test
{
    char x[123456];
};

However, this second example compiles just fine and that surprises me a lot.

My naiive understanding of implicit template instantiation suggested that foo<Test>() is instantiated at line marked (2) and that class Test is still incomplete at that point. Which made me think that applying sizeof operator to it would result in the same compilation error.

Godbolt proves me wrong even with --std=c++98 -- generated assembler code shows that foo<> returns correct value, and another godbolt dashboard (thanks, Marek R!) shows that this example seems valid across several compilers and standard options. I can't figure out why... So my questions are:

  1. Does that second code snippet constitute a well-formed program according to C++17 standard?

  2. What is the point of instantiation of function foo<Test>()?

  3. Why is Test treated as a completely defined class in the body of instantiated foo<>()?

Edit:
The question linked as a duplicate asked a different question. It asked: "is the compiler conforming?" and the answer was: "yes, the compiler is allowed to do that". This question, on the contrary, asks: "is the code well-formed?" (see question #1 above) and the answer, judging by the comments, seems to be "no, it's ill-formed".

Igor G
  • 1,838
  • 6
  • 18
  • 1
    [better godbolt](https://godbolt.org/z/G7M9Thdhb). – Marek R Oct 07 '22 at 17:15
  • 1
    Related/dupe: [Can the point-of-instantiation be delayed until the end of the translation unit?](https://stackoverflow.com/questions/23030403/can-the-point-of-instantiation-be-delayed-until-the-end-of-the-translation-unit). – Jason Oct 07 '22 at 17:19
  • Adding constexpr [confuses clang](https://godbolt.org/z/zfx8Pxb7Y). – Marek R Oct 07 '22 at 17:21
  • @MarekR Not really confusing it. Clang just seems to decide to instantiate `constexpr` function template specialization earlier. Either way is permitted by the standard. – user17732522 Oct 07 '22 at 17:39
  • 1
    Recap answer: There are two possible points of instantiation. One after `bar`'s definition and one at the end of the translation unit. If they give different meaning to instantiations (as is the case here) the program is ill-formed, no diagnostic required. Basically the compiler can choose either point to actually try the instantiation. It may compile or may not compile, no guarantees. – user17732522 Oct 07 '22 at 17:43
  • @user17732522, "If they give different meaning to instantiations (as is the case here) the program is ill-formed, no diagnostic required." -- I think that's the answer I was looking for. Would you mind converting this comment to an answer, if I can have this question reopened? – Igor G Oct 07 '22 at 17:50

0 Answers0