Commit e1939449 authored by Xavier Thompson's avatar Xavier Thompson

Implement runtime isolation check for template fields

parent 5c79474f
...@@ -975,12 +975,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -975,12 +975,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
""" """
scope = entry.type.scope scope = entry.type.scope
check_cypclass_attrs = [ check_cypclass_attrs = []
e check_template_attrs = []
for e in scope.entries.values() for e in scope.entries.values():
if e.type.is_cyp_class and e.name != "this" and not e.is_type if e.is_type or e.name == "this":
and not e.type.is_qualified_cyp_class continue
] elif e.type.is_cyp_class and not e.type.is_qualified_cyp_class:
check_cypclass_attrs.append(e)
elif e.type.is_template_typename:
check_template_attrs.append(e)
# potential template # potential template
if entry.type.templates: if entry.type.templates:
templates_code = "template <typename %s>" % ", typename ".join(t.name for t in entry.type.templates) templates_code = "template <typename %s>" % ", typename ".join(t.name for t in entry.type.templates)
...@@ -994,13 +997,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -994,13 +997,15 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln("{") code.putln("{")
for attr in check_cypclass_attrs: for attr in check_cypclass_attrs:
code.putln("visit(this->%s, arg);" % attr.cname) code.putln("visit(this->%s, arg);" % attr.cname)
for attr in check_template_attrs:
code.putln("__Pyx_CyObject_visit_template(visit, this->%s, arg);" % attr.cname)
code.putln("}") code.putln("}")
# isolation check method # isolation check method
if templates_code: if templates_code:
code.putln(templates_code) code.putln(templates_code)
code.putln("int %s::CyObject_iso() const" % namespace) code.putln("int %s::CyObject_iso() const" % namespace)
code.putln("{") code.putln("{")
if check_cypclass_attrs: if check_cypclass_attrs or check_template_attrs:
code.putln("return __Pyx_CyObject_owning(this) == 1;") code.putln("return __Pyx_CyObject_owning(this) == 1;")
else: else:
code.putln("return this->CyObject_GETREF() == 1;") code.putln("return this->CyObject_GETREF() == 1;")
......
...@@ -6010,6 +6010,8 @@ def template_parameter_code(T, for_display = 0, pyrex = 0): ...@@ -6010,6 +6010,8 @@ def template_parameter_code(T, for_display = 0, pyrex = 0):
Return the code string for a template parameter in a template instanciation. Return the code string for a template parameter in a template instanciation.
""" """
if T.is_cyp_class and not for_display: if T.is_cyp_class and not for_display:
if T.is_qualified_cyp_class:
return "Cy_Ref<%s, true>" % T.empty_declaration_code()
return "Cy_Ref<%s>" % T.empty_declaration_code() return "Cy_Ref<%s>" % T.empty_declaration_code()
else: else:
return T.declaration_code('', for_display, None, pyrex) return T.declaration_code('', for_display, None, pyrex)
...@@ -135,7 +135,7 @@ ...@@ -135,7 +135,7 @@
template <typename T> template <typename T>
struct Cy_has_hash<T, typename std::enable_if<std::is_convertible<decltype( std::declval<T>().__hash__() ), std::size_t>::value>::type> : std::true_type {}; struct Cy_has_hash<T, typename std::enable_if<std::is_convertible<decltype( std::declval<T>().__hash__() ), std::size_t>::value>::type> : std::true_type {};
template <typename T> template <typename T, bool iso = false>
struct Cy_Ref_impl { struct Cy_Ref_impl {
T* uobj = nullptr; T* uobj = nullptr;
...@@ -151,8 +151,8 @@ ...@@ -151,8 +151,8 @@
} }
} }
template<typename U, typename std::enable_if<std::is_convertible<U*, T*>::value, int>::type = 0> template<typename U, bool _iso, typename std::enable_if<std::is_convertible<U*, T*>::value, int>::type = 0>
Cy_Ref_impl(const Cy_Ref_impl<U>& rhs) : uobj(rhs.uobj) { Cy_Ref_impl(const Cy_Ref_impl<U, _iso>& rhs) : uobj(rhs.uobj) {
if (uobj != nullptr) { if (uobj != nullptr) {
uobj->CyObject_INCREF(); uobj->CyObject_INCREF();
} }
...@@ -162,8 +162,8 @@ ...@@ -162,8 +162,8 @@
rhs.uobj = nullptr; rhs.uobj = nullptr;
} }
template<typename U, typename std::enable_if<std::is_convertible<U*, T*>::value, int>::type = 0> template<typename U, bool _iso, typename std::enable_if<std::is_convertible<U*, T*>::value, int>::type = 0>
Cy_Ref_impl(Cy_Ref_impl<U>&& rhs) noexcept : uobj(rhs.uobj) { Cy_Ref_impl(Cy_Ref_impl<U, _iso>&& rhs) noexcept : uobj(rhs.uobj) {
rhs.uobj = nullptr; rhs.uobj = nullptr;
} }
...@@ -204,8 +204,8 @@ ...@@ -204,8 +204,8 @@
return obj; return obj;
} }
template <typename U> template <typename U, bool _iso>
bool operator==(const Cy_Ref_impl<U>& rhs) const noexcept { bool operator==(const Cy_Ref_impl<U, _iso>& rhs) const noexcept {
return uobj == rhs.uobj; return uobj == rhs.uobj;
} }
...@@ -215,7 +215,7 @@ ...@@ -215,7 +215,7 @@
} }
template <typename U> template <typename U>
friend bool operator==(U* lhs, const Cy_Ref_impl<T>& rhs) noexcept { friend bool operator==(U* lhs, const Cy_Ref_impl<T, iso>& rhs) noexcept {
return lhs == rhs.uobj; return lhs == rhs.uobj;
} }
...@@ -223,12 +223,12 @@ ...@@ -223,12 +223,12 @@
return uobj == nullptr; return uobj == nullptr;
} }
friend bool operator==(std::nullptr_t, const Cy_Ref_impl<T>& rhs) noexcept { friend bool operator==(std::nullptr_t, const Cy_Ref_impl<T, iso>& rhs) noexcept {
return rhs.uobj == nullptr; return rhs.uobj == nullptr;
} }
template <typename U> template <typename U, bool _iso>
bool operator!=(const Cy_Ref_impl<U>& rhs) const noexcept { bool operator!=(const Cy_Ref_impl<U, _iso>& rhs) const noexcept {
return uobj != rhs.uobj; return uobj != rhs.uobj;
} }
...@@ -238,7 +238,7 @@ ...@@ -238,7 +238,7 @@
} }
template <typename U> template <typename U>
friend bool operator!=(U* lhs, const Cy_Ref_impl<T>& rhs) noexcept { friend bool operator!=(U* lhs, const Cy_Ref_impl<T, iso>& rhs) noexcept {
return lhs != rhs.uobj; return lhs != rhs.uobj;
} }
...@@ -246,52 +246,57 @@ ...@@ -246,52 +246,57 @@
return uobj != nullptr; return uobj != nullptr;
} }
friend bool operator!=(std::nullptr_t, const Cy_Ref_impl<T>& rhs) noexcept { friend bool operator!=(std::nullptr_t, const Cy_Ref_impl<T, iso>& rhs) noexcept {
return rhs.uobj != nullptr; return rhs.uobj != nullptr;
} }
}; };
namespace std { namespace std {
template <typename T> template <typename T, bool iso>
struct hash<Cy_Ref_impl<T>> { struct hash<Cy_Ref_impl<T, iso>> {
template <typename U = T, typename std::enable_if<!Cy_has_hash<U>::value, int>::type = 0> template <typename U = T, typename std::enable_if<!Cy_has_hash<U>::value, int>::type = 0>
size_t operator()(const Cy_Ref_impl<T>& ref) const { size_t operator()(const Cy_Ref_impl<T, iso>& ref) const {
static_assert(!Cy_has_equality<U>::value, "Cypclasses that define __eq__ must also define __hash__ to be hashable"); static_assert(!Cy_has_equality<U>::value, "Cypclasses that define __eq__ must also define __hash__ to be hashable");
return std::hash<T*>()(ref.uobj); return std::hash<T*>()(ref.uobj);
} }
template <typename U = T, typename std::enable_if<Cy_has_hash<U>::value, int>::type = 0> template <typename U = T, typename std::enable_if<Cy_has_hash<U>::value, int>::type = 0>
size_t operator()(const Cy_Ref_impl<T>& ref) const { size_t operator()(const Cy_Ref_impl<T, iso>& ref) const {
static_assert(Cy_has_equality<U>::value, "Cypclasses that define __hash__ must also define __eq__ to be hashable"); static_assert(Cy_has_equality<U>::value, "Cypclasses that define __hash__ must also define __eq__ to be hashable");
return ref.uobj->__hash__(); return ref.uobj->__hash__();
} }
}; };
template <typename T> template <typename T, bool iso>
struct equal_to<Cy_Ref_impl<T>> { struct equal_to<Cy_Ref_impl<T, iso>> {
template <typename U = T, typename std::enable_if<!Cy_has_equality<U>::value, int>::type = 0> template <typename U = T, typename std::enable_if<!Cy_has_equality<U>::value, int>::type = 0>
bool operator()(const Cy_Ref_impl<T>& lhs, const Cy_Ref_impl<T>& rhs) const { bool operator()(const Cy_Ref_impl<T, iso>& lhs, const Cy_Ref_impl<T, iso>& rhs) const {
return lhs.uobj == rhs.uobj; return lhs.uobj == rhs.uobj;
} }
template <typename U = T, typename std::enable_if<Cy_has_equality<U>::value, int>::type = 0> template <typename U = T, typename std::enable_if<Cy_has_equality<U>::value, int>::type = 0>
bool operator()(const Cy_Ref_impl<T>& lhs, const Cy_Ref_impl<T>& rhs) const { bool operator()(const Cy_Ref_impl<T, iso>& lhs, const Cy_Ref_impl<T, iso>& rhs) const {
Cy_INCREF(rhs.uobj); Cy_INCREF(rhs.uobj);
return lhs.uobj->operator==(rhs.uobj); return lhs.uobj->operator==(rhs.uobj);
} }
}; };
} }
template <typename T> template <typename T, bool iso = false>
struct Cy_Ref_t { struct Cy_Ref_t {
using type = Cy_Ref_impl<T>; using type = Cy_Ref_impl<T, iso>;
}; };
template <typename T> template <typename T>
struct Cy_Ref_t<Cy_Ref_impl<T>> { struct Cy_Ref_t<Cy_Ref_impl<T, false>> {
using type = Cy_Ref_impl<T>; using type = Cy_Ref_impl<T, false>;
}; };
template <typename T> template <typename T>
using Cy_Ref = typename Cy_Ref_t<T>::type; struct Cy_Ref_t<Cy_Ref_impl<T, true>> {
using type = Cy_Ref_impl<T, true>;
};
template <typename T, bool iso = false>
using Cy_Ref = typename Cy_Ref_t<T, iso>::type;
template <typename T> template <typename T>
struct Cy_Raw_t { struct Cy_Raw_t {
...@@ -299,7 +304,12 @@ ...@@ -299,7 +304,12 @@
}; };
template <typename T> template <typename T>
struct Cy_Raw_t<Cy_Ref_impl<T>> { struct Cy_Raw_t<Cy_Ref_impl<T, false>> {
using type = T*;
};
template <typename T>
struct Cy_Raw_t<Cy_Ref_impl<T, true>> {
using type = T*; using type = T*;
}; };
...@@ -489,6 +499,25 @@ ...@@ -489,6 +499,25 @@
return ob; return ob;
} }
/*
* Traverse template fields.
*/
template <typename T>
struct Cy_traverse_iso : std::false_type {};
template <typename T>
struct Cy_traverse_iso<Cy_Ref_impl<T, false>> : std::true_type {};
template <typename T, typename std::enable_if<!Cy_traverse_iso<T>::value, int>::type = 0>
static inline void __Pyx_CyObject_visit_template(void (*visit)(const CyObject *o, void*arg), const T& o, void *arg) {
}
template <typename T, typename std::enable_if<Cy_traverse_iso<T>::value, int>::type = 0>
static inline void __Pyx_CyObject_visit_template(void (*visit)(const CyObject *o, void*arg), const T& o, void *arg) {
visit(o.uobj, arg);
}
/* /*
* Visit callback to collect reachable fields. * Visit callback to collect reachable fields.
*/ */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment