Refactor traversal of bases in deduction of template parameters from base

classes of an argument to use CXXRecordDecl::forallBases. Fix forallBases to
only visit each base class once.

llvm-svn: 267453
This commit is contained in:
Richard Smith 2016-04-25 19:28:08 +00:00
parent 99c14524ec
commit 2eba90e0db
2 changed files with 33 additions and 49 deletions

View File

@ -137,6 +137,7 @@ CXXRecordDecl::isCurrentInstantiation(const DeclContext *CurContext) const {
bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches, bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches,
bool AllowShortCircuit) const { bool AllowShortCircuit) const {
SmallVector<const CXXRecordDecl*, 8> Queue; SmallVector<const CXXRecordDecl*, 8> Queue;
llvm::SmallPtrSet<const CXXRecordDecl*, 8> Enqueued;
const CXXRecordDecl *Record = this; const CXXRecordDecl *Record = this;
bool AllMatches = true; bool AllMatches = true;
@ -158,12 +159,14 @@ bool CXXRecordDecl::forallBases(ForallBasesCallback BaseMatches,
AllMatches = false; AllMatches = false;
continue; continue;
} }
Queue.push_back(Base); if (Enqueued.insert(Base).second) {
if (!BaseMatches(Base)) { Queue.push_back(Base);
if (AllowShortCircuit) return false; if (!BaseMatches(Base)) {
AllMatches = false; if (AllowShortCircuit) return false;
continue; AllMatches = false;
continue;
}
} }
} }

View File

@ -1454,54 +1454,35 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// otherwise fail. If they yield more than one possible deduced A, the // otherwise fail. If they yield more than one possible deduced A, the
// type deduction fails. // 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; bool Successful = false;
while (!ToVisit.empty()) { RecordT->getAsCXXRecordDecl()->forallBases([&](
// Retrieve the next class in the inheritance hierarchy. const CXXRecordDecl *Base) {
const RecordType *NextT = ToVisit.pop_back_val(); // Start with a fresh copy of the old deduced arguments.
SmallVector<DeducedTemplateArgument, 8> DeducedBase(DeducedOrig.begin(),
DeducedOrig.end());
// If we have already seen this type, skip it. TemplateDeductionInfo BaseInfo(Info.getLocation());
if (!Visited.insert(NextT).second) Sema::TemplateDeductionResult BaseResult =
continue; DeduceTemplateArguments(S, TemplateParams, SpecParam,
S.Context.getRecordType(Base),
BaseInfo, DeducedBase);
// If this is a base class, try to perform template argument // If template argument deduction for this base was successful,
// deduction from it. // note that we had some success. Otherwise, ignore any deductions
if (NextT != RecordT) { // from this base class.
TemplateDeductionInfo BaseInfo(Info.getLocation()); if (BaseResult == Sema::TDK_Success) {
Sema::TemplateDeductionResult BaseResult = // FIXME: If we've already been successful, deduction should fail
DeduceTemplateArguments(S, TemplateParams, SpecParam, // due to ambiguity.
QualType(NextT, 0), BaseInfo, Deduced); Successful = true;
Deduced.swap(DeducedBase);
// If template argument deduction for this base was successful, Info.Param = BaseInfo.Param;
// note that we had some success. Otherwise, ignore any deductions Info.FirstArg = BaseInfo.FirstArg;
// from this base class. Info.SecondArg = BaseInfo.SecondArg;
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;
} }
// Visit base classes // Keep going.
CXXRecordDecl *Next = cast<CXXRecordDecl>(NextT->getDecl()); return true;
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) if (Successful)
return Sema::TDK_Success; return Sema::TDK_Success;