Home > Back-end >  Why do I get the "child has a base whose type uses the anonymous namespace" warning here
Why do I get the "child has a base whose type uses the anonymous namespace" warning here

Time:06-30

I am trying to understand why I get a warning -Wsubobject-linkage when trying to compile this code:

base.hh

#pragma once

#include <iostream>

template<char const *s>
class Base
{
public:
  void print()
  {
    std::cout << s << std::endl;
  }
};

child.hh

#pragma once

#include "base.hh"

constexpr char const hello[] = "Hello world!";

class Child : public Base<hello>
{
};

main.cc

#include "child.hh"

int main(void)
{
  Child c;
  c.print();
  return 0;
}

When running g main.cc I get this warning:

In file included from main.cc:1:
child.hh:7:7: warning: ‘Child’ has a base ‘Base<(& hello)>’ whose type uses the anonymous namespace [-Wsubobject-linkage]
    7 | class Child : public Base<hello>
      |       ^~~~~

This warning does not occur if the templated value is an int or if child.hh is copied in main.cc I do not understand what justifies this warning here, and what I'm supposed to understand from it.

CodePudding user response:

The warning is appropriate, just worded a bit unclear.

hello is declared constexpr, as well as redundantly const. A const variable generally has internal linkage (with some exceptions like variable templates, inline variables, etc.).

Therefore hello in the template argument to Base<hello> is a pointer to an internal linkage object. In each translation unit it will refer to a different hello local to that translation unit.

Consequently Base<hello> will be different types in different translation units and so if you include child.hh in more than one translation unit you will violate ODR on Child's definition and therefore your program will have undefined behavior.

The warning is telling you that. The use of "anonymous namespace" is not good. It should say something like "whose type refers to an entity with internal linkage". But otherwise it is exactly stating the problem.

This happens only if you use a pointer or reference to the object as template argument. If you take just the value of a variable, then it doesn't matter whether that variable has internal or external linkage since the type Base<...> will be determined by the value of the variable, not the identity of the variable.


I don't know why you need the template argument to be a pointer here, but if you really need it and you actually want to include the .hh file in multiple .cc files (directly or indirectly), then you need to give hello external linkage. Then you will have the problem that an external linkage variable may only be defined in one translation unit, which you can circumvent by making the variable inline:

inline constexpr char hello[] = "Hello world!";

inline implies external linkage (even if the variable is const) and constexpr implies const.

CodePudding user response:

If child.hh is included in multiple TUs, it would violate ODR and lead to undefined behavior NDR as explained here.

A new bug for better wording of the warning has been submitted here:

Bug 106141 - Better wording for warning: ‘Child’ has a base ‘Base<(& hello)>’ whose type uses the anonymous namespace [-Wsubobject-linkage]


There is also an old bug submitted as:

Bug 86491 - bogus and unsuppressible warning: 'YYY' has a base 'ZZZ' whose type uses the anonymous namespace.

  • Related