r337481 - Fix template argument deduction when a parameter pack has a value

Richard Smith via cfe-commits cfe-commits at lists.llvm.org
Thu Jul 19 12:00:37 PDT 2018


Author: rsmith
Date: Thu Jul 19 12:00:37 2018
New Revision: 337481

URL: http://llvm.org/viewvc/llvm-project?rev=337481&view=rev
Log:
Fix template argument deduction when a parameter pack has a value
provided by an outer template.

We made the incorrect assumption in various places that the only way we
can have any arguments already provided for a pack during template
argument deduction was from a partially-specified pack. That's not true;
we can also have arguments from an enclosing already-instantiated
template, and that can even result in the function template's own pack
parameters having a fixed length and not being packs for the purposes of
template argument deduction.

Modified:
    cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
    cfe/trunk/include/clang/Sema/Sema.h
    cfe/trunk/include/clang/Sema/TemplateDeduction.h
    cfe/trunk/lib/Sema/SemaOverload.cpp
    cfe/trunk/lib/Sema/SemaTemplate.cpp
    cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
    cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
    cfe/trunk/test/SemaTemplate/pack-deduction.cpp

Modified: cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td?rev=337481&r1=337480&r2=337481&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticSemaKinds.td Thu Jul 19 12:00:37 2018
@@ -3589,6 +3589,9 @@ def note_ovl_candidate_bad_deduction : N
     "candidate template ignored: failed template argument deduction">;
 def note_ovl_candidate_incomplete_deduction : Note<"candidate template ignored: "
     "couldn't infer template argument %0">;
+def note_ovl_candidate_incomplete_deduction_pack : Note<"candidate template ignored: "
+    "deduced too few arguments for expanded pack %0; no argument for %ordinal1 "
+    "expanded parameter in deduced argument pack %2">;
 def note_ovl_candidate_inconsistent_deduction : Note<
     "candidate template ignored: deduced conflicting %select{types|values|"
     "templates}0 for parameter %1%diff{ ($ vs. $)|}2,3">;
@@ -4462,6 +4465,9 @@ def err_pack_expansion_length_conflict :
 def err_pack_expansion_length_conflict_multilevel : Error<
   "pack expansion contains parameter pack %0 that has a different "
   "length (%1 vs. %2) from outer parameter packs">;
+def err_pack_expansion_length_conflict_partial : Error<
+  "pack expansion contains parameter pack %0 that has a different "
+  "length (at least %1 vs. %2) from outer parameter packs">;
 def err_pack_expansion_member_init : Error<
   "pack expansion for initialization of member %0">;
 

Modified: cfe/trunk/include/clang/Sema/Sema.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/Sema.h?rev=337481&r1=337480&r2=337481&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/Sema.h (original)
+++ cfe/trunk/include/clang/Sema/Sema.h Thu Jul 19 12:00:37 2018
@@ -6911,6 +6911,9 @@ public:
     /// Template argument deduction did not deduce a value
     /// for every template parameter.
     TDK_Incomplete,
+    /// Template argument deduction did not deduce a value for every
+    /// expansion of an expanded template parameter pack.
+    TDK_IncompletePack,
     /// Template argument deduction produced inconsistent
     /// deduced values for the given template parameter.
     TDK_Inconsistent,

Modified: cfe/trunk/include/clang/Sema/TemplateDeduction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Sema/TemplateDeduction.h?rev=337481&r1=337480&r2=337481&view=diff
==============================================================================
--- cfe/trunk/include/clang/Sema/TemplateDeduction.h (original)
+++ cfe/trunk/include/clang/Sema/TemplateDeduction.h Thu Jul 19 12:00:37 2018
@@ -51,6 +51,10 @@ class TemplateDeductionInfo {
   /// The template parameter depth for which we're performing deduction.
   unsigned DeducedDepth;
 
+  /// The number of parameters with explicitly-specified template arguments,
+  /// up to and including the partially-specified pack (if any).
+  unsigned ExplicitArgs = 0;
+
   /// Warnings (and follow-on notes) that were suppressed due to
   /// SFINAE while performing template argument deduction.
   SmallVector<PartialDiagnosticAt, 4> SuppressedDiagnostics;
@@ -73,6 +77,11 @@ public:
     return DeducedDepth;
   }
 
+  /// Get the number of explicitly-specified arguments.
+  unsigned getNumExplicitArgs() const {
+    return ExplicitArgs;
+  }
+
   /// Take ownership of the deduced template argument list.
   TemplateArgumentList *take() {
     TemplateArgumentList *Result = Deduced;
@@ -100,6 +109,13 @@ public:
     return SuppressedDiagnostics.front();
   }
 
+  /// Provide an initial template argument list that contains the
+  /// explicitly-specified arguments.
+  void setExplicitArgs(TemplateArgumentList *NewDeduced) {
+    Deduced = NewDeduced;
+    ExplicitArgs = Deduced->size();
+  }
+
   /// Provide a new template argument list that contains the
   /// results of template argument deduction.
   void reset(TemplateArgumentList *NewDeduced) {
@@ -149,6 +165,9 @@ public:
   ///   TDK_Incomplete: this is the first template parameter whose
   ///   corresponding template argument was not deduced.
   ///
+  ///   TDK_IncompletePack: this is the expanded parameter pack for
+  ///   which we deduced too few arguments.
+  ///
   ///   TDK_Inconsistent: this is the template parameter for which
   ///   two different template argument values were deduced.
   TemplateParameter Param;
@@ -159,6 +178,9 @@ public:
   /// Depending on the result of the template argument deduction,
   /// this template argument may have different meanings:
   ///
+  ///   TDK_IncompletePack: this is the number of arguments we deduced
+  ///   for the pack.
+  ///
   ///   TDK_Inconsistent: this argument is the first value deduced
   ///   for the corresponding template parameter.
   ///

Modified: cfe/trunk/lib/Sema/SemaOverload.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaOverload.cpp?rev=337481&r1=337480&r2=337481&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaOverload.cpp (original)
+++ cfe/trunk/lib/Sema/SemaOverload.cpp Thu Jul 19 12:00:37 2018
@@ -629,6 +629,8 @@ clang::MakeDeductionFailureInfo(ASTConte
     break;
   }
 
+  case Sema::TDK_IncompletePack:
+    // FIXME: It's slightly wasteful to allocate two TemplateArguments for this.
   case Sema::TDK_Inconsistent:
   case Sema::TDK_Underqualified: {
     // FIXME: Should allocate from normal heap so that we can free this later.
@@ -671,6 +673,7 @@ void DeductionFailureInfo::Destroy() {
   case Sema::TDK_NonDependentConversionFailure:
     break;
 
+  case Sema::TDK_IncompletePack:
   case Sema::TDK_Inconsistent:
   case Sema::TDK_Underqualified:
   case Sema::TDK_DeducedMismatch:
@@ -720,6 +723,7 @@ TemplateParameter DeductionFailureInfo::
   case Sema::TDK_InvalidExplicitArguments:
     return TemplateParameter::getFromOpaqueValue(Data);
 
+  case Sema::TDK_IncompletePack:
   case Sema::TDK_Inconsistent:
   case Sema::TDK_Underqualified:
     return static_cast<DFIParamWithArguments*>(Data)->Param;
@@ -740,6 +744,7 @@ TemplateArgumentList *DeductionFailureIn
   case Sema::TDK_TooManyArguments:
   case Sema::TDK_TooFewArguments:
   case Sema::TDK_Incomplete:
+  case Sema::TDK_IncompletePack:
   case Sema::TDK_InvalidExplicitArguments:
   case Sema::TDK_Inconsistent:
   case Sema::TDK_Underqualified:
@@ -777,6 +782,7 @@ const TemplateArgument *DeductionFailure
   case Sema::TDK_NonDependentConversionFailure:
     return nullptr;
 
+  case Sema::TDK_IncompletePack:
   case Sema::TDK_Inconsistent:
   case Sema::TDK_Underqualified:
   case Sema::TDK_DeducedMismatch:
@@ -798,6 +804,7 @@ const TemplateArgument *DeductionFailure
   case Sema::TDK_Invalid:
   case Sema::TDK_InstantiationDepth:
   case Sema::TDK_Incomplete:
+  case Sema::TDK_IncompletePack:
   case Sema::TDK_TooManyArguments:
   case Sema::TDK_TooFewArguments:
   case Sema::TDK_InvalidExplicitArguments:
@@ -9893,6 +9900,17 @@ static void DiagnoseBadDeduction(Sema &S
     return;
   }
 
+  case Sema::TDK_IncompletePack: {
+    assert(ParamD && "no parameter found for incomplete deduction result");
+    S.Diag(Templated->getLocation(),
+           diag::note_ovl_candidate_incomplete_deduction_pack)
+        << ParamD->getDeclName()
+        << (DeductionFailure.getFirstArg()->pack_size() + 1)
+        << *DeductionFailure.getFirstArg();
+    MaybeEmitInheritedConstructorNote(S, Found);
+    return;
+  }
+
   case Sema::TDK_Underqualified: {
     assert(ParamD && "no parameter found for bad qualifiers deduction result");
     TemplateTypeParmDecl *TParam = cast<TemplateTypeParmDecl>(ParamD);
@@ -10372,6 +10390,7 @@ static unsigned RankDeductionFailure(con
 
   case Sema::TDK_Invalid:
   case Sema::TDK_Incomplete:
+  case Sema::TDK_IncompletePack:
     return 1;
 
   case Sema::TDK_Underqualified:

Modified: cfe/trunk/lib/Sema/SemaTemplate.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplate.cpp?rev=337481&r1=337480&r2=337481&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplate.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplate.cpp Thu Jul 19 12:00:37 2018
@@ -4914,27 +4914,6 @@ bool Sema::CheckTemplateArgument(NamedDe
   return false;
 }
 
-/// Diagnose an arity mismatch in the
-static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template,
-                                  SourceLocation TemplateLoc,
-                                  TemplateArgumentListInfo &TemplateArgs) {
-  TemplateParameterList *Params = Template->getTemplateParameters();
-  unsigned NumParams = Params->size();
-  unsigned NumArgs = TemplateArgs.size();
-
-  SourceRange Range;
-  if (NumArgs > NumParams)
-    Range = SourceRange(TemplateArgs[NumParams].getLocation(),
-                        TemplateArgs.getRAngleLoc());
-  S.Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
-    << (NumArgs > NumParams)
-    << (int)S.getTemplateNameKindForDiagnostics(TemplateName(Template))
-    << Template << Range;
-  S.Diag(Template->getLocation(), diag::note_template_decl_here)
-    << Params->getSourceRange();
-  return true;
-}
-
 /// Check whether the template parameter is a pack expansion, and if so,
 /// determine the number of parameters produced by that expansion. For instance:
 ///
@@ -4988,7 +4967,15 @@ static bool diagnoseMissingArgument(Sema
   // FIXME: If there's a more recent default argument that *is* visible,
   // diagnose that it was declared too late.
 
-  return diagnoseArityMismatch(S, TD, Loc, Args);
+  TemplateParameterList *Params = TD->getTemplateParameters();
+
+  S.Diag(Loc, diag::err_template_arg_list_different_arity)
+    << /*not enough args*/0
+    << (int)S.getTemplateNameKindForDiagnostics(TemplateName(TD))
+    << TD;
+  S.Diag(TD->getLocation(), diag::note_template_decl_here)
+    << Params->getSourceRange();
+  return true;
 }
 
 /// Check that the given template argument list is well-formed
@@ -5040,7 +5027,7 @@ bool Sema::CheckTemplateArgumentList(
       } else if (ArgIdx == NumArgs && !PartialTemplateArgs) {
         // Not enough arguments for this parameter pack.
         Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
-          << false
+          << /*not enough args*/0
           << (int)getTemplateNameKindForDiagnostics(TemplateName(Template))
           << Template;
         Diag(Template->getLocation(), diag::note_template_decl_here)
@@ -5235,8 +5222,16 @@ bool Sema::CheckTemplateArgumentList(
 
   // If we have any leftover arguments, then there were too many arguments.
   // Complain and fail.
-  if (ArgIdx < NumArgs)
-    return diagnoseArityMismatch(*this, Template, TemplateLoc, NewArgs);
+  if (ArgIdx < NumArgs) {
+    Diag(TemplateLoc, diag::err_template_arg_list_different_arity)
+        << /*too many args*/1
+        << (int)getTemplateNameKindForDiagnostics(TemplateName(Template))
+        << Template
+        << SourceRange(NewArgs[ArgIdx].getLocation(), NewArgs.getRAngleLoc());
+    Diag(Template->getLocation(), diag::note_template_decl_here)
+        << Params->getSourceRange();
+    return true;
+  }
 
   // No problems found with the new argument list, propagate changes back
   // to caller.

Modified: cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp?rev=337481&r1=337480&r2=337481&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateDeduction.cpp Thu Jul 19 12:00:37 2018
@@ -662,6 +662,19 @@ static TemplateParameter makeTemplatePar
   return TemplateParameter(cast<TemplateTemplateParmDecl>(D));
 }
 
+/// If \p Param is an expanded parameter pack, get the number of expansions.
+static Optional<unsigned> getExpandedPackSize(NamedDecl *Param) {
+  if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
+    if (NTTP->isExpandedParameterPack())
+      return NTTP->getNumExpansionTypes();
+
+  if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param))
+    if (TTP->isExpandedParameterPack())
+      return TTP->getNumExpansionTemplateParameters();
+
+  return None;
+}
+
 /// A pack that we're currently deducing.
 struct clang::DeducedPack {
   // The index of the pack.
@@ -688,10 +701,83 @@ namespace {
 /// A scope in which we're performing pack deduction.
 class PackDeductionScope {
 public:
+  /// Prepare to deduce the packs named within Pattern.
   PackDeductionScope(Sema &S, TemplateParameterList *TemplateParams,
                      SmallVectorImpl<DeducedTemplateArgument> &Deduced,
                      TemplateDeductionInfo &Info, TemplateArgument Pattern)
       : S(S), TemplateParams(TemplateParams), Deduced(Deduced), Info(Info) {
+    unsigned NumNamedPacks = addPacks(Pattern);
+    finishConstruction(NumNamedPacks);
+  }
+
+  /// Prepare to directly deduce arguments of the parameter with index \p Index.
+  PackDeductionScope(Sema &S, TemplateParameterList *TemplateParams,
+                     SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+                     TemplateDeductionInfo &Info, unsigned Index)
+      : S(S), TemplateParams(TemplateParams), Deduced(Deduced), Info(Info) {
+    addPack(Index);
+    finishConstruction(1);
+  }
+
+private:
+  void addPack(unsigned Index) {
+    // Save the deduced template argument for the parameter pack expanded
+    // by this pack expansion, then clear out the deduction.
+    DeducedPack Pack(Index);
+    Pack.Saved = Deduced[Index];
+    Deduced[Index] = TemplateArgument();
+
+    // FIXME: What if we encounter multiple packs with different numbers of
+    // pre-expanded expansions? (This should already have been diagnosed
+    // during substitution.)
+    if (Optional<unsigned> ExpandedPackExpansions =
+            getExpandedPackSize(TemplateParams->getParam(Index)))
+      FixedNumExpansions = ExpandedPackExpansions;
+
+    Packs.push_back(Pack);
+  }
+
+  unsigned addPacks(TemplateArgument Pattern) {
+    // Compute the set of template parameter indices that correspond to
+    // parameter packs expanded by the pack expansion.
+    llvm::SmallBitVector SawIndices(TemplateParams->size());
+
+    auto AddPack = [&](unsigned Index) {
+      if (SawIndices[Index])
+        return;
+      SawIndices[Index] = true;
+      addPack(Index);
+    };
+
+    // First look for unexpanded packs in the pattern.
+    SmallVector<UnexpandedParameterPack, 2> Unexpanded;
+    S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
+    for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
+      unsigned Depth, Index;
+      std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
+      if (Depth == Info.getDeducedDepth())
+        AddPack(Index);
+    }
+    assert(!Packs.empty() && "Pack expansion without unexpanded packs?");
+
+    unsigned NumNamedPacks = Packs.size();
+
+    // We can also have deduced template parameters that do not actually
+    // appear in the pattern, but can be deduced by it (the type of a non-type
+    // template parameter pack, in particular). These won't have prevented us
+    // from partially expanding the pack.
+    llvm::SmallBitVector Used(TemplateParams->size());
+    MarkUsedTemplateParameters(S.Context, Pattern, /*OnlyDeduced*/true,
+                               Info.getDeducedDepth(), Used);
+    for (int Index = Used.find_first(); Index != -1;
+         Index = Used.find_next(Index))
+      if (TemplateParams->getParam(Index)->isParameterPack())
+        AddPack(Index);
+
+    return NumNamedPacks;
+  }
+
+  void finishConstruction(unsigned NumNamedPacks) {
     // Dig out the partially-substituted pack, if there is one.
     const TemplateArgument *PartialPackArgs = nullptr;
     unsigned NumPartialPackArgs = 0;
@@ -701,60 +787,29 @@ public:
               &PartialPackArgs, &NumPartialPackArgs))
         PartialPackDepthIndex = getDepthAndIndex(Partial);
 
-    // Compute the set of template parameter indices that correspond to
-    // parameter packs expanded by the pack expansion.
-    {
-      llvm::SmallBitVector SawIndices(TemplateParams->size());
-
-      auto AddPack = [&](unsigned Index) {
-        if (SawIndices[Index])
-          return;
-        SawIndices[Index] = true;
-
-        // Save the deduced template argument for the parameter pack expanded
-        // by this pack expansion, then clear out the deduction.
-        DeducedPack Pack(Index);
-        Pack.Saved = Deduced[Index];
-        Deduced[Index] = TemplateArgument();
-
-        Packs.push_back(Pack);
-      };
-
-      // First look for unexpanded packs in the pattern.
-      SmallVector<UnexpandedParameterPack, 2> Unexpanded;
-      S.collectUnexpandedParameterPacks(Pattern, Unexpanded);
-      for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) {
-        unsigned Depth, Index;
-        std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]);
-        if (Depth == Info.getDeducedDepth())
-          AddPack(Index);
-      }
-      assert(!Packs.empty() && "Pack expansion without unexpanded packs?");
-
-      // This pack expansion will have been partially expanded iff the only
-      // unexpanded parameter pack within it is the partially-substituted pack.
-      IsPartiallyExpanded =
-          Packs.size() == 1 &&
-          PartialPackDepthIndex ==
-              std::make_pair(Info.getDeducedDepth(), Packs.front().Index);
-
-      // Skip over the pack elements that were expanded into separate arguments.
-      if (IsPartiallyExpanded)
-        PackElements += NumPartialPackArgs;
-
-      // We can also have deduced template parameters that do not actually
-      // appear in the pattern, but can be deduced by it (the type of a non-type
-      // template parameter pack, in particular). These won't have prevented us
-      // from partially expanding the pack.
-      llvm::SmallBitVector Used(TemplateParams->size());
-      MarkUsedTemplateParameters(S.Context, Pattern, /*OnlyDeduced*/true,
-                                 Info.getDeducedDepth(), Used);
-      for (int Index = Used.find_first(); Index != -1;
-           Index = Used.find_next(Index))
-        if (TemplateParams->getParam(Index)->isParameterPack())
-          AddPack(Index);
+    // This pack expansion will have been partially or fully expanded if
+    // it only names explicitly-specified parameter packs (including the
+    // partially-substituted one, if any).
+    bool IsExpanded = true;
+    for (unsigned I = 0; I != NumNamedPacks; ++I) {
+      if (Packs[I].Index >= Info.getNumExplicitArgs()) {
+        IsExpanded = false;
+        IsPartiallyExpanded = false;
+        break;
+      }
+      if (PartialPackDepthIndex ==
+            std::make_pair(Info.getDeducedDepth(), Packs[I].Index)) {
+        IsPartiallyExpanded = true;
+      }
     }
 
+    // Skip over the pack elements that were expanded into separate arguments.
+    // If we partially expanded, this is the number of partial arguments.
+    if (IsPartiallyExpanded)
+      PackElements += NumPartialPackArgs;
+    else if (IsExpanded)
+      PackElements += *FixedNumExpansions;
+
     for (auto &Pack : Packs) {
       if (Info.PendingDeducedPacks.size() > Pack.Index)
         Pack.Outer = Info.PendingDeducedPacks[Pack.Index];
@@ -773,12 +828,13 @@ public:
         // FIXME: If we could represent a "depth i, index j, pack elem k"
         // parameter, we could substitute the partially-substituted pack
         // everywhere and avoid this.
-        if (Pack.New.size() > PackElements)
+        if (!IsPartiallyExpanded)
           Deduced[Pack.Index] = Pack.New[PackElements];
       }
     }
   }
 
+public:
   ~PackDeductionScope() {
     for (auto &Pack : Packs)
       Info.PendingDeducedPacks[Pack.Index] = Pack.Outer;
@@ -788,6 +844,18 @@ public:
   /// sequence of (prior) function parameters / template arguments.
   bool isPartiallyExpanded() { return IsPartiallyExpanded; }
 
+  /// Determine whether this pack expansion scope has a known, fixed arity.
+  /// This happens if it involves a pack from an outer template that has
+  /// (notionally) already been expanded.
+  bool hasFixedArity() { return FixedNumExpansions.hasValue(); }
+
+  /// Determine whether the next element of the argument is still part of this
+  /// pack. This is the case unless the pack is already expanded to a fixed
+  /// length.
+  bool hasNextElement() {
+    return !FixedNumExpansions || *FixedNumExpansions > PackElements;
+  }
+
   /// Move to deducing the next element in each pack that is being deduced.
   void nextPackElement() {
     // Capture the deduced template arguments for each parameter pack expanded
@@ -813,13 +881,21 @@ public:
   /// Finish template argument deduction for a set of argument packs,
   /// producing the argument packs and checking for consistency with prior
   /// deductions.
-  Sema::TemplateDeductionResult finish() {
+  Sema::TemplateDeductionResult
+  finish(bool TreatNoDeductionsAsNonDeduced = true) {
     // Build argument packs for each of the parameter packs expanded by this
     // pack expansion.
     for (auto &Pack : Packs) {
       // Put back the old value for this pack.
       Deduced[Pack.Index] = Pack.Saved;
 
+      // If we are deducing the size of this pack even if we didn't deduce any
+      // values for it, then make sure we build a pack of the right size.
+      // FIXME: Should we always deduce the size, even if the pack appears in
+      // a non-deduced context?
+      if (!TreatNoDeductionsAsNonDeduced)
+        Pack.New.resize(PackElements);
+
       // Build or find a new value for this pack.
       DeducedTemplateArgument NewPack;
       if (PackElements && Pack.New.empty()) {
@@ -875,14 +951,24 @@ public:
         Result = checkDeducedTemplateArguments(S.Context, OldPack, NewPack);
       }
 
+      NamedDecl *Param = TemplateParams->getParam(Pack.Index);
       if (Result.isNull()) {
-        Info.Param =
-            makeTemplateParameter(TemplateParams->getParam(Pack.Index));
+        Info.Param = makeTemplateParameter(Param);
         Info.FirstArg = OldPack;
         Info.SecondArg = NewPack;
         return Sema::TDK_Inconsistent;
       }
 
+      // If we have a pre-expanded pack and we didn't deduce enough elements
+      // for it, fail deduction.
+      if (Optional<unsigned> Expansions = getExpandedPackSize(Param)) {
+        if (*Expansions != PackElements) {
+          Info.Param = makeTemplateParameter(Param);
+          Info.FirstArg = Result;
+          return Sema::TDK_IncompletePack;
+        }
+      }
+
       *Loc = Result;
     }
 
@@ -896,6 +982,8 @@ private:
   TemplateDeductionInfo &Info;
   unsigned PackElements = 0;
   bool IsPartiallyExpanded = false;
+  /// The number of expansions, if we have a fully-expanded pack in this scope.
+  Optional<unsigned> FixedNumExpansions;
 
   SmallVector<DeducedPack, 2> Packs;
 };
@@ -987,8 +1075,10 @@ DeduceTemplateArguments(Sema &S,
     QualType Pattern = Expansion->getPattern();
     PackDeductionScope PackScope(S, TemplateParams, Deduced, Info, Pattern);
 
-    if (ParamIdx + 1 == NumParams) {
-      for (; ArgIdx < NumArgs; ++ArgIdx) {
+    // A pack scope with fixed arity is not really a pack any more, so is not
+    // a non-deduced context.
+    if (ParamIdx + 1 == NumParams || PackScope.hasFixedArity()) {
+      for (; ArgIdx < NumArgs && PackScope.hasNextElement(); ++ArgIdx) {
         // Deduce template arguments from the pattern.
         if (Sema::TemplateDeductionResult Result
               = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, Pattern,
@@ -2193,6 +2283,8 @@ static bool hasPackExpansionBeforeEnd(Ar
     if (A.getKind() == TemplateArgument::Pack)
       return hasPackExpansionBeforeEnd(A.pack_elements());
 
+    // FIXME: If this is a fixed-arity pack expansion from an outer level of
+    // templates, it should not be treated as a pack expansion.
     if (A.isPackExpansion())
       FoundPackExpansion = true;
   }
@@ -2262,7 +2354,9 @@ DeduceTemplateArguments(Sema &S, Templat
     // Keep track of the deduced template arguments for each parameter pack
     // expanded by this pack expansion (the outer index) and for each
     // template argument (the inner SmallVectors).
-    for (; hasTemplateArgumentForDeduction(Args, ArgIdx); ++ArgIdx) {
+    for (; hasTemplateArgumentForDeduction(Args, ArgIdx) &&
+           PackScope.hasNextElement();
+         ++ArgIdx) {
       // Deduce template arguments from the pattern.
       if (Sema::TemplateDeductionResult Result
             = DeduceTemplateArguments(S, TemplateParams, Pattern, Args[ArgIdx],
@@ -2534,6 +2628,16 @@ static Sema::TemplateDeductionResult Con
   for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
     NamedDecl *Param = TemplateParams->getParam(I);
 
+    // C++0x [temp.arg.explicit]p3:
+    //    A trailing template parameter pack (14.5.3) not otherwise deduced will
+    //    be deduced to an empty sequence of template arguments.
+    // FIXME: Where did the word "trailing" come from?
+    if (Deduced[I].isNull() && Param->isTemplateParameterPack()) {
+      if (auto Result = PackDeductionScope(S, TemplateParams, Deduced, Info, I)
+                            .finish(/*TreatNoDeductionsAsNonDeduced*/false))
+        return Result;
+    }
+
     if (!Deduced[I].isNull()) {
       if (I < NumAlreadyConverted) {
         // We may have had explicitly-specified template arguments for a
@@ -2568,40 +2672,6 @@ static Sema::TemplateDeductionResult Con
       continue;
     }
 
-    // C++0x [temp.arg.explicit]p3:
-    //    A trailing template parameter pack (14.5.3) not otherwise deduced will
-    //    be deduced to an empty sequence of template arguments.
-    // FIXME: Where did the word "trailing" come from?
-    if (Param->isTemplateParameterPack()) {
-      // We may have had explicitly-specified template arguments for this
-      // template parameter pack. If so, our empty deduction extends the
-      // explicitly-specified set (C++0x [temp.arg.explicit]p9).
-      const TemplateArgument *ExplicitArgs;
-      unsigned NumExplicitArgs;
-      if (CurrentInstantiationScope &&
-          CurrentInstantiationScope->getPartiallySubstitutedPack(
-              &ExplicitArgs, &NumExplicitArgs) == Param) {
-        Builder.push_back(TemplateArgument(
-            llvm::makeArrayRef(ExplicitArgs, NumExplicitArgs)));
-
-        // Forget the partially-substituted pack; its substitution is now
-        // complete.
-        CurrentInstantiationScope->ResetPartiallySubstitutedPack();
-      } else {
-        // Go through the motions of checking the empty argument pack against
-        // the parameter pack.
-        DeducedTemplateArgument DeducedPack(TemplateArgument::getEmptyPack());
-        if (ConvertDeducedTemplateArgument(S, Param, DeducedPack, Template,
-                                           Info, IsDeduced, Builder)) {
-          Info.Param = makeTemplateParameter(Param);
-          // FIXME: These template arguments are temporary. Free them!
-          Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
-          return Sema::TDK_SubstitutionFailure;
-        }
-      }
-      continue;
-    }
-
     // Substitute into the default template argument, if available.
     bool HasDefaultArg = false;
     TemplateDecl *TD = dyn_cast<TemplateDecl>(Template);
@@ -2962,7 +3032,7 @@ Sema::SubstituteExplicitTemplateArgument
       Trap.hasErrorOccurred()) {
     unsigned Index = Builder.size();
     if (Index >= TemplateParams->size())
-      Index = TemplateParams->size() - 1;
+      return TDK_SubstitutionFailure;
     Info.Param = makeTemplateParameter(TemplateParams->getParam(Index));
     return TDK_InvalidExplicitArguments;
   }
@@ -2971,7 +3041,7 @@ Sema::SubstituteExplicitTemplateArgument
   // template arguments.
   TemplateArgumentList *ExplicitArgumentList
     = TemplateArgumentList::CreateCopy(Context, Builder);
-  Info.reset(ExplicitArgumentList);
+  Info.setExplicitArgs(ExplicitArgumentList);
 
   // Template argument deduction and the final substitution should be
   // done in the context of the templated declaration.  Explicit
@@ -2983,14 +3053,19 @@ Sema::SubstituteExplicitTemplateArgument
   // note that the template argument pack is partially substituted and record
   // the explicit template arguments. They'll be used as part of deduction
   // for this template parameter pack.
-  for (unsigned I = 0, N = Builder.size(); I != N; ++I) {
-    const TemplateArgument &Arg = Builder[I];
+  unsigned PartiallySubstitutedPackIndex = -1u;
+  if (!Builder.empty()) {
+    const TemplateArgument &Arg = Builder.back();
     if (Arg.getKind() == TemplateArgument::Pack) {
-      CurrentInstantiationScope->SetPartiallySubstitutedPack(
-                                                 TemplateParams->getParam(I),
-                                                             Arg.pack_begin(),
-                                                             Arg.pack_size());
-      break;
+      auto *Param = TemplateParams->getParam(Builder.size() - 1);
+      // If this is a fully-saturated fixed-size pack, it should be
+      // fully-substituted, not partially-substituted.
+      Optional<unsigned> Expansions = getExpandedPackSize(Param);
+      if (!Expansions || Arg.pack_size() < *Expansions) {
+        PartiallySubstitutedPackIndex = Builder.size() - 1;
+        CurrentInstantiationScope->SetPartiallySubstitutedPack(
+            Param, Arg.pack_begin(), Arg.pack_size());
+      }
     }
   }
 
@@ -3080,13 +3155,13 @@ Sema::SubstituteExplicitTemplateArgument
   //   case, the empty template argument list <> itself may also be omitted.
   //
   // Take all of the explicitly-specified arguments and put them into
-  // the set of deduced template arguments. Explicitly-specified
-  // parameter packs, however, will be set to NULL since the deduction
-  // mechanisms handle explicitly-specified argument packs directly.
+  // the set of deduced template arguments. The partially-substituted
+  // parameter pack, however, will be set to NULL since the deduction
+  // mechanism handles the partially-substituted argument pack directly.
   Deduced.reserve(TemplateParams->size());
   for (unsigned I = 0, N = ExplicitArgumentList->size(); I != N; ++I) {
     const TemplateArgument &Arg = ExplicitArgumentList->get(I);
-    if (Arg.getKind() == TemplateArgument::Pack)
+    if (I == PartiallySubstitutedPackIndex)
       Deduced.push_back(DeducedTemplateArgument());
     else
       Deduced.push_back(Arg);
@@ -3852,8 +3927,9 @@ Sema::TemplateDeductionResult Sema::Dedu
     // the length of the explicitly-specified pack if it's expanded by the
     // parameter pack and 0 otherwise, and we treat each deduction as a
     // non-deduced context.
-    if (ParamIdx + 1 == NumParamTypes) {
-      for (; ArgIdx < Args.size(); PackScope.nextPackElement(), ++ArgIdx) {
+    if (ParamIdx + 1 == NumParamTypes || PackScope.hasFixedArity()) {
+      for (; ArgIdx < Args.size() && PackScope.hasNextElement();
+           PackScope.nextPackElement(), ++ArgIdx) {
         ParamTypesForArgChecking.push_back(ParamPattern);
         if (auto Result = DeduceCallArgument(ParamPattern, ArgIdx))
           return Result;

Modified: cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp?rev=337481&r1=337480&r2=337481&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp (original)
+++ cfe/trunk/lib/Sema/SemaTemplateVariadic.cpp Thu Jul 19 12:00:37 2018
@@ -646,7 +646,9 @@ bool Sema::CheckParameterPacksForExpansi
   RetainExpansion = false;
   std::pair<IdentifierInfo *, SourceLocation> FirstPack;
   bool HaveFirstPack = false;
-  
+  Optional<unsigned> NumPartialExpansions;
+  SourceLocation PartiallySubstitutedPackLoc;
+
   for (ArrayRef<UnexpandedParameterPack>::iterator i = Unexpanded.begin(),
                                                  end = Unexpanded.end();
                                                   i != end; ++i) {
@@ -711,8 +713,13 @@ bool Sema::CheckParameterPacksForExpansi
                     = CurrentInstantiationScope->getPartiallySubstitutedPack()){
         unsigned PartialDepth, PartialIndex;
         std::tie(PartialDepth, PartialIndex) = getDepthAndIndex(PartialPack);
-        if (PartialDepth == Depth && PartialIndex == Index)
+        if (PartialDepth == Depth && PartialIndex == Index) {
           RetainExpansion = true;
+          // We don't actually know the new pack size yet.
+          NumPartialExpansions = NewPackSize;
+          PartiallySubstitutedPackLoc = i->second;
+          continue;
+        }
       }
     }
     
@@ -742,6 +749,28 @@ bool Sema::CheckParameterPacksForExpansi
     }
   }
 
+  // If we're performing a partial expansion but we also have a full expansion,
+  // expand to the number of common arguments. For example, given:
+  //
+  //   template<typename ...T> struct A {
+  //     template<typename ...U> void f(pair<T, U>...);
+  //   };
+  //
+  // ... a call to 'A<int, int>().f<int>' should expand the pack once and
+  // retain an expansion.
+  if (NumPartialExpansions) {
+    if (NumExpansions && *NumExpansions < *NumPartialExpansions) {
+      NamedDecl *PartialPack =
+          CurrentInstantiationScope->getPartiallySubstitutedPack();
+      Diag(EllipsisLoc, diag::err_pack_expansion_length_conflict_partial)
+        << PartialPack << *NumPartialExpansions << *NumExpansions
+        << SourceRange(PartiallySubstitutedPackLoc);
+      return true;
+    }
+
+    NumExpansions = NumPartialExpansions;
+  }
+
   return false;
 }
 

Modified: cfe/trunk/test/SemaTemplate/pack-deduction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaTemplate/pack-deduction.cpp?rev=337481&r1=337480&r2=337481&view=diff
==============================================================================
--- cfe/trunk/test/SemaTemplate/pack-deduction.cpp (original)
+++ cfe/trunk/test/SemaTemplate/pack-deduction.cpp Thu Jul 19 12:00:37 2018
@@ -65,3 +65,104 @@ namespace PR14615 {
     void f() { check<char>(1, 2); } // expected-error {{no matching function}}
   }
 }
+
+namespace fully_expanded_packs {
+  template<typename ...T> struct A {
+    template<T ...X> static constexpr int f() {
+      // expected-note at -1 1+{{deduced too few arguments for expanded pack 'X'}}
+      // expected-note at -2 1+{{too many template arguments}}
+      return (X + ... + 0); // expected-warning {{extension}}
+    }
+
+    template<T ...X, int Y> static constexpr int g() {
+      // expected-note at -1 1+{{deduced too few arguments for expanded pack 'X'}}
+      // expected-note at -2 1+{{couldn't infer template argument 'Y'}}
+      // expected-note at -3 1+{{too many template arguments}}
+      return (X + ... + (1000 * Y)); // expected-warning {{extension}}
+    }
+
+    template<T ...X, int Y, T ...Z> static constexpr int h() {
+      // expected-note at -1 1+{{deduced too few arguments for expanded pack 'X'}}
+      // expected-note at -2 1+{{couldn't infer template argument 'Y'}}
+      // expected-note at -3 1+{{deduced too few arguments for expanded pack 'Z'}}
+      // expected-note at -4 1+{{too many template arguments}}
+      return (X + ... + (1000 * Y)) + 1000000 * (Z + ... + 0); // expected-warning 2{{extension}}
+    }
+
+    template<T ...X, int ...Z> static constexpr int i() {
+      return (X + ... + 0) + 1000 * (Z + ... + 0); // expected-warning 2{{extension}}
+    }
+
+    template<T ...X, int Y, int ...Z> static constexpr int j() {
+      return (X + ... + (1000 * Y)) + 1000000 * (Z + ... + 0); // expected-warning 2{{extension}}
+    }
+  };
+
+  void check_invalid_calls() {
+    A<int, int>::f(); // expected-error {{no matching function}}
+    A<int, int>::f<>(); // expected-error {{no matching function}}
+    A<int, int>::f<0>(); // expected-error {{no matching function}}
+    A<int, int>::g(); // expected-error {{no matching function}}
+    A<int, int>::g<>(); // expected-error {{no matching function}}
+    A<int, int>::g<0>(); // expected-error {{no matching function}}
+    A<int, int>::g<0, 0>(); // expected-error {{no matching function}}
+    A<>::f<0>(); // expected-error {{no matching function}}
+    A<>::g(); // expected-error {{no matching function}}
+    A<>::g<>(); // expected-error {{no matching function}}
+    A<>::g<0, 0>(); // expected-error {{no matching function}}
+    A<>::h<>(); // expected-error {{no matching function}}
+    A<int>::h<>(); // expected-error {{no matching function}}
+    A<int>::h<0, 0>(); // expected-error {{no matching function}}
+    A<>::h<0, 0>(); // expected-error {{no matching function}}
+  }
+
+  static_assert(A<>::f() == 0, "");
+  static_assert(A<int>::f<1>() == 1, "");
+  static_assert(A<>::g<1>() == 1000, "");
+  static_assert(A<int>::g<1, 2>() == 2001, "");
+  static_assert(A<>::h<1>() == 1000, "");
+  static_assert(A<int>::h<1, 2, 3>() == 3002001, "");
+  static_assert(A<int, int>::h<1, 20, 3, 4, 50>() == 54003021, "");
+  static_assert(A<>::i<1>() == 1000, "");
+  static_assert(A<int>::i<1>() == 1, "");
+  static_assert(A<>::j<1, 2, 30>() == 32001000, "");
+  static_assert(A<int>::j<1, 2, 3, 40>() == 43002001, "");
+}
+
+namespace partial_full_mix {
+  template<typename T, typename U> struct pair {};
+  template<typename ...T> struct tuple {};
+  template<typename ...T> struct A {
+    template<typename ...U> static pair<tuple<T...>, tuple<U...>> f(pair<T, U> ...p);
+    // expected-note at -1 {{[with U = <char, double, long>]: pack expansion contains parameter pack 'U' that has a different length (2 vs. 3) from outer parameter packs}}
+    // expected-note at -2 {{[with U = <char, double, void>]: pack expansion contains parameter pack 'U' that has a different length (at least 3 vs. 2) from outer parameter packs}}
+
+    template<typename ...U> static pair<tuple<T...>, tuple<U...>> g(pair<T, U> ...p, ...);
+    // expected-note at -1 {{[with U = <char, double, long>]: pack expansion contains parameter pack 'U' that has a different length (2 vs. 3) from outer parameter packs}}
+
+    template<typename ...U> static tuple<U...> h(tuple<pair<T, U>..., pair<int, int>>);
+    // expected-note at -1 {{[with U = <int [2]>]: pack expansion contains parameter pack 'U' that has a different length (2 vs. 1) from outer parameter packs}}
+  };
+
+  pair<tuple<int, float>, tuple<char, double>> k1 = A<int, float>().f<char>(pair<int, char>(), pair<float, double>());
+  pair<tuple<int, float>, tuple<char, double>> k2 = A<int, float>().f<char>(pair<int, char>(), pair<float, double>(), pair<void, long>()); // expected-error {{no match}}
+  pair<tuple<int, float>, tuple<char, double>> k3 = A<int, float>().f<char, double, void>(pair<int, char>(), pair<float, double>()); // expected-error {{no match}}
+
+  // FIXME: We should accept this by treating the pack 'p' as having a fixed length of 2 here.
+  pair<tuple<int, float>, tuple<char, double>> k4 = A<int, float>().g<char>(pair<int, char>(), pair<float, double>(), pair<void, long>()); // expected-error {{no match}}
+
+  // FIXME: We should accept this by treating the pack of pairs as having a fixed length of 2 here.
+  tuple<int[2], int[4]> k5 = A<int[1], int[3]>::h<int[2]>(tuple<pair<int[1], int[2]>, pair<int[3], int[4]>, pair<int[5], int[5]>>()); // expected-error {{no match}}
+}
+
+namespace substitution_vs_function_deduction {
+  template <typename... T> struct A {
+    template <typename... U> void f(void(*...)(T, U)); // expected-warning {{ISO C++11 requires a parenthesized pack declaration to have a name}}
+    template <typename... U> void g(void...(T, U)); // expected-note {{could not match 'void (T, U)' against 'void (*)(int, int)'}}
+  };
+  void f(int, int) {
+    A<int>().f(f);
+    // FIXME: We fail to decay the parameter to a pointer type.
+    A<int>().g(f); // expected-error {{no match}}
+  }
+}




More information about the cfe-commits mailing list