erik.pilkington created this revision. erik.pilkington added a reviewer: rsmith. erik.pilkington added a subscriber: cfe-commits.
Previously, clang would incorrectly reject the following: ``` struct S {}; template<class T, int i> struct D : T {}; template<class T> void Foo(D<T, 1>); int fn() { D<D<S, 1>, 0> v; Foo(v); } ``` The problem is that clang initially tries to apply D<S, 1> for T in Foo, storing the result (in Deduced). Then clang tries to match 0 for 1 in Foo, would fail, and begin to consider the base classes of v (per temp.deduct.call p4.3), without resetting the original faulty assumption. This patch simply saves the deduced arguments before attempting the faulty deduction, then restores them once the faulty deduction fails. Note: This section of code still has a somewhat related latent bug where ambiguous base class deductions are left undiagnosed, for example: ``` int fn2() { D<D<D<S, 1>, 1>, 0> v; Foo(v); // error, is T deduced to be S or D<S, 1>? } ``` Which is outlawed by temp.deduct.call p5. I have another patch that fixes this, which I'll submit once(/if) this goes through. 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 @@ -1421,21 +1421,29 @@ const TemplateSpecializationType *SpecParam = cast<TemplateSpecializationType>(Param); + SmallVector<DeducedTemplateArgument, 8> DeducedOrig(Deduced.begin(), + Deduced.end()); + // 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. + // 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. // - // More importantly: // These alternatives are considered only if type deduction would - // otherwise fail. + // otherwise fail. If they yield more than one possible deduced A, the + // type deduction fails. + + // Reset the incorrectly deduced argument from above. + Deduced = DeducedOrig; + 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 @@ -1450,8 +1458,6 @@ 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();
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 @@ -1421,21 +1421,29 @@ const TemplateSpecializationType *SpecParam = cast<TemplateSpecializationType>(Param); + SmallVector<DeducedTemplateArgument, 8> DeducedOrig(Deduced.begin(), + Deduced.end()); + // 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. + // 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. // - // More importantly: // These alternatives are considered only if type deduction would - // otherwise fail. + // otherwise fail. If they yield more than one possible deduced A, the + // type deduction fails. + + // Reset the incorrectly deduced argument from above. + Deduced = DeducedOrig; + 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 @@ -1450,8 +1458,6 @@ 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();
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits