Skip to content

Commit df762a1

Browse files
authored
[SemaCXX] Recognise initializer_list injected-class-name types as initializer_lists (#90210)
This allows the implicitly-generated deduction guide for the copy constructor to be recognised as an initializer-list constructor, allowing CTAD for std::initializer_list
1 parent 93e69ab commit df762a1

File tree

4 files changed

+21
-10
lines changed

4 files changed

+21
-10
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,8 @@ Bug Fixes to C++ Support
590590
- Fixed a use-after-free bug in parsing of type constraints with default arguments that involve lambdas. (#GH67235)
591591
- Fixed bug in which the body of a consteval lambda within a template was not parsed as within an
592592
immediate function context.
593+
- Fix CTAD for ``std::initializer_list``. This allows ``std::initializer_list{1, 2, 3}`` to be deduced as
594+
``std::initializer_list<int>`` as intended.
593595

594596
Bug Fixes to AST Handling
595597
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12054,11 +12054,17 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) {
1205412054

1205512055
Template = Specialization->getSpecializedTemplate();
1205612056
Arguments = Specialization->getTemplateArgs().data();
12057-
} else if (const TemplateSpecializationType *TST =
12058-
Ty->getAs<TemplateSpecializationType>()) {
12059-
Template = dyn_cast_or_null<ClassTemplateDecl>(
12060-
TST->getTemplateName().getAsTemplateDecl());
12061-
Arguments = TST->template_arguments().begin();
12057+
} else {
12058+
const TemplateSpecializationType *TST = nullptr;
12059+
if (auto *ICN = Ty->getAs<InjectedClassNameType>())
12060+
TST = ICN->getInjectedTST();
12061+
else
12062+
TST = Ty->getAs<TemplateSpecializationType>();
12063+
if (TST) {
12064+
Template = dyn_cast_or_null<ClassTemplateDecl>(
12065+
TST->getTemplateName().getAsTemplateDecl());
12066+
Arguments = TST->template_arguments().begin();
12067+
}
1206212068
}
1206312069
if (!Template)
1206412070
return false;

clang/lib/Sema/SemaInit.cpp

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10790,8 +10790,6 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
1079010790
// FIXME: Perform "exact type" matching first, per CWG discussion?
1079110791
// Or implement this via an implied 'T(T) -> T' deduction guide?
1079210792

10793-
// FIXME: Do we need/want a std::initializer_list<T> special case?
10794-
1079510793
// Look up deduction guides, including those synthesized from constructors.
1079610794
//
1079710795
// C++1z [over.match.class.deduct]p1:

clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,19 @@ namespace std {
1212
size_t n;
1313
initializer_list();
1414
};
15-
// FIXME: This should probably not be necessary.
16-
template<typename T> initializer_list(initializer_list<T>) -> initializer_list<T>;
1715
}
1816

1917
template<typename T> constexpr bool has_type(...) { return false; }
2018
template<typename T> constexpr bool has_type(T&) { return true; }
2119

22-
std::initializer_list il = {1, 2, 3, 4, 5};
20+
std::initializer_list il1 = {1, 2, 3, 4, 5};
21+
auto il2 = std::initializer_list{1, 2, 3, 4};
22+
auto il3 = std::initializer_list{il1};
23+
auto il4 = std::initializer_list{il1, il1, il1};
24+
static_assert(has_type<std::initializer_list<int>>(il1));
25+
static_assert(has_type<std::initializer_list<int>>(il2));
26+
static_assert(has_type<std::initializer_list<int>>(il3));
27+
static_assert(has_type<std::initializer_list<std::initializer_list<int>>>(il4));
2328

2429
template<typename T> struct vector {
2530
template<typename Iter> vector(Iter, Iter);

0 commit comments

Comments
 (0)