8

Minimal example I got is a bit complicated:

struct A { };

template <int>
struct Parent { };

template <int N>
constexpr int operator*(A, Parent<N>*) { return N; }

template <class T>
using ptr = T*;

template <int>
struct Other { };

template <int N>
struct Kid: Parent<N> { 
    static Other<A{} * ptr<Kid>{}> o;
};

int main() {
    Kid<2>{};
}

[gcc] compiles the code without any problem, [clang] complains about matching Parent against Kid problem:

prog.cc:7:15: note: candidate template ignored: could not match 'Parent' against 'Kid'
constexpr int operator*(A, Parent<N>*) { return N; }

To get more absurd when we change the code a bit:

struct A { };

template <int>
struct Parent { };

template <int N>
constexpr int operator*(A, Parent<N>*) { return N; }

template <class T>
using ptr = T*;

template <int>
struct Other { };

template <int N>
struct Kid: Parent<N> { 
    static constexpr int s = A{} * ptr<Kid>{};
};

int main() {
    Other<Kid<2>::s>{};
}

[clang] also compiles the code. So... is it a bug or am I starting to go insane?

W.F.
  • 13,888
  • 2
  • 34
  • 81
  • 2
    Can't help with a 100% answer, but in general I've found `gcc` to be more permissive than `clang` while the latter follows the standard more closely. I would suspect that's the case here. However, the Intel compiler also accepts the code. – davmac Dec 17 '17 at 11:53

1 Answers1

6

Clang is right to the letter of the law. Yes, Kid is derived from Parent. But that relationship can only be established once Kid is a completely defined type. And well, [class.mem]/6:

A class is considered a completely-defined object type ([basic.types]) (or complete type) at the closing } of the class-specifier. Within the class member-specification, the class is regarded as complete within function bodies, default arguments, noexcept-specifiers, and default member initializers (including such things in nested classes). Otherwise it is regarded as incomplete within its own class member-specification.

We are in the "otherwise" part I highlighted. Even though we are dealing with pointers, the class is not yet considered defined for the pointer conversion to be valid. GCC is overly permissive.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • 1
    Yep it sounds like **the answer** :) and at least you haven't said I went insane ;) By the way - nice winter hat! – W.F. Dec 17 '17 at 12:26
  • If no one comes with any objections I'll file a bug... let's hope I'll find some shorter MCVE... ;) – W.F. Dec 17 '17 at 12:28
  • 1
    @W.F. - I too am hopeful to see if anyone can shed more light on this. And you aren't insane by any stretch of the word, but that example... ;) – StoryTeller - Unslander Monica Dec 17 '17 at 12:32
  • @W.F. - wait. Abort. Kid is an inconplete type in the OP. Clang is right... – StoryTeller - Unslander Monica Dec 17 '17 at 15:00
  • Yeah we're dealing with incomplete type but on the other hand we're casting a pointers not an instance itself... you think one cannot do that inside a class? PS. don't worry haven't filed bug yet - this takes a while... ;) – W.F. Dec 17 '17 at 15:10
  • @W.F. - Updated. I was being foolish. It'd disallowed from being considered defined at that point and place. It would work inside a member function definition however. According to the specification. – StoryTeller - Unslander Monica Dec 17 '17 at 16:40
  • Yep... my mind kept suggesting me that this is the case here... Thanks for being tenacious! – W.F. Dec 17 '17 at 16:46
  • @W.F. - Thanks for the brain teaser :) These questions make visiting SO worthwhile – StoryTeller - Unslander Monica Dec 17 '17 at 16:47
  • Ok, you can called me insane ;) Why does [this](https://wandbox.org/permlink/kmNeOIurUQo3VE0Q) compile in clang? – W.F. Dec 17 '17 at 18:49
  • @W.F. - ¯\\_(ツ)_/¯ Definite lack of consistency. But I'll argue it's simply an extension that isn't applied in this case because reasons. I'm much more sure of the quote I have now. – StoryTeller - Unslander Monica Dec 17 '17 at 18:59
  • Your right, though ill-formed with no diagnostic should be forbidden :) – W.F. Dec 17 '17 at 19:15
  • 1
    @W.F. - Yeah. [Btw, here's further proof Clang is well aware of this rule](http://coliru.stacked-crooked.com/a/f9bc9a5bfd04bb4a). But you know... I don't see anything that necessitates the class to be fully defined for the conversion to happen. Neither [here](https://timsong-cpp.github.io/cppwp/n4659/conv.ptr#3), nor [here](https://timsong-cpp.github.io/cppwp/n4659/class.derived#2) or even [here](https://timsong-cpp.github.io/cppwp/n4659/basic.def.odr#5). Interesting... – StoryTeller - Unslander Monica Dec 17 '17 at 19:35
  • 1
    This is not the first time that this case of in class static initialization is discussed. This is just a hole in the standard that is kept to make the life of compiler implementer easy, but make the life of coder a hell. I think the commitee should open the oxford dictionnary, read "tool" definition and reconsider the axiomatic bases of their judgment. – Oliv Dec 19 '17 at 10:00