Skip to content
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

Restrict ADL for reference_wrapper and thread #3101

Merged
merged 4 commits into from
Oct 12, 2022
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
4 changes: 2 additions & 2 deletions stl/inc/thread
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ private:
static unsigned int __stdcall _Invoke(void* _RawVals) noexcept /* terminates */ {
// adapt invoke of user's callable object to _beginthreadex's thread procedure
const unique_ptr<_Tuple> _FnVals(static_cast<_Tuple*>(_RawVals));
_Tuple& _Tup = *_FnVals;
_Tuple& _Tup = *_FnVals.get(); // avoid ADL, handle incomplete types
_STD invoke(_STD move(_STD get<_Indices>(_Tup))...);
_Cnd_do_broadcast_at_thread_exit(); // TRANSITION, ABI
return 0;
Expand Down Expand Up @@ -311,7 +311,7 @@ public:

jthread& operator=(jthread&& _Other) noexcept {
// note: the standard specifically disallows making self-move-assignment a no-op here
// N4861 [thread.jthread.cons]/13
// N4917 33.4.4.2 [thread.jthread.cons]/12
// Effects: If joinable() is true, calls request_stop() and then join(). Assigns the state
// of x to *this and sets x to a default constructed state.
_Try_cancel_and_join();
Expand Down
53 changes: 29 additions & 24 deletions stl/inc/type_traits
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ using add_rvalue_reference_t = typename _Add_reference<_Ty>::_Rvalue;

_EXPORT_STD template <class _Ty>
add_rvalue_reference_t<_Ty> declval() noexcept {
static_assert(_Always_false<_Ty>, "Calling declval is ill-formed, see N4892 [declval]/2.");
static_assert(_Always_false<_Ty>, "Calling declval is ill-formed, see N4917 22.2.6 [declval]/2.");
}

_EXPORT_STD template <class _Ty>
Expand Down Expand Up @@ -1189,8 +1189,8 @@ using _Conditional_type = decltype(false ? _STD declval<_Ty1>() : _STD declval<_
template <class _Ty1, class _Ty2, class = void>
struct _Const_lvalue_cond_oper {};

// N4810 [meta.trans.other]/3.3.4 (per the proposed resolution of LWG-3205): "Otherwise, if remove_cvref_t</**/> denotes
// a type..."
// N4917 21.3.8.7 [meta.trans.other]/3.3.4 (per the proposed resolution of LWG-3205): "Otherwise, if
// remove_cvref_t</**/> denotes a type..."
template <class _Ty1, class _Ty2>
struct _Const_lvalue_cond_oper<_Ty1, _Ty2, void_t<_Conditional_type<const _Ty1&, const _Ty2&>>> {
using type = remove_cvref_t<_Conditional_type<const _Ty1&, const _Ty2&>>;
Expand Down Expand Up @@ -1267,11 +1267,11 @@ struct _Copy_cv_impl<const volatile _From> {
using _Apply = const volatile _To;
};
template <class _From, class _To>
using _Copy_cv = // N4810 [meta.trans.other]/2.3
using _Copy_cv = // N4917 21.3.8.7 [meta.trans.other]/2.3
typename _Copy_cv_impl<_From>::template _Apply<_To>;

template <class _Ty1>
struct _Add_qualifiers { // _Add_qualifiers<A>::template _Apply is XREF(A) from N4810 [meta.trans.other]/2.1
struct _Add_qualifiers { // _Add_qualifiers<A>::template _Apply is XREF(A) from N4917 21.3.8.7 [meta.trans.other]/2.2
template <class _Ty2>
using _Apply = _Copy_cv<_Ty1, _Ty2>;
};
Expand All @@ -1288,7 +1288,7 @@ struct _Add_qualifiers<_Ty1&&> {

#if !defined(__EDG__) && !defined(__clang__) // TRANSITION, DevCom-10095944
template <class _Ty1, class _Ty2>
using _Cond_res_if_right = // N4810 [meta.trans.other]/2.4
using _Cond_res_if_right = // N4917 21.3.8.7 [meta.trans.other]/2.4
decltype(false ? _Returns_exactly<_Ty1>() : _Returns_exactly<_Ty2>());

template <class _Ty>
Expand All @@ -1310,7 +1310,7 @@ template <class _Ty1, class _Ty2>
using _Cond_res = typename _Cond_res_workaround<_Ty1, _Ty2>::type;
#else // ^^^ workaround / no workaround vvv
template <class _Ty1, class _Ty2>
using _Cond_res = // N4810 [meta.trans.other]/2.4
using _Cond_res = // N4917 21.3.8.7 [meta.trans.other]/2.4
decltype(false ? _Returns_exactly<_Ty1>() : _Returns_exactly<_Ty2>());
#endif // ^^^ no workaround ^^^

Expand All @@ -1320,30 +1320,30 @@ struct common_reference;
_EXPORT_STD template <class... _Types>
using common_reference_t = typename common_reference<_Types...>::type;

// N4810 [meta.trans.other]/5.1: "If sizeof...(T) is zero ..."
// N4917 21.3.8.7 [meta.trans.other]/5.1: "If sizeof...(T) is zero ..."
template <>
struct common_reference<> {};

// N4810 [meta.trans.other]/5.2: "...if sizeof...(T) is one ..."
// N4917 21.3.8.7 [meta.trans.other]/5.2: "...if sizeof...(T) is one ..."
template <class _Ty>
struct common_reference<_Ty> {
using type = _Ty;
};

// N4810 [meta.trans.other]/5.3: "...if sizeof...(T) is two..."
// N4917 21.3.8.7 [meta.trans.other]/5.3: "...if sizeof...(T) is two..."

// N4810 [meta.trans.other]/5.3.4: "if common_type_t<T1, T2> is well-formed..."
// N4810 [meta.trans.other]/5.3.5: "Otherwise, there shall be no member type."
// N4917 21.3.8.7 [meta.trans.other]/5.3.4: "if common_type_t<T1, T2> is well-formed..."
// N4917 21.3.8.7 [meta.trans.other]/5.3.5: "Otherwise, there shall be no member type."
template <class _Ty1, class _Ty2, class = void>
struct _Common_reference2C : common_type<_Ty1, _Ty2> {};

// N4810 [meta.trans.other]/5.3.3: "if COND_RES(T1, T2) is well-formed..."
// N4917 21.3.8.7 [meta.trans.other]/5.3.3: "if COND_RES(T1, T2) is well-formed..."
template <class _Ty1, class _Ty2>
struct _Common_reference2C<_Ty1, _Ty2, void_t<_Cond_res<_Ty1, _Ty2>>> {
using type = _Cond_res<_Ty1, _Ty2>;
};

// N4810 [meta.trans.other]/5.3.2: "if basic_common_reference<[...]>::type is well-formed..."
// N4917 21.3.8.7 [meta.trans.other]/5.3.2: "if basic_common_reference<[...]>::type is well-formed..."
template <class _Ty1, class _Ty2>
using _Basic_specialization = typename basic_common_reference<remove_cvref_t<_Ty1>, remove_cvref_t<_Ty2>,
_Add_qualifiers<_Ty1>::template _Apply, _Add_qualifiers<_Ty2>::template _Apply>::type;
Expand All @@ -1356,7 +1356,7 @@ struct _Common_reference2B<_Ty1, _Ty2, void_t<_Basic_specialization<_Ty1, _Ty2>>
using type = _Basic_specialization<_Ty1, _Ty2>;
};

// N4810 [meta.trans.other]/5.3.1: "If T1 and T2 are reference types and COMMON_REF(T1, T2) is well-formed..."
// N4917 21.3.8.7 [meta.trans.other]/5.3.1: "If T1 and T2 are reference types and COMMON_REF(T1, T2) is well-formed..."
template <class _Ty1, class _Ty2, class = void>
struct _Common_reference2A : _Common_reference2B<_Ty1, _Ty2> {};

Expand All @@ -1366,17 +1366,19 @@ using _LL_common_ref = _Result;

template <class _Ty1, class _Ty2>
struct _Common_reference2A<_Ty1&, _Ty2&, void_t<_LL_common_ref<_Ty1, _Ty2>>> {
using type = _LL_common_ref<_Ty1, _Ty2>; // "both lvalues" case from N4810 [meta.trans.other]/2.5
using type = _LL_common_ref<_Ty1, _Ty2>; // "both lvalues" case from N4917 21.3.8.7 [meta.trans.other]/2.5
};

template <class _Ty1, class _Ty2>
struct _Common_reference2A<_Ty1&&, _Ty2&, enable_if_t<is_convertible_v<_Ty1&&, _LL_common_ref<const _Ty1, _Ty2>>>> {
using type = _LL_common_ref<const _Ty1, _Ty2>; // "rvalue and lvalue" case from N4810 [meta.trans.other]/2.7
using type =
_LL_common_ref<const _Ty1, _Ty2>; // "rvalue and lvalue" case from N4917 21.3.8.7 [meta.trans.other]/2.7
};

template <class _Ty1, class _Ty2>
struct _Common_reference2A<_Ty1&, _Ty2&&, enable_if_t<is_convertible_v<_Ty2&&, _LL_common_ref<const _Ty2, _Ty1>>>> {
using type = _LL_common_ref<const _Ty2, _Ty1>; // "lvalue and rvalue" case from N4810 [meta.trans.other]/2.8
using type =
_LL_common_ref<const _Ty2, _Ty1>; // "lvalue and rvalue" case from N4917 21.3.8.7 [meta.trans.other]/2.8
};

template <class _Ty1, class _Ty2>
Expand All @@ -1386,13 +1388,13 @@ template <class _Ty1, class _Ty2>
struct _Common_reference2A<_Ty1&&, _Ty2&&,
enable_if_t<
is_convertible_v<_Ty1&&, _RR_common_ref<_Ty1, _Ty2>> && is_convertible_v<_Ty2&&, _RR_common_ref<_Ty1, _Ty2>>>> {
using type = _RR_common_ref<_Ty1, _Ty2>; // "both rvalues" case from N4810 [meta.trans.other]/2.6
using type = _RR_common_ref<_Ty1, _Ty2>; // "both rvalues" case from N4917 21.3.8.7 [meta.trans.other]/2.6
};

template <class _Ty1, class _Ty2>
struct common_reference<_Ty1, _Ty2> : _Common_reference2A<_Ty1, _Ty2> {};

// N4810 [meta.trans.other]/5.4: "if sizeof...(T) is greater than two..."
// N4917 21.3.8.7 [meta.trans.other]/5.4: "if sizeof...(T) is greater than two..."
template <class _Void, class _Ty1, class _Ty2, class... _Types>
struct _Fold_common_reference {};
template <class _Ty1, class _Ty2, class... _Types>
Expand Down Expand Up @@ -1448,8 +1450,9 @@ _EXPORT_STD template <class _Ty>
class reference_wrapper;

// std::invoke isn't constexpr in C++17, and normally implementers are forbidden from "strengthening" constexpr
// (WG21-N4842 [constexpr.functions]/1), yet both std::apply and std::visit are required to be constexpr and have
// invoke-like behavior. As a result, we've chosen to apply the part of P1065R2 resolving LWG-2894 as a defect report.
// (WG21-N4917 16.4.6.7 [constexpr.functions]/1), yet both std::apply and std::visit are required to be constexpr and
// have invoke-like behavior. As a result, we've chosen to apply the part of P1065R2 resolving LWG-2894 as a defect
// report.

enum class _Invoker_strategy {
_Functor,
Expand Down Expand Up @@ -1854,7 +1857,8 @@ template <class _Ty, class _Uty, class = void>
struct _Refwrap_has_ctor_from : false_type {};

template <class _Ty, class _Uty>
struct _Refwrap_has_ctor_from<_Ty, _Uty, void_t<decltype(_Refwrap_ctor_fun<_Ty>(_STD declval<_Uty>()))>> : true_type {};
struct _Refwrap_has_ctor_from<_Ty, _Uty, void_t<decltype(_STD _Refwrap_ctor_fun<_Ty>(_STD declval<_Uty>()))>>
: true_type {}; // _STD _Refwrap_ctor_fun is qualified: avoid ADL, handle incomplete types

_EXPORT_STD template <class _Ty>
class reference_wrapper
Expand All @@ -1871,7 +1875,8 @@ public:
template <class _Uty, enable_if_t<conjunction_v<negation<is_same<_Remove_cvref_t<_Uty>, reference_wrapper>>,
_Refwrap_has_ctor_from<_Ty, _Uty>>,
int> = 0>
_CONSTEXPR20 reference_wrapper(_Uty&& _Val) noexcept(noexcept(_Refwrap_ctor_fun<_Ty>(_STD declval<_Uty>()))) {
_CONSTEXPR20 reference_wrapper(_Uty&& _Val) noexcept(
noexcept(_STD _Refwrap_ctor_fun<_Ty>(_STD declval<_Uty>()))) { // qualified: avoid ADL, handle incomplete types
_Ty& _Ref = static_cast<_Uty&&>(_Val);
_Ptr = _STD addressof(_Ref);
}
Expand Down
20 changes: 10 additions & 10 deletions tests/libcxx/expected_results.txt
Original file line number Diff line number Diff line change
Expand Up @@ -369,15 +369,19 @@ std/utilities/meta/meta.trans/meta.trans.other/aligned_storage.pass.cpp FAIL
std/depr/depr.c.headers/math_h.pass.cpp FAIL
std/numerics/c.math/cmath.pass.cpp FAIL

# GH-2358: <filesystem>: path's comparison operators are IF-NDR
std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp FAIL

# GH-1374: Spaceship CPO wording in [cmp.alg] needs an overhaul
# (Technically an STL bug until the wording in the working draft is fixed to agree.)
std/language.support/cmp/cmp.alg/partial_order.pass.cpp FAIL
std/language.support/cmp/cmp.alg/strong_order.pass.cpp FAIL
std/language.support/cmp/cmp.alg/weak_order.pass.cpp FAIL

# GH-1596: <algorithm>: unqualified calls to _Adl_verify_range incorrectly cause instantiation
std/algorithms/robust_against_adl.compile.pass.cpp FAIL
std/strings/basic.string/string.modifiers/robust_against_adl.pass.cpp FAIL

# GH-3100: <memory> etc.: ADL should be avoided when calling _Construct_in_place and its friends
std/utilities/function.objects/func.wrap/func.wrap.func/robust_against_adl.pass.cpp FAIL


# *** CRT BUGS ***
# We're permanently missing aligned_alloc().
Expand Down Expand Up @@ -581,6 +585,9 @@ std/utilities/format/format.functions/locale-specific_form.pass.cpp FAIL
# libc++ chose option A for [time.clock.file.members], and we chose option B.
std/time/time.clock/time.clock.file/to_from_sys.pass.cpp FAIL

# libc++'s filesystem::path::iterator model bidirectional_iterator, which is not guaranteed by the Standard
std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp FAIL

# libc++ is missing various Ranges DRs
std/language.support/support.limits/support.limits.general/ranges.version.compile.pass.cpp FAIL

Expand Down Expand Up @@ -781,13 +788,6 @@ std/re/re.const/re.matchflag/match_prev_avail.pass.cpp FAIL
# Not yet analyzed. Many diagnostics.
std/input.output/filesystems/class.path/path.member/path.charconv.pass.cpp FAIL

# Not yet analyzed. Probably ADL shenanigans.
std/algorithms/robust_against_adl.compile.pass.cpp FAIL
std/strings/basic.string/string.modifiers/robust_against_adl.pass.cpp FAIL
std/thread/thread.threads/thread.thread.class/thread.thread.constr/robust_against_adl.pass.cpp FAIL
std/utilities/function.objects/func.wrap/func.wrap.func/robust_against_adl.pass.cpp FAIL
std/utilities/function.objects/refwrap/refwrap.invoke/robust_against_adl.pass.cpp FAIL

# Not yet analyzed. Possibly C1XX constexpr bug.
std/utilities/function.objects/func.invoke/invoke_constexpr.pass.cpp:0 FAIL

Expand Down
20 changes: 10 additions & 10 deletions tests/libcxx/skipped_tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -370,15 +370,19 @@ utilities\meta\meta.trans\meta.trans.other\aligned_storage.pass.cpp
depr\depr.c.headers\math_h.pass.cpp
numerics\c.math\cmath.pass.cpp

# GH-2358: <filesystem>: path's comparison operators are IF-NDR
input.output\filesystems\class.path\range_concept_conformance.compile.pass.cpp

# GH-1374: Spaceship CPO wording in [cmp.alg] needs an overhaul
# (Technically an STL bug until the wording in the working draft is fixed to agree.)
language.support\cmp\cmp.alg\partial_order.pass.cpp
language.support\cmp\cmp.alg\strong_order.pass.cpp
language.support\cmp\cmp.alg\weak_order.pass.cpp

# GH-1596: <algorithm>: unqualified calls to _Adl_verify_range incorrectly cause instantiation
algorithms\robust_against_adl.compile.pass.cpp
strings\basic.string\string.modifiers\robust_against_adl.pass.cpp

# GH-3100: <memory> etc.: ADL should be avoided when calling _Construct_in_place and its friends
utilities\function.objects\func.wrap\func.wrap.func\robust_against_adl.pass.cpp


# *** CRT BUGS ***
# We're permanently missing aligned_alloc().
Expand Down Expand Up @@ -582,6 +586,9 @@ utilities\format\format.functions\locale-specific_form.pass.cpp
# libc++ chose option A for [time.clock.file.members], and we chose option B.
time\time.clock\time.clock.file\to_from_sys.pass.cpp

# libc++'s filesystem::path::iterator model bidirectional_iterator, which is not guaranteed by the Standard
input.output\filesystems\class.path\range_concept_conformance.compile.pass.cpp

# libc++ is missing various Ranges DRs
language.support\support.limits\support.limits.general\ranges.version.compile.pass.cpp

Expand Down Expand Up @@ -782,13 +789,6 @@ re\re.const\re.matchflag\match_prev_avail.pass.cpp
# Not yet analyzed. Many diagnostics.
input.output\filesystems\class.path\path.member\path.charconv.pass.cpp

# Not yet analyzed. Probably ADL shenanigans.
algorithms\robust_against_adl.compile.pass.cpp
strings\basic.string\string.modifiers\robust_against_adl.pass.cpp
thread\thread.threads\thread.thread.class\thread.thread.constr\robust_against_adl.pass.cpp
utilities\function.objects\func.wrap\func.wrap.func\robust_against_adl.pass.cpp
utilities\function.objects\refwrap\refwrap.invoke\robust_against_adl.pass.cpp

# Not yet analyzed. Possibly C1XX constexpr bug.
utilities\function.objects\func.invoke\invoke_constexpr.pass.cpp

Expand Down