Commit ec5a056e authored by Jeroen Demeyer's avatar Jeroen Demeyer

Support for "volatile" keyword

parent 4b64bbe1
......@@ -822,8 +822,8 @@ class FunctionState(object):
A C string referring to the variable is returned.
"""
if type.is_const and not type.is_reference:
type = type.const_base_type
if type.is_cv_qualified and not type.is_reference:
type = type.cv_base_type
elif type.is_reference and not type.is_fake_reference:
type = type.ref_base_type
if not type.is_pyobject and not type.is_memoryviewslice:
......
......@@ -881,8 +881,8 @@ class ExprNode(Node):
if used_as_reference and not src_type.is_reference:
dst_type = dst_type.ref_base_type
if src_type.is_const:
src_type = src_type.const_base_type
if src_type.is_cv_qualified:
src_type = src_type.cv_base_type
if src_type.is_fused or dst_type.is_fused:
# See if we are coercing a fused function to a pointer to a
......@@ -2868,8 +2868,8 @@ class NextNode(AtomicExprNode):
item_type = env.lookup_operator_for_types(self.pos, "*", [iterator_type]).type.return_type
if item_type.is_reference:
item_type = item_type.ref_base_type
if item_type.is_const:
item_type = item_type.const_base_type
if item_type.is_cv_qualified:
item_type = item_type.cv_base_type
return item_type
else:
# Avoid duplication of complicated logic.
......
......@@ -487,7 +487,7 @@ def copy_c_or_fortran_cname(memview):
def get_copy_new_utility(pos, from_memview, to_memview):
if (from_memview.dtype != to_memview.dtype and
not (from_memview.dtype.is_const and from_memview.dtype.const_base_type == to_memview.dtype)):
not (from_memview.dtype.is_cv_qualified and from_memview.dtype.cv_base_type == to_memview.dtype)):
error(pos, "dtypes must be the same!")
return
if len(from_memview.axes) != len(to_memview.axes):
......
......@@ -1273,8 +1273,10 @@ class FusedTypeNode(CBaseTypeNode):
return PyrexTypes.FusedType(types, name=self.name)
class CConstTypeNode(CBaseTypeNode):
class CConstOrVolatileTypeNode(CBaseTypeNode):
# base_type CBaseTypeNode
# is_const boolean
# is_volatile boolean
child_attrs = ["base_type"]
......@@ -1282,8 +1284,8 @@ class CConstTypeNode(CBaseTypeNode):
base = self.base_type.analyse(env, could_be_name)
if base.is_pyobject:
error(self.pos,
"Const base type cannot be a Python object")
return PyrexTypes.c_const_type(base)
"Const/volatile base type cannot be a Python object")
return PyrexTypes.c_const_or_volatile_type(base, self.is_const, self.is_volatile)
class CVarDefNode(StatNode):
......
......@@ -317,8 +317,8 @@ def p_typecast(s):
base_type = p_c_base_type(s)
is_memslice = isinstance(base_type, Nodes.MemoryViewSliceTypeNode)
is_template = isinstance(base_type, Nodes.TemplatedTypeNode)
is_const = isinstance(base_type, Nodes.CConstTypeNode)
if (not is_memslice and not is_template and not is_const
is_const_volatile = isinstance(base_type, Nodes.CConstOrVolatileTypeNode)
if (not is_memslice and not is_template and not is_const_volatile
and base_type.name is None):
s.error("Unknown type")
declarator = p_c_declarator(s, empty = 1)
......@@ -2479,16 +2479,31 @@ def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
complex = 0
module_path = []
pos = s.position()
if not s.sy == 'IDENT':
error(pos, "Expected an identifier, found '%s'" % s.sy)
if s.systring == 'const':
# Handle const/volatile
is_const = is_volatile = 0
while True:
if s.systring == 'const':
if is_const: error(pos, "Duplicate 'const'")
is_const = 1
elif s.systring == 'volatile':
if is_volatile: error(pos, "Duplicate 'volatile'")
is_volatile = 1
else:
break
s.next()
if is_const or is_volatile:
base_type = p_c_base_type(s, self_flag=self_flag, nonempty=nonempty, templates=templates)
if isinstance(base_type, Nodes.MemoryViewSliceTypeNode):
# reverse order to avoid having to write "(const int)[:]"
base_type.base_type_node = Nodes.CConstTypeNode(pos, base_type=base_type.base_type_node)
base_type.base_type_node = Nodes.CConstOrVolatileTypeNode(pos,
base_type=base_type.base_type_node, is_const=is_const, is_volatile=is_volatile)
return base_type
return Nodes.CConstTypeNode(pos, base_type=base_type)
return Nodes.CConstOrVolatileTypeNode(pos,
base_type=base_type, is_const=is_const, is_volatile=is_volatile)
if s.sy != 'IDENT':
error(pos, "Expected an identifier, found '%s'" % s.sy)
if looking_at_base_type(s):
#print "p_c_simple_base_type: looking_at_base_type at", s.position()
is_basic = 1
......
......@@ -176,7 +176,9 @@ class PyrexType(BaseType):
# is_ptr boolean Is a C pointer type
# is_null_ptr boolean Is the type of NULL
# is_reference boolean Is a C reference type
# is_const boolean Is a C const type.
# is_const boolean Is a C const type
# is_volatile boolean Is a C volatile type
# is_cv_qualified boolean Is a C const or volatile type
# is_cfunction boolean Is a C function type
# is_struct_or_union boolean Is a C struct or union type
# is_struct boolean Is a C struct type
......@@ -236,6 +238,8 @@ class PyrexType(BaseType):
is_null_ptr = 0
is_reference = 0
is_const = 0
is_volatile = 0
is_cv_qualified = 0
is_cfunction = 0
is_struct_or_union = 0
is_cpp_class = 0
......@@ -713,8 +717,8 @@ class MemoryViewSliceType(PyrexType):
to_axes_f = contig_dim + follow_dim * (ndim -1)
dtype = self.dtype
if dtype.is_const:
dtype = dtype.const_base_type
if dtype.is_cv_qualified:
dtype = dtype.cv_base_type
to_memview_c = MemoryViewSliceType(dtype, to_axes_c)
to_memview_f = MemoryViewSliceType(dtype, to_axes_f)
......@@ -791,15 +795,18 @@ class MemoryViewSliceType(PyrexType):
# return False
src_dtype, dst_dtype = src.dtype, dst.dtype
if dst_dtype.is_const:
# Requesting read-only views is always ok => consider only the non-const base type.
dst_dtype = dst_dtype.const_base_type
if src_dtype.is_const:
# When assigning between read-only views, compare only the non-const base types.
src_dtype = src_dtype.const_base_type
elif copying and src_dtype.is_const:
# Copying by value => ignore const on source.
src_dtype = src_dtype.const_base_type
# We can add but not remove const/volatile modifiers
# (except if we are copying by value, then anything is fine)
if not copying:
if src_dtype.is_const and not dst_dtype.is_const:
return False
if src_dtype.is_volatile and not dst_dtype.is_volatile:
return False
# const/volatile checks are done, remove those qualifiers
if src_dtype.is_cv_qualified:
src_dtype = src_dtype.cv_base_type
if dst_dtype.is_cv_qualified:
dst_dtype = dst_dtype.cv_base_type
if src_dtype != dst_dtype:
return False
......@@ -1558,58 +1565,74 @@ class PythranExpr(CType):
return hash(self.pythran_type)
class CConstType(BaseType):
class CConstOrVolatileType(BaseType):
"A C const or volatile type"
is_const = 1
is_cv_qualified = 1
def __init__(self, const_base_type):
self.const_base_type = const_base_type
if const_base_type.has_attributes and const_base_type.scope is not None:
from . import Symtab
self.scope = Symtab.CConstScope(const_base_type.scope)
def __init__(self, base_type, is_const=0, is_volatile=0):
self.cv_base_type = base_type
self.is_const = is_const
self.is_volatile = is_volatile
if base_type.has_attributes and base_type.scope is not None:
from .Symtab import CConstOrVolatileScope
self.scope = CConstOrVolatileScope(base_type.scope, is_const, is_volatile)
def cv_string(self):
cvstring = ""
if self.is_const:
cvstring = "const " + cvstring
if self.is_volatile:
cvstring = "volatile " + cvstring
return cvstring
def __repr__(self):
return "<CConstType %s>" % repr(self.const_base_type)
return "<CConstOrVolatileType %s%r>" % (self.cv_string(), self.cv_base_type)
def __str__(self):
return self.declaration_code("", for_display=1)
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
cv = self.cv_string()
if for_display or pyrex:
return "const " + self.const_base_type.declaration_code(entity_code, for_display, dll_linkage, pyrex)
return cv + self.cv_base_type.declaration_code(entity_code, for_display, dll_linkage, pyrex)
else:
return self.const_base_type.declaration_code("const %s" % entity_code, for_display, dll_linkage, pyrex)
return self.cv_base_type.declaration_code(cv + entity_code, for_display, dll_linkage, pyrex)
def specialize(self, values):
base_type = self.const_base_type.specialize(values)
if base_type == self.const_base_type:
base_type = self.cv_base_type.specialize(values)
if base_type == self.cv_base_type:
return self
else:
return CConstType(base_type)
return CConstOrVolatileType(base_type,
self.is_const, self.is_volatile)
def deduce_template_params(self, actual):
return self.const_base_type.deduce_template_params(actual)
return self.cv_base_type.deduce_template_params(actual)
def can_coerce_to_pyobject(self, env):
return self.const_base_type.can_coerce_to_pyobject(env)
return self.cv_base_type.can_coerce_to_pyobject(env)
def can_coerce_from_pyobject(self, env):
return self.const_base_type.can_coerce_from_pyobject(env)
return self.cv_base_type.can_coerce_from_pyobject(env)
def create_to_py_utility_code(self, env):
if self.const_base_type.create_to_py_utility_code(env):
self.to_py_function = self.const_base_type.to_py_function
if self.cv_base_type.create_to_py_utility_code(env):
self.to_py_function = self.cv_base_type.to_py_function
return True
def same_as_resolved_type(self, other_type):
if other_type.is_const:
return self.const_base_type.same_as_resolved_type(other_type.const_base_type)
# Accept const LHS <- non-const RHS.
return self.const_base_type.same_as_resolved_type(other_type)
if other_type.is_cv_qualified:
return self.cv_base_type.same_as_resolved_type(other_type.cv_base_type)
# Accept cv LHS <- non-cv RHS.
return self.cv_base_type.same_as_resolved_type(other_type)
def __getattr__(self, name):
return getattr(self.const_base_type, name)
return getattr(self.cv_base_type, name)
def CConstType(base_type):
return CConstOrVolatileType(base_type, is_const=1)
class FusedType(CType):
......@@ -2302,8 +2325,8 @@ class CPointerBaseType(CType):
def __init__(self, base_type):
self.base_type = base_type
if base_type.is_const:
base_type = base_type.const_base_type
if base_type.is_cv_qualified:
base_type = base_type.cv_base_type
for char_type in (c_char_type, c_uchar_type, c_schar_type):
if base_type.same_as(char_type):
self.is_string = 1
......@@ -2527,8 +2550,8 @@ class CPtrType(CPointerBaseType):
return 1
if other_type.is_null_ptr:
return 1
if self.base_type.is_const:
self = CPtrType(self.base_type.const_base_type)
if self.base_type.is_cv_qualified:
self = CPtrType(self.base_type.cv_base_type)
if self.base_type.is_cfunction:
if other_type.is_ptr:
other_type = other_type.base_type.resolve()
......@@ -3709,8 +3732,8 @@ class CppClassType(CType):
return specialized
def deduce_template_params(self, actual):
if actual.is_const:
actual = actual.const_base_type
if actual.is_cv_qualified:
actual = actual.cv_base_type
if actual.is_reference:
actual = actual.ref_base_type
if self == actual:
......@@ -4452,10 +4475,10 @@ def widest_numeric_type(type1, type2):
type1 = type1.ref_base_type
if type2.is_reference:
type2 = type2.ref_base_type
if type1.is_const:
type1 = type1.const_base_type
if type2.is_const:
type2 = type2.const_base_type
if type1.is_cv_qualified:
type1 = type1.cv_base_type
if type2.is_cv_qualified:
type2 = type2.cv_base_type
if type1 == type2:
widest_type = type1
elif type1.is_complex or type2.is_complex:
......@@ -4675,6 +4698,13 @@ def c_const_type(base_type):
else:
return CConstType(base_type)
def c_const_or_volatile_type(base_type, is_const, is_volatile):
# Construct a C const/volatile type.
if base_type is error_type:
return error_type
else:
return CConstOrVolatileType(base_type, is_const, is_volatile)
def same_type(type1, type2):
return type1.same_as(type2)
......
......@@ -2523,23 +2523,27 @@ class PropertyScope(Scope):
return None
class CConstScope(Scope):
class CConstOrVolatileScope(Scope):
def __init__(self, const_base_type_scope):
def __init__(self, base_type_scope, is_const=0, is_volatile=0):
Scope.__init__(
self,
'const_' + const_base_type_scope.name,
const_base_type_scope.outer_scope,
const_base_type_scope.parent_scope)
self.const_base_type_scope = const_base_type_scope
'cv_' + base_type_scope.name,
base_type_scope.outer_scope,
base_type_scope.parent_scope)
self.base_type_scope = base_type_scope
self.is_const = is_const
self.is_volatile = is_volatile
def lookup_here(self, name):
entry = self.const_base_type_scope.lookup_here(name)
entry = self.base_type_scope.lookup_here(name)
if entry is not None:
entry = copy.copy(entry)
entry.type = PyrexTypes.c_const_type(entry.type)
entry.type = PyrexTypes.c_const_or_volatile_type(
entry.type, self.is_const, self.is_volatile)
return entry
class TemplateScope(Scope):
def __init__(self, name, outer_scope):
Scope.__init__(self, name, outer_scope, None)
......
......@@ -533,8 +533,8 @@ def find_spanning_type(type1, type2):
def simply_type(result_type, pos):
if result_type.is_reference:
result_type = result_type.ref_base_type
if result_type.is_const:
result_type = result_type.const_base_type
if result_type.is_cv_qualified:
result_type = result_type.cv_base_type
if result_type.is_cpp_class:
result_type.check_nullary_constructor(pos)
if result_type.is_array:
......
# mode: compile
cdef volatile int x = 1
cdef const volatile char* greeting1 = "hello world"
cdef volatile const char* greeting2 = "goodbye"
cdef extern from "stdlib.h":
volatile void* malloc(size_t)
cdef volatile long* test(volatile size_t s):
cdef volatile long* arr = <long*><volatile long*>malloc(s)
return arr
test(64)
......@@ -19,9 +19,11 @@ cdef func(const int a, const int* b, const (int*) c, const S s, int *const d,
d = NULL
t = &s
cdef volatile object v
_ERRORS = """
3:5: Const base type cannot be a Python object
3:5: Const/volatile base type cannot be a Python object
8:5: Assignment to const 'x'
15:4: Assignment to const 'a'
16:4: Assignment to const 'c'
......@@ -29,4 +31,5 @@ _ERRORS = """
18:5: Assignment to const attribute 'member'
19:4: Assignment to const 'd'
20:4: Assignment to const 't'
22:5: Const/volatile base type cannot be a Python object
"""
# mode: error
cdef extern from *:
cdef const const int a
cdef const volatile int b
cdef volatile const int c
cdef volatile volatile int d
_ERRORS = """
4:9: Duplicate 'const'
7:9: Duplicate 'volatile'
"""
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