Mordante created this revision.
Mordante added a reviewer: rsmith.
Mordante added a project: clang.

The overload resolution for enums with a fixed underlaying type has changed in 
the C++14 standard. This patch implements the new rule.

      

Note: I don't have access to the CWG 1601 paper, but based on 
https://en.cppreference.com/w/cpp/language/overload_resolution I applied the 
fix retroactively to C++11.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D65695

Files:
  clang/lib/Sema/SemaOverload.cpp
  clang/test/CXX/drs/dr16xx.cpp
  clang/test/CXX/drs/dr6xx.cpp
  clang/www/cxx_dr_status.html

Index: clang/www/cxx_dr_status.html
===================================================================
--- clang/www/cxx_dr_status.html
+++ clang/www/cxx_dr_status.html
@@ -9421,7 +9421,7 @@
     <td><a href="http://wg21.link/cwg1601";>1601</a></td>
     <td>C++14</td>
     <td>Promotion of enumeration with fixed underlying type</td>
-    <td class="none" align="center">Unknown</td>
+    <td class="svn" align="center">SVN (C++11 onwards)</td>
   </tr>
   <tr class="open" id="1602">
     <td><a href="http://wg21.link/cwg1602";>1602</a></td>
Index: clang/test/CXX/drs/dr6xx.cpp
===================================================================
--- clang/test/CXX/drs/dr6xx.cpp
+++ clang/test/CXX/drs/dr6xx.cpp
@@ -1007,9 +1007,10 @@
   void j(long); // expected-note {{candidate}}
   int d = j(g); // expected-error {{ambiguous}}
 
-  int k(short); // expected-note {{candidate}}
-  void k(int); // expected-note {{candidate}}
-  int x = k(g); // expected-error {{ambiguous}}
+  // Valid per dr1601
+  int k(short);
+  void k(int);
+  int x = k(g);
 }
 #endif
 
Index: clang/test/CXX/drs/dr16xx.cpp
===================================================================
--- clang/test/CXX/drs/dr16xx.cpp
+++ clang/test/CXX/drs/dr16xx.cpp
@@ -23,6 +23,17 @@
 } // std
 #endif
 
+namespace dr1601 { // dr1601
+#if __cplusplus >= 201103L
+enum E : char { e };
+void f(char);
+void f(int);
+void g() {
+  f(e);
+}
+#endif
+} // namespace dr1601
+
 namespace dr1611 { // dr1611: dup 1658
   struct A { A(int); };
   struct B : virtual A { virtual void f() = 0; };
Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -3751,6 +3751,26 @@
           !SCS2.IsLvalueReference && SCS2.BindsToFunctionLvalue);
 }
 
+/// Returns the underlaying type of a fixed enum of the \a SCS's @c FromType
+/// if the \a SCS uses an integral promotion. Upon failure an empty type is
+/// returned.
+static QualType
+getFixedEnumUnderlayingType(const StandardConversionSequence &SCS) {
+
+  if (SCS.Second != ICK_Integral_Promotion)
+    return QualType();
+
+  QualType FromType = SCS.getFromType();
+  if (!FromType->isEnumeralType())
+    return QualType();
+
+  EnumDecl *Enum = FromType->getAs<EnumType>()->getDecl();
+  if (!Enum->isFixed())
+    return QualType();
+
+  return Enum->getIntegerType();
+}
+
 /// CompareStandardConversionSequences - Compare two standard
 /// conversion sequences to determine whether one is better than the
 /// other or if they are indistinguishable (C++ 13.3.3.2p3).
@@ -3792,6 +3812,23 @@
              ? ImplicitConversionSequence::Better
              : ImplicitConversionSequence::Worse;
 
+  // C++14 [over.ics.rank]p4b2:
+  // This is retroactively applied to C++11 by 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.
+  QualType UnderlayingType1 = getFixedEnumUnderlayingType(SCS1);
+  QualType UnderlayingType2 = getFixedEnumUnderlayingType(SCS2);
+  if (!UnderlayingType1.isNull() && !UnderlayingType2.isNull()) {
+    if (SCS1.getToType(1) == UnderlayingType1 &&
+        SCS2.getToType(1) != UnderlayingType2)
+      return ImplicitConversionSequence::Better;
+    else if (SCS1.getToType(1) != UnderlayingType1 &&
+             SCS2.getToType(1) == UnderlayingType2)
+      return ImplicitConversionSequence::Worse;
+  }
+
   // C++ [over.ics.rank]p4b2:
   //
   //   If class B is derived directly or indirectly from class A,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [PATCH] D65695: I... Mark de Wever via Phabricator via cfe-commits

Reply via email to