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
cc88aaec
"example/example-numpy-dtypes.py" did not exist on "103d5eadc36ccc361474c7793bf4b588b16fce23"
Commit
cc88aaec
authored
Jan 31, 2017
by
Pim Schellart
Committed by
Wenzel Jakob
Jan 31, 2017
Browse files
Add check for matching holder_type when inheriting (#588)
parent
7830e850
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
53 additions
and
1 deletion
+53
-1
include/pybind11/attr.h
include/pybind11/attr.h
+12
-0
include/pybind11/cast.h
include/pybind11/cast.h
+2
-0
include/pybind11/pybind11.h
include/pybind11/pybind11.h
+2
-0
tests/test_inheritance.cpp
tests/test_inheritance.cpp
+17
-0
tests/test_inheritance.py
tests/test_inheritance.py
+20
-1
No files found.
include/pybind11/attr.h
View file @
cc88aaec
...
...
@@ -185,6 +185,9 @@ struct type_record {
/// Does the class require its own metaclass?
bool
metaclass
:
1
;
/// Is the default (unique_ptr) holder type used?
bool
default_holder
:
1
;
PYBIND11_NOINLINE
void
add_base
(
const
std
::
type_info
*
base
,
void
*
(
*
caster
)(
void
*
))
{
auto
base_info
=
detail
::
get_type_info
(
*
base
,
false
);
if
(
!
base_info
)
{
...
...
@@ -194,6 +197,15 @@ struct type_record {
"
\"
referenced unknown base type
\"
"
+
tname
+
"
\"
"
);
}
if
(
default_holder
!=
base_info
->
default_holder
)
{
std
::
string
tname
(
base
->
name
());
detail
::
clean_type_id
(
tname
);
pybind11_fail
(
"generic_type: type
\"
"
+
std
::
string
(
name
)
+
"
\"
"
+
(
default_holder
?
"does not have"
:
"has"
)
+
" a non-default holder type while its base
\"
"
+
tname
+
"
\"
"
+
(
base_info
->
default_holder
?
"does not"
:
"does"
));
}
bases
.
append
((
PyObject
*
)
base_info
->
type
);
if
(
base_info
->
type
->
tp_dictoffset
!=
0
)
...
...
include/pybind11/cast.h
View file @
cc88aaec
...
...
@@ -32,6 +32,8 @@ struct type_info {
/** A simple type never occurs as a (direct or indirect) parent
* of a class that makes use of multiple inheritance */
bool
simple_type
=
true
;
/* for base vs derived holder_type checks */
bool
default_holder
=
true
;
};
PYBIND11_NOINLINE
inline
internals
&
get_internals
()
{
...
...
include/pybind11/pybind11.h
View file @
cc88aaec
...
...
@@ -741,6 +741,7 @@ protected:
tinfo
->
type_size
=
rec
->
type_size
;
tinfo
->
init_holder
=
rec
->
init_holder
;
tinfo
->
direct_conversions
=
&
internals
.
direct_conversions
[
tindex
];
tinfo
->
default_holder
=
rec
->
default_holder
;
internals
.
registered_types_cpp
[
tindex
]
=
tinfo
;
internals
.
registered_types_py
[
type
]
=
tinfo
;
...
...
@@ -1006,6 +1007,7 @@ public:
record
.
instance_size
=
sizeof
(
instance_type
);
record
.
init_holder
=
init_holder
;
record
.
dealloc
=
dealloc
;
record
.
default_holder
=
std
::
is_same
<
holder_type
,
std
::
unique_ptr
<
type
>>::
value
;
/* Register base classes specified via template arguments to class_, if any */
bool
unused
[]
=
{
(
add_base
<
options
>
(
record
),
false
)...,
false
};
...
...
tests/test_inheritance.cpp
View file @
cc88aaec
...
...
@@ -49,6 +49,12 @@ struct BaseClass { virtual ~BaseClass() {} };
struct
DerivedClass1
:
BaseClass
{
};
struct
DerivedClass2
:
BaseClass
{
};
struct
MismatchBase1
{
};
struct
MismatchDerived1
:
MismatchBase1
{
};
struct
MismatchBase2
{
};
struct
MismatchDerived2
:
MismatchBase2
{
};
test_initializer
inheritance
([](
py
::
module
&
m
)
{
py
::
class_
<
Pet
>
pet_class
(
m
,
"Pet"
);
pet_class
...
...
@@ -97,4 +103,15 @@ test_initializer inheritance([](py::module &m) {
py
::
isinstance
<
Unregistered
>
(
l
[
6
])
);
});
m
.
def
(
"test_mismatched_holder_type_1"
,
[]()
{
auto
m
=
py
::
module
::
import
(
"__main__"
);
py
::
class_
<
MismatchBase1
,
std
::
shared_ptr
<
MismatchBase1
>>
(
m
,
"MismatchBase1"
);
py
::
class_
<
MismatchDerived1
,
MismatchBase1
>
(
m
,
"MismatchDerived1"
);
});
m
.
def
(
"test_mismatched_holder_type_2"
,
[]()
{
auto
m
=
py
::
module
::
import
(
"__main__"
);
py
::
class_
<
MismatchBase2
>
(
m
,
"MismatchBase2"
);
py
::
class_
<
MismatchDerived2
,
std
::
shared_ptr
<
MismatchDerived2
>
,
MismatchBase2
>
(
m
,
"MismatchDerived2"
);
});
});
tests/test_inheritance.py
View file @
cc88aaec
...
...
@@ -37,7 +37,8 @@ def test_automatic_upcasting():
assert
type
(
return_class_1
()).
__name__
==
"DerivedClass1"
assert
type
(
return_class_2
()).
__name__
==
"DerivedClass2"
assert
type
(
return_none
()).
__name__
==
"NoneType"
# Repeat these a few times in a random order to ensure no invalid caching is applied
# Repeat these a few times in a random order to ensure no invalid caching
# is applied
assert
type
(
return_class_n
(
1
)).
__name__
==
"DerivedClass1"
assert
type
(
return_class_n
(
2
)).
__name__
==
"DerivedClass2"
assert
type
(
return_class_n
(
0
)).
__name__
==
"BaseClass"
...
...
@@ -53,3 +54,21 @@ def test_isinstance():
objects
=
[
tuple
(),
dict
(),
Pet
(
"Polly"
,
"parrot"
)]
+
[
Dog
(
"Molly"
)]
*
4
expected
=
(
True
,
True
,
True
,
True
,
True
,
False
,
False
)
assert
test_isinstance
(
objects
)
==
expected
def
test_holder
():
from
pybind11_tests
import
test_mismatched_holder_type_1
,
test_mismatched_holder_type_2
with
pytest
.
raises
(
RuntimeError
)
as
excinfo
:
test_mismatched_holder_type_1
()
assert
str
(
excinfo
.
value
)
==
(
"generic_type: type
\"
MismatchDerived1
\"
does not have "
"a non-default holder type while its base "
"
\"
MismatchBase1
\"
does"
)
with
pytest
.
raises
(
RuntimeError
)
as
excinfo
:
test_mismatched_holder_type_2
()
assert
str
(
excinfo
.
value
)
==
(
"generic_type: type
\"
MismatchDerived2
\"
has a "
"non-default holder type while its base "
"
\"
MismatchBase2
\"
does not"
)
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