From 4d4a4100f68dfc50bd3b67de40101761be8ffdb7 Mon Sep 17 00:00:00 2001 From: Louis Dionne Date: Wed, 14 Aug 2024 14:04:22 -0400 Subject: [PATCH] [libc++] Fix ambiguous constructors for std::complex and std::optional (#103409) Fixes #101960 (cherry picked from commit 4d08bb11eea5907fa9cdfe4c7bc9d5c91e79c6a7) --- libcxx/include/complex | 9 +++-- libcxx/include/optional | 9 +++-- .../gh_101960_ambiguous_ctor.pass.cpp | 38 +++++++++++++++++++ .../gh_101960_internal_ctor.compile.pass.cpp | 28 ++++++++++++++ 4 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 libcxx/test/std/numerics/complex.number/complex.special/gh_101960_ambiguous_ctor.pass.cpp 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/complex b/libcxx/include/complex index 22271acaf7358db..e6534025de57e53 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 ::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& __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 ::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& __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 ::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& __c); diff --git a/libcxx/include/optional b/libcxx/include/optional index f9cbcbfa595d1ab..41d7515a2b6892e 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 - _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 - _LIBCPP_HIDE_FROM_ABI constexpr explicit optional(__optional_construct_from_invoke_tag, _Fp&& __f, _Args&&... __args) + template ::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_ctor.pass.cpp b/libcxx/test/std/numerics/complex.number/complex.special/gh_101960_ambiguous_ctor.pass.cpp new file mode 100644 index 000000000000000..bffe8764386a750 --- /dev/null +++ b/libcxx/test/std/numerics/complex.number/complex.special/gh_101960_ambiguous_ctor.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 +// +//===----------------------------------------------------------------------===// + +// + +// Regression test for https://github.com/llvm/llvm-project/issues/101960 where we used to +// trigger an ambiguous constructor. + +#include +#include + +struct NastyConvertible { + template + operator T() const { + return T(0); + } +}; + +template +void test() { + NastyConvertible nasty; + std::complex x(nasty, nasty); + assert(x.real() == T(0)); + assert(x.imag() == T(0)); +} + +int main(int, char**) { + test(); + test(); + test(); + + return 0; +} 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 000000000000000..1a1d6f52a5fec95 --- /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 + +// + +// 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 +#include + +struct NastyConvertible { + template + operator T() { + return 0; + } +}; + +using F = int(int); + +static_assert(!std::is_constructible, NastyConvertible, int(int), int>::value);