r270016 - Fix PR27601 by reverting [r267453] - Refactor traversal of bases in deduction of template parameters from base
Faisal Vali via cfe-commits
cfe-commits at lists.llvm.org
Wed May 18 19:28:21 PDT 2016
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
More information about the cfe-commits
mailing list