aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarek Polacek <polacek@redhat.com>2019-10-09 17:49:26 +0000
committerMarek Polacek <mpolacek@gcc.gnu.org>2019-10-09 17:49:26 +0000
commite295e3d981355c61b72eca2ee58864958655cc31 (patch)
treed1b8598399fa993a898daaad3a2f9c7df5232162
parentcb57504a550158913258e5be8ddb991376475efb (diff)
downloadgcc-e295e3d981355c61b72eca2ee58864958655cc31.zip
gcc-e295e3d981355c61b72eca2ee58864958655cc31.tar.gz
gcc-e295e3d981355c61b72eca2ee58864958655cc31.tar.bz2
PR c++/92032 - DR 1601: Promotion of enum with fixed underlying type.
I've been messing with compare_ics recently and noticed that we don't implement CWG 1601, which should be fairly easy. Thus this patch. 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. * 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. From-SVN: r276766
-rw-r--r--gcc/cp/ChangeLog8
-rw-r--r--gcc/cp/call.c39
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/scoped_enum10.C37
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/scoped_enum11.C35
5 files changed, 123 insertions, 2 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index e633823..4eb18294 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,11 @@
+2019-10-09 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.
+
2019-10-08 Andrew Sutton <asutton@lock3software.com>
Jason Merrill <jason@redhat.com>
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index d36564d..33ec6a2 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -1472,8 +1472,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;
}
@@ -10473,6 +10483,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 a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 9318655..f1e3a99 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2019-10-09 Marek Polacek <polacek@redhat.com>
+
+ PR c++/92032 - DR 1601: Promotion of enum with fixed underlying type.
+ * g++.dg/cpp0x/scoped_enum10.C: New test.
+ * g++.dg/cpp0x/scoped_enum11.C: New test.
+
2019-10-08 Andrew Sutton <asutton@lock3software.com>
* lib/target-supports.exp (check_effective_target_concepts): Check
diff --git a/gcc/testsuite/g++.dg/cpp0x/scoped_enum10.C b/gcc/testsuite/g++.dg/cpp0x/scoped_enum10.C
new file mode 100644
index 0000000..054b908
--- /dev/null
+++ b/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 a/gcc/testsuite/g++.dg/cpp0x/scoped_enum11.C b/gcc/testsuite/g++.dg/cpp0x/scoped_enum11.C
new file mode 100644
index 0000000..e6dcfba
--- /dev/null
+++ b/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" }
+}