[clang] [clang] CTAD: use index and depth to retrieve template parameter for TemplateParamsReferencedInTemplateArgumentList (PR #98013)

Haojian Wu via cfe-commits cfe-commits at lists.llvm.org
Mon Jul 8 04:25:50 PDT 2024


https://github.com/hokein created https://github.com/llvm/llvm-project/pull/98013

As described in https://github.com/llvm/llvm-project/issues/90209#issuecomment-2135972202, Clang may not preserve enough information during template argument deduction. This can result in a merely canonical `TemplateTypeParmType` with a null `Decl`, leading to an incomplete template parameter list for the synthesized deduction guide.

This patch addresses the issue by using the index and depth information to retrieve the corresponding template parameter, rather than relying on `TTP->getDecl()`.

Fixes #90209

>From 1b4a711ebe32879608026007de7fc373d44fbcf4 Mon Sep 17 00:00:00 2001
From: Haojian Wu <hokein.wu at gmail.com>
Date: Mon, 8 Jul 2024 13:19:13 +0200
Subject: [PATCH] [clang] CTAD: use index and depth to retrieve template
 parameters in TemplateParamsReferencedInTemplateArgumentList.

---
 clang/lib/Sema/SemaTemplate.cpp        | 31 +++++++++++++++++++-------
 clang/test/AST/ast-dump-ctad-alias.cpp | 25 +++++++++++++++++++++
 2 files changed, 48 insertions(+), 8 deletions(-)

diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 07b3f793b3a29d..46be2e90df847f 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2653,20 +2653,34 @@ struct ConvertConstructorToDeductionGuideTransform {
 // Find all template parameters that appear in the given DeducedArgs.
 // Return the indices of the template parameters in the TemplateParams.
 SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList(
-    ArrayRef<NamedDecl *> TemplateParams,
+    const TemplateParameterList* TemplateParamsList,
     ArrayRef<TemplateArgument> DeducedArgs) {
   struct TemplateParamsReferencedFinder
       : public RecursiveASTVisitor<TemplateParamsReferencedFinder> {
+    const TemplateParameterList* TemplateParamList;
     llvm::DenseSet<NamedDecl *> TemplateParams;
     llvm::DenseSet<const NamedDecl *> ReferencedTemplateParams;
 
-    TemplateParamsReferencedFinder(ArrayRef<NamedDecl *> TemplateParams)
-        : TemplateParams(TemplateParams.begin(), TemplateParams.end()) {}
+    TemplateParamsReferencedFinder(
+        const TemplateParameterList *TemplateParamList)
+        : TemplateParamList(TemplateParamList),
+          TemplateParams(TemplateParamList->begin(), TemplateParamList->end()) {
+    }
 
     bool VisitTemplateTypeParmType(TemplateTypeParmType *TTP) {
-      MarkAppeared(TTP->getDecl());
+      // We use the index and depth to retrieve the corresponding template
+      // parameter from the parameter list.
+      // Note that Clang may not preserve type sugar during template argument
+      // deduction. In such cases, the TTP is a canonical TemplateTypeParamType,
+      // which only retains its index and depth information.
+      if (TTP->getDepth() == TemplateParamList->getDepth() &&
+          TTP->getIndex() < TemplateParamList->size()) {
+        ReferencedTemplateParams.insert(
+            TemplateParamList->getParam(TTP->getIndex()));
+      }
       return true;
     }
+
     bool VisitDeclRefExpr(DeclRefExpr *DRE) {
       MarkAppeared(DRE->getFoundDecl());
       return true;
@@ -2683,12 +2697,13 @@ SmallVector<unsigned> TemplateParamsReferencedInTemplateArgumentList(
         ReferencedTemplateParams.insert(ND);
     }
   };
-  TemplateParamsReferencedFinder Finder(TemplateParams);
+  TemplateParamsReferencedFinder Finder(TemplateParamsList);
   Finder.TraverseTemplateArguments(DeducedArgs);
 
   SmallVector<unsigned> Results;
-  for (unsigned Index = 0; Index < TemplateParams.size(); ++Index) {
-    if (Finder.ReferencedTemplateParams.contains(TemplateParams[Index]))
+  for (unsigned Index = 0; Index < TemplateParamsList->size(); ++Index) {
+    if (Finder.ReferencedTemplateParams.contains(
+            TemplateParamsList->getParam(Index)))
       Results.push_back(Index);
   }
   return Results;
@@ -3047,7 +3062,7 @@ BuildDeductionGuideForTypeAlias(Sema &SemaRef,
   }
   auto DeducedAliasTemplateParams =
       TemplateParamsReferencedInTemplateArgumentList(
-          AliasTemplate->getTemplateParameters()->asArray(), DeducedArgs);
+          AliasTemplate->getTemplateParameters(), DeducedArgs);
   // All template arguments null by default.
   SmallVector<TemplateArgument> TemplateArgsForBuildingFPrime(
       F->getTemplateParameters()->size());
diff --git a/clang/test/AST/ast-dump-ctad-alias.cpp b/clang/test/AST/ast-dump-ctad-alias.cpp
index 6f07a62e9a0691..adccad97a205b4 100644
--- a/clang/test/AST/ast-dump-ctad-alias.cpp
+++ b/clang/test/AST/ast-dump-ctad-alias.cpp
@@ -99,3 +99,28 @@ BFoo b2(1.0, 2.0);
 // CHECK-NEXT: | | |-ParmVarDecl {{.*}} 'type-parameter-0-0'
 // CHECK-NEXT: | | `-ParmVarDecl {{.*}} 'type-parameter-0-0'
 // CHECK-NEXT: | `-CXXDeductionGuideDecl {{.*}} implicit used <deduction guide for BFoo> 'auto (double, double) -> Foo<double, double>' implicit_instantiation
+
+namespace GH90209 {
+template <class Ts>
+struct List {
+  List(int);
+};
+
+template <class T1>
+struct TemplatedClass {
+  TemplatedClass(T1);
+};
+
+template <class T1>
+TemplatedClass(T1) -> TemplatedClass<List<T1>>;
+
+template <class T2>
+using ATemplatedClass = TemplatedClass<List<T2>>;
+
+ATemplatedClass test(1);
+// Verify that we have a correct template parameter list for the deduction guide.
+//
+// CHECK:      FunctionTemplateDecl {{.*}} <deduction guide for ATemplatedClass>
+// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} class depth 0 index 0 T2
+// CHECK-NEXT: |-TypeTraitExpr {{.*}} 'bool' __is_deducible
+} // namespace GH90209
\ No newline at end of file



More information about the cfe-commits mailing list