Skip to content

Commit eb00182

Browse files
authored
[Clang] prevent errors for deduction guides using deduced type aliases (#117450)
Fixes #54909 --- Clang incorrectly produces diagnostics for alias templates in deduction guides, treating them as separate from their underlying types. This issue arises because Clang doesn't properly handle `TypeAliasTemplateDecl` when comparing template names for equality in the context of deduction guides, resulting in diagnostics that don't align with the C++ standard. As the C++ standard specifies - _an alias template is considered a synonym for its underlying type_ With this change, Clang now correctly resolves alias templates to their underlying types in deduction guides, ensuring compliance with the C++ standard.
1 parent 427be07 commit eb00182

File tree

3 files changed

+35
-18
lines changed

3 files changed

+35
-18
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,9 @@ Improvements to Clang's diagnostics
590590

591591
- Fixed a false negative ``-Wunused-private-field`` diagnostic when a defaulted comparison operator is defined out of class (#GH116961).
592592

593+
- Clang now supports using alias templates in deduction guides, aligning with the C++ standard,
594+
which treats alias templates as synonyms for their underlying types (#GH54909).
595+
593596
Improvements to Clang's time-trace
594597
----------------------------------
595598

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11451,23 +11451,29 @@ bool Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
1145111451
bool MightInstantiateToSpecialization = false;
1145211452
if (auto RetTST =
1145311453
TSI->getTypeLoc().getAsAdjusted<TemplateSpecializationTypeLoc>()) {
11454-
TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName();
11455-
bool TemplateMatches = Context.hasSameTemplateName(
11456-
SpecifiedName, GuidedTemplate, /*IgnoreDeduced=*/true);
11457-
11458-
const QualifiedTemplateName *Qualifiers =
11459-
SpecifiedName.getAsQualifiedTemplateName();
11460-
assert(Qualifiers && "expected QualifiedTemplate");
11461-
bool SimplyWritten = !Qualifiers->hasTemplateKeyword() &&
11462-
Qualifiers->getQualifier() == nullptr;
11463-
if (SimplyWritten && TemplateMatches)
11464-
AcceptableReturnType = true;
11465-
else {
11466-
// This could still instantiate to the right type, unless we know it
11467-
// names the wrong class template.
11468-
auto *TD = SpecifiedName.getAsTemplateDecl();
11469-
MightInstantiateToSpecialization = !(TD && isa<ClassTemplateDecl>(TD) &&
11470-
!TemplateMatches);
11454+
const TemplateSpecializationType *TST = RetTST.getTypePtr();
11455+
while (TST && TST->isTypeAlias())
11456+
TST = TST->getAliasedType()->getAs<TemplateSpecializationType>();
11457+
11458+
if (TST) {
11459+
TemplateName SpecifiedName = TST->getTemplateName();
11460+
bool TemplateMatches = Context.hasSameTemplateName(
11461+
SpecifiedName, GuidedTemplate, /*IgnoreDeduced=*/true);
11462+
11463+
const QualifiedTemplateName *Qualifiers =
11464+
SpecifiedName.getAsQualifiedTemplateName();
11465+
assert(Qualifiers && "expected QualifiedTemplate");
11466+
bool SimplyWritten = !Qualifiers->hasTemplateKeyword() &&
11467+
Qualifiers->getQualifier() == nullptr;
11468+
if (SimplyWritten && TemplateMatches)
11469+
AcceptableReturnType = true;
11470+
else {
11471+
// This could still instantiate to the right type, unless we know it
11472+
// names the wrong class template.
11473+
auto *TD = SpecifiedName.getAsTemplateDecl();
11474+
MightInstantiateToSpecialization =
11475+
!(TD && isa<ClassTemplateDecl>(TD) && !TemplateMatches);
11476+
}
1147111477
}
1147211478
} else if (!RetTy.hasQualifiers() && RetTy->isDependentType()) {
1147311479
MightInstantiateToSpecialization = true;

clang/test/CXX/temp/temp.deduct.guide/p3.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ template<template<typename> typename TT> struct E { // expected-note 2{{template
3333
};
3434

3535
A(int) -> int; // expected-error {{deduced type 'int' of deduction guide is not a specialization of template 'A'}}
36-
template <typename T> A(T)->B<T>; // expected-error {{deduced type 'B<T>' (aka 'A<T>') of deduction guide is not written as a specialization of template 'A'}}
36+
template <typename T> A(T)->B<T>;
3737
template<typename T> A(T*) -> const A<T>; // expected-error {{deduced type 'const A<T>' of deduction guide is not a specialization of template 'A'}}
3838

3939
// A deduction-guide shall be declared in the same scope as the corresponding
@@ -71,3 +71,11 @@ namespace WrongScope {
7171
Local(int) -> Local<int>; // expected-error {{expected}}
7272
}
7373
}
74+
75+
namespace GH54909 {
76+
template <class T> struct A {};
77+
struct B {};
78+
79+
template <typename T> using C = B;
80+
template <typename T> A() -> C<T>; // expected-error {{deduced type 'C<T>' (aka 'GH54909::B') of deduction guide is not a specialization of template 'A'}}
81+
}

0 commit comments

Comments
 (0)