Mordante updated this revision to Diff 302140.
Mordante added a comment.

- No longer store the `InitListExpr` instead store the size difference between 
the array and initializer  list.
- Removed the dead code for P0388.
- Don't add overloads where the initializer list has more elements than the 
array to be initialized.
- Since the size validation is simpler now it's directly in 
`CompareImplicitConversionSequences` instead of the helper class 
`CompareListInitializationSequences`.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D87563/new/

https://reviews.llvm.org/D87563

Files:
  clang/include/clang/Sema/Overload.h
  clang/lib/Sema/SemaOverload.cpp
  clang/test/SemaCXX/overload-call.cpp

Index: clang/test/SemaCXX/overload-call.cpp
===================================================================
--- clang/test/SemaCXX/overload-call.cpp
+++ clang/test/SemaCXX/overload-call.cpp
@@ -688,3 +688,41 @@
     f(pmf);
   }
 }
+
+#if __cplusplus >= 201103L
+// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1307
+// DR1307
+// For review are we sure the example with array of unknown bounds is DR1307 and not P0388? P0388 is resolved in
+// https://reviews.llvm.org/D87566
+namespace InitializerListToArray {
+void f(int(&&)[2]); // expected-note {{candidate function not viable}}
+void f(int(&&)[3]); // expected-note {{candidate function not viable}}
+void f(int(&&)[4]); // expected-note {{candidate function not viable}}
+
+void g() {
+  f({1});
+  f({1, 2});
+  f({1, 2, 3});
+  f({1, 2, 3, 4});
+  f({1, 2, 3, 4, 5}); // expected-error {{no matching function for call to 'f'}}
+}
+
+struct S {
+  S();
+  S(double);
+};
+
+void h(S(&&)[2]); // expected-note {{candidate function not viable}}
+void h(S(&&)[3]); // expected-note {{candidate function not viable}}
+void h(S(&&)[4]); // expected-note {{candidate function not viable}}
+
+void i() {
+  h({1});
+  h({1, 2});
+  h({1, 2, 3});
+  h({1, 2, 3, 4});
+  h({1, 2, 3, 4, 5}); // expected-error {{no matching function for call to 'h'}}
+}
+
+} // namespace InitializerListToArray
+#endif
Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -3809,6 +3809,15 @@
     if (!ICS1.isStdInitializerListElement() &&
         ICS2.isStdInitializerListElement())
       return ImplicitConversionSequence::Worse;
+
+    if (ICS1.isConstantArrayElement() && ICS2.isConstantArrayElement()) {
+      llvm::APInt Diff1 = ICS1.getConstantArraySizeDiff();
+      llvm::APInt Diff2 = ICS2.getConstantArraySizeDiff();
+      if (Diff1.ult(Diff2))
+        return ImplicitConversionSequence::Better;
+      if (Diff2.ult(Diff1))
+        return ImplicitConversionSequence::Worse;
+    }
   }
 
   if (ICS1.isStandard())
@@ -5062,9 +5071,16 @@
   // FIXME: We're missing a lot of these checks.
   bool toStdInitializerList = false;
   QualType X;
-  if (ToType->isArrayType())
+  Optional<llvm::APInt> ArraySizeDiff;
+  if (ToType->isArrayType()) {
+    // Has the initializer list exactly N elements or fewer than N elements?
+    if (const auto *CAT = S.getASTContext().getAsConstantArrayType(ToType)) {
+      if (CAT->getSize().ult(From->getNumInits()))
+        return Result;
+      ArraySizeDiff = CAT->getSize() - From->getNumInits();
+    }
     X = S.Context.getAsArrayType(ToType)->getElementType();
-  else
+  } else
     toStdInitializerList = S.isStdInitializerList(ToType, &X);
   if (!X.isNull()) {
     for (unsigned i = 0, e = From->getNumInits(); i < e; ++i) {
@@ -5095,6 +5111,8 @@
     }
 
     Result.setStdInitializerListElement(toStdInitializerList);
+    if (ArraySizeDiff)
+      Result.setConstantArraySizeDiff(*ArraySizeDiff);
     return Result;
   }
 
Index: clang/include/clang/Sema/Overload.h
===================================================================
--- clang/include/clang/Sema/Overload.h
+++ clang/include/clang/Sema/Overload.h
@@ -539,6 +539,17 @@
     /// sequence only represents the worst element conversion.
     unsigned StdInitializerListElement : 1;
 
+    /// Whether the target is really a constant array, and the sequence only
+    /// represents the worst element conversion.
+    unsigned ConstantArrayElement : 1;
+
+    /// The number of elements the std::initalizer_list has less then the
+    /// number of elements in the array. A value of 0 means the same number of
+    /// elements. If the std::initializer_list has more elements than the array
+    /// the conversion sequence will be marked as a bad conversion and this
+    /// field won't be used.
+    llvm::APInt ConstantArraySizeDiff{};
+
     void setKind(Kind K) {
       destruct();
       ConversionKind = K;
@@ -568,13 +579,17 @@
     };
 
     ImplicitConversionSequence()
-        : ConversionKind(Uninitialized), StdInitializerListElement(false) {
+        : ConversionKind(Uninitialized), StdInitializerListElement(false),
+          ConstantArrayElement(false) {
       Standard.setAsIdentityConversion();
     }
 
     ImplicitConversionSequence(const ImplicitConversionSequence &Other)
         : ConversionKind(Other.ConversionKind),
-          StdInitializerListElement(Other.StdInitializerListElement) {
+          StdInitializerListElement(Other.StdInitializerListElement),
+          ConstantArrayElement(Other.ConstantArrayElement),
+          ConstantArraySizeDiff(Other.ConstantArraySizeDiff) {
+
       switch (ConversionKind) {
       case Uninitialized: break;
       case StandardConversion: Standard = Other.Standard; break;
@@ -680,6 +695,16 @@
       StdInitializerListElement = V;
     }
 
+    bool isConstantArrayElement() const { return ConstantArrayElement; }
+    void setConstantArraySizeDiff(llvm::APInt Value) {
+      ConstantArrayElement = true;
+      ConstantArraySizeDiff = Value;
+    }
+    llvm::APInt getConstantArraySizeDiff() const {
+      assert(ConstantArrayElement);
+      return ConstantArraySizeDiff;
+    }
+
     /// Form an "implicit" conversion sequence from nullptr_t to bool, for a
     /// direct-initialization of a bool object from nullptr_t.
     static ImplicitConversionSequence getNullptrToBool(QualType SourceType,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to