Skip to content

[clang] remove unneeded template deduction canonicalizations #101594

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 4, 2024

Conversation

mizvekov
Copy link
Contributor

@mizvekov mizvekov commented Aug 2, 2024

This is mostly a cleanups patch, with some hard to observe sugar preservation improvements.

Except for the function template deduction changes which improve some pre-existing diagnostics a little bit.

@mizvekov mizvekov self-assigned this Aug 2, 2024
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Aug 2, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 2, 2024

@llvm/pr-subscribers-clang

Author: Matheus Izvekov (mizvekov)

Changes

This is mostly a cleanups patch, with some hard to observe sugar preservation improvements.

Except for the function template deduction changes which improve some pre-existing diagnostics a little bit.


Full diff: https://github.com/llvm/llvm-project/pull/101594.diff

4 Files Affected:

  • (modified) clang/lib/Sema/SemaTemplate.cpp (+2-2)
  • (modified) clang/lib/Sema/SemaTemplateDeduction.cpp (+31-55)
  • (modified) clang/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp (+4-4)
  • (modified) clang/test/SemaCXX/cxx1y-generic-lambdas.cpp (+2-2)
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index c22e329bef2b9..cb16e8caa9a8a 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -4202,7 +4202,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
     TemplateDeductionInfo Info(FailedCandidates.getLocation());
 
     if (TemplateDeductionResult Result =
-            DeduceTemplateArguments(Partial, CanonicalConverted, Info);
+            DeduceTemplateArguments(Partial, SugaredConverted, Info);
         Result != TemplateDeductionResult::Success) {
       // Store the failed-deduction information for use in diagnostics, later.
       // TODO: Actually use the failed-deduction info?
@@ -4213,7 +4213,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
     } else {
       Matched.push_back(PartialSpecMatchResult());
       Matched.back().Partial = Partial;
-      Matched.back().Args = Info.takeCanonical();
+      Matched.back().Args = Info.takeSugared();
     }
   }
 
diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp
index db7f233dcef73..eeeb780299e78 100644
--- a/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -503,7 +503,6 @@ static TemplateDeductionResult DeduceNonTypeTemplateArgument(
     const NonTypeTemplateParmDecl *NTTP, ValueDecl *D, QualType T,
     TemplateDeductionInfo &Info,
     SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
-  D = D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr;
   TemplateArgument New(D, T);
   return DeduceNonTypeTemplateArgument(
       S, TemplateParams, NTTP, DeducedTemplateArgument(New), T, Info, Deduced);
@@ -1380,11 +1379,6 @@ static bool isForwardingReference(QualType Param, unsigned FirstInnerIndex) {
   return false;
 }
 
-static CXXRecordDecl *getCanonicalRD(QualType T) {
-  return cast<CXXRecordDecl>(
-      T->castAs<RecordType>()->getDecl()->getCanonicalDecl());
-}
-
 ///  Attempt to deduce the template arguments by checking the base types
 ///  according to (C++20 [temp.deduct.call] p4b3.
 ///
@@ -1439,7 +1433,7 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
     for (const auto &Base : RD->bases()) {
       QualType T = Base.getType();
       assert(T->isRecordType() && "Base class that isn't a record?");
-      if (Visited.insert(::getCanonicalRD(T)).second)
+      if (Visited.insert(T->getAsCXXRecordDecl()).second)
         ToVisit.push_back(T);
     }
   };
@@ -1460,7 +1454,7 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
 
     // If this was a successful deduction, add it to the list of matches,
     // otherwise we need to continue searching its bases.
-    const CXXRecordDecl *RD = ::getCanonicalRD(NextT);
+    const CXXRecordDecl *RD = NextT->getAsCXXRecordDecl();
     if (BaseResult == TemplateDeductionResult::Success)
       Matches.insert({RD, DeducedCopy});
     else
@@ -1481,7 +1475,7 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD,
     // We can give up once we have a single item (or have run out of things to
     // search) since cyclical inheritance isn't valid.
     while (Matches.size() > 1 && !ToVisit.empty()) {
-      const CXXRecordDecl *RD = ::getCanonicalRD(ToVisit.pop_back_val());
+      const CXXRecordDecl *RD = ToVisit.pop_back_val()->getAsCXXRecordDecl();
       Matches.erase(RD);
 
       // Always add all bases, since the inheritance tree can contain
@@ -2030,15 +2024,16 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
       if (!S.isCompleteType(Info.getLocation(), A))
         return Result;
 
-      if (getCanonicalRD(A)->isInvalidDecl())
+      const CXXRecordDecl *RD = A->getAsCXXRecordDecl();
+      if (RD->isInvalidDecl())
         return Result;
 
       // Reset the incorrectly deduced argument from above.
       Deduced = DeducedOrig;
 
       // Check bases according to C++14 [temp.deduct.call] p4b3:
-      auto BaseResult = DeduceTemplateBases(S, getCanonicalRD(A),
-                                            TemplateParams, P, Info, Deduced);
+      auto BaseResult =
+          DeduceTemplateBases(S, RD, TemplateParams, P, Info, Deduced);
       return BaseResult != TemplateDeductionResult::Invalid ? BaseResult
                                                             : Result;
     }
@@ -3369,9 +3364,7 @@ Sema::DeduceTemplateArgumentsFromType(TemplateDecl *TD, QualType FromType,
     // Use the InjectedClassNameType.
     PType = Context.getTypeDeclType(CTD->getTemplatedDecl());
   } else if (const auto *AliasTemplate = dyn_cast<TypeAliasTemplateDecl>(TD)) {
-    PType = AliasTemplate->getTemplatedDecl()
-                ->getUnderlyingType()
-                .getCanonicalType();
+    PType = AliasTemplate->getTemplatedDecl()->getUnderlyingType();
   } else {
     assert(false && "Expected a class or alias template");
   }
@@ -3505,15 +3498,15 @@ TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments(
   // the explicit template arguments. They'll be used as part of deduction
   // for this template parameter pack.
   unsigned PartiallySubstitutedPackIndex = -1u;
-  if (!CanonicalBuilder.empty()) {
-    const TemplateArgument &Arg = CanonicalBuilder.back();
+  if (!SugaredBuilder.empty()) {
+    const TemplateArgument &Arg = SugaredBuilder.back();
     if (Arg.getKind() == TemplateArgument::Pack) {
-      auto *Param = TemplateParams->getParam(CanonicalBuilder.size() - 1);
+      auto *Param = TemplateParams->getParam(SugaredBuilder.size() - 1);
       // If this is a fully-saturated fixed-size pack, it should be
       // fully-substituted, not partially-substituted.
       std::optional<unsigned> Expansions = getExpandedPackSize(Param);
       if (!Expansions || Arg.pack_size() < *Expansions) {
-        PartiallySubstitutedPackIndex = CanonicalBuilder.size() - 1;
+        PartiallySubstitutedPackIndex = SugaredBuilder.size() - 1;
         CurrentInstantiationScope->SetPartiallySubstitutedPack(
             Param, Arg.pack_begin(), Arg.pack_size());
       }
@@ -3890,8 +3883,8 @@ TemplateDeductionResult Sema::FinishTemplateArgumentDeduction(
   if (!Specialization || Specialization->isInvalidDecl())
     return TemplateDeductionResult::SubstitutionFailure;
 
-  assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() ==
-         FunctionTemplate->getCanonicalDecl());
+  assert(isSameDeclaration(Specialization->getPrimaryTemplate(),
+                           FunctionTemplate));
 
   // If the template argument list is owned by the function template
   // specialization, release it.
@@ -4736,8 +4729,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
   // types, template argument deduction fails.
   if (!ArgFunctionType.isNull()) {
     if (IsAddressOfFunction ? !isSameOrCompatibleFunctionType(
-                                  Context.getCanonicalType(SpecializationType),
-                                  Context.getCanonicalType(ArgFunctionType))
+                                  SpecializationType, ArgFunctionType)
                             : !Context.hasSameFunctionTypeIgnoringExceptionSpec(
                                   SpecializationType, ArgFunctionType)) {
       Info.FirstArg = TemplateArgument(SpecializationType);
@@ -4751,7 +4743,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
 
 TemplateDeductionResult Sema::DeduceTemplateArguments(
     FunctionTemplateDecl *ConversionTemplate, QualType ObjectType,
-    Expr::Classification ObjectClassification, QualType ToType,
+    Expr::Classification ObjectClassification, QualType A,
     CXXConversionDecl *&Specialization, TemplateDeductionInfo &Info) {
   if (ConversionTemplate->isInvalidDecl())
     return TemplateDeductionResult::Invalid;
@@ -4759,11 +4751,8 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
   CXXConversionDecl *ConversionGeneric
     = cast<CXXConversionDecl>(ConversionTemplate->getTemplatedDecl());
 
-  QualType FromType = ConversionGeneric->getConversionType();
-
-  // Canonicalize the types for deduction.
-  QualType P = Context.getCanonicalType(FromType);
-  QualType A = Context.getCanonicalType(ToType);
+  QualType P = ConversionGeneric->getConversionType();
+  bool IsReferenceP = P->isReferenceType(), IsReferenceA = A->isReferenceType();
 
   // C++0x [temp.deduct.conv]p2:
   //   If P is a reference type, the type referred to by P is used for
@@ -4779,7 +4768,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
     // We work around a defect in the standard here: cv-qualifiers are also
     // removed from P and A in this case, unless P was a reference type. This
     // seems to mostly match what other compilers are doing.
-    if (!FromType->getAs<ReferenceType>()) {
+    if (!IsReferenceP) {
       A = A.getUnqualifiedType();
       P = P.getUnqualifiedType();
     }
@@ -4835,7 +4824,7 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
   //     - If the original A is a reference type, A can be more
   //       cv-qualified than the deduced A (i.e., the type referred to
   //       by the reference)
-  if (ToType->isReferenceType())
+  if (IsReferenceA)
     TDF |= TDF_ArgWithReferenceType;
   //     - The deduced A can be another pointer or pointer to member
   //       type that can be converted to A via a qualification
@@ -5736,17 +5725,6 @@ FunctionTemplateDecl *Sema::getMoreSpecializedTemplate(
   return AtLeastAsConstrained1 ? FT1 : FT2;
 }
 
-/// Determine if the two templates are equivalent.
-static bool isSameTemplate(TemplateDecl *T1, TemplateDecl *T2) {
-  if (T1 == T2)
-    return true;
-
-  if (!T1 || !T2)
-    return false;
-
-  return T1->getCanonicalDecl() == T2->getCanonicalDecl();
-}
-
 UnresolvedSetIterator Sema::getMostSpecialized(
     UnresolvedSetIterator SpecBegin, UnresolvedSetIterator SpecEnd,
     TemplateSpecCandidateSet &FailedCandidates,
@@ -5774,9 +5752,9 @@ UnresolvedSetIterator Sema::getMostSpecialized(
     FunctionTemplateDecl *Challenger
       = cast<FunctionDecl>(*I)->getPrimaryTemplate();
     assert(Challenger && "Not a function template specialization?");
-    if (isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger, Loc,
-                                                  TPOC_Other, 0),
-                       Challenger)) {
+    if (declaresSameEntity(getMoreSpecializedTemplate(BestTemplate, Challenger,
+                                                      Loc, TPOC_Other, 0),
+                           Challenger)) {
       Best = I;
       BestTemplate = Challenger;
     }
@@ -5789,9 +5767,9 @@ UnresolvedSetIterator Sema::getMostSpecialized(
     FunctionTemplateDecl *Challenger
       = cast<FunctionDecl>(*I)->getPrimaryTemplate();
     if (I != Best &&
-        !isSameTemplate(getMoreSpecializedTemplate(BestTemplate, Challenger,
-                                                   Loc, TPOC_Other, 0),
-                        BestTemplate)) {
+        !declaresSameEntity(getMoreSpecializedTemplate(BestTemplate, Challenger,
+                                                       Loc, TPOC_Other, 0),
+                            BestTemplate)) {
       Ambiguous = true;
       break;
     }
@@ -6116,11 +6094,10 @@ Sema::getMoreSpecializedPartialSpecialization(
          "the partial specializations being compared should specialize"
          " the same template.");
   TemplateName Name(PS1->getSpecializedTemplate());
-  TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
   QualType PT1 = Context.getTemplateSpecializationType(
-      CanonTemplate, PS1->getTemplateArgs().asArray());
+      Name, PS1->getTemplateArgs().asArray());
   QualType PT2 = Context.getTemplateSpecializationType(
-      CanonTemplate, PS2->getTemplateArgs().asArray());
+      Name, PS2->getTemplateArgs().asArray());
 
   TemplateDeductionInfo Info(Loc);
   return getMoreSpecialized(*this, PT1, PT2, PS1, PS2, Info);
@@ -6129,12 +6106,11 @@ Sema::getMoreSpecializedPartialSpecialization(
 bool Sema::isMoreSpecializedThanPrimary(
     VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) {
   VarTemplateDecl *Primary = Spec->getSpecializedTemplate();
-  TemplateName CanonTemplate =
-      Context.getCanonicalTemplateName(TemplateName(Primary));
+  TemplateName Name(Primary);
   QualType PrimaryT = Context.getTemplateSpecializationType(
-      CanonTemplate, Primary->getInjectedTemplateArgs());
+      Name, Primary->getInjectedTemplateArgs());
   QualType PartialT = Context.getTemplateSpecializationType(
-      CanonTemplate, Spec->getTemplateArgs().asArray());
+      Name, Spec->getTemplateArgs().asArray());
 
   VarTemplatePartialSpecializationDecl *MaybeSpec =
       getMoreSpecialized(*this, PartialT, PrimaryT, Spec, Primary, Info);
diff --git a/clang/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp b/clang/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp
index f38fb2c6d71e7..a3464d6668178 100644
--- a/clang/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp
+++ b/clang/test/SemaCXX/cxx1y-generic-lambdas-variadics.cpp
@@ -16,7 +16,7 @@ struct X { };
 struct Y { };
 struct Z { };
 
-int test() { 
+int test() {
   {
     auto L = [](auto ... as) { };
     L.operator()<bool>(true);
@@ -36,7 +36,7 @@ int test() {
   {
     auto L = [](auto a, auto b, auto ... cs) { };
     L.operator()<bool, char>(false, 'a');
-    L.operator()<bool, char, const char*>(false, 'a', "jim");    
+    L.operator()<bool, char, const char*>(false, 'a', "jim");
   }
 
   {
@@ -77,7 +77,7 @@ int test() {
     M(6.26, "jim", true);
     M.operator()<X>(6.26, "jim", false, X{}, Y{}, Z{});
   }
-  
+
   return 0;
 }
  int run = test();
@@ -106,7 +106,7 @@ namespace PR33082 {
   template<int ...I> void a() {
     int arr[] = { [](auto ...K) { (void)I; } ... };
     // expected-error@-1   {{no viable conversion}}
-    // expected-note-re@-2 {{candidate template ignored: could not match 'auto (*)(type-parameter-0-0...){{.*}}' against 'int'}}
+    // expected-note-re@-2 {{candidate template ignored: could not match 'auto (*)(auto...){{.*}}' against 'int'}}
   }
 
   template<typename ...T> struct Pack {};
diff --git a/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp b/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
index 22765542b1aa0..3066bb0d0f0cc 100644
--- a/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
+++ b/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
@@ -217,7 +217,7 @@ namespace conversion_operator {
     int (&fp2)(int) = [](auto a) { return a; };  // expected-error{{non-const lvalue}}
     int (&&fp3)(int) = [](auto a) { return a; };
     // expected-error@-1   {{no viable conversion}}
-    // expected-note-re@-2 {{candidate template ignored: could not match 'auto (*)(type-parameter-0-0){{.*}}' against 'int (int)'}}
+    // expected-note-re@-2 {{candidate template ignored: could not match 'auto (*)(auto){{.*}}' against 'int (int)'}}
 
     using F = int(int);
     using G = int(void*);
@@ -293,7 +293,7 @@ int test() {
     print("a = ", a, "\n");
     return [](auto b) ->decltype(a) {
       // expected-error@-1   {{no viable conversion}}
-      // expected-note-re@-2 {{candidate template ignored: could not match 'int (*)(type-parameter-0-0){{.*}}' against 'int'}}
+      // expected-note-re@-2 {{candidate template ignored: could not match 'auto (*)(auto){{.*}}' ({{.*}}) against 'decltype(a)' (aka 'int')}}
       print("b = ", b, "\n");
       return b;
     };

@mizvekov mizvekov changed the base branch from main to users/mizvekov/clang-fix-GH60336 August 3, 2024 02:16
@mizvekov mizvekov force-pushed the users/mizvekov/clang-deduction-improvements branch from 074e6fa to 86c6801 Compare August 3, 2024 02:16
@mizvekov mizvekov requested a review from zyn0217 August 3, 2024 03:41
Copy link
Contributor

@cor3ntin cor3ntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM modulo nit

@mizvekov mizvekov force-pushed the users/mizvekov/clang-fix-GH60336 branch from 5fa1cc6 to 56c022e Compare August 4, 2024 21:23
Base automatically changed from users/mizvekov/clang-fix-GH60336 to main August 4, 2024 22:00
This is mostly a cleanups patch, with some hard to observe
sugar preservation improvements.

Except for the function template deduction changes
which improve some pre-existing diagnostics a little bit.
@mizvekov mizvekov force-pushed the users/mizvekov/clang-deduction-improvements branch from 86c6801 to fd9bdcc Compare August 4, 2024 22:03
@mizvekov mizvekov merged commit 8a26c6d into main Aug 4, 2024
7 checks passed
@mizvekov mizvekov deleted the users/mizvekov/clang-deduction-improvements branch August 4, 2024 22:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants