2015-05-20 34 views
8

Proszę rozważyć następujące testcase (zmniejszone ze źródła LLVM):std :: make_unique, nazw anonimowe i ODR

//% 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>(); } 

i

//% 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>(); } 

Czy to narusza regułę jedna definicja?

gcc-6 obecnie tak myśli:

~ % 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> 
     ^
+0

Czy to się zdarza, jeśli nadadzą się przestrzenie nazw zawierające nazwy 'A', takie jak' Bob' i 'Cinderella'? – Yakk

+0

Nie. Używanie nazwanych przestrzeni nazw działa dobrze. Wygląda coraz bardziej jak błąd kompilatora. – octoploid

Odpowiedz

6

To był błąd GCC (który znajdował się w drzewie devel na kilka dni). Problem został spowodowany przez inną poprawkę, która spowodowała, że ​​GCC uznał niejawne typedefs za anonimowe, a zatem zewnętrzne struktury zostały scalone (niepoprawnie). Sprawa jest już naprawiona, chciałbym usłyszeć o ostrzeżeniach, które mogą wydawać się fałszywe.

+0

Dzięki. BTW Zapomniałem wspomnieć, że problem jest śledzony tutaj: https://gc.gnu.org/bugzilla/show_bug.cgi?id=66180 – octoploid

-2

Masz dwie różne definicje klasy. Skompilowanie tych dwóch elementów prowadzi do konfliktu bezpośredniego, chyba że te dwa kończą się oddzielnymi przestrzeniami nazw. Przypuszczam, że to może być słuszne.

Czego można chcieć szukać, to czy te dwie funkcje implementacji wzajemnie się wykluczają. Mogą istnieć dwa różne pliki źródłowe z oddzielnymi definicjami, ale są przypadki, w których posiadanie dwóch definicji może mieć sens (tj. Mam interfejs API do wątków w systemach Windows i Linux i muszę mieć dwie różne definicje na podstawie moich ustawień kompilacji).

+11

Nienazwane przestrzenie nazw powinny wyróżniać te definicje w różnych programach. – myaut