diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -108,6 +108,10 @@ Bug Fixes to C++ Support ^^^^^^^^^^^^^^^^^^^^^^^^ +- Fix CTAD for ``std::initializer_list``. This allows + ``std::initializer_list{1, 2, 3}`` to be deduced as + ``std::initializer_list`` as intended. + Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -11749,11 +11749,17 @@ Template = Specialization->getSpecializedTemplate(); Arguments = Specialization->getTemplateArgs().data(); - } else if (const TemplateSpecializationType *TST = - Ty->getAs()) { - Template = dyn_cast_or_null( - TST->getTemplateName().getAsTemplateDecl()); - Arguments = TST->template_arguments().begin(); + } else { + const TemplateSpecializationType *TST = nullptr; + if (auto *ICN = Ty->getAs()) + TST = ICN->getInjectedTST(); + else + TST = Ty->getAs(); + if (TST) { + Template = dyn_cast_or_null( + 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 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -10589,8 +10589,6 @@ // 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 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 --- a/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp +++ b/clang/test/SemaCXX/cxx1z-class-template-argument-deduction.cpp @@ -12,14 +12,19 @@ size_t n; initializer_list(); }; - // FIXME: This should probably not be necessary. - template initializer_list(initializer_list) -> initializer_list; } template constexpr bool has_type(...) { return false; } template 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>(il1)); +static_assert(has_type>(il2)); +static_assert(has_type>(il3)); +static_assert(has_type>>(il4)); template struct vector { template vector(Iter, Iter);