[neon/forks/sip6/Neon/release] debian: Add a patch to support enum base types.
Dmitry Shachnev
null at kde.org
Sun Aug 17 07:48:50 BST 2025
Git commit efd45145f0cc16aaafd9a8acd8f9e112f1003dcc by Dmitry Shachnev.
Committed on 24/05/2025 at 19:14.
Pushed by carlosdem into branch 'Neon/release'.
Add a patch to support enum base types.
Refs: #1088101.
M +6 -0 debian/changelog
A +292 -0 debian/patches/enum_base_types.diff
M +1 -0 debian/patches/series
https://invent.kde.org/neon/forks/sip6/-/commit/efd45145f0cc16aaafd9a8acd8f9e112f1003dcc
diff --git a/debian/changelog b/debian/changelog
index 9761f2b..cb3b609 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+sip6 (6.10.0-2) UNRELEASED; urgency=medium
+
+ * Add a patch to support enum base types (refs: #1088101).
+
+ -- Dmitry Shachnev <mitya57 at debian.org> Sat, 24 May 2025 22:13:15 +0300
+
sip6 (6.10.0-1) unstable; urgency=medium
* New upstream release.
diff --git a/debian/patches/enum_base_types.diff b/debian/patches/enum_base_types.diff
new file mode 100644
index 0000000..f242770
--- /dev/null
+++ b/debian/patches/enum_base_types.diff
@@ -0,0 +1,292 @@
+From: Phil Thompson <phil at riverbankcomputing.com>
+Date: Sat, 24 May 2025 17:04:25 +0100
+Subject: Support enum base types
+
+---
+ docs/specification_files.rst | 5 +++-
+ sipbuild/generator/outputs/code/code.py | 35 +++++++++++++++++++++--
+ sipbuild/generator/parser/parser_manager.py | 6 ++--
+ sipbuild/generator/parser/rules.py | 32 ++++++++++++++++++---
+ sipbuild/generator/resolver/resolver.py | 44 +++++++++++++++++++++++++++--
+ sipbuild/generator/specification.py | 3 ++
+ 6 files changed, 113 insertions(+), 12 deletions(-)
+
+diff --git a/docs/specification_files.rst b/docs/specification_files.rst
+index dce839a..fd5b330 100644
+--- a/docs/specification_files.rst
++++ b/docs/specification_files.rst
+@@ -203,10 +203,13 @@ file.
+ *mapped-type-template* :: = **template** **<** *type-list* **>**
+ *mapped-type*
+
+- *enum* ::= **enum** [*enum-key*] [*name*] [*enum-annotations*] **{** {*enum-line*} **};**
++ *enum* ::= **enum** [*enum-key*] [*name*] [**:** *enum-base*]
++ [*enum-annotations*] **{** {*enum-line*} **};**
+
+ *enum-key* ::= [**class** | **struct**]
+
++ *enum-base* ::= *base-type*
++
+ *enum-line* ::= [:directive:`%If` | *name* [*enum-annotations*] **,**
+
+ *function* ::= *typed-name* **(** [*argument-list*] **)** [**noexcept**]
+diff --git a/sipbuild/generator/outputs/code/code.py b/sipbuild/generator/outputs/code/code.py
+index 997e3c3..f243956 100644
+--- a/sipbuild/generator/outputs/code/code.py
++++ b/sipbuild/generator/outputs/code/code.py
+@@ -5371,6 +5371,10 @@ def _call_args(sf, spec, cpp_signature, py_signature):
+ if nr_derefs == 1:
+ indirection = '&'
+
++ if _arg_is_small_enum(arg):
++ prefix = 'static_cast<' + fmt_enum_as_cpp_type(arg.definition) + '>('
++ suffix = ')'
++
+ # See if we need to cast a Python void * to the correct C/C++ pointer
+ # type. Note that we assume that the arguments correspond and are just
+ # different types.
+@@ -5452,6 +5456,8 @@ def _argument_variable(sf, spec, scope, arg, arg_nr):
+ saved_is_reference = arg.is_reference
+ saved_is_const = arg.is_const
+
++ use_typename = True
++
+ if arg.type in (ArgumentType.ASCII_STRING, ArgumentType.LATIN1_STRING, ArgumentType.UTF8_STRING, ArgumentType.SSTRING, ArgumentType.USTRING, ArgumentType.STRING, ArgumentType.WSTRING):
+ if not arg.is_reference:
+ if nr_derefs == 2:
+@@ -5465,6 +5471,10 @@ def _argument_variable(sf, spec, scope, arg, arg_nr):
+ else:
+ arg.derefs = []
+
++ if _arg_is_small_enum(arg):
++ arg.type = ArgumentType.INT
++ use_typename = False
++
+ # Array sizes are always Py_ssize_t.
+ if arg.array is ArrayArgument.ARRAY_SIZE:
+ arg.type = ArgumentType.SSIZE
+@@ -5475,7 +5485,7 @@ def _argument_variable(sf, spec, scope, arg, arg_nr):
+ arg.is_const = False
+
+ modified_arg_cpp_type = fmt_argument_as_cpp_type(spec, arg,
+- scope=scope_iface_file)
++ scope=scope_iface_file, use_typename=use_typename)
+
+ sf.write(f' {modified_arg_cpp_type} {arg_name}')
+
+@@ -5492,8 +5502,14 @@ def _argument_variable(sf, spec, scope, arg, arg_nr):
+ if arg.type in (ArgumentType.CLASS, ArgumentType.MAPPED) and (nr_derefs == 0 or arg.is_reference):
+ sf.write(f'&{arg_name}def')
+ else:
++ if _arg_is_small_enum(arg):
++ sf.write('static_cast<int>(')
++
+ sf.write(fmt_value_list_as_cpp_expression(spec, arg.default_value))
+
++ if _arg_is_small_enum(arg):
++ sf.write(')')
++
+ sf.write(';\n')
+
+ # Some types have supporting variables.
+@@ -7496,9 +7512,16 @@ def _get_slot_arg(spec, overload, arg_nr):
+
+ arg = overload.py_signature.args[arg_nr]
+
+- dereference = '*' if arg.type in (ArgumentType.CLASS, ArgumentType.MAPPED) and len(arg.derefs) == 0 else ''
++ prefix = suffix = ''
+
+- return dereference + fmt_argument_as_name(spec, arg, arg_nr)
++ if arg.type in (ArgumentType.CLASS, ArgumentType.MAPPED):
++ if len(arg.derefs) == 0:
++ prefix = '*'
++ elif _arg_is_small_enum(arg):
++ prefix = 'static_cast<' + fmt_enum_as_cpp_type(arg.definition) + '>('
++ suffix = ')'
++
++ return prefix + fmt_argument_as_name(spec, arg, arg_nr) + suffix
+
+
+ # A map of operators and their complements.
+@@ -8993,6 +9016,12 @@ def _optional_ptr(is_ptr, name):
+ return name if is_ptr else 'SIP_NULLPTR'
+
+
++def _arg_is_small_enum(arg):
++ """ Return True if an argument refers to a small C++11 enum. """
++
++ return arg.type is ArgumentType.ENUM and arg.definition.enum_base_type is not None
++
++
+ # The map of slots to C++ names.
+ _SLOT_NAME_MAP = {
+ PySlot.ADD: 'operator+',
+diff --git a/sipbuild/generator/parser/parser_manager.py b/sipbuild/generator/parser/parser_manager.py
+index 202c243..8bdc35f 100644
+--- a/sipbuild/generator/parser/parser_manager.py
++++ b/sipbuild/generator/parser/parser_manager.py
+@@ -565,7 +565,8 @@ class ParserManager:
+ if self.parsing_virtual or len(scope.dealloc_code) != 0:
+ scope.needs_shadow = True
+
+- def add_enum(self, p, symbol, cpp_name, is_scoped, annotations, members):
++ def add_enum(self, p, symbol, cpp_name, is_scoped, enum_base_type,
++ annotations, members):
+ """ Create a new enum and add it to the current scope. """
+
+ if self.scope_access_specifier is AccessSpecifier.PRIVATE:
+@@ -616,7 +617,8 @@ class ParserManager:
+
+ w_enum = WrappedEnum(base_type, fq_cpp_name, self.module_state.module,
+ cached_fq_cpp_name=cached_fq_cpp_name, is_scoped=is_scoped,
+- py_name=py_name, scope=self.scope)
++ enum_base_type=enum_base_type, py_name=py_name,
++ scope=self.scope)
+
+ if self.scope_access_specifier is AccessSpecifier.PROTECTED:
+ if not self._protected_is_public:
+diff --git a/sipbuild/generator/parser/rules.py b/sipbuild/generator/parser/rules.py
+index 85090e1..ca9e0e3 100644
+--- a/sipbuild/generator/parser/rules.py
++++ b/sipbuild/generator/parser/rules.py
+@@ -2186,28 +2186,52 @@ _ENUM_MEMBER_ANNOTATIONS = (
+
+
+ def p_enum_decl(p):
+- "enum_decl : enum opt_enum_key opt_name opt_annos '{' opt_enum_body '}' ';'"
++ "enum_decl : enum opt_enum_key opt_name opt_enum_base opt_annos '{' opt_enum_body '}' ';'"
+
+ pm = p.parser.pm
+
+ if pm.skipping:
+ return
+
+- pm.check_annotations(p, 4, "enum", _ENUM_ANNOTATIONS)
++ pm.check_annotations(p, 5, "enum", _ENUM_ANNOTATIONS)
+
+- pm.add_enum(p, 1, p[3], p[2], p[4], p[6])
++ pm.add_enum(p, 1, p[3], p[2], p[4], p[5], p[7])
+
+
+ def p_opt_enum_key(p):
+ """opt_enum_key : class
+ | struct
+- | union
+ | empty"""
+
++ pm = p.parser.pm
++
++ if pm.skipping:
++ return
++
++ if p[1] is not None:
++ pm.cpp_only(p, 1, "enum keys")
++
+ # Return True if the enum is scoped.
+ p[0] = p[1] is not None
+
+
++def p_opt_enum_base(p):
++ """opt_enum_base : ':' base_type
++ | empty"""
++
++ pm = p.parser.pm
++
++ if pm.skipping:
++ return
++
++ if len(p) == 3:
++ pm.cpp_only(p, 1, "enum bases")
++
++ p[0] = p[2]
++ else:
++ p[0] = None
++
++
+ def p_opt_enum_body(p):
+ """opt_enum_body : enum_body
+ | empty"""
+diff --git a/sipbuild/generator/resolver/resolver.py b/sipbuild/generator/resolver/resolver.py
+index e4211f0..5ec6194 100644
+--- a/sipbuild/generator/resolver/resolver.py
++++ b/sipbuild/generator/resolver/resolver.py
+@@ -196,8 +196,9 @@ def _resolve_module(spec, mod, error_log, final_checks, seen=None):
+ for imported_mod in mod.imports:
+ _resolve_module(spec, imported_mod, error_log, final_checks, seen=seen)
+
+- # Resolve typedefs, variables and global functions.
++ # Resolve typedefs, enums, variables and global functions.
+ _resolve_typedefs(spec, mod, error_log)
++ _resolve_enums(spec, mod, error_log)
+ _resolve_variables(spec, mod, error_log)
+ _resolve_scope_overloads(spec, mod.overloads, error_log, final_checks)
+
+@@ -920,7 +921,6 @@ def _resolve_scope_overloads(spec, overloads, error_log, final_checks,
+ break
+
+ if isinstance(scope, WrappedClass):
+-
+ if scope.deprecated and not overload.deprecated :
+ overload.deprecated = scope.deprecated
+
+@@ -928,6 +928,46 @@ def _resolve_scope_overloads(spec, overloads, error_log, final_checks,
+ scope.is_abstract = True
+
+
++# The supported enum base types. Note that we use the STRING types and the
++# BYTE types because there is no opportunity to apply the /PyInt/ annotation
++# and there can be no confusion about context. We still need the BYTE types
++# because /PyInt/ could have been specified in a typedef.
++_ENUM_BASE_TYPES = (
++ ArgumentType.STRING,
++ ArgumentType.SSTRING,
++ ArgumentType.USTRING,
++ ArgumentType.BYTE,
++ ArgumentType.SBYTE,
++ ArgumentType.UBYTE,
++ ArgumentType.SHORT,
++ ArgumentType.USHORT,
++ ArgumentType.INT,
++ ArgumentType.UINT,
++)
++
++def _resolve_enums(spec, mod, error_log):
++ """ Resolve the base types for the enums of a module. """
++
++ for enum in spec.enums:
++ if enum.module is mod:
++ base_type = enum.enum_base_type
++
++ if base_type is None:
++ continue
++
++ _resolve_type(spec, enum.module, enum.scope, base_type, error_log)
++
++ # The current ABI implementations only support enums no larger than
++ # an int.
++ if base_type.type not in _ENUM_BASE_TYPES or len(base_type.derefs) != 0:
++ error_log.log(f"unsupported enum base type",
++ source_location=base_type.source_location)
++
++ # The default is int.
++ if base_type.type is ArgumentType.INT:
++ enum.enum_base_type = None
++
++
+ def _resolve_variables(spec, mod, error_log):
+ """ Resolve the data types for the variables of a module. """
+
+diff --git a/sipbuild/generator/specification.py b/sipbuild/generator/specification.py
+index 57376ba..d0c1ea2 100644
+--- a/sipbuild/generator/specification.py
++++ b/sipbuild/generator/specification.py
+@@ -1666,6 +1666,9 @@ class WrappedEnum:
+ # The defining module.
+ module: Module
+
++ # The C++11 enum base type.
++ enum_base_type: Optional[Argument] = None
++
+ # The cached fully qualified C++ name.
+ cached_fq_cpp_name: Optional[CachedName] = None
+
diff --git a/debian/patches/series b/debian/patches/series
index 457087d..27cf999 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -1,2 +1,3 @@
intersphinx_local.diff
system_ply.diff
+enum_base_types.diff
More information about the Neon-commits
mailing list