https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67896
--- Comment #1 from Roger Ferrer Ibanez <roger.ferrer at bsc dot es> --- Hi, after some debugging I think I understand what happens but I'm not sure I can provide an acceptable fix for that. When comparing __Poly8x8_t and __Poly16x8_t types (these are the builtin types for poly8x8_t and poly16x8_t respectively) in the C++ FE, the sequence involves "comptypes" and then "structural_comptypes". Since both types are vectors, the number of elements is the same (i.e. TYPE_VECTOR_SUBPARTS is 8 for the two vector types), so it only remains to check the element type (i.e. the TREE_TYPE) of the vector (these are __Poly8_t and __Poly16_t). At this point "structural_comptypes" sees that both types are INTEGER_TYPE and then proceeds to compare them using TYPE_CANONICAL but at this point for both types the canonical type is NULL, so the structural comparison trivially succeeds. Types __Poly8x8_t and __Poly16x8_t are initialized in "aarch64_init_simd_builtin_types" in "gcc/config/aarch64/aarch64-builtins.c". There is an array of structs, called aarch64_simd_types, with two fields, among others, eltype (element type) and itype (internal type). At some point the code initializes the several __PolyS_t (where S = {8, 16, 64, 128}) with a distinct type of integer type {QI, HI, DI, TI} (note that itype is also initialized) aarch64_simd_types[Poly8_t].eltype = aarch64_simd_types[Poly8_t].itype = build_distinct_type_copy (unsigned_intQI_type_node); aarch64_simd_types[Poly16_t].eltype = aarch64_simd_types[Poly16_t].itype = build_distinct_type_copy (unsigned_intHI_type_node); ... and a bit later it makes sure __PolySxN_t have their element type to their respective __PolyS_t. aarch64_simd_types[Poly8x8_t].eltype = aarch64_simd_types[Poly8_t].itype; ... aarch64_simd_types[Poly16x8_t].eltype = aarch64_simd_types[Poly16_t].itype; And it finally proceeds to build the vector types except if the itype is not null. Only the nonvector __PolyS_t types have a non-null itype (it was assigned above) so they are not set a vector type. for (i = 0; i < nelts; i++) { tree eltype = aarch64_simd_types[i].eltype; enum machine_mode mode = aarch64_simd_types[i].mode; if (aarch64_simd_types[i].itype == NULL) aarch64_simd_types[i].itype = build_distinct_type_copy (build_vector_type (eltype, GET_MODE_NUNITS (mode))); tdecl = add_builtin_type (aarch64_simd_types[i].name, aarch64_simd_types[i].itype); TYPE_NAME (aarch64_simd_types[i].itype) = tdecl; SET_TYPE_STRUCTURAL_EQUALITY (aarch64_simd_types[i].itype); } The last statement in the loop ensures that the type is compared using structural equality. This effectively sets the canonical type to zero, according to the macro in tree.h #define SET_TYPE_STRUCTURAL_EQUALITY(NODE) (TYPE_CANONICAL (NODE) = NULL_TREE) My knowledge of the internals of GCC is too limited at this point to state whether setting structural equality for all these types is OK. I think, though, that setting structural equality for the non-vector types (thus nullifying their canonical type) may be wrong: it makes two __PolyS_N_t types (where N is the same) identical at the eyes of the C++ FE. The following crude patch seems to let the C++ FE distinguish the two types. --- /home/roger/soft/gcc/src/gcc-5.2.0/gcc/config/aarch64/aarch64-builtins.c 2015-04-01 13:18:03.000000000 +0200 +++ config/aarch64/aarch64-builtins.c 2015-10-11 23:51:05.315828614 +0200 @@ -628,15 +628,20 @@ tree eltype = aarch64_simd_types[i].eltype; enum machine_mode mode = aarch64_simd_types[i].mode; + bool is_vector = false; if (aarch64_simd_types[i].itype == NULL) - aarch64_simd_types[i].itype = - build_distinct_type_copy + { + aarch64_simd_types[i].itype = + build_distinct_type_copy (build_vector_type (eltype, GET_MODE_NUNITS (mode))); + is_vector = true; + } tdecl = add_builtin_type (aarch64_simd_types[i].name, aarch64_simd_types[i].itype); TYPE_NAME (aarch64_simd_types[i].itype) = tdecl; - SET_TYPE_STRUCTURAL_EQUALITY (aarch64_simd_types[i].itype); + if (is_vector) + SET_TYPE_STRUCTURAL_EQUALITY (aarch64_simd_types[i].itype); } #define AARCH64_BUILD_SIGNED_TYPE(mode) \ With this change, g++ is able to tell the two types apart. $ cat test.cc typedef __Poly8x8_t A; typedef __Poly16x8_t A; $ aarch64-linux-gnu-g++ -fsyntax-only test.cc -Wall test.cc:2:22: error: conflicting declaration ‘typedef __vector(8) __Poly16_t A’ typedef __Poly16x8_t A; ^ test.cc:1:21: note: previous declaration as ‘typedef __vector(8) __Poly8_t A’ typedef __Poly8x8_t A; Caveat: I debugged this problem in a cross-compiler without real hardware so I do not know if this is OK or not. Hope this helps. Kind regards,