Skip to content

[libc++] Fix ambiguous constructors for std::complex and std::optional #103409

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions libcxx/include/complex
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
9 changes: 6 additions & 3 deletions libcxx/include/optional
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
Original file line number Diff line number Diff line change
@@ -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);
Loading