[libcxx-commits] [libcxx] [libc++] Fix ambiguous std::complex constructor (PR #103409)

Louis Dionne via libcxx-commits libcxx-commits at lists.llvm.org
Tue Aug 13 13:16:46 PDT 2024


https://github.com/ldionne updated https://github.com/llvm/llvm-project/pull/103409

>From bd1bb45c1b6e0616ddecebd1994b02cc971973c6 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Tue, 13 Aug 2024 16:01:44 -0400
Subject: [PATCH 1/2] [libc++] Fix ambiguous std::complex constructor

Fixes #101960
---
 libcxx/include/complex                        |  9 +++--
 .../gh_101960_ambiguous_constructor.pass.cpp  | 38 +++++++++++++++++++
 2 files changed, 44 insertions(+), 3 deletions(-)
 create mode 100644 libcxx/test/std/numerics/complex.number/complex.special/gh_101960_ambiguous_constructor.pass.cpp

diff --git a/libcxx/include/complex b/libcxx/include/complex
index 22271acaf7358d..e6534025de57e5 100644
--- a/libcxx/include/complex
+++ b/libcxx/include/complex
@@ -421,7 +421,8 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(float __re = 0.0f, float __im = 0.0f) : __re_(__re), __im_(__im) {}
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(__from_builtin_tag, _Complex float __v)
+  template <class _Tag, __enable_if_t<_IsSame<_Tag, __from_builtin_tag>::value, int> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit complex(_Tag, _Complex float __v)
       : __re_(__real__ __v), __im_(__imag__ __v) {}
 
   _LIBCPP_HIDE_FROM_ABI explicit _LIBCPP_CONSTEXPR complex(const complex<double>& __c);
@@ -517,7 +518,8 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(double __re = 0.0, double __im = 0.0) : __re_(__re), __im_(__im) {}
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(__from_builtin_tag, _Complex double __v)
+  template <class _Tag, __enable_if_t<_IsSame<_Tag, __from_builtin_tag>::value, int> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit complex(_Tag, _Complex double __v)
       : __re_(__real__ __v), __im_(__imag__ __v) {}
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(const complex<float>& __c);
@@ -617,7 +619,8 @@ public:
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(long double __re = 0.0L, long double __im = 0.0L)
       : __re_(__re), __im_(__im) {}
 
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(__from_builtin_tag, _Complex long double __v)
+  template <class _Tag, __enable_if_t<_IsSame<_Tag, __from_builtin_tag>::value, int> = 0>
+  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR explicit complex(_Tag, _Complex long double __v)
       : __re_(__real__ __v), __im_(__imag__ __v) {}
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR complex(const complex<float>& __c);
diff --git a/libcxx/test/std/numerics/complex.number/complex.special/gh_101960_ambiguous_constructor.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.special/gh_101960_ambiguous_constructor.pass.cpp
new file mode 100644
index 00000000000000..bffe8764386a75
--- /dev/null
+++ b/libcxx/test/std/numerics/complex.number/complex.special/gh_101960_ambiguous_constructor.pass.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// <complex>
+
+// Regression test for https://github.com/llvm/llvm-project/issues/101960 where we used to
+// trigger an ambiguous constructor.
+
+#include <complex>
+#include <cassert>
+
+struct NastyConvertible {
+  template <class T>
+  operator T() const {
+    return T(0);
+  }
+};
+
+template <class T>
+void test() {
+  NastyConvertible nasty;
+  std::complex<T> x(nasty, nasty);
+  assert(x.real() == T(0));
+  assert(x.imag() == T(0));
+}
+
+int main(int, char**) {
+  test<float>();
+  test<double>();
+  test<long double>();
+
+  return 0;
+}

>From 5b2df451b29085b76a8f65b43e8882c736f82fc4 Mon Sep 17 00:00:00 2001
From: Louis Dionne <ldionne.2 at gmail.com>
Date: Tue, 13 Aug 2024 16:16:02 -0400
Subject: [PATCH 2/2] Also fix issue for optional

---
 libcxx/include/optional                       |  9 ++++--
 ....cpp => gh_101960_ambiguous_ctor.pass.cpp} |  0
 .../gh_101960_internal_ctor.compile.pass.cpp  | 28 +++++++++++++++++++
 3 files changed, 34 insertions(+), 3 deletions(-)
 rename libcxx/test/std/numerics/complex.number/complex.special/{gh_101960_ambiguous_constructor.pass.cpp => gh_101960_ambiguous_ctor.pass.cpp} (100%)
 create mode 100644 libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/gh_101960_internal_ctor.compile.pass.cpp

diff --git a/libcxx/include/optional b/libcxx/include/optional
index f9cbcbfa595d1a..41d7515a2b6892 100644
--- a/libcxx/include/optional
+++ b/libcxx/include/optional
@@ -301,7 +301,7 @@ struct __optional_destruct_base<_Tp, false> {
 
 #  if _LIBCPP_STD_VER >= 23
   template <class _Fp, class... _Args>
-  _LIBCPP_HIDE_FROM_ABI constexpr __optional_destruct_base(
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit __optional_destruct_base(
       __optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args)
       : __val_(std::invoke(std::forward<_Fp>(__f), std::forward<_Args>(__args)...)), __engaged_(true) {}
 #  endif
@@ -707,8 +707,11 @@ public:
   }
 
 #  if _LIBCPP_STD_VER >= 23
-  template <class _Fp, class... _Args>
-  _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(__optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args)
+  template <class _Tag,
+            class _Fp,
+            class... _Args,
+            __enable_if_t<_IsSame<_Tag, __optional_construct_from_invoke_tag>::value, int> = 0>
+  _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(_Tag, _Fp&& __f, _Args&&... __args)
       : __base(__optional_construct_from_invoke_tag{}, std::forward<_Fp>(__f), std::forward<_Args>(__args)...) {}
 #  endif
 
diff --git a/libcxx/test/std/numerics/complex.number/complex.special/gh_101960_ambiguous_constructor.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.special/gh_101960_ambiguous_ctor.pass.cpp
similarity index 100%
rename from libcxx/test/std/numerics/complex.number/complex.special/gh_101960_ambiguous_constructor.pass.cpp
rename to libcxx/test/std/numerics/complex.number/complex.special/gh_101960_ambiguous_ctor.pass.cpp
diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/gh_101960_internal_ctor.compile.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/gh_101960_internal_ctor.compile.pass.cpp
new file mode 100644
index 00000000000000..1a1d6f52a5fec9
--- /dev/null
+++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.ctor/gh_101960_internal_ctor.compile.pass.cpp
@@ -0,0 +1,28 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+
+// <optional>
+
+// Regression test for https://github.com/llvm/llvm-project/issues/101960 where a constructor
+// of std::optional that should have been private was instead publicly available.
+
+#include <optional>
+#include <type_traits>
+
+struct NastyConvertible {
+  template <class T>
+  operator T() {
+    return 0;
+  }
+};
+
+using F = int(int);
+
+static_assert(!std::is_constructible<std::optional<int>, NastyConvertible, int(int), int>::value);



More information about the libcxx-commits mailing list