[clang] dd0fba1 - [clang][Sema] Use original template pattern when declaring implicit deduction guides for nested template classes (#68379)

via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 16 12:17:40 PDT 2023


Author: antangelo
Date: 2023-10-16T15:17:36-04:00
New Revision: dd0fba11690f9fef304d5f48cde646e5eca8d3c0

URL: https://github.com/llvm/llvm-project/commit/dd0fba11690f9fef304d5f48cde646e5eca8d3c0
DIFF: https://github.com/llvm/llvm-project/commit/dd0fba11690f9fef304d5f48cde646e5eca8d3c0.diff

LOG: [clang][Sema] Use original template pattern when declaring implicit deduction guides for nested template classes (#68379)

When a nested template is instantiated, the template pattern of the
inner class is not copied into the outer class
ClassTemplateSpecializationDecl. The specialization contains a
ClassTemplateDecl with an empty record that points to the original
template pattern instead.

As a result, when looking up the constructors of the inner class, no
results are returned. This patch finds the original template pattern and
uses that for the lookup instead.

Based on CWG2471 we must also substitute the known outer template
arguments when creating deduction guides for the inner class.

Fixes #46200
Fixes #57812

Added: 
    clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaTemplate.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 58c06edb6deeaf8..ff66d2c272098c8 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -513,6 +513,11 @@ Bug Fixes to C++ Support
   rather than prefer the non-templated constructor as specified in
   [standard.group]p3.
 
+- Fix a bug where implicit deduction guides are not correctly generated for nested template
+  classes. Fixes:
+  (`#46200 <https://github.com/llvm/llvm-project/issues/46200>`_)
+  (`#57812 <https://github.com/llvm/llvm-project/issues/57812>`_)
+
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
 - Fixed an import failure of recursive friend class template.

diff  --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index ff370dd1e080b2b..fba5b2213917065 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2250,6 +2250,7 @@ struct ConvertConstructorToDeductionGuideTransform {
 
   Sema &SemaRef;
   ClassTemplateDecl *Template;
+  ClassTemplateDecl *NestedPattern = nullptr;
 
   DeclContext *DC = Template->getDeclContext();
   CXXRecordDecl *Primary = Template->getTemplatedDecl();
@@ -2327,6 +2328,8 @@ struct ConvertConstructorToDeductionGuideTransform {
     if (FTD) {
       Args.addOuterTemplateArguments(SubstArgs);
       Args.addOuterRetainedLevel();
+      if (NestedPattern)
+        Args.addOuterRetainedLevels(NestedPattern->getTemplateDepth());
     }
 
     FunctionProtoTypeLoc FPTL = CD->getTypeSourceInfo()->getTypeLoc()
@@ -2438,10 +2441,17 @@ struct ConvertConstructorToDeductionGuideTransform {
     SmallVector<QualType, 4> ParamTypes;
     const FunctionProtoType *T = TL.getTypePtr();
 
+    MultiLevelTemplateArgumentList OuterInstantiationArgs;
+    if (NestedPattern)
+      OuterInstantiationArgs = SemaRef.getTemplateInstantiationArgs(Template);
+
     //    -- The types of the function parameters are those of the constructor.
     for (auto *OldParam : TL.getParams()) {
       ParmVarDecl *NewParam =
           transformFunctionTypeParam(OldParam, Args, MaterializedTypedefs);
+      if (NestedPattern && NewParam)
+        NewParam = transformFunctionTypeParam(NewParam, OuterInstantiationArgs,
+                                              MaterializedTypedefs);
       if (!NewParam)
         return QualType();
       ParamTypes.push_back(NewParam->getType());
@@ -2647,13 +2657,23 @@ void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,
   if (BuildingDeductionGuides.isInvalid())
     return;
 
+  // If the template is nested, then we need to use the original
+  // pattern to iterate over the constructors.
+  ClassTemplateDecl *Pattern = Transform.Template;
+  while (Pattern->getInstantiatedFromMemberTemplate()) {
+    if (Pattern->isMemberSpecialization())
+      break;
+    Pattern = Pattern->getInstantiatedFromMemberTemplate();
+    Transform.NestedPattern = Pattern;
+  }
+
   // Convert declared constructors into deduction guide templates.
   // FIXME: Skip constructors for which deduction must necessarily fail (those
   // for which some class template parameter without a default argument never
   // appears in a deduced context).
   llvm::SmallPtrSet<NamedDecl *, 8> ProcessedCtors;
   bool AddedAny = false;
-  for (NamedDecl *D : LookupConstructors(Transform.Primary)) {
+  for (NamedDecl *D : LookupConstructors(Pattern->getTemplatedDecl())) {
     D = D->getUnderlyingDecl();
     if (D->isInvalidDecl() || D->isImplicit())
       continue;

diff  --git a/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp b/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
new file mode 100644
index 000000000000000..4915c687cf4c4ef
--- /dev/null
+++ b/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -std=c++17 -verify %s
+// expected-no-diagnostics
+
+template<class T> struct S {
+    template<class U> struct N {
+        N(T) {}
+        N(T, U) {}
+        template<class V> N(V, U) {}
+    };
+};
+
+S<int>::N x{"a", 1};


        


More information about the cfe-commits mailing list