Skip to content

Commit a2989c4

Browse files
authored
Merge pull request #240 from robotpy/trampoline-ns
Put trampolines in original class namespace
2 parents c710cde + 1caea5d commit a2989c4

File tree

5 files changed

+89
-30
lines changed

5 files changed

+89
-30
lines changed

robotpy_build/autowrap/context.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,12 @@ class BaseClassData:
287287
Render data for each base that a class inherits
288288
"""
289289

290+
#: Just the class name
291+
cls_name: str
292+
293+
#: This ends with ::
294+
namespace_: str
295+
290296
#: C++ name, including all known components
291297
full_cpp_name: str # was x_qualname
292298

robotpy_build/autowrap/cxxparser.py

Lines changed: 35 additions & 15 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, str, typing.List[str]]:
195197
all_parts = []
196198
nameonly_parts = []
197199

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

220224
return (
225+
last_segment.name,
221226
"::".join(most_parts),
222227
"::".join(all_parts),
223228
"::".join(nameonly_parts),
229+
"::".join(ns_parts),
224230
tparam_list,
225231
)
226232

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

289295
# Needed for trampoline
290-
cls_cpp_identifier: str
291296
template_argument_list: str
292297
base_template_params: str
293298
base_template_args: str
@@ -751,7 +756,6 @@ def on_class_start(self, state: AWClassBlockState) -> typing.Optional[bool]:
751756
defer_private_virtual_methods=[],
752757
defer_protected_fields=[],
753758
# Trampoline data
754-
cls_cpp_identifier=cls_cpp_identifier,
755759
template_argument_list=template_argument_list,
756760
base_template_args=base_template_args_s,
757761
base_template_params=base_template_params_s,
@@ -824,28 +828,38 @@ def _process_class_bases(
824828
if base.access == "private":
825829
continue
826830

827-
cpp_name, cpp_name_w_templates, dep_cpp_name, tparam_list = _fmt_base_name(
828-
base.typename
829-
)
831+
(
832+
cpp_name,
833+
full_cpp_name,
834+
cpp_name_w_templates,
835+
dep_cpp_name,
836+
base_ns,
837+
tparam_list,
838+
) = _fmt_base_name(base.typename)
830839
if ignored_bases.pop(cpp_name_w_templates, None):
831840
continue
832841

833842
# Sometimes, we can't guess all the information about the base, so the
834843
# user needs to specify it explicitly.
835-
user_bqual = class_data.base_qualnames.get(cpp_name)
844+
user_bqual = class_data.base_qualnames.get(full_cpp_name)
836845
if user_bqual:
837846
cpp_name_w_templates = user_bqual
838847
# TODO: sometimes need to add this to pybase_params, but
839848
# that would require parsing this more. Seems sufficiently
840849
# obscure, going to omit it for now.
841850
tp = user_bqual.find("<")
842851
if tp == -1:
843-
cpp_name = user_bqual
852+
full_cpp_name = user_bqual
844853
template_params = ""
845854
else:
846-
cpp_name = user_bqual[:tp]
855+
full_cpp_name = user_bqual[:tp]
847856
template_params = user_bqual[tp + 1 : -1]
848-
dep_cpp_name = cpp_name
857+
dep_cpp_name = full_cpp_name
858+
ns_idx = full_cpp_name.rfind("::")
859+
if ns_idx == -1:
860+
base_ns = ""
861+
else:
862+
base_ns = full_cpp_name[:ns_idx]
849863
else:
850864
# TODO: we don't handle nested child classes with templates here
851865
# ... but that has to be rather obscure?
@@ -858,15 +872,21 @@ def _process_class_bases(
858872
# If no explicit namespace specified, we assume base classes
859873
# live in the same namespace as the class
860874
if len(base.typename.segments) == 1:
861-
cpp_name = f"{cls_namespace}::{cpp_name}"
875+
base_ns = cls_namespace
876+
full_cpp_name = f"{cls_namespace}::{full_cpp_name}"
862877
cpp_name_w_templates = f"{cls_namespace}::{cpp_name_w_templates}"
863878
dep_cpp_name = f"{cls_namespace}::{dep_cpp_name}"
864879

865-
base_identifier = cpp_name.translate(_qualname_trans)
880+
base_identifier = full_cpp_name.translate(_qualname_trans)
881+
882+
if base_ns:
883+
base_ns = f"{base_ns}::"
866884

867885
bases.append(
868886
BaseClassData(
869-
full_cpp_name=cpp_name,
887+
cls_name=cpp_name,
888+
namespace_=base_ns,
889+
full_cpp_name=full_cpp_name,
870890
full_cpp_name_w_templates=cpp_name_w_templates,
871891
full_cpp_name_identifier=base_identifier,
872892
dep_cpp_name=dep_cpp_name,
@@ -1242,8 +1262,8 @@ def on_class_end(self, state: AWClassBlockState) -> None:
12421262
if cdata.template_argument_list:
12431263
tmpl = f", {cdata.template_argument_list}"
12441264

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}>"
1265+
trampoline_cfg = f"{ctx.namespace}::PyTrampolineCfg_{ctx.cpp_name}<{cdata.template_argument_list}>"
1266+
tname = f"{ctx.namespace}::PyTrampoline_{ctx.cpp_name}<typename {ctx.full_cpp_name}{tmpl}, typename {trampoline_cfg}>"
12471267
tvar = f"{ctx.cpp_name}_Trampoline"
12481268

12491269
ctx.trampoline = TrampolineData(

robotpy_build/autowrap/render_cls_rpy_include.py

Lines changed: 16 additions & 15 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,24 +120,24 @@ 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:
129-
r.writeln(f"struct PyTrampolineCfg_{cls.full_cpp_name_identifier} :")
127+
r.writeln(f"struct PyTrampolineCfg_{cls.cpp_name} :")
130128

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

137135
r.writeln("CfgBase")
138136

139137
for base in cls.bases:
140138
r.writeln(">")
141139
else:
142-
r.writeln(f"struct PyTrampolineCfg_{cls.full_cpp_name_identifier} : CfgBase")
140+
r.writeln(f"struct PyTrampolineCfg_{cls.cpp_name} : CfgBase")
143141

144142
r.writeln("{")
145143

@@ -164,11 +162,11 @@ def _render_cls_trampoline(
164162
r.writeln(
165163
f"template <typename PyTrampolineBase{precomma(template_parameter_list)}, typename PyTrampolineCfg>"
166164
)
167-
r.writeln(f"using PyTrampolineBase_{cls.full_cpp_name_identifier} =")
165+
r.writeln(f"using PyTrampolineBase_{cls.cpp_name} =")
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.cls_name}<")
172170

173171
with r.indent():
174172
r.writeln("PyTrampolineBase")
@@ -184,8 +182,8 @@ def _render_cls_trampoline(
184182
;
185183
186184
template <typename PyTrampolineBase{ precomma(template_parameter_list) }, typename PyTrampolineCfg>
187-
struct PyTrampoline_{ cls.full_cpp_name_identifier } : PyTrampolineBase_{ cls.full_cpp_name_identifier }<PyTrampolineBase{ precomma(template_argument_list) }, PyTrampolineCfg> {{
188-
using PyTrampolineBase_{ cls.full_cpp_name_identifier }<PyTrampolineBase{ precomma(template_argument_list) }, PyTrampolineCfg>::PyTrampolineBase_{ cls.full_cpp_name_identifier };
185+
struct PyTrampoline_{ cls.cpp_name } : PyTrampolineBase_{ cls.cpp_name }<PyTrampolineBase{ precomma(template_argument_list) }, PyTrampolineCfg> {{
186+
using PyTrampolineBase_{ cls.cpp_name }<PyTrampolineBase{ precomma(template_argument_list) }, PyTrampolineCfg>::PyTrampolineBase_{ cls.cpp_name };
189187
"""
190188
)
191189

@@ -194,7 +192,7 @@ def _render_cls_trampoline(
194192
r.write_trim(
195193
f"""
196194
template <typename PyTrampolineBase{ precomma(template_parameter_list) }, typename PyTrampolineCfg>
197-
struct PyTrampoline_{ cls.full_cpp_name_identifier } : PyTrampolineBase {{
195+
struct PyTrampoline_{ cls.cpp_name } : PyTrampolineBase {{
198196
using PyTrampolineBase::PyTrampolineBase;
199197
"""
200198
)
@@ -234,11 +232,11 @@ def _render_cls_trampoline(
234232
with r.indent():
235233
all_decls = ", ".join(p.decl for p in fn.all_params)
236234
all_names = ", ".join(p.arg_name for p in fn.all_params)
237-
r.writeln(f"PyTrampoline_{cls.full_cpp_name_identifier}({all_decls}) :")
235+
r.writeln(f"PyTrampoline_{cls.cpp_name}({all_decls}) :")
238236

239237
if cls.bases:
240238
r.writeln(
241-
f" PyTrampolineBase_{cls.full_cpp_name_identifier}<PyTrampolineBase{precomma(trampoline.tmpl_args)}, PyTrampolineCfg>({all_names})"
239+
f" PyTrampolineBase_{cls.cpp_name}<PyTrampolineBase{precomma(trampoline.tmpl_args)}, PyTrampolineCfg>({all_names})"
242240
)
243241
else:
244242
r.writeln(f" PyTrampolineBase({all_names})")
@@ -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)