Skip to content

Commit 4efad83

Browse files
committed
Put trampolines in original class namespace
- 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
1 parent c710cde commit 4efad83

File tree

5 files changed

+63
-12
lines changed

5 files changed

+63
-12
lines changed

robotpy_build/autowrap/context.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,9 @@ class BaseClassData:
296296
#: turned into underscores.
297297
full_cpp_name_identifier: str # was x_qualname_
298298

299+
#: This ends with ::
300+
namespace_: str
301+
299302
#: C++ name + components, no template parameters
300303
dep_cpp_name: str
301304

robotpy_build/autowrap/cxxparser.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,9 @@ def _count_and_unwrap(
191191
assert False
192192

193193

194-
def _fmt_base_name(typename: PQName) -> typing.Tuple[str, str, str, typing.List[str]]:
194+
def _fmt_base_name(
195+
typename: PQName,
196+
) -> typing.Tuple[str, str, str, str, typing.List[str]]:
195197
all_parts = []
196198
nameonly_parts = []
197199

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

210212
if last_segment.specialization:
211213
most_parts = all_parts[:-1]
214+
ns_parts = all_parts[:-1]
212215
all_parts.append(last_segment.format())
213216
most_parts.append(last_segment.name)
214217
tparam_list = [arg.format() for arg in last_segment.specialization.args]
215218
else:
219+
ns_parts = all_parts[:]
216220
all_parts.append(last_segment.name)
217221
most_parts = all_parts
218222
tparam_list = []
@@ -221,6 +225,7 @@ def _fmt_base_name(typename: PQName) -> typing.Tuple[str, str, str, typing.List[
221225
"::".join(most_parts),
222226
"::".join(all_parts),
223227
"::".join(nameonly_parts),
228+
"::".join(ns_parts),
224229
tparam_list,
225230
)
226231

@@ -824,8 +829,8 @@ def _process_class_bases(
824829
if base.access == "private":
825830
continue
826831

827-
cpp_name, cpp_name_w_templates, dep_cpp_name, tparam_list = _fmt_base_name(
828-
base.typename
832+
cpp_name, cpp_name_w_templates, dep_cpp_name, base_ns, tparam_list = (
833+
_fmt_base_name(base.typename)
829834
)
830835
if ignored_bases.pop(cpp_name_w_templates, None):
831836
continue
@@ -846,6 +851,11 @@ def _process_class_bases(
846851
cpp_name = user_bqual[:tp]
847852
template_params = user_bqual[tp + 1 : -1]
848853
dep_cpp_name = cpp_name
854+
ns_idx = cpp_name.rfind("::")
855+
if ns_idx == -1:
856+
base_ns = ""
857+
else:
858+
base_ns = cpp_name[:ns_idx]
849859
else:
850860
# TODO: we don't handle nested child classes with templates here
851861
# ... but that has to be rather obscure?
@@ -858,17 +868,22 @@ def _process_class_bases(
858868
# If no explicit namespace specified, we assume base classes
859869
# live in the same namespace as the class
860870
if len(base.typename.segments) == 1:
871+
base_ns = cls_namespace
861872
cpp_name = f"{cls_namespace}::{cpp_name}"
862873
cpp_name_w_templates = f"{cls_namespace}::{cpp_name_w_templates}"
863874
dep_cpp_name = f"{cls_namespace}::{dep_cpp_name}"
864875

865876
base_identifier = cpp_name.translate(_qualname_trans)
866877

878+
if base_ns:
879+
base_ns = f"{base_ns}::"
880+
867881
bases.append(
868882
BaseClassData(
869883
full_cpp_name=cpp_name,
870884
full_cpp_name_w_templates=cpp_name_w_templates,
871885
full_cpp_name_identifier=base_identifier,
886+
namespace_=base_ns,
872887
dep_cpp_name=dep_cpp_name,
873888
template_params=template_params,
874889
)
@@ -1242,8 +1257,8 @@ def on_class_end(self, state: AWClassBlockState) -> None:
12421257
if cdata.template_argument_list:
12431258
tmpl = f", {cdata.template_argument_list}"
12441259

1245-
trampoline_cfg = f"rpygen::PyTrampolineCfg_{cdata.cls_cpp_identifier}<{cdata.template_argument_list}>"
1246-
tname = f"rpygen::PyTrampoline_{cdata.cls_cpp_identifier}<typename {ctx.full_cpp_name}{tmpl}, typename {trampoline_cfg}>"
1260+
trampoline_cfg = f"{cdata.ctx.namespace}::PyTrampolineCfg_{cdata.cls_cpp_identifier}<{cdata.template_argument_list}>"
1261+
tname = f"{cdata.ctx.namespace}::PyTrampoline_{cdata.cls_cpp_identifier}<typename {ctx.full_cpp_name}{tmpl}, typename {trampoline_cfg}>"
12471262
tvar = f"{ctx.cpp_name}_Trampoline"
12481263

12491264
ctx.trampoline = TrampolineData(

robotpy_build/autowrap/render_cls_rpy_include.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,8 @@ def _render_cls_trampoline(
101101
for base in cls.bases:
102102
r.writeln(f"#include <rpygen/{ base.full_cpp_name_identifier }.hpp>")
103103

104-
r.writeln("\nnamespace rpygen {")
105-
106104
if cls.namespace:
107-
r.writeln(f"\nusing namespace {cls.namespace};")
105+
r.writeln(f"\nnamespace {cls.namespace.strip('::')} {{")
108106

109107
if hctx.using_declarations:
110108
r.writeln()
@@ -122,7 +120,7 @@ def _render_cls_trampoline(
122120
#
123121

124122
r.writeln(
125-
f"\ntemplate <{postcomma(template_parameter_list)}typename CfgBase = EmptyTrampolineCfg>"
123+
f"\ntemplate <{postcomma(template_parameter_list)}typename CfgBase = rpygen::EmptyTrampolineCfg>"
126124
)
127125

128126
if cls.bases:
@@ -131,7 +129,7 @@ def _render_cls_trampoline(
131129
with r.indent():
132130
for base in cls.bases:
133131
r.writeln(
134-
f"PyTrampolineCfg_{base.full_cpp_name_identifier}<{postcomma(base.template_params)}"
132+
f"{base.namespace_}PyTrampolineCfg_{base.full_cpp_name_identifier}<{postcomma(base.template_params)}"
135133
)
136134

137135
r.writeln("CfgBase")
@@ -168,7 +166,7 @@ def _render_cls_trampoline(
168166

169167
for base in cls.bases:
170168
r.rel_indent(2)
171-
r.writeln(f"PyTrampoline_{base.full_cpp_name_identifier}<")
169+
r.writeln(f"{base.namespace_}PyTrampoline_{base.full_cpp_name_identifier}<")
172170

173171
with r.indent():
174172
r.writeln("PyTrampolineBase")
@@ -284,7 +282,10 @@ def _render_cls_trampoline(
284282
r.writeln()
285283
r.write_trim(trampoline.inline_code)
286284

287-
r.writeln("};\n\n}; // namespace rpygen")
285+
r.writeln("};\n\n")
286+
287+
if cls.namespace:
288+
r.writeln(f"}}; // namespace {cls.namespace}")
288289

289290

290291
def _render_cls_trampoline_virtual_method(

tests/cpp/pyproject.toml.tmpl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ generate = [
6161
{ lifetime = "lifetime.h" },
6262
{ nested = "nested.h" },
6363
{ ns_class = "ns_class.h" },
64+
{ ns_hidden = "ns_hidden.h" },
6465
{ operators = "operators.h" },
6566
{ overloads = "overloads.h" },
6667
{ parameters = "parameters.h" },
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#pragma once
2+
3+
namespace n {
4+
enum class E {
5+
Item,
6+
};
7+
};
8+
9+
namespace o {
10+
struct O {
11+
O() = default;
12+
virtual ~O() = default;
13+
};
14+
15+
class AnotherC;
16+
};
17+
18+
namespace n::h {
19+
class C : public o::O {
20+
public:
21+
// E is resolved here because it's in the parent namespace but our
22+
// trampoline was originally in a different namespace and failed
23+
virtual E fn() { return E::Item; }
24+
};
25+
};
26+
27+
struct o::AnotherC {
28+
AnotherC() = default;
29+
virtual ~AnotherC() = default;
30+
virtual int fn() { return 1; }
31+
};

0 commit comments

Comments
 (0)