[libc++] Fix ADL for `make_error_{code,condition}`

Implement LWG 3629, by making lookup for make_error_code and
make_error_condition only consider names found by ADL. This is achieved
by adding a block scope using-declaration for a function that will be
found by unqualified lookup, preventing unqualified lookup from
continuing to enclosing scopes (the class scope, then enclosing
namespaces). The function named by the using declaration is not
viable, so overload resolution must select a candidate found by ADL.

This fixes https://github.com/llvm/llvm-project/issues/57614

Differential Revision: https://reviews.llvm.org/D134943
This commit is contained in:
Jonathan Wakely 2022-09-30 09:22:01 -04:00 committed by Louis Dionne
parent 0011c0a159
commit ef843c8271
6 changed files with 190 additions and 5 deletions

View File

@ -186,6 +186,7 @@
"`3721 <https://wg21.link/LWG3721>`__","Allow an ``arg-id`` with a value of zero for ``width`` in ``std-format-spec``","July 2022","|Complete|","16.0","|format|"
"`3724 <https://wg21.link/LWG3724>`__","``decay-copy`` should be constrained","July 2022","|Complete|","14.0"
"","","","",""
"`3645 <https://wg21.link/LWG3645>`__","``resize_and_overwrite`` is overspecified to call its callback with lvalues","Not voted in","|Complete|","14.0",""
"`3629 <https://wg21.link/LWG3629>`__","``make_error_code`` and ``make_error_condition`` are customization points","Not voted in","|Complete|","16.0",""
"`3631 <https://wg21.link/LWG3631>`__","``basic_format_arg(T&&)`` should use ``remove_cvref_t<T>`` throughout","Not voted in","|Complete|","15.0",""
"`3645 <https://wg21.link/LWG3645>`__","``resize_and_overwrite`` is overspecified to call its callback with lvalues","Not voted in","|Complete|","14.0",""
"","","","",""

Can't render this file because it has a wrong number of fields in line 2.

View File

@ -256,6 +256,13 @@ public:
_LIBCPP_FUNC_VIS const error_category& generic_category() _NOEXCEPT;
_LIBCPP_FUNC_VIS const error_category& system_category() _NOEXCEPT;
namespace __adl_only {
// Those cause ADL to trigger but they are not viable candidates,
// so they are never actually selected.
void make_error_condition() = delete;
void make_error_code() = delete;
} // namespace __adl_only
class _LIBCPP_TYPE_VIS error_condition
{
int __val_;
@ -273,7 +280,10 @@ public:
error_condition(_Ep __e,
typename enable_if<is_error_condition_enum<_Ep>::value>::type* = nullptr
) _NOEXCEPT
{*this = make_error_condition(__e);}
{
using __adl_only::make_error_condition;
*this = make_error_condition(__e);
}
_LIBCPP_INLINE_VISIBILITY
void assign(int __val, const error_category& __cat) _NOEXCEPT
@ -290,7 +300,11 @@ public:
error_condition&
>::type
operator=(_Ep __e) _NOEXCEPT
{*this = make_error_condition(__e); return *this;}
{
using __adl_only::make_error_condition;
*this = make_error_condition(__e);
return *this;
}
_LIBCPP_INLINE_VISIBILITY
void clear() _NOEXCEPT
@ -336,7 +350,10 @@ public:
error_code(_Ep __e,
typename enable_if<is_error_code_enum<_Ep>::value>::type* = nullptr
) _NOEXCEPT
{*this = make_error_code(__e);}
{
using __adl_only::make_error_code;
*this = make_error_code(__e);
}
_LIBCPP_INLINE_VISIBILITY
void assign(int __val, const error_category& __cat) _NOEXCEPT
@ -353,7 +370,11 @@ public:
error_code&
>::type
operator=(_Ep __e) _NOEXCEPT
{*this = make_error_code(__e); return *this;}
{
using __adl_only::make_error_code;
*this = make_error_code(__e);
return *this;
}
_LIBCPP_INLINE_VISIBILITY
void clear() _NOEXCEPT

View File

@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// <system_error>
// class error_code
// template <ErrorCodeEnum E> error_code(E e);
// Regression test for https://github.com/llvm/llvm-project/issues/57614
int make_error_code; // It's important that this comes before <system_error>
#include <system_error>
#include <cassert>
#include <type_traits>
namespace user {
enum Err {};
std::error_code make_error_code(Err) { return std::error_code(42, std::generic_category()); }
}
namespace std {
template <>
struct is_error_code_enum<user::Err> : true_type {};
}
int main(int, char**) {
std::error_code e((user::Err()));
assert(e.value() == 42);
assert(e.category() == std::generic_category());
return 0;
}

View File

@ -0,0 +1,41 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// <system_error>
// class error_code
// template <ErrorCodeEnum E> error_code& operator=(E e);
// Regression test for https://github.com/llvm/llvm-project/issues/57614
int make_error_code; // It's important that this comes before <system_error>
#include <system_error>
#include <cassert>
#include <type_traits>
namespace user {
enum Err {};
std::error_code make_error_code(Err) { return std::error_code(42, std::generic_category()); }
}
namespace std {
template <>
struct is_error_code_enum<user::Err> : true_type {};
}
int main(int, char**) {
std::error_code e;
e = user::Err();
assert(e.value() == 42);
assert(e.category() == std::generic_category());
return 0;
}

View File

@ -0,0 +1,40 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// <system_error>
// class error_condition
// template <ErrorCodeEnum E> error_condition(E e);
// Regression test for https://github.com/llvm/llvm-project/issues/57614
int make_error_condition; // It's important that this comes before <system_error>
#include <system_error>
#include <cassert>
#include <type_traits>
namespace user {
enum Err {};
std::error_condition make_error_condition(Err) { return std::error_condition(42, std::generic_category()); }
}
namespace std {
template <>
struct is_error_condition_enum<user::Err> : true_type {};
}
int main(int, char**) {
std::error_condition e((user::Err()));
assert(e.value() == 42);
assert(e.category() == std::generic_category());
return 0;
}

View File

@ -0,0 +1,42 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// <system_error>
// class error_condition
// template <ErrorCodeEnum E> error_condition& operator=(E e);
// Regression test for https://github.com/llvm/llvm-project/issues/57614
int make_error_condition; // It's important that this comes before <system_error>
#include <system_error>
#include <cassert>
#include <type_traits>
#include "test_macros.h"
namespace user {
enum Err {};
std::error_condition make_error_condition(Err) { return std::error_condition(42, std::generic_category()); }
}
namespace std {
template <>
struct is_error_condition_enum<user::Err> : true_type {};
}
int main(int, char**) {
std::error_condition e;
e = user::Err();
assert(e.value() == 42);
assert(e.category() == std::generic_category());
return 0;
}