]> granicus.if.org Git - clang/commitdiff
Factor out checking of template arguments after deduction into a separate
authorRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 21 Dec 2016 01:10:31 +0000 (01:10 +0000)
committerRichard Smith <richard-llvm@metafoo.co.uk>
Wed, 21 Dec 2016 01:10:31 +0000 (01:10 +0000)
function. (This change would also allow us to handle default template arguments
in partial specializations if the standard ever permits them.)

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@290225 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaTemplateDeduction.cpp

index dc96d3f544e9c9f7b4a9b3a7ba9f6b9105f0e1fa..06a2deff39d3f56b686f53a815903305fa4e455b 100644 (file)
@@ -2214,6 +2214,130 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
   return ConvertArg(Arg, 0);
 }
 
+// FIXME: This should not be a template, but
+// ClassTemplatePartialSpecializationDecl sadly does not derive from
+// TemplateDecl.
+template<typename TemplateDeclT>
+static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments(
+    Sema &S, TemplateDeclT *Template,
+    SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+    TemplateDeductionInfo &Info, SmallVectorImpl<TemplateArgument> &Builder,
+    LocalInstantiationScope *CurrentInstantiationScope = nullptr,
+    unsigned NumAlreadyConverted = 0, bool PartialOverloading = false) {
+  TemplateParameterList *TemplateParams = Template->getTemplateParameters();
+
+  for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
+    NamedDecl *Param = TemplateParams->getParam(I);
+
+    if (!Deduced[I].isNull()) {
+      if (I < NumAlreadyConverted) {
+        // We have already fully type-checked and converted this
+        // argument, because it was explicitly-specified. Just record the
+        // presence of this argument.
+        Builder.push_back(Deduced[I]);
+        // We may have had explicitly-specified template arguments for a
+        // template parameter pack (that may or may not have been extended
+        // via additional deduced arguments).
+        if (Param->isParameterPack() && CurrentInstantiationScope) {
+          if (CurrentInstantiationScope->getPartiallySubstitutedPack() ==
+              Param) {
+            // Forget the partially-substituted pack; its substitution is now
+            // complete.
+            CurrentInstantiationScope->ResetPartiallySubstitutedPack();
+          }
+        }
+        continue;
+      }
+
+      // We have deduced this argument, so it still needs to be
+      // checked and converted.
+      if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Template, Info,
+                                         isa<FunctionTemplateDecl>(Template),
+                                         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;
+    }
+
+    // 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,
+                isa<FunctionTemplateDecl>(Template), 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);
+    if (!TD) {
+      assert(isa<ClassTemplatePartialSpecializationDecl>(Template));
+      return Sema::TDK_Incomplete;
+    }
+
+    TemplateArgumentLoc DefArg = S.SubstDefaultTemplateArgumentIfAvailable(
+        TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, Builder,
+        HasDefaultArg);
+
+    // If there was no default argument, deduction is incomplete.
+    if (DefArg.getArgument().isNull()) {
+      Info.Param = makeTemplateParameter(
+          const_cast<NamedDecl *>(TemplateParams->getParam(I)));
+      Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
+      if (PartialOverloading) break;
+
+      return HasDefaultArg ? Sema::TDK_SubstitutionFailure
+                           : Sema::TDK_Incomplete;
+    }
+
+    // Check whether we can actually use the default argument.
+    if (S.CheckTemplateArgument(Param, DefArg, TD, TD->getLocation(),
+                                TD->getSourceRange().getEnd(), 0, Builder,
+                                Sema::CTAK_Specified)) {
+      Info.Param = makeTemplateParameter(
+                         const_cast<NamedDecl *>(TemplateParams->getParam(I)));
+      // FIXME: These template arguments are temporary. Free them!
+      Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
+      return Sema::TDK_SubstitutionFailure;
+    }
+
+    // If we get here, we successfully used the default template argument.
+  }
+
+  return Sema::TDK_Success;
+}
+
 /// Complete template argument deduction for a class template partial
 /// specialization.
 static Sema::TemplateDeductionResult
@@ -2232,25 +2356,9 @@ FinishTemplateArgumentDeduction(Sema &S,
   //   [...] or if any template argument remains neither deduced nor
   //   explicitly specified, template argument deduction fails.
   SmallVector<TemplateArgument, 4> Builder;
-  TemplateParameterList *PartialParams = Partial->getTemplateParameters();
-  for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) {
-    NamedDecl *Param = PartialParams->getParam(I);
-    if (Deduced[I].isNull()) {
-      Info.Param = makeTemplateParameter(Param);
-      return Sema::TDK_Incomplete;
-    }
-
-    // We have deduced this argument, so it still needs to be
-    // checked and converted.
-    if (ConvertDeducedTemplateArgument(S, Param, Deduced[I],
-                                       Partial, Info, false,
-                                       Builder)) {
-      Info.Param = makeTemplateParameter(Param);
-      // FIXME: These template arguments are temporary. Free them!
-      Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
-      return Sema::TDK_SubstitutionFailure;
-    }
-  }
+  if (auto Result = ConvertDeducedTemplateArguments(S, Partial, Deduced,
+                                                    Info, Builder))
+    return Result;
 
   // Form the template argument list from the deduced template arguments.
   TemplateArgumentList *DeducedArgumentList
@@ -2372,24 +2480,9 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
   //   [...] or if any template argument remains neither deduced nor
   //   explicitly specified, template argument deduction fails.
   SmallVector<TemplateArgument, 4> Builder;
-  TemplateParameterList *PartialParams = Partial->getTemplateParameters();
-  for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) {
-    NamedDecl *Param = PartialParams->getParam(I);
-    if (Deduced[I].isNull()) {
-      Info.Param = makeTemplateParameter(Param);
-      return Sema::TDK_Incomplete;
-    }
-
-    // We have deduced this argument, so it still needs to be
-    // checked and converted.
-    if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Partial,
-                                       Info, false, Builder)) {
-      Info.Param = makeTemplateParameter(Param);
-      // FIXME: These template arguments are temporary. Free them!
-      Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
-      return Sema::TDK_SubstitutionFailure;
-    }
-  }
+  if (auto Result = ConvertDeducedTemplateArguments(S, Partial, Deduced,
+                                                    Info, Builder))
+    return Result;
 
   // Form the template argument list from the deduced template arguments.
   TemplateArgumentList *DeducedArgumentList = TemplateArgumentList::CreateCopy(
@@ -2819,9 +2912,6 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
                                       TemplateDeductionInfo &Info,
         SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs,
                                       bool PartialOverloading) {
-  TemplateParameterList *TemplateParams
-    = FunctionTemplate->getTemplateParameters();
-
   // Unevaluated SFINAE context.
   EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated);
   SFINAETrap Trap(*this);
@@ -2842,114 +2932,11 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
   //   [...] or if any template argument remains neither deduced nor
   //   explicitly specified, template argument deduction fails.
   SmallVector<TemplateArgument, 4> Builder;
-  for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) {
-    NamedDecl *Param = TemplateParams->getParam(I);
-
-    if (!Deduced[I].isNull()) {
-      if (I < NumExplicitlySpecified) {
-        // We have already fully type-checked and converted this
-        // argument, because it was explicitly-specified. Just record the
-        // presence of this argument.
-        Builder.push_back(Deduced[I]);
-        // We may have had explicitly-specified template arguments for a
-        // template parameter pack (that may or may not have been extended
-        // via additional deduced arguments).
-        if (Param->isParameterPack() && CurrentInstantiationScope) {
-          if (CurrentInstantiationScope->getPartiallySubstitutedPack() ==
-              Param) {
-            // Forget the partially-substituted pack; its substitution is now
-            // complete.
-            CurrentInstantiationScope->ResetPartiallySubstitutedPack();
-          }
-        }
-        continue;
-      }
-
-      // We have deduced this argument, so it still needs to be
-      // checked and converted.
-      if (ConvertDeducedTemplateArgument(*this, Param, Deduced[I],
-                                         FunctionTemplate, Info,
-                                         true, Builder)) {
-        Info.Param = makeTemplateParameter(Param);
-        // FIXME: These template arguments are temporary. Free them!
-        Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
-        return TDK_SubstitutionFailure;
-      }
-
-      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(*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));
-          return TDK_SubstitutionFailure;
-        }
-      }
-      continue;
-    }
-
-    // Substitute into the default template argument, if available.
-    bool HasDefaultArg = false;
-    TemplateArgumentLoc DefArg
-      = SubstDefaultTemplateArgumentIfAvailable(FunctionTemplate,
-                                              FunctionTemplate->getLocation(),
-                                  FunctionTemplate->getSourceRange().getEnd(),
-                                                Param,
-                                                Builder, HasDefaultArg);
-
-    // If there was no default argument, deduction is incomplete.
-    if (DefArg.getArgument().isNull()) {
-      Info.Param = makeTemplateParameter(
-                         const_cast<NamedDecl *>(TemplateParams->getParam(I)));
-      Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
-      if (PartialOverloading) break;
-
-      return HasDefaultArg ? TDK_SubstitutionFailure : TDK_Incomplete;
-    }
-
-    // Check whether we can actually use the default argument.
-    if (CheckTemplateArgument(Param, DefArg,
-                              FunctionTemplate,
-                              FunctionTemplate->getLocation(),
-                              FunctionTemplate->getSourceRange().getEnd(),
-                              0, Builder,
-                              CTAK_Specified)) {
-      Info.Param = makeTemplateParameter(
-                         const_cast<NamedDecl *>(TemplateParams->getParam(I)));
-      // FIXME: These template arguments are temporary. Free them!
-      Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
-      return TDK_SubstitutionFailure;
-    }
-
-    // If we get here, we successfully used the default template argument.
-  }
+  if (auto Result = ConvertDeducedTemplateArguments(
+          *this, FunctionTemplate, Deduced, Info, Builder,
+          CurrentInstantiationScope, NumExplicitlySpecified,
+          PartialOverloading))
+    return Result;
 
   // Form the template argument list from the deduced template arguments.
   TemplateArgumentList *DeducedArgumentList