On Jan 24, 2008 11:41 AM, Jakub Jelinek <[EMAIL PROTECTED]> wrote: > On Thu, Jan 24, 2008 at 04:06:47PM +0100, Richard Guenther wrote: > > On Jan 24, 2008 3:58 PM, Doug Gregor <[EMAIL PROTECTED]> wrote: > > The middle-end type system (useless_type_conversion_p) says that > > pointers to int and pointers to int __attribute__((may_alias)) are > > distinct (you can't use one in place of the other without changning > > semantics) - because the pointed to types have different alias sets. > > > > Now, for rvalues that doesn't matter, so indeed a value of type > > int and a value of type int __attribute__((may_alias)) can be used > > in place of each other. So I stand corrected and they should indeed > > have the same canonical type. > > See also http://gcc.gnu.org/PR34936. Is int __attribute__((may_alias)) > supposed to be mangled the same as int? And if so, it should for cp/call.c > purposes be treated the same as well.
I just started venturing down this rabbit hole when I saw your note. Since we previously ignored the may_alias attribute, we ended up treating "int" and its may_alias typedef as identical nodes; that also seems like the right answer from the perspective of C++, because I think we want these types to mangle the same, act identical in overload resolution, etc. However, both the mangler (PR 34936) and the structural type checking routines (PR 34935) are unprepared for attribute-qualified typedefs like these, because they depend on the TYPE_MAIN_VARIANT being equivalent to one the predefined type nodes (which isn't the case with attribute-qualified typedefs). The canonical type system gets this right: it sees the types as equivalent, and always gives us a path from the typedef'd, attribute-qualified versions of types back to the predefined type nodes (which are the canonical versions, by design). So, I'm fixing both PRs by using canonical types. With 34935, we end up just relying on canonical types to compare INTEGER_TYPE, FIXED_POINT_TYPE, and REAL_TYPE nodes, because there's no other way to do it without fundamentally changing how attribute-qualified typedefs are represented. With 34936, we just map the builtin type down to its canonical form, which will be one of the predefined type nodes. The attached patch fixes both PRs. Regression tests are still running on i686-pc-linux-gnu, but assuming no problems crop up... okay for mainline? - Doug 2008-01-24 Douglas Gregor <[EMAIL PROTECTED]> Jakub Jelinek <[EMAIL PROTECTED]> PR c++/34935 PR c++/34936 * typeck.c (structural_comptypes): Handle comparisons of VOID_TYPE, BOOLEAN_TYPE, INTEGER_TYPE, FIXED_POINT_TYPE, and REAL_TYPE nodes. * mangle.c (write_builtin_type): Map down to the canonical type, which will be one of the predefined type nodes. 2008-01-24 Douglas Gregor <[EMAIL PROTECTED]> Jakub Jelinek <[EMAIL PROTECTED]> PR c++/34935 PR c++/34936 * g++.dg/ext/alias-canon.C: New. * g++.dg/ext/alias-mangle.C: New.
Index: cp/typeck.c =================================================================== --- cp/typeck.c (revision 131778) +++ cp/typeck.c (working copy) @@ -976,6 +976,30 @@ structural_comptypes (tree t1, tree t2, /* Compare the types. Break out if they could be the same. */ switch (TREE_CODE (t1)) { + case VOID_TYPE: + case BOOLEAN_TYPE: + /* All void and bool types are the same. */ + break; + + case INTEGER_TYPE: + case FIXED_POINT_TYPE: + case REAL_TYPE: + /* With these nodes, we can't determine type equivalence by + looking at what is stored in the nodes themselves, because + two nodes might have different TYPE_MAIN_VARIANTs but still + represent the same type. For example, wchar_t and int could + have the same properties (TYPE_PRECISION, TYPE_MIN_VALUE, + TYPE_MAX_VALUE, etc.), but have different TYPE_MAIN_VARIANTs + and are distinct types. On the other hand, int and the + following typedef + + typedef int INT __attribute((may_alias)); + + have identical properties, different TYPE_MAIN_VARIANTs, but + represent the same type. The canonical type system keeps + track of equivalence in this case, so we fall back on it. */ + return TYPE_CANONICAL (t1) == TYPE_CANONICAL (t2); + case TEMPLATE_TEMPLATE_PARM: case BOUND_TEMPLATE_TEMPLATE_PARM: if (TEMPLATE_TYPE_IDX (t1) != TEMPLATE_TYPE_IDX (t2) Index: cp/mangle.c =================================================================== --- cp/mangle.c (revision 131778) +++ cp/mangle.c (working copy) @@ -1768,6 +1768,9 @@ write_CV_qualifiers_for_type (const tree static void write_builtin_type (tree type) { + if (TYPE_CANONICAL (type)) + type = TYPE_CANONICAL (type); + switch (TREE_CODE (type)) { case VOID_TYPE: Index: testsuite/g++.dg/ext/alias-canon.C =================================================================== --- testsuite/g++.dg/ext/alias-canon.C (revision 0) +++ testsuite/g++.dg/ext/alias-canon.C (revision 0) @@ -0,0 +1,41 @@ +// PR c++/34935 +/* { dg-do compile } */ +/* { dg-final { scan-assembler "_Z1fi" } } */ +/* { dg-final { scan-assembler "_Z1fb" } } */ +/* { dg-final { scan-assembler "_Z1fd" } } */ +/* { dg-final { scan-assembler "_Z1ff" } } */ +/* { dg-final { scan-assembler "_Z1fw" } } */ + +typedef int INT __attribute((may_alias)); + +void f(int); +void f(INT) { } + +typedef bool BOOL __attribute((may_alias)); + +void f(bool); +void f(BOOL) { } + +typedef float FLOAT __attribute((may_alias)); + +void f(float); +void f(FLOAT) { } + +typedef double DOUBLE __attribute((may_alias)); + +void f(double); +void f(DOUBLE) {} + +typedef wchar_t WCHAR_T __attribute((may_alias)); + +void f(wchar_t); +void f(WCHAR_T) {} + +void test() +{ + f(0); + f(true); + f(1.0f); + f(1.0); + f(L'f'); +} Index: testsuite/g++.dg/ext/alias-mangle.C =================================================================== --- testsuite/g++.dg/ext/alias-mangle.C (revision 0) +++ testsuite/g++.dg/ext/alias-mangle.C (revision 0) @@ -0,0 +1,11 @@ +// PR c++/34936 +// { dg-do compile } +/* { dg-final { scan-assembler "_ZN1AIdEC1Ev" } } */ +typedef double X __attribute((may_alias)) ; + +template<typename> struct A +{ + A(); +}; + +A<X> a;