r259688 - Ensure that we substitute into the declaration of a template parameter pack

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Wed Feb 3 12:40:31 PST 2016


Author: rsmith
Date: Wed Feb  3 14:40:30 2016
New Revision: 259688

URL: http://llvm.org/viewvc/llvm-project?rev=259688&view=rev
Log:
Ensure that we substitute into the declaration of a template parameter pack
(that is not a pack expansion) during template argument deduction, even if we
deduced that the pack would be empty.

Added:
    cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp
Modified:
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=259688&r1=259687&r2=259688&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Wed Feb  3 14:40:30 2016
@@ -2119,8 +2119,25 @@ ConvertDeducedTemplateArgument(Sema &S,
       PackedArgsBuilder.push_back(Output.pop_back_val());
     }
 
-    // FIXME: If the pack is empty and this is a template template parameter,
-    // we still need to substitute into the parameter itself.
+    // If the pack is empty, we still need to substitute into the parameter
+    // itself, in case that substitution fails. For non-type parameters, we did
+    // this above. For type parameters, no substitution is ever required.
+    auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param);
+    if (TTP && PackedArgsBuilder.empty()) {
+      // Set up a template instantiation context.
+      LocalInstantiationScope Scope(S);
+      Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template,
+                                       TTP, Output,
+                                       Template->getSourceRange());
+      if (Inst.isInvalid())
+        return true;
+
+      TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
+                                        Output.data(), Output.size());
+      if (!S.SubstDecl(TTP, S.CurContext,
+                       MultiLevelTemplateArgumentList(TemplateArgs)))
+        return true;
+    }
 
     // Create the resulting argument pack.
     Output.push_back(
@@ -2808,11 +2825,22 @@ Sema::FinishTemplateArgumentDeduction(Fu
         Builder.push_back(TemplateArgument(
             llvm::makeArrayRef(ExplicitArgs, NumExplicitArgs)));
 
-        // Forget the partially-substituted pack; it's substitution is now
+        // Forget the partially-substituted pack; its substitution is now
         // complete.
         CurrentInstantiationScope->ResetPartiallySubstitutedPack();
       } else {
-        Builder.push_back(TemplateArgument::getEmptyPack());
+        // Go through the motions of checking the empty argument pack against
+        // the parameter pack.
+        DeducedTemplateArgument DeducedPack(TemplateArgument::getEmptyPack());
+        if (ConvertDeducedTemplateArgument(*this, Param, DeducedPack,
+                                           FunctionTemplate, Info, true,
+                                           Builder)) {
+          Info.Param = makeTemplateParameter(Param);
+          // FIXME: These template arguments are temporary. Free them!
+          Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(),
+                                                      Builder.size()));
+          return TDK_SubstitutionFailure;
+        }
       }
       continue;
     }

Added: cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp?rev=259688&view=auto
==============================================================================
--- cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp (added)
+++ cfe/trunk/test/CXX/temp/temp.fct.spec/temp.deduct/p7.cpp Wed Feb  3 14:40:30 2016
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -std=c++11 -verify %s
+
+struct Q { typedef int type; };
+
+// "The substitution occurs in all types and expressions that are used in [...]
+// template parameter declarations." In particular, we must substitute into the
+// type of a parameter pack that is not a pack expansion, even if we know the
+// corresponding argument pack is empty.
+template<typename T, typename T::type...> void a(T);
+int &a(...);
+int &a_disabled = a(0);
+int &a_enabled = a(Q()); // expected-error {{cannot bind to a temporary of type 'void'}}
+
+template<typename T, template<typename T::type> class ...X> void b(T);
+int &b(...);
+int &b_disabled = b(0);
+int &b_enabled = b(Q()); // expected-error {{cannot bind to a temporary of type 'void'}}
+
+template<typename T, template<typename T::type...> class ...X> void c(T);
+int &c(...);
+int &c_disabled = c(0);
+int &c_enabled = c(Q()); // expected-error {{cannot bind to a temporary of type 'void'}}




More information about the cfe-commits mailing list