erik.pilkington updated this revision to Diff 53164. erik.pilkington marked an inline comment as done. erik.pilkington added a comment.
Avoid another copy when Arg is not a record type. Richard: I don't think it's possible to avoid copying Deduced when Arg is not a complete type, because we only try to complete it when we know that the deduction would otherwise fail (therefore clobbering Deduced). If this looks good, would you mind committing it? Thanks for reviewing! http://reviews.llvm.org/D18868 Files: lib/Sema/SemaTemplateDeduction.cpp test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp
Index: test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp =================================================================== --- test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp +++ test/CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.call/p3.cpp @@ -146,3 +146,17 @@ } } + +namespace PR27155 { + +struct B {}; + +template<class T, int i> struct D : T {}; +template<class T> void Foo(D<T, 1>); + +int fn() { + D<D<B, 1>, 0> f; + Foo(f); +} + +} Index: lib/Sema/SemaTemplateDeduction.cpp =================================================================== --- lib/Sema/SemaTemplateDeduction.cpp +++ lib/Sema/SemaTemplateDeduction.cpp @@ -1418,87 +1418,94 @@ // TT<i> // TT<> case Type::TemplateSpecialization: { - const TemplateSpecializationType *SpecParam - = cast<TemplateSpecializationType>(Param); - - // Try to deduce template arguments from the template-id. - Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg, - Info, Deduced); - - if (Result && (TDF & TDF_DerivedClass)) { - // C++ [temp.deduct.call]p3b3: - // If P is a class, and P has the form template-id, then A can be a - // derived class of the deduced A. Likewise, if P is a pointer to a - // class of the form template-id, A can be a pointer to a derived - // class pointed to by the deduced A. - // - // More importantly: - // These alternatives are considered only if type deduction would - // otherwise fail. - if (const RecordType *RecordT = Arg->getAs<RecordType>()) { - // We cannot inspect base classes as part of deduction when the type - // is incomplete, so either instantiate any templates necessary to - // complete the type, or skip over it if it cannot be completed. - if (!S.isCompleteType(Info.getLocation(), Arg)) - return Result; - - // 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; - SmallVector<DeducedTemplateArgument, 8> DeducedOrig(Deduced.begin(), - Deduced.end()); - 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; - } - - // 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>()); - } - } + const TemplateSpecializationType *SpecParam = + cast<TemplateSpecializationType>(Param); + + // When Arg cannot be a derived class, we can just try to deduce template + // arguments from the template-id. + const RecordType *RecordT = Arg->getAs<RecordType>(); + if (!(TDF & TDF_DerivedClass) || !RecordT) + return DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg, Info, + Deduced); + + SmallVector<DeducedTemplateArgument, 8> DeducedOrig(Deduced.begin(), + Deduced.end()); + + Sema::TemplateDeductionResult Result = DeduceTemplateArguments( + S, TemplateParams, SpecParam, Arg, Info, Deduced); + + if (Result == Sema::TDK_Success) + return Result; + + // We cannot inspect base classes as part of deduction when the type + // is incomplete, so either instantiate any templates necessary to + // complete the type, or skip over it if it cannot be completed. + 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<const RecordType *, 8> Visited; + SmallVector<const RecordType *, 8> ToVisit; + ToVisit.push_back(RecordT); + bool Successful = false; + 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 (Successful) - return Sema::TDK_Success; + // 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; } + // 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; + return Result; }
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits