diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 585e1535b1585..08e79984fe336 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 `_) +- Fixes CTAD for aggregates on nested template classes. Fixes: + (`#77599 `_) + - Fix crash when importing the same module with an dynamic initializer twice in different visibility. Fixes (`#67893 `_) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 3170f41e8033f..91e4cb7b68a24 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(Template->getTemplatedDecl()); + auto *Pattern = Template; + while (Pattern->getInstantiatedFromMemberTemplate()) { + if (Pattern->isMemberSpecialization()) + break; + Pattern = Pattern->getInstantiatedFromMemberTemplate(); + } + + auto *RD = cast(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 0655d36335206..839d508b911f0 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(); @@ -2425,9 +2428,13 @@ struct ConvertConstructorToDeductionGuideTransform { // Build the parameters, needed during deduction / substitution. SmallVector 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( + ClassTemplateDecl *Pattern = + Transform.NestedPattern ? Transform.NestedPattern : Transform.Template; + ContextRAII SavedContext(*this, Pattern->getTemplatedDecl()); + + auto *DG = cast( 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 c44ec6918c7af..38b6706595a11 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 struct S { template struct N { @@ -36,11 +35,14 @@ using NonTypeParam = decltype(ntp); using NonTypeParam = non_type_param::B; template -concept C = (sizeof(T) == sizeof(A)); +concept True = true; + +template +concept False = false; template struct concepts { template struct B { - template Z> B(Y, Z); + template Z> B(Y, Z); }; }; @@ -50,7 +52,7 @@ using Concepts = concepts::B; template struct requires_clause { template struct B { - template requires (sizeof(Z) == sizeof(X)) + template requires true B(Y, Z); }; }; @@ -58,3 +60,27 @@ template struct requires_clause { requires_clause::B req(1, 2); using RC = decltype(req); using RC = requires_clause::B; + +template struct nested_init_list { + template Y> + struct B { + X x; + Y y; + }; + + template + struct concept_fail { // #INIT_LIST_INNER_INVALID + X x; + F f; + }; +}; + +nested_init_list::B nil {1, 2}; +using NIL = decltype(nil); +using NIL = nested_init_list::B; + +// expected-error@+1 {{no viable constructor or deduction guide for deduction of template arguments of 'concept_fail'}} +nested_init_list::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}}