Reputation: 635
Please consider the following testcase (reduced from LLVM source):
//% cat foo1.cpp
#include <memory>
namespace {
class A {
int i;
};
}
class G {
std::unique_ptr<A> foo() const;
};
std::unique_ptr<A> G::foo() const { return std::make_unique<A>(); }
and
//% cat foo2.cpp
#include <memory>
namespace {
class A {
bool a;
};
}
class H {
std::unique_ptr<A> bar() const;
};
std::unique_ptr<A> H::bar() const { return std::make_unique<A>(); }
Does this violate the One Definition Rule?
gcc-6 currently thinks so:
~ % g++ -flto -shared -std=c++14 foo1.cpp foo2.cpp
/home/trippels/gcc_test/usr/local/include/c++/6.0.0/tuple:187:72: warning: type ‘struct _Base’ violates one definition rule [-Wodr]
typedef _Head_base<_Idx, _Head, __empty_not_final<_Head>::value> _Base;
^
/home/trippels/gcc_test/usr/local/include/c++/6.0.0/tuple:187:72: note: a different type is defined in another translation unit
typedef _Head_base<_Idx, _Head, __empty_not_final<_Head>::value> _Base;
^
/home/trippels/gcc_test/usr/local/include/c++/6.0.0/tuple:147:13: note: the first difference of corresponding definitions is field ‘_M_head_impl’
_Head _M_head_impl;
^
/home/trippels/gcc_test/usr/local/include/c++/6.0.0/tuple:147:13: note: a field of same name but different type is defined in another translation unit
_Head _M_head_impl;
^
foo1.cpp:3:7: note: type ‘struct A’ defined in anonymous namespace can not match type ‘struct A’
class A {
^
foo2.cpp:3:7: note: the incompatible type defined in anonymous namespace in another translation unit
class A {
^
/home/trippels/gcc_test/usr/local/include/c++/6.0.0/tuple:598:40: warning: type ‘struct _Inherited’ violates one definition rule [-Wodr]
typedef _Tuple_impl<0, _T1, _T2> _Inherited;
^
/home/trippels/gcc_test/usr/local/include/c++/6.0.0/tuple:598:40: note: a type with the same name but different base type is defined in another translation unit
typedef _Tuple_impl<0, _T1, _T2> _Inherited;
^
/home/trippels/gcc_test/usr/local/include/c++/6.0.0/tuple:102:12: note: type ‘struct _Head_base’ defined in anonymous namespace can not match type ‘struct _Head_base’
struct _Head_base<_Idx, _Head, false>
^
/home/trippels/gcc_test/usr/local/include/c++/6.0.0/tuple:102:12: note: the incompatible type defined in anonymous namespace in another translation unit
struct _Head_base<_Idx, _Head, false>
^
/home/trippels/gcc_test/usr/local/include/c++/6.0.0/bits/unique_ptr.h:151:41: warning: type ‘struct element_type’ violates one definition rule [-Wodr]
typedef _Tp element_type;
^
/home/trippels/gcc_test/usr/local/include/c++/6.0.0/bits/unique_ptr.h:151:41: note: a different type is defined in another translation unit
typedef _Tp element_type;
^
foo1.cpp:4:7: note: the first difference of corresponding definitions is field ‘i’
int i;
^
foo2.cpp:4:8: note: a field with different name is defined in another translation unit
bool a;
^
/home/trippels/gcc_test/usr/local/include/c++/6.0.0/tuple:598:40: warning: type ‘struct _Inherited’ violates one definition rule [-Wodr]
typedef _Tuple_impl<0, _T1, _T2> _Inherited;
^
/home/trippels/gcc_test/usr/local/include/c++/6.0.0/tuple:598:40: note: a type with the same name but different base type is defined in another translation unit
typedef _Tuple_impl<0, _T1, _T2> _Inherited;
^
/home/trippels/gcc_test/usr/local/include/c++/6.0.0/tuple:102:12: note: type ‘struct _Head_base’ defined in anonymous namespace can not match type ‘struct _Head_base’
struct _Head_base<_Idx, _Head, false>
^
/home/trippels/gcc_test/usr/local/include/c++/6.0.0/tuple:102:12: note: the incompatible type defined in anonymous namespace in another translation unit
struct _Head_base<_Idx, _Head, false>
^
Upvotes: 8
Views: 688
Reputation: 649
This was GCC bug (which was in the devel tree just for few days). The problem was caused by another fix that made GCC to consider implicit typedefs non-anonymous and thus the outer structures got type merged (incorrectly so). The testcase is fixed now, I would be interested to hear about more warnings that may appear bogus.
Upvotes: 6
Reputation: 6190
You have two different definitions of a class. Compiling the two together results in a direct conflict unless these two end up in separate namespaces. I suppose this might be right.
What you might want to look for is whether the two implementation features are mutually exclusive. There might be two different source files with separate definitions, but there are cases where having two definitions might make sense (i.e. I have a threading API on Windows and Linux and I need to have two different definitions based on my compilation settings).
Upvotes: -2