Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 13 additions & 9 deletions src/cpyrt/Converters.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -3382,15 +3382,19 @@ cppjit::cpyrt::CreateConverter(const std::string& fullType, cdims_t dims) {
return (h->second)(dims);

// mutable pointer references (T*&) are incompatible with Python's object
// model
// model; a string that resolves to no type keeps the ban
if (!isConst && cpd == "*&") {
return new NotImplementedConverter{
PyExc_TypeError,
"argument type '" + resolvedType +
"' is not supported: non-const references to pointers (T*&) allow a"
" function to replace the pointer itself. Python cannot represent "
"this safely. Consider changing the"
" C++ API to return the new pointer or use a wrapper"};
interop::TCppType_t refType =
interop::GetType(resolvedType, /* enable_slow_lookup */ true);
if (!refType || interop::IsMutablePtrRefType(refType)) {
return new NotImplementedConverter{
PyExc_TypeError,
"argument type '" + resolvedType +
"' is not supported: non-const references to pointers (T*&) "
"allow a function to replace the pointer itself. Python cannot "
"represent this safely. Consider changing the"
" C++ API to return the new pointer or use a wrapper"};
}
}

// drop const, as that is mostly meaningless to python (with the exception
Expand Down Expand Up @@ -3615,7 +3619,7 @@ cppjit::cpyrt::CreateConverter(interop::TCppType_t type, cdims_t dims) {

// mutable pointer references (T*&) are incompatible with Python's object
// model
if (!isConst && cpd == "*&") {
if (!isConst && cpd == "*&" && interop::IsMutablePtrRefType(resolvedType)) {
return new NotImplementedConverter{
PyExc_TypeError,
"argument type '" + resolvedTypeStr +
Expand Down
2 changes: 2 additions & 0 deletions src/interop/cppjit_interop.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,8 @@ std::string ResolveEnum(TCppScope_t enum_scope);
RPY_EXPORTED
bool IsLValueReferenceType(TCppType_t type);
RPY_EXPORTED
bool IsMutablePtrRefType(TCppType_t type);
RPY_EXPORTED
bool IsRValueReferenceType(TCppType_t type);
RPY_EXPORTED
bool IsClassType(TCppType_t type);
Expand Down
10 changes: 10 additions & 0 deletions src/interop/interop_wrapper.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,16 @@ bool interop::IsLValueReferenceType(TCppType_t type) {
return Cpp::GetValueKind(type) == Cpp::ValueKind::LValue;
}

// Whether the callee can rebind a pointer through this reference (T*&);
// false for T* const& and for references to non-pointers.
bool interop::IsMutablePtrRefType(TCppType_t type) {
if (!Cpp::IsReferenceType(type))
return false;
TCppType_t nonref = Cpp::GetNonReferenceType(type);
return Cpp::IsPointerType(nonref) &&
!Cpp::HasTypeQualifier(nonref, Cpp::QualKind::Const);
}

bool interop::IsClassType(TCppType_t type) { return Cpp::IsRecordType(type); }

bool interop::IsIntegerType(TCppType_t type, bool* is_signed /*= nullptr*/) {
Expand Down
22 changes: 22 additions & 0 deletions test/test_conversions.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,28 @@ def test05_bool_conversions(self):
assert ns.Test2(True)
assert not ns.Test2(False)

def test06_pointer_const_reference(self):
"""A T* const& argument is accepted; only T*& is banned"""

import cppjit

cppjit.cppdef("""\
namespace PtrConstRef {
struct A { int v = 3; };
int by_const_ref(A* const& a) { return a->v; }
void by_mutable_ref(A*& a) { a = nullptr; }
}""")

ns = cppjit.gbl.PtrConstRef
a = ns.A()

# the callee cannot rebind the pointer, so this is safe to pass
assert ns.by_const_ref(a) == 3

# a mutable pointer reference stays unsupported
with raises(TypeError):
ns.by_mutable_ref(a)

def test07_mutable_voidp_reference(self):
"""An object can be passed through a non-const void*& argument"""

Expand Down
Loading