[clang] [clang-tools-extra] [clang] check deduction consistency when partial ordering function templates (PR #100692)
Matheus Izvekov via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 26 12:10:06 PDT 2024
================
@@ -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
More information about the cfe-commits
mailing list