From f80bd9b8a8103f39f5fece019abf86d41098cec1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Spaits?= Date: Tue, 18 Jun 2024 20:45:23 +0200 Subject: [PATCH] [Sema][CTAD] Allow user defined conversion for copy-list-initialization (#94752) Fixes #62925. The following code: ```cpp #include int main() { std::map m1 = {std::pair{"foo", 2}, {"bar", 3}}; // guide #2 std::map m2(m1.begin(), m1.end()); // guide #1 } ``` Is rejected by clang, but accepted by both gcc and msvc: https://godbolt.org/z/6v4fvabb5 . So basically CTAD with copy-list-initialization is rejected. Note that this exact code is also used in a cppreference article: https://en.cppreference.com/w/cpp/container/map/deduction_guides I checked the C++11 and C++20 standard drafts to see whether suppressing user conversion is the correct thing to do for user conversions. Based on the standard I don't think that it is correct. ``` 13.3.1.4 Copy-initialization of class by user-defined conversion [over.match.copy] Under the conditions specified in 8.5, as part of a copy-initialization of an object of class type, a user-defined conversion can be invoked to convert an initializer expression to the type of the object being initialized. Overload resolution is used to select the user-defined conversion to be invoked ``` So we could use user defined conversions according to the standard. ``` If a narrowing conversion is required to initialize any of the elements, the program is ill-formed. ``` We should not do narrowing. ``` In copy-list-initialization, if an explicit constructor is chosen, the initialization is ill-formed. ``` We should not use explicit constructors. --- clang/docs/ReleaseNotes.rst | 6 +++ clang/include/clang/Sema/Initialization.h | 2 +- clang/lib/Sema/SemaInit.cpp | 6 +-- .../SemaCXX/ctad-copy-init-list-narrowing.cpp | 46 +++++++++++++++++++ 4 files changed, 55 insertions(+), 5 deletions(-) create mode 100644 clang/test/SemaCXX/ctad-copy-init-list-narrowing.cpp diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index bbbc04308df334..0f958d213172ae 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -207,6 +207,12 @@ C++20 Feature Support to update the ``__cpp_concepts`` macro to `202002L`. This enables ```` from libstdc++ to work correctly with Clang. +- User defined constructors are allowed for copy-list-initialization with CTAD. + The example code for deduction guides for std::map in + (`cppreference `_) + will now work. + (#GH62925). + C++23 Feature Support ^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Sema/Initialization.h b/clang/include/clang/Sema/Initialization.h index f443e327eaf329..4b876db436b48c 100644 --- a/clang/include/clang/Sema/Initialization.h +++ b/clang/include/clang/Sema/Initialization.h @@ -603,7 +603,7 @@ class InitializationKind { /// Normal context IC_Normal, - /// Normal context, but allows explicit conversion functionss + /// Normal context, but allows explicit conversion functions IC_ExplicitConvs, /// Implicit context (value initialization) diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index e805834c0fd38e..494787253f0927 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -10906,8 +10906,6 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( // FIXME: The "second phase of [over.match.list] case can also // theoretically happen here, but it's not clear whether we can // ever have a parameter of the right type. - bool SuppressUserConversions = Kind.isCopyInit(); - if (TD) { SmallVector TmpInits; for (Expr *E : Inits) @@ -10917,12 +10915,12 @@ QualType Sema::DeduceTemplateSpecializationFromInitializer( TmpInits.push_back(E); AddTemplateOverloadCandidate( TD, FoundDecl, /*ExplicitArgs=*/nullptr, TmpInits, Candidates, - SuppressUserConversions, + /*SuppressUserConversions=*/false, /*PartialOverloading=*/false, AllowExplicit, ADLCallKind::NotADL, /*PO=*/{}, AllowAggregateDeductionCandidate); } else { AddOverloadCandidate(GD, FoundDecl, Inits, Candidates, - SuppressUserConversions, + /*SuppressUserConversions=*/false, /*PartialOverloading=*/false, AllowExplicit); } }; diff --git a/clang/test/SemaCXX/ctad-copy-init-list-narrowing.cpp b/clang/test/SemaCXX/ctad-copy-init-list-narrowing.cpp new file mode 100644 index 00000000000000..368857c83a88e7 --- /dev/null +++ b/clang/test/SemaCXX/ctad-copy-init-list-narrowing.cpp @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -fsyntax-only -verify -Wno-unused-value -std=c++20 %s + +namespace std { +typedef decltype(sizeof(int)) size_t; + +template +struct initializer_list { + const E *p; + size_t n; + initializer_list(const E *p, size_t n) : p(p), n(n) {} +}; + +// Classes to use to reproduce the exact scenario present in #62925. +template +class pair { + public: + pair(T f, Y s) {} +}; + +template +class map { + public: + map(std::initializer_list>) {} + map(std::initializer_list>, int a) {} +}; + +} // namespace std + +// This is the almost the exact code that was in issue #62925. +void testOneLevelNesting() { + std::map mOk = {std::pair{5, 'a'}, {6, 'b'}, {7, 'c'}}; + + // Verify that narrowing conversion is disabled in the first level of nesting. + std::map mNarrow = {std::pair{5, 'a'}, {6.0f, 'b'}, {7, 'c'}}; // expected-error {{type 'float' cannot be narrowed to 'int' in initializer list}} // expected-note {{insert an explicit cast to silence this issue}} +} + +void testMultipleLevelNesting() { + std::map aOk = {{std::pair{5, 'c'}, {5, 'c'}}, 5}; + + // Verify that narrowing conversion is disabled when it is not in a nested + // in another std::initializer_list, but it happens in the most outer one. + std::map aNarrowNested = {{std::pair{5, 'c'}, {5.0f, 'c'}}, 5}; // expected-error {{type 'float' cannot be narrowed to 'int' in initializer list}} // expected-note {{insert an explicit cast to silence this issue}} + + // Verify that narrowing conversion is disabled in the first level of nesting. + std::map aNarrow = {{std::pair{5, 'c'}, {5, 'c'}}, 5.0f}; // expected-error {{type 'float' cannot be narrowed to 'int' in initializer list}} // expected-note {{insert an explicit cast to silence this issue}} +}