[pypy-commit] creflect default: in-progress: refactoring: like C, we distinguish now "type qualifiers"

arigo noreply at buildbot.pypy.org
Sun Nov 30 22:29:41 CET 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r129:7673f248edbc
Date: 2014-11-30 22:29 +0100
http://bitbucket.org/cffi/creflect/changeset/7673f248edbc/

Log:	in-progress: refactoring: like C, we distinguish now "type
	qualifiers" as something different from types

diff --git a/creflect/codegen.py b/creflect/codegen.py
--- a/creflect/codegen.py
+++ b/creflect/codegen.py
@@ -7,11 +7,13 @@
         if parent is None:
             self.crx_type_vars = []
             self.crx_type_cache = {}
+            self.crx_qualtype_vars = []
             self.crx_field_vars = []
             self.crx_top_level = self
         else:
             self.crx_type_vars = parent.crx_type_vars
             self.crx_type_cache = parent.crx_type_cache
+            self.crx_qualtype_vars = parent.crx_qualtype_vars
             self.crx_field_vars = parent.crx_field_vars
             self.crx_top_level = parent.crx_top_level
 
@@ -40,13 +42,12 @@
         self.writeline('%s = %s;' % (t1, expr))
         return t1
 
-    def add_array_crx_types(self, array_size):
-        if array_size > 0:
-            a1 = self._get_next_name('a')
-            self.crx_type_vars.append('*%s[%d]' % (a1, array_size))
-            return a1
-        else:
+    def write_crx_qualtype_var(self, array_size):
+        if array_size == 0:
             return '0'
+        a1 = 'a%d' % (len(self.crx_qualtype_vars) + 1)
+        self.crx_qualtype_vars.append('%s[%d]' % (a1, array_size))
+        return a1
 
     def write_crx_field_var(self, nfields):
         d1 = 'd%d' % (len(self.crx_field_vars) + 1)
@@ -67,6 +68,8 @@
     if funcblock.crx_type_vars:
         funcblock.writedecl("_crx_type_t %s;" % (
             ', '.join(funcblock.crx_type_vars),))
+    for a1 in funcblock.crx_qualtype_vars:
+        funcblock.writedecl("_crx_qual_type %s;" % a1)
     for d1 in funcblock.crx_field_vars:
         funcblock.writedecl("_crx_field_t %s;" % d1)
 
diff --git a/creflect/commontypes.py b/creflect/commontypes.py
--- a/creflect/commontypes.py
+++ b/creflect/commontypes.py
@@ -19,7 +19,7 @@
     '_Bool':              'i',
     }
 
-def resolve_common_type(names, const):
+def resolve_common_type(names):
     # reduce synonyms to a single chosen combination
     names = list(names)
     if names != ['signed', 'char']:    # keep this unmodified
@@ -44,8 +44,5 @@
         names = newnames + names
     ident = ' '.join(names)
     if ident == 'void':
-        if const:
-            return model.const_void_type
-        else:
-            return model.void_type
-    return model.PrimitiveType(ident, const)
+        return model.void_type
+    return model.PrimitiveType(ident)
diff --git a/creflect/cparser.py b/creflect/cparser.py
--- a/creflect/cparser.py
+++ b/creflect/cparser.py
@@ -68,7 +68,7 @@
     def __init__(self, cdefblock, first_lineno=1):
         self.cdefblock = cdefblock
         self.first_lineno = first_lineno
-        self._struct_union_enum_decl = {}
+        self.struct_union_enum_decl = {}
 
     def prepare_source(self):
         csource = remove_comments(self.cdefblock)
@@ -104,130 +104,125 @@
         assert ast.ext[0].name == '__crx_unknown_t'
         for decl in ast.ext[1:]:
             if isinstance(decl, pycparser.c_ast.Decl):
-                self._parse_decl(decl)
+                self.parse_decl(decl)
             elif isinstance(decl, pycparser.c_ast.Typedef):
-                self._parse_typedef(decl)
+                self.parse_typedef(decl)
             else:
-                self._parse_error("unrecognized construct", decl)
+                self.parse_error("unrecognized construct", decl)
         return self.declarations
 
-    def _parse_error(self, msg, decl):
+    def parse_error(self, msg, decl):
         raise CDefError(msg, self, decl.coord.line - 1)
 
-    def _parse_decl(self, decl):
+    def parse_decl(self, decl):
         node = decl.type
         if isinstance(node, pycparser.c_ast.FuncDecl):
-            tp = self._get_type(node)
-            assert isinstance(tp, model.FunctionType)
-            self.declarations.append(model.FuncDecl(decl.name, tp))
+            qualtp = self.get_qualtype(node)
+            assert isinstance(qualtp.type, model.FunctionType)
+            self.declarations.append(model.FuncDecl(decl.name, qualtp))
         else:
             const = 'const' in decl.quals
             if isinstance(node, pycparser.c_ast.Struct):
                 if node.decls is not None:
-                    self._get_struct_union_enum_type('struct', node, const)
+                    self.get_struct_union_enum_type('struct', node, const)
             elif isinstance(node, pycparser.c_ast.Union):
                 if node.decls is not None:
-                    self._get_struct_union_enum_type('union', node, const)
+                    self.get_struct_union_enum_type('union', node, const)
             elif isinstance(node, pycparser.c_ast.Enum):
                 if node.values is not None:
-                    self._get_struct_union_enum_type('enum', node, const)
+                    self.get_struct_union_enum_type('enum', node, const)
             elif not decl.name:
                 raise api.CDefError("construct does not declare any variable",
                                     decl)
             #
             if decl.name:
-                tp = self._get_type(node, partial_length_ok=True)
-                if self._is_constant_globalvar(node):
-                    self.declarations.append(model.ConstDecl(decl.name, tp))
+                qualtp = self.get_qualtype(node)
+                if self.is_constant_globalvar(node):
+                    self.declarations.append(model.ConstDecl(decl.name, qualtp))
                 else:
-                    self.declarations.append(model.VarDecl(decl.name, tp))
+                    self.declarations.append(model.VarDecl(decl.name, qualtp))
 
-    def _parse_typedef(self, decl):
+    def parse_typedef(self, decl):
         if not decl.name:
-            self._parse_error("typedef does not declare any name", decl)
-        if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType)
-                and decl.type.type.names == ['__dotdotdot__']):
-            realtype = model.unknown_type(decl.name)
-        elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and
-              isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and
-              isinstance(decl.type.type.type,
-                         pycparser.c_ast.IdentifierType) and
-              decl.type.type.type.names == ['__dotdotdot__']):
-            realtype = model.unknown_ptr_type(decl.name)
-        else:
-            realtype = self._get_type(decl.type, approx_name = '$' + decl.name)
+            self.parse_error("typedef does not declare any name", decl)
+        qualtype = self.get_qualtype(decl.type, approx_name = '$'+decl.name)
         if decl.name in self.typedefs:
-            self._parse_error("duplicate typedef declaring %r" % (decl.name,))
-        self.typedefs[decl.name] = model.UserType(decl.name, realtype)
-        self.declarations.append(model.TypeDefDecl(decl.name, realtype))
+            self.parse_error("duplicate typedef declaring %r" % (decl.name,))
+        self.typedefs[decl.name] = model.UserType(decl.name)
+        self.declarations.append(model.TypeDefDecl(decl.name, qualtype))
 
-    def _get_type(self, typenode, approx_name=None, partial_length_ok=False):
+    def get_qualtype(self, typenode, approx_name=None):
         # first, dereference typedefs, if we have it already parsed, we're good
         if (isinstance(typenode, pycparser.c_ast.TypeDecl) and
             isinstance(typenode.type, pycparser.c_ast.IdentifierType) and
             len(typenode.type.names) == 1):
             typename = typenode.type.names[0]
             if typename in self.typedefs:
-                return self.typedefs[typenode.type.names[0]]
+                return model.QualType(self.typedefs[typenode.type.names[0]],
+                                      quals_num(typenode.quals))
             if typename == '__crx_unknown_t':
                 assert approx_name, "XXX"
-                return model.UnknownType(approx_name)
+                return model.QualType(model.UnknownType(approx_name),
+                                      quals_num(typenode.quals))
         #
         if isinstance(typenode, pycparser.c_ast.ArrayDecl):
             # array type
             if typenode.dim is None:
                 length = None
             else:
-                length = self._parse_constant(
-                    typenode.dim, partial_length_ok=partial_length_ok)
-            return model.ArrayType(self._get_type(typenode.type), length)
+                length = self.parse_constant(typenode.dim)
+            qualtype = self.get_qualtype(typenode.type)
+            return model.QualType(model.ArrayType(qualtype.type, length),
+                                  qualtype.quals)
         #
         if isinstance(typenode, pycparser.c_ast.PtrDecl):
             # pointer type
-            const = 'const' in typenode.quals
             if approx_name:
                 approx_name = '$' + approx_name
-            realtype = self._get_type(typenode.type, approx_name)
-            return model.PointerType(realtype, const)
+            qualtype = self.get_qualtype(typenode.type, approx_name)
+            return model.QualType(model.PointerType(qualtype),
+                                  quals_num(typenode.quals))
         #
         if isinstance(typenode, pycparser.c_ast.TypeDecl):
             const = 'const' in typenode.quals
             type = typenode.type
             if isinstance(type, pycparser.c_ast.IdentifierType):
                 # assume a primitive type.
-                return resolve_common_type(type.names, const)
+                realtype = resolve_common_type(type.names)
+                return model.QualType(realtype, quals_num(typenode.quals))
             #
             if isinstance(type, pycparser.c_ast.Struct):
                 # 'struct foobar'
-                return self._get_struct_union_enum_type('struct', type, const,
-                                                        approx_name)
+                return self.get_struct_union_enum_type('struct', type, const,
+                                                       approx_name)
             #
             if isinstance(type, pycparser.c_ast.Union):
                 # 'union foobar'
-                return self._get_struct_union_enum_type('union', type, const,
-                                                        approx_name)
+                return self.get_struct_union_enum_type('union', type, const,
+                                                       approx_name)
             #
             if isinstance(type, pycparser.c_ast.Enum):
                 # 'enum foobar'
-                return self._get_struct_union_enum_type('enum', type, const,
-                                                        approx_name)
+                return self.get_struct_union_enum_type('enum', type, const,
+                                                       approx_name)
         #
         if isinstance(typenode, pycparser.c_ast.FuncDecl):
-            # a function type
-            return self._parse_function_type(typenode, approx_name)
+            # a function type (it is never qualified)
+            return model.QualType(
+                self.parse_function_type(typenode, approx_name), 0)
         #
         # nested anonymous structs or unions end up here
         if isinstance(typenode, pycparser.c_ast.Struct):
-            return self._get_struct_union_enum_type('struct', typenode, const,
-                                                    name, nested=True)
+            return self.get_struct_union_enum_type('struct', typenode, const,
+                                                   name, nested=True)
         if isinstance(typenode, pycparser.c_ast.Union):
-            return self._get_struct_union_enum_type('union', typenode, const,
-                                                    name, nested=True)
+            return self.get_struct_union_enum_type('union', typenode, const,
+                                                   name, nested=True)
         #
         raise api.FFIError(":%d: bad or unsupported type declaration" %
                 typenode.coord.line)
 
-    def _parse_function_type(self, typenode, funcname=None):
+    def parse_function_type(self, typenode, funcname=None):
         params = list(getattr(typenode.args, 'params', []))
         ellipsis = (
             len(params) > 0 and
@@ -243,37 +238,32 @@
             isinstance(params[0].type.type, pycparser.c_ast.IdentifierType)
                 and list(params[0].type.type.names) == ['void']):
             del params[0]
-        args = [self._as_func_arg(self._get_type(argdeclnode.type))
-                for argdeclnode in params]
-        result = self._get_type(typenode.type)
-        return model.FunctionType(tuple(args), result, ellipsis)
+        #
+        args_quals = [self.get_qualtype(argdeclnode.type)
+                      for argdeclnode in params]
+        # ignore the quals of the result type (GCC produces a warning with
+        # -Wignored-qualifiers, but it is not even included in -Wall)
+        qual_result = self.get_qualtype(typenode.type)
+        return model.FunctionType(tuple(args_quals), qual_result.type, ellipsis)
 
-    def _as_func_arg(self, type):
-        if isinstance(type, model.ArrayType):
-            return model.PointerType(type.item, const=False)
-        elif isinstance(type, model.FunctionType):
-            return model.PointerType(type, const=False)
-        else:
-            return type
-
-    def _is_constant_globalvar(self, typenode):
+    def is_constant_globalvar(self, typenode):
         if isinstance(typenode, pycparser.c_ast.PtrDecl):
             return 'const' in typenode.quals
         if isinstance(typenode, pycparser.c_ast.TypeDecl):
             return 'const' in typenode.quals
         return False
 
-    def _get_struct_union_enum_type(self, kind, type, const, approx_name=None):
+    def get_struct_union_enum_type(self, kind, type, const, approx_name=None):
         name = type.name or approx_name
         if not name or name.startswith('$$$'):
-            self._parse_error("not implemented: anonymous 'struct' elsewhere "
-                              "than in 'typedef struct { ... } typename;' or "
-                              "'typedef struct { ... } *typename;'", type)
+            self.parse_error("not implemented: anonymous 'struct' elsewhere "
+                             "than in 'typedef struct { ... } typename;' or "
+                             "'typedef struct { ... } *typename;'", type)
         result = model.StructOrUnionOrEnum(kind, name, const)
         #
         # get the type declaration or create it if needed
         key = '%s %s' % (kind, name)
-        typedecl = self._struct_union_enum_decl.get(key, None)
+        typedecl = self.struct_union_enum_decl.get(key, None)
         #
         if typedecl is None:
             if kind == 'struct' or kind == 'union':
@@ -282,7 +272,7 @@
                 typedecl = XXX
             else:
                 raise AssertionError("kind = %r" % (kind,))
-            self._struct_union_enum_decl[key] = typedecl
+            self.struct_union_enum_decl[key] = typedecl
             must_add = True
         else:
             must_add = False
@@ -290,12 +280,12 @@
         # is there a 'type.decls'?  If yes, then this is the place in the
         # C sources that declare the fields.
         if type.decls is not None:
-            self._add_fields_declaration(typedecl, type.decls)
+            self.add_fields_declaration(typedecl, type.decls)
         if must_add:
             self.declarations.append(typedecl)
         return result
 
-    def _add_fields_declaration(self, typedecl, fields):
+    def add_fields_declaration(self, typedecl, fields):
         if typedecl.fldnames is not None:
             raise api.CDefError("duplicate declaration of struct %s" % name)
         fldnames = []
@@ -307,13 +297,13 @@
             if decl.bitsize is None:
                 bitsize = -1
             else:
-                bitsize = self._parse_constant(decl.bitsize)
-            self._partial_length = False
-            type = self._get_type(decl.type, partial_length_ok=True)
-            if self._partial_length:
-                self._make_partial(tp, nested)
+                bitsize = self.parse_constant(decl.bitsize)
+            self.partial_length = False
+            type = self.get_type(decl.type)
+            if self.partial_length:
+                self.make_partial(tp, nested)
             #if isinstance(type, model.StructType) and type.partial:
-            #    self._make_partial(tp, nested)
+            #    self.make_partial(tp, nested)
             fldnames.append(decl.name or '')
             fldtypes.append(type)
             fldbitsize.append(bitsize)
@@ -326,5 +316,18 @@
                 raise NotImplementedError("%s: using both bitfields and '...;'"
                                           % (tp,))
 
-    def _parse_constant(self, *args, **kwds):
-        return None     # XXX
+    def parse_constant(self, constant):
+        return int(constant.value)   # xxx
+
+
+def quals_num(quals):
+    assert isinstance(quals, (list, str))
+    if isinstance(quals, str):
+        quals = [quals]
+    result = 0
+    for qual in quals:
+        if qual == 'const':
+            result |= model.CRX_CONST
+        if qual == 'volatile':
+            result |= model.CRX_VOLATILE
+    return result
diff --git a/creflect/creflect.h b/creflect/creflect.h
--- a/creflect/creflect.h
+++ b/creflect/creflect.h
@@ -10,8 +10,14 @@
 typedef void (*_crx_trampoline1_fn)(void *fn, void *args[], void *res);
 
 typedef struct {
+    _crx_type_t *type;
+    int qualifiers;
+} _crx_qual_type;
+
+typedef struct {
     const char *name;
     _crx_type_t *type;
+    int qualifiers;
     size_t offset;
     int numbits, bitshift;
 } _crx_field_t;
@@ -29,6 +35,9 @@
     long double as_long_double;
 } _crx_num_const_t;
 
+#define _CRX_CONST     1
+#define _CRX_VOLATILE  2
+
 #define _CRX_SELF struct _crx_builder_s *
 typedef struct _crx_builder_s {
     _crx_type_t *(*get_void_type)(_CRX_SELF);
@@ -41,27 +50,25 @@
     _crx_type_t *(*get_float_type)(_CRX_SELF, size_t,
                                    const char *);
     _crx_type_t *(*get_function_type)(_CRX_SELF, _crx_type_t *,
-                                      _crx_type_t *[], int,
+                                      _crx_qual_type[], int,
                                       _crx_trampoline1_fn);
     _crx_type_t *(*get_ellipsis_function_type)(_CRX_SELF, _crx_type_t *,
-                                               _crx_type_t *[], int);
-    _crx_type_t *(*get_pointer_type)(_CRX_SELF, _crx_type_t *);
-    _crx_type_t *(*get_const_type)(_CRX_SELF, _crx_type_t *);
+                                               _crx_qual_type[], int);
+    _crx_type_t *(*get_pointer_type)(_CRX_SELF, _crx_type_t *, int);
     _crx_type_t *(*get_array_type)(_CRX_SELF, _crx_type_t *, size_t);
     _crx_type_t *(*get_incomplete_array_type)(_CRX_SELF, _crx_type_t *);
     _crx_type_t *(*get_struct_type)(_CRX_SELF, const char *);
     _crx_type_t *(*get_union_type)(_CRX_SELF, const char *);
     _crx_type_t *(*get_enum_type)(_CRX_SELF, const char *);
-    _crx_type_t *(*get_user_type)(_CRX_SELF, const char *);
+    _crx_qual_type(*get_user_type)(_CRX_SELF, const char *);
     _crx_type_t *(*get_unknown_type)(_CRX_SELF, const char *);
     void (*complete)(_CRX_SELF, _crx_type_t *,
                      size_t, size_t, _crx_field_t[], int);
     void (*complete_enum)(_CRX_SELF, _crx_type_t *, _crx_type_t *);
-    void (*define_type)(_CRX_SELF, const char *, _crx_type_t *);
-    void (*define_var)(_CRX_SELF, const char *, _crx_type_t *,
-                       void *);
+    void (*define_type)(_CRX_SELF, const char *, _crx_type_t *, int);
+    void (*define_var)(_CRX_SELF, const char *, _crx_type_t *, int, void *);
     void (*define_func)(_CRX_SELF, const char *, _crx_type_t *,
-                        _crx_type_t *[], int, _crx_trampoline0_fn, void *);
+                        _crx_qual_type[], int, _crx_trampoline0_fn, void *);
     void (*define_num_const)(_CRX_SELF, const char *, _crx_type_t *,
                              _crx_num_const_t *);
     void (*error)(_CRX_SELF, const char *);
diff --git a/creflect/creflect_debug_print.c b/creflect/creflect_debug_print.c
--- a/creflect/creflect_debug_print.c
+++ b/creflect/creflect_debug_print.c
@@ -32,6 +32,31 @@
     return t;
 }
 
+static const char *show_qualtype2(_crx_type_t *type, int qualifiers)
+{
+    size_t la = strlen(type->text);
+    size_t extra = 1;
+    if (qualifiers & _CRX_VOLATILE) extra += strlen("VOLATILE ");
+    if (qualifiers & _CRX_CONST)    extra += strlen("CONST "   );
+    char *p = malloc(la + extra);
+    char *q = p;
+    if (qualifiers & _CRX_VOLATILE) {
+        strcpy(q, "VOLATILE ");
+        q += strlen("VOLATILE ");
+    }
+    if (qualifiers & _CRX_CONST) {
+        strcpy(q, "CONST ");
+        q += strlen("CONST ");
+    }
+    strcat(q, type->text);
+    return p;
+}
+
+static const char *show_qualtype1(_crx_qual_type qualtype)
+{
+    return show_qualtype2(qualtype.type, qualtype.qualifiers);
+}
+
 static _crx_type_t *tst_get_void_type(_crx_builder_t *cb)
 {
     return newtype("void");
@@ -108,13 +133,13 @@
 }
 
 static _crx_type_t *tst_get_function_type(_crx_builder_t *cb, _crx_type_t *ret,
-                                          _crx_type_t *args[], int nargs,
+                                          _crx_qual_type args[], int nargs,
                                           _crx_trampoline1_fn trampl)
 {
     int i;
     const char *prev = "FUNC( ";
     for (i = 0; i < nargs; i++) {
-        prev = newtype2(prev, args[i]->text)->text;
+        prev = newtype2(prev, show_qualtype1(args[i]))->text;
         prev = newtype2(prev, " -> ")->text;
     }
     prev = newtype2(prev, ret->text)->text;
@@ -123,21 +148,17 @@
 
 static _crx_type_t *tst_get_ellipsis_function_type(_crx_builder_t *cb,
                                                    _crx_type_t *ret,
-                                                   _crx_type_t *args[],
+                                                   _crx_qual_type args[],
                                                    int nargs)
 {
     _crx_type_t *dotdotdot = newtype2("... -> ", ret->text);
     return tst_get_function_type(cb, dotdotdot, args, nargs, 0);
 }
 
-static _crx_type_t *tst_get_pointer_type(_crx_builder_t *cb, _crx_type_t *t)
+static _crx_type_t *tst_get_pointer_type(_crx_builder_t *cb,
+                                         _crx_type_t *type, int qualifiers)
 {
-    return newtype2("PTR ", t->text);
-}
-
-static _crx_type_t *tst_get_const_type(_crx_builder_t *cb, _crx_type_t *t)
-{
-    return newtype2("CONST ", t->text);
+    return newtype2("PTR ", show_qualtype2(type, qualifiers));
 }
 
 static _crx_type_t *tst_get_array_type(_crx_builder_t *cb, _crx_type_t *t,
@@ -169,9 +190,12 @@
     return newtype2("ENUM ", name);
 }
 
-static _crx_type_t *tst_get_user_type(_crx_builder_t *cb, const char *name)
+static _crx_qual_type tst_get_user_type(_crx_builder_t *cb, const char *name)
 {
-    return newtype(name);
+    _crx_qual_type result;
+    result.type = newtype(name);
+    result.qualifiers = 0;   // approximation: we don't really know here
+    return result;
 }
 
 static _crx_type_t *tst_get_unknown_type(_crx_builder_t *cb, const char *name)
@@ -186,7 +210,8 @@
     int i;
     printf("%s:\n", t->text);
     for (i = 0; i < nfields; i++) {
-        printf("| %s: %s\n", fields[i].name, fields[i].type->text);
+        printf("| %s: %s\n", fields[i].name,
+               show_qualtype2(fields[i].type, fields[i].qualifiers));
     }
 }
 
@@ -196,25 +221,26 @@
     abort();
 }
 
-static void tst_define_type(_crx_builder_t *cb, const char *name, _crx_type_t *t)
+static void tst_define_type(_crx_builder_t *cb, const char *name,
+                            _crx_type_t *type, int qualifiers)
 {
-    printf("TYPEDEF %s = %s\n", name, t->text);
+    printf("TYPEDEF %s = %s\n", name, show_qualtype2(type, qualifiers));
 }
 
-static void tst_define_var(_crx_builder_t *cb, const char *name, _crx_type_t *t,
-                           void *addr)
+static void tst_define_var(_crx_builder_t *cb, const char *name,
+                           _crx_type_t *type, int qualifiers, void *addr)
 {
-    printf("VAR %s: %s\n", name, t->text);
+    printf("VAR %s: %s\n", name, show_qualtype2(type, qualifiers));
 }
 
 static void tst_define_func(_crx_builder_t *cb, const char *name,
-                            _crx_type_t *ret, _crx_type_t *args[], int nargs,
+                            _crx_type_t *ret, _crx_qual_type args[], int nargs,
                             _crx_trampoline0_fn trampl, void *directcall)
 {
     int i;
     printf("FUNC %s: ", name);
     for (i = 0; i < nargs; i++)
-        printf("%s -> ", args[i]->text);
+        printf("%s -> ", show_qualtype1(args[i]));
     printf("%s\n", ret->text);
 }
 
@@ -263,7 +289,6 @@
     tst_get_function_type,
     tst_get_ellipsis_function_type,
     tst_get_pointer_type,
-    tst_get_const_type,
     tst_get_array_type,
     tst_get_incomplete_array_type,
     tst_get_struct_type,
diff --git a/creflect/model.py b/creflect/model.py
--- a/creflect/model.py
+++ b/creflect/model.py
@@ -1,26 +1,61 @@
 from .codegen import CodeBlock
 
+CRX_CONST    = 1
+CRX_VOLATILE = 2
+
+
+class QualType(object):
+    def __init__(self, type, quals=0):
+        self.type = type
+        self.quals = quals
+
+    def get_c_name(self, replace_with=''):
+        if self.quals & CRX_CONST:
+            replace_with = ('const ' + replace_with).rstrip()
+        if self.quals & CRX_VOLATILE:
+            replace_with = ('volatile ' + replace_with).rstrip()
+        #
+        if replace_with == '' and ' &' in self.type.c_name_with_marker:
+            replace_from = ' &'
+        else:
+            replace_from = '&'
+        return self.type.c_name_with_marker.replace(replace_from, replace_with)
+
+    def inspect_qualtype(self, block, inspect):
+        return self.type.inspect_type(block, inspect, self.quals)
+
+    def as_func_arg(self):
+        if isinstance(self.type, ArrayType):
+            return QualType(PointerType(QualType(self.type.item, self.quals)),
+                            0)
+        if isinstance(self.type, FunctionType):
+            return QualType(PointerType(self), 0)
+        return self
+
+    def __repr__(self):
+        return '<QualType %s>' % (self.get_c_name(),)
+
+    def __eq__(self, other):
+        return (self.__class__ == other.__class__ and
+                self.type == other.type and self.quals == other.quals)
+
+    def __ne__(self, other):
+        return not self == other
+
+    def __hash__(self):
+        return hash((self.type, self.quals))
+
 
 class BaseType(object):
 
-    def get_c_name(self, replace_with=''):
-        return self.c_name_with_marker.replace('&', replace_with).rstrip()
-
     def __repr__(self):
-        return '<%s>' % (self.get_c_name(),)
+        return '<%s %s>' % (self.__class__.__name__,
+                            QualType(self).get_c_name(),)
 
     def _get_items(self):
-        return [(name, getattr(self, name))
-                for name in (self._attrs_ + 'const')]
+        return [(name, getattr(self, name)) for name in self._attrs_]
 
-    def inspect_type(self, block, inspect):
-        t1 = self.inspect_nonconst_type(block, inspect)
-        if self.const:
-            return block.write_crx_type_var('cb->get_const_type(cb, %s)' % t1)
-        else:
-            return t1
-
-    def inspect_nonconst_type(self, block, inspect):
+    def inspect_type(self, block, inspect, qualifiers):
         raise NotImplementedError
 
     def shadow_global_var(self, top_level_block, name):
@@ -40,18 +75,14 @@
 class VoidType(BaseType):
     _attrs_ = ()
 
-    def __init__(self, const):
-        self.const = const
+    def __init__(self):
         self.c_name_with_marker = 'void &'
-        if const:
-            self.c_name_with_marker = 'const ' + self.c_name_with_marker
 
-    def inspect_nonconst_type(self, block, inspect):
+    def inspect_type(self, block, inspect, qualifiers):
         inspect.flush()
         return block.write_crx_type_var('cb->get_void_type(cb)')
 
-void_type = VoidType(const=False)
-const_void_type = VoidType(const=True)
+void_type = VoidType()
 
 
 class PrimitiveType(BaseType):
@@ -75,13 +106,10 @@
         '_Bool':              'u',
         }
 
-    def __init__(self, name, const):
+    def __init__(self, name):
         assert name in self.ALL_PRIMITIVE_TYPES, repr(name)
         self.name = name
-        self.const = const
         self.c_name_with_marker = name + ' &'
-        if const:
-            self.c_name_with_marker = 'const ' + self.c_name_with_marker
 
     def is_char_type(self):
         return self.ALL_PRIMITIVE_TYPES[self.name] == 'c'
@@ -94,7 +122,7 @@
     def is_float_type(self):
         return self.ALL_PRIMITIVE_TYPES[self.name] == 'f'
 
-    def inspect_nonconst_type(self, block, inspect):
+    def inspect_type(self, block, inspect, qualifiers):
         if isinstance(inspect, TypeInspector):
             star_p1 = inspect.fetch_star_p1()
             comment1 = inspect.get_comment(0, False, "a valid type", minlevel=1)
@@ -106,7 +134,7 @@
             block.writedecl("char b[sizeof(%s)];%s" % (star_p1, comment1))
             if self.is_float_type():
                 block.writeline("memset(b, 0, sizeof(b));")
-            elif self.const:
+            elif qualifiers & CRX_CONST:
                 block.writeline("memset(b, -1, sizeof(b));")
             inspect.assign_to_p1("b")
             if self.is_float_type():
@@ -114,7 +142,7 @@
             else:
                 op = '<< 1'
             block.writeline("(void)(%s %s);%s" % (star_p1, op, comment2))
-            if not self.const:
+            if not (qualifiers & CRX_CONST):
                 block.writeline("%s = -1;%s" % (star_p1, comment3))
             if self.is_integer_type():
                 hint = self.name.split()
@@ -196,14 +224,13 @@
 
 class FunctionType(BaseType):
     _attrs_ = ('args', 'result', 'ellipsis')
-    const = True
 
     def __init__(self, args, result, ellipsis):
-        self.args = args
-        self.result = result
+        self.args = args        # list of QualTypes
+        self.result = result    # a plain BaseType
         self.ellipsis = ellipsis
         #
-        reprargs = [arg.get_c_name() for arg in self.args]
+        reprargs = [qualarg.get_c_name() for qualarg in self.args]
         if self.ellipsis:
             reprargs.append('...')
         reprargs = reprargs or ['void']
@@ -213,30 +240,30 @@
 
     def _get_arg_ret_types(self, block):
         inspect = MissingInspector()
-        t1 = self.result.inspect_type(block, inspect)
-        t_args = [arg.inspect_type(block, inspect) for arg in self.args]
-        a2 = block.add_array_crx_types(len(t_args))
-        for i, t in enumerate(t_args):
-            block.writeline('%s[%d] = %s;' % (a2, i, t))
+        t1 = self.result.inspect_type(block, inspect, 0)
+        a2 = block.write_crx_qualtype_var(len(self.args))
+        for i, arg in enumerate(self.args):
+            t3 = arg.inspect_qualtype(block, inspect)
+            block.writeline('%s[%d].type = %s;' % (a2, i, t3))
+            block.writeline('%s[%d].qualifiers = %d;' % (a2, i, arg.quals))
         return t1, a2
 
     def _get_c_call_sequence(self, varname):
         call = ['    ']
         if not isinstance(self.result, VoidType):
-            call.append('*(%s)result = ' % (self.result.get_c_name('*'),))
+            call.append('*(%s)result = ' % (
+                QualType(self.result).get_c_name('*'),))
         call.append(varname)
         call.append('(')
         for i in range(len(self.args)):
             if i > 0:
                 call.append(', ')
-            call.append('*(%s)args[%d]' % (self.args[i].get_c_name('*'), i))
+            call.append('*(%s)args[%d]' % (
+                self.args[i].as_func_arg().get_c_name('*'), i))
         call.append(');')
         return ''.join(call)
 
-    def inspect_type(self, block, inspect):
-        # this class overrides inspect_type() instead of
-        # inspect_nonconst_type(), to avoid the extra call to get_const_type()
-
+    def inspect_type(self, block, inspect, qualifiers):
         # this variable is set if we support slightly misdeclared function
         # args or return value; this is the case only for typedefs that
         # declare a pointer to a function without ellipsis.
@@ -245,7 +272,7 @@
         if common_case:
             inspect.flush()
         else:
-            inspect.flush('(%s)' % self.get_c_name('(*)'),
+            inspect.flush('(%s)' % QualType(self).get_c_name('(*)'),
                 "a function pointer type with exactly the given signature")
 
         if self.ellipsis:
@@ -254,7 +281,7 @@
         if common_case:
             decl = '%s f' % inspect.typename
         else:
-            decl = self.get_c_name('(*f)')
+            decl = QualType(self).get_c_name('(*f)')
 
         toplevel = block.crx_top_level
         extraname = block._get_next_name('f')
@@ -273,7 +300,7 @@
 
     def inspect_type_ellipsis(self, block, inspect):
         if isinstance(inspect, VarInspector):
-            decl = self.get_c_name("(*p1)")
+            decl = QualType(self).get_c_name("(*p1)")
             block.writeline("%s = &%s;  /* check that '%s' is a function with"
                             " exactly the given signature */" % (
                                 decl, inspect.varname, inspect.varname))
@@ -290,7 +317,7 @@
         wrline = top_level_block.writeline
         args = [arg.get_c_name('a%d' % i) for i, arg in enumerate(self.args)]
         decl = '%s(%s)' % (shadowname, ', '.join(args) or 'void')
-        wrline('static %s {' % self.result.get_c_name(decl))
+        wrline('static %s {' % QualType(self.result).get_c_name(decl))
         args = ['a%d' % i for i, arg in enumerate(self.args)]
         wrline('    %s%s(%s);' % ('' if isinstance(self.result, VoidType)
                                   else 'return ',
@@ -317,30 +344,25 @@
 
 
 class PointerType(BaseType):
-    _attrs_ = ('totype',)
-    _base_pattern       = {
-        (False, False): "*&",
-        (True, False): "(*&)",
-        (False, True): "*const &",
-        (True, True): "(*const &)",
-        }
+    _attrs_ = ('toqualtype',)
 
-    def __init__(self, totype, const):
-        self.totype = totype
-        self.const = const
-        base = self.totype.c_name_with_marker
-        parens = isinstance(self.totype, (ArrayType, FunctionType))
-        extra = self._base_pattern[parens, self.const]
-        self.c_name_with_marker = base.replace('&', extra)
+    def __init__(self, toqualtype):
+        assert isinstance(toqualtype, QualType)
+        self.toqualtype = toqualtype
+        if isinstance(toqualtype.type, (ArrayType, FunctionType)):
+            name = self.toqualtype.get_c_name('(*&)')
+        else:
+            name = self.toqualtype.get_c_name('*&')
+        self.c_name_with_marker = name
 
-    def inspect_nonconst_type(self, block, inspect):
+    def inspect_type(self, block, inspect, qualifiers):
         if isinstance(inspect, TypeInspector):
             star_p1 = inspect.fetch_star_p1()
             new_var = 'p%d' % (len(inspect.levels) + 2,)
             block.writedecl("char *%s;" % (new_var,))
             inspect.assign_to_p1("&%s" % (new_var,))
             #
-            if self.const:
+            if qualifiers & CRX_CONST:
                 errmsg = "type '%s' is not a pointer, but an array type" % (
                     inspect.get_comment_type(0, False),)
                 inspect.assign_target = new_var
@@ -371,13 +393,13 @@
                                          inspect.varname, self.get_c_name()))
                 block.writeline("(void)p1;")
             inspect = MissingInspector()
-        t1 = self.totype.inspect_type(block, inspect)
-        return block.write_crx_type_var('cb->get_pointer_type(cb, %s)' % t1)
+        t1 = self.toqualtype.inspect_qualtype(block, inspect)
+        return block.write_crx_type_var('cb->get_pointer_type(cb, %s, %d)'
+                                        % (t1, self.toqualtype.quals))
 
 
 class ArrayType(BaseType):
     _attrs_ = ('item', 'length')
-    const = True     # not really applicable, but must have one
 
     def __init__(self, item, length):
         self.item = item
@@ -385,20 +407,12 @@
         #
         if length is None:
             brackets = '&[]'
-        elif length == '...':
-            brackets = '&[/*...*/]'
         else:
             brackets = '&[%d]' % length
-        if ' &' in self.item.c_name_with_marker:
-            replace_from = ' &'
-        else:
-            replace_from = '&'
         self.c_name_with_marker = (
-            self.item.c_name_with_marker.replace(replace_from, brackets))
+            self.item.c_name_with_marker.replace('&', brackets))
 
-    def inspect_type(self, block, inspect):
-        # this class overrides inspect_type() instead of
-        # inspect_nonconst_type(), to avoid the extra call to get_const_type()
+    def inspect_type(self, block, inspect, qualifiers):
         if isinstance(inspect, TypeInspector):
             star_p1 = inspect.fetch_star_p1()
             errmsg = "type '%s' is not an array, but a pointer type" % (
@@ -424,7 +438,7 @@
             inspect = MissingInspector()
         else:
             star_p1 = None
-        t1 = self.item.inspect_type(block, inspect)
+        t1 = self.item.inspect_type(block, inspect, qualifiers)
         if star_p1 is not None:
             expr = 'cb->get_array_type(cb, %s, sizeof(%s) / sizeof(*%s))' % (
                 t1, star_p1, star_p1)
@@ -436,10 +450,9 @@
 class StructOrUnionOrEnum(BaseType):
     _attrs_ = ('kind', 'name')
 
-    def __init__(self, kind, name, const):
+    def __init__(self, kind, name):
         self.kind = kind
         self.name = name
-        self.const = const
         self.c_name_with_marker = '%s %s &' % (self.kind, self.name)
         if const:
             self.c_name_with_marker = 'const ' + self.c_name_with_marker
@@ -448,23 +461,19 @@
         return block.write_crx_type_var('cb->get_%s_type(cb, "%s")' % (
             self.kind, self.name))
 
-    def inspect_nonconst_type(self, block, inspect):
+    def inspect_type(self, block, inspect, qualifiers):
         inspect.flush()
         return self.get_type_var(block)
 
 
 class UserType(BaseType):
-    _attrs_ = ('name', 'realtype')
+    _attrs_ = ('name',)
 
-    def __init__(self, name, realtype, const=False):
+    def __init__(self, name):
         self.name = name
-        self.realtype = realtype
-        self.const = const or realtype.const
         self.c_name_with_marker = name + ' &'
-        if const:
-            self.c_name_with_marker = 'const ' + self.c_name_with_marker
 
-    def inspect_nonconst_type(self, block, inspect):
+    def inspect_type(self, block, inspect, qualifiers):
         inspect.flush()
         if isinstance(inspect, VarInspector):
             decl = self.get_c_name("*p1")
@@ -478,13 +487,12 @@
 
 class UnknownType(BaseType):
     _attrs_ = ('approx_name',)
-    const = False
 
     def __init__(self, approx_name):
         self.approx_name = approx_name
         self.c_name_with_marker = '... &'
 
-    def inspect_nonconst_type(self, block, inspect):
+    def inspect_type(self, block, inspect, qualifiers):
         inspect.flush()
         return block.write_crx_type_var('cb->get_unknown_type(cb, "%s")' % (
             self.approx_name,))
@@ -688,41 +696,43 @@
 
 
 class TypeDefDecl(object):
-    def __init__(self, name, type):
+    def __init__(self, name, qualtype):
         self.name = name
-        self.type = type
+        self.qualtype = qualtype
 
     def write_declaration(self, funcblock):
         block = CodeBlock(funcblock)
         inspect = TypeInspector(block, self.name)
-        t1 = self.type.inspect_type(block, inspect)
+        t1 = self.qualtype.inspect_qualtype(block, inspect)
         inspect.stop()
-        block.writeline('cb->define_type(cb, "%s", %s);' % (self.name, t1))
+        block.writeline('cb->define_type(cb, "%s", %s, %d);' % (
+            self.name, t1, self.qualtype.quals))
         funcblock.write_subblock(block)
 
 
 class VarDecl(object):
-    def __init__(self, name, type):
+    def __init__(self, name, qualtype):
         self.name = name
-        self.type = type
+        self.qualtype = qualtype
 
     def write_declaration(self, funcblock):
         block = CodeBlock(funcblock)
         inspect = VarInspector(block, self.name)
-        t1 = self.type.inspect_type(block, inspect)
-        shadow = self.type.shadow_global_var(block.crx_top_level, self.name)
-        block.writeline('cb->define_var(cb, "%s", %s, &%s);' % (
-            self.name, t1, shadow))
+        t1 = self.qualtype.inspect_qualtype(block, inspect)
+        shadow = self.qualtype.type.shadow_global_var(block.crx_top_level,
+                                                      self.name)
+        block.writeline('cb->define_var(cb, "%s", %s, %d, &%s);' % (
+            self.name, t1, self.qualtype.quals, shadow))
         funcblock.write_subblock(block)
 
 
 class FuncDecl(VarDecl):
     def write_declaration(self, funcblock):
-        if self.type.ellipsis:
+        if self.qualtype.type.ellipsis:
             VarDecl.write_declaration(self, funcblock)
         else:
             block = CodeBlock(funcblock)
-            self.type.write_func_decl(block, self.name)
+            self.qualtype.type.write_func_decl(block, self.name)
             funcblock.write_subblock(block)
 
 
diff --git a/creflect/test/codegen/002.c b/creflect/test/codegen/002.c
--- a/creflect/test/codegen/002.c
+++ b/creflect/test/codegen/002.c
@@ -11,8 +11,8 @@
         p1 = (void *)&p2;
         *p1 = (void *)0;    /* check that 'num_t' is a pointer type */
         t1 = cb->get_void_type(cb);
-        t2 = cb->get_pointer_type(cb, t1);
-        cb->define_type(cb, "num_t", t2);
+        t2 = cb->get_pointer_type(cb, t1, 0);
+        cb->define_type(cb, "num_t", t2, 0);
 #expect TYPEDEF num_t = PTR void
     }
 }
diff --git a/creflect/test/codegen/002b.c b/creflect/test/codegen/002b.c
--- a/creflect/test/codegen/002b.c
+++ b/creflect/test/codegen/002b.c
@@ -15,10 +15,10 @@
         **p1 = (void *)&p4;  /* check that '*num_t' is a pointer type */
         ***p1 = (void *)0;    /* check that '**num_t' is a pointer type */
         t1 = cb->get_void_type(cb);
-        t2 = cb->get_pointer_type(cb, t1);
-        t3 = cb->get_pointer_type(cb, t2);
-        t4 = cb->get_pointer_type(cb, t3);
-        cb->define_type(cb, "num_t", t4);
+        t2 = cb->get_pointer_type(cb, t1, 0);
+        t3 = cb->get_pointer_type(cb, t2, 0);
+        t4 = cb->get_pointer_type(cb, t3, 0);
+        cb->define_type(cb, "num_t", t4, 0);
 #expect TYPEDEF num_t = PTR PTR PTR void
     }
 }
diff --git a/creflect/test/codegen/002c.c b/creflect/test/codegen/002c.c
--- a/creflect/test/codegen/002c.c
+++ b/creflect/test/codegen/002c.c
@@ -4,16 +4,15 @@
 
 void test002c(_crx_builder_t *cb)
 {
-    _crx_type_t *t1, *t2, *t3;
+    _crx_type_t *t1, *t2;
     {
         num_t *p1;
         char *p2;
         p1 = (void *)&p2;
         *p1 = (void *)0;    /* check that 'num_t' is a pointer type */
         t1 = cb->get_void_type(cb);
-        t2 = cb->get_const_type(cb, t1);
-        t3 = cb->get_pointer_type(cb, t2);
-        cb->define_type(cb, "num_t", t3);
+        t2 = cb->get_pointer_type(cb, t1, 1);
+        cb->define_type(cb, "num_t", t2, 0);
 #expect TYPEDEF num_t = PTR CONST void
     }
 }
diff --git a/creflect/test/codegen/002d.c b/creflect/test/codegen/002d.c
new file mode 100644
--- /dev/null
+++ b/creflect/test/codegen/002d.c
@@ -0,0 +1,22 @@
+typedef void *const num_t;
+
+# ____________________________________________________________
+
+void test002d(_crx_builder_t *cb)
+{
+    _crx_type_t *t1, *t2;
+    {
+        num_t *p1;
+        char *p2;
+        p1 = (void *)&p2;
+        p2 = (void *)0;
+        if ((void *)p1 == (void *)*p1) {
+            cb->error(cb, "type 'num_t' is not a pointer, but an array type");
+            return;
+        }
+        t1 = cb->get_void_type(cb);
+        t2 = cb->get_pointer_type(cb, t1, 0);
+        cb->define_type(cb, "num_t", t2, 1);
+#expect TYPEDEF num_t = CONST PTR void
+    }
+}
diff --git a/creflect/test/codegen/003.c b/creflect/test/codegen/003.c
--- a/creflect/test/codegen/003.c
+++ b/creflect/test/codegen/003.c
@@ -12,7 +12,7 @@
         (void)(*p1 << 1);  /* check that 'num_t' is an integer type */
         *p1 = -1;  /* check that 'num_t' is not declared 'const' */
         t1 = _CRX_INT_TYPE(cb, *p1, "int");
-        cb->define_type(cb, "num_t", t1);
+        cb->define_type(cb, "num_t", t1, 0);
 #expect TYPEDEF num_t = int
     }
 }
diff --git a/creflect/test/codegen/003b.c b/creflect/test/codegen/003b.c
--- a/creflect/test/codegen/003b.c
+++ b/creflect/test/codegen/003b.c
@@ -12,7 +12,7 @@
         (void)(*p1 << 1);  /* check that 'num_t' is an integer type */
         *p1 = -1;  /* check that 'num_t' is not declared 'const' */
         t1 = _CRX_INT_TYPE(cb, *p1, "long");
-        cb->define_type(cb, "num_t", t1);
+        cb->define_type(cb, "num_t", t1, 0);
 #expect TYPEDEF num_t = long
     }
 }
diff --git a/creflect/test/codegen/003c.c b/creflect/test/codegen/003c.c
--- a/creflect/test/codegen/003c.c
+++ b/creflect/test/codegen/003c.c
@@ -12,7 +12,7 @@
         (void)(*p1 << 1);  /* check that 'num_t' is an integer type */
         *p1 = -1;  /* check that 'num_t' is not declared 'const' */
         t1 = _CRX_INT_TYPE(cb, *p1, "long long");
-        cb->define_type(cb, "num_t", t1);
+        cb->define_type(cb, "num_t", t1, 0);
 #expect TYPEDEF num_t = long long
     }
 }
diff --git a/creflect/test/codegen/003d.c b/creflect/test/codegen/003d.c
--- a/creflect/test/codegen/003d.c
+++ b/creflect/test/codegen/003d.c
@@ -12,7 +12,7 @@
         (void)(*p1 << 1);  /* check that 'num_t' is an integer type */
         *p1 = -1;  /* check that 'num_t' is not declared 'const' */
         t1 = _CRX_INT_TYPE(cb, *p1, "char");
-        cb->define_type(cb, "num_t", t1);
+        cb->define_type(cb, "num_t", t1, 0);
 #expect TYPEDEF num_t = signed char
     }
 }
diff --git a/creflect/test/codegen/003e.c b/creflect/test/codegen/003e.c
--- a/creflect/test/codegen/003e.c
+++ b/creflect/test/codegen/003e.c
@@ -16,7 +16,7 @@
             return;
         }
         t1 = cb->get_char_type(cb);
-        cb->define_type(cb, "num_t", t1);
+        cb->define_type(cb, "num_t", t1, 0);
 #expect TYPEDEF num_t = char
     }
 }
diff --git a/creflect/test/codegen/003f.c b/creflect/test/codegen/003f.c
--- a/creflect/test/codegen/003f.c
+++ b/creflect/test/codegen/003f.c
@@ -12,7 +12,7 @@
         (void)(*p1 << 1);  /* check that 'num_t' is an integer type */
         *p1 = -1;  /* check that 'num_t' is not declared 'const' */
         t1 = _CRX_INT_TYPE(cb, *p1, "long long");
-        cb->define_type(cb, "num_t", t1);
+        cb->define_type(cb, "num_t", t1, 0);
 #expect TYPEDEF num_t = unsigned long long
     }
 }
diff --git a/creflect/test/codegen/003g.c b/creflect/test/codegen/003g.c
--- a/creflect/test/codegen/003g.c
+++ b/creflect/test/codegen/003g.c
@@ -17,7 +17,7 @@
             return;
         }
         t1 = cb->get_float_type(cb, sizeof(*p1), "double");
-        cb->define_type(cb, "num_t", t1);
+        cb->define_type(cb, "num_t", t1, 0);
 #expect TYPEDEF num_t = double
     }
 }
diff --git a/creflect/test/codegen/003h.c b/creflect/test/codegen/003h.c
--- a/creflect/test/codegen/003h.c
+++ b/creflect/test/codegen/003h.c
@@ -16,7 +16,7 @@
         (void)(*p1 << 1);  /* check that 'num_t' is an integer type */
         *p1 = -1;  /* check that 'num_t' is not declared 'const' */
         t1 = _CRX_INT_TYPE(cb, *p1, "long long");
-        cb->define_type(cb, "num_t", t1);
+        cb->define_type(cb, "num_t", t1, 0);
 #expect TYPEDEF num_t = int
     }
 }
diff --git a/creflect/test/codegen/003i.c b/creflect/test/codegen/003i.c
--- a/creflect/test/codegen/003i.c
+++ b/creflect/test/codegen/003i.c
@@ -12,7 +12,7 @@
         (void)(*p1 << 1);  /* check that 'num_t' is an integer type */
         *p1 = -1;  /* check that 'num_t' is not declared 'const' */
         t1 = _CRX_INT_TYPE(cb, *p1, "char");
-        cb->define_type(cb, "num_t", t1);
+        cb->define_type(cb, "num_t", t1, 0);
 #expect TYPEDEF num_t = signed char
     }
 }
diff --git a/creflect/test/codegen/004.c b/creflect/test/codegen/004.c
--- a/creflect/test/codegen/004.c
+++ b/creflect/test/codegen/004.c
@@ -14,8 +14,8 @@
         (void)(**p1 << 1);  /* check that '*num_t' is an integer type */
         **p1 = -1;  /* check that '*num_t' is not declared 'const' */
         t1 = _CRX_INT_TYPE(cb, **p1, "int");
-        t2 = cb->get_pointer_type(cb, t1);
-        cb->define_type(cb, "num_t", t2);
+        t2 = cb->get_pointer_type(cb, t1, 0);
+        cb->define_type(cb, "num_t", t2, 0);
 #expect TYPEDEF num_t = PTR int
     }
 }
diff --git a/creflect/test/codegen/004b.c b/creflect/test/codegen/004b.c
--- a/creflect/test/codegen/004b.c
+++ b/creflect/test/codegen/004b.c
@@ -16,9 +16,9 @@
         (void)(***p1 << 1);  /* check that '**num_t' is an integer type */
         ***p1 = -1;  /* check that '**num_t' is not declared 'const' */
         t1 = _CRX_INT_TYPE(cb, ***p1, "int");
-        t2 = cb->get_pointer_type(cb, t1);
-        t3 = cb->get_pointer_type(cb, t2);
-        cb->define_type(cb, "num_t", t3);
+        t2 = cb->get_pointer_type(cb, t1, 0);
+        t3 = cb->get_pointer_type(cb, t2, 0);
+        cb->define_type(cb, "num_t", t3, 0);
 #expect TYPEDEF num_t = PTR PTR int
     }
 }
diff --git a/creflect/test/codegen/005.c b/creflect/test/codegen/005.c
--- a/creflect/test/codegen/005.c
+++ b/creflect/test/codegen/005.c
@@ -17,7 +17,7 @@
         **p1 = -1;  /* check that 'foo_t[]' is not declared 'const' */
         t1 = _CRX_INT_TYPE(cb, **p1, "int");
         t2 = cb->get_array_type(cb, t1, sizeof(*p1) / sizeof(**p1));
-        cb->define_type(cb, "foo_t", t2);
+        cb->define_type(cb, "foo_t", t2, 0);
 #expect TYPEDEF foo_t = ARRAY[27] int
     }
 }
diff --git a/creflect/test/codegen/005b.c b/creflect/test/codegen/005b.c
--- a/creflect/test/codegen/005b.c
+++ b/creflect/test/codegen/005b.c
@@ -18,9 +18,9 @@
         (void)(***p1 << 1);  /* check that '*foo_t[]' is an integer type */
         ***p1 = -1;  /* check that '*foo_t[]' is not declared 'const' */
         t1 = _CRX_INT_TYPE(cb, ***p1, "int");
-        t2 = cb->get_pointer_type(cb, t1);
+        t2 = cb->get_pointer_type(cb, t1, 0);
         t3 = cb->get_array_type(cb, t2, sizeof(*p1) / sizeof(**p1));
-        cb->define_type(cb, "foo_t", t3);
+        cb->define_type(cb, "foo_t", t3, 0);
 #expect TYPEDEF foo_t = ARRAY[27] PTR int
     }
 }
diff --git a/creflect/test/codegen/005c.c b/creflect/test/codegen/005c.c
--- a/creflect/test/codegen/005c.c
+++ b/creflect/test/codegen/005c.c
@@ -19,8 +19,8 @@
         ***p1 = -1;  /* check that '(*foo_t)[]' is not declared 'const' */
         t1 = _CRX_INT_TYPE(cb, ***p1, "int");
         t2 = cb->get_array_type(cb, t1, sizeof(**p1) / sizeof(***p1));
-        t3 = cb->get_pointer_type(cb, t2);
-        cb->define_type(cb, "foo_t", t3);
+        t3 = cb->get_pointer_type(cb, t2, 0);
+        cb->define_type(cb, "foo_t", t3, 0);
 #expect TYPEDEF foo_t = PTR ARRAY[27] int
     }
 }
diff --git a/creflect/test/codegen/005d.c b/creflect/test/codegen/005d.c
--- a/creflect/test/codegen/005d.c
+++ b/creflect/test/codegen/005d.c
@@ -38,16 +38,16 @@
         (void)(**********p1 << 1);  /* check that '**(***foo_t[][])[][]' is an integer type */
         **********p1 = -1;  /* check that '**(***foo_t[][])[][]' is not declared 'const' */
         t1 = _CRX_INT_TYPE(cb, **********p1, "int");
-        t2 = cb->get_pointer_type(cb, t1);
-        t3 = cb->get_pointer_type(cb, t2);
+        t2 = cb->get_pointer_type(cb, t1, 0);
+        t3 = cb->get_pointer_type(cb, t2, 0);
         t4 = cb->get_array_type(cb, t3, sizeof(*******p1) / sizeof(********p1));
         t5 = cb->get_array_type(cb, t4, sizeof(******p1) / sizeof(*******p1));
-        t6 = cb->get_pointer_type(cb, t5);
-        t7 = cb->get_pointer_type(cb, t6);
-        t8 = cb->get_pointer_type(cb, t7);
+        t6 = cb->get_pointer_type(cb, t5, 0);
+        t7 = cb->get_pointer_type(cb, t6, 0);
+        t8 = cb->get_pointer_type(cb, t7, 0);
         t9 = cb->get_array_type(cb, t8, sizeof(**p1) / sizeof(***p1));
         t10 = cb->get_array_type(cb, t9, sizeof(*p1) / sizeof(**p1));
-        cb->define_type(cb, "foo_t", t10);
+        cb->define_type(cb, "foo_t", t10, 0);
 #expect TYPEDEF foo_t = ARRAY[4] ARRAY[3] PTR PTR PTR ARRAY[27] ARRAY[91] PTR PTR int
     }
 }
diff --git a/creflect/test/codegen/006.c b/creflect/test/codegen/006.c
--- a/creflect/test/codegen/006.c
+++ b/creflect/test/codegen/006.c
@@ -4,7 +4,7 @@
 
 void test006(_crx_builder_t *cb)
 {
-    _crx_type_t *t1, *t2;
+    _crx_type_t *t1;
     {
         num_t *p1;
         char b[sizeof(*p1)];
@@ -12,8 +12,7 @@
         p1 = (void *)b;
         (void)(*p1 << 1);  /* check that 'num_t' is an integer type */
         t1 = _CRX_INT_TYPE(cb, *p1, "int");
-        t2 = cb->get_const_type(cb, t1);
-        cb->define_type(cb, "num_t", t2);
+        cb->define_type(cb, "num_t", t1, 1);
 #expect TYPEDEF num_t = CONST unsigned int
     }
 }
diff --git a/creflect/test/codegen/006b.c b/creflect/test/codegen/006b.c
--- a/creflect/test/codegen/006b.c
+++ b/creflect/test/codegen/006b.c
@@ -4,7 +4,7 @@
 
 void test006b(_crx_builder_t *cb)
 {
-    _crx_type_t *t1, *t2, *t3;
+    _crx_type_t *t1, *t2;
     {
         num_t *p1;
         char *p2;
@@ -18,9 +18,8 @@
         (void)(**p1 << 1);  /* check that '*num_t' is an integer type */
         **p1 = -1;  /* check that '*num_t' is not declared 'const' */
         t1 = _CRX_INT_TYPE(cb, **p1, "int");
-        t2 = cb->get_pointer_type(cb, t1);
-        t3 = cb->get_const_type(cb, t2);
-        cb->define_type(cb, "num_t", t3);
+        t2 = cb->get_pointer_type(cb, t1, 0);
+        cb->define_type(cb, "num_t", t2, 1);
 #expect TYPEDEF num_t = CONST PTR int
     }
 }
diff --git a/creflect/test/codegen/006c.c b/creflect/test/codegen/006c.c
--- a/creflect/test/codegen/006c.c
+++ b/creflect/test/codegen/006c.c
@@ -4,7 +4,7 @@
 
 void test006c(_crx_builder_t *cb)
 {
-    _crx_type_t *t1, *t2, *t3, *t4;
+    _crx_type_t *t1, *t2, *t3;
     {
         foo_t *p1;
         char *p2;
@@ -23,9 +23,8 @@
         ***p1 = -1;  /* check that '(*foo_t)[]' is not declared 'const' */
         t1 = _CRX_INT_TYPE(cb, ***p1, "int");
         t2 = cb->get_array_type(cb, t1, sizeof(**p1) / sizeof(***p1));
-        t3 = cb->get_pointer_type(cb, t2);
-        t4 = cb->get_const_type(cb, t3);
-        cb->define_type(cb, "foo_t", t4);
+        t3 = cb->get_pointer_type(cb, t2, 0);
+        cb->define_type(cb, "foo_t", t3, 1);
 #expect TYPEDEF foo_t = CONST PTR ARRAY[27] int
     }
 }
diff --git a/creflect/test/codegen/007.c b/creflect/test/codegen/007.c
--- a/creflect/test/codegen/007.c
+++ b/creflect/test/codegen/007.c
@@ -7,7 +7,7 @@
     _crx_type_t *t1;
     {
         t1 = cb->get_unknown_type(cb, "$num_t");
-        cb->define_type(cb, "num_t", t1);
+        cb->define_type(cb, "num_t", t1, 0);
 #expect TYPEDEF num_t = UNKNOWN $num_t
     }
 }
diff --git a/creflect/test/codegen/func-001b.c b/creflect/test/codegen/func-001b.c
--- a/creflect/test/codegen/func-001b.c
+++ b/creflect/test/codegen/func-001b.c
@@ -36,25 +36,33 @@
 
 void testfunc_001b(_crx_builder_t *cb)
 {
-    _crx_type_t *t1, *t2, *a3[1], *t4, *a5[2], *a6[2];
+    _crx_type_t *t1, *t2, *t3;
+    _crx_qual_type a1[1];
+    _crx_qual_type a2[2];
+    _crx_qual_type a3[2];
     {
         t1 = cb->get_unsigned_type(cb, sizeof(unsigned int), "unsigned int");
         t2 = cb->get_signed_type(cb, sizeof(long), "long");
-        a3[0] = t2;
-        cb->define_func(cb, "f", t1, a3, 1, &testfunc_001b__c_f, &testfunc_001b__d_f);
+        a1[0].type = t2;
+        a1[0].qualifiers = 0;
+        cb->define_func(cb, "f", t1, a1, 1, &testfunc_001b__c_f, &testfunc_001b__d_f);
 #expect FUNC f: long -> unsigned int
     }
     {
-        t4 = cb->get_signed_type(cb, sizeof(int), "int");
-        a5[0] = t4;
-        a5[1] = t4;
-        cb->define_func(cb, "g", t2, a5, 2, &testfunc_001b__c_g, &testfunc_001b__d_g);
+        t3 = cb->get_signed_type(cb, sizeof(int), "int");
+        a2[0].type = t3;
+        a2[0].qualifiers = 0;
+        a2[1].type = t3;
+        a2[1].qualifiers = 0;
+        cb->define_func(cb, "g", t2, a2, 2, &testfunc_001b__c_g, &testfunc_001b__d_g);
 #expect FUNC g: int -> int -> long
     }
     {
-        a6[0] = t4;
-        a6[1] = t4;
-        cb->define_func(cb, "h", t2, a6, 2, &testfunc_001b__c_h, &testfunc_001b__d_h);
+        a3[0].type = t3;
+        a3[0].qualifiers = 0;
+        a3[1].type = t3;
+        a3[1].qualifiers = 0;
+        cb->define_func(cb, "h", t2, a3, 2, &testfunc_001b__c_h, &testfunc_001b__d_h);
 #expect FUNC h: int -> int -> long
     }
 }
diff --git a/creflect/test/codegen/func-001c.c b/creflect/test/codegen/func-001c.c
--- a/creflect/test/codegen/func-001c.c
+++ b/creflect/test/codegen/func-001c.c
@@ -16,12 +16,14 @@
 
 void testfunc_001c(_crx_builder_t *cb)
 {
-    _crx_type_t *t1, *t2, *a3[1];
+    _crx_type_t *t1, *t2;
+    _crx_qual_type a1[1];
     {
         t1 = cb->get_float_type(cb, sizeof(double), "double");
         t2 = cb->get_float_type(cb, sizeof(float), "float");
-        a3[0] = t2;
-        cb->define_func(cb, "f", t1, a3, 1, &testfunc_001c__c_f, &testfunc_001c__d_f);
+        a1[0].type = t2;
+        a1[0].qualifiers = 0;
+        cb->define_func(cb, "f", t1, a1, 1, &testfunc_001c__c_f, &testfunc_001c__d_f);
 #expect FUNC f: float -> double
     }
 }
diff --git a/creflect/test/codegen/func-002.c b/creflect/test/codegen/func-002.c
--- a/creflect/test/codegen/func-002.c
+++ b/creflect/test/codegen/func-002.c
@@ -9,14 +9,16 @@
 
 void testfunc_002(_crx_builder_t *cb)
 {
-    _crx_type_t *t1, *a2[1], *t3;
+    _crx_type_t *t1, *t2;
+    _crx_qual_type a1[1];
     {
         int (*p1)(int, ...) = &f;  /* check that 'f' is a function with exactly the given signature */
         (void)p1;
         t1 = cb->get_signed_type(cb, sizeof(int), "int");
-        a2[0] = t1;
-        t3 = cb->get_ellipsis_function_type(cb, t1, a2, 1);
-        cb->define_var(cb, "f", t3, &f);
+        a1[0].type = t1;
+        a1[0].qualifiers = 0;
+        t2 = cb->get_ellipsis_function_type(cb, t1, a1, 1);
+        cb->define_var(cb, "f", t2, 0, &f);
 #expect VAR f: FUNC( int -> ... -> int )
     }
 }
diff --git a/creflect/test/codegen/func-003.c b/creflect/test/codegen/func-003.c
--- a/creflect/test/codegen/func-003.c
+++ b/creflect/test/codegen/func-003.c
@@ -9,7 +9,8 @@
 
 void testfunc_003(_crx_builder_t *cb)
 {
-    _crx_type_t *t1, *t2, *a3[3], *t4, *t5;
+    _crx_type_t *t1, *t2, *t3, *t4;
+    _crx_qual_type a1[3];
     {
         func_t *p1;
         char *p2;
@@ -17,12 +18,15 @@
         *p1 = (void *)0;    /* check that 'func_t' is a pointer type */
         t1 = cb->get_signed_type(cb, sizeof(int), "int");
         t2 = cb->get_signed_type(cb, sizeof(long), "long");
-        a3[0] = t2;
-        a3[1] = t2;
-        a3[2] = t1;
-        t4 = cb->get_function_type(cb, t1, a3, 3, &testfunc_003__f1);
-        t5 = cb->get_pointer_type(cb, t4);
-        cb->define_type(cb, "func_t", t5);
+        a1[0].type = t2;
+        a1[0].qualifiers = 0;
+        a1[1].type = t2;
+        a1[1].qualifiers = 0;
+        a1[2].type = t1;
+        a1[2].qualifiers = 0;
+        t3 = cb->get_function_type(cb, t1, a1, 3, &testfunc_003__f1);
+        t4 = cb->get_pointer_type(cb, t3, 0);
+        cb->define_type(cb, "func_t", t4, 0);
 #expect TYPEDEF func_t = PTR FUNC( long -> long -> int -> int )
     }
 }
diff --git a/creflect/test/codegen/func-003b.c b/creflect/test/codegen/func-003b.c
--- a/creflect/test/codegen/func-003b.c
+++ b/creflect/test/codegen/func-003b.c
@@ -4,7 +4,8 @@
 
 void testfunc_003b(_crx_builder_t *cb)
 {
-    _crx_type_t *t1, *t2, *a3[1], *t4, *t5;
+    _crx_type_t *t1, *t2, *t3, *t4;
+    _crx_qual_type a1[1];
     {
         func_t *p1;
         char *p2;
@@ -12,10 +13,11 @@
         *p1 = (int (*)(long, ...))0;    /* check that 'func_t' is a function pointer type with exactly the given signature */
         t1 = cb->get_signed_type(cb, sizeof(int), "int");
         t2 = cb->get_signed_type(cb, sizeof(long), "long");
-        a3[0] = t2;
-        t4 = cb->get_ellipsis_function_type(cb, t1, a3, 1);
-        t5 = cb->get_pointer_type(cb, t4);
-        cb->define_type(cb, "func_t", t5);
+        a1[0].type = t2;
+        a1[0].qualifiers = 0;
+        t3 = cb->get_ellipsis_function_type(cb, t1, a1, 1);
+        t4 = cb->get_pointer_type(cb, t3, 0);
+        cb->define_type(cb, "func_t", t4, 0);
 #expect TYPEDEF func_t = PTR FUNC( long -> ... -> int )
     }
 }
diff --git a/creflect/test/codegen/func-004.c b/creflect/test/codegen/func-004.c
--- a/creflect/test/codegen/func-004.c
+++ b/creflect/test/codegen/func-004.c
@@ -9,7 +9,8 @@
 
 void testfunc_004(_crx_builder_t *cb)
 {
-    _crx_type_t *t1, *t2, *a3[2], *t4, *t5, *t6;
+    _crx_type_t *t1, *t2, *t3, *t4, *t5;
+    _crx_qual_type a1[2];
     {
         func_t *p1;
         char *p2;
@@ -19,12 +20,14 @@
         **p1 = (int (*)(long, int))0;    /* check that '*func_t' is a function pointer type with exactly the given signature */
         t1 = cb->get_signed_type(cb, sizeof(int), "int");
         t2 = cb->get_signed_type(cb, sizeof(long), "long");
-        a3[0] = t2;
-        a3[1] = t1;
-        t4 = cb->get_function_type(cb, t1, a3, 2, &testfunc_004__f1);
-        t5 = cb->get_pointer_type(cb, t4);
-        t6 = cb->get_pointer_type(cb, t5);
-        cb->define_type(cb, "func_t", t6);
+        a1[0].type = t2;
+        a1[0].qualifiers = 0;
+        a1[1].type = t1;
+        a1[1].qualifiers = 0;
+        t3 = cb->get_function_type(cb, t1, a1, 2, &testfunc_004__f1);
+        t4 = cb->get_pointer_type(cb, t3, 0);
+        t5 = cb->get_pointer_type(cb, t4, 0);
+        cb->define_type(cb, "func_t", t5, 0);
 #expect TYPEDEF func_t = PTR PTR FUNC( long -> int -> int )
     }
 }
diff --git a/creflect/test/codegen/func-005.c b/creflect/test/codegen/func-005.c
--- a/creflect/test/codegen/func-005.c
+++ b/creflect/test/codegen/func-005.c
@@ -1,16 +1,16 @@
-void f(int[], long(char, short));
+void f(const int[], long(char, short));
 
 # ____________________________________________________________
 
-void f(int a[], long g(char, short)) { }
+void f(const int a[], long g(char, short)) { }
 
 # ____________________________________________________________
 
 static void testfunc_005__c_f(void *args[], void *result) {
-    f(*(int **)args[0], *(long (**)(char, short))args[1]);
+    f(*(int const **)args[0], *(long (**)(char, short))args[1]);
 }
 
-static void testfunc_005__d_f(int *a0, long (*a1)(char, short)) {
+static void testfunc_005__d_f(int const a0[], long a1(char, short)) {
     f(a0, a1);
 }
 
@@ -21,21 +21,26 @@
 
 void testfunc_005(_crx_builder_t *cb)
 {
-    _crx_type_t *t1, *t2, *t3, *t4, *t5, *t6, *a7[2], *t8, *t9, *a10[2];
+    _crx_type_t *t1, *t2, *t3, *t4, *t5, *t6, *t7;
+    _crx_qual_type a1[2];
+    _crx_qual_type a2[2];
     {
         t1 = cb->get_void_type(cb);
         t2 = cb->get_signed_type(cb, sizeof(int), "int");
-        t3 = cb->get_pointer_type(cb, t2);
+        t3 = cb->get_incomplete_array_type(cb, t2);
+        a1[0].type = t3;
+        a1[0].qualifiers = 1;
         t4 = cb->get_signed_type(cb, sizeof(long), "long");
         t5 = cb->get_char_type(cb);
+        a2[0].type = t5;
+        a2[0].qualifiers = 0;
         t6 = cb->get_signed_type(cb, sizeof(short), "short");
-        a7[0] = t5;
-        a7[1] = t6;
-        t8 = cb->get_function_type(cb, t4, a7, 2, &testfunc_005__f4);
-        t9 = cb->get_pointer_type(cb, t8);
-        a10[0] = t3;
-        a10[1] = t9;
-        cb->define_func(cb, "f", t1, a10, 2, &testfunc_005__c_f, &testfunc_005__d_f);
-#expect FUNC f: PTR int -> PTR FUNC( char -> short -> long ) -> void
+        a2[1].type = t6;
+        a2[1].qualifiers = 0;
+        t7 = cb->get_function_type(cb, t4, a2, 2, &testfunc_005__f4);
+        a1[1].type = t7;
+        a1[1].qualifiers = 0;
+        cb->define_func(cb, "f", t1, a1, 2, &testfunc_005__c_f, &testfunc_005__d_f);
+#expect FUNC f: CONST ARRAY[] int -> FUNC( char -> short -> long ) -> void
     }
 }
diff --git a/creflect/test/codegen/glob-001.c b/creflect/test/codegen/glob-001.c
--- a/creflect/test/codegen/glob-001.c
+++ b/creflect/test/codegen/glob-001.c
@@ -9,8 +9,8 @@
         void *p1 = someglob;  /* check that 'someglob' is a pointer */
         if (0) { someglob = p1; }  /* check that 'someglob' is a pointer variable, and not an array or a constant */
         t1 = cb->get_void_type(cb);
-        t2 = cb->get_pointer_type(cb, t1);
-        cb->define_var(cb, "someglob", t2, &someglob);
+        t2 = cb->get_pointer_type(cb, t1, 0);
+        cb->define_var(cb, "someglob", t2, 0, &someglob);
 #expect VAR someglob: PTR void
     }
 }
diff --git a/creflect/test/codegen/glob-002.c b/creflect/test/codegen/glob-002.c
--- a/creflect/test/codegen/glob-002.c
+++ b/creflect/test/codegen/glob-002.c
@@ -10,7 +10,7 @@
         (void)p1;
         t1 = cb->get_char_type(cb);
         t2 = cb->get_array_type(cb, t1, sizeof(someglob) / sizeof(*someglob));
-        cb->define_var(cb, "someglob", t2, &someglob);
+        cb->define_var(cb, "someglob", t2, 0, &someglob);
 #expect VAR someglob: ARRAY[100] char
     }
 }
diff --git a/creflect/test/codegen/glob-002b.c b/creflect/test/codegen/glob-002b.c
--- a/creflect/test/codegen/glob-002b.c
+++ b/creflect/test/codegen/glob-002b.c
@@ -12,7 +12,7 @@
         (void)p1;
         t1 = cb->get_signed_type(cb, sizeof(int), "int");
         t2 = cb->get_array_type(cb, t1, sizeof(someglob) / sizeof(*someglob));
-        cb->define_var(cb, "someglob", t2, &someglob);
+        cb->define_var(cb, "someglob", t2, 0, &someglob);
 #expect VAR someglob: ARRAY[100] int
     }
 }
diff --git a/creflect/test/codegen/glob-002c.c b/creflect/test/codegen/glob-002c.c
--- a/creflect/test/codegen/glob-002c.c
+++ b/creflect/test/codegen/glob-002c.c
@@ -11,7 +11,7 @@
         int *p1 = &someglob;  /* check that 'someglob' is of type 'int' */
         (void)p1;
         t1 = cb->get_signed_type(cb, sizeof(int), "int");
-        cb->define_var(cb, "someglob", t1, &someglob);
+        cb->define_var(cb, "someglob", t1, 0, &someglob);
 #expect VAR someglob: int
     }
 }
diff --git a/creflect/test/codegen/glob-002d.c b/creflect/test/codegen/glob-002d.c
--- a/creflect/test/codegen/glob-002d.c
+++ b/creflect/test/codegen/glob-002d.c
@@ -9,8 +9,8 @@
         int **p1 = &someglob;  /* check that 'someglob' is of type 'int *' */
         (void)p1;
         t1 = cb->get_signed_type(cb, sizeof(int), "int");
-        t2 = cb->get_pointer_type(cb, t1);
-        cb->define_var(cb, "someglob", t2, &someglob);
+        t2 = cb->get_pointer_type(cb, t1, 0);
+        cb->define_var(cb, "someglob", t2, 0, &someglob);
 #expect VAR someglob: PTR int
     }
 }
diff --git a/creflect/test/codegen/glob-004.c b/creflect/test/codegen/glob-004.c
--- a/creflect/test/codegen/glob-004.c
+++ b/creflect/test/codegen/glob-004.c
@@ -18,8 +18,8 @@
         a3[0] = t2;
         a3[1] = t2;
         t4 = cb->get_function_type(cb, t1, a3, 2, &testglob_004__f1);
-        t5 = cb->get_pointer_type(cb, t4);
-        cb->define_var(cb, "someglob", t5, &someglob);
+        t5 = cb->get_pointer_type(cb, t4, 0);
+        cb->define_var(cb, "someglob", t5, 0, &someglob);
 #expect VAR someglob: PTR FUNC( long -> long -> int )
     }
 }
diff --git a/creflect/test/codegen/glob-005.c b/creflect/test/codegen/glob-005.c
--- a/creflect/test/codegen/glob-005.c
+++ b/creflect/test/codegen/glob-005.c
@@ -13,15 +13,16 @@
         p1 = (void *)&p2;
         *p1 = (void *)0;    /* check that 'mytype_t' is a pointer type */
         t1 = cb->get_void_type(cb);
-        t2 = cb->get_pointer_type(cb, t1);
-        cb->define_type(cb, "mytype_t", t2);
+        t2 = cb->get_pointer_type(cb, t1, 0);
+        cb->define_type(cb, "mytype_t", t2, 0);
 #expect TYPEDEF mytype_t = PTR void
     }
     {
         mytype_t *p1 = &foobar;  /* check that 'foobar' is of type 'mytype_t' */
+        int q1 = 0;
         (void)p1;
-        t3 = cb->get_user_type(cb, "mytype_t");
-        cb->define_var(cb, "foobar", t3, &foobar);
+        t3 = cb->get_user_type(cb, "mytype_t", &q1);
+        cb->define_var(cb, "foobar", t3, q1, &foobar);
 #expect VAR foobar: mytype_t
     }
 }
diff --git a/creflect/test/codegen/struct-001.c b/creflect/test/codegen/struct-001.c
--- a/creflect/test/codegen/struct-001.c
+++ b/creflect/test/codegen/struct-001.c
@@ -20,6 +20,7 @@
         t2 = _CRX_INT_TYPE(cb, p1->aa, "int");
         d1[0].name = "aa";
         d1[0].type = t2;
+        d1[0].qualifiers = 0;
         d1[0].offset = o;
         d1[0].numbits = -1;
         d1[0].bitshift = -1;
@@ -34,6 +35,7 @@
         t3 = _CRX_INT_TYPE(cb, p1->bb, "int");
         d1[1].name = "bb";
         d1[1].type = t3;
+        d1[1].qualifiers = 0;
         d1[1].offset = o;
         d1[1].numbits = -1;
         d1[1].bitshift = -1;
diff --git a/creflect/test/codegen/struct-001b.c b/creflect/test/codegen/struct-001b.c
--- a/creflect/test/codegen/struct-001b.c
+++ b/creflect/test/codegen/struct-001b.c
@@ -6,7 +6,7 @@
 
 void teststruct_001b(_crx_builder_t *cb)
 {
-    _crx_type_t *t1, *t2, *t3;
+    _crx_type_t *t1, *t2;
     _crx_field_t d1[1];
     t1 = cb->get_struct_type(cb, "foo_s");
     {
@@ -17,9 +17,9 @@
         p1 = (void *)(((char *)b) - o);
         (void)(p1->aa << 1);  /* check that 'struct foo_s::aa' is an integer type */
         t2 = _CRX_INT_TYPE(cb, p1->aa, "int");
-        t3 = cb->get_const_type(cb, t2);
         d1[0].name = "aa";
-        d1[0].type = t3;
+        d1[0].type = t2;
+        d1[0].qualifiers = _CRX_CONST;
         d1[0].offset = o;
         d1[0].numbits = -1;
         d1[0].bitshift = -1;
diff --git a/creflect/test/codegen/struct-002.c b/creflect/test/codegen/struct-002.c
--- a/creflect/test/codegen/struct-002.c
+++ b/creflect/test/codegen/struct-002.c
@@ -16,9 +16,10 @@
         p1 = (void *)(((char *)&p2) - o);
         p1->aa = (void *)0;    /* check that 'struct foo_s::aa' is a pointer type */
         t2 = cb->get_void_type(cb);
-        t3 = cb->get_pointer_type(cb, t2);
+        t3 = cb->get_pointer_type(cb, t2, 0);
         d1[0].name = "aa";
         d1[0].type = t3;
+        d1[0].qualifiers = 0;
         d1[0].offset = o;
         d1[0].numbits = -1;
         d1[0].bitshift = -1;
diff --git a/creflect/test/codegen/struct-003.c b/creflect/test/codegen/struct-003.c
--- a/creflect/test/codegen/struct-003.c
+++ b/creflect/test/codegen/struct-003.c
@@ -19,9 +19,10 @@
         (void)(*p1->aa << 1);  /* check that '*struct foo_s::aa' is an integer type */
         *p1->aa = -1;  /* check that '*struct foo_s::aa' is not declared 'const' */
         t2 = _CRX_INT_TYPE(cb, *p1->aa, "int");
-        t3 = cb->get_pointer_type(cb, t2);
+        t3 = cb->get_pointer_type(cb, t2, 0);
         d1[0].name = "aa";
         d1[0].type = t3;
+        d1[0].qualifiers = 0;
         d1[0].offset = o;
         d1[0].numbits = -1;
         d1[0].bitshift = -1;
diff --git a/creflect/test/codegen/struct-004.c b/creflect/test/codegen/struct-004.c
--- a/creflect/test/codegen/struct-004.c
+++ b/creflect/test/codegen/struct-004.c
@@ -24,6 +24,7 @@
         t3 = cb->get_array_type(cb, t2, sizeof(p1->aa) / sizeof(*p1->aa));
         d1[0].name = "aa";
         d1[0].type = t3;
+        d1[0].qualifiers = 0;
         d1[0].offset = o;
         d1[0].numbits = -1;
         d1[0].bitshift = -1;
diff --git a/creflect/test/codegen/struct-005.c b/creflect/test/codegen/struct-005.c
--- a/creflect/test/codegen/struct-005.c
+++ b/creflect/test/codegen/struct-005.c
@@ -17,6 +17,7 @@
         t2 = _CRX_INT_TYPE(cb, p1->aa, "int");
         d1[0].name = "aa";
         d1[0].type = t2;
+        d1[0].qualifiers = 0;
         d1[0].offset = o;
         d1[0].numbits = -1;
         d1[0].bitshift = -1;
@@ -27,7 +28,7 @@
 #expect STRUCT $foo_t:
 #expect | aa: int
     {
-        cb->define_type(cb, "foo_t", t1);
+        cb->define_type(cb, "foo_t", t1, 0);
 #expect TYPEDEF foo_t = STRUCT $foo_t
     }
 }
diff --git a/creflect/test/codegen/struct-005b.c b/creflect/test/codegen/struct-005b.c
--- a/creflect/test/codegen/struct-005b.c
+++ b/creflect/test/codegen/struct-005b.c
@@ -17,6 +17,7 @@
         t2 = _CRX_INT_TYPE(cb, p1->aa, "int");
         d1[0].name = "aa";
         d1[0].type = t2;
+        d1[0].qualifiers = 0;
         d1[0].offset = o;
         d1[0].numbits = -1;
         d1[0].bitshift = -1;
@@ -31,8 +32,8 @@
         char *p2;
         p1 = (void *)&p2;
         *p1 = (void *)0;    /* check that 'foo_p' is a pointer type */
-        t3 = cb->get_pointer_type(cb, t1);
-        cb->define_type(cb, "foo_p", t3);
+        t3 = cb->get_pointer_type(cb, t1, 0);
+        cb->define_type(cb, "foo_p", t3, 0);
 #expect TYPEDEF foo_p = PTR STRUCT $$foo_p
     }
 }
diff --git a/creflect/test/codegen/struct-006.c b/creflect/test/codegen/struct-006.c
--- a/creflect/test/codegen/struct-006.c
+++ b/creflect/test/codegen/struct-006.c
@@ -11,7 +11,7 @@
                  NULL, 0);
 #expect STRUCT $foo_t:
     {
-        cb->define_type(cb, "foo_t", t1);
+        cb->define_type(cb, "foo_t", t1, 0);
 #expect TYPEDEF foo_t = STRUCT $foo_t
     }
 }
diff --git a/creflect/test/test_cparser.py b/creflect/test/test_cparser.py
--- a/creflect/test/test_cparser.py
+++ b/creflect/test/test_cparser.py
@@ -1,6 +1,7 @@
 import py
 from cStringIO import StringIO
 from creflect.cparser import CSource, remove_comments, CDefError
+from creflect.model import TypeDefDecl, VarDecl
 
 
 def test_remove_comments():
@@ -41,3 +42,46 @@
       TypeDecl: f, []
         IdentifierType: ['unsigned', 'long']
 """
+
+def get_c_name(csrc):
+    csource = CSource("typedef %s;" % (csrc,))
+    typedefdecl = csource.get_declarations()[-1]
+    assert isinstance(typedefdecl, TypeDefDecl)
+    return typedefdecl.qualtype.get_c_name('x')
+
+def get_decl_name(csrc):
+    csource = CSource("%s;" % (csrc,))
+    vardecl = csource.get_declarations()[-1]
+    assert isinstance(vardecl, VarDecl)   # or subclass FuncDecl or ConstDecl
+    return vardecl.qualtype.get_c_name('x')
+
+def test_c_name():
+    assert get_c_name('long int x') == 'long x'
+    assert get_c_name('int***x') == 'int ***x'
+    assert get_c_name('const int x') == 'int const x'
+    assert get_c_name('int(x[5])') == 'int x[5]'
+    assert get_c_name('int(*x[5])') == 'int *x[5]'
+    assert get_c_name('int(*x)[5]') == 'int (*x)[5]'
+    assert get_c_name('const int *x[5]') == 'int const *x[5]'
+    assert get_c_name('int *const x[5]') == 'int *const x[5]'
+    assert get_c_name('int (*const x)[5]') == 'int (*const x)[5]'
+    assert get_c_name('const int(*x)[5]') == 'int const (*x)[5]'
+    #
+    assert get_c_name('const int x[5]') == 'int const x[5]'
+    assert get_c_name('void* x') == 'void *x'
+    assert get_c_name('int x(long,...)') == 'int x(long, ...)'
+    assert get_c_name('const int x(long,...)') == 'int x(long, ...)'  # ignored
+    assert get_c_name('int *(x(long,...))') == 'int *x(long, ...)'
+    assert get_c_name('int (*x)(long,...)') == 'int (*x)(long, ...)'
+    assert get_c_name('const int *x') == 'int const *x'
+    assert get_c_name('int * const x') == 'int *const x'
+    #
+    # hacks to declare two types
+    assert get_c_name('int tt; typedef tt x') == 'tt x'
+    assert get_c_name('int tt; typedef const tt x') == 'tt const x'
+    assert get_c_name('const __crx_unknown_t *x') == '... const *x'
+
+def test_decl_name():
+    assert get_decl_name('int x') == 'int x'
+    assert get_decl_name('const int x') == 'int const x'
+    assert get_decl_name('int x(long)') == 'int x(long)'
diff --git a/setup.py b/setup.py
new file mode 100644
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,10 @@
+from distutils.core import setup
+from distutils.extension import Extension
+
+setup(
+    ext_modules=[
+        Extension(name = 'zeffir',
+                  sources=['zeffir/zeffir.c',
+                           'creflect/creflect_cdecl.c'],
+        )
+    ])
diff --git a/zeffir/zef_builder.c b/zeffir/zef_builder.c
--- a/zeffir/zef_builder.c
+++ b/zeffir/zef_builder.c
@@ -165,10 +165,12 @@
 }
 
 static void zef_define_num_const(_crx_builder_t *cb, const char *name,
-                                 _crx_type_t *t, _crx_num_const_t *value)
+                                 _crx_type_t *ct, _crx_num_const_t *value)
 {
     PyObject *dict = ((zeffir_builder_t *)cb)->dict;
 
+    assert(ct->ct_flags & CT_PRIMITIVE_ANY);
+
     PyObject *x = PyInt_FromLong(value->as_int);
     if (x == NULL)
         return;


More information about the pypy-commit mailing list