Skip to content

Commit 45dc480

Browse files
committed
Ensure function_refs are copyable even from non-const references
A subtle bug was found where attempting to copy a non-const function_ref lvalue would actually invoke the generic forwarding constructor (as it was a closer match - being T& rather than the const T& of the implicit copy constructor). In the particular case this lead to a dangling function_ref member (since it had referenced the function_ref passed by value to its ctor, rather than the outer function_ref that was still alive) SFINAE the converting constructor to not be considered if the copy constructor is available and demonstrate that this causes the copy to refer to the original functor, not to the function_ref it was copied from. (without the code change, the test would fail as Y would be referencing X and Y() would see the result of the mutation to X, ie: 2) llvm-svn: 221753
1 parent 434df0a commit 45dc480

File tree

3 files changed

+34
-2
lines changed

3 files changed

+34
-2
lines changed

llvm/include/llvm/ADT/STLExtras.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,11 @@ class function_ref<Ret(Params...)> {
7777
}
7878

7979
public:
80-
template<typename Callable>
81-
function_ref(Callable &&callable)
80+
template <typename Callable>
81+
function_ref(Callable &&callable,
82+
typename std::enable_if<
83+
!std::is_same<typename std::remove_reference<Callable>::type,
84+
function_ref>::value>::type * = nullptr)
8285
: callback(callback_fn<typename std::remove_reference<Callable>::type>),
8386
callable(reinterpret_cast<intptr_t>(&callable)) {}
8487
Ret operator()(Params ...params) const {

llvm/unittests/ADT/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ set(ADTSources
1313
DenseMapTest.cpp
1414
DenseSetTest.cpp
1515
FoldingSet.cpp
16+
FunctionRefTest.cpp
1617
HashingTest.cpp
1718
ilistTest.cpp
1819
ImmutableMapTest.cpp
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//===- llvm/unittest/ADT/MakeUniqueTest.cpp - make_unique unit tests ------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "llvm/ADT/STLExtras.h"
11+
#include "gtest/gtest.h"
12+
13+
using namespace llvm;
14+
15+
namespace {
16+
17+
// Ensure that copies of a function_ref copy the underlying state rather than
18+
// causing one function_ref to chain to the next.
19+
TEST(FunctionRefTest, Copy) {
20+
auto A = [] { return 1; };
21+
auto B = [] { return 2; };
22+
function_ref<int()> X = A;
23+
function_ref<int()> Y = X;
24+
X = B;
25+
EXPECT_EQ(1, Y());
26+
}
27+
28+
}

0 commit comments

Comments
 (0)