Skip to content

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

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 5 commits into from
Jul 11, 2024

Conversation

hokein
Copy link
Collaborator

@hokein hokein commented Jul 8, 2024

As described in #90209 (comment), 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

@hokein hokein requested review from mizvekov and zyn0217 July 8, 2024 11:25
@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" labels Jul 8, 2024
@llvmbot
Copy link
Member

llvmbot commented Jul 8, 2024

@llvm/pr-subscribers-clang

Author: Haojian Wu (hokein)

Changes

As described in #90209 (comment), 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


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

2 Files Affected:

  • (modified) clang/lib/Sema/SemaTemplate.cpp (+23-8)
  • (modified) clang/test/AST/ast-dump-ctad-alias.cpp (+25)
diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 07b3f793b3a29..46be2e90df847 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 6f07a62e9a069..adccad97a205b 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

Copy link

github-actions bot commented Jul 8, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

// CHECK: FunctionTemplateDecl {{.*}} <deduction guide for ATemplatedClass>
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} class depth 0 index 0 T2
// CHECK-NEXT: |-TypeTraitExpr {{.*}} 'bool' __is_deducible
} // namespace GH90209
Copy link
Contributor

Choose a reason for hiding this comment

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

Minor nit: there is now a missing newline at end of file

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done.

Copy link
Contributor

Choose a reason for hiding this comment

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

The GitHub editor still shows the missing newline at end of file marker.

Comment on lines 2673 to 2675
// 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.
Copy link
Contributor

Choose a reason for hiding this comment

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

I would remove this section of the comment, as I think this sort of implies it would be ok to use the type sugar if it were available, but if we rely on this for correct compilation of the program, it doesn't make sense to call it type sugar anymore.

Suggested change
// 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.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done.

@hokein hokein force-pushed the fix-ctad-template-ref branch from 1b4a711 to 7626982 Compare July 11, 2024 09:10
Copy link
Collaborator Author

@hokein hokein left a comment

Choose a reason for hiding this comment

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

Thanks for the review.

Comment on lines 2673 to 2675
// 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.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done.

// CHECK: FunctionTemplateDecl {{.*}} <deduction guide for ATemplatedClass>
// CHECK-NEXT: |-TemplateTypeParmDecl {{.*}} class depth 0 index 0 T2
// CHECK-NEXT: |-TypeTraitExpr {{.*}} 'bool' __is_deducible
} // namespace GH90209
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done.

Copy link
Contributor

@mizvekov mizvekov left a comment

Choose a reason for hiding this comment

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

LGTM, sans:

  • missing newline at end of test file
  • A similar test for template template parameter.

@hokein hokein merged commit 8b7263b into llvm:main Jul 11, 2024
5 of 6 checks passed
@hokein hokein deleted the fix-ctad-template-ref branch July 11, 2024 14:03
aaryanshukla pushed a commit to aaryanshukla/llvm-project that referenced this pull request Jul 14, 2024
…TemplateParamsReferencedInTemplateArgumentList (llvm#98013)

As described in llvm#90209 (comment),
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 llvm#90209
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.

CTAD: parameter pack assertion crash when synthesizing deduction guides for alias
3 participants