[clang] [SemaCXX] Recognise initializer_list injected-class-name types as initializer_lists (PR #90210)
Mital Ashok via cfe-commits
cfe-commits at lists.llvm.org
Fri Apr 26 06:34:42 PDT 2024
https://github.com/MitalAshok created https://github.com/llvm/llvm-project/pull/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
>From ff65636895e8bceb5b4d6497a0e9ccda0c5fa22a Mon Sep 17 00:00:00 2001
From: Mital Ashok <mital at mitalashok.co.uk>
Date: Fri, 26 Apr 2024 13:44:17 +0100
Subject: [PATCH] [SemaCXX] Recognise initializer_list injected-class-name
types as initializer_lists
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
---
clang/docs/ReleaseNotes.rst | 2 ++
clang/lib/Sema/SemaDeclCXX.cpp | 16 +++++++++++-----
clang/lib/Sema/SemaInit.cpp | 2 --
.../cxx1z-class-template-argument-deduction.cpp | 11 ++++++++---
4 files changed, 21 insertions(+), 10 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 92563262cc6737..4065de5745aae6 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -581,6 +581,8 @@ Bug Fixes to C++ Support
- Fixed a use-after-free bug in parsing of type constraints with default arguments that involve lambdas. (#GH67235)
- Fixed bug in which the body of a consteval lambda within a template was not parsed as within an
immediate function context.
+- Fix CTAD for ``std::initializer_list``. This allows ``std::initializer_list{1, 2, 3}`` to be deduced as
+ ``std::initializer_list<int>`` as intended.
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index abdbc9d8830c03..8d98f593817bda 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -12052,11 +12052,17 @@ bool Sema::isStdInitializerList(QualType Ty, QualType *Element) {
Template = Specialization->getSpecializedTemplate();
Arguments = Specialization->getTemplateArgs().data();
- } else if (const TemplateSpecializationType *TST =
- Ty->getAs<TemplateSpecializationType>()) {
- Template = dyn_cast_or_null<ClassTemplateDecl>(
- TST->getTemplateName().getAsTemplateDecl());
- Arguments = TST->template_arguments().begin();
+ } else {
+ const TemplateSpecializationType *TST = nullptr;
+ if (auto *ICN = Ty->getAs<InjectedClassNameType>())
+ TST = ICN->getInjectedTST();
+ else
+ TST = Ty->getAs<TemplateSpecializationType>();
+ if (TST) {
+ Template = dyn_cast_or_null<ClassTemplateDecl>(
+ TST->getTemplateName().getAsTemplateDecl());
+ Arguments = TST->template_arguments().begin();
+ }
}
if (!Template)
return false;
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 003a157990d307..842d165c60d94c 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -10790,8 +10790,6 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer(
// FIXME: Perform "exact type" matching first, per CWG discussion?
// Or implement this via an implied 'T(T) -> T' deduction guide?
- // FIXME: Do we need/want a std::initializer_list<T> special case?
-
// Look up deduction guides, including those synthesized from constructors.
//
// C++1z [over.match.class.deduct]p1:
diff --git a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
index 2f067ea53a5029..90404f115c75f7 100644
--- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
+++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp
@@ -12,14 +12,19 @@ namespace std {
size_t n;
initializer_list();
};
- // FIXME: This should probably not be necessary.
- template<typename T> initializer_list(initializer_list<T>) -> initializer_list<T>;
}
template<typename T> constexpr bool has_type(...) { return false; }
template<typename T> constexpr bool has_type(T&) { return true; }
-std::initializer_list il = {1, 2, 3, 4, 5};
+std::initializer_list il1 = {1, 2, 3, 4, 5};
+auto il2 = std::initializer_list{1, 2, 3, 4};
+auto il3 = std::initializer_list{il1};
+auto il4 = std::initializer_list{il1, il1, il1};
+static_assert(has_type<std::initializer_list<int>>(il1));
+static_assert(has_type<std::initializer_list<int>>(il2));
+static_assert(has_type<std::initializer_list<int>>(il3));
+static_assert(has_type<std::initializer_list<std::initializer_list<int>>>(il4));
template<typename T> struct vector {
template<typename Iter> vector(Iter, Iter);
More information about the cfe-commits
mailing list