[PATCH] D18868: [Sema] PR27155: Fix a template argument deduction bug with base classes

Erik Pilkington via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 7 14:22:17 PDT 2016


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();


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D18868.52948.patch
Type: text/x-patch
Size: 3016 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20160407/fc6394d1/attachment.bin>


More information about the cfe-commits mailing list