Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
gaoqiong
pybind11
Commits
5812d64b
Commit
5812d64b
authored
Sep 08, 2016
by
Wenzel Jakob
Committed by
GitHub
Sep 08, 2016
Browse files
Merge pull request #394 from jagerman/fix-ref-heap-casts
Fix ref heap casts
parents
587aa328
c03db9ba
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
65 additions
and
5 deletions
+65
-5
include/pybind11/cast.h
include/pybind11/cast.h
+18
-5
tests/test_issues.cpp
tests/test_issues.cpp
+32
-0
tests/test_issues.py
tests/test_issues.py
+15
-0
No files found.
include/pybind11/cast.h
View file @
5812d64b
...
...
@@ -264,24 +264,25 @@ using cast_op_type = typename std::conditional<std::is_pointer<typename std::rem
/// Generic type caster for objects stored on the heap
template
<
typename
type
>
class
type_caster_base
:
public
type_caster_generic
{
using
itype
=
intrinsic_t
<
type
>
;
public:
static
PYBIND11_DESCR
name
()
{
return
type_descr
(
_
<
type
>
());
}
type_caster_base
()
:
type_caster_generic
(
typeid
(
type
))
{
}
static
handle
cast
(
const
type
&
src
,
return_value_policy
policy
,
handle
parent
)
{
static
handle
cast
(
const
i
type
&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
==
return_value_policy
::
automatic
||
policy
==
return_value_policy
::
automatic_reference
)
policy
=
return_value_policy
::
copy
;
return
cast
(
&
src
,
policy
,
parent
);
}
static
handle
cast
(
type
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
static
handle
cast
(
i
type
&&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
==
return_value_policy
::
automatic
||
policy
==
return_value_policy
::
automatic_reference
)
policy
=
return_value_policy
::
move
;
return
cast
(
&
src
,
policy
,
parent
);
}
static
handle
cast
(
const
type
*
src
,
return_value_policy
policy
,
handle
parent
)
{
static
handle
cast
(
const
i
type
*
src
,
return_value_policy
policy
,
handle
parent
)
{
return
type_caster_generic
::
cast
(
src
,
policy
,
parent
,
src
?
&
typeid
(
*
src
)
:
nullptr
,
&
typeid
(
type
),
make_copy_constructor
(
src
),
make_move_constructor
(
src
));
...
...
@@ -289,8 +290,8 @@ public:
template
<
typename
T
>
using
cast_op_type
=
pybind11
::
detail
::
cast_op_type
<
T
>
;
operator
type
*
()
{
return
(
type
*
)
value
;
}
operator
type
&
()
{
if
(
!
value
)
throw
reference_cast_error
();
return
*
((
type
*
)
value
);
}
operator
i
type
*
()
{
return
(
type
*
)
value
;
}
operator
i
type
&
()
{
if
(
!
value
)
throw
reference_cast_error
();
return
*
((
i
type
*
)
value
);
}
protected:
typedef
void
*
(
*
Constructor
)(
const
void
*
stream
);
...
...
@@ -859,10 +860,22 @@ template <typename T> struct move_if_unreferenced<T, typename std::enable_if<
>::
type
>
:
std
::
true_type
{};
template
<
typename
T
>
using
move_never
=
std
::
integral_constant
<
bool
,
!
move_always
<
T
>::
value
&&
!
move_if_unreferenced
<
T
>::
value
>
;
// Detect whether returning a `type` from a cast on type's type_caster is going to result in a
// reference or pointer to a local variable of the type_caster. Basically, only
// non-reference/pointer `type`s and reference/pointers from a type_caster_generic are safe;
// everything else returns a reference/pointer to a local variable.
template
<
typename
type
>
using
cast_is_temporary_value_reference
=
bool_constant
<
(
std
::
is_reference
<
type
>::
value
||
std
::
is_pointer
<
type
>::
value
)
&&
!
std
::
is_base_of
<
type_caster_generic
,
make_caster
<
type
>>::
value
>
;
NAMESPACE_END
(
detail
)
template
<
typename
T
>
T
cast
(
const
handle
&
handle
)
{
using
type_caster
=
detail
::
make_caster
<
T
>
;
static_assert
(
!
detail
::
cast_is_temporary_value_reference
<
T
>::
value
,
"Unable to cast type to reference: value is local to type caster"
);
type_caster
conv
;
if
(
!
conv
.
load
(
handle
,
true
))
{
#if defined(NDEBUG)
...
...
tests/test_issues.cpp
View file @
5812d64b
...
...
@@ -191,6 +191,38 @@ void init_issues(py::module &m) {
py
::
class_
<
MoveIssue2
>
(
m2
,
"MoveIssue2"
).
def
(
py
::
init
<
int
>
()).
def_readwrite
(
"value"
,
&
MoveIssue2
::
v
);
m2
.
def
(
"get_moveissue1"
,
[](
int
i
)
->
MoveIssue1
*
{
return
new
MoveIssue1
(
i
);
},
py
::
return_value_policy
::
move
);
m2
.
def
(
"get_moveissue2"
,
[](
int
i
)
{
return
MoveIssue2
(
i
);
},
py
::
return_value_policy
::
move
);
// Issue 392: overridding reference-returning functions
class
OverrideTest
{
public:
struct
A
{
int
value
=
99
;
};
int
v
;
A
a
;
explicit
OverrideTest
(
int
v
)
:
v
{
v
}
{}
virtual
int
int_value
()
{
return
v
;
}
virtual
int
&
int_ref
()
{
return
v
;
}
virtual
A
A_value
()
{
return
a
;
}
virtual
A
&
A_ref
()
{
return
a
;
}
};
class
PyOverrideTest
:
public
OverrideTest
{
public:
using
OverrideTest
::
OverrideTest
;
int
int_value
()
override
{
PYBIND11_OVERLOAD
(
int
,
OverrideTest
,
int_value
);
}
// Not allowed (uncommenting should hit a static_assert failure): we can't get a reference
// to a python numeric value, since we only copy values in the numeric type caster:
// int &int_ref() override { PYBIND11_OVERLOAD(int &, OverrideTest, int_ref); }
A
A_value
()
override
{
PYBIND11_OVERLOAD
(
A
,
OverrideTest
,
A_value
);
}
A
&
A_ref
()
override
{
PYBIND11_OVERLOAD
(
A
&
,
OverrideTest
,
A_ref
);
}
};
py
::
class_
<
OverrideTest
::
A
>
(
m2
,
"OverrideTest_A"
)
.
def_readwrite
(
"value"
,
&
OverrideTest
::
A
::
value
);
py
::
class_
<
OverrideTest
,
PyOverrideTest
>
(
m2
,
"OverrideTest"
)
.
def
(
py
::
init
<
int
>
())
.
def
(
"int_value"
,
&
OverrideTest
::
int_value
)
// .def("int_ref", &OverrideTest::int_ref)
.
def
(
"A_value"
,
&
OverrideTest
::
A_value
)
.
def
(
"A_ref"
,
&
OverrideTest
::
A_ref
);
}
// MSVC workaround: trying to use a lambda here crashes MSCV
...
...
tests/test_issues.py
View file @
5812d64b
...
...
@@ -166,3 +166,18 @@ def test_move_fallback():
assert
m2
.
value
==
2
m1
=
get_moveissue1
(
1
)
assert
m1
.
value
==
1
def
test_override_ref
():
from
pybind11_tests.issues
import
OverrideTest
o
=
OverrideTest
(
42
)
# Not allowed (see associated .cpp comment)
#i = o.int_ref()
#assert o.int_ref() == 42
assert
o
.
int_value
()
==
42
assert
o
.
A_value
().
value
==
99
a
=
o
.
A_ref
()
assert
a
.
value
==
99
a
.
value
=
7
assert
a
.
value
==
7
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment