Skip to content

Commit

Permalink
Support C++17 noexcept function type in base::Bind
Browse files Browse the repository at this point in the history
In C++17, noexcept keyword is a part of the function type, and that
causes a pattern match failure on base::Bind implementation.
This CL fixes the failure by falling it back to bare function cases.

Bug: 752720
Change-Id: I98c71977fa3fd759956c86e394fb9e30179c951c
Reviewed-on: https://chromium-review.googlesource.com/1027530
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Commit-Queue: Taiju Tsuiki <tzik@chromium.org>
Cr-Commit-Position: refs/heads/master@{#553913}
  • Loading branch information
tzik authored and Commit Bot committed Apr 26, 2018
1 parent 899655f commit d58a892
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 7 deletions.
31 changes: 24 additions & 7 deletions base/bind_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -397,9 +397,9 @@ struct FunctorTraits<R (*)(Args...)> {
static constexpr bool is_method = false;
static constexpr bool is_nullable = true;

template <typename... RunArgs>
static R Invoke(R (*function)(Args...), RunArgs&&... args) {
return function(std::forward<RunArgs>(args)...);
template <typename Function, typename... RunArgs>
static R Invoke(Function&& function, RunArgs&&... args) {
return std::forward<Function>(function)(std::forward<RunArgs>(args)...);
}
};

Expand Down Expand Up @@ -440,8 +440,8 @@ struct FunctorTraits<R (Receiver::*)(Args...)> {
static constexpr bool is_method = true;
static constexpr bool is_nullable = true;

template <typename ReceiverPtr, typename... RunArgs>
static R Invoke(R (Receiver::*method)(Args...),
template <typename Method, typename ReceiverPtr, typename... RunArgs>
static R Invoke(Method method,
ReceiverPtr&& receiver_ptr,
RunArgs&&... args) {
return ((*receiver_ptr).*method)(std::forward<RunArgs>(args)...);
Expand All @@ -455,14 +455,31 @@ struct FunctorTraits<R (Receiver::*)(Args...) const> {
static constexpr bool is_method = true;
static constexpr bool is_nullable = true;

template <typename ReceiverPtr, typename... RunArgs>
static R Invoke(R (Receiver::*method)(Args...) const,
template <typename Method, typename ReceiverPtr, typename... RunArgs>
static R Invoke(Method method,
ReceiverPtr&& receiver_ptr,
RunArgs&&... args) {
return ((*receiver_ptr).*method)(std::forward<RunArgs>(args)...);
}
};

#ifdef __cpp_noexcept_function_type
// noexcept makes a distinct function type in C++17.
// I.e. `void(*)()` and `void(*)() noexcept` are same in pre-C++17, and
// different in C++17.
template <typename R, typename... Args>
struct FunctorTraits<R (*)(Args...) noexcept> : FunctorTraits<R (*)(Args...)> {
};

template <typename R, typename Receiver, typename... Args>
struct FunctorTraits<R (Receiver::*)(Args...) noexcept>
: FunctorTraits<R (Receiver::*)(Args...)> {};

template <typename R, typename Receiver, typename... Args>
struct FunctorTraits<R (Receiver::*)(Args...) const noexcept>
: FunctorTraits<R (Receiver::*)(Args...) const> {};
#endif

// For IgnoreResults.
template <typename T>
struct FunctorTraits<IgnoreResultHelper<T>> : FunctorTraits<T> {
Expand Down
16 changes: 16 additions & 0 deletions base/bind_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,10 @@ void TakesACallback(const Closure& callback) {
callback.Run();
}

int Noexcept() noexcept {
return 42;
}

class BindTest : public ::testing::Test {
public:
BindTest() {
Expand All @@ -326,6 +330,8 @@ class BindTest : public ::testing::Test {
}

static int IntFunc0() { return static_func_mock_ptr->IntMethod0(); }
int NoexceptMethod() noexcept { return 42; }
int ConstNoexceptMethod() const noexcept { return 42; }

protected:
StrictMock<NoRef> no_ref_;
Expand Down Expand Up @@ -1469,6 +1475,16 @@ TEST_F(BindTest, UnwrapPassed) {
EXPECT_EQ(p, internal::Unwrap(Passed(WrapUnique(p))).get());
}

TEST_F(BindTest, BindNoexcept) {
EXPECT_EQ(42, base::BindOnce(&Noexcept).Run());
EXPECT_EQ(
42,
base::BindOnce(&BindTest::NoexceptMethod, base::Unretained(this)).Run());
EXPECT_EQ(
42, base::BindOnce(&BindTest::ConstNoexceptMethod, base::Unretained(this))
.Run());
}

// Test null callbacks cause a DCHECK.
TEST(BindDeathTest, NullCallback) {
base::Callback<void(int)> null_cb;
Expand Down

0 comments on commit d58a892

Please sign in to comment.