checker: fix checking of default field initialisations, that are part of unions of structs tagged with @[noinit] (#21587)

This commit is contained in:
Delyan Angelov 2024-05-28 17:27:43 +03:00 committed by GitHub
parent 80397e679e
commit 09eaae5f7a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 90 additions and 5 deletions

View File

@ -341,6 +341,8 @@ pub:
is_deprecated bool
pub mut:
is_recursive bool
is_part_of_union bool
container_typ Type
default_expr Expr
default_expr_typ Type
name string

View File

@ -14,6 +14,13 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) {
mut struct_sym, struct_typ_idx := c.table.find_sym_and_type_idx(node.name)
mut has_generic_types := false
if mut struct_sym.info is ast.Struct {
for mut symfield in struct_sym.info.fields {
symfield.container_typ = struct_typ_idx
if struct_sym.info.is_union {
symfield.is_part_of_union = true
}
}
if node.language == .v && !c.is_builtin_mod && !struct_sym.info.is_anon {
c.check_valid_pascal_case(node.name, 'struct name', node.pos)
}
@ -844,12 +851,22 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
node.pos)
}
if !node.has_update_expr && !field.has_default_expr && !field.typ.is_ptr()
&& !field.typ.has_flag(.option) && c.table.final_sym(field.typ).kind == .struct_ {
mut zero_struct_init := ast.StructInit{
pos: node.pos
typ: field.typ
&& !field.typ.has_flag(.option) {
field_final_sym := c.table.final_sym(field.typ)
if field_final_sym.kind == .struct_ {
mut zero_struct_init := ast.StructInit{
pos: node.pos
typ: field.typ
}
if field.is_part_of_union {
if field.name in inited_fields {
// fields that are part of an union, should only be checked, when they are explicitly initialised
c.struct_init(mut zero_struct_init, true, mut inited_fields)
}
} else {
c.struct_init(mut zero_struct_init, true, mut inited_fields)
}
}
c.struct_init(mut zero_struct_init, true, mut inited_fields)
}
}
for embed in info.embeds {

View File

@ -0,0 +1,22 @@
module structs_with_noinit
@[noinit]
pub struct Image {}
@[noinit]
pub struct Rect {}
@[noinit]
pub struct Circle {}
pub fn make_circle() Circle {
return Circle{}
}
pub fn make_image() Image {
return Image{}
}
pub fn make_rect() Rect {
return Rect{}
}

View File

@ -0,0 +1,44 @@
module main
import structs_with_noinit
enum RenderableKind {
circle
image
rect
}
union RenderableValue {
circle structs_with_noinit.Circle
image structs_with_noinit.Image
rect structs_with_noinit.Rect
}
struct Renderable {
RenderableValue
kind RenderableKind
}
fn draw(r Renderable) int {
match r.kind {
.circle {
println('()')
return 999
}
.rect {
println('[]')
}
.image {
println('o_O')
}
}
return 1
}
fn test_initialisation_of_a_struct_containing_embedded_union_field() {
r := Renderable{
kind: .circle
circle: structs_with_noinit.make_circle()
}
assert draw(r) == 999
}