Skip to content

Commit

Permalink
Put trampolines in original class namespace
Browse files Browse the repository at this point in the history
- This simplifies wrapping somewhat and avoids compile errors when the
  trampoline references a class in a parent namespace
- This is a breaking change -- bindings need to be recompiled to match
  each other
  • Loading branch information
virtuald committed Dec 18, 2024
1 parent c710cde commit 5fed2c2
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 12 deletions.
3 changes: 3 additions & 0 deletions robotpy_build/autowrap/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,9 @@ class BaseClassData:
#: turned into underscores.
full_cpp_name_identifier: str # was x_qualname_

#: This ends with ::
namespace_: str

#: C++ name + components, no template parameters
dep_cpp_name: str

Expand Down
25 changes: 20 additions & 5 deletions robotpy_build/autowrap/cxxparser.py
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,9 @@ def _count_and_unwrap(
assert False


def _fmt_base_name(typename: PQName) -> typing.Tuple[str, str, str, typing.List[str]]:
def _fmt_base_name(
typename: PQName,
) -> typing.Tuple[str, str, str, str, typing.List[str]]:
all_parts = []
nameonly_parts = []

Expand All @@ -209,10 +211,12 @@ def _fmt_base_name(typename: PQName) -> typing.Tuple[str, str, str, typing.List[

if last_segment.specialization:
most_parts = all_parts[:-1]
ns_parts = all_parts[:-1]
all_parts.append(last_segment.format())
most_parts.append(last_segment.name)
tparam_list = [arg.format() for arg in last_segment.specialization.args]
else:
ns_parts = all_parts[:]
all_parts.append(last_segment.name)
most_parts = all_parts
tparam_list = []
Expand All @@ -221,6 +225,7 @@ def _fmt_base_name(typename: PQName) -> typing.Tuple[str, str, str, typing.List[
"::".join(most_parts),
"::".join(all_parts),
"::".join(nameonly_parts),
"::".join(ns_parts),
tparam_list,
)

Expand Down Expand Up @@ -824,8 +829,8 @@ def _process_class_bases(
if base.access == "private":
continue

cpp_name, cpp_name_w_templates, dep_cpp_name, tparam_list = _fmt_base_name(
base.typename
cpp_name, cpp_name_w_templates, dep_cpp_name, base_ns, tparam_list = (
_fmt_base_name(base.typename)
)
if ignored_bases.pop(cpp_name_w_templates, None):
continue
Expand All @@ -846,6 +851,11 @@ def _process_class_bases(
cpp_name = user_bqual[:tp]
template_params = user_bqual[tp + 1 : -1]
dep_cpp_name = cpp_name
ns_idx = cpp_name.rfind("::")
if ns_idx == -1:
base_ns = ""
else:
base_ns = cpp_name[:ns_idx]
else:
# TODO: we don't handle nested child classes with templates here
# ... but that has to be rather obscure?
Expand All @@ -858,17 +868,22 @@ def _process_class_bases(
# If no explicit namespace specified, we assume base classes
# live in the same namespace as the class
if len(base.typename.segments) == 1:
base_ns = cls_namespace
cpp_name = f"{cls_namespace}::{cpp_name}"
cpp_name_w_templates = f"{cls_namespace}::{cpp_name_w_templates}"
dep_cpp_name = f"{cls_namespace}::{dep_cpp_name}"

base_identifier = cpp_name.translate(_qualname_trans)

if base_ns:
base_ns = f"{base_ns}::"

bases.append(
BaseClassData(
full_cpp_name=cpp_name,
full_cpp_name_w_templates=cpp_name_w_templates,
full_cpp_name_identifier=base_identifier,
namespace_=base_ns,
dep_cpp_name=dep_cpp_name,
template_params=template_params,
)
Expand Down Expand Up @@ -1242,8 +1257,8 @@ def on_class_end(self, state: AWClassBlockState) -> None:
if cdata.template_argument_list:
tmpl = f", {cdata.template_argument_list}"

trampoline_cfg = f"rpygen::PyTrampolineCfg_{cdata.cls_cpp_identifier}<{cdata.template_argument_list}>"
tname = f"rpygen::PyTrampoline_{cdata.cls_cpp_identifier}<typename {ctx.full_cpp_name}{tmpl}, typename {trampoline_cfg}>"
trampoline_cfg = f"{cdata.ctx.namespace}::PyTrampolineCfg_{cdata.cls_cpp_identifier}<{cdata.template_argument_list}>"
tname = f"{cdata.ctx.namespace}::PyTrampoline_{cdata.cls_cpp_identifier}<typename {ctx.full_cpp_name}{tmpl}, typename {trampoline_cfg}>"
tvar = f"{ctx.cpp_name}_Trampoline"

ctx.trampoline = TrampolineData(
Expand Down
15 changes: 8 additions & 7 deletions robotpy_build/autowrap/render_cls_rpy_include.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,8 @@ def _render_cls_trampoline(
for base in cls.bases:
r.writeln(f"#include <rpygen/{ base.full_cpp_name_identifier }.hpp>")

r.writeln("\nnamespace rpygen {")

if cls.namespace:
r.writeln(f"\nusing namespace {cls.namespace};")
r.writeln(f"\nnamespace {cls.namespace} {{")

if hctx.using_declarations:
r.writeln()
Expand All @@ -122,7 +120,7 @@ def _render_cls_trampoline(
#

r.writeln(
f"\ntemplate <{postcomma(template_parameter_list)}typename CfgBase = EmptyTrampolineCfg>"
f"\ntemplate <{postcomma(template_parameter_list)}typename CfgBase = rpygen::EmptyTrampolineCfg>"
)

if cls.bases:
Expand All @@ -131,7 +129,7 @@ def _render_cls_trampoline(
with r.indent():
for base in cls.bases:
r.writeln(
f"PyTrampolineCfg_{base.full_cpp_name_identifier}<{postcomma(base.template_params)}"
f"{base.namespace_}PyTrampolineCfg_{base.full_cpp_name_identifier}<{postcomma(base.template_params)}"
)

r.writeln("CfgBase")
Expand Down Expand Up @@ -168,7 +166,7 @@ def _render_cls_trampoline(

for base in cls.bases:
r.rel_indent(2)
r.writeln(f"PyTrampoline_{base.full_cpp_name_identifier}<")
r.writeln(f"{base.namespace_}PyTrampoline_{base.full_cpp_name_identifier}<")

with r.indent():
r.writeln("PyTrampolineBase")
Expand Down Expand Up @@ -284,7 +282,10 @@ def _render_cls_trampoline(
r.writeln()
r.write_trim(trampoline.inline_code)

r.writeln("};\n\n}; // namespace rpygen")
r.writeln("};\n\n")

if cls.namespace:
r.writeln(f"}}; // namespace {cls.namespace}")


def _render_cls_trampoline_virtual_method(
Expand Down
1 change: 1 addition & 0 deletions tests/cpp/pyproject.toml.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ generate = [
{ lifetime = "lifetime.h" },
{ nested = "nested.h" },
{ ns_class = "ns_class.h" },
{ ns_hidden = "ns_hidden.h" },
{ operators = "operators.h" },
{ overloads = "overloads.h" },
{ parameters = "parameters.h" },
Expand Down
23 changes: 23 additions & 0 deletions tests/cpp/rpytest/ft/include/ns_hidden.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#pragma once

namespace n {
enum class E {
Item,
};
};

namespace o {
struct O {
O() = default;
virtual ~O() = default;
};
};

namespace n::h {
class C : public o::O {
public:
// E is resolved here because it's in the parent namespace but our
// trampoline was originally in a different namespace and failed
virtual E fn() { return E::Item; }
};
};

0 comments on commit 5fed2c2

Please sign in to comment.