[clang] b3ea9b3 - Reland "[clang] Fix CTAD for aggregates for nested template classes" (#78670)

via cfe-commits cfe-commits at lists.llvm.org
Fri Jan 19 20:06:49 PST 2024


Author: antangelo
Date: 2024-01-19T23:06:44-05:00
New Revision: b3ea9b398fe656fab5d78d6b2c58bba975badc07

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

LOG: Reland "[clang] Fix CTAD for aggregates for nested template classes" (#78670)

Reland of #78387

Use the template pattern in determining whether to synthesize the
aggregate deduction guide, and update
DeclareImplicitDeductionGuideFromInitList to substitute outer template
arguments.

The tests in the original patch made an assumption about the size of a
pointer type, and this led to them failing on targets with 32-bit
pointers. The tests have been updated to not depend on the size of any
type. This only requires updates to the test file, no functionality has
otherwise changed between this and the original patch.

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaInit.cpp
    clang/lib/Sema/SemaTemplate.cpp
    clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 585e1535b15852..08e79984fe3362 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -1001,6 +1001,9 @@ Bug Fixes to C++ Support
 - Clang now allows parenthesized initialization of arrays in `operator new[]`.
   Fixes: (`#68198 <https://github.com/llvm/llvm-project/issues/68198>`_)
 
+- Fixes CTAD for aggregates on nested template classes. Fixes:
+  (`#77599 <https://github.com/llvm/llvm-project/issues/77599>`_)
+
 - Fix crash when importing the same module with an dynamic initializer twice
   in 
diff erent visibility.
   Fixes (`#67893 <https://github.com/llvm/llvm-project/issues/67893>`_)

diff  --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 3170f41e8033f2..91e4cb7b68a24a 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -10751,7 +10751,14 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
     bool HasAnyDeductionGuide = false;
 
     auto SynthesizeAggrGuide = [&](InitListExpr *ListInit) {
-      auto *RD = cast<CXXRecordDecl>(Template->getTemplatedDecl());
+      auto *Pattern = Template;
+      while (Pattern->getInstantiatedFromMemberTemplate()) {
+        if (Pattern->isMemberSpecialization())
+          break;
+        Pattern = Pattern->getInstantiatedFromMemberTemplate();
+      }
+
+      auto *RD = cast<CXXRecordDecl>(Pattern->getTemplatedDecl());
       if (!(RD->getDefinition() && RD->isAggregate()))
         return;
       QualType Ty = Context.getRecordType(RD);

diff  --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp
index 0655d363352067..839d508b911f06 100644
--- a/clang/lib/Sema/SemaTemplate.cpp
+++ b/clang/lib/Sema/SemaTemplate.cpp
@@ -2418,6 +2418,9 @@ struct ConvertConstructorToDeductionGuideTransform {
     QualType Result = SemaRef.BuildFunctionType(DeducedType, ParamTypes, Loc,
                                                 DeductionGuideName, EPI);
     TypeSourceInfo *TSI = SemaRef.Context.getTrivialTypeSourceInfo(Result, Loc);
+    if (NestedPattern)
+      TSI = SemaRef.SubstType(TSI, OuterInstantiationArgs, Loc,
+                              DeductionGuideName);
 
     FunctionProtoTypeLoc FPTL =
         TSI->getTypeLoc().castAs<FunctionProtoTypeLoc>();
@@ -2425,9 +2428,13 @@ struct ConvertConstructorToDeductionGuideTransform {
     // Build the parameters, needed during deduction / substitution.
     SmallVector<ParmVarDecl*, 4> Params;
     for (auto T : ParamTypes) {
-      ParmVarDecl *NewParam = ParmVarDecl::Create(
-          SemaRef.Context, DC, Loc, Loc, nullptr, T,
-          SemaRef.Context.getTrivialTypeSourceInfo(T, Loc), SC_None, nullptr);
+      auto *TSI = SemaRef.Context.getTrivialTypeSourceInfo(T, Loc);
+      if (NestedPattern)
+        TSI = SemaRef.SubstType(TSI, OuterInstantiationArgs, Loc,
+                                DeclarationName());
+      ParmVarDecl *NewParam =
+          ParmVarDecl::Create(SemaRef.Context, DC, Loc, Loc, nullptr,
+                              TSI->getType(), TSI, SC_None, nullptr);
       NewParam->setScopeInfo(0, Params.size());
       FPTL.setParam(Params.size(), NewParam);
       Params.push_back(NewParam);
@@ -2670,8 +2677,14 @@ FunctionTemplateDecl *Sema::DeclareImplicitDeductionGuideFromInitList(
   if (BuildingDeductionGuides.isInvalid())
     return nullptr;
 
-  return cast<FunctionTemplateDecl>(
+  ClassTemplateDecl *Pattern =
+      Transform.NestedPattern ? Transform.NestedPattern : Transform.Template;
+  ContextRAII SavedContext(*this, Pattern->getTemplatedDecl());
+
+  auto *DG = cast<FunctionTemplateDecl>(
       Transform.buildSimpleDeductionGuide(ParamTypes));
+  SavedContext.pop();
+  return DG;
 }
 
 void Sema::DeclareImplicitDeductionGuides(TemplateDecl *Template,

diff  --git a/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp b/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
index c44ec6918c7afb..38b6706595a116 100644
--- a/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
+++ b/clang/test/SemaTemplate/nested-implicit-deduction-guides.cpp
@@ -1,5 +1,4 @@
 // RUN: %clang_cc1 -std=c++20 -verify %s
-// expected-no-diagnostics
 
 template<class T> struct S {
     template<class U> struct N {
@@ -36,11 +35,14 @@ using NonTypeParam = decltype(ntp);
 using NonTypeParam = non_type_param<int>::B<int>;
 
 template<typename A, typename T>
-concept C = (sizeof(T) == sizeof(A));
+concept True = true;
+
+template<typename T>
+concept False = false;
 
 template<class X> struct concepts {
     template<class Y> struct B {
-        template<class K = X, C<K> Z> B(Y, Z);
+        template<class K = X, True<K> Z> B(Y, Z);
     };
 };
 
@@ -50,7 +52,7 @@ using Concepts = concepts<int>::B<int>;
 
 template<class X> struct requires_clause {
     template<class Y> struct B {
-        template<class Z> requires (sizeof(Z) == sizeof(X))
+        template<class Z> requires true
             B(Y, Z);
     };
 };
@@ -58,3 +60,27 @@ template<class X> struct requires_clause {
 requires_clause<int>::B req(1, 2);
 using RC = decltype(req);
 using RC = requires_clause<int>::B<int>;
+
+template<typename X> struct nested_init_list {
+    template<True<X> Y>
+    struct B {
+        X x;
+        Y y;
+    };
+
+    template<False F>
+    struct concept_fail { // #INIT_LIST_INNER_INVALID
+        X x;
+        F f;
+    };
+};
+
+nested_init_list<int>::B nil {1, 2};
+using NIL = decltype(nil);
+using NIL = nested_init_list<int>::B<int>;
+
+// expected-error at +1 {{no viable constructor or deduction guide for deduction of template arguments of 'concept_fail'}}
+nested_init_list<int>::concept_fail nil_invalid{1, ""};
+// expected-note@#INIT_LIST_INNER_INVALID {{candidate template ignored: substitution failure [with F = const char *]: constraints not satisfied for class template 'concept_fail' [with F = const char *]}}
+// expected-note@#INIT_LIST_INNER_INVALID {{candidate function template not viable: requires 1 argument, but 2 were provided}}
+// expected-note@#INIT_LIST_INNER_INVALID {{candidate function template not viable: requires 0 arguments, but 2 were provided}}


        


More information about the cfe-commits mailing list