[clang] 40beb1f - CWG2076: Permit implicit conversions within a single level of braces
Richard Smith via cfe-commits
cfe-commits at lists.llvm.org
Thu Apr 22 16:49:49 PDT 2021
Author: Richard Smith
Date: 2021-04-22T16:49:39-07:00
New Revision: 40beb1f84a3d72ea39fcee1dcb66c3cefb5d5644
URL: https://github.com/llvm/llvm-project/commit/40beb1f84a3d72ea39fcee1dcb66c3cefb5d5644
DIFF: https://github.com/llvm/llvm-project/commit/40beb1f84a3d72ea39fcee1dcb66c3cefb5d5644.diff
LOG: CWG2076: Permit implicit conversions within a single level of braces
during overload resolution, even when calling a copy constructor.
Added:
Modified:
clang/lib/Sema/SemaOverload.cpp
clang/test/CXX/drs/dr14xx.cpp
clang/test/CXX/drs/dr20xx.cpp
Removed:
################################################################################
diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp
index feef15689fafd..179da2ac26d77 100644
--- a/clang/lib/Sema/SemaOverload.cpp
+++ b/clang/lib/Sema/SemaOverload.cpp
@@ -3346,10 +3346,7 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
bool Usable = !Info.Constructor->isInvalidDecl() &&
S.isInitListConstructor(Info.Constructor);
if (Usable) {
- // If the first argument is (a reference to) the target type,
- // suppress conversions.
- bool SuppressUserConversions = isFirstArgumentCompatibleWithType(
- S.Context, Info.Constructor, ToType);
+ bool SuppressUserConversions = false;
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr, From,
@@ -3473,14 +3470,18 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
/*AllowExplicit*/ true);
if (Usable) {
bool SuppressUserConversions = !ConstructorsOnly;
+ // C++20 [over.best.ics.general]/4.5:
+ // if the target is the first parameter of a constructor [of class
+ // X] and the constructor [...] is a candidate by [...] the second
+ // phase of [over.match.list] when the initializer list has exactly
+ // one element that is itself an initializer list, [...] and the
+ // conversion is to X or reference to cv X, user-defined conversion
+ // sequences are not cnosidered.
if (SuppressUserConversions && ListInitializing) {
- SuppressUserConversions = false;
- if (NumArgs == 1) {
- // If the first argument is (a reference to) the target type,
- // suppress conversions.
- SuppressUserConversions = isFirstArgumentCompatibleWithType(
- S.Context, Info.Constructor, ToType);
- }
+ SuppressUserConversions =
+ NumArgs == 1 && isa<InitListExpr>(Args[0]) &&
+ isFirstArgumentCompatibleWithType(S.Context, Info.Constructor,
+ ToType);
}
if (Info.ConstructorTmpl)
S.AddTemplateOverloadCandidate(
diff --git a/clang/test/CXX/drs/dr14xx.cpp b/clang/test/CXX/drs/dr14xx.cpp
index 866f2fe0bf85a..70bf1ea70e38e 100644
--- a/clang/test/CXX/drs/dr14xx.cpp
+++ b/clang/test/CXX/drs/dr14xx.cpp
@@ -296,6 +296,9 @@ namespace std {
} // std
namespace dr1467 { // dr1467: 3.7 c++11
+ // Note that the change to [over.best.ics] was partially undone by DR2076;
+ // the resulting rule is tested with the tests for that change.
+
// List-initialization of aggregate from same-type object
namespace basic0 {
@@ -419,7 +422,7 @@ namespace dr1467 { // dr1467: 3.7 c++11
void f() { Value{{{1,2},{3,4}}}; }
}
namespace NonAmbiguous {
- // The original implementation made this case ambigious due to the special
+ // The original implementation made this case ambiguous due to the special
// handling of one element initialization lists.
void f(int(&&)[1]);
void f(unsigned(&&)[1]);
diff --git a/clang/test/CXX/drs/dr20xx.cpp b/clang/test/CXX/drs/dr20xx.cpp
index 56cc1161a00c8..9a0c772973eca 100644
--- a/clang/test/CXX/drs/dr20xx.cpp
+++ b/clang/test/CXX/drs/dr20xx.cpp
@@ -49,6 +49,47 @@ namespace dr2026 { // dr2026: 11
}
}
+namespace dr2076 { // dr2076: 13
+#if __cplusplus >= 201103L
+ namespace std_example {
+ struct A { A(int); };
+ struct B { B(A); };
+ B b{{0}};
+
+ struct Params { int a; int b; };
+ struct Foo {
+ Foo(Params);
+ };
+ Foo foo{{1, 2}};
+ }
+
+ struct string_view {
+ string_view(int); // not an aggregate
+ };
+ struct string {
+ string(int); // not an aggregate
+ operator string_view() const;
+ };
+
+ void foo(const string &); // expected-note {{cannot convert initializer list}}
+ void bar(string_view); // expected-note 2{{cannot convert initializer list}}
+
+ void func(const string &arg) {
+ // An argument in one set of braces is subject to user-defined conversions;
+ // an argument in two sets of braces is not, but an identity conversion is
+ // still OK.
+ foo(arg);
+ foo({arg});
+ foo({{arg}});
+ foo({{{arg}}}); // expected-error {{no matching function}}
+ bar(arg);
+ bar({arg});
+ bar({{arg}}); // expected-error {{no matching function}}
+ bar({{{arg}}}); // expected-error {{no matching function}}
+ }
+#endif
+}
+
namespace dr2082 { // dr2082: 11
void test1(int x, int = sizeof(x)); // ok
#if __cplusplus >= 201103L
More information about the cfe-commits
mailing list