diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 58c06edb6deea..ff66d2c272098 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 `_) + (`#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 ff370dd1e080b..fba5b22139170 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 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 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 0000000000000..4915c687cf4c4 --- /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 struct S { + template struct N { + N(T) {} + N(T, U) {} + template N(V, U) {} + }; +}; + +S::N x{"a", 1};