Message ID | 20191008221409.GA2949@redhat.com |
---|---|
State | New |
Headers | show |
Series | C++ PATCH for c++/92032 - DR 1601: Promotion of enum with fixed underlying type | expand |
OK. On 10/8/19 6:14 PM, Marek Polacek wrote: > I've been messing with compare_ics recently and noticed that we don't > implement CWG 1601, which should be fairly easy. > > The motivating example is > > enum E : char { e }; > void f(char); > void f(int); > void g() { > f(e); > } > > where the call to f was ambiguous but we should choose f(char). > > Currently we give f(int) cr_promotion in standard_conversion, while > f(char) remains cr_std, which is worse than cr_promotion. So I thought > I'd give it cr_promotion also and then add a tiebreaker to compare_ics. > > Bootstrapped/regtested on x86_64-linux, ok for trunk? > > 2019-10-08 Marek Polacek <polacek@redhat.com> > > PR c++/92032 - DR 1601: Promotion of enum with fixed underlying type. > * call.c (standard_conversion): When converting an enumeration with > a fixed underlying type to the underlying type, give it the cr_promotion > rank. > (compare_ics): Implement a tiebreaker as per CWG 1601. > > * g++.dg/cpp0x/scoped_enum10.C: New test. > * g++.dg/cpp0x/scoped_enum11.C: New test. > > diff --git gcc/cp/call.c gcc/cp/call.c > index 6c9acac4614..10172855d4d 100644 > --- gcc/cp/call.c > +++ gcc/cp/call.c > @@ -1484,8 +1484,18 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, > > conv = build_conv (ck_std, to, conv); > > - /* Give this a better rank if it's a promotion. */ > - if (same_type_p (to, type_promotes_to (from)) > + tree underlying_type = NULL_TREE; > + if (TREE_CODE (from) == ENUMERAL_TYPE > + && ENUM_FIXED_UNDERLYING_TYPE_P (from)) > + underlying_type = ENUM_UNDERLYING_TYPE (from); > + > + /* Give this a better rank if it's a promotion. > + > + To handle CWG 1601, also bump the rank if we are converting > + an enumeration with a fixed underlying type to the underlying > + type. */ > + if ((same_type_p (to, type_promotes_to (from)) > + || (underlying_type && same_type_p (to, underlying_type))) > && next_conversion (conv)->rank <= cr_promotion) > conv->rank = cr_promotion; > } > @@ -10506,6 +10516,31 @@ compare_ics (conversion *ics1, conversion *ics2) > } > } > > + /* [over.ics.rank] > + > + Per CWG 1601: > + -- A conversion that promotes an enumeration whose underlying type > + is fixed to its underlying type is better than one that promotes to > + the promoted underlying type, if the two are different. */ > + if (ics1->rank == cr_promotion > + && ics2->rank == cr_promotion > + && UNSCOPED_ENUM_P (from_type1) > + && ENUM_FIXED_UNDERLYING_TYPE_P (from_type1) > + && same_type_p (from_type1, from_type2)) > + { > + tree utype = ENUM_UNDERLYING_TYPE (from_type1); > + tree prom = type_promotes_to (from_type1); > + if (!same_type_p (utype, prom)) > + { > + if (same_type_p (to_type1, utype) > + && same_type_p (to_type2, prom)) > + return 1; > + else if (same_type_p (to_type2, utype) > + && same_type_p (to_type1, prom)) > + return -1; > + } > + } > + > /* Neither conversion sequence is better than the other. */ > return 0; > } > diff --git gcc/testsuite/g++.dg/cpp0x/scoped_enum10.C gcc/testsuite/g++.dg/cpp0x/scoped_enum10.C > new file mode 100644 > index 00000000000..b588581cd3e > --- /dev/null > +++ gcc/testsuite/g++.dg/cpp0x/scoped_enum10.C > @@ -0,0 +1,37 @@ > +// PR c++/92032 - DR 1601: Promotion of enumeration with fixed underlying type. > +// { dg-do compile { target c++11 } } > + > +enum E : char { e }; > +enum F : int { f }; > +enum G : long { g }; > +enum H : unsigned { h }; > + > +int f1(char); > +void f1(int); > + > +void f2(int); > +int f2(char); > + > +int f3(int); > +void f3(short); > + > +int f4(long); > +void f4(int); > + > +void f5(unsigned); > +int f5(int); > + > +int f6(unsigned); > +void f6(int); > + > +void > +test () > +{ > + int r = 0; > + r += f1 (e); > + r += f2 (e); > + r += f3 (f); > + r += f4 (g); > + r += f5 (f); > + r += f6 (h); > +} > diff --git gcc/testsuite/g++.dg/cpp0x/scoped_enum11.C gcc/testsuite/g++.dg/cpp0x/scoped_enum11.C > new file mode 100644 > index 00000000000..e6dcfbac9d8 > --- /dev/null > +++ gcc/testsuite/g++.dg/cpp0x/scoped_enum11.C > @@ -0,0 +1,35 @@ > +// PR c++/92032 - DR 1601: Promotion of enumeration with fixed underlying type. > +// { dg-do compile { target c++11 } } > + > +enum E1 : long { e1 }; > +enum E2 : short { e2 }; > + > +int f1(short); > +void f1(int); > + > +void f2(int); > +int f2(short); > + > +void f3(int); > +int f3(long); > + > +int f4(short); > +void f4(long); > + > +int f5(int); > +void f5(long); > + > +int f6(unsigned int); // { dg-message "candidate" } > +void f6(long); // { dg-message "candidate" } > + > +void > +fn () > +{ > + int r = 0; > + r += f1 (e2); > + r += f2 (e2); > + r += f3 (e1); > + r += f4 (e2); > + r += f5 (e2); > + r += f6 (e2); // { dg-error "ambiguous" } > +} >
diff --git gcc/cp/call.c gcc/cp/call.c index 6c9acac4614..10172855d4d 100644 --- gcc/cp/call.c +++ gcc/cp/call.c @@ -1484,8 +1484,18 @@ standard_conversion (tree to, tree from, tree expr, bool c_cast_p, conv = build_conv (ck_std, to, conv); - /* Give this a better rank if it's a promotion. */ - if (same_type_p (to, type_promotes_to (from)) + tree underlying_type = NULL_TREE; + if (TREE_CODE (from) == ENUMERAL_TYPE + && ENUM_FIXED_UNDERLYING_TYPE_P (from)) + underlying_type = ENUM_UNDERLYING_TYPE (from); + + /* Give this a better rank if it's a promotion. + + To handle CWG 1601, also bump the rank if we are converting + an enumeration with a fixed underlying type to the underlying + type. */ + if ((same_type_p (to, type_promotes_to (from)) + || (underlying_type && same_type_p (to, underlying_type))) && next_conversion (conv)->rank <= cr_promotion) conv->rank = cr_promotion; } @@ -10506,6 +10516,31 @@ compare_ics (conversion *ics1, conversion *ics2) } } + /* [over.ics.rank] + + Per CWG 1601: + -- A conversion that promotes an enumeration whose underlying type + is fixed to its underlying type is better than one that promotes to + the promoted underlying type, if the two are different. */ + if (ics1->rank == cr_promotion + && ics2->rank == cr_promotion + && UNSCOPED_ENUM_P (from_type1) + && ENUM_FIXED_UNDERLYING_TYPE_P (from_type1) + && same_type_p (from_type1, from_type2)) + { + tree utype = ENUM_UNDERLYING_TYPE (from_type1); + tree prom = type_promotes_to (from_type1); + if (!same_type_p (utype, prom)) + { + if (same_type_p (to_type1, utype) + && same_type_p (to_type2, prom)) + return 1; + else if (same_type_p (to_type2, utype) + && same_type_p (to_type1, prom)) + return -1; + } + } + /* Neither conversion sequence is better than the other. */ return 0; } diff --git gcc/testsuite/g++.dg/cpp0x/scoped_enum10.C gcc/testsuite/g++.dg/cpp0x/scoped_enum10.C new file mode 100644 index 00000000000..b588581cd3e --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/scoped_enum10.C @@ -0,0 +1,37 @@ +// PR c++/92032 - DR 1601: Promotion of enumeration with fixed underlying type. +// { dg-do compile { target c++11 } } + +enum E : char { e }; +enum F : int { f }; +enum G : long { g }; +enum H : unsigned { h }; + +int f1(char); +void f1(int); + +void f2(int); +int f2(char); + +int f3(int); +void f3(short); + +int f4(long); +void f4(int); + +void f5(unsigned); +int f5(int); + +int f6(unsigned); +void f6(int); + +void +test () +{ + int r = 0; + r += f1 (e); + r += f2 (e); + r += f3 (f); + r += f4 (g); + r += f5 (f); + r += f6 (h); +} diff --git gcc/testsuite/g++.dg/cpp0x/scoped_enum11.C gcc/testsuite/g++.dg/cpp0x/scoped_enum11.C new file mode 100644 index 00000000000..e6dcfbac9d8 --- /dev/null +++ gcc/testsuite/g++.dg/cpp0x/scoped_enum11.C @@ -0,0 +1,35 @@ +// PR c++/92032 - DR 1601: Promotion of enumeration with fixed underlying type. +// { dg-do compile { target c++11 } } + +enum E1 : long { e1 }; +enum E2 : short { e2 }; + +int f1(short); +void f1(int); + +void f2(int); +int f2(short); + +void f3(int); +int f3(long); + +int f4(short); +void f4(long); + +int f5(int); +void f5(long); + +int f6(unsigned int); // { dg-message "candidate" } +void f6(long); // { dg-message "candidate" } + +void +fn () +{ + int r = 0; + r += f1 (e2); + r += f2 (e2); + r += f3 (e1); + r += f4 (e2); + r += f5 (e2); + r += f6 (e2); // { dg-error "ambiguous" } +}