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):
type_node = Nodes.TemplatedTypeNode(
pos = self.pos,
positional_args = template_values,
keyword_args = None)
keyword_args = None,
is_reference = False)
return type_node.analyse(env, base_type = base_type)
else:
index = self.index.compile_time_value(env)
......@@ -11376,6 +11377,11 @@ class CoerceFromPyTypeNode(CoercionNode):
if not result_type.create_from_py_utility_code(env):
error(arg.pos,
"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.arg.is_name and self.arg.entry and self.arg.entry.is_pyglobal:
warning(arg.pos,
......
......@@ -1110,7 +1110,7 @@ class TemplatedTypeNode(CBaseTypeNode):
error(template_node.pos, "unknown type in template argument")
return error_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:
# Buffer
......@@ -2821,7 +2821,6 @@ class DefNode(FuncDefNode):
error(arg.pos, "Only Python type arguments can have 'not None'")
if arg.or_none:
error(arg.pos, "Only Python type arguments can have 'or None'")
env.fused_to_specific = f2s
def analyse_signature(self, env):
......
......@@ -2168,7 +2168,8 @@ def p_buffer_or_template(s, base_type_node, templates):
result = Nodes.TemplatedTypeNode(pos,
positional_args = positional_args,
keyword_args = keyword_dict,
base_type_node = base_type_node)
base_type_node = base_type_node,
is_reference = (s.sy == '&'))
return result
def p_bracketed_base_type(s, base_type_node, nonempty, empty):
......
......@@ -4,7 +4,6 @@
from __future__ import absolute_import
import re
import copy
import re
......@@ -3217,7 +3216,7 @@ class CppClassType(CType):
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.cname = cname
self.scope = scope
......@@ -3227,6 +3226,7 @@ class CppClassType(CType):
self.template_type = template_type
self.specializations = {}
self.is_cpp_string = cname in cpp_string_conversions
self.is_reference = is_reference
def use_conversion_utility(self, from_or_to):
pass
......@@ -3350,7 +3350,7 @@ class CppClassType(CType):
T.get_fused_types(result, seen)
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():
error(pos, "'%s' type is not a template" % self)
return error_type
......@@ -3366,19 +3366,19 @@ class CppClassType(CType):
"Python object type '%s' cannot be used as a template argument" % value)
if has_object_template_param:
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:
return self
if self.templates is None:
self.templates = []
key = tuple(values.items())
key = tuple(values.items()) + (is_reference,)
if key in self.specializations:
return self.specializations[key]
template_values = [t.specialize(values) for t in self.templates]
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
# to avoid infinite recursion on circular references.
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