Index: lib/Sema/SemaOverload.cpp =================================================================== --- lib/Sema/SemaOverload.cpp +++ lib/Sema/SemaOverload.cpp @@ -3677,6 +3677,24 @@ !SCS2.IsLvalueReference && SCS2.BindsToFunctionLvalue); } +/// \brief Returns whether given standard conversion sequence is converting an +/// unscoped enumeration, whose underlying type is fixed, to its underlying +/// type. +static bool +isEnumConversionToUnderlyingType(const ASTContext &Context, + const StandardConversionSequence &SCS) { + QualType FromType = SCS.getFromType(); + + const EnumType *FromEnumType = FromType->getAs(); + if (!FromEnumType || FromEnumType->getDecl()->isScoped() || + !FromEnumType->getDecl()->isFixed()) + return false; + + QualType ToType = SCS.getToType(1); + QualType Underlying = FromEnumType->getDecl()->getIntegerType(); + return Context.hasSameUnqualifiedType(Underlying, ToType); +} + /// 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). @@ -3847,6 +3865,19 @@ S.Context.getTypeSize(SCS1.getToType(2))) return ImplicitConversionSequence::Better; + // Per DR1601, which is included in C++14; 13.3.3.2p4b2 + // -- 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 (S.getLangOpts().CPlusPlus11 && + (SCS1.getToType(1).getTypePtr() != SCS2.getToType(1).getTypePtr())) { + bool S1ConvResult = isEnumConversionToUnderlyingType(S.Context, SCS1); + bool S2ConvResult = isEnumConversionToUnderlyingType(S.Context, SCS2); + if (S1ConvResult && !S2ConvResult) + return ImplicitConversionSequence::Better; + else if (!S1ConvResult && S2ConvResult) + return ImplicitConversionSequence::Worse; + } return ImplicitConversionSequence::Indistinguishable; } Index: test/CXX/drs/dr16xx.cpp =================================================================== --- test/CXX/drs/dr16xx.cpp +++ test/CXX/drs/dr16xx.cpp @@ -3,6 +3,25 @@ // RUN: %clang_cc1 -std=c++14 -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors // RUN: %clang_cc1 -std=c++1z -triple x86_64-unknown-unknown %s -verify -fexceptions -fcxx-exceptions -pedantic-errors +namespace dr1601 { +#if __cplusplus >= 201103L + enum B : bool { b }; + enum C : char { c }; + enum E { e }; + + int &func(bool); // expected-note{{candidate function}} + double &func(char); // expected-note{{candidate function}} + void func(unsigned); // expected-note{{candidate function}} + void func(long); // expected-note{{candidate function}} + + void g() { + int &r = func(b); + double &d = func(c); + func(e); // expected-error {{call to 'func' is ambiguous}} + } +#endif +} + namespace dr1611 { // dr1611: dup 1658 struct A { A(int); }; struct B : virtual A { virtual void f() = 0; };