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

--- Comment #4 from Andy Lutomirski <luto at kernel dot org> ---
(In reply to Andrew Pinski from comment #3)
> Basically ParameterizedTestFactory<Test> does not have internal linkage as
> Test does not internal linkage.
> 
> If another source file has:
> ```
> 
> namespace { struct LocalEnum {}; }
> 
> struct Test {
>   typedef LocalEnum ParamType;
>   static void AddToRegistry() {
>     TestMetaFactory<Test> factory;
>   }
> };
> ```
> 
> Then TestMetaFactory<Test>::ParamType would have 2 different types as
> LocalEnum in both TUs have internal linkage.

You lost me here.

If I had two source files, each of which included the header, and the second
source file also defined the struct Test as you describe in this comment, then
surely that's the ODR violation right there: the second TU defines a struct
called Test that has a different definition than the first TU (as its ParamType
is different).

But I don't see how this makes GCC's warning valid.  Sure, I can create an ODR
violation by creating one directly as in your example, but that doesn't mean
that the code *that GCC is warning about* has much if anything to do with it. 
Otherwise GCC would warn about:


namespace { struct LocalEnum {}; }

struct Test {
  typedef LocalEnum ParamType;
  static void AddToRegistry() {
    ParamType();
  }
};

or even just about:

struct Test {
};


I agree that if I had struct Test in a header, gcc should warn, although I
think I would struggle a bit to put Test in a header without either also
putting the anonymous namespace in a header or writing some utterly outrageous
code in which I define LocalEnum outside a header and then reference it from a
header.

So...

(In reply to Andrew Pinski from comment #1)
> I think this warning is correct here.
> Since Test has external linkage but Test::ParamType is local linkage.
> 
> So its of TestMetaFactory<Test> in Test::AddToRegistry makes it possible to
> have an ODR violation.
> 

The addition to a registry can at most put an object that has *dynamic* type
Test somewhere that another TU can find it, but that's not an ODR violation. 
No amount of template magic or virtual magic would let me actually statically
name the type Test from another TU without already first violating ODR by
copying the definition of the type Test to that TU.

Based on my reading of the gcc docs and my experience reducing this test case,
I think that gcc has some heuristics in the Wsubobject-linkage logic based on
which things live in headers and which things live in the main C++ file.  And I
think my example breaks those heuristics.  Basically, there are some templates,
and the fully expanded-out type of those templates' instances includes
something defined in the main C++ file, which means that those instances can't
be named outside this TU.  Maybe there are some examples that are different
from my example where one could repeat the parts in the C++ file in a different
TU *without violating ODR by the mere fact that of that repetition* and thus
generate an ODR violation in the template, but all the examples I'm coming up
with have something with internal linkage that actually lives in a header.  And
my example has no such thing.

Reply via email to