Author: faisalv Date: Wed May 18 21:28:21 2016 New Revision: 270016 URL: http://llvm.org/viewvc/llvm-project?rev=270016&view=rev Log: Fix PR27601 by reverting [r267453] - Refactor traversal of bases in deduction of template parameters from base
This reversal is being done with r267453's author's (i.e. Richard Smith's) permission. This fixes https://llvm.org/bugs/show_bug.cgi?id=27601 Also, per Richard's request the examples from the bug report have been added to our test suite. Modified: cfe/trunk/lib/AST/CXXInheritance.cpp cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp cfe/trunk/test/SemaTemplate/deduction.cpp Modified: cfe/trunk/lib/AST/CXXInheritance.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CXXInheritance.cpp?rev=270016&r1=270015&r2=270016&view=diff ============================================================================== --- cfe/trunk/lib/AST/CXXInheritance.cpp (original) +++ cfe/trunk/lib/AST/CXXInheritance.cpp Wed May 18 21:28:21 2016 @@ -137,7 +137,6 @@ CXXRecordDecl::isCurrentInstantiation(co bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches, bool AllowShortCircuit) const { SmallVector<const CXXRecordDecl*, 8> Queue; - llvm::SmallPtrSet<const CXXRecordDecl*, 8> Enqueued; const CXXRecordDecl *Record = this; bool AllMatches = true; @@ -159,14 +158,12 @@ bool CXXRecordDecl::forallBases(ForallBa AllMatches = false; continue; } - - if (Enqueued.insert(Base).second) { - Queue.push_back(Base); - if (!BaseMatches(Base)) { - if (AllowShortCircuit) return false; - AllMatches = false; - continue; - } + + Queue.push_back(Base); + if (!BaseMatches(Base)) { + if (AllowShortCircuit) return false; + AllMatches = false; + continue; } } Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=270016&r1=270015&r2=270016&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original) +++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed May 18 21:28:21 2016 @@ -1454,35 +1454,54 @@ DeduceTemplateArgumentsByTypeMatch(Sema // 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<const RecordType *, 8> Visited; + SmallVector<const RecordType *, 8> ToVisit; + ToVisit.push_back(RecordT); bool Successful = false; - RecordT->getAsCXXRecordDecl()->forallBases([&]( - const CXXRecordDecl *Base) { - // Start with a fresh copy of the old deduced arguments. - SmallVector<DeducedTemplateArgument, 8> DeducedBase(DeducedOrig.begin(), - DeducedOrig.end()); - - TemplateDeductionInfo BaseInfo(Info.getLocation()); - Sema::TemplateDeductionResult BaseResult = - DeduceTemplateArguments(S, TemplateParams, SpecParam, - S.Context.getRecordType(Base), - BaseInfo, DeducedBase); - - // 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) { - // FIXME: If we've already been successful, deduction should fail - // due to ambiguity. - Successful = true; - Deduced.swap(DeducedBase); - Info.Param = BaseInfo.Param; - Info.FirstArg = BaseInfo.FirstArg; - Info.SecondArg = BaseInfo.SecondArg; + 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(Info.getLocation()); + 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) { + Successful = true; + DeducedOrig.clear(); + DeducedOrig.append(Deduced.begin(), Deduced.end()); + Info.Param = BaseInfo.Param; + Info.FirstArg = BaseInfo.FirstArg; + Info.SecondArg = BaseInfo.SecondArg; + } else + Deduced = DeducedOrig; } - // Keep going. - return true; - }); + // Visit base classes + CXXRecordDecl *Next = cast<CXXRecordDecl>(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<RecordType>()); + } + } if (Successful) return Sema::TDK_Success; Modified: cfe/trunk/test/SemaTemplate/deduction.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/deduction.cpp?rev=270016&r1=270015&r2=270016&view=diff ============================================================================== --- cfe/trunk/test/SemaTemplate/deduction.cpp (original) +++ cfe/trunk/test/SemaTemplate/deduction.cpp Wed May 18 21:28:21 2016 @@ -218,3 +218,50 @@ namespace NonDeducedNestedNameSpecifier template<typename T> int f(A<T>, typename A<T>::template B<T>); int k = f(A<int>(), 0); } + +namespace PR27601_RecursivelyInheritedBaseSpecializationsDeductionAmbiguity { +namespace ns1 { + +template<class...> struct B { }; +template<class H, class ... Ts> struct B<H, Ts...> : B<> { }; +template<class ... Ts> struct D : B<Ts...> { }; + +template<class T, class ... Ts> void f(B<T, Ts...> &) { } + +int main() { + D<int, char> d; + f<int>(d); +} +} //end ns1 + +namespace ns2 { + +template <int i, typename... Es> struct tup_impl; + +template <int i> struct tup_impl<i> {}; // empty tail + +template <int i, typename Head, typename... Tail> +struct tup_impl<i, Head, Tail...> : tup_impl<i + 1, Tail...> { + using value_type = Head; + Head head; +}; + +template <typename... Es> struct tup : tup_impl<0, Es...> {}; + +template <typename Head, int i, typename... Tail> +Head &get_helper(tup_impl<i, Head, Tail...> &t) { + return t.head; +} + +template <typename Head, int i, typename... Tail> +Head const &get_helper(tup_impl<i, Head, Tail...> const &t) { + return t.head; +} + +int main() { + tup<int, double, char> t; + get_helper<double>(t); + return 0; +} +} // end ns2 +} \ No newline at end of file _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits