diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index c4086a5bcbf36..93d1e76938b22 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -593,6 +593,9 @@ Improvements to Clang's diagnostics - Fixed a false negative ``-Wunused-private-field`` diagnostic when a defaulted comparison operator is defined out of class (#GH116961). +- Clang now supports using alias templates in deduction guides, aligning with the C++ standard, + which treats alias templates as synonyms for their underlying types (#GH54909). + Improvements to Clang's time-trace ---------------------------------- diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 26041e53de506..3ff365649c93d 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11451,23 +11451,29 @@ bool Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R, bool MightInstantiateToSpecialization = false; if (auto RetTST = TSI->getTypeLoc().getAsAdjusted()) { - TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName(); - bool TemplateMatches = Context.hasSameTemplateName( - SpecifiedName, GuidedTemplate, /*IgnoreDeduced=*/true); - - const QualifiedTemplateName *Qualifiers = - SpecifiedName.getAsQualifiedTemplateName(); - assert(Qualifiers && "expected QualifiedTemplate"); - bool SimplyWritten = !Qualifiers->hasTemplateKeyword() && - Qualifiers->getQualifier() == nullptr; - if (SimplyWritten && TemplateMatches) - AcceptableReturnType = true; - else { - // This could still instantiate to the right type, unless we know it - // names the wrong class template. - auto *TD = SpecifiedName.getAsTemplateDecl(); - MightInstantiateToSpecialization = !(TD && isa(TD) && - !TemplateMatches); + const TemplateSpecializationType *TST = RetTST.getTypePtr(); + while (TST && TST->isTypeAlias()) + TST = TST->getAliasedType()->getAs(); + + if (TST) { + TemplateName SpecifiedName = TST->getTemplateName(); + bool TemplateMatches = Context.hasSameTemplateName( + SpecifiedName, GuidedTemplate, /*IgnoreDeduced=*/true); + + const QualifiedTemplateName *Qualifiers = + SpecifiedName.getAsQualifiedTemplateName(); + assert(Qualifiers && "expected QualifiedTemplate"); + bool SimplyWritten = !Qualifiers->hasTemplateKeyword() && + Qualifiers->getQualifier() == nullptr; + if (SimplyWritten && TemplateMatches) + AcceptableReturnType = true; + else { + // This could still instantiate to the right type, unless we know it + // names the wrong class template. + auto *TD = SpecifiedName.getAsTemplateDecl(); + MightInstantiateToSpecialization = + !(TD && isa(TD) && !TemplateMatches); + } } } else if (!RetTy.hasQualifiers() && RetTy->isDependentType()) { MightInstantiateToSpecialization = true; diff --git a/clang/test/CXX/temp/temp.deduct.guide/p3.cpp b/clang/test/CXX/temp/temp.deduct.guide/p3.cpp index c5404847beb06..195ba2831439d 100644 --- a/clang/test/CXX/temp/temp.deduct.guide/p3.cpp +++ b/clang/test/CXX/temp/temp.deduct.guide/p3.cpp @@ -33,7 +33,7 @@ template typename TT> struct E { // expected-note 2{{template }; A(int) -> int; // expected-error {{deduced type 'int' of deduction guide is not a specialization of template 'A'}} -template A(T)->B; // expected-error {{deduced type 'B' (aka 'A') of deduction guide is not written as a specialization of template 'A'}} +template A(T)->B; template A(T*) -> const A; // expected-error {{deduced type 'const A' of deduction guide is not a specialization of template 'A'}} // A deduction-guide shall be declared in the same scope as the corresponding @@ -71,3 +71,11 @@ namespace WrongScope { Local(int) -> Local; // expected-error {{expected}} } } + +namespace GH54909 { +template struct A {}; +struct B {}; + +template using C = B; +template A() -> C; // expected-error {{deduced type 'C' (aka 'GH54909::B') of deduction guide is not a specialization of template 'A'}} +}