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
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits