Skip to content

Commit 56cb2d7

Browse files
committed
v3: fix defer control flow and string alias comparisons
1 parent 73248e7 commit 56cb2d7

2 files changed

Lines changed: 91 additions & 17 deletions

File tree

vlib/v3/gen/fastc/fastc.v

Lines changed: 63 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,7 @@ struct FastcEnumInfo {
335335
struct FastcTypeDeclarations {
336336
declarations string
337337
enum_string_helpers string
338+
alias_base_types map[string]string
338339
}
339340

340341
struct FastcLoopBlockResult {
@@ -349,6 +350,7 @@ struct Parser {
349350
imports map[string]string
350351
declared_types map[string]bool
351352
declared_kinds map[string]FastcDeclaredTypeKind
353+
alias_base_types map[string]string
352354
struct_fields map[string]map[string]string
353355
struct_field_info map[string][]FastcStructField
354356
constants map[string]string
@@ -381,6 +383,7 @@ mut:
381383
current_receiver string
382384
expected_expression_type string
383385
capturing_defer bool
386+
defer_depth int
384387
captured_defer_lines []string
385388
deferred_lines []string
386389
deferred_block_starts []int
@@ -465,15 +468,15 @@ fn generate_source_files(sources []FastcSourceFile, prefs &pref.Preferences) !st
465468
type_declarations := type_output.declarations
466469
mut constant_types := map[string]string{}
467470
mut global_types := map[string]string{}
468-
fastc_render_struct_field_defaults(prefs, declared_types, declared_kinds, struct_fields, mut
469-
struct_field_info, functions, constants, public_constants, constant_types, globals,
470-
public_globals, global_types)!
471+
fastc_render_struct_field_defaults(prefs, declared_types, declared_kinds,
472+
type_output.alias_base_types, struct_fields, mut struct_field_info, functions, constants,
473+
public_constants, constant_types, globals, public_globals, global_types)!
471474
constant_output := fastc_generate_constant_declarations(sources, prefs, declared_types,
472-
declared_kinds, struct_fields, struct_field_info, functions, constants, public_constants,
473-
globals, public_globals, mut constant_types)!
475+
declared_kinds, type_output.alias_base_types, struct_fields, struct_field_info, functions,
476+
constants, public_constants, globals, public_globals, mut constant_types)!
474477
global_output := fastc_generate_global_declarations(sources, prefs, declared_types,
475-
declared_kinds, struct_fields, struct_field_info, functions, constants, public_constants,
476-
constant_types, globals, public_globals, mut global_types)!
478+
declared_kinds, type_output.alias_base_types, struct_fields, struct_field_info, functions,
479+
constants, public_constants, constant_types, globals, public_globals, mut global_types)!
477480
for constant_type in constant_types.values() {
478481
fastc_register_composite_type(constant_type, mut composite_types)
479482
}
@@ -496,6 +499,7 @@ fn generate_source_files(sources []FastcSourceFile, prefs &pref.Preferences) !st
496499
imports: source_file.header.imports
497500
declared_types: declared_types
498501
declared_kinds: declared_kinds
502+
alias_base_types: type_output.alias_base_types
499503
struct_fields: struct_fields
500504
struct_field_info: struct_field_info
501505
constants: constants
@@ -1264,7 +1268,7 @@ fn fastc_register_global(header FastcSourceHeader, name string, is_public bool,
12641268
}
12651269
}
12661270

1267-
fn fastc_generate_global_declarations(sources []FastcSourceFile, prefs &pref.Preferences, declared_types map[string]bool, declared_kinds map[string]FastcDeclaredTypeKind, struct_fields map[string]map[string]string, struct_field_info map[string][]FastcStructField, functions map[string]FastcFunctionSignature, constants map[string]string, public_constants map[string]bool, constant_types map[string]string, globals map[string]string, public_globals map[string]bool, mut global_types map[string]string) !FastcGlobalDeclarations {
1271+
fn fastc_generate_global_declarations(sources []FastcSourceFile, prefs &pref.Preferences, declared_types map[string]bool, declared_kinds map[string]FastcDeclaredTypeKind, alias_base_types map[string]string, struct_fields map[string]map[string]string, struct_field_info map[string][]FastcStructField, functions map[string]FastcFunctionSignature, constants map[string]string, public_constants map[string]bool, constant_types map[string]string, globals map[string]string, public_globals map[string]bool, mut global_types map[string]string) !FastcGlobalDeclarations {
12681272
mut out := strings.new_builder(1024)
12691273
mut module_initializers := map[string]string{}
12701274
ordered_sources := fastc_sources_in_dependency_order(sources)!
@@ -1280,6 +1284,7 @@ fn fastc_generate_global_declarations(sources []FastcSourceFile, prefs &pref.Pre
12801284
imports: source_file.header.imports
12811285
declared_types: declared_types
12821286
declared_kinds: declared_kinds
1287+
alias_base_types: alias_base_types
12831288
struct_fields: struct_fields
12841289
struct_field_info: struct_field_info
12851290
constants: constants
@@ -1385,7 +1390,7 @@ fn (mut g Parser) parse_global_declaration(mut out strings.Builder, mut initiali
13851390
g.skip_semicolons()
13861391
}
13871392

1388-
fn fastc_render_struct_field_defaults(prefs &pref.Preferences, declared_types map[string]bool, declared_kinds map[string]FastcDeclaredTypeKind, struct_fields map[string]map[string]string, mut struct_field_info map[string][]FastcStructField, functions map[string]FastcFunctionSignature, constants map[string]string, public_constants map[string]bool, constant_types map[string]string, globals map[string]string, public_globals map[string]bool, global_types map[string]string) ! {
1393+
fn fastc_render_struct_field_defaults(prefs &pref.Preferences, declared_types map[string]bool, declared_kinds map[string]FastcDeclaredTypeKind, alias_base_types map[string]string, struct_fields map[string]map[string]string, mut struct_field_info map[string][]FastcStructField, functions map[string]FastcFunctionSignature, constants map[string]string, public_constants map[string]bool, constant_types map[string]string, globals map[string]string, public_globals map[string]bool, global_types map[string]string) ! {
13891394
mut type_names := struct_field_info.keys()
13901395
type_names.sort()
13911396
for type_name in type_names {
@@ -1405,6 +1410,7 @@ fn fastc_render_struct_field_defaults(prefs &pref.Preferences, declared_types ma
14051410
imports: field.imports
14061411
declared_types: declared_types
14071412
declared_kinds: declared_kinds
1413+
alias_base_types: alias_base_types
14081414
struct_fields: struct_fields
14091415
struct_field_info: struct_field_info
14101416
constants: constants
@@ -1445,7 +1451,7 @@ fn fastc_render_struct_field_defaults(prefs &pref.Preferences, declared_types ma
14451451
}
14461452
}
14471453

1448-
fn fastc_generate_constant_declarations(sources []FastcSourceFile, prefs &pref.Preferences, declared_types map[string]bool, declared_kinds map[string]FastcDeclaredTypeKind, struct_fields map[string]map[string]string, struct_field_info map[string][]FastcStructField, functions map[string]FastcFunctionSignature, constants map[string]string, public_constants map[string]bool, globals map[string]string, public_globals map[string]bool, mut constant_types map[string]string) !FastcConstantDeclarations {
1454+
fn fastc_generate_constant_declarations(sources []FastcSourceFile, prefs &pref.Preferences, declared_types map[string]bool, declared_kinds map[string]FastcDeclaredTypeKind, alias_base_types map[string]string, struct_fields map[string]map[string]string, struct_field_info map[string][]FastcStructField, functions map[string]FastcFunctionSignature, constants map[string]string, public_constants map[string]bool, globals map[string]string, public_globals map[string]bool, mut constant_types map[string]string) !FastcConstantDeclarations {
14491455
mut values := []FastcConstantValue{}
14501456
ordered_sources := fastc_sources_in_dependency_order(sources)!
14511457
for source_file in ordered_sources {
@@ -1459,6 +1465,7 @@ fn fastc_generate_constant_declarations(sources []FastcSourceFile, prefs &pref.P
14591465
imports: source_file.header.imports
14601466
declared_types: declared_types
14611467
declared_kinds: declared_kinds
1468+
alias_base_types: alias_base_types
14621469
struct_fields: struct_fields
14631470
struct_field_info: struct_field_info
14641471
constants: constants
@@ -1689,6 +1696,7 @@ fn fastc_generate_type_declarations(sources []FastcSourceFile, prefs &pref.Prefe
16891696
mut out := strings.new_builder(4096)
16901697
mut bodies := strings.new_builder(4096)
16911698
mut enum_infos := []FastcEnumInfo{}
1699+
mut alias_base_types := map[string]string{}
16921700
mut keys := declared_kinds.keys()
16931701
keys.sort()
16941702
for type_id, key in keys {
@@ -1705,7 +1713,7 @@ fn fastc_generate_type_declarations(sources []FastcSourceFile, prefs &pref.Prefe
17051713
for source_file in sources {
17061714
fastc_emit_source_type_declarations(source_file, prefs, declared_types, declared_kinds,
17071715
constants, public_constants, mut struct_fields, mut struct_field_info, mut
1708-
composite_types, mut enum_infos, mut bodies)!
1716+
composite_types, mut alias_base_types, mut enum_infos, mut bodies)!
17091717
}
17101718
mut composite_names := composite_types.keys()
17111719
composite_names.sort()
@@ -1727,6 +1735,7 @@ fn fastc_generate_type_declarations(sources []FastcSourceFile, prefs &pref.Prefe
17271735
} else {
17281736
''
17291737
}
1738+
alias_base_types: alias_base_types
17301739
}
17311740
}
17321741

@@ -1808,7 +1817,7 @@ fn fastc_c_composite_definition_end(source string, start int) ?int {
18081817
return none
18091818
}
18101819

1811-
fn fastc_emit_source_type_declarations(source_file FastcSourceFile, prefs &pref.Preferences, declared_types map[string]bool, declared_kinds map[string]FastcDeclaredTypeKind, constants map[string]string, public_constants map[string]bool, mut struct_fields map[string]map[string]string, mut struct_field_info map[string][]FastcStructField, mut composite_types map[string]bool, mut enum_infos []FastcEnumInfo, mut out strings.Builder) ! {
1820+
fn fastc_emit_source_type_declarations(source_file FastcSourceFile, prefs &pref.Preferences, declared_types map[string]bool, declared_kinds map[string]FastcDeclaredTypeKind, constants map[string]string, public_constants map[string]bool, mut struct_fields map[string]map[string]string, mut struct_field_info map[string][]FastcStructField, mut composite_types map[string]bool, mut alias_base_types map[string]string, mut enum_infos []FastcEnumInfo, mut out strings.Builder) ! {
18121821
mut file_set := token.FileSet.new()
18131822
mut file := file_set.add_file(source_file.path, source_file.source.len)
18141823
file.index_lines(source_file.source)
@@ -1831,7 +1840,8 @@ fn fastc_emit_source_type_declarations(source_file FastcSourceFile, prefs &pref.
18311840
}
18321841
fastc_emit_source_type_declarations(selected_source, prefs, declared_types,
18331842
declared_kinds, constants, public_constants, mut struct_fields, mut
1834-
struct_field_info, mut composite_types, mut enum_infos, mut out)!
1843+
struct_field_info, mut composite_types, mut alias_base_types, mut
1844+
enum_infos, mut out)!
18351845
}
18361846
tok = selected.tok
18371847
next_enum_is_flag = false
@@ -1860,7 +1870,8 @@ fn fastc_emit_source_type_declarations(source_file FastcSourceFile, prefs &pref.
18601870
}
18611871
if depth == 0 && tok == .key_type {
18621872
tok = fastc_emit_alias_declaration(mut scan, source_file, declared_types,
1863-
declared_kinds, prefs.building_v, mut struct_fields, mut struct_field_info, mut out)!
1873+
declared_kinds, prefs.building_v, mut struct_fields, mut struct_field_info, mut
1874+
alias_base_types, mut out)!
18641875
continue
18651876
}
18661877
if tok == .lcbr {
@@ -2425,7 +2436,7 @@ fn fastc_emit_interface_declaration(mut scan scanner.Scanner, source_file FastcS
24252436
return tok
24262437
}
24272438

2428-
fn fastc_emit_alias_declaration(mut scan scanner.Scanner, source_file FastcSourceFile, declared_types map[string]bool, declared_kinds map[string]FastcDeclaredTypeKind, allow_short_placeholders bool, mut struct_fields map[string]map[string]string, mut struct_field_info map[string][]FastcStructField, mut out strings.Builder) !token.Token {
2439+
fn fastc_emit_alias_declaration(mut scan scanner.Scanner, source_file FastcSourceFile, declared_types map[string]bool, declared_kinds map[string]FastcDeclaredTypeKind, allow_short_placeholders bool, mut struct_fields map[string]map[string]string, mut struct_field_info map[string][]FastcStructField, mut alias_base_types map[string]string, mut out strings.Builder) !token.Token {
24292440
mut tok := scan.scan()
24302441
if tok != .name {
24312442
return error('fastc parser does not support type alias in ${source_file.path}')
@@ -2456,6 +2467,7 @@ fn fastc_emit_alias_declaration(mut scan scanner.Scanner, source_file FastcSourc
24562467
out.writeln('typedef struct { void *_object; u32 _typ; } ${c_name};')
24572468
} else if fastc_primitive_c_type(name) == none && declared_kinds[key] == .alias_ {
24582469
out.writeln('typedef ${base} ${c_name};')
2470+
alias_base_types[c_name] = base
24592471
mut layout_type := base.trim_right('*')
24602472
if layout_type.starts_with('Array_') {
24612473
layout_type = 'array'
@@ -4580,6 +4592,23 @@ fn (mut g Parser) parse_block_body() !bool {
45804592
}
45814593

45824594
fn (mut g Parser) parse_statement() !bool {
4595+
if g.defer_depth > 0 {
4596+
match g.tok {
4597+
.key_return {
4598+
return g.unsupported('`return` not allowed inside a `defer` block')
4599+
}
4600+
.key_break, .key_continue {
4601+
return g.unsupported('`${g.tok.str()}` is not allowed in defer statements')
4602+
}
4603+
.key_goto {
4604+
return g.unsupported('goto is not allowed in defer statements')
4605+
}
4606+
.key_defer {
4607+
return g.unsupported('`defer` blocks cannot be nested')
4608+
}
4609+
else {}
4610+
}
4611+
}
45834612
return match g.tok {
45844613
.dollar {
45854614
g.parse_comptime_if_statement()!
@@ -4691,9 +4720,11 @@ fn (mut g Parser) parse_defer() ! {
46914720
previous_capture := g.capturing_defer
46924721
previous_lines := g.captured_defer_lines.clone()
46934722
g.capturing_defer = true
4723+
g.defer_depth++
46944724
g.captured_defer_lines = []string{}
46954725
_ = g.parse_block_body()!
46964726
block := g.captured_defer_lines.clone()
4727+
g.defer_depth--
46974728
g.capturing_defer = previous_capture
46984729
g.captured_defer_lines = previous_lines.clone()
46994730
g.deferred_block_starts << g.deferred_lines.len
@@ -9245,7 +9276,8 @@ fn (g &Parser) render_string_comparison_expression(tokens []FastcExpressionToken
92459276
right_tokens := tokens[i + 1..]
92469277
left_type := g.infer_expression_type(left_tokens) or { return none }
92479278
right_type := g.infer_expression_type(right_tokens) or { return none }
9248-
if left_type.trim_right('*') != 'string' || right_type.trim_right('*') != 'string' {
9279+
if g.underlying_alias_type(left_type).trim_right('*') != 'string'
9280+
|| g.underlying_alias_type(right_type).trim_right('*') != 'string' {
92499281
return none
92509282
}
92519283
left_source := g.render_comparison_operand(left_tokens, 'string') or { return none }
@@ -12174,6 +12206,21 @@ fn (g &Parser) semantic_type_key(c_type string) string {
1217412206
return base
1217512207
}
1217612208

12209+
fn (g &Parser) underlying_alias_type(c_type string) string {
12210+
mut resolved := c_type
12211+
mut seen := map[string]bool{}
12212+
for {
12213+
base := resolved.trim_right('*')
12214+
if base in seen {
12215+
return resolved
12216+
}
12217+
alias_base := g.alias_base_types[base] or { return resolved }
12218+
seen[base] = true
12219+
resolved = alias_base + resolved[base.len..]
12220+
}
12221+
return resolved
12222+
}
12223+
1217712224
fn fastc_number_expression_type(literal string) string {
1217812225
clean := literal.replace('_', '')
1217912226
if clean.contains('.') || (!(clean.starts_with('0x') || clean.starts_with('0X'))

vlib/v3/gen/fastc/fastc_test.v

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1619,10 +1619,16 @@ fn test_comparison_and_logical_operands_are_validated() {
16191619

16201620
c_source := generate("module main
16211621
1622+
type Label = string
1623+
16221624
fn same(left string, right string) bool {
16231625
return left == right
16241626
}
16251627
1628+
fn same_label(first Label, second Label) bool {
1629+
return first == second
1630+
}
1631+
16261632
fn main() {
16271633
left := 1
16281634
right := 2
@@ -1635,6 +1641,8 @@ fn main() {
16351641
println('alpha' <= 'alpha')
16361642
println('beta' >= 'beta')
16371643
println('alpha' != 'beta')
1644+
println(same_label(Label('same'), Label('same')))
1645+
println(Label('alpha') < Label('beta'))
16381646
}
16391647
",
16401648
'valid_boolean_operands.v', prefs) or { panic(err) }
@@ -1643,6 +1651,7 @@ fn main() {
16431651
assert c_source.contains('v_fastc_println_bool'), c_source
16441652
assert c_source.contains('static bool builtin__string_eq'), c_source
16451653
assert c_source.contains('builtin__string_eq(left,right)'), c_source
1654+
assert c_source.contains('builtin__string_eq(first,second)'), c_source
16461655
assert c_source.contains('builtin__string_lt("alpha","beta")'), c_source
16471656

16481657
root := os.join_path(os.vtmp_dir(), 'v3_fastc_boolean_operands_${os.getpid()}')
@@ -1659,7 +1668,7 @@ fn main() {
16591668
assert compile_result.exit_code == 0, compile_result.output
16601669
run_result := cmdexec.run(bin_file, [])
16611670
assert run_result.exit_code == 0, run_result.output
1662-
assert run_result.output.trim_space() == 'true\ntrue\ntrue\ntrue\ntrue\ntrue\ntrue\ntrue'
1671+
assert run_result.output.trim_space() == 'true\ntrue\ntrue\ntrue\ntrue\ntrue\ntrue\ntrue\ntrue\ntrue'
16631672
}
16641673

16651674
fn test_match_branch_values_must_match_the_subject_type() {
@@ -1768,6 +1777,24 @@ fn main() {
17681777
assert deferred_assignment < returned_temporary
17691778
}
17701779

1780+
fn test_control_flow_is_rejected_inside_deferred_blocks() {
1781+
prefs := pref.new_preferences()
1782+
for source, expected in {
1783+
'module main\nfn value() int { defer { return 2 } return 1 }\n': '`return` not allowed inside a `defer` block'
1784+
'module main\nfn main() { for { defer { break } break } }\n': '`break` is not allowed in defer statements'
1785+
'module main\nfn main() { for { defer { continue } break } }\n': '`continue` is not allowed in defer statements'
1786+
'module main\nfn main() { defer { goto done } done: println(1) }\n': 'goto is not allowed in defer statements'
1787+
'module main\nfn main() { defer { defer { println(1) } } }\n': '`defer` blocks cannot be nested'
1788+
} {
1789+
mut message := ''
1790+
_ := generate(source, 'invalid_defer_control_flow.v', prefs) or {
1791+
message = err.msg()
1792+
''
1793+
}
1794+
assert message.contains(expected), message
1795+
}
1796+
}
1797+
17711798
fn test_mutable_function_parameters_require_mutable_arguments() {
17721799
prefs := pref.new_preferences()
17731800
mut pointer_message := ''

0 commit comments

Comments
 (0)