Index: clang/lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- clang/lib/Sema/SemaTemplateDeduction.cpp +++ clang/lib/Sema/SemaTemplateDeduction.cpp @@ -1201,6 +1201,159 @@ return false; } +// Attempt to deduce the template arguments by checking the base types according +// to (C++ [temp.deduct.call] p4b3. +/// +/// \param S the semantic analysis object within which we are deducing +/// +/// \param RecordT the top level record object we are deducing against. +/// +/// \param TemplateParams the template parameters that we are deducing +/// +/// \param SpecParam the template specialization parameter type. +/// +/// \param Info information about the template argument deduction itself +/// +/// \param Deduced the deduced template arguments +/// +/// \returns the result of template argument deduction with the bases. "invalid" +/// means no matches, "success" found a single item, and the +/// "MiscellaneousDeductionFailure" result happens when the match is ambiguous. +static Sema::TemplateDeductionResult DeduceTemplateBases( + Sema &S, const RecordType *RecordT, TemplateParameterList *TemplateParams, + const TemplateSpecializationType *SpecParam, TemplateDeductionInfo &Info, + SmallVectorImpl &Deduced) { + // C++14 [temp.deduct.call] p4b3: + // If P is a class and P has the form simple-template-id, then the + // 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. 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 + // type deduction fails. + + // A structure to represent the successful matches. + struct BaseMatch { + const RecordType *RT; + TemplateDeductionInfo BaseInfo; + SmallVector Deduction; + + BaseMatch(const RecordType *RT, const TemplateDeductionInfo &Info, + const llvm::SmallVectorImpl &Deduced) + : RT(RT), BaseInfo(TemplateDeductionInfo::ForBase, Info), + Deduction(Deduced.begin(), Deduced.end()) {} + BaseMatch(BaseMatch &&LHS) + : RT(LHS.RT), BaseInfo(TemplateDeductionInfo::ForBase, LHS.BaseInfo), + Deduction(std::move(LHS.Deduction)) { + BaseInfo.Param = std::move(LHS.BaseInfo.Param); + BaseInfo.FirstArg = std::move(LHS.BaseInfo.FirstArg); + BaseInfo.SecondArg = std::move(LHS.BaseInfo.SecondArg); + } + + BaseMatch &operator=(BaseMatch &&LHS) { + RT = LHS.RT; + BaseInfo.Param = std::move(LHS.BaseInfo.Param); + BaseInfo.FirstArg = std::move(LHS.BaseInfo.FirstArg); + BaseInfo.SecondArg = std::move(LHS.BaseInfo.SecondArg); + Deduction = std::move(LHS.Deduction); + return *this; + } + }; + // Use a breadth-first search through the bases to collect the set of + // successful matches. Visited contains the set of nodes we have already + // visited, while ToVisit is our stack of records that we still need to + // visit. Matches contains a list of matches that have yet to be + // disqualified. + llvm::SmallPtrSet Visited; + SmallVector ToVisit; + SmallVector Matches; + + auto AddBases = [&ToVisit](const RecordType *RT) { + CXXRecordDecl *RD = cast(RT->getDecl()); + for (const auto &Base : RD->bases()) { + assert(Base.getType()->isRecordType() && + "Base class that isn't a record?"); + ToVisit.push_back(Base.getType()->getAs()); + } + }; + + // Set up the loop by adding all the bases. + AddBases(RecordT); + + // Search each path of bases until we either run into a successful match + // (where all bases of IT are invalid), or we run out of bases. + while (!ToVisit.empty()) { + const RecordType *NextT = ToVisit.pop_back_val(); + // If we have already seen this type, skip it. + if (!Visited.insert(NextT).second) + continue; + + BaseMatch &CurMatch = Matches.emplace_back(NextT, Info, Deduced); + Sema::TemplateDeductionResult BaseResult = DeduceTemplateArguments( + S, TemplateParams, SpecParam, QualType(NextT, 0), CurMatch.BaseInfo, + CurMatch.Deduction); + + // If the match was not a successful deduction, we have to search its bases. + if (BaseResult != Sema::TDK_Success) { + AddBases(NextT); + Matches.pop_back(); + } + } + + // At this point, 'Matches' contains a list of seemingly valid bases, however + // in the event that we have more than 1 match, it is possible that the base + // of one of the matches might be disqualified for being a base of another + // valid match. We can count on cyclical instantiations being invalid to + // simplify the disqualifications. That is, if A & B are both matches, and B + // inherits from A (disqualifying A), we know that A cannot inherit from B. + if (Matches.size() > 1) { + for (const BaseMatch &Match : Matches) + AddBases(Match.RT); + + Visited.clear(); + + // We can give up once we have a single item (or have run out of things to + // search) since cyclical inheritence isn't valid. + while (Matches.size() > 1 && !ToVisit.empty()) { + const RecordType *NextT = ToVisit.pop_back_val(); + // If we have already seen this type, skip it. + if (!Visited.insert(NextT).second) + continue; + + BaseMatch CurMatch(NextT, Info, Deduced); + Sema::TemplateDeductionResult BaseResult = DeduceTemplateArguments( + S, TemplateParams, SpecParam, QualType(NextT, 0), CurMatch.BaseInfo, + CurMatch.Deduction); + + // If this iS a match, it isn't valid due to CWG2303. So, remove it + // from the possible matches. + if (BaseResult == Sema::TDK_Success) + llvm::erase_if(Matches, + [NextT](const BaseMatch &M) { return M.RT == NextT; }); + + // Always add all bases, since the inheritence tree can contain + // disqualifications for multiple matches. + AddBases(NextT); + } + } + + if (Matches.empty()) + return Sema::TDK_Invalid; + if (Matches.size() > 1) + return Sema::TDK_MiscellaneousDeductionFailure; + + std::swap(Matches[0].Deduction, Deduced); + Info.Param = Matches[0].BaseInfo.Param; + Info.FirstArg = Matches[0].BaseInfo.FirstArg; + Info.SecondArg = Matches[0].BaseInfo.SecondArg; + return Sema::TDK_Success; +} + /// Deduce the template arguments by comparing the parameter type and /// the argument type (C++ [temp.deduct.type]). /// @@ -1787,78 +1940,15 @@ if (!S.isCompleteType(Info.getLocation(), Arg)) return Result; - // C++14 [temp.deduct.call] p4b3: - // If P is a class and P has the form simple-template-id, then the - // 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. - // - // These alternatives are considered only if type deduction would - // otherwise fail. If they yield more than one possible deduced A, the - // type deduction fails. - // Reset the incorrectly deduced argument from above. Deduced = DeducedOrig; - // Use data recursion to crawl through the list of base classes. - // Visited contains the set of nodes we have already visited, while - // ToVisit is our stack of records that we still need to visit. - llvm::SmallPtrSet Visited; - SmallVector ToVisit; - ToVisit.push_back(RecordT); - bool Successful = false; - SmallVector SuccessfulDeduced; - while (!ToVisit.empty()) { - // Retrieve the next class in the inheritance hierarchy. - const RecordType *NextT = ToVisit.pop_back_val(); - - // If we have already seen this type, skip it. - if (!Visited.insert(NextT).second) - continue; - - // If this is a base class, try to perform template argument - // deduction from it. - if (NextT != RecordT) { - TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info); - Sema::TemplateDeductionResult BaseResult = - DeduceTemplateArguments(S, TemplateParams, SpecParam, - QualType(NextT, 0), BaseInfo, Deduced); - - // If template argument deduction for this base was successful, - // note that we had some success. Otherwise, ignore any deductions - // from this base class. - if (BaseResult == Sema::TDK_Success) { - // If we've already seen some success, then deduction fails due to - // an ambiguity (temp.deduct.call p5). - if (Successful) - return Sema::TDK_MiscellaneousDeductionFailure; - - Successful = true; - std::swap(SuccessfulDeduced, Deduced); - - Info.Param = BaseInfo.Param; - Info.FirstArg = BaseInfo.FirstArg; - Info.SecondArg = BaseInfo.SecondArg; - } - - 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 (Successful) { - std::swap(SuccessfulDeduced, Deduced); - return Sema::TDK_Success; - } + // Check bases according to C++14 [temp.deduct.call] p4b3: + Sema::TemplateDeductionResult BaseResult = DeduceTemplateBases( + S, RecordT, TemplateParams, SpecParam, Info, Deduced); + if (BaseResult != Sema::TDK_Invalid) + return BaseResult; return Result; } Index: clang/test/CXX/drs/dr23xx.cpp =================================================================== --- clang/test/CXX/drs/dr23xx.cpp +++ clang/test/CXX/drs/dr23xx.cpp @@ -113,3 +113,35 @@ extern template const int d; #endif } + +#if __cplusplus >= 201103L +namespace dr2303 { // dr2303: 12 +template +struct A; +template <> +struct A<> {}; +template +struct A : A {}; +struct B : A {}; +struct C : A, A {}; // expected-warning {{direct base 'A' is inaccessible}} +struct D : A, A {}; // expected-warning {{direct base 'A' is inaccessible}} +struct E : A {}; +struct F : B, E {}; + +template +void f(const A &) { + static_assert(sizeof...(T) == 2, "Should only match A"); +} +template +void f2(const A *); + +void g() { + f(B{}); // This is no longer ambiguous. + B b; + f2(&b); + f(C{}); + f(D{}); + f(F{}); // expected-error {{ambiguous conversion from derived class}} +} +} //namespace dr2303 +#endif Index: clang/www/cxx_dr_status.html =================================================================== --- clang/www/cxx_dr_status.html +++ clang/www/cxx_dr_status.html @@ -1504,7 +1504,7 @@ 244 CD1 Destructor lookup - Clang 11 + Clang 11 245 @@ -2789,7 +2789,7 @@ 458 C++11 Hiding of member template parameters by other members - Clang 11 + Clang 11 459 @@ -3967,7 +3967,7 @@ 654 CD1 Conversions to and from nullptr_t - Superseded by 1423 + Superseded by 1423 655 @@ -8353,7 +8353,7 @@ 1423 CD3 Convertibility of nullptr to bool - Clang 11 + Clang 11 1424 @@ -8899,7 +8899,7 @@ 1514 C++14 Ambiguity between enumeration definition and zero-length bit-field - Clang 11 + Clang 11 1515 @@ -10333,7 +10333,7 @@ 1753 CD4 decltype-specifier in nested-name-specifier of destructor - Clang 11 + Clang 11 1754 @@ -11611,7 +11611,7 @@ 1966 CD4 Colon following enumeration elaborated-type-specifier - Clang 11 + Clang 11 1967 @@ -11971,7 +11971,7 @@ 2026 CD4 Zero-initialization and constexpr - Clang 11 + Clang 11 2027 @@ -12307,7 +12307,7 @@ 2082 CD4 Referring to parameters in unevaluated operands of default arguments - Clang 11 + Clang 11 2083 @@ -12757,7 +12757,7 @@ 2157 CD4 Further disambiguation of enumeration elaborated-type-specifier - Clang 11 + Clang 11 2158 @@ -13213,7 +13213,7 @@ 2233 DRWP Function parameter packs following default arguments - Clang 11 + Clang 11 2234 @@ -13633,7 +13633,7 @@ 2303 DRWP Partial ordering and recursive variadic inheritance - Unknown + Clang 12 2304 @@ -13891,7 +13891,7 @@ 2346 DRWP Local variables in default arguments - Clang 11 + Clang 11 2347 @@ -14499,6 +14499,24 @@ Unintended description of abbreviated function templates Unknown + + 2448 + open + Cv-qualification of arithmetic types and deprecation of volatile + Not resolved + + + 2449 + open + Thunks as an implementation technique for pointers to virtual functions + Not resolved + + + 2450 + open + braced-init-list as a template-argument + Not resolved + Index: clang/www/make_cxx_dr_status =================================================================== --- clang/www/make_cxx_dr_status +++ clang/www/make_cxx_dr_status @@ -1,4 +1,5 @@ #! /usr/bin/env python + import sys, os, re index = 'cwg_index.html' @@ -93,7 +94,7 @@ Available in Clang? ''' -latest_release = 10 +latest_release = 11 def availability(issue): status = status_map.get(issue, 'unknown')