Commit 3a728498 authored by scoder's avatar scoder

Merge pull request #335 from BigFav/master

Generate warning when Python object is used as C++ container reference parameter.
parents cde87ac4 c66287f6
...@@ -2870,7 +2870,8 @@ class IndexNode(ExprNode): ...@@ -2870,7 +2870,8 @@ class IndexNode(ExprNode):
type_node = Nodes.TemplatedTypeNode( type_node = Nodes.TemplatedTypeNode(
pos = self.pos, pos = self.pos,
positional_args = template_values, positional_args = template_values,
keyword_args = None) keyword_args = None,
is_reference = False)
return type_node.analyse(env, base_type = base_type) return type_node.analyse(env, base_type = base_type)
else: else:
index = self.index.compile_time_value(env) index = self.index.compile_time_value(env)
...@@ -11376,6 +11377,11 @@ class CoerceFromPyTypeNode(CoercionNode): ...@@ -11376,6 +11377,11 @@ class CoerceFromPyTypeNode(CoercionNode):
if not result_type.create_from_py_utility_code(env): if not result_type.create_from_py_utility_code(env):
error(arg.pos, error(arg.pos,
"Cannot convert Python object to '%s'" % result_type) "Cannot convert Python object to '%s'" % result_type)
elif result_type.is_reference:
warning(arg.pos,
"Cannot pass Python object as C++ data structure "
"reference (%s &), will pass by copy." % result_type,
level=1)
if self.type.is_string or self.type.is_pyunicode_ptr: if self.type.is_string or self.type.is_pyunicode_ptr:
if self.arg.is_name and self.arg.entry and self.arg.entry.is_pyglobal: if self.arg.is_name and self.arg.entry and self.arg.entry.is_pyglobal:
warning(arg.pos, warning(arg.pos,
......
...@@ -1110,7 +1110,7 @@ class TemplatedTypeNode(CBaseTypeNode): ...@@ -1110,7 +1110,7 @@ class TemplatedTypeNode(CBaseTypeNode):
error(template_node.pos, "unknown type in template argument") error(template_node.pos, "unknown type in template argument")
return error_type return error_type
template_types.append(type) template_types.append(type)
self.type = base_type.specialize_here(self.pos, template_types) self.type = base_type.specialize_here(self.pos, template_types, is_reference=self.is_reference)
elif base_type.is_pyobject: elif base_type.is_pyobject:
# Buffer # Buffer
...@@ -2821,7 +2821,6 @@ class DefNode(FuncDefNode): ...@@ -2821,7 +2821,6 @@ class DefNode(FuncDefNode):
error(arg.pos, "Only Python type arguments can have 'not None'") error(arg.pos, "Only Python type arguments can have 'not None'")
if arg.or_none: if arg.or_none:
error(arg.pos, "Only Python type arguments can have 'or None'") error(arg.pos, "Only Python type arguments can have 'or None'")
env.fused_to_specific = f2s env.fused_to_specific = f2s
def analyse_signature(self, env): def analyse_signature(self, env):
......
...@@ -2168,7 +2168,8 @@ def p_buffer_or_template(s, base_type_node, templates): ...@@ -2168,7 +2168,8 @@ def p_buffer_or_template(s, base_type_node, templates):
result = Nodes.TemplatedTypeNode(pos, result = Nodes.TemplatedTypeNode(pos,
positional_args = positional_args, positional_args = positional_args,
keyword_args = keyword_dict, keyword_args = keyword_dict,
base_type_node = base_type_node) base_type_node = base_type_node,
is_reference = (s.sy == '&'))
return result return result
def p_bracketed_base_type(s, base_type_node, nonempty, empty): def p_bracketed_base_type(s, base_type_node, nonempty, empty):
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
from __future__ import absolute_import from __future__ import absolute_import
import re
import copy import copy
import re import re
...@@ -3217,7 +3216,7 @@ class CppClassType(CType): ...@@ -3217,7 +3216,7 @@ class CppClassType(CType):
subtypes = ['templates'] subtypes = ['templates']
def __init__(self, name, scope, cname, base_classes, templates = None, template_type = None): def __init__(self, name, scope, cname, base_classes, templates = None, template_type = None, is_reference = False):
self.name = name self.name = name
self.cname = cname self.cname = cname
self.scope = scope self.scope = scope
...@@ -3227,6 +3226,7 @@ class CppClassType(CType): ...@@ -3227,6 +3226,7 @@ class CppClassType(CType):
self.template_type = template_type self.template_type = template_type
self.specializations = {} self.specializations = {}
self.is_cpp_string = cname in cpp_string_conversions self.is_cpp_string = cname in cpp_string_conversions
self.is_reference = is_reference
def use_conversion_utility(self, from_or_to): def use_conversion_utility(self, from_or_to):
pass pass
...@@ -3350,7 +3350,7 @@ class CppClassType(CType): ...@@ -3350,7 +3350,7 @@ class CppClassType(CType):
T.get_fused_types(result, seen) T.get_fused_types(result, seen)
return result return result
def specialize_here(self, pos, template_values = None): def specialize_here(self, pos, template_values = None, is_reference = False):
if not self.is_template_type(): if not self.is_template_type():
error(pos, "'%s' type is not a template" % self) error(pos, "'%s' type is not a template" % self)
return error_type return error_type
...@@ -3366,19 +3366,19 @@ class CppClassType(CType): ...@@ -3366,19 +3366,19 @@ class CppClassType(CType):
"Python object type '%s' cannot be used as a template argument" % value) "Python object type '%s' cannot be used as a template argument" % value)
if has_object_template_param: if has_object_template_param:
return error_type return error_type
return self.specialize(dict(zip(self.templates, template_values))) return self.specialize(dict(zip(self.templates, template_values)), is_reference)
def specialize(self, values): def specialize(self, values, is_reference = False):
if not self.templates and not self.namespace: if not self.templates and not self.namespace:
return self return self
if self.templates is None: if self.templates is None:
self.templates = [] self.templates = []
key = tuple(values.items()) key = tuple(values.items()) + (is_reference,)
if key in self.specializations: if key in self.specializations:
return self.specializations[key] return self.specializations[key]
template_values = [t.specialize(values) for t in self.templates] template_values = [t.specialize(values) for t in self.templates]
specialized = self.specializations[key] = \ specialized = self.specializations[key] = \
CppClassType(self.name, None, self.cname, [], template_values, template_type=self) CppClassType(self.name, None, self.cname, [], template_values, template_type=self, is_reference=is_reference)
# Need to do these *after* self.specializations[key] is set # Need to do these *after* self.specializations[key] is set
# to avoid infinite recursion on circular references. # to avoid infinite recursion on circular references.
specialized.base_classes = [b.specialize(values) for b in self.base_classes] specialized.base_classes = [b.specialize(values) for b in self.base_classes]
......
# mode: error
# tag: werror
import numpy as np
cimport numpy as np
from libcpp.vector cimport vector
cdef extern from *:
void cpp_function_vector1(vector[int])
void cpp_function_vector2(vector[int] &)
void cpp_function_2_vec_refs(vector[int] &, vector[int] &)
def main():
cdef np.ndarray[int, ndim=1, mode="c"] arr = np.zeros(10, dtype='intc')
cpp_function_vector1(arr)
cpp_function_vector2(arr)
cpp_function_vector2(arr)
cpp_function_2_vec_refs(arr, arr)
cdef vector[int] vec
vec.push_back(0)
cpp_function_vector2(vec)
_ERRORS = """
17:28: Cannot pass Python object as C++ data structure reference (vector[int] &), will pass by copy.
18:28: Cannot pass Python object as C++ data structure reference (vector[int] &), will pass by copy.
19:31: Cannot pass Python object as C++ data structure reference (vector[int] &), will pass by copy.
19:36: Cannot pass Python object as C++ data structure reference (vector[int] &), will pass by copy.
31:15: '<init>' redeclared
31:15: '<init>' redeclared
32:15: '<init>' redeclared
32:15: '<init>' redeclared
32:15: '<init>' redeclared
33:15: '<init>' redeclared
33:15: '<init>' redeclared
33:15: '<init>' redeclared
34:15: '<init>' redeclared
44:19: 'assign' redeclared
44:19: 'assign' redeclared
45:35: 'assign' redeclared
55:22: 'erase' redeclared
55:22: 'erase' redeclared
56:22: 'erase' redeclared
58:23: 'insert' redeclared
58:23: 'insert' redeclared
59:19: 'insert' redeclared
59:19: 'insert' redeclared
59:19: 'insert' redeclared
60:19: 'insert' redeclared
69:19: 'resize' redeclared
69:19: 'resize' redeclared
70:19: 'resize' redeclared
"""
# mode: error
# tag: werror
from libcpp.set cimport set
cdef extern from "foo.cpp":
void cpp_function_set1(set[int])
void cpp_function_set2(set[int] &)
def pass_py_obj_as_cpp_cont_ref():
cdef list ordered_set = [0, 0, 0, 0, 0]
cpp_function_set1(ordered_set)
cpp_function_set2(ordered_set)
_ERRORS = """
5:13: '<init>' redeclared
5:13: '<init>' redeclared
6:13: '<init>' redeclared
6:13: '<init>' redeclared
6:13: '<init>' redeclared
6:13: '<init>' redeclared
6:13: '<init>' redeclared
7:13: '<init>' redeclared
7:13: '<init>' redeclared
7:13: '<init>' redeclared
14:33: Cannot pass Python object as C++ data structure reference (set[int] &), will pass by copy.
21:12: '<init>' redeclared
21:12: '<init>' redeclared
22:12: '<init>' redeclared
40:18: 'erase' redeclared
40:18: 'erase' redeclared
41:18: 'erase' redeclared
41:18: 'erase' redeclared
41:18: 'erase' redeclared
42:20: 'erase' redeclared
45:35: 'insert' redeclared
45:35: 'insert' redeclared
46:23: 'insert' redeclared
"""
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