[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