Index: clang/lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- clang/lib/Sema/SemaTemplateDeduction.cpp +++ clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1792,7 +1792,10 @@ // transformed A can be a derived class of the deduced A. Likewise if // P is a pointer to a class of the form simple-template-id, the // transformed A can be a pointer to a derived class pointed to by the - // deduced A. + // deduced A. However, if there is a class C that is a (direct or + // indirect) base class of D and derived (directly or indirectly) from a + // class B and that would be a valid deduced A, the deduced A cannot be + // B or pointer to B, respectively. // // These alternatives are considered only if type deduction would // otherwise fail. If they yield more than one possible deduced A, the @@ -1812,6 +1815,7 @@ while (!ToVisit.empty()) { // Retrieve the next class in the inheritance hierarchy. const RecordType *NextT = ToVisit.pop_back_val(); + bool SkipBases = false; // If we have already seen this type, skip it. if (!Visited.insert(NextT).second) @@ -1840,21 +1844,33 @@ Info.Param = BaseInfo.Param; Info.FirstArg = BaseInfo.FirstArg; Info.SecondArg = BaseInfo.SecondArg; + + // In order to implement CWG2303 (added the following to p4b3): + // However, if there is a class C that is a (direct or indirect) + // base class of D and derived (directly or indirectly) from a + // class B and that would be a valid deduced A, the deduced A + // cannot be B or pointer to B, respectively. + // We shouldn't visit the bases of a successful match ('C'), as they + // could only be 'B' here. + SkipBases = true; } Deduced = DeducedOrig; } // Visit base classes - CXXRecordDecl *Next = cast(NextT->getDecl()); - for (const auto &Base : Next->bases()) { - assert(Base.getType()->isRecordType() && - "Base class that isn't a record?"); - ToVisit.push_back(Base.getType()->getAs()); + if (!SkipBases) { + CXXRecordDecl *Next = cast(NextT->getDecl()); + for (const auto &Base : Next->bases()) { + assert(Base.getType()->isRecordType() && + "Base class that isn't a record?"); + ToVisit.push_back(Base.getType()->getAs()); + } } } if (Successful) { + // TODO std::swap(SuccessfulDeduced, Deduced); return Sema::TDK_Success; } Index: clang/test/CXX/drs/dr23xx.cpp =================================================================== --- clang/test/CXX/drs/dr23xx.cpp +++ clang/test/CXX/drs/dr23xx.cpp @@ -113,3 +113,26 @@ extern template const int d; #endif } + +#if __cplusplus >= 201103L +namespace dr2303 { +template +struct A; +template <> +struct A<> {}; +template +struct A : A {}; +struct B : A {}; + +template +void f(const A &); +template +void f2(const A *); + +void g() { + f(B{}); // This is no longer ambiguous. + B b; + f2(&b); +} +} //namespace dr2303 +#endif