From f6628b985ee1ec094d0a5149b3012069bea6374c Mon Sep 17 00:00:00 2001 From: Hojun-Cho Date: Sat, 8 Aug 2026 01:29:15 +0900 Subject: [PATCH] test: migrate 24 residual carriers into the fixture corpus Audit-driven migrate-and-retire wave (one read-only auditor per carrier batch, verdicts row-checked through the full corpus gate): every retired carrier's assertions are now owned by declarative fixtures or an existing owner. 238 new fixtures land (corpus 1,239 -> 1,477; cells 2,954), covering enum/str/slice/tagged array elements, inferred-length arrays, global slice/str zero-init and literals, global array/pointer field reads and stores, struct-literal slice fields, struct returns, float arithmetic, size/int limits, sort and log-vstream behavior, place-addressed stores, and append places. Rejection rows STRENGTHEN the old nonzero-exit checks to required diagnostic fragments; all byte-id claims fold into the blanket test-data-byteid sweep (now 1,142 compared, 0 pinned-divergent). Four carriers were fully redundant with existing fixtures/lang tests (749, 722, 765, and 771's byteid rows) and retire without new rows. Native carriers 171 -> 147 (residual 135 -> 111). --- docs/test-system-v2.md | 10 +- internal/wwfixture/types.ww | 14 +- test/wcc/682_arr_enum_elem.c | 334 ---- test/wcc/683_arr_strslice_elem.c | 433 ----- test/wcc/684_arr_infer_len.c | 408 ----- test/wcc/685_arr_tagged_elem.c | 413 ----- test/wcc/686_slice_str_global_zero.c | 247 --- test/wcc/687_slice_literal_global.c | 416 ----- test/wcc/688_global_arr_elem_field.c | 298 ---- test/wcc/689_globptr_field_read_run.c | 324 ---- test/wcc/689_globptr_field_store_run.c | 258 --- test/wcc/689_structlit_slice_field.c | 362 ---- test/wcc/698_cgreturn_struct.c | 500 ------ test/wcc/722_match_slice_variant.c | 182 -- test/wcc/725_nested_if_labels.c | 156 -- test/wcc/736_cstage_label_ssot.c | 175 -- test/wcc/749_sumtype_forward.c | 310 ---- test/wcc/765_star_fn_deref.c | 247 --- test/wcc/771_widen_transitive.c | 234 --- test/wcc/779_log_vstream_run.c | 376 ---- test/wcc/805_placeaddr_store.c | 1525 ----------------- test/wcc/806_append_place.c | 1005 ----------- test/wcc/952_floats_run.c | 438 ----- test/wcc/958_types_sizelim_run.c | 155 -- test/wcc/959_types_intlim_run.c | 154 -- test/wcc/963_sort_run.c | 199 --- test/wcc/data/r682_enum_frame_smash/case.ww | 8 + test/wcc/data/r682_enum_global_idx0/case.ww | 7 + test/wcc/data/r682_enum_global_read/case.ww | 7 + .../wcc/data/r682_enum_local_init_sum/case.ww | 7 + test/wcc/data/r682_enum_local_read/case.ww | 7 + test/wcc/data/r682_enum_local_signed/case.ww | 7 + test/wcc/data/r682_enum_width1_u8/case.ww | 7 + test/wcc/data/r682_enum_width2_i16/case.ww | 7 + test/wcc/data/r683_slice_cap_copy/case.ww | 10 + test/wcc/data/r683_slice_cap_direct0/case.ww | 9 + test/wcc/data/r683_slice_cap_direct1/case.ww | 9 + test/wcc/data/r683_slice_len0/case.ww | 9 + test/wcc/data/r683_slice_len1/case.ww | 9 + test/wcc/data/r683_slice_ptr/case.ww | 10 + test/wcc/data/r683_slice_stride3/case.ww | 10 + test/wcc/data/r683_str_cap_copy/case.ww | 9 + test/wcc/data/r683_str_cap_direct0/case.ww | 8 + test/wcc/data/r683_str_cap_direct1/case.ww | 8 + test/wcc/data/r683_str_len1/case.ww | 8 + .../data/r683_str_lit_cap_symmetry/case.ww | 5 + test/wcc/data/r683_struct_elem/case.ww | 7 + test/wcc/data/r684_local_int_elem/case.ww | 6 + test/wcc/data/r684_local_one_len/case.ww | 6 + test/wcc/data/r684_local_str_elem/case.ww | 6 + test/wcc/data/r684_local_str_len/case.ww | 6 + test/wcc/data/r684_local_u8_elem/case.ww | 6 + test/wcc/data/r684_local_u8_len/case.ww | 6 + test/wcc/data/r684_mod_int_elem/case.ww | 6 + test/wcc/data/r684_mod_one_elem/case.ww | 6 + test/wcc/data/r684_mod_one_len/case.ww | 6 + test/wcc/data/r684_mod_str_len/case.ww | 6 + .../wcc/data/r684_noinit_local_reject/case.ww | 6 + test/wcc/data/r684_noinit_mod_reject/case.ww | 4 + .../data/r684_nonarray_local_reject/case.ww | 6 + .../wcc/data/r685_tagged_bool_variant/case.ww | 10 + test/wcc/data/r685_tagged_boxed_void/case.ww | 16 + test/wcc/data/r685_tagged_lit_first/case.ww | 10 + test/wcc/data/r685_tagged_lit_second/case.ww | 10 + test/wcc/data/r685_tagged_lit_sum106/case.ww | 16 + .../data/r685_tagged_repeat_reject/case.ww | 7 + test/wcc/data/r685_tagged_stride3/case.ww | 10 + test/wcc/data/r685_tagged_var_sum/case.ww | 18 + test/wcc/data/r686_slice_glob_cap/case.ww | 4 + test/wcc/data/r686_slice_glob_len/case.ww | 4 + .../wcc/data/r686_slice_glob_ptr_null/case.ww | 7 + test/wcc/data/r686_str_glob_len/case.ww | 4 + test/wcc/data/r686_str_glob_ptr_null/case.ww | 7 + test/wcc/data/r687_alias_slice/case.ww | 5 + test/wcc/data/r687_i32_sum/case.ww | 4 + test/wcc/data/r687_i64_e1/case.ww | 4 + test/wcc/data/r687_i64_lencap/case.ww | 4 + test/wcc/data/r687_neg_def_slicelit/case.ww | 4 + .../wcc/data/r687_neg_repeat_slicelit/case.ww | 4 + test/wcc/data/r687_neg_str_slicelit/case.ww | 4 + test/wcc/data/r687_one_edge/case.ww | 4 + test/wcc/data/r687_struct_3f/case.ww | 7 + .../wcc/data/r687_struct_arrvar_local/case.ww | 8 + test/wcc/data/r687_struct_one/case.ww | 7 + test/wcc/data/r687_struct_pt/case.ww | 7 + test/wcc/data/r687_u8_cap/case.ww | 4 + test/wcc/data/r687_u8_e0/case.ww | 4 + test/wcc/data/r687_u8_e2/case.ww | 4 + test/wcc/data/r687_u8_len/case.ww | 4 + test/wcc/data/r687_u8_sum/case.ww | 6 + test/wcc/data/r688_arr_a0/case.ww | 5 + test/wcc/data/r688_arr_a1/case.ww | 5 + test/wcc/data/r688_arr_b0/case.ww | 5 + test/wcc/data/r688_arr_b1/case.ww | 5 + test/wcc/data/r688_rec_tag1/case.ww | 5 + test/wcc/data/r688_rec_x1/case.ww | 5 + test/wcc/data/r688_rec_y1/case.ww | 5 + test/wcc/data/r688_slice_x1_byteid/case.ww | 6 + test/wcc/data/r689_gpr_chain_i64_sink/case.ww | 6 + test/wcc/data/r689_gpr_chain_str_len/case.ww | 5 + .../data/r689_gpr_chain_struct_field/case.ww | 6 + test/wcc/data/r689_gpr_float_field/case.ww | 5 + test/wcc/data/r689_gpr_local_ptr_ctrl/case.ww | 4 + test/wcc/data/r689_gpr_param_ctrl/case.ww | 5 + test/wcc/data/r689_gpr_pslice_len/case.ww | 4 + .../data/r689_gpr_scalar_off0_off8/case.ww | 5 + test/wcc/data/r689_gpr_scalar_off8/case.ww | 5 + test/wcc/data/r689_gpr_str_field/case.ww | 5 + test/wcc/data/r689_gpr_tagged_field/case.ww | 5 + .../data/r689_gpr_tagged_slice_field/case.ww | 5 + .../r689_gpr_tagged_slice_field_local/case.ww | 4 + test/wcc/data/r689_gps_chained/case.ww | 6 + test/wcc/data/r689_gps_compound_off0/case.ww | 5 + test/wcc/data/r689_gps_compound_off8/case.ww | 5 + test/wcc/data/r689_gps_indexed/case.ww | 6 + test/wcc/data/r689_gps_local_ptr_ctrl/case.ww | 4 + .../wcc/data/r689_gps_param_off0_ctrl/case.ww | 5 + test/wcc/data/r689_gps_str_field/case.ww | 5 + test/wcc/data/r689_gps_struct_field/case.ww | 6 + test/wcc/data/r689_slf_off_cap/case.ww | 9 + test/wcc/data/r689_slf_off_head/case.ww | 9 + test/wcc/data/r689_slf_off_len/case.ww | 9 + test/wcc/data/r689_slf_slice_cap/case.ww | 9 + test/wcc/data/r689_slf_slice_len/case.ww | 9 + test/wcc/data/r689_slf_slice_n/case.ww | 9 + test/wcc/data/r689_slf_slice_ptr/case.ww | 9 + test/wcc/data/r689_slf_str_name_len/case.ww | 9 + test/wcc/data/r689_slf_str_s_len/case.ww | 9 + test/wcc/data/r689_slf_two_b_cap/case.ww | 10 + test/wcc/data/r689_slf_two_b_len/case.ww | 10 + .../case.ww | 9 + .../r698_bare_let_struct_maxalign4/case.ww | 7 + test/wcc/data/r698_decoder_ident_sret/case.ww | 14 + .../data/r698_dot_recv_call_global/case.ww | 7 + .../wcc/data/r698_dot_recv_call_local/case.ww | 10 + .../data/r698_dot_recv_call_viaptr/case.ww | 11 + .../data/r698_dot_structlit_ellipsis/case.ww | 10 + test/wcc/data/r698_five_i64_lit_sret/case.ww | 7 + .../case.ww | 8 + .../case.ww | 5 + .../wcc/data/r698_one_i64_lit_discard/case.ww | 5 + test/wcc/data/r698_pair_i64_i32_recv/case.ww | 5 + .../data/r698_pair_i64_lit_discard/case.ww | 5 + test/wcc/data/r698_quad_i64_lit_sret/case.ww | 5 + test/wcc/data/r698_recv_i32_arr6_u8/case.ww | 5 + .../case.ww | 9 + .../data/r698_trip_i32_ident_return/case.ww | 8 + .../data/r698_trip_i64_ident_discard/case.ww | 8 + .../data/r698_trip_i64_lit_discard/case.ww | 5 + .../data/r725_retscr_nested_if_labels/case.ww | 17 + .../data/r736_tagscr_two_ptr_stores/case.ww | 10 + .../r736_tagscr_two_sizes_compile/case.ww | 11 + test/wcc/data/r771_spread_alt_widen/case.ww | 11 + test/wcc/data/r779_branched_lprintln/case.ww | 27 + .../data/r779_lprintln_custom_sink/case.ww | 19 + .../data/r779_printfln_default_stderr/case.ww | 8 + .../data/r779_println_default_stderr/case.ww | 8 + .../data/r805_agg_array_field_movl/case.ww | 18 + .../wcc/data/r805_agg_array_field_odd/case.ww | 18 + .../data/r805_agg_fresh_two_stores/case.ww | 22 + .../data/r805_agg_from_ident_deref/case.ww | 28 + test/wcc/data/r805_agg_nested_lit/case.ww | 20 + test/wcc/data/r805_agg_structlit_40b/case.ww | 28 + test/wcc/data/r805_amp_spine/case.ww | 18 + .../wcc/data/r805_arr_field_idx_store/case.ww | 13 + test/wcc/data/r805_array_base_deref/case.ww | 16 + .../wcc/data/r805_c3_alias_arr_viaptr/case.ww | 28 + .../data/r805_c3_alias_slice_reads/case.ww | 34 + test/wcc/data/r805_c3_composed_match/case.ww | 50 + test/wcc/data/r805_c3_free_operand/case.ww | 23 + test/wcc/data/r805_c3_letbound_alias/case.ww | 18 + test/wcc/data/r805_c4_let_deref_leaf/case.ww | 18 + test/wcc/data/r805_c4_let_elem_sizes/case.ww | 27 + test/wcc/data/r805_c4_let_slice_elem/case.ww | 11 + test/wcc/data/r805_c4_range_byvalue/case.ww | 34 + test/wcc/data/r805_c4_range_edges/case.ww | 22 + test/wcc/data/r805_compound_bits_shr/case.ww | 20 + test/wcc/data/r805_compound_narrow/case.ww | 26 + test/wcc/data/r805_compound_ops/case.ww | 31 + .../wcc/data/r805_neutral_ident_bases/case.ww | 18 + test/wcc/data/r805_neutral_reads/case.ww | 13 + test/wcc/data/r805_read_depth2_deref/case.ww | 19 + test/wcc/data/r805_read_depth2_idx/case.ww | 17 + test/wcc/data/r805_read_slicefield/case.ww | 21 + test/wcc/data/r805_read_widths_spine/case.ww | 19 + .../data/r805_reject_addrof_callbase/case.ww | 12 + .../wcc/data/r805_reject_agg_call_reg/case.ww | 11 + .../data/r805_reject_agg_call_sret/case.ww | 13 + .../wcc/data/r805_reject_agg_compound/case.ww | 13 + .../data/r805_reject_assign_callbase/case.ww | 12 + test/wcc/data/r805_reject_float/case.ww | 9 + .../data/r805_reject_let_unhandled/case.ww | 10 + .../data/r805_reject_read_callbase/case.ww | 12 + test/wcc/data/r805_reject_read_tagged/case.ww | 12 + .../wcc/data/r805_reject_str_compound/case.ww | 9 + test/wcc/data/r805_reject_tagged/case.ww | 10 + test/wcc/data/r805_runtime_call_idx/case.ww | 17 + test/wcc/data/r805_slice_field_member/case.ww | 20 + .../wcc/data/r805_store_bool_compound/case.ww | 23 + .../wcc/data/r805_store_size_neighbor/case.ww | 11 + test/wcc/data/r805_str_field_member/case.ww | 15 + test/wcc/data/r805_widths_signed/case.ww | 17 + test/wcc/data/r805_widths_unsigned/case.ww | 18 + test/wcc/data/r806ap_deref_spine/case.ww | 19 + test/wcc/data/r806ap_deref_src/case.ww | 13 + test/wcc/data/r806ap_derefspine_field/case.ww | 17 + test/wcc/data/r806ap_elem_kinds_place/case.ww | 31 + test/wcc/data/r806ap_identroot_dot/case.ww | 14 + .../wcc/data/r806ap_idx_computed_elem/case.ww | 17 + test/wcc/data/r806ap_idxfield_struct/case.ww | 24 + test/wcc/data/r806ap_neutral_direct/case.ww | 18 + test/wcc/data/r806ap_realloc_loop/case.ww | 29 + test/wcc/data/r806ap_reentrant_value/case.ww | 25 + test/wcc/data/r806ap_reject_call_src/case.ww | 9 + .../r806ap_reject_spread_array_src/case.ww | 8 + .../r806ap_reject_spread_call_src/case.ww | 8 + test/wcc/data/r806ap_scalar_param/case.ww | 14 + test/wcc/data/r806ap_scalar_u8_multi/case.ww | 10 + .../data/r806ap_self_append_realloc/case.ww | 20 + .../data/r806ap_selfidx_oldlen_once/case.ww | 20 + test/wcc/data/r806ap_slice_elem/case.ww | 13 + test/wcc/data/r806ap_spread_dup_copy/case.ww | 31 + .../data/r806ap_spread_growth_place/case.ww | 16 + .../data/r806ap_spread_narrow_signed/case.ww | 13 + test/wcc/data/r806ap_spread_param/case.ww | 13 + .../data/r806ap_spread_place_deref/case.ww | 18 + .../data/r806ap_spread_place_kinds/case.ww | 25 + .../r806ap_spread_selfalias_chain/case.ww | 14 + test/wcc/data/r806ap_spread_wide/case.ww | 16 + test/wcc/data/r806ap_str_elem/case.ww | 14 + test/wcc/data/r806ap_struct_ident/case.ww | 15 + test/wcc/data/r806ap_struct_lit/case.ww | 15 + test/wcc/data/r806ap_tagged_elem/case.ww | 12 + test/wcc/data/r952_absf64_copysignf64/case.ww | 14 + test/wcc/data/r952_absf64_value/case.ww | 6 + test/wcc/data/r952_f32_width_consts/case.ww | 11 + test/wcc/data/r952_f32bits_roundtrip/case.ww | 16 + test/wcc/data/r952_f32frombits_value/case.ww | 6 + test/wcc/data/r952_f64bits_roundtrip/case.ww | 11 + test/wcc/data/r952_f64frombits_value/case.ww | 6 + test/wcc/data/r952_floatinfo_f32shape/case.ww | 16 + test/wcc/data/r952_floatinfo_f64shape/case.ww | 19 + .../wcc/data/r952_floatinfo_instances/case.ww | 21 + test/wcc/data/r952_frexpf64_exact/case.ww | 22 + test/wcc/data/r952_frexpf64_range/case.ww | 12 + test/wcc/data/r952_frexpf64_value/case.ww | 7 + test/wcc/data/r952_isnan_isinf/case.ww | 16 + test/wcc/data/r952_issubnormalf64/case.ww | 11 + test/wcc/data/r952_nan_inf_bits/case.ww | 15 + .../wcc/data/r952_normalizef64_normal/case.ww | 10 + .../data/r952_normalizef64_subnormal/case.ww | 12 + test/wcc/data/r952_normalizef64_value/case.ww | 8 + test/wcc/data/r952_signf64_preds/case.ww | 13 + test/wcc/data/r958_size_limits/case.ww | 11 + test/wcc/data/r958_size_max_arith/case.ww | 8 + test/wcc/data/r958_uintptr_limits/case.ww | 11 + test/wcc/data/r958_uintptr_max_arith/case.ww | 8 + test/wcc/data/r959_int_limits/case.ww | 12 + test/wcc/data/r959_int_max_arith/case.ww | 8 + test/wcc/data/r959_uint_limits/case.ww | 12 + test/wcc/data/r959_uint_max_arith/case.ww | 8 + test/wcc/data/r963_sort_lbisect/case.ww | 30 + test/wcc/data/r963_sort_rbisect/case.ww | 30 + test/wcc/data/r963_sort_search/case.ww | 28 + 264 files changed, 2768 insertions(+), 9161 deletions(-) delete mode 100644 test/wcc/682_arr_enum_elem.c delete mode 100644 test/wcc/683_arr_strslice_elem.c delete mode 100644 test/wcc/684_arr_infer_len.c delete mode 100644 test/wcc/685_arr_tagged_elem.c delete mode 100644 test/wcc/686_slice_str_global_zero.c delete mode 100644 test/wcc/687_slice_literal_global.c delete mode 100644 test/wcc/688_global_arr_elem_field.c delete mode 100644 test/wcc/689_globptr_field_read_run.c delete mode 100644 test/wcc/689_globptr_field_store_run.c delete mode 100644 test/wcc/689_structlit_slice_field.c delete mode 100644 test/wcc/698_cgreturn_struct.c delete mode 100644 test/wcc/722_match_slice_variant.c delete mode 100644 test/wcc/725_nested_if_labels.c delete mode 100644 test/wcc/736_cstage_label_ssot.c delete mode 100644 test/wcc/749_sumtype_forward.c delete mode 100644 test/wcc/765_star_fn_deref.c delete mode 100644 test/wcc/771_widen_transitive.c delete mode 100644 test/wcc/779_log_vstream_run.c delete mode 100644 test/wcc/805_placeaddr_store.c delete mode 100644 test/wcc/806_append_place.c delete mode 100644 test/wcc/952_floats_run.c delete mode 100644 test/wcc/958_types_sizelim_run.c delete mode 100644 test/wcc/959_types_intlim_run.c delete mode 100644 test/wcc/963_sort_run.c create mode 100644 test/wcc/data/r682_enum_frame_smash/case.ww create mode 100644 test/wcc/data/r682_enum_global_idx0/case.ww create mode 100644 test/wcc/data/r682_enum_global_read/case.ww create mode 100644 test/wcc/data/r682_enum_local_init_sum/case.ww create mode 100644 test/wcc/data/r682_enum_local_read/case.ww create mode 100644 test/wcc/data/r682_enum_local_signed/case.ww create mode 100644 test/wcc/data/r682_enum_width1_u8/case.ww create mode 100644 test/wcc/data/r682_enum_width2_i16/case.ww create mode 100644 test/wcc/data/r683_slice_cap_copy/case.ww create mode 100644 test/wcc/data/r683_slice_cap_direct0/case.ww create mode 100644 test/wcc/data/r683_slice_cap_direct1/case.ww create mode 100644 test/wcc/data/r683_slice_len0/case.ww create mode 100644 test/wcc/data/r683_slice_len1/case.ww create mode 100644 test/wcc/data/r683_slice_ptr/case.ww create mode 100644 test/wcc/data/r683_slice_stride3/case.ww create mode 100644 test/wcc/data/r683_str_cap_copy/case.ww create mode 100644 test/wcc/data/r683_str_cap_direct0/case.ww create mode 100644 test/wcc/data/r683_str_cap_direct1/case.ww create mode 100644 test/wcc/data/r683_str_len1/case.ww create mode 100644 test/wcc/data/r683_str_lit_cap_symmetry/case.ww create mode 100644 test/wcc/data/r683_struct_elem/case.ww create mode 100644 test/wcc/data/r684_local_int_elem/case.ww create mode 100644 test/wcc/data/r684_local_one_len/case.ww create mode 100644 test/wcc/data/r684_local_str_elem/case.ww create mode 100644 test/wcc/data/r684_local_str_len/case.ww create mode 100644 test/wcc/data/r684_local_u8_elem/case.ww create mode 100644 test/wcc/data/r684_local_u8_len/case.ww create mode 100644 test/wcc/data/r684_mod_int_elem/case.ww create mode 100644 test/wcc/data/r684_mod_one_elem/case.ww create mode 100644 test/wcc/data/r684_mod_one_len/case.ww create mode 100644 test/wcc/data/r684_mod_str_len/case.ww create mode 100644 test/wcc/data/r684_noinit_local_reject/case.ww create mode 100644 test/wcc/data/r684_noinit_mod_reject/case.ww create mode 100644 test/wcc/data/r684_nonarray_local_reject/case.ww create mode 100644 test/wcc/data/r685_tagged_bool_variant/case.ww create mode 100644 test/wcc/data/r685_tagged_boxed_void/case.ww create mode 100644 test/wcc/data/r685_tagged_lit_first/case.ww create mode 100644 test/wcc/data/r685_tagged_lit_second/case.ww create mode 100644 test/wcc/data/r685_tagged_lit_sum106/case.ww create mode 100644 test/wcc/data/r685_tagged_repeat_reject/case.ww create mode 100644 test/wcc/data/r685_tagged_stride3/case.ww create mode 100644 test/wcc/data/r685_tagged_var_sum/case.ww create mode 100644 test/wcc/data/r686_slice_glob_cap/case.ww create mode 100644 test/wcc/data/r686_slice_glob_len/case.ww create mode 100644 test/wcc/data/r686_slice_glob_ptr_null/case.ww create mode 100644 test/wcc/data/r686_str_glob_len/case.ww create mode 100644 test/wcc/data/r686_str_glob_ptr_null/case.ww create mode 100644 test/wcc/data/r687_alias_slice/case.ww create mode 100644 test/wcc/data/r687_i32_sum/case.ww create mode 100644 test/wcc/data/r687_i64_e1/case.ww create mode 100644 test/wcc/data/r687_i64_lencap/case.ww create mode 100644 test/wcc/data/r687_neg_def_slicelit/case.ww create mode 100644 test/wcc/data/r687_neg_repeat_slicelit/case.ww create mode 100644 test/wcc/data/r687_neg_str_slicelit/case.ww create mode 100644 test/wcc/data/r687_one_edge/case.ww create mode 100644 test/wcc/data/r687_struct_3f/case.ww create mode 100644 test/wcc/data/r687_struct_arrvar_local/case.ww create mode 100644 test/wcc/data/r687_struct_one/case.ww create mode 100644 test/wcc/data/r687_struct_pt/case.ww create mode 100644 test/wcc/data/r687_u8_cap/case.ww create mode 100644 test/wcc/data/r687_u8_e0/case.ww create mode 100644 test/wcc/data/r687_u8_e2/case.ww create mode 100644 test/wcc/data/r687_u8_len/case.ww create mode 100644 test/wcc/data/r687_u8_sum/case.ww create mode 100644 test/wcc/data/r688_arr_a0/case.ww create mode 100644 test/wcc/data/r688_arr_a1/case.ww create mode 100644 test/wcc/data/r688_arr_b0/case.ww create mode 100644 test/wcc/data/r688_arr_b1/case.ww create mode 100644 test/wcc/data/r688_rec_tag1/case.ww create mode 100644 test/wcc/data/r688_rec_x1/case.ww create mode 100644 test/wcc/data/r688_rec_y1/case.ww create mode 100644 test/wcc/data/r688_slice_x1_byteid/case.ww create mode 100644 test/wcc/data/r689_gpr_chain_i64_sink/case.ww create mode 100644 test/wcc/data/r689_gpr_chain_str_len/case.ww create mode 100644 test/wcc/data/r689_gpr_chain_struct_field/case.ww create mode 100644 test/wcc/data/r689_gpr_float_field/case.ww create mode 100644 test/wcc/data/r689_gpr_local_ptr_ctrl/case.ww create mode 100644 test/wcc/data/r689_gpr_param_ctrl/case.ww create mode 100644 test/wcc/data/r689_gpr_pslice_len/case.ww create mode 100644 test/wcc/data/r689_gpr_scalar_off0_off8/case.ww create mode 100644 test/wcc/data/r689_gpr_scalar_off8/case.ww create mode 100644 test/wcc/data/r689_gpr_str_field/case.ww create mode 100644 test/wcc/data/r689_gpr_tagged_field/case.ww create mode 100644 test/wcc/data/r689_gpr_tagged_slice_field/case.ww create mode 100644 test/wcc/data/r689_gpr_tagged_slice_field_local/case.ww create mode 100644 test/wcc/data/r689_gps_chained/case.ww create mode 100644 test/wcc/data/r689_gps_compound_off0/case.ww create mode 100644 test/wcc/data/r689_gps_compound_off8/case.ww create mode 100644 test/wcc/data/r689_gps_indexed/case.ww create mode 100644 test/wcc/data/r689_gps_local_ptr_ctrl/case.ww create mode 100644 test/wcc/data/r689_gps_param_off0_ctrl/case.ww create mode 100644 test/wcc/data/r689_gps_str_field/case.ww create mode 100644 test/wcc/data/r689_gps_struct_field/case.ww create mode 100644 test/wcc/data/r689_slf_off_cap/case.ww create mode 100644 test/wcc/data/r689_slf_off_head/case.ww create mode 100644 test/wcc/data/r689_slf_off_len/case.ww create mode 100644 test/wcc/data/r689_slf_slice_cap/case.ww create mode 100644 test/wcc/data/r689_slf_slice_len/case.ww create mode 100644 test/wcc/data/r689_slf_slice_n/case.ww create mode 100644 test/wcc/data/r689_slf_slice_ptr/case.ww create mode 100644 test/wcc/data/r689_slf_str_name_len/case.ww create mode 100644 test/wcc/data/r689_slf_str_s_len/case.ww create mode 100644 test/wcc/data/r689_slf_two_b_cap/case.ww create mode 100644 test/wcc/data/r689_slf_two_b_len/case.ww create mode 100644 test/wcc/data/r698_assign_ident_call_recv_pair_i64_i32/case.ww create mode 100644 test/wcc/data/r698_bare_let_struct_maxalign4/case.ww create mode 100644 test/wcc/data/r698_decoder_ident_sret/case.ww create mode 100644 test/wcc/data/r698_dot_recv_call_global/case.ww create mode 100644 test/wcc/data/r698_dot_recv_call_local/case.ww create mode 100644 test/wcc/data/r698_dot_recv_call_viaptr/case.ww create mode 100644 test/wcc/data/r698_dot_structlit_ellipsis/case.ww create mode 100644 test/wcc/data/r698_five_i64_lit_sret/case.ww create mode 100644 test/wcc/data/r698_let_ident_memcpy_pair_i64_i32/case.ww create mode 100644 test/wcc/data/r698_mix_i32_i32_i64_i64_lit_discard/case.ww create mode 100644 test/wcc/data/r698_one_i64_lit_discard/case.ww create mode 100644 test/wcc/data/r698_pair_i64_i32_recv/case.ww create mode 100644 test/wcc/data/r698_pair_i64_lit_discard/case.ww create mode 100644 test/wcc/data/r698_quad_i64_lit_sret/case.ww create mode 100644 test/wcc/data/r698_recv_i32_arr6_u8/case.ww create mode 100644 test/wcc/data/r698_structlit_nested_call_recv_pair_i64_i32/case.ww create mode 100644 test/wcc/data/r698_trip_i32_ident_return/case.ww create mode 100644 test/wcc/data/r698_trip_i64_ident_discard/case.ww create mode 100644 test/wcc/data/r698_trip_i64_lit_discard/case.ww create mode 100644 test/wcc/data/r725_retscr_nested_if_labels/case.ww create mode 100644 test/wcc/data/r736_tagscr_two_ptr_stores/case.ww create mode 100644 test/wcc/data/r736_tagscr_two_sizes_compile/case.ww create mode 100644 test/wcc/data/r771_spread_alt_widen/case.ww create mode 100644 test/wcc/data/r779_branched_lprintln/case.ww create mode 100644 test/wcc/data/r779_lprintln_custom_sink/case.ww create mode 100644 test/wcc/data/r779_printfln_default_stderr/case.ww create mode 100644 test/wcc/data/r779_println_default_stderr/case.ww create mode 100644 test/wcc/data/r805_agg_array_field_movl/case.ww create mode 100644 test/wcc/data/r805_agg_array_field_odd/case.ww create mode 100644 test/wcc/data/r805_agg_fresh_two_stores/case.ww create mode 100644 test/wcc/data/r805_agg_from_ident_deref/case.ww create mode 100644 test/wcc/data/r805_agg_nested_lit/case.ww create mode 100644 test/wcc/data/r805_agg_structlit_40b/case.ww create mode 100644 test/wcc/data/r805_amp_spine/case.ww create mode 100644 test/wcc/data/r805_arr_field_idx_store/case.ww create mode 100644 test/wcc/data/r805_array_base_deref/case.ww create mode 100644 test/wcc/data/r805_c3_alias_arr_viaptr/case.ww create mode 100644 test/wcc/data/r805_c3_alias_slice_reads/case.ww create mode 100644 test/wcc/data/r805_c3_composed_match/case.ww create mode 100644 test/wcc/data/r805_c3_free_operand/case.ww create mode 100644 test/wcc/data/r805_c3_letbound_alias/case.ww create mode 100644 test/wcc/data/r805_c4_let_deref_leaf/case.ww create mode 100644 test/wcc/data/r805_c4_let_elem_sizes/case.ww create mode 100644 test/wcc/data/r805_c4_let_slice_elem/case.ww create mode 100644 test/wcc/data/r805_c4_range_byvalue/case.ww create mode 100644 test/wcc/data/r805_c4_range_edges/case.ww create mode 100644 test/wcc/data/r805_compound_bits_shr/case.ww create mode 100644 test/wcc/data/r805_compound_narrow/case.ww create mode 100644 test/wcc/data/r805_compound_ops/case.ww create mode 100644 test/wcc/data/r805_neutral_ident_bases/case.ww create mode 100644 test/wcc/data/r805_neutral_reads/case.ww create mode 100644 test/wcc/data/r805_read_depth2_deref/case.ww create mode 100644 test/wcc/data/r805_read_depth2_idx/case.ww create mode 100644 test/wcc/data/r805_read_slicefield/case.ww create mode 100644 test/wcc/data/r805_read_widths_spine/case.ww create mode 100644 test/wcc/data/r805_reject_addrof_callbase/case.ww create mode 100644 test/wcc/data/r805_reject_agg_call_reg/case.ww create mode 100644 test/wcc/data/r805_reject_agg_call_sret/case.ww create mode 100644 test/wcc/data/r805_reject_agg_compound/case.ww create mode 100644 test/wcc/data/r805_reject_assign_callbase/case.ww create mode 100644 test/wcc/data/r805_reject_float/case.ww create mode 100644 test/wcc/data/r805_reject_let_unhandled/case.ww create mode 100644 test/wcc/data/r805_reject_read_callbase/case.ww create mode 100644 test/wcc/data/r805_reject_read_tagged/case.ww create mode 100644 test/wcc/data/r805_reject_str_compound/case.ww create mode 100644 test/wcc/data/r805_reject_tagged/case.ww create mode 100644 test/wcc/data/r805_runtime_call_idx/case.ww create mode 100644 test/wcc/data/r805_slice_field_member/case.ww create mode 100644 test/wcc/data/r805_store_bool_compound/case.ww create mode 100644 test/wcc/data/r805_store_size_neighbor/case.ww create mode 100644 test/wcc/data/r805_str_field_member/case.ww create mode 100644 test/wcc/data/r805_widths_signed/case.ww create mode 100644 test/wcc/data/r805_widths_unsigned/case.ww create mode 100644 test/wcc/data/r806ap_deref_spine/case.ww create mode 100644 test/wcc/data/r806ap_deref_src/case.ww create mode 100644 test/wcc/data/r806ap_derefspine_field/case.ww create mode 100644 test/wcc/data/r806ap_elem_kinds_place/case.ww create mode 100644 test/wcc/data/r806ap_identroot_dot/case.ww create mode 100644 test/wcc/data/r806ap_idx_computed_elem/case.ww create mode 100644 test/wcc/data/r806ap_idxfield_struct/case.ww create mode 100644 test/wcc/data/r806ap_neutral_direct/case.ww create mode 100644 test/wcc/data/r806ap_realloc_loop/case.ww create mode 100644 test/wcc/data/r806ap_reentrant_value/case.ww create mode 100644 test/wcc/data/r806ap_reject_call_src/case.ww create mode 100644 test/wcc/data/r806ap_reject_spread_array_src/case.ww create mode 100644 test/wcc/data/r806ap_reject_spread_call_src/case.ww create mode 100644 test/wcc/data/r806ap_scalar_param/case.ww create mode 100644 test/wcc/data/r806ap_scalar_u8_multi/case.ww create mode 100644 test/wcc/data/r806ap_self_append_realloc/case.ww create mode 100644 test/wcc/data/r806ap_selfidx_oldlen_once/case.ww create mode 100644 test/wcc/data/r806ap_slice_elem/case.ww create mode 100644 test/wcc/data/r806ap_spread_dup_copy/case.ww create mode 100644 test/wcc/data/r806ap_spread_growth_place/case.ww create mode 100644 test/wcc/data/r806ap_spread_narrow_signed/case.ww create mode 100644 test/wcc/data/r806ap_spread_param/case.ww create mode 100644 test/wcc/data/r806ap_spread_place_deref/case.ww create mode 100644 test/wcc/data/r806ap_spread_place_kinds/case.ww create mode 100644 test/wcc/data/r806ap_spread_selfalias_chain/case.ww create mode 100644 test/wcc/data/r806ap_spread_wide/case.ww create mode 100644 test/wcc/data/r806ap_str_elem/case.ww create mode 100644 test/wcc/data/r806ap_struct_ident/case.ww create mode 100644 test/wcc/data/r806ap_struct_lit/case.ww create mode 100644 test/wcc/data/r806ap_tagged_elem/case.ww create mode 100644 test/wcc/data/r952_absf64_copysignf64/case.ww create mode 100644 test/wcc/data/r952_absf64_value/case.ww create mode 100644 test/wcc/data/r952_f32_width_consts/case.ww create mode 100644 test/wcc/data/r952_f32bits_roundtrip/case.ww create mode 100644 test/wcc/data/r952_f32frombits_value/case.ww create mode 100644 test/wcc/data/r952_f64bits_roundtrip/case.ww create mode 100644 test/wcc/data/r952_f64frombits_value/case.ww create mode 100644 test/wcc/data/r952_floatinfo_f32shape/case.ww create mode 100644 test/wcc/data/r952_floatinfo_f64shape/case.ww create mode 100644 test/wcc/data/r952_floatinfo_instances/case.ww create mode 100644 test/wcc/data/r952_frexpf64_exact/case.ww create mode 100644 test/wcc/data/r952_frexpf64_range/case.ww create mode 100644 test/wcc/data/r952_frexpf64_value/case.ww create mode 100644 test/wcc/data/r952_isnan_isinf/case.ww create mode 100644 test/wcc/data/r952_issubnormalf64/case.ww create mode 100644 test/wcc/data/r952_nan_inf_bits/case.ww create mode 100644 test/wcc/data/r952_normalizef64_normal/case.ww create mode 100644 test/wcc/data/r952_normalizef64_subnormal/case.ww create mode 100644 test/wcc/data/r952_normalizef64_value/case.ww create mode 100644 test/wcc/data/r952_signf64_preds/case.ww create mode 100644 test/wcc/data/r958_size_limits/case.ww create mode 100644 test/wcc/data/r958_size_max_arith/case.ww create mode 100644 test/wcc/data/r958_uintptr_limits/case.ww create mode 100644 test/wcc/data/r958_uintptr_max_arith/case.ww create mode 100644 test/wcc/data/r959_int_limits/case.ww create mode 100644 test/wcc/data/r959_int_max_arith/case.ww create mode 100644 test/wcc/data/r959_uint_limits/case.ww create mode 100644 test/wcc/data/r959_uint_max_arith/case.ww create mode 100644 test/wcc/data/r963_sort_lbisect/case.ww create mode 100644 test/wcc/data/r963_sort_rbisect/case.ww create mode 100644 test/wcc/data/r963_sort_search/case.ww diff --git a/docs/test-system-v2.md b/docs/test-system-v2.md index 2f79e721..b49b27f0 100644 --- a/docs/test-system-v2.md +++ b/docs/test-system-v2.md @@ -32,13 +32,13 @@ categories out of the ordinary developer target. | Fixed point and self-host | `test-bootstrap` | | Host linker/platform behavior | `test-platform` | -The live declarative compiler corpus has 1,229 fixtures and 2,458 C/WW cells: -314 expected rejections (290 shared and 24 stage-specific), 12 compile-only -successes, 137 exit-zero programs, and 766 explicit-exit programs. +The live declarative compiler corpus has 1,477 fixtures and 2,954 C/WW cells: +335 expected rejections (311 shared and 24 stage-specific), 17 compile-only +successes, 191 exit-zero programs, and 934 explicit-exit programs. -171 native C carriers remain. They are partitioned exactly once as five +147 native C carriers remain. They are partitioned exactly once as five in-process units, 24 byte/artifact gates, six bootstrap gates, one platform -gate, and 135 residual compiler, package-layout, ABI, diagnostic-observer, +gate, and 111 residual compiler, package-layout, ABI, diagnostic-observer, driver, linker, or FFI gates. Rows migrated to fixtures or native `@test` owners were removed from those carriers; there is no compatibility execution path for retired rows. 61 former byte/artifact carriers whose only assertion diff --git a/internal/wwfixture/types.ww b/internal/wwfixture/types.ww index 70252814..7906f5c6 100644 --- a/internal/wwfixture/types.ww +++ b/internal/wwfixture/types.ww @@ -1,13 +1,13 @@ package wwfixture; def protocolversion: i32 = 1; -def corpuscount: i32 = 1239; -def errorcount: i32 = 314; -def compilecount: i32 = 12; -def runcount: i32 = 146; -def runexitcount: i32 = 767; -def nativecount: i32 = 2478; -def corpushash: str = "369aca2f1c0081faf7297d8fa976a7374d97a07b76d2df079f7eea60660bda2a"; +def corpuscount: i32 = 1477; +def errorcount: i32 = 335; +def compilecount: i32 = 17; +def runcount: i32 = 191; +def runexitcount: i32 = 934; +def nativecount: i32 = 2954; +def corpushash: str = "64258f4de9ac7d71c4ad6221dd2ae7338a38cd5c620fc4ce22c1105021559e83"; type directive = enum i32 { ERROR = 0, diff --git a/test/wcc/682_arr_enum_elem.c b/test/wcc/682_arr_enum_elem.c deleted file mode 100644 index 70f7192e..00000000 --- a/test/wcc/682_arr_enum_elem.c +++ /dev/null @@ -1,334 +0,0 @@ -/* - * 682_arr_enum_elem — cstage and wwstage agree, byte-for-byte and at - * runtime, on `[N]enum` element access (task #8). - * - * The bug: wwstage's elemsizeofc (selfhost/cmd/wcc/cgenutil.ww) was the - * odd-one-out among the elem*c helpers — its siblings elemissignedc / - * elemisfloatc read the checker-stamped tinfo (t.type_.sub), but - * elemsizeofc derived the element width purely structurally - * (elemsizeof -> primsize -> slotsize). A named-narrow element - * (`[N]tk`, tk = enum i32) is not a builtin prim, so primsize returned - * 0 and elemsizeofc fell through to a raw 8-byte slot instead of the - * enum's i32 backing (4). That mis-sized BOTH manifestations through - * the one choke-point: - * (a) cgindex READ — `a[i]` strode by 8 (MOVQ) where cstage strode by - * 4 (MOVSXD), reading the wrong/out-of-bounds element for i>=1. - * (b) array-init STORE — a local `[N]enum` literal init stored at - * stride 8 into a stride-4 frame slot, overrunning the slot and - * smashing the frame -> wwstage-built binary SEGFAULTED. - * cstage is runtime-correct (cgen.c N_INDEX idx_eff(bt)->sub->size, - * N_LET array-init lu->sub->size, cgen.c:6387). The fix aligns wwstage - * UP: elemsizeofc now reads the element size off the stamped tinfo - * (peeling TY_NAMED), recovering 4 for `enum i32` and bringing all four - * elem*c helpers onto the same tinfo SSoT. - * - * No in-tree `[N]enum` / aliased-narrow element existed before kwtab, - * which is why this was byte-id-gate-blind until now. - * - * row | shape | want - * -----------------+------------------------------------+-------------- - * global_idx0 | global [4]tk, return g[0]. idx0 is | 7 + byte-id - * | stride-independent (offset 0). | - * global_read | global [4]tk, return g[2]. Pre-fix | 99 + byte-id - * | stride-8 read offset 16 = past the | - * | 16-byte array -> garbage. | - * local_read | LOCAL [4]tk init, return a[1]. | 21 + byte-id - * | Exercises the array-init STORE + | - * | the stride-4 READ together. | - * local_init_sum | LOCAL [4]tk, return a[0]+a[3]. | 10 + byte-id - * | First+last element after init. | - * local_signed | LOCAL [2]tk with a negative enum | 251 (-5) - * | value, return a[0]:i32. Pins the | + byte-id - * | MOVSXD sign-extend at stride 4 | - * | (pre-fix MOVQ read 8 bytes). | - * frame_smash | LOCAL [6]tk init + read a[5]. | 5 + byte-id - * | Pre-fix stride-8 store writes 48 | - * | bytes into a 24-byte slot -> | - * | frame smash / SEGFAULT under | - * | wwstage. Correct stride-4 store | - * | (24 bytes) round-trips a[5]=5. | - * width1_u8 | LOCAL [3]tu (enum u8), read a[1]. | 200 + byte-id - * | Pins the narrow-scalar class at | - * | width 1: stride-1 store + MOVZBQ | - * | zero-extend load (UNSIGNED enum). | - * | Pre-fix stride-8 store/read over- | - * | runs the 3-byte slot -> garbage. | - * width2_i16 | LOCAL [3]ts (enum i16) w/ negative | 251 (-5) - * | value, read a[1]:i32. Pins width 2:| + byte-id - * | stride-2 store + MOVSWQ sign- | - * | extend (pre-fix stride-8 garbage). | - * - * width1/width2 widen the coverage from the single enum-i32 (width 4) - * case to the whole {1,2,4} narrow-scalar class the fix closes, and add - * the unsigned (MOVZBQ) load path alongside the signed (MOVSXD/MOVSWQ). - * - * Exit-code rows confirm both stages run correctly. The asm-byte-id - * rows pin the symmetric stride-4 MOVSXD emit (cstage == wwstage); - * pre-fix wwstage emitted stride-8 MOVQ, so the diff was non-empty. - */ -#include -#include -#include -#include -#include -#include -#include "wwtestpkg.h" - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want; }; - -static const struct row rows[] = { - { "global_idx0", - "type tk = enum i32 { A = 7i32, B = 21i32, C = 99i32, D = 3i32 };\n" - "let g: [4]tk = [tk.A, tk.B, tk.C, tk.D];\n" - "fn main() i32 = {\n" - "\treturn g[0]: i32;\n" - "};\n", - 7 }, - - { "global_read", - "type tk = enum i32 { A = 7i32, B = 21i32, C = 99i32, D = 3i32 };\n" - "let g: [4]tk = [tk.A, tk.B, tk.C, tk.D];\n" - "fn main() i32 = {\n" - "\treturn g[2]: i32;\n" - "};\n", - 99 }, - - { "local_read", - "type tk = enum i32 { A = 7i32, B = 21i32, C = 99i32, D = 3i32 };\n" - "fn main() i32 = {\n" - "\tlet a: [4]tk = [tk.A, tk.B, tk.C, tk.D];\n" - "\treturn a[1]: i32;\n" - "};\n", - 21 }, - - { "local_init_sum", - "type tk = enum i32 { A = 7i32, B = 21i32, C = 99i32, D = 3i32 };\n" - "fn main() i32 = {\n" - "\tlet a: [4]tk = [tk.A, tk.B, tk.C, tk.D];\n" - "\treturn (a[0]: i32) + (a[3]: i32);\n" - "};\n", - 10 }, - - { "local_signed", - "type tk = enum i32 { A = 7i32, G = -5i32 };\n" - "fn main() i32 = {\n" - "\tlet a: [2]tk = [tk.G, tk.A];\n" - "\treturn a[0]: i32;\n" - "};\n", - 251 }, - - { "frame_smash", - "type tk = enum i32 { A = 7i32, B = 21i32, C = 99i32,\n" - "\tD = 3i32, E = 11i32, F = 5i32 };\n" - "fn main() i32 = {\n" - "\tlet a: [6]tk = [tk.A, tk.B, tk.C, tk.D, tk.E, tk.F];\n" - "\treturn a[5]: i32;\n" - "};\n", - 5 }, - - { "width1_u8", - "type tu = enum u8 { A = 7u8, B = 200u8, C = 3u8 };\n" - "fn main() i32 = {\n" - "\tlet a: [3]tu = [tu.A, tu.B, tu.C];\n" - "\treturn a[1]: i32;\n" - "};\n", - 200 }, - - { "width2_i16", - "type ts = enum i16 { A = 7i16, G = -5i16, C = 99i16 };\n" - "fn main() i32 = {\n" - "\tlet a: [3]ts = [ts.A, ts.G, ts.C];\n" - "\treturn a[1]: i32;\n" - "};\n", - 251 }, -}; - -static int -run_driver(const char *driver, const struct row *r, int i) -{ - char tmpdir[64], src[128], outbin[128], scratch[160], cmd[1024]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/aee_%d_d_%d", getpid(), i); - snprintf(src, sizeof src, "%s/aee_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/aee_%d_%d", tmpdir, getpid(), i); - snprintf(scratch, sizeof scratch, "%s.sepwork", outbin); - - if (mkdir(tmpdir, 0755) != 0) { - perror(tmpdir); - return -1; - } - int result = -1; - FILE *f = fopen(src, "wb"); - if (!f) { perror(src); goto cleanup; } - wwtest_fputs(r->src, f); - if (fclose(f) != 0) { perror(src); goto cleanup; } - - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null", - driver, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: build via %s failed\n", - r->label, driver); - goto cleanup; - } - - result = runwait(outbin); - -cleanup: - /* `ww build -o` retains this exact caller-owned scratch tree. */ - snprintf(cmd, sizeof cmd, "rm -rf %s", scratch); - int cleanfail = runwait(cmd) != 0; - if (unlink(outbin) != 0 && errno != ENOENT) { - perror(outbin); cleanfail = 1; - } - if (unlink(src) != 0 && errno != ENOENT) { - perror(src); cleanfail = 1; - } - if (rmdir(tmpdir) != 0) { - perror(tmpdir); cleanfail = 1; - } - if (cleanfail && result == r->want) result = -1; - return result; -} - -/* asm_byte_identical — generate .s via cstage's w6c and wwstage's - * w6c_ww and diff. This is the regression-pinning row for #8: pre-fix - * wwstage emitted stride-8 MOVQ where cstage emitted stride-4 MOVSXD, - * so the diff was non-empty. */ -static int -asm_byte_identical(const char *bin, const struct row *r, int i) -{ - char tmpdir[64], src[128], cs[128], ws[128], cmd[1024]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/aee_asm_%d_%d", getpid(), i); - snprintf(src, sizeof src, "%s/input.ww", tmpdir); - snprintf(cs, sizeof cs, "%s/c.s", tmpdir); - snprintf(ws, sizeof ws, "%s/w.s", tmpdir); - if (mkdir(tmpdir, 0755) != 0) { - perror(tmpdir); - return -1; - } - int rc = -1; - - FILE *f = fopen(src, "wb"); - if (!f) { perror(src); goto cleanup; } - wwtest_fputs(r->src, f); - if (fclose(f) != 0) { perror(src); goto cleanup; } - - snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c errored\n", r->label); - goto cleanup; - } - snprintf(cmd, sizeof cmd, "%s/w6c_ww -o %s %s 2>/dev/null", - bin, ws, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww errored\n", r->label); - goto cleanup; - } - - FILE *fc = fopen(cs, "rb"); - FILE *fw = fopen(ws, "rb"); - rc = 0; - if (!fc || !fw) { - rc = -1; - } else { - for (;;) { - int a = fgetc(fc); - int b = fgetc(fw); - if (a != b) { rc = -1; break; } - if (a == EOF) break; - } - } - if (fc) fclose(fc); - if (fw) fclose(fw); - if (rc != 0) - fprintf(stderr, "row[%s]: cstage vs wwstage asm differs\n", - r->label); - -cleanup: - if (unlink(src) != 0 && errno != ENOENT) { - perror(src); rc = -1; - } - if (unlink(cs) != 0 && errno != ENOENT) { - perror(cs); rc = -1; - } - if (unlink(ws) != 0 && errno != ENOENT) { - perror(ws); rc = -1; - } - if (rmdir(tmpdir) != 0) { - perror(tmpdir); rc = -1; - } - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - char wdrv[1024]; - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - - struct { const char *name; const char *path; int gated_on_existence; } - drivers[] = { - { "cstage", cdrv, 0 }, - { "wwstage", wdrv, 1 }, - { NULL, NULL, 0 }, - }; - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - - for (int d = 0; drivers[d].name; d++) { - if (drivers[d].gated_on_existence - && access(drivers[d].path, X_OK) != 0) { - fprintf(stderr, "arr_enum_elem: skip %s (no %s)\n", - drivers[d].name, drivers[d].path); - continue; - } - for (int i = 0; i < n; i++) { - int got = run_driver(drivers[d].path, &rows[i], i); - total++; - if (got != rows[i].want) { - fprintf(stderr, - "arr_enum_elem[%s][%s]: exit=%d want=%d\n", - drivers[d].name, rows[i].label, - got, rows[i].want); - fail++; - } - } - } - - if (access(wdrv, X_OK) == 0) { - for (int i = 0; i < n; i++) { - total++; - if (asm_byte_identical(bin, &rows[i], i) != 0) - fail++; - } - } - - if (fail) { - fprintf(stderr, - "arr_enum_elem: %d/%d fixtures failed\n", fail, total); - return 1; - } - printf("arr_enum_elem: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/683_arr_strslice_elem.c b/test/wcc/683_arr_strslice_elem.c deleted file mode 100644 index e4b40c88..00000000 --- a/test/wcc/683_arr_strslice_elem.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - * 683_arr_strslice_elem — cstage and wwstage agree, byte-for-byte and - * at runtime, that an `[N][]u8` / `[N]str` array-LITERAL init copies the - * FULL 24B {ptr,len,cap} header of every element (task #20, the #270 - * aggregate-element-store family's str/slice arm). - * - * The bug: cgen's N_LET / N_ARRLIT per-element store lowered each str/ - * slice element's header into AX=ptr/BX=len/CX=cap (cgexpr) but stored - * only some words — a slice element fell through to the scalar 1-word - * MOVQ (dropping .len AND .cap), and a str element stored 2 words - * (dropping .cap, latent). Each element is 24B and must be copied - * whole. wwstage was worse: a slice element matched no esz branch, so - * esz stayed the 8 sentinel — the per-element stride collapsed (element - * i+1 overwrote element i's tail), the -96-vs-80 cs!=ww frame - * divergence. struct/array/tuple elements already copied correctly via - * the #270-1c is_agg multi-word path; str/slice were the documented - * follow-up (cgen.c:9037-9042, cgenstmt.ww deferral comment). - * - * The fix (BOTH stages, converged byte-identical): cstage adds - * is_slice_el = type_isslice(esub) and stores 3 words (incl CX->base+16) - * for `is_str_el || is_slice_el`; wwstage adds isslicel (TY_SLICE -> - * esz = esubti.size, fixing the stride) and the matching 3-word store. - * - * Cap is validated BOTH ways: a WHOLE-ELEMENT COPY (`let q = t[i]; q.cap`) - * AND a DIRECT `t[i].cap` read. The direct read was a SEPARATE bug (task - * #13, the #20 store's read-sibling): the `.cap` field-extract on an - * INDEXED slice/str element returned .ptr on cstage (it shuffled only - * .len BX→AX, leaving AX=.ptr for cap) and emitted NO read on wwstage - * (the cgdot non-ident catch-all handled only .ptr/.len) — divergent. - * Fix (BOTH stages, byte-id): cgexpr leaves the full {ptr,len,cap} header - * via cgslicehdr for an indexed element, so .cap shuffles CX→AX, the twin - * of the .len BX→AX shuffle. The direct-cap rows must equal the - * whole-element-copy oracle (which #20 made correct). - * - * Mutation-sanity (the per-word coverage): the .len rows fail if the - * store drops the .len word (the pre-fix slice 1-word store), and the - * cap-via-copy rows fail if it drops the .cap word (the pre-fix str - * 2-word store) — so a regression to a 1-word or 2-word store is caught. - * - * row | shape | want - * -----------------+------------------------------------+-------------- - * slice_len1 | [2][]u8, return t[1].len. Pre-fix | 2 + byte-id - * | slice 1-word store dropped .len. | - * slice_len0 | [2][]u8, return t[0].len. | 3 + byte-id - * slice_stride3 | [3][]u8, return t[2].len. Exercises| 7 + byte-id - * | the 24B per-element stride (the | - * | wwstage 8-sentinel frame-offset | - * | bug overran into the wrong slot). | - * slice_cap_copy | [2][]u8 w/ caps 7,6; let q=t[0]; | 7 + byte-id - * | return q.cap. Validates the stored | - * | .cap word (pre-fix dropped). | - * slice_ptr | [2][]u8 over a backing array; let | 4 + byte-id - * | q=t[1]; return q[0]. Pins .ptr | - * | stored correctly (deref the elem). | - * str_len1 | [2]str=[a,b], return t[1].len. | 2 + byte-id - * str_cap_copy | [2]str=["abcde","xy"]; let q=t[0]; | 5 + byte-id - * | return q.cap. The latent str cap- | - * | drop (pre-fix garbage); cap=len=5 | - * | for a static literal. | - * struct_elem | [2]Pt struct literal, return | 4 + byte-id - * | t[1].y. Regression pin: the is_agg | - * | multi-word path is untouched by | - * | the str/slice branch. | - * - * Exit-code rows confirm both stages run correctly. The asm-byte-id rows - * pin the symmetric 3-word store (cstage == wwstage); pre-fix wwstage - * mis-strided (slice esz=8) and under-copied, so the diff was non-empty. - */ -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -/* want == BYTEID_ONLY: the row's runtime value is non-deterministic (a - * link-time address), so only the cstage/wwstage asm-byte-id is asserted; - * the build must still succeed on both stages. Used for the `"abc".cap` - * symmetry edge (a string-literal .cap is meaningless garbage on both - * stages, but rule 10 still requires byte-identical asm). */ -#define BYTEID_ONLY (-2147483647 - 1) - -struct row { const char *label; const char *src; int want; }; - -static const struct row rows[] = { - { "slice_len1", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet a: []u8; a.ptr = &hb[0]; a.len = 3; a.cap = 8;\n" - "\tlet b: []u8; b.ptr = &hb[0]; b.len = 2; b.cap = 8;\n" - "\tlet t: [2][]u8 = [a, b];\n" - "\treturn t[1].len: i32;\n" - "};\n", - 2 }, - - { "slice_len0", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet a: []u8; a.ptr = &hb[0]; a.len = 3; a.cap = 8;\n" - "\tlet b: []u8; b.ptr = &hb[0]; b.len = 2; b.cap = 8;\n" - "\tlet t: [2][]u8 = [a, b];\n" - "\treturn t[0].len: i32;\n" - "};\n", - 3 }, - - { "slice_stride3", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet a: []u8; a.ptr = &hb[0]; a.len = 3; a.cap = 8;\n" - "\tlet b: []u8; b.ptr = &hb[0]; b.len = 5; b.cap = 8;\n" - "\tlet c: []u8; c.ptr = &hb[0]; c.len = 7; c.cap = 8;\n" - "\tlet t: [3][]u8 = [a, b, c];\n" - "\treturn t[2].len: i32;\n" - "};\n", - 7 }, - - { "slice_cap_copy", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet a: []u8; a.ptr = &hb[0]; a.len = 3; a.cap = 7;\n" - "\tlet b: []u8; b.ptr = &hb[0]; b.len = 2; b.cap = 6;\n" - "\tlet t: [2][]u8 = [a, b];\n" - "\tlet q: []u8 = t[0];\n" - "\treturn q.cap: i32;\n" - "};\n", - 7 }, - - /* #13 direct-read rows: `t[i].cap` straight (no copy via a let). - * Must equal the slice_cap_copy / str_cap_copy oracle. Pre-fix: - * cstage returned .ptr (a heap/stack address, != 7/6), wwstage - * emitted no read (stale AX) — and the two diverged. */ - { "slice_cap_direct0", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet a: []u8; a.ptr = &hb[0]; a.len = 3; a.cap = 7;\n" - "\tlet b: []u8; b.ptr = &hb[0]; b.len = 2; b.cap = 6;\n" - "\tlet t: [2][]u8 = [a, b];\n" - "\treturn t[0].cap: i32;\n" - "};\n", - 7 }, - - { "slice_cap_direct1", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet a: []u8; a.ptr = &hb[0]; a.len = 3; a.cap = 7;\n" - "\tlet b: []u8; b.ptr = &hb[0]; b.len = 2; b.cap = 6;\n" - "\tlet t: [2][]u8 = [a, b];\n" - "\treturn t[1].cap: i32;\n" - "};\n", - 6 }, - - { "str_cap_direct0", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet a: str = \"abcde\";\n" - "\tlet b: str = \"xy\";\n" - "\tlet t: [2]str = [a, b];\n" - "\treturn t[0].cap: i32;\n" - "};\n", - 5 }, - - { "str_cap_direct1", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet a: str = \"abcde\";\n" - "\tlet b: str = \"xy\";\n" - "\tlet t: [2]str = [a, b];\n" - "\treturn t[1].cap: i32;\n" - "};\n", - 2 }, - - /* #13 symmetry edge: `.cap` of a BARE string literal. The wwstage - * checker types N_STRLIT as `str` (cstage types it untyped_str), so - * the .cap kind-gate would wrongly shuffle CX→AX on wwstage only — - * but a literal's cgexpr never loads a CX cap, and cstage never - * shuffles it, so both must return AX (ptr) unshuffled. Byte-id only: - * the value is a link-time address (non-deterministic). Pre-fix this - * row's asm DIFFERED (wwstage had the stray MOVQ CX, AX). */ - { "str_lit_cap_symmetry", - "package main;\n" - "export fn main() i32 = {\n" - "\treturn \"abc\".cap: i32;\n" - "};\n", - BYTEID_ONLY }, - - { "slice_ptr", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8; hb[0] = 9u8; hb[1] = 4u8;\n" - "\tlet a: []u8; a.ptr = &hb[0]; a.len = 3; a.cap = 8;\n" - "\tlet b: []u8; b.ptr = &hb[1]; b.len = 2; b.cap = 8;\n" - "\tlet t: [2][]u8 = [a, b];\n" - "\tlet q: []u8 = t[1];\n" - "\treturn q[0]: i32;\n" - "};\n", - 4 }, - - { "str_len1", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet a: str = \"abc\";\n" - "\tlet b: str = \"de\";\n" - "\tlet t: [2]str = [a, b];\n" - "\treturn t[1].len: i32;\n" - "};\n", - 2 }, - - { "str_cap_copy", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet a: str = \"abcde\";\n" - "\tlet b: str = \"xy\";\n" - "\tlet t: [2]str = [a, b];\n" - "\tlet q: str = t[0];\n" - "\treturn q.cap: i32;\n" - "};\n", - 5 }, - - /* Regression pin: a [N]struct element copies multi-word via the - * pre-existing #270-1c is_agg path, NOT the new str/slice 3-word - * header branch. Proves the str/slice esz/store change leaves the - * is_agg element path untouched (byte-id holds for it too). */ - { "struct_elem", - "package main;\n" - "type Pt = struct { x: i32, y: i32 };\n" - "export fn main() i32 = {\n" - "\tlet t: [2]Pt = [Pt { x = 1, y = 2 }, Pt { x = 3, y = 4 }];\n" - "\treturn t[1].y: i32;\n" - "};\n", - 4 }, -}; - -static int -run_driver(const char *driver, const struct row *r, int i) -{ - char tmpdir[64], src[128], outbin[128], scratch[160], cmd[1024]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/asse_%d_d_%d", getpid(), i); - snprintf(src, sizeof src, "%s/asse_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/asse_%d_%d", tmpdir, getpid(), i); - snprintf(scratch, sizeof scratch, "%s.sepwork", outbin); - if (mkdir(tmpdir, 0755) != 0) { - perror(tmpdir); - return -1; - } - int result = -1; - - FILE *f = fopen(src, "wb"); - if (!f) { perror(src); goto cleanup; } - fputs(r->src, f); - if (fclose(f) != 0) { perror(src); goto cleanup; } - - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null", - driver, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: build via %s failed\n", - r->label, driver); - goto cleanup; - } - - result = runwait(outbin); - -cleanup: - /* `ww build -o` retains this exact caller-owned scratch tree. */ - snprintf(cmd, sizeof cmd, "rm -rf %s", scratch); - int cleanfail = runwait(cmd) != 0; - if (unlink(outbin) != 0 && errno != ENOENT) { - perror(outbin); cleanfail = 1; - } - if (unlink(src) != 0 && errno != ENOENT) { - perror(src); cleanfail = 1; - } - if (rmdir(tmpdir) != 0) { - perror(tmpdir); cleanfail = 1; - } - if (cleanfail && (r->want == BYTEID_ONLY || result == r->want)) - result = -1; - return result; -} - -/* asm_byte_identical — generate .s via cstage's w6c and wwstage's - * w6c_ww and diff. The regression-pinning row for #20: pre-fix wwstage - * mis-strided the slice element (esz=8) and under-copied, so the diff - * was non-empty; the converged 3-word store makes them identical. */ -static int -asm_byte_identical(const char *bin, const struct row *r, int i) -{ - char tmpdir[64], src[128], cs[128], ws[128], cmd[1024]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/asse_asm_%d_%d", getpid(), i); - snprintf(src, sizeof src, "%s/input.ww", tmpdir); - snprintf(cs, sizeof cs, "%s/c.s", tmpdir); - snprintf(ws, sizeof ws, "%s/w.s", tmpdir); - if (mkdir(tmpdir, 0755) != 0) { - perror(tmpdir); - return -1; - } - int rc = -1; - - FILE *f = fopen(src, "wb"); - if (!f) { perror(src); goto cleanup; } - fputs(r->src, f); - if (fclose(f) != 0) { perror(src); goto cleanup; } - - snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c errored\n", r->label); - goto cleanup; - } - snprintf(cmd, sizeof cmd, "%s/w6c_ww -o %s %s 2>/dev/null", - bin, ws, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww errored\n", r->label); - goto cleanup; - } - - FILE *fc = fopen(cs, "rb"); - FILE *fw = fopen(ws, "rb"); - rc = 0; - if (!fc || !fw) { - rc = -1; - } else { - for (;;) { - int a = fgetc(fc); - int b = fgetc(fw); - if (a != b) { rc = -1; break; } - if (a == EOF) break; - } - } - if (fc) fclose(fc); - if (fw) fclose(fw); - if (rc != 0) - fprintf(stderr, "row[%s]: cstage vs wwstage asm differs\n", - r->label); - -cleanup: - if (unlink(src) != 0 && errno != ENOENT) { - perror(src); rc = -1; - } - if (unlink(cs) != 0 && errno != ENOENT) { - perror(cs); rc = -1; - } - if (unlink(ws) != 0 && errno != ENOENT) { - perror(ws); rc = -1; - } - if (rmdir(tmpdir) != 0) { - perror(tmpdir); rc = -1; - } - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - char wdrv[1024]; - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - - struct { const char *name; const char *path; int gated_on_existence; } - drivers[] = { - { "cstage", cdrv, 0 }, - { "wwstage", wdrv, 1 }, - { NULL, NULL, 0 }, - }; - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - - for (int d = 0; drivers[d].name; d++) { - if (drivers[d].gated_on_existence - && access(drivers[d].path, X_OK) != 0) { - fprintf(stderr, "arr_strslice_elem: skip %s (no %s)\n", - drivers[d].name, drivers[d].path); - continue; - } - for (int i = 0; i < n; i++) { - int got = run_driver(drivers[d].path, &rows[i], i); - total++; - /* BYTEID_ONLY rows assert asm byte-id below; here only - * the build must succeed (run_driver returns -1 on a - * build/run failure). The exit value is ignored. */ - int bad = rows[i].want == BYTEID_ONLY - ? (got == -1) : (got != rows[i].want); - if (bad) { - fprintf(stderr, - "arr_strslice_elem[%s][%s]: exit=%d want=%d\n", - drivers[d].name, rows[i].label, - got, rows[i].want); - fail++; - } - } - } - - if (access(wdrv, X_OK) == 0) { - for (int i = 0; i < n; i++) { - total++; - if (asm_byte_identical(bin, &rows[i], i) != 0) - fail++; - } - } - - if (fail) { - fprintf(stderr, - "arr_strslice_elem: %d/%d fixtures failed\n", fail, total); - return 1; - } - printf("arr_strslice_elem: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/684_arr_infer_len.c b/test/wcc/684_arr_infer_len.c deleted file mode 100644 index dda321cc..00000000 --- a/test/wcc/684_arr_infer_len.c +++ /dev/null @@ -1,408 +0,0 @@ -/* - * 684_arr_infer_len — cstage and wwstage agree, byte-for-byte and at - * runtime, that a `[_]T = [...]` array infers its length from the - * initialiser's element count (task #7, a canonical Hare form). - * - * The bug: `[_]T` silently miscompiled to a zero-length array. The - * parser already left the array type's length child nil as the infer - * sentinel (distinct from an explicit `[N]`), but neither checker - * stamped the real count — so `len(x)` / `x.len` returned 0 with no - * diagnostic (rule-7 silent miscompile). Module-level was worse on - * wwstage: `x.len` on ANY global array (even explicit `[N]`) fell to - * the SB fallback and mis-emitted `MOVQ len(SB), AX` (linker: - * undefined reference to len). - * - * The fix (BOTH stages, converged byte-identical): - * - checker (cmd/wcc/check.c clet + module-level N_LET; - * selfhost/cmd/wcc/check.ww inferarraylen): count the array-literal - * elements and stamp the length onto the array TYPE. cgen already - * keys stride/length/data off the stamped length, so it "just - * works" (rob's #7 ruling). A `[_]T` with no array-literal init - * can't infer → LOUD error, never a silent zero-length array. - * - cgen (selfhost/cmd/wcc/cgenexpr.ww cgdot): a top-level `[N]T` - * global's `.len` / `.ptr` pseudo-fields, the wwstage arm that was - * missing (cstage cgen.c:8011 already handled it). - * - * Coverage: `[_]int` / `[_]str` / `[_]u8`, both local and module-level, - * `len` read-back and element read-back, dual-stage runtime + asm - * byte-id. Mutation-sanity: the old collapse-to-0 fails every `*_len` - * row (len would be 0, not the count). Plus three negative rows where - * `[_]T` can't infer (no init / non-array init) — both stages must - * FAIL the build. - * - * row | shape | want - * ----------------+--------------------------------------+------ - * local_int_len | local [_]int=[10,20,30,40], x.len | 4 - * local_int_elem | local, x[2] | 30 - * mod_int_len | global [_]int=[..], x.len | 4 - * mod_int_elem | global, x[2] | 30 - * local_str_len | local [_]str=["a","b","c"], x.len | 3 - * local_str_elem | local [_]str=["ab","cde"], x[0].len | 2 - * mod_str_len | global [_]str=["a","b","c"], x.len | 3 - * local_u8_len | local [_]u8=[1..5], x.len | 5 - * local_u8_elem | local, x[4] | 5 - * local_one_len | local [_]int=[7], x.len (1-elem edge)| 1 - * mod_one_len | global [_]int=[7], x.len | 1 - * mod_one_elem | global, x[0] | 7 - */ -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want; }; - -static const struct row rows[] = { - { "local_int_len", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet x: [_]int = [10, 20, 30, 40];\n" - "\treturn x.len: i32;\n" - "};\n", - 4 }, - - { "local_int_elem", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet x: [_]int = [10, 20, 30, 40];\n" - "\treturn x[2]: i32;\n" - "};\n", - 30 }, - - { "mod_int_len", - "package main;\n" - "let x: [_]int = [10, 20, 30, 40];\n" - "export fn main() i32 = {\n" - "\treturn x.len: i32;\n" - "};\n", - 4 }, - - { "mod_int_elem", - "package main;\n" - "let x: [_]int = [10, 20, 30, 40];\n" - "export fn main() i32 = {\n" - "\treturn x[2]: i32;\n" - "};\n", - 30 }, - - { "local_str_len", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet x: [_]str = [\"a\", \"b\", \"c\"];\n" - "\treturn x.len: i32;\n" - "};\n", - 3 }, - - { "local_str_elem", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet x: [_]str = [\"ab\", \"cde\"];\n" - "\treturn x[0].len: i32;\n" - "};\n", - 2 }, - - { "mod_str_len", - "package main;\n" - "let x: [_]str = [\"a\", \"b\", \"c\"];\n" - "export fn main() i32 = {\n" - "\treturn x.len: i32;\n" - "};\n", - 3 }, - - { "local_u8_len", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet x: [_]u8 = [1u8, 2u8, 3u8, 4u8, 5u8];\n" - "\treturn x.len: i32;\n" - "};\n", - 5 }, - - { "local_u8_elem", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet x: [_]u8 = [1u8, 2u8, 3u8, 4u8, 5u8];\n" - "\treturn x[4]: i32;\n" - "};\n", - 5 }, - - /* 1-element edge — the minimal non-empty count; under the old - * collapse-to-0 bug `.len` reads 0, not 1, so this row also fails - * the mutation. */ - { "local_one_len", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet x: [_]int = [7];\n" - "\treturn x.len: i32;\n" - "};\n", - 1 }, - - { "mod_one_len", - "package main;\n" - "let x: [_]int = [7];\n" - "export fn main() i32 = {\n" - "\treturn x.len: i32;\n" - "};\n", - 1 }, - - { "mod_one_elem", - "package main;\n" - "let x: [_]int = [7];\n" - "export fn main() i32 = {\n" - "\treturn x[0]: i32;\n" - "};\n", - 7 }, -}; - -/* `[_]T` that can't infer its length — both stages must FAIL the build - * (loud diagnostic, not a silent zero-length array). */ -static const char *neg[] = { - /* no init, local */ - "package main;\n" - "export fn main() i32 = {\n" - "\tlet x: [_]str;\n" - "\treturn 0;\n" - "};\n", - /* no init, module-level */ - "package main;\n" - "let x: [_]int;\n" - "export fn main() i32 = { return 0; };\n", - /* non-array initialiser */ - "package main;\n" - "export fn main() i32 = {\n" - "\tlet x: [_]int = 5;\n" - "\treturn 0;\n" - "};\n", -}; - -static int -run_driver(const char *driver, const struct row *r, int i) -{ - char tmpdir[64], src[128], outbin[128], scratch[160], rmcmd[192], cmd[1024]; - int result = -1, setupfail = 0, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/ail_%d_d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(src, sizeof src, "%s/ail_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/ail_%d_%d", tmpdir, getpid(), i); - snprintf(scratch, sizeof scratch, "%s.sepwork", outbin); - - FILE *f = fopen(src, "wb"); - if (!f) { setupfail = 1; goto cleanup; } - int writefail = fputs(r->src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) { setupfail = 1; goto cleanup; } - - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null", - driver, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: build via %s failed\n", - r->label, driver); - goto cleanup; - } - - result = runwait(outbin); -cleanup: - if (setupfail) - fprintf(stderr, "row[%s]: temporary setup failed\n", r->label); - snprintf(rmcmd, sizeof rmcmd, "rm -rf -- %s", scratch); - if (runwait(rmcmd) != 0) cleanfail = 1; - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: temporary cleanup failed\n", r->label); - if (result == r->want) return -1; - } - return result; -} - -/* build_should_fail — a `[_]T` that can't infer must error on `driver`; - * returns 0 when the build correctly FAILS, positive when it wrongly - * succeeds, and negative on fixture infrastructure failure. */ -static int -build_should_fail(const char *driver, const char *src, int i) -{ - char tmpdir[64], s[128], outbin[128], scratch[160], rmcmd[192], cmd[1024]; - int result = -1, setupfail = 0, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/ailn_%d_d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(s, sizeof s, "%s/ailn_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/ailn_%d_%d", tmpdir, getpid(), i); - snprintf(scratch, sizeof scratch, "%s.sepwork", outbin); - - FILE *f = fopen(s, "wb"); - if (!f) { setupfail = 1; goto cleanup; } - int writefail = fputs(src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) { setupfail = 1; goto cleanup; } - - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null", - driver, outbin, s); - int rc = runwait(cmd); - result = rc == 0 ? 1 : 0; /* build must NOT succeed */ -cleanup: - if (setupfail) - fprintf(stderr, "arr_infer_len[neg%d]: temporary setup failed\n", i); - snprintf(rmcmd, sizeof rmcmd, "rm -rf -- %s", scratch); - if (runwait(rmcmd) != 0) cleanfail = 1; - if (unlink(s) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "arr_infer_len[neg%d]: temporary cleanup failed\n", i); - if (result == 0) return -1; - } - return result; -} - -/* asm_byte_identical — w6c vs w6c_ww .s for the same source must match. */ -static int -asm_byte_identical(const char *bin, const struct row *r, int i) -{ - char tmpdir[64], src[96], cs[96], ws[96], cmd[1024]; - int rc = -1, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/ail_asm_%d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(src, sizeof src, "%s/t.ww", tmpdir); - snprintf(cs, sizeof cs, "%s/c.s", tmpdir); - snprintf(ws, sizeof ws, "%s/w.s", tmpdir); - - FILE *f = fopen(src, "wb"); - if (!f) goto cleanup; - int writefail = fputs(r->src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) goto cleanup; - - snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c errored\n", r->label); - goto cleanup; - } - snprintf(cmd, sizeof cmd, "%s/w6c_ww -o %s %s 2>/dev/null", - bin, ws, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww errored\n", r->label); - goto cleanup; - } - - FILE *fc = fopen(cs, "rb"); - FILE *fw = fopen(ws, "rb"); - rc = 0; - if (!fc || !fw) { - rc = -1; - } else { - for (;;) { - int a = fgetc(fc); - int b = fgetc(fw); - if (a != b) { rc = -1; break; } - if (a == EOF) break; - } - } - if (fc) fclose(fc); - if (fw) fclose(fw); - if (rc != 0) - fprintf(stderr, "row[%s]: cstage vs wwstage asm differs\n", - r->label); -cleanup: - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(cs) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(ws) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: temporary cleanup failed\n", r->label); - return -1; - } - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - char wdrv[1024]; - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - - struct { const char *name; const char *path; int gated_on_existence; } - drivers[] = { - { "cstage", cdrv, 0 }, - { "wwstage", wdrv, 1 }, - { NULL, NULL, 0 }, - }; - - int n = (int)(sizeof rows / sizeof rows[0]); - int nn = (int)(sizeof neg / sizeof neg[0]); - int total = 0, fail = 0; - - for (int d = 0; drivers[d].name; d++) { - if (drivers[d].gated_on_existence - && access(drivers[d].path, X_OK) != 0) { - fprintf(stderr, "arr_infer_len: skip %s (no %s)\n", - drivers[d].name, drivers[d].path); - continue; - } - for (int i = 0; i < n; i++) { - int got = run_driver(drivers[d].path, &rows[i], i); - total++; - if (got != rows[i].want) { - fprintf(stderr, - "arr_infer_len[%s][%s]: exit=%d want=%d\n", - drivers[d].name, rows[i].label, - got, rows[i].want); - fail++; - } - } - for (int i = 0; i < nn; i++) { - total++; - int nr = build_should_fail(drivers[d].path, neg[i], 100 + i); - if (nr != 0) { - if (nr > 0) - fprintf(stderr, - "arr_infer_len[%s][neg%d]: built ok, " - "expected a loud error\n", - drivers[d].name, i); - else - fprintf(stderr, - "arr_infer_len[%s][neg%d]: fixture infrastructure failed\n", - drivers[d].name, i); - fail++; - } - } - } - - if (access(wdrv, X_OK) == 0) { - for (int i = 0; i < n; i++) { - total++; - if (asm_byte_identical(bin, &rows[i], i) != 0) - fail++; - } - } - - if (fail) { - fprintf(stderr, - "arr_infer_len: %d/%d fixtures failed\n", fail, total); - return 1; - } - printf("arr_infer_len: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/685_arr_tagged_elem.c b/test/wcc/685_arr_tagged_elem.c deleted file mode 100644 index ebd1eebb..00000000 --- a/test/wcc/685_arr_tagged_elem.c +++ /dev/null @@ -1,413 +0,0 @@ -/* - * 685_arr_tagged_elem — cstage and wwstage agree, byte-for-byte and at - * runtime, that a `[N]tagged` array-LITERAL init boxes the FULL tag+ - * payload slot of every element (task #12, the #270 aggregate-element- - * store family's tagged-union arm; sibling of #20's str/slice arm in - * test 683). - * - * The bug: cgen's N_ARRLIT per-element store excluded TY_TAGGED from the - * is_agg predicate, so a tagged element fell through to the scalar - * 1-word MOVQ — it stored the raw scalar (99) into WORD0 (the TAG slot), - * with NO tag word and NO payload placement. A subsequent `match` found - * no variant (tag was the payload value, not a variant index) and the - * arms silently produced 0. wwstage was worse: esz stayed the 8 sentinel - * for a 16B tagged element (the #8-class stride trap), so element i+1 - * overran element i's tail. The under-copy DEPTH (1 word vs full slot) - * is byte-id-blind — both stages stored 1 word, so the asm-byte-id gate - * passed green on both-wrong; only the runtime readback below catches it. - * - * The fix (BOTH stages, converged byte-identical): route each tagged - * element through the SAME cg_widen_tagged_store / cgwidentaggedstore - * choke-point every other tagged store uses (let-init, vararg gather, - * struct-field) — NOT a new is_agg branch (is_agg word-copies/fatals and - * never boxes the tag). cstage adds is_tagged_el = esubu->kind == - * TY_TAGGED; wwstage adds istaggedel and sizes esz from the stamped - * tinfo (esubti.size, rule-13) so the 16B/24B stride is correct. - * - * row | shape | want - * ----------------+-------------------------------------+----------- - * lit_sum106 | [2]cell=[99i64,7i64] (cell= | 106 (ken - * | (i64|bool)); match+sum both. | oracle) - * lit_first | same; match t[0] only. | 99 - * lit_second | same; match t[1] only. | 7 - * bool_variant | [2]cell=[5i64, true]; match t[1]. | 1 pins the - * | The bool arm only fires if the tag | tag word - * | word was written (not payload-in- | was placed - * | word0). Pre-fix: 0 (no tag). | - * var_sum | [2]cell=[a,b] (a=40i64,b=2i64 | 42 variable- - * | idents); match+sum. Repro B. | source - * stride3 | [3]cell=[10i64,20i64,30i64]; match | 30 16B per- - * | t[2]. Exercises the per-element | element - * | slot stride (wwstage 8-sentinel | stride - * | overran into the wrong slot). | - * boxed_void | [3](i32|void)=[1i32,2i32,void]; | 13 bare-value - * | match: i32 arm sums payload, void | box: tag + - * | arm adds 10. 1+2+10. | payload + - * | | zero-pad - * - * The asm-byte-id rows pin the symmetric widen (cstage == wwstage). The - * under-copy itself is byte-id-blind (see above) — these rows guard the - * stride/op symmetry, the runtime rows guard the correctness. - */ -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want; }; - -static const struct row rows[] = { - { "lit_sum106", - "package main;\n" - "type cell = (i64 | bool);\n" - "export fn main() i32 = {\n" - "\tlet t: [2]cell = [99i64, 7i64];\n" - "\tlet sum: i64 = 0i64;\n" - "\tlet i: i32 = 0;\n" - "\tfor (i < 2) {\n" - "\t\tmatch (t[i]) {\n" - "\t\tcase let v: i64 => { sum = sum + v; };\n" - "\t\tcase let z: bool => { sum = sum + 1i64; };\n" - "\t\t};\n" - "\t\ti = i + 1;\n" - "\t};\n" - "\treturn sum: i32;\n" - "};\n", - 106 }, - - { "lit_first", - "package main;\n" - "type cell = (i64 | bool);\n" - "export fn main() i32 = {\n" - "\tlet t: [2]cell = [99i64, 7i64];\n" - "\tmatch (t[0]) {\n" - "\tcase let v: i64 => { return v: i32; };\n" - "\tcase let z: bool => { return -1; };\n" - "\t};\n" - "};\n", - 99 }, - - { "lit_second", - "package main;\n" - "type cell = (i64 | bool);\n" - "export fn main() i32 = {\n" - "\tlet t: [2]cell = [99i64, 7i64];\n" - "\tmatch (t[1]) {\n" - "\tcase let v: i64 => { return v: i32; };\n" - "\tcase let z: bool => { return -1; };\n" - "\t};\n" - "};\n", - 7 }, - - { "bool_variant", - "package main;\n" - "type cell = (i64 | bool);\n" - "export fn main() i32 = {\n" - "\tlet t: [2]cell = [5i64, true];\n" - "\tmatch (t[1]) {\n" - "\tcase let v: i64 => { return -1; };\n" - "\tcase let z: bool => { if (z) { return 1; }; return 0; };\n" - "\t};\n" - "};\n", - 1 }, - - { "var_sum", - "package main;\n" - "type cell = (i64 | bool);\n" - "export fn main() i32 = {\n" - "\tlet a: cell = 40i64;\n" - "\tlet b: cell = 2i64;\n" - "\tlet t: [2]cell = [a, b];\n" - "\tlet sum: i64 = 0i64;\n" - "\tlet i: i32 = 0;\n" - "\tfor (i < 2) {\n" - "\t\tmatch (t[i]) {\n" - "\t\tcase let v: i64 => { sum = sum + v; };\n" - "\t\tcase let z: bool => { sum = sum + 100i64; };\n" - "\t\t};\n" - "\t\ti = i + 1;\n" - "\t};\n" - "\treturn sum: i32;\n" - "};\n", - 42 }, - - { "stride3", - "package main;\n" - "type cell = (i64 | bool);\n" - "export fn main() i32 = {\n" - "\tlet t: [3]cell = [10i64, 20i64, 30i64];\n" - "\tmatch (t[2]) {\n" - "\tcase let v: i64 => { return v: i32; };\n" - "\tcase let z: bool => { return -1; };\n" - "\t};\n" - "};\n", - 30 }, - - { "boxed_void", - "package main;\n" - "type ov = (i32 | void);\n" - "export fn main() i32 = {\n" - "\tlet t: [3]ov = [1i32, 2i32, void];\n" - "\tlet sum: i32 = 0;\n" - "\tlet i: i32 = 0;\n" - "\tfor (i < 3) {\n" - "\t\tmatch (t[i]) {\n" - "\t\tcase let v: i32 => { sum = sum + v; };\n" - "\t\tcase void => { sum = sum + 10; };\n" - "\t\t};\n" - "\t\ti = i + 1;\n" - "\t};\n" - "\treturn sum;\n" - "};\n", - 13 }, -}; - -/* rule-7 loud-stop: `[N]tagged = [x, ...]` repeat-fill is not wired - * (cg_widen_tagged_store consumes the node and trashes AX, so the - * repeat re-store would write garbage). Both stages must FAIL the - * build loudly, not silently emit a broken array. */ -static const char *neg[] = { - "package main;\n" - "type cell = (i64 | bool);\n" - "export fn main() i32 = {\n" - "\tlet t: [3]cell = [99i64...];\n" - "\treturn 0;\n" - "};\n", -}; - -static int -run_driver(const char *driver, const struct row *r, int i) -{ - char src[128], tmpdir[64], outbin[128], scratch[160], rmcmd[192], cmd[1024]; - int result = -1, setupfail = 0, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/atag_%d_d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(src, sizeof src, "%s/atag_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/atag_%d_%d", tmpdir, getpid(), i); - snprintf(scratch, sizeof scratch, "%s.sepwork", outbin); - - FILE *f = fopen(src, "wb"); - if (!f) { setupfail = 1; goto cleanup; } - int writefail = fputs(r->src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) { setupfail = 1; goto cleanup; } - - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null", - driver, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: build via %s failed\n", - r->label, driver); - goto cleanup; - } - result = runwait(outbin); -cleanup: - if (setupfail) - fprintf(stderr, "row[%s]: temporary setup failed\n", r->label); - snprintf(rmcmd, sizeof rmcmd, "rm -rf -- %s", scratch); - if (runwait(rmcmd) != 0) cleanfail = 1; - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: temporary cleanup failed\n", r->label); - if (result == r->want) return -1; - } - return result; -} - -/* build_should_fail — a `[N]tagged=[x,...]` repeat-fill must error on - * `driver` (rule-7 loud-stop); returns 0 when the build correctly - * FAILS, positive when it wrongly succeeds, and negative on fixture - * infrastructure failure. */ -static int -build_should_fail(const char *driver, const char *src, int i) -{ - char s[128], tmpdir[64], outbin[128], scratch[160], rmcmd[192], cmd[1024]; - int result = -1, setupfail = 0, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/atagn_%d_d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(s, sizeof s, "%s/atagn_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/atagn_%d_%d", tmpdir, getpid(), i); - snprintf(scratch, sizeof scratch, "%s.sepwork", outbin); - - FILE *f = fopen(s, "wb"); - if (!f) { setupfail = 1; goto cleanup; } - int writefail = fputs(src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) { setupfail = 1; goto cleanup; } - - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null", - driver, outbin, s); - int rc = runwait(cmd); - result = rc == 0 ? 1 : 0; /* build must NOT succeed */ -cleanup: - if (setupfail) - fprintf(stderr, "arr_tagged_elem[neg%d]: temporary setup failed\n", i); - snprintf(rmcmd, sizeof rmcmd, "rm -rf -- %s", scratch); - if (runwait(rmcmd) != 0) cleanfail = 1; - if (unlink(s) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "arr_tagged_elem[neg%d]: temporary cleanup failed\n", i); - if (result == 0) return -1; - } - return result; -} - -/* asm_byte_identical — generate .s via cstage's w6c and wwstage's - * w6c_ww and diff. The under-copy depth is byte-id-blind (both stages - * stored 1 word pre-fix), so this row guards only the symmetric widen - * stride/op; the runtime rows above are the correctness net. */ -static int -asm_byte_identical(const char *bin, const struct row *r, int i) -{ - char tmpdir[64], src[96], cs[96], ws[96], cmd[1024]; - int rc = -1, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/atag_asm_%d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(src, sizeof src, "%s/t.ww", tmpdir); - snprintf(cs, sizeof cs, "%s/c.s", tmpdir); - snprintf(ws, sizeof ws, "%s/w.s", tmpdir); - - FILE *f = fopen(src, "wb"); - if (!f) goto cleanup; - int writefail = fputs(r->src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) goto cleanup; - - snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c errored\n", r->label); - goto cleanup; - } - snprintf(cmd, sizeof cmd, "%s/w6c_ww -o %s %s 2>/dev/null", - bin, ws, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww errored\n", r->label); - goto cleanup; - } - - FILE *fc = fopen(cs, "rb"); - FILE *fw = fopen(ws, "rb"); - rc = 0; - if (!fc || !fw) { - rc = -1; - } else { - for (;;) { - int a = fgetc(fc); - int b = fgetc(fw); - if (a != b) { rc = -1; break; } - if (a == EOF) break; - } - } - if (fc) fclose(fc); - if (fw) fclose(fw); - if (rc != 0) - fprintf(stderr, "row[%s]: cstage vs wwstage asm differs\n", - r->label); - -cleanup: - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(cs) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(ws) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: temporary cleanup failed\n", r->label); - return -1; - } - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - char wdrv[1024]; - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - - struct { const char *name; const char *path; int gated_on_existence; } - drivers[] = { - { "cstage", cdrv, 0 }, - { "wwstage", wdrv, 1 }, - { NULL, NULL, 0 }, - }; - - int n = (int)(sizeof rows / sizeof rows[0]); - int nn = (int)(sizeof neg / sizeof neg[0]); - int total = 0, fail = 0; - - for (int d = 0; drivers[d].name; d++) { - if (drivers[d].gated_on_existence - && access(drivers[d].path, X_OK) != 0) { - fprintf(stderr, "arr_tagged_elem: skip %s (no %s)\n", - drivers[d].name, drivers[d].path); - continue; - } - for (int i = 0; i < n; i++) { - int got = run_driver(drivers[d].path, &rows[i], i); - total++; - if (got != rows[i].want) { - fprintf(stderr, - "arr_tagged_elem[%s][%s]: exit=%d want=%d\n", - drivers[d].name, rows[i].label, - got, rows[i].want); - fail++; - } - } - for (int i = 0; i < nn; i++) { - total++; - int nr = build_should_fail(drivers[d].path, neg[i], 100 + i); - if (nr != 0) { - if (nr > 0) - fprintf(stderr, - "arr_tagged_elem[%s][neg%d]: built ok, " - "expected a loud error (rule-7)\n", - drivers[d].name, i); - else - fprintf(stderr, - "arr_tagged_elem[%s][neg%d]: fixture infrastructure failed\n", - drivers[d].name, i); - fail++; - } - } - } - - if (access(wdrv, X_OK) == 0) { - for (int i = 0; i < n; i++) { - total++; - if (asm_byte_identical(bin, &rows[i], i) != 0) - fail++; - } - } - - if (fail) { - fprintf(stderr, - "arr_tagged_elem: %d/%d fixtures failed\n", fail, total); - return 1; - } - printf("arr_tagged_elem: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/686_slice_str_global_zero.c b/test/wcc/686_slice_str_global_zero.c deleted file mode 100644 index 2964c122..00000000 --- a/test/wcc/686_slice_str_global_zero.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * 686_slice_str_global_zero — a bare module-level `str` global and a - * bare `[]u8` slice global emit their 24-byte zero header EXACTLY ONCE, - * and cstage / wwstage agree byte-for-byte (task #10 part b). - * - * The bug (wwstage only): post-#1, size(str) == size(slice) == 24. The - * emitletdataw str arm and slice arm were sequential `if`s gated on - * SIZE alone, so both matched a 24-byte bare global and BOTH fired the - * no-rhs zero fallback — two `DATAW main.g` rows. cstage discriminates - * on type kind (let_isstr / let_isslice) and emits one. Runtime reads - * the null header {0,0,0} correctly either way, so the divergence is - * byte-id-visible only — the asm_byte_identical gate is the real - * discriminator; the exit-code rows assert correctness is preserved. - * - * The fix: emitletdataw's str and slice arms now branch on the declared - * type kind (letdeclkind, TY_NAMED-peeled, mirroring let_isstr/ - * let_isslice), mutually exclusive, so a 24B global hits one arm. - * - * row | shape | want - * -----------------+----------------------------------------+------ - * slice_len | global let g:[]u8; g.len | 0 - * slice_cap | global let g:[]u8; g.cap | 0 - * slice_ptr_null | global let g:[]u8; g.ptr==nil ? 7 : 0 | 7 - * str_len | global let s:str; s.len | 0 - * str_ptr_null | global let s:str; s.ptr==nil ? 9 : 0 | 9 - */ -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want; }; - -static const struct row rows[] = { - { "slice_len", - "package main;\n" - "let g: []u8;\n" - "export fn main() i32 = { return g.len: i32; };\n", - 0 }, - - { "slice_cap", - "package main;\n" - "let g: []u8;\n" - "export fn main() i32 = { return g.cap: i32; };\n", - 0 }, - - { "slice_ptr_null", - "package main;\n" - "let g: []u8;\n" - "export fn main() i32 = {\n" - "\tif (g.ptr == nil) { return 7; };\n" - "\treturn 0;\n" - "};\n", - 7 }, - - { "str_len", - "package main;\n" - "let s: str;\n" - "export fn main() i32 = { return s.len: i32; };\n", - 0 }, - - { "str_ptr_null", - "package main;\n" - "let s: str;\n" - "export fn main() i32 = {\n" - "\tif (s.ptr == nil) { return 9; };\n" - "\treturn 0;\n" - "};\n", - 9 }, -}; - -static int -run_driver(const char *driver, const struct row *r, int i) -{ - char src[128], tmpdir[64], outbin[128], scratch[160], rmcmd[192], cmd[1024]; - int result = -1, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/ssgz_%d_d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(src, sizeof src, "%s/ssgz_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/ssgz_%d_%d", tmpdir, getpid(), i); - snprintf(scratch, sizeof scratch, "%s.sepwork", outbin); - - FILE *f = fopen(src, "wb"); - if (!f) goto cleanup; - int writefail = fputs(r->src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) goto cleanup; - - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null", - driver, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: build via %s failed\n", - r->label, driver); - goto cleanup; - } - result = runwait(outbin); -cleanup: - snprintf(rmcmd, sizeof rmcmd, "rm -rf -- %s", scratch); - if (runwait(rmcmd) != 0) cleanfail = 1; - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: temporary cleanup failed\n", r->label); - if (result == r->want) return -1; - } - return result; -} - -/* asm_byte_identical — w6c vs w6c_ww .s for the same source must match. - * This is the #10-part-b discriminator: the old size-keyed double-emit - * produced a second DATAW row in the wwstage .s. */ -static int -asm_byte_identical(const char *bin, const struct row *r, int i) -{ - char tmpdir[64], src[96], cs[96], ws[96], cmd[1024]; - int rc = -1, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/ssgz_asm_%d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(src, sizeof src, "%s/t.ww", tmpdir); - snprintf(cs, sizeof cs, "%s/c.s", tmpdir); - snprintf(ws, sizeof ws, "%s/w.s", tmpdir); - - FILE *f = fopen(src, "wb"); - if (!f) goto cleanup; - int writefail = fputs(r->src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) goto cleanup; - - snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c errored\n", r->label); - goto cleanup; - } - snprintf(cmd, sizeof cmd, "%s/w6c_ww -o %s %s 2>/dev/null", - bin, ws, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww errored\n", r->label); - goto cleanup; - } - - FILE *fc = fopen(cs, "rb"); - FILE *fw = fopen(ws, "rb"); - rc = 0; - if (!fc || !fw) { - rc = -1; - } else { - for (;;) { - int a = fgetc(fc); - int b = fgetc(fw); - if (a != b) { rc = -1; break; } - if (a == EOF) break; - } - } - if (fc) fclose(fc); - if (fw) fclose(fw); - if (rc != 0) - fprintf(stderr, "row[%s]: cstage vs wwstage asm differs\n", - r->label); -cleanup: - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(cs) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(ws) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: temporary cleanup failed\n", r->label); - return -1; - } - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - char wdrv[1024]; - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - - struct { const char *name; const char *path; int gated_on_existence; } - drivers[] = { - { "cstage", cdrv, 0 }, - { "wwstage", wdrv, 1 }, - { NULL, NULL, 0 }, - }; - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - - for (int d = 0; drivers[d].name; d++) { - if (drivers[d].gated_on_existence - && access(drivers[d].path, X_OK) != 0) { - fprintf(stderr, "slice_str_global_zero: skip %s (no %s)\n", - drivers[d].name, drivers[d].path); - continue; - } - for (int i = 0; i < n; i++) { - int got = run_driver(drivers[d].path, &rows[i], i); - total++; - if (got != rows[i].want) { - fprintf(stderr, - "slice_str_global_zero[%s][%s]: exit=%d want=%d\n", - drivers[d].name, rows[i].label, - got, rows[i].want); - fail++; - } - } - } - - if (access(wdrv, X_OK) == 0) { - for (int i = 0; i < n; i++) { - total++; - if (asm_byte_identical(bin, &rows[i], i) != 0) - fail++; - } - } - - if (fail) { - fprintf(stderr, - "slice_str_global_zero: %d/%d fixtures failed\n", - fail, total); - return 1; - } - printf("slice_str_global_zero: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/687_slice_literal_global.c b/test/wcc/687_slice_literal_global.c deleted file mode 100644 index a09ad9cb..00000000 --- a/test/wcc/687_slice_literal_global.c +++ /dev/null @@ -1,416 +0,0 @@ -/* - * 687_slice_literal_global — module-level slice-literal static init - * `let g: []T = [v0, v1, …];` materializes a writable backing + a 24B - * { ptr, len, cap } header + a DATAR patching ptr -> backing, and cstage - * / wwstage agree byte-for-byte and at runtime (task #10 part a). - * - * The bug: emit_lets / emitletdataw had str-lit + array-lit arms but no - * slice-lit arm, so a `let g: []u8 = [1u8,2u8,3u8]` emitted NO `DATAW - * main.g` — BOTH stages failed to link ("undefined reference to main.g"). - * byte-id-blind; only the link step exposed it. (wwstage further needed - * #18: its checker desugared the module-level initializer to an N_SLICE - * runtime borrow, so the rhs reached cgen as N_SLICE not N_ARRLIT — fixed - * first so this arm sees the raw array literal, mirroring cstage.) - * - * The fix (BOTH stages, byte-identical): emit_slice_data / emitslicedata - * route the k element bytes through the emit_array_lit_bytes choke-point - * (synthesized [k]T), then emit the header (ptr placeholder + LE len + LE - * cap, all = k) and the ptr-patch DATAR. Backing symbol ".d". - * - * Coverage: []u8 (element read-back + len + cap + sum), []i64 (wider - * element), []i32, and a 1-element edge. Plus dual-stage asm byte-id. - * Mutation-sanity: the old no-emit fails every row at LINK. Plus negative - * rows where the slice-literal static init must FAIL the build loudly - * (rule 7): read-only `def`, `...` repeat, and slice-of-str (per-element - * relocs / #17 deferred). - * - * row | shape | want - * ----------------+------------------------------------------+------ - * u8_e0 | let g:[]u8=[1,2,3]; g[0] | 1 - * u8_e2 | g[2] | 3 - * u8_len | g.len | 3 - * u8_cap | g.cap | 3 - * u8_sum | g[0]+g[1]+g[2]+g.len+g.cap | 12 - * i64_e1 | let g:[]i64=[10,20,30]; g[1] | 20 - * i64_lencap | g.len+g.cap | 6 - * i32_sum | let g:[]i32=[7,8,9]; g[0]+g[1]+g[2] | 24 - * one_edge | let g:[]u8=[42]; g[0]+g.len | 43 - * struct_pt | []pt=[pt{1,2},pt{3,4}]; sum+len+cap | 14 - * struct_3f | []q (u8,i64,i32) two elems; sum+len | 23 - * struct_one | []pt=[pt{5,6}]; sum+len+cap (count==1) | 13 - * struct_arrvar_l | local let arr:[2]pt; let g:[]pt=arr | 14 - * - * #19: wwstage's checker over-rejected the inline NAMED-STRUCT-element - * array->slice (`let g:[]pt=[pt{..},pt{..}]`) — its N_ARRLIT element-type - * inference returned the N_STRUCTLIT body (N_TSTRUCT, per #66) and the - * array->slice isassignable typeeqast saw a TNAME-vs-TSTRUCT kind mismatch - * against the declared N_TNAME element. cstage already inferred the NAMED - * type. Fix: infer the named type for a named struct-literal first element - * (check.ww N_ARRLIT arm); typeeqast untouched. - */ -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want; }; - -static const struct row rows[] = { - { "u8_e0", - "package main;\n" - "let g: []u8 = [1u8, 2u8, 3u8];\n" - "export fn main() i32 = { return g[0]: i32; };\n", - 1 }, - { "u8_e2", - "package main;\n" - "let g: []u8 = [1u8, 2u8, 3u8];\n" - "export fn main() i32 = { return g[2]: i32; };\n", - 3 }, - { "u8_len", - "package main;\n" - "let g: []u8 = [1u8, 2u8, 3u8];\n" - "export fn main() i32 = { return g.len: i32; };\n", - 3 }, - { "u8_cap", - "package main;\n" - "let g: []u8 = [1u8, 2u8, 3u8];\n" - "export fn main() i32 = { return g.cap: i32; };\n", - 3 }, - { "u8_sum", - "package main;\n" - "let g: []u8 = [1u8, 2u8, 3u8];\n" - "export fn main() i32 = {\n" - "\treturn (g[0]:i32)+(g[1]:i32)+(g[2]:i32)+(g.len:i32)+(g.cap:i32);\n" - "};\n", - 12 }, - { "i64_e1", - "package main;\n" - "let g: []i64 = [10i64, 20i64, 30i64];\n" - "export fn main() i32 = { return g[1]: i32; };\n", - 20 }, - { "i64_lencap", - "package main;\n" - "let g: []i64 = [10i64, 20i64, 30i64];\n" - "export fn main() i32 = { return (g.len:i32)+(g.cap:i32); };\n", - 6 }, - { "i32_sum", - "package main;\n" - "let g: []i32 = [7i32, 8i32, 9i32];\n" - "export fn main() i32 = { return (g[0]:i32)+(g[1]:i32)+(g[2]:i32); };\n", - 24 }, - { "one_edge", - "package main;\n" - "let g: []u8 = [42u8];\n" - "export fn main() i32 = { return (g[0]:i32)+(g.len:i32); };\n", - 43 }, - /* aliased slice type: `type S = []u8` IS a slice — both stages must - * route through emit_slice_data. cstage resolves it via type_unwrap; - * wwstage letvarisslice resolves the alias chain (#10). */ - { "alias_slice", - "package main;\n" - "type S = []u8;\n" - "let g: S = [1u8, 2u8, 3u8];\n" - "export fn main() i32 = { return (g[0]:i32)+(g.len:i32)+(g.cap:i32); };\n", - 7 }, - /* #19: inline NAMED-STRUCT-element array->slice. wwstage's checker - * over-rejected this — the N_ARRLIT element-type inference picked up - * the N_STRUCTLIT's body (N_TSTRUCT, per #66) and the array->slice - * isassignable typeeqast saw a TNAME-vs-TSTRUCT kind mismatch (the - * declared element is N_TNAME). Fix infers the NAMED element. cstage - * already accepted; emit_array_lit_bytes' struct-field recursion - * makes the backing byte-identical. */ - { "struct_pt", - "package main;\n" - "type pt = struct { a: i64, b: i64 };\n" - "let g: []pt = [pt{a=1i64, b=2i64}, pt{a=3i64, b=4i64}];\n" - "export fn main() i32 = {\n" - "\treturn (g[0].a:i32)+(g[0].b:i32)+(g[1].a:i32)+(g[1].b:i32)+(g.len:i32)+(g.cap:i32);\n" - "};\n", - 14 }, - /* 3-field mixed-width struct stresses field offsets in the backing - * (u8 @0, i64 @8, i32 @16 — non-uniform strides). */ - { "struct_3f", - "package main;\n" - "type q = struct { a: u8, b: i64, c: i32 };\n" - "let g: []q = [q{a=1u8, b=2i64, c=3i32}, q{a=4u8, b=5i64, c=6i32}];\n" - "export fn main() i32 = {\n" - "\treturn (g[0].a:i32)+(g[0].b:i32)+(g[0].c:i32)+(g[1].a:i32)+(g[1].b:i32)+(g[1].c:i32)+(g.len:i32);\n" - "};\n", - 23 }, - /* single-element []struct (count==1 backing edge). */ - { "struct_one", - "package main;\n" - "type pt = struct { a: i64, b: i64 };\n" - "let g: []pt = [pt{a=5i64, b=6i64}];\n" - "export fn main() i32 = {\n" - "\treturn (g[0].a:i32)+(g[0].b:i32)+(g.len:i32)+(g.cap:i32);\n" - "};\n", - 13 }, - /* regression: the array-VARIABLE form already accepted (arr carries a - * clean N_TNAME). Local scope, since the MODULE-scope variable form is - * the still-deferred #22 (no backing symbol -> link fail on BOTH - * stages). */ - { "struct_arrvar_local", - "package main;\n" - "type pt = struct { a: i64, b: i64 };\n" - "export fn main() i32 = {\n" - "\tlet arr: [2]pt = [pt{a=1i64, b=2i64}, pt{a=3i64, b=4i64}];\n" - "\tlet g: []pt = arr;\n" - "\treturn (g[0].a:i32)+(g[0].b:i32)+(g[1].a:i32)+(g[1].b:i32)+(g.len:i32)+(g.cap:i32);\n" - "};\n", - 14 }, -}; - -/* slice-literal static init that must FAIL the build loudly (rule 7). */ -static const char *neg[] = { - /* read-only `def` can't carry the ptr reloc (DATAR holder must be - * DATAW, w6a asm.c:362). */ - "package main;\n" - "def g: []u8 = [1u8, 2u8, 3u8];\n" - "export fn main() i32 = { return g.len: i32; };\n", - /* `...` repeat has no target length in a slice literal. Uses the - * reachable repeat spelling `[v...]` (no comma) so the cgen loud-stop - * is exercised — the comma form `[v, ...]` parse-errors first and - * would test the parser, not the emit_slice_data guard. */ - "package main;\n" - "let g: []u8 = [1u8, 2u8...];\n" - "export fn main() i32 = { return g.len: i32; };\n", - /* slice-of-str needs per-element relocs (#17) — deferred loud-stop. */ - "package main;\n" - "let g: []str = [\"a\", \"b\"];\n" - "export fn main() i32 = { return g.len: i32; };\n", -}; - -static int -run_driver(const char *driver, const struct row *r, int i) -{ - char tmpdir[64], src[128], outbin[128], scratch[160], rmcmd[192], cmd[1024]; - int result = -1, setupfail = 0, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/slg_%d_d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(src, sizeof src, "%s/slg_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/slg_%d_%d", tmpdir, getpid(), i); - snprintf(scratch, sizeof scratch, "%s.sepwork", outbin); - - FILE *f = fopen(src, "wb"); - if (!f) { setupfail = 1; goto cleanup; } - int writefail = fputs(r->src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) { setupfail = 1; goto cleanup; } - - /* Ordinary build retains caller-owned .sepwork scratch beside -o. */ - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null", - driver, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: build via %s failed\n", - r->label, driver); - goto cleanup; - } - result = runwait(outbin); -cleanup: - if (setupfail) - fprintf(stderr, "row[%s]: temporary setup failed\n", r->label); - snprintf(rmcmd, sizeof rmcmd, "rm -rf -- %s", scratch); - if (runwait(rmcmd) != 0) cleanfail = 1; - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: temporary cleanup failed\n", r->label); - if (result == r->want) return -1; - } - return result; -} - -/* build_should_fail — 0 on the expected rejection, positive on an - * unexpected successful build, negative on fixture infrastructure failure. */ -static int -build_should_fail(const char *driver, const char *src, int i) -{ - char tmpdir[64], s[128], outbin[128], scratch[160], rmcmd[192], cmd[1024]; - int result = -1, setupfail = 0, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/slgn_%d_d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(s, sizeof s, "%s/slgn_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/slgn_%d_%d", tmpdir, getpid(), i); - snprintf(scratch, sizeof scratch, "%s.sepwork", outbin); - - FILE *f = fopen(s, "wb"); - if (!f) { setupfail = 1; goto cleanup; } - int writefail = fputs(src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) { setupfail = 1; goto cleanup; } - - /* A rejected ordinary build can also leave caller-owned .sepwork. */ - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null", - driver, outbin, s); - int rc = runwait(cmd); - result = rc == 0 ? 1 : 0; /* build must NOT succeed */ -cleanup: - if (setupfail) - fprintf(stderr, "slice_literal_global[neg%d]: temporary setup failed\n", i); - snprintf(rmcmd, sizeof rmcmd, "rm -rf -- %s", scratch); - if (runwait(rmcmd) != 0) cleanfail = 1; - if (unlink(s) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "slice_literal_global[neg%d]: temporary cleanup failed\n", i); - if (result == 0) return -1; - } - return result; -} - -/* asm_byte_identical — w6c vs w6c_ww .s for the same source must match. */ -static int -asm_byte_identical(const char *bin, const struct row *r, int i) -{ - char tmpdir[64], src[96], cs[96], ws[96], cmd[1024]; - int rc = -1, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/slg_asm_%d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(src, sizeof src, "%s/t.ww", tmpdir); - snprintf(cs, sizeof cs, "%s/c.s", tmpdir); - snprintf(ws, sizeof ws, "%s/w.s", tmpdir); - - FILE *f = fopen(src, "wb"); - if (!f) goto cleanup; - int writefail = fputs(r->src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) goto cleanup; - - snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c errored\n", r->label); - goto cleanup; - } - snprintf(cmd, sizeof cmd, "%s/w6c_ww -o %s %s 2>/dev/null", - bin, ws, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww errored\n", r->label); - goto cleanup; - } - - FILE *fc = fopen(cs, "rb"); - FILE *fw = fopen(ws, "rb"); - rc = 0; - if (!fc || !fw) { - rc = -1; - } else { - for (;;) { - int a = fgetc(fc); - int b = fgetc(fw); - if (a != b) { rc = -1; break; } - if (a == EOF) break; - } - } - if (fc) fclose(fc); - if (fw) fclose(fw); - if (rc != 0) - fprintf(stderr, "row[%s]: cstage vs wwstage asm differs\n", - r->label); -cleanup: - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(cs) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(ws) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: temporary cleanup failed\n", r->label); - return -1; - } - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - char wdrv[1024]; - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - - struct { const char *name; const char *path; int gated_on_existence; } - drivers[] = { - { "cstage", cdrv, 0 }, - { "wwstage", wdrv, 1 }, - { NULL, NULL, 0 }, - }; - - int n = (int)(sizeof rows / sizeof rows[0]); - int nn = (int)(sizeof neg / sizeof neg[0]); - int total = 0, fail = 0; - - for (int d = 0; drivers[d].name; d++) { - if (drivers[d].gated_on_existence - && access(drivers[d].path, X_OK) != 0) { - fprintf(stderr, "slice_literal_global: skip %s (no %s)\n", - drivers[d].name, drivers[d].path); - continue; - } - for (int i = 0; i < n; i++) { - int got = run_driver(drivers[d].path, &rows[i], i); - total++; - if (got != rows[i].want) { - fprintf(stderr, - "slice_literal_global[%s][%s]: exit=%d want=%d\n", - drivers[d].name, rows[i].label, - got, rows[i].want); - fail++; - } - } - for (int i = 0; i < nn; i++) { - total++; - int nr = build_should_fail(drivers[d].path, neg[i], 100 + i); - if (nr != 0) { - if (nr > 0) - fprintf(stderr, - "slice_literal_global[%s][neg%d]: built ok, " - "expected a loud error\n", - drivers[d].name, i); - else - fprintf(stderr, - "slice_literal_global[%s][neg%d]: fixture infrastructure failed\n", - drivers[d].name, i); - fail++; - } - } - } - - if (access(wdrv, X_OK) == 0) { - for (int i = 0; i < n; i++) { - total++; - if (asm_byte_identical(bin, &rows[i], i) != 0) - fail++; - } - } - - if (fail) { - fprintf(stderr, - "slice_literal_global: %d/%d fixtures failed\n", - fail, total); - return 1; - } - printf("slice_literal_global: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/688_global_arr_elem_field.c b/test/wcc/688_global_arr_elem_field.c deleted file mode 100644 index 350d8f36..00000000 --- a/test/wcc/688_global_arr_elem_field.c +++ /dev/null @@ -1,298 +0,0 @@ -/* - * 688_global_arr_elem_field — a module-GLOBAL indexed struct-element - * `.field` READ (`g[i].field`, g at module scope) lowers the field - * offset, not just the element stride. The READ twin of #11 (which - * fixed the global `g[i] = v` WRITE) and the #15 sibling. - * - * Pre-fix (#21): the `arr[i].field` N_DOT branch in both stages was - * gated on a LOCAL lookup (cstage localfind != 0, wwstage - * localfindnode != nil). A module-global base missed it and fell - * through — cstage to a generic index-load that drops f->offset - * (reads element[i] at offset 0, so g[0].b returned a's value), and - * wwstage to the module-qualified fallback (garbage — no g load). - * Byte-id-divergent silent miscompile. - * - * The fix (BOTH stages, converged byte-identical): resolve the global - * the same way the N_INDEX arm does (cstage let_islet || def_isarraydef; - * wwstage letvartnode || defvartnode) and dispatch the base load by - * shape — array -> LEAQ name(SB) (the symbol IS the storage), - * slice/ptr -> MOVQ name(SB) (the symbol's first word IS the .ptr) — - * then load the field at f->offset, exactly as the local arm does. - * esz = element stride and f->offset both come from the type table. - * - * Coverage: - * arr_a0/a1 | [2]pt struct array, g[0].a / g[1].a — control, - * | offset 0. RUNTIME + byte-id. - * arr_b0/b1 | [2]pt, g[0].b / g[1].b — THE bug (offset 8, the - * | reads that returned a's value pre-fix). RUNTIME. - * rec_* | [2]rec { tag:u8, x:i32, y:i64 } — non-8-aligned - * | fields (x@4, y@8) + a u8 sub-word leaf, to stress - * | f->offset and the load-width path. RUNTIME. - * slice_x1 | [2]rec backing + `let g: []rec = arr;`, g[1].x - * | read. Exercises the slice-base MOVQ-deref arm - * | (MOVQ g(SB),BX loads .ptr) — the asm is byte-id and - * | correct, but a slice-of-struct module global does - * | not data-emit a symbol yet (a separate, pre-existing - * | data-emission gap, sibling of #10/#20), so it cannot - * | LINK/run. Asserted byte-id ONLY; filed separately. - * - * Why this was never caught: 680/681 cover only LOCAL `[N]struct` - * bases (BP-relative). The global base routes through name(SB) and was - * a distinct, untested arm. - * - * Cstage and wwstage each on every runtime fixture; wwstage gated on - * access(X_OK). All fixtures additionally asm-byte-id checked. - */ -#include -#include -#include -#include -#include -#include -#include "wwtestpkg.h" - -/* want == BYTEID_ONLY: the row cannot LINK/run (a slice-of-struct - * module global does not data-emit yet — separate gap), so only the - * cstage/wwstage asm-byte-id is asserted, never an exit value. */ -#define BYTEID_ONLY (-2147483647 - 1) - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want; }; - -static const struct row rows[] = { - /* [2]pt, .a field at offset 0 — control. */ - { "arr_a0", - "type pt = struct { a: i64, b: i64 };\n" - "let g: [2]pt = [pt { a = 1, b = 2 }, pt { a = 3, b = 4 }];\n" - "export fn main() i32 = { return g[0].a: i32; };\n", - 1 }, - { "arr_a1", - "type pt = struct { a: i64, b: i64 };\n" - "let g: [2]pt = [pt { a = 1, b = 2 }, pt { a = 3, b = 4 }];\n" - "export fn main() i32 = { return g[1].a: i32; };\n", - 3 }, - /* [2]pt, .b at offset 8 — THE bug: pre-fix g[i].b returned a's - * value (cstage) or garbage (wwstage). */ - { "arr_b0", - "type pt = struct { a: i64, b: i64 };\n" - "let g: [2]pt = [pt { a = 1, b = 2 }, pt { a = 3, b = 4 }];\n" - "export fn main() i32 = { return g[0].b: i32; };\n", - 2 }, - { "arr_b1", - "type pt = struct { a: i64, b: i64 };\n" - "let g: [2]pt = [pt { a = 1, b = 2 }, pt { a = 3, b = 4 }];\n" - "export fn main() i32 = { return g[1].b: i32; };\n", - 4 }, - /* [2]rec, non-8-aligned i32 field (x@4) on the second element — - * stresses f->offset combined with the element stride. */ - { "rec_x1", - "type rec = struct { tag: u8, x: i32, y: i64 };\n" - "let g: [2]rec = [rec { tag = 1u8, x = 100, y = 11 }," - " rec { tag = 2u8, x = 200, y = 22 }];\n" - "export fn main() i32 = { return g[1].x: i32; };\n", - 200 }, - /* [2]rec, i64 field (y@8) on the second element. */ - { "rec_y1", - "type rec = struct { tag: u8, x: i32, y: i64 };\n" - "let g: [2]rec = [rec { tag = 1u8, x = 100, y = 11 }," - " rec { tag = 2u8, x = 200, y = 22 }];\n" - "export fn main() i32 = { return g[1].y: i32; };\n", - 22 }, - /* [2]rec, u8 leaf (tag@0) — sub-word zero-extend load on a - * global element base. */ - { "rec_tag1", - "type rec = struct { tag: u8, x: i32, y: i64 };\n" - "let g: [2]rec = [rec { tag = 1u8, x = 100, y = 11 }," - " rec { tag = 2u8, x = 200, y = 22 }];\n" - "export fn main() i32 = { return g[1].tag: i32; };\n", - 2 }, - /* slice-base MOVQ-deref arm: `let g: []rec = arr;`, g[1].b read. - * Byte-id only — a slice-of-struct module global does not - * data-emit yet (separate gap), so it cannot link/run. The .s - * holds MOVQ g(SB),BX (the .ptr load) + the correct f->offset on - * both stages. */ - { "slice_x1", - "type rec = struct { tag: u8, x: i32, y: i64 };\n" - "let arr: [2]rec = [rec { tag = 1u8, x = 100, y = 11 }," - " rec { tag = 2u8, x = 200, y = 22 }];\n" - "let g: []rec = arr;\n" - "export fn main() i32 = { return g[1].x: i32; };\n", - BYTEID_ONLY }, -}; - -static int -run_driver(const char *driver, const struct row *r, int i) -{ - char tmpdir[64], src[128], outbin[128], scratch[160], rmcmd[192], cmd[1024]; - int result = -1, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/gae_%d_d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(src, sizeof src, "%s/gae_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/gae_%d_%d", tmpdir, getpid(), i); - snprintf(scratch, sizeof scratch, "%s.sepwork", outbin); - - FILE *f = fopen(src, "wb"); - if (!f) goto cleanup; - wwtest_fputs(r->src, f); - int writefail = ferror(f); - if (fclose(f) != 0) writefail = 1; - if (writefail) goto cleanup; - - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null", - driver, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: build via %s failed\n", - r->label, driver); - goto cleanup; - } - result = runwait(outbin); -cleanup: - snprintf(rmcmd, sizeof rmcmd, "rm -rf -- %s", scratch); - if (runwait(rmcmd) != 0) cleanfail = 1; - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: temporary cleanup failed\n", r->label); - if (result == r->want) return -1; - } - return result; -} - -/* asm_byte_identical — generate .s via cstage's w6c and wwstage's - * w6c_ww and diff. Pins rule-10 convergence: pre-fix the global-base - * read diverged (cstage dropped f->offset, wwstage emitted no g load). */ -static int -asm_byte_identical(const char *bin, const struct row *r, int i) -{ - char tmpdir[64], src[96], cs[96], ws[96], cmd[1024]; - int rc = -1, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/gae_asm_%d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(src, sizeof src, "%s/t.ww", tmpdir); - snprintf(cs, sizeof cs, "%s/c.s", tmpdir); - snprintf(ws, sizeof ws, "%s/w.s", tmpdir); - - FILE *f = fopen(src, "wb"); - if (!f) goto cleanup; - wwtest_fputs(r->src, f); - int writefail = ferror(f); - if (fclose(f) != 0) writefail = 1; - if (writefail) goto cleanup; - - snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c errored\n", r->label); - goto cleanup; - } - snprintf(cmd, sizeof cmd, "%s/w6c_ww -o %s %s 2>/dev/null", - bin, ws, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww errored\n", r->label); - goto cleanup; - } - - FILE *fc = fopen(cs, "rb"); - FILE *fw = fopen(ws, "rb"); - rc = 0; - if (!fc || !fw) { - rc = -1; - } else { - for (;;) { - int a = fgetc(fc); - int b = fgetc(fw); - if (a != b) { rc = -1; break; } - if (a == EOF) break; - } - } - if (fc) fclose(fc); - if (fw) fclose(fw); - if (rc != 0) - fprintf(stderr, "row[%s]: cstage vs wwstage asm differs\n", - r->label); -cleanup: - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(cs) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(ws) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: temporary cleanup failed\n", r->label); - return -1; - } - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - char wdrv[1024]; - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - - struct { const char *name; const char *path; int gated_on_existence; } - drivers[] = { - { "cstage", cdrv, 0 }, - { "wwstage", wdrv, 1 }, - { NULL, NULL, 0 }, - }; - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - - for (int d = 0; drivers[d].name; d++) { - if (drivers[d].gated_on_existence - && access(drivers[d].path, X_OK) != 0) { - fprintf(stderr, "global_arr_elem_field: skip %s (no %s)\n", - drivers[d].name, drivers[d].path); - continue; - } - for (int i = 0; i < n; i++) { - if (rows[i].want == BYTEID_ONLY) - continue; /* byte-id only below */ - int got = run_driver(drivers[d].path, &rows[i], i); - total++; - if (got != rows[i].want) { - fprintf(stderr, - "global_arr_elem_field[%s][%s]: exit=%d want=%d\n", - drivers[d].name, rows[i].label, - got, rows[i].want); - fail++; - } - } - } - - if (access(wdrv, X_OK) == 0) { - for (int i = 0; i < n; i++) { - total++; - if (asm_byte_identical(bin, &rows[i], i) != 0) - fail++; - } - } - - if (fail) { - fprintf(stderr, - "global_arr_elem_field: %d/%d fixtures failed\n", fail, total); - return 1; - } - printf("global_arr_elem_field: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/689_globptr_field_read_run.c b/test/wcc/689_globptr_field_read_run.c deleted file mode 100644 index 9886db6a..00000000 --- a/test/wcc/689_globptr_field_read_run.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * 689_globptr_field_read_run (#15) — reading a field through a module- - * GLOBAL `*struct` pointer base (`gp.f`, single-dot) loads correctly AND - * cstage / wwstage agree byte-for-byte. - * - * THE BUG (both stages, two different wrong ways — no byte-id oracle until - * one side was fixed, but they DID diverge): a global `*struct` ptr base - * carries via_ptr=1 but has NO local slot (localfind/localfindnode = 0), - * so the pointer-to-struct field-READ arm never loaded the pointer VALUE - * from the global's data slot before applying the field offset: - * cstage : `MOVQ (BP),BX; MOVQ 8(BX),AX` — derefed the saved BP → SEGV. - * wwstage: `MOVQ f(SB),AX` — collapsed gp.f to a bare - * undefined symbol `f`. - * Read twin of the #6 STORE fix (689_globptr_field_store_run). - * - * THE FIX (both stages converge): load the pointer value via SB first — - * `MOVQ gp(SB),BX; MOVQ off(BX),AX` - * cstage: base load is now `off==0 && let_islet → MOVQ mafn(gp)(SB),BX`. - * wwstage: a dedicated global-ptr arm (lc==nil + isletvar + N_TPTR) emits - * `MOVQ name(SB),BX` and shares the field tail (cgptrfieldload). - * - * shape | want - * -------------------------------+------ - * gp.f (scalar, offset 8) | 170 - * gp.f+gp.g (scalar, offset 0/8) | 14 - * let x=gp.sf; x.len (str field) | 3 - * gp.d : i32 (f64 field) | 7 - * match gp.t (tagged field, 16B) | 5 - * gp.len (*[]u8 pseudo-field) | 3 - * lp.f (LOCAL ptr control) | 42 - * bump param p.f (param control) | 10 - * gp.sf.len (CHAINED str leaf) | 3 (#16) - * gp.x.q (CHAINED struct leaf)| 7 (#16) - * gp.x.q i64 sink, (v>>32) | 1 (#18 spine-narrow PIN) - * Each row also asserts w6c .s == w6c_ww .s byte-identical. - * Pre-fix: cstage SEGV(139) on every global-ptr row; wwstage ran wrong; - * cs vs ww .s differed. - * - * #16 (chained-through-global-ptr-root, the last two rows): after #15 - * both stages RAN correct but byte-DIVERGED on the chained-N_DOT spine — - * cstage offset-folds (LEAQ name(SB),CX; MOVQ (CX),CX; MOVQ (CX)) - * while wwstage's chained spine bailed (dotchainresolve missed a global - * `*struct` root) onto the naive inner-load-and-shuffle catch-all. Fix - * aligns wwstage UP: dotchainresolve resolves a global `*struct` root as - * isglobal && ptrroot and the spine emits the same offset-fold (rule 10). - */ -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { - const char *name; - const char *src; - int want; -}; - -static const struct row ROWS[] = { -{ "scalar_off8", - "package main;\n" - "type S = struct { a: i64, f: i64 };\n" - "let gp: *S = nil;\n" - "export fn main() i32 = { let s: S = S{a=0,f=0}; gp = &s;" - " s.f = 170; return gp.f: i32; };\n", 170 }, -{ "scalar_off0_off8", - "package main;\n" - "type S = struct { f: i64, g: i64 };\n" - "let gp: *S = nil;\n" - "export fn main() i32 = { let s: S = S{f=0,g=0}; gp = &s;" - " s.f = 5; s.g = 9; return (gp.f + gp.g): i32; };\n", 14 }, -{ "str_field", - "package main;\n" - "type S = struct { a: i64, sf: str };\n" - "let gp: *S = nil;\n" - "export fn main() i32 = { let s: S = S{a=0,sf=\"abc\"}; gp = &s;" - " let x: str = gp.sf; return x.len: i32; };\n", 3 }, -{ "float_field", - "package main;\n" - "type S = struct { a: i64, d: f64 };\n" - "let gp: *S = nil;\n" - "export fn main() i32 = { let s: S = S{a=0,d=0.0}; gp = &s;" - " s.d = 7.0; return (gp.d): i32; };\n", 7 }, -{ "tagged_field", - "package main;\n" - "type S = struct { a: i64, t: (i64 | i32) };\n" - "let gp: *S = nil;\n" - "export fn main() i32 = { let s: S = S{a=0,t=5i32}; gp = &s;" - " let v: i32 = 0; match (gp.t) { case let x: i32 => v = x;" - " case let y: i64 => v = y: i32; }; return v; };\n", 5 }, -{ "tagged_slice_field", - /* #17: a 32B slice-payload tagged field (8B tag + 24B slice = - * full 4-reg cursor) read via global *struct ptr. cgloadtaggedfield - * fills AX/DX/CX/R8; wwstage loaded R8@+24 before CX@+16 while - * cstage's direct *struct-ptr arm loads them in offset order, so the - * .s byte-diverged (both ran correct). The 16B tagged_field row above - * is too small to fire the R8/CX split. */ - "package main;\n" - "type S = struct { a: i64, t: (i64 | []u8) };\n" - "let gp: *S = nil;\n" - "export fn main() i32 = { let s: S = S{a=0,t=3i64}; gp = &s;" - " let v: i32 = 0; match (gp.t) { case let x: i64 => v = x: i32;" - " case let y: []u8 => v = len(y): i32; }; return v; };\n", 3 }, -{ "tagged_slice_field_local", - /* #17 twin: same 32B slice-payload tagged read, but via a LOCAL - * *struct ptr. cgptrfieldload is shared by the local (MOVQ off(BP),BX) - * and global (MOVQ name(SB),BX) direct *struct-ptr arms, so the same - * cxlast=false fix closes both — this row locks the local path against - * a future regression of the R8/CX order. */ - "package main;\n" - "type S = struct { a: i64, t: (i64 | []u8) };\n" - "export fn main() i32 = { let s: S = S{a=0,t=3i64}; let p: *S = &s;" - " let v: i32 = 0; match (p.t) { case let x: i64 => v = x: i32;" - " case let y: []u8 => v = len(y): i32; }; return v; };\n", 3 }, -{ "pslice_len", - "package main;\n" - "let gp: *[]u8 = nil;\n" - "export fn main() i32 = { let b: []u8 = [1u8,2u8,3u8]; gp = &b;" - " return (gp.len): i32; };\n", 3 }, -{ "local_ptr_ctrl", - "package main;\n" - "type S = struct { a: i64, f: i64 };\n" - "export fn main() i32 = { let s: S = S{a=0,f=0}; let lp: *S = &s;" - " s.f = 42; return lp.f: i32; };\n", 42 }, -{ "param_ctrl", - "package main;\n" - "type S = struct { f: i64, g: i64 };\n" - "fn rd(p: *S) i32 = { return (p.f + p.g): i32; };\n" - "export fn main() i32 = { let s: S = S{f=4,g=6}; return rd(&s); };\n", 10 }, -/* #16: CHAINED read through a global-`*struct` root. Pre-fix BOTH stages - * ran correct after #15 but byte-DIVERGED — cstage offset-folds (LEAQ - * name(SB),CX; MOVQ (CX),CX; MOVQ (CX)) while wwstage's chained - * spine bailed (dotchainresolve missed a global `*struct` root) onto the - * naive inner-load-and-shuffle catch-all. */ -{ "chain_str_len", - "package main;\n" - "type S = struct { a: i64, sf: str };\n" - "let gp: *S = nil;\n" - "export fn main() i32 = { let s: S = S{a=0,sf=\"abc\"}; gp = &s;" - " return gp.sf.len: i32; };\n", 3 }, -{ "chain_struct_field", - "package main;\n" - "type Inner = struct { p: i64, q: i64 };\n" - "type S = struct { a: i64, x: Inner };\n" - "let gp: *S = nil;\n" - "export fn main() i32 = { let s: S = S{a=0,x=Inner{p=0,q=0}}; gp = &s;" - " s.x.q = 7; return gp.x.q: i32; };\n", 7 }, -/* #18 PIN: a CHAINED read into an i64 SINK must NOT carry a spurious load/ - * spine narrow. q holds 0x1_0000_0001; we observe the HIGH word via - * (v>>32):i32 — a truncating MOVSXD on the chained load would sign-extend - * the low word (1) and the high word would vanish (1 -> 0). The legitimate - * MOVSXD must stay on the `:i32` RETURN cast only (after a full 64-bit - * SARQ over the complete i64). Verified no-bug at HEAD; this row guards the - * spine-narrow family (cf. fld-load-op / int-cast-no-truncate fixes). */ -{ "chain_i64_sink", - "package main;\n" - "type T = struct { q: i64 };\n" - "type S = struct { x: T };\n" - "let gp: *S = nil;\n" - "export fn main() i32 = { let s: S = S{x=T{q=0}}; gp = &s;" - " s.x.q = 4294967297; let v: i64 = gp.x.q; return (v >> 32): i32; };\n", 1 }, -}; - -#define NROWS ((int)(sizeof ROWS / sizeof ROWS[0])) - -/* build+run one row through `driver`; return exit code or -1. */ -static int -run_driver(const char *driver, const char *src, int idx, int want) -{ - char tmpdir[64], srcf[128], outbin[160], scratch[192], rmcmd[224], cmd[2400]; - int result = -1, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/gpfr_%d_%d_d", getpid(), idx); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(srcf, sizeof srcf, "%s/t.ww", tmpdir); - snprintf(outbin, sizeof outbin, "%s/t", tmpdir); - snprintf(scratch, sizeof scratch, "%s.sepwork", outbin); - - FILE *f = fopen(srcf, "wb"); - if (!f) goto cleanup; - int writefail = fputs(src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) goto cleanup; - - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null", - driver, outbin, srcf); - if (runwait(cmd) != 0) goto cleanup; - result = runwait(outbin); -cleanup: - snprintf(rmcmd, sizeof rmcmd, "rm -rf -- %s", scratch); - if (runwait(rmcmd) != 0) cleanfail = 1; - if (unlink(srcf) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "globptr_field_read[%d]: temporary cleanup failed\n", idx); - if (result == want) return -1; - } - return result; -} - -/* Emit .s for `tool`; the caller owns srcf and asmf. */ -static int -emit_asm(const char *bin, const char *tool, const char *srcf, - const char *asmf) -{ - char cmd[2400]; - snprintf(cmd, sizeof cmd, "%s/%s -o %s %s 2>/dev/null", - bin, tool, asmf, srcf); - int rc = runwait(cmd); - return rc == 0 ? 0 : -1; -} - -static int -files_identical(const char *a, const char *b) -{ - FILE *fa = fopen(a, "rb"), *fb = fopen(b, "rb"); - if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return 0; } - int ca, cb, same = 1; - do { - ca = fgetc(fa); cb = fgetc(fb); - if (ca != cb) { same = 0; break; } - } while (ca != EOF); - fclose(fa); fclose(fb); - return same; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - char cdrv[1024], wdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - int have_ww = (access(wdrv, X_OK) == 0); - - int fail = 0, total = 0; - for (int i = 0; i < NROWS; i++) { - const struct row *r = &ROWS[i]; - - total++; - int gc = run_driver(cdrv, r->src, i, r->want); - if (gc != r->want) { - fprintf(stderr, "globptr_field_read[%s,cstage]: run=%d want=%d\n", - r->name, gc, r->want); - fail++; - } - if (have_ww) { - total++; - int gw = run_driver(wdrv, r->src, i, r->want); - if (gw != r->want) { - fprintf(stderr, "globptr_field_read[%s,wwstage]: run=%d want=%d\n", - r->name, gw, r->want); - fail++; - } - } - - /* byte-id: w6c .s == w6c_ww .s */ - if (have_ww) { - char td[80], srcf[96], csf[96], wwf[96]; - int ec = -1, ew = -1, same = 0, setupfail = 0, cleanfail = 0; - snprintf(td, sizeof td, "/tmp/gpfr_asm_%d_%d", getpid(), i); - snprintf(srcf, sizeof srcf, "%s/t.ww", td); - snprintf(csf, sizeof csf, "%s/c.s", td); - snprintf(wwf, sizeof wwf, "%s/w.s", td); - total++; - if (mkdir(td, 0755) == 0) { - FILE *f = fopen(srcf, "wb"); - if (f) { - int writefail = fputs(r->src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (!writefail) { - ec = emit_asm(bin, "w6c", srcf, csf); - ew = emit_asm(bin, "w6c_ww", srcf, wwf); - same = ec == 0 && ew == 0 - && files_identical(csf, wwf); - } else setupfail = 1; - } else setupfail = 1; - if (unlink(srcf) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(csf) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(wwf) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(td) != 0) cleanfail = 1; - } else setupfail = 1; - if (setupfail) - fprintf(stderr, "globptr_field_read[%s]: temporary setup failed\n", - r->name); - if (!same) { - fprintf(stderr, "globptr_field_read[%s]: cs/ww .s NOT " - "byte-identical (ec=%d ew=%d)\n", r->name, ec, ew); - fail++; - } - if (cleanfail) { - fprintf(stderr, "globptr_field_read[%s]: temporary cleanup failed\n", - r->name); - if (same) fail++; - } - } - } - - if (fail) { - fprintf(stderr, "globptr_field_read_run: %d/%d checks failed\n", - fail, total); - return 1; - } - printf("globptr_field_read_run: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/689_globptr_field_store_run.c b/test/wcc/689_globptr_field_store_run.c deleted file mode 100644 index d6abc174..00000000 --- a/test/wcc/689_globptr_field_store_run.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * 689_globptr_field_store_run (#6) — a module-GLOBAL `*struct` pointer base - * (`gp.f = v` / `gp.f += v` / `gp.x.y = v` / `gp.a[i].f = v`) stores - * correctly AND cstage / wwstage agree byte-for-byte. - * - * THE BUG (cstage only): a global `*struct` ptr base carries via_ptr=1 but - * has no local slot — localfind returns 0, so the enumerated via_ptr field- - * store arms emitted `MOVQ (BP),BX` (deref the saved BP = garbage → SEGV). - * The plain-scalar-`=` STORE half was already correct (the #47/#8 fix, LEAQ - * gp(SB)), so load/store were asymmetric. wwstage routes every case EXCEPT - * plain-scalar-`=` through its F6 cgplaceaddr resolver and was correct. - * - * THE FIX (align cstage UP): decline the global-`*struct`-ptr base at the - * enumerated arm's dispatch for compound + non-scalar (and a chained - * `gp.x.y` root), so cstage falls to its OWN F6 assign-resolver — byte- - * identical to wwstage. Plain-scalar-`=` stays in the enumerated arm (its - * #47 byte-id is undisturbed); a local ptr and a param at offset 0 - * (localfind != 0) also stay local. - * - * shape | want - * ------------------------------+------ - * gp.f += 5 (compound off 8) | 5 - * gp.f += 7 (compound off 0) | 7 - * gp.in = Inner{7,9} (struct) | 16 - * gp.sf = "hi" (str field) | 2 - * gp.x.y=11; gp.x.z+=7 (chain) | 18 - * gp.a[1].f=5; gp.a[1].g+=8 | 13 - * lp.f += 5 (LOCAL ptr ctrl) | 5 - * bump(&s): p.f/p.g (param ctrl)| 10 - * Each row also asserts w6c .s == w6c_ww .s byte-identical. - * Pre-fix: cstage SEGV(139) on every global-ptr row; cs vs ww .s differed. - */ -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { - const char *name; - const char *src; - int want; -}; - -static const struct row ROWS[] = { -{ "compound_off8", - "package main;\n" - "type S = struct { a: i64, f: i64 };\n" - "let gp: *S = nil;\n" - "export fn main() i32 = { let s: S = S{a=0,f=0}; gp = &s;" - " gp.f += 5; return s.f: i32; };\n", 5 }, -{ "compound_off0", - "package main;\n" - "type S = struct { f: i64, g: i64 };\n" - "let gp: *S = nil;\n" - "export fn main() i32 = { let s: S = S{f=0,g=0}; gp = &s;" - " gp.f += 7; return s.f: i32; };\n", 7 }, -{ "struct_field", - "package main;\n" - "type I = struct { x: i64, y: i64 };\n" - "type S = struct { a: i64, in: I };\n" - "let gp: *S = nil;\n" - "export fn main() i32 = { let s: S = S{a=0,in=I{x=0,y=0}}; gp = &s;" - " gp.in = I{x=7,y=9}; return (s.in.x+s.in.y): i32; };\n", 16 }, -{ "str_field", - "package main;\n" - "type S = struct { a: i64, sf: str };\n" - "let gp: *S = nil;\n" - "export fn main() i32 = { let s: S = S{a=0,sf=\"\"}; gp = &s;" - " gp.sf = \"hi\"; return (s.sf.len): i32; };\n", 2 }, -{ "chained", - "package main;\n" - "type I = struct { y: i64, z: i64 };\n" - "type S = struct { a: i64, x: I };\n" - "let gp: *S = nil;\n" - "export fn main() i32 = { let s: S = S{a=0,x=I{y=0,z=0}}; gp = &s;" - " gp.x.y = 11; gp.x.z += 7; return (s.x.y+s.x.z): i32; };\n", 18 }, -{ "indexed", - "package main;\n" - "type E = struct { f: i64, g: i64 };\n" - "type S = struct { n: i64, a: [3]E };\n" - "let gp: *S = nil;\n" - "export fn main() i32 = { let s: S; gp = &s;" - " gp.a[1].f = 5; gp.a[1].g += 8; return (s.a[1].f+s.a[1].g): i32; };\n", 13 }, -{ "local_ptr_ctrl", - "package main;\n" - "type S = struct { a: i64, f: i64 };\n" - "export fn main() i32 = { let s: S = S{a=0,f=0}; let lp: *S = &s;" - " lp.f += 5; return s.f: i32; };\n", 5 }, -{ "param_off0_ctrl", - "package main;\n" - "type S = struct { f: i64, g: i64 };\n" - "fn bump(p: *S) void = { p.f += 3; p.g += 4; };\n" - "export fn main() i32 = { let s: S = S{f=1,g=2}; bump(&s);" - " return (s.f+s.g): i32; };\n", 10 }, -}; - -#define NROWS ((int)(sizeof ROWS / sizeof ROWS[0])) - -/* build+run one row through `driver`; return exit code or -1. */ -static int -run_driver(const char *driver, const char *src, int idx, int want) -{ - char tmpdir[64], srcf[128], outbin[160], scratch[192], rmcmd[224], cmd[2400]; - int result = -1, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/gpfs_%d_%d_d", getpid(), idx); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(srcf, sizeof srcf, "%s/t.ww", tmpdir); - snprintf(outbin, sizeof outbin, "%s/t", tmpdir); - snprintf(scratch, sizeof scratch, "%s.sepwork", outbin); - - FILE *f = fopen(srcf, "wb"); - if (!f) goto cleanup; - int writefail = fputs(src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) goto cleanup; - - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null", - driver, outbin, srcf); - if (runwait(cmd) != 0) goto cleanup; - result = runwait(outbin); -cleanup: - snprintf(rmcmd, sizeof rmcmd, "rm -rf -- %s", scratch); - if (runwait(rmcmd) != 0) cleanfail = 1; - if (unlink(srcf) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "globptr_field_store[%d]: temporary cleanup failed\n", idx); - if (result == want) return -1; - } - return result; -} - -/* Emit .s for `tool`; the caller owns srcf and asmf. */ -static int -emit_asm(const char *bin, const char *tool, const char *srcf, - const char *asmf) -{ - char cmd[2400]; - snprintf(cmd, sizeof cmd, "%s/%s -o %s %s 2>/dev/null", - bin, tool, asmf, srcf); - int rc = runwait(cmd); - return rc == 0 ? 0 : -1; -} - -static int -files_identical(const char *a, const char *b) -{ - FILE *fa = fopen(a, "rb"), *fb = fopen(b, "rb"); - if (!fa || !fb) { if (fa) fclose(fa); if (fb) fclose(fb); return 0; } - int ca, cb, same = 1; - do { - ca = fgetc(fa); cb = fgetc(fb); - if (ca != cb) { same = 0; break; } - } while (ca != EOF); - fclose(fa); fclose(fb); - return same; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - char cdrv[1024], wdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - int have_ww = (access(wdrv, X_OK) == 0); - - int fail = 0, total = 0; - for (int i = 0; i < NROWS; i++) { - const struct row *r = &ROWS[i]; - - total++; - int gc = run_driver(cdrv, r->src, i, r->want); - if (gc != r->want) { - fprintf(stderr, "globptr_field_store[%s,cstage]: run=%d want=%d\n", - r->name, gc, r->want); - fail++; - } - if (have_ww) { - total++; - int gw = run_driver(wdrv, r->src, i, r->want); - if (gw != r->want) { - fprintf(stderr, "globptr_field_store[%s,wwstage]: run=%d want=%d\n", - r->name, gw, r->want); - fail++; - } - } - - /* byte-id: w6c .s == w6c_ww .s */ - if (have_ww) { - char td[80], srcf[96], csf[96], wwf[96]; - int ec = -1, ew = -1, same = 0, setupfail = 0, cleanfail = 0; - snprintf(td, sizeof td, "/tmp/gpfs_asm_%d_%d", getpid(), i); - snprintf(srcf, sizeof srcf, "%s/t.ww", td); - snprintf(csf, sizeof csf, "%s/c.s", td); - snprintf(wwf, sizeof wwf, "%s/w.s", td); - total++; - if (mkdir(td, 0755) == 0) { - FILE *f = fopen(srcf, "wb"); - if (f) { - int writefail = fputs(r->src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (!writefail) { - ec = emit_asm(bin, "w6c", srcf, csf); - ew = emit_asm(bin, "w6c_ww", srcf, wwf); - same = ec == 0 && ew == 0 - && files_identical(csf, wwf); - } else setupfail = 1; - } else setupfail = 1; - if (unlink(srcf) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(csf) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(wwf) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(td) != 0) cleanfail = 1; - } else setupfail = 1; - if (setupfail) - fprintf(stderr, "globptr_field_store[%s]: temporary setup failed\n", - r->name); - if (!same) { - fprintf(stderr, "globptr_field_store[%s]: cs/ww .s NOT " - "byte-identical (ec=%d ew=%d)\n", r->name, ec, ew); - fail++; - } - if (cleanfail) { - fprintf(stderr, "globptr_field_store[%s]: temporary cleanup failed\n", - r->name); - if (same) fail++; - } - } - } - - if (fail) { - fprintf(stderr, "globptr_field_store_run: %d/%d checks failed\n", - fail, total); - return 1; - } - printf("globptr_field_store_run: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/689_structlit_slice_field.c b/test/wcc/689_structlit_slice_field.c deleted file mode 100644 index 7026d46b..00000000 --- a/test/wcc/689_structlit_slice_field.c +++ /dev/null @@ -1,362 +0,0 @@ -/* - * 689_structlit_slice_field — cstage and wwstage agree, byte-for-byte - * and at runtime, that a struct-LITERAL initializer `cl{ items = b, n = - * .. }` with a SLICE field copies the FULL 24B { ptr, len, cap } header - * of that field (task #24). - * - * The bug: cg_structlit_fill / cgstructlitfill had a TY_STR arm that - * stored all three header words (ptr@+0, len@+8, cap@+16), but NO - * TY_SLICE arm — a slice field fell through to the generic scalar tail - * which stored only the ptr word, so the stored .len and .cap read 0. - * str fields (same 24B shape) worked; slice fields silently dropped - * two words. Both stages emitted IDENTICAL wrong asm (the 990-997 - * byte-id gate was green on both-wrong), so RUNTIME readback is the - * correctness net. Same is_str/is_slice discrimination gap as #10 - * part-b, here in the struct-literal field-init path. - * - * The fix (BOTH stages, converged byte-identical): the str arm's guard - * widens to `TY_STR || TY_SLICE` (cstage) / `isstrtype || isslicetype` - * (wwstage) — a slice rides the existing, already-correct 3-word store. - * The TAGGED arm stays ordered BEFORE it, so a nullable/tagged slice - * (TY_TAGGED) still routes to the widener, not the 3-word store. - * - * Mutation-sanity: the .len and .cap rows fail if the store drops - * either word (the pre-fix 1-word slice store), and the scalar-field - * rows (y.n, y.head) pin that the field beside/before the slice is - * untouched. The str_* rows are a regression pin on the untouched str - * arm. - * - * row | shape | want - * ---------------+------------------------------------------+------ - * slice_len | cl{items=b,n=9}; b.len=5; y.items.len | 5 - * slice_cap | cl{items=b,n=9}; b.cap=8; y.items.cap | 8 - * slice_n | cl{items=b,n=9}; y.n (scalar beside slice)| 9 - * slice_ptr | hb[0]=4; cl{items=b,..}; y.items[0] | 4 - * off_len | struct{head:i64,s:[]u8}; s @foff 8; | 7 - * | s.len=7; y.s.len (pins disp+foff+8 hdr) | - * off_cap | same; s.cap=8; y.s.cap (disp+foff+16) | 8 - * off_head | same; head=1; y.head (scalar before slice)| 1 - * two_b_len | struct{a:[]u8,b:[]u8}; b @foff 24; | 6 - * | b.len=6; y.b.len (2nd slice, non-0 foff) | - * two_b_cap | same; b.cap=8; y.b.cap | 8 - * str_name_len | struct{s:[]u8,name:str}; name="hello"; | 5 - * | y.name.len (str arm regression pin) | - * str_s_len | same; s.len=3; y.s.len (slice beside str) | 3 - * - * The asm-byte-id rows pin the symmetric fix (cstage == wwstage); a - * non-empty diff means one stage missed the new slice arm. - */ -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want; }; - -static const struct row rows[] = { - { "slice_len", - "package main;\n" - "type cl = struct { items: []u8, n: i64 };\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet b: []u8; b.ptr = &hb[0]; b.len = 5; b.cap = 8;\n" - "\tlet y: cl = cl { items = b, n = 9i64 };\n" - "\treturn y.items.len: i32;\n" - "};\n", - 5 }, - - { "slice_cap", - "package main;\n" - "type cl = struct { items: []u8, n: i64 };\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet b: []u8; b.ptr = &hb[0]; b.len = 5; b.cap = 8;\n" - "\tlet y: cl = cl { items = b, n = 9i64 };\n" - "\treturn y.items.cap: i32;\n" - "};\n", - 8 }, - - { "slice_n", - "package main;\n" - "type cl = struct { items: []u8, n: i64 };\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet b: []u8; b.ptr = &hb[0]; b.len = 5; b.cap = 8;\n" - "\tlet y: cl = cl { items = b, n = 9i64 };\n" - "\treturn y.n: i32;\n" - "};\n", - 9 }, - - { "slice_ptr", - "package main;\n" - "type cl = struct { items: []u8, n: i64 };\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8; hb[0] = 4u8;\n" - "\tlet b: []u8; b.ptr = &hb[0]; b.len = 5; b.cap = 8;\n" - "\tlet y: cl = cl { items = b, n = 9i64 };\n" - "\treturn y.items[0]: i32;\n" - "};\n", - 4 }, - - /* slice field at a NON-ZERO field offset (head: i64 @0, s @8). - * Pins disp+foff+8/+16 in the stored header. */ - { "off_len", - "package main;\n" - "type hs = struct { head: i64, s: []u8 };\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet b: []u8; b.ptr = &hb[0]; b.len = 7; b.cap = 8;\n" - "\tlet y: hs = hs { head = 1i64, s = b };\n" - "\treturn y.s.len: i32;\n" - "};\n", - 7 }, - - { "off_cap", - "package main;\n" - "type hs = struct { head: i64, s: []u8 };\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet b: []u8; b.ptr = &hb[0]; b.len = 7; b.cap = 8;\n" - "\tlet y: hs = hs { head = 1i64, s = b };\n" - "\treturn y.s.cap: i32;\n" - "};\n", - 8 }, - - { "off_head", - "package main;\n" - "type hs = struct { head: i64, s: []u8 };\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet b: []u8; b.ptr = &hb[0]; b.len = 7; b.cap = 8;\n" - "\tlet y: hs = hs { head = 1i64, s = b };\n" - "\treturn y.head: i32;\n" - "};\n", - 1 }, - - /* two slice fields: a @0, b @24. Pins the 2nd slice's header at a - * non-zero field offset (the 24B stride). */ - { "two_b_len", - "package main;\n" - "type tt = struct { a: []u8, b: []u8 };\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet p: []u8; p.ptr = &hb[0]; p.len = 3; p.cap = 8;\n" - "\tlet q: []u8; q.ptr = &hb[0]; q.len = 6; q.cap = 8;\n" - "\tlet y: tt = tt { a = p, b = q };\n" - "\treturn y.b.len: i32;\n" - "};\n", - 6 }, - - { "two_b_cap", - "package main;\n" - "type tt = struct { a: []u8, b: []u8 };\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet p: []u8; p.ptr = &hb[0]; p.len = 3; p.cap = 8;\n" - "\tlet q: []u8; q.ptr = &hb[0]; q.len = 6; q.cap = 8;\n" - "\tlet y: tt = tt { a = p, b = q };\n" - "\treturn y.b.cap: i32;\n" - "};\n", - 8 }, - - /* str field beside a slice field — the untouched str arm must still - * store its full header (regression pin). */ - { "str_name_len", - "package main;\n" - "type sn = struct { s: []u8, name: str };\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet b: []u8; b.ptr = &hb[0]; b.len = 3; b.cap = 8;\n" - "\tlet y: sn = sn { s = b, name = \"hello\" };\n" - "\treturn y.name.len: i32;\n" - "};\n", - 5 }, - - { "str_s_len", - "package main;\n" - "type sn = struct { s: []u8, name: str };\n" - "export fn main() i32 = {\n" - "\tlet hb: [8]u8;\n" - "\tlet b: []u8; b.ptr = &hb[0]; b.len = 3; b.cap = 8;\n" - "\tlet y: sn = sn { s = b, name = \"hello\" };\n" - "\treturn y.s.len: i32;\n" - "};\n", - 3 }, -}; - -static int -run_driver(const char *driver, const struct row *r, int i) -{ - char tmpdir[64], src[128], outbin[128], scratch[160], rmcmd[192], cmd[1024]; - int result = -1, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/slf_%d_d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(src, sizeof src, "%s/slf_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/slf_%d_%d", tmpdir, getpid(), i); - snprintf(scratch, sizeof scratch, "%s.sepwork", outbin); - - FILE *f = fopen(src, "wb"); - if (!f) goto cleanup; - int writefail = fputs(r->src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) goto cleanup; - - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>/dev/null", - driver, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: build via %s failed\n", - r->label, driver); - goto cleanup; - } - result = runwait(outbin); -cleanup: - snprintf(rmcmd, sizeof rmcmd, "rm -rf -- %s", scratch); - if (runwait(rmcmd) != 0) cleanfail = 1; - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: temporary cleanup failed\n", r->label); - if (result == r->want) return -1; - } - return result; -} - -/* asm_byte_identical — w6c vs w6c_ww .s for the same source must match. - * Pre-fix BOTH stages dropped len+cap identically (byte-id green on - * both-wrong); the symmetric fix keeps them byte-identical and correct. */ -static int -asm_byte_identical(const char *bin, const struct row *r, int i) -{ - char tmpdir[64], src[96], cs[96], ws[96], cmd[1024]; - int rc = -1, cleanfail = 0; - snprintf(tmpdir, sizeof tmpdir, "/tmp/slf_asm_%d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) return -1; - snprintf(src, sizeof src, "%s/t.ww", tmpdir); - snprintf(cs, sizeof cs, "%s/c.s", tmpdir); - snprintf(ws, sizeof ws, "%s/w.s", tmpdir); - - FILE *f = fopen(src, "wb"); - if (!f) goto cleanup; - int writefail = fputs(r->src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) goto cleanup; - - snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c errored\n", r->label); - goto cleanup; - } - snprintf(cmd, sizeof cmd, "%s/w6c_ww -o %s %s 2>/dev/null", - bin, ws, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww errored\n", r->label); - goto cleanup; - } - - FILE *fc = fopen(cs, "rb"); - FILE *fw = fopen(ws, "rb"); - rc = 0; - if (!fc || !fw) { - rc = -1; - } else { - for (;;) { - int a = fgetc(fc); - int b = fgetc(fw); - if (a != b) { rc = -1; break; } - if (a == EOF) break; - } - } - if (fc) fclose(fc); - if (fw) fclose(fw); - if (rc != 0) - fprintf(stderr, "row[%s]: cstage vs wwstage asm differs\n", - r->label); -cleanup: - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(cs) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(ws) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: temporary cleanup failed\n", r->label); - return -1; - } - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - char wdrv[1024]; - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - - struct { const char *name; const char *path; int gated_on_existence; } - drivers[] = { - { "cstage", cdrv, 0 }, - { "wwstage", wdrv, 1 }, - { NULL, NULL, 0 }, - }; - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - - for (int d = 0; drivers[d].name; d++) { - if (drivers[d].gated_on_existence - && access(drivers[d].path, X_OK) != 0) { - fprintf(stderr, "structlit_slice_field: skip %s (no %s)\n", - drivers[d].name, drivers[d].path); - continue; - } - for (int i = 0; i < n; i++) { - int got = run_driver(drivers[d].path, &rows[i], i); - total++; - if (got != rows[i].want) { - fprintf(stderr, - "structlit_slice_field[%s][%s]: exit=%d want=%d\n", - drivers[d].name, rows[i].label, - got, rows[i].want); - fail++; - } - } - } - - if (access(wdrv, X_OK) == 0) { - for (int i = 0; i < n; i++) { - total++; - if (asm_byte_identical(bin, &rows[i], i) != 0) - fail++; - } - } - - if (fail) { - fprintf(stderr, - "structlit_slice_field: %d/%d fixtures failed\n", - fail, total); - return 1; - } - printf("structlit_slice_field: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/698_cgreturn_struct.c b/test/wcc/698_cgreturn_struct.c deleted file mode 100644 index c235ea58..00000000 --- a/test/wcc/698_cgreturn_struct.c +++ /dev/null @@ -1,500 +0,0 @@ -/* - * 698_cgreturn_struct — whole-struct return ABI across both 3-reg - * register-return (≤24B) and SysV sret (>24B, task #23) paths. - * - * Pre-#7: `return s;` from a struct-returning fn fell through to the - * scalar path: only the first 8 bytes of the struct made it to AX, - * the rest was silently dropped. #7 wired the ≤24B producer side - * (materialise into @retscr, load AX/DX/CX). The >24B case stayed - * OUT OF SCOPE — fell through to the same scalar path — until task - * #23 landed standard SysV sret discipline (caller pre-allocates - * dest, passes &dest in RDI, callee writes through *RDI and returns - * RDI in RAX). Surfaced by lib/encoding/utf8 pre-flight when the - * Hoehrmann decoder (`struct { offs: size, src: []u8 }`, 32B) hit - * the OUT-OF-SCOPE path; the marker pattern bit precisely when its - * scope hit, which is the right escalation signal. - * - * What this test pins: - * - cstage and wwstage emit byte-identical asm for every fixture, - * including the new 25B+ sret rows (the bootstrap byte-identity - * invariant — if either stage's scanlocals / cgreturn / cgcall - * drifts, the diff catches it). - * - Each fixture compiles+links+runs without crashing under both - * drivers (proves the prologue SUBQ reserves enough frame for - * @retscr / @sretarg / @sretscr; an under-booked frame would - * smash the saved BP / return address). - * - End-to-end value verification (caller reads AX/DX/CX into a - * dst slot, or sret writes through *RDI) is deferred to #5's - * test surface and the new 9xx semantic test for #23. Here we - * check the cgreturn side doesn't crash or produce invalid asm. - * - * Coverage: ≤24B shapes — 8B one-field, 16B two-i64, 24B three-i64, - * mixed-alignment i32+i32+i64+i64 (totsize 24 with the i32-pair - * packed), and N_IDENT rhs (let-init then `return p;`). Plus the - * new 25B+ rows added with #23: 32B i64×4, the utf8 decoder shape - * (i64 + []u8 = 32B aligned, the canonical surfacing case), and - * 40B i64×5. - */ -#include -#include -#include -#include -#include -#include -#include "wwtestpkg.h" - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; int want; }; - -static const struct row rows[] = { - /* 8B single-i64 field: smallest struct return. Exercises the - * sz=8 path where only AX is meaningful (DX/CX zero-padded). */ - { "one_i64_lit", - "type one = struct { v: i64 };\n" - "fn mk() one = { return one { v = 42i64 }; };\n" - "fn main() i32 = { mk(); return 0; };\n", - 0 }, - /* 16B two-i64 (the SysV 16B aggregate shape, but routed through - * our 3-reg path uniformly). N_STRUCTLIT rhs. */ - { "pair_i64_lit", - "type pair = struct { a: i64, b: i64 };\n" - "fn mk() pair = { return pair { a = 1i64, b = 2i64 }; };\n" - "fn main() i32 = { mk(); return 0; };\n", - 0 }, - /* 24B three-i64 — the headline shape: AX/DX/CX each carry one - * word, no zero pad needed in scratch. */ - { "trip_i64_lit", - "type trip = struct { x: i64, y: i64, z: i64 };\n" - "fn mk() trip = { return trip { x = 7i64, y = 11i64, z = 13i64 }; };\n" - "fn main() i32 = { mk(); return 0; };\n", - 0 }, - /* Mixed i32+i32+i64+i64: registerstruct packs two i32s into - * one quadword (a@0, b@4, c@8, d@16), totsize 24 after tail - * pad. Exercises the MOVL store-op branch in the structlit - * field walker. */ - { "mix_i32_i32_i64_i64_lit", - "type mix = struct { a: i32, b: i32, c: i64, d: i64 };\n" - "fn mk() mix = { return mix { a = 3, b = 5, c = 11i64, d = 12i64 }; };\n" - "fn main() i32 = { mk(); return 0; };\n", - 0 }, - /* N_IDENT rhs: let-init the struct then return it. Exercises - * the word-copy-from-slot branch (vs the structlit branch - * above). The let-init zero-fills the slot, so the trailing - * partial-word handlers (MOVL/MOVB) stay dormant — but the - * sz=24 path covers all three MOVQ words. */ - { "trip_i64_ident", - "type trip = struct { x: i64, y: i64, z: i64 };\n" - "fn mk() trip = {\n" - " let p: trip = trip { x = 100i64, y = 200i64, z = 300i64 };\n" - " return p;\n" - "};\n" - "fn main() i32 = { mk(); return 0; };\n", - 0 }, - /* 32B four-i64 — first row past the 24B → sret threshold. - * Hits the sret prologue (@sretarg ← DI), the structlit-fill - * through *(@sretarg), and `MOVQ @sretarg(BP), AX; RET`. */ - { "quad_i64_lit_sret", - "type quad = struct { a: i64, b: i64, c: i64, d: i64 };\n" - "fn mk() quad = { return quad { a = 1i64, b = 2i64, c = 3i64, d = 4i64 }; };\n" - "fn main() i32 = { let q: quad = mk(); return 0; };\n", - 0 }, - /* utf8 decoder shape (the surfacing case for #23): - * `struct { offs: i64, src: []u8 }` — i64 at +0, slice at +8 - * (16B+8B alignment, totsize 32). N_IDENT rhs exercises the - * sret word-copy-from-rhs-slot branch. */ - { "decoder_ident_sret", - "type decoder = struct { offs: i64, src: []u8 };\n" - "fn mk(s: []u8) decoder = {\n" - " let r: decoder;\n" - " r.offs = 0i64;\n" - " r.src = s;\n" - " return r;\n" - "};\n" - "fn main() i32 = {\n" - " let b: [1]u8;\n" - " let d: decoder = mk(b[0:1]);\n" - " return 0;\n" - "};\n", - 0 }, - /* 40B five-i64 — second sret row, sized past 32B to exercise - * the sretscr / @sretarg sizing for a larger struct in the - * same fn family. */ - { "five_i64_lit_sret", - "type five = struct { a: i64, b: i64, c: i64, d: i64, e: i64 };\n" - "fn mk() five = {\n" - " return five { a = 1i64, b = 2i64, c = 3i64, d = 4i64, e = 5i64 };\n" - "};\n" - "fn main() i32 = { let f: five = mk(); return 0; };\n", - 0 }, - /* #169 RETURN, maxalign<8: struct{i32,i32,i32} natural extent 12, - * maxalign 4 → cstage rt->size = round(12,4) = 12. The N_IDENT - * return word-copy loop sizes on rsz; pre-fix wwstage used the - * slot-padded totsize (round(12,8) = 16) → emitted MOVQ+MOVQ - * where cstage emits MOVQ+MOVL. Byte-id catches it; value - * readback (a+b+c) is correct in both stages either way. */ - { "trip_i32_ident_return", - "type t3 = struct { a: i32, b: i32, c: i32 };\n" - "fn mk() t3 = {\n" - " let s: t3 = t3 { a = 1, b = 2, c = 3 };\n" - " return s;\n" - "};\n" - "fn main() i32 = { let p: t3 = mk(); return p.a + p.b + p.c - 6; };\n", - 0 }, - /* #169 RECV, maxalign==8 + sub-8 tail: struct{i64,i32} natural - * extent 12, maxalign 8 → cstage lu->size = round(12,8) = 16. - * The `let p = mk()` receive sizes on structnaturalsize; pre-fix - * it returned the unrounded 12 → emitted MOVQ+MOVL where cstage - * emits MOVQ+MOVQ. mk returns via structlit (no RETURN-side - * divergence), isolating the RECV split. */ - { "pair_i64_i32_recv", - "type pt = struct { a: i64, b: i32 };\n" - "fn mk() pt = { return pt { a = 7i64, b = 9i32 }; };\n" - "fn main() i32 = { let p: pt = mk(); return p.b - 9; };\n", - 0 }, - /* #169 RECV, composite [N]u8 field: struct{i32,[6]u8} natural - * extent 10, maxalign 4 → cstage lu->size = round(10,4) = 12. - * Guards that a [N]u8 field's natural extent (10, NOT slot- - * rounded) feeds structabisize and rounds to maxalign, not 8: - * pre-fix the RECV used the unrounded structnaturalsize (10) → - * MOVW tail; the slot-padded totsize (16) would give MOVQ; only - * the maxalign-rounded 12 gives the MOVL cstage emits. The [6]u8 - * align must come from tinfo.align (1), not an fsz ladder (which - * would read 4 off the 6-byte slot) — here the i32 sets maxalign - * anyway, but the row pins the composite-field path byte-id. - * mk returns via struct literal so the bare-let local zero-init - * (a separate same-class latent) stays out of the fixture. */ - { "recv_i32_arr6_u8", - "type s6 = struct { n: i32, a: [6]u8 };\n" - "fn mk() s6 = " - "{ return s6 { n = 4i32, a = [1u8, 2u8, 3u8, 4u8, 5u8, 6u8] }; };\n" - "fn main() i32 = { let p: s6 = mk(); return p.n - 4; };\n", - 0 }, - /* DOT register-RECV: `obj.f = mk();` where the field type is a - * struct{i64,i32} (natural 12, maxalign 8 → cstage lu->size 16). - * Pre-fix wwstage sized the AX/DX/CX → field stores on the - * unrounded structnaturalsize (12) → MOVQ+MOVL where cstage emits - * MOVQ+MOVQ. The byte-id discriminator hits regardless of value - * read-back. Three flavors cover the *struct base, direct local, - * and global base sites that share the class. */ - { "dot_recv_call_local", - "type pt = struct { a: i64, b: i32 };\n" - "type box = struct { v: pt };\n" - "fn mk() pt = { return pt { a = 7i64, b = 9i32 }; };\n" - "fn main() i32 = {\n" - " let b: box;\n" - " b.v = mk();\n" - " return b.v.b - 9;\n" - "};\n", - 0 }, - { "dot_recv_call_viaptr", - "type pt = struct { a: i64, b: i32 };\n" - "type box = struct { v: pt };\n" - "fn mk() pt = { return pt { a = 7i64, b = 9i32 }; };\n" - "fn fill(p: *box) void = { p.v = mk(); return; };\n" - "fn main() i32 = {\n" - " let b: box;\n" - " fill(&b);\n" - " return b.v.b - 9;\n" - "};\n", - 0 }, - { "dot_recv_call_global", - "type pt = struct { a: i64, b: i32 };\n" - "type box = struct { v: pt };\n" - "let g: box = box { v = pt { a = 0i64, b = 0i32 } };\n" - "fn mk() pt = { return pt { a = 7i64, b = 9i32 }; };\n" - "fn main() i32 = { g.v = mk(); return g.v.b - 9; };\n", - 0 }, - /* structlit ELLIPSIS zero-fill at a DOT site. cstage zeroes the - * slot at `lu->size` (maxalign-rounded); wwstage pre-fix passed - * structnaturalsize (12 for struct{i64,i32}) as the totsize - * bound but cstage rounds to maxalign (16) before zeroing. The - * `..., ...` literal forces the ELLIPSIS path. Outer box keeps - * maxalign==8 so its own zero-init / structlit-init stays out - * of the registerstruct fsz-ladder latent (task #18). */ - { "dot_structlit_ellipsis", - "type s = struct { a: i64, b: i32 };\n" - "type box = struct { v: s };\n" - "fn mk() box = " - "{ return box { v = s { a = 0i64, b = 0i32 } }; };\n" - "fn main() i32 = {\n" - " let b: box = mk();\n" - " b.v = s { a = 5i64, ... };\n" - " return b.v.b;\n" - "};\n", - 0 }, - /* Bare `let z: T;` zero-init of a maxalign<8 struct. Slot is - * round-to-8 (ti.slotsize); cstage zeroes only `lu->size` - * (maxalign-rounded, check.c:760). struct{i32,i32,i32} natural 12, - * maxalign 4 → cstage emits XORQ + MOVQ + MOVL (12B); pre-fix - * wwstage emitted XORQ + MOVQ + MOVQ (slot 16B). Value-correct - * either way; byte-id catches the trailing 4B widen. */ - { "bare_let_struct_maxalign4", - "type t3 = struct { a: i32, b: i32, c: i32 };\n" - "fn main() i32 = {\n" - " let z: t3;\n" - " return z.a + z.b + z.c;\n" - "};\n", - 0 }, - /* `let p2: T = p1;` ident memcpy. struct{i64,i32} natural 12, - * maxalign 8 → cstage N_LET sets sz = lu->size = 16 (cgen.c:7533, - * struct-IDENT branch :7869) and emits MOVQ+MOVQ for the per-qword - * copy. Pre-fix wwstage sized the run on structnaturalsize (12) → - * MOVQ+MOVL. The byte-id catches the 4B widen; both stages - * round-trip the value correctly because the high 4B of the rhs - * slot were zero-init'd by the source let. */ - { "let_ident_memcpy_pair_i64_i32", - "type pt = struct { a: i64, b: i32 };\n" - "fn main() i32 = {\n" - " let p1: pt = pt { a = 7i64, b = 9i32 };\n" - " let p2: pt = p1;\n" - " return p2.b - 9;\n" - "};\n", - 0 }, - /* `s = mk();` ident-lhs register RECV (sibling of dot_recv_call_*). - * struct{i64,i32} natural 12, maxalign 8 → cstage N_ASSIGN-IDENT - * sets sz = lu->size = 16 (cgen.c:4704) and stores AX/DX with - * MOVQ+MOVQ. Pre-fix wwstage used structnaturalsize (12) → - * MOVQ+MOVL. byte-id discriminator regardless of value readback. */ - { "assign_ident_call_recv_pair_i64_i32", - "type pt = struct { a: i64, b: i32 };\n" - "fn mk() pt = { return pt { a = 7i64, b = 9i32 }; };\n" - "fn main() i32 = {\n" - " let s: pt = pt { a = 0i64, b = 0i32 };\n" - " s = mk();\n" - " return s.b - 9;\n" - "};\n", - 0 }, - /* Nested struct N_CALL inside a structlit field: the outer literal - * has field `v` whose type is struct{i64,i32}; the value is mk(). - * cstage's cg_structlit_fill reads fl->type->size at the nested- - * call branch (cgen.c:2121) — per check.c:760 that's the maxalign- - * rounded ABI extent (16). Pre-fix wwstage cgstructlitfill used - * structnaturalsize (12) → MOVQ+MOVL where cstage emits MOVQ+MOVQ. - * mk returns via a structlit so the producer side stays out of the - * comparison; only the nested-call-recv ladder shifts. */ - { "structlit_nested_call_recv_pair_i64_i32", - "type pt = struct { a: i64, b: i32 };\n" - "type box = struct { v: pt };\n" - "fn mk() pt = { return pt { a = 7i64, b = 9i32 }; };\n" - "fn main() i32 = {\n" - " let b: box = box { v = mk() };\n" - " return b.v.b - 9;\n" - "};\n", - 0 }, -}; - -static int -run_driver(const char *driver, const struct row *r, int i) -{ - char tmpdir[64], src[128], outbin[128], sepwork[160], cmd[1024]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/wcrs_%d_d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) { - fprintf(stderr, "row[%s]: mkdir %s failed\n", r->label, tmpdir); - return -1; - } - snprintf(src, sizeof src, "%s/wcrs_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/wcrs_%d_%d", tmpdir, getpid(), i); - snprintf(sepwork, sizeof sepwork, "%s.sepwork", outbin); - - int got = -1; - FILE *f = fopen(src, "wb"); - if (!f) goto cleanup; - wwtest_fputs(r->src, f); - int writebad = ferror(f); - if (fclose(f) != 0) writebad = 1; - if (writebad) goto cleanup; - - snprintf(cmd, sizeof cmd, "%s build -o %s %s", driver, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: build via %s failed\n", - r->label, driver); - goto cleanup; - } - - got = runwait(outbin); - - /* Ordinary build leaves `.sepwork` to its caller. This exact - * tree is beneath tmpdir, whose mkdir above established ownership. */ -cleanup: - { - int cleanup_fail = 0; - snprintf(cmd, sizeof cmd, "rm -rf %s", sepwork); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: cleanup %s failed\n", - r->label, sepwork); - cleanup_fail = 1; - } - if (unlink(src) != 0 && errno != ENOENT) { - fprintf(stderr, "row[%s]: cleanup %s failed\n", r->label, src); - cleanup_fail = 1; - } - if (unlink(outbin) != 0 && errno != ENOENT) { - fprintf(stderr, "row[%s]: cleanup %s failed\n", - r->label, outbin); - cleanup_fail = 1; - } - if (rmdir(tmpdir) != 0) { - fprintf(stderr, "row[%s]: cleanup %s failed\n", - r->label, tmpdir); - cleanup_fail = 1; - } - if (cleanup_fail && got == r->want) got = -1; - } - return got; -} - -/* asm_byte_identical — generate .s via cstage's w6c and wwstage's w6c_ww - * and diff. Catches scanlocals / cgreturn drift between the two stages, - * which the bootstrap byte-identity (995_self_rebuild) covers globally - * but doesn't surface as a focused-fixture failure. */ -static int -asm_byte_identical(const char *bin, const struct row *r, int i) -{ - char tmpdir[64], src[128], cs[128], ws[128], cmd[1024]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/wcrs_asm_%d_%d", getpid(), i); - if (mkdir(tmpdir, 0755) != 0) { - fprintf(stderr, "row[%s]: mkdir %s failed\n", r->label, tmpdir); - return -1; - } - snprintf(src, sizeof src, "%s/input.ww", tmpdir); - snprintf(cs, sizeof cs, "%s/cstage.s", tmpdir); - snprintf(ws, sizeof ws, "%s/wwstage.s", tmpdir); - - int rc = -1; - FILE *f = fopen(src, "wb"); - if (!f) goto cleanup; - wwtest_fputs(r->src, f); - int writebad = ferror(f); - if (fclose(f) != 0) writebad = 1; - if (writebad) goto cleanup; - - snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c errored\n", r->label); - goto cleanup; - } - snprintf(cmd, sizeof cmd, "%s/w6c_ww -o %s %s 2>/dev/null", - bin, ws, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww errored\n", r->label); - goto cleanup; - } - - FILE *fc = fopen(cs, "rb"); - FILE *fw = fopen(ws, "rb"); - rc = 0; - if (!fc || !fw) { - rc = -1; - } else { - for (;;) { - int a = fgetc(fc); - int b = fgetc(fw); - if (a != b) { rc = -1; break; } - if (a == EOF) break; - } - } - if (fc) fclose(fc); - if (fw) fclose(fw); - if (rc != 0) - fprintf(stderr, "row[%s]: cstage vs wwstage asm differs\n", - r->label); - -cleanup: - { - int cleanup_fail = 0; - if (unlink(src) != 0 && errno != ENOENT) { - fprintf(stderr, "row[%s]: cleanup %s failed\n", r->label, src); - cleanup_fail = 1; - } - if (unlink(cs) != 0 && errno != ENOENT) { - fprintf(stderr, "row[%s]: cleanup %s failed\n", r->label, cs); - cleanup_fail = 1; - } - if (unlink(ws) != 0 && errno != ENOENT) { - fprintf(stderr, "row[%s]: cleanup %s failed\n", r->label, ws); - cleanup_fail = 1; - } - if (rmdir(tmpdir) != 0) { - fprintf(stderr, "row[%s]: cleanup %s failed\n", - r->label, tmpdir); - cleanup_fail = 1; - } - if (cleanup_fail && rc == 0) rc = -1; - } - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - char wdrv[1024]; - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - - struct { const char *name; const char *path; int gated_on_existence; } - drivers[] = { - { "cstage", cdrv, 0 }, - { "wwstage", wdrv, 1 }, - { NULL, NULL, 0 }, - }; - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - - /* Compile+run for each (driver, row). */ - for (int d = 0; drivers[d].name; d++) { - if (drivers[d].gated_on_existence - && access(drivers[d].path, X_OK) != 0) { - fprintf(stderr, "cgreturn_struct: skip %s (no %s)\n", - drivers[d].name, drivers[d].path); - continue; - } - for (int i = 0; i < n; i++) { - int got = run_driver(drivers[d].path, &rows[i], i); - total++; - if (got != rows[i].want) { - fprintf(stderr, - "cgreturn_struct[%s][%s]: exit=%d want=%d\n", - drivers[d].name, rows[i].label, - got, rows[i].want); - fail++; - } - } - } - - /* Asm byte-identity diff, only when both stages exist. */ - if (access(wdrv, X_OK) == 0) { - for (int i = 0; i < n; i++) { - total++; - if (asm_byte_identical(bin, &rows[i], i) != 0) - fail++; - } - } - - if (fail) { - fprintf(stderr, - "cgreturn_struct: %d/%d fixtures failed\n", fail, total); - return 1; - } - printf("cgreturn_struct: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/722_match_slice_variant.c b/test/wcc/722_match_slice_variant.c deleted file mode 100644 index dadc4452..00000000 --- a/test/wcc/722_match_slice_variant.c +++ /dev/null @@ -1,182 +0,0 @@ -/* - * 722_match_slice_variant — Class A asm-presence + byte-id sentinel - * for task #19. Pins that the variant tag chosen for a `[]T` arm in a - * `(scalar | []T)` tagged union matches between cstage and wwstage at - * BOTH dispatch (cgmatch's `CMPQ $K, AX`) and call-site (the - * `MOVQ $K, AX` widening that materialises the tag for the slice - * payload). - * - * Pre-fix wwstage's name-keyed flatvariantidx / str-shape fallback - * landed on tag 0 for any `[]T` lookup (pat.str == "" because the - * variant node is N_TSLICE, not N_TNAME). Both the case arm and the - * call-site emitted `$0` — internally consistent inside wwstage, but - * the cstage-vs-wwstage cmp -s diverges from cstage's correct `$1`. - * Class A: silent until wwstage path engaged. 967_bytes_run was - * compiled through cstage only and never tripped; lib/strings landing - * pulls bytes through wwstage and surfaces the dispatch miscompile - * via 995_self_rebuild. - * - * Asserts cmp -s byte-id on the canonical (u8 | []u8) probe plus - * other (scalar | []scalar) shapes from rob's matrix. - */ -#include -#include -#include -#include -#include -#include -#include "wwtestpkg.h" - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { - const char *label; - const char *src; -}; - -static const struct row rows[] = { - /* The canonical (u8 | []u8) repro from bytes.index. */ - { "u8_slice_u8", - "fn pick(n: (u8 | []u8)) i32 = {\n" - " match (n) {\n" - " case let c: u8 => return 1;\n" - " case let s: []u8 => return 2;\n" - " };\n" - " return 0;\n" - "};\n" - "export fn main() i32 = {\n" - " let r1: i32 = pick(7u8);\n" - " let buf: [2]u8;\n" - " let r2: i32 = pick(buf[0:2]);\n" - " if (r1 != 1) { return 11; };\n" - " if (r2 != 2) { return 12; };\n" - " return 0;\n" - "};\n" }, - /* Reverse-order shape (slice arm first): the same shape-fallback - * that lost (u8 | []u8) must also resolve ([]u8 | u8) without - * accidentally inverting via the str-shape collapse. */ - { "slice_u8_then_u8", - "fn pick(n: ([]u8 | u8)) i32 = {\n" - " match (n) {\n" - " case let s: []u8 => return 1;\n" - " case let c: u8 => return 2;\n" - " };\n" - " return 0;\n" - "};\n" - "export fn main() i32 = {\n" - " let buf: [2]u8;\n" - " let r1: i32 = pick(buf[0:2]);\n" - " let r2: i32 = pick(7u8);\n" - " if (r1 != 1) { return 11; };\n" - " if (r2 != 2) { return 12; };\n" - " return 0;\n" - "};\n" }, - /* Three-arm (u8 | []u8 | str): proves the slice axis composes with - * the existing str axis (str arm at idx 2 stays at idx 2). */ - { "u8_slice_u8_str", - "fn pick(n: (u8 | []u8 | str)) i32 = {\n" - " match (n) {\n" - " case let c: u8 => return 1;\n" - " case let s: []u8 => return 2;\n" - " case let t: str => return 3;\n" - " };\n" - " return 0;\n" - "};\n" - "export fn main() i32 = {\n" - " let buf: [2]u8;\n" - " if (pick(7u8) != 1) { return 11; };\n" - " if (pick(buf[0:2]) != 2) { return 12; };\n" - " if (pick(\"hi\") != 3) { return 13; };\n" - " return 0;\n" - "};\n" }, -}; - -static int -emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap) -{ - char src[64], cmd[1024]; - snprintf(src, sizeof src, "/tmp/msv_asm_%d_%d.ww", getpid(), i); - snprintf(out_s, cap, "/tmp/msv_asm_%d_%d_%s.s", - getpid(), i, w6c[strlen(w6c) - 1] == 'w' ? "ww" : "c"); - - FILE *f = fopen(src, "wb"); - if (!f) return -1; - wwtest_fputs(r->src, f); - fclose(f); - - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src); - int rc = runwait(cmd); - unlink(src); - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[512]; - if (bin[0] != '/') { - char cwd[256]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char w6c[640], w6c_ww[640]; - snprintf(w6c, sizeof w6c, "%s/w6c", bin); - snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin); - - int have_ww = (access(w6c_ww, X_OK) == 0); - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - - for (int i = 0; i < n; i++) { - char cs_path[128], ws_path[128]; - - if (emit_s(w6c, &rows[i], i, cs_path, sizeof cs_path) != 0) { - fprintf(stderr, - "match_slice_variant[cstage][%s]: w6c failed\n", - rows[i].label); - fail++; total++; continue; - } - - if (!have_ww) { unlink(cs_path); continue; } - - if (emit_s(w6c_ww, &rows[i], i, ws_path, sizeof ws_path) != 0) { - fprintf(stderr, - "match_slice_variant[wwstage][%s]: w6c_ww failed\n", - rows[i].label); - fail++; total++; - unlink(cs_path); - continue; - } - total++; - char cmd[512]; - snprintf(cmd, sizeof cmd, "cmp -s %s %s", cs_path, ws_path); - if (runwait(cmd) != 0) { - fprintf(stderr, - "match_slice_variant[%s]: cstage vs wwstage asm differs\n", - rows[i].label); - fail++; - } - - unlink(cs_path); unlink(ws_path); - } - - if (fail) { - fprintf(stderr, - "match_slice_variant: %d/%d fixtures failed\n", fail, total); - return 1; - } - printf("match_slice_variant: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/725_nested_if_labels.c b/test/wcc/725_nested_if_labels.c deleted file mode 100644 index 915bbc96..00000000 --- a/test/wcc/725_nested_if_labels.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * 725_nested_if_labels — sentinel for STATUS-3 #15. Cstage's - * `cgen.c`-side per-function ≤24B-struct return path called - * `mklabel(c, "retscr")`, consuming one `labelseq` counter slot per - * function that returns a struct. Wwstage's equivalent emits a - * fixed-name `@retscr` SSoT (mirrors `c.retscroff` in - * selfhost/cmd/wcc/cgen.ww). Net effect pre-fix: every subsequent - * control-flow label (`ct_N`, `ce_N`, `else_N`, `end_N`) in any such - * function was 1 ahead in cstage. - * - * Filed STATUS-3 #15. Previously byte-id drift only; 995_self_rebuild - * masked because the bootstrap main.combined.ww's drift was within - * the threshold the test happens to allow. lib/strings (commit 1) + - * lib/time.add nested-if shapes compounded the skew past that - * threshold once worker-strings-v2 attempted the landing — promotes - * #15 from latent to bootstrap-blocking. - * - * Fix aligns cstage DOWN to wwstage's single-slot SSoT (rule 10): - * cgen.c's two `mklabel(c, "retscr")` sites now use the fixed string - * "@retscr" passed to local_alloc. Labels never appear in emitted - * asm — only the labelseq side-effect mattered, and dropping it - * lets cstage's label numbering match wwstage's. - * - * Row pins asm `cmp -s` byte-id between stages on the canonical - * time.add shape: ≤24B struct return + nested if/if/fallthrough. - */ -#include -#include -#include -#include -#include -#include -#include "wwtestpkg.h" - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; }; - -static const struct row rows[] = { - /* Plain struct return + nested-if (time.add shape — struct - * `instant` return, multi-arm if/if/fallthrough). Each return - * site hits cgreturn's ≤24B-struct arm which allocates - * @retscr; pre-fix mklabel(c, "retscr") bumped labelseq, post- - * fix the fixed name leaves labelseq alone so cstage's - * ct/ce/end numbering matches wwstage. */ - { "struct_return_then_nested_if", - "type instant = struct { sec: i64, nsec: i64 };\n" - "export fn add(i: instant, x: i64) instant = {\n" - " let r: instant;\n" - " if (x == 0i64) {\n" - " r.sec = i.sec; r.nsec = i.nsec;\n" - " return r;\n" - " };\n" - " if (x > 0i64) {\n" - " r.sec = i.sec + x; r.nsec = i.nsec;\n" - " return r;\n" - " };\n" - " r.sec = i.sec - 1i64; r.nsec = i.nsec + x;\n" - " return r;\n" - "};\n" }, -}; - -static int -emit_s(const char *w6c, const struct row *r, int i, char *out_s, size_t cap) -{ - char src[64], cmd[1024]; - snprintf(src, sizeof src, "/tmp/nil_asm_%d_%d.ww", getpid(), i); - snprintf(out_s, cap, "/tmp/nil_asm_%d_%d_%s.s", - getpid(), i, w6c[strlen(w6c) - 1] == 'w' ? "ww" : "c"); - - FILE *f = fopen(src, "wb"); - if (!f) return -1; - wwtest_fputs(r->src, f); - fclose(f); - - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src); - int rc = runwait(cmd); - unlink(src); - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[512]; - if (bin[0] != '/') { - char cwd[256]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char w6c[640], w6c_ww[640]; - snprintf(w6c, sizeof w6c, "%s/w6c", bin); - snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin); - - int have_ww = (access(w6c_ww, X_OK) == 0); - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - - for (int i = 0; i < n; i++) { - char cs_path[128], ws_path[128]; - - if (emit_s(w6c, &rows[i], i, cs_path, sizeof cs_path) != 0) { - fprintf(stderr, - "nested_if_labels[cstage][%s]: w6c failed\n", - rows[i].label); - fail++; total++; continue; - } - total++; - - if (!have_ww) { unlink(cs_path); continue; } - - if (emit_s(w6c_ww, &rows[i], i, ws_path, sizeof ws_path) != 0) { - fprintf(stderr, - "nested_if_labels[wwstage][%s]: w6c_ww failed\n", - rows[i].label); - fail++; total++; - unlink(cs_path); - continue; - } - total++; - - /* Byte-id between stages — the fix-pin. Pre-fix cstage's - * `add_ct_N` was 1 ahead of wwstage's; post-fix they match. */ - total++; - char cmd[512]; - snprintf(cmd, sizeof cmd, "cmp -s %s %s", cs_path, ws_path); - if (runwait(cmd) != 0) { - fprintf(stderr, - "nested_if_labels[%s]: cstage vs wwstage asm differs\n", - rows[i].label); - fail++; - } - - unlink(cs_path); unlink(ws_path); - } - - if (fail) { - fprintf(stderr, - "nested_if_labels: %d/%d fixtures failed\n", fail, total); - return 1; - } - printf("nested_if_labels: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/736_cstage_label_ssot.c b/test/wcc/736_cstage_label_ssot.c deleted file mode 100644 index fd71fa08..00000000 --- a/test/wcc/736_cstage_label_ssot.c +++ /dev/null @@ -1,175 +0,0 @@ -/* - * 736_cstage_label_ssot — sentinel for STATUS-4 #26. Cstage's tagged- - * scratch sites previously stamped per-call labels via mklabel "tagbase" - * / "tagscr" / "argscr" / "idxscr". Each call bumped `labelseq` and - * allocated a fresh frame slot. Wwstage's mirrors use `@`-prefix names - * routed through `localadd` (selfhost/cmd/wcc/cgen.ww) — the `@`-dedup - * shares one slot per name per fn and never touches labelseq. Per-fn - * `@tagbase` is one slot (8B); per-fn `@tagscr` is ONE slot shared - * across cgwidentaggedstore via_outer (cgenutil.ww:2918), pushargsrev - * struct-payload widen (cgenutil.ww:180) and cgindex tagged-element - * (cgenexpr.ww:3524). - * - * Post-#26 cstage caches `cg_tagbase` + `cg_tagscr` (single shared slot - * across the three @tagscr sites — matches wwstage's namespace exactly). - * The size-strategy gap remains: wwstage's scanlocals pre-pass sizes - * `c.tagscrsz` to the per-fn max BEFORE emit; cstage has no pre-pass, - * so first call across the 3 sites sizes the slot and subsequent - * callers must fit. fatal() per rule 7 if growth is needed. Long-term - * convergence (wwstage DOWN to first-use+fail-loud on BOTH stages, or - * cstage UP to a scanlocals pre-pass) is filed as #26c — separate - * concern, not in #26's scope. - * - * succ_rows pin cstage vs wwstage asm `cmp -s` byte-id on the - * canonical pointer-rooted two-tagged-store shapes. Pre-#26 cstage's - * frame was 16B larger (extra @tagbase + @tagscr per call); post-#26 - * they match. The old fail_rows family pre-located the Class A - * landmine (a fn needing the single @tagscr slot to GROW within one - * cgfn → rule-7 fatal); #44 size-keys the scratch (@tagscr, one - * slot per distinct slot size) so that shape now compiles — it moved - * into succ_rows, and the dedicated runtime rows live in - * 926_tagscr_sizes_run. */ -#include -#include -#include -#include -#include -#include -#include "wwtestpkg.h" - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { const char *label; const char *src; }; - -static const struct row succ_rows[] = { - /* Two struct-pointer-rooted tagged stores in the same fn. Each - * `c.v = (...: bag);` enters cg_widen_tagged_store with a - * non-BP base (D_BX, pointer-rooted dst) which routes through - * the @tagbase spill + @tagscr scratch path. Pre-#26: 2 @tagbase - * slots + 2 @tagscr slots in cstage's frame; wwstage shares one - * @tagbase + one @tagscr via localadd `@`-dedup. Post-#26: cstage - * caches both per-fn via cg_tagbase / cg_tagscr (mirrors - * cg_retscr from #15-cstage) so the second call reuses, matching - * wwstage. */ - { "two_struct_ptr_tagged_stores", - "type pair = struct { hi: i64, lo: i64 };\n" - "type bag = (pair | i64);\n" - "type cell = struct { v: bag };\n" - "export fn run(c: *cell, p: pair, q: pair) i64 = {\n" - " c.v = (p: bag);\n" - " c.v = (q: bag);\n" - " return 0i64;\n" - "};\n" }, - /* Two pointer-rooted tagged stores into DIFFERENTLY-sized union - * slots within one fn. Pre-#44 this was the fail_rows landmine: - * the single first-use-sized @tagscr couldn't grow → cstage - * fatal "@tagscr cached sz". #44 keys the scratch by slot size - * (@tagscr), so each store pins its own slot and the shape - * compiles byte-id on both stages. */ - { "tagscr_two_sizes", - "type small = (i64 | i32);\n" - "type big = (i64 | str);\n" - "type cell_a = struct { v: small };\n" - "type cell_b = struct { v: big };\n" - "export fn run(a: *cell_a, b: *cell_b, x: i64, s: str) i64 = {\n" - " a.v = (x: small);\n" - " b.v = (s: big);\n" - " return 0i64;\n" - "};\n" }, -}; - -static int -emit_s(const char *w6c, const char *src_text, int i, char *out_s, size_t cap) -{ - char src[64], cmd[1024]; - snprintf(src, sizeof src, "/tmp/lbl_ssot_%d_%d.ww", getpid(), i); - snprintf(out_s, cap, "/tmp/lbl_ssot_%d_%d_%s.s", - getpid(), i, w6c[strlen(w6c) - 1] == 'w' ? "ww" : "c"); - - FILE *f = fopen(src, "wb"); - if (!f) return -1; - wwtest_fputs(src_text, f); - fclose(f); - - snprintf(cmd, sizeof cmd, "%s -o %s %s 2>/dev/null", w6c, out_s, src); - int rc = runwait(cmd); - unlink(src); - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[512]; - if (bin[0] != '/') { - char cwd[256]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char w6c[640], w6c_ww[640]; - snprintf(w6c, sizeof w6c, "%s/w6c", bin); - snprintf(w6c_ww, sizeof w6c_ww, "%s/w6c_ww", bin); - - int have_ww = (access(w6c_ww, X_OK) == 0); - - int total = 0, fail = 0; - - int nsucc = (int)(sizeof succ_rows / sizeof succ_rows[0]); - for (int i = 0; i < nsucc; i++) { - char cs_path[128], ws_path[128]; - - if (emit_s(w6c, succ_rows[i].src, i, cs_path, sizeof cs_path) != 0) { - fprintf(stderr, - "cstage_label_ssot[cstage][%s]: w6c failed\n", - succ_rows[i].label); - fail++; total++; continue; - } - total++; - - if (!have_ww) { unlink(cs_path); continue; } - - if (emit_s(w6c_ww, succ_rows[i].src, i, ws_path, sizeof ws_path) != 0) { - fprintf(stderr, - "cstage_label_ssot[wwstage][%s]: w6c_ww failed\n", - succ_rows[i].label); - fail++; total++; - unlink(cs_path); - continue; - } - total++; - - /* Byte-id between stages — the fix-pin. Pre-fix cstage's - * frame was 16B larger and the second-store offsets pointed - * at extra slots; post-fix they match. */ - total++; - char cmd[512]; - snprintf(cmd, sizeof cmd, "cmp -s %s %s", cs_path, ws_path); - if (runwait(cmd) != 0) { - fprintf(stderr, - "cstage_label_ssot[%s]: cstage vs wwstage asm differs\n", - succ_rows[i].label); - fail++; - } - - unlink(cs_path); unlink(ws_path); - } - - if (fail) { - fprintf(stderr, - "cstage_label_ssot: %d/%d fixtures failed\n", fail, total); - return 1; - } - printf("cstage_label_ssot: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/749_sumtype_forward.c b/test/wcc/749_sumtype_forward.c deleted file mode 100644 index 35112b3a..00000000 --- a/test/wcc/749_sumtype_forward.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * 749_sumtype_forward — sentinel for #12. - * - * Pre-fix wwstage hardcoded the param's first-variant tag when - * forwarding a sum-typed variadic element to a scalar (T|U) param. - * cgindex emitted the tagged-CALL ABI (AX=tag, DX=word0, CX=word1[, - * R8=word2]) for `needles[i]` correctly, then pushargsrev's widening - * detection — keyed only on N_IDENT-source — fell into the scalar - * widening branch: XORQ DX,DX / PUSHQ DX / PUSHQ AX / MOVQ $1,AX / - * PUSHQ AX. The hardcoded `$1` made the callee always run the rune - * arm; payload was the slice's first ptr word reinterpreted as a rune. - * - * cstage knew the arg's static type via check.c (`a->type == p->type`) - * so the widen flag stayed off and the natural-push tagged-arg arm - * pushed CX/DX/AX. - * - * Fix: wwstage pushargsrev now treats `arg.kind == N_INDEX && - * istaggedtype(indexvaluetnode(arg))` as already-tagged (matching - * slot size to the param) and pushes CX/DX/AX in the natural-push - * fallthrough. - * - * Rows assert per-stage runtime AND byte-id at the affected callsite. - * - * row | what it pins - * -------------------------------+-------------------------------- - * forward_index_of_sum_variadic | #12 wedge. Pre-fix wwstage - * | returned 11 (helper saw garbage - * | rune); cstage returned 0. - * | Post-fix both return 0. - * forward_ident_sum | Sibling: forward an ident-source - * | sum local to a sum-typed scalar - * | param. Stays on the N_IDENT - * | aistagged path — non-regression. - * forward_literal_sum | Sibling: forward a literal-source - * | value (str) to a sum-typed scalar - * | param. Stays on the widening - * | path — non-regression. - */ -#include -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -struct row { - /* Runtime ownership: test/wcc/data/r749_sumtype_forward_*. */ - const char *label; - const char *src; -}; - -static const struct row rows[] = { - /* 1. Original #12 wedge. helper(needles[i]) where needles is - * (str|rune)... — N_INDEX of sum-typed slice element forwarded - * to a scalar (str|rune) param. pick("foo","world",'x') hits - * the 'x' rune at i=2, so helper returns true and pick returns - * true. main returns 0 on success. */ - { "forward_index_of_sum_variadic", - "package main;\n" - "fn helper(needle: (str | rune)) bool = {\n" - " match (needle) {\n" - " case let s: str => return s.len > 0;\n" - " case let r: rune => return r == 'x';\n" - " };\n" - " return false;\n" - "};\n" - "fn pick(needles: (str | rune)...) bool = {\n" - " let i: i32 = 0;\n" - " for (i < needles.len) {\n" - " if (helper(needles[i])) { return true; };\n" - " i += 1;\n" - " };\n" - " return false;\n" - "};\n" - "export fn main() i32 = {\n" - " if (!pick(\"foo\", \"world\", 'x')) { return 11; };\n" - " return 0;\n" - "};\n" }, - - /* 2. Ident-source sum-arg. needle is a (str|rune) local; helper - * call routes through the existing N_IDENT-aistagged path. The - * (str|rune) ident is built from a str literal so the rune arm - * shouldn't fire. */ - { "forward_ident_sum", - "package main;\n" - "fn helper(needle: (str | rune)) bool = {\n" - " match (needle) {\n" - " case let s: str => return s.len == 3;\n" - " case let r: rune => return false;\n" - " };\n" - " return false;\n" - "};\n" - "export fn main() i32 = {\n" - " let needle: (str | rune) = \"foo\";\n" - " if (!helper(needle)) { return 11; };\n" - " return 0;\n" - "};\n" }, - - /* 3. Literal-source sum-arg. helper(\"foo\") widens the str at - * the call site. Stays on the widening path (param tagged, arg - * not tagged) and pushes a synthesised (tag=0, ptr, len) slot. */ - { "forward_literal_sum", - "package main;\n" - "fn helper(needle: (str | rune)) bool = {\n" - " match (needle) {\n" - " case let s: str => return s.len == 3;\n" - " case let r: rune => return false;\n" - " };\n" - " return false;\n" - "};\n" - "export fn main() i32 = {\n" - " if (!helper(\"foo\")) { return 11; };\n" - " return 0;\n" - "};\n" }, -}; - -/* read_file slurps a file whole, returning a malloc'd buffer - * (NUL-terminated) or NULL on error. */ -static char * -read_file(const char *path, size_t *outsz) -{ - FILE *f = fopen(path, "rb"); - if (!f) return NULL; - fseek(f, 0, SEEK_END); - long n = ftell(f); - fseek(f, 0, SEEK_SET); - if (n < 0) { fclose(f); return NULL; } - char *buf = malloc((size_t)n + 1); - if (!buf) { fclose(f); return NULL; } - size_t got = fread(buf, 1, (size_t)n, f); - fclose(f); - buf[got] = '\0'; - if (outsz) *outsz = got; - return buf; -} - -/* slice_at finds the line beginning with `CALL\tmain.helper(SB)` and - * returns a pointer to the start of the block four lines above (the - * three PUSHQ + the tag MOV in the pre-fix case, the three PUSHQ in - * the post-fix). For our byte-id check we compare a 64-byte window - * starting at the first newline above that anchor. */ -static const char * -helper_callsite(const char *asm_buf) -{ - const char *anchor = strstr(asm_buf, "CALL\tmain.helper(SB)"); - if (!anchor) return NULL; - /* walk back ~12 lines so the slice straddles the args set-up. */ - const char *p = anchor; - int back = 12; - while (back > 0 && p > asm_buf) { - p--; - if (*p == '\n') back--; - } - return p; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[512]; - if (bin[0] != '/') { - char cwd[256]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cw6[640], ww6[640]; - snprintf(cw6, sizeof cw6, "%s/w6c", bin); - snprintf(ww6, sizeof ww6, "%s/w6c_ww", bin); - int have_w6cww = (access(ww6, X_OK) == 0); - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - - for (int i = 0; i < n; i++) { - const struct row *r = &rows[i]; - - char src[160], tmpdir[96], css[160], wss[160]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/sumtype_fwd_%d_d_%d", - getpid(), i); - if (mkdir(tmpdir, 0755) != 0) { - fprintf(stderr, - "sumtype_forward[%s]: cannot acquire temp directory: %s\n", - r->label, strerror(errno)); - fail++; total++; - continue; - } - snprintf(src, sizeof src, "%s/sumtype_fwd_%d_%d.ww", - tmpdir, getpid(), i); - snprintf(css, sizeof css, "%s/cs.s", tmpdir); - snprintf(wss, sizeof wss, "%s/ws.s", tmpdir); - char *cs_asm = NULL, *ws_asm = NULL; - size_t cs_n = 0, ws_n = 0; - - FILE *f = fopen(src, "wb"); - if (!f) { - fprintf(stderr, "sumtype_forward[%s]: cannot create source: %s\n", - r->label, strerror(errno)); - fail++; total++; - goto cleanup; - } - int write_failed = fputs(r->src, f) == EOF; - if (fclose(f) != 0) write_failed = 1; - if (write_failed) { - fprintf(stderr, "sumtype_forward[%s]: cannot write source\n", - r->label); - fail++; total++; - goto cleanup; - } - - /* Byte-id of the helper(needles[i]) callsite window. Emit - * each stage's .s explicitly to a known path inside tmpdir - * (w6c emits no .sepwork, so no leak) and compare. Only the - * first row has a main.helper call; rows 2/3 also have one - * but a simpler shape — match them all for symmetry. */ - if (have_w6cww) { - char emit[1100]; - total++; - snprintf(emit, sizeof emit, "%s -o %s %s 2>/dev/null", - cw6, css, src); - if (runwait(emit) != 0) { - fprintf(stderr, - "sumtype_forward[cstage][%s]: w6c failed\n", - r->label); - fail++; - goto cleanup; - } - cs_asm = read_file(css, &cs_n); - if (cs_asm == NULL) { - fprintf(stderr, - "sumtype_forward[cstage][%s]: cannot read %s\n", - r->label, css); - fail++; - goto cleanup; - } - snprintf(emit, sizeof emit, "%s -o %s %s 2>/dev/null", - ww6, wss, src); - if (runwait(emit) != 0) { - fprintf(stderr, - "sumtype_forward[wwstage][%s]: w6c_ww failed\n", - r->label); - fail++; - goto cleanup; - } - ws_asm = read_file(wss, &ws_n); - if (ws_asm == NULL) { - fprintf(stderr, - "sumtype_forward[wwstage][%s]: cannot read %s\n", - r->label, wss); - fail++; - goto cleanup; - } - const char *cs_site = helper_callsite(cs_asm); - const char *ws_site = helper_callsite(ws_asm); - if (!cs_site || !ws_site) { - fprintf(stderr, - "sumtype_forward[bid][%s]: no callsite anchor\n", - r->label); - fail++; - } else if (strncmp(cs_site, ws_site, 96) != 0) { - fprintf(stderr, - "sumtype_forward[bid][%s]: callsite asm diverged\n", - r->label); - fprintf(stderr, " cs: %.96s\n", cs_site); - fprintf(stderr, " ws: %.96s\n", ws_site); - fail++; - } - } - - cleanup: ; - free(cs_asm); - free(ws_asm); - int cleanup_fail = 0; - const char *files[] = { src, css, wss }; - for (size_t k = 0; k < sizeof files / sizeof files[0]; k++) { - if (unlink(files[k]) != 0 && errno != ENOENT) { - fprintf(stderr, "sumtype_forward[%s]: unlink %s: %s\n", - r->label, files[k], strerror(errno)); - cleanup_fail = 1; - } - } - if (rmdir(tmpdir) != 0) { - fprintf(stderr, "sumtype_forward[%s]: rmdir %s: %s\n", - r->label, tmpdir, strerror(errno)); - cleanup_fail = 1; - } - if (cleanup_fail) fail++; - } - - if (fail) { - fprintf(stderr, - "sumtype_forward: %d/%d rows failed\n", fail, total); - return 1; - } - printf("sumtype_forward: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/765_star_fn_deref.c b/test/wcc/765_star_fn_deref.c deleted file mode 100644 index 6394026b..00000000 --- a/test/wcc/765_star_fn_deref.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - * 765_star_fn_deref — root-cause lock for project #185. Pre-fix master - * (5478695 baseline, post-#180), the cgen N_UN TK_STAR arm applied - * the generic pointer-load `MOVQ (AX), AX` to a *fn operand. cgexpr - * on the operand already left AX = fn-addr (post-#180 LEAQ); the - * spurious second load then read the first instruction word and the - * subsequent CALL AX jumped through that junk address, segfaulting. - * - * Fix: cmd/w6c/cgen.c N_UN TK_STAR opens with a TY_NAMED-peel + - * TY_FN early-break — leave AX as the fn-addr cgexpr produced. - * Selfhost twin in selfhost/cmd/wcc/cgenexpr.ww cgun TK_STAR uses the - * same shape via tinfo.kind walk (TY_NAMED peel then TY_FN check), - * mirroring ref/harec/src/check.c expr_call's - * STORAGE_POINTER→STORAGE_FUNCTION path (harec skips the deref since - * the pointer IS the address). - * - * #181 deferral: wwstage's checker bails asserttyped on the - * `(*f)(...)` deref-call N_CALL shape (filed as project #181 — type_ - * stamp gap on the call-of-derefed-fn-ptr). Until #181 lands the - * wwstage rows can't even reach cgen, so every row in this fixture - * is gated CSTAGE-ONLY via stage_mask. Symmetry of the wwstage cgen - * change is covered indirectly by the 990-997 self-build byte-id - * gates (any cgen-side asymmetry would surface there); #181's own - * probe will lock the wwstage runtime once the bail lifts. - * - * GATE-BLIND RISK (ken's note): byte-id alone cannot catch this - * class — both stages drop the SAME instruction symmetrically, so - * cs.s == ww.s holds either way. Runtime exit-code is the only - * correctness net here, hence the multi-row table covering callee - * shapes that exercise distinct ABI codepaths. - * - * Coverage: - * 1. minimal — `let f = &add1; (*f)(7) == 8` - * 2. branched_callee — pick aa or bb by runtime cond; verify - * the SELECTED fn is actually invoked - * (#105 lesson: single-callee masks via - * address-constant aliasing) - * 3. alias_chain — `let f = &fn; let g = f; (*g)(7)` — - * catches if cgen re-evaluates *f after - * the assignment - * 4. fn_with_args — multiple args, scalar + ptr mix; ABI - * register layout survives the deref- - * call - * 5. fn_tuple_return — (i64, str) return shape; multi-reg - * return ABI survives the deref-call - * - * Gates per row: - * a. cstage builds (exit 0); proves the checker stamps the - * deref-call N_CALL on the cstage side. - * b. cstage runs and exits with the row's expected_exit; pre-fix - * every row was 139 (SIGSEGV). - * - * GATE POLARITY: must stay GREEN. A red here means either the cgen - * TK_STAR TY_FN early-break regressed, or stage symmetry drifted - * far enough to surface here (unlikely while wwstage rows stay - * gated off). - */ -#include -#include -#include -#include -#include -#include -#include "wwtestpkg.h" - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -/* stage_mask bits — every row is cstage-only until #181 lifts the - * wwstage asserttyped bail on `(*f)(x)`. STAGE_WW defined for - * structural parity with 764. */ -#define STAGE_CS 1 -#define STAGE_WW 2 - -struct row { - const char *label; - const char *src; - int expected_exit; - int stage_mask; -}; - -static const struct row rows[] = { - { "minimal", - "fn add1(x: i32) i32 = { return x + 1; };\n" - "export fn main() i32 = {\n" - " let f: *fn(x: i32) i32 = &add1;\n" - " return (*f)(7);\n" - "};\n", - 8, - STAGE_CS }, - /* Branched-callee: the if-arm forces a runtime choice between - * two distinct fn addresses, defeating any constant-aliasing - * mask of the deref miscompile (#105 lesson). */ - { "branched_callee", - "fn aa(x: i32) i32 = { return x; };\n" - "fn bb(x: i32) i32 = { return x + 100; };\n" - "export fn main() i32 = {\n" - " let pick: i32 = 1;\n" - " let f: *fn(x: i32) i32 = &aa;\n" - " if (pick != 0) { f = &bb; };\n" - " return (*f)(7);\n" - "};\n", - 107, - STAGE_CS }, - { "alias_chain", - "fn add1(x: i32) i32 = { return x + 1; };\n" - "export fn main() i32 = {\n" - " let f: *fn(x: i32) i32 = &add1;\n" - " let g: *fn(x: i32) i32 = f;\n" - " return (*g)(7);\n" - "};\n", - 8, - STAGE_CS }, - { "fn_with_args", - "fn many(a: i32, b: i32, p: *i32) i32 = { return a + b + *p; };\n" - "export fn main() i32 = {\n" - " let z: i32 = 5;\n" - " let f: *fn(a: i32, b: i32, p: *i32) i32 = &many;\n" - " return (*f)(3, 7, &z);\n" - "};\n", - 15, - STAGE_CS }, - /* Tuple-return: exercises the multi-register return ABI through - * the deref-call. Tagged size 16B+ would also hit the AX:DX:CX - * convention; (i64, str) keeps it simple while still covering - * the multi-reg path. */ - { "fn_tuple_return", - "fn pair(x: i32) (i32, i32) = { return (x, x + 1); };\n" - "export fn main() i32 = {\n" - " let f: *fn(x: i32) (i32, i32) = &pair;\n" - " let a, b = (*f)(7);\n" - " return a + b;\n" - "};\n", - 15, - STAGE_CS }, -}; - -static int -write_source(const char *src_path, const char *src) -{ - FILE *f = fopen(src_path, "wb"); - if (!f) return -1; - wwtest_fputs(src, f); - int rc = ferror(f) ? -1 : 0; - if (fclose(f) != 0) rc = -1; - return rc; -} - -static int -cleanup_tmp(const char *tmpdir) -{ - char p[512]; - int rc = 0; - snprintf(p, sizeof p, "%s/main765.ww", tmpdir); - if (unlink(p) != 0 && errno != ENOENT) rc = -1; - snprintf(p, sizeof p, "%s/main765", tmpdir); - if (unlink(p) != 0 && errno != ENOENT) rc = -1; - snprintf(p, sizeof p, "rm -rf %s/main765.sepwork", tmpdir); - if (runwait(p) != 0) rc = -1; - if (rmdir(tmpdir) != 0) rc = -1; - return rc; -} - -static int -build_via_driver(const char *driver, const char *outbin, const char *src) -{ - char cmd[1024]; - snprintf(cmd, sizeof cmd, "timeout 180 %s build -o %s %s 2>/dev/null", - driver, outbin, src); - return runwait(cmd); -} - -/* run_row — build + run; returns the binary's exit code (-1 on - * build failure). expected_exit comparison done at the call site. */ -static int -run_row(const char *driver, const struct row *r, int seq) -{ - (void)seq; - char tmpdir[] = "/tmp/wcsfd_XXXXXX"; - char src[256], outbin[512]; - if (mkdtemp(tmpdir) == NULL) return -1; - snprintf(src, sizeof src, "%s/main765.ww", tmpdir); - snprintf(outbin, sizeof outbin, "%s/main765", tmpdir); - int rc = -1; - if (write_source(src, r->src) != 0) { - goto out; - } - if (build_via_driver(driver, outbin, src) == 0) - rc = runwait(outbin); -out: - if (cleanup_tmp(tmpdir) != 0) { - fprintf(stderr, "star_fn_deref[%s]: cleanup failed\n", r->label); - rc = -1; - } - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[1024]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - int seq = 0; - - for (int i = 0; i < n; i++) { - if (rows[i].stage_mask & STAGE_CS) { - total++; - int got = run_row(cdrv, &rows[i], seq++); - if (got != rows[i].expected_exit) { - fprintf(stderr, - "star_fn_deref[cstage][%s]: exit=%d want=%d\n", - rows[i].label, got, rows[i].expected_exit); - fail++; - } - } - /* STAGE_WW path intentionally absent — see header #181 - * deferral note. When #181 lands and the wwstage runtime - * gate flips on, mirror the 764 wdrv runwait pattern. */ - } - - if (fail) { - fprintf(stderr, "star_fn_deref: %d/%d fixtures failed\n", - fail, total); - return 1; - } - printf("star_fn_deref: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/771_widen_transitive.c b/test/wcc/771_widen_transitive.c deleted file mode 100644 index dada6599..00000000 --- a/test/wcc/771_widen_transitive.c +++ /dev/null @@ -1,234 +0,0 @@ -/* - * 771_widen_transitive — residual artifact owner. - * - * Symmetric runtime and rejection coverage lives in wwfixture under - * test/wcc/data/r771_*. This wrapper retains only compiler-output byte - * identity plus the intentionally C-stage-only spread runtime row. - */ -#include -#include -#include -#include -#include -#include - -struct row { - const char *label; - const char *src; - const char *fixture; - int byte_id; - int cstage_run; - int expected_exit; -}; - -static const struct row rows[] = { - { "spread_alt_widen", - "package main;\n" - "type underread = !i32;\n" - "type nomem = !void;\n" - "type wrapper = !(underread | nomem);\n" - "export fn main() i32 = {\n" - " let u: underread;\n" - " let r: (size | ...wrapper) = u;\n" - " if (r is underread) { return 70; };\n" - " return 99;\n" - "};\n", - NULL, 0, 1, 70 }, - { "direct_flat_variant", - NULL, "test/wcc/data/r771_direct_flat_variant/case.ww", - 1, 0, 71 }, - { "branched_callee_widen", - NULL, "test/wcc/data/r771_branched_callee_widen/case.ww", - 1, 0, 72 }, - { "wrapper_typed_widen", - NULL, "test/wcc/data/r771_wrapper_typed_widen/case.ww", - 1, 0, 73 }, -}; - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} -static int -write_source(const char *path, const char *src) -{ - FILE *f = fopen(path, "wb"); - if (!f) return -1; - int rc = fputs(src, f) == EOF ? -1 : 0; - if (fclose(f) != 0) rc = -1; - return rc; -} - -static int -materialize_source(const char *cwd, const struct row *r, const char *dst) -{ - if (r->src) return write_source(dst, r->src); - char path[1024], buf[4096]; - snprintf(path, sizeof path, "%s/%s", cwd, r->fixture); - FILE *in = fopen(path, "rb"); - if (!in) return -1; - FILE *out = fopen(dst, "wb"); - if (!out) { fclose(in); return -1; } - int rc = 0; - for (;;) { - size_t n = fread(buf, 1, sizeof buf, in); - if (n != 0 && fwrite(buf, 1, n, out) != n) { rc = -1; break; } - if (n < sizeof buf) { - if (ferror(in)) rc = -1; - break; - } - } - if (fclose(out) != 0) rc = -1; - fclose(in); - return rc; -} - -static int -cleanup_tmp(const char *tmpdir, const char *base) -{ - char p[640]; - int rc = 0; - snprintf(p, sizeof p, "%s/%s.ww", tmpdir, base); - if (unlink(p) != 0 && errno != ENOENT) rc = -1; - snprintf(p, sizeof p, "%s/%s", tmpdir, base); - if (unlink(p) != 0 && errno != ENOENT) rc = -1; - snprintf(p, sizeof p, "rm -rf %s/%s.sepwork", tmpdir, base); - if (runwait(p) != 0) rc = -1; - if (rmdir(tmpdir) != 0) rc = -1; - return rc; -} - -static int -build_via_driver(const char *driver, const char *tmpdir, const char *cwd, - const char *src, int asm_only) -{ - char cmd[2048]; - (void)cwd; - snprintf(cmd, sizeof cmd, - "cd %s && b='%s'; timeout 180 %s build %s" - "-o \"${b%%.ww}\" \"$b\" 2>/dev/null", - tmpdir, src, driver, asm_only ? "-S " : ""); - return runwait(cmd); -} - -static int -run_cstage(const char *driver, const char *cwd, const struct row *r, int seq) -{ - (void)seq; - char td[] = "/tmp/r771_r_XXXXXX"; - char src[512], base[64], exe[768]; - if (mkdtemp(td) == NULL) return -1; - snprintf(base, sizeof base, "main771"); - snprintf(src, sizeof src, "%s/%s.ww", td, base); - int rc = -1; - if (materialize_source(cwd, r, src) != 0) goto out; - rc = build_via_driver(driver, td, cwd, src, 0); - if (rc == 0) { - snprintf(exe, sizeof exe, "%s/%s", td, base); - rc = runwait(exe); - } -out: - if (cleanup_tmp(td, base) != 0) { - fprintf(stderr, "widen_transitive[%s]: run cleanup failed\n", - r->label); - rc = -1; - } - return rc; -} - -static int -asm_byte_identical(const char *cdrv, const char *wdrv, const char *cwd, - const struct row *r, int seq) -{ - (void)seq; - char tc[] = "/tmp/r771_c_XXXXXX"; - char tw[] = "/tmp/r771_w_XXXXXX"; - char src[512], base[64], cs[512], ws[512]; - snprintf(base, sizeof base, "main771"); - if (mkdtemp(tc) == NULL) return -1; - if (mkdtemp(tw) == NULL) { - if (cleanup_tmp(tc, base) != 0) - fprintf(stderr, "widen_transitive[%s]: setup cleanup failed\n", - r->label); - return -1; - } - int rc = -1; - snprintf(src, sizeof src, "%s/%s.ww", tc, base); - if (materialize_source(cwd, r, src) != 0) goto out; - if (build_via_driver(cdrv, tc, cwd, src, 1) != 0) goto out; - snprintf(cs, sizeof cs, "%s/%s.sepwork/__root.s", tc, base); - snprintf(src, sizeof src, "%s/%s.ww", tw, base); - if (materialize_source(cwd, r, src) != 0) goto out; - if (build_via_driver(wdrv, tw, cwd, src, 1) != 0) goto out; - snprintf(ws, sizeof ws, "%s/%s.sepwork/__root.s", tw, base); - FILE *fc = fopen(cs, "rb"), *fw = fopen(ws, "rb"); - if (fc && fw) { - rc = 0; - for (;;) { - int a = fgetc(fc), b = fgetc(fw); - if (a != b) { rc = -1; break; } - if (a == EOF) break; - } - } - if (fc) fclose(fc); - if (fw) fclose(fw); -out: - if (cleanup_tmp(tc, base) != 0) { - fprintf(stderr, "widen_transitive[%s]: c cleanup failed\n", r->label); - rc = -1; - } - if (cleanup_tmp(tw, base) != 0) { - fprintf(stderr, "widen_transitive[%s]: ww cleanup failed\n", r->label); - rc = -1; - } - return rc; -} - -int -main(void) -{ - char cwd[512]; - if (!getcwd(cwd, sizeof cwd)) return 1; - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[1024]; - if (bin[0] != '/') { - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - char cdrv[1200], wdrv[1200]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - int fail = 0, total = 0, seq = 0; - int wwpresent = access(wdrv, X_OK) == 0; - for (size_t i = 0; i < sizeof rows / sizeof rows[0]; i++) { - if (rows[i].cstage_run) { - total++; - int got = run_cstage(cdrv, cwd, &rows[i], seq++); - if (got != rows[i].expected_exit) { - fprintf(stderr, "widen_transitive[cstage-only run][%s]: exit=%d want=%d\n", - rows[i].label, got, rows[i].expected_exit); - fail++; - } - } - if (wwpresent && rows[i].byte_id) { - total++; - if (asm_byte_identical(cdrv, wdrv, cwd, &rows[i], seq++) != 0) { - fprintf(stderr, "widen_transitive[byte-id][%s]: assembly differs\n", - rows[i].label); - fail++; - } - } - } - if (!wwpresent) fprintf(stderr, "widen_transitive: skip byte-id (no %s)\n", wdrv); - if (fail) { - fprintf(stderr, "widen_transitive: %d/%d residual gates failed\n", fail, total); - return 1; - } - printf("widen_transitive: %d/%d residual gates ok\n", total, total); - return 0; -} diff --git a/test/wcc/779_log_vstream_run.c b/test/wcc/779_log_vstream_run.c deleted file mode 100644 index 8e18a6c1..00000000 --- a/test/wcc/779_log_vstream_run.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - * 779_log_vstream_run — project #94 fold-eFinal sentinel. Pins the - * single-surface lib/log: module-static stderrsink_ctx_g with - * `vt: io.vtable` as the first field for the intrusive cast, the 10 - * exported variants of log.ww's surface (new / lprintln / println / - * lprintfln / printfln / lfatal / fatal / lfatalf / fatalf / - * setlogger), a logger vtable + stdlogger over an io.stream sink, and - * lazy ensureinit wiring the stderr default + silent / default / - * global *logger globals. The fold-eFinal FLIP collapsed the dual - * surface into this one Hare-shaped surface (bare names, no suffix). - * - * Each row imports os + log + memio + io. log itself imports fmt, - * so the formattable / field types flow through transitively. - * - * Cstage-only per row (no STAGE_WW, no byte_id). #209 (the wwstage - * checker bail on match-arm-over-formattable when fmt is imported - * transitively — which lib/log does for the logger vtable signatures + - * the fmt.fprint / fprintf dispatch in stdprintln / stdprintfln) is now - * CLOSED; wwstage compiles fmt/log. The residual blocker is the - * pre-existing cgen cluster #226 (io.read error-remap nominal-identity) - * + #227 (spread-union widen/return-ABI), surfaced once fmt codegens - * under wwstage. Existing 971 logtest runs the @test fixture under - * cstage `ww run` only. 995 self-rebuild dodges it because no selfhost - * cmd imports log transitively. Byte-id graduates when #226 (+#227) land. - * - * row | what it pins - * --------------------------+-------------------------------------- - * println_v_default_stderr | log.println through the [[default]] - * | global, routed to fd 2 via the - * | module-static stderrsink_ctx_g. Asserts - * | ensureinit wires + dispatches without - * | crashing; stderr capture is left to the - * | shell runner. Pins the full chain: - * | println → lprintln(global) → - * | (*logger).println → stdprintln → - * | fmt.fprint + io.write("\n"). - * printfln_v_default_stderr | Same chain as row 1 but through the - * | format-string slot (printfln → - * | lprintfln(global) → stdprintfln - * | → fmt.fprintf + io.write("\n")). - * | Pins the {n}-placeholder dispatch - * | through vformatfield reaches the - * | default sink. - * lprintln_v_custom_sink | memio.fixed-backed stdlogger; - * | log.new wires the vtable + sink, - * | log.lprintln dispatches "hi" + 7i64 - * | through stdprintln. Asserts the - * | exact bytes ("hi 7\n") land in the - * | caller's buffer (fixed borrows - * | the slice, so the bytes are visible - * | back through buf[]). - * branched_lprintln | branched callee per #105: two distinct - * | stdlogger sinks runtime-selected via - * | *logger pointer. lprintln dispatches - * | through the picked sink only; the - * | other stays empty. Catches a constant- - * | fold mistake in the fn-ptr dispatch - * | (mirror of 778's branched_bufio_wrap). - * - * DEFERRALS / RELATED (NOT addressed by this row): - * - * - #206 (bare &fn → (*alias|void)): 2 cast sites at ensureinit - * in lib/log/log.ww; the explicit casts are KEPT (ken/#214 — - * cast-drop is a separate deferred payoff gated on #214). - * - * - #173 (TRY-on-tagged-return both-stages broken): stderrwrite - * constructs nomem and widens to io.error explicitly rather than - * using `os.trywrite(...)?`; same shape memio.ww + fmt.ww + - * bufio.ww adopt. - * - * - #226 (io.read error-remap nominal-identity) + #227 (spread-union - * widen/return-ABI): every row is STAGE_CS-only; byte-id deferred - * until they land. #209 (the checker bail) is already closed. - * - * BOOTSTRAP-EMBED CHECK: log is NOT embedded in any selfhost - * combined.ww (grep `package log\|import log` returns empty), so the - * fold-eFinal log collapse does not require a Makefile regen (#110); - * only lib/log/ + lib/fmt/ test paths see the surface. 990-997 - * byte-id gates stay green by virtue of log being test-only. - * - * GATE POLARITY: must stay GREEN. A red here means lib/log - * regressed, the module-static stderrsink_ctx_g zero-init or chained - * vt-field assigns regressed, the intrusive io.stream→*stderrsink_ctx - * cast miscomputed offsets, ensureinit's one-shot guard broke, or - * the fn-ptr dispatch through logger.println / printfln stopped - * resolving. - */ -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -#define STAGE_CS 1 -#define STAGE_WW 2 - -struct row { - const char *label; - const char *src; - int want_exit; - int stage_mask; - int byte_id; -}; - -static const struct row rows[] = { - { "println_v_default_stderr", - "package main;\n" - "import os;\n" - "import log;\n" - "export fn main() i32 = {\n" - " log.println(\"hello\");\n" - " return 42;\n" - "};\n", - 42, - STAGE_CS, 0 }, - { "printfln_v_default_stderr", - "package main;\n" - "import os;\n" - "import log;\n" - "export fn main() i32 = {\n" - " log.printfln(\"v={}\", 7i64);\n" - " return 43;\n" - "};\n", - 43, - STAGE_CS, 0 }, - { "lprintln_v_custom_sink", - "package main;\n" - "import os;\n" - "import log;\n" - "import memio;\n" - "import io;\n" - "export fn main() i32 = {\n" - " let buf: [16]u8;\n" - " let st: memio.stream = memio.fixed(buf[0:16]);\n" - " let vs: io.stream = &st.vt;\n" - " let sl: log.stdlogger = log.new(vs);\n" - " log.lprintln(&sl.logger, \"hi\", 7i64);\n" - " if (buf[0] != 104u8) { return 91; };\n" - " if (buf[1] != 105u8) { return 92; };\n" - " if (buf[2] != 32u8) { return 93; };\n" - " if (buf[3] != 55u8) { return 94; };\n" - " if (buf[4] != 10u8) { return 95; };\n" - " return 44;\n" - "};\n", - 44, - STAGE_CS, 0 }, - { "branched_lprintln", - "package main;\n" - "import os;\n" - "import log;\n" - "import memio;\n" - "import io;\n" - "export fn main() i32 = {\n" - " let bufA: [16]u8;\n" - " let bufB: [16]u8;\n" - " let stA: memio.stream = memio.fixed(bufA[0:16]);\n" - " let vsA: io.stream = &stA.vt;\n" - " let stB: memio.stream = memio.fixed(bufB[0:16]);\n" - " let vsB: io.stream = &stB.vt;\n" - " let slA: log.stdlogger = log.new(vsA);\n" - " let slB: log.stdlogger = log.new(vsB);\n" - " let sel: i32 = 1;\n" - " let chosen: *log.logger = &slA.logger;\n" - " if (sel == 0) { chosen = &slB.logger; };\n" - " log.lprintln(chosen, \"pick\");\n" - " if (bufA[0] != 112u8) { return 91; };\n" - " if (bufA[1] != 105u8) { return 92; };\n" - " if (bufA[2] != 99u8) { return 93; };\n" - " if (bufA[3] != 107u8) { return 94; };\n" - " if (bufA[4] != 10u8) { return 95; };\n" - " if (bufB[0] != 0u8) { return 96; };\n" - " return 45;\n" - "};\n", - 45, - STAGE_CS, 0 }, -}; - -static int -write_source(const char *path, const char *src) -{ - FILE *f = fopen(path, "wb"); - if (!f) return -1; - int bad = fputs(src, f) == EOF || ferror(f); - if (fclose(f) != 0) bad = 1; - return bad ? -1 : 0; -} - -/* Per-row tmpdir cleanup. `ww build` retains its exact - * .sepwork tree; remove that tree, the source, and the bare - * executable before removing the invocation-owned directory. */ -static int -cleanup_tmp(const char *tmpdir, const char *base) -{ - char p[640]; - int rc = 0; - snprintf(p, sizeof p, "%s/%s.ww", tmpdir, base); - if (unlink(p) != 0 && errno != ENOENT) rc = -1; - snprintf(p, sizeof p, "rm -rf -- %s/%s.sepwork", tmpdir, base); - if (runwait(p) != 0) rc = -1; - snprintf(p, sizeof p, "%s/%s", tmpdir, base); - if (unlink(p) != 0 && errno != ENOENT) rc = -1; - if (rmdir(tmpdir) != 0) rc = -1; - return rc; -} - -static int -build_via_driver(const char *driver, const char *tmpdir, const char *cwd, - const char *src) -{ - char cmd[2048]; - snprintf(cmd, sizeof cmd, - "cd %s && timeout 180 %s build -I %s/lib %s 2>/dev/null", - tmpdir, driver, cwd, src); - return runwait(cmd); -} - -static int -run_row(const char *driver, const char *cwd, const struct row *r, int seq) -{ - char tmpdir[256], src[512], base[64], outbin[768]; - snprintf(tmpdir, sizeof tmpdir, "/tmp/lvs_%d_d_%d", getpid(), seq); - snprintf(base, sizeof base, "main779"); - snprintf(src, sizeof src, "%s/%s.ww", tmpdir, base); - if (mkdir(tmpdir, 0755) != 0) return -1; - if (write_source(src, r->src) != 0) { - if (cleanup_tmp(tmpdir, base) != 0) - fprintf(stderr, "row[%s]: setup cleanup failed\n", r->label); - return -1; - } - int rc; - int br = build_via_driver(driver, tmpdir, cwd, src); - if (br == 0) { - snprintf(outbin, sizeof outbin, "%s/%s", tmpdir, base); - /* Suppress stderr for rows 1/2 — the default-sink probes - * write through fd 2; don't pollute the test runner's - * stderr. */ - char runcmd[1024]; - snprintf(runcmd, sizeof runcmd, "%s 2>/dev/null", outbin); - rc = runwait(runcmd); - } else { - rc = -1; - } - if (cleanup_tmp(tmpdir, base) != 0) return -1; - return rc; -} - -/* asm_byte_identical — diff cstage vs wwstage .s. Parallel trees keep - * each driver's retained .sepwork output separate. Unused - * for fold-e5 — every row is STAGE_CS-only per #226/#227 (#209, the - * checker bail, is closed) — but kept scaffolded for when those cgen - * folds land and byte-id graduates. */ -static int -asm_byte_identical(const char *cdrv, const char *wdrv, const char *cwd, - const struct row *r, int seq) -{ - char src[512], tdc[256], tdw[256], base[64], cs[512], ws[512]; - snprintf(tdc, sizeof tdc, "/tmp/lvs_%d_c_%d", getpid(), seq); - snprintf(tdw, sizeof tdw, "/tmp/lvs_%d_w_%d", getpid(), seq); - snprintf(base, sizeof base, "main779"); - if (mkdir(tdc, 0755) != 0) return -1; - if (mkdir(tdw, 0755) != 0) { - if (cleanup_tmp(tdc, base) != 0) - fprintf(stderr, "row[%s]: setup cleanup failed\n", r->label); - return -1; - } - snprintf(src, sizeof src, "%s/%s.ww", tdc, base); - if (write_source(src, r->src) != 0) { - int clean_c = cleanup_tmp(tdc, base); - int clean_w = cleanup_tmp(tdw, base); - if (clean_c != 0 || clean_w != 0) - fprintf(stderr, "row[%s]: setup cleanup failed\n", r->label); - return -1; - } - int rc = -1; - if (build_via_driver(cdrv, tdc, cwd, src) != 0) goto out; - snprintf(cs, sizeof cs, "%s/%s.sepwork/__root.s", tdc, base); - - snprintf(src, sizeof src, "%s/%s.ww", tdw, base); - if (write_source(src, r->src) != 0) goto out; - if (build_via_driver(wdrv, tdw, cwd, src) != 0) goto out; - snprintf(ws, sizeof ws, "%s/%s.sepwork/__root.s", tdw, base); - - FILE *fc = fopen(cs, "rb"); - FILE *fw = fopen(ws, "rb"); - if (fc && fw) { - rc = 0; - for (;;) { - int a = fgetc(fc); - int b = fgetc(fw); - if (a != b) { rc = -1; break; } - if (a == EOF) break; - } - } - if (fc) fclose(fc); - if (fw) fclose(fw); -out: - if (cleanup_tmp(tdc, base) != 0) rc = -1; - if (cleanup_tmp(tdw, base) != 0) rc = -1; - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char cwd[256]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - char absbin[512]; - if (bin[0] != '/') { - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[640], wdrv[640]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - int wwpresent = (access(wdrv, X_OK) == 0); - int seq = 0; - - for (int i = 0; i < n; i++) { - if (rows[i].stage_mask & STAGE_CS) { - total++; - int got = run_row(cdrv, cwd, &rows[i], seq++); - if (got != rows[i].want_exit) { - fprintf(stderr, - "log_vstream_run[cs][%s]: exit=%d want=%d\n", - rows[i].label, got, rows[i].want_exit); - fail++; - } - } - if (wwpresent && (rows[i].stage_mask & STAGE_WW)) { - total++; - int got = run_row(wdrv, cwd, &rows[i], seq++); - if (got != rows[i].want_exit) { - fprintf(stderr, - "log_vstream_run[ww][%s]: exit=%d want=%d\n", - rows[i].label, got, rows[i].want_exit); - fail++; - } - if (rows[i].byte_id) { - total++; - if (asm_byte_identical(cdrv, wdrv, cwd, &rows[i], seq++) != 0) { - fprintf(stderr, - "log_vstream_run[byte-id][%s]: cstage vs wwstage asm differs\n", - rows[i].label); - fail++; - } - } - } - } - - if (!wwpresent) - fprintf(stderr, "log_vstream_run: skip wwstage (no %s)\n", wdrv); - - if (fail) { - fprintf(stderr, "log_vstream_run: %d/%d fixtures failed\n", - fail, total); - return 1; - } - printf("log_vstream_run: %d/%d ok\n", total, total); - return 0; -} diff --git a/test/wcc/805_placeaddr_store.c b/test/wcc/805_placeaddr_store.c deleted file mode 100644 index 0102aa5d..00000000 --- a/test/wcc/805_placeaddr_store.c +++ /dev/null @@ -1,1525 +0,0 @@ -/* - * 805_placeaddr_store — cstage and wwstage agree, byte-for-byte and at - * runtime, that a store through a deref-of-pointer-to-slice/array - * element field — `(*ts)[i].field = v` and `(*ts)[i].field OP= v` — - * lands the value (F6, task #4 of the regex fold-2b blockers; the - * run_thread hot shape `threads: *[]thread`). - * - * Pre-C1 BOTH stages compiled this shape to NOTHING, byte-identically: - * the lhs N_DOT spine roots at N_UN(STAR), so the `arr[i].field` arm - * (idxbase must be N_IDENT) and the chained-ptr-field arm (base must - * be *struct) both miss, and the N_ASSIGN dispatch fell off the switch - * silently — rhs never even evaluated. The fix routes base-address - * derivation through the cgplaceaddr resolver (cmd/w6c/cgen.c, mirror - * selfhost/cmd/wcc/cgenexpr.ww); each call-site keeps its own - * load/store emission, and every N_DOT lvalue the resolver can't - * address now dies LOUD ("unsupported assign target shape") instead of - * silently dropping (rule 7). C1.25 (#23) wires the aggregate field - * STORE on top of the resolver: literal rhs materialises into a FRESH - * per-use @placescr slot then word-copies to the resolved address; - * addressable rhs (ident/global/dot/deref) takes its source address - * straight from the #265/#268 dispatch. Field kinds the resolver arm - * does not wire yet (float / tagged / aggregate-compound / str-slice - * compound / call-rhs into aggregate) hard-stop with their own - * diagnostics — the reject rows pin the exact text on BOTH stages. - * Non-DOT lvalue tail residue is task #22. - * - * C2 (F4 + FA3-cstage, task #6): the READ side. cgplaceaddr grew an - * N_IDENT root and recursion-driven N_INDEX bases; case N_DOT routes - * every TYPED read no enumerated arm matched through the resolver, and - * BOTH silent fallbacks died: the module-leaf `MOVQ (SB)` is - * gated to UNTYPED chains (pre-C2 it swallowed any unmatched dot chain - * — a silent global read of a colliding symbol), and the offset-blind - * cgexpr catch-all is gated to untyped-str pseudo-fields (pre-C2 a - * nonzero-offset field behind a deref-index spine read element word 0; - * offset-0 scalars worked by coincidence). TK_AMP's silent tail is the - * same resolver-or-loud (`&threads[0].cap` used to SEGFAULT on deref, - * reviewer-A route). The C1.25 raw-byte readbacks graduate to typed - * depth-2 reads below. wwstage cgdot/cgun mirror symmetrically; the - * ptr-chained global-root remainder stays LOUD (task #37). - * - * C3 (F7+F10, task #8): wwstage's cgdot N_INDEX-base arm re-keyed from - * tnode KINDs + structlookup-by-name onto the checker-stamped tinfo - * (#209/#211 name-keyed→tinfo-SSoT cluster), mirroring cstage's arm - * 1:1. Pre-C3 a base typed via an N_TNAME alias (`type result = - * []capture`) missed the name-keyed arm and died at the interim C2 - * loud guard (and pre-C2, fell silently into the SB fallback). The - * c3_* rows below pin the alias-typed base class plus the composed - * regex hot shape and the free()-operand consumption (FA6). - * - * row | shape | want - * --------------------+----------------------------------------+------ - * store_size_neighbor | (*ts)[1].pc = 9, elem 0 intact | 19 - * store_bool_compound | p7a4 verbatim: =, +=, bool store | 0 - * widths_unsigned | u8/u16/u32 stores (MOVB/MOVW/MOVL) | 42 - * widths_signed | i8/i16/i32 negative stores + readback | 43 - * compound_ops | += -= *= |= /= (DIVQ + IDIVQ) %= <<= | 44 - * str_field_member | (*ts)[i].name = "hi" (3-word header) | 45 - * array_base_deref | (*ta)[i].pc via *[3]t, = and += | 46 - * runtime_call_idx | (*ts)[geti()].pc — call-idx clobber | 47 - * compound_bits_shr | &= ^= >>= signed (SARQ) + uns (SHRQ) | 48 - * compound_narrow | u8/i8/i16/u16/i32/u32 OP= (narrow | 49 - * | fldloadop: MOVSBQ/MOVZBQ/MOVSWQ/...) | - * slice_field_member | (*ts)[i].xs = s ([]i64, 3-word header) | 50 - * neutral_ident_bases | x.f / a[i].f / p.f = and += (untouched | 51 - * | enumerated arms — runtime-pins the | - * | resolver's asm-neutrality claim) | - * agg_structlit_40b | C1.25: 40B capture literal store via | 52 - * | fresh @placescr + word-copy, incl ... | - * agg_from_ident_deref| C1.25: aggregate from ident + *p rhs | 53 - * agg_nested_lit | C1.25: nested struct literal (#18) | 54 - * agg_array_field_odd | C1.25: [3]u8 field, MOVW/MOVB tails | 55 - * agg_fresh_two_stores| C1.25: two same-size structlit stores | 56 - * | in ONE fn — distinct @placescr slots | - * agg_array_field_movl| C1.25: [3]u32 field, MOVQ+MOVL tail | 57 - * reject_agg_compound | compound on aggregate field | BUILD_FAIL - * reject_agg_call_sret| >24B call rhs (#234-tail) | BUILD_FAIL - * reject_agg_call_reg | ≤24B call rhs (task #24) | BUILD_FAIL - * reject_float | f64 field store | BUILD_FAIL - * reject_tagged | tagged-union field store | BUILD_FAIL - * reject_str_compound | (*ts)[i].name += — str/slice compound | BUILD_FAIL - * arr_field_idx_store | h.arr[1].pc = / += (C1's reject_tail, | 58 - * | graduated by the C2 resolver arms) | - * read_depth2_idx | ts[i].cap.start/.end/.content.len — | 59 - * | typed depth-2 behind an IDENT index | - * read_depth2_deref | (*ts)[i].cap.start + offset-0 .pc | 60 - * read_widths_spine | i8..u32/f64/f32/[3]u8 behind (*p)[i] | 61 - * read_slicefield | let h = (*p)[i].xs (FA3/pA5) + .cap | 62 - * amp_spine | &ts[1].cap / &(*p)[0].cap — deref, | 63 - * | compound through the pointer | - * neutral_reads | ident-root chain, "abc".len, (*p).f — | 64 - * | untouched-arm asm-neutrality pins | - * reject_read_tagged | (*ts)[i].tg read behind spine | BUILD_FAIL - * reject_read_callbase| mk()[0].pc read (unaddressable base) | BUILD_FAIL - * reject_assign_callbs| mk()[0].pc = (assign-tail text keeps | BUILD_FAIL - * | its carrier post arr_field_idx_store) | - * reject_addrof_callbs| &mk()[0].pc (TK_AMP loud tail) | BUILD_FAIL - * c3_alias_slice_reads| F10: alias-slice base l[i].f — narrow | 65 - * | signed/unsigned, i64, f64, str, []T, | - * | [N]T-field-then-index | - * c3_alias_arr_viaptr | F10: alias [2]S base + alias []*S | 66 - * | (viaptr element) reads | - * c3_letbound_alias | p11b essence sans task-#14 `?`: let | 67 - * | m: result = f(); m[i].field reads | - * c3_composed_match | F7: match(re.insts[(*ts)[i].pc]) + | 68 - * | (*ts)[i] compound/store (p7 hot shape) | - * c3_free_operand | FA6: free((*ts)[i].slicefield) reads | 69 - * | through the operand (pA9) | - * c4_let_slice_elem | F5: let e = xs[0], 16B struct elem | 70 - * | (p6min13 graduated — cstage emitted | - * | NOTHING, wwstage 8B truncation) | - * c4_let_elem_sizes | F5: 24B/40B/12B(MOVQ+MOVL tail) elems | 71 - * c4_let_deref_leaf | reviewer-C2 inheritance: let c = | 72 - * | (*ts)[i].cap (40B leaf behind deref | - * | spine; ww loud retired, cs no-copy | - * | fixed) | - * c4_range_byvalue | F5/FC0: by-value range payload full- | 73 - * | width copy — []struct (sum BOTH | - * | fields), []capture 40B (str field | - * | header), []str (24B header .len) | - * c4_range_edges | range edges: empty slice (zero iters), | 74 - * | binder MUTATION (by-VALUE: writes must | - * | not reach the slice), 12B elem | - * | (MOVQ+MOVL tail in the range copy) | - * reject_let_unhandled| `let p: pair = mk()!` — non-place rhs | BUILD_FAIL - * | dies at C4's loud let tail (was | - * | SILENT: cs no init, ww 8B) | - * - * BUILD_FAIL rows also assert the diagnostic TEXT (stderr substring, - * both stages) — a build that fails for any other reason (parse error, - * crash) is a vacuous reject and fails the row. - * - * Every non-BUILD_FAIL row also asserts cstage/wwstage asm byte-id. - */ -#include -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -/* want == BUILD_FAIL: the row must FAIL to build on both stages AND - * emit expect_err on stderr (rule 7 — never a silent acceptance; - * without the message check a row would pass vacuously on any - * unrelated build failure). */ -#define BUILD_FAIL (-2147483647 - 1) - -struct row { - const char *label; - const char *src; - int want; - const char *expect_err; /* BUILD_FAIL rows: required stderr substring */ -}; - -static const struct row rows[] = { - { "store_size_neighbor", - "package main;\n" - "type thread = struct { pc: size, matched: bool };\n" - "fn setpc(ts: *[]thread, i: size) void = { (*ts)[i].pc = 9; };\n" - "export fn main() i32 = {\n" - "\tlet ts: []thread = [];\n" - "\tappend(ts, thread { pc = 1, matched = false });\n" - "\tappend(ts, thread { pc = 2, matched = false });\n" - "\tsetpc(&ts, 1);\n" - "\treturn (ts[0].pc*10 + ts[1].pc): i32;\n" - "};\n", - 19, NULL }, - - /* The original F6 probe (scratch/fold2b_probes/p7a4), graduated - * verbatim: plain scalar store, compound +=, bool store. */ - { "store_bool_compound", - "package main;\n" - "type thread = struct { pc: size, matched: bool };\n" - "fn setpc(ts: *[]thread, i: size) void = {\n" - "\t(*ts)[i].pc = 9;\n" - "};\n" - "fn bump(ts: *[]thread, i: size) void = {\n" - "\t(*ts)[i].pc += 1;\n" - "};\n" - "fn markm(ts: *[]thread, i: size) void = {\n" - "\t(*ts)[i].matched = true;\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet ts: []thread = [];\n" - "\tappend(ts, thread { pc = 7, matched = false });\n" - "\tsetpc(&ts, 0);\n" - "\tif (ts[0].pc != 9) { return 1; };\n" - "\tbump(&ts, 0);\n" - "\tif (ts[0].pc != 10) { return 2; };\n" - "\tmarkm(&ts, 0);\n" - "\tif (!ts[0].matched) { return 3; };\n" - "\treturn 0;\n" - "};\n", - 0, NULL }, - - { "widths_unsigned", - "package main;\n" - "type t = struct { a: u8, b: u16, c: u32 };\n" - "fn seta(ts: *[]t, i: size) void = { (*ts)[i].a = 200u8; };\n" - "fn setb(ts: *[]t, i: size) void = { (*ts)[i].b = 60000u16; };\n" - "fn setc(ts: *[]t, i: size) void = { (*ts)[i].c = 70000u32; };\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { a = 5u8, b = 6u16, c = 7u32 });\n" - "\tappend(ts, t { a = 5u8, b = 6u16, c = 7u32 });\n" - "\tseta(&ts, 1); setb(&ts, 1); setc(&ts, 1);\n" - "\tif (ts[1].a != 200u8) { return 1; };\n" - "\tif (ts[1].b != 60000u16) { return 2; };\n" - "\tif (ts[1].c != 70000u32) { return 3; };\n" - "\tif (ts[0].a != 5u8) { return 4; };\n" - "\tif (ts[0].c != 7u32) { return 5; };\n" - "\treturn 42;\n" - "};\n", - 42, NULL }, - - { "widths_signed", - "package main;\n" - "type t = struct { a: i8, b: i16, c: i32 };\n" - "fn seta(ts: *[]t, i: size) void = { (*ts)[i].a = -7i8; };\n" - "fn setb(ts: *[]t, i: size) void = { (*ts)[i].b = -300i16; };\n" - "fn setc(ts: *[]t, i: size) void = { (*ts)[i].c = -70000i32; };\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { a = 1i8, b = 2i16, c = 3i32 });\n" - "\tappend(ts, t { a = 1i8, b = 2i16, c = 3i32 });\n" - "\tseta(&ts, 1); setb(&ts, 1); setc(&ts, 1);\n" - "\tif (ts[1].a != -7i8) { return 1; };\n" - "\tif (ts[1].b != -300i16) { return 2; };\n" - "\tif (ts[1].c != -70000i32) { return 3; };\n" - "\tif (ts[0].a != 1i8) { return 4; };\n" - "\treturn 43;\n" - "};\n", - 43, NULL }, - - /* All-arm compound coverage: unsigned size /= (DIVQ), signed int - * /= and i64 %= on negatives (CQO+IDIVQ), <<=, and the plain - * += -= *= |= trio on a fourth field. */ - { "compound_ops", - "package main;\n" - "type t = struct { s: int, u: size, n: i64, m: i64 };\n" - "fn divs(ts: *[]t, i: size) void = { (*ts)[i].s /= 4; };\n" - "fn modn(ts: *[]t, i: size) void = { (*ts)[i].n %= 5; };\n" - "fn divu(ts: *[]t, i: size) void = { (*ts)[i].u /= 3; };\n" - "fn shl(ts: *[]t, i: size) void = { (*ts)[i].u <<= 2; };\n" - "fn addm(ts: *[]t, i: size) void = { (*ts)[i].m += 7; };\n" - "fn subm(ts: *[]t, i: size) void = { (*ts)[i].m -= 2; };\n" - "fn mulm(ts: *[]t, i: size) void = { (*ts)[i].m *= 3; };\n" - "fn orm(ts: *[]t, i: size) void = { (*ts)[i].m |= 4; };\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { s = 4, u = 5, n = 6, m = 1 });\n" - "\tappend(ts, t { s = -12, u = 9, n = -13, m = 4 });\n" - "\tdivs(&ts, 1);\n" - "\tif (ts[1].s != -3) { return 1; };\n" - "\tmodn(&ts, 1);\n" - "\tif (ts[1].n != -3) { return 2; };\n" - "\tdivu(&ts, 1);\n" - "\tif (ts[1].u != 3) { return 3; };\n" - "\tshl(&ts, 1);\n" - "\tif (ts[1].u != 12) { return 4; };\n" - "\taddm(&ts, 1);\n" - "\tsubm(&ts, 1);\n" - "\tmulm(&ts, 1);\n" - "\torm(&ts, 1);\n" - "\tif (ts[1].m != 31) { return 5; };\n" - "\tif (ts[0].s != 4) { return 6; };\n" - "\treturn 44;\n" - "};\n", - 44, NULL }, - - /* str field: the rhs leaves {ptr,len,cap} in (AX,BX,CX); the - * place address stages through DX so the triple survives. */ - { "str_field_member", - "package main;\n" - "type t = struct { pc: size, name: str };\n" - "fn setname(ts: *[]t, i: size) void = { (*ts)[i].name = \"hi\"; };\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 1, name = \"\" });\n" - "\tappend(ts, t { pc = 2, name = \"\" });\n" - "\tsetname(&ts, 1);\n" - "\tlet nm: str = ts[1].name;\n" - "\tif (nm.len != 2) { return 1; };\n" - "\tif (nm[0] != 104u8) { return 2; };\n" - "\tif (ts[0].name.len != 0) { return 3; };\n" - "\treturn 45;\n" - "};\n", - 45, NULL }, - - /* *[N]T base: the array place IS the element storage (no .ptr - * hop), unlike the slice-header deref the rows above take. */ - { "array_base_deref", - "package main;\n" - "type t = struct { pc: size, matched: bool };\n" - "fn setarr(ta: *[3]t, i: size) void = { (*ta)[i].pc = 9; };\n" - "fn bumparr(ta: *[3]t, i: size) void = { (*ta)[i].pc += 2; };\n" - "export fn main() i32 = {\n" - "\tlet ta: [3]t;\n" - "\tta[0].pc = 1; ta[1].pc = 2; ta[2].pc = 3;\n" - "\tsetarr(&ta, 1);\n" - "\tif (ta[1].pc != 9) { return 1; };\n" - "\tbumparr(&ta, 1);\n" - "\tif (ta[1].pc != 11) { return 2; };\n" - "\tif (ta[0].pc != 1) { return 3; };\n" - "\tif (ta[2].pc != 3) { return 4; };\n" - "\treturn 46;\n" - "};\n", - 46, NULL }, - - /* Call-result index: cgexpr(idx) inside the resolver clobbers - * caller-saved regs; the spilled rhs and place address must - * survive. */ - { "runtime_call_idx", - "package main;\n" - "type t = struct { pc: size, matched: bool };\n" - "fn geti() size = { return 1; };\n" - "fn setpc(ts: *[]t) void = { (*ts)[geti()].pc = 9; };\n" - "fn bump(ts: *[]t) void = { (*ts)[geti()].pc += 1; };\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 1, matched = false });\n" - "\tappend(ts, t { pc = 2, matched = false });\n" - "\tsetpc(&ts);\n" - "\tif (ts[1].pc != 9) { return 1; };\n" - "\tbump(&ts);\n" - "\tif (ts[1].pc != 10) { return 2; };\n" - "\tif (ts[0].pc != 1) { return 3; };\n" - "\treturn 47;\n" - "};\n", - 47, NULL }, - - /* The remaining compound arms: ANDQ/XORQ, and BOTH >>= forms — - * SARQ (signed, sign bit must replicate) vs SHRQ (unsigned). */ - { "compound_bits_shr", - "package main;\n" - "type t = struct { s: int, u: size, n: i64, m: i64 };\n" - "fn ands(ts: *[]t, i: size) void = { (*ts)[i].m &= 6; };\n" - "fn xors(ts: *[]t, i: size) void = { (*ts)[i].m ^= 3; };\n" - "fn sars(ts: *[]t, i: size) void = { (*ts)[i].s >>= 2; };\n" - "fn shrs(ts: *[]t, i: size) void = { (*ts)[i].u >>= 1; };\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { s = -16, u = 8, n = 0, m = 7 });\n" - "\tands(&ts, 0);\n" - "\tif (ts[0].m != 6) { return 1; };\n" - "\txors(&ts, 0);\n" - "\tif (ts[0].m != 5) { return 2; };\n" - "\tsars(&ts, 0);\n" - "\tif (ts[0].s != -4) { return 3; };\n" - "\tshrs(&ts, 0);\n" - "\tif (ts[0].u != 4) { return 4; };\n" - "\treturn 48;\n" - "};\n", - 48, NULL }, - - /* Narrow-width compounds: the widths rows above only exercise - * plain `=` (fldstoreop); compounds also take the fldloadop - * narrow LOAD (MOVSBQ/MOVZBQ/MOVSWQ/MOVZWQ/MOVSXD/MOVL) — i8/i16 - * negatives pin the sign-extension, u8 250 pins zero-extension. */ - { "compound_narrow", - "package main;\n" - "type t = struct { a: i8, b: u8, c: i16, d: u16, e: i32, f: u32 };\n" - "fn adda(ts: *[]t, i: size) void = { (*ts)[i].a += 1i8; };\n" - "fn addb(ts: *[]t, i: size) void = { (*ts)[i].b += 200u8; };\n" - "fn subc(ts: *[]t, i: size) void = { (*ts)[i].c -= 300i16; };\n" - "fn shld(ts: *[]t, i: size) void = { (*ts)[i].d <<= 3u16; };\n" - "fn mule(ts: *[]t, i: size) void = { (*ts)[i].e *= -3i32; };\n" - "fn orf(ts: *[]t, i: size) void = { (*ts)[i].f |= 8u32; };\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { a = -5i8, b = 50u8, c = 100i16, d = 2u16, e = 7i32, f = 5u32 });\n" - "\tadda(&ts, 0);\n" - "\tif (ts[0].a != -4i8) { return 1; };\n" - "\taddb(&ts, 0);\n" - "\tif (ts[0].b != 250u8) { return 2; };\n" - "\tsubc(&ts, 0);\n" - "\tif (ts[0].c != -200i16) { return 3; };\n" - "\tshld(&ts, 0);\n" - "\tif (ts[0].d != 16u16) { return 4; };\n" - "\tmule(&ts, 0);\n" - "\tif (ts[0].e != -21i32) { return 5; };\n" - "\torf(&ts, 0);\n" - "\tif (ts[0].f != 13u32) { return 6; };\n" - "\treturn 49;\n" - "};\n", - 49, NULL }, - - /* Slice field, same 3-word path as str. Field init goes through - * an ident-bound empty slice, NOT `xs = []`: a bare empty-slice - * literal as a struct-lit field inside an append arg leaves a - * garbage header on MASTER too (pre-existing, task #9 family) — - * this row pins the F6 store, not that bug. */ - { "slice_field_member", - "package main;\n" - "type t = struct { pc: size, xs: []i64 };\n" - "fn setxs(ts: *[]t, i: size, s: []i64) void = { (*ts)[i].xs = s; };\n" - "export fn main() i32 = {\n" - "\tlet empty: []i64 = [];\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 1, xs = empty });\n" - "\tappend(ts, t { pc = 2, xs = empty });\n" - "\tlet s: []i64 = [];\n" - "\tappend(s, 11);\n" - "\tappend(s, 22);\n" - "\tsetxs(&ts, 1, s);\n" - "\tif (ts[1].xs.len != 2) { return 1; };\n" - "\tif (ts[1].xs[1] != 22) { return 2; };\n" - "\tif (ts[0].xs.len != 0) { return 3; };\n" - "\tif (ts[0].pc != 1) { return 4; };\n" - "\tif (ts[1].pc != 2) { return 5; };\n" - "\treturn 50;\n" - "};\n", - 50, NULL }, - - /* Ident-rooted lvalues stay with the enumerated arms (the - * resolver must never fire for them) — this row runtime-pins the - * shapes the 78-probe asm-neutrality sweep diffed statically. */ - { "neutral_ident_bases", - "package main;\n" - "type t = struct { pc: size, matched: bool };\n" - "export fn main() i32 = {\n" - "\tlet x: t = t { pc = 1, matched = false };\n" - "\tx.pc = 5;\n" - "\tx.pc += 2;\n" - "\tlet a: [2]t;\n" - "\ta[0].pc = 3; a[1].pc = 4;\n" - "\ta[1].pc += 10;\n" - "\tlet p: *t = &x;\n" - "\tp.pc = 20;\n" - "\tp.pc += 1;\n" - "\tif (x.pc != 21) { return 1; };\n" - "\tif (a[1].pc != 14) { return 2; };\n" - "\tif (a[0].pc != 3) { return 3; };\n" - "\treturn 51;\n" - "};\n", - 51, NULL }, - - /* The fold-2b 40B capture store (p7b/p7_composed) — wired in a - * follow-up resolver commit; until then it must die LOUD, never - * the pre-C1 silent drop. */ - /* C1.25 (#23): the run_thread 40B capture store, graduated from - * BUILD_FAIL (C1's loud boundary) to wired. Literal rhs goes - * through a FRESH per-use @placescr materialise + word-copy; the - * `...` setter pins the autofill zero loop; neighbour element + - * sibling field readbacks pin the stride and copy length. */ - /* Readback was RAW bytes over ts.ptr until C2 — a depth-2 read - * behind an index (ts[1].cap.start) was the F4 walker gap (task - * #6) and link-failed on the cgen.c global-leaf fallback. C2 - * graduation: typed depth-2 readbacks (the documented note). */ - { "agg_structlit_40b", - "package main;\n" - "type capture = struct { content: str, start: size, end: size };\n" - "type t = struct { pc: size, cap: capture };\n" - "fn setcap(ts: *[]t, i: size) void = {\n" - "\t(*ts)[i].cap = capture { content = \"hit\", start = 2, end = 4 };\n" - "};\n" - "fn clearcap(ts: *[]t, i: size) void = {\n" - "\t(*ts)[i].cap = capture { content = \"z\", ... };\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet z: capture = capture { content = \"\", start = 0, end = 0 };\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 7, cap = z });\n" - "\tappend(ts, t { pc = 8, cap = z });\n" - "\tsetcap(&ts, 1);\n" - "\tif (ts[1].cap.content.len != 3) { return 1; };\n" - "\tif (ts[1].cap.start != 2) { return 2; };\n" - "\tif (ts[1].cap.end != 4) { return 3; };\n" - "\tif (ts[1].pc != 8) { return 4; };\n" - "\tif (ts[0].cap.content.len != 0) { return 5; };\n" - "\tif (ts[0].pc != 7) { return 6; };\n" - "\tclearcap(&ts, 1);\n" - "\tif (ts[1].cap.content.len != 1) { return 7; };\n" - "\tif (ts[1].cap.start != 0) { return 8; };\n" - "\tif (ts[1].cap.end != 0) { return 9; };\n" - "\treturn 52;\n" - "};\n", - 52, NULL }, - - /* Addressable aggregate sources via the #265/#268 dispatch: - * local ident (LEAQ slot) and deref (*pc). Typed depth-2 - * readbacks since C2 (were raw bytes over ts.ptr). */ - { "agg_from_ident_deref", - "package main;\n" - "type capture = struct { content: str, start: size, end: size };\n" - "type t = struct { pc: size, cap: capture };\n" - "fn copycap(ts: *[]t, i: size, src: capture) void = {\n" - "\t(*ts)[i].cap = src;\n" - "};\n" - "fn derefcap(ts: *[]t, i: size, pc: *capture) void = {\n" - "\t(*ts)[i].cap = *pc;\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet z: capture = capture { content = \"\", start = 0, end = 0 };\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 7, cap = z });\n" - "\tappend(ts, t { pc = 8, cap = z });\n" - "\tlet a: capture = capture { content = \"ab\", start = 1, end = 3 };\n" - "\tcopycap(&ts, 1, a);\n" - "\tif (ts[1].cap.content.len != 2) { return 1; };\n" - "\tif (ts[1].cap.start != 1) { return 2; };\n" - "\tif (ts[1].cap.end != 3) { return 3; };\n" - "\tlet b: capture = capture { content = \"wxyz\", start = 5, end = 9 };\n" - "\tderefcap(&ts, 0, &b);\n" - "\tif (ts[0].cap.content.len != 4) { return 4; };\n" - "\tif (ts[0].cap.start != 5) { return 5; };\n" - "\tif (ts[0].cap.end != 9) { return 6; };\n" - "\tif (ts[1].cap.start != 1) { return 7; };\n" - "\treturn 53;\n" - "};\n", - 53, NULL }, - - /* Nested struct-typed literal field inside the stored literal — - * the #18 recursion through cg_structlit_fill must land the inner - * bytes in the @placescr image before the copy. */ - { "agg_nested_lit", - "package main;\n" - "type inner = struct { x: i64, y: i64 };\n" - "type big = struct { a: i64, ib: inner };\n" - "type t = struct { pc: size, bg: big };\n" - "fn setbg(ts: *[]t, i: size) void = {\n" - "\t(*ts)[i].bg = big { a = 1, ib = inner { x = 2, y = 3 } };\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet z: big = big { a = 0, ib = inner { x = 0, y = 0 } };\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 7, bg = z });\n" - "\tsetbg(&ts, 0);\n" - "\tlet bp: *u8 = ts.ptr: *u8;\n" - "\tif (bp[8] != 1u8) { return 1; };\n" - "\tif (bp[16] != 2u8) { return 2; };\n" - "\tif (bp[24] != 3u8) { return 3; };\n" - "\tif (ts[0].pc != 7) { return 4; };\n" - "\treturn 54;\n" - "};\n", - 54, NULL }, - - /* [3]u8 array field from an ident source — TY_ARRAY aggregate arm - * + the MOVW/MOVB copy tails (fsz=3). */ - { "agg_array_field_odd", - "package main;\n" - "type t = struct { pc: size, arr: [3]u8 };\n" - "fn setarr(ts: *[]t, i: size, src: [3]u8) void = {\n" - "\t(*ts)[i].arr = src;\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet a3: [3]u8 = [9u8, 8u8, 7u8];\n" - "\tlet z3: [3]u8 = [0u8, 0u8, 0u8];\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 5, arr = z3 });\n" - "\tsetarr(&ts, 0, a3);\n" - "\tif (ts[0].arr[0] != 9u8) { return 1; };\n" - "\tif (ts[0].arr[1] != 8u8) { return 2; };\n" - "\tif (ts[0].arr[2] != 7u8) { return 3; };\n" - "\tif (ts[0].pc != 5) { return 4; };\n" - "\treturn 55;\n" - "};\n", - 55, NULL }, - - /* Two same-size structlit stores in ONE fn — each must get its - * own FRESH @placescr slot and both must land (the #31 multi- - * live discipline pin). The stronger shape — a structlit whose - * FIELD expr recurses into a same-size aggregate assign, the - * fresh-per-use rationale proper — is not constructible today: - * match-expr (the only stmt-carrying expr) is a parse reject in - * field position; fresh-per-use stays defensive (rob ruling). */ - { "agg_fresh_two_stores", - "package main;\n" - "type capture = struct { content: str, start: size, end: size };\n" - "type t = struct { pc: size, cap: capture };\n" - "fn settwo(ts: *[]t) void = {\n" - "\t(*ts)[0].cap = capture { content = \"aa\", start = 1, end = 2 };\n" - "\t(*ts)[1].cap = capture { content = \"bbb\", start = 3, end = 4 };\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet z: capture = capture { content = \"\", start = 0, end = 0 };\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 7, cap = z });\n" - "\tappend(ts, t { pc = 8, cap = z });\n" - "\tsettwo(&ts);\n" - "\tif (ts[0].cap.content.len != 2) { return 1; };\n" - "\tif (ts[0].cap.start != 1) { return 2; };\n" - "\tif (ts[0].cap.end != 2) { return 3; };\n" - "\tif (ts[1].cap.content.len != 3) { return 4; };\n" - "\tif (ts[1].cap.start != 3) { return 5; };\n" - "\tif (ts[1].cap.end != 4) { return 6; };\n" - "\treturn 56;\n" - "};\n", - 56, NULL }, - - /* [3]u32 field (fsz=12) — the MOVL copy tail, untouched by the - * 40B (all-MOVQ) and [3]u8 (MOVW+MOVB) rows. - * - * Matrix honesty, TY_TUPLE: the arm wires tuple fields and a - * local-ident tuple source stores correctly (cstage-verified), - * but a dual-stage row is blocked by three PRE-EXISTING tuple - * gaps outside this arm: by-value tuple param drops word 2 at - * runtime (both stages, master too), wwstage tuple-let init - * `let a: (i64,i64) = (3,4)` drops the word-2 store (cs≠ww), - * and `a.0 =` element assign is unwired (loud). Tuple-field row - * graduates with that family (filed). */ - { "agg_array_field_movl", - "package main;\n" - "type t = struct { pc: size, arr: [3]u32 };\n" - "fn setarr(ts: *[]t, i: size, src: [3]u32) void = {\n" - "\t(*ts)[i].arr = src;\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet a3: [3]u32 = [9u32, 8u32, 7u32];\n" - "\tlet z3: [3]u32 = [0u32, 0u32, 0u32];\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 5, arr = z3 });\n" - "\tsetarr(&ts, 0, a3);\n" - "\tif (ts[0].arr[0] != 9u32) { return 1; };\n" - "\tif (ts[0].arr[1] != 8u32) { return 2; };\n" - "\tif (ts[0].arr[2] != 7u32) { return 3; };\n" - "\tif (ts[0].pc != 5) { return 4; };\n" - "\treturn 57;\n" - "};\n", - 57, NULL }, - - /* Compound on an aggregate field is meaningless — stays loud. */ - { "reject_agg_compound", - "package main;\n" - "type capture = struct { content: str, start: size, end: size };\n" - "type t = struct { pc: size, cap: capture };\n" - "fn addcap(ts: *[]t, i: size, src: capture) void = {\n" - "\t(*ts)[i].cap += src;\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tlet a: capture = capture { content = \"\", start = 0, end = 0 };\n" - "\taddcap(&ts, 0, a);\n" - "\treturn 0;\n" - "};\n", - BUILD_FAIL, - "assign-resolver: compound on aggregate field not wired (rule-7)" }, - - /* sret-class call rhs (>24B return) needs a runtime-RDI dest — - * the #234-tail deferral. */ - { "reject_agg_call_sret", - "package main;\n" - "type capture = struct { content: str, start: size, end: size };\n" - "type t = struct { pc: size, cap: capture };\n" - "fn mk() capture = {\n" - "\treturn capture { content = \"x\", start = 1, end = 2 };\n" - "};\n" - "fn setcap(ts: *[]t, i: size) void = { (*ts)[i].cap = mk(); };\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tsetcap(&ts, 0);\n" - "\treturn 0;\n" - "};\n", - BUILD_FAIL, - "assign-resolver: sret call into aggregate field unwired " - "(#234-tail/rule-7)" }, - - /* ≤24B reg-return call rhs — deferred, task #24. */ - { "reject_agg_call_reg", - "package main;\n" - "type pair = struct { a: i64, b: i64 };\n" - "type t = struct { pc: size, pr: pair };\n" - "fn mk() pair = { return pair { a = 1, b = 2 }; };\n" - "fn setpr(ts: *[]t, i: size) void = { (*ts)[i].pr = mk(); };\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tsetpr(&ts, 0);\n" - "\treturn 0;\n" - "};\n", - BUILD_FAIL, - "assign-resolver: call result into aggregate field unwired " - "(task #24/rule-7)" }, - - { "reject_float", - "package main;\n" - "type t = struct { pc: size, f: f64 };\n" - "fn setf(ts: *[]t, i: size) void = { (*ts)[i].f = 1.5; };\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tsetf(&ts, 0);\n" - "\treturn 0;\n" - "};\n", - BUILD_FAIL, "assign-resolver: float field not wired (rule-7)" }, - - { "reject_tagged", - "package main;\n" - "type v = (i64 | bool);\n" - "type t = struct { pc: size, tg: v };\n" - "fn settg(ts: *[]t, i: size) void = { (*ts)[i].tg = 5; };\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tsettg(&ts, 0);\n" - "\treturn 0;\n" - "};\n", - BUILD_FAIL, "assign-resolver: tagged field not wired (rule-7)" }, - - /* Compound on a str field reaches cgen (the checker admits it) — - * it must hit the resolver's own loud stop, not the silent tail. */ - { "reject_str_compound", - "package main;\n" - "type t = struct { pc: size, name: str };\n" - "fn addname(ts: *[]t, i: size) void = { (*ts)[i].name += \"x\"; };\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\taddname(&ts, 0);\n" - "\treturn 0;\n" - "};\n", - BUILD_FAIL, - "assign-resolver: compound on str/slice field not wired (rule-7)" }, - - /* C1's reject_tail (index base is a dot chain), graduated by the - * C2 resolver arms (N_IDENT root + recursive N_INDEX bases) — - * store, compound, readback, and neighbour-intact pins. */ - { "arr_field_idx_store", - "package main;\n" - "type t = struct { pc: size, matched: bool };\n" - "type holder = struct { arr: [3]t, n: i64 };\n" - "export fn main() i32 = {\n" - "\tlet h: holder = holder { n = 0, ... };\n" - "\th.arr[1].pc = 5;\n" - "\th.arr[1].pc += 2;\n" - "\tif (h.arr[1].pc != 7) { return 1; };\n" - "\tif (h.arr[0].pc != 0) { return 2; };\n" - "\tif (h.arr[2].pc != 0) { return 3; };\n" - "\treturn 58;\n" - "};\n", - 58, NULL }, - - /* C2 (F4): typed depth-2 reads behind an IDENT-indexed root — - * the p6min9/p6min10 read shape (nonzero offsets, both elements, - * pseudo .len behind the spine, and the global-collision check: - * a module global named `end` must NOT be read). Elements are - * built with NESTED literals, not `cap = rc1` ident rhs — the - * probes' own construction shape is the #36 under-copy (struct- - * ident field rhs copies 8B), which keeps p6min9/p6min10 - * themselves blocked on #36 with their read-half fixed here. */ - { "read_depth2_idx", - "package main;\n" - "type capture = struct { content: str, start: size, end: size };\n" - "type t = struct { pc: size, cap: capture };\n" - "let end: size = 777;\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 5, cap = capture { content = \"abc\", start = 11, end = 13 } });\n" - "\tappend(ts, t { pc = 6, cap = capture { content = \"wy\", start = 21, end = 23 } });\n" - "\tif (ts[0].cap.end == 777) { return 66; };\n" - "\tif (ts[0].cap.end != 13) { return 1; };\n" - "\tif (ts[0].cap.start != 11) { return 2; };\n" - "\tif (ts[1].cap.end != 23) { return 3; };\n" - "\tif (ts[1].cap.content.len != 2) { return 4; };\n" - "\tif (ts[1].pc != 6) { return 5; };\n" - "\treturn 59;\n" - "};\n", - 59, NULL }, - - /* C2 (F4): the same chain behind a DEREF-rooted index — plus the - * offset-0 scalar (.pc) that pre-C2 cstage read correctly only by - * COINCIDENCE through the offset-blind catch-all (ken's FA3 - * correction); now it routes through the resolver in both - * stages. */ - { "read_depth2_deref", - "package main;\n" - "type capture = struct { content: str, start: size, end: size };\n" - "type t = struct { pc: size, cap: capture };\n" - "fn rd(ts: *[]t) i32 = {\n" - "\tif ((*ts)[0].pc != 5) { return 1; };\n" - "\tif ((*ts)[0].cap.start != 11) { return 2; };\n" - "\tif ((*ts)[0].cap.end != 13) { return 3; };\n" - "\tif ((*ts)[1].cap.end != 23) { return 4; };\n" - "\treturn 0;\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 5, cap = capture { content = \"abc\", start = 11, end = 13 } });\n" - "\tappend(ts, t { pc = 6, cap = capture { content = \"wy\", start = 21, end = 23 } });\n" - "\tlet rc: i32 = rd(&ts);\n" - "\tif (rc != 0) { return rc; };\n" - "\treturn 60;\n" - "};\n", - 60, NULL }, - - /* C2 (F4): leaf-kind matrix behind the deref-index spine — narrow - * signed/unsigned (fldloadop sign/zero extension), f64/f32 via - * X0, and an `[N]u8` field leaf (address semantics, outer index - * applies). */ - { "read_widths_spine", - "package main;\n" - "type inner = struct { b: i8, ub: u8, w: i16, uw: u16, d: i32, ud: u32, f: f64, g: f32, arr: [3]u8 };\n" - "type box = struct { pad: size, it: inner };\n" - "export fn main() i32 = {\n" - "\tlet bs: []box = [];\n" - "\tappend(bs, box { pad = 1, it = inner { b = -5i8, ub = 200u8, w = -300i16, uw = 60000u16, d = -70000, ud = 4000000000u32, f = 1.5, g = 2.5f32, arr = [7u8, 8u8, 9u8] } });\n" - "\tlet p: *[]box = &bs;\n" - "\tif ((*p)[0].it.b != -5i8) { return 1; };\n" - "\tif ((*p)[0].it.ub != 200u8) { return 2; };\n" - "\tif ((*p)[0].it.w != -300i16) { return 3; };\n" - "\tif ((*p)[0].it.uw != 60000u16) { return 4; };\n" - "\tif ((*p)[0].it.d != -70000) { return 5; };\n" - "\tif ((*p)[0].it.ud != 4000000000u32) { return 6; };\n" - "\tif ((*p)[0].it.f != 1.5) { return 7; };\n" - "\tif ((*p)[0].it.g != 2.5f32) { return 8; };\n" - "\tif ((*p)[0].it.arr[1] != 8u8) { return 9; };\n" - "\treturn 61;\n" - "};\n", - 61, NULL }, - - /* FA3/pA5 graduated: 24B slice-header field read behind a deref- - * index spine — pre-C2 cstage took the offset-blind catch-all - * (one wrong-offset MOVQ + stale BX/CX as the header), wwstage - * silently emitted NOTHING. Plus the .cap pseudo behind the same - * spine (recurses through the resolver). */ - { "read_slicefield", - "package main;\n" - "type box = struct { pc: size, xs: []size };\n" - "fn grab(p: *[]box, i: size) i32 = {\n" - "\tlet h: []size = (*p)[i].xs;\n" - "\tif (len(h) != 2) { return 1; };\n" - "\tif (h[0] != (7: size)) { return 2; };\n" - "\tif (h[1] != (8: size)) { return 3; };\n" - "\tif ((*p)[i].xs.cap < 2) { return 4; };\n" - "\treturn 0;\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet src: []size = [];\n" - "\tappend(src, (7: size));\n" - "\tappend(src, (8: size));\n" - "\tlet bs: []box = [];\n" - "\tappend(bs, box { pc = 1, xs = src });\n" - "\tlet rc: i32 = grab(&bs, 0);\n" - "\tif (rc != 0) { return rc; };\n" - "\treturn 62;\n" - "};\n", - 62, NULL }, - - /* Reviewer-A route: address-of a field through an indexed / - * deref-indexed spine, then deref + compound through the pointer. - * Pre-C2 BOTH stages silently dropped the & (stale AX as the - * address — gate-blind SEGFAULT). */ - { "amp_spine", - "package main;\n" - "type capture = struct { content: str, start: size, end: size };\n" - "type t = struct { pc: size, cap: capture };\n" - "fn bump(cp: *capture) void = { cp.end += 100; };\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 5, cap = capture { content = \"abc\", start = 11, end = 13 } });\n" - "\tappend(ts, t { pc = 6, cap = capture { content = \"wy\", start = 21, end = 23 } });\n" - "\tlet cp: *capture = &ts[1].cap;\n" - "\tif (cp.start != 21) { return 1; };\n" - "\tbump(cp);\n" - "\tif (ts[1].cap.end != 123) { return 2; };\n" - "\tlet pp: *[]t = &ts;\n" - "\tlet dp: *capture = &(*pp)[0].cap;\n" - "\tif (dp.end != 13) { return 3; };\n" - "\treturn 63;\n" - "};\n", - 63, NULL }, - - /* Asm-neutrality pins for the arms the C2 gates must NOT disturb: - * ident-rooted value chain (chain walker), `(*p).f` retarget, - * untyped-str literal pseudo-fields (the gated catch-all's only - * legitimate tenant). A tuple-positional pin is blocked by the - * pre-existing #33 wwstage tuple-let word-2 drop (filed). */ - { "neutral_reads", - "package main;\n" - "type capture = struct { content: str, start: size, end: size };\n" - "type t = struct { pc: size, cap: capture };\n" - "fn pcof(p: *t) size = { return (*p).pc; };\n" - "export fn main() i32 = {\n" - "\tlet x: t = t { pc = 9, cap = capture { content = \"hi\", start = 1, end = 2 } };\n" - "\tif (x.cap.start != 1) { return 1; };\n" - "\tif (x.cap.content.len != 2) { return 2; };\n" - "\tif (pcof(&x) != 9) { return 3; };\n" - "\tif (\"abc\".len != 3) { return 4; };\n" - "\treturn 64;\n" - "};\n", - 64, NULL }, - - /* Tagged leaf behind a spine: no canonical register convention - * is emitted by the read-resolver yet — must die LOUD, not load - * 8 of 16+ bytes (rule 7). */ - { "reject_read_tagged", - "package main;\n" - "type v = (i64 | bool);\n" - "type t = struct { pc: size, tg: v };\n" - "fn rd(ts: *[]t, i: size) i64 = {\n" - "\tlet x: v = (*ts)[i].tg;\n" - "\treturn 1;\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\treturn rd(&ts, 0): i32;\n" - "};\n", - BUILD_FAIL, "read-resolver: tagged field read not wired (rule-7)" }, - - /* A call-result index base has no storage address — the resolver - * must refuse and the read tail must be LOUD (pre-C2: cstage - * emitted an offset-blind garbage read, wwstage nothing). */ - { "reject_read_callbase", - "package main;\n" - "type t = struct { pc: size, matched: bool };\n" - "fn mk() []t = {\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 3, matched = true });\n" - "\treturn ts;\n" - "};\n" - "export fn main() i32 = {\n" - "\tif (mk()[0].pc != 3) { return 1; };\n" - "\treturn 0;\n" - "};\n", - BUILD_FAIL, "unsupported field-read shape" }, - - /* The assign-tail diagnostic keeps a carrier now that C1's - * reject_tail shape (h.arr[1].pc) graduated: a call-base lvalue - * is unaddressable. */ - { "reject_assign_callbase", - "package main;\n" - "type t = struct { pc: size, matched: bool };\n" - "fn mk() []t = {\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 3, matched = true });\n" - "\treturn ts;\n" - "};\n" - "export fn main() i32 = {\n" - "\tmk()[0].pc = 2;\n" - "\treturn 0;\n" - "};\n", - BUILD_FAIL, "unsupported assign target shape" }, - - /* TK_AMP loud tail (the C2 replacement for the silent drop). */ - { "reject_addrof_callbase", - "package main;\n" - "type t = struct { pc: size, matched: bool };\n" - "fn mk() []t = {\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 3, matched = true });\n" - "\treturn ts;\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet p: *size = &mk()[0].pc;\n" - "\treturn (*p): i32;\n" - "};\n", - BUILD_FAIL, "unsupported address-of shape" }, - - /* C3 (task #8) F10 class: the index BASE is typed via an N_TNAME - * alias — pre-C3 wwstage's name-keyed arm missed it (interim C2 - * loud guard). Field-kind matrix mirrors the cstage arm's - * dispatch: narrow signed/unsigned, 8B, float, str header, slice - * header, [N]T field as outer-index base (#270-1a). Construction - * goes through DIRECT-typed locals: the alias-typed `= []` / - * arrlit-init/global-DATA sites are a separate filed family - * (unmasked behind C3, not cgdot). */ - { "c3_alias_slice_reads", - "package main;\n" - "type wide = struct { b: u8, w: i16, d: u32, q: i64, f: f64,\n" - "\ts: str, xs: []size, m: [2]u32 };\n" - "type wlist = []wide;\n" - "fn mkw(k: i64) wide = {\n" - "\tlet xs: []size = [];\n" - "\tlet x0: size = (10 + k): size;\n" - "\tlet x1: size = (20 + k): size;\n" - "\tappend(xs, x0);\n" - "\tappend(xs, x1);\n" - "\tlet m0: u32 = (40 + k): u32;\n" - "\tlet m1: u32 = (50 + k): u32;\n" - "\treturn wide { b = (k + 1): u8, w = (0 - k): i16,\n" - "\t\td = (100 + k): u32, q = k, f = 2.5f64, s = \"ab\",\n" - "\t\txs = xs, m = [m0, m1] };\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet l0: []wide = [];\n" - "\tlet w1: wide = mkw(1);\n" - "\tlet w2: wide = mkw(2);\n" - "\tappend(l0, w1);\n" - "\tappend(l0, w2);\n" - "\tlet l: wlist = l0;\n" - "\tif (l[0].b != 2u8) { return 1; };\n" - "\tif (l[0].w != -1i16) { return 2; };\n" - "\tif (l[1].d != 102u32) { return 3; };\n" - "\tif (l[1].q != 2i64) { return 4; };\n" - "\tif (l[0].f != 2.5f64) { return 5; };\n" - "\tif (l[0].s.len != 2) { return 6; };\n" - "\tif (l[1].xs[1] != (22: size)) { return 7; };\n" - "\tif (l[0].m[1] != 51u32) { return 8; };\n" - "\treturn 65;\n" - "};\n", - 65, NULL }, - - /* F10 sibling bases: alias-typed [2]S array (local), and an - * alias-typed []*S whose ELEMENT is a pointer (the arm's viaptr - * deref hop). */ - { "c3_alias_arr_viaptr", - "package main;\n" - "type wide = struct { b: u8, q: i64, xs: []size };\n" - "type warr = [2]wide;\n" - "type pw = *wide;\n" - "type plist = []pw;\n" - "fn mkw(k: i64) wide = {\n" - "\tlet xs: []size = [];\n" - "\tlet x0: size = (10 + k): size;\n" - "\tappend(xs, x0);\n" - "\treturn wide { b = (k + 1): u8, q = k, xs = xs };\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet w3: wide = mkw(3);\n" - "\tlet w4: wide = mkw(4);\n" - "\tlet a0: [2]wide = [w3, w4];\n" - "\tlet a: warr = a0;\n" - "\tif (a[0].q != 3i64) { return 1; };\n" - "\tif (a[1].b != 5u8) { return 2; };\n" - "\tlet w5: wide = mkw(5);\n" - "\tlet ps0: []pw = [];\n" - "\tappend(ps0, &w5);\n" - "\tlet ps: plist = ps0;\n" - "\tif (ps[0].q != 5i64) { return 3; };\n" - "\tif (ps[0].b != 6u8) { return 4; };\n" - "\tif (ps[0].xs[0] != (15: size)) { return 5; };\n" - "\treturn 66;\n" - "};\n", - 66, NULL }, - - /* p11b's F10 essence with the task-#14-gated `?` factored out: a - * let bound from a fn returning the alias, indexed-field reads off - * it (m's tnode is the N_TNAME alias `result`). */ - { "c3_letbound_alias", - "package main;\n" - "type capture = struct { content: str, start: size, end: size };\n" - "type result = []capture;\n" - "fn mk() result = {\n" - "\tlet caps: []capture = [];\n" - "\tappend(caps, capture { content = \"xy\", start = 1, end = 3 });\n" - "\tappend(caps, capture { content = \"z\", start = 4, end = 5 });\n" - "\treturn caps;\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet m: result = mk();\n" - "\tif (len(m) != 2) { return 1; };\n" - "\tif (m[0].start != 1) { return 2; };\n" - "\tif (m[0].content.len != 2) { return 3; };\n" - "\tif (m[1].end != 5) { return 4; };\n" - "\treturn 67;\n" - "};\n", - 67, NULL }, - - /* F7: the composed regex run_thread hot shape — a tagged-slice - * field indexed by a deref-index-field chain, match-dispatched, - * plus compound/store back through the same spine (p7_composed - * core; the strings.frombytes tail lives with task #29). */ - { "c3_composed_match", - "package main;\n" - "type inst_lit = rune;\n" - "type inst_any = void;\n" - "type inst_match = bool;\n" - "type inst = (inst_lit | inst_any | inst_match);\n" - "type re_t = struct { insts: []inst, n_reps: size };\n" - "type capture = struct { content: str, start: size, end: size };\n" - "type thread = struct { pc: size, root_capture: capture, failed: bool };\n" - "fn step(re: *re_t, ts: *[]thread, i: size) i32 = {\n" - "\tmatch (re.insts[(*ts)[i].pc]) {\n" - "\tcase let lt: inst_lit => {\n" - "\t\t(*ts)[i].root_capture = capture { content = \"hit\", start = 2, end = 4 };\n" - "\t\t(*ts)[i].pc += 1;\n" - "\t\treturn 1;\n" - "\t};\n" - "\tcase inst_any => {\n" - "\t\t(*ts)[i].failed = true;\n" - "\t\treturn 2;\n" - "\t};\n" - "\tcase let m: inst_match => {\n" - "\t\t(*ts)[i].pc += 2;\n" - "\t\treturn 3;\n" - "\t};\n" - "\t};\n" - "\treturn 9;\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet insts: []inst = [];\n" - "\tappend(insts, ('a': inst_lit));\n" - "\tlet av: inst_any;\n" - "\tlet v: inst = av;\n" - "\tappend(insts, v);\n" - "\tappend(insts, (true: inst_match));\n" - "\tlet re: re_t = re_t { insts = insts, n_reps = 0 };\n" - "\tlet ts: []thread = [];\n" - "\tlet z: capture = capture { content = \"\", start = 0, end = 0 };\n" - "\tappend(ts, thread { pc = 0, root_capture = z, failed = false });\n" - "\tif (step(&re, &ts, 0) != 1) { return 1; };\n" - "\tif (ts[0].pc != 1) { return 2; };\n" - "\tif (ts[0].root_capture.start != 2) { return 3; };\n" - "\tif (step(&re, &ts, 0) != 2) { return 4; };\n" - "\tif (!ts[0].failed) { return 5; };\n" - "\tlet p: *[]thread = &ts;\n" - "\t(*p)[0].pc += 1;\n" - "\tif (ts[0].pc != 2) { return 6; };\n" - "\tif (step(&re, &ts, 0) != 3) { return 7; };\n" - "\tif (ts[0].pc != 4) { return 8; };\n" - "\treturn 68;\n" - "};\n", - 68, NULL }, - - /* FA6 (pA9): free() consumes its operand via cgexpr — the - * deref-index-field reads inside the operand are C3's reads, the - * free arm itself is sound. Pure acceptance row. */ - { "c3_free_operand", - "package main;\n" - "type capture = struct { content: str, start: size };\n" - "type thread = struct { pc: size, captures: []capture,\n" - "\trep_counters: []size };\n" - "fn delete_thread(i: size, threads: *[]thread) void = {\n" - "\tfree((*threads)[i].captures);\n" - "\tfree((*threads)[i].rep_counters);\n" - "\tdelete((*threads)[i]);\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet z: []capture;\n" - "\tlet zr: []size;\n" - "\tlet xs: []thread = [];\n" - "\tappend(xs, thread { pc = 1, captures = z, rep_counters = zr });\n" - "\tappend(xs, thread { pc = 2, captures = z, rep_counters = zr });\n" - "\tappend(xs, thread { pc = 3, captures = z, rep_counters = zr });\n" - "\tdelete_thread(1, &xs);\n" - "\tif (len(xs) != 2) { return 1; };\n" - "\tif (xs[0].pc != 1) { return 2; };\n" - "\tif (xs[1].pc != 3) { return 3; };\n" - "\treturn 69;\n" - "};\n", - 69, NULL }, - - /* C4 (F5, task #7): `let e = xs[0]` from a SLICE base — the #265 - * source-addr enumeration had TY_ARRAY/N_DOT/N_INDEX bases but no - * TY_SLICE base, so cstage emitted NOTHING (slot uninitialised) - * and wwstage fell to its scalar default (8B truncation) — - * gate-blind cs≠ww. p6min13 graduated verbatim; the slice base - * now resolves through cgplaceaddr. - * - * LANDMINE (task #43): the UNANNOTATED form `let e = xs[0]` is - * still cs≠ww — wwstage's aggn/letslotsize gates are annotation- - * keyed and skip the copy arm (8B truncation) while cstage keys - * the stamped n->type and full-copies. No dual-driver row can pin - * a divergent shape; every row below annotates. Do NOT read the - * annotated rows as covering the inferred form. */ - { "c4_let_slice_elem", - "package main;\n" - "type th = struct { pc: size, matched: bool };\n" - "export fn main() i32 = {\n" - "\tlet xs: []th = [];\n" - "\tappend(xs, th { pc = 7, matched = true });\n" - "\tlet e: th = xs[0];\n" - "\tif (e.pc != 7) { return 1; };\n" - "\tif (!e.matched) { return 2; };\n" - "\treturn 70;\n" - "};\n", - 70, NULL }, - - /* C4 size matrix: 24B (3-word run), 40B (str header + 2 words), - * and 12B (maxalign 4 → MOVQ+MOVL tail) elements. */ - { "c4_let_elem_sizes", - "package main;\n" - "type t3 = struct { a: i64, b: i64, c: i64 };\n" - "type capture = struct { content: str, start: size, end: size };\n" - "type t12 = struct { x: u32, y: u32, z: u32 };\n" - "export fn main() i32 = {\n" - "\tlet xs: []t3 = [];\n" - "\tappend(xs, t3 { a = 1, b = 2, c = 3 });\n" - "\tappend(xs, t3 { a = 4, b = 5, c = 6 });\n" - "\tlet e: t3 = xs[1];\n" - "\tif (e.a != 4) { return 1; };\n" - "\tif (e.b != 5) { return 2; };\n" - "\tif (e.c != 6) { return 3; };\n" - "\tlet cs: []capture = [];\n" - "\tappend(cs, capture { content = \"abc\", start = 11, end = 13 });\n" - "\tlet c: capture = cs[0];\n" - "\tif (c.content.len != 3) { return 4; };\n" - "\tif (c.start != 11) { return 5; };\n" - "\tif (c.end != 13) { return 6; };\n" - "\tlet ns: []t12 = [];\n" - "\tappend(ns, t12 { x = 7u32, y = 8u32, z = 9u32 });\n" - "\tlet n: t12 = ns[0];\n" - "\tif (n.x != 7u32) { return 7; };\n" - "\tif (n.y != 8u32) { return 8; };\n" - "\tif (n.z != 9u32) { return 9; };\n" - "\treturn 71;\n" - "};\n", - 71, NULL }, - - /* Reviewer-C2 inheritance: aggregate leaf behind a deref spine - * into a let — `let c = (*ts)[i].cap`. Pre-C4 wwstage loud-bailed - * at its cgdot aggregate-leaf gate (correct per rule 7) while - * cstage SILENTLY emitted no copy; both now route the let copy - * through the resolver. */ - { "c4_let_deref_leaf", - "package main;\n" - "type capture = struct { content: str, start: size, end: size };\n" - "type t = struct { pc: size, cap: capture };\n" - "fn grab(ts: *[]t, i: size) i32 = {\n" - "\tlet c: capture = (*ts)[i].cap;\n" - "\tif (c.start != 11) { return 1; };\n" - "\tif (c.end != 13) { return 2; };\n" - "\tif (c.content.len != 3) { return 3; };\n" - "\treturn 0;\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet ts: []t = [];\n" - "\tappend(ts, t { pc = 5, cap = capture { content = \"abc\", start = 11, end = 13 } });\n" - "\tlet rc: i32 = grab(&ts, 0);\n" - "\tif (rc != 0) { return rc; };\n" - "\treturn 72;\n" - "};\n", - 72, NULL }, - - /* C4 (F5/FC0): by-value range payload copies through the same - * full-width machinery — pre-C4 the single fldloadop word - * truncated every aggregate element to 8B (cstage), wwstage's - * structural esz fell to its 8-sentinel (or 1 for non-ident - * scrutinees: regex.finish's cs≠ww hunk) and the ww checker left - * the binding typeless (asserttyped bail on any field read). - * Rows: []struct sum of BOTH fields, []capture (40B, str header - * inside), []str (24B header, .len readback). */ - { "c4_range_byvalue", - "package main;\n" - "type th = struct { pc: size, weight: size };\n" - "type capture = struct { content: str, start: size, end: size };\n" - "export fn main() i32 = {\n" - "\tlet xs: []th = [];\n" - "\tappend(xs, th { pc = 7, weight = 100 });\n" - "\tappend(xs, th { pc = 8, weight = 200 });\n" - "\tlet total: size = 0;\n" - "\tfor (let t .. xs) {\n" - "\t\ttotal += t.pc;\n" - "\t\ttotal += t.weight;\n" - "\t};\n" - "\tif (total != 315) { return 1; };\n" - "\tlet cs: []capture = [];\n" - "\tappend(cs, capture { content = \"abc\", start = 11, end = 13 });\n" - "\tappend(cs, capture { content = \"wy\", start = 21, end = 23 });\n" - "\tlet csum: size = 0;\n" - "\tfor (let cp .. cs) {\n" - "\t\tcsum += cp.content.len: size;\n" - "\t\tcsum += cp.start;\n" - "\t\tcsum += cp.end;\n" - "\t};\n" - "\tif (csum != 73) { return 2; };\n" - "\tlet ss: []str = [];\n" - "\tappend(ss, \"hello\");\n" - "\tappend(ss, \"worldly\");\n" - "\tlet slen: size = 0;\n" - "\tfor (let s .. ss) {\n" - "\t\tslen += s.len: size;\n" - "\t};\n" - "\tif (slen != 12) { return 3; };\n" - "\treturn 73;\n" - "};\n", - 73, NULL }, - - /* C4 range edges: zero-iteration over an empty slice; binder - * MUTATION pinning Hare's by-VALUE payload semantics (writes to - * the binder land in its frame slot copy, never the slice — a - * by-reference regression would flip xs[0]); and a 12B element - * exercising the sized MOVL tail of the range word-copy (the - * 16B/24B/40B rows above are all full-word). */ - { "c4_range_edges", - "package main;\n" - "type th = struct { pc: size, matched: bool };\n" - "type t12 = struct { x: u32, y: u32, z: u32 };\n" - "export fn main() i32 = {\n" - "\tlet es: []th = [];\n" - "\tfor (let t .. es) { return 1; };\n" - "\tlet xs: []th = [];\n" - "\tappend(xs, th { pc = 7, matched = true });\n" - "\tlet cnt: size = 0;\n" - "\tfor (let t2 .. xs) { t2.pc = 99; t2.matched = false; cnt += 1; };\n" - "\tif (cnt != 1) { return 2; };\n" - "\tif (xs[0].pc != 7) { return 3; };\n" - "\tif (!xs[0].matched) { return 4; };\n" - "\tlet ns: []t12 = [];\n" - "\tappend(ns, t12 { x = 1u32, y = 2u32, z = 3u32 });\n" - "\tappend(ns, t12 { x = 4u32, y = 5u32, z = 6u32 });\n" - "\tlet sum: size = 0;\n" - "\tfor (let n .. ns) { sum += n.x: size; sum += n.y: size; sum += n.z: size; };\n" - "\tif (sum != 21) { return 5; };\n" - "\treturn 74;\n" - "};\n", - 74, NULL }, - - /* C4 loud tail: a non-place rhs (tagged unwrap into a struct let) - * has no source address and nothing below the aggregate arm can - * initialise a >8B slot — pre-C4 cstage emitted NO init and - * wwstage stored 8B, both silent. */ - { "reject_let_unhandled", - "package main;\n" - "type pair = struct { a: i64, b: i64 };\n" - "fn mk() (pair | nomem) = {\n" - "\treturn pair { a = 1, b = 2 };\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet p: pair = mk()!;\n" - "\treturn p.a: i32;\n" - "};\n", - BUILD_FAIL, - "let: aggregate init from unhandled rhs shape (task #7/rule-7)" }, -}; - -/* errlog_has — the build-failure stderr must carry the row's expected - * diagnostic; any other failure (parse error, crash) is a vacuous - * reject and must not pass. */ -static int -errlog_has(const char *path, const char *needle) -{ - FILE *f = fopen(path, "rb"); - if (!f) return 0; - char buf[8192]; - size_t got = fread(buf, 1, sizeof buf - 1, f); - fclose(f); - buf[got] = '\0'; - return strstr(buf, needle) != NULL; -} - -static int -run_driver(const char *driver, const struct row *r, int i) -{ - char tmpdir[] = "/tmp/plad_XXXXXX"; - char src[128], outbin[128], errlog[128], scratch[160], rmcmd[192]; - char cmd[1200]; - int result = -2; - if (mkdtemp(tmpdir) == NULL) { - fprintf(stderr, "row[%s]: workspace acquisition failed\n", r->label); - return result; - } - snprintf(src, sizeof src, "%s/plad_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/plad_%d_%d", tmpdir, getpid(), i); - snprintf(errlog, sizeof errlog, "%s/err", tmpdir); - snprintf(scratch, sizeof scratch, "%s.sepwork", outbin); - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", scratch); - - FILE *f = fopen(src, "wb"); - if (!f) goto done; - fputs(r->src, f); - int werr = ferror(f); - if (fclose(f) != 0) werr = 1; - if (werr) goto done; - - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>%s", - driver, outbin, src, errlog); - if (runwait(cmd) != 0) { - result = -1; - if (r->want != BUILD_FAIL) { - fprintf(stderr, "row[%s]: build via %s failed\n", - r->label, driver); - } else if (r->expect_err && - !errlog_has(errlog, r->expect_err)) { - fprintf(stderr, "row[%s]: %s build failed without " - "expected diagnostic \"%s\"\n", - r->label, driver, r->expect_err); - result = -3; /* failed, but for the wrong reason */ - } - goto done; - } - - result = runwait(outbin); - -done: - { - int cleanfail = 0; - if (runwait(rmcmd) != 0) cleanfail = 1; - if (unlink(errlog) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: workspace cleanup failed\n", r->label); - int passed = r->want == BUILD_FAIL - ? result == -1 : result == r->want; - if (passed) result = -2; - } - } - return result; -} - -/* asm_byte_identical — generate .s via cstage's w6c and wwstage's - * w6c_ww and diff. The resolver emission is written fresh on both - * sides, so this is the converged-by-construction gate: any drift in - * the idx-scale/spill/deref sequence shows here. */ -static int -asm_byte_identical(const char *bin, const struct row *r, int i) -{ - (void)i; - char dir[] = "/tmp/plad_asm_XXXXXX"; - char src[128], cs[128], ws[128], cmd[1024]; - int rc = -1; - if (mkdtemp(dir) == NULL) return -1; - snprintf(src, sizeof src, "%s/input.ww", dir); - snprintf(cs, sizeof cs, "%s/c.s", dir); - snprintf(ws, sizeof ws, "%s/w.s", dir); - - FILE *f = fopen(src, "wb"); - if (!f) goto done; - fputs(r->src, f); - int werr = ferror(f); - if (fclose(f) != 0) werr = 1; - if (werr) goto done; - - snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c errored\n", r->label); - goto done; - } - snprintf(cmd, sizeof cmd, "%s/w6c_ww -o %s %s 2>/dev/null", - bin, ws, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww errored\n", r->label); - goto done; - } - - FILE *fc = fopen(cs, "rb"); - FILE *fw = fopen(ws, "rb"); - rc = 0; - if (!fc || !fw) { - rc = -1; - } else { - for (;;) { - int a = fgetc(fc); - int b = fgetc(fw); - if (a != b) { rc = -1; break; } - if (a == EOF) break; - } - } - if (fc) fclose(fc); - if (fw) fclose(fw); - if (rc != 0) - fprintf(stderr, "row[%s]: cstage vs wwstage asm differs\n", - r->label); - -done: - { - int cleanfail = 0; - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(cs) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(ws) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(dir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: asm workspace cleanup failed\n", - r->label); - rc = -1; - } - } - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[2080]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[2120]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - char wdrv[2120]; - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - - struct { const char *name; const char *path; int gated_on_existence; } - drivers[] = { - { "cstage", cdrv, 0 }, - { "wwstage", wdrv, 1 }, - { NULL, NULL, 0 }, - }; - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - - for (int d = 0; drivers[d].name; d++) { - if (drivers[d].gated_on_existence - && access(drivers[d].path, X_OK) != 0) { - fprintf(stderr, "placeaddr_store: skip %s (no %s)\n", - drivers[d].name, drivers[d].path); - continue; - } - for (int i = 0; i < n; i++) { - int got = run_driver(drivers[d].path, &rows[i], i); - total++; - int bad = rows[i].want == BUILD_FAIL - ? (got != -1) : (got != rows[i].want); - if (bad) { - fprintf(stderr, - "placeaddr_store[%s][%s]: exit=%d want=%d\n", - drivers[d].name, rows[i].label, - got, rows[i].want); - fail++; - } - } - } - - if (access(wdrv, X_OK) == 0) { - for (int i = 0; i < n; i++) { - if (rows[i].want == BUILD_FAIL) - continue; - total++; - if (asm_byte_identical(bin, &rows[i], i) != 0) - fail++; - } - } - - if (fail) { - fprintf(stderr, - "placeaddr_store: %d/%d fixtures failed\n", fail, total); - return 1; - } - printf("placeaddr_store: %d fixtures passed\n", total); - return 0; -} diff --git a/test/wcc/806_append_place.c b/test/wcc/806_append_place.c deleted file mode 100644 index d129a34d..00000000 --- a/test/wcc/806_append_place.c +++ /dev/null @@ -1,1005 +0,0 @@ -/* - * 806_append_place — cstage and wwstage agree, byte-for-byte and at - * runtime, that `append(*p, v)` / `append(*p, items...)` through a - * pointer-to-slice place lands the element (FA1, task #15 of the regex - * fold-2b blockers; the add_thread hot shape `threads: *[]thread`). - * - * Pre-fix this was ONE mirrored choke-point with TWO failure modes: - * cstage 0-defaulted the header base for any non-ident target - * (`sn_off = (sn->kind==N_IDENT) ? localfind : 0`), so 0(BP)/8(BP) - * became the "slice header" and rt_ensure corrupted the CALLER frame - * (SIGSEGV); wwstage cgappend silently emitted NOTHING (gate-blind - * cs≠ww). The fix re-keys the append lowering from BP-displacement - * assumptions onto a resolver-provided header PLACE (cgplaceaddr's - * third consumer after C1 assign-stores and C1.25 aggregate-field - * stores): the derived header address is spilled to a per-fn - * @apphdrscr slot so it survives rt_ensure (realloc moves .ptr, never - * the header), and every header access reloads from the slot. - * Ident-local targets keep the legacy BP-disp emission byte-identical. - * Any target place the resolver can't address dies LOUD (rule 7) — - * the old silent corruption can't come back through an unwired shape. - * - * row | shape | want - * ---------------------+-----------------------------------------+------ - * scalar_param | append(*p, v) i64 via *[]i64 param | 60 - * scalar_u8_multi | append(*q, a, b) u8 via local ptr | 61 - * spread_param | append(*p, src...) i64 spread | 62 - * spread_narrow_signed | append(*p, src...) i32 (MOVSXD load | 63 - * | keyed off stamped tinfo, no tnode) | - * spread_wide | append(*p, src...) str (24B word-copy) | 64 - * str_elem | append(*p, "hi") 3-word header | 65 - * slice_elem | append(*p, one) [][]u8 3-word header | 66 - * tagged_elem | append(*p, 42) (i64|void) widen-box | 67 - * struct_lit | pA6 verbatim: append(*p, box{...}) | 68 - * struct_ident | append(*p, b) local struct word-copy | 69 - * realloc_loop | 100 appends via param, branched callee, | 70 - * | cap-crossing reallocs, full multi-field | - * | readback + caller-frame sentinels | - * deref_spine | append((*q)[i].xs, v) resolver spine | 71 - * neutral_direct | ident-local appends (the legacy arm — | 72 - * | runtime-pins the asm-neutrality claim) | - * reentrant_value | append(*p, match{.. append(*q,..) ..}) | 33 - * | — nested indirect append inside the | - * | outer's value expr; pins the per-SITE | - * | @apphdrscr slot (a shared slot clobbers)| - * identroot_dot | h.xs via *holder param — C1.5's reject, | 73 - * | graduated by C2's resolver ident root | - * idxfield_struct | append(res, threads[i].root_capture) | 74 - * | 56B indexed-FIELD source (#49, ha:819) | - * idx_computed_elem | append(ds, bs[i + 1]) computed-index | 75 - * | whole-element source | - * derefspine_field | append(*r, (*q)[i].rc) param spines | 76 - * | both sides | - * deref_src | append(*ds, *p) deref source | 77 - * self_append_realloc | append(bs, bs[i]) ×33 — source inside | 78 - * | the grown slice, resolve-after-grow | - * selfidx_oldlen_once | append(bs, bs[f(bs)]) — index expr runs | 80 - * | ONCE, PRE-grow (sees old len): the #49 | - * | ruling's split-order semantics pin | - * elem_kinds_place | place-resolved SOURCE × every other | 79 - * | element kind (scalar/narrow/str/slice/ | - * | tagged via the pre-existing arms) | - * spread_place_deref | append(*p, (*q)[i].xs...) — the old #35 | 81 - * | reject source, graduated (cgplaceaddr) | - * spread_dup_copy | PG6: deref-spine + indexed 56B-struct | 139 - * | spread sources (regex.ha:569/820 dup | - * | shapes) + copy-semantics pin | - * spread_place_kinds | place-sourced spread × str header / | 82 - * | narrow i32 / empty deref source | - * spread_growth_place | 40-elem place-sourced spread crossing | 83 - * | cap doublings (dst base moves mid-loop) | - * spread_selfalias_chain| source header inside the dst's grown | 119 - * | buffer — #49 stale-base hole pin | - * reject_spread_call_src| CALL rvalue spread source — #35 | BUILD_FAIL - * | residual (task #27) | - * reject_spread_array_src| [N]T array spread source — was a | BUILD_FAIL - * | silent 16-byte garbage header read | - * reject_call_src | CALL rvalue element source — the #49 | BUILD_FAIL - * | loud tail (#42-style bound) | - * - * BUILD_FAIL rows also assert the diagnostic TEXT (stderr substring, - * both stages) — a build that fails for any other reason (parse error, - * crash) is a vacuous reject and fails the row. - * - * Every non-BUILD_FAIL row also asserts cstage/wwstage asm byte-id. - * - * Readbacks deliberately avoid the still-open F2/F5 read shapes - * (`len(xs[i].field)`, `let s = xs[i].field`) — those are tracked - * separately; this test pins the append WRITE path. - */ -#include -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return -1; -} - -/* want == BUILD_FAIL: the row must FAIL to build on both stages AND - * emit expect_err on stderr (rule 7 — never a silent acceptance; - * without the message check a row would pass vacuously on any - * unrelated build failure). */ -#define BUILD_FAIL (-2147483647 - 1) - -struct row { - const char *label; - const char *src; - int want; - const char *expect_err; /* BUILD_FAIL rows: required stderr substring */ -}; - -static const struct row rows[] = { - /* The FA1 minimum: two appends through a *[]i64 param, then a - * third through a local pointer binding. */ - { "scalar_param", - "package main;\n" - "fn add(p: *[]i64, v: i64) void = { append(*p, v); };\n" - "export fn main() i32 = {\n" - "\tlet xs: []i64 = [];\n" - "\tadd(&xs, 5);\n" - "\tadd(&xs, 9);\n" - "\tif (len(xs) != 2) { return 1; };\n" - "\tif (xs[0] != 5 || xs[1] != 9) { return 2; };\n" - "\tlet q: *[]i64 = &xs;\n" - "\tappend(*q, 11);\n" - "\tif (len(xs) != 3 || xs[2] != 11) { return 3; };\n" - "\treturn 60;\n" - "};\n", - 60, NULL }, - - /* esz=1 store (MOVB) + multi-value list through one resolve. */ - { "scalar_u8_multi", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet bs: []u8 = [];\n" - "\tlet q: *[]u8 = &bs;\n" - "\tappend(*q, 1u8, 2u8);\n" - "\tif (len(bs) != 2) { return 1; };\n" - "\tif (bs[0] != 1u8 || bs[1] != 2u8) { return 2; };\n" - "\treturn 61;\n" - "};\n", - 61, NULL }, - - { "spread_param", - "package main;\n" - "fn addall(p: *[]i64, src: []i64) void = { append(*p, src...); };\n" - "export fn main() i32 = {\n" - "\tlet xs: []i64 = [];\n" - "\tappend(xs, 1, 2);\n" - "\tlet ys: []i64 = [];\n" - "\taddall(&ys, xs);\n" - "\taddall(&ys, xs);\n" - "\tif (len(ys) != 4) { return 1; };\n" - "\tif (ys[0] != 1 || ys[1] != 2 || ys[3] != 2) { return 2; };\n" - "\treturn 62;\n" - "};\n", - 62, NULL }, - - /* Indirect mode has no declared tnode — the spread element LOAD - * op (sign extension) must come off the stamped tinfo; negative - * i32 elements pin MOVSXD. */ - { "spread_narrow_signed", - "package main;\n" - "fn addall(p: *[]i32, src: []i32) void = { append(*p, src...); };\n" - "export fn main() i32 = {\n" - "\tlet xs: []i32 = [];\n" - "\tappend(xs, -7i32, 9i32);\n" - "\tlet ys: []i32 = [];\n" - "\taddall(&ys, xs);\n" - "\tif (len(ys) != 2) { return 1; };\n" - "\tif (ys[0] != -7i32) { return 2; };\n" - "\tif (ys[1] != 9i32) { return 3; };\n" - "\treturn 63;\n" - "};\n", - 63, NULL }, - - /* Wide (24B) spread element word-copy through the deref target. */ - { "spread_wide", - "package main;\n" - "fn addall(p: *[]str, src: []str) void = { append(*p, src...); };\n" - "export fn main() i32 = {\n" - "\tlet ss: []str = [];\n" - "\tappend(ss, \"ab\");\n" - "\tappend(ss, \"cde\");\n" - "\tlet tt: []str = [];\n" - "\taddall(&tt, ss);\n" - "\tif (len(tt) != 2) { return 1; };\n" - "\tlet a: str = tt[0];\n" - "\tlet b: str = tt[1];\n" - "\tif (a.len != 2 || b.len != 3) { return 2; };\n" - "\tif (b[0] != 'c') { return 3; };\n" - "\treturn 64;\n" - "};\n", - 64, NULL }, - - /* str element: cgexpr leaves {ptr,len,cap} in AX/BX/CX; all three - * must survive rt_ensure AND the indirect header reload. */ - { "str_elem", - "package main;\n" - "fn adds(p: *[]str, v: str) void = { append(*p, v); };\n" - "export fn main() i32 = {\n" - "\tlet ss: []str = [];\n" - "\tadds(&ss, \"hi\");\n" - "\tadds(&ss, \"world\");\n" - "\tif (len(ss) != 2) { return 1; };\n" - "\tlet a: str = ss[0];\n" - "\tlet b: str = ss[1];\n" - "\tif (a.len != 2 || b.len != 5) { return 2; };\n" - "\tif (a[0] != 'h' || b[0] != 'w') { return 3; };\n" - "\treturn 65;\n" - "};\n", - 65, NULL }, - - { "slice_elem", - "package main;\n" - "fn addv(p: *[][]u8, v: []u8) void = { append(*p, v); };\n" - "export fn main() i32 = {\n" - "\tlet vv: [][]u8 = [];\n" - "\tlet one: []u8 = [];\n" - "\tappend(one, 5u8, 6u8);\n" - "\taddv(&vv, one);\n" - "\tif (len(vv) != 1) { return 1; };\n" - "\tlet got: []u8 = vv[0];\n" - "\tif (len(got) != 2 || got[1] != 6u8) { return 2; };\n" - "\treturn 66;\n" - "};\n", - 66, NULL }, - - /* Tagged element: the #12 widen choke-point boxes through the - * resolver-derived slot pointer (grow-first, no register form). */ - { "tagged_elem", - "package main;\n" - "type tu = (i64 | void);\n" - "fn addt(p: *[]tu, v: i64) void = { append(*p, v); };\n" - "export fn main() i32 = {\n" - "\tlet ts: []tu = [];\n" - "\taddt(&ts, 42);\n" - "\tif (len(ts) != 1) { return 1; };\n" - "\tlet t0: tu = ts[0];\n" - "\tif (!(t0 is i64)) { return 2; };\n" - "\treturn 67;\n" - "};\n", - 67, NULL }, - - /* The pA6 repro, verbatim shapes: struct-literal element fill - * through @appendscr while the header address sits in @apphdrscr. */ - { "struct_lit", - "package main;\n" - "type box = struct { pc: size, matched: bool };\n" - "fn add(p: *[]box, v: size) void = {\n" - "\tappend(*p, box { pc = v, matched = false });\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet bs: []box = [];\n" - "\tadd(&bs, 5);\n" - "\tadd(&bs, 9);\n" - "\tif (len(bs) != 2) { return 1; };\n" - "\tif (bs[0].pc != 5) { return 2; };\n" - "\tif (bs[1].pc != 9) { return 3; };\n" - "\treturn 68;\n" - "};\n", - 68, NULL }, - - { "struct_ident", - "package main;\n" - "type box = struct { pc: size, matched: bool };\n" - "fn add(p: *[]box, v: size) void = {\n" - "\tlet b: box = box { pc = v, matched = true };\n" - "\tappend(*p, b);\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet bs: []box = [];\n" - "\tadd(&bs, 7);\n" - "\tif (len(bs) != 1) { return 1; };\n" - "\tif (bs[0].pc != 7) { return 2; };\n" - "\tif (!bs[0].matched) { return 3; };\n" - "\treturn 69;\n" - "};\n", - 69, NULL }, - - /* The corruption symptom row: 100 appends through the param in a - * loop with a branched callee — crosses several cap-doubling - * reallocs. Sentinels on BOTH sides of the slice local pin the - * caller frame (pre-fix cstage incremented 8(BP) and passed (BP) - * to rt_ensure → caller-frame corruption); the full readback pins - * every element across the realloc moves. */ - { "realloc_loop", - "package main;\n" - "type box = struct { pc: size, matched: bool };\n" - "fn add(p: *[]box, v: size) void = {\n" - "\tif (v % 2 == 0) {\n" - "\t\tappend(*p, box { pc = v, matched = true });\n" - "\t} else {\n" - "\t\tappend(*p, box { pc = v, matched = false });\n" - "\t};\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet lo: i64 = 0x5151;\n" - "\tlet bs: []box = [];\n" - "\tlet hi: i64 = 0x7272;\n" - "\tlet i: size = 0;\n" - "\tfor (i < 100) {\n" - "\t\tadd(&bs, i);\n" - "\t\ti += 1;\n" - "\t};\n" - "\tif (len(bs) != 100) { return 1; };\n" - "\tlet j: size = 0;\n" - "\tfor (j < 100) {\n" - "\t\tif (bs[j].pc != j) { return 2; };\n" - "\t\tif (bs[j].matched != (j % 2 == 0)) { return 3; };\n" - "\t\tj += 1;\n" - "\t};\n" - "\tif (lo != 0x5151 || hi != 0x7272) { return 4; };\n" - "\treturn 70;\n" - "};\n", - 70, NULL }, - - /* Deeper resolver spine: the header is a slice FIELD of an element - * behind a deref ((*q)[i].xs — N_DOT over N_INDEX over N_UN). - * Readback via a *holder ptr-dot, a sound read path. */ - { "deref_spine", - "package main;\n" - "type holder = struct { tag: i64, xs: []i64 };\n" - "fn addspine(q: *[]holder, i: i64, v: i64) void = {\n" - "\tappend((*q)[i].xs, v);\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet hs: []holder = [];\n" - "\tlet h0: holder = holder { tag = 1, xs = [] };\n" - "\tappend(hs, h0);\n" - "\taddspine(&hs, 0, 41);\n" - "\taddspine(&hs, 0, 43);\n" - "\tlet hp: *holder = &hs[0];\n" - "\tlet g: []i64 = hp.xs;\n" - "\tif (len(g) != 2) { return 1; };\n" - "\tif (g[0] != 41 || g[1] != 43) { return 2; };\n" - "\tif (hp.tag != 1) { return 3; };\n" - "\treturn 71;\n" - "};\n", - 71, NULL }, - - /* Ident-local targets stay with the legacy BP-disp emission (the - * resolver must never fire for them) — this row runtime-pins the - * shapes the before/after asm sweep diffed statically. */ - { "neutral_direct", - "package main;\n" - "type box = struct { pc: size, matched: bool };\n" - "export fn main() i32 = {\n" - "\tlet xs: []i64 = [];\n" - "\tappend(xs, 7);\n" - "\tappend(xs, 8, 9);\n" - "\tlet ys: []i64 = [];\n" - "\tappend(ys, xs...);\n" - "\tlet ss: []str = [];\n" - "\tappend(ss, \"hi\");\n" - "\tlet ps: []box = [];\n" - "\tappend(ps, box { pc = 1, matched = false });\n" - "\tif (len(xs) != 3 || xs[2] != 9) { return 1; };\n" - "\tif (len(ys) != 3 || ys[0] != 7) { return 2; };\n" - "\tif (len(ss) != 1 || len(ps) != 1) { return 3; };\n" - "\treturn 72;\n" - "};\n", - 72, NULL }, - - /* Reentrancy: a nested append-through-pointer inside the outer - * append's VALUE expression (match-yield arm) spills its own - * header address. Pins the per-SITE @apphdrscr slot — a shared - * per-fn slot hands the outer's post-rt_ensure reloads the inner - * target's header and the outer element lands in the wrong - * slice (silent, both counts wrong). */ - { "reentrant_value", - "package main;\n" - "type tu = (i64 | void);\n" - "fn nest(p: *[]i64, q: *[]i64, t: tu) void = {\n" - "\tappend(*p, match (t) {\n" - "\tcase let x: i64 => {\n" - "\t\tappend(*q, 500);\n" - "\t\tyield x;\n" - "\t};\n" - "\tcase void => {\n" - "\t\tyield 0;\n" - "\t};\n" - "\t});\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet a: []i64 = [];\n" - "\tlet b: []i64 = [];\n" - "\tlet t: tu = 7;\n" - "\tnest(&a, &b, t);\n" - "\tif (len(a) != 1) { return 1; };\n" - "\tif (len(b) != 1) { return 2; };\n" - "\tif (a[0] != 7) { return 3; };\n" - "\tif (b[0] != 500) { return 4; };\n" - "\treturn 33;\n" - "};\n", - 33, NULL }, - - /* Ident-rooted dot target (h.xs through *holder): C1.5's loud - * boundary (the resolver had no ident root then; pre-FA1 this - * shape silently corrupted the frame in cstage), graduated by - * C2's cgplaceaddr N_IDENT root — the *holder base derefs once - * inside the N_DOT hop and the header place lands on &h.xs. - * Readbacks use the .len pseudo, not len(): len() of a non-tuple - * N_DOT is the pre-existing F2 enumeration gap (task #10). */ - { "identroot_dot", - "package main;\n" - "type holder = struct { tag: i64, xs: []i64 };\n" - "fn addfield(h: *holder, v: i64) void = { append(h.xs, v); };\n" - "export fn main() i32 = {\n" - "\tlet hl: holder = holder { tag = 2, xs = [] };\n" - "\taddfield(&hl, 9);\n" - "\taddfield(&hl, 11);\n" - "\tif (hl.xs[0] != 9) { return 1; };\n" - "\tif (hl.xs[1] != 11) { return 2; };\n" - "\tif (hl.xs.len != 2) { return 3; };\n" - "\tif (hl.tag != 2) { return 4; };\n" - "\treturn 73;\n" - "};\n", - 73, NULL }, - - /* #49 (#35's single-element sibling): the struct-element append - * arm dispatched on SOURCE node kind — N_STRUCTLIT and N_IDENT - * only; every place-resolvable chain (the regex.ha:819 - * result-build line `append(res, threads[best_idx].root_capture)`) - * died on the rule-7 fatal. The fix routes the remaining shapes - * through cgplaceaddr (the C1 resolver): dst slot spills to - * @appendscr, source resolves AFTER the grow, whole-width - * word-copy through DX. Five rows: indexed-field 56B capture, - * computed-index whole element, deref-spine through params, - * deref source, self-append across reallocs. */ - { "idxfield_struct", - "package main;\n" - "type capture = struct { content: str, start: size,\n" - "\tstart_bytesize: size, end: size, end_bytesize: size };\n" - "type thread = struct { pc: size, root_capture: capture,\n" - "\tmatched: bool };\n" - "export fn main() i32 = {\n" - "\tlet threads: []thread = [];\n" - "\tappend(threads, thread { pc = 7, ... });\n" - "\tappend(threads, thread { pc = 1, root_capture = capture {\n" - "\t\tcontent = \"bcd\", start = 1, start_bytesize = 2,\n" - "\t\tend = 4, end_bytesize = 5 }, ... });\n" - "\tlet res: []capture = [];\n" - "\tlet i: size = 1;\n" - "\tappend(res, threads[i].root_capture);\n" - "\tif (len(res) != 1) { return 1; };\n" - "\tif (res[0].start != 1) { return 2; };\n" - "\tif (res[0].start_bytesize != 2) { return 3; };\n" - "\tif (res[0].end != 4) { return 4; };\n" - "\tif (res[0].end_bytesize != 5) { return 5; };\n" - "\tif (res[0].content.len != 3) { return 6; };\n" - "\tif (threads[1].root_capture.end != 4) { return 7; };\n" - "\treturn 74;\n" - "};\n", - 74, NULL }, - - { "idx_computed_elem", - "package main;\n" - "type box = struct { pc: size, a: i64, b: i64, x: i64 };\n" - "export fn main() i32 = {\n" - "\tlet bs: []box = [];\n" - "\tappend(bs, box { pc = 1, a = 10, ... });\n" - "\tappend(bs, box { pc = 2, a = 20, ... });\n" - "\tappend(bs, box { pc = 3, a = 30, b = 7, x = 8 });\n" - "\tlet ds: []box = [];\n" - "\tlet i: i64 = 1;\n" - "\tappend(ds, bs[i + 1]);\n" - "\tif (len(ds) != 1) { return 1; };\n" - "\tif (ds[0].pc != 3) { return 2; };\n" - "\tif (ds[0].a != 30) { return 3; };\n" - "\tif (ds[0].b != 7 || ds[0].x != 8) { return 4; };\n" - "\treturn 75;\n" - "};\n", - 75, NULL }, - - { "derefspine_field", - "package main;\n" - "type cap = struct { s: size, e: size };\n" - "type th = struct { pc: size, rc: cap, m: bool };\n" - "fn pick(r: *[]cap, q: *[]th, i: size) void = {\n" - "\tappend(*r, (*q)[i].rc);\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet ts: []th = [];\n" - "\tappend(ts, th { pc = 1, rc = cap { s = 5, e = 9 }, ... });\n" - "\tlet rs: []cap = [];\n" - "\tpick(&rs, &ts, 0);\n" - "\tif (len(rs) != 1) { return 1; };\n" - "\tif (rs[0].s != 5) { return 2; };\n" - "\tif (rs[0].e != 9) { return 3; };\n" - "\treturn 76;\n" - "};\n", - 76, NULL }, - - { "deref_src", - "package main;\n" - "type box = struct { pc: size, a: i64, b: i64, x: i64 };\n" - "fn addsrc(ds: *[]box, p: *box) void = { append(*ds, *p); };\n" - "export fn main() i32 = {\n" - "\tlet b: box = box { pc = 4, a = 40, b = 41, x = 42 };\n" - "\tlet ds: []box = [];\n" - "\taddsrc(&ds, &b);\n" - "\tif (len(ds) != 1) { return 1; };\n" - "\tif (ds[0].pc != 4) { return 2; };\n" - "\tif (ds[0].a != 40 || ds[0].b != 41 || ds[0].x != 42) { return 3; };\n" - "\treturn 77;\n" - "};\n", - 77, NULL }, - - /* Self-append: the source element lives in the SLICE BEING GROWN, - * so its address is only valid post-rt_ensure — pins the - * resolve-AFTER-grow order across several cap-doubling reallocs. - * Sentinels around the header pin the frame. */ - { "self_append_realloc", - "package main;\n" - "type box = struct { pc: size, a: i64, b: i64, x: i64 };\n" - "export fn main() i32 = {\n" - "\tlet lo: i64 = 111;\n" - "\tlet bs: []box = [];\n" - "\tlet hi: i64 = 222;\n" - "\tappend(bs, box { pc = 9, a = 100, b = 200, x = 300 });\n" - "\tlet i: i32 = 0;\n" - "\tfor (i < 33) {\n" - "\t\tappend(bs, bs[i]);\n" - "\t\ti += 1;\n" - "\t};\n" - "\tif (len(bs) != 34) { return 1; };\n" - "\tif (bs[0].pc != 9 || bs[33].pc != 9) { return 2; };\n" - "\tif (bs[17].a != 100 || bs[33].b != 200) { return 3; };\n" - "\tif (bs[33].x != 300) { return 4; };\n" - "\tif (lo != 111 || hi != 222) { return 5; };\n" - "\treturn 78;\n" - "};\n", - 78, NULL }, - - /* The #49 ruling's order pin, positive semantics row (converged - * with Hare, not a documented divergence): the source chain's - * rvalues — here a CALLED index helper reading the slice's len — - * evaluate exactly ONCE, PRE-grow. calls != 1 catches a - * double-evaluation; bs[2] != old-last catches a post-grow - * resolution (the helper would see the bumped len and return the - * uninitialized new slot — the pre-split emission failed exactly - * there, exit 3). */ - { "selfidx_oldlen_once", - "package main;\n" - "type box = struct { pc: i64, a: i64 };\n" - "let calls: i64 = 0;\n" - "fn lastidx(xs: []box) i64 = {\n" - "\tcalls += 1;\n" - "\tlet n: i64 = len(xs): i64;\n" - "\treturn n - 1;\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet bs: []box = [];\n" - "\tappend(bs, box { pc = 11, a = 1 });\n" - "\tappend(bs, box { pc = 4242, a = 2 });\n" - "\tappend(bs, bs[lastidx(bs)]);\n" - "\tif (calls != 1) { return 1; };\n" - "\tif (len(bs) != 3) { return 2; };\n" - "\tif (bs[2].pc != 4242 || bs[2].a != 2) { return 3; };\n" - "\tif (bs[0].pc != 11) { return 4; };\n" - "\treturn 80;\n" - "};\n", - 80, NULL }, - - /* Element-kind × place-source matrix: struct was the ONLY kind - * the source-shape dispatch rejected — scalar (wide + narrow), - * str-header, slice-header and tagged sources route through the - * pre-existing cgexpr-based arms and already worked at 796d41b. - * This row is the regression net pinning that matrix (runtime + - * byte-id, dual-driver), not a fix pin. */ - { "elem_kinds_place", - "package main;\n" - "type box = struct { n: i64, m: i32, name: str, xs: []u8 };\n" - "type tv = (i64 | void);\n" - "export fn main() i32 = {\n" - "\tlet inner: []u8 = [];\n" - "\tappend(inner, 7u8);\n" - "\tappend(inner, 8u8);\n" - "\tlet bs: []box = [];\n" - "\tappend(bs, box { n = 41, m = 9, name = \"hello\", xs = inner });\n" - "\tlet ns: []i64 = [];\n" - "\tappend(ns, bs[0].n);\n" - "\tlet ms: []i32 = [];\n" - "\tappend(ms, bs[0].m);\n" - "\tlet ss: []str = [];\n" - "\tappend(ss, bs[0].name);\n" - "\tlet vs: [][]u8 = [];\n" - "\tappend(vs, bs[0].xs);\n" - "\tlet ts: []tv = [];\n" - "\tappend(ts, bs[0].n);\n" - "\tif (len(ns) != 1 || ns[0] != 41) { return 1; };\n" - "\tif (len(ms) != 1 || ms[0] != 9) { return 2; };\n" - "\tif (len(ss) != 1 || len(ss[0]) != 5) { return 3; };\n" - "\tif (len(vs) != 1 || len(vs[0]) != 2) { return 4; };\n" - "\tif (vs[0][1] != 8u8) { return 5; };\n" - "\tmatch (ts[0]) {\n" - "\tcase let v: i64 => { if (v != 41) { return 6; }; };\n" - "\tcase void => { return 7; };\n" - "\t};\n" - "\treturn 79;\n" - "};\n", - 79, NULL }, - - /* #35 graduation: the FA4-era designed boundary — a place-chain - * spread SOURCE — now resolves through cgplaceaddr (header - * address pre-grow, ptr/len re-read through it per iteration). - * This row is the OLD reject source verbatim, now with elements - * and a readback. */ - { "spread_place_deref", - "package main;\n" - "type holder = struct { tag: i64, xs: []i64 };\n" - "fn dup(p: *[]i64, q: *[]holder, i: i64) void = {\n" - "\tappend(*p, (*q)[i].xs...);\n" - "};\n" - "export fn main() i32 = {\n" - "\tlet inner: []i64 = [];\n" - "\tappend(inner, 5);\n" - "\tappend(inner, 9);\n" - "\tlet ys: []i64 = [];\n" - "\tlet hs: []holder = [];\n" - "\tappend(hs, holder { tag = 1, xs = inner });\n" - "\tdup(&ys, &hs, 0);\n" - "\tif (len(ys) != 2) { return 1; };\n" - "\tif (ys[0] != 5 || ys[1] != 9) { return 2; };\n" - "\treturn 81;\n" - "};\n", - 81, NULL }, - - /* #35, the fold-5 dup shapes (PG6): (a) deref-spine source - * `(*tsp)[0].caps...` (add_thread regex.ha:569/572), (b) indexed - * source `ts[0].caps...` (search ha:820), 56B struct elements; - * plus the COPY-semantics pin — mutating the dup must not touch - * the source. */ - { "spread_dup_copy", - "package main;\n" - "type capture = struct {\n" - "\tcontent: str,\n" - "\tstart: size,\n" - "\tstart_bytesize: size,\n" - "\tend: size,\n" - "\tend_bytesize: size,\n" - "};\n" - "type thr = struct { pc: size, caps: []capture };\n" - "export fn main() i32 = {\n" - "\tlet c0: []capture = [];\n" - "\tappend(c0, capture { content = \"x\", start = 3: size, start_bytesize = 3: size, end = 8: size, end_bytesize = 8: size });\n" - "\tappend(c0, capture { content = \"yz\", start = 5: size, start_bytesize = 5: size, end = 9: size, end_bytesize = 9: size });\n" - "\tlet ts: []thr = [];\n" - "\tappend(ts, thr { pc = 0: size, caps = c0 });\n" - "\tlet tsp = &ts;\n" - "\tlet dup: []capture = [];\n" - "\tappend(dup, (*tsp)[0].caps...);\n" - "\tif (len(dup) != 2) { return 1; };\n" - "\tif (len(dup[1].content) != 2 || dup[1].content[0] != 'y') { return 2; };\n" - "\tlet res: []capture = [];\n" - "\tappend(res, ts[0].caps...);\n" - "\tif (len(res) != 2) { return 3; };\n" - "\tif (res[0].end != 8 || res[1].start != 5) { return 4; };\n" - "\tdup[0].start = 100: size;\n" - "\tif (ts[0].caps[0].start != 3) { return 5; };\n" - "\tlet acc = dup[0].start + dup[1].end + res[0].start + res[1].end_bytesize\n" - "\t\t+ ts[0].caps[0].end + (len(dup): size) * 5;\n" - "\treturn acc: i32;\n" - "};\n", - 139, NULL }, - - /* #35 element kinds through a PLACE source: str 24B headers, - * narrow i32 (scalar load/store width), and the empty source - * (zero-iteration loop) through a deref. */ - { "spread_place_kinds", - "package main;\n" - "type holder = struct { tag: i64, ss: []str, ns: []i32 };\n" - "export fn main() i32 = {\n" - "\tlet h = holder { tag = 1, ss = [], ns = [] };\n" - "\tappend(h.ss, \"ab\");\n" - "\tappend(h.ss, \"cde\");\n" - "\tappend(h.ns, 7: i32);\n" - "\tlet hs: []holder = [];\n" - "\tappend(hs, h);\n" - "\tlet ss: []str = [];\n" - "\tappend(ss, hs[0].ss...);\n" - "\tif (len(ss) != 2) { return 1; };\n" - "\tif (len(ss[0]) != 2 || ss[0][1] != 'b') { return 2; };\n" - "\tif (len(ss[1]) != 3 || ss[1][2] != 'e') { return 3; };\n" - "\tlet ns: []i32 = [];\n" - "\tappend(ns, hs[0].ns...);\n" - "\tif (len(ns) != 1 || ns[0] != 7) { return 4; };\n" - "\tlet empty: []i64 = [];\n" - "\tlet ep = ∅\n" - "\tlet acc: []i64 = [];\n" - "\tappend(acc, (*ep)...);\n" - "\tif (len(acc) != 0) { return 5; };\n" - "\treturn 82;\n" - "};\n", - 82, NULL }, - - /* #35 growth across cap: a 40-element place-sourced spread into a - * non-empty dst crosses several cap doublings — rt_ensure moves - * the dst base mid-loop; every slot lands because the dst header - * re-reads post-grow each iteration. */ - { "spread_growth_place", - "package main;\n" - "type holder = struct { tag: i64, xs: []i64 };\n" - "export fn main() i32 = {\n" - "\tlet big: []i64 = [];\n" - "\tlet i: i64 = 0;\n" - "\tfor (i < 40) { append(big, i); i += 1; };\n" - "\tlet hs: []holder = [];\n" - "\tappend(hs, holder { tag = 2, xs = big });\n" - "\tlet dst: []i64 = [];\n" - "\tappend(dst, 100);\n" - "\tappend(dst, hs[0].xs...);\n" - "\tif (len(dst) != 41) { return 1; };\n" - "\tif (dst[0] != 100 || dst[1] != 0 || dst[40] != 39) { return 2; };\n" - "\treturn 83;\n" - "};\n", - 83, NULL }, - - /* #35 aliasing: the source HEADER lives inside the dst's own - * buffer (xs[0].kids reached through xs.ptr); the first grow - * reallocs that buffer. The pre-grow-resolved header address then - * reads the STALE copy — bit-identical under the non-reclaiming - * rt/malloc, the documented #49 stale-base hole. Pins that the - * spread terminates AND copies the right elements. */ - { "spread_selfalias_chain", - "package main;\n" - "type tnode = struct { v: i64, kids: []tnode };\n" - "export fn main() i32 = {\n" - "\tlet inner: []tnode = [];\n" - "\tappend(inner, tnode { v = 7, kids = [] });\n" - "\tappend(inner, tnode { v = 9, kids = [] });\n" - "\tlet xs: []tnode = [];\n" - "\tappend(xs, tnode { v = 1, kids = inner });\n" - "\tappend(xs, xs[0].kids...);\n" - "\tif (len(xs) != 3) { return 1; };\n" - "\tif (xs[0].v != 1 || xs[1].v != 7 || xs[2].v != 9) { return 2; };\n" - "\treturn (81 + xs[1].v * 2 + xs[2].v * 2 + (len(xs): i64) * 2): i32;\n" - "};\n", - 119, NULL }, - - /* The #35 residual boundary (task #27): a CALL rvalue spread - * source has no place to resolve — stays loud until a - * scratch-receive route lands. */ - { "reject_spread_call_src", - "package main;\n" - "fn mk() []i64 = { let r: []i64 = []; append(r, 5); return r; };\n" - "export fn main() i32 = {\n" - "\tlet xs: []i64 = [];\n" - "\tappend(xs, mk()...);\n" - "\treturn 0;\n" - "};\n", - BUILD_FAIL, "#35: append() spread source shape unsupported (rule-7)" }, - - /* The #35 residual boundary (task #27): a [N]T ARRAY source place - * IS its storage, not a {ptr,len,cap} header — pre-guard the - * ident path silently read its first 16 data bytes as ptr/len. - * Loud until wired. */ - { "reject_spread_array_src", - "package main;\n" - "export fn main() i32 = {\n" - "\tlet a: [2]i64 = [3, 4];\n" - "\tlet xs: []i64 = [];\n" - "\tappend(xs, a...);\n" - "\treturn 0;\n" - "};\n", - BUILD_FAIL, "#35: append() spread source shape unsupported (rule-7)" }, - - /* The #49 boundary: a CALL rvalue source has no place to resolve - * — stays loud (the #42-style bound) until a scratch-receive - * route lands. */ - { "reject_call_src", - "package main;\n" - "type box = struct { pc: size, a: i64 };\n" - "fn mk() box = { return box { pc = 1, a = 2 }; };\n" - "export fn main() i32 = {\n" - "\tlet bs: []box = [];\n" - "\tappend(bs, mk());\n" - "\treturn 0;\n" - "};\n", - BUILD_FAIL, "#34: append() struct element source shape unsupported (rule-7)" }, -}; - -/* errlog_has — the build-failure stderr must carry the row's expected - * diagnostic; any other failure (parse error, crash) is a vacuous - * reject and must not pass. */ -static int -errlog_has(const char *path, const char *needle) -{ - FILE *f = fopen(path, "rb"); - if (!f) return 0; - char buf[8192]; - size_t got = fread(buf, 1, sizeof buf - 1, f); - fclose(f); - buf[got] = '\0'; - return strstr(buf, needle) != NULL; -} - -static int -run_driver(const char *driver, const struct row *r, int i) -{ - char tmpdir[] = "/tmp/applp_XXXXXX"; - char src[128], outbin[128], errlog[160], scratch[192]; - char rmcmd[224], cmd[1200]; - int result = -2; - if (mkdtemp(tmpdir) == NULL) { - fprintf(stderr, "row[%s]: workspace acquisition failed\n", r->label); - return result; - } - snprintf(src, sizeof src, "%s/applp_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/applp_%d_%d", tmpdir, getpid(), i); - snprintf(errlog, sizeof errlog, "%s/err", tmpdir); - snprintf(scratch, sizeof scratch, "%s.sepwork", outbin); - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", scratch); - - FILE *f = fopen(src, "wb"); - if (!f) goto done; - fputs(r->src, f); - int werr = ferror(f); - if (fclose(f) != 0) werr = 1; - if (werr) goto done; - - snprintf(cmd, sizeof cmd, "%s build -o %s %s 2>%s", - driver, outbin, src, errlog); - if (runwait(cmd) != 0) { - result = -1; - if (r->want != BUILD_FAIL) { - fprintf(stderr, "row[%s]: build via %s failed\n", - r->label, driver); - } else if (r->expect_err && - !errlog_has(errlog, r->expect_err)) { - fprintf(stderr, "row[%s]: %s build failed without " - "expected diagnostic \"%s\"\n", - r->label, driver, r->expect_err); - result = -3; /* failed, but for the wrong reason */ - } - goto done; - } - - result = runwait(outbin); - -done: - { - int cleanfail = 0; - if (runwait(rmcmd) != 0) cleanfail = 1; - if (unlink(errlog) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: workspace cleanup failed\n", r->label); - int passed = r->want == BUILD_FAIL - ? result == -1 : result == r->want; - if (passed) result = -2; - } - } - return result; -} - -/* asm_byte_identical — generate .s via cstage's w6c and wwstage's - * w6c_ww and diff. The header-place emission is written fresh on both - * sides, so this is the converged-by-construction gate: any drift in - * the resolve/spill/reload sequence shows here. */ -static int -asm_byte_identical(const char *bin, const struct row *r, int i) -{ - (void)i; - char dir[] = "/tmp/applp_asm_XXXXXX"; - char src[128], cs[128], ws[128], cmd[1024]; - int rc = -1; - if (mkdtemp(dir) == NULL) return -1; - snprintf(src, sizeof src, "%s/input.ww", dir); - snprintf(cs, sizeof cs, "%s/c.s", dir); - snprintf(ws, sizeof ws, "%s/w.s", dir); - - FILE *f = fopen(src, "wb"); - if (!f) goto done; - fputs(r->src, f); - int werr = ferror(f); - if (fclose(f) != 0) werr = 1; - if (werr) goto done; - - snprintf(cmd, sizeof cmd, "%s/w6c -o %s %s 2>/dev/null", bin, cs, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c errored\n", r->label); - goto done; - } - snprintf(cmd, sizeof cmd, "%s/w6c_ww -o %s %s 2>/dev/null", - bin, ws, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: w6c_ww errored\n", r->label); - goto done; - } - - FILE *fc = fopen(cs, "rb"); - FILE *fw = fopen(ws, "rb"); - rc = 0; - if (!fc || !fw) { - rc = -1; - } else { - for (;;) { - int a = fgetc(fc); - int b = fgetc(fw); - if (a != b) { rc = -1; break; } - if (a == EOF) break; - } - } - if (fc) fclose(fc); - if (fw) fclose(fw); - if (rc != 0) - fprintf(stderr, "row[%s]: cstage vs wwstage asm differs\n", - r->label); - -done: - { - int cleanfail = 0; - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(cs) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(ws) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(dir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row[%s]: asm workspace cleanup failed\n", - r->label); - rc = -1; - } - } - return rc; -} - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char absbin[2080]; - if (bin[0] != '/') { - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - char cdrv[2120]; - snprintf(cdrv, sizeof cdrv, "%s/ww", bin); - char wdrv[2120]; - snprintf(wdrv, sizeof wdrv, "%s/ww_ww", bin); - - struct { const char *name; const char *path; int gated_on_existence; } - drivers[] = { - { "cstage", cdrv, 0 }, - { "wwstage", wdrv, 1 }, - { NULL, NULL, 0 }, - }; - - int n = (int)(sizeof rows / sizeof rows[0]); - int total = 0, fail = 0; - - for (int d = 0; drivers[d].name; d++) { - if (drivers[d].gated_on_existence - && access(drivers[d].path, X_OK) != 0) { - fprintf(stderr, "append_place: skip %s (no %s)\n", - drivers[d].name, drivers[d].path); - continue; - } - for (int i = 0; i < n; i++) { - int got = run_driver(drivers[d].path, &rows[i], i); - total++; - int bad = rows[i].want == BUILD_FAIL - ? (got != -1) : (got != rows[i].want); - if (bad) { - fprintf(stderr, - "append_place[%s][%s]: exit=%d want=%d\n", - drivers[d].name, rows[i].label, - got, rows[i].want); - fail++; - } - } - } - - if (access(wdrv, X_OK) == 0) { - for (int i = 0; i < n; i++) { - if (rows[i].want == BUILD_FAIL) - continue; - total++; - if (asm_byte_identical(bin, &rows[i], i) != 0) - fail++; - } - } - - if (fail) { - fprintf(stderr, - "append_place: %d/%d fixtures failed\n", fail, total); - return 1; - } - printf("append_place: %d fixtures passed\n", total); - return 0; -} diff --git a/test/wcc/952_floats_run.c b/test/wcc/952_floats_run.c deleted file mode 100644 index 78886bba..00000000 --- a/test/wcc/952_floats_run.c +++ /dev/null @@ -1,438 +0,0 @@ -/* - * 952_floats_run — runtime regression net for lib/math/floats fold-1 - * (f64bits, f64frombits, isnan, isinf, signf64, absf64, copysignf64, - * ispositivef64, isnegativef64) plus the fold-2a decompose step - * (issubnormalf64, normalizef64, frexpf64). The classify/sign/bits surface rides - * the f64-codegen paths fixed by #96 (deref-load -> MOVSD/X0) and #97 - * (compare consults PF for NaN); normalizef64 additionally rides the #102 - * 16B-tuple-from-call receive (its (f64, i64) return) and the f64 multiply - * on the subnormal path. Both stages emit byte-identical asm, so the - * 990-997 byte-id gates can't catch a reintroduction — only an - * executed-and-checked runtime probe can. This file is that probe. - * - * frexpf64 rides two now-landed cgen fixes: the `n == 0f64` zero guard - * (#103 — a no-decimal f64 literal now reaches XMM) and its (f64, i64) - * tuple return + .0/.1 destructure (#105 — the tuple f64-word read). The - * frexpf64(0.0) row is the key regressor: it exercises both the early - * return AND the tuple receive. As with the normalizef64 rows, tuple - * fields are spilled to a let before any f64-literal comparison (a - * tuple-field f64 compared directly against a literal `r.0 == 0.0` was the - * #105 mis-load); the .1 i64 field is compared in place. - * - * Table-driven like 951_f64cgen_run: each row is a self-contained ww - * program importing math; the C-side cstage `ww build -I lib` compiles - * it, we run the binary and assert the exit code. Self-checking rows - * return 0 on pass / a locator code on the first failing assertion; - * value-propagation rows return a computed result compared to want_exit. - * - * cstage-only by design (mirrors 951 + 969_checked_run): `ww_ww run` is - * broken (#95) and per-program wwstage byte-id is the 990-997 gates' job. - * - * NaN/INF operands are built at runtime through opaque zero()/one() fns - * so the checker can't const-fold them away (matches 951's #97 rows). - */ -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return 1; -} - -struct row { const char *src; int want_exit; }; - -static const struct row rows[] = { - /* f64bits + f64frombits round-trip. 0x3FF0000000000000 == 1.0, - * 0x4045000000000000 == 42.0. Round-trip through tobits/frombits - * must preserve the bit pattern (both u64 and f64 deref-loads). */ - { "package main;\n" - "import math;\n" - "export fn main() i32 = {\n" - " if (math.f64bits(1.0) != 0x3FF0000000000000u64) { return 1; };\n" - " if (math.f64bits(0.0) != 0u64) { return 2; };\n" - " let rt: f64 = math.f64frombits(math.f64bits(-2.5));\n" - " if (rt != -2.5) { return 3; };\n" - " if (math.f64frombits(0x4045000000000000u64) != 42.0) { return 4; };\n" - " return 0;\n" - "};\n", 0 }, - /* f64frombits value propagation: a u64 bit pattern reinterpreted as - * f64 then truncated to i32. On #96 the deref strands the value in a - * GPR and the i32 cast reads stale X0. */ - { "package main;\n" - "import math;\n" - "export fn main() i32 = {\n" - " return math.f64frombits(0x4045000000000000u64): i32;\n" - "};\n", 42 }, - /* isnan + isinf. Runtime NaN/INF via opaque zero()/one() so the - * checker can't const-fold. isnan rides #97 (self-inequality must - * be true for NaN); isinf rides #96 (f64bits deref-load). */ - { "package main;\n" - "import math;\n" - "fn zero() f64 = { return 0.0; };\n" - "fn one() f64 = { return 1.0; };\n" - "export fn main() i32 = {\n" - " let nan: f64 = zero() / zero();\n" - " if (!math.isnan(nan)) { return 1; };\n" - " if (math.isnan(1.0)) { return 2; };\n" - " let inf: f64 = one() / zero();\n" - " if (!math.isinf(inf)) { return 3; };\n" - " if (!math.isinf(-inf)) { return 4; };\n" - " if (math.isinf(nan)) { return 5; };\n" - " if (math.isinf(1.23)) { return 6; };\n" - " return 0;\n" - "};\n", 0 }, - /* signf64 + ispositivef64 + isnegativef64. +0.0 has a clear sign - * bit so signf64(0.0) == 1 (zero is positive). */ - { "package main;\n" - "import math;\n" - "export fn main() i32 = {\n" - " if (math.signf64(3.0) != 1i64) { return 1; };\n" - " if (math.signf64(-3.0) != -1i64) { return 2; };\n" - " if (math.signf64(0.0) != 1i64) { return 3; };\n" - " if (!math.ispositivef64(3.0)) { return 4; };\n" - " if (math.ispositivef64(-3.0)) { return 5; };\n" - " if (!math.isnegativef64(-3.0)) { return 6; };\n" - " if (math.isnegativef64(3.0)) { return 7; };\n" - " return 0;\n" - "};\n", 0 }, - /* absf64 + copysignf64. absf64(NaN) stays NaN (early return before - * the bit-mask). copysign transfers y's sign onto x's magnitude. */ - { "package main;\n" - "import math;\n" - "fn zero() f64 = { return 0.0; };\n" - "export fn main() i32 = {\n" - " if (math.absf64(-3.0) != 3.0) { return 1; };\n" - " if (math.absf64(3.0) != 3.0) { return 2; };\n" - " let nan: f64 = zero() / zero();\n" - " if (!math.isnan(math.absf64(nan))) { return 3; };\n" - " if (math.copysignf64(3.0, -1.0) != -3.0) { return 4; };\n" - " if (math.copysignf64(-3.0, 1.0) != 3.0) { return 5; };\n" - " if (math.copysignf64(3.0, 1.0) != 3.0) { return 6; };\n" - " return 0;\n" - "};\n", 0 }, - /* absf64 value propagation: f64 result truncated to i32 (rides #96 - * f64-return through X0). */ - { "package main;\n" - "import math;\n" - "export fn main() i32 = {\n" - " return math.absf64(-7.0): i32;\n" - "};\n", 7 }, - /* issubnormalf64: normals and zero are not subnormal; the smallest - * positive f64 (bits == 1, ~5e-324) is. Built via f64frombits so the - * checker can't fold a subnormal literal (which it would flush). */ - { "package main;\n" - "import math;\n" - "export fn main() i32 = {\n" - " if (math.issubnormalf64(16.0)) { return 1; };\n" - " if (math.issubnormalf64(0.0)) { return 2; };\n" - " if (math.issubnormalf64(1.0)) { return 3; };\n" - " let s: f64 = math.f64frombits(1u64);\n" - " if (!math.issubnormalf64(s)) { return 4; };\n" - " return 0;\n" - "};\n", 0 }, - /* normalizef64 on a normal value returns (n, 0). The (f64, i64) tuple - * rides the #102 16B-tuple-from-call receive; r.0 is spilled to a let - * before comparison (see header). */ - { "package main;\n" - "import math;\n" - "export fn main() i32 = {\n" - " const r = math.normalizef64(16.0);\n" - " const m: f64 = r.0;\n" - " if (m != 16.0) { return 1; };\n" - " if (r.1 != 0i64) { return 2; };\n" - " return 0;\n" - "};\n", 0 }, - /* normalizef64 on a subnormal multiplies by 2^52 (f64 multiply inside a - * tuple return) and returns exp -52; the result is no longer subnormal - * and is nonzero. */ - { "package main;\n" - "import math;\n" - "export fn main() i32 = {\n" - " let s: f64 = math.f64frombits(1u64);\n" - " const r = math.normalizef64(s);\n" - " if (r.1 != -52i64) { return 1; };\n" - " const m: f64 = r.0;\n" - " if (math.issubnormalf64(m)) { return 2; };\n" - " if (m == 0.0) { return 3; };\n" - " return 0;\n" - "};\n", 0 }, - /* normalizef64 value propagation: normal-path .0 truncated to i32 - * (spilled to a let to dodge the tuple-field-compare mis-load; the - * cast itself reads the field fine). */ - { "package main;\n" - "import math;\n" - "export fn main() i32 = {\n" - " const r = math.normalizef64(42.0);\n" - " const m: f64 = r.0;\n" - " return m: i32;\n" - "};\n", 42 }, - /* frexpf64 exact (mantissa, exp): 8.0 -> (0.5, 4), 1.0 -> (0.5, 1), - * 0.75 -> (0.75, 0), and the key 0.0 -> (0.0, 0) early-return row - * (rides #103 `n == 0f64` + #105 tuple receive). Tuple .0 spilled to a - * let before the f64-literal compare; .1 compared in place. */ - { "package main;\n" - "import math;\n" - "export fn main() i32 = {\n" - " const a = math.frexpf64(8.0);\n" - " const am: f64 = a.0;\n" - " if (am != 0.5) { return 1; };\n" - " if (a.1 != 4i64) { return 2; };\n" - " const b = math.frexpf64(1.0);\n" - " const bm: f64 = b.0;\n" - " if (bm != 0.5) { return 3; };\n" - " if (b.1 != 1i64) { return 4; };\n" - " const c = math.frexpf64(0.0);\n" - " const cm: f64 = c.0;\n" - " if (cm != 0.0) { return 5; };\n" - " if (c.1 != 0i64) { return 6; };\n" - " const d = math.frexpf64(0.75);\n" - " const dm: f64 = d.0;\n" - " if (dm != 0.75) { return 7; };\n" - " if (d.1 != 0i64) { return 8; };\n" - " return 0;\n" - "};\n", 0 }, - /* frexpf64 mantissa range + reconstruction: for a nonzero input the - * mantissa is in [0.5, 1) and mantissa * 2^exp reproduces n. 12.0 -> - * (0.75, 4); 0.75 * 16 (== 2^4) == 12. */ - { "package main;\n" - "import math;\n" - "export fn main() i32 = {\n" - " const r = math.frexpf64(12.0);\n" - " const m: f64 = r.0;\n" - " if (m < 0.5) { return 1; };\n" - " if (m >= 1.0) { return 2; };\n" - " if (r.1 != 4i64) { return 3; };\n" - " if (m * 16.0 != 12.0) { return 4; };\n" - " return 0;\n" - "};\n", 0 }, - /* frexpf64 value propagation: 1024.0 == 2^10 -> (0.5, 11); the i64 exp - * field cast to i32 propagates as 11. */ - { "package main;\n" - "import math;\n" - "export fn main() i32 = {\n" - " const r = math.frexpf64(1024.0);\n" - " return r.1: i32;\n" - "};\n", 11 }, - /* --- strconv-foundation fold-1: F32 width constants. Mirror - * ref/hare/math/floats.ha:27,30,33,43,46. The shape values (23/8/ - * 127, 0x7FFFFF, 0xFF) are facts of IEEE 754 binary32 — any drift - * here means F32_* def-folding broke. */ - { "package main;\n" - "import math;\n" - "export fn main() i32 = {\n" - " if (math.F32_MANTISSA_BITS != 23u32) { return 1; };\n" - " if (math.F32_EXPONENT_BITS != 8u32) { return 2; };\n" - " if (math.F32_EXPONENT_BIAS != 127u32) { return 3; };\n" - " if (math.F32_MANTISSA_MASK != 0x7FFFFFu32) { return 4; };\n" - " if (math.F32_EXPONENT_MASK != 0xFFu32) { return 5; };\n" - " return 0;\n" - "};\n", 0 }, - /* f32bits / f32frombits round-trip. Mirror - * ref/hare/math/floats.ha:8,14 + ref/hare/math/+test/floats_test.ha:4 - * (the f32 leg). 1.0f32 -> 0x3F800000, 2.0f32 -> 0x40000000, - * -1.0f32 -> 0xBF800000, 0.0f32 -> 0u32. Rides the f32-literal - * materialise path (#104 fold-1) and the f32 ptr-deref read/write. */ - { "package main;\n" - "import math;\n" - "export fn main() i32 = {\n" - " if (math.f32bits(1.0f32) != 0x3F800000u32) { return 1; };\n" - " if (math.f32bits(2.0f32) != 0x40000000u32) { return 2; };\n" - " if (math.f32bits(-1.0f32) != 0xBF800000u32) { return 3; };\n" - " if (math.f32bits(0.0f32) != 0u32) { return 4; };\n" - " if (math.f32frombits(0x3F800000u32) != 1.0f32) { return 5; };\n" - " if (math.f32frombits(0x40000000u32) != 2.0f32) { return 6; };\n" - " if (math.f32frombits(0xBF800000u32) != -1.0f32) { return 7; };\n" - " if (math.f32frombits(0u32) != 0.0f32) { return 8; };\n" - " let v: f32 = 123456.0f32;\n" - " if (math.f32frombits(math.f32bits(v)) != v) { return 9; };\n" - " return 0;\n" - "};\n", 0 }, - /* f32bits value propagation: bit pattern 0x42280000 == 42.0f32; the - * u32 cast to i32 propagates as 42. */ - { "package main;\n" - "import math;\n" - "export fn main() i32 = {\n" - " return math.f32frombits(0x42280000u32): i32;\n" - "};\n", 42 }, - /* floatinfo struct: f64-shape instance, address-of must round-trip - * through a *floatinfo pointer parameter — that's the call shape - * stof's eisel_lemire (`f: *floatinfo`) uses in fold-4. Mirrors - * ref/hare/math/floats.ha:103. Stack-local because module-level - * struct lets-with-init don't lower yet (gap reported with lead). - * Field assignments rather than a struct literal: ww's N_DOT-qualified - * `math.floatinfo { ... }` literal trips the cross-module resolver - * (#16/#17, task list #12). */ - { "package main;\n" - "import math;\n" - "fn readbits(p: *math.floatinfo) u64 = { return p.mantbits; };\n" - "export fn main() i32 = {\n" - " let info: math.floatinfo;\n" - " info.mantbits = 52u64;\n" - " info.expbits = 11u64;\n" - " info.expbias = 1023;\n" - " info.mantmask = 0xFFFFFFFFFFFFFu64;\n" - " info.expmask = 0x7FFu64;\n" - " if (info.mantbits != 52u64) { return 1; };\n" - " if (info.expbits != 11u64) { return 2; };\n" - " if (info.expbias != 1023) { return 3; };\n" - " if (info.mantmask != 0xFFFFFFFFFFFFFu64) { return 4; };\n" - " if (info.expmask != 0x7FFu64) { return 5; };\n" - " if (readbits(&info) != 52u64) { return 6; };\n" - " return 0;\n" - "};\n", 0 }, - /* floatinfo f32-shape instance. Same fold as above; verifies the - * struct type is width-agnostic (Hare exports both f64info and - * f32info, ref/hare/math/floats.ha:117,126). */ - { "package main;\n" - "import math;\n" - "fn readbits(p: *math.floatinfo) u64 = { return p.mantbits; };\n" - "export fn main() i32 = {\n" - " let info: math.floatinfo;\n" - " info.mantbits = 23u64;\n" - " info.expbits = 8u64;\n" - " info.expbias = 127;\n" - " info.mantmask = 0x7FFFFFu64;\n" - " info.expmask = 0xFFu64;\n" - " if (info.mantbits != 23u64) { return 1; };\n" - " if (info.expbias != 127) { return 2; };\n" - " if (readbits(&info) != 23u64) { return 3; };\n" - " return 0;\n" - "};\n", 0 }, - /* --- strconv-foundation fold-1b: NAN_BITS / INF_BITS sentinels. - * Hare exports `def NAN = 0.0/0.0;` / `def INF = 1.0/0.0;` (ref/hare/ - * math/floats.ha:137,141); ww materializes via f64frombits(NAN_BITS) - * / f64frombits(INF_BITS) until #129 closes. The bit values are - * IEEE-754 facts (quiet-NaN: exp-all-ones + mantissa-MSB; +Inf: - * exp-all-ones + mantissa-zero) — any drift means the def-folded - * sentinels broke. */ - { "package main;\n" - "import math;\n" - "export fn main() i32 = {\n" - " if (math.NAN_BITS != 0x7FF8000000000000u64) { return 1; };\n" - " if (math.INF_BITS != 0x7FF0000000000000u64) { return 2; };\n" - " let n: f64 = math.f64frombits(math.NAN_BITS);\n" - " if (!math.isnan(n)) { return 3; };\n" - " if (math.isnan(1.0)) { return 4; };\n" - " let i: f64 = math.f64frombits(math.INF_BITS);\n" - " if (!math.isinf(i)) { return 5; };\n" - " if (!math.isinf(-i)) { return 6; };\n" - " if (math.isinf(1.23)) { return 7; };\n" - " return 0;\n" - "};\n", 0 }, - /* f64info / f32info module-scope instances, read cross-module through - * a *floatinfo pointer parameter — the exact call shape stof's - * eisel_lemire (`f: *floatinfo`) uses in fold-4. Address-of a - * module-level def lowers to LEAQ since #149; the field reads - * round-trip the static-init DATA the #129 A.2 path emits. Mirrors - * ref/hare/math/floats.ha:117,126. Pointer-param (not direct - * math.f64info.expbias) because a cross-module struct-field direct read - * leaks the field name as an extern (#150, task list #48). */ - { "package main;\n" - "import math;\n" - "fn rdbias(f: *math.floatinfo) int = { return f.expbias; };\n" - "fn rdmant(f: *math.floatinfo) u64 = { return f.mantbits; };\n" - "fn rdmask(f: *math.floatinfo) u64 = { return f.mantmask; };\n" - "fn rdebits(f: *math.floatinfo) u64 = { return f.expbits; };\n" - "fn rdemask(f: *math.floatinfo) u64 = { return f.expmask; };\n" - "export fn main() i32 = {\n" - " if (rdbias(&math.f64info) != 1023) { return 1; };\n" - " if (rdmant(&math.f64info) != 52u64) { return 2; };\n" - " if (rdmask(&math.f64info) != 0xFFFFFFFFFFFFFu64) { return 3; };\n" - " if (rdbias(&math.f32info) != 127) { return 4; };\n" - " if (rdmant(&math.f32info) != 23u64) { return 5; };\n" - " if (rdmask(&math.f32info) != 0x7FFFFFu64) { return 6; };\n" - " if (rdebits(&math.f64info) != 11u64) { return 7; };\n" - " if (rdemask(&math.f64info) != 0x7FFu64) { return 8; };\n" - " if (rdebits(&math.f32info) != 8u64) { return 9; };\n" - " if (rdemask(&math.f32info) != 0xFFu64) { return 10; };\n" - " return 0;\n" - "};\n", 0 }, - { NULL, 0 } -}; - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - char absbin[1024]; - if (bin[0] != '/') { - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - int n = 0, fail = 0; - for (int i = 0; rows[i].src; i++, n++) { - char tmpdir[] = "/tmp/wwflt_XXXXXX"; - if (mkdtemp(tmpdir) == NULL) { - fprintf(stderr, "row %d: mkdtemp failed\n", i); - fail++; - continue; - } - int rowfail = 0; - char src[128], outbin[128], cmd[2048]; - snprintf(src, sizeof src, "%s/case.ww", tmpdir); - snprintf(outbin, sizeof outbin, "%s/out", tmpdir); - - FILE *f = fopen(src, "wb"); - if (f == NULL) { - fprintf(stderr, "row %d: source open failed\n", i); - rowfail = 1; - goto cleanup; - } - int writefail = fputs(rows[i].src, f) == EOF; - if (fclose(f) != 0) writefail = 1; - if (writefail) { - fprintf(stderr, "row %d: source write failed\n", i); - rowfail = 1; - goto cleanup; - } - - snprintf(cmd, sizeof cmd, "%s/ww build -I %s/lib -o %s %s", - bin, cwd, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row %d: build failed\n src: %s\n", - i, rows[i].src); - rowfail = 1; - goto cleanup; - } - - int got = runwait(outbin); - if (got != rows[i].want_exit) { - fprintf(stderr, "row %d: exit %d, want %d\n src: %s\n", - i, got, rows[i].want_exit, rows[i].src); - rowfail = 1; - } - -cleanup: - { - int cleanfail = 0; - snprintf(cmd, sizeof cmd, "rm -rf %s/out.sepwork", tmpdir); - if (runwait(cmd) != 0) cleanfail = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanfail = 1; - if (unlink(src) != 0 && errno != ENOENT) cleanfail = 1; - if (rmdir(tmpdir) != 0) cleanfail = 1; - if (cleanfail) { - fprintf(stderr, "row %d: temporary cleanup failed\n", i); - rowfail = 1; - } - } - if (rowfail) fail++; - } - if (fail) { - fprintf(stderr, "%d/%d floats tests failed\n", fail, n); - return 1; - } - printf("floats: %d/%d ok\n", n, n); - return 0; -} diff --git a/test/wcc/958_types_sizelim_run.c b/test/wcc/958_types_sizelim_run.c deleted file mode 100644 index 4f286205..00000000 --- a/test/wcc/958_types_sizelim_run.c +++ /dev/null @@ -1,155 +0,0 @@ -/* - * 958_types_sizelim_run — runtime proof of the lib/types SIZE_* and - * UINTPTR_* limit constants (faithful port of ref/hare/types/arch+ - * x86_64.ha:16-26). Asserts both the values (MIN==0, MAX==U64_MAX) and - * that the consts are usable as their declared type in arithmetic and an - * i32 cast. - * - * SIZE_MAX is the no-cast def `def SIZE_MAX: size = U64_MAX;` — size is in - * the unsigned class and 8B-wide on amd64, so the u64→size init coerces - * without a cast (#113). UINTPTR_MAX keeps Hare's explicit cast - * (`U64_MAX: uintptr`) because uintptr is outside the unsigned class. A - * green row IS the proof both forms compiled and carry the right value. - * - * INT_MIN/MAX + UINT_MIN/MAX are deferred to #114 (ww int=8B vs Hare's 4B - * on amd64 makes the value question open); RUNE_MAX is deferred to #112 - * (no \U rune-escape lexer yet). Only the 4 SIZE/UINTPTR consts land here. - * - * Table-driven like 957_size_type_run / 952_floats_run: each row is a - * self-contained ww program; the cstage `ww build -I lib` compiles it, we - * run the binary and assert the exit code. cstage-only by design (mirrors - * 951/952/957): per-program wwstage byte-id is the 990-997 gates' job. - */ -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return 1; -} - -struct row { const char *src; int want_exit; }; - -static const struct row rows[] = { - /* size limits: SIZE_MIN is zero; SIZE_MAX equals U64_MAX both by - * direct compare and by the all-ones wrap (MAX + 1 == 0 on 8B). */ - { "package main;\n" - "import types;\n" - "export fn main() i32 = {\n" - " let lo: size = types.SIZE_MIN;\n" - " if (lo != 0) { return 1; };\n" - " let hi: size = types.SIZE_MAX;\n" - " if (hi != (types.U64_MAX): size) { return 2; };\n" - " if (hi + 1 != 0) { return 3; };\n" - " return 0;\n" - "};\n", 0 }, - /* SIZE_MAX usable in size arithmetic, propagated through an i32 - * cast: (2^64-1) + 43 wraps to 42. */ - { "package main;\n" - "import types;\n" - "export fn main() i32 = {\n" - " let hi: size = types.SIZE_MAX;\n" - " let v: size = hi + 43;\n" - " return v: i32;\n" - "};\n", 42 }, - /* uintptr limits: UINTPTR_MIN is zero; UINTPTR_MAX equals U64_MAX - * (Hare's explicit-cast def) both by compare and by the wrap. */ - { "package main;\n" - "import types;\n" - "export fn main() i32 = {\n" - " let lo: uintptr = types.UINTPTR_MIN;\n" - " if (lo != 0) { return 1; };\n" - " let hi: uintptr = types.UINTPTR_MAX;\n" - " if (hi != (types.U64_MAX): uintptr) { return 2; };\n" - " if (hi + 1 != 0) { return 3; };\n" - " return 0;\n" - "};\n", 0 }, - /* UINTPTR_MAX usable in uintptr arithmetic, propagated through an - * i32 cast: (2^64-1) + 43 wraps to 42. */ - { "package main;\n" - "import types;\n" - "export fn main() i32 = {\n" - " let hi: uintptr = types.UINTPTR_MAX;\n" - " let v: uintptr = hi + 43;\n" - " return v: i32;\n" - "};\n", 42 }, - { NULL, 0 } -}; - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - char absbin[1024]; - if (bin[0] != '/') { - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - int n = 0, fail = 0; - for (int i = 0; rows[i].src; i++, n++) { - char tmpdir[64] = "/tmp/wwslim_XXXXXX"; - if (mkdtemp(tmpdir) == NULL) { - perror("types_sizelim: mkdtemp"); - fail++; - continue; - } - - char src[128], outbin[128], sepwork[160], rmcmd[192]; - snprintf(src, sizeof src, "%s/wwslim_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/out", tmpdir); - snprintf(sepwork, sizeof sepwork, "%s.sepwork", outbin); - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", sepwork); - - FILE *f = fopen(src, "wb"); - if (f == NULL) { fail++; goto cleanup; } - fputs(rows[i].src, f); - fclose(f); - - char cmd[2048]; - snprintf(cmd, sizeof cmd, "%s/ww build -I %s/lib -o %s %s", - bin, cwd, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row %d: build failed\n src: %s\n", - i, rows[i].src); - fail++; - goto cleanup; - } - - int got = runwait(outbin); - if (got != rows[i].want_exit) { - fprintf(stderr, "row %d: exit %d, want %d\n src: %s\n", - i, got, rows[i].want_exit, rows[i].src); - fail++; - } - -cleanup: { - int cleanbad = 0; - if (unlink(src) != 0 && errno != ENOENT) cleanbad = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanbad = 1; - if (runwait(rmcmd) != 0) cleanbad = 1; - if (rmdir(tmpdir) != 0) cleanbad = 1; - if (cleanbad) { - fprintf(stderr, "row %d: temporary cleanup failed\n", i); - fail++; - } - } - } - if (fail) { - fprintf(stderr, "%d/%d types_sizelim tests failed\n", fail, n); - return 1; - } - printf("types_sizelim: %d/%d ok\n", n, n); - return 0; -} diff --git a/test/wcc/959_types_intlim_run.c b/test/wcc/959_types_intlim_run.c deleted file mode 100644 index 4d4d53af..00000000 --- a/test/wcc/959_types_intlim_run.c +++ /dev/null @@ -1,154 +0,0 @@ -/* - * 959_types_intlim_run — runtime proof of the lib/types INT_* and UINT_* - * limit constants. ww's int/uint are machine-word (8B on amd64, type.c:58), - * so the limits are DERIVED from size(int) (Go-style, cf math.MaxInt) rather - * than aliased to a per-arch literal the way Hare does (arch+x86_64.ha maps - * INT_MAX→I32_MAX). On amd64 the derived forms must therefore equal the 64-bit - * limits: INT_MAX==I64_MAX, INT_MIN==I64_MIN, UINT_MAX==U64_MAX, UINT_MIN==0 - * (#114, user ruling). - * - * Each row asserts both the value (vs the literal AND vs the i64/u64 limit - * const) and usability — the derived def survives const-fold, carries the - * right machine-word width, and is usable in arithmetic that wraps through an - * i32 cast (INT_MAX+43 and UINT_MAX+43 each wrap to 42 in the low 32 bits). - * - * Table-driven like 958_types_sizelim_run: each row is a self-contained ww - * program; the cstage `ww build -I lib` compiles it, we run the binary and - * assert the exit code. cstage-only by design (mirrors 951/952/957/958): - * per-program wwstage byte-id is the 990-997 gates' job. - */ -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return 1; -} - -struct row { const char *src; int want_exit; }; - -static const struct row rows[] = { - /* int limits: INT_MIN is I64_MIN, INT_MAX is I64_MAX — both by - * direct literal compare and against the i64 limit const. */ - { "package main;\n" - "import types;\n" - "export fn main() i32 = {\n" - " let lo: int = types.INT_MIN;\n" - " if (lo != -9223372036854775808) { return 1; };\n" - " if (lo: i64 != types.I64_MIN) { return 2; };\n" - " let hi: int = types.INT_MAX;\n" - " if (hi != 9223372036854775807) { return 3; };\n" - " if (hi: i64 != types.I64_MAX) { return 4; };\n" - " return 0;\n" - "};\n", 0 }, - /* INT_MAX usable in int arithmetic, propagated through an i32 cast: - * INT_MAX + 43 wraps past INT_MIN; low 32 bits are 42. */ - { "package main;\n" - "import types;\n" - "export fn main() i32 = {\n" - " let hi: int = types.INT_MAX;\n" - " let v: int = hi + 43;\n" - " return v: i32;\n" - "};\n", 42 }, - /* uint limits: UINT_MIN is zero; UINT_MAX is U64_MAX — both by - * compare and by the all-ones wrap (MAX + 1 == 0 on 8B). */ - { "package main;\n" - "import types;\n" - "export fn main() i32 = {\n" - " let lo: uint = types.UINT_MIN;\n" - " if (lo != 0) { return 1; };\n" - " let hi: uint = types.UINT_MAX;\n" - " if (hi != 18446744073709551615) { return 2; };\n" - " if (hi: u64 != types.U64_MAX) { return 3; };\n" - " if (hi + 1 != 0) { return 4; };\n" - " return 0;\n" - "};\n", 0 }, - /* UINT_MAX usable in uint arithmetic, propagated through an i32 - * cast: (2^64-1) + 43 wraps to 42. */ - { "package main;\n" - "import types;\n" - "export fn main() i32 = {\n" - " let hi: uint = types.UINT_MAX;\n" - " let v: uint = hi + 43;\n" - " return v: i32;\n" - "};\n", 42 }, - { NULL, 0 } -}; - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - char absbin[1024]; - if (bin[0] != '/') { - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - int n = 0, fail = 0; - for (int i = 0; rows[i].src; i++, n++) { - char tmpdir[64] = "/tmp/wwilim_XXXXXX"; - if (mkdtemp(tmpdir) == NULL) { - perror("types_intlim: mkdtemp"); - fail++; - continue; - } - - char src[128], outbin[128], sepwork[160], rmcmd[192]; - snprintf(src, sizeof src, "%s/wwilim_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/out", tmpdir); - snprintf(sepwork, sizeof sepwork, "%s.sepwork", outbin); - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", sepwork); - - FILE *f = fopen(src, "wb"); - if (f == NULL) { fail++; goto cleanup; } - fputs(rows[i].src, f); - fclose(f); - - char cmd[2048]; - snprintf(cmd, sizeof cmd, "%s/ww build -I %s/lib -o %s %s", - bin, cwd, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row %d: build failed\n src: %s\n", - i, rows[i].src); - fail++; - goto cleanup; - } - - int got = runwait(outbin); - if (got != rows[i].want_exit) { - fprintf(stderr, "row %d: exit %d, want %d\n src: %s\n", - i, got, rows[i].want_exit, rows[i].src); - fail++; - } - -cleanup: { - int cleanbad = 0; - if (unlink(src) != 0 && errno != ENOENT) cleanbad = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanbad = 1; - if (runwait(rmcmd) != 0) cleanbad = 1; - if (rmdir(tmpdir) != 0) cleanbad = 1; - if (cleanbad) { - fprintf(stderr, "row %d: temporary cleanup failed\n", i); - fail++; - } - } - } - if (fail) { - fprintf(stderr, "%d/%d types_intlim tests failed\n", fail, n); - return 1; - } - printf("types_intlim: %d/%d ok\n", n, n); - return 0; -} diff --git a/test/wcc/963_sort_run.c b/test/wcc/963_sort_run.c deleted file mode 100644 index 1712f78a..00000000 --- a/test/wcc/963_sort_run.c +++ /dev/null @@ -1,199 +0,0 @@ -/* - * 963_sort_run — runtime proof of lib/sort's search + lbisect + rbisect - * (faithful port of ref/hare/sort/{search,bisect}.ha). The three rows - * mirror the three relevant @test fns in ref/hare/sort/+test.ha - * (search:42-51, lbisect:8-23, rbisect:25-40), instantiated on a - * concrete []i32 with a real cmpfunc. - * - * lib/sort rides the opaque type-erasure surface proven by 962 - * (slice->[]opaque, *opaque<->*u8 reinterpret, uintptr byte stride). The - * functions are exercised only here — they are dead in the bootstrap, so - * no 990-997 gate touches them; this executed-and-checked probe is their - * coverage (per the bootstrap-coverage discipline). - * - * The comparator binds its derefs to locals (`let va = *pa; if (va < - * vb)`) rather than Hare's inline `if (*pa < *pb)`: the inline-deref-in- - * comparison shape is mis-compiled by a PRE-EXISTING cgen bug (#116 / - * task #18, the same family 962's header documents). The bug is in the - * user-supplied comparator, NOT in search/bisect — those bind `r = - * cmp(...)` then compare, so the lib port is faithful and unaffected. - * - * Table-driven like 958_types_sizelim_run / 952_floats_run: each row is a - * self-contained ww program `import sort;`. cstage `ww build -I lib` - * compiles it, we run the binary and assert the exit code (0 == every - * assertion held; a small locator otherwise). cstage-only by design - * (mirrors 958/962): lib/sort is not compiler-imported, so per-program - * wwstage byte-id is out of scope and the 990-997 gates are unaffected. - */ -#include -#include -#include -#include -#include -#include - -static int -runwait(const char *cmd) -{ - int rc = system(cmd); - if (rc == -1) return -1; - if (WIFEXITED(rc)) return WEXITSTATUS(rc); - return 1; -} - -#define INTS \ - "fn ints(a: *opaque, b: *opaque) int = {\n" \ - " let pa: *i32 = a: *i32;\n" \ - " let pb: *i32 = b: *i32;\n" \ - " let va: i32 = *pa;\n" \ - " let vb: i32 = *pb;\n" \ - " if (va < vb) { return -1; };\n" \ - " if (va > vb) { return 1; };\n" \ - " return 0;\n" \ - "};\n" - -struct row { const char *label; const char *src; int want_exit; }; - -static const struct row rows[] = { - /* search: every present key resolves to its index; an absent key - * is void. ref/hare/sort/+test.ha:42-51. */ - { "search", - "package main;\n" - "import sort;\n" - INTS - "export fn main() i32 = {\n" - " let nums: [10]i32 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];\n" - " let s: []i32 = nums[0:10];\n" - " let n: size = len(s): size;\n" - " let i: size = 0;\n" - " for (i < n) {\n" - " let key: i32 = nums[i];\n" - " let p: size = sort.search(s, size(i32), &key, ints) as size;\n" - " if (p != i) { return 1; };\n" - " i = i + 1;\n" - " };\n" - " let miss: i32 = 1337;\n" - " let r = sort.search(s, size(i32), &miss, ints);\n" - " if (!(r is void)) { return 2; };\n" - " return 0;\n" - "};\n", 0 }, - /* lbisect: first-occurrence index for present values; insertion - * point for absent ones. ref/hare/sort/+test.ha:8-23. */ - { "lbisect", - "package main;\n" - "import sort;\n" - INTS - "export fn main() i32 = {\n" - " let nums: [10]i32 = [1, 3, 4, 4, 5, 7, 9, 11, 11, 11];\n" - " let s: []i32 = nums[0:10];\n" - " let n: size = len(s): size;\n" - " let i: size = 0;\n" - " for (i < n) {\n" - " if (i == 0 || nums[i - 1] != nums[i]) {\n" - " let key: i32 = nums[i];\n" - " if (sort.lbisect(s, size(i32), &key, ints) != i) { return 1; };\n" - " };\n" - " i = i + 1;\n" - " };\n" - " let n0: i32 = 0; if (sort.lbisect(s, size(i32), &n0, ints) != 0) { return 2; };\n" - " let n6: i32 = 6; if (sort.lbisect(s, size(i32), &n6, ints) != 5) { return 3; };\n" - " let n8: i32 = 8; if (sort.lbisect(s, size(i32), &n8, ints) != 6) { return 4; };\n" - " let n12: i32 = 12; if (sort.lbisect(s, size(i32), &n12, ints) != n) { return 5; };\n" - " return 0;\n" - "};\n", 0 }, - /* rbisect: last-occurrence+1 index for present values; insertion - * point for absent ones. ref/hare/sort/+test.ha:25-40. */ - { "rbisect", - "package main;\n" - "import sort;\n" - INTS - "export fn main() i32 = {\n" - " let nums: [10]i32 = [1, 3, 4, 4, 5, 7, 9, 11, 11, 11];\n" - " let s: []i32 = nums[0:10];\n" - " let n: size = len(s): size;\n" - " let i: size = 0;\n" - " for (i < n) {\n" - " if (i == n - 1 || nums[i + 1] != nums[i]) {\n" - " let key: i32 = nums[i];\n" - " if (sort.rbisect(s, size(i32), &key, ints) != i + 1) { return 1; };\n" - " };\n" - " i = i + 1;\n" - " };\n" - " let n0: i32 = 0; if (sort.rbisect(s, size(i32), &n0, ints) != 0) { return 2; };\n" - " let n6: i32 = 6; if (sort.rbisect(s, size(i32), &n6, ints) != 5) { return 3; };\n" - " let n8: i32 = 8; if (sort.rbisect(s, size(i32), &n8, ints) != 6) { return 4; };\n" - " let n12: i32 = 12; if (sort.rbisect(s, size(i32), &n12, ints) != n) { return 5; };\n" - " return 0;\n" - "};\n", 0 }, - { NULL, NULL, 0 } -}; - -int -main(void) -{ - const char *bin = getenv("BIN"); - if (!bin) bin = "out/bin"; - char cwd[1024]; - if (getcwd(cwd, sizeof cwd) == NULL) return 1; - char absbin[1024]; - if (bin[0] != '/') { - snprintf(absbin, sizeof absbin, "%s/%s", cwd, bin); - bin = absbin; - } - - int n = 0, fail = 0; - for (int i = 0; rows[i].src; i++, n++) { - char tmpdir[64] = "/tmp/wwsort_XXXXXX"; - if (mkdtemp(tmpdir) == NULL) { - perror("sort: mkdtemp"); - fail++; - continue; - } - - char src[128], outbin[128], sepwork[160], rmcmd[192]; - snprintf(src, sizeof src, "%s/wwsort_%d_%d.ww", tmpdir, getpid(), i); - snprintf(outbin, sizeof outbin, "%s/out", tmpdir); - snprintf(sepwork, sizeof sepwork, "%s.sepwork", outbin); - snprintf(rmcmd, sizeof rmcmd, "rm -rf %s", sepwork); - - FILE *f = fopen(src, "wb"); - if (f == NULL) { fail++; goto cleanup; } - fputs(rows[i].src, f); - fclose(f); - - char cmd[2048]; - snprintf(cmd, sizeof cmd, "%s/ww build -I %s/lib -o %s %s", - bin, cwd, outbin, src); - if (runwait(cmd) != 0) { - fprintf(stderr, "row[%s]: build failed\n", rows[i].label); - fail++; - goto cleanup; - } - - int got = runwait(outbin); - if (got != rows[i].want_exit) { - fprintf(stderr, "row[%s]: exit %d, want %d\n", - rows[i].label, got, rows[i].want_exit); - fail++; - } - -cleanup: { - int cleanbad = 0; - if (unlink(src) != 0 && errno != ENOENT) cleanbad = 1; - if (unlink(outbin) != 0 && errno != ENOENT) cleanbad = 1; - if (runwait(rmcmd) != 0) cleanbad = 1; - if (rmdir(tmpdir) != 0) cleanbad = 1; - if (cleanbad) { - fprintf(stderr, "row[%s]: temporary cleanup failed\n", - rows[i].label); - fail++; - } - } - } - if (fail) { - fprintf(stderr, "%d/%d sort tests failed\n", fail, n); - return 1; - } - printf("sort: %d/%d ok\n", n, n); - return 0; -} diff --git a/test/wcc/data/r682_enum_frame_smash/case.ww b/test/wcc/data/r682_enum_frame_smash/case.ww new file mode 100644 index 00000000..a4f4a2ed --- /dev/null +++ b/test/wcc/data/r682_enum_frame_smash/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 5 +package main; +type tk = enum i32 { A = 7i32, B = 21i32, C = 99i32, + D = 3i32, E = 11i32, F = 5i32 }; +fn main() i32 = { + let a: [6]tk = [tk.A, tk.B, tk.C, tk.D, tk.E, tk.F]; + return a[5]: i32; +}; diff --git a/test/wcc/data/r682_enum_global_idx0/case.ww b/test/wcc/data/r682_enum_global_idx0/case.ww new file mode 100644 index 00000000..f3aa0857 --- /dev/null +++ b/test/wcc/data/r682_enum_global_idx0/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 7 +package main; +type tk = enum i32 { A = 7i32, B = 21i32, C = 99i32, D = 3i32 }; +let g: [4]tk = [tk.A, tk.B, tk.C, tk.D]; +fn main() i32 = { + return g[0]: i32; +}; diff --git a/test/wcc/data/r682_enum_global_read/case.ww b/test/wcc/data/r682_enum_global_read/case.ww new file mode 100644 index 00000000..3993b4da --- /dev/null +++ b/test/wcc/data/r682_enum_global_read/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 99 +package main; +type tk = enum i32 { A = 7i32, B = 21i32, C = 99i32, D = 3i32 }; +let g: [4]tk = [tk.A, tk.B, tk.C, tk.D]; +fn main() i32 = { + return g[2]: i32; +}; diff --git a/test/wcc/data/r682_enum_local_init_sum/case.ww b/test/wcc/data/r682_enum_local_init_sum/case.ww new file mode 100644 index 00000000..4dab31cd --- /dev/null +++ b/test/wcc/data/r682_enum_local_init_sum/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 10 +package main; +type tk = enum i32 { A = 7i32, B = 21i32, C = 99i32, D = 3i32 }; +fn main() i32 = { + let a: [4]tk = [tk.A, tk.B, tk.C, tk.D]; + return (a[0]: i32) + (a[3]: i32); +}; diff --git a/test/wcc/data/r682_enum_local_read/case.ww b/test/wcc/data/r682_enum_local_read/case.ww new file mode 100644 index 00000000..cc9c7d3a --- /dev/null +++ b/test/wcc/data/r682_enum_local_read/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 21 +package main; +type tk = enum i32 { A = 7i32, B = 21i32, C = 99i32, D = 3i32 }; +fn main() i32 = { + let a: [4]tk = [tk.A, tk.B, tk.C, tk.D]; + return a[1]: i32; +}; diff --git a/test/wcc/data/r682_enum_local_signed/case.ww b/test/wcc/data/r682_enum_local_signed/case.ww new file mode 100644 index 00000000..5fa7a2aa --- /dev/null +++ b/test/wcc/data/r682_enum_local_signed/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 251 +package main; +type tk = enum i32 { A = 7i32, G = -5i32 }; +fn main() i32 = { + let a: [2]tk = [tk.G, tk.A]; + return a[0]: i32; +}; diff --git a/test/wcc/data/r682_enum_width1_u8/case.ww b/test/wcc/data/r682_enum_width1_u8/case.ww new file mode 100644 index 00000000..6af9739b --- /dev/null +++ b/test/wcc/data/r682_enum_width1_u8/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 200 +package main; +type tu = enum u8 { A = 7u8, B = 200u8, C = 3u8 }; +fn main() i32 = { + let a: [3]tu = [tu.A, tu.B, tu.C]; + return a[1]: i32; +}; diff --git a/test/wcc/data/r682_enum_width2_i16/case.ww b/test/wcc/data/r682_enum_width2_i16/case.ww new file mode 100644 index 00000000..fbb77ce8 --- /dev/null +++ b/test/wcc/data/r682_enum_width2_i16/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 251 +package main; +type ts = enum i16 { A = 7i16, G = -5i16, C = 99i16 }; +fn main() i32 = { + let a: [3]ts = [ts.A, ts.G, ts.C]; + return a[1]: i32; +}; diff --git a/test/wcc/data/r683_slice_cap_copy/case.ww b/test/wcc/data/r683_slice_cap_copy/case.ww new file mode 100644 index 00000000..e6a306fe --- /dev/null +++ b/test/wcc/data/r683_slice_cap_copy/case.ww @@ -0,0 +1,10 @@ +//ww:run-exit 7 +package main; +export fn main() i32 = { + let hb: [8]u8; + let a: []u8; a.ptr = &hb[0]; a.len = 3; a.cap = 7; + let b: []u8; b.ptr = &hb[0]; b.len = 2; b.cap = 6; + let t: [2][]u8 = [a, b]; + let q: []u8 = t[0]; + return q.cap: i32; +}; diff --git a/test/wcc/data/r683_slice_cap_direct0/case.ww b/test/wcc/data/r683_slice_cap_direct0/case.ww new file mode 100644 index 00000000..2bac6bd2 --- /dev/null +++ b/test/wcc/data/r683_slice_cap_direct0/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 7 +package main; +export fn main() i32 = { + let hb: [8]u8; + let a: []u8; a.ptr = &hb[0]; a.len = 3; a.cap = 7; + let b: []u8; b.ptr = &hb[0]; b.len = 2; b.cap = 6; + let t: [2][]u8 = [a, b]; + return t[0].cap: i32; +}; diff --git a/test/wcc/data/r683_slice_cap_direct1/case.ww b/test/wcc/data/r683_slice_cap_direct1/case.ww new file mode 100644 index 00000000..0ceaa515 --- /dev/null +++ b/test/wcc/data/r683_slice_cap_direct1/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 6 +package main; +export fn main() i32 = { + let hb: [8]u8; + let a: []u8; a.ptr = &hb[0]; a.len = 3; a.cap = 7; + let b: []u8; b.ptr = &hb[0]; b.len = 2; b.cap = 6; + let t: [2][]u8 = [a, b]; + return t[1].cap: i32; +}; diff --git a/test/wcc/data/r683_slice_len0/case.ww b/test/wcc/data/r683_slice_len0/case.ww new file mode 100644 index 00000000..fed3bd81 --- /dev/null +++ b/test/wcc/data/r683_slice_len0/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 3 +package main; +export fn main() i32 = { + let hb: [8]u8; + let a: []u8; a.ptr = &hb[0]; a.len = 3; a.cap = 8; + let b: []u8; b.ptr = &hb[0]; b.len = 2; b.cap = 8; + let t: [2][]u8 = [a, b]; + return t[0].len: i32; +}; diff --git a/test/wcc/data/r683_slice_len1/case.ww b/test/wcc/data/r683_slice_len1/case.ww new file mode 100644 index 00000000..5dd204f3 --- /dev/null +++ b/test/wcc/data/r683_slice_len1/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 2 +package main; +export fn main() i32 = { + let hb: [8]u8; + let a: []u8; a.ptr = &hb[0]; a.len = 3; a.cap = 8; + let b: []u8; b.ptr = &hb[0]; b.len = 2; b.cap = 8; + let t: [2][]u8 = [a, b]; + return t[1].len: i32; +}; diff --git a/test/wcc/data/r683_slice_ptr/case.ww b/test/wcc/data/r683_slice_ptr/case.ww new file mode 100644 index 00000000..832cc516 --- /dev/null +++ b/test/wcc/data/r683_slice_ptr/case.ww @@ -0,0 +1,10 @@ +//ww:run-exit 4 +package main; +export fn main() i32 = { + let hb: [8]u8; hb[0] = 9u8; hb[1] = 4u8; + let a: []u8; a.ptr = &hb[0]; a.len = 3; a.cap = 8; + let b: []u8; b.ptr = &hb[1]; b.len = 2; b.cap = 8; + let t: [2][]u8 = [a, b]; + let q: []u8 = t[1]; + return q[0]: i32; +}; diff --git a/test/wcc/data/r683_slice_stride3/case.ww b/test/wcc/data/r683_slice_stride3/case.ww new file mode 100644 index 00000000..478c821b --- /dev/null +++ b/test/wcc/data/r683_slice_stride3/case.ww @@ -0,0 +1,10 @@ +//ww:run-exit 7 +package main; +export fn main() i32 = { + let hb: [8]u8; + let a: []u8; a.ptr = &hb[0]; a.len = 3; a.cap = 8; + let b: []u8; b.ptr = &hb[0]; b.len = 5; b.cap = 8; + let c: []u8; c.ptr = &hb[0]; c.len = 7; c.cap = 8; + let t: [3][]u8 = [a, b, c]; + return t[2].len: i32; +}; diff --git a/test/wcc/data/r683_str_cap_copy/case.ww b/test/wcc/data/r683_str_cap_copy/case.ww new file mode 100644 index 00000000..566a3072 --- /dev/null +++ b/test/wcc/data/r683_str_cap_copy/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 5 +package main; +export fn main() i32 = { + let a: str = "abcde"; + let b: str = "xy"; + let t: [2]str = [a, b]; + let q: str = t[0]; + return q.cap: i32; +}; diff --git a/test/wcc/data/r683_str_cap_direct0/case.ww b/test/wcc/data/r683_str_cap_direct0/case.ww new file mode 100644 index 00000000..10e95740 --- /dev/null +++ b/test/wcc/data/r683_str_cap_direct0/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 5 +package main; +export fn main() i32 = { + let a: str = "abcde"; + let b: str = "xy"; + let t: [2]str = [a, b]; + return t[0].cap: i32; +}; diff --git a/test/wcc/data/r683_str_cap_direct1/case.ww b/test/wcc/data/r683_str_cap_direct1/case.ww new file mode 100644 index 00000000..a1841b71 --- /dev/null +++ b/test/wcc/data/r683_str_cap_direct1/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 2 +package main; +export fn main() i32 = { + let a: str = "abcde"; + let b: str = "xy"; + let t: [2]str = [a, b]; + return t[1].cap: i32; +}; diff --git a/test/wcc/data/r683_str_len1/case.ww b/test/wcc/data/r683_str_len1/case.ww new file mode 100644 index 00000000..ed01e09c --- /dev/null +++ b/test/wcc/data/r683_str_len1/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 2 +package main; +export fn main() i32 = { + let a: str = "abc"; + let b: str = "de"; + let t: [2]str = [a, b]; + return t[1].len: i32; +}; diff --git a/test/wcc/data/r683_str_lit_cap_symmetry/case.ww b/test/wcc/data/r683_str_lit_cap_symmetry/case.ww new file mode 100644 index 00000000..366f3e66 --- /dev/null +++ b/test/wcc/data/r683_str_lit_cap_symmetry/case.ww @@ -0,0 +1,5 @@ +//ww:compile +package main; +export fn main() i32 = { + return "abc".cap: i32; +}; diff --git a/test/wcc/data/r683_struct_elem/case.ww b/test/wcc/data/r683_struct_elem/case.ww new file mode 100644 index 00000000..c36dd537 --- /dev/null +++ b/test/wcc/data/r683_struct_elem/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 4 +package main; +type Pt = struct { x: i32, y: i32 }; +export fn main() i32 = { + let t: [2]Pt = [Pt { x = 1, y = 2 }, Pt { x = 3, y = 4 }]; + return t[1].y: i32; +}; diff --git a/test/wcc/data/r684_local_int_elem/case.ww b/test/wcc/data/r684_local_int_elem/case.ww new file mode 100644 index 00000000..807a3d42 --- /dev/null +++ b/test/wcc/data/r684_local_int_elem/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 30 +package main; +export fn main() i32 = { + let x: [_]int = [10, 20, 30, 40]; + return x[2]: i32; +}; diff --git a/test/wcc/data/r684_local_one_len/case.ww b/test/wcc/data/r684_local_one_len/case.ww new file mode 100644 index 00000000..abc460d5 --- /dev/null +++ b/test/wcc/data/r684_local_one_len/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 1 +package main; +export fn main() i32 = { + let x: [_]int = [7]; + return x.len: i32; +}; diff --git a/test/wcc/data/r684_local_str_elem/case.ww b/test/wcc/data/r684_local_str_elem/case.ww new file mode 100644 index 00000000..e74e16c0 --- /dev/null +++ b/test/wcc/data/r684_local_str_elem/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 2 +package main; +export fn main() i32 = { + let x: [_]str = ["ab", "cde"]; + return x[0].len: i32; +}; diff --git a/test/wcc/data/r684_local_str_len/case.ww b/test/wcc/data/r684_local_str_len/case.ww new file mode 100644 index 00000000..03962e12 --- /dev/null +++ b/test/wcc/data/r684_local_str_len/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 3 +package main; +export fn main() i32 = { + let x: [_]str = ["a", "b", "c"]; + return x.len: i32; +}; diff --git a/test/wcc/data/r684_local_u8_elem/case.ww b/test/wcc/data/r684_local_u8_elem/case.ww new file mode 100644 index 00000000..06cd5b38 --- /dev/null +++ b/test/wcc/data/r684_local_u8_elem/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 5 +package main; +export fn main() i32 = { + let x: [_]u8 = [1u8, 2u8, 3u8, 4u8, 5u8]; + return x[4]: i32; +}; diff --git a/test/wcc/data/r684_local_u8_len/case.ww b/test/wcc/data/r684_local_u8_len/case.ww new file mode 100644 index 00000000..283aeccb --- /dev/null +++ b/test/wcc/data/r684_local_u8_len/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 5 +package main; +export fn main() i32 = { + let x: [_]u8 = [1u8, 2u8, 3u8, 4u8, 5u8]; + return x.len: i32; +}; diff --git a/test/wcc/data/r684_mod_int_elem/case.ww b/test/wcc/data/r684_mod_int_elem/case.ww new file mode 100644 index 00000000..09313f40 --- /dev/null +++ b/test/wcc/data/r684_mod_int_elem/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 30 +package main; +let x: [_]int = [10, 20, 30, 40]; +export fn main() i32 = { + return x[2]: i32; +}; diff --git a/test/wcc/data/r684_mod_one_elem/case.ww b/test/wcc/data/r684_mod_one_elem/case.ww new file mode 100644 index 00000000..02d6ea76 --- /dev/null +++ b/test/wcc/data/r684_mod_one_elem/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 7 +package main; +let x: [_]int = [7]; +export fn main() i32 = { + return x[0]: i32; +}; diff --git a/test/wcc/data/r684_mod_one_len/case.ww b/test/wcc/data/r684_mod_one_len/case.ww new file mode 100644 index 00000000..30bbf4f1 --- /dev/null +++ b/test/wcc/data/r684_mod_one_len/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 1 +package main; +let x: [_]int = [7]; +export fn main() i32 = { + return x.len: i32; +}; diff --git a/test/wcc/data/r684_mod_str_len/case.ww b/test/wcc/data/r684_mod_str_len/case.ww new file mode 100644 index 00000000..06a9b1c8 --- /dev/null +++ b/test/wcc/data/r684_mod_str_len/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 3 +package main; +let x: [_]str = ["a", "b", "c"]; +export fn main() i32 = { + return x.len: i32; +}; diff --git a/test/wcc/data/r684_noinit_local_reject/case.ww b/test/wcc/data/r684_noinit_local_reject/case.ww new file mode 100644 index 00000000..cb944544 --- /dev/null +++ b/test/wcc/data/r684_noinit_local_reject/case.ww @@ -0,0 +1,6 @@ +//ww:error "[_]T needs an array-literal initialiser" +package main; +export fn main() i32 = { + let x: [_]str; + return 0; +}; diff --git a/test/wcc/data/r684_noinit_mod_reject/case.ww b/test/wcc/data/r684_noinit_mod_reject/case.ww new file mode 100644 index 00000000..c361e0b1 --- /dev/null +++ b/test/wcc/data/r684_noinit_mod_reject/case.ww @@ -0,0 +1,4 @@ +//ww:error "[_]T needs an array-literal initialiser" +package main; +let x: [_]int; +export fn main() i32 = { return 0; }; diff --git a/test/wcc/data/r684_nonarray_local_reject/case.ww b/test/wcc/data/r684_nonarray_local_reject/case.ww new file mode 100644 index 00000000..c2781df4 --- /dev/null +++ b/test/wcc/data/r684_nonarray_local_reject/case.ww @@ -0,0 +1,6 @@ +//ww:error "[_]T needs an array-literal initialiser" +package main; +export fn main() i32 = { + let x: [_]int = 5; + return 0; +}; diff --git a/test/wcc/data/r685_tagged_bool_variant/case.ww b/test/wcc/data/r685_tagged_bool_variant/case.ww new file mode 100644 index 00000000..628730fd --- /dev/null +++ b/test/wcc/data/r685_tagged_bool_variant/case.ww @@ -0,0 +1,10 @@ +//ww:run-exit 1 +package main; +type cell = (i64 | bool); +export fn main() i32 = { + let t: [2]cell = [5i64, true]; + match (t[1]) { + case let v: i64 => { return -1; }; + case let z: bool => { if (z) { return 1; }; return 0; }; + }; +}; diff --git a/test/wcc/data/r685_tagged_boxed_void/case.ww b/test/wcc/data/r685_tagged_boxed_void/case.ww new file mode 100644 index 00000000..e27d3db7 --- /dev/null +++ b/test/wcc/data/r685_tagged_boxed_void/case.ww @@ -0,0 +1,16 @@ +//ww:run-exit 13 +package main; +type ov = (i32 | void); +export fn main() i32 = { + let t: [3]ov = [1i32, 2i32, void]; + let sum: i32 = 0; + let i: i32 = 0; + for (i < 3) { + match (t[i]) { + case let v: i32 => { sum = sum + v; }; + case void => { sum = sum + 10; }; + }; + i = i + 1; + }; + return sum; +}; diff --git a/test/wcc/data/r685_tagged_lit_first/case.ww b/test/wcc/data/r685_tagged_lit_first/case.ww new file mode 100644 index 00000000..1c1fd3e0 --- /dev/null +++ b/test/wcc/data/r685_tagged_lit_first/case.ww @@ -0,0 +1,10 @@ +//ww:run-exit 99 +package main; +type cell = (i64 | bool); +export fn main() i32 = { + let t: [2]cell = [99i64, 7i64]; + match (t[0]) { + case let v: i64 => { return v: i32; }; + case let z: bool => { return -1; }; + }; +}; diff --git a/test/wcc/data/r685_tagged_lit_second/case.ww b/test/wcc/data/r685_tagged_lit_second/case.ww new file mode 100644 index 00000000..ed86e124 --- /dev/null +++ b/test/wcc/data/r685_tagged_lit_second/case.ww @@ -0,0 +1,10 @@ +//ww:run-exit 7 +package main; +type cell = (i64 | bool); +export fn main() i32 = { + let t: [2]cell = [99i64, 7i64]; + match (t[1]) { + case let v: i64 => { return v: i32; }; + case let z: bool => { return -1; }; + }; +}; diff --git a/test/wcc/data/r685_tagged_lit_sum106/case.ww b/test/wcc/data/r685_tagged_lit_sum106/case.ww new file mode 100644 index 00000000..12d118ae --- /dev/null +++ b/test/wcc/data/r685_tagged_lit_sum106/case.ww @@ -0,0 +1,16 @@ +//ww:run-exit 106 +package main; +type cell = (i64 | bool); +export fn main() i32 = { + let t: [2]cell = [99i64, 7i64]; + let sum: i64 = 0i64; + let i: i32 = 0; + for (i < 2) { + match (t[i]) { + case let v: i64 => { sum = sum + v; }; + case let z: bool => { sum = sum + 1i64; }; + }; + i = i + 1; + }; + return sum: i32; +}; diff --git a/test/wcc/data/r685_tagged_repeat_reject/case.ww b/test/wcc/data/r685_tagged_repeat_reject/case.ww new file mode 100644 index 00000000..14ee8454 --- /dev/null +++ b/test/wcc/data/r685_tagged_repeat_reject/case.ww @@ -0,0 +1,7 @@ +//ww:error "repeat of a tagged-union array-literal element not wired" +package main; +type cell = (i64 | bool); +export fn main() i32 = { + let t: [3]cell = [99i64...]; + return 0; +}; diff --git a/test/wcc/data/r685_tagged_stride3/case.ww b/test/wcc/data/r685_tagged_stride3/case.ww new file mode 100644 index 00000000..f7cdb4ec --- /dev/null +++ b/test/wcc/data/r685_tagged_stride3/case.ww @@ -0,0 +1,10 @@ +//ww:run-exit 30 +package main; +type cell = (i64 | bool); +export fn main() i32 = { + let t: [3]cell = [10i64, 20i64, 30i64]; + match (t[2]) { + case let v: i64 => { return v: i32; }; + case let z: bool => { return -1; }; + }; +}; diff --git a/test/wcc/data/r685_tagged_var_sum/case.ww b/test/wcc/data/r685_tagged_var_sum/case.ww new file mode 100644 index 00000000..1c194d37 --- /dev/null +++ b/test/wcc/data/r685_tagged_var_sum/case.ww @@ -0,0 +1,18 @@ +//ww:run-exit 42 +package main; +type cell = (i64 | bool); +export fn main() i32 = { + let a: cell = 40i64; + let b: cell = 2i64; + let t: [2]cell = [a, b]; + let sum: i64 = 0i64; + let i: i32 = 0; + for (i < 2) { + match (t[i]) { + case let v: i64 => { sum = sum + v; }; + case let z: bool => { sum = sum + 100i64; }; + }; + i = i + 1; + }; + return sum: i32; +}; diff --git a/test/wcc/data/r686_slice_glob_cap/case.ww b/test/wcc/data/r686_slice_glob_cap/case.ww new file mode 100644 index 00000000..1ed17769 --- /dev/null +++ b/test/wcc/data/r686_slice_glob_cap/case.ww @@ -0,0 +1,4 @@ +//ww:run +package main; +let g: []u8; +export fn main() i32 = { return g.cap: i32; }; diff --git a/test/wcc/data/r686_slice_glob_len/case.ww b/test/wcc/data/r686_slice_glob_len/case.ww new file mode 100644 index 00000000..bd728b9d --- /dev/null +++ b/test/wcc/data/r686_slice_glob_len/case.ww @@ -0,0 +1,4 @@ +//ww:run +package main; +let g: []u8; +export fn main() i32 = { return g.len: i32; }; diff --git a/test/wcc/data/r686_slice_glob_ptr_null/case.ww b/test/wcc/data/r686_slice_glob_ptr_null/case.ww new file mode 100644 index 00000000..cdd33745 --- /dev/null +++ b/test/wcc/data/r686_slice_glob_ptr_null/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 7 +package main; +let g: []u8; +export fn main() i32 = { + if (g.ptr == nil) { return 7; }; + return 0; +}; diff --git a/test/wcc/data/r686_str_glob_len/case.ww b/test/wcc/data/r686_str_glob_len/case.ww new file mode 100644 index 00000000..05817739 --- /dev/null +++ b/test/wcc/data/r686_str_glob_len/case.ww @@ -0,0 +1,4 @@ +//ww:run +package main; +let s: str; +export fn main() i32 = { return s.len: i32; }; diff --git a/test/wcc/data/r686_str_glob_ptr_null/case.ww b/test/wcc/data/r686_str_glob_ptr_null/case.ww new file mode 100644 index 00000000..75b54664 --- /dev/null +++ b/test/wcc/data/r686_str_glob_ptr_null/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 9 +package main; +let s: str; +export fn main() i32 = { + if (s.ptr == nil) { return 9; }; + return 0; +}; diff --git a/test/wcc/data/r687_alias_slice/case.ww b/test/wcc/data/r687_alias_slice/case.ww new file mode 100644 index 00000000..2d245b67 --- /dev/null +++ b/test/wcc/data/r687_alias_slice/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 7 +package main; +type S = []u8; +let g: S = [1u8, 2u8, 3u8]; +export fn main() i32 = { return (g[0]:i32)+(g.len:i32)+(g.cap:i32); }; diff --git a/test/wcc/data/r687_i32_sum/case.ww b/test/wcc/data/r687_i32_sum/case.ww new file mode 100644 index 00000000..4d2a0935 --- /dev/null +++ b/test/wcc/data/r687_i32_sum/case.ww @@ -0,0 +1,4 @@ +//ww:run-exit 24 +package main; +let g: []i32 = [7i32, 8i32, 9i32]; +export fn main() i32 = { return (g[0]:i32)+(g[1]:i32)+(g[2]:i32); }; diff --git a/test/wcc/data/r687_i64_e1/case.ww b/test/wcc/data/r687_i64_e1/case.ww new file mode 100644 index 00000000..e4586526 --- /dev/null +++ b/test/wcc/data/r687_i64_e1/case.ww @@ -0,0 +1,4 @@ +//ww:run-exit 20 +package main; +let g: []i64 = [10i64, 20i64, 30i64]; +export fn main() i32 = { return g[1]: i32; }; diff --git a/test/wcc/data/r687_i64_lencap/case.ww b/test/wcc/data/r687_i64_lencap/case.ww new file mode 100644 index 00000000..ddeb69d2 --- /dev/null +++ b/test/wcc/data/r687_i64_lencap/case.ww @@ -0,0 +1,4 @@ +//ww:run-exit 6 +package main; +let g: []i64 = [10i64, 20i64, 30i64]; +export fn main() i32 = { return (g.len:i32)+(g.cap:i32); }; diff --git a/test/wcc/data/r687_neg_def_slicelit/case.ww b/test/wcc/data/r687_neg_def_slicelit/case.ww new file mode 100644 index 00000000..bf8af611 --- /dev/null +++ b/test/wcc/data/r687_neg_def_slicelit/case.ww @@ -0,0 +1,4 @@ +//ww:error "module-level slice-literal init needs a writable `let`" +package main; +def g: []u8 = [1u8, 2u8, 3u8]; +export fn main() i32 = { return g.len: i32; }; diff --git a/test/wcc/data/r687_neg_repeat_slicelit/case.ww b/test/wcc/data/r687_neg_repeat_slicelit/case.ww new file mode 100644 index 00000000..6ccece66 --- /dev/null +++ b/test/wcc/data/r687_neg_repeat_slicelit/case.ww @@ -0,0 +1,4 @@ +//ww:error "'...' repeat has no target length in a slice literal" +package main; +let g: []u8 = [1u8, 2u8...]; +export fn main() i32 = { return g.len: i32; }; diff --git a/test/wcc/data/r687_neg_str_slicelit/case.ww b/test/wcc/data/r687_neg_str_slicelit/case.ww new file mode 100644 index 00000000..a0125bdc --- /dev/null +++ b/test/wcc/data/r687_neg_str_slicelit/case.ww @@ -0,0 +1,4 @@ +//ww:error "slice-of-{str,slice,tagged} literal static-init unsupported" +package main; +let g: []str = ["a", "b"]; +export fn main() i32 = { return g.len: i32; }; diff --git a/test/wcc/data/r687_one_edge/case.ww b/test/wcc/data/r687_one_edge/case.ww new file mode 100644 index 00000000..4b68df9b --- /dev/null +++ b/test/wcc/data/r687_one_edge/case.ww @@ -0,0 +1,4 @@ +//ww:run-exit 43 +package main; +let g: []u8 = [42u8]; +export fn main() i32 = { return (g[0]:i32)+(g.len:i32); }; diff --git a/test/wcc/data/r687_struct_3f/case.ww b/test/wcc/data/r687_struct_3f/case.ww new file mode 100644 index 00000000..88186aa3 --- /dev/null +++ b/test/wcc/data/r687_struct_3f/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 23 +package main; +type q = struct { a: u8, b: i64, c: i32 }; +let g: []q = [q{a=1u8, b=2i64, c=3i32}, q{a=4u8, b=5i64, c=6i32}]; +export fn main() i32 = { + return (g[0].a:i32)+(g[0].b:i32)+(g[0].c:i32)+(g[1].a:i32)+(g[1].b:i32)+(g[1].c:i32)+(g.len:i32); +}; diff --git a/test/wcc/data/r687_struct_arrvar_local/case.ww b/test/wcc/data/r687_struct_arrvar_local/case.ww new file mode 100644 index 00000000..d8002022 --- /dev/null +++ b/test/wcc/data/r687_struct_arrvar_local/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 14 +package main; +type pt = struct { a: i64, b: i64 }; +export fn main() i32 = { + let arr: [2]pt = [pt{a=1i64, b=2i64}, pt{a=3i64, b=4i64}]; + let g: []pt = arr; + return (g[0].a:i32)+(g[0].b:i32)+(g[1].a:i32)+(g[1].b:i32)+(g.len:i32)+(g.cap:i32); +}; diff --git a/test/wcc/data/r687_struct_one/case.ww b/test/wcc/data/r687_struct_one/case.ww new file mode 100644 index 00000000..9ad56034 --- /dev/null +++ b/test/wcc/data/r687_struct_one/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 13 +package main; +type pt = struct { a: i64, b: i64 }; +let g: []pt = [pt{a=5i64, b=6i64}]; +export fn main() i32 = { + return (g[0].a:i32)+(g[0].b:i32)+(g.len:i32)+(g.cap:i32); +}; diff --git a/test/wcc/data/r687_struct_pt/case.ww b/test/wcc/data/r687_struct_pt/case.ww new file mode 100644 index 00000000..9bde6fcd --- /dev/null +++ b/test/wcc/data/r687_struct_pt/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 14 +package main; +type pt = struct { a: i64, b: i64 }; +let g: []pt = [pt{a=1i64, b=2i64}, pt{a=3i64, b=4i64}]; +export fn main() i32 = { + return (g[0].a:i32)+(g[0].b:i32)+(g[1].a:i32)+(g[1].b:i32)+(g.len:i32)+(g.cap:i32); +}; diff --git a/test/wcc/data/r687_u8_cap/case.ww b/test/wcc/data/r687_u8_cap/case.ww new file mode 100644 index 00000000..816589a7 --- /dev/null +++ b/test/wcc/data/r687_u8_cap/case.ww @@ -0,0 +1,4 @@ +//ww:run-exit 3 +package main; +let g: []u8 = [1u8, 2u8, 3u8]; +export fn main() i32 = { return g.cap: i32; }; diff --git a/test/wcc/data/r687_u8_e0/case.ww b/test/wcc/data/r687_u8_e0/case.ww new file mode 100644 index 00000000..52a076c9 --- /dev/null +++ b/test/wcc/data/r687_u8_e0/case.ww @@ -0,0 +1,4 @@ +//ww:run-exit 1 +package main; +let g: []u8 = [1u8, 2u8, 3u8]; +export fn main() i32 = { return g[0]: i32; }; diff --git a/test/wcc/data/r687_u8_e2/case.ww b/test/wcc/data/r687_u8_e2/case.ww new file mode 100644 index 00000000..bff2fd50 --- /dev/null +++ b/test/wcc/data/r687_u8_e2/case.ww @@ -0,0 +1,4 @@ +//ww:run-exit 3 +package main; +let g: []u8 = [1u8, 2u8, 3u8]; +export fn main() i32 = { return g[2]: i32; }; diff --git a/test/wcc/data/r687_u8_len/case.ww b/test/wcc/data/r687_u8_len/case.ww new file mode 100644 index 00000000..4c273946 --- /dev/null +++ b/test/wcc/data/r687_u8_len/case.ww @@ -0,0 +1,4 @@ +//ww:run-exit 3 +package main; +let g: []u8 = [1u8, 2u8, 3u8]; +export fn main() i32 = { return g.len: i32; }; diff --git a/test/wcc/data/r687_u8_sum/case.ww b/test/wcc/data/r687_u8_sum/case.ww new file mode 100644 index 00000000..3ffe7165 --- /dev/null +++ b/test/wcc/data/r687_u8_sum/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 12 +package main; +let g: []u8 = [1u8, 2u8, 3u8]; +export fn main() i32 = { + return (g[0]:i32)+(g[1]:i32)+(g[2]:i32)+(g.len:i32)+(g.cap:i32); +}; diff --git a/test/wcc/data/r688_arr_a0/case.ww b/test/wcc/data/r688_arr_a0/case.ww new file mode 100644 index 00000000..27ff082b --- /dev/null +++ b/test/wcc/data/r688_arr_a0/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 1 +package main; +type pt = struct { a: i64, b: i64 }; +let g: [2]pt = [pt { a = 1, b = 2 }, pt { a = 3, b = 4 }]; +export fn main() i32 = { return g[0].a: i32; }; diff --git a/test/wcc/data/r688_arr_a1/case.ww b/test/wcc/data/r688_arr_a1/case.ww new file mode 100644 index 00000000..16f3d295 --- /dev/null +++ b/test/wcc/data/r688_arr_a1/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 3 +package main; +type pt = struct { a: i64, b: i64 }; +let g: [2]pt = [pt { a = 1, b = 2 }, pt { a = 3, b = 4 }]; +export fn main() i32 = { return g[1].a: i32; }; diff --git a/test/wcc/data/r688_arr_b0/case.ww b/test/wcc/data/r688_arr_b0/case.ww new file mode 100644 index 00000000..ca8f83ec --- /dev/null +++ b/test/wcc/data/r688_arr_b0/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 2 +package main; +type pt = struct { a: i64, b: i64 }; +let g: [2]pt = [pt { a = 1, b = 2 }, pt { a = 3, b = 4 }]; +export fn main() i32 = { return g[0].b: i32; }; diff --git a/test/wcc/data/r688_arr_b1/case.ww b/test/wcc/data/r688_arr_b1/case.ww new file mode 100644 index 00000000..6d817714 --- /dev/null +++ b/test/wcc/data/r688_arr_b1/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 4 +package main; +type pt = struct { a: i64, b: i64 }; +let g: [2]pt = [pt { a = 1, b = 2 }, pt { a = 3, b = 4 }]; +export fn main() i32 = { return g[1].b: i32; }; diff --git a/test/wcc/data/r688_rec_tag1/case.ww b/test/wcc/data/r688_rec_tag1/case.ww new file mode 100644 index 00000000..e6bfac4a --- /dev/null +++ b/test/wcc/data/r688_rec_tag1/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 2 +package main; +type rec = struct { tag: u8, x: i32, y: i64 }; +let g: [2]rec = [rec { tag = 1u8, x = 100, y = 11 }, rec { tag = 2u8, x = 200, y = 22 }]; +export fn main() i32 = { return g[1].tag: i32; }; diff --git a/test/wcc/data/r688_rec_x1/case.ww b/test/wcc/data/r688_rec_x1/case.ww new file mode 100644 index 00000000..3e63237c --- /dev/null +++ b/test/wcc/data/r688_rec_x1/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 200 +package main; +type rec = struct { tag: u8, x: i32, y: i64 }; +let g: [2]rec = [rec { tag = 1u8, x = 100, y = 11 }, rec { tag = 2u8, x = 200, y = 22 }]; +export fn main() i32 = { return g[1].x: i32; }; diff --git a/test/wcc/data/r688_rec_y1/case.ww b/test/wcc/data/r688_rec_y1/case.ww new file mode 100644 index 00000000..e2cf78b1 --- /dev/null +++ b/test/wcc/data/r688_rec_y1/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 22 +package main; +type rec = struct { tag: u8, x: i32, y: i64 }; +let g: [2]rec = [rec { tag = 1u8, x = 100, y = 11 }, rec { tag = 2u8, x = 200, y = 22 }]; +export fn main() i32 = { return g[1].y: i32; }; diff --git a/test/wcc/data/r688_slice_x1_byteid/case.ww b/test/wcc/data/r688_slice_x1_byteid/case.ww new file mode 100644 index 00000000..2e92ef90 --- /dev/null +++ b/test/wcc/data/r688_slice_x1_byteid/case.ww @@ -0,0 +1,6 @@ +//ww:compile +package main; +type rec = struct { tag: u8, x: i32, y: i64 }; +let arr: [2]rec = [rec { tag = 1u8, x = 100, y = 11 }, rec { tag = 2u8, x = 200, y = 22 }]; +let g: []rec = arr; +export fn main() i32 = { return g[1].x: i32; }; diff --git a/test/wcc/data/r689_gpr_chain_i64_sink/case.ww b/test/wcc/data/r689_gpr_chain_i64_sink/case.ww new file mode 100644 index 00000000..71af82e2 --- /dev/null +++ b/test/wcc/data/r689_gpr_chain_i64_sink/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 1 +package main; +type T = struct { q: i64 }; +type S = struct { x: T }; +let gp: *S = nil; +export fn main() i32 = { let s: S = S{x=T{q=0}}; gp = &s; s.x.q = 4294967297; let v: i64 = gp.x.q; return (v >> 32): i32; }; diff --git a/test/wcc/data/r689_gpr_chain_str_len/case.ww b/test/wcc/data/r689_gpr_chain_str_len/case.ww new file mode 100644 index 00000000..6f4d1559 --- /dev/null +++ b/test/wcc/data/r689_gpr_chain_str_len/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 3 +package main; +type S = struct { a: i64, sf: str }; +let gp: *S = nil; +export fn main() i32 = { let s: S = S{a=0,sf="abc"}; gp = &s; return gp.sf.len: i32; }; diff --git a/test/wcc/data/r689_gpr_chain_struct_field/case.ww b/test/wcc/data/r689_gpr_chain_struct_field/case.ww new file mode 100644 index 00000000..60e8288f --- /dev/null +++ b/test/wcc/data/r689_gpr_chain_struct_field/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 7 +package main; +type Inner = struct { p: i64, q: i64 }; +type S = struct { a: i64, x: Inner }; +let gp: *S = nil; +export fn main() i32 = { let s: S = S{a=0,x=Inner{p=0,q=0}}; gp = &s; s.x.q = 7; return gp.x.q: i32; }; diff --git a/test/wcc/data/r689_gpr_float_field/case.ww b/test/wcc/data/r689_gpr_float_field/case.ww new file mode 100644 index 00000000..c41473fb --- /dev/null +++ b/test/wcc/data/r689_gpr_float_field/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 7 +package main; +type S = struct { a: i64, d: f64 }; +let gp: *S = nil; +export fn main() i32 = { let s: S = S{a=0,d=0.0}; gp = &s; s.d = 7.0; return (gp.d): i32; }; diff --git a/test/wcc/data/r689_gpr_local_ptr_ctrl/case.ww b/test/wcc/data/r689_gpr_local_ptr_ctrl/case.ww new file mode 100644 index 00000000..3346b922 --- /dev/null +++ b/test/wcc/data/r689_gpr_local_ptr_ctrl/case.ww @@ -0,0 +1,4 @@ +//ww:run-exit 42 +package main; +type S = struct { a: i64, f: i64 }; +export fn main() i32 = { let s: S = S{a=0,f=0}; let lp: *S = &s; s.f = 42; return lp.f: i32; }; diff --git a/test/wcc/data/r689_gpr_param_ctrl/case.ww b/test/wcc/data/r689_gpr_param_ctrl/case.ww new file mode 100644 index 00000000..2773054e --- /dev/null +++ b/test/wcc/data/r689_gpr_param_ctrl/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 10 +package main; +type S = struct { f: i64, g: i64 }; +fn rd(p: *S) i32 = { return (p.f + p.g): i32; }; +export fn main() i32 = { let s: S = S{f=4,g=6}; return rd(&s); }; diff --git a/test/wcc/data/r689_gpr_pslice_len/case.ww b/test/wcc/data/r689_gpr_pslice_len/case.ww new file mode 100644 index 00000000..8cf97a46 --- /dev/null +++ b/test/wcc/data/r689_gpr_pslice_len/case.ww @@ -0,0 +1,4 @@ +//ww:run-exit 3 +package main; +let gp: *[]u8 = nil; +export fn main() i32 = { let b: []u8 = [1u8,2u8,3u8]; gp = &b; return (gp.len): i32; }; diff --git a/test/wcc/data/r689_gpr_scalar_off0_off8/case.ww b/test/wcc/data/r689_gpr_scalar_off0_off8/case.ww new file mode 100644 index 00000000..be6d994f --- /dev/null +++ b/test/wcc/data/r689_gpr_scalar_off0_off8/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 14 +package main; +type S = struct { f: i64, g: i64 }; +let gp: *S = nil; +export fn main() i32 = { let s: S = S{f=0,g=0}; gp = &s; s.f = 5; s.g = 9; return (gp.f + gp.g): i32; }; diff --git a/test/wcc/data/r689_gpr_scalar_off8/case.ww b/test/wcc/data/r689_gpr_scalar_off8/case.ww new file mode 100644 index 00000000..1a785a32 --- /dev/null +++ b/test/wcc/data/r689_gpr_scalar_off8/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 170 +package main; +type S = struct { a: i64, f: i64 }; +let gp: *S = nil; +export fn main() i32 = { let s: S = S{a=0,f=0}; gp = &s; s.f = 170; return gp.f: i32; }; diff --git a/test/wcc/data/r689_gpr_str_field/case.ww b/test/wcc/data/r689_gpr_str_field/case.ww new file mode 100644 index 00000000..5e41460d --- /dev/null +++ b/test/wcc/data/r689_gpr_str_field/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 3 +package main; +type S = struct { a: i64, sf: str }; +let gp: *S = nil; +export fn main() i32 = { let s: S = S{a=0,sf="abc"}; gp = &s; let x: str = gp.sf; return x.len: i32; }; diff --git a/test/wcc/data/r689_gpr_tagged_field/case.ww b/test/wcc/data/r689_gpr_tagged_field/case.ww new file mode 100644 index 00000000..96b640e1 --- /dev/null +++ b/test/wcc/data/r689_gpr_tagged_field/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 5 +package main; +type S = struct { a: i64, t: (i64 | i32) }; +let gp: *S = nil; +export fn main() i32 = { let s: S = S{a=0,t=5i32}; gp = &s; let v: i32 = 0; match (gp.t) { case let x: i32 => v = x; case let y: i64 => v = y: i32; }; return v; }; diff --git a/test/wcc/data/r689_gpr_tagged_slice_field/case.ww b/test/wcc/data/r689_gpr_tagged_slice_field/case.ww new file mode 100644 index 00000000..2b276352 --- /dev/null +++ b/test/wcc/data/r689_gpr_tagged_slice_field/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 3 +package main; +type S = struct { a: i64, t: (i64 | []u8) }; +let gp: *S = nil; +export fn main() i32 = { let s: S = S{a=0,t=3i64}; gp = &s; let v: i32 = 0; match (gp.t) { case let x: i64 => v = x: i32; case let y: []u8 => v = len(y): i32; }; return v; }; diff --git a/test/wcc/data/r689_gpr_tagged_slice_field_local/case.ww b/test/wcc/data/r689_gpr_tagged_slice_field_local/case.ww new file mode 100644 index 00000000..8cc818e0 --- /dev/null +++ b/test/wcc/data/r689_gpr_tagged_slice_field_local/case.ww @@ -0,0 +1,4 @@ +//ww:run-exit 3 +package main; +type S = struct { a: i64, t: (i64 | []u8) }; +export fn main() i32 = { let s: S = S{a=0,t=3i64}; let p: *S = &s; let v: i32 = 0; match (p.t) { case let x: i64 => v = x: i32; case let y: []u8 => v = len(y): i32; }; return v; }; diff --git a/test/wcc/data/r689_gps_chained/case.ww b/test/wcc/data/r689_gps_chained/case.ww new file mode 100644 index 00000000..3b4f923f --- /dev/null +++ b/test/wcc/data/r689_gps_chained/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 18 +package main; +type I = struct { y: i64, z: i64 }; +type S = struct { a: i64, x: I }; +let gp: *S = nil; +export fn main() i32 = { let s: S = S{a=0,x=I{y=0,z=0}}; gp = &s; gp.x.y = 11; gp.x.z += 7; return (s.x.y+s.x.z): i32; }; diff --git a/test/wcc/data/r689_gps_compound_off0/case.ww b/test/wcc/data/r689_gps_compound_off0/case.ww new file mode 100644 index 00000000..9cdb74c9 --- /dev/null +++ b/test/wcc/data/r689_gps_compound_off0/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 7 +package main; +type S = struct { f: i64, g: i64 }; +let gp: *S = nil; +export fn main() i32 = { let s: S = S{f=0,g=0}; gp = &s; gp.f += 7; return s.f: i32; }; diff --git a/test/wcc/data/r689_gps_compound_off8/case.ww b/test/wcc/data/r689_gps_compound_off8/case.ww new file mode 100644 index 00000000..6a55c253 --- /dev/null +++ b/test/wcc/data/r689_gps_compound_off8/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 5 +package main; +type S = struct { a: i64, f: i64 }; +let gp: *S = nil; +export fn main() i32 = { let s: S = S{a=0,f=0}; gp = &s; gp.f += 5; return s.f: i32; }; diff --git a/test/wcc/data/r689_gps_indexed/case.ww b/test/wcc/data/r689_gps_indexed/case.ww new file mode 100644 index 00000000..ec5a5fd1 --- /dev/null +++ b/test/wcc/data/r689_gps_indexed/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 13 +package main; +type E = struct { f: i64, g: i64 }; +type S = struct { n: i64, a: [3]E }; +let gp: *S = nil; +export fn main() i32 = { let s: S; gp = &s; gp.a[1].f = 5; gp.a[1].g += 8; return (s.a[1].f+s.a[1].g): i32; }; diff --git a/test/wcc/data/r689_gps_local_ptr_ctrl/case.ww b/test/wcc/data/r689_gps_local_ptr_ctrl/case.ww new file mode 100644 index 00000000..d092d1fd --- /dev/null +++ b/test/wcc/data/r689_gps_local_ptr_ctrl/case.ww @@ -0,0 +1,4 @@ +//ww:run-exit 5 +package main; +type S = struct { a: i64, f: i64 }; +export fn main() i32 = { let s: S = S{a=0,f=0}; let lp: *S = &s; lp.f += 5; return s.f: i32; }; diff --git a/test/wcc/data/r689_gps_param_off0_ctrl/case.ww b/test/wcc/data/r689_gps_param_off0_ctrl/case.ww new file mode 100644 index 00000000..6cec5aca --- /dev/null +++ b/test/wcc/data/r689_gps_param_off0_ctrl/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 10 +package main; +type S = struct { f: i64, g: i64 }; +fn bump(p: *S) void = { p.f += 3; p.g += 4; }; +export fn main() i32 = { let s: S = S{f=1,g=2}; bump(&s); return (s.f+s.g): i32; }; diff --git a/test/wcc/data/r689_gps_str_field/case.ww b/test/wcc/data/r689_gps_str_field/case.ww new file mode 100644 index 00000000..5d82b690 --- /dev/null +++ b/test/wcc/data/r689_gps_str_field/case.ww @@ -0,0 +1,5 @@ +//ww:run-exit 2 +package main; +type S = struct { a: i64, sf: str }; +let gp: *S = nil; +export fn main() i32 = { let s: S = S{a=0,sf=""}; gp = &s; gp.sf = "hi"; return (s.sf.len): i32; }; diff --git a/test/wcc/data/r689_gps_struct_field/case.ww b/test/wcc/data/r689_gps_struct_field/case.ww new file mode 100644 index 00000000..e90c232d --- /dev/null +++ b/test/wcc/data/r689_gps_struct_field/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 16 +package main; +type I = struct { x: i64, y: i64 }; +type S = struct { a: i64, in: I }; +let gp: *S = nil; +export fn main() i32 = { let s: S = S{a=0,in=I{x=0,y=0}}; gp = &s; gp.in = I{x=7,y=9}; return (s.in.x+s.in.y): i32; }; diff --git a/test/wcc/data/r689_slf_off_cap/case.ww b/test/wcc/data/r689_slf_off_cap/case.ww new file mode 100644 index 00000000..ded52819 --- /dev/null +++ b/test/wcc/data/r689_slf_off_cap/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 8 +package main; +type hs = struct { head: i64, s: []u8 }; +export fn main() i32 = { + let hb: [8]u8; + let b: []u8; b.ptr = &hb[0]; b.len = 7; b.cap = 8; + let y: hs = hs { head = 1i64, s = b }; + return y.s.cap: i32; +}; diff --git a/test/wcc/data/r689_slf_off_head/case.ww b/test/wcc/data/r689_slf_off_head/case.ww new file mode 100644 index 00000000..6761fc0c --- /dev/null +++ b/test/wcc/data/r689_slf_off_head/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 1 +package main; +type hs = struct { head: i64, s: []u8 }; +export fn main() i32 = { + let hb: [8]u8; + let b: []u8; b.ptr = &hb[0]; b.len = 7; b.cap = 8; + let y: hs = hs { head = 1i64, s = b }; + return y.head: i32; +}; diff --git a/test/wcc/data/r689_slf_off_len/case.ww b/test/wcc/data/r689_slf_off_len/case.ww new file mode 100644 index 00000000..cf6af85c --- /dev/null +++ b/test/wcc/data/r689_slf_off_len/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 7 +package main; +type hs = struct { head: i64, s: []u8 }; +export fn main() i32 = { + let hb: [8]u8; + let b: []u8; b.ptr = &hb[0]; b.len = 7; b.cap = 8; + let y: hs = hs { head = 1i64, s = b }; + return y.s.len: i32; +}; diff --git a/test/wcc/data/r689_slf_slice_cap/case.ww b/test/wcc/data/r689_slf_slice_cap/case.ww new file mode 100644 index 00000000..f895698a --- /dev/null +++ b/test/wcc/data/r689_slf_slice_cap/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 8 +package main; +type cl = struct { items: []u8, n: i64 }; +export fn main() i32 = { + let hb: [8]u8; + let b: []u8; b.ptr = &hb[0]; b.len = 5; b.cap = 8; + let y: cl = cl { items = b, n = 9i64 }; + return y.items.cap: i32; +}; diff --git a/test/wcc/data/r689_slf_slice_len/case.ww b/test/wcc/data/r689_slf_slice_len/case.ww new file mode 100644 index 00000000..441c5982 --- /dev/null +++ b/test/wcc/data/r689_slf_slice_len/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 5 +package main; +type cl = struct { items: []u8, n: i64 }; +export fn main() i32 = { + let hb: [8]u8; + let b: []u8; b.ptr = &hb[0]; b.len = 5; b.cap = 8; + let y: cl = cl { items = b, n = 9i64 }; + return y.items.len: i32; +}; diff --git a/test/wcc/data/r689_slf_slice_n/case.ww b/test/wcc/data/r689_slf_slice_n/case.ww new file mode 100644 index 00000000..8cd3b351 --- /dev/null +++ b/test/wcc/data/r689_slf_slice_n/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 9 +package main; +type cl = struct { items: []u8, n: i64 }; +export fn main() i32 = { + let hb: [8]u8; + let b: []u8; b.ptr = &hb[0]; b.len = 5; b.cap = 8; + let y: cl = cl { items = b, n = 9i64 }; + return y.n: i32; +}; diff --git a/test/wcc/data/r689_slf_slice_ptr/case.ww b/test/wcc/data/r689_slf_slice_ptr/case.ww new file mode 100644 index 00000000..cb813c9b --- /dev/null +++ b/test/wcc/data/r689_slf_slice_ptr/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 4 +package main; +type cl = struct { items: []u8, n: i64 }; +export fn main() i32 = { + let hb: [8]u8; hb[0] = 4u8; + let b: []u8; b.ptr = &hb[0]; b.len = 5; b.cap = 8; + let y: cl = cl { items = b, n = 9i64 }; + return y.items[0]: i32; +}; diff --git a/test/wcc/data/r689_slf_str_name_len/case.ww b/test/wcc/data/r689_slf_str_name_len/case.ww new file mode 100644 index 00000000..5e178481 --- /dev/null +++ b/test/wcc/data/r689_slf_str_name_len/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 5 +package main; +type sn = struct { s: []u8, name: str }; +export fn main() i32 = { + let hb: [8]u8; + let b: []u8; b.ptr = &hb[0]; b.len = 3; b.cap = 8; + let y: sn = sn { s = b, name = "hello" }; + return y.name.len: i32; +}; diff --git a/test/wcc/data/r689_slf_str_s_len/case.ww b/test/wcc/data/r689_slf_str_s_len/case.ww new file mode 100644 index 00000000..f6898eb2 --- /dev/null +++ b/test/wcc/data/r689_slf_str_s_len/case.ww @@ -0,0 +1,9 @@ +//ww:run-exit 3 +package main; +type sn = struct { s: []u8, name: str }; +export fn main() i32 = { + let hb: [8]u8; + let b: []u8; b.ptr = &hb[0]; b.len = 3; b.cap = 8; + let y: sn = sn { s = b, name = "hello" }; + return y.s.len: i32; +}; diff --git a/test/wcc/data/r689_slf_two_b_cap/case.ww b/test/wcc/data/r689_slf_two_b_cap/case.ww new file mode 100644 index 00000000..067eb652 --- /dev/null +++ b/test/wcc/data/r689_slf_two_b_cap/case.ww @@ -0,0 +1,10 @@ +//ww:run-exit 8 +package main; +type tt = struct { a: []u8, b: []u8 }; +export fn main() i32 = { + let hb: [8]u8; + let p: []u8; p.ptr = &hb[0]; p.len = 3; p.cap = 8; + let q: []u8; q.ptr = &hb[0]; q.len = 6; q.cap = 8; + let y: tt = tt { a = p, b = q }; + return y.b.cap: i32; +}; diff --git a/test/wcc/data/r689_slf_two_b_len/case.ww b/test/wcc/data/r689_slf_two_b_len/case.ww new file mode 100644 index 00000000..2e56a75c --- /dev/null +++ b/test/wcc/data/r689_slf_two_b_len/case.ww @@ -0,0 +1,10 @@ +//ww:run-exit 6 +package main; +type tt = struct { a: []u8, b: []u8 }; +export fn main() i32 = { + let hb: [8]u8; + let p: []u8; p.ptr = &hb[0]; p.len = 3; p.cap = 8; + let q: []u8; q.ptr = &hb[0]; q.len = 6; q.cap = 8; + let y: tt = tt { a = p, b = q }; + return y.b.len: i32; +}; diff --git a/test/wcc/data/r698_assign_ident_call_recv_pair_i64_i32/case.ww b/test/wcc/data/r698_assign_ident_call_recv_pair_i64_i32/case.ww new file mode 100644 index 00000000..2b6453ed --- /dev/null +++ b/test/wcc/data/r698_assign_ident_call_recv_pair_i64_i32/case.ww @@ -0,0 +1,9 @@ +//ww:run +package main; +type pt = struct { a: i64, b: i32 }; +fn mk() pt = { return pt { a = 7i64, b = 9i32 }; }; +fn main() i32 = { + let s: pt = pt { a = 0i64, b = 0i32 }; + s = mk(); + return s.b - 9; +}; diff --git a/test/wcc/data/r698_bare_let_struct_maxalign4/case.ww b/test/wcc/data/r698_bare_let_struct_maxalign4/case.ww new file mode 100644 index 00000000..544e419d --- /dev/null +++ b/test/wcc/data/r698_bare_let_struct_maxalign4/case.ww @@ -0,0 +1,7 @@ +//ww:run +package main; +type t3 = struct { a: i32, b: i32, c: i32 }; +fn main() i32 = { + let z: t3; + return z.a + z.b + z.c; +}; diff --git a/test/wcc/data/r698_decoder_ident_sret/case.ww b/test/wcc/data/r698_decoder_ident_sret/case.ww new file mode 100644 index 00000000..0c53bb42 --- /dev/null +++ b/test/wcc/data/r698_decoder_ident_sret/case.ww @@ -0,0 +1,14 @@ +//ww:run +package main; +type decoder = struct { offs: i64, src: []u8 }; +fn mk(s: []u8) decoder = { + let r: decoder; + r.offs = 0i64; + r.src = s; + return r; +}; +fn main() i32 = { + let b: [1]u8; + let d: decoder = mk(b[0:1]); + return 0; +}; diff --git a/test/wcc/data/r698_dot_recv_call_global/case.ww b/test/wcc/data/r698_dot_recv_call_global/case.ww new file mode 100644 index 00000000..5164da55 --- /dev/null +++ b/test/wcc/data/r698_dot_recv_call_global/case.ww @@ -0,0 +1,7 @@ +//ww:run +package main; +type pt = struct { a: i64, b: i32 }; +type box = struct { v: pt }; +let g: box = box { v = pt { a = 0i64, b = 0i32 } }; +fn mk() pt = { return pt { a = 7i64, b = 9i32 }; }; +fn main() i32 = { g.v = mk(); return g.v.b - 9; }; diff --git a/test/wcc/data/r698_dot_recv_call_local/case.ww b/test/wcc/data/r698_dot_recv_call_local/case.ww new file mode 100644 index 00000000..078967e8 --- /dev/null +++ b/test/wcc/data/r698_dot_recv_call_local/case.ww @@ -0,0 +1,10 @@ +//ww:run +package main; +type pt = struct { a: i64, b: i32 }; +type box = struct { v: pt }; +fn mk() pt = { return pt { a = 7i64, b = 9i32 }; }; +fn main() i32 = { + let b: box; + b.v = mk(); + return b.v.b - 9; +}; diff --git a/test/wcc/data/r698_dot_recv_call_viaptr/case.ww b/test/wcc/data/r698_dot_recv_call_viaptr/case.ww new file mode 100644 index 00000000..955ca5ec --- /dev/null +++ b/test/wcc/data/r698_dot_recv_call_viaptr/case.ww @@ -0,0 +1,11 @@ +//ww:run +package main; +type pt = struct { a: i64, b: i32 }; +type box = struct { v: pt }; +fn mk() pt = { return pt { a = 7i64, b = 9i32 }; }; +fn fill(p: *box) void = { p.v = mk(); return; }; +fn main() i32 = { + let b: box; + fill(&b); + return b.v.b - 9; +}; diff --git a/test/wcc/data/r698_dot_structlit_ellipsis/case.ww b/test/wcc/data/r698_dot_structlit_ellipsis/case.ww new file mode 100644 index 00000000..08cdbfe7 --- /dev/null +++ b/test/wcc/data/r698_dot_structlit_ellipsis/case.ww @@ -0,0 +1,10 @@ +//ww:run +package main; +type s = struct { a: i64, b: i32 }; +type box = struct { v: s }; +fn mk() box = { return box { v = s { a = 0i64, b = 0i32 } }; }; +fn main() i32 = { + let b: box = mk(); + b.v = s { a = 5i64, ... }; + return b.v.b; +}; diff --git a/test/wcc/data/r698_five_i64_lit_sret/case.ww b/test/wcc/data/r698_five_i64_lit_sret/case.ww new file mode 100644 index 00000000..6dd0c1d8 --- /dev/null +++ b/test/wcc/data/r698_five_i64_lit_sret/case.ww @@ -0,0 +1,7 @@ +//ww:run +package main; +type five = struct { a: i64, b: i64, c: i64, d: i64, e: i64 }; +fn mk() five = { + return five { a = 1i64, b = 2i64, c = 3i64, d = 4i64, e = 5i64 }; +}; +fn main() i32 = { let f: five = mk(); return 0; }; diff --git a/test/wcc/data/r698_let_ident_memcpy_pair_i64_i32/case.ww b/test/wcc/data/r698_let_ident_memcpy_pair_i64_i32/case.ww new file mode 100644 index 00000000..052dede9 --- /dev/null +++ b/test/wcc/data/r698_let_ident_memcpy_pair_i64_i32/case.ww @@ -0,0 +1,8 @@ +//ww:run +package main; +type pt = struct { a: i64, b: i32 }; +fn main() i32 = { + let p1: pt = pt { a = 7i64, b = 9i32 }; + let p2: pt = p1; + return p2.b - 9; +}; diff --git a/test/wcc/data/r698_mix_i32_i32_i64_i64_lit_discard/case.ww b/test/wcc/data/r698_mix_i32_i32_i64_i64_lit_discard/case.ww new file mode 100644 index 00000000..552ef52a --- /dev/null +++ b/test/wcc/data/r698_mix_i32_i32_i64_i64_lit_discard/case.ww @@ -0,0 +1,5 @@ +//ww:run +package main; +type mix = struct { a: i32, b: i32, c: i64, d: i64 }; +fn mk() mix = { return mix { a = 3, b = 5, c = 11i64, d = 12i64 }; }; +fn main() i32 = { mk(); return 0; }; diff --git a/test/wcc/data/r698_one_i64_lit_discard/case.ww b/test/wcc/data/r698_one_i64_lit_discard/case.ww new file mode 100644 index 00000000..b63280ff --- /dev/null +++ b/test/wcc/data/r698_one_i64_lit_discard/case.ww @@ -0,0 +1,5 @@ +//ww:run +package main; +type one = struct { v: i64 }; +fn mk() one = { return one { v = 42i64 }; }; +fn main() i32 = { mk(); return 0; }; diff --git a/test/wcc/data/r698_pair_i64_i32_recv/case.ww b/test/wcc/data/r698_pair_i64_i32_recv/case.ww new file mode 100644 index 00000000..3e5e1822 --- /dev/null +++ b/test/wcc/data/r698_pair_i64_i32_recv/case.ww @@ -0,0 +1,5 @@ +//ww:run +package main; +type pt = struct { a: i64, b: i32 }; +fn mk() pt = { return pt { a = 7i64, b = 9i32 }; }; +fn main() i32 = { let p: pt = mk(); return p.b - 9; }; diff --git a/test/wcc/data/r698_pair_i64_lit_discard/case.ww b/test/wcc/data/r698_pair_i64_lit_discard/case.ww new file mode 100644 index 00000000..dcf48ace --- /dev/null +++ b/test/wcc/data/r698_pair_i64_lit_discard/case.ww @@ -0,0 +1,5 @@ +//ww:run +package main; +type pair = struct { a: i64, b: i64 }; +fn mk() pair = { return pair { a = 1i64, b = 2i64 }; }; +fn main() i32 = { mk(); return 0; }; diff --git a/test/wcc/data/r698_quad_i64_lit_sret/case.ww b/test/wcc/data/r698_quad_i64_lit_sret/case.ww new file mode 100644 index 00000000..1bce165c --- /dev/null +++ b/test/wcc/data/r698_quad_i64_lit_sret/case.ww @@ -0,0 +1,5 @@ +//ww:run +package main; +type quad = struct { a: i64, b: i64, c: i64, d: i64 }; +fn mk() quad = { return quad { a = 1i64, b = 2i64, c = 3i64, d = 4i64 }; }; +fn main() i32 = { let q: quad = mk(); return 0; }; diff --git a/test/wcc/data/r698_recv_i32_arr6_u8/case.ww b/test/wcc/data/r698_recv_i32_arr6_u8/case.ww new file mode 100644 index 00000000..2e1534b1 --- /dev/null +++ b/test/wcc/data/r698_recv_i32_arr6_u8/case.ww @@ -0,0 +1,5 @@ +//ww:run +package main; +type s6 = struct { n: i32, a: [6]u8 }; +fn mk() s6 = { return s6 { n = 4i32, a = [1u8, 2u8, 3u8, 4u8, 5u8, 6u8] }; }; +fn main() i32 = { let p: s6 = mk(); return p.n - 4; }; diff --git a/test/wcc/data/r698_structlit_nested_call_recv_pair_i64_i32/case.ww b/test/wcc/data/r698_structlit_nested_call_recv_pair_i64_i32/case.ww new file mode 100644 index 00000000..5a0ec1c5 --- /dev/null +++ b/test/wcc/data/r698_structlit_nested_call_recv_pair_i64_i32/case.ww @@ -0,0 +1,9 @@ +//ww:run +package main; +type pt = struct { a: i64, b: i32 }; +type box = struct { v: pt }; +fn mk() pt = { return pt { a = 7i64, b = 9i32 }; }; +fn main() i32 = { + let b: box = box { v = mk() }; + return b.v.b - 9; +}; diff --git a/test/wcc/data/r698_trip_i32_ident_return/case.ww b/test/wcc/data/r698_trip_i32_ident_return/case.ww new file mode 100644 index 00000000..c8444897 --- /dev/null +++ b/test/wcc/data/r698_trip_i32_ident_return/case.ww @@ -0,0 +1,8 @@ +//ww:run +package main; +type t3 = struct { a: i32, b: i32, c: i32 }; +fn mk() t3 = { + let s: t3 = t3 { a = 1, b = 2, c = 3 }; + return s; +}; +fn main() i32 = { let p: t3 = mk(); return p.a + p.b + p.c - 6; }; diff --git a/test/wcc/data/r698_trip_i64_ident_discard/case.ww b/test/wcc/data/r698_trip_i64_ident_discard/case.ww new file mode 100644 index 00000000..64d5aa1a --- /dev/null +++ b/test/wcc/data/r698_trip_i64_ident_discard/case.ww @@ -0,0 +1,8 @@ +//ww:run +package main; +type trip = struct { x: i64, y: i64, z: i64 }; +fn mk() trip = { + let p: trip = trip { x = 100i64, y = 200i64, z = 300i64 }; + return p; +}; +fn main() i32 = { mk(); return 0; }; diff --git a/test/wcc/data/r698_trip_i64_lit_discard/case.ww b/test/wcc/data/r698_trip_i64_lit_discard/case.ww new file mode 100644 index 00000000..ad8806f4 --- /dev/null +++ b/test/wcc/data/r698_trip_i64_lit_discard/case.ww @@ -0,0 +1,5 @@ +//ww:run +package main; +type trip = struct { x: i64, y: i64, z: i64 }; +fn mk() trip = { return trip { x = 7i64, y = 11i64, z = 13i64 }; }; +fn main() i32 = { mk(); return 0; }; diff --git a/test/wcc/data/r725_retscr_nested_if_labels/case.ww b/test/wcc/data/r725_retscr_nested_if_labels/case.ww new file mode 100644 index 00000000..f717c91c --- /dev/null +++ b/test/wcc/data/r725_retscr_nested_if_labels/case.ww @@ -0,0 +1,17 @@ +//ww:compile +package main; +type instant = struct { sec: i64, nsec: i64 }; +export fn add(i: instant, x: i64) instant = { + let r: instant; + if (x == 0i64) { + r.sec = i.sec; r.nsec = i.nsec; + return r; + }; + if (x > 0i64) { + r.sec = i.sec + x; r.nsec = i.nsec; + return r; + }; + r.sec = i.sec - 1i64; r.nsec = i.nsec + x; + return r; +}; +export fn main() i32 = { return 0; }; diff --git a/test/wcc/data/r736_tagscr_two_ptr_stores/case.ww b/test/wcc/data/r736_tagscr_two_ptr_stores/case.ww new file mode 100644 index 00000000..01aec70d --- /dev/null +++ b/test/wcc/data/r736_tagscr_two_ptr_stores/case.ww @@ -0,0 +1,10 @@ +//ww:compile +package main; +type pair = struct { hi: i64, lo: i64 }; +type bag = (pair | i64); +type cell = struct { v: bag }; +export fn run(c: *cell, p: pair, q: pair) i64 = { + c.v = (p: bag); + c.v = (q: bag); + return 0i64; +}; diff --git a/test/wcc/data/r736_tagscr_two_sizes_compile/case.ww b/test/wcc/data/r736_tagscr_two_sizes_compile/case.ww new file mode 100644 index 00000000..f3f4b101 --- /dev/null +++ b/test/wcc/data/r736_tagscr_two_sizes_compile/case.ww @@ -0,0 +1,11 @@ +//ww:compile +package main; +type small = (i64 | i32); +type big = (i64 | str); +type cell_a = struct { v: small }; +type cell_b = struct { v: big }; +export fn run(a: *cell_a, b: *cell_b, x: i64, s: str) i64 = { + a.v = (x: small); + b.v = (s: big); + return 0i64; +}; diff --git a/test/wcc/data/r771_spread_alt_widen/case.ww b/test/wcc/data/r771_spread_alt_widen/case.ww new file mode 100644 index 00000000..0bf85caa --- /dev/null +++ b/test/wcc/data/r771_spread_alt_widen/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 70 +package main; +type underread = !i32; +type nomem = !void; +type wrapper = !(underread | nomem); +export fn main() i32 = { + let u: underread; + let r: (size | ...wrapper) = u; + if (r is underread) { return 70; }; + return 99; +}; diff --git a/test/wcc/data/r779_branched_lprintln/case.ww b/test/wcc/data/r779_branched_lprintln/case.ww new file mode 100644 index 00000000..fcca4ec7 --- /dev/null +++ b/test/wcc/data/r779_branched_lprintln/case.ww @@ -0,0 +1,27 @@ +//ww:run-exit 45 +package main; +import os; +import log; +import memio; +import io; +export fn main() i32 = { + let bufA: [16]u8; + let bufB: [16]u8; + let stA: memio.stream = memio.fixed(bufA[0:16]); + let vsA: io.stream = &stA.vt; + let stB: memio.stream = memio.fixed(bufB[0:16]); + let vsB: io.stream = &stB.vt; + let slA: log.stdlogger = log.new(vsA); + let slB: log.stdlogger = log.new(vsB); + let sel: i32 = 1; + let chosen: *log.logger = &slA.logger; + if (sel == 0) { chosen = &slB.logger; }; + log.lprintln(chosen, "pick"); + if (bufA[0] != 112u8) { return 91; }; + if (bufA[1] != 105u8) { return 92; }; + if (bufA[2] != 99u8) { return 93; }; + if (bufA[3] != 107u8) { return 94; }; + if (bufA[4] != 10u8) { return 95; }; + if (bufB[0] != 0u8) { return 96; }; + return 45; +}; diff --git a/test/wcc/data/r779_lprintln_custom_sink/case.ww b/test/wcc/data/r779_lprintln_custom_sink/case.ww new file mode 100644 index 00000000..26c8b473 --- /dev/null +++ b/test/wcc/data/r779_lprintln_custom_sink/case.ww @@ -0,0 +1,19 @@ +//ww:run-exit 44 +package main; +import os; +import log; +import memio; +import io; +export fn main() i32 = { + let buf: [16]u8; + let st: memio.stream = memio.fixed(buf[0:16]); + let vs: io.stream = &st.vt; + let sl: log.stdlogger = log.new(vs); + log.lprintln(&sl.logger, "hi", 7i64); + if (buf[0] != 104u8) { return 91; }; + if (buf[1] != 105u8) { return 92; }; + if (buf[2] != 32u8) { return 93; }; + if (buf[3] != 55u8) { return 94; }; + if (buf[4] != 10u8) { return 95; }; + return 44; +}; diff --git a/test/wcc/data/r779_printfln_default_stderr/case.ww b/test/wcc/data/r779_printfln_default_stderr/case.ww new file mode 100644 index 00000000..7255a026 --- /dev/null +++ b/test/wcc/data/r779_printfln_default_stderr/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 43 +package main; +import os; +import log; +export fn main() i32 = { + log.printfln("v={}", 7i64); + return 43; +}; diff --git a/test/wcc/data/r779_println_default_stderr/case.ww b/test/wcc/data/r779_println_default_stderr/case.ww new file mode 100644 index 00000000..a6077643 --- /dev/null +++ b/test/wcc/data/r779_println_default_stderr/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 42 +package main; +import os; +import log; +export fn main() i32 = { + log.println("hello"); + return 42; +}; diff --git a/test/wcc/data/r805_agg_array_field_movl/case.ww b/test/wcc/data/r805_agg_array_field_movl/case.ww new file mode 100644 index 00000000..74704678 --- /dev/null +++ b/test/wcc/data/r805_agg_array_field_movl/case.ww @@ -0,0 +1,18 @@ +//ww:run-exit 57 +package main; +type t = struct { pc: size, arr: [3]u32 }; +fn setarr(ts: *[]t, i: size, src: [3]u32) void = { + (*ts)[i].arr = src; +}; +export fn main() i32 = { + let a3: [3]u32 = [9u32, 8u32, 7u32]; + let z3: [3]u32 = [0u32, 0u32, 0u32]; + let ts: []t = []; + append(ts, t { pc = 5, arr = z3 }); + setarr(&ts, 0, a3); + if (ts[0].arr[0] != 9u32) { return 1; }; + if (ts[0].arr[1] != 8u32) { return 2; }; + if (ts[0].arr[2] != 7u32) { return 3; }; + if (ts[0].pc != 5) { return 4; }; + return 57; +}; diff --git a/test/wcc/data/r805_agg_array_field_odd/case.ww b/test/wcc/data/r805_agg_array_field_odd/case.ww new file mode 100644 index 00000000..c0237859 --- /dev/null +++ b/test/wcc/data/r805_agg_array_field_odd/case.ww @@ -0,0 +1,18 @@ +//ww:run-exit 55 +package main; +type t = struct { pc: size, arr: [3]u8 }; +fn setarr(ts: *[]t, i: size, src: [3]u8) void = { + (*ts)[i].arr = src; +}; +export fn main() i32 = { + let a3: [3]u8 = [9u8, 8u8, 7u8]; + let z3: [3]u8 = [0u8, 0u8, 0u8]; + let ts: []t = []; + append(ts, t { pc = 5, arr = z3 }); + setarr(&ts, 0, a3); + if (ts[0].arr[0] != 9u8) { return 1; }; + if (ts[0].arr[1] != 8u8) { return 2; }; + if (ts[0].arr[2] != 7u8) { return 3; }; + if (ts[0].pc != 5) { return 4; }; + return 55; +}; diff --git a/test/wcc/data/r805_agg_fresh_two_stores/case.ww b/test/wcc/data/r805_agg_fresh_two_stores/case.ww new file mode 100644 index 00000000..dfa96f48 --- /dev/null +++ b/test/wcc/data/r805_agg_fresh_two_stores/case.ww @@ -0,0 +1,22 @@ +//ww:run-exit 56 +package main; +type capture = struct { content: str, start: size, end: size }; +type t = struct { pc: size, cap: capture }; +fn settwo(ts: *[]t) void = { + (*ts)[0].cap = capture { content = "aa", start = 1, end = 2 }; + (*ts)[1].cap = capture { content = "bbb", start = 3, end = 4 }; +}; +export fn main() i32 = { + let z: capture = capture { content = "", start = 0, end = 0 }; + let ts: []t = []; + append(ts, t { pc = 7, cap = z }); + append(ts, t { pc = 8, cap = z }); + settwo(&ts); + if (ts[0].cap.content.len != 2) { return 1; }; + if (ts[0].cap.start != 1) { return 2; }; + if (ts[0].cap.end != 2) { return 3; }; + if (ts[1].cap.content.len != 3) { return 4; }; + if (ts[1].cap.start != 3) { return 5; }; + if (ts[1].cap.end != 4) { return 6; }; + return 56; +}; diff --git a/test/wcc/data/r805_agg_from_ident_deref/case.ww b/test/wcc/data/r805_agg_from_ident_deref/case.ww new file mode 100644 index 00000000..f35b8ef4 --- /dev/null +++ b/test/wcc/data/r805_agg_from_ident_deref/case.ww @@ -0,0 +1,28 @@ +//ww:run-exit 53 +package main; +type capture = struct { content: str, start: size, end: size }; +type t = struct { pc: size, cap: capture }; +fn copycap(ts: *[]t, i: size, src: capture) void = { + (*ts)[i].cap = src; +}; +fn derefcap(ts: *[]t, i: size, pc: *capture) void = { + (*ts)[i].cap = *pc; +}; +export fn main() i32 = { + let z: capture = capture { content = "", start = 0, end = 0 }; + let ts: []t = []; + append(ts, t { pc = 7, cap = z }); + append(ts, t { pc = 8, cap = z }); + let a: capture = capture { content = "ab", start = 1, end = 3 }; + copycap(&ts, 1, a); + if (ts[1].cap.content.len != 2) { return 1; }; + if (ts[1].cap.start != 1) { return 2; }; + if (ts[1].cap.end != 3) { return 3; }; + let b: capture = capture { content = "wxyz", start = 5, end = 9 }; + derefcap(&ts, 0, &b); + if (ts[0].cap.content.len != 4) { return 4; }; + if (ts[0].cap.start != 5) { return 5; }; + if (ts[0].cap.end != 9) { return 6; }; + if (ts[1].cap.start != 1) { return 7; }; + return 53; +}; diff --git a/test/wcc/data/r805_agg_nested_lit/case.ww b/test/wcc/data/r805_agg_nested_lit/case.ww new file mode 100644 index 00000000..1575be07 --- /dev/null +++ b/test/wcc/data/r805_agg_nested_lit/case.ww @@ -0,0 +1,20 @@ +//ww:run-exit 54 +package main; +type inner = struct { x: i64, y: i64 }; +type big = struct { a: i64, ib: inner }; +type t = struct { pc: size, bg: big }; +fn setbg(ts: *[]t, i: size) void = { + (*ts)[i].bg = big { a = 1, ib = inner { x = 2, y = 3 } }; +}; +export fn main() i32 = { + let z: big = big { a = 0, ib = inner { x = 0, y = 0 } }; + let ts: []t = []; + append(ts, t { pc = 7, bg = z }); + setbg(&ts, 0); + let bp: *u8 = ts.ptr: *u8; + if (bp[8] != 1u8) { return 1; }; + if (bp[16] != 2u8) { return 2; }; + if (bp[24] != 3u8) { return 3; }; + if (ts[0].pc != 7) { return 4; }; + return 54; +}; diff --git a/test/wcc/data/r805_agg_structlit_40b/case.ww b/test/wcc/data/r805_agg_structlit_40b/case.ww new file mode 100644 index 00000000..1baff656 --- /dev/null +++ b/test/wcc/data/r805_agg_structlit_40b/case.ww @@ -0,0 +1,28 @@ +//ww:run-exit 52 +package main; +type capture = struct { content: str, start: size, end: size }; +type t = struct { pc: size, cap: capture }; +fn setcap(ts: *[]t, i: size) void = { + (*ts)[i].cap = capture { content = "hit", start = 2, end = 4 }; +}; +fn clearcap(ts: *[]t, i: size) void = { + (*ts)[i].cap = capture { content = "z", ... }; +}; +export fn main() i32 = { + let z: capture = capture { content = "", start = 0, end = 0 }; + let ts: []t = []; + append(ts, t { pc = 7, cap = z }); + append(ts, t { pc = 8, cap = z }); + setcap(&ts, 1); + if (ts[1].cap.content.len != 3) { return 1; }; + if (ts[1].cap.start != 2) { return 2; }; + if (ts[1].cap.end != 4) { return 3; }; + if (ts[1].pc != 8) { return 4; }; + if (ts[0].cap.content.len != 0) { return 5; }; + if (ts[0].pc != 7) { return 6; }; + clearcap(&ts, 1); + if (ts[1].cap.content.len != 1) { return 7; }; + if (ts[1].cap.start != 0) { return 8; }; + if (ts[1].cap.end != 0) { return 9; }; + return 52; +}; diff --git a/test/wcc/data/r805_amp_spine/case.ww b/test/wcc/data/r805_amp_spine/case.ww new file mode 100644 index 00000000..766fa5cb --- /dev/null +++ b/test/wcc/data/r805_amp_spine/case.ww @@ -0,0 +1,18 @@ +//ww:run-exit 63 +package main; +type capture = struct { content: str, start: size, end: size }; +type t = struct { pc: size, cap: capture }; +fn bump(cp: *capture) void = { cp.end += 100; }; +export fn main() i32 = { + let ts: []t = []; + append(ts, t { pc = 5, cap = capture { content = "abc", start = 11, end = 13 } }); + append(ts, t { pc = 6, cap = capture { content = "wy", start = 21, end = 23 } }); + let cp: *capture = &ts[1].cap; + if (cp.start != 21) { return 1; }; + bump(cp); + if (ts[1].cap.end != 123) { return 2; }; + let pp: *[]t = &ts; + let dp: *capture = &(*pp)[0].cap; + if (dp.end != 13) { return 3; }; + return 63; +}; diff --git a/test/wcc/data/r805_arr_field_idx_store/case.ww b/test/wcc/data/r805_arr_field_idx_store/case.ww new file mode 100644 index 00000000..3ae0b047 --- /dev/null +++ b/test/wcc/data/r805_arr_field_idx_store/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 58 +package main; +type t = struct { pc: size, matched: bool }; +type holder = struct { arr: [3]t, n: i64 }; +export fn main() i32 = { + let h: holder = holder { n = 0, ... }; + h.arr[1].pc = 5; + h.arr[1].pc += 2; + if (h.arr[1].pc != 7) { return 1; }; + if (h.arr[0].pc != 0) { return 2; }; + if (h.arr[2].pc != 0) { return 3; }; + return 58; +}; diff --git a/test/wcc/data/r805_array_base_deref/case.ww b/test/wcc/data/r805_array_base_deref/case.ww new file mode 100644 index 00000000..daabd5a2 --- /dev/null +++ b/test/wcc/data/r805_array_base_deref/case.ww @@ -0,0 +1,16 @@ +//ww:run-exit 46 +package main; +type t = struct { pc: size, matched: bool }; +fn setarr(ta: *[3]t, i: size) void = { (*ta)[i].pc = 9; }; +fn bumparr(ta: *[3]t, i: size) void = { (*ta)[i].pc += 2; }; +export fn main() i32 = { + let ta: [3]t; + ta[0].pc = 1; ta[1].pc = 2; ta[2].pc = 3; + setarr(&ta, 1); + if (ta[1].pc != 9) { return 1; }; + bumparr(&ta, 1); + if (ta[1].pc != 11) { return 2; }; + if (ta[0].pc != 1) { return 3; }; + if (ta[2].pc != 3) { return 4; }; + return 46; +}; diff --git a/test/wcc/data/r805_c3_alias_arr_viaptr/case.ww b/test/wcc/data/r805_c3_alias_arr_viaptr/case.ww new file mode 100644 index 00000000..69ddfe4b --- /dev/null +++ b/test/wcc/data/r805_c3_alias_arr_viaptr/case.ww @@ -0,0 +1,28 @@ +//ww:run-exit 66 +package main; +type wide = struct { b: u8, q: i64, xs: []size }; +type warr = [2]wide; +type pw = *wide; +type plist = []pw; +fn mkw(k: i64) wide = { + let xs: []size = []; + let x0: size = (10 + k): size; + append(xs, x0); + return wide { b = (k + 1): u8, q = k, xs = xs }; +}; +export fn main() i32 = { + let w3: wide = mkw(3); + let w4: wide = mkw(4); + let a0: [2]wide = [w3, w4]; + let a: warr = a0; + if (a[0].q != 3i64) { return 1; }; + if (a[1].b != 5u8) { return 2; }; + let w5: wide = mkw(5); + let ps0: []pw = []; + append(ps0, &w5); + let ps: plist = ps0; + if (ps[0].q != 5i64) { return 3; }; + if (ps[0].b != 6u8) { return 4; }; + if (ps[0].xs[0] != (15: size)) { return 5; }; + return 66; +}; diff --git a/test/wcc/data/r805_c3_alias_slice_reads/case.ww b/test/wcc/data/r805_c3_alias_slice_reads/case.ww new file mode 100644 index 00000000..5437d80c --- /dev/null +++ b/test/wcc/data/r805_c3_alias_slice_reads/case.ww @@ -0,0 +1,34 @@ +//ww:run-exit 65 +package main; +type wide = struct { b: u8, w: i16, d: u32, q: i64, f: f64, + s: str, xs: []size, m: [2]u32 }; +type wlist = []wide; +fn mkw(k: i64) wide = { + let xs: []size = []; + let x0: size = (10 + k): size; + let x1: size = (20 + k): size; + append(xs, x0); + append(xs, x1); + let m0: u32 = (40 + k): u32; + let m1: u32 = (50 + k): u32; + return wide { b = (k + 1): u8, w = (0 - k): i16, + d = (100 + k): u32, q = k, f = 2.5f64, s = "ab", + xs = xs, m = [m0, m1] }; +}; +export fn main() i32 = { + let l0: []wide = []; + let w1: wide = mkw(1); + let w2: wide = mkw(2); + append(l0, w1); + append(l0, w2); + let l: wlist = l0; + if (l[0].b != 2u8) { return 1; }; + if (l[0].w != -1i16) { return 2; }; + if (l[1].d != 102u32) { return 3; }; + if (l[1].q != 2i64) { return 4; }; + if (l[0].f != 2.5f64) { return 5; }; + if (l[0].s.len != 2) { return 6; }; + if (l[1].xs[1] != (22: size)) { return 7; }; + if (l[0].m[1] != 51u32) { return 8; }; + return 65; +}; diff --git a/test/wcc/data/r805_c3_composed_match/case.ww b/test/wcc/data/r805_c3_composed_match/case.ww new file mode 100644 index 00000000..ad9a1035 --- /dev/null +++ b/test/wcc/data/r805_c3_composed_match/case.ww @@ -0,0 +1,50 @@ +//ww:run-exit 68 +package main; +type inst_lit = rune; +type inst_any = void; +type inst_match = bool; +type inst = (inst_lit | inst_any | inst_match); +type re_t = struct { insts: []inst, n_reps: size }; +type capture = struct { content: str, start: size, end: size }; +type thread = struct { pc: size, root_capture: capture, failed: bool }; +fn step(re: *re_t, ts: *[]thread, i: size) i32 = { + match (re.insts[(*ts)[i].pc]) { + case let lt: inst_lit => { + (*ts)[i].root_capture = capture { content = "hit", start = 2, end = 4 }; + (*ts)[i].pc += 1; + return 1; + }; + case inst_any => { + (*ts)[i].failed = true; + return 2; + }; + case let m: inst_match => { + (*ts)[i].pc += 2; + return 3; + }; + }; + return 9; +}; +export fn main() i32 = { + let insts: []inst = []; + append(insts, ('a': inst_lit)); + let av: inst_any; + let v: inst = av; + append(insts, v); + append(insts, (true: inst_match)); + let re: re_t = re_t { insts = insts, n_reps = 0 }; + let ts: []thread = []; + let z: capture = capture { content = "", start = 0, end = 0 }; + append(ts, thread { pc = 0, root_capture = z, failed = false }); + if (step(&re, &ts, 0) != 1) { return 1; }; + if (ts[0].pc != 1) { return 2; }; + if (ts[0].root_capture.start != 2) { return 3; }; + if (step(&re, &ts, 0) != 2) { return 4; }; + if (!ts[0].failed) { return 5; }; + let p: *[]thread = &ts; + (*p)[0].pc += 1; + if (ts[0].pc != 2) { return 6; }; + if (step(&re, &ts, 0) != 3) { return 7; }; + if (ts[0].pc != 4) { return 8; }; + return 68; +}; diff --git a/test/wcc/data/r805_c3_free_operand/case.ww b/test/wcc/data/r805_c3_free_operand/case.ww new file mode 100644 index 00000000..0af6e253 --- /dev/null +++ b/test/wcc/data/r805_c3_free_operand/case.ww @@ -0,0 +1,23 @@ +//ww:run-exit 69 +package main; +type capture = struct { content: str, start: size }; +type thread = struct { pc: size, captures: []capture, + rep_counters: []size }; +fn delete_thread(i: size, threads: *[]thread) void = { + free((*threads)[i].captures); + free((*threads)[i].rep_counters); + delete((*threads)[i]); +}; +export fn main() i32 = { + let z: []capture; + let zr: []size; + let xs: []thread = []; + append(xs, thread { pc = 1, captures = z, rep_counters = zr }); + append(xs, thread { pc = 2, captures = z, rep_counters = zr }); + append(xs, thread { pc = 3, captures = z, rep_counters = zr }); + delete_thread(1, &xs); + if (len(xs) != 2) { return 1; }; + if (xs[0].pc != 1) { return 2; }; + if (xs[1].pc != 3) { return 3; }; + return 69; +}; diff --git a/test/wcc/data/r805_c3_letbound_alias/case.ww b/test/wcc/data/r805_c3_letbound_alias/case.ww new file mode 100644 index 00000000..cf519a38 --- /dev/null +++ b/test/wcc/data/r805_c3_letbound_alias/case.ww @@ -0,0 +1,18 @@ +//ww:run-exit 67 +package main; +type capture = struct { content: str, start: size, end: size }; +type result = []capture; +fn mk() result = { + let caps: []capture = []; + append(caps, capture { content = "xy", start = 1, end = 3 }); + append(caps, capture { content = "z", start = 4, end = 5 }); + return caps; +}; +export fn main() i32 = { + let m: result = mk(); + if (len(m) != 2) { return 1; }; + if (m[0].start != 1) { return 2; }; + if (m[0].content.len != 2) { return 3; }; + if (m[1].end != 5) { return 4; }; + return 67; +}; diff --git a/test/wcc/data/r805_c4_let_deref_leaf/case.ww b/test/wcc/data/r805_c4_let_deref_leaf/case.ww new file mode 100644 index 00000000..1981b6af --- /dev/null +++ b/test/wcc/data/r805_c4_let_deref_leaf/case.ww @@ -0,0 +1,18 @@ +//ww:run-exit 72 +package main; +type capture = struct { content: str, start: size, end: size }; +type t = struct { pc: size, cap: capture }; +fn grab(ts: *[]t, i: size) i32 = { + let c: capture = (*ts)[i].cap; + if (c.start != 11) { return 1; }; + if (c.end != 13) { return 2; }; + if (c.content.len != 3) { return 3; }; + return 0; +}; +export fn main() i32 = { + let ts: []t = []; + append(ts, t { pc = 5, cap = capture { content = "abc", start = 11, end = 13 } }); + let rc: i32 = grab(&ts, 0); + if (rc != 0) { return rc; }; + return 72; +}; diff --git a/test/wcc/data/r805_c4_let_elem_sizes/case.ww b/test/wcc/data/r805_c4_let_elem_sizes/case.ww new file mode 100644 index 00000000..56a3cf7c --- /dev/null +++ b/test/wcc/data/r805_c4_let_elem_sizes/case.ww @@ -0,0 +1,27 @@ +//ww:run-exit 71 +package main; +type t3 = struct { a: i64, b: i64, c: i64 }; +type capture = struct { content: str, start: size, end: size }; +type t12 = struct { x: u32, y: u32, z: u32 }; +export fn main() i32 = { + let xs: []t3 = []; + append(xs, t3 { a = 1, b = 2, c = 3 }); + append(xs, t3 { a = 4, b = 5, c = 6 }); + let e: t3 = xs[1]; + if (e.a != 4) { return 1; }; + if (e.b != 5) { return 2; }; + if (e.c != 6) { return 3; }; + let cs: []capture = []; + append(cs, capture { content = "abc", start = 11, end = 13 }); + let c: capture = cs[0]; + if (c.content.len != 3) { return 4; }; + if (c.start != 11) { return 5; }; + if (c.end != 13) { return 6; }; + let ns: []t12 = []; + append(ns, t12 { x = 7u32, y = 8u32, z = 9u32 }); + let n: t12 = ns[0]; + if (n.x != 7u32) { return 7; }; + if (n.y != 8u32) { return 8; }; + if (n.z != 9u32) { return 9; }; + return 71; +}; diff --git a/test/wcc/data/r805_c4_let_slice_elem/case.ww b/test/wcc/data/r805_c4_let_slice_elem/case.ww new file mode 100644 index 00000000..33ab241b --- /dev/null +++ b/test/wcc/data/r805_c4_let_slice_elem/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 70 +package main; +type th = struct { pc: size, matched: bool }; +export fn main() i32 = { + let xs: []th = []; + append(xs, th { pc = 7, matched = true }); + let e: th = xs[0]; + if (e.pc != 7) { return 1; }; + if (!e.matched) { return 2; }; + return 70; +}; diff --git a/test/wcc/data/r805_c4_range_byvalue/case.ww b/test/wcc/data/r805_c4_range_byvalue/case.ww new file mode 100644 index 00000000..f0012743 --- /dev/null +++ b/test/wcc/data/r805_c4_range_byvalue/case.ww @@ -0,0 +1,34 @@ +//ww:run-exit 73 +package main; +type th = struct { pc: size, weight: size }; +type capture = struct { content: str, start: size, end: size }; +export fn main() i32 = { + let xs: []th = []; + append(xs, th { pc = 7, weight = 100 }); + append(xs, th { pc = 8, weight = 200 }); + let total: size = 0; + for (let t .. xs) { + total += t.pc; + total += t.weight; + }; + if (total != 315) { return 1; }; + let cs: []capture = []; + append(cs, capture { content = "abc", start = 11, end = 13 }); + append(cs, capture { content = "wy", start = 21, end = 23 }); + let csum: size = 0; + for (let cp .. cs) { + csum += cp.content.len: size; + csum += cp.start; + csum += cp.end; + }; + if (csum != 73) { return 2; }; + let ss: []str = []; + append(ss, "hello"); + append(ss, "worldly"); + let slen: size = 0; + for (let s .. ss) { + slen += s.len: size; + }; + if (slen != 12) { return 3; }; + return 73; +}; diff --git a/test/wcc/data/r805_c4_range_edges/case.ww b/test/wcc/data/r805_c4_range_edges/case.ww new file mode 100644 index 00000000..3ca572d0 --- /dev/null +++ b/test/wcc/data/r805_c4_range_edges/case.ww @@ -0,0 +1,22 @@ +//ww:run-exit 74 +package main; +type th = struct { pc: size, matched: bool }; +type t12 = struct { x: u32, y: u32, z: u32 }; +export fn main() i32 = { + let es: []th = []; + for (let t .. es) { return 1; }; + let xs: []th = []; + append(xs, th { pc = 7, matched = true }); + let cnt: size = 0; + for (let t2 .. xs) { t2.pc = 99; t2.matched = false; cnt += 1; }; + if (cnt != 1) { return 2; }; + if (xs[0].pc != 7) { return 3; }; + if (!xs[0].matched) { return 4; }; + let ns: []t12 = []; + append(ns, t12 { x = 1u32, y = 2u32, z = 3u32 }); + append(ns, t12 { x = 4u32, y = 5u32, z = 6u32 }); + let sum: size = 0; + for (let n .. ns) { sum += n.x: size; sum += n.y: size; sum += n.z: size; }; + if (sum != 21) { return 5; }; + return 74; +}; diff --git a/test/wcc/data/r805_compound_bits_shr/case.ww b/test/wcc/data/r805_compound_bits_shr/case.ww new file mode 100644 index 00000000..85fe53ab --- /dev/null +++ b/test/wcc/data/r805_compound_bits_shr/case.ww @@ -0,0 +1,20 @@ +//ww:run-exit 48 +package main; +type t = struct { s: int, u: size, n: i64, m: i64 }; +fn ands(ts: *[]t, i: size) void = { (*ts)[i].m &= 6; }; +fn xors(ts: *[]t, i: size) void = { (*ts)[i].m ^= 3; }; +fn sars(ts: *[]t, i: size) void = { (*ts)[i].s >>= 2; }; +fn shrs(ts: *[]t, i: size) void = { (*ts)[i].u >>= 1; }; +export fn main() i32 = { + let ts: []t = []; + append(ts, t { s = -16, u = 8, n = 0, m = 7 }); + ands(&ts, 0); + if (ts[0].m != 6) { return 1; }; + xors(&ts, 0); + if (ts[0].m != 5) { return 2; }; + sars(&ts, 0); + if (ts[0].s != -4) { return 3; }; + shrs(&ts, 0); + if (ts[0].u != 4) { return 4; }; + return 48; +}; diff --git a/test/wcc/data/r805_compound_narrow/case.ww b/test/wcc/data/r805_compound_narrow/case.ww new file mode 100644 index 00000000..0f21cce0 --- /dev/null +++ b/test/wcc/data/r805_compound_narrow/case.ww @@ -0,0 +1,26 @@ +//ww:run-exit 49 +package main; +type t = struct { a: i8, b: u8, c: i16, d: u16, e: i32, f: u32 }; +fn adda(ts: *[]t, i: size) void = { (*ts)[i].a += 1i8; }; +fn addb(ts: *[]t, i: size) void = { (*ts)[i].b += 200u8; }; +fn subc(ts: *[]t, i: size) void = { (*ts)[i].c -= 300i16; }; +fn shld(ts: *[]t, i: size) void = { (*ts)[i].d <<= 3u16; }; +fn mule(ts: *[]t, i: size) void = { (*ts)[i].e *= -3i32; }; +fn orf(ts: *[]t, i: size) void = { (*ts)[i].f |= 8u32; }; +export fn main() i32 = { + let ts: []t = []; + append(ts, t { a = -5i8, b = 50u8, c = 100i16, d = 2u16, e = 7i32, f = 5u32 }); + adda(&ts, 0); + if (ts[0].a != -4i8) { return 1; }; + addb(&ts, 0); + if (ts[0].b != 250u8) { return 2; }; + subc(&ts, 0); + if (ts[0].c != -200i16) { return 3; }; + shld(&ts, 0); + if (ts[0].d != 16u16) { return 4; }; + mule(&ts, 0); + if (ts[0].e != -21i32) { return 5; }; + orf(&ts, 0); + if (ts[0].f != 13u32) { return 6; }; + return 49; +}; diff --git a/test/wcc/data/r805_compound_ops/case.ww b/test/wcc/data/r805_compound_ops/case.ww new file mode 100644 index 00000000..f8cbc0e4 --- /dev/null +++ b/test/wcc/data/r805_compound_ops/case.ww @@ -0,0 +1,31 @@ +//ww:run-exit 44 +package main; +type t = struct { s: int, u: size, n: i64, m: i64 }; +fn divs(ts: *[]t, i: size) void = { (*ts)[i].s /= 4; }; +fn modn(ts: *[]t, i: size) void = { (*ts)[i].n %= 5; }; +fn divu(ts: *[]t, i: size) void = { (*ts)[i].u /= 3; }; +fn shl(ts: *[]t, i: size) void = { (*ts)[i].u <<= 2; }; +fn addm(ts: *[]t, i: size) void = { (*ts)[i].m += 7; }; +fn subm(ts: *[]t, i: size) void = { (*ts)[i].m -= 2; }; +fn mulm(ts: *[]t, i: size) void = { (*ts)[i].m *= 3; }; +fn orm(ts: *[]t, i: size) void = { (*ts)[i].m |= 4; }; +export fn main() i32 = { + let ts: []t = []; + append(ts, t { s = 4, u = 5, n = 6, m = 1 }); + append(ts, t { s = -12, u = 9, n = -13, m = 4 }); + divs(&ts, 1); + if (ts[1].s != -3) { return 1; }; + modn(&ts, 1); + if (ts[1].n != -3) { return 2; }; + divu(&ts, 1); + if (ts[1].u != 3) { return 3; }; + shl(&ts, 1); + if (ts[1].u != 12) { return 4; }; + addm(&ts, 1); + subm(&ts, 1); + mulm(&ts, 1); + orm(&ts, 1); + if (ts[1].m != 31) { return 5; }; + if (ts[0].s != 4) { return 6; }; + return 44; +}; diff --git a/test/wcc/data/r805_neutral_ident_bases/case.ww b/test/wcc/data/r805_neutral_ident_bases/case.ww new file mode 100644 index 00000000..8e350764 --- /dev/null +++ b/test/wcc/data/r805_neutral_ident_bases/case.ww @@ -0,0 +1,18 @@ +//ww:run-exit 51 +package main; +type t = struct { pc: size, matched: bool }; +export fn main() i32 = { + let x: t = t { pc = 1, matched = false }; + x.pc = 5; + x.pc += 2; + let a: [2]t; + a[0].pc = 3; a[1].pc = 4; + a[1].pc += 10; + let p: *t = &x; + p.pc = 20; + p.pc += 1; + if (x.pc != 21) { return 1; }; + if (a[1].pc != 14) { return 2; }; + if (a[0].pc != 3) { return 3; }; + return 51; +}; diff --git a/test/wcc/data/r805_neutral_reads/case.ww b/test/wcc/data/r805_neutral_reads/case.ww new file mode 100644 index 00000000..701b1eac --- /dev/null +++ b/test/wcc/data/r805_neutral_reads/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 64 +package main; +type capture = struct { content: str, start: size, end: size }; +type t = struct { pc: size, cap: capture }; +fn pcof(p: *t) size = { return (*p).pc; }; +export fn main() i32 = { + let x: t = t { pc = 9, cap = capture { content = "hi", start = 1, end = 2 } }; + if (x.cap.start != 1) { return 1; }; + if (x.cap.content.len != 2) { return 2; }; + if (pcof(&x) != 9) { return 3; }; + if ("abc".len != 3) { return 4; }; + return 64; +}; diff --git a/test/wcc/data/r805_read_depth2_deref/case.ww b/test/wcc/data/r805_read_depth2_deref/case.ww new file mode 100644 index 00000000..c1ce6a36 --- /dev/null +++ b/test/wcc/data/r805_read_depth2_deref/case.ww @@ -0,0 +1,19 @@ +//ww:run-exit 60 +package main; +type capture = struct { content: str, start: size, end: size }; +type t = struct { pc: size, cap: capture }; +fn rd(ts: *[]t) i32 = { + if ((*ts)[0].pc != 5) { return 1; }; + if ((*ts)[0].cap.start != 11) { return 2; }; + if ((*ts)[0].cap.end != 13) { return 3; }; + if ((*ts)[1].cap.end != 23) { return 4; }; + return 0; +}; +export fn main() i32 = { + let ts: []t = []; + append(ts, t { pc = 5, cap = capture { content = "abc", start = 11, end = 13 } }); + append(ts, t { pc = 6, cap = capture { content = "wy", start = 21, end = 23 } }); + let rc: i32 = rd(&ts); + if (rc != 0) { return rc; }; + return 60; +}; diff --git a/test/wcc/data/r805_read_depth2_idx/case.ww b/test/wcc/data/r805_read_depth2_idx/case.ww new file mode 100644 index 00000000..53beb576 --- /dev/null +++ b/test/wcc/data/r805_read_depth2_idx/case.ww @@ -0,0 +1,17 @@ +//ww:run-exit 59 +package main; +type capture = struct { content: str, start: size, end: size }; +type t = struct { pc: size, cap: capture }; +let end: size = 777; +export fn main() i32 = { + let ts: []t = []; + append(ts, t { pc = 5, cap = capture { content = "abc", start = 11, end = 13 } }); + append(ts, t { pc = 6, cap = capture { content = "wy", start = 21, end = 23 } }); + if (ts[0].cap.end == 777) { return 66; }; + if (ts[0].cap.end != 13) { return 1; }; + if (ts[0].cap.start != 11) { return 2; }; + if (ts[1].cap.end != 23) { return 3; }; + if (ts[1].cap.content.len != 2) { return 4; }; + if (ts[1].pc != 6) { return 5; }; + return 59; +}; diff --git a/test/wcc/data/r805_read_slicefield/case.ww b/test/wcc/data/r805_read_slicefield/case.ww new file mode 100644 index 00000000..667248be --- /dev/null +++ b/test/wcc/data/r805_read_slicefield/case.ww @@ -0,0 +1,21 @@ +//ww:run-exit 62 +package main; +type box = struct { pc: size, xs: []size }; +fn grab(p: *[]box, i: size) i32 = { + let h: []size = (*p)[i].xs; + if (len(h) != 2) { return 1; }; + if (h[0] != (7: size)) { return 2; }; + if (h[1] != (8: size)) { return 3; }; + if ((*p)[i].xs.cap < 2) { return 4; }; + return 0; +}; +export fn main() i32 = { + let src: []size = []; + append(src, (7: size)); + append(src, (8: size)); + let bs: []box = []; + append(bs, box { pc = 1, xs = src }); + let rc: i32 = grab(&bs, 0); + if (rc != 0) { return rc; }; + return 62; +}; diff --git a/test/wcc/data/r805_read_widths_spine/case.ww b/test/wcc/data/r805_read_widths_spine/case.ww new file mode 100644 index 00000000..9eee4b65 --- /dev/null +++ b/test/wcc/data/r805_read_widths_spine/case.ww @@ -0,0 +1,19 @@ +//ww:run-exit 61 +package main; +type inner = struct { b: i8, ub: u8, w: i16, uw: u16, d: i32, ud: u32, f: f64, g: f32, arr: [3]u8 }; +type box = struct { pad: size, it: inner }; +export fn main() i32 = { + let bs: []box = []; + append(bs, box { pad = 1, it = inner { b = -5i8, ub = 200u8, w = -300i16, uw = 60000u16, d = -70000, ud = 4000000000u32, f = 1.5, g = 2.5f32, arr = [7u8, 8u8, 9u8] } }); + let p: *[]box = &bs; + if ((*p)[0].it.b != -5i8) { return 1; }; + if ((*p)[0].it.ub != 200u8) { return 2; }; + if ((*p)[0].it.w != -300i16) { return 3; }; + if ((*p)[0].it.uw != 60000u16) { return 4; }; + if ((*p)[0].it.d != -70000) { return 5; }; + if ((*p)[0].it.ud != 4000000000u32) { return 6; }; + if ((*p)[0].it.f != 1.5) { return 7; }; + if ((*p)[0].it.g != 2.5f32) { return 8; }; + if ((*p)[0].it.arr[1] != 8u8) { return 9; }; + return 61; +}; diff --git a/test/wcc/data/r805_reject_addrof_callbase/case.ww b/test/wcc/data/r805_reject_addrof_callbase/case.ww new file mode 100644 index 00000000..e14f7ce5 --- /dev/null +++ b/test/wcc/data/r805_reject_addrof_callbase/case.ww @@ -0,0 +1,12 @@ +//ww:error "unsupported address-of shape" +package main; +type t = struct { pc: size, matched: bool }; +fn mk() []t = { + let ts: []t = []; + append(ts, t { pc = 3, matched = true }); + return ts; +}; +export fn main() i32 = { + let p: *size = &mk()[0].pc; + return (*p): i32; +}; diff --git a/test/wcc/data/r805_reject_agg_call_reg/case.ww b/test/wcc/data/r805_reject_agg_call_reg/case.ww new file mode 100644 index 00000000..ac326218 --- /dev/null +++ b/test/wcc/data/r805_reject_agg_call_reg/case.ww @@ -0,0 +1,11 @@ +//ww:error "assign-resolver: call result into aggregate field unwired (task #24/rule-7)" +package main; +type pair = struct { a: i64, b: i64 }; +type t = struct { pc: size, pr: pair }; +fn mk() pair = { return pair { a = 1, b = 2 }; }; +fn setpr(ts: *[]t, i: size) void = { (*ts)[i].pr = mk(); }; +export fn main() i32 = { + let ts: []t = []; + setpr(&ts, 0); + return 0; +}; diff --git a/test/wcc/data/r805_reject_agg_call_sret/case.ww b/test/wcc/data/r805_reject_agg_call_sret/case.ww new file mode 100644 index 00000000..118c3928 --- /dev/null +++ b/test/wcc/data/r805_reject_agg_call_sret/case.ww @@ -0,0 +1,13 @@ +//ww:error "assign-resolver: sret call into aggregate field unwired (#234-tail/rule-7)" +package main; +type capture = struct { content: str, start: size, end: size }; +type t = struct { pc: size, cap: capture }; +fn mk() capture = { + return capture { content = "x", start = 1, end = 2 }; +}; +fn setcap(ts: *[]t, i: size) void = { (*ts)[i].cap = mk(); }; +export fn main() i32 = { + let ts: []t = []; + setcap(&ts, 0); + return 0; +}; diff --git a/test/wcc/data/r805_reject_agg_compound/case.ww b/test/wcc/data/r805_reject_agg_compound/case.ww new file mode 100644 index 00000000..2e4c3630 --- /dev/null +++ b/test/wcc/data/r805_reject_agg_compound/case.ww @@ -0,0 +1,13 @@ +//ww:error "assign-resolver: compound on aggregate field not wired (rule-7)" +package main; +type capture = struct { content: str, start: size, end: size }; +type t = struct { pc: size, cap: capture }; +fn addcap(ts: *[]t, i: size, src: capture) void = { + (*ts)[i].cap += src; +}; +export fn main() i32 = { + let ts: []t = []; + let a: capture = capture { content = "", start = 0, end = 0 }; + addcap(&ts, 0, a); + return 0; +}; diff --git a/test/wcc/data/r805_reject_assign_callbase/case.ww b/test/wcc/data/r805_reject_assign_callbase/case.ww new file mode 100644 index 00000000..22e71a55 --- /dev/null +++ b/test/wcc/data/r805_reject_assign_callbase/case.ww @@ -0,0 +1,12 @@ +//ww:error "unsupported assign target shape" +package main; +type t = struct { pc: size, matched: bool }; +fn mk() []t = { + let ts: []t = []; + append(ts, t { pc = 3, matched = true }); + return ts; +}; +export fn main() i32 = { + mk()[0].pc = 2; + return 0; +}; diff --git a/test/wcc/data/r805_reject_float/case.ww b/test/wcc/data/r805_reject_float/case.ww new file mode 100644 index 00000000..225a4399 --- /dev/null +++ b/test/wcc/data/r805_reject_float/case.ww @@ -0,0 +1,9 @@ +//ww:error "assign-resolver: float field not wired (rule-7)" +package main; +type t = struct { pc: size, f: f64 }; +fn setf(ts: *[]t, i: size) void = { (*ts)[i].f = 1.5; }; +export fn main() i32 = { + let ts: []t = []; + setf(&ts, 0); + return 0; +}; diff --git a/test/wcc/data/r805_reject_let_unhandled/case.ww b/test/wcc/data/r805_reject_let_unhandled/case.ww new file mode 100644 index 00000000..ddb93197 --- /dev/null +++ b/test/wcc/data/r805_reject_let_unhandled/case.ww @@ -0,0 +1,10 @@ +//ww:error "let: aggregate init from unhandled rhs shape (task #7/rule-7)" +package main; +type pair = struct { a: i64, b: i64 }; +fn mk() (pair | nomem) = { + return pair { a = 1, b = 2 }; +}; +export fn main() i32 = { + let p: pair = mk()!; + return p.a: i32; +}; diff --git a/test/wcc/data/r805_reject_read_callbase/case.ww b/test/wcc/data/r805_reject_read_callbase/case.ww new file mode 100644 index 00000000..3bc5ca5c --- /dev/null +++ b/test/wcc/data/r805_reject_read_callbase/case.ww @@ -0,0 +1,12 @@ +//ww:error "unsupported field-read shape" +package main; +type t = struct { pc: size, matched: bool }; +fn mk() []t = { + let ts: []t = []; + append(ts, t { pc = 3, matched = true }); + return ts; +}; +export fn main() i32 = { + if (mk()[0].pc != 3) { return 1; }; + return 0; +}; diff --git a/test/wcc/data/r805_reject_read_tagged/case.ww b/test/wcc/data/r805_reject_read_tagged/case.ww new file mode 100644 index 00000000..570bc5f1 --- /dev/null +++ b/test/wcc/data/r805_reject_read_tagged/case.ww @@ -0,0 +1,12 @@ +//ww:error "read-resolver: tagged field read not wired (rule-7)" +package main; +type v = (i64 | bool); +type t = struct { pc: size, tg: v }; +fn rd(ts: *[]t, i: size) i64 = { + let x: v = (*ts)[i].tg; + return 1; +}; +export fn main() i32 = { + let ts: []t = []; + return rd(&ts, 0): i32; +}; diff --git a/test/wcc/data/r805_reject_str_compound/case.ww b/test/wcc/data/r805_reject_str_compound/case.ww new file mode 100644 index 00000000..7d17daaa --- /dev/null +++ b/test/wcc/data/r805_reject_str_compound/case.ww @@ -0,0 +1,9 @@ +//ww:error "assign-resolver: compound on str/slice field not wired (rule-7)" +package main; +type t = struct { pc: size, name: str }; +fn addname(ts: *[]t, i: size) void = { (*ts)[i].name += "x"; }; +export fn main() i32 = { + let ts: []t = []; + addname(&ts, 0); + return 0; +}; diff --git a/test/wcc/data/r805_reject_tagged/case.ww b/test/wcc/data/r805_reject_tagged/case.ww new file mode 100644 index 00000000..ed748376 --- /dev/null +++ b/test/wcc/data/r805_reject_tagged/case.ww @@ -0,0 +1,10 @@ +//ww:error "assign-resolver: tagged field not wired (rule-7)" +package main; +type v = (i64 | bool); +type t = struct { pc: size, tg: v }; +fn settg(ts: *[]t, i: size) void = { (*ts)[i].tg = 5; }; +export fn main() i32 = { + let ts: []t = []; + settg(&ts, 0); + return 0; +}; diff --git a/test/wcc/data/r805_runtime_call_idx/case.ww b/test/wcc/data/r805_runtime_call_idx/case.ww new file mode 100644 index 00000000..9a86b9a2 --- /dev/null +++ b/test/wcc/data/r805_runtime_call_idx/case.ww @@ -0,0 +1,17 @@ +//ww:run-exit 47 +package main; +type t = struct { pc: size, matched: bool }; +fn geti() size = { return 1; }; +fn setpc(ts: *[]t) void = { (*ts)[geti()].pc = 9; }; +fn bump(ts: *[]t) void = { (*ts)[geti()].pc += 1; }; +export fn main() i32 = { + let ts: []t = []; + append(ts, t { pc = 1, matched = false }); + append(ts, t { pc = 2, matched = false }); + setpc(&ts); + if (ts[1].pc != 9) { return 1; }; + bump(&ts); + if (ts[1].pc != 10) { return 2; }; + if (ts[0].pc != 1) { return 3; }; + return 47; +}; diff --git a/test/wcc/data/r805_slice_field_member/case.ww b/test/wcc/data/r805_slice_field_member/case.ww new file mode 100644 index 00000000..4b21c5cd --- /dev/null +++ b/test/wcc/data/r805_slice_field_member/case.ww @@ -0,0 +1,20 @@ +//ww:run-exit 50 +package main; +type t = struct { pc: size, xs: []i64 }; +fn setxs(ts: *[]t, i: size, s: []i64) void = { (*ts)[i].xs = s; }; +export fn main() i32 = { + let empty: []i64 = []; + let ts: []t = []; + append(ts, t { pc = 1, xs = empty }); + append(ts, t { pc = 2, xs = empty }); + let s: []i64 = []; + append(s, 11); + append(s, 22); + setxs(&ts, 1, s); + if (ts[1].xs.len != 2) { return 1; }; + if (ts[1].xs[1] != 22) { return 2; }; + if (ts[0].xs.len != 0) { return 3; }; + if (ts[0].pc != 1) { return 4; }; + if (ts[1].pc != 2) { return 5; }; + return 50; +}; diff --git a/test/wcc/data/r805_store_bool_compound/case.ww b/test/wcc/data/r805_store_bool_compound/case.ww new file mode 100644 index 00000000..7b5a76a9 --- /dev/null +++ b/test/wcc/data/r805_store_bool_compound/case.ww @@ -0,0 +1,23 @@ +//ww:run +package main; +type thread = struct { pc: size, matched: bool }; +fn setpc(ts: *[]thread, i: size) void = { + (*ts)[i].pc = 9; +}; +fn bump(ts: *[]thread, i: size) void = { + (*ts)[i].pc += 1; +}; +fn markm(ts: *[]thread, i: size) void = { + (*ts)[i].matched = true; +}; +export fn main() i32 = { + let ts: []thread = []; + append(ts, thread { pc = 7, matched = false }); + setpc(&ts, 0); + if (ts[0].pc != 9) { return 1; }; + bump(&ts, 0); + if (ts[0].pc != 10) { return 2; }; + markm(&ts, 0); + if (!ts[0].matched) { return 3; }; + return 0; +}; diff --git a/test/wcc/data/r805_store_size_neighbor/case.ww b/test/wcc/data/r805_store_size_neighbor/case.ww new file mode 100644 index 00000000..191a70f7 --- /dev/null +++ b/test/wcc/data/r805_store_size_neighbor/case.ww @@ -0,0 +1,11 @@ +//ww:run-exit 19 +package main; +type thread = struct { pc: size, matched: bool }; +fn setpc(ts: *[]thread, i: size) void = { (*ts)[i].pc = 9; }; +export fn main() i32 = { + let ts: []thread = []; + append(ts, thread { pc = 1, matched = false }); + append(ts, thread { pc = 2, matched = false }); + setpc(&ts, 1); + return (ts[0].pc*10 + ts[1].pc): i32; +}; diff --git a/test/wcc/data/r805_str_field_member/case.ww b/test/wcc/data/r805_str_field_member/case.ww new file mode 100644 index 00000000..a96e343d --- /dev/null +++ b/test/wcc/data/r805_str_field_member/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 45 +package main; +type t = struct { pc: size, name: str }; +fn setname(ts: *[]t, i: size) void = { (*ts)[i].name = "hi"; }; +export fn main() i32 = { + let ts: []t = []; + append(ts, t { pc = 1, name = "" }); + append(ts, t { pc = 2, name = "" }); + setname(&ts, 1); + let nm: str = ts[1].name; + if (nm.len != 2) { return 1; }; + if (nm[0] != 104u8) { return 2; }; + if (ts[0].name.len != 0) { return 3; }; + return 45; +}; diff --git a/test/wcc/data/r805_widths_signed/case.ww b/test/wcc/data/r805_widths_signed/case.ww new file mode 100644 index 00000000..7a1c598e --- /dev/null +++ b/test/wcc/data/r805_widths_signed/case.ww @@ -0,0 +1,17 @@ +//ww:run-exit 43 +package main; +type t = struct { a: i8, b: i16, c: i32 }; +fn seta(ts: *[]t, i: size) void = { (*ts)[i].a = -7i8; }; +fn setb(ts: *[]t, i: size) void = { (*ts)[i].b = -300i16; }; +fn setc(ts: *[]t, i: size) void = { (*ts)[i].c = -70000i32; }; +export fn main() i32 = { + let ts: []t = []; + append(ts, t { a = 1i8, b = 2i16, c = 3i32 }); + append(ts, t { a = 1i8, b = 2i16, c = 3i32 }); + seta(&ts, 1); setb(&ts, 1); setc(&ts, 1); + if (ts[1].a != -7i8) { return 1; }; + if (ts[1].b != -300i16) { return 2; }; + if (ts[1].c != -70000i32) { return 3; }; + if (ts[0].a != 1i8) { return 4; }; + return 43; +}; diff --git a/test/wcc/data/r805_widths_unsigned/case.ww b/test/wcc/data/r805_widths_unsigned/case.ww new file mode 100644 index 00000000..a9a7a56b --- /dev/null +++ b/test/wcc/data/r805_widths_unsigned/case.ww @@ -0,0 +1,18 @@ +//ww:run-exit 42 +package main; +type t = struct { a: u8, b: u16, c: u32 }; +fn seta(ts: *[]t, i: size) void = { (*ts)[i].a = 200u8; }; +fn setb(ts: *[]t, i: size) void = { (*ts)[i].b = 60000u16; }; +fn setc(ts: *[]t, i: size) void = { (*ts)[i].c = 70000u32; }; +export fn main() i32 = { + let ts: []t = []; + append(ts, t { a = 5u8, b = 6u16, c = 7u32 }); + append(ts, t { a = 5u8, b = 6u16, c = 7u32 }); + seta(&ts, 1); setb(&ts, 1); setc(&ts, 1); + if (ts[1].a != 200u8) { return 1; }; + if (ts[1].b != 60000u16) { return 2; }; + if (ts[1].c != 70000u32) { return 3; }; + if (ts[0].a != 5u8) { return 4; }; + if (ts[0].c != 7u32) { return 5; }; + return 42; +}; diff --git a/test/wcc/data/r806ap_deref_spine/case.ww b/test/wcc/data/r806ap_deref_spine/case.ww new file mode 100644 index 00000000..f38d6cdc --- /dev/null +++ b/test/wcc/data/r806ap_deref_spine/case.ww @@ -0,0 +1,19 @@ +//ww:run-exit 71 +package main; +type holder = struct { tag: i64, xs: []i64 }; +fn addspine(q: *[]holder, i: i64, v: i64) void = { + append((*q)[i].xs, v); +}; +export fn main() i32 = { + let hs: []holder = []; + let h0: holder = holder { tag = 1, xs = [] }; + append(hs, h0); + addspine(&hs, 0, 41); + addspine(&hs, 0, 43); + let hp: *holder = &hs[0]; + let g: []i64 = hp.xs; + if (len(g) != 2) { return 1; }; + if (g[0] != 41 || g[1] != 43) { return 2; }; + if (hp.tag != 1) { return 3; }; + return 71; +}; diff --git a/test/wcc/data/r806ap_deref_src/case.ww b/test/wcc/data/r806ap_deref_src/case.ww new file mode 100644 index 00000000..8a9b3db9 --- /dev/null +++ b/test/wcc/data/r806ap_deref_src/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 77 +package main; +type box = struct { pc: size, a: i64, b: i64, x: i64 }; +fn addsrc(ds: *[]box, p: *box) void = { append(*ds, *p); }; +export fn main() i32 = { + let b: box = box { pc = 4, a = 40, b = 41, x = 42 }; + let ds: []box = []; + addsrc(&ds, &b); + if (len(ds) != 1) { return 1; }; + if (ds[0].pc != 4) { return 2; }; + if (ds[0].a != 40 || ds[0].b != 41 || ds[0].x != 42) { return 3; }; + return 77; +}; diff --git a/test/wcc/data/r806ap_derefspine_field/case.ww b/test/wcc/data/r806ap_derefspine_field/case.ww new file mode 100644 index 00000000..3fc7a1b9 --- /dev/null +++ b/test/wcc/data/r806ap_derefspine_field/case.ww @@ -0,0 +1,17 @@ +//ww:run-exit 76 +package main; +type cap = struct { s: size, e: size }; +type th = struct { pc: size, rc: cap, m: bool }; +fn pick(r: *[]cap, q: *[]th, i: size) void = { + append(*r, (*q)[i].rc); +}; +export fn main() i32 = { + let ts: []th = []; + append(ts, th { pc = 1, rc = cap { s = 5, e = 9 }, ... }); + let rs: []cap = []; + pick(&rs, &ts, 0); + if (len(rs) != 1) { return 1; }; + if (rs[0].s != 5) { return 2; }; + if (rs[0].e != 9) { return 3; }; + return 76; +}; diff --git a/test/wcc/data/r806ap_elem_kinds_place/case.ww b/test/wcc/data/r806ap_elem_kinds_place/case.ww new file mode 100644 index 00000000..1a3da1bd --- /dev/null +++ b/test/wcc/data/r806ap_elem_kinds_place/case.ww @@ -0,0 +1,31 @@ +//ww:run-exit 79 +package main; +type box = struct { n: i64, m: i32, name: str, xs: []u8 }; +type tv = (i64 | void); +export fn main() i32 = { + let inner: []u8 = []; + append(inner, 7u8); + append(inner, 8u8); + let bs: []box = []; + append(bs, box { n = 41, m = 9, name = "hello", xs = inner }); + let ns: []i64 = []; + append(ns, bs[0].n); + let ms: []i32 = []; + append(ms, bs[0].m); + let ss: []str = []; + append(ss, bs[0].name); + let vs: [][]u8 = []; + append(vs, bs[0].xs); + let ts: []tv = []; + append(ts, bs[0].n); + if (len(ns) != 1 || ns[0] != 41) { return 1; }; + if (len(ms) != 1 || ms[0] != 9) { return 2; }; + if (len(ss) != 1 || len(ss[0]) != 5) { return 3; }; + if (len(vs) != 1 || len(vs[0]) != 2) { return 4; }; + if (vs[0][1] != 8u8) { return 5; }; + match (ts[0]) { + case let v: i64 => { if (v != 41) { return 6; }; }; + case void => { return 7; }; + }; + return 79; +}; diff --git a/test/wcc/data/r806ap_identroot_dot/case.ww b/test/wcc/data/r806ap_identroot_dot/case.ww new file mode 100644 index 00000000..b93ab8fa --- /dev/null +++ b/test/wcc/data/r806ap_identroot_dot/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 73 +package main; +type holder = struct { tag: i64, xs: []i64 }; +fn addfield(h: *holder, v: i64) void = { append(h.xs, v); }; +export fn main() i32 = { + let hl: holder = holder { tag = 2, xs = [] }; + addfield(&hl, 9); + addfield(&hl, 11); + if (hl.xs[0] != 9) { return 1; }; + if (hl.xs[1] != 11) { return 2; }; + if (hl.xs.len != 2) { return 3; }; + if (hl.tag != 2) { return 4; }; + return 73; +}; diff --git a/test/wcc/data/r806ap_idx_computed_elem/case.ww b/test/wcc/data/r806ap_idx_computed_elem/case.ww new file mode 100644 index 00000000..62a21a4e --- /dev/null +++ b/test/wcc/data/r806ap_idx_computed_elem/case.ww @@ -0,0 +1,17 @@ +//ww:run-exit 75 +package main; +type box = struct { pc: size, a: i64, b: i64, x: i64 }; +export fn main() i32 = { + let bs: []box = []; + append(bs, box { pc = 1, a = 10, ... }); + append(bs, box { pc = 2, a = 20, ... }); + append(bs, box { pc = 3, a = 30, b = 7, x = 8 }); + let ds: []box = []; + let i: i64 = 1; + append(ds, bs[i + 1]); + if (len(ds) != 1) { return 1; }; + if (ds[0].pc != 3) { return 2; }; + if (ds[0].a != 30) { return 3; }; + if (ds[0].b != 7 || ds[0].x != 8) { return 4; }; + return 75; +}; diff --git a/test/wcc/data/r806ap_idxfield_struct/case.ww b/test/wcc/data/r806ap_idxfield_struct/case.ww new file mode 100644 index 00000000..17de13f0 --- /dev/null +++ b/test/wcc/data/r806ap_idxfield_struct/case.ww @@ -0,0 +1,24 @@ +//ww:run-exit 74 +package main; +type capture = struct { content: str, start: size, + start_bytesize: size, end: size, end_bytesize: size }; +type thread = struct { pc: size, root_capture: capture, + matched: bool }; +export fn main() i32 = { + let threads: []thread = []; + append(threads, thread { pc = 7, ... }); + append(threads, thread { pc = 1, root_capture = capture { + content = "bcd", start = 1, start_bytesize = 2, + end = 4, end_bytesize = 5 }, ... }); + let res: []capture = []; + let i: size = 1; + append(res, threads[i].root_capture); + if (len(res) != 1) { return 1; }; + if (res[0].start != 1) { return 2; }; + if (res[0].start_bytesize != 2) { return 3; }; + if (res[0].end != 4) { return 4; }; + if (res[0].end_bytesize != 5) { return 5; }; + if (res[0].content.len != 3) { return 6; }; + if (threads[1].root_capture.end != 4) { return 7; }; + return 74; +}; diff --git a/test/wcc/data/r806ap_neutral_direct/case.ww b/test/wcc/data/r806ap_neutral_direct/case.ww new file mode 100644 index 00000000..08e5b4f8 --- /dev/null +++ b/test/wcc/data/r806ap_neutral_direct/case.ww @@ -0,0 +1,18 @@ +//ww:run-exit 72 +package main; +type box = struct { pc: size, matched: bool }; +export fn main() i32 = { + let xs: []i64 = []; + append(xs, 7); + append(xs, 8, 9); + let ys: []i64 = []; + append(ys, xs...); + let ss: []str = []; + append(ss, "hi"); + let ps: []box = []; + append(ps, box { pc = 1, matched = false }); + if (len(xs) != 3 || xs[2] != 9) { return 1; }; + if (len(ys) != 3 || ys[0] != 7) { return 2; }; + if (len(ss) != 1 || len(ps) != 1) { return 3; }; + return 72; +}; diff --git a/test/wcc/data/r806ap_realloc_loop/case.ww b/test/wcc/data/r806ap_realloc_loop/case.ww new file mode 100644 index 00000000..c0db5963 --- /dev/null +++ b/test/wcc/data/r806ap_realloc_loop/case.ww @@ -0,0 +1,29 @@ +//ww:run-exit 70 +package main; +type box = struct { pc: size, matched: bool }; +fn add(p: *[]box, v: size) void = { + if (v % 2 == 0) { + append(*p, box { pc = v, matched = true }); + } else { + append(*p, box { pc = v, matched = false }); + }; +}; +export fn main() i32 = { + let lo: i64 = 0x5151; + let bs: []box = []; + let hi: i64 = 0x7272; + let i: size = 0; + for (i < 100) { + add(&bs, i); + i += 1; + }; + if (len(bs) != 100) { return 1; }; + let j: size = 0; + for (j < 100) { + if (bs[j].pc != j) { return 2; }; + if (bs[j].matched != (j % 2 == 0)) { return 3; }; + j += 1; + }; + if (lo != 0x5151 || hi != 0x7272) { return 4; }; + return 70; +}; diff --git a/test/wcc/data/r806ap_reentrant_value/case.ww b/test/wcc/data/r806ap_reentrant_value/case.ww new file mode 100644 index 00000000..a5af72bd --- /dev/null +++ b/test/wcc/data/r806ap_reentrant_value/case.ww @@ -0,0 +1,25 @@ +//ww:run-exit 33 +package main; +type tu = (i64 | void); +fn nest(p: *[]i64, q: *[]i64, t: tu) void = { + append(*p, match (t) { + case let x: i64 => { + append(*q, 500); + yield x; + }; + case void => { + yield 0; + }; + }); +}; +export fn main() i32 = { + let a: []i64 = []; + let b: []i64 = []; + let t: tu = 7; + nest(&a, &b, t); + if (len(a) != 1) { return 1; }; + if (len(b) != 1) { return 2; }; + if (a[0] != 7) { return 3; }; + if (b[0] != 500) { return 4; }; + return 33; +}; diff --git a/test/wcc/data/r806ap_reject_call_src/case.ww b/test/wcc/data/r806ap_reject_call_src/case.ww new file mode 100644 index 00000000..5220b6c8 --- /dev/null +++ b/test/wcc/data/r806ap_reject_call_src/case.ww @@ -0,0 +1,9 @@ +//ww:error "#34: append() struct element source shape unsupported (rule-7)" +package main; +type box = struct { pc: size, a: i64 }; +fn mk() box = { return box { pc = 1, a = 2 }; }; +export fn main() i32 = { + let bs: []box = []; + append(bs, mk()); + return 0; +}; diff --git a/test/wcc/data/r806ap_reject_spread_array_src/case.ww b/test/wcc/data/r806ap_reject_spread_array_src/case.ww new file mode 100644 index 00000000..e8a958cf --- /dev/null +++ b/test/wcc/data/r806ap_reject_spread_array_src/case.ww @@ -0,0 +1,8 @@ +//ww:error "#35: append() spread source shape unsupported (rule-7)" +package main; +export fn main() i32 = { + let a: [2]i64 = [3, 4]; + let xs: []i64 = []; + append(xs, a...); + return 0; +}; diff --git a/test/wcc/data/r806ap_reject_spread_call_src/case.ww b/test/wcc/data/r806ap_reject_spread_call_src/case.ww new file mode 100644 index 00000000..27dc4b58 --- /dev/null +++ b/test/wcc/data/r806ap_reject_spread_call_src/case.ww @@ -0,0 +1,8 @@ +//ww:error "#35: append() spread source shape unsupported (rule-7)" +package main; +fn mk() []i64 = { let r: []i64 = []; append(r, 5); return r; }; +export fn main() i32 = { + let xs: []i64 = []; + append(xs, mk()...); + return 0; +}; diff --git a/test/wcc/data/r806ap_scalar_param/case.ww b/test/wcc/data/r806ap_scalar_param/case.ww new file mode 100644 index 00000000..13a17bba --- /dev/null +++ b/test/wcc/data/r806ap_scalar_param/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 60 +package main; +fn add(p: *[]i64, v: i64) void = { append(*p, v); }; +export fn main() i32 = { + let xs: []i64 = []; + add(&xs, 5); + add(&xs, 9); + if (len(xs) != 2) { return 1; }; + if (xs[0] != 5 || xs[1] != 9) { return 2; }; + let q: *[]i64 = &xs; + append(*q, 11); + if (len(xs) != 3 || xs[2] != 11) { return 3; }; + return 60; +}; diff --git a/test/wcc/data/r806ap_scalar_u8_multi/case.ww b/test/wcc/data/r806ap_scalar_u8_multi/case.ww new file mode 100644 index 00000000..9dd34084 --- /dev/null +++ b/test/wcc/data/r806ap_scalar_u8_multi/case.ww @@ -0,0 +1,10 @@ +//ww:run-exit 61 +package main; +export fn main() i32 = { + let bs: []u8 = []; + let q: *[]u8 = &bs; + append(*q, 1u8, 2u8); + if (len(bs) != 2) { return 1; }; + if (bs[0] != 1u8 || bs[1] != 2u8) { return 2; }; + return 61; +}; diff --git a/test/wcc/data/r806ap_self_append_realloc/case.ww b/test/wcc/data/r806ap_self_append_realloc/case.ww new file mode 100644 index 00000000..89af73ae --- /dev/null +++ b/test/wcc/data/r806ap_self_append_realloc/case.ww @@ -0,0 +1,20 @@ +//ww:run-exit 78 +package main; +type box = struct { pc: size, a: i64, b: i64, x: i64 }; +export fn main() i32 = { + let lo: i64 = 111; + let bs: []box = []; + let hi: i64 = 222; + append(bs, box { pc = 9, a = 100, b = 200, x = 300 }); + let i: i32 = 0; + for (i < 33) { + append(bs, bs[i]); + i += 1; + }; + if (len(bs) != 34) { return 1; }; + if (bs[0].pc != 9 || bs[33].pc != 9) { return 2; }; + if (bs[17].a != 100 || bs[33].b != 200) { return 3; }; + if (bs[33].x != 300) { return 4; }; + if (lo != 111 || hi != 222) { return 5; }; + return 78; +}; diff --git a/test/wcc/data/r806ap_selfidx_oldlen_once/case.ww b/test/wcc/data/r806ap_selfidx_oldlen_once/case.ww new file mode 100644 index 00000000..a567c3da --- /dev/null +++ b/test/wcc/data/r806ap_selfidx_oldlen_once/case.ww @@ -0,0 +1,20 @@ +//ww:run-exit 80 +package main; +type box = struct { pc: i64, a: i64 }; +let calls: i64 = 0; +fn lastidx(xs: []box) i64 = { + calls += 1; + let n: i64 = len(xs): i64; + return n - 1; +}; +export fn main() i32 = { + let bs: []box = []; + append(bs, box { pc = 11, a = 1 }); + append(bs, box { pc = 4242, a = 2 }); + append(bs, bs[lastidx(bs)]); + if (calls != 1) { return 1; }; + if (len(bs) != 3) { return 2; }; + if (bs[2].pc != 4242 || bs[2].a != 2) { return 3; }; + if (bs[0].pc != 11) { return 4; }; + return 80; +}; diff --git a/test/wcc/data/r806ap_slice_elem/case.ww b/test/wcc/data/r806ap_slice_elem/case.ww new file mode 100644 index 00000000..f440f9ab --- /dev/null +++ b/test/wcc/data/r806ap_slice_elem/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 66 +package main; +fn addv(p: *[][]u8, v: []u8) void = { append(*p, v); }; +export fn main() i32 = { + let vv: [][]u8 = []; + let one: []u8 = []; + append(one, 5u8, 6u8); + addv(&vv, one); + if (len(vv) != 1) { return 1; }; + let got: []u8 = vv[0]; + if (len(got) != 2 || got[1] != 6u8) { return 2; }; + return 66; +}; diff --git a/test/wcc/data/r806ap_spread_dup_copy/case.ww b/test/wcc/data/r806ap_spread_dup_copy/case.ww new file mode 100644 index 00000000..88f19b7a --- /dev/null +++ b/test/wcc/data/r806ap_spread_dup_copy/case.ww @@ -0,0 +1,31 @@ +//ww:run-exit 139 +package main; +type capture = struct { + content: str, + start: size, + start_bytesize: size, + end: size, + end_bytesize: size, +}; +type thr = struct { pc: size, caps: []capture }; +export fn main() i32 = { + let c0: []capture = []; + append(c0, capture { content = "x", start = 3: size, start_bytesize = 3: size, end = 8: size, end_bytesize = 8: size }); + append(c0, capture { content = "yz", start = 5: size, start_bytesize = 5: size, end = 9: size, end_bytesize = 9: size }); + let ts: []thr = []; + append(ts, thr { pc = 0: size, caps = c0 }); + let tsp = &ts; + let dup: []capture = []; + append(dup, (*tsp)[0].caps...); + if (len(dup) != 2) { return 1; }; + if (len(dup[1].content) != 2 || dup[1].content[0] != 'y') { return 2; }; + let res: []capture = []; + append(res, ts[0].caps...); + if (len(res) != 2) { return 3; }; + if (res[0].end != 8 || res[1].start != 5) { return 4; }; + dup[0].start = 100: size; + if (ts[0].caps[0].start != 3) { return 5; }; + let acc = dup[0].start + dup[1].end + res[0].start + res[1].end_bytesize + + ts[0].caps[0].end + (len(dup): size) * 5; + return acc: i32; +}; diff --git a/test/wcc/data/r806ap_spread_growth_place/case.ww b/test/wcc/data/r806ap_spread_growth_place/case.ww new file mode 100644 index 00000000..3b4852e5 --- /dev/null +++ b/test/wcc/data/r806ap_spread_growth_place/case.ww @@ -0,0 +1,16 @@ +//ww:run-exit 83 +package main; +type holder = struct { tag: i64, xs: []i64 }; +export fn main() i32 = { + let big: []i64 = []; + let i: i64 = 0; + for (i < 40) { append(big, i); i += 1; }; + let hs: []holder = []; + append(hs, holder { tag = 2, xs = big }); + let dst: []i64 = []; + append(dst, 100); + append(dst, hs[0].xs...); + if (len(dst) != 41) { return 1; }; + if (dst[0] != 100 || dst[1] != 0 || dst[40] != 39) { return 2; }; + return 83; +}; diff --git a/test/wcc/data/r806ap_spread_narrow_signed/case.ww b/test/wcc/data/r806ap_spread_narrow_signed/case.ww new file mode 100644 index 00000000..00597b0a --- /dev/null +++ b/test/wcc/data/r806ap_spread_narrow_signed/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 63 +package main; +fn addall(p: *[]i32, src: []i32) void = { append(*p, src...); }; +export fn main() i32 = { + let xs: []i32 = []; + append(xs, -7i32, 9i32); + let ys: []i32 = []; + addall(&ys, xs); + if (len(ys) != 2) { return 1; }; + if (ys[0] != -7i32) { return 2; }; + if (ys[1] != 9i32) { return 3; }; + return 63; +}; diff --git a/test/wcc/data/r806ap_spread_param/case.ww b/test/wcc/data/r806ap_spread_param/case.ww new file mode 100644 index 00000000..efa133ff --- /dev/null +++ b/test/wcc/data/r806ap_spread_param/case.ww @@ -0,0 +1,13 @@ +//ww:run-exit 62 +package main; +fn addall(p: *[]i64, src: []i64) void = { append(*p, src...); }; +export fn main() i32 = { + let xs: []i64 = []; + append(xs, 1, 2); + let ys: []i64 = []; + addall(&ys, xs); + addall(&ys, xs); + if (len(ys) != 4) { return 1; }; + if (ys[0] != 1 || ys[1] != 2 || ys[3] != 2) { return 2; }; + return 62; +}; diff --git a/test/wcc/data/r806ap_spread_place_deref/case.ww b/test/wcc/data/r806ap_spread_place_deref/case.ww new file mode 100644 index 00000000..6cea6dea --- /dev/null +++ b/test/wcc/data/r806ap_spread_place_deref/case.ww @@ -0,0 +1,18 @@ +//ww:run-exit 81 +package main; +type holder = struct { tag: i64, xs: []i64 }; +fn dup(p: *[]i64, q: *[]holder, i: i64) void = { + append(*p, (*q)[i].xs...); +}; +export fn main() i32 = { + let inner: []i64 = []; + append(inner, 5); + append(inner, 9); + let ys: []i64 = []; + let hs: []holder = []; + append(hs, holder { tag = 1, xs = inner }); + dup(&ys, &hs, 0); + if (len(ys) != 2) { return 1; }; + if (ys[0] != 5 || ys[1] != 9) { return 2; }; + return 81; +}; diff --git a/test/wcc/data/r806ap_spread_place_kinds/case.ww b/test/wcc/data/r806ap_spread_place_kinds/case.ww new file mode 100644 index 00000000..8838d621 --- /dev/null +++ b/test/wcc/data/r806ap_spread_place_kinds/case.ww @@ -0,0 +1,25 @@ +//ww:run-exit 82 +package main; +type holder = struct { tag: i64, ss: []str, ns: []i32 }; +export fn main() i32 = { + let h = holder { tag = 1, ss = [], ns = [] }; + append(h.ss, "ab"); + append(h.ss, "cde"); + append(h.ns, 7: i32); + let hs: []holder = []; + append(hs, h); + let ss: []str = []; + append(ss, hs[0].ss...); + if (len(ss) != 2) { return 1; }; + if (len(ss[0]) != 2 || ss[0][1] != 'b') { return 2; }; + if (len(ss[1]) != 3 || ss[1][2] != 'e') { return 3; }; + let ns: []i32 = []; + append(ns, hs[0].ns...); + if (len(ns) != 1 || ns[0] != 7) { return 4; }; + let empty: []i64 = []; + let ep = ∅ + let acc: []i64 = []; + append(acc, (*ep)...); + if (len(acc) != 0) { return 5; }; + return 82; +}; diff --git a/test/wcc/data/r806ap_spread_selfalias_chain/case.ww b/test/wcc/data/r806ap_spread_selfalias_chain/case.ww new file mode 100644 index 00000000..fb9a5b2c --- /dev/null +++ b/test/wcc/data/r806ap_spread_selfalias_chain/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 119 +package main; +type tnode = struct { v: i64, kids: []tnode }; +export fn main() i32 = { + let inner: []tnode = []; + append(inner, tnode { v = 7, kids = [] }); + append(inner, tnode { v = 9, kids = [] }); + let xs: []tnode = []; + append(xs, tnode { v = 1, kids = inner }); + append(xs, xs[0].kids...); + if (len(xs) != 3) { return 1; }; + if (xs[0].v != 1 || xs[1].v != 7 || xs[2].v != 9) { return 2; }; + return (81 + xs[1].v * 2 + xs[2].v * 2 + (len(xs): i64) * 2): i32; +}; diff --git a/test/wcc/data/r806ap_spread_wide/case.ww b/test/wcc/data/r806ap_spread_wide/case.ww new file mode 100644 index 00000000..8cbd436c --- /dev/null +++ b/test/wcc/data/r806ap_spread_wide/case.ww @@ -0,0 +1,16 @@ +//ww:run-exit 64 +package main; +fn addall(p: *[]str, src: []str) void = { append(*p, src...); }; +export fn main() i32 = { + let ss: []str = []; + append(ss, "ab"); + append(ss, "cde"); + let tt: []str = []; + addall(&tt, ss); + if (len(tt) != 2) { return 1; }; + let a: str = tt[0]; + let b: str = tt[1]; + if (a.len != 2 || b.len != 3) { return 2; }; + if (b[0] != 'c') { return 3; }; + return 64; +}; diff --git a/test/wcc/data/r806ap_str_elem/case.ww b/test/wcc/data/r806ap_str_elem/case.ww new file mode 100644 index 00000000..b6ded850 --- /dev/null +++ b/test/wcc/data/r806ap_str_elem/case.ww @@ -0,0 +1,14 @@ +//ww:run-exit 65 +package main; +fn adds(p: *[]str, v: str) void = { append(*p, v); }; +export fn main() i32 = { + let ss: []str = []; + adds(&ss, "hi"); + adds(&ss, "world"); + if (len(ss) != 2) { return 1; }; + let a: str = ss[0]; + let b: str = ss[1]; + if (a.len != 2 || b.len != 5) { return 2; }; + if (a[0] != 'h' || b[0] != 'w') { return 3; }; + return 65; +}; diff --git a/test/wcc/data/r806ap_struct_ident/case.ww b/test/wcc/data/r806ap_struct_ident/case.ww new file mode 100644 index 00000000..e8c243c4 --- /dev/null +++ b/test/wcc/data/r806ap_struct_ident/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 69 +package main; +type box = struct { pc: size, matched: bool }; +fn add(p: *[]box, v: size) void = { + let b: box = box { pc = v, matched = true }; + append(*p, b); +}; +export fn main() i32 = { + let bs: []box = []; + add(&bs, 7); + if (len(bs) != 1) { return 1; }; + if (bs[0].pc != 7) { return 2; }; + if (!bs[0].matched) { return 3; }; + return 69; +}; diff --git a/test/wcc/data/r806ap_struct_lit/case.ww b/test/wcc/data/r806ap_struct_lit/case.ww new file mode 100644 index 00000000..980ae87d --- /dev/null +++ b/test/wcc/data/r806ap_struct_lit/case.ww @@ -0,0 +1,15 @@ +//ww:run-exit 68 +package main; +type box = struct { pc: size, matched: bool }; +fn add(p: *[]box, v: size) void = { + append(*p, box { pc = v, matched = false }); +}; +export fn main() i32 = { + let bs: []box = []; + add(&bs, 5); + add(&bs, 9); + if (len(bs) != 2) { return 1; }; + if (bs[0].pc != 5) { return 2; }; + if (bs[1].pc != 9) { return 3; }; + return 68; +}; diff --git a/test/wcc/data/r806ap_tagged_elem/case.ww b/test/wcc/data/r806ap_tagged_elem/case.ww new file mode 100644 index 00000000..cef738bc --- /dev/null +++ b/test/wcc/data/r806ap_tagged_elem/case.ww @@ -0,0 +1,12 @@ +//ww:run-exit 67 +package main; +type tu = (i64 | void); +fn addt(p: *[]tu, v: i64) void = { append(*p, v); }; +export fn main() i32 = { + let ts: []tu = []; + addt(&ts, 42); + if (len(ts) != 1) { return 1; }; + let t0: tu = ts[0]; + if (!(t0 is i64)) { return 2; }; + return 67; +}; diff --git a/test/wcc/data/r952_absf64_copysignf64/case.ww b/test/wcc/data/r952_absf64_copysignf64/case.ww new file mode 100644 index 00000000..3bbb81e8 --- /dev/null +++ b/test/wcc/data/r952_absf64_copysignf64/case.ww @@ -0,0 +1,14 @@ +//ww:run +package main; +import math; +fn zero() f64 = { return 0.0; }; +export fn main() i32 = { + if (math.absf64(-3.0) != 3.0) { return 1; }; + if (math.absf64(3.0) != 3.0) { return 2; }; + let nan: f64 = zero() / zero(); + if (!math.isnan(math.absf64(nan))) { return 3; }; + if (math.copysignf64(3.0, -1.0) != -3.0) { return 4; }; + if (math.copysignf64(-3.0, 1.0) != 3.0) { return 5; }; + if (math.copysignf64(3.0, 1.0) != 3.0) { return 6; }; + return 0; +}; diff --git a/test/wcc/data/r952_absf64_value/case.ww b/test/wcc/data/r952_absf64_value/case.ww new file mode 100644 index 00000000..be180516 --- /dev/null +++ b/test/wcc/data/r952_absf64_value/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 7 +package main; +import math; +export fn main() i32 = { + return math.absf64(-7.0): i32; +}; diff --git a/test/wcc/data/r952_f32_width_consts/case.ww b/test/wcc/data/r952_f32_width_consts/case.ww new file mode 100644 index 00000000..480cd56f --- /dev/null +++ b/test/wcc/data/r952_f32_width_consts/case.ww @@ -0,0 +1,11 @@ +//ww:run +package main; +import math; +export fn main() i32 = { + if (math.F32_MANTISSA_BITS != 23u32) { return 1; }; + if (math.F32_EXPONENT_BITS != 8u32) { return 2; }; + if (math.F32_EXPONENT_BIAS != 127u32) { return 3; }; + if (math.F32_MANTISSA_MASK != 0x7FFFFFu32) { return 4; }; + if (math.F32_EXPONENT_MASK != 0xFFu32) { return 5; }; + return 0; +}; diff --git a/test/wcc/data/r952_f32bits_roundtrip/case.ww b/test/wcc/data/r952_f32bits_roundtrip/case.ww new file mode 100644 index 00000000..75bd3a2f --- /dev/null +++ b/test/wcc/data/r952_f32bits_roundtrip/case.ww @@ -0,0 +1,16 @@ +//ww:run +package main; +import math; +export fn main() i32 = { + if (math.f32bits(1.0f32) != 0x3F800000u32) { return 1; }; + if (math.f32bits(2.0f32) != 0x40000000u32) { return 2; }; + if (math.f32bits(-1.0f32) != 0xBF800000u32) { return 3; }; + if (math.f32bits(0.0f32) != 0u32) { return 4; }; + if (math.f32frombits(0x3F800000u32) != 1.0f32) { return 5; }; + if (math.f32frombits(0x40000000u32) != 2.0f32) { return 6; }; + if (math.f32frombits(0xBF800000u32) != -1.0f32) { return 7; }; + if (math.f32frombits(0u32) != 0.0f32) { return 8; }; + let v: f32 = 123456.0f32; + if (math.f32frombits(math.f32bits(v)) != v) { return 9; }; + return 0; +}; diff --git a/test/wcc/data/r952_f32frombits_value/case.ww b/test/wcc/data/r952_f32frombits_value/case.ww new file mode 100644 index 00000000..fb873c4a --- /dev/null +++ b/test/wcc/data/r952_f32frombits_value/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 42 +package main; +import math; +export fn main() i32 = { + return math.f32frombits(0x42280000u32): i32; +}; diff --git a/test/wcc/data/r952_f64bits_roundtrip/case.ww b/test/wcc/data/r952_f64bits_roundtrip/case.ww new file mode 100644 index 00000000..e3c55bb4 --- /dev/null +++ b/test/wcc/data/r952_f64bits_roundtrip/case.ww @@ -0,0 +1,11 @@ +//ww:run +package main; +import math; +export fn main() i32 = { + if (math.f64bits(1.0) != 0x3FF0000000000000u64) { return 1; }; + if (math.f64bits(0.0) != 0u64) { return 2; }; + let rt: f64 = math.f64frombits(math.f64bits(-2.5)); + if (rt != -2.5) { return 3; }; + if (math.f64frombits(0x4045000000000000u64) != 42.0) { return 4; }; + return 0; +}; diff --git a/test/wcc/data/r952_f64frombits_value/case.ww b/test/wcc/data/r952_f64frombits_value/case.ww new file mode 100644 index 00000000..1466b604 --- /dev/null +++ b/test/wcc/data/r952_f64frombits_value/case.ww @@ -0,0 +1,6 @@ +//ww:run-exit 42 +package main; +import math; +export fn main() i32 = { + return math.f64frombits(0x4045000000000000u64): i32; +}; diff --git a/test/wcc/data/r952_floatinfo_f32shape/case.ww b/test/wcc/data/r952_floatinfo_f32shape/case.ww new file mode 100644 index 00000000..bf8cb08b --- /dev/null +++ b/test/wcc/data/r952_floatinfo_f32shape/case.ww @@ -0,0 +1,16 @@ +//ww:run +package main; +import math; +fn readbits(p: *math.floatinfo) u64 = { return p.mantbits; }; +export fn main() i32 = { + let info: math.floatinfo; + info.mantbits = 23u64; + info.expbits = 8u64; + info.expbias = 127; + info.mantmask = 0x7FFFFFu64; + info.expmask = 0xFFu64; + if (info.mantbits != 23u64) { return 1; }; + if (info.expbias != 127) { return 2; }; + if (readbits(&info) != 23u64) { return 3; }; + return 0; +}; diff --git a/test/wcc/data/r952_floatinfo_f64shape/case.ww b/test/wcc/data/r952_floatinfo_f64shape/case.ww new file mode 100644 index 00000000..7306ad3b --- /dev/null +++ b/test/wcc/data/r952_floatinfo_f64shape/case.ww @@ -0,0 +1,19 @@ +//ww:run +package main; +import math; +fn readbits(p: *math.floatinfo) u64 = { return p.mantbits; }; +export fn main() i32 = { + let info: math.floatinfo; + info.mantbits = 52u64; + info.expbits = 11u64; + info.expbias = 1023; + info.mantmask = 0xFFFFFFFFFFFFFu64; + info.expmask = 0x7FFu64; + if (info.mantbits != 52u64) { return 1; }; + if (info.expbits != 11u64) { return 2; }; + if (info.expbias != 1023) { return 3; }; + if (info.mantmask != 0xFFFFFFFFFFFFFu64) { return 4; }; + if (info.expmask != 0x7FFu64) { return 5; }; + if (readbits(&info) != 52u64) { return 6; }; + return 0; +}; diff --git a/test/wcc/data/r952_floatinfo_instances/case.ww b/test/wcc/data/r952_floatinfo_instances/case.ww new file mode 100644 index 00000000..dc6f3f96 --- /dev/null +++ b/test/wcc/data/r952_floatinfo_instances/case.ww @@ -0,0 +1,21 @@ +//ww:run +package main; +import math; +fn rdbias(f: *math.floatinfo) int = { return f.expbias; }; +fn rdmant(f: *math.floatinfo) u64 = { return f.mantbits; }; +fn rdmask(f: *math.floatinfo) u64 = { return f.mantmask; }; +fn rdebits(f: *math.floatinfo) u64 = { return f.expbits; }; +fn rdemask(f: *math.floatinfo) u64 = { return f.expmask; }; +export fn main() i32 = { + if (rdbias(&math.f64info) != 1023) { return 1; }; + if (rdmant(&math.f64info) != 52u64) { return 2; }; + if (rdmask(&math.f64info) != 0xFFFFFFFFFFFFFu64) { return 3; }; + if (rdbias(&math.f32info) != 127) { return 4; }; + if (rdmant(&math.f32info) != 23u64) { return 5; }; + if (rdmask(&math.f32info) != 0x7FFFFFu64) { return 6; }; + if (rdebits(&math.f64info) != 11u64) { return 7; }; + if (rdemask(&math.f64info) != 0x7FFu64) { return 8; }; + if (rdebits(&math.f32info) != 8u64) { return 9; }; + if (rdemask(&math.f32info) != 0xFFu64) { return 10; }; + return 0; +}; diff --git a/test/wcc/data/r952_frexpf64_exact/case.ww b/test/wcc/data/r952_frexpf64_exact/case.ww new file mode 100644 index 00000000..9898b06b --- /dev/null +++ b/test/wcc/data/r952_frexpf64_exact/case.ww @@ -0,0 +1,22 @@ +//ww:run +package main; +import math; +export fn main() i32 = { + const a = math.frexpf64(8.0); + const am: f64 = a.0; + if (am != 0.5) { return 1; }; + if (a.1 != 4i64) { return 2; }; + const b = math.frexpf64(1.0); + const bm: f64 = b.0; + if (bm != 0.5) { return 3; }; + if (b.1 != 1i64) { return 4; }; + const c = math.frexpf64(0.0); + const cm: f64 = c.0; + if (cm != 0.0) { return 5; }; + if (c.1 != 0i64) { return 6; }; + const d = math.frexpf64(0.75); + const dm: f64 = d.0; + if (dm != 0.75) { return 7; }; + if (d.1 != 0i64) { return 8; }; + return 0; +}; diff --git a/test/wcc/data/r952_frexpf64_range/case.ww b/test/wcc/data/r952_frexpf64_range/case.ww new file mode 100644 index 00000000..c199ede9 --- /dev/null +++ b/test/wcc/data/r952_frexpf64_range/case.ww @@ -0,0 +1,12 @@ +//ww:run +package main; +import math; +export fn main() i32 = { + const r = math.frexpf64(12.0); + const m: f64 = r.0; + if (m < 0.5) { return 1; }; + if (m >= 1.0) { return 2; }; + if (r.1 != 4i64) { return 3; }; + if (m * 16.0 != 12.0) { return 4; }; + return 0; +}; diff --git a/test/wcc/data/r952_frexpf64_value/case.ww b/test/wcc/data/r952_frexpf64_value/case.ww new file mode 100644 index 00000000..659dd493 --- /dev/null +++ b/test/wcc/data/r952_frexpf64_value/case.ww @@ -0,0 +1,7 @@ +//ww:run-exit 11 +package main; +import math; +export fn main() i32 = { + const r = math.frexpf64(1024.0); + return r.1: i32; +}; diff --git a/test/wcc/data/r952_isnan_isinf/case.ww b/test/wcc/data/r952_isnan_isinf/case.ww new file mode 100644 index 00000000..47a1c637 --- /dev/null +++ b/test/wcc/data/r952_isnan_isinf/case.ww @@ -0,0 +1,16 @@ +//ww:run +package main; +import math; +fn zero() f64 = { return 0.0; }; +fn one() f64 = { return 1.0; }; +export fn main() i32 = { + let nan: f64 = zero() / zero(); + if (!math.isnan(nan)) { return 1; }; + if (math.isnan(1.0)) { return 2; }; + let inf: f64 = one() / zero(); + if (!math.isinf(inf)) { return 3; }; + if (!math.isinf(-inf)) { return 4; }; + if (math.isinf(nan)) { return 5; }; + if (math.isinf(1.23)) { return 6; }; + return 0; +}; diff --git a/test/wcc/data/r952_issubnormalf64/case.ww b/test/wcc/data/r952_issubnormalf64/case.ww new file mode 100644 index 00000000..ea904eff --- /dev/null +++ b/test/wcc/data/r952_issubnormalf64/case.ww @@ -0,0 +1,11 @@ +//ww:run +package main; +import math; +export fn main() i32 = { + if (math.issubnormalf64(16.0)) { return 1; }; + if (math.issubnormalf64(0.0)) { return 2; }; + if (math.issubnormalf64(1.0)) { return 3; }; + let s: f64 = math.f64frombits(1u64); + if (!math.issubnormalf64(s)) { return 4; }; + return 0; +}; diff --git a/test/wcc/data/r952_nan_inf_bits/case.ww b/test/wcc/data/r952_nan_inf_bits/case.ww new file mode 100644 index 00000000..cf2c52bf --- /dev/null +++ b/test/wcc/data/r952_nan_inf_bits/case.ww @@ -0,0 +1,15 @@ +//ww:run +package main; +import math; +export fn main() i32 = { + if (math.NAN_BITS != 0x7FF8000000000000u64) { return 1; }; + if (math.INF_BITS != 0x7FF0000000000000u64) { return 2; }; + let n: f64 = math.f64frombits(math.NAN_BITS); + if (!math.isnan(n)) { return 3; }; + if (math.isnan(1.0)) { return 4; }; + let i: f64 = math.f64frombits(math.INF_BITS); + if (!math.isinf(i)) { return 5; }; + if (!math.isinf(-i)) { return 6; }; + if (math.isinf(1.23)) { return 7; }; + return 0; +}; diff --git a/test/wcc/data/r952_normalizef64_normal/case.ww b/test/wcc/data/r952_normalizef64_normal/case.ww new file mode 100644 index 00000000..bd46ad3f --- /dev/null +++ b/test/wcc/data/r952_normalizef64_normal/case.ww @@ -0,0 +1,10 @@ +//ww:run +package main; +import math; +export fn main() i32 = { + const r = math.normalizef64(16.0); + const m: f64 = r.0; + if (m != 16.0) { return 1; }; + if (r.1 != 0i64) { return 2; }; + return 0; +}; diff --git a/test/wcc/data/r952_normalizef64_subnormal/case.ww b/test/wcc/data/r952_normalizef64_subnormal/case.ww new file mode 100644 index 00000000..1c2fd227 --- /dev/null +++ b/test/wcc/data/r952_normalizef64_subnormal/case.ww @@ -0,0 +1,12 @@ +//ww:run +package main; +import math; +export fn main() i32 = { + let s: f64 = math.f64frombits(1u64); + const r = math.normalizef64(s); + if (r.1 != -52i64) { return 1; }; + const m: f64 = r.0; + if (math.issubnormalf64(m)) { return 2; }; + if (m == 0.0) { return 3; }; + return 0; +}; diff --git a/test/wcc/data/r952_normalizef64_value/case.ww b/test/wcc/data/r952_normalizef64_value/case.ww new file mode 100644 index 00000000..a64cf47b --- /dev/null +++ b/test/wcc/data/r952_normalizef64_value/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 42 +package main; +import math; +export fn main() i32 = { + const r = math.normalizef64(42.0); + const m: f64 = r.0; + return m: i32; +}; diff --git a/test/wcc/data/r952_signf64_preds/case.ww b/test/wcc/data/r952_signf64_preds/case.ww new file mode 100644 index 00000000..9d4cb9d9 --- /dev/null +++ b/test/wcc/data/r952_signf64_preds/case.ww @@ -0,0 +1,13 @@ +//ww:run +package main; +import math; +export fn main() i32 = { + if (math.signf64(3.0) != 1i64) { return 1; }; + if (math.signf64(-3.0) != -1i64) { return 2; }; + if (math.signf64(0.0) != 1i64) { return 3; }; + if (!math.ispositivef64(3.0)) { return 4; }; + if (math.ispositivef64(-3.0)) { return 5; }; + if (!math.isnegativef64(-3.0)) { return 6; }; + if (math.isnegativef64(3.0)) { return 7; }; + return 0; +}; diff --git a/test/wcc/data/r958_size_limits/case.ww b/test/wcc/data/r958_size_limits/case.ww new file mode 100644 index 00000000..61e9600c --- /dev/null +++ b/test/wcc/data/r958_size_limits/case.ww @@ -0,0 +1,11 @@ +//ww:run +package main; +import types; +export fn main() i32 = { + let lo: size = types.SIZE_MIN; + if (lo != 0) { return 1; }; + let hi: size = types.SIZE_MAX; + if (hi != (types.U64_MAX): size) { return 2; }; + if (hi + 1 != 0) { return 3; }; + return 0; +}; diff --git a/test/wcc/data/r958_size_max_arith/case.ww b/test/wcc/data/r958_size_max_arith/case.ww new file mode 100644 index 00000000..e6c72266 --- /dev/null +++ b/test/wcc/data/r958_size_max_arith/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 42 +package main; +import types; +export fn main() i32 = { + let hi: size = types.SIZE_MAX; + let v: size = hi + 43; + return v: i32; +}; diff --git a/test/wcc/data/r958_uintptr_limits/case.ww b/test/wcc/data/r958_uintptr_limits/case.ww new file mode 100644 index 00000000..26bcefda --- /dev/null +++ b/test/wcc/data/r958_uintptr_limits/case.ww @@ -0,0 +1,11 @@ +//ww:run +package main; +import types; +export fn main() i32 = { + let lo: uintptr = types.UINTPTR_MIN; + if (lo != 0) { return 1; }; + let hi: uintptr = types.UINTPTR_MAX; + if (hi != (types.U64_MAX): uintptr) { return 2; }; + if (hi + 1 != 0) { return 3; }; + return 0; +}; diff --git a/test/wcc/data/r958_uintptr_max_arith/case.ww b/test/wcc/data/r958_uintptr_max_arith/case.ww new file mode 100644 index 00000000..3dfb16b1 --- /dev/null +++ b/test/wcc/data/r958_uintptr_max_arith/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 42 +package main; +import types; +export fn main() i32 = { + let hi: uintptr = types.UINTPTR_MAX; + let v: uintptr = hi + 43; + return v: i32; +}; diff --git a/test/wcc/data/r959_int_limits/case.ww b/test/wcc/data/r959_int_limits/case.ww new file mode 100644 index 00000000..6a04f807 --- /dev/null +++ b/test/wcc/data/r959_int_limits/case.ww @@ -0,0 +1,12 @@ +//ww:run +package main; +import types; +export fn main() i32 = { + let lo: int = types.INT_MIN; + if (lo != -9223372036854775808) { return 1; }; + if (lo: i64 != types.I64_MIN) { return 2; }; + let hi: int = types.INT_MAX; + if (hi != 9223372036854775807) { return 3; }; + if (hi: i64 != types.I64_MAX) { return 4; }; + return 0; +}; diff --git a/test/wcc/data/r959_int_max_arith/case.ww b/test/wcc/data/r959_int_max_arith/case.ww new file mode 100644 index 00000000..e6100c5a --- /dev/null +++ b/test/wcc/data/r959_int_max_arith/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 42 +package main; +import types; +export fn main() i32 = { + let hi: int = types.INT_MAX; + let v: int = hi + 43; + return v: i32; +}; diff --git a/test/wcc/data/r959_uint_limits/case.ww b/test/wcc/data/r959_uint_limits/case.ww new file mode 100644 index 00000000..2dec2bf5 --- /dev/null +++ b/test/wcc/data/r959_uint_limits/case.ww @@ -0,0 +1,12 @@ +//ww:run +package main; +import types; +export fn main() i32 = { + let lo: uint = types.UINT_MIN; + if (lo != 0) { return 1; }; + let hi: uint = types.UINT_MAX; + if (hi != 18446744073709551615) { return 2; }; + if (hi: u64 != types.U64_MAX) { return 3; }; + if (hi + 1 != 0) { return 4; }; + return 0; +}; diff --git a/test/wcc/data/r959_uint_max_arith/case.ww b/test/wcc/data/r959_uint_max_arith/case.ww new file mode 100644 index 00000000..70afdedc --- /dev/null +++ b/test/wcc/data/r959_uint_max_arith/case.ww @@ -0,0 +1,8 @@ +//ww:run-exit 42 +package main; +import types; +export fn main() i32 = { + let hi: uint = types.UINT_MAX; + let v: uint = hi + 43; + return v: i32; +}; diff --git a/test/wcc/data/r963_sort_lbisect/case.ww b/test/wcc/data/r963_sort_lbisect/case.ww new file mode 100644 index 00000000..fedf4407 --- /dev/null +++ b/test/wcc/data/r963_sort_lbisect/case.ww @@ -0,0 +1,30 @@ +//ww:run +package main; +import sort; +fn ints(a: *opaque, b: *opaque) int = { + let pa: *i32 = a: *i32; + let pb: *i32 = b: *i32; + let va: i32 = *pa; + let vb: i32 = *pb; + if (va < vb) { return -1; }; + if (va > vb) { return 1; }; + return 0; +}; +export fn main() i32 = { + let nums: [10]i32 = [1, 3, 4, 4, 5, 7, 9, 11, 11, 11]; + let s: []i32 = nums[0:10]; + let n: size = len(s): size; + let i: size = 0; + for (i < n) { + if (i == 0 || nums[i - 1] != nums[i]) { + let key: i32 = nums[i]; + if (sort.lbisect(s, size(i32), &key, ints) != i) { return 1; }; + }; + i = i + 1; + }; + let n0: i32 = 0; if (sort.lbisect(s, size(i32), &n0, ints) != 0) { return 2; }; + let n6: i32 = 6; if (sort.lbisect(s, size(i32), &n6, ints) != 5) { return 3; }; + let n8: i32 = 8; if (sort.lbisect(s, size(i32), &n8, ints) != 6) { return 4; }; + let n12: i32 = 12; if (sort.lbisect(s, size(i32), &n12, ints) != n) { return 5; }; + return 0; +}; diff --git a/test/wcc/data/r963_sort_rbisect/case.ww b/test/wcc/data/r963_sort_rbisect/case.ww new file mode 100644 index 00000000..1cb1d6bf --- /dev/null +++ b/test/wcc/data/r963_sort_rbisect/case.ww @@ -0,0 +1,30 @@ +//ww:run +package main; +import sort; +fn ints(a: *opaque, b: *opaque) int = { + let pa: *i32 = a: *i32; + let pb: *i32 = b: *i32; + let va: i32 = *pa; + let vb: i32 = *pb; + if (va < vb) { return -1; }; + if (va > vb) { return 1; }; + return 0; +}; +export fn main() i32 = { + let nums: [10]i32 = [1, 3, 4, 4, 5, 7, 9, 11, 11, 11]; + let s: []i32 = nums[0:10]; + let n: size = len(s): size; + let i: size = 0; + for (i < n) { + if (i == n - 1 || nums[i + 1] != nums[i]) { + let key: i32 = nums[i]; + if (sort.rbisect(s, size(i32), &key, ints) != i + 1) { return 1; }; + }; + i = i + 1; + }; + let n0: i32 = 0; if (sort.rbisect(s, size(i32), &n0, ints) != 0) { return 2; }; + let n6: i32 = 6; if (sort.rbisect(s, size(i32), &n6, ints) != 5) { return 3; }; + let n8: i32 = 8; if (sort.rbisect(s, size(i32), &n8, ints) != 6) { return 4; }; + let n12: i32 = 12; if (sort.rbisect(s, size(i32), &n12, ints) != n) { return 5; }; + return 0; +}; diff --git a/test/wcc/data/r963_sort_search/case.ww b/test/wcc/data/r963_sort_search/case.ww new file mode 100644 index 00000000..35d480d5 --- /dev/null +++ b/test/wcc/data/r963_sort_search/case.ww @@ -0,0 +1,28 @@ +//ww:run +package main; +import sort; +fn ints(a: *opaque, b: *opaque) int = { + let pa: *i32 = a: *i32; + let pb: *i32 = b: *i32; + let va: i32 = *pa; + let vb: i32 = *pb; + if (va < vb) { return -1; }; + if (va > vb) { return 1; }; + return 0; +}; +export fn main() i32 = { + let nums: [10]i32 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + let s: []i32 = nums[0:10]; + let n: size = len(s): size; + let i: size = 0; + for (i < n) { + let key: i32 = nums[i]; + let p: size = sort.search(s, size(i32), &key, ints) as size; + if (p != i) { return 1; }; + i = i + 1; + }; + let miss: i32 = 1337; + let r = sort.search(s, size(i32), &miss, ints); + if (!(r is void)) { return 2; }; + return 0; +};