2015-05-20 22 views
8

Si prega di considerare quanto segue TestCase (ridotto da fonte LLVM):std :: make_unique, namespace anonimo e 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>(); } 

e

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

Questo violare la regola Una definizione?

gcc-6 attualmente la pensa così:

~ % 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

Questo succede ancora se si danno gli spazi dei nomi che racchiudono i nomi di 'A's, come' Bob' e 'Cenerentola'? – Yakk

+0

No. L'uso degli spazi dei nomi con nome funziona correttamente. Sembra sempre più simile a un bug del compilatore. – octoploid

risposta

6

Questo era un bug GCC (che era nell'albero di sviluppo solo per pochi giorni). Il problema era causato da un'altra correzione che rendeva GCC in grado di considerare typedef impliciti non anonimi e quindi le strutture esterne ottenevano il tipo unificato (in modo errato). Il testcase è stato riparato ora, sarei interessato a conoscere altri avvertimenti che potrebbero apparire fasulli.

+0

Grazie. BTW Ho dimenticato di menzionare che il problema è tracciato qui: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66180 – octoploid

-2

Hai due diverse definizioni di una classe. La compilazione dei due insieme risulta in un conflitto diretto a meno che questi due non finiscano in spazi dei nomi separati. Suppongo che potrebbe essere giusto.

Quello che si vorrebbe cercare è se le due funzionalità di implementazione si escludono a vicenda. Potrebbero esserci due file sorgente diversi con definizioni separate, ma ci sono casi in cui avere due definizioni potrebbe avere senso (ad esempio, ho un'API di threading su Windows e Linux e ho bisogno di avere due definizioni diverse in base alle impostazioni della mia compilation).

+11

Gli spazi dei nomi senza nome dovrebbero rendere queste definizioni univoche in tutto il programma. – myaut