Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions robotpy_build/autowrap/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,12 @@ class BaseClassData:
Render data for each base that a class inherits
"""

#: Just the class name
cls_name: str

#: This ends with ::
namespace_: str

#: C++ name, including all known components
full_cpp_name: str # was x_qualname

Expand Down
50 changes: 35 additions & 15 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, str, typing.List[str]]:
all_parts = []
nameonly_parts = []

Expand All @@ -209,18 +211,22 @@ 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 = []

return (
last_segment.name,
"::".join(most_parts),
"::".join(all_parts),
"::".join(nameonly_parts),
"::".join(ns_parts),
tparam_list,
)

Expand Down Expand Up @@ -287,7 +293,6 @@ class ClassStateData(typing.NamedTuple):
defer_protected_fields: typing.List[Field]

# Needed for trampoline
cls_cpp_identifier: str
template_argument_list: str
base_template_params: str
base_template_args: str
Expand Down Expand Up @@ -751,7 +756,6 @@ def on_class_start(self, state: AWClassBlockState) -> typing.Optional[bool]:
defer_private_virtual_methods=[],
defer_protected_fields=[],
# Trampoline data
cls_cpp_identifier=cls_cpp_identifier,
template_argument_list=template_argument_list,
base_template_args=base_template_args_s,
base_template_params=base_template_params_s,
Expand Down Expand Up @@ -824,28 +828,38 @@ 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,
full_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

# Sometimes, we can't guess all the information about the base, so the
# user needs to specify it explicitly.
user_bqual = class_data.base_qualnames.get(cpp_name)
user_bqual = class_data.base_qualnames.get(full_cpp_name)
if user_bqual:
cpp_name_w_templates = user_bqual
# TODO: sometimes need to add this to pybase_params, but
# that would require parsing this more. Seems sufficiently
# obscure, going to omit it for now.
tp = user_bqual.find("<")
if tp == -1:
cpp_name = user_bqual
full_cpp_name = user_bqual
template_params = ""
else:
cpp_name = user_bqual[:tp]
full_cpp_name = user_bqual[:tp]
template_params = user_bqual[tp + 1 : -1]
dep_cpp_name = cpp_name
dep_cpp_name = full_cpp_name
ns_idx = full_cpp_name.rfind("::")
if ns_idx == -1:
base_ns = ""
else:
base_ns = full_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,15 +872,21 @@ 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:
cpp_name = f"{cls_namespace}::{cpp_name}"
base_ns = cls_namespace
full_cpp_name = f"{cls_namespace}::{full_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)
base_identifier = full_cpp_name.translate(_qualname_trans)

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

bases.append(
BaseClassData(
full_cpp_name=cpp_name,
cls_name=cpp_name,
namespace_=base_ns,
full_cpp_name=full_cpp_name,
full_cpp_name_w_templates=cpp_name_w_templates,
full_cpp_name_identifier=base_identifier,
dep_cpp_name=dep_cpp_name,
Expand Down Expand Up @@ -1242,8 +1262,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"{ctx.namespace}::PyTrampolineCfg_{ctx.cpp_name}<{cdata.template_argument_list}>"
tname = f"{ctx.namespace}::PyTrampoline_{ctx.cpp_name}<typename {ctx.full_cpp_name}{tmpl}, typename {trampoline_cfg}>"
tvar = f"{ctx.cpp_name}_Trampoline"

ctx.trampoline = TrampolineData(
Expand Down
31 changes: 16 additions & 15 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.strip('::')} {{")

if hctx.using_declarations:
r.writeln()
Expand All @@ -122,24 +120,24 @@ 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:
r.writeln(f"struct PyTrampolineCfg_{cls.full_cpp_name_identifier} :")
r.writeln(f"struct PyTrampolineCfg_{cls.cpp_name} :")

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.cls_name}<{postcomma(base.template_params)}"
)

r.writeln("CfgBase")

for base in cls.bases:
r.writeln(">")
else:
r.writeln(f"struct PyTrampolineCfg_{cls.full_cpp_name_identifier} : CfgBase")
r.writeln(f"struct PyTrampolineCfg_{cls.cpp_name} : CfgBase")

r.writeln("{")

Expand All @@ -164,11 +162,11 @@ def _render_cls_trampoline(
r.writeln(
f"template <typename PyTrampolineBase{precomma(template_parameter_list)}, typename PyTrampolineCfg>"
)
r.writeln(f"using PyTrampolineBase_{cls.full_cpp_name_identifier} =")
r.writeln(f"using PyTrampolineBase_{cls.cpp_name} =")

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.cls_name}<")

with r.indent():
r.writeln("PyTrampolineBase")
Expand All @@ -184,8 +182,8 @@ def _render_cls_trampoline(
;

template <typename PyTrampolineBase{ precomma(template_parameter_list) }, typename PyTrampolineCfg>
struct PyTrampoline_{ cls.full_cpp_name_identifier } : PyTrampolineBase_{ cls.full_cpp_name_identifier }<PyTrampolineBase{ precomma(template_argument_list) }, PyTrampolineCfg> {{
using PyTrampolineBase_{ cls.full_cpp_name_identifier }<PyTrampolineBase{ precomma(template_argument_list) }, PyTrampolineCfg>::PyTrampolineBase_{ cls.full_cpp_name_identifier };
struct PyTrampoline_{ cls.cpp_name } : PyTrampolineBase_{ cls.cpp_name }<PyTrampolineBase{ precomma(template_argument_list) }, PyTrampolineCfg> {{
using PyTrampolineBase_{ cls.cpp_name }<PyTrampolineBase{ precomma(template_argument_list) }, PyTrampolineCfg>::PyTrampolineBase_{ cls.cpp_name };
"""
)

Expand All @@ -194,7 +192,7 @@ def _render_cls_trampoline(
r.write_trim(
f"""
template <typename PyTrampolineBase{ precomma(template_parameter_list) }, typename PyTrampolineCfg>
struct PyTrampoline_{ cls.full_cpp_name_identifier } : PyTrampolineBase {{
struct PyTrampoline_{ cls.cpp_name } : PyTrampolineBase {{
using PyTrampolineBase::PyTrampolineBase;
"""
)
Expand Down Expand Up @@ -234,11 +232,11 @@ def _render_cls_trampoline(
with r.indent():
all_decls = ", ".join(p.decl for p in fn.all_params)
all_names = ", ".join(p.arg_name for p in fn.all_params)
r.writeln(f"PyTrampoline_{cls.full_cpp_name_identifier}({all_decls}) :")
r.writeln(f"PyTrampoline_{cls.cpp_name}({all_decls}) :")

if cls.bases:
r.writeln(
f" PyTrampolineBase_{cls.full_cpp_name_identifier}<PyTrampolineBase{precomma(trampoline.tmpl_args)}, PyTrampolineCfg>({all_names})"
f" PyTrampolineBase_{cls.cpp_name}<PyTrampolineBase{precomma(trampoline.tmpl_args)}, PyTrampolineCfg>({all_names})"
)
else:
r.writeln(f" PyTrampolineBase({all_names})")
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
31 changes: 31 additions & 0 deletions tests/cpp/rpytest/ft/include/ns_hidden.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

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

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

class AnotherC;
};

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; }
};
};

struct o::AnotherC {
AnotherC() = default;
virtual ~AnotherC() = default;
virtual int fn() { return 1; }
};
Loading