================
@@ -5425,34 +5534,112 @@ static bool isAtLeastAsSpecializedAs(Sema &S, 
SourceLocation Loc,
   //   the partial ordering is done:
   TemplateDeductionInfo Info(Loc);
   switch (TPOC) {
-  case TPOC_Call:
+  case TPOC_Call: {
     if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(),
                                 Args1.data(), Args1.size(), Info, Deduced,
                                 TDF_None, /*PartialOrdering=*/true) !=
         TemplateDeductionResult::Success)
       return false;
 
-    break;
+    SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
+                                                 Deduced.end());
+    Sema::InstantiatingTemplate Inst(
+        S, Info.getLocation(), FT2, DeducedArgs,
+        Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info);
+    if (Inst.isInvalid())
+      return false;
 
-  case TPOC_Conversion:
+    bool AtLeastAsSpecialized = true;
+    S.runWithSufficientStackSpace(Info.getLocation(), [&] {
+      AtLeastAsSpecialized =
+          ::DeduceForEachType(
+              S, TemplateParams, Args2.data(), Args2.size(), Args1.data(),
+              Args1.size(), Info, Deduced,
+              /*PartialOrdering=*/true, /*FinishingDeduction=*/true,
+              [&FT2](Sema &S, TemplateParameterList *, int ArgIdx, QualType P,
+                     QualType A, TemplateDeductionInfo &Info,
+                     SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+                     bool PartialOrdering) {
+                return ::FinishTemplateArgumentDeduction(S, FT2, ArgIdx, P, A,
+                                                         Deduced, Info);
+              }) == TemplateDeductionResult::Success;
+    });
+    if (!AtLeastAsSpecialized)
+      return false;
+  } break;
+
+  case TPOC_Conversion: {
     //   - In the context of a call to a conversion operator, the return types
     //     of the conversion function templates are used.
     if (DeduceTemplateArgumentsByTypeMatch(
             S, TemplateParams, Proto2->getReturnType(), 
Proto1->getReturnType(),
             Info, Deduced, TDF_None,
             /*PartialOrdering=*/true) != TemplateDeductionResult::Success)
       return false;
-    break;
 
-  case TPOC_Other:
+    SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
+                                                 Deduced.end());
+    Sema::InstantiatingTemplate Inst(
+        S, Info.getLocation(), FT2, DeducedArgs,
+        Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info);
+    if (Inst.isInvalid())
+      return false;
+
+    bool AtLeastAsSpecialized;
+    S.runWithSufficientStackSpace(Info.getLocation(), [&] {
+      AtLeastAsSpecialized = ::FinishTemplateArgumentDeduction(
+                                 S, FT2, /*ArgIdx=*/-1, 
Proto2->getReturnType(),
+                                 Proto1->getReturnType(), Deduced,
+                                 Info) == TemplateDeductionResult::Success;
+    });
+    if (!AtLeastAsSpecialized)
+      return false;
+  } break;
+
+  case TPOC_Other: {
     //   - In other contexts (14.6.6.2) the function template's function type
     //     is used.
     if (DeduceTemplateArgumentsByTypeMatch(
             S, TemplateParams, FD2->getType(), FD1->getType(), Info, Deduced,
             TDF_AllowCompatibleFunctionType,
             /*PartialOrdering=*/true) != TemplateDeductionResult::Success)
       return false;
-    break;
+
+    SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),
+                                                 Deduced.end());
+    Sema::InstantiatingTemplate Inst(
+        S, Info.getLocation(), FT2, DeducedArgs,
+        Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info);
+    if (Inst.isInvalid())
+      return false;
+
+    bool AtLeastAsSpecialized;
+    S.runWithSufficientStackSpace(Info.getLocation(), [&] {
+      AtLeastAsSpecialized = ::FinishTemplateArgumentDeduction(
+                                 S, FT2, /*ArgIdx=*/-1, 
Proto2->getReturnType(),
+                                 Proto1->getReturnType(), Deduced,
+                                 Info) == TemplateDeductionResult::Success;
+      if (!AtLeastAsSpecialized)
+        return;
+      S.runWithSufficientStackSpace(Info.getLocation(), [&] {
+        AtLeastAsSpecialized =
+            ::DeduceForEachType(
+                S, TemplateParams, Proto2->getParamTypes().data(),
+                Proto2->getParamTypes().size(), Proto1->getParamTypes().data(),
+                Proto1->getParamTypes().size(), Info, Deduced,
+                /*PartialOrdering=*/true, /*FinishingDeduction=*/true,
+                [&FT2](Sema &S, TemplateParameterList *, int ArgIdx, QualType 
P,
+                       QualType A, TemplateDeductionInfo &Info,
+                       SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+                       bool PartialOrdering) {
+                  return ::FinishTemplateArgumentDeduction(S, FT2, ArgIdx, P, 
A,
+                                                           Deduced, Info);
+                }) == TemplateDeductionResult::Success;
+      });
+    });
----------------
mizvekov wrote:

Since the deduction itself ignores the exception specification 
(`TDF_AllowCompatibleFunctionType`), it would seem strange to check exception 
spec compatibility now, when we could have done that during deduction.

Otherwise, this would fail the first example in `ExplicitArgs` from 
`CXX/temp/temp.fct.spec/temp.deduct/temp.deduct.partial/p3.cpp`:
```C++
namespace ExplicitArgs {
  template<typename T, typename U>
  constexpr int f(U) noexcept(noexcept(T())) {
    return 0;
  }

  template<typename T>
  constexpr int f(T*) noexcept {
    return 1;
  }

  template<>
  constexpr int f<int>(int*) noexcept {
    return 2;
  }

  static_assert(f<int>(1) == 0);
  static_assert(f<short>(y) == 1);
  static_assert(f<int>(x) == 2);
```

But also otherwise, we would not handle packs correctly.
See temp_deduct_type_example3 in `CXX/CXX/drs/cwg6xx.cpp`

```C++
   template<class T, class... U> void f(T*, U...){}
    template<class T> void f(T){}
    template void f(int*);
```
We would fail the consistency check as we would get A = `void (T)`, InstP = 
`void (T, U...)` if I remember right.

https://github.com/llvm/llvm-project/pull/100692
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to