Skip to content

Commit 88e240b

Browse files
authored
fix: Fetch virtual table dependencies in resolver (#1535)
Previously, when visiting the virtual-table pointer of a class or function block, the resolver added a dependency on the intrinsic `VOID` type but not on the concrete `__vtable_*` struct and its members. Codegen then failed with “unknown type” when expanding opaque types that reference vtable members. This commit fixes that, such that the members of the virtual table are fetched and added as dependencies in the resolver module. A minimal reproducible example would be ``` // file: main.st FUNCTION main VAR baseInstance: base; baseRef: POINTER TO base; END_VAR baseRef := ADR(baseInstance); baseRef^.foo(); END_FUNCTION // file: base.st FUNCTION_BLOCK base METHOD foo printf('base::foo$N'); END_METHOD END_FUNCTION_BLOCK ```
1 parent c8a55ad commit 88e240b

File tree

17 files changed

+242
-39
lines changed

17 files changed

+242
-39
lines changed

src/codegen/tests/initialization_test/complex_initializers.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -414,23 +414,23 @@ fn nested_initializer_pous() {
414414
%foo = type { i32*, [81 x i8]*, %bar }
415415
%bar = type { i32*, %baz }
416416
%baz = type { i32*, [81 x i8]* }
417-
%sideProg = type { [81 x i8]*, %foo }
418-
%__vtable_foo = type { void (%foo*)* }
419-
%__vtable_bar = type { void (%bar*)* }
420417
%__vtable_baz = type { void (%baz*)* }
418+
%__vtable_bar = type { void (%bar*)* }
419+
%__vtable_foo = type { void (%foo*)* }
420+
%sideProg = type { [81 x i8]*, %foo }
421421
422422
@str = global [81 x i8] c"hello\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00"
423423
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @__init___Test, i8* null }]
424424
@mainProg_instance = global %mainProg zeroinitializer
425425
@__foo__init = unnamed_addr constant %foo zeroinitializer
426426
@__bar__init = unnamed_addr constant %bar zeroinitializer
427427
@__baz__init = unnamed_addr constant %baz zeroinitializer
428-
@sideProg_instance = global %sideProg zeroinitializer
428+
@____vtable_baz__init = unnamed_addr constant %__vtable_baz zeroinitializer
429+
@____vtable_bar__init = unnamed_addr constant %__vtable_bar zeroinitializer
429430
@____vtable_foo__init = unnamed_addr constant %__vtable_foo zeroinitializer
431+
@sideProg_instance = global %sideProg zeroinitializer
430432
@__vtable_foo_instance = global %__vtable_foo zeroinitializer
431-
@____vtable_bar__init = unnamed_addr constant %__vtable_bar zeroinitializer
432433
@__vtable_bar_instance = global %__vtable_bar zeroinitializer
433-
@____vtable_baz__init = unnamed_addr constant %__vtable_baz zeroinitializer
434434
@__vtable_baz_instance = global %__vtable_baz zeroinitializer
435435
436436
define void @foo(%foo* %0) {
@@ -1321,8 +1321,8 @@ fn global_instance() {
13211321
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @__init___Test, i8* null }]
13221322
@prog_instance = global %prog zeroinitializer
13231323
@__foo__init = unnamed_addr constant %foo zeroinitializer
1324-
@fb = global %foo zeroinitializer
13251324
@____vtable_foo__init = unnamed_addr constant %__vtable_foo zeroinitializer
1325+
@fb = global %foo zeroinitializer
13261326
@__vtable_foo_instance = global %__vtable_foo zeroinitializer
13271327
13281328
define void @foo(%foo* %0) {
@@ -1448,8 +1448,8 @@ fn aliased_types() {
14481448
@llvm.global_ctors = appending global [1 x { i32, void ()*, i8* }] [{ i32, void ()*, i8* } { i32 0, void ()* @__init___Test, i8* null }]
14491449
@prog_instance = global %prog zeroinitializer
14501450
@__foo__init = unnamed_addr constant %foo zeroinitializer
1451-
@global_alias = global %foo zeroinitializer
14521451
@____vtable_foo__init = unnamed_addr constant %__vtable_foo zeroinitializer
1452+
@global_alias = global %foo zeroinitializer
14531453
@__vtable_foo_instance = global %__vtable_foo zeroinitializer
14541454
14551455
define void @foo(%foo* %0) {
@@ -3174,8 +3174,8 @@ fn user_fb_init_in_global_struct() {
31743174
@prog_instance = global %prog zeroinitializer
31753175
@__bar__init = unnamed_addr constant %bar zeroinitializer
31763176
@__foo__init = unnamed_addr constant %foo zeroinitializer
3177-
@str = global %bar zeroinitializer
31783177
@____vtable_foo__init = unnamed_addr constant %__vtable_foo zeroinitializer
3178+
@str = global %bar zeroinitializer
31793179
@__vtable_foo_instance = global %__vtable_foo zeroinitializer
31803180
31813181
define void @foo(%foo* %0) {

src/codegen/tests/oop_tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1344,8 +1344,8 @@ fn pass_this_to_method() {
13441344
@____vtable_FB_Test__init = unnamed_addr constant %__vtable_FB_Test zeroinitializer
13451345
@__FB_Test__init = unnamed_addr constant %FB_Test { i32* null, i16 5 }
13461346
@__FB_Test2__init = unnamed_addr constant %FB_Test2 zeroinitializer
1347-
@__vtable_FB_Test_instance = global %__vtable_FB_Test zeroinitializer
13481347
@____vtable_FB_Test2__init = unnamed_addr constant %__vtable_FB_Test2 zeroinitializer
1348+
@__vtable_FB_Test_instance = global %__vtable_FB_Test zeroinitializer
13491349
@__vtable_FB_Test2_instance = global %__vtable_FB_Test2 zeroinitializer
13501350
13511351
define void @FB_Test(%FB_Test* %0) {

src/resolver.rs

Lines changed: 34 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,44 +1582,52 @@ impl<'i> TypeAnnotator<'i> {
15821582
fn get_datatype_dependencies(
15831583
&self,
15841584
datatype_name: &str,
1585-
resolved: FxIndexSet<Dependency>,
1585+
mut resolved: FxIndexSet<Dependency>,
15861586
) -> FxIndexSet<Dependency> {
1587-
let mut resolved_names = resolved;
15881587
let Some(datatype) = self
15891588
.index
15901589
.find_type(datatype_name)
15911590
.or_else(|| self.annotation_map.new_index.find_type(datatype_name))
15921591
else {
1593-
return resolved_names;
1592+
return resolved;
15941593
};
1595-
if resolved_names.insert(Dependency::Datatype(datatype.get_name().to_string())) {
1596-
match datatype.get_type_information() {
1597-
DataTypeInformation::Struct { members, source, .. } => {
1598-
for member in members {
1599-
resolved_names =
1600-
self.get_datatype_dependencies(member.get_type_name(), resolved_names);
1601-
}
16021594

1603-
if let StructSource::Pou(PouType::Method { parent, .. }) = source {
1604-
resolved_names = self.get_datatype_dependencies(parent, resolved_names);
1605-
}
1595+
// Return if the datatype has already been visited
1596+
if !resolved.insert(Dependency::Datatype(datatype.get_name().to_string())) {
1597+
return resolved;
1598+
};
16061599

1607-
resolved_names
1600+
match datatype.get_type_information() {
1601+
DataTypeInformation::Struct { members, source, .. } => {
1602+
for member in members {
1603+
resolved = self.get_datatype_dependencies(member.get_type_name(), resolved);
16081604
}
1609-
DataTypeInformation::Array { inner_type_name, .. }
1610-
| DataTypeInformation::Pointer { inner_type_name, .. } => {
1611-
resolved_names
1612-
.insert(Dependency::Datatype(datatype.get_type_information().get_name().to_string()));
1613-
self.get_datatype_dependencies(inner_type_name, resolved_names)
1614-
}
1615-
_ => {
1616-
let name =
1617-
self.index.get_intrinsic_type_information(datatype.get_type_information()).get_name();
1618-
self.get_datatype_dependencies(name, resolved_names)
1605+
1606+
match source {
1607+
StructSource::Pou(PouType::Class | PouType::FunctionBlock) => {
1608+
// While the members of a struct such as a class or function block are visited
1609+
// recursively, the vtable itself is declared as a VOID pointer. Thus, when landing
1610+
// in the pointer variant branch of this function, a datatype dependency of VOID will
1611+
// be returned. However, the actual vtable is a struct with all the function pointers
1612+
// of a POU. Therefore, we need to explicitly visit the `__vtable_...` datatype here.
1613+
let name = format!("__vtable_{}", datatype.get_name());
1614+
self.get_datatype_dependencies(&name, resolved)
1615+
}
1616+
StructSource::Pou(PouType::Method { parent, .. }) => {
1617+
self.get_datatype_dependencies(parent, resolved)
1618+
}
1619+
_ => resolved,
16191620
}
16201621
}
1621-
} else {
1622-
resolved_names
1622+
DataTypeInformation::Array { inner_type_name, .. }
1623+
| DataTypeInformation::Pointer { inner_type_name, .. } => {
1624+
resolved.insert(Dependency::Datatype(datatype.get_type_information().get_name().to_string()));
1625+
self.get_datatype_dependencies(inner_type_name, resolved)
1626+
}
1627+
_ => {
1628+
let dt_info = self.index.get_intrinsic_type_information(datatype.get_type_information());
1629+
self.get_datatype_dependencies(dt_info.get_name(), resolved)
1630+
}
16231631
}
16241632
}
16251633

src/resolver/tests/const_resolver_tests.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1413,6 +1413,5 @@ fn leading_unary_plus_in_global_const_reference_is_resolvable() {
14131413
);
14141414

14151415
let (_, unresolvable) = evaluate_constants(index);
1416-
dbg!(&unresolvable);
14171416
assert_eq!(unresolvable.len(), 0);
14181417
}

src/tests/adr/initializer_functions_adr.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -756,10 +756,10 @@ fn generating_init_functions() {
756756
@__bar__init = unnamed_addr constant %bar zeroinitializer
757757
@__foo__init = unnamed_addr constant %foo zeroinitializer
758758
@__myStruct__init = unnamed_addr constant %myStruct zeroinitializer
759-
@s = global %myStruct zeroinitializer
760759
@____vtable_foo__init = unnamed_addr constant %__vtable_foo zeroinitializer
761-
@__vtable_foo_instance = global %__vtable_foo zeroinitializer
762760
@____vtable_bar__init = unnamed_addr constant %__vtable_bar zeroinitializer
761+
@s = global %myStruct zeroinitializer
762+
@__vtable_foo_instance = global %__vtable_foo zeroinitializer
763763
@__vtable_bar_instance = global %__vtable_bar zeroinitializer
764764
765765
define void @foo(%foo* %0) {
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
CLASS ClassA
2+
METHOD alpha
3+
printf('ClassA::alpha$N');
4+
END_METHOD
5+
6+
METHOD bravo
7+
printf('ClassA::bravo$N');
8+
END_METHOD
9+
10+
METHOD charlie
11+
printf('ClassA::charlie$N');
12+
END_METHOD
13+
14+
METHOD delta
15+
printf('ClassA::delta$N');
16+
END_METHOD
17+
END_CLASS
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CLASS ClassB EXTENDS ClassA
2+
METHOD bravo
3+
printf('ClassB::bravo$N');
4+
END_METHOD
5+
END_CLASS
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CLASS ClassC EXTENDS ClassB
2+
METHOD charlie
3+
printf('ClassC::charlie$N');
4+
END_METHOD
5+
END_CLASS
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
CLASS ClassD EXTENDS ClassC
2+
METHOD alpha
3+
printf('ClassD::alpha$N');
4+
END_METHOD
5+
6+
METHOD bravo
7+
printf('ClassD::bravo$N');
8+
END_METHOD
9+
10+
METHOD charlie
11+
printf('ClassD::charlie$N');
12+
END_METHOD
13+
14+
METHOD delta
15+
printf('ClassD::delta$N');
16+
END_METHOD
17+
END_CLASS
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
FUNCTION main
2+
VAR
3+
instanceA: ClassA;
4+
instanceB: ClassB;
5+
instanceC: ClassC;
6+
instanceD: ClassD;
7+
8+
refInstanceA: POINTER TO ClassA;
9+
END_VAR
10+
11+
refInstanceA := ADR(instanceA);
12+
refInstanceA^.alpha();
13+
refInstanceA^.bravo();
14+
refInstanceA^.charlie();
15+
refInstanceA^.delta();
16+
17+
refInstanceA := ADR(instanceB);
18+
refInstanceA^.alpha();
19+
refInstanceA^.bravo();
20+
refInstanceA^.charlie();
21+
refInstanceA^.delta();
22+
23+
refInstanceA := ADR(instanceC);
24+
refInstanceA^.alpha();
25+
refInstanceA^.bravo();
26+
refInstanceA^.charlie();
27+
refInstanceA^.delta();
28+
29+
refInstanceA := ADR(instanceD);
30+
refInstanceA^.alpha();
31+
refInstanceA^.bravo();
32+
refInstanceA^.charlie();
33+
refInstanceA^.delta();
34+
END_FUNCTION

0 commit comments

Comments
 (0)