| author | |
| committer | |
| log | 928ce5e326ccd1b7456002c28f34975b5bc4b13f |
| tree | 5706376fe74103223511f5a4954ce2dff0b08d0e |
| parent | 2f3ad48c9b35ccac377e710a4eee6b35f60b119f |
| parent | e8a9caa3dd0aef7b745b8197afecec90598b2cdd |
| signature | Commit is signed but in an unrecognized format. |
47 files changed, 3555 insertions(+), 1739 deletions(-)
src/all_types.hpp+118-31| ... | ... | @@ -47,6 +47,19 @@ struct ResultLocPeer; |
| 47 | 47 | struct ResultLocPeerParent; |
| 48 | 48 | struct ResultLocBitCast; |
| 49 | 49 | |
| 50 | enum PtrLen { | |
| 51 | PtrLenUnknown, | |
| 52 | PtrLenSingle, | |
| 53 | PtrLenC, | |
| 54 | }; | |
| 55 | ||
| 56 | enum UndefAllowed { | |
| 57 | UndefOk, | |
| 58 | UndefBad, | |
| 59 | LazyOkNoUndef, | |
| 60 | LazyOk, | |
| 61 | }; | |
| 62 | ||
| 50 | 63 | enum X64CABIClass { |
| 51 | 64 | X64CABIClass_Unknown, |
| 52 | 65 | X64CABIClass_MEMORY, |
| ... | ... | @@ -69,9 +82,9 @@ struct IrExecutable { |
| 69 | 82 | IrExecutable *source_exec; |
| 70 | 83 | IrAnalyze *analysis; |
| 71 | 84 | Scope *begin_scope; |
| 85 | ErrorMsg *first_err_trace_msg; | |
| 72 | 86 | ZigList<Tld *> tld_list; |
| 73 | 87 | |
| 74 | bool invalid; | |
| 75 | 88 | bool is_inline; |
| 76 | 89 | bool is_generic_instantiation; |
| 77 | 90 | bool need_err_code_spill; |
| ... | ... | @@ -255,6 +268,7 @@ enum ConstValSpecial { |
| 255 | 268 | ConstValSpecialRuntime, |
| 256 | 269 | ConstValSpecialStatic, |
| 257 | 270 | ConstValSpecialUndef, |
| 271 | ConstValSpecialLazy, | |
| 258 | 272 | }; |
| 259 | 273 | |
| 260 | 274 | enum RuntimeHintErrorUnion { |
| ... | ... | @@ -291,6 +305,82 @@ struct ConstGlobalRefs { |
| 291 | 305 | uint32_t align; |
| 292 | 306 | }; |
| 293 | 307 | |
| 308 | enum LazyValueId { | |
| 309 | LazyValueIdInvalid, | |
| 310 | LazyValueIdAlignOf, | |
| 311 | LazyValueIdPtrType, | |
| 312 | LazyValueIdOptType, | |
| 313 | LazyValueIdSliceType, | |
| 314 | LazyValueIdFnType, | |
| 315 | LazyValueIdErrUnionType, | |
| 316 | }; | |
| 317 | ||
| 318 | struct LazyValue { | |
| 319 | LazyValueId id; | |
| 320 | }; | |
| 321 | ||
| 322 | struct LazyValueAlignOf { | |
| 323 | LazyValue base; | |
| 324 | ||
| 325 | IrAnalyze *ira; | |
| 326 | IrInstruction *target_type; | |
| 327 | }; | |
| 328 | ||
| 329 | struct LazyValueSliceType { | |
| 330 | LazyValue base; | |
| 331 | ||
| 332 | IrAnalyze *ira; | |
| 333 | IrInstruction *elem_type; | |
| 334 | IrInstruction *align_inst; // can be null | |
| 335 | ||
| 336 | bool is_const; | |
| 337 | bool is_volatile; | |
| 338 | bool is_allowzero; | |
| 339 | }; | |
| 340 | ||
| 341 | struct LazyValuePtrType { | |
| 342 | LazyValue base; | |
| 343 | ||
| 344 | IrAnalyze *ira; | |
| 345 | IrInstruction *elem_type; | |
| 346 | IrInstruction *align_inst; // can be null | |
| 347 | ||
| 348 | PtrLen ptr_len; | |
| 349 | uint32_t bit_offset_in_host; | |
| 350 | ||
| 351 | uint32_t host_int_bytes; | |
| 352 | bool is_const; | |
| 353 | bool is_volatile; | |
| 354 | bool is_allowzero; | |
| 355 | }; | |
| 356 | ||
| 357 | struct LazyValueOptType { | |
| 358 | LazyValue base; | |
| 359 | ||
| 360 | IrAnalyze *ira; | |
| 361 | IrInstruction *payload_type; | |
| 362 | }; | |
| 363 | ||
| 364 | struct LazyValueFnType { | |
| 365 | LazyValue base; | |
| 366 | ||
| 367 | IrAnalyze *ira; | |
| 368 | AstNode *proto_node; | |
| 369 | IrInstruction **param_types; | |
| 370 | IrInstruction *align_inst; // can be null | |
| 371 | IrInstruction *return_type; | |
| 372 | ||
| 373 | bool is_generic; | |
| 374 | }; | |
| 375 | ||
| 376 | struct LazyValueErrUnionType { | |
| 377 | LazyValue base; | |
| 378 | ||
| 379 | IrAnalyze *ira; | |
| 380 | IrInstruction *err_set_type; | |
| 381 | IrInstruction *payload_type; | |
| 382 | }; | |
| 383 | ||
| 294 | 384 | struct ConstExprValue { |
| 295 | 385 | ZigType *type; |
| 296 | 386 | ConstValSpecial special; |
| ... | ... | @@ -318,6 +408,7 @@ struct ConstExprValue { |
| 318 | 408 | ConstPtrValue x_ptr; |
| 319 | 409 | ConstArgTuple x_arg_tuple; |
| 320 | 410 | Buf *x_enum_literal; |
| 411 | LazyValue *x_lazy; | |
| 321 | 412 | |
| 322 | 413 | // populated if special == ConstValSpecialRuntime |
| 323 | 414 | RuntimeHintErrorUnion rh_error_union; |
| ... | ... | @@ -364,6 +455,7 @@ enum TldResolution { |
| 364 | 455 | TldResolutionUnresolved, |
| 365 | 456 | TldResolutionResolving, |
| 366 | 457 | TldResolutionInvalid, |
| 458 | TldResolutionOkLazy, | |
| 367 | 459 | TldResolutionOk, |
| 368 | 460 | }; |
| 369 | 461 | |
| ... | ... | @@ -420,10 +512,12 @@ struct TypeEnumField { |
| 420 | 512 | |
| 421 | 513 | struct TypeUnionField { |
| 422 | 514 | Buf *name; |
| 515 | ZigType *type_entry; // available after ResolveStatusSizeKnown | |
| 516 | ConstExprValue *type_val; // available after ResolveStatusZeroBitsKnown | |
| 423 | 517 | TypeEnumField *enum_field; |
| 424 | ZigType *type_entry; | |
| 425 | 518 | AstNode *decl_node; |
| 426 | 519 | uint32_t gen_index; |
| 520 | uint32_t align; | |
| 427 | 521 | }; |
| 428 | 522 | |
| 429 | 523 | enum NodeType { |
| ... | ... | @@ -849,6 +943,8 @@ struct AstNodeStructField { |
| 849 | 943 | Buf *name; |
| 850 | 944 | AstNode *type; |
| 851 | 945 | AstNode *value; |
| 946 | // populated if the "align(A)" is present | |
| 947 | AstNode *align_expr; | |
| 852 | 948 | }; |
| 853 | 949 | |
| 854 | 950 | struct AstNodeStringLiteral { |
| ... | ... | @@ -944,6 +1040,7 @@ struct AstNodeEnumLiteral { |
| 944 | 1040 | |
| 945 | 1041 | struct AstNode { |
| 946 | 1042 | enum NodeType type; |
| 1043 | bool already_traced_this_node; | |
| 947 | 1044 | size_t line; |
| 948 | 1045 | size_t column; |
| 949 | 1046 | ZigType *owner; |
| ... | ... | @@ -1039,12 +1136,6 @@ struct FnTypeId { |
| 1039 | 1136 | uint32_t fn_type_id_hash(FnTypeId*); |
| 1040 | 1137 | bool fn_type_id_eql(FnTypeId *a, FnTypeId *b); |
| 1041 | 1138 | |
| 1042 | enum PtrLen { | |
| 1043 | PtrLenUnknown, | |
| 1044 | PtrLenSingle, | |
| 1045 | PtrLenC, | |
| 1046 | }; | |
| 1047 | ||
| 1048 | 1139 | struct ZigTypePointer { |
| 1049 | 1140 | ZigType *child_type; |
| 1050 | 1141 | ZigType *slice_parent; |
| ... | ... | @@ -1055,6 +1146,7 @@ struct ZigTypePointer { |
| 1055 | 1146 | bool is_const; |
| 1056 | 1147 | bool is_volatile; |
| 1057 | 1148 | bool allow_zero; |
| 1149 | bool resolve_loop_flag_zero_bits; | |
| 1058 | 1150 | }; |
| 1059 | 1151 | |
| 1060 | 1152 | struct ZigTypeInt { |
| ... | ... | @@ -1073,7 +1165,8 @@ struct ZigTypeArray { |
| 1073 | 1165 | |
| 1074 | 1166 | struct TypeStructField { |
| 1075 | 1167 | Buf *name; |
| 1076 | ZigType *type_entry; | |
| 1168 | ZigType *type_entry; // available after ResolveStatusSizeKnown | |
| 1169 | ConstExprValue *type_val; // available after ResolveStatusZeroBitsKnown | |
| 1077 | 1170 | size_t src_index; |
| 1078 | 1171 | size_t gen_index; |
| 1079 | 1172 | size_t offset; // byte offset from beginning of struct |
| ... | ... | @@ -1129,15 +1222,16 @@ struct ZigTypeStruct { |
| 1129 | 1222 | ResolveStatus resolve_status; |
| 1130 | 1223 | |
| 1131 | 1224 | bool is_slice; |
| 1132 | bool resolve_loop_flag; // set this flag temporarily to detect infinite loops | |
| 1133 | bool reported_infinite_err; | |
| 1134 | 1225 | // whether any of the fields require comptime |
| 1135 | 1226 | // known after ResolveStatusZeroBitsKnown |
| 1136 | 1227 | bool requires_comptime; |
| 1228 | bool resolve_loop_flag_zero_bits; | |
| 1229 | bool resolve_loop_flag_other; | |
| 1137 | 1230 | }; |
| 1138 | 1231 | |
| 1139 | 1232 | struct ZigTypeOptional { |
| 1140 | 1233 | ZigType *child_type; |
| 1234 | ResolveStatus resolve_status; | |
| 1141 | 1235 | }; |
| 1142 | 1236 | |
| 1143 | 1237 | struct ZigTypeErrorUnion { |
| ... | ... | @@ -1155,26 +1249,20 @@ struct ZigTypeErrorSet { |
| 1155 | 1249 | |
| 1156 | 1250 | struct ZigTypeEnum { |
| 1157 | 1251 | AstNode *decl_node; |
| 1158 | ContainerLayout layout; | |
| 1159 | uint32_t src_field_count; | |
| 1160 | 1252 | TypeEnumField *fields; |
| 1161 | bool is_invalid; // true if any fields are invalid | |
| 1162 | 1253 | ZigType *tag_int_type; |
| 1163 | 1254 | |
| 1164 | 1255 | ScopeDecls *decls_scope; |
| 1165 | 1256 | |
| 1166 | // set this flag temporarily to detect infinite loops | |
| 1167 | bool embedded_in_current; | |
| 1168 | bool reported_infinite_err; | |
| 1169 | // whether we've finished resolving it | |
| 1170 | bool complete; | |
| 1171 | ||
| 1172 | bool zero_bits_loop_flag; | |
| 1173 | bool zero_bits_known; | |
| 1174 | ||
| 1175 | 1257 | LLVMValueRef name_function; |
| 1176 | 1258 | |
| 1177 | 1259 | HashMap<Buf *, TypeEnumField *, buf_hash, buf_eql_buf> fields_by_name; |
| 1260 | uint32_t src_field_count; | |
| 1261 | ||
| 1262 | ContainerLayout layout; | |
| 1263 | ResolveStatus resolve_status; | |
| 1264 | ||
| 1265 | bool resolve_loop_flag; | |
| 1178 | 1266 | }; |
| 1179 | 1267 | |
| 1180 | 1268 | uint32_t type_ptr_hash(const ZigType *ptr); |
| ... | ... | @@ -1187,7 +1275,7 @@ struct ZigTypeUnion { |
| 1187 | 1275 | HashMap<Buf *, TypeUnionField *, buf_hash, buf_eql_buf> fields_by_name; |
| 1188 | 1276 | ZigType *tag_type; // always an enum or null |
| 1189 | 1277 | LLVMTypeRef union_llvm_type; |
| 1190 | ZigType *most_aligned_union_member; | |
| 1278 | TypeUnionField *most_aligned_union_member; | |
| 1191 | 1279 | size_t gen_union_index; |
| 1192 | 1280 | size_t gen_tag_index; |
| 1193 | 1281 | size_t union_abi_size; |
| ... | ... | @@ -1199,11 +1287,11 @@ struct ZigTypeUnion { |
| 1199 | 1287 | ResolveStatus resolve_status; |
| 1200 | 1288 | |
| 1201 | 1289 | bool have_explicit_tag_type; |
| 1202 | bool resolve_loop_flag; // set this flag temporarily to detect infinite loops | |
| 1203 | bool reported_infinite_err; | |
| 1204 | 1290 | // whether any of the fields require comptime |
| 1205 | 1291 | // the value is not valid until zero_bits_known == true |
| 1206 | 1292 | bool requires_comptime; |
| 1293 | bool resolve_loop_flag_zero_bits; | |
| 1294 | bool resolve_loop_flag_other; | |
| 1207 | 1295 | }; |
| 1208 | 1296 | |
| 1209 | 1297 | struct FnGenParamInfo { |
| ... | ... | @@ -1715,6 +1803,7 @@ struct CodeGen { |
| 1715 | 1803 | //////////////////////////// Runtime State |
| 1716 | 1804 | LLVMModuleRef module; |
| 1717 | 1805 | ZigList<ErrorMsg*> errors; |
| 1806 | ErrorMsg *trace_err; | |
| 1718 | 1807 | LLVMBuilderRef builder; |
| 1719 | 1808 | ZigLLVMDIBuilder *dbuilder; |
| 1720 | 1809 | ZigLLVMDICompileUnit *compile_unit; |
| ... | ... | @@ -1767,7 +1856,6 @@ struct CodeGen { |
| 1767 | 1856 | ZigList<Tld *> resolve_queue; |
| 1768 | 1857 | size_t resolve_queue_index; |
| 1769 | 1858 | ZigList<TimeEvent> timing_events; |
| 1770 | ZigList<AstNode *> tld_ref_source_node_stack; | |
| 1771 | 1859 | ZigList<ZigFn *> inline_fns; |
| 1772 | 1860 | ZigList<ZigFn *> test_fns; |
| 1773 | 1861 | ZigList<ErrorTableEntry *> errors_by_index; |
| ... | ... | @@ -1852,7 +1940,6 @@ struct CodeGen { |
| 1852 | 1940 | ZigFn *main_fn; |
| 1853 | 1941 | ZigFn *panic_fn; |
| 1854 | 1942 | TldFn *panic_tld_fn; |
| 1855 | AstNode *root_export_decl; | |
| 1856 | 1943 | |
| 1857 | 1944 | WantPIC want_pic; |
| 1858 | 1945 | WantStackCheck want_stack_check; |
| ... | ... | @@ -1940,7 +2027,7 @@ struct CodeGen { |
| 1940 | 2027 | Buf *zig_lib_dir; |
| 1941 | 2028 | Buf *zig_std_dir; |
| 1942 | 2029 | Buf *dynamic_linker_path; |
| 1943 | Buf *version_script_path; | |
| 2030 | Buf *version_script_path; | |
| 1944 | 2031 | |
| 1945 | 2032 | const char **llvm_argv; |
| 1946 | 2033 | size_t llvm_argv_len; |
| ... | ... | @@ -3657,13 +3744,13 @@ enum ResultLocId { |
| 3657 | 3744 | ResultLocIdBitCast, |
| 3658 | 3745 | }; |
| 3659 | 3746 | |
| 3660 | // Additions to this struct may need to be handled in | |
| 3747 | // Additions to this struct may need to be handled in | |
| 3661 | 3748 | // ir_reset_result |
| 3662 | 3749 | struct ResultLoc { |
| 3663 | 3750 | ResultLocId id; |
| 3664 | 3751 | bool written; |
| 3665 | 3752 | bool allow_write_through_const; |
| 3666 | IrInstruction *resolved_loc; // result ptr | |
| 3753 | IrInstruction *resolved_loc; // result ptr | |
| 3667 | 3754 | IrInstruction *source_instruction; |
| 3668 | 3755 | IrInstruction *gen_instruction; // value to store to the result loc |
| 3669 | 3756 | ZigType *implicit_elem_type; |
src/analyze.cpp+853-479| ... | ... | @@ -20,7 +20,7 @@ |
| 20 | 20 | |
| 21 | 21 | static const size_t default_backward_branch_quota = 1000; |
| 22 | 22 | |
| 23 | static Error resolve_struct_type(CodeGen *g, ZigType *struct_type); | |
| 23 | static Error ATTRIBUTE_MUST_USE resolve_struct_type(CodeGen *g, ZigType *struct_type); | |
| 24 | 24 | |
| 25 | 25 | static Error ATTRIBUTE_MUST_USE resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type); |
| 26 | 26 | static Error ATTRIBUTE_MUST_USE resolve_struct_alignment(CodeGen *g, ZigType *struct_type); |
| ... | ... | @@ -59,13 +59,15 @@ ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) { |
| 59 | 59 | root_struct->source_code, root_struct->line_offsets, msg); |
| 60 | 60 | |
| 61 | 61 | g->errors.append(err); |
| 62 | g->trace_err = err; | |
| 62 | 63 | return err; |
| 63 | 64 | } |
| 64 | 65 | |
| 65 | ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg) { | |
| 66 | ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) { | |
| 66 | 67 | Token fake_token; |
| 67 | 68 | fake_token.start_line = node->line; |
| 68 | 69 | fake_token.start_column = node->column; |
| 70 | node->already_traced_this_node = true; | |
| 69 | 71 | return add_token_error(g, node->owner, &fake_token, msg); |
| 70 | 72 | } |
| 71 | 73 | |
| ... | ... | @@ -271,6 +273,8 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { |
| 271 | 273 | return type_entry->data.structure.resolve_status >= status; |
| 272 | 274 | case ZigTypeIdUnion: |
| 273 | 275 | return type_entry->data.unionation.resolve_status >= status; |
| 276 | case ZigTypeIdEnum: | |
| 277 | return type_entry->data.enumeration.resolve_status >= status; | |
| 274 | 278 | case ZigTypeIdFnFrame: |
| 275 | 279 | switch (status) { |
| 276 | 280 | case ResolveStatusInvalid: |
| ... | ... | @@ -285,32 +289,28 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { |
| 285 | 289 | case ResolveStatusLLVMFull: |
| 286 | 290 | return type_entry->llvm_type != nullptr; |
| 287 | 291 | } |
| 288 | case ZigTypeIdEnum: | |
| 292 | case ZigTypeIdOpaque: | |
| 293 | return status < ResolveStatusSizeKnown; | |
| 294 | case ZigTypeIdPointer: | |
| 289 | 295 | switch (status) { |
| 290 | case ResolveStatusUnstarted: | |
| 291 | return true; | |
| 292 | 296 | case ResolveStatusInvalid: |
| 293 | 297 | zig_unreachable(); |
| 298 | case ResolveStatusUnstarted: | |
| 299 | return true; | |
| 294 | 300 | case ResolveStatusZeroBitsKnown: |
| 295 | return type_entry->data.enumeration.zero_bits_known; | |
| 296 | 301 | case ResolveStatusAlignmentKnown: |
| 297 | return type_entry->data.enumeration.zero_bits_known; | |
| 298 | 302 | case ResolveStatusSizeKnown: |
| 299 | return type_entry->data.enumeration.complete; | |
| 303 | return type_entry->abi_size != SIZE_MAX; | |
| 300 | 304 | case ResolveStatusLLVMFwdDecl: |
| 301 | 305 | case ResolveStatusLLVMFull: |
| 302 | return type_entry->llvm_di_type != nullptr; | |
| 306 | return type_entry->llvm_type != nullptr; | |
| 303 | 307 | } |
| 304 | zig_unreachable(); | |
| 305 | case ZigTypeIdOpaque: | |
| 306 | return status < ResolveStatusSizeKnown; | |
| 307 | 308 | case ZigTypeIdMetaType: |
| 308 | 309 | case ZigTypeIdVoid: |
| 309 | 310 | case ZigTypeIdBool: |
| 310 | 311 | case ZigTypeIdUnreachable: |
| 311 | 312 | case ZigTypeIdInt: |
| 312 | 313 | case ZigTypeIdFloat: |
| 313 | case ZigTypeIdPointer: | |
| 314 | 314 | case ZigTypeIdArray: |
| 315 | 315 | case ZigTypeIdComptimeFloat: |
| 316 | 316 | case ZigTypeIdComptimeInt: |
| ... | ... | @@ -460,8 +460,6 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons |
| 460 | 460 | } |
| 461 | 461 | } |
| 462 | 462 | |
| 463 | assert(type_is_resolved(child_type, ResolveStatusZeroBitsKnown)); | |
| 464 | ||
| 465 | 463 | ZigType *entry = new_type_table_entry(ZigTypeIdPointer); |
| 466 | 464 | |
| 467 | 465 | const char *star_str = ptr_len_to_star_str(ptr_len); |
| ... | ... | @@ -491,17 +489,21 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons |
| 491 | 489 | buf_ptr(&child_type->name)); |
| 492 | 490 | } |
| 493 | 491 | |
| 494 | assert(child_type->id != ZigTypeIdInvalid); | |
| 495 | ||
| 496 | if (type_has_bits(child_type)) { | |
| 497 | entry->abi_size = g->builtin_types.entry_usize->abi_size; | |
| 498 | entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; | |
| 499 | entry->abi_align = g->builtin_types.entry_usize->abi_align; | |
| 492 | if (type_is_resolved(child_type, ResolveStatusZeroBitsKnown)) { | |
| 493 | if (type_has_bits(child_type)) { | |
| 494 | entry->abi_size = g->builtin_types.entry_usize->abi_size; | |
| 495 | entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; | |
| 496 | entry->abi_align = g->builtin_types.entry_usize->abi_align; | |
| 497 | } else { | |
| 498 | assert(byte_alignment == 0); | |
| 499 | entry->abi_size = 0; | |
| 500 | entry->size_in_bits = 0; | |
| 501 | entry->abi_align = 0; | |
| 502 | } | |
| 500 | 503 | } else { |
| 501 | assert(byte_alignment == 0); | |
| 502 | entry->abi_size = 0; | |
| 503 | entry->size_in_bits = 0; | |
| 504 | entry->abi_align = 0; | |
| 504 | entry->abi_size = SIZE_MAX; | |
| 505 | entry->size_in_bits = SIZE_MAX; | |
| 506 | entry->abi_align = UINT32_MAX; | |
| 505 | 507 | } |
| 506 | 508 | |
| 507 | 509 | entry->data.pointer.ptr_len = ptr_len; |
| ... | ... | @@ -564,6 +566,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { |
| 564 | 566 | } |
| 565 | 567 | |
| 566 | 568 | entry->data.maybe.child_type = child_type; |
| 569 | entry->data.maybe.resolve_status = ResolveStatusSizeKnown; | |
| 567 | 570 | |
| 568 | 571 | child_type->optional_parent = entry; |
| 569 | 572 | return entry; |
| ... | ... | @@ -865,7 +868,7 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 865 | 868 | return table_entry->value; |
| 866 | 869 | } |
| 867 | 870 | if (fn_type_id->return_type != nullptr) { |
| 868 | if ((err = ensure_complete_type(g, fn_type_id->return_type))) | |
| 871 | if ((err = type_resolve(g, fn_type_id->return_type, ResolveStatusSizeKnown))) | |
| 869 | 872 | return g->builtin_types.entry_invalid; |
| 870 | 873 | assert(fn_type_id->return_type->id != ZigTypeIdOpaque); |
| 871 | 874 | } else { |
| ... | ... | @@ -960,31 +963,276 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind |
| 960 | 963 | return entry; |
| 961 | 964 | } |
| 962 | 965 | |
| 963 | ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name) { | |
| 966 | ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, | |
| 967 | Buf *type_name, UndefAllowed undef) | |
| 968 | { | |
| 964 | 969 | size_t backward_branch_count = 0; |
| 965 | 970 | size_t backward_branch_quota = default_backward_branch_quota; |
| 966 | 971 | return ir_eval_const_value(g, scope, node, type_entry, |
| 967 | 972 | &backward_branch_count, &backward_branch_quota, |
| 968 | nullptr, nullptr, node, type_name, nullptr, nullptr); | |
| 973 | nullptr, nullptr, node, type_name, nullptr, nullptr, undef); | |
| 969 | 974 | } |
| 970 | 975 | |
| 971 | ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { | |
| 972 | ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr); | |
| 973 | if (type_is_invalid(result->type)) | |
| 974 | return g->builtin_types.entry_invalid; | |
| 976 | static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type, | |
| 977 | ConstExprValue *parent_type_val, bool *is_zero_bits) | |
| 978 | { | |
| 979 | Error err; | |
| 980 | if (type_val->special != ConstValSpecialLazy) { | |
| 981 | assert(type_val->special == ConstValSpecialStatic); | |
| 982 | if ((type_val->data.x_type->id == ZigTypeIdStruct && | |
| 983 | type_val->data.x_type->data.structure.resolve_loop_flag_zero_bits) || | |
| 984 | (type_val->data.x_type->id == ZigTypeIdUnion && | |
| 985 | type_val->data.x_type->data.unionation.resolve_loop_flag_zero_bits) || | |
| 986 | type_val->data.x_type->id == ZigTypeIdPointer) | |
| 987 | { | |
| 988 | // Does a struct/union which contains a pointer field to itself have bits? Yes. | |
| 989 | *is_zero_bits = false; | |
| 990 | return ErrorNone; | |
| 991 | } | |
| 992 | if ((err = type_resolve(g, type_val->data.x_type, ResolveStatusZeroBitsKnown))) | |
| 993 | return err; | |
| 994 | *is_zero_bits = (type_val->data.x_type->abi_size == 0); | |
| 995 | return ErrorNone; | |
| 996 | } | |
| 997 | switch (type_val->data.x_lazy->id) { | |
| 998 | case LazyValueIdInvalid: | |
| 999 | case LazyValueIdAlignOf: | |
| 1000 | zig_unreachable(); | |
| 1001 | case LazyValueIdPtrType: { | |
| 1002 | LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(type_val->data.x_lazy); | |
| 975 | 1003 | |
| 976 | assert(result->special != ConstValSpecialRuntime); | |
| 977 | // Reject undefined as valid `type` type even though the specification | |
| 978 | // allows it to be casted to anything. | |
| 979 | // See also ir_resolve_type() | |
| 980 | if (result->special == ConstValSpecialUndef) { | |
| 981 | add_node_error(g, node, | |
| 982 | buf_sprintf("expected type 'type', found '%s'", | |
| 983 | buf_ptr(&g->builtin_types.entry_undef->name))); | |
| 984 | return g->builtin_types.entry_invalid; | |
| 1004 | if (parent_type_val == &lazy_ptr_type->elem_type->value) { | |
| 1005 | // Does a struct which contains a pointer field to itself have bits? Yes. | |
| 1006 | *is_zero_bits = false; | |
| 1007 | return ErrorNone; | |
| 1008 | } else { | |
| 1009 | if (parent_type_val == nullptr) { | |
| 1010 | parent_type_val = type_val; | |
| 1011 | } | |
| 1012 | return type_val_resolve_zero_bits(g, &lazy_ptr_type->elem_type->value, parent_type, | |
| 1013 | parent_type_val, is_zero_bits); | |
| 1014 | } | |
| 1015 | } | |
| 1016 | case LazyValueIdOptType: | |
| 1017 | case LazyValueIdSliceType: | |
| 1018 | case LazyValueIdErrUnionType: | |
| 1019 | *is_zero_bits = false; | |
| 1020 | return ErrorNone; | |
| 1021 | case LazyValueIdFnType: { | |
| 1022 | LazyValueFnType *lazy_fn_type = reinterpret_cast<LazyValueFnType *>(type_val->data.x_lazy); | |
| 1023 | *is_zero_bits = lazy_fn_type->is_generic; | |
| 1024 | return ErrorNone; | |
| 1025 | } | |
| 1026 | } | |
| 1027 | zig_unreachable(); | |
| 1028 | } | |
| 1029 | ||
| 1030 | Error type_val_resolve_is_opaque_type(CodeGen *g, ConstExprValue *type_val, bool *is_opaque_type) { | |
| 1031 | if (type_val->special != ConstValSpecialLazy) { | |
| 1032 | assert(type_val->special == ConstValSpecialStatic); | |
| 1033 | *is_opaque_type = (type_val->data.x_type->id == ZigTypeIdOpaque); | |
| 1034 | return ErrorNone; | |
| 1035 | } | |
| 1036 | switch (type_val->data.x_lazy->id) { | |
| 1037 | case LazyValueIdInvalid: | |
| 1038 | case LazyValueIdAlignOf: | |
| 1039 | zig_unreachable(); | |
| 1040 | case LazyValueIdSliceType: | |
| 1041 | case LazyValueIdPtrType: | |
| 1042 | case LazyValueIdFnType: | |
| 1043 | case LazyValueIdOptType: | |
| 1044 | case LazyValueIdErrUnionType: | |
| 1045 | *is_opaque_type = false; | |
| 1046 | return ErrorNone; | |
| 1047 | } | |
| 1048 | zig_unreachable(); | |
| 1049 | } | |
| 1050 | ||
| 1051 | static ReqCompTime type_val_resolve_requires_comptime(CodeGen *g, ConstExprValue *type_val) { | |
| 1052 | if (type_val->special != ConstValSpecialLazy) { | |
| 1053 | return type_requires_comptime(g, type_val->data.x_type); | |
| 1054 | } | |
| 1055 | switch (type_val->data.x_lazy->id) { | |
| 1056 | case LazyValueIdInvalid: | |
| 1057 | case LazyValueIdAlignOf: | |
| 1058 | zig_unreachable(); | |
| 1059 | case LazyValueIdSliceType: { | |
| 1060 | LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(type_val->data.x_lazy); | |
| 1061 | return type_val_resolve_requires_comptime(g, &lazy_slice_type->elem_type->value); | |
| 1062 | } | |
| 1063 | case LazyValueIdPtrType: { | |
| 1064 | LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(type_val->data.x_lazy); | |
| 1065 | return type_val_resolve_requires_comptime(g, &lazy_ptr_type->elem_type->value); | |
| 1066 | } | |
| 1067 | case LazyValueIdOptType: { | |
| 1068 | LazyValueOptType *lazy_opt_type = reinterpret_cast<LazyValueOptType *>(type_val->data.x_lazy); | |
| 1069 | return type_val_resolve_requires_comptime(g, &lazy_opt_type->payload_type->value); | |
| 1070 | } | |
| 1071 | case LazyValueIdFnType: { | |
| 1072 | LazyValueFnType *lazy_fn_type = reinterpret_cast<LazyValueFnType *>(type_val->data.x_lazy); | |
| 1073 | if (lazy_fn_type->is_generic) | |
| 1074 | return ReqCompTimeYes; | |
| 1075 | switch (type_val_resolve_requires_comptime(g, &lazy_fn_type->return_type->value)) { | |
| 1076 | case ReqCompTimeInvalid: | |
| 1077 | return ReqCompTimeInvalid; | |
| 1078 | case ReqCompTimeYes: | |
| 1079 | return ReqCompTimeYes; | |
| 1080 | case ReqCompTimeNo: | |
| 1081 | break; | |
| 1082 | } | |
| 1083 | size_t param_count = lazy_fn_type->proto_node->data.fn_proto.params.length; | |
| 1084 | for (size_t i = 0; i < param_count; i += 1) { | |
| 1085 | AstNode *param_node = lazy_fn_type->proto_node->data.fn_proto.params.at(i); | |
| 1086 | bool param_is_var_args = param_node->data.param_decl.is_var_args; | |
| 1087 | if (param_is_var_args) break; | |
| 1088 | switch (type_val_resolve_requires_comptime(g, &lazy_fn_type->param_types[i]->value)) { | |
| 1089 | case ReqCompTimeInvalid: | |
| 1090 | return ReqCompTimeInvalid; | |
| 1091 | case ReqCompTimeYes: | |
| 1092 | return ReqCompTimeYes; | |
| 1093 | case ReqCompTimeNo: | |
| 1094 | break; | |
| 1095 | } | |
| 1096 | } | |
| 1097 | return ReqCompTimeNo; | |
| 1098 | } | |
| 1099 | case LazyValueIdErrUnionType: { | |
| 1100 | LazyValueErrUnionType *lazy_err_union_type = | |
| 1101 | reinterpret_cast<LazyValueErrUnionType *>(type_val->data.x_lazy); | |
| 1102 | return type_val_resolve_requires_comptime(g, &lazy_err_union_type->payload_type->value); | |
| 1103 | } | |
| 1104 | } | |
| 1105 | zig_unreachable(); | |
| 1106 | } | |
| 1107 | ||
| 1108 | static Error type_val_resolve_abi_size(CodeGen *g, AstNode *source_node, ConstExprValue *type_val, | |
| 1109 | size_t *abi_size, size_t *size_in_bits) | |
| 1110 | { | |
| 1111 | Error err; | |
| 1112 | ||
| 1113 | start_over: | |
| 1114 | if (type_val->special != ConstValSpecialLazy) { | |
| 1115 | assert(type_val->special == ConstValSpecialStatic); | |
| 1116 | ZigType *ty = type_val->data.x_type; | |
| 1117 | if ((err = type_resolve(g, ty, ResolveStatusSizeKnown))) | |
| 1118 | return err; | |
| 1119 | *abi_size = ty->abi_size; | |
| 1120 | *size_in_bits = ty->size_in_bits; | |
| 1121 | return ErrorNone; | |
| 1122 | } | |
| 1123 | switch (type_val->data.x_lazy->id) { | |
| 1124 | case LazyValueIdInvalid: | |
| 1125 | case LazyValueIdAlignOf: | |
| 1126 | zig_unreachable(); | |
| 1127 | case LazyValueIdSliceType: | |
| 1128 | *abi_size = g->builtin_types.entry_usize->abi_size * 2; | |
| 1129 | *size_in_bits = g->builtin_types.entry_usize->size_in_bits * 2; | |
| 1130 | return ErrorNone; | |
| 1131 | case LazyValueIdPtrType: | |
| 1132 | case LazyValueIdFnType: | |
| 1133 | *abi_size = g->builtin_types.entry_usize->abi_size; | |
| 1134 | *size_in_bits = g->builtin_types.entry_usize->size_in_bits; | |
| 1135 | return ErrorNone; | |
| 1136 | case LazyValueIdOptType: | |
| 1137 | case LazyValueIdErrUnionType: | |
| 1138 | if ((err = ir_resolve_lazy(g, source_node, type_val))) | |
| 1139 | return err; | |
| 1140 | goto start_over; | |
| 1141 | } | |
| 1142 | zig_unreachable(); | |
| 1143 | } | |
| 1144 | ||
| 1145 | Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align) { | |
| 1146 | Error err; | |
| 1147 | if (type_val->special != ConstValSpecialLazy) { | |
| 1148 | assert(type_val->special == ConstValSpecialStatic); | |
| 1149 | ZigType *ty = type_val->data.x_type; | |
| 1150 | if (ty->id == ZigTypeIdPointer) { | |
| 1151 | *abi_align = g->builtin_types.entry_usize->abi_align; | |
| 1152 | return ErrorNone; | |
| 1153 | } | |
| 1154 | if ((err = type_resolve(g, ty, ResolveStatusAlignmentKnown))) | |
| 1155 | return err; | |
| 1156 | *abi_align = ty->abi_align; | |
| 1157 | return ErrorNone; | |
| 1158 | } | |
| 1159 | switch (type_val->data.x_lazy->id) { | |
| 1160 | case LazyValueIdInvalid: | |
| 1161 | case LazyValueIdAlignOf: | |
| 1162 | zig_unreachable(); | |
| 1163 | case LazyValueIdSliceType: | |
| 1164 | case LazyValueIdPtrType: | |
| 1165 | case LazyValueIdFnType: | |
| 1166 | *abi_align = g->builtin_types.entry_usize->abi_align; | |
| 1167 | return ErrorNone; | |
| 1168 | case LazyValueIdOptType: { | |
| 1169 | LazyValueOptType *lazy_opt_type = reinterpret_cast<LazyValueOptType *>(type_val->data.x_lazy); | |
| 1170 | return type_val_resolve_abi_align(g, &lazy_opt_type->payload_type->value, abi_align); | |
| 1171 | } | |
| 1172 | case LazyValueIdErrUnionType: { | |
| 1173 | LazyValueErrUnionType *lazy_err_union_type = | |
| 1174 | reinterpret_cast<LazyValueErrUnionType *>(type_val->data.x_lazy); | |
| 1175 | uint32_t payload_abi_align; | |
| 1176 | if ((err = type_val_resolve_abi_align(g, &lazy_err_union_type->payload_type->value, | |
| 1177 | &payload_abi_align))) | |
| 1178 | { | |
| 1179 | return err; | |
| 1180 | } | |
| 1181 | *abi_align = (payload_abi_align > g->err_tag_type->abi_align) ? | |
| 1182 | payload_abi_align : g->err_tag_type->abi_align; | |
| 1183 | return ErrorNone; | |
| 1184 | } | |
| 985 | 1185 | } |
| 1186 | zig_unreachable(); | |
| 1187 | } | |
| 986 | 1188 | |
| 987 | assert(result->data.x_type != nullptr); | |
| 1189 | static OnePossibleValue type_val_resolve_has_one_possible_value(CodeGen *g, ConstExprValue *type_val) { | |
| 1190 | if (type_val->special != ConstValSpecialLazy) { | |
| 1191 | return type_has_one_possible_value(g, type_val->data.x_type); | |
| 1192 | } | |
| 1193 | switch (type_val->data.x_lazy->id) { | |
| 1194 | case LazyValueIdInvalid: | |
| 1195 | case LazyValueIdAlignOf: | |
| 1196 | zig_unreachable(); | |
| 1197 | case LazyValueIdSliceType: // it has the len field | |
| 1198 | case LazyValueIdOptType: // it has the optional bit | |
| 1199 | case LazyValueIdFnType: | |
| 1200 | return OnePossibleValueNo; | |
| 1201 | case LazyValueIdPtrType: { | |
| 1202 | Error err; | |
| 1203 | bool zero_bits; | |
| 1204 | if ((err = type_val_resolve_zero_bits(g, type_val, nullptr, nullptr, &zero_bits))) { | |
| 1205 | return OnePossibleValueInvalid; | |
| 1206 | } | |
| 1207 | if (zero_bits) { | |
| 1208 | return OnePossibleValueYes; | |
| 1209 | } else { | |
| 1210 | return OnePossibleValueNo; | |
| 1211 | } | |
| 1212 | } | |
| 1213 | case LazyValueIdErrUnionType: { | |
| 1214 | LazyValueErrUnionType *lazy_err_union_type = | |
| 1215 | reinterpret_cast<LazyValueErrUnionType *>(type_val->data.x_lazy); | |
| 1216 | switch (type_val_resolve_has_one_possible_value(g, &lazy_err_union_type->err_set_type->value)) { | |
| 1217 | case OnePossibleValueInvalid: | |
| 1218 | return OnePossibleValueInvalid; | |
| 1219 | case OnePossibleValueNo: | |
| 1220 | return OnePossibleValueNo; | |
| 1221 | case OnePossibleValueYes: | |
| 1222 | return type_val_resolve_has_one_possible_value(g, &lazy_err_union_type->payload_type->value); | |
| 1223 | } | |
| 1224 | } | |
| 1225 | } | |
| 1226 | zig_unreachable(); | |
| 1227 | } | |
| 1228 | ||
| 1229 | ZigType *analyze_type_expr(CodeGen *g, Scope *scope, AstNode *node) { | |
| 1230 | ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, | |
| 1231 | nullptr, UndefBad); | |
| 1232 | if (type_is_invalid(result->type)) | |
| 1233 | return g->builtin_types.entry_invalid; | |
| 1234 | src_assert(result->special == ConstValSpecialStatic, node); | |
| 1235 | src_assert(result->data.x_type != nullptr, node); | |
| 988 | 1236 | return result->data.x_type; |
| 989 | 1237 | } |
| 990 | 1238 | |
| ... | ... | @@ -1032,11 +1280,12 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou |
| 1032 | 1280 | } |
| 1033 | 1281 | |
| 1034 | 1282 | static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) { |
| 1035 | ConstExprValue *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), nullptr); | |
| 1283 | ConstExprValue *align_result = analyze_const_value(g, scope, node, get_align_amt_type(g), | |
| 1284 | nullptr, UndefBad); | |
| 1036 | 1285 | if (type_is_invalid(align_result->type)) |
| 1037 | 1286 | return false; |
| 1038 | 1287 | |
| 1039 | uint32_t align_bytes = bigint_as_unsigned(&align_result->data.x_bigint); | |
| 1288 | uint32_t align_bytes = bigint_as_u32(&align_result->data.x_bigint); | |
| 1040 | 1289 | if (align_bytes == 0) { |
| 1041 | 1290 | add_node_error(g, node, buf_sprintf("alignment must be >= 1")); |
| 1042 | 1291 | return false; |
| ... | ... | @@ -1054,7 +1303,7 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf ** |
| 1054 | 1303 | ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, |
| 1055 | 1304 | PtrLenUnknown, 0, 0, 0, false); |
| 1056 | 1305 | ZigType *str_type = get_slice_type(g, ptr_type); |
| 1057 | ConstExprValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr); | |
| 1306 | ConstExprValue *result_val = analyze_const_value(g, scope, node, str_type, nullptr, UndefBad); | |
| 1058 | 1307 | if (type_is_invalid(result_val->type)) |
| 1059 | 1308 | return false; |
| 1060 | 1309 | |
| ... | ... | @@ -1068,7 +1317,7 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf ** |
| 1068 | 1317 | return true; |
| 1069 | 1318 | } |
| 1070 | 1319 | expand_undef_array(g, array_val); |
| 1071 | size_t len = bigint_as_unsigned(&len_field->data.x_bigint); | |
| 1320 | size_t len = bigint_as_usize(&len_field->data.x_bigint); | |
| 1072 | 1321 | Buf *result = buf_alloc(); |
| 1073 | 1322 | buf_resize(result, len); |
| 1074 | 1323 | for (size_t i = 0; i < len; i += 1) { |
| ... | ... | @@ -1078,7 +1327,7 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf ** |
| 1078 | 1327 | add_node_error(g, node, buf_sprintf("use of undefined value")); |
| 1079 | 1328 | return false; |
| 1080 | 1329 | } |
| 1081 | uint64_t big_c = bigint_as_unsigned(&char_val->data.x_bigint); | |
| 1330 | uint64_t big_c = bigint_as_u64(&char_val->data.x_bigint); | |
| 1082 | 1331 | assert(big_c <= UINT8_MAX); |
| 1083 | 1332 | uint8_t c = (uint8_t)big_c; |
| 1084 | 1333 | buf_ptr(result)[i] = c; |
| ... | ... | @@ -1404,7 +1653,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc |
| 1404 | 1653 | add_node_error(g, proto_node, |
| 1405 | 1654 | buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447")); |
| 1406 | 1655 | return g->builtin_types.entry_invalid; |
| 1407 | //return get_generic_fn_type(g, &fn_type_id); | |
| 1408 | 1656 | } |
| 1409 | 1657 | |
| 1410 | 1658 | ZigType *specified_return_type = analyze_type_expr(g, child_scope, fn_proto->return_type); |
| ... | ... | @@ -1423,14 +1671,17 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc |
| 1423 | 1671 | } |
| 1424 | 1672 | |
| 1425 | 1673 | if (!calling_convention_allows_zig_types(fn_type_id.cc) && |
| 1426 | fn_type_id.return_type->id != ZigTypeIdVoid && | |
| 1427 | !type_allowed_in_extern(g, fn_type_id.return_type)) | |
| 1674 | fn_type_id.return_type->id != ZigTypeIdVoid) | |
| 1428 | 1675 | { |
| 1429 | add_node_error(g, fn_proto->return_type, | |
| 1430 | buf_sprintf("return type '%s' not allowed in function with calling convention '%s'", | |
| 1431 | buf_ptr(&fn_type_id.return_type->name), | |
| 1432 | calling_convention_name(fn_type_id.cc))); | |
| 1433 | return g->builtin_types.entry_invalid; | |
| 1676 | if ((err = type_resolve(g, fn_type_id.return_type, ResolveStatusSizeKnown))) | |
| 1677 | return g->builtin_types.entry_invalid; | |
| 1678 | if (!type_allowed_in_extern(g, fn_type_id.return_type)) { | |
| 1679 | add_node_error(g, fn_proto->return_type, | |
| 1680 | buf_sprintf("return type '%s' not allowed in function with calling convention '%s'", | |
| 1681 | buf_ptr(&fn_type_id.return_type->name), | |
| 1682 | calling_convention_name(fn_type_id.cc))); | |
| 1683 | return g->builtin_types.entry_invalid; | |
| 1684 | } | |
| 1434 | 1685 | } |
| 1435 | 1686 | |
| 1436 | 1687 | switch (fn_type_id.return_type->id) { |
| ... | ... | @@ -1490,7 +1741,7 @@ bool type_is_invalid(ZigType *type_entry) { |
| 1490 | 1741 | case ZigTypeIdUnion: |
| 1491 | 1742 | return type_entry->data.unionation.resolve_status == ResolveStatusInvalid; |
| 1492 | 1743 | case ZigTypeIdEnum: |
| 1493 | return type_entry->data.enumeration.is_invalid; | |
| 1744 | return type_entry->data.enumeration.resolve_status == ResolveStatusInvalid; | |
| 1494 | 1745 | default: |
| 1495 | 1746 | return false; |
| 1496 | 1747 | } |
| ... | ... | @@ -1584,6 +1835,17 @@ static size_t get_abi_size_bytes(size_t size_in_bits, size_t pointer_size_bytes) |
| 1584 | 1835 | return align_forward(store_size_bytes, abi_align); |
| 1585 | 1836 | } |
| 1586 | 1837 | |
| 1838 | ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field) { | |
| 1839 | Error err; | |
| 1840 | if (struct_field->type_entry == nullptr) { | |
| 1841 | if ((err = ir_resolve_lazy(g, struct_field->decl_node, struct_field->type_val))) { | |
| 1842 | return nullptr; | |
| 1843 | } | |
| 1844 | struct_field->type_entry = struct_field->type_val->data.x_type; | |
| 1845 | } | |
| 1846 | return struct_field->type_entry; | |
| 1847 | } | |
| 1848 | ||
| 1587 | 1849 | static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { |
| 1588 | 1850 | assert(struct_type->id == ZigTypeIdStruct); |
| 1589 | 1851 | |
| ... | ... | @@ -1599,12 +1861,11 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { |
| 1599 | 1861 | |
| 1600 | 1862 | AstNode *decl_node = struct_type->data.structure.decl_node; |
| 1601 | 1863 | |
| 1602 | if (struct_type->data.structure.resolve_loop_flag) { | |
| 1864 | if (struct_type->data.structure.resolve_loop_flag_other) { | |
| 1603 | 1865 | if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { |
| 1604 | 1866 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 1605 | ErrorMsg *msg = add_node_error(g, decl_node, | |
| 1606 | buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name))); | |
| 1607 | emit_error_notes_for_ref_stack(g, msg); | |
| 1867 | add_node_error(g, decl_node, | |
| 1868 | buf_sprintf("struct '%s' depends on itself", buf_ptr(&struct_type->name))); | |
| 1608 | 1869 | } |
| 1609 | 1870 | return ErrorSemanticAnalyzeFail; |
| 1610 | 1871 | } |
| ... | ... | @@ -1615,20 +1876,10 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { |
| 1615 | 1876 | size_t field_count = struct_type->data.structure.src_field_count; |
| 1616 | 1877 | |
| 1617 | 1878 | bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked); |
| 1618 | struct_type->data.structure.resolve_loop_flag = true; | |
| 1879 | struct_type->data.structure.resolve_loop_flag_other = true; | |
| 1619 | 1880 | |
| 1620 | 1881 | uint32_t *host_int_bytes = packed ? allocate<uint32_t>(struct_type->data.structure.gen_field_count) : nullptr; |
| 1621 | 1882 | |
| 1622 | // Resolve sizes of all the field types. Done before the offset loop because the offset | |
| 1623 | // loop has to look ahead. | |
| 1624 | for (size_t i = 0; i < field_count; i += 1) { | |
| 1625 | TypeStructField *field = &struct_type->data.structure.fields[i]; | |
| 1626 | if ((err = type_resolve(g, field->type_entry, ResolveStatusSizeKnown))) { | |
| 1627 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 1628 | return ErrorSemanticAnalyzeFail; | |
| 1629 | } | |
| 1630 | } | |
| 1631 | ||
| 1632 | 1883 | size_t packed_bits_offset = 0; |
| 1633 | 1884 | size_t next_offset = 0; |
| 1634 | 1885 | size_t first_packed_bits_offset_misalign = SIZE_MAX; |
| ... | ... | @@ -1641,13 +1892,25 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { |
| 1641 | 1892 | TypeStructField *field = &struct_type->data.structure.fields[i]; |
| 1642 | 1893 | if (field->gen_index == SIZE_MAX) |
| 1643 | 1894 | continue; |
| 1644 | ZigType *field_type = field->type_entry; | |
| 1645 | assert(field_type != nullptr); | |
| 1646 | 1895 | |
| 1647 | 1896 | field->gen_index = gen_field_index; |
| 1648 | 1897 | field->offset = next_offset; |
| 1649 | 1898 | |
| 1650 | 1899 | if (packed) { |
| 1900 | ZigType *field_type = resolve_struct_field_type(g, field); | |
| 1901 | if (field_type == nullptr) { | |
| 1902 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 1903 | return err; | |
| 1904 | } | |
| 1905 | if ((err = type_resolve(g, field->type_entry, ResolveStatusSizeKnown))) { | |
| 1906 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 1907 | return err; | |
| 1908 | } | |
| 1909 | if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field->type_entry, field->decl_node))) { | |
| 1910 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 1911 | return err; | |
| 1912 | } | |
| 1913 | ||
| 1651 | 1914 | size_t field_size_in_bits = type_size_bits(g, field_type); |
| 1652 | 1915 | size_t next_packed_bits_offset = packed_bits_offset + field_size_in_bits; |
| 1653 | 1916 | |
| ... | ... | @@ -1683,6 +1946,15 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { |
| 1683 | 1946 | } |
| 1684 | 1947 | packed_bits_offset = next_packed_bits_offset; |
| 1685 | 1948 | } else { |
| 1949 | size_t field_abi_size; | |
| 1950 | size_t field_size_in_bits; | |
| 1951 | if ((err = type_val_resolve_abi_size(g, field->decl_node, field->type_val, | |
| 1952 | &field_abi_size, &field_size_in_bits))) | |
| 1953 | { | |
| 1954 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 1955 | return err; | |
| 1956 | } | |
| 1957 | ||
| 1686 | 1958 | gen_field_index += 1; |
| 1687 | 1959 | size_t next_src_field_index = i + 1; |
| 1688 | 1960 | for (; next_src_field_index < field_count; next_src_field_index += 1) { |
| ... | ... | @@ -1690,9 +1962,9 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { |
| 1690 | 1962 | break; |
| 1691 | 1963 | } |
| 1692 | 1964 | } |
| 1693 | size_t next_abi_align = (next_src_field_index == field_count) ? | |
| 1694 | abi_align : struct_type->data.structure.fields[next_src_field_index].type_entry->abi_align; | |
| 1695 | next_offset = next_field_offset(next_offset, abi_align, field_type->abi_size, next_abi_align); | |
| 1965 | size_t next_align = (next_src_field_index == field_count) ? | |
| 1966 | abi_align : struct_type->data.structure.fields[next_src_field_index].align; | |
| 1967 | next_offset = next_field_offset(next_offset, abi_align, field_abi_size, next_align); | |
| 1696 | 1968 | size_in_bits = next_offset * 8; |
| 1697 | 1969 | } |
| 1698 | 1970 | } |
| ... | ... | @@ -1708,9 +1980,39 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { |
| 1708 | 1980 | struct_type->size_in_bits = size_in_bits; |
| 1709 | 1981 | struct_type->data.structure.resolve_status = ResolveStatusSizeKnown; |
| 1710 | 1982 | struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index; |
| 1711 | struct_type->data.structure.resolve_loop_flag = false; | |
| 1983 | struct_type->data.structure.resolve_loop_flag_other = false; | |
| 1712 | 1984 | struct_type->data.structure.host_int_bytes = host_int_bytes; |
| 1713 | 1985 | |
| 1986 | ||
| 1987 | // Resolve types for fields | |
| 1988 | if (!packed) { | |
| 1989 | for (size_t i = 0; i < field_count; i += 1) { | |
| 1990 | TypeStructField *field = &struct_type->data.structure.fields[i]; | |
| 1991 | ZigType *field_type = resolve_struct_field_type(g, field); | |
| 1992 | if (field_type == nullptr) { | |
| 1993 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 1994 | return err; | |
| 1995 | } | |
| 1996 | ||
| 1997 | if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) { | |
| 1998 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 1999 | return err; | |
| 2000 | } | |
| 2001 | ||
| 2002 | if (struct_type->data.structure.layout == ContainerLayoutExtern && | |
| 2003 | !type_allowed_in_extern(g, field_type)) | |
| 2004 | { | |
| 2005 | add_node_error(g, field->decl_node, | |
| 2006 | buf_sprintf("extern structs cannot contain fields of type '%s'", | |
| 2007 | buf_ptr(&field_type->name))); | |
| 2008 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 2009 | return ErrorSemanticAnalyzeFail; | |
| 2010 | } | |
| 2011 | ||
| 2012 | } | |
| 2013 | } | |
| 2014 | ||
| 2015 | ||
| 1714 | 2016 | return ErrorNone; |
| 1715 | 2017 | } |
| 1716 | 2018 | |
| ... | ... | @@ -1728,22 +2030,21 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { |
| 1728 | 2030 | if (union_type->data.unionation.resolve_status >= ResolveStatusAlignmentKnown) |
| 1729 | 2031 | return ErrorNone; |
| 1730 | 2032 | |
| 1731 | if (union_type->data.unionation.resolve_loop_flag) { | |
| 1732 | if (!union_type->data.unionation.reported_infinite_err) { | |
| 1733 | AstNode *decl_node = union_type->data.unionation.decl_node; | |
| 1734 | union_type->data.unionation.reported_infinite_err = true; | |
| 2033 | AstNode *decl_node = union_type->data.structure.decl_node; | |
| 2034 | ||
| 2035 | if (union_type->data.unionation.resolve_loop_flag_other) { | |
| 2036 | if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { | |
| 1735 | 2037 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 1736 | ErrorMsg *msg = add_node_error(g, decl_node, | |
| 1737 | buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name))); | |
| 1738 | emit_error_notes_for_ref_stack(g, msg); | |
| 2038 | add_node_error(g, decl_node, | |
| 2039 | buf_sprintf("union '%s' depends on itself", buf_ptr(&union_type->name))); | |
| 1739 | 2040 | } |
| 1740 | 2041 | return ErrorSemanticAnalyzeFail; |
| 1741 | 2042 | } |
| 1742 | 2043 | |
| 1743 | 2044 | // set temporary flag |
| 1744 | union_type->data.unionation.resolve_loop_flag = true; | |
| 2045 | union_type->data.unionation.resolve_loop_flag_other = true; | |
| 1745 | 2046 | |
| 1746 | ZigType *most_aligned_union_member = nullptr; | |
| 2047 | TypeUnionField *most_aligned_union_member = nullptr; | |
| 1747 | 2048 | uint32_t field_count = union_type->data.unionation.src_field_count; |
| 1748 | 2049 | bool packed = union_type->data.unionation.layout == ContainerLayoutPacked; |
| 1749 | 2050 | |
| ... | ... | @@ -1752,34 +2053,44 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { |
| 1752 | 2053 | if (field->gen_index == UINT32_MAX) |
| 1753 | 2054 | continue; |
| 1754 | 2055 | |
| 1755 | size_t this_field_align; | |
| 1756 | if (packed) { | |
| 1757 | // TODO: https://github.com/ziglang/zig/issues/1512 | |
| 1758 | this_field_align = 1; | |
| 1759 | // This is the same hack as resolve_struct_alignment. See the comment there. | |
| 1760 | } else if (field->type_entry == nullptr) { | |
| 1761 | this_field_align = g->builtin_types.entry_usize->abi_align; | |
| 1762 | } else { | |
| 2056 | AstNode *align_expr = field->decl_node->data.struct_field.align_expr; | |
| 2057 | if (align_expr != nullptr) { | |
| 2058 | if (!analyze_const_align(g, &union_type->data.unionation.decls_scope->base, align_expr, | |
| 2059 | &field->align)) | |
| 2060 | { | |
| 2061 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | |
| 2062 | return err; | |
| 2063 | } | |
| 2064 | add_node_error(g, field->decl_node, | |
| 2065 | buf_create_from_str("TODO implement field alignment syntax for unions. https://github.com/ziglang/zig/issues/3125")); | |
| 2066 | } else if (packed) { | |
| 2067 | field->align = 1; | |
| 2068 | } else if (field->type_entry != nullptr) { | |
| 1763 | 2069 | if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { |
| 1764 | 2070 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 1765 | return ErrorSemanticAnalyzeFail; | |
| 2071 | return err; | |
| 2072 | } | |
| 2073 | field->align = field->type_entry->abi_align; | |
| 2074 | } else { | |
| 2075 | if ((err = type_val_resolve_abi_align(g, field->type_val, &field->align))) { | |
| 2076 | if (g->trace_err != nullptr) { | |
| 2077 | g->trace_err = add_error_note(g, g->trace_err, field->decl_node, | |
| 2078 | buf_create_from_str("while checking this field")); | |
| 2079 | } | |
| 2080 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | |
| 2081 | return err; | |
| 1766 | 2082 | } |
| 1767 | ||
| 1768 | 2083 | if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) |
| 1769 | 2084 | return ErrorSemanticAnalyzeFail; |
| 1770 | ||
| 1771 | this_field_align = field->type_entry->abi_align; | |
| 1772 | 2085 | } |
| 1773 | 2086 | |
| 1774 | if (most_aligned_union_member == nullptr || | |
| 1775 | this_field_align > most_aligned_union_member->abi_align) | |
| 1776 | { | |
| 1777 | most_aligned_union_member = field->type_entry; | |
| 2087 | if (most_aligned_union_member == nullptr || field->align > most_aligned_union_member->align) { | |
| 2088 | most_aligned_union_member = field; | |
| 1778 | 2089 | } |
| 1779 | 2090 | } |
| 1780 | 2091 | |
| 1781 | 2092 | // unset temporary flag |
| 1782 | union_type->data.unionation.resolve_loop_flag = false; | |
| 2093 | union_type->data.unionation.resolve_loop_flag_other = false; | |
| 1783 | 2094 | union_type->data.unionation.resolve_status = ResolveStatusAlignmentKnown; |
| 1784 | 2095 | union_type->data.unionation.most_aligned_union_member = most_aligned_union_member; |
| 1785 | 2096 | |
| ... | ... | @@ -1793,18 +2104,18 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { |
| 1793 | 2104 | union_type->abi_align = tag_type->abi_align; |
| 1794 | 2105 | union_type->data.unionation.gen_tag_index = SIZE_MAX; |
| 1795 | 2106 | union_type->data.unionation.gen_union_index = SIZE_MAX; |
| 1796 | } else if (tag_type->abi_align > most_aligned_union_member->abi_align) { | |
| 2107 | } else if (tag_type->abi_align > most_aligned_union_member->align) { | |
| 1797 | 2108 | union_type->abi_align = tag_type->abi_align; |
| 1798 | 2109 | union_type->data.unionation.gen_tag_index = 0; |
| 1799 | 2110 | union_type->data.unionation.gen_union_index = 1; |
| 1800 | 2111 | } else { |
| 1801 | union_type->abi_align = most_aligned_union_member->abi_align; | |
| 2112 | union_type->abi_align = most_aligned_union_member->align; | |
| 1802 | 2113 | union_type->data.unionation.gen_union_index = 0; |
| 1803 | 2114 | union_type->data.unionation.gen_tag_index = 1; |
| 1804 | 2115 | } |
| 1805 | 2116 | } else { |
| 1806 | 2117 | assert(most_aligned_union_member != nullptr); |
| 1807 | union_type->abi_align = most_aligned_union_member->abi_align; | |
| 2118 | union_type->abi_align = most_aligned_union_member->align; | |
| 1808 | 2119 | union_type->data.unionation.gen_union_index = SIZE_MAX; |
| 1809 | 2120 | union_type->data.unionation.gen_tag_index = SIZE_MAX; |
| 1810 | 2121 | } |
| ... | ... | @@ -1812,6 +2123,17 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { |
| 1812 | 2123 | return ErrorNone; |
| 1813 | 2124 | } |
| 1814 | 2125 | |
| 2126 | ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field) { | |
| 2127 | Error err; | |
| 2128 | if (union_field->type_entry == nullptr) { | |
| 2129 | if ((err = ir_resolve_lazy(g, union_field->decl_node, union_field->type_val))) { | |
| 2130 | return nullptr; | |
| 2131 | } | |
| 2132 | union_field->type_entry = union_field->type_val->data.x_type; | |
| 2133 | } | |
| 2134 | return union_field->type_entry; | |
| 2135 | } | |
| 2136 | ||
| 1815 | 2137 | static Error resolve_union_type(CodeGen *g, ZigType *union_type) { |
| 1816 | 2138 | assert(union_type->id == ZigTypeIdUnion); |
| 1817 | 2139 | |
| ... | ... | @@ -1831,30 +2153,32 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { |
| 1831 | 2153 | assert(decl_node->type == NodeTypeContainerDecl); |
| 1832 | 2154 | |
| 1833 | 2155 | uint32_t field_count = union_type->data.unionation.src_field_count; |
| 1834 | ZigType *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; | |
| 2156 | TypeUnionField *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; | |
| 1835 | 2157 | |
| 1836 | 2158 | assert(union_type->data.unionation.fields); |
| 1837 | 2159 | |
| 1838 | 2160 | size_t union_abi_size = 0; |
| 1839 | 2161 | size_t union_size_in_bits = 0; |
| 1840 | 2162 | |
| 1841 | if (union_type->data.unionation.resolve_loop_flag) { | |
| 1842 | if (!union_type->data.unionation.reported_infinite_err) { | |
| 1843 | union_type->data.unionation.reported_infinite_err = true; | |
| 2163 | if (union_type->data.unionation.resolve_loop_flag_other) { | |
| 2164 | if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { | |
| 1844 | 2165 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 1845 | ErrorMsg *msg = add_node_error(g, decl_node, | |
| 1846 | buf_sprintf("union '%s' depends on its own size", buf_ptr(&union_type->name))); | |
| 1847 | emit_error_notes_for_ref_stack(g, msg); | |
| 2166 | add_node_error(g, decl_node, | |
| 2167 | buf_sprintf("union '%s' depends on itself", buf_ptr(&union_type->name))); | |
| 1848 | 2168 | } |
| 1849 | 2169 | return ErrorSemanticAnalyzeFail; |
| 1850 | 2170 | } |
| 1851 | 2171 | |
| 1852 | 2172 | // set temporary flag |
| 1853 | union_type->data.unionation.resolve_loop_flag = true; | |
| 2173 | union_type->data.unionation.resolve_loop_flag_other = true; | |
| 1854 | 2174 | |
| 1855 | 2175 | for (uint32_t i = 0; i < field_count; i += 1) { |
| 1856 | 2176 | TypeUnionField *union_field = &union_type->data.unionation.fields[i]; |
| 1857 | ZigType *field_type = union_field->type_entry; | |
| 2177 | ZigType *field_type = resolve_union_field_type(g, union_field); | |
| 2178 | if (field_type == nullptr) { | |
| 2179 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | |
| 2180 | return ErrorSemanticAnalyzeFail; | |
| 2181 | } | |
| 1858 | 2182 | |
| 1859 | 2183 | if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) { |
| 1860 | 2184 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| ... | ... | @@ -1874,11 +2198,11 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { |
| 1874 | 2198 | // The union itself for now has to be treated as being independently aligned. |
| 1875 | 2199 | // See https://github.com/ziglang/zig/issues/2166. |
| 1876 | 2200 | if (most_aligned_union_member != nullptr) { |
| 1877 | union_abi_size = align_forward(union_abi_size, most_aligned_union_member->abi_align); | |
| 2201 | union_abi_size = align_forward(union_abi_size, most_aligned_union_member->align); | |
| 1878 | 2202 | } |
| 1879 | 2203 | |
| 1880 | 2204 | // unset temporary flag |
| 1881 | union_type->data.unionation.resolve_loop_flag = false; | |
| 2205 | union_type->data.unionation.resolve_loop_flag_other = false; | |
| 1882 | 2206 | union_type->data.unionation.resolve_status = ResolveStatusSizeKnown; |
| 1883 | 2207 | union_type->data.unionation.union_abi_size = union_abi_size; |
| 1884 | 2208 | |
| ... | ... | @@ -1897,7 +2221,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { |
| 1897 | 2221 | field_sizes[union_type->data.unionation.gen_tag_index] = tag_type->abi_size; |
| 1898 | 2222 | field_aligns[union_type->data.unionation.gen_tag_index] = tag_type->abi_align; |
| 1899 | 2223 | field_sizes[union_type->data.unionation.gen_union_index] = union_abi_size; |
| 1900 | field_aligns[union_type->data.unionation.gen_union_index] = most_aligned_union_member->abi_align; | |
| 2224 | field_aligns[union_type->data.unionation.gen_union_index] = most_aligned_union_member->align; | |
| 1901 | 2225 | size_t field2_offset = next_field_offset(0, union_type->abi_align, field_sizes[0], field_aligns[1]); |
| 1902 | 2226 | union_type->abi_size = next_field_offset(field2_offset, union_type->abi_align, field_sizes[1], union_type->abi_align); |
| 1903 | 2227 | union_type->size_in_bits = union_type->abi_size * 8; |
| ... | ... | @@ -1925,24 +2249,25 @@ static bool type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty) { |
| 1925 | 2249 | static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 1926 | 2250 | assert(enum_type->id == ZigTypeIdEnum); |
| 1927 | 2251 | |
| 1928 | if (enum_type->data.enumeration.is_invalid) | |
| 2252 | if (enum_type->data.enumeration.resolve_status == ResolveStatusInvalid) | |
| 1929 | 2253 | return ErrorSemanticAnalyzeFail; |
| 1930 | ||
| 1931 | if (enum_type->data.enumeration.zero_bits_known) | |
| 2254 | if (enum_type->data.enumeration.resolve_status >= ResolveStatusZeroBitsKnown) | |
| 1932 | 2255 | return ErrorNone; |
| 1933 | 2256 | |
| 1934 | if (enum_type->data.enumeration.zero_bits_loop_flag) { | |
| 1935 | ErrorMsg *msg = add_node_error(g, enum_type->data.enumeration.decl_node, | |
| 1936 | buf_sprintf("'%s' depends on itself", buf_ptr(&enum_type->name))); | |
| 1937 | emit_error_notes_for_ref_stack(g, msg); | |
| 1938 | enum_type->data.enumeration.is_invalid = true; | |
| 2257 | AstNode *decl_node = enum_type->data.enumeration.decl_node; | |
| 2258 | assert(decl_node->type == NodeTypeContainerDecl); | |
| 2259 | ||
| 2260 | if (enum_type->data.enumeration.resolve_loop_flag) { | |
| 2261 | if (enum_type->data.enumeration.resolve_status != ResolveStatusInvalid) { | |
| 2262 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; | |
| 2263 | add_node_error(g, decl_node, | |
| 2264 | buf_sprintf("enum '%s' depends on itself", | |
| 2265 | buf_ptr(&enum_type->name))); | |
| 2266 | } | |
| 1939 | 2267 | return ErrorSemanticAnalyzeFail; |
| 1940 | 2268 | } |
| 1941 | 2269 | |
| 1942 | enum_type->data.enumeration.zero_bits_loop_flag = true; | |
| 1943 | ||
| 1944 | AstNode *decl_node = enum_type->data.enumeration.decl_node; | |
| 1945 | assert(decl_node->type == NodeTypeContainerDecl); | |
| 2270 | enum_type->data.enumeration.resolve_loop_flag = true; | |
| 1946 | 2271 | |
| 1947 | 2272 | assert(!enum_type->data.enumeration.fields); |
| 1948 | 2273 | uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; |
| ... | ... | @@ -1951,9 +2276,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 1951 | 2276 | |
| 1952 | 2277 | enum_type->data.enumeration.src_field_count = field_count; |
| 1953 | 2278 | enum_type->data.enumeration.fields = nullptr; |
| 1954 | enum_type->data.enumeration.is_invalid = true; | |
| 1955 | enum_type->data.enumeration.zero_bits_loop_flag = false; | |
| 1956 | enum_type->data.enumeration.zero_bits_known = true; | |
| 2279 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; | |
| 1957 | 2280 | return ErrorSemanticAnalyzeFail; |
| 1958 | 2281 | } |
| 1959 | 2282 | |
| ... | ... | @@ -1982,14 +2305,14 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 1982 | 2305 | if (decl_node->data.container_decl.init_arg_expr != nullptr) { |
| 1983 | 2306 | ZigType *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr); |
| 1984 | 2307 | if (type_is_invalid(wanted_tag_int_type)) { |
| 1985 | enum_type->data.enumeration.is_invalid = true; | |
| 2308 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; | |
| 1986 | 2309 | } else if (wanted_tag_int_type->id != ZigTypeIdInt) { |
| 1987 | enum_type->data.enumeration.is_invalid = true; | |
| 2310 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; | |
| 1988 | 2311 | add_node_error(g, decl_node->data.container_decl.init_arg_expr, |
| 1989 | 2312 | buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name))); |
| 1990 | 2313 | } else if (enum_type->data.enumeration.layout == ContainerLayoutExtern && |
| 1991 | 2314 | !type_is_valid_extern_enum_tag(g, wanted_tag_int_type)) { |
| 1992 | enum_type->data.enumeration.is_invalid = true; | |
| 2315 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; | |
| 1993 | 2316 | ErrorMsg *msg = add_node_error(g, decl_node->data.container_decl.init_arg_expr, |
| 1994 | 2317 | buf_sprintf("'%s' is not a valid tag type for an extern enum", |
| 1995 | 2318 | buf_ptr(&wanted_tag_int_type->name))); |
| ... | ... | @@ -2022,6 +2345,11 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2022 | 2345 | buf_sprintf("structs and unions, not enums, support field types")); |
| 2023 | 2346 | add_error_note(g, msg, decl_node, |
| 2024 | 2347 | buf_sprintf("consider 'union(enum)' here")); |
| 2348 | } else if (field_node->data.struct_field.align_expr != nullptr) { | |
| 2349 | ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.align_expr, | |
| 2350 | buf_sprintf("structs and unions, not enums, support field alignment")); | |
| 2351 | add_error_note(g, msg, decl_node, | |
| 2352 | buf_sprintf("consider 'union(enum)' here")); | |
| 2025 | 2353 | } |
| 2026 | 2354 | |
| 2027 | 2355 | auto field_entry = enum_type->data.enumeration.fields_by_name.put_unique(type_enum_field->name, type_enum_field); |
| ... | ... | @@ -2029,7 +2357,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2029 | 2357 | ErrorMsg *msg = add_node_error(g, field_node, |
| 2030 | 2358 | buf_sprintf("duplicate enum field: '%s'", buf_ptr(type_enum_field->name))); |
| 2031 | 2359 | add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here")); |
| 2032 | enum_type->data.enumeration.is_invalid = true; | |
| 2360 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; | |
| 2033 | 2361 | continue; |
| 2034 | 2362 | } |
| 2035 | 2363 | |
| ... | ... | @@ -2037,9 +2365,10 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2037 | 2365 | |
| 2038 | 2366 | if (tag_value != nullptr) { |
| 2039 | 2367 | // A user-specified value is available |
| 2040 | ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); | |
| 2368 | ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, | |
| 2369 | nullptr, UndefBad); | |
| 2041 | 2370 | if (type_is_invalid(result->type)) { |
| 2042 | enum_type->data.enumeration.is_invalid = true; | |
| 2371 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; | |
| 2043 | 2372 | continue; |
| 2044 | 2373 | } |
| 2045 | 2374 | |
| ... | ... | @@ -2060,7 +2389,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2060 | 2389 | if (!bigint_fits_in_bits(&type_enum_field->value, |
| 2061 | 2390 | tag_int_type->size_in_bits, |
| 2062 | 2391 | tag_int_type->data.integral.is_signed)) { |
| 2063 | enum_type->data.enumeration.is_invalid = true; | |
| 2392 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; | |
| 2064 | 2393 | |
| 2065 | 2394 | Buf *val_buf = buf_alloc(); |
| 2066 | 2395 | bigint_append_buf(val_buf, &type_enum_field->value, 10); |
| ... | ... | @@ -2075,7 +2404,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2075 | 2404 | // Make sure the value is unique |
| 2076 | 2405 | auto entry = occupied_tag_values.put_unique(type_enum_field->value, field_node); |
| 2077 | 2406 | if (entry != nullptr) { |
| 2078 | enum_type->data.enumeration.is_invalid = true; | |
| 2407 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; | |
| 2079 | 2408 | |
| 2080 | 2409 | Buf *val_buf = buf_alloc(); |
| 2081 | 2410 | bigint_append_buf(val_buf, &type_enum_field->value, 10); |
| ... | ... | @@ -2089,13 +2418,12 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2089 | 2418 | last_enum_field = type_enum_field; |
| 2090 | 2419 | } |
| 2091 | 2420 | |
| 2092 | enum_type->data.enumeration.zero_bits_loop_flag = false; | |
| 2093 | enum_type->data.enumeration.zero_bits_known = true; | |
| 2094 | enum_type->data.enumeration.complete = true; | |
| 2095 | ||
| 2096 | if (enum_type->data.enumeration.is_invalid) | |
| 2421 | if (enum_type->data.enumeration.resolve_status == ResolveStatusInvalid) | |
| 2097 | 2422 | return ErrorSemanticAnalyzeFail; |
| 2098 | 2423 | |
| 2424 | enum_type->data.enumeration.resolve_loop_flag = false; | |
| 2425 | enum_type->data.enumeration.resolve_status = ResolveStatusSizeKnown; | |
| 2426 | ||
| 2099 | 2427 | return ErrorNone; |
| 2100 | 2428 | } |
| 2101 | 2429 | |
| ... | ... | @@ -2112,16 +2440,17 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { |
| 2112 | 2440 | AstNode *decl_node = struct_type->data.structure.decl_node; |
| 2113 | 2441 | assert(decl_node->type == NodeTypeContainerDecl); |
| 2114 | 2442 | |
| 2115 | if (struct_type->data.structure.resolve_loop_flag) { | |
| 2116 | // TODO This is a problem. I believe it can be solved with lazy values. | |
| 2117 | struct_type->size_in_bits = SIZE_MAX; | |
| 2118 | struct_type->abi_size = SIZE_MAX; | |
| 2119 | struct_type->data.structure.resolve_status = ResolveStatusZeroBitsKnown; | |
| 2120 | struct_type->data.structure.resolve_loop_flag = false; | |
| 2121 | return ErrorNone; | |
| 2443 | if (struct_type->data.structure.resolve_loop_flag_zero_bits) { | |
| 2444 | if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { | |
| 2445 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 2446 | add_node_error(g, decl_node, | |
| 2447 | buf_sprintf("struct '%s' depends on itself", | |
| 2448 | buf_ptr(&struct_type->name))); | |
| 2449 | } | |
| 2450 | return ErrorSemanticAnalyzeFail; | |
| 2122 | 2451 | } |
| 2123 | 2452 | |
| 2124 | struct_type->data.structure.resolve_loop_flag = true; | |
| 2453 | struct_type->data.structure.resolve_loop_flag_zero_bits = true; | |
| 2125 | 2454 | |
| 2126 | 2455 | assert(!struct_type->data.structure.fields); |
| 2127 | 2456 | size_t field_count = decl_node->data.container_decl.fields.length; |
| ... | ... | @@ -2153,58 +2482,60 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { |
| 2153 | 2482 | return ErrorSemanticAnalyzeFail; |
| 2154 | 2483 | } |
| 2155 | 2484 | |
| 2156 | ZigType *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); | |
| 2157 | type_struct_field->type_entry = field_type; | |
| 2158 | if (type_is_invalid(field_type)) { | |
| 2485 | ConstExprValue *field_type_val = analyze_const_value(g, scope, | |
| 2486 | field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); | |
| 2487 | if (type_is_invalid(field_type_val->type)) { | |
| 2159 | 2488 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 2160 | 2489 | return ErrorSemanticAnalyzeFail; |
| 2161 | 2490 | } |
| 2491 | assert(field_type_val->special != ConstValSpecialRuntime); | |
| 2492 | type_struct_field->type_val = field_type_val; | |
| 2162 | 2493 | if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) |
| 2163 | 2494 | return ErrorSemanticAnalyzeFail; |
| 2164 | 2495 | |
| 2165 | if (struct_type->data.structure.layout == ContainerLayoutExtern && | |
| 2166 | !type_allowed_in_extern(g, field_type)) | |
| 2167 | { | |
| 2168 | add_node_error(g, field_node, | |
| 2169 | buf_sprintf("extern structs cannot contain fields of type '%s'", | |
| 2170 | buf_ptr(&field_type->name))); | |
| 2496 | bool field_is_opaque_type; | |
| 2497 | if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { | |
| 2171 | 2498 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 2172 | 2499 | return ErrorSemanticAnalyzeFail; |
| 2173 | } else if (struct_type->data.structure.layout == ContainerLayoutPacked) { | |
| 2174 | if ((err = emit_error_unless_type_allowed_in_packed_struct(g, field_type, field_node))) { | |
| 2175 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 2176 | return ErrorSemanticAnalyzeFail; | |
| 2177 | } | |
| 2178 | 2500 | } |
| 2179 | ||
| 2180 | type_struct_field->src_index = i; | |
| 2181 | type_struct_field->gen_index = SIZE_MAX; | |
| 2182 | ||
| 2183 | if (field_type->id == ZigTypeIdOpaque) { | |
| 2501 | if (field_is_opaque_type) { | |
| 2184 | 2502 | add_node_error(g, field_node->data.struct_field.type, |
| 2185 | 2503 | buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs")); |
| 2186 | 2504 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 2187 | 2505 | return ErrorSemanticAnalyzeFail; |
| 2188 | 2506 | } |
| 2189 | switch (type_requires_comptime(g, field_type)) { | |
| 2507 | ||
| 2508 | type_struct_field->src_index = i; | |
| 2509 | type_struct_field->gen_index = SIZE_MAX; | |
| 2510 | ||
| 2511 | switch (type_val_resolve_requires_comptime(g, field_type_val)) { | |
| 2190 | 2512 | case ReqCompTimeYes: |
| 2191 | 2513 | struct_type->data.structure.requires_comptime = true; |
| 2192 | 2514 | break; |
| 2193 | 2515 | case ReqCompTimeInvalid: |
| 2516 | if (g->trace_err != nullptr) { | |
| 2517 | g->trace_err = add_error_note(g, g->trace_err, field_node, | |
| 2518 | buf_create_from_str("while checking this field")); | |
| 2519 | } | |
| 2194 | 2520 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 2195 | 2521 | return ErrorSemanticAnalyzeFail; |
| 2196 | 2522 | case ReqCompTimeNo: |
| 2197 | 2523 | break; |
| 2198 | 2524 | } |
| 2199 | 2525 | |
| 2200 | if (!type_has_bits(field_type)) | |
| 2526 | bool field_is_zero_bits; | |
| 2527 | if ((err = type_val_resolve_zero_bits(g, field_type_val, struct_type, nullptr, &field_is_zero_bits))) { | |
| 2528 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 2529 | return ErrorSemanticAnalyzeFail; | |
| 2530 | } | |
| 2531 | if (field_is_zero_bits) | |
| 2201 | 2532 | continue; |
| 2202 | 2533 | |
| 2203 | 2534 | type_struct_field->gen_index = gen_field_index; |
| 2204 | 2535 | gen_field_index += 1; |
| 2205 | 2536 | } |
| 2206 | 2537 | |
| 2207 | struct_type->data.structure.resolve_loop_flag = false; | |
| 2538 | struct_type->data.structure.resolve_loop_flag_zero_bits = false; | |
| 2208 | 2539 | struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index; |
| 2209 | 2540 | if (gen_field_index != 0) { |
| 2210 | 2541 | struct_type->abi_size = SIZE_MAX; |
| ... | ... | @@ -2234,17 +2565,16 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { |
| 2234 | 2565 | |
| 2235 | 2566 | AstNode *decl_node = struct_type->data.structure.decl_node; |
| 2236 | 2567 | |
| 2237 | if (struct_type->data.structure.resolve_loop_flag) { | |
| 2568 | if (struct_type->data.structure.resolve_loop_flag_other) { | |
| 2238 | 2569 | if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { |
| 2239 | 2570 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 2240 | ErrorMsg *msg = add_node_error(g, decl_node, | |
| 2241 | buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name))); | |
| 2242 | emit_error_notes_for_ref_stack(g, msg); | |
| 2571 | add_node_error(g, decl_node, | |
| 2572 | buf_sprintf("struct '%s' depends on itself", buf_ptr(&struct_type->name))); | |
| 2243 | 2573 | } |
| 2244 | 2574 | return ErrorSemanticAnalyzeFail; |
| 2245 | 2575 | } |
| 2246 | 2576 | |
| 2247 | struct_type->data.structure.resolve_loop_flag = true; | |
| 2577 | struct_type->data.structure.resolve_loop_flag_other = true; | |
| 2248 | 2578 | assert(decl_node->type == NodeTypeContainerDecl); |
| 2249 | 2579 | |
| 2250 | 2580 | size_t field_count = struct_type->data.structure.src_field_count; |
| ... | ... | @@ -2255,35 +2585,35 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { |
| 2255 | 2585 | if (field->gen_index == SIZE_MAX) |
| 2256 | 2586 | continue; |
| 2257 | 2587 | |
| 2258 | size_t this_field_align; | |
| 2259 | if (packed) { | |
| 2260 | // TODO: https://github.com/ziglang/zig/issues/1512 | |
| 2261 | this_field_align = 1; | |
| 2262 | // TODO If we have no type_entry for the field, we've already failed to | |
| 2263 | // compile the program correctly. This stage1 compiler needs a deeper | |
| 2264 | // reworking to make this correct, or we can ignore the problem | |
| 2265 | // and make sure it is fixed in stage2. This workaround is for when | |
| 2266 | // there is a false positive of a dependency loop, of alignment depending | |
| 2267 | // on itself. When this false positive happens we assume a pointer-aligned | |
| 2268 | // field, which is usually fine but could be incorrectly over-aligned or | |
| 2269 | // even under-aligned. See https://github.com/ziglang/zig/issues/1512 | |
| 2270 | } else if (field->type_entry == nullptr) { | |
| 2271 | this_field_align = g->builtin_types.entry_usize->abi_align; | |
| 2588 | AstNode *align_expr = field->decl_node->data.struct_field.align_expr; | |
| 2589 | if (align_expr != nullptr) { | |
| 2590 | if (!analyze_const_align(g, &struct_type->data.structure.decls_scope->base, align_expr, | |
| 2591 | &field->align)) | |
| 2592 | { | |
| 2593 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | |
| 2594 | return err; | |
| 2595 | } | |
| 2596 | } else if (packed) { | |
| 2597 | field->align = 1; | |
| 2272 | 2598 | } else { |
| 2273 | if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { | |
| 2599 | if ((err = type_val_resolve_abi_align(g, field->type_val, &field->align))) { | |
| 2600 | if (g->trace_err != nullptr) { | |
| 2601 | g->trace_err = add_error_note(g, g->trace_err, field->decl_node, | |
| 2602 | buf_create_from_str("while checking this field")); | |
| 2603 | } | |
| 2274 | 2604 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 2275 | return ErrorSemanticAnalyzeFail; | |
| 2605 | return err; | |
| 2276 | 2606 | } |
| 2277 | this_field_align = field->type_entry->abi_align; | |
| 2607 | if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) | |
| 2608 | return ErrorSemanticAnalyzeFail; | |
| 2278 | 2609 | } |
| 2279 | 2610 | |
| 2280 | // TODO: https://github.com/ziglang/zig/issues/1512 | |
| 2281 | if (this_field_align > struct_type->abi_align) { | |
| 2282 | struct_type->abi_align = this_field_align; | |
| 2611 | if (field->align > struct_type->abi_align) { | |
| 2612 | struct_type->abi_align = field->align; | |
| 2283 | 2613 | } |
| 2284 | 2614 | } |
| 2285 | 2615 | |
| 2286 | struct_type->data.structure.resolve_loop_flag = false; | |
| 2616 | struct_type->data.structure.resolve_loop_flag_other = false; | |
| 2287 | 2617 | |
| 2288 | 2618 | if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) { |
| 2289 | 2619 | return ErrorSemanticAnalyzeFail; |
| ... | ... | @@ -2304,23 +2634,21 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 2304 | 2634 | if (union_type->data.unionation.resolve_status >= ResolveStatusZeroBitsKnown) |
| 2305 | 2635 | return ErrorNone; |
| 2306 | 2636 | |
| 2307 | if (union_type->data.unionation.resolve_loop_flag) { | |
| 2308 | // If we get here it's due to recursion. From this we conclude that the struct is | |
| 2309 | // not zero bits. | |
| 2310 | // TODO actually it could still be zero bits. Here we should continue analyzing | |
| 2311 | // the union from the next field index. | |
| 2312 | union_type->data.unionation.resolve_status = ResolveStatusZeroBitsKnown; | |
| 2313 | union_type->data.unionation.resolve_loop_flag = false; | |
| 2314 | union_type->abi_size = SIZE_MAX; | |
| 2315 | union_type->size_in_bits = SIZE_MAX; | |
| 2316 | return ErrorNone; | |
| 2317 | } | |
| 2318 | ||
| 2319 | union_type->data.unionation.resolve_loop_flag = true; | |
| 2320 | ||
| 2321 | 2637 | AstNode *decl_node = union_type->data.unionation.decl_node; |
| 2322 | 2638 | assert(decl_node->type == NodeTypeContainerDecl); |
| 2323 | 2639 | |
| 2640 | if (union_type->data.unionation.resolve_loop_flag_zero_bits) { | |
| 2641 | if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { | |
| 2642 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | |
| 2643 | add_node_error(g, decl_node, | |
| 2644 | buf_sprintf("union '%s' depends on itself", | |
| 2645 | buf_ptr(&union_type->name))); | |
| 2646 | } | |
| 2647 | return ErrorSemanticAnalyzeFail; | |
| 2648 | } | |
| 2649 | ||
| 2650 | union_type->data.unionation.resolve_loop_flag_zero_bits = true; | |
| 2651 | ||
| 2324 | 2652 | assert(union_type->data.unionation.fields == nullptr); |
| 2325 | 2653 | uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; |
| 2326 | 2654 | if (field_count == 0) { |
| ... | ... | @@ -2380,14 +2708,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 2380 | 2708 | tag_type->size_in_bits = tag_int_type->size_in_bits; |
| 2381 | 2709 | |
| 2382 | 2710 | tag_type->data.enumeration.tag_int_type = tag_int_type; |
| 2383 | tag_type->data.enumeration.zero_bits_known = true; | |
| 2711 | tag_type->data.enumeration.resolve_status = ResolveStatusSizeKnown; | |
| 2384 | 2712 | tag_type->data.enumeration.decl_node = decl_node; |
| 2385 | 2713 | tag_type->data.enumeration.layout = ContainerLayoutAuto; |
| 2386 | 2714 | tag_type->data.enumeration.src_field_count = field_count; |
| 2387 | 2715 | tag_type->data.enumeration.fields = allocate<TypeEnumField>(field_count); |
| 2388 | 2716 | tag_type->data.enumeration.fields_by_name.init(field_count); |
| 2389 | 2717 | tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope; |
| 2390 | tag_type->data.enumeration.complete = true; | |
| 2391 | 2718 | } else if (enum_type_node != nullptr) { |
| 2392 | 2719 | ZigType *enum_type = analyze_type_expr(g, scope, enum_type_node); |
| 2393 | 2720 | if (type_is_invalid(enum_type)) { |
| ... | ... | @@ -2429,49 +2756,68 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 2429 | 2756 | return ErrorSemanticAnalyzeFail; |
| 2430 | 2757 | } |
| 2431 | 2758 | |
| 2432 | ZigType *field_type; | |
| 2759 | bool field_is_zero_bits; | |
| 2433 | 2760 | if (field_node->data.struct_field.type == nullptr) { |
| 2434 | if (decl_node->data.container_decl.auto_enum || decl_node->data.container_decl.init_arg_expr != nullptr) { | |
| 2435 | field_type = g->builtin_types.entry_void; | |
| 2761 | if (decl_node->data.container_decl.auto_enum || | |
| 2762 | decl_node->data.container_decl.init_arg_expr != nullptr) | |
| 2763 | { | |
| 2764 | union_field->type_entry = g->builtin_types.entry_void; | |
| 2765 | field_is_zero_bits = true; | |
| 2436 | 2766 | } else { |
| 2437 | 2767 | add_node_error(g, field_node, buf_sprintf("union field missing type")); |
| 2438 | 2768 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 2439 | 2769 | return ErrorSemanticAnalyzeFail; |
| 2440 | 2770 | } |
| 2441 | 2771 | } else { |
| 2442 | field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); | |
| 2443 | if ((err = type_resolve(g, field_type, ResolveStatusAlignmentKnown))) { | |
| 2772 | ConstExprValue *field_type_val = analyze_const_value(g, scope, | |
| 2773 | field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); | |
| 2774 | if (type_is_invalid(field_type_val->type)) { | |
| 2444 | 2775 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 2445 | 2776 | return ErrorSemanticAnalyzeFail; |
| 2446 | 2777 | } |
| 2778 | assert(field_type_val->special != ConstValSpecialRuntime); | |
| 2779 | union_field->type_val = field_type_val; | |
| 2447 | 2780 | if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) |
| 2448 | 2781 | return ErrorSemanticAnalyzeFail; |
| 2449 | } | |
| 2450 | union_field->type_entry = field_type; | |
| 2451 | 2782 | |
| 2452 | if (field_type->id == ZigTypeIdOpaque) { | |
| 2453 | add_node_error(g, field_node->data.struct_field.type, | |
| 2454 | buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in unions")); | |
| 2455 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | |
| 2456 | return ErrorSemanticAnalyzeFail; | |
| 2457 | } | |
| 2783 | bool field_is_opaque_type; | |
| 2784 | if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { | |
| 2785 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | |
| 2786 | return ErrorSemanticAnalyzeFail; | |
| 2787 | } | |
| 2788 | if (field_is_opaque_type) { | |
| 2789 | add_node_error(g, field_node->data.struct_field.type, | |
| 2790 | buf_create_from_str( | |
| 2791 | "opaque types have unknown size and therefore cannot be directly embedded in unions")); | |
| 2792 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | |
| 2793 | return ErrorSemanticAnalyzeFail; | |
| 2794 | } | |
| 2458 | 2795 | |
| 2459 | switch (type_requires_comptime(g, field_type)) { | |
| 2460 | case ReqCompTimeInvalid: | |
| 2796 | switch (type_val_resolve_requires_comptime(g, field_type_val)) { | |
| 2797 | case ReqCompTimeInvalid: | |
| 2798 | if (g->trace_err != nullptr) { | |
| 2799 | g->trace_err = add_error_note(g, g->trace_err, field_node, | |
| 2800 | buf_create_from_str("while checking this field")); | |
| 2801 | } | |
| 2802 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | |
| 2803 | return ErrorSemanticAnalyzeFail; | |
| 2804 | case ReqCompTimeYes: | |
| 2805 | union_type->data.unionation.requires_comptime = true; | |
| 2806 | break; | |
| 2807 | case ReqCompTimeNo: | |
| 2808 | break; | |
| 2809 | } | |
| 2810 | ||
| 2811 | if ((err = type_val_resolve_zero_bits(g, field_type_val, union_type, nullptr, &field_is_zero_bits))) { | |
| 2461 | 2812 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 2462 | 2813 | return ErrorSemanticAnalyzeFail; |
| 2463 | case ReqCompTimeYes: | |
| 2464 | union_type->data.unionation.requires_comptime = true; | |
| 2465 | break; | |
| 2466 | case ReqCompTimeNo: | |
| 2467 | break; | |
| 2814 | } | |
| 2468 | 2815 | } |
| 2469 | 2816 | |
| 2470 | 2817 | if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) { |
| 2471 | 2818 | ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value, |
| 2472 | buf_sprintf("non-enum union field assignment")); | |
| 2473 | add_error_note(g, msg, decl_node, | |
| 2474 | buf_sprintf("consider 'union(enum)' here")); | |
| 2819 | buf_create_from_str("untagged union field assignment")); | |
| 2820 | add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here")); | |
| 2475 | 2821 | } |
| 2476 | 2822 | |
| 2477 | 2823 | if (create_enum_type) { |
| ... | ... | @@ -2489,7 +2835,8 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 2489 | 2835 | // In a second pass we will fill in the unspecified ones. |
| 2490 | 2836 | if (tag_value != nullptr) { |
| 2491 | 2837 | ZigType *tag_int_type = tag_type->data.enumeration.tag_int_type; |
| 2492 | ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, nullptr); | |
| 2838 | ConstExprValue *result = analyze_const_value(g, scope, tag_value, tag_int_type, | |
| 2839 | nullptr, UndefBad); | |
| 2493 | 2840 | if (type_is_invalid(result->type)) { |
| 2494 | 2841 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 2495 | 2842 | return ErrorSemanticAnalyzeFail; |
| ... | ... | @@ -2530,7 +2877,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 2530 | 2877 | } |
| 2531 | 2878 | assert(union_field->enum_field != nullptr); |
| 2532 | 2879 | |
| 2533 | if (!type_has_bits(field_type)) | |
| 2880 | if (field_is_zero_bits) | |
| 2534 | 2881 | continue; |
| 2535 | 2882 | |
| 2536 | 2883 | union_field->gen_index = gen_field_index; |
| ... | ... | @@ -2607,7 +2954,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 2607 | 2954 | return ErrorSemanticAnalyzeFail; |
| 2608 | 2955 | } |
| 2609 | 2956 | |
| 2610 | union_type->data.unionation.resolve_loop_flag = false; | |
| 2957 | union_type->data.unionation.resolve_loop_flag_zero_bits = false; | |
| 2611 | 2958 | |
| 2612 | 2959 | union_type->data.unionation.gen_field_count = gen_field_index; |
| 2613 | 2960 | bool zero_bits = gen_field_index == 0 && (field_count < 2 || !src_have_tag); |
| ... | ... | @@ -2664,6 +3011,8 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node) { |
| 2664 | 3011 | fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr : |
| 2665 | 3012 | proto_node->data.fn_proto.fn_def_node->data.fn_def.body; |
| 2666 | 3013 | |
| 3014 | fn_entry->analyzed_executable.source_node = fn_entry->body_node; | |
| 3015 | ||
| 2667 | 3016 | return fn_entry; |
| 2668 | 3017 | } |
| 2669 | 3018 | |
| ... | ... | @@ -2690,7 +3039,7 @@ void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn) { |
| 2690 | 3039 | fake_decl->data.symbol_expr.symbol = tld_fn->base.name; |
| 2691 | 3040 | |
| 2692 | 3041 | // call this for the side effects of casting to panic_fn_type |
| 2693 | analyze_const_value(g, tld_fn->base.parent_scope, fake_decl, panic_fn_type, nullptr); | |
| 3042 | analyze_const_value(g, tld_fn->base.parent_scope, fake_decl, panic_fn_type, nullptr, UndefBad); | |
| 2694 | 3043 | } |
| 2695 | 3044 | |
| 2696 | 3045 | ZigType *get_test_fn_type(CodeGen *g) { |
| ... | ... | @@ -2836,7 +3185,8 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 2836 | 3185 | static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) { |
| 2837 | 3186 | assert(tld_comptime->base.source_node->type == NodeTypeCompTime); |
| 2838 | 3187 | AstNode *expr_node = tld_comptime->base.source_node->data.comptime_expr.expr; |
| 2839 | analyze_const_value(g, tld_comptime->base.parent_scope, expr_node, g->builtin_types.entry_void, nullptr); | |
| 3188 | analyze_const_value(g, tld_comptime->base.parent_scope, expr_node, g->builtin_types.entry_void, | |
| 3189 | nullptr, UndefBad); | |
| 2840 | 3190 | } |
| 2841 | 3191 | |
| 2842 | 3192 | static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { |
| ... | ... | @@ -2931,7 +3281,7 @@ void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source |
| 2931 | 3281 | |
| 2932 | 3282 | void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) { |
| 2933 | 3283 | Tld *tld = get_container_scope(g->compile_var_import)->decl_table.get(name); |
| 2934 | resolve_top_level_decl(g, tld, tld->source_node); | |
| 3284 | resolve_top_level_decl(g, tld, tld->source_node, false); | |
| 2935 | 3285 | assert(tld->id == TldIdVar); |
| 2936 | 3286 | TldVar *tld_var = (TldVar *)tld; |
| 2937 | 3287 | tld_var->var->const_value = value; |
| ... | ... | @@ -3173,7 +3523,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf |
| 3173 | 3523 | return variable_entry; |
| 3174 | 3524 | } |
| 3175 | 3525 | |
| 3176 | static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { | |
| 3526 | static void resolve_decl_var(CodeGen *g, TldVar *tld_var, bool allow_lazy) { | |
| 3177 | 3527 | AstNode *source_node = tld_var->base.source_node; |
| 3178 | 3528 | AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration; |
| 3179 | 3529 | |
| ... | ... | @@ -3185,9 +3535,8 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { |
| 3185 | 3535 | ZigType *explicit_type = nullptr; |
| 3186 | 3536 | if (var_decl->type) { |
| 3187 | 3537 | if (tld_var->analyzing_type) { |
| 3188 | ErrorMsg *msg = add_node_error(g, var_decl->type, | |
| 3538 | add_node_error(g, var_decl->type, | |
| 3189 | 3539 | buf_sprintf("type of '%s' depends on itself", buf_ptr(tld_var->base.name))); |
| 3190 | emit_error_notes_for_ref_stack(g, msg); | |
| 3191 | 3540 | explicit_type = g->builtin_types.entry_invalid; |
| 3192 | 3541 | } else { |
| 3193 | 3542 | tld_var->analyzing_type = true; |
| ... | ... | @@ -3205,7 +3554,8 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { |
| 3205 | 3554 | if (explicit_type && explicit_type->id == ZigTypeIdInvalid) { |
| 3206 | 3555 | implicit_type = explicit_type; |
| 3207 | 3556 | } else if (var_decl->expr) { |
| 3208 | init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, var_decl->symbol); | |
| 3557 | init_value = analyze_const_value(g, tld_var->base.parent_scope, var_decl->expr, explicit_type, | |
| 3558 | var_decl->symbol, allow_lazy ? LazyOk : UndefOk); | |
| 3209 | 3559 | assert(init_value); |
| 3210 | 3560 | implicit_type = init_value->type; |
| 3211 | 3561 | |
| ... | ... | @@ -3360,7 +3710,8 @@ static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, Sco |
| 3360 | 3710 | using_namespace->base.resolution = TldResolutionResolving; |
| 3361 | 3711 | assert(using_namespace->base.source_node->type == NodeTypeUsingNamespace); |
| 3362 | 3712 | ConstExprValue *result = analyze_const_value(g, &dest_decls_scope->base, |
| 3363 | using_namespace->base.source_node->data.using_namespace.expr, g->builtin_types.entry_type, nullptr); | |
| 3713 | using_namespace->base.source_node->data.using_namespace.expr, g->builtin_types.entry_type, | |
| 3714 | nullptr, UndefBad); | |
| 3364 | 3715 | using_namespace->using_namespace_value = result; |
| 3365 | 3716 | |
| 3366 | 3717 | if (type_is_invalid(result->type)) { |
| ... | ... | @@ -3380,51 +3731,61 @@ static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, Sco |
| 3380 | 3731 | } |
| 3381 | 3732 | } |
| 3382 | 3733 | |
| 3383 | void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node) { | |
| 3384 | if (tld->resolution != TldResolutionUnresolved) | |
| 3734 | void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool allow_lazy) { | |
| 3735 | bool want_resolve_lazy = tld->resolution == TldResolutionOkLazy && !allow_lazy; | |
| 3736 | if (tld->resolution != TldResolutionUnresolved && !want_resolve_lazy) | |
| 3385 | 3737 | return; |
| 3386 | 3738 | |
| 3387 | assert(tld->resolution != TldResolutionResolving); | |
| 3388 | 3739 | tld->resolution = TldResolutionResolving; |
| 3389 | g->tld_ref_source_node_stack.append(source_node); | |
| 3390 | 3740 | |
| 3391 | 3741 | switch (tld->id) { |
| 3392 | case TldIdVar: | |
| 3393 | { | |
| 3394 | TldVar *tld_var = (TldVar *)tld; | |
| 3395 | resolve_decl_var(g, tld_var); | |
| 3396 | break; | |
| 3397 | } | |
| 3398 | case TldIdFn: | |
| 3399 | { | |
| 3400 | TldFn *tld_fn = (TldFn *)tld; | |
| 3401 | resolve_decl_fn(g, tld_fn); | |
| 3402 | break; | |
| 3403 | } | |
| 3404 | case TldIdContainer: | |
| 3405 | { | |
| 3406 | TldContainer *tld_container = (TldContainer *)tld; | |
| 3407 | resolve_decl_container(g, tld_container); | |
| 3408 | break; | |
| 3409 | } | |
| 3410 | case TldIdCompTime: | |
| 3411 | { | |
| 3412 | TldCompTime *tld_comptime = (TldCompTime *)tld; | |
| 3413 | resolve_decl_comptime(g, tld_comptime); | |
| 3414 | break; | |
| 3742 | case TldIdVar: { | |
| 3743 | TldVar *tld_var = (TldVar *)tld; | |
| 3744 | if (want_resolve_lazy) { | |
| 3745 | ir_resolve_lazy(g, source_node, tld_var->var->const_value); | |
| 3746 | } else { | |
| 3747 | resolve_decl_var(g, tld_var, allow_lazy); | |
| 3415 | 3748 | } |
| 3749 | tld->resolution = allow_lazy ? TldResolutionOkLazy : TldResolutionOk; | |
| 3750 | break; | |
| 3751 | } | |
| 3752 | case TldIdFn: { | |
| 3753 | TldFn *tld_fn = (TldFn *)tld; | |
| 3754 | resolve_decl_fn(g, tld_fn); | |
| 3755 | ||
| 3756 | tld->resolution = TldResolutionOk; | |
| 3757 | break; | |
| 3758 | } | |
| 3759 | case TldIdContainer: { | |
| 3760 | TldContainer *tld_container = (TldContainer *)tld; | |
| 3761 | resolve_decl_container(g, tld_container); | |
| 3762 | ||
| 3763 | tld->resolution = TldResolutionOk; | |
| 3764 | break; | |
| 3765 | } | |
| 3766 | case TldIdCompTime: { | |
| 3767 | TldCompTime *tld_comptime = (TldCompTime *)tld; | |
| 3768 | resolve_decl_comptime(g, tld_comptime); | |
| 3769 | ||
| 3770 | tld->resolution = TldResolutionOk; | |
| 3771 | break; | |
| 3772 | } | |
| 3416 | 3773 | case TldIdUsingNamespace: { |
| 3417 | 3774 | TldUsingNamespace *tld_using_namespace = (TldUsingNamespace *)tld; |
| 3418 | 3775 | assert(tld_using_namespace->base.parent_scope->id == ScopeIdDecls); |
| 3419 | 3776 | ScopeDecls *dest_decls_scope = (ScopeDecls *)tld_using_namespace->base.parent_scope; |
| 3420 | 3777 | preview_use_decl(g, tld_using_namespace, dest_decls_scope); |
| 3421 | 3778 | resolve_use_decl(g, tld_using_namespace, dest_decls_scope); |
| 3779 | ||
| 3780 | tld->resolution = TldResolutionOk; | |
| 3422 | 3781 | break; |
| 3423 | 3782 | } |
| 3424 | 3783 | } |
| 3425 | 3784 | |
| 3426 | tld->resolution = TldResolutionOk; | |
| 3427 | g->tld_ref_source_node_stack.pop(); | |
| 3785 | if (g->trace_err != nullptr && source_node != nullptr && !source_node->already_traced_this_node) { | |
| 3786 | g->trace_err = add_error_note(g, g->trace_err, source_node, buf_create_from_str("referenced here")); | |
| 3787 | source_node->already_traced_this_node = true; | |
| 3788 | } | |
| 3428 | 3789 | } |
| 3429 | 3790 | |
| 3430 | 3791 | Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) { |
| ... | ... | @@ -3550,7 +3911,7 @@ TypeUnionField *find_union_field_by_tag(ZigType *type_entry, const BigInt *tag) |
| 3550 | 3911 | } |
| 3551 | 3912 | |
| 3552 | 3913 | TypeEnumField *find_enum_field_by_tag(ZigType *enum_type, const BigInt *tag) { |
| 3553 | assert(enum_type->data.enumeration.zero_bits_known); | |
| 3914 | assert(type_is_resolved(enum_type, ResolveStatusZeroBitsKnown)); | |
| 3554 | 3915 | for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) { |
| 3555 | 3916 | TypeEnumField *field = &enum_type->data.enumeration.fields[i]; |
| 3556 | 3917 | if (bigint_cmp(&field->value, tag) == CmpEQ) { |
| ... | ... | @@ -3619,43 +3980,6 @@ ZigType *container_ref_type(ZigType *type_entry) { |
| 3619 | 3980 | type_entry->data.pointer.child_type : type_entry; |
| 3620 | 3981 | } |
| 3621 | 3982 | |
| 3622 | Error resolve_container_type(CodeGen *g, ZigType *type_entry) { | |
| 3623 | switch (type_entry->id) { | |
| 3624 | case ZigTypeIdStruct: | |
| 3625 | return resolve_struct_type(g, type_entry); | |
| 3626 | case ZigTypeIdEnum: | |
| 3627 | return resolve_enum_zero_bits(g, type_entry); | |
| 3628 | case ZigTypeIdUnion: | |
| 3629 | return resolve_union_type(g, type_entry); | |
| 3630 | case ZigTypeIdPointer: | |
| 3631 | case ZigTypeIdMetaType: | |
| 3632 | case ZigTypeIdVoid: | |
| 3633 | case ZigTypeIdBool: | |
| 3634 | case ZigTypeIdUnreachable: | |
| 3635 | case ZigTypeIdInt: | |
| 3636 | case ZigTypeIdFloat: | |
| 3637 | case ZigTypeIdArray: | |
| 3638 | case ZigTypeIdComptimeFloat: | |
| 3639 | case ZigTypeIdComptimeInt: | |
| 3640 | case ZigTypeIdEnumLiteral: | |
| 3641 | case ZigTypeIdUndefined: | |
| 3642 | case ZigTypeIdNull: | |
| 3643 | case ZigTypeIdOptional: | |
| 3644 | case ZigTypeIdErrorUnion: | |
| 3645 | case ZigTypeIdErrorSet: | |
| 3646 | case ZigTypeIdFn: | |
| 3647 | case ZigTypeIdBoundFn: | |
| 3648 | case ZigTypeIdInvalid: | |
| 3649 | case ZigTypeIdArgTuple: | |
| 3650 | case ZigTypeIdOpaque: | |
| 3651 | case ZigTypeIdVector: | |
| 3652 | case ZigTypeIdFnFrame: | |
| 3653 | case ZigTypeIdAnyFrame: | |
| 3654 | zig_unreachable(); | |
| 3655 | } | |
| 3656 | zig_unreachable(); | |
| 3657 | } | |
| 3658 | ||
| 3659 | 3983 | ZigType *get_src_ptr_type(ZigType *type) { |
| 3660 | 3984 | if (type->id == ZigTypeIdPointer) return type; |
| 3661 | 3985 | if (type->id == ZigTypeIdFn) return type; |
| ... | ... | @@ -3791,6 +4115,13 @@ static void resolve_async_fn_frame(CodeGen *g, ZigFn *fn) { |
| 3791 | 4115 | ZigType *frame_type = get_fn_frame_type(g, fn); |
| 3792 | 4116 | Error err; |
| 3793 | 4117 | if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) { |
| 4118 | if (g->trace_err != nullptr && frame_type->data.frame.resolve_loop_src_node != nullptr && | |
| 4119 | !frame_type->data.frame.reported_loop_err) | |
| 4120 | { | |
| 4121 | frame_type->data.frame.reported_loop_err = true; | |
| 4122 | g->trace_err = add_error_note(g, g->trace_err, frame_type->data.frame.resolve_loop_src_node, | |
| 4123 | buf_sprintf("when analyzing type '%s' here", buf_ptr(&frame_type->name))); | |
| 4124 | } | |
| 3794 | 4125 | fn->anal_state = FnAnalStateInvalid; |
| 3795 | 4126 | return; |
| 3796 | 4127 | } |
| ... | ... | @@ -3906,7 +4237,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) { |
| 3906 | 4237 | &fn->analyzed_executable, fn_type_id->return_type, return_type_node); |
| 3907 | 4238 | fn->src_implicit_return_type = block_return_type; |
| 3908 | 4239 | |
| 3909 | if (type_is_invalid(block_return_type) || fn->analyzed_executable.invalid) { | |
| 4240 | if (type_is_invalid(block_return_type) || fn->analyzed_executable.first_err_trace_msg != nullptr) { | |
| 3910 | 4241 | assert(g->errors.length > 0); |
| 3911 | 4242 | fn->anal_state = FnAnalStateInvalid; |
| 3912 | 4243 | return; |
| ... | ... | @@ -3990,7 +4321,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { |
| 3990 | 4321 | assert(!fn_type->data.fn.is_generic); |
| 3991 | 4322 | |
| 3992 | 4323 | ir_gen_fn(g, fn_table_entry); |
| 3993 | if (fn_table_entry->ir_executable.invalid) { | |
| 4324 | if (fn_table_entry->ir_executable.first_err_trace_msg != nullptr) { | |
| 3994 | 4325 | fn_table_entry->anal_state = FnAnalStateInvalid; |
| 3995 | 4326 | return; |
| 3996 | 4327 | } |
| ... | ... | @@ -4128,12 +4459,14 @@ void semantic_analyze(CodeGen *g) { |
| 4128 | 4459 | { |
| 4129 | 4460 | for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) { |
| 4130 | 4461 | Tld *tld = g->resolve_queue.at(g->resolve_queue_index); |
| 4462 | g->trace_err = nullptr; | |
| 4131 | 4463 | AstNode *source_node = nullptr; |
| 4132 | resolve_top_level_decl(g, tld, source_node); | |
| 4464 | resolve_top_level_decl(g, tld, source_node, false); | |
| 4133 | 4465 | } |
| 4134 | 4466 | |
| 4135 | 4467 | for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { |
| 4136 | 4468 | ZigFn *fn_entry = g->fn_defs.at(g->fn_defs_index); |
| 4469 | g->trace_err = nullptr; | |
| 4137 | 4470 | analyze_fn_body(g, fn_entry); |
| 4138 | 4471 | } |
| 4139 | 4472 | } |
| ... | ... | @@ -4145,6 +4478,7 @@ void semantic_analyze(CodeGen *g) { |
| 4145 | 4478 | // second pass over functions for detecting async |
| 4146 | 4479 | for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { |
| 4147 | 4480 | ZigFn *fn = g->fn_defs.at(g->fn_defs_index); |
| 4481 | g->trace_err = nullptr; | |
| 4148 | 4482 | analyze_fn_async(g, fn, true); |
| 4149 | 4483 | if (fn_is_async(fn) && fn->non_async_node != nullptr) { |
| 4150 | 4484 | ErrorMsg *msg = add_node_error(g, fn->proto_node, |
| ... | ... | @@ -4790,7 +5124,10 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { |
| 4790 | 5124 | case ZigTypeIdStruct: |
| 4791 | 5125 | for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { |
| 4792 | 5126 | TypeStructField *field = &type_entry->data.structure.fields[i]; |
| 4793 | switch (type_has_one_possible_value(g, field->type_entry)) { | |
| 5127 | OnePossibleValue opv = (field->type_entry != nullptr) ? | |
| 5128 | type_has_one_possible_value(g, field->type_entry) : | |
| 5129 | type_val_resolve_has_one_possible_value(g, field->type_val); | |
| 5130 | switch (opv) { | |
| 4794 | 5131 | case OnePossibleValueInvalid: |
| 4795 | 5132 | return OnePossibleValueInvalid; |
| 4796 | 5133 | case OnePossibleValueNo: |
| ... | ... | @@ -4816,18 +5153,19 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { |
| 4816 | 5153 | case ZigTypeIdUnion: |
| 4817 | 5154 | if (type_entry->data.unionation.src_field_count > 1) |
| 4818 | 5155 | return OnePossibleValueNo; |
| 4819 | return type_has_one_possible_value(g, type_entry->data.unionation.fields[0].type_entry); | |
| 5156 | TypeUnionField *only_field = &type_entry->data.unionation.fields[0]; | |
| 5157 | if (only_field->type_entry != nullptr) { | |
| 5158 | return type_has_one_possible_value(g, only_field->type_entry); | |
| 5159 | } | |
| 5160 | return type_val_resolve_has_one_possible_value(g, only_field->type_val); | |
| 4820 | 5161 | } |
| 4821 | 5162 | zig_unreachable(); |
| 4822 | 5163 | } |
| 4823 | 5164 | |
| 4824 | ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { | |
| 5165 | ReqCompTime type_requires_comptime(CodeGen *g, ZigType *ty) { | |
| 4825 | 5166 | Error err; |
| 4826 | if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) | |
| 4827 | return ReqCompTimeInvalid; | |
| 4828 | switch (type_entry->id) { | |
| 5167 | switch (ty->id) { | |
| 4829 | 5168 | case ZigTypeIdInvalid: |
| 4830 | case ZigTypeIdOpaque: | |
| 4831 | 5169 | zig_unreachable(); |
| 4832 | 5170 | case ZigTypeIdComptimeFloat: |
| 4833 | 5171 | case ZigTypeIdComptimeInt: |
| ... | ... | @@ -4839,23 +5177,36 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { |
| 4839 | 5177 | case ZigTypeIdArgTuple: |
| 4840 | 5178 | return ReqCompTimeYes; |
| 4841 | 5179 | case ZigTypeIdArray: |
| 4842 | return type_requires_comptime(g, type_entry->data.array.child_type); | |
| 5180 | return type_requires_comptime(g, ty->data.array.child_type); | |
| 4843 | 5181 | case ZigTypeIdStruct: |
| 4844 | return type_entry->data.structure.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; | |
| 5182 | if (ty->data.structure.resolve_loop_flag_zero_bits) { | |
| 5183 | // Does a struct which contains a pointer field to itself require comptime? No. | |
| 5184 | return ReqCompTimeNo; | |
| 5185 | } | |
| 5186 | if ((err = type_resolve(g, ty, ResolveStatusZeroBitsKnown))) | |
| 5187 | return ReqCompTimeInvalid; | |
| 5188 | return ty->data.structure.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; | |
| 4845 | 5189 | case ZigTypeIdUnion: |
| 4846 | return type_entry->data.unionation.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; | |
| 5190 | if (ty->data.unionation.resolve_loop_flag_zero_bits) { | |
| 5191 | // Does a union which contains a pointer field to itself require comptime? No. | |
| 5192 | return ReqCompTimeNo; | |
| 5193 | } | |
| 5194 | if ((err = type_resolve(g, ty, ResolveStatusZeroBitsKnown))) | |
| 5195 | return ReqCompTimeInvalid; | |
| 5196 | return ty->data.unionation.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo; | |
| 4847 | 5197 | case ZigTypeIdOptional: |
| 4848 | return type_requires_comptime(g, type_entry->data.maybe.child_type); | |
| 5198 | return type_requires_comptime(g, ty->data.maybe.child_type); | |
| 4849 | 5199 | case ZigTypeIdErrorUnion: |
| 4850 | return type_requires_comptime(g, type_entry->data.error_union.payload_type); | |
| 5200 | return type_requires_comptime(g, ty->data.error_union.payload_type); | |
| 4851 | 5201 | case ZigTypeIdPointer: |
| 4852 | if (type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) { | |
| 5202 | if (ty->data.pointer.child_type->id == ZigTypeIdOpaque) { | |
| 4853 | 5203 | return ReqCompTimeNo; |
| 4854 | 5204 | } else { |
| 4855 | return type_requires_comptime(g, type_entry->data.pointer.child_type); | |
| 5205 | return type_requires_comptime(g, ty->data.pointer.child_type); | |
| 4856 | 5206 | } |
| 4857 | 5207 | case ZigTypeIdFn: |
| 4858 | return type_entry->data.fn.is_generic ? ReqCompTimeYes : ReqCompTimeNo; | |
| 5208 | return ty->data.fn.is_generic ? ReqCompTimeYes : ReqCompTimeNo; | |
| 5209 | case ZigTypeIdOpaque: | |
| 4859 | 5210 | case ZigTypeIdEnum: |
| 4860 | 5211 | case ZigTypeIdErrorSet: |
| 4861 | 5212 | case ZigTypeIdBool: |
| ... | ... | @@ -5143,34 +5494,6 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_ |
| 5143 | 5494 | } |
| 5144 | 5495 | |
| 5145 | 5496 | |
| 5146 | void init_const_undefined(CodeGen *g, ConstExprValue *const_val) { | |
| 5147 | Error err; | |
| 5148 | ZigType *wanted_type = const_val->type; | |
| 5149 | if (wanted_type->id == ZigTypeIdArray) { | |
| 5150 | const_val->special = ConstValSpecialStatic; | |
| 5151 | const_val->data.x_array.special = ConstArraySpecialUndef; | |
| 5152 | } else if (wanted_type->id == ZigTypeIdStruct) { | |
| 5153 | if ((err = ensure_complete_type(g, wanted_type))) { | |
| 5154 | return; | |
| 5155 | } | |
| 5156 | ||
| 5157 | const_val->special = ConstValSpecialStatic; | |
| 5158 | size_t field_count = wanted_type->data.structure.src_field_count; | |
| 5159 | const_val->data.x_struct.fields = create_const_vals(field_count); | |
| 5160 | for (size_t i = 0; i < field_count; i += 1) { | |
| 5161 | ConstExprValue *field_val = &const_val->data.x_struct.fields[i]; | |
| 5162 | field_val->type = wanted_type->data.structure.fields[i].type_entry; | |
| 5163 | assert(field_val->type); | |
| 5164 | init_const_undefined(g, field_val); | |
| 5165 | field_val->parent.id = ConstParentIdStruct; | |
| 5166 | field_val->parent.data.p_struct.struct_val = const_val; | |
| 5167 | field_val->parent.data.p_struct.field_index = i; | |
| 5168 | } | |
| 5169 | } else { | |
| 5170 | const_val->special = ConstValSpecialUndef; | |
| 5171 | } | |
| 5172 | } | |
| 5173 | ||
| 5174 | 5497 | ConstExprValue *create_const_vals(size_t count) { |
| 5175 | 5498 | ConstGlobalRefs *global_refs = allocate<ConstGlobalRefs>(count); |
| 5176 | 5499 | ConstExprValue *vals = allocate<ConstExprValue>(count); |
| ... | ... | @@ -5180,10 +5503,6 @@ ConstExprValue *create_const_vals(size_t count) { |
| 5180 | 5503 | return vals; |
| 5181 | 5504 | } |
| 5182 | 5505 | |
| 5183 | Error ensure_complete_type(CodeGen *g, ZigType *type_entry) { | |
| 5184 | return type_resolve(g, type_entry, ResolveStatusSizeKnown); | |
| 5185 | } | |
| 5186 | ||
| 5187 | 5506 | static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) { |
| 5188 | 5507 | if (orig_fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) |
| 5189 | 5508 | return orig_fn_type; |
| ... | ... | @@ -5197,27 +5516,6 @@ static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) { |
| 5197 | 5516 | return fn_type; |
| 5198 | 5517 | } |
| 5199 | 5518 | |
| 5200 | static void emit_error_notes_for_type_loop(CodeGen *g, ErrorMsg *msg, ZigType *stop_type, | |
| 5201 | ZigType *ty, AstNode *src_node) | |
| 5202 | { | |
| 5203 | ErrorMsg *note = add_error_note(g, msg, src_node, | |
| 5204 | buf_sprintf("when analyzing type '%s' here", buf_ptr(&ty->name))); | |
| 5205 | if (ty == stop_type) | |
| 5206 | return; | |
| 5207 | switch (ty->id) { | |
| 5208 | case ZigTypeIdFnFrame: { | |
| 5209 | ty->data.frame.reported_loop_err = true; | |
| 5210 | ZigType *depending_type = ty->data.frame.resolve_loop_type; | |
| 5211 | if (depending_type == nullptr) | |
| 5212 | return; | |
| 5213 | emit_error_notes_for_type_loop(g, note, stop_type, | |
| 5214 | depending_type, ty->data.frame.resolve_loop_src_node); | |
| 5215 | } | |
| 5216 | default: | |
| 5217 | return; | |
| 5218 | } | |
| 5219 | } | |
| 5220 | ||
| 5221 | 5519 | static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5222 | 5520 | Error err; |
| 5223 | 5521 | |
| ... | ... | @@ -5229,14 +5527,8 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5229 | 5527 | |
| 5230 | 5528 | if (frame_type->data.frame.resolve_loop_type != nullptr) { |
| 5231 | 5529 | if (!frame_type->data.frame.reported_loop_err) { |
| 5232 | frame_type->data.frame.reported_loop_err = true; | |
| 5233 | ErrorMsg *msg = add_node_error(g, fn->proto_node, | |
| 5530 | add_node_error(g, fn->proto_node, | |
| 5234 | 5531 | buf_sprintf("'%s' depends on itself", buf_ptr(&frame_type->name))); |
| 5235 | emit_error_notes_for_type_loop(g, msg, | |
| 5236 | frame_type, | |
| 5237 | frame_type->data.frame.resolve_loop_type, | |
| 5238 | frame_type->data.frame.resolve_loop_src_node); | |
| 5239 | emit_error_notes_for_ref_stack(g, msg); | |
| 5240 | 5532 | } |
| 5241 | 5533 | return ErrorSemanticAnalyzeFail; |
| 5242 | 5534 | } |
| ... | ... | @@ -5252,11 +5544,9 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5252 | 5544 | return ErrorSemanticAnalyzeFail; |
| 5253 | 5545 | break; |
| 5254 | 5546 | case FnAnalStateProbing: { |
| 5255 | ErrorMsg *msg = add_node_error(g, fn->proto_node, | |
| 5547 | add_node_error(g, fn->proto_node, | |
| 5256 | 5548 | buf_sprintf("cannot resolve '%s': function not fully analyzed yet", |
| 5257 | 5549 | buf_ptr(&frame_type->name))); |
| 5258 | ir_add_analysis_trace(fn->ir_executable.analysis, msg, | |
| 5259 | buf_sprintf("depends on its own frame here")); | |
| 5260 | 5550 | return ErrorSemanticAnalyzeFail; |
| 5261 | 5551 | } |
| 5262 | 5552 | } |
| ... | ... | @@ -5327,10 +5617,8 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5327 | 5617 | if (callee->anal_state == FnAnalStateProbing) { |
| 5328 | 5618 | ErrorMsg *msg = add_node_error(g, fn->proto_node, |
| 5329 | 5619 | buf_sprintf("unable to determine async function frame of '%s'", buf_ptr(&fn->symbol_name))); |
| 5330 | ErrorMsg *note = add_error_note(g, msg, call->base.source_node, | |
| 5620 | g->trace_err = add_error_note(g, msg, call->base.source_node, | |
| 5331 | 5621 | buf_sprintf("analysis of function '%s' depends on the frame", buf_ptr(&callee->symbol_name))); |
| 5332 | ir_add_analysis_trace(callee->ir_executable.analysis, note, | |
| 5333 | buf_sprintf("depends on the frame here")); | |
| 5334 | 5622 | return ErrorSemanticAnalyzeFail; |
| 5335 | 5623 | } |
| 5336 | 5624 | |
| ... | ... | @@ -5442,6 +5730,37 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5442 | 5730 | return ErrorNone; |
| 5443 | 5731 | } |
| 5444 | 5732 | |
| 5733 | static Error resolve_pointer_zero_bits(CodeGen *g, ZigType *ty) { | |
| 5734 | Error err; | |
| 5735 | ||
| 5736 | if (ty->abi_size != SIZE_MAX) | |
| 5737 | return ErrorNone; | |
| 5738 | ||
| 5739 | if (ty->data.pointer.resolve_loop_flag_zero_bits) { | |
| 5740 | ty->abi_size = g->builtin_types.entry_usize->abi_size; | |
| 5741 | ty->size_in_bits = g->builtin_types.entry_usize->size_in_bits; | |
| 5742 | ty->abi_align = g->builtin_types.entry_usize->abi_align; | |
| 5743 | return ErrorNone; | |
| 5744 | } | |
| 5745 | ty->data.pointer.resolve_loop_flag_zero_bits = true; | |
| 5746 | ||
| 5747 | ZigType *elem_type = ty->data.pointer.child_type; | |
| 5748 | ||
| 5749 | if ((err = type_resolve(g, elem_type, ResolveStatusZeroBitsKnown))) | |
| 5750 | return err; | |
| 5751 | ||
| 5752 | if (type_has_bits(elem_type)) { | |
| 5753 | ty->abi_size = g->builtin_types.entry_usize->abi_size; | |
| 5754 | ty->size_in_bits = g->builtin_types.entry_usize->size_in_bits; | |
| 5755 | ty->abi_align = g->builtin_types.entry_usize->abi_align; | |
| 5756 | } else { | |
| 5757 | ty->abi_size = 0; | |
| 5758 | ty->size_in_bits = 0; | |
| 5759 | ty->abi_align = 0; | |
| 5760 | } | |
| 5761 | return ErrorNone; | |
| 5762 | } | |
| 5763 | ||
| 5445 | 5764 | Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { |
| 5446 | 5765 | if (type_is_invalid(ty)) |
| 5447 | 5766 | return ErrorSemanticAnalyzeFail; |
| ... | ... | @@ -5451,36 +5770,48 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { |
| 5451 | 5770 | case ResolveStatusInvalid: |
| 5452 | 5771 | zig_unreachable(); |
| 5453 | 5772 | case ResolveStatusZeroBitsKnown: |
| 5454 | if (ty->id == ZigTypeIdStruct) { | |
| 5455 | return resolve_struct_zero_bits(g, ty); | |
| 5456 | } else if (ty->id == ZigTypeIdEnum) { | |
| 5457 | return resolve_enum_zero_bits(g, ty); | |
| 5458 | } else if (ty->id == ZigTypeIdUnion) { | |
| 5459 | return resolve_union_zero_bits(g, ty); | |
| 5773 | switch (ty->id) { | |
| 5774 | case ZigTypeIdStruct: | |
| 5775 | return resolve_struct_zero_bits(g, ty); | |
| 5776 | case ZigTypeIdEnum: | |
| 5777 | return resolve_enum_zero_bits(g, ty); | |
| 5778 | case ZigTypeIdUnion: | |
| 5779 | return resolve_union_zero_bits(g, ty); | |
| 5780 | case ZigTypeIdPointer: | |
| 5781 | return resolve_pointer_zero_bits(g, ty); | |
| 5782 | default: | |
| 5783 | return ErrorNone; | |
| 5460 | 5784 | } |
| 5461 | return ErrorNone; | |
| 5462 | 5785 | case ResolveStatusAlignmentKnown: |
| 5463 | if (ty->id == ZigTypeIdStruct) { | |
| 5464 | return resolve_struct_alignment(g, ty); | |
| 5465 | } else if (ty->id == ZigTypeIdEnum) { | |
| 5466 | return resolve_enum_zero_bits(g, ty); | |
| 5467 | } else if (ty->id == ZigTypeIdUnion) { | |
| 5468 | return resolve_union_alignment(g, ty); | |
| 5469 | } else if (ty->id == ZigTypeIdFnFrame) { | |
| 5470 | return resolve_async_frame(g, ty); | |
| 5786 | switch (ty->id) { | |
| 5787 | case ZigTypeIdStruct: | |
| 5788 | return resolve_struct_alignment(g, ty); | |
| 5789 | case ZigTypeIdEnum: | |
| 5790 | return resolve_enum_zero_bits(g, ty); | |
| 5791 | case ZigTypeIdUnion: | |
| 5792 | return resolve_union_alignment(g, ty); | |
| 5793 | case ZigTypeIdFnFrame: | |
| 5794 | return resolve_async_frame(g, ty); | |
| 5795 | case ZigTypeIdPointer: | |
| 5796 | return resolve_pointer_zero_bits(g, ty); | |
| 5797 | default: | |
| 5798 | return ErrorNone; | |
| 5471 | 5799 | } |
| 5472 | return ErrorNone; | |
| 5473 | 5800 | case ResolveStatusSizeKnown: |
| 5474 | if (ty->id == ZigTypeIdStruct) { | |
| 5475 | return resolve_struct_type(g, ty); | |
| 5476 | } else if (ty->id == ZigTypeIdEnum) { | |
| 5477 | return resolve_enum_zero_bits(g, ty); | |
| 5478 | } else if (ty->id == ZigTypeIdUnion) { | |
| 5479 | return resolve_union_type(g, ty); | |
| 5480 | } else if (ty->id == ZigTypeIdFnFrame) { | |
| 5481 | return resolve_async_frame(g, ty); | |
| 5801 | switch (ty->id) { | |
| 5802 | case ZigTypeIdStruct: | |
| 5803 | return resolve_struct_type(g, ty); | |
| 5804 | case ZigTypeIdEnum: | |
| 5805 | return resolve_enum_zero_bits(g, ty); | |
| 5806 | case ZigTypeIdUnion: | |
| 5807 | return resolve_union_type(g, ty); | |
| 5808 | case ZigTypeIdFnFrame: | |
| 5809 | return resolve_async_frame(g, ty); | |
| 5810 | case ZigTypeIdPointer: | |
| 5811 | return resolve_pointer_zero_bits(g, ty); | |
| 5812 | default: | |
| 5813 | return ErrorNone; | |
| 5482 | 5814 | } |
| 5483 | return ErrorNone; | |
| 5484 | 5815 | case ResolveStatusLLVMFwdDecl: |
| 5485 | 5816 | case ResolveStatusLLVMFull: |
| 5486 | 5817 | resolve_llvm_types(g, ty, status); |
| ... | ... | @@ -5855,6 +6186,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 5855 | 6186 | case ConstValSpecialRuntime: |
| 5856 | 6187 | buf_appendf(buf, "(runtime value)"); |
| 5857 | 6188 | return; |
| 6189 | case ConstValSpecialLazy: | |
| 6190 | buf_appendf(buf, "(lazy value)"); | |
| 6191 | return; | |
| 5858 | 6192 | case ConstValSpecialUndef: |
| 5859 | 6193 | buf_appendf(buf, "undefined"); |
| 5860 | 6194 | return; |
| ... | ... | @@ -5976,7 +6310,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 5976 | 6310 | { |
| 5977 | 6311 | if (is_slice(type_entry)) { |
| 5978 | 6312 | ConstExprValue *len_val = &const_val->data.x_struct.fields[slice_len_index]; |
| 5979 | size_t len = bigint_as_unsigned(&len_val->data.x_bigint); | |
| 6313 | size_t len = bigint_as_usize(&len_val->data.x_bigint); | |
| 5980 | 6314 | |
| 5981 | 6315 | ConstExprValue *ptr_val = &const_val->data.x_struct.fields[slice_ptr_index]; |
| 5982 | 6316 | if (ptr_val->special == ConstValSpecialUndef) { |
| ... | ... | @@ -6051,12 +6385,12 @@ ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { |
| 6051 | 6385 | entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type); |
| 6052 | 6386 | entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type); |
| 6053 | 6387 | |
| 6054 | if (size_in_bits >= 128) { | |
| 6388 | if (size_in_bits >= 128 && entry->abi_align < 16) { | |
| 6055 | 6389 | // Override the incorrect alignment reported by LLVM. Clang does this as well. |
| 6056 | 6390 | // On x86_64 there are some instructions like CMPXCHG16B which require this. |
| 6057 | 6391 | // On all targets, integers 128 bits and above have ABI alignment of 16. |
| 6392 | // However for some targets, LLVM incorrectly reports this as 8. | |
| 6058 | 6393 | // See: https://github.com/ziglang/zig/issues/2987 |
| 6059 | assert(entry->abi_align == 8); // if this trips we can remove the workaround | |
| 6060 | 6394 | entry->abi_align = 16; |
| 6061 | 6395 | } |
| 6062 | 6396 | } |
| ... | ... | @@ -6229,6 +6563,40 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { |
| 6229 | 6563 | zig_unreachable(); |
| 6230 | 6564 | } |
| 6231 | 6565 | |
| 6566 | static void init_const_undefined(CodeGen *g, ConstExprValue *const_val) { | |
| 6567 | Error err; | |
| 6568 | ZigType *wanted_type = const_val->type; | |
| 6569 | if (wanted_type->id == ZigTypeIdArray) { | |
| 6570 | const_val->special = ConstValSpecialStatic; | |
| 6571 | const_val->data.x_array.special = ConstArraySpecialUndef; | |
| 6572 | } else if (wanted_type->id == ZigTypeIdStruct) { | |
| 6573 | if ((err = type_resolve(g, wanted_type, ResolveStatusZeroBitsKnown))) { | |
| 6574 | return; | |
| 6575 | } | |
| 6576 | ||
| 6577 | const_val->special = ConstValSpecialStatic; | |
| 6578 | size_t field_count = wanted_type->data.structure.src_field_count; | |
| 6579 | const_val->data.x_struct.fields = create_const_vals(field_count); | |
| 6580 | for (size_t i = 0; i < field_count; i += 1) { | |
| 6581 | ConstExprValue *field_val = &const_val->data.x_struct.fields[i]; | |
| 6582 | field_val->type = wanted_type->data.structure.fields[i].type_entry; | |
| 6583 | assert(field_val->type); | |
| 6584 | init_const_undefined(g, field_val); | |
| 6585 | field_val->parent.id = ConstParentIdStruct; | |
| 6586 | field_val->parent.data.p_struct.struct_val = const_val; | |
| 6587 | field_val->parent.data.p_struct.field_index = i; | |
| 6588 | } | |
| 6589 | } else { | |
| 6590 | const_val->special = ConstValSpecialUndef; | |
| 6591 | } | |
| 6592 | } | |
| 6593 | ||
| 6594 | void expand_undef_struct(CodeGen *g, ConstExprValue *const_val) { | |
| 6595 | if (const_val->special == ConstValSpecialUndef) { | |
| 6596 | init_const_undefined(g, const_val); | |
| 6597 | } | |
| 6598 | } | |
| 6599 | ||
| 6232 | 6600 | // Canonicalize the array value as ConstArraySpecialNone |
| 6233 | 6601 | void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { |
| 6234 | 6602 | size_t elem_count; |
| ... | ... | @@ -6492,7 +6860,7 @@ bool type_ptr_eql(const ZigType *a, const ZigType *b) { |
| 6492 | 6860 | |
| 6493 | 6861 | ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { |
| 6494 | 6862 | Tld *tld = get_container_scope(codegen->compile_var_import)->decl_table.get(buf_create_from_str(name)); |
| 6495 | resolve_top_level_decl(codegen, tld, nullptr); | |
| 6863 | resolve_top_level_decl(codegen, tld, nullptr, false); | |
| 6496 | 6864 | assert(tld->id == TldIdVar); |
| 6497 | 6865 | TldVar *tld_var = (TldVar *)tld; |
| 6498 | 6866 | ConstExprValue *var_value = tld_var->var->const_value; |
| ... | ... | @@ -6707,19 +7075,6 @@ bool ptr_allows_addr_zero(ZigType *ptr_type) { |
| 6707 | 7075 | return false; |
| 6708 | 7076 | } |
| 6709 | 7077 | |
| 6710 | void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg) { | |
| 6711 | size_t i = g->tld_ref_source_node_stack.length; | |
| 6712 | for (;;) { | |
| 6713 | if (i == 0) | |
| 6714 | break; | |
| 6715 | i -= 1; | |
| 6716 | AstNode *source_node = g->tld_ref_source_node_stack.at(i); | |
| 6717 | if (source_node) { | |
| 6718 | msg = add_error_note(g, msg, source_node, buf_sprintf("referenced here")); | |
| 6719 | } | |
| 6720 | } | |
| 6721 | } | |
| 6722 | ||
| 6723 | 7078 | Buf *type_bare_name(ZigType *type_entry) { |
| 6724 | 7079 | if (is_slice(type_entry)) { |
| 6725 | 7080 | return &type_entry->name; |
| ... | ... | @@ -7122,10 +7477,9 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS |
| 7122 | 7477 | struct_type->data.structure.resolve_status = ResolveStatusLLVMFull; |
| 7123 | 7478 | } |
| 7124 | 7479 | |
| 7125 | static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type) { | |
| 7126 | assert(!enum_type->data.enumeration.is_invalid); | |
| 7127 | assert(enum_type->data.enumeration.complete); | |
| 7128 | if (enum_type->llvm_di_type != nullptr) return; | |
| 7480 | static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatus wanted_resolve_status) { | |
| 7481 | assert(enum_type->data.enumeration.resolve_status >= ResolveStatusSizeKnown); | |
| 7482 | if (enum_type->data.enumeration.resolve_status >= wanted_resolve_status) return; | |
| 7129 | 7483 | |
| 7130 | 7484 | Scope *scope = &enum_type->data.enumeration.decls_scope->base; |
| 7131 | 7485 | ZigType *import = get_scope_import(scope); |
| ... | ... | @@ -7146,6 +7500,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type) { |
| 7146 | 7500 | debug_align_in_bits, |
| 7147 | 7501 | ZigLLVM_DIFlags_Zero, |
| 7148 | 7502 | nullptr, di_element_types, (int)debug_field_count, 0, nullptr, ""); |
| 7503 | enum_type->data.enumeration.resolve_status = ResolveStatusLLVMFull; | |
| 7149 | 7504 | return; |
| 7150 | 7505 | } |
| 7151 | 7506 | |
| ... | ... | @@ -7178,14 +7533,16 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type) { |
| 7178 | 7533 | get_llvm_di_type(g, tag_int_type), ""); |
| 7179 | 7534 | |
| 7180 | 7535 | enum_type->llvm_di_type = tag_di_type; |
| 7536 | enum_type->data.enumeration.resolve_status = ResolveStatusLLVMFull; | |
| 7181 | 7537 | } |
| 7182 | 7538 | |
| 7183 | 7539 | static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveStatus wanted_resolve_status) { |
| 7184 | 7540 | if (union_type->data.unionation.resolve_status >= wanted_resolve_status) return; |
| 7185 | 7541 | |
| 7186 | ZigType *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; | |
| 7542 | TypeUnionField *most_aligned_union_member = union_type->data.unionation.most_aligned_union_member; | |
| 7187 | 7543 | ZigType *tag_type = union_type->data.unionation.tag_type; |
| 7188 | if (most_aligned_union_member == nullptr) { | |
| 7544 | uint32_t gen_field_count = union_type->data.unionation.gen_field_count; | |
| 7545 | if (gen_field_count == 0) { | |
| 7189 | 7546 | union_type->llvm_type = get_llvm_type(g, tag_type); |
| 7190 | 7547 | union_type->llvm_di_type = get_llvm_di_type(g, tag_type); |
| 7191 | 7548 | union_type->data.unionation.resolve_status = ResolveStatusLLVMFull; |
| ... | ... | @@ -7209,7 +7566,6 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 7209 | 7566 | if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return; |
| 7210 | 7567 | } |
| 7211 | 7568 | |
| 7212 | uint32_t gen_field_count = union_type->data.unionation.gen_field_count; | |
| 7213 | 7569 | ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(gen_field_count); |
| 7214 | 7570 | uint32_t field_count = union_type->data.unionation.src_field_count; |
| 7215 | 7571 | for (uint32_t i = 0; i < field_count; i += 1) { |
| ... | ... | @@ -7236,17 +7592,17 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 7236 | 7592 | if (tag_type == nullptr || !type_has_bits(tag_type)) { |
| 7237 | 7593 | assert(most_aligned_union_member != nullptr); |
| 7238 | 7594 | |
| 7239 | size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->abi_size; | |
| 7595 | size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->type_entry->abi_size; | |
| 7240 | 7596 | if (padding_bytes > 0) { |
| 7241 | 7597 | ZigType *u8_type = get_int_type(g, false, 8); |
| 7242 | 7598 | ZigType *padding_array = get_array_type(g, u8_type, padding_bytes); |
| 7243 | 7599 | LLVMTypeRef union_element_types[] = { |
| 7244 | most_aligned_union_member->llvm_type, | |
| 7600 | most_aligned_union_member->type_entry->llvm_type, | |
| 7245 | 7601 | get_llvm_type(g, padding_array), |
| 7246 | 7602 | }; |
| 7247 | 7603 | LLVMStructSetBody(union_type->llvm_type, union_element_types, 2, false); |
| 7248 | 7604 | } else { |
| 7249 | LLVMStructSetBody(union_type->llvm_type, &most_aligned_union_member->llvm_type, 1, false); | |
| 7605 | LLVMStructSetBody(union_type->llvm_type, &most_aligned_union_member->type_entry->llvm_type, 1, false); | |
| 7250 | 7606 | } |
| 7251 | 7607 | union_type->data.unionation.union_llvm_type = union_type->llvm_type; |
| 7252 | 7608 | union_type->data.unionation.gen_tag_index = SIZE_MAX; |
| ... | ... | @@ -7257,7 +7613,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 7257 | 7613 | ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&union_type->name), |
| 7258 | 7614 | import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), |
| 7259 | 7615 | union_type->data.unionation.union_abi_size * 8, |
| 7260 | most_aligned_union_member->abi_align * 8, | |
| 7616 | most_aligned_union_member->align * 8, | |
| 7261 | 7617 | ZigLLVM_DIFlags_Zero, union_inner_di_types, |
| 7262 | 7618 | gen_field_count, 0, ""); |
| 7263 | 7619 | |
| ... | ... | @@ -7268,14 +7624,14 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 7268 | 7624 | } |
| 7269 | 7625 | |
| 7270 | 7626 | LLVMTypeRef union_type_ref; |
| 7271 | size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->abi_size; | |
| 7627 | size_t padding_bytes = union_type->data.unionation.union_abi_size - most_aligned_union_member->type_entry->abi_size; | |
| 7272 | 7628 | if (padding_bytes == 0) { |
| 7273 | union_type_ref = get_llvm_type(g, most_aligned_union_member); | |
| 7629 | union_type_ref = get_llvm_type(g, most_aligned_union_member->type_entry); | |
| 7274 | 7630 | } else { |
| 7275 | 7631 | ZigType *u8_type = get_int_type(g, false, 8); |
| 7276 | 7632 | ZigType *padding_array = get_array_type(g, u8_type, padding_bytes); |
| 7277 | 7633 | LLVMTypeRef union_element_types[] = { |
| 7278 | get_llvm_type(g, most_aligned_union_member), | |
| 7634 | get_llvm_type(g, most_aligned_union_member->type_entry), | |
| 7279 | 7635 | get_llvm_type(g, padding_array), |
| 7280 | 7636 | }; |
| 7281 | 7637 | union_type_ref = LLVMStructType(union_element_types, 2, false); |
| ... | ... | @@ -7291,7 +7647,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 7291 | 7647 | ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, |
| 7292 | 7648 | ZigLLVMTypeToScope(union_type->llvm_di_type), "AnonUnion", |
| 7293 | 7649 | import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), |
| 7294 | most_aligned_union_member->size_in_bits, 8*most_aligned_union_member->abi_align, | |
| 7650 | most_aligned_union_member->type_entry->size_in_bits, 8*most_aligned_union_member->align, | |
| 7295 | 7651 | ZigLLVM_DIFlags_Zero, union_inner_di_types, gen_field_count, 0, ""); |
| 7296 | 7652 | |
| 7297 | 7653 | uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->llvm_type, |
| ... | ... | @@ -7302,8 +7658,8 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 7302 | 7658 | ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, |
| 7303 | 7659 | ZigLLVMTypeToScope(union_type->llvm_di_type), "payload", |
| 7304 | 7660 | import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), |
| 7305 | most_aligned_union_member->size_in_bits, | |
| 7306 | 8*most_aligned_union_member->abi_align, | |
| 7661 | most_aligned_union_member->type_entry->size_in_bits, | |
| 7662 | 8*most_aligned_union_member->align, | |
| 7307 | 7663 | union_offset_in_bits, |
| 7308 | 7664 | ZigLLVM_DIFlags_Zero, union_di_type); |
| 7309 | 7665 | |
| ... | ... | @@ -7340,6 +7696,9 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 7340 | 7696 | static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { |
| 7341 | 7697 | if (type->llvm_di_type != nullptr) return; |
| 7342 | 7698 | |
| 7699 | if (resolve_pointer_zero_bits(g, type) != ErrorNone) | |
| 7700 | zig_unreachable(); | |
| 7701 | ||
| 7343 | 7702 | if (!type_has_bits(type)) { |
| 7344 | 7703 | type->llvm_type = g->builtin_types.entry_void->llvm_type; |
| 7345 | 7704 | type->llvm_di_type = g->builtin_types.entry_void->llvm_di_type; |
| ... | ... | @@ -7406,8 +7765,11 @@ static void resolve_llvm_types_integer(CodeGen *g, ZigType *type) { |
| 7406 | 7765 | type->llvm_type = LLVMIntType(type->size_in_bits); |
| 7407 | 7766 | } |
| 7408 | 7767 | |
| 7409 | static void resolve_llvm_types_optional(CodeGen *g, ZigType *type) { | |
| 7410 | if (type->llvm_di_type != nullptr) return; | |
| 7768 | static void resolve_llvm_types_optional(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { | |
| 7769 | assert(type->id == ZigTypeIdOptional); | |
| 7770 | assert(type->data.maybe.resolve_status != ResolveStatusInvalid); | |
| 7771 | assert(type->data.maybe.resolve_status >= ResolveStatusSizeKnown); | |
| 7772 | if (type->data.maybe.resolve_status >= wanted_resolve_status) return; | |
| 7411 | 7773 | |
| 7412 | 7774 | LLVMTypeRef bool_llvm_type = get_llvm_type(g, g->builtin_types.entry_bool); |
| 7413 | 7775 | ZigLLVMDIType *bool_llvm_di_type = get_llvm_di_type(g, g->builtin_types.entry_bool); |
| ... | ... | @@ -7416,30 +7778,41 @@ static void resolve_llvm_types_optional(CodeGen *g, ZigType *type) { |
| 7416 | 7778 | if (!type_has_bits(child_type)) { |
| 7417 | 7779 | type->llvm_type = bool_llvm_type; |
| 7418 | 7780 | type->llvm_di_type = bool_llvm_di_type; |
| 7781 | type->data.maybe.resolve_status = ResolveStatusLLVMFull; | |
| 7419 | 7782 | return; |
| 7420 | 7783 | } |
| 7421 | 7784 | |
| 7422 | LLVMTypeRef child_llvm_type = get_llvm_type(g, child_type); | |
| 7423 | ZigLLVMDIType *child_llvm_di_type = get_llvm_di_type(g, child_type); | |
| 7424 | ||
| 7425 | 7785 | if (type_is_nonnull_ptr(child_type) || child_type->id == ZigTypeIdErrorSet) { |
| 7426 | type->llvm_type = child_llvm_type; | |
| 7427 | type->llvm_di_type = child_llvm_di_type; | |
| 7786 | type->llvm_type = get_llvm_type(g, child_type); | |
| 7787 | type->llvm_di_type = get_llvm_di_type(g, child_type); | |
| 7788 | type->data.maybe.resolve_status = ResolveStatusLLVMFull; | |
| 7428 | 7789 | return; |
| 7429 | 7790 | } |
| 7430 | 7791 | |
| 7792 | ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit); | |
| 7793 | ZigLLVMDIFile *di_file = nullptr; | |
| 7794 | unsigned line = 0; | |
| 7795 | ||
| 7796 | if (type->data.maybe.resolve_status < ResolveStatusLLVMFwdDecl) { | |
| 7797 | type->llvm_type = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&type->name)); | |
| 7798 | unsigned dwarf_kind = ZigLLVMTag_DW_structure_type(); | |
| 7799 | type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, | |
| 7800 | dwarf_kind, buf_ptr(&type->name), | |
| 7801 | compile_unit_scope, di_file, line); | |
| 7802 | ||
| 7803 | type->data.maybe.resolve_status = ResolveStatusLLVMFwdDecl; | |
| 7804 | if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return; | |
| 7805 | } | |
| 7806 | ||
| 7807 | LLVMTypeRef child_llvm_type = get_llvm_type(g, child_type); | |
| 7808 | ZigLLVMDIType *child_llvm_di_type = get_llvm_di_type(g, child_type); | |
| 7809 | if (type->data.maybe.resolve_status >= wanted_resolve_status) return; | |
| 7810 | ||
| 7431 | 7811 | LLVMTypeRef elem_types[] = { |
| 7432 | 7812 | get_llvm_type(g, child_type), |
| 7433 | 7813 | LLVMInt1Type(), |
| 7434 | 7814 | }; |
| 7435 | type->llvm_type = LLVMStructType(elem_types, 2, false); | |
| 7436 | ||
| 7437 | ZigLLVMDIScope *compile_unit_scope = ZigLLVMCompileUnitToScope(g->compile_unit); | |
| 7438 | ZigLLVMDIFile *di_file = nullptr; | |
| 7439 | unsigned line = 0; | |
| 7440 | type->llvm_di_type = ZigLLVMCreateReplaceableCompositeType(g->dbuilder, | |
| 7441 | ZigLLVMTag_DW_structure_type(), buf_ptr(&type->name), | |
| 7442 | compile_unit_scope, di_file, line); | |
| 7815 | LLVMStructSetBody(type->llvm_type, elem_types, 2, false); | |
| 7443 | 7816 | |
| 7444 | 7817 | uint64_t val_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, child_llvm_type); |
| 7445 | 7818 | uint64_t val_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, child_llvm_type); |
| ... | ... | @@ -7474,6 +7847,7 @@ static void resolve_llvm_types_optional(CodeGen *g, ZigType *type) { |
| 7474 | 7847 | |
| 7475 | 7848 | ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type); |
| 7476 | 7849 | type->llvm_di_type = replacement_di_type; |
| 7850 | type->data.maybe.resolve_status = ResolveStatusLLVMFull; | |
| 7477 | 7851 | } |
| 7478 | 7852 | |
| 7479 | 7853 | static void resolve_llvm_types_error_union(CodeGen *g, ZigType *type) { |
| ... | ... | @@ -7909,7 +8283,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r |
| 7909 | 8283 | else |
| 7910 | 8284 | return resolve_llvm_types_struct(g, type, wanted_resolve_status, nullptr); |
| 7911 | 8285 | case ZigTypeIdEnum: |
| 7912 | return resolve_llvm_types_enum(g, type); | |
| 8286 | return resolve_llvm_types_enum(g, type, wanted_resolve_status); | |
| 7913 | 8287 | case ZigTypeIdUnion: |
| 7914 | 8288 | return resolve_llvm_types_union(g, type, wanted_resolve_status); |
| 7915 | 8289 | case ZigTypeIdPointer: |
| ... | ... | @@ -7917,7 +8291,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r |
| 7917 | 8291 | case ZigTypeIdInt: |
| 7918 | 8292 | return resolve_llvm_types_integer(g, type); |
| 7919 | 8293 | case ZigTypeIdOptional: |
| 7920 | return resolve_llvm_types_optional(g, type); | |
| 8294 | return resolve_llvm_types_optional(g, type, wanted_resolve_status); | |
| 7921 | 8295 | case ZigTypeIdErrorUnion: |
| 7922 | 8296 | return resolve_llvm_types_error_union(g, type); |
| 7923 | 8297 | case ZigTypeIdArray: |
src/analyze.hpp+9-8| ... | ... | @@ -11,10 +11,9 @@ |
| 11 | 11 | #include "all_types.hpp" |
| 12 | 12 | |
| 13 | 13 | void semantic_analyze(CodeGen *g); |
| 14 | ErrorMsg *add_node_error(CodeGen *g, const AstNode *node, Buf *msg); | |
| 14 | ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg); | |
| 15 | 15 | ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg); |
| 16 | 16 | ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg); |
| 17 | void emit_error_notes_for_ref_stack(CodeGen *g, ErrorMsg *msg); | |
| 18 | 17 | ZigType *new_type_table_entry(ZigTypeId id); |
| 19 | 18 | ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn); |
| 20 | 19 | ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const); |
| ... | ... | @@ -59,7 +58,7 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *abs_full_path, Bu |
| 59 | 58 | ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name, ScopeFnDef **crossed_fndef_scope); |
| 60 | 59 | Tld *find_decl(CodeGen *g, Scope *scope, Buf *name); |
| 61 | 60 | Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name); |
| 62 | void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node); | |
| 61 | void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool allow_lazy); | |
| 63 | 62 | |
| 64 | 63 | ZigType *get_src_ptr_type(ZigType *type); |
| 65 | 64 | ZigType *get_codegen_ptr_type(ZigType *type); |
| ... | ... | @@ -71,7 +70,6 @@ bool type_is_complete(ZigType *type_entry); |
| 71 | 70 | bool type_is_resolved(ZigType *type_entry, ResolveStatus status); |
| 72 | 71 | bool type_is_invalid(ZigType *type_entry); |
| 73 | 72 | bool type_is_global_error_set(ZigType *err_set_type); |
| 74 | Error resolve_container_type(CodeGen *g, ZigType *type_entry); | |
| 75 | 73 | ScopeDecls *get_container_scope(ZigType *type_entry); |
| 76 | 74 | TypeStructField *find_struct_type_field(ZigType *type_entry, Buf *name); |
| 77 | 75 | TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name); |
| ... | ... | @@ -95,7 +93,6 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node); |
| 95 | 93 | ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value); |
| 96 | 94 | void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_count_alloc); |
| 97 | 95 | AstNode *get_param_decl_node(ZigFn *fn_entry, size_t index); |
| 98 | Error ATTRIBUTE_MUST_USE ensure_complete_type(CodeGen *g, ZigType *type_entry); | |
| 99 | 96 | Error ATTRIBUTE_MUST_USE type_resolve(CodeGen *g, ZigType *type_entry, ResolveStatus status); |
| 100 | 97 | void complete_enum(CodeGen *g, ZigType *enum_type); |
| 101 | 98 | bool ir_get_var_is_comptime(ZigVar *var); |
| ... | ... | @@ -169,12 +166,11 @@ ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t |
| 169 | 166 | void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_index_start, size_t arg_index_end); |
| 170 | 167 | ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_t arg_index_end); |
| 171 | 168 | |
| 172 | void init_const_undefined(CodeGen *g, ConstExprValue *const_val); | |
| 173 | ||
| 174 | 169 | ConstExprValue *create_const_vals(size_t count); |
| 175 | 170 | |
| 176 | 171 | ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); |
| 177 | 172 | void expand_undef_array(CodeGen *g, ConstExprValue *const_val); |
| 173 | void expand_undef_struct(CodeGen *g, ConstExprValue *const_val); | |
| 178 | 174 | void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value); |
| 179 | 175 | |
| 180 | 176 | const char *type_id_name(ZigTypeId id); |
| ... | ... | @@ -244,9 +240,14 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa |
| 244 | 240 | |
| 245 | 241 | void src_assert(bool ok, AstNode *source_node); |
| 246 | 242 | bool is_container(ZigType *type_entry); |
| 247 | ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, Buf *type_name); | |
| 243 | ConstExprValue *analyze_const_value(CodeGen *g, Scope *scope, AstNode *node, ZigType *type_entry, | |
| 244 | Buf *type_name, UndefAllowed undef); | |
| 248 | 245 | |
| 249 | 246 | void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn); |
| 250 | 247 | bool fn_is_async(ZigFn *fn); |
| 251 | 248 | |
| 249 | Error type_val_resolve_abi_align(CodeGen *g, ConstExprValue *type_val, uint32_t *abi_align); | |
| 250 | ZigType *resolve_union_field_type(CodeGen *g, TypeUnionField *union_field); | |
| 251 | ZigType *resolve_struct_field_type(CodeGen *g, TypeStructField *struct_field); | |
| 252 | ||
| 252 | 253 | #endif |
src/bigint.cpp+22-1| ... | ... | @@ -15,6 +15,8 @@ |
| 15 | 15 | #include <limits> |
| 16 | 16 | #include <algorithm> |
| 17 | 17 | |
| 18 | static uint64_t bigint_as_unsigned(const BigInt *bigint); | |
| 19 | ||
| 18 | 20 | static void bigint_normalize(BigInt *dest) { |
| 19 | 21 | const uint64_t *digits = bigint_ptr(dest); |
| 20 | 22 | |
| ... | ... | @@ -1660,7 +1662,7 @@ size_t bigint_clz(const BigInt *bi, size_t bit_count) { |
| 1660 | 1662 | return count; |
| 1661 | 1663 | } |
| 1662 | 1664 | |
| 1663 | uint64_t bigint_as_unsigned(const BigInt *bigint) { | |
| 1665 | static uint64_t bigint_as_unsigned(const BigInt *bigint) { | |
| 1664 | 1666 | assert(!bigint->is_negative); |
| 1665 | 1667 | if (bigint->digit_count == 0) { |
| 1666 | 1668 | return 0; |
| ... | ... | @@ -1671,6 +1673,25 @@ uint64_t bigint_as_unsigned(const BigInt *bigint) { |
| 1671 | 1673 | } |
| 1672 | 1674 | } |
| 1673 | 1675 | |
| 1676 | uint64_t bigint_as_u64(const BigInt *bigint) | |
| 1677 | { | |
| 1678 | return bigint_as_unsigned(bigint); | |
| 1679 | } | |
| 1680 | ||
| 1681 | uint32_t bigint_as_u32(const BigInt *bigint) { | |
| 1682 | uint64_t value64 = bigint_as_unsigned(bigint); | |
| 1683 | uint32_t value32 = (uint32_t)value64; | |
| 1684 | assert (value64 == value32); | |
| 1685 | return value32; | |
| 1686 | } | |
| 1687 | ||
| 1688 | size_t bigint_as_usize(const BigInt *bigint) { | |
| 1689 | uint64_t value64 = bigint_as_unsigned(bigint); | |
| 1690 | size_t valueUsize = (size_t)value64; | |
| 1691 | assert (value64 == valueUsize); | |
| 1692 | return valueUsize; | |
| 1693 | } | |
| 1694 | ||
| 1674 | 1695 | int64_t bigint_as_signed(const BigInt *bigint) { |
| 1675 | 1696 | if (bigint->digit_count == 0) { |
| 1676 | 1697 | return 0; |
src/bigint.hpp+4-1| ... | ... | @@ -36,7 +36,10 @@ void bigint_init_bigfloat(BigInt *dest, const BigFloat *op); |
| 36 | 36 | void bigint_init_data(BigInt *dest, const uint64_t *digits, size_t digit_count, bool is_negative); |
| 37 | 37 | |
| 38 | 38 | // panics if number won't fit |
| 39 | uint64_t bigint_as_unsigned(const BigInt *bigint); | |
| 39 | uint64_t bigint_as_u64(const BigInt *bigint); | |
| 40 | uint32_t bigint_as_u32(const BigInt *bigint); | |
| 41 | size_t bigint_as_usize(const BigInt *bigint); | |
| 42 | ||
| 40 | 43 | int64_t bigint_as_signed(const BigInt *bigint); |
| 41 | 44 | |
| 42 | 45 | static inline const uint64_t *bigint_ptr(const BigInt *bigint) { |
src/codegen.cpp+28-13| ... | ... | @@ -2872,7 +2872,7 @@ static void add_error_range_check(CodeGen *g, ZigType *err_set_type, ZigType *in |
| 2872 | 2872 | eval_min_max_value_int(g, int_type, &biggest_possible_err_val, true); |
| 2873 | 2873 | |
| 2874 | 2874 | if (bigint_fits_in_bits(&biggest_possible_err_val, 64, false) && |
| 2875 | bigint_as_unsigned(&biggest_possible_err_val) < g->errors_by_index.length) | |
| 2875 | bigint_as_usize(&biggest_possible_err_val) < g->errors_by_index.length) | |
| 2876 | 2876 | { |
| 2877 | 2877 | ok_bit = neq_zero_bit; |
| 2878 | 2878 | } else { |
| ... | ... | @@ -3052,8 +3052,10 @@ static LLVMValueRef ir_render_ptr_of_array_to_slice(CodeGen *g, IrExecutable *ex |
| 3052 | 3052 | IrInstructionPtrOfArrayToSlice *instruction) |
| 3053 | 3053 | { |
| 3054 | 3054 | ZigType *actual_type = instruction->operand->value.type; |
| 3055 | LLVMValueRef expr_val = ir_llvm_value(g, instruction->operand); | |
| 3056 | assert(expr_val); | |
| 3055 | ZigType *slice_type = instruction->base.value.type; | |
| 3056 | ZigType *slice_ptr_type = slice_type->data.structure.fields[slice_ptr_index].type_entry; | |
| 3057 | size_t ptr_index = slice_type->data.structure.fields[slice_ptr_index].gen_index; | |
| 3058 | size_t len_index = slice_type->data.structure.fields[slice_len_index].gen_index; | |
| 3057 | 3059 | |
| 3058 | 3060 | LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); |
| 3059 | 3061 | |
| ... | ... | @@ -3061,15 +3063,21 @@ static LLVMValueRef ir_render_ptr_of_array_to_slice(CodeGen *g, IrExecutable *ex |
| 3061 | 3063 | ZigType *array_type = actual_type->data.pointer.child_type; |
| 3062 | 3064 | assert(array_type->id == ZigTypeIdArray); |
| 3063 | 3065 | |
| 3064 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, slice_ptr_index, ""); | |
| 3065 | LLVMValueRef indices[] = { | |
| 3066 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), | |
| 3067 | LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 0, false), | |
| 3068 | }; | |
| 3069 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, ""); | |
| 3070 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | |
| 3066 | if (type_has_bits(actual_type)) { | |
| 3067 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, ptr_index, ""); | |
| 3068 | LLVMValueRef indices[] = { | |
| 3069 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), | |
| 3070 | LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 0, false), | |
| 3071 | }; | |
| 3072 | LLVMValueRef expr_val = ir_llvm_value(g, instruction->operand); | |
| 3073 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, ""); | |
| 3074 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | |
| 3075 | } else if (ir_want_runtime_safety(g, &instruction->base)) { | |
| 3076 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, ptr_index, ""); | |
| 3077 | gen_undef_init(g, slice_ptr_type->abi_align, slice_ptr_type, ptr_field_ptr); | |
| 3078 | } | |
| 3071 | 3079 | |
| 3072 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, slice_len_index, ""); | |
| 3080 | LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, len_index, ""); | |
| 3073 | 3081 | LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, |
| 3074 | 3082 | array_type->data.array.len, false); |
| 3075 | 3083 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); |
| ... | ... | @@ -3386,6 +3394,8 @@ static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) { |
| 3386 | 3394 | |
| 3387 | 3395 | static bool value_is_all_undef(ConstExprValue *const_val) { |
| 3388 | 3396 | switch (const_val->special) { |
| 3397 | case ConstValSpecialLazy: | |
| 3398 | zig_unreachable(); | |
| 3389 | 3399 | case ConstValSpecialRuntime: |
| 3390 | 3400 | return false; |
| 3391 | 3401 | case ConstValSpecialUndef: |
| ... | ... | @@ -3525,6 +3535,8 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir |
| 3525 | 3535 | } |
| 3526 | 3536 | |
| 3527 | 3537 | static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) { |
| 3538 | if (instruction->base.value.special != ConstValSpecialRuntime) | |
| 3539 | return ir_llvm_value(g, &instruction->base); | |
| 3528 | 3540 | ZigVar *var = instruction->var; |
| 3529 | 3541 | if (type_has_bits(var->var_type)) { |
| 3530 | 3542 | assert(var->value_ref); |
| ... | ... | @@ -6041,6 +6053,7 @@ static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *un |
| 6041 | 6053 | |
| 6042 | 6054 | static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) { |
| 6043 | 6055 | switch (const_val->special) { |
| 6056 | case ConstValSpecialLazy: | |
| 6044 | 6057 | case ConstValSpecialRuntime: |
| 6045 | 6058 | zig_unreachable(); |
| 6046 | 6059 | case ConstValSpecialUndef: |
| ... | ... | @@ -6300,6 +6313,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 6300 | 6313 | assert(type_has_bits(type_entry)); |
| 6301 | 6314 | |
| 6302 | 6315 | switch (const_val->special) { |
| 6316 | case ConstValSpecialLazy: | |
| 6317 | zig_unreachable(); | |
| 6303 | 6318 | case ConstValSpecialRuntime: |
| 6304 | 6319 | zig_unreachable(); |
| 6305 | 6320 | case ConstValSpecialUndef: |
| ... | ... | @@ -6563,7 +6578,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 6563 | 6578 | uint64_t pad_bytes = type_entry->data.unionation.union_abi_size - field_type_bytes; |
| 6564 | 6579 | LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value, ""); |
| 6565 | 6580 | make_unnamed_struct = is_llvm_value_unnamed_type(g, payload_value->type, correctly_typed_value) || |
| 6566 | payload_value->type != type_entry->data.unionation.most_aligned_union_member; | |
| 6581 | payload_value->type != type_entry->data.unionation.most_aligned_union_member->type_entry; | |
| 6567 | 6582 | |
| 6568 | 6583 | { |
| 6569 | 6584 | if (pad_bytes == 0) { |
| ... | ... | @@ -8905,7 +8920,7 @@ static void gen_root_source(CodeGen *g) { |
| 8905 | 8920 | } |
| 8906 | 8921 | Tld *panic_tld = find_decl(g, &get_container_scope(import_with_panic)->base, buf_create_from_str("panic")); |
| 8907 | 8922 | assert(panic_tld != nullptr); |
| 8908 | resolve_top_level_decl(g, panic_tld, nullptr); | |
| 8923 | resolve_top_level_decl(g, panic_tld, nullptr, false); | |
| 8909 | 8924 | } |
| 8910 | 8925 | |
| 8911 | 8926 |
src/ir.cpp+966-580| ... | ... | @@ -152,11 +152,6 @@ struct ConstCastBadAllowsZero { |
| 152 | 152 | }; |
| 153 | 153 | |
| 154 | 154 | |
| 155 | enum UndefAllowed { | |
| 156 | UndefOk, | |
| 157 | UndefBad, | |
| 158 | }; | |
| 159 | ||
| 160 | 155 | static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); |
| 161 | 156 | static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, |
| 162 | 157 | ResultLoc *result_loc); |
| ... | ... | @@ -234,6 +229,7 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c |
| 234 | 229 | } |
| 235 | 230 | case ConstPtrSpecialBaseStruct: { |
| 236 | 231 | ConstExprValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val; |
| 232 | expand_undef_struct(g, struct_val); | |
| 237 | 233 | result = &struct_val->data.x_struct.fields[const_val->data.x_ptr.data.base_struct.field_index]; |
| 238 | 234 | break; |
| 239 | 235 | } |
| ... | ... | @@ -402,7 +398,7 @@ static void ir_ref_var(ZigVar *var) { |
| 402 | 398 | ZigType *ir_analyze_type_expr(IrAnalyze *ira, Scope *scope, AstNode *node) { |
| 403 | 399 | ConstExprValue *result = ir_eval_const_value(ira->codegen, scope, node, ira->codegen->builtin_types.entry_type, |
| 404 | 400 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, nullptr, |
| 405 | node, nullptr, ira->new_irb.exec, nullptr); | |
| 401 | node, nullptr, ira->new_irb.exec, nullptr, UndefBad); | |
| 406 | 402 | |
| 407 | 403 | if (type_is_invalid(result->type)) |
| 408 | 404 | return ira->codegen->builtin_types.entry_invalid; |
| ... | ... | @@ -5766,7 +5762,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode |
| 5766 | 5762 | buf_sprintf("value %s too large for u32 bit offset", buf_ptr(val_buf))); |
| 5767 | 5763 | return irb->codegen->invalid_instruction; |
| 5768 | 5764 | } |
| 5769 | bit_offset_start = bigint_as_unsigned(node->data.pointer_type.bit_offset_start); | |
| 5765 | bit_offset_start = bigint_as_u32(node->data.pointer_type.bit_offset_start); | |
| 5770 | 5766 | } |
| 5771 | 5767 | |
| 5772 | 5768 | uint32_t host_int_bytes = 0; |
| ... | ... | @@ -5778,7 +5774,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode |
| 5778 | 5774 | buf_sprintf("value %s too large for u32 byte count", buf_ptr(val_buf))); |
| 5779 | 5775 | return irb->codegen->invalid_instruction; |
| 5780 | 5776 | } |
| 5781 | host_int_bytes = bigint_as_unsigned(node->data.pointer_type.host_int_bytes); | |
| 5777 | host_int_bytes = bigint_as_u32(node->data.pointer_type.host_int_bytes); | |
| 5782 | 5778 | } |
| 5783 | 5779 | |
| 5784 | 5780 | if (host_int_bytes != 0 && bit_offset_start >= host_int_bytes * 8) { |
| ... | ... | @@ -6858,7 +6854,7 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod |
| 6858 | 6854 | uint32_t len = asm_token.end - asm_token.start - 2; |
| 6859 | 6855 | |
| 6860 | 6856 | add_node_error(irb->codegen, node, |
| 6861 | buf_sprintf("could not find '%.*s' in the inputs or outputs.", | |
| 6857 | buf_sprintf("could not find '%.*s' in the inputs or outputs", | |
| 6862 | 6858 | len, ptr)); |
| 6863 | 6859 | return irb->codegen->invalid_instruction; |
| 6864 | 6860 | } |
| ... | ... | @@ -8111,7 +8107,12 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc |
| 8111 | 8107 | ir_build_reset_result(irb, scope, node, result_loc); |
| 8112 | 8108 | } |
| 8113 | 8109 | IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval, result_loc); |
| 8114 | irb->exec->invalid = irb->exec->invalid || (result == irb->codegen->invalid_instruction); | |
| 8110 | if (result == irb->codegen->invalid_instruction) { | |
| 8111 | if (irb->exec->first_err_trace_msg == nullptr) { | |
| 8112 | irb->exec->first_err_trace_msg = irb->codegen->trace_err; | |
| 8113 | } | |
| 8114 | src_assert(irb->exec->first_err_trace_msg != nullptr, node); | |
| 8115 | } | |
| 8115 | 8116 | return result; |
| 8116 | 8117 | } |
| 8117 | 8118 | |
| ... | ... | @@ -8119,21 +8120,20 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) { |
| 8119 | 8120 | return ir_gen_node_extra(irb, node, scope, LValNone, nullptr); |
| 8120 | 8121 | } |
| 8121 | 8122 | |
| 8122 | static void invalidate_exec(IrExecutable *exec) { | |
| 8123 | if (exec->invalid) | |
| 8123 | static void invalidate_exec(IrExecutable *exec, ErrorMsg *msg) { | |
| 8124 | if (exec->first_err_trace_msg != nullptr) | |
| 8124 | 8125 | return; |
| 8125 | 8126 | |
| 8126 | exec->invalid = true; | |
| 8127 | exec->first_err_trace_msg = msg; | |
| 8127 | 8128 | |
| 8128 | 8129 | for (size_t i = 0; i < exec->tld_list.length; i += 1) { |
| 8129 | 8130 | exec->tld_list.items[i]->resolution = TldResolutionInvalid; |
| 8130 | 8131 | } |
| 8131 | 8132 | |
| 8132 | 8133 | if (exec->source_exec != nullptr) |
| 8133 | invalidate_exec(exec->source_exec); | |
| 8134 | invalidate_exec(exec->source_exec, msg); | |
| 8134 | 8135 | } |
| 8135 | 8136 | |
| 8136 | ||
| 8137 | 8137 | bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_executable) { |
| 8138 | 8138 | assert(node->owner); |
| 8139 | 8139 | |
| ... | ... | @@ -8151,8 +8151,10 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 8151 | 8151 | |
| 8152 | 8152 | IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone, nullptr); |
| 8153 | 8153 | assert(result); |
| 8154 | if (irb->exec->invalid) | |
| 8154 | if (irb->exec->first_err_trace_msg != nullptr) { | |
| 8155 | codegen->trace_err = irb->exec->first_err_trace_msg; | |
| 8155 | 8156 | return false; |
| 8157 | } | |
| 8156 | 8158 | |
| 8157 | 8159 | if (!instr_is_unreachable(result)) { |
| 8158 | 8160 | ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, result->source_node, result)); |
| ... | ... | @@ -8181,15 +8183,9 @@ static void ir_add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, Error |
| 8181 | 8183 | ir_add_call_stack_errors(codegen, exec->parent_exec, err_msg, limit - 1); |
| 8182 | 8184 | } |
| 8183 | 8185 | |
| 8184 | void ir_add_analysis_trace(IrAnalyze *ira, ErrorMsg *err_msg, Buf *text) { | |
| 8185 | IrInstruction *old_instruction = ira->old_irb.current_basic_block->instruction_list.at(ira->instruction_index); | |
| 8186 | add_error_note(ira->codegen, err_msg, old_instruction->source_node, text); | |
| 8187 | ir_add_call_stack_errors(ira->codegen, ira->new_irb.exec, err_msg, 10); | |
| 8188 | } | |
| 8189 | ||
| 8190 | 8186 | static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) { |
| 8191 | invalidate_exec(exec); | |
| 8192 | 8187 | ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); |
| 8188 | invalidate_exec(exec, err_msg); | |
| 8193 | 8189 | if (exec->parent_exec) { |
| 8194 | 8190 | ir_add_call_stack_errors(codegen, exec, err_msg, 10); |
| 8195 | 8191 | } |
| ... | ... | @@ -8223,6 +8219,7 @@ static Error eval_comptime_ptr_reinterpret(IrAnalyze *ira, CodeGen *codegen, Ast |
| 8223 | 8219 | { |
| 8224 | 8220 | Error err; |
| 8225 | 8221 | assert(ptr_val->type->id == ZigTypeIdPointer); |
| 8222 | assert(ptr_val->special == ConstValSpecialStatic); | |
| 8226 | 8223 | ConstExprValue tmp = {}; |
| 8227 | 8224 | tmp.special = ConstValSpecialStatic; |
| 8228 | 8225 | tmp.type = ptr_val->type->data.pointer.child_type; |
| ... | ... | @@ -9016,7 +9013,8 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc |
| 9016 | 9013 | } |
| 9017 | 9014 | |
| 9018 | 9015 | ConstExprValue *const_val = ir_resolve_const(ira, instruction, UndefBad); |
| 9019 | assert(const_val != nullptr); | |
| 9016 | if (const_val == nullptr) | |
| 9017 | return false; | |
| 9020 | 9018 | |
| 9021 | 9019 | bool const_val_is_int = (const_val->type->id == ZigTypeIdInt || const_val->type->id == ZigTypeIdComptimeInt); |
| 9022 | 9020 | bool const_val_is_float = (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat); |
| ... | ... | @@ -9376,6 +9374,14 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted |
| 9376 | 9374 | result.id = ConstCastResultIdInvalid; |
| 9377 | 9375 | return result; |
| 9378 | 9376 | } |
| 9377 | if ((err = type_resolve(g, wanted_type, ResolveStatusZeroBitsKnown))) { | |
| 9378 | result.id = ConstCastResultIdInvalid; | |
| 9379 | return result; | |
| 9380 | } | |
| 9381 | if ((err = type_resolve(g, actual_type, ResolveStatusZeroBitsKnown))) { | |
| 9382 | result.id = ConstCastResultIdInvalid; | |
| 9383 | return result; | |
| 9384 | } | |
| 9379 | 9385 | bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len; |
| 9380 | 9386 | if ((ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr) && |
| 9381 | 9387 | type_has_bits(wanted_type) == type_has_bits(actual_type) && |
| ... | ... | @@ -10634,7 +10640,7 @@ static void ir_finish_bb(IrAnalyze *ira) { |
| 10634 | 10640 | |
| 10635 | 10641 | static IrInstruction *ir_unreach_error(IrAnalyze *ira) { |
| 10636 | 10642 | ira->old_bb_index = SIZE_MAX; |
| 10637 | ira->new_irb.exec->invalid = true; | |
| 10643 | assert(ira->new_irb.exec->first_err_trace_msg != nullptr); | |
| 10638 | 10644 | return ira->codegen->unreach_instruction; |
| 10639 | 10645 | } |
| 10640 | 10646 | |
| ... | ... | @@ -10722,32 +10728,57 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio |
| 10722 | 10728 | return const_instr; |
| 10723 | 10729 | } |
| 10724 | 10730 | |
| 10731 | static Error ir_resolve_const_val(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, | |
| 10732 | ConstExprValue *val, UndefAllowed undef_allowed) | |
| 10733 | { | |
| 10734 | Error err; | |
| 10735 | for (;;) { | |
| 10736 | switch (val->special) { | |
| 10737 | case ConstValSpecialStatic: | |
| 10738 | return ErrorNone; | |
| 10739 | case ConstValSpecialRuntime: | |
| 10740 | if (!type_has_bits(val->type)) | |
| 10741 | return ErrorNone; | |
| 10742 | ||
| 10743 | exec_add_error_node(codegen, exec, source_node, | |
| 10744 | buf_sprintf("unable to evaluate constant expression")); | |
| 10745 | return ErrorSemanticAnalyzeFail; | |
| 10746 | case ConstValSpecialUndef: | |
| 10747 | if (undef_allowed == UndefOk || undef_allowed == LazyOk) | |
| 10748 | return ErrorNone; | |
| 10749 | ||
| 10750 | exec_add_error_node(codegen, exec, source_node, | |
| 10751 | buf_sprintf("use of undefined value here causes undefined behavior")); | |
| 10752 | return ErrorSemanticAnalyzeFail; | |
| 10753 | case ConstValSpecialLazy: | |
| 10754 | if (undef_allowed == LazyOk || undef_allowed == LazyOkNoUndef) | |
| 10755 | return ErrorNone; | |
| 10756 | ||
| 10757 | if ((err = ir_resolve_lazy(codegen, source_node, val))) | |
| 10758 | return err; | |
| 10759 | ||
| 10760 | continue; | |
| 10761 | } | |
| 10762 | } | |
| 10763 | } | |
| 10764 | ||
| 10725 | 10765 | static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed) { |
| 10726 | switch (value->value.special) { | |
| 10727 | case ConstValSpecialStatic: | |
| 10728 | return &value->value; | |
| 10729 | case ConstValSpecialRuntime: | |
| 10730 | if (!type_has_bits(value->value.type)) { | |
| 10731 | return &value->value; | |
| 10732 | } | |
| 10733 | ir_add_error(ira, value, buf_sprintf("unable to evaluate constant expression")); | |
| 10734 | return nullptr; | |
| 10735 | case ConstValSpecialUndef: | |
| 10736 | if (undef_allowed == UndefOk) { | |
| 10737 | return &value->value; | |
| 10738 | } else { | |
| 10739 | ir_add_error(ira, value, buf_sprintf("use of undefined value here causes undefined behavior")); | |
| 10740 | return nullptr; | |
| 10741 | } | |
| 10766 | Error err; | |
| 10767 | if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, value->source_node, | |
| 10768 | &value->value, undef_allowed))) | |
| 10769 | { | |
| 10770 | return nullptr; | |
| 10742 | 10771 | } |
| 10743 | zig_unreachable(); | |
| 10772 | return &value->value; | |
| 10744 | 10773 | } |
| 10745 | 10774 | |
| 10746 | 10775 | ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, |
| 10747 | 10776 | ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota, |
| 10748 | 10777 | ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, |
| 10749 | IrExecutable *parent_exec, AstNode *expected_type_source_node) | |
| 10778 | IrExecutable *parent_exec, AstNode *expected_type_source_node, UndefAllowed undef_allowed) | |
| 10750 | 10779 | { |
| 10780 | Error err; | |
| 10781 | ||
| 10751 | 10782 | if (expected_type != nullptr && type_is_invalid(expected_type)) |
| 10752 | 10783 | return &codegen->invalid_instruction->value; |
| 10753 | 10784 | |
| ... | ... | @@ -10761,8 +10792,10 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod |
| 10761 | 10792 | ir_executable->begin_scope = scope; |
| 10762 | 10793 | ir_gen(codegen, node, scope, ir_executable); |
| 10763 | 10794 | |
| 10764 | if (ir_executable->invalid) | |
| 10795 | if (ir_executable->first_err_trace_msg != nullptr) { | |
| 10796 | codegen->trace_err = ir_executable->first_err_trace_msg; | |
| 10765 | 10797 | return &codegen->invalid_instruction->value; |
| 10798 | } | |
| 10766 | 10799 | |
| 10767 | 10800 | if (codegen->verbose_ir) { |
| 10768 | 10801 | fprintf(stderr, "\nSource: "); |
| ... | ... | @@ -10783,8 +10816,9 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod |
| 10783 | 10816 | analyzed_executable->backward_branch_quota = backward_branch_quota; |
| 10784 | 10817 | analyzed_executable->begin_scope = scope; |
| 10785 | 10818 | ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, expected_type_source_node); |
| 10786 | if (type_is_invalid(result_type)) | |
| 10819 | if (type_is_invalid(result_type)) { | |
| 10787 | 10820 | return &codegen->invalid_instruction->value; |
| 10821 | } | |
| 10788 | 10822 | |
| 10789 | 10823 | if (codegen->verbose_ir) { |
| 10790 | 10824 | fprintf(stderr, "{ // (analyzed)\n"); |
| ... | ... | @@ -10792,7 +10826,14 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod |
| 10792 | 10826 | fprintf(stderr, "}\n"); |
| 10793 | 10827 | } |
| 10794 | 10828 | |
| 10795 | return ir_exec_const_result(codegen, analyzed_executable); | |
| 10829 | ConstExprValue *result = ir_exec_const_result(codegen, analyzed_executable); | |
| 10830 | if (type_is_invalid(result->type)) | |
| 10831 | return &codegen->invalid_instruction->value; | |
| 10832 | ||
| 10833 | if ((err = ir_resolve_const_val(codegen, analyzed_executable, node, result, undef_allowed))) | |
| 10834 | return &codegen->invalid_instruction->value; | |
| 10835 | ||
| 10836 | return result; | |
| 10796 | 10837 | } |
| 10797 | 10838 | |
| 10798 | 10839 | static ErrorTableEntry *ir_resolve_error(IrAnalyze *ira, IrInstruction *err_value) { |
| ... | ... | @@ -10813,22 +10854,43 @@ static ErrorTableEntry *ir_resolve_error(IrAnalyze *ira, IrInstruction *err_valu |
| 10813 | 10854 | return const_val->data.x_err_set; |
| 10814 | 10855 | } |
| 10815 | 10856 | |
| 10816 | static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { | |
| 10857 | static ZigType *ir_resolve_const_type(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, | |
| 10858 | ConstExprValue *val) | |
| 10859 | { | |
| 10860 | Error err; | |
| 10861 | if ((err = ir_resolve_const_val(codegen, exec, source_node, val, UndefBad))) | |
| 10862 | return codegen->builtin_types.entry_invalid; | |
| 10863 | ||
| 10864 | assert(val->data.x_type != nullptr); | |
| 10865 | return val->data.x_type; | |
| 10866 | } | |
| 10867 | ||
| 10868 | static ConstExprValue *ir_resolve_type_lazy(IrAnalyze *ira, IrInstruction *type_value) { | |
| 10817 | 10869 | if (type_is_invalid(type_value->value.type)) |
| 10818 | return ira->codegen->builtin_types.entry_invalid; | |
| 10870 | return nullptr; | |
| 10819 | 10871 | |
| 10820 | 10872 | if (type_value->value.type->id != ZigTypeIdMetaType) { |
| 10821 | 10873 | ir_add_error(ira, type_value, |
| 10822 | 10874 | buf_sprintf("expected type 'type', found '%s'", buf_ptr(&type_value->value.type->name))); |
| 10823 | return ira->codegen->builtin_types.entry_invalid; | |
| 10875 | return nullptr; | |
| 10824 | 10876 | } |
| 10825 | 10877 | |
| 10826 | ConstExprValue *const_val = ir_resolve_const(ira, type_value, UndefBad); | |
| 10827 | if (!const_val) | |
| 10878 | Error err; | |
| 10879 | if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, type_value->source_node, | |
| 10880 | &type_value->value, LazyOk))) | |
| 10881 | { | |
| 10882 | return nullptr; | |
| 10883 | } | |
| 10884 | ||
| 10885 | return &type_value->value; | |
| 10886 | } | |
| 10887 | ||
| 10888 | static ZigType *ir_resolve_type(IrAnalyze *ira, IrInstruction *type_value) { | |
| 10889 | ConstExprValue *val = ir_resolve_type_lazy(ira, type_value); | |
| 10890 | if (val == nullptr) | |
| 10828 | 10891 | return ira->codegen->builtin_types.entry_invalid; |
| 10829 | 10892 | |
| 10830 | assert(const_val->data.x_type != nullptr); | |
| 10831 | return const_val->data.x_type; | |
| 10893 | return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, type_value->source_node, val); | |
| 10832 | 10894 | } |
| 10833 | 10895 | |
| 10834 | 10896 | static ZigType *ir_resolve_int_type(IrAnalyze *ira, IrInstruction *type_value) { |
| ... | ... | @@ -11026,14 +11088,21 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou |
| 11026 | 11088 | } |
| 11027 | 11089 | |
| 11028 | 11090 | static IrInstruction *ir_analyze_frame_ptr_to_anyframe(IrAnalyze *ira, IrInstruction *source_instr, |
| 11029 | IrInstruction *value, ZigType *wanted_type) | |
| 11091 | IrInstruction *frame_ptr, ZigType *wanted_type) | |
| 11030 | 11092 | { |
| 11031 | if (instr_is_comptime(value)) { | |
| 11032 | zig_panic("TODO comptime frame pointer"); | |
| 11093 | if (instr_is_comptime(frame_ptr)) { | |
| 11094 | ConstExprValue *ptr_val = ir_resolve_const(ira, frame_ptr, UndefBad); | |
| 11095 | if (ptr_val == nullptr) | |
| 11096 | return ira->codegen->invalid_instruction; | |
| 11097 | ||
| 11098 | ir_assert(ptr_val->type->id == ZigTypeIdPointer, source_instr); | |
| 11099 | if (ptr_val->data.x_ptr.mut != ConstPtrMutRuntimeVar) { | |
| 11100 | zig_panic("TODO comptime frame pointer"); | |
| 11101 | } | |
| 11033 | 11102 | } |
| 11034 | 11103 | |
| 11035 | 11104 | IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, |
| 11036 | wanted_type, value, CastOpBitCast); | |
| 11105 | wanted_type, frame_ptr, CastOpBitCast); | |
| 11037 | 11106 | result->value.type = wanted_type; |
| 11038 | 11107 | return result; |
| 11039 | 11108 | } |
| ... | ... | @@ -11152,6 +11221,9 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi |
| 11152 | 11221 | ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type, |
| 11153 | 11222 | is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); |
| 11154 | 11223 | |
| 11224 | if ((err = type_resolve(ira->codegen, ptr_type, ResolveStatusZeroBitsKnown))) | |
| 11225 | return ira->codegen->invalid_instruction; | |
| 11226 | ||
| 11155 | 11227 | IrInstruction *result_loc; |
| 11156 | 11228 | if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) { |
| 11157 | 11229 | result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value.type, nullptr, true, |
| ... | ... | @@ -11322,7 +11394,7 @@ static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruc |
| 11322 | 11394 | IrInstruction *target, ZigType *wanted_type) |
| 11323 | 11395 | { |
| 11324 | 11396 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 11325 | init_const_undefined(ira->codegen, &result->value); | |
| 11397 | result->value.special = ConstValSpecialUndef; | |
| 11326 | 11398 | return result; |
| 11327 | 11399 | } |
| 11328 | 11400 | |
| ... | ... | @@ -11345,10 +11417,13 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so |
| 11345 | 11417 | return ira->codegen->invalid_instruction; |
| 11346 | 11418 | TypeUnionField *union_field = find_union_field_by_tag(wanted_type, &val->data.x_enum_tag); |
| 11347 | 11419 | assert(union_field != nullptr); |
| 11348 | if ((err = type_resolve(ira->codegen, union_field->type_entry, ResolveStatusZeroBitsKnown))) | |
| 11420 | ZigType *field_type = resolve_union_field_type(ira->codegen, union_field); | |
| 11421 | if (field_type == nullptr) | |
| 11422 | return ira->codegen->invalid_instruction; | |
| 11423 | if ((err = type_resolve(ira->codegen, field_type, ResolveStatusZeroBitsKnown))) | |
| 11349 | 11424 | return ira->codegen->invalid_instruction; |
| 11350 | 11425 | |
| 11351 | switch (type_has_one_possible_value(ira->codegen, union_field->type_entry)) { | |
| 11426 | switch (type_has_one_possible_value(ira->codegen, field_type)) { | |
| 11352 | 11427 | case OnePossibleValueInvalid: |
| 11353 | 11428 | return ira->codegen->invalid_instruction; |
| 11354 | 11429 | case OnePossibleValueNo: { |
| ... | ... | @@ -11357,7 +11432,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so |
| 11357 | 11432 | ErrorMsg *msg = ir_add_error(ira, source_instr, |
| 11358 | 11433 | buf_sprintf("cast to union '%s' must initialize '%s' field '%s'", |
| 11359 | 11434 | buf_ptr(&wanted_type->name), |
| 11360 | buf_ptr(&union_field->type_entry->name), | |
| 11435 | buf_ptr(&field_type->name), | |
| 11361 | 11436 | buf_ptr(union_field->name))); |
| 11362 | 11437 | add_error_note(ira->codegen, msg, field_node, |
| 11363 | 11438 | buf_sprintf("field '%s' declared here", buf_ptr(union_field->name))); |
| ... | ... | @@ -11373,7 +11448,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so |
| 11373 | 11448 | bigint_init_bigint(&result->value.data.x_union.tag, &val->data.x_enum_tag); |
| 11374 | 11449 | result->value.data.x_union.payload = create_const_vals(1); |
| 11375 | 11450 | result->value.data.x_union.payload->special = ConstValSpecialStatic; |
| 11376 | result->value.data.x_union.payload->type = union_field->type_entry; | |
| 11451 | result->value.data.x_union.payload->type = field_type; | |
| 11377 | 11452 | return result; |
| 11378 | 11453 | } |
| 11379 | 11454 | |
| ... | ... | @@ -11390,12 +11465,17 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so |
| 11390 | 11465 | buf_ptr(&wanted_type->name))); |
| 11391 | 11466 | for (uint32_t i = 0; i < wanted_type->data.unionation.src_field_count; i += 1) { |
| 11392 | 11467 | TypeUnionField *union_field = &wanted_type->data.unionation.fields[i]; |
| 11393 | if (type_has_bits(union_field->type_entry)) { | |
| 11468 | ZigType *field_type = resolve_union_field_type(ira->codegen, union_field); | |
| 11469 | if (field_type == nullptr) | |
| 11470 | return ira->codegen->invalid_instruction; | |
| 11471 | if ((err = type_resolve(ira->codegen, field_type, ResolveStatusZeroBitsKnown))) | |
| 11472 | return ira->codegen->invalid_instruction; | |
| 11473 | if (type_has_bits(field_type)) { | |
| 11394 | 11474 | AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at(i); |
| 11395 | 11475 | add_error_note(ira->codegen, msg, field_node, |
| 11396 | 11476 | buf_sprintf("field '%s' has type '%s'", |
| 11397 | 11477 | buf_ptr(union_field->name), |
| 11398 | buf_ptr(&union_field->type_entry->name))); | |
| 11478 | buf_ptr(&field_type->name))); | |
| 11399 | 11479 | } |
| 11400 | 11480 | } |
| 11401 | 11481 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -11461,7 +11541,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour |
| 11461 | 11541 | |
| 11462 | 11542 | ZigType *actual_type = target->value.type; |
| 11463 | 11543 | |
| 11464 | if ((err = ensure_complete_type(ira->codegen, wanted_type))) | |
| 11544 | if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusSizeKnown))) | |
| 11465 | 11545 | return ira->codegen->invalid_instruction; |
| 11466 | 11546 | |
| 11467 | 11547 | if (actual_type != wanted_type->data.enumeration.tag_int_type) { |
| ... | ... | @@ -11550,7 +11630,7 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc |
| 11550 | 11630 | return ira->codegen->invalid_instruction; |
| 11551 | 11631 | } |
| 11552 | 11632 | |
| 11553 | size_t index = bigint_as_unsigned(&val->data.x_bigint); | |
| 11633 | size_t index = bigint_as_usize(&val->data.x_bigint); | |
| 11554 | 11634 | result->value.data.x_err_set = ira->codegen->errors_by_index.at(index); |
| 11555 | 11635 | return result; |
| 11556 | 11636 | } else { |
| ... | ... | @@ -12508,26 +12588,22 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc |
| 12508 | 12588 | return ir_build_load_ptr_gen(ira, source_instruction, ptr, child_type, result_loc_inst); |
| 12509 | 12589 | } |
| 12510 | 12590 | |
| 12511 | static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out) { | |
| 12512 | if (type_is_invalid(value->value.type)) | |
| 12513 | return false; | |
| 12514 | ||
| 12515 | IrInstruction *casted_value = ir_implicit_cast(ira, value, get_align_amt_type(ira->codegen)); | |
| 12516 | if (type_is_invalid(casted_value->value.type)) | |
| 12517 | return false; | |
| 12518 | ||
| 12519 | ConstExprValue *const_val = ir_resolve_const(ira, casted_value, UndefBad); | |
| 12520 | if (!const_val) | |
| 12591 | static bool ir_resolve_const_align(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, | |
| 12592 | ConstExprValue *const_val, uint32_t *out) | |
| 12593 | { | |
| 12594 | Error err; | |
| 12595 | if ((err = ir_resolve_const_val(codegen, exec, source_node, const_val, UndefBad))) | |
| 12521 | 12596 | return false; |
| 12522 | 12597 | |
| 12523 | uint32_t align_bytes = bigint_as_unsigned(&const_val->data.x_bigint); | |
| 12598 | uint32_t align_bytes = bigint_as_u32(&const_val->data.x_bigint); | |
| 12524 | 12599 | if (align_bytes == 0) { |
| 12525 | ir_add_error(ira, value, buf_sprintf("alignment must be >= 1")); | |
| 12600 | exec_add_error_node(codegen, exec, source_node, buf_sprintf("alignment must be >= 1")); | |
| 12526 | 12601 | return false; |
| 12527 | 12602 | } |
| 12528 | 12603 | |
| 12529 | 12604 | if (!is_power_of_2(align_bytes)) { |
| 12530 | ir_add_error(ira, value, buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes)); | |
| 12605 | exec_add_error_node(codegen, exec, source_node, | |
| 12606 | buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes)); | |
| 12531 | 12607 | return false; |
| 12532 | 12608 | } |
| 12533 | 12609 | |
| ... | ... | @@ -12535,6 +12611,18 @@ static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out |
| 12535 | 12611 | return true; |
| 12536 | 12612 | } |
| 12537 | 12613 | |
| 12614 | static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out) { | |
| 12615 | if (type_is_invalid(value->value.type)) | |
| 12616 | return false; | |
| 12617 | ||
| 12618 | IrInstruction *casted_value = ir_implicit_cast(ira, value, get_align_amt_type(ira->codegen)); | |
| 12619 | if (type_is_invalid(casted_value->value.type)) | |
| 12620 | return false; | |
| 12621 | ||
| 12622 | return ir_resolve_const_align(ira->codegen, ira->new_irb.exec, value->source_node, | |
| 12623 | &casted_value->value, out); | |
| 12624 | } | |
| 12625 | ||
| 12538 | 12626 | static bool ir_resolve_unsigned(IrAnalyze *ira, IrInstruction *value, ZigType *int_type, uint64_t *out) { |
| 12539 | 12627 | if (type_is_invalid(value->value.type)) |
| 12540 | 12628 | return false; |
| ... | ... | @@ -12547,7 +12635,7 @@ static bool ir_resolve_unsigned(IrAnalyze *ira, IrInstruction *value, ZigType *i |
| 12547 | 12635 | if (!const_val) |
| 12548 | 12636 | return false; |
| 12549 | 12637 | |
| 12550 | *out = bigint_as_unsigned(&const_val->data.x_bigint); | |
| 12638 | *out = bigint_as_u64(&const_val->data.x_bigint); | |
| 12551 | 12639 | return true; |
| 12552 | 12640 | } |
| 12553 | 12641 | |
| ... | ... | @@ -12595,7 +12683,7 @@ static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, Atomic |
| 12595 | 12683 | if (!const_val) |
| 12596 | 12684 | return false; |
| 12597 | 12685 | |
| 12598 | *out = (AtomicOrder)bigint_as_unsigned(&const_val->data.x_enum_tag); | |
| 12686 | *out = (AtomicOrder)bigint_as_u32(&const_val->data.x_enum_tag); | |
| 12599 | 12687 | return true; |
| 12600 | 12688 | } |
| 12601 | 12689 | |
| ... | ... | @@ -12615,7 +12703,7 @@ static bool ir_resolve_atomic_rmw_op(IrAnalyze *ira, IrInstruction *value, Atomi |
| 12615 | 12703 | if (!const_val) |
| 12616 | 12704 | return false; |
| 12617 | 12705 | |
| 12618 | *out = (AtomicRmwOp)bigint_as_unsigned(&const_val->data.x_enum_tag); | |
| 12706 | *out = (AtomicRmwOp)bigint_as_u32(&const_val->data.x_enum_tag); | |
| 12619 | 12707 | return true; |
| 12620 | 12708 | } |
| 12621 | 12709 | |
| ... | ... | @@ -12635,7 +12723,7 @@ static bool ir_resolve_global_linkage(IrAnalyze *ira, IrInstruction *value, Glob |
| 12635 | 12723 | if (!const_val) |
| 12636 | 12724 | return false; |
| 12637 | 12725 | |
| 12638 | *out = (GlobalLinkageId)bigint_as_unsigned(&const_val->data.x_enum_tag); | |
| 12726 | *out = (GlobalLinkageId)bigint_as_u32(&const_val->data.x_enum_tag); | |
| 12639 | 12727 | return true; |
| 12640 | 12728 | } |
| 12641 | 12729 | |
| ... | ... | @@ -12655,7 +12743,7 @@ static bool ir_resolve_float_mode(IrAnalyze *ira, IrInstruction *value, FloatMod |
| 12655 | 12743 | if (!const_val) |
| 12656 | 12744 | return false; |
| 12657 | 12745 | |
| 12658 | *out = (FloatMode)bigint_as_unsigned(&const_val->data.x_enum_tag); | |
| 12746 | *out = (FloatMode)bigint_as_u32(&const_val->data.x_enum_tag); | |
| 12659 | 12747 | return true; |
| 12660 | 12748 | } |
| 12661 | 12749 | |
| ... | ... | @@ -12684,7 +12772,7 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { |
| 12684 | 12772 | return array_val->data.x_array.data.s_buf; |
| 12685 | 12773 | } |
| 12686 | 12774 | expand_undef_array(ira->codegen, array_val); |
| 12687 | size_t len = bigint_as_unsigned(&len_field->data.x_bigint); | |
| 12775 | size_t len = bigint_as_usize(&len_field->data.x_bigint); | |
| 12688 | 12776 | Buf *result = buf_alloc(); |
| 12689 | 12777 | buf_resize(result, len); |
| 12690 | 12778 | for (size_t i = 0; i < len; i += 1) { |
| ... | ... | @@ -12694,7 +12782,7 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { |
| 12694 | 12782 | ir_add_error(ira, casted_value, buf_sprintf("use of undefined value")); |
| 12695 | 12783 | return nullptr; |
| 12696 | 12784 | } |
| 12697 | uint64_t big_c = bigint_as_unsigned(&char_val->data.x_bigint); | |
| 12785 | uint64_t big_c = bigint_as_u64(&char_val->data.x_bigint); | |
| 12698 | 12786 | assert(big_c <= UINT8_MAX); |
| 12699 | 12787 | uint8_t c = (uint8_t)big_c; |
| 12700 | 12788 | buf_ptr(result)[i] = c; |
| ... | ... | @@ -12719,7 +12807,9 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio |
| 12719 | 12807 | if (type_is_invalid(operand->value.type)) |
| 12720 | 12808 | return ir_unreach_error(ira); |
| 12721 | 12809 | |
| 12722 | if (!instr_is_comptime(operand) && handle_is_ptr(ira->explicit_return_type)) { | |
| 12810 | if (!instr_is_comptime(operand) && ira->explicit_return_type != nullptr && | |
| 12811 | handle_is_ptr(ira->explicit_return_type)) | |
| 12812 | { | |
| 12723 | 12813 | // result location mechanism took care of it. |
| 12724 | 12814 | IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope, |
| 12725 | 12815 | instruction->base.source_node, nullptr); |
| ... | ... | @@ -13576,21 +13666,34 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 13576 | 13666 | if (type_is_invalid(casted_op2->value.type)) |
| 13577 | 13667 | return ira->codegen->invalid_instruction; |
| 13578 | 13668 | |
| 13579 | if (op1->value.special == ConstValSpecialUndef || casted_op2->value.special == ConstValSpecialUndef) { | |
| 13580 | IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type); | |
| 13581 | result->value.special = ConstValSpecialUndef; | |
| 13582 | return result; | |
| 13669 | // If either operand is undef, result is undef. | |
| 13670 | ConstExprValue *op1_val = nullptr; | |
| 13671 | ConstExprValue *op2_val = nullptr; | |
| 13672 | if (instr_is_comptime(op1)) { | |
| 13673 | op1_val = ir_resolve_const(ira, op1, UndefOk); | |
| 13674 | if (op1_val == nullptr) | |
| 13675 | return ira->codegen->invalid_instruction; | |
| 13676 | if (op1_val->special == ConstValSpecialUndef) | |
| 13677 | return ir_const_undef(ira, &instruction->base, op1->value.type); | |
| 13583 | 13678 | } |
| 13584 | if (casted_op2->value.special == ConstValSpecialStatic && op1->value.special == ConstValSpecialStatic && | |
| 13679 | if (instr_is_comptime(casted_op2)) { | |
| 13680 | op2_val = ir_resolve_const(ira, casted_op2, UndefOk); | |
| 13681 | if (op2_val == nullptr) | |
| 13682 | return ira->codegen->invalid_instruction; | |
| 13683 | if (op2_val->special == ConstValSpecialUndef) | |
| 13684 | return ir_const_undef(ira, &instruction->base, op1->value.type); | |
| 13685 | } | |
| 13686 | ||
| 13687 | if (op2_val != nullptr && op1_val != nullptr && | |
| 13585 | 13688 | (op1->value.data.x_ptr.special == ConstPtrSpecialHardCodedAddr || |
| 13586 | 13689 | op1->value.data.x_ptr.special == ConstPtrSpecialNull)) |
| 13587 | 13690 | { |
| 13588 | uint64_t start_addr = (op1->value.data.x_ptr.special == ConstPtrSpecialNull) ? | |
| 13589 | 0 : op1->value.data.x_ptr.data.hard_coded_addr.addr; | |
| 13691 | uint64_t start_addr = (op1_val->data.x_ptr.special == ConstPtrSpecialNull) ? | |
| 13692 | 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr; | |
| 13590 | 13693 | uint64_t elem_offset; |
| 13591 | 13694 | if (!ir_resolve_usize(ira, casted_op2, &elem_offset)) |
| 13592 | 13695 | return ira->codegen->invalid_instruction; |
| 13593 | ZigType *elem_type = op1->value.type->data.pointer.child_type; | |
| 13696 | ZigType *elem_type = op1_val->type->data.pointer.child_type; | |
| 13594 | 13697 | if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) |
| 13595 | 13698 | return ira->codegen->invalid_instruction; |
| 13596 | 13699 | uint64_t byte_offset = type_size(ira->codegen, elem_type) * elem_offset; |
| ... | ... | @@ -13602,7 +13705,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 13602 | 13705 | } else { |
| 13603 | 13706 | zig_unreachable(); |
| 13604 | 13707 | } |
| 13605 | IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type); | |
| 13708 | IrInstruction *result = ir_const(ira, &instruction->base, op1_val->type); | |
| 13606 | 13709 | result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; |
| 13607 | 13710 | result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar; |
| 13608 | 13711 | result->value.data.x_ptr.data.hard_coded_addr.addr = new_addr; |
| ... | ... | @@ -13829,7 +13932,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i |
| 13829 | 13932 | op1_array_val = ptr_val->data.x_ptr.data.base_array.array_val; |
| 13830 | 13933 | op1_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; |
| 13831 | 13934 | ConstExprValue *len_val = &op1_val->data.x_struct.fields[slice_len_index]; |
| 13832 | op1_array_end = op1_array_index + bigint_as_unsigned(&len_val->data.x_bigint); | |
| 13935 | op1_array_end = op1_array_index + bigint_as_usize(&len_val->data.x_bigint); | |
| 13833 | 13936 | } else { |
| 13834 | 13937 | ir_add_error(ira, op1, |
| 13835 | 13938 | buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->value.type->name))); |
| ... | ... | @@ -13862,7 +13965,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i |
| 13862 | 13965 | op2_array_val = ptr_val->data.x_ptr.data.base_array.array_val; |
| 13863 | 13966 | op2_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; |
| 13864 | 13967 | ConstExprValue *len_val = &op2_val->data.x_struct.fields[slice_len_index]; |
| 13865 | op2_array_end = op2_array_index + bigint_as_unsigned(&len_val->data.x_bigint); | |
| 13968 | op2_array_end = op2_array_index + bigint_as_usize(&len_val->data.x_bigint); | |
| 13866 | 13969 | } else { |
| 13867 | 13970 | ir_add_error(ira, op2, |
| 13868 | 13971 | buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name))); |
| ... | ... | @@ -14171,9 +14274,13 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, |
| 14171 | 14274 | } |
| 14172 | 14275 | break; |
| 14173 | 14276 | case ReqCompTimeNo: |
| 14174 | if (init_val != nullptr) { | |
| 14175 | if (init_val->special == ConstValSpecialStatic && | |
| 14176 | init_val->type->id == ZigTypeIdFn && | |
| 14277 | if (init_val != nullptr && value_is_comptime(init_val)) { | |
| 14278 | if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, | |
| 14279 | decl_var_instruction->base.source_node, init_val, UndefOk))) | |
| 14280 | { | |
| 14281 | result_type = ira->codegen->builtin_types.entry_invalid; | |
| 14282 | } else if (init_val->type->id == ZigTypeIdFn && | |
| 14283 | init_val->special != ConstValSpecialUndef && | |
| 14177 | 14284 | init_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr && |
| 14178 | 14285 | init_val->data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways) |
| 14179 | 14286 | { |
| ... | ... | @@ -14231,7 +14338,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, |
| 14231 | 14338 | } |
| 14232 | 14339 | } |
| 14233 | 14340 | |
| 14234 | if (init_val != nullptr && init_val->special != ConstValSpecialRuntime) { | |
| 14341 | if (init_val != nullptr && value_is_comptime(init_val)) { | |
| 14235 | 14342 | // Resolve ConstPtrMutInfer |
| 14236 | 14343 | if (var->gen_is_const) { |
| 14237 | 14344 | var_ptr->value.data.x_ptr.mut = ConstPtrMutComptimeConst; |
| ... | ... | @@ -14242,6 +14349,10 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, |
| 14242 | 14349 | // since it's a comptime val there are no instructions for it. |
| 14243 | 14350 | // we memcpy the init value here |
| 14244 | 14351 | IrInstruction *deref = ir_get_deref(ira, var_ptr, var_ptr, nullptr); |
| 14352 | if (type_is_invalid(deref->value.type)) { | |
| 14353 | var->var_type = ira->codegen->builtin_types.entry_invalid; | |
| 14354 | return ira->codegen->invalid_instruction; | |
| 14355 | } | |
| 14245 | 14356 | // If this assertion trips, something is wrong with the IR instructions, because |
| 14246 | 14357 | // we expected the above deref to return a constant value, but it created a runtime |
| 14247 | 14358 | // instruction. |
| ... | ... | @@ -14250,7 +14361,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, |
| 14250 | 14361 | ir_analyze_store_ptr(ira, var_ptr, var_ptr, deref, false); |
| 14251 | 14362 | } |
| 14252 | 14363 | |
| 14253 | if (var_ptr->value.special == ConstValSpecialStatic && var->mem_slot_index != SIZE_MAX) { | |
| 14364 | if (instr_is_comptime(var_ptr) && var->mem_slot_index != SIZE_MAX) { | |
| 14254 | 14365 | assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length); |
| 14255 | 14366 | ConstExprValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index); |
| 14256 | 14367 | copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const); |
| ... | ... | @@ -14515,28 +14626,23 @@ static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, |
| 14515 | 14626 | static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira, |
| 14516 | 14627 | IrInstructionErrorUnion *instruction) |
| 14517 | 14628 | { |
| 14518 | Error err; | |
| 14629 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); | |
| 14630 | result->value.special = ConstValSpecialLazy; | |
| 14519 | 14631 | |
| 14520 | ZigType *err_set_type = ir_resolve_type(ira, instruction->err_set->child); | |
| 14521 | if (type_is_invalid(err_set_type)) | |
| 14522 | return ira->codegen->invalid_instruction; | |
| 14523 | ||
| 14524 | ZigType *payload_type = ir_resolve_type(ira, instruction->payload->child); | |
| 14525 | if (type_is_invalid(payload_type)) | |
| 14526 | return ira->codegen->invalid_instruction; | |
| 14632 | LazyValueErrUnionType *lazy_err_union_type = allocate<LazyValueErrUnionType>(1); | |
| 14633 | lazy_err_union_type->ira = ira; | |
| 14634 | result->value.data.x_lazy = &lazy_err_union_type->base; | |
| 14635 | lazy_err_union_type->base.id = LazyValueIdErrUnionType; | |
| 14527 | 14636 | |
| 14528 | if (err_set_type->id != ZigTypeIdErrorSet) { | |
| 14529 | ir_add_error(ira, instruction->err_set->child, | |
| 14530 | buf_sprintf("expected error set type, found type '%s'", | |
| 14531 | buf_ptr(&err_set_type->name))); | |
| 14637 | lazy_err_union_type->err_set_type = instruction->err_set->child; | |
| 14638 | if (ir_resolve_type_lazy(ira, lazy_err_union_type->err_set_type) == nullptr) | |
| 14532 | 14639 | return ira->codegen->invalid_instruction; |
| 14533 | } | |
| 14534 | 14640 | |
| 14535 | if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) | |
| 14641 | lazy_err_union_type->payload_type = instruction->payload->child; | |
| 14642 | if (ir_resolve_type_lazy(ira, lazy_err_union_type->payload_type) == nullptr) | |
| 14536 | 14643 | return ira->codegen->invalid_instruction; |
| 14537 | ZigType *result_type = get_error_union_type(ira->codegen, err_set_type, payload_type); | |
| 14538 | 14644 | |
| 14539 | return ir_const_type(ira, &instruction->base, result_type); | |
| 14645 | return result; | |
| 14540 | 14646 | } |
| 14541 | 14647 | |
| 14542 | 14648 | static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_inst, ZigType *var_type, |
| ... | ... | @@ -14555,6 +14661,10 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in |
| 14555 | 14661 | |
| 14556 | 14662 | if ((err = type_resolve(ira->codegen, var_type, ResolveStatusZeroBitsKnown))) |
| 14557 | 14663 | return ira->codegen->invalid_instruction; |
| 14664 | if (align != 0) { | |
| 14665 | if ((err = type_resolve(ira->codegen, var_type, ResolveStatusAlignmentKnown))) | |
| 14666 | return ira->codegen->invalid_instruction; | |
| 14667 | } | |
| 14558 | 14668 | assert(result->base.value.data.x_ptr.special != ConstPtrSpecialInvalid); |
| 14559 | 14669 | |
| 14560 | 14670 | pointee->type = var_type; |
| ... | ... | @@ -15174,23 +15284,25 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 15174 | 15284 | |
| 15175 | 15285 | bool comptime_var_mem = ir_get_var_is_comptime(var); |
| 15176 | 15286 | bool linkage_makes_it_runtime = var->decl_node->data.variable_declaration.is_extern; |
| 15177 | bool is_const = var->src_is_const; | |
| 15178 | 15287 | bool is_volatile = false; |
| 15179 | 15288 | |
| 15289 | IrInstruction *result = ir_build_var_ptr(&ira->new_irb, | |
| 15290 | instruction->scope, instruction->source_node, var); | |
| 15291 | result->value.type = get_pointer_to_type_extra(ira->codegen, var->var_type, | |
| 15292 | var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0, false); | |
| 15293 | ||
| 15180 | 15294 | if (linkage_makes_it_runtime) |
| 15181 | 15295 | goto no_mem_slot; |
| 15182 | 15296 | |
| 15183 | if (var->const_value->special == ConstValSpecialStatic) { | |
| 15297 | if (value_is_comptime(var->const_value)) { | |
| 15184 | 15298 | mem_slot = var->const_value; |
| 15185 | } else { | |
| 15186 | if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) { | |
| 15187 | // find the relevant exec_context | |
| 15188 | assert(var->owner_exec != nullptr); | |
| 15189 | assert(var->owner_exec->analysis != nullptr); | |
| 15190 | IrExecContext *exec_context = &var->owner_exec->analysis->exec_context; | |
| 15191 | assert(var->mem_slot_index < exec_context->mem_slot_list.length); | |
| 15192 | mem_slot = exec_context->mem_slot_list.at(var->mem_slot_index); | |
| 15193 | } | |
| 15299 | } else if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) { | |
| 15300 | // find the relevant exec_context | |
| 15301 | assert(var->owner_exec != nullptr); | |
| 15302 | assert(var->owner_exec->analysis != nullptr); | |
| 15303 | IrExecContext *exec_context = &var->owner_exec->analysis->exec_context; | |
| 15304 | assert(var->mem_slot_index < exec_context->mem_slot_list.length); | |
| 15305 | mem_slot = exec_context->mem_slot_list.at(var->mem_slot_index); | |
| 15194 | 15306 | } |
| 15195 | 15307 | |
| 15196 | 15308 | if (mem_slot != nullptr) { |
| ... | ... | @@ -15198,6 +15310,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 15198 | 15310 | case ConstValSpecialRuntime: |
| 15199 | 15311 | goto no_mem_slot; |
| 15200 | 15312 | case ConstValSpecialStatic: // fallthrough |
| 15313 | case ConstValSpecialLazy: // fallthrough | |
| 15201 | 15314 | case ConstValSpecialUndef: { |
| 15202 | 15315 | ConstPtrMut ptr_mut; |
| 15203 | 15316 | if (comptime_var_mem) { |
| ... | ... | @@ -15208,8 +15321,11 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 15208 | 15321 | assert(!comptime_var_mem); |
| 15209 | 15322 | ptr_mut = ConstPtrMutRuntimeVar; |
| 15210 | 15323 | } |
| 15211 | return ir_get_const_ptr(ira, instruction, mem_slot, var->var_type, | |
| 15212 | ptr_mut, is_const, is_volatile, var->align_bytes); | |
| 15324 | result->value.special = ConstValSpecialStatic; | |
| 15325 | result->value.data.x_ptr.mut = ptr_mut; | |
| 15326 | result->value.data.x_ptr.special = ConstPtrSpecialRef; | |
| 15327 | result->value.data.x_ptr.data.ref.pointee = mem_slot; | |
| 15328 | return result; | |
| 15213 | 15329 | } |
| 15214 | 15330 | } |
| 15215 | 15331 | zig_unreachable(); |
| ... | ... | @@ -15217,15 +15333,10 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 15217 | 15333 | |
| 15218 | 15334 | no_mem_slot: |
| 15219 | 15335 | |
| 15220 | IrInstruction *var_ptr_instruction = ir_build_var_ptr(&ira->new_irb, | |
| 15221 | instruction->scope, instruction->source_node, var); | |
| 15222 | var_ptr_instruction->value.type = get_pointer_to_type_extra(ira->codegen, var->var_type, | |
| 15223 | var->src_is_const, is_volatile, PtrLenSingle, var->align_bytes, 0, 0, false); | |
| 15224 | ||
| 15225 | 15336 | bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); |
| 15226 | var_ptr_instruction->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack; | |
| 15337 | result->value.data.rh_ptr = in_fn_scope ? RuntimeHintPtrStack : RuntimeHintPtrNonStack; | |
| 15227 | 15338 | |
| 15228 | return var_ptr_instruction; | |
| 15339 | return result; | |
| 15229 | 15340 | } |
| 15230 | 15341 | |
| 15231 | 15342 | // This function is called when a comptime value becomes accessible at runtime. |
| ... | ... | @@ -15489,7 +15600,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15489 | 15600 | AstNode *body_node = fn_entry->body_node; |
| 15490 | 15601 | result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type, |
| 15491 | 15602 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, |
| 15492 | nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec, return_type_node); | |
| 15603 | nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec, return_type_node, | |
| 15604 | UndefOk); | |
| 15493 | 15605 | |
| 15494 | 15606 | if (inferred_err_set_type != nullptr) { |
| 15495 | 15607 | inferred_err_set_type->data.error_set.infer_fn = nullptr; |
| ... | ... | @@ -15513,8 +15625,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15513 | 15625 | ira->codegen->memoized_fn_eval_table.put(exec_scope, result); |
| 15514 | 15626 | } |
| 15515 | 15627 | |
| 15516 | if (type_is_invalid(result->type)) | |
| 15628 | if (type_is_invalid(result->type)) { | |
| 15517 | 15629 | return ira->codegen->invalid_instruction; |
| 15630 | } | |
| 15518 | 15631 | } |
| 15519 | 15632 | |
| 15520 | 15633 | IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->type); |
| ... | ... | @@ -15685,7 +15798,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15685 | 15798 | ConstExprValue *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope, |
| 15686 | 15799 | fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen), |
| 15687 | 15800 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, |
| 15688 | nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec, nullptr); | |
| 15801 | nullptr, nullptr, fn_proto_node->data.fn_proto.align_expr, nullptr, ira->new_irb.exec, | |
| 15802 | nullptr, UndefBad); | |
| 15689 | 15803 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, |
| 15690 | 15804 | impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr); |
| 15691 | 15805 | copy_const_val(&const_instruction->base.value, align_result, true); |
| ... | ... | @@ -16066,51 +16180,20 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source |
| 16066 | 16180 | zig_unreachable(); |
| 16067 | 16181 | } |
| 16068 | 16182 | |
| 16069 | static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { | |
| 16070 | Error err; | |
| 16071 | IrInstruction *value = un_op_instruction->value->child; | |
| 16072 | ZigType *type_entry = ir_resolve_type(ira, value); | |
| 16073 | if (type_is_invalid(type_entry)) | |
| 16074 | return ira->codegen->invalid_instruction; | |
| 16075 | if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusSizeKnown))) | |
| 16076 | return ira->codegen->invalid_instruction; | |
| 16183 | static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp *instruction) { | |
| 16184 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); | |
| 16185 | result->value.special = ConstValSpecialLazy; | |
| 16077 | 16186 | |
| 16078 | switch (type_entry->id) { | |
| 16079 | case ZigTypeIdInvalid: | |
| 16080 | zig_unreachable(); | |
| 16081 | case ZigTypeIdMetaType: | |
| 16082 | case ZigTypeIdVoid: | |
| 16083 | case ZigTypeIdBool: | |
| 16084 | case ZigTypeIdInt: | |
| 16085 | case ZigTypeIdVector: | |
| 16086 | case ZigTypeIdFloat: | |
| 16087 | case ZigTypeIdPointer: | |
| 16088 | case ZigTypeIdArray: | |
| 16089 | case ZigTypeIdStruct: | |
| 16090 | case ZigTypeIdComptimeFloat: | |
| 16091 | case ZigTypeIdComptimeInt: | |
| 16092 | case ZigTypeIdEnumLiteral: | |
| 16093 | case ZigTypeIdUndefined: | |
| 16094 | case ZigTypeIdNull: | |
| 16095 | case ZigTypeIdOptional: | |
| 16096 | case ZigTypeIdErrorUnion: | |
| 16097 | case ZigTypeIdErrorSet: | |
| 16098 | case ZigTypeIdEnum: | |
| 16099 | case ZigTypeIdUnion: | |
| 16100 | case ZigTypeIdFn: | |
| 16101 | case ZigTypeIdBoundFn: | |
| 16102 | case ZigTypeIdArgTuple: | |
| 16103 | case ZigTypeIdFnFrame: | |
| 16104 | case ZigTypeIdAnyFrame: | |
| 16105 | return ir_const_type(ira, &un_op_instruction->base, get_optional_type(ira->codegen, type_entry)); | |
| 16187 | LazyValueOptType *lazy_opt_type = allocate<LazyValueOptType>(1); | |
| 16188 | lazy_opt_type->ira = ira; | |
| 16189 | result->value.data.x_lazy = &lazy_opt_type->base; | |
| 16190 | lazy_opt_type->base.id = LazyValueIdOptType; | |
| 16106 | 16191 | |
| 16107 | case ZigTypeIdUnreachable: | |
| 16108 | case ZigTypeIdOpaque: | |
| 16109 | ir_add_error_node(ira, un_op_instruction->base.source_node, | |
| 16110 | buf_sprintf("type '%s' not optional", buf_ptr(&type_entry->name))); | |
| 16111 | return ira->codegen->invalid_instruction; | |
| 16112 | } | |
| 16113 | zig_unreachable(); | |
| 16192 | lazy_opt_type->payload_type = instruction->value->child; | |
| 16193 | if (ir_resolve_type_lazy(ira, lazy_opt_type->payload_type) == nullptr) | |
| 16194 | return ira->codegen->invalid_instruction; | |
| 16195 | ||
| 16196 | return result; | |
| 16114 | 16197 | } |
| 16115 | 16198 | |
| 16116 | 16199 | static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInstruction *source_instr, ZigType *scalar_type, |
| ... | ... | @@ -16727,14 +16810,14 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 16727 | 16810 | return ira->codegen->invalid_instruction; |
| 16728 | 16811 | |
| 16729 | 16812 | bool safety_check_on = elem_ptr_instruction->safety_check_on; |
| 16730 | if ((err = ensure_complete_type(ira->codegen, return_type->data.pointer.child_type))) | |
| 16813 | if ((err = type_resolve(ira->codegen, return_type->data.pointer.child_type, ResolveStatusSizeKnown))) | |
| 16731 | 16814 | return ira->codegen->invalid_instruction; |
| 16732 | 16815 | |
| 16733 | 16816 | uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type); |
| 16734 | 16817 | uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type); |
| 16735 | 16818 | uint64_t ptr_align = get_ptr_align(ira->codegen, return_type); |
| 16736 | 16819 | if (instr_is_comptime(casted_elem_index)) { |
| 16737 | uint64_t index = bigint_as_unsigned(&casted_elem_index->value.data.x_bigint); | |
| 16820 | uint64_t index = bigint_as_u64(&casted_elem_index->value.data.x_bigint); | |
| 16738 | 16821 | if (array_type->id == ZigTypeIdArray) { |
| 16739 | 16822 | uint64_t array_len = array_type->data.array.len; |
| 16740 | 16823 | if (index >= array_len) { |
| ... | ... | @@ -16896,7 +16979,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 16896 | 16979 | ConstExprValue *len_field = &array_ptr_val->data.x_struct.fields[slice_len_index]; |
| 16897 | 16980 | IrInstruction *result = ir_const(ira, &elem_ptr_instruction->base, return_type); |
| 16898 | 16981 | ConstExprValue *out_val = &result->value; |
| 16899 | uint64_t slice_len = bigint_as_unsigned(&len_field->data.x_bigint); | |
| 16982 | uint64_t slice_len = bigint_as_u64(&len_field->data.x_bigint); | |
| 16900 | 16983 | if (index >= slice_len) { |
| 16901 | 16984 | ir_add_error_node(ira, elem_ptr_instruction->base.source_node, |
| 16902 | 16985 | buf_sprintf("index %" ZIG_PRI_u64 " outside slice of size %" ZIG_PRI_u64, |
| ... | ... | @@ -17005,7 +17088,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, |
| 17005 | 17088 | auto entry = container_scope->decl_table.maybe_get(field_name); |
| 17006 | 17089 | Tld *tld = entry ? entry->value : nullptr; |
| 17007 | 17090 | if (tld && tld->id == TldIdFn) { |
| 17008 | resolve_top_level_decl(ira->codegen, tld, source_instr->source_node); | |
| 17091 | resolve_top_level_decl(ira->codegen, tld, source_instr->source_node, false); | |
| 17009 | 17092 | if (tld->resolution == TldResolutionInvalid) |
| 17010 | 17093 | return ira->codegen->invalid_instruction; |
| 17011 | 17094 | TldFn *tld_fn = (TldFn *)tld; |
| ... | ... | @@ -17038,27 +17121,31 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, |
| 17038 | 17121 | static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction *source_instr, |
| 17039 | 17122 | TypeStructField *field, IrInstruction *struct_ptr, ZigType *struct_type, bool initializing) |
| 17040 | 17123 | { |
| 17041 | switch (type_has_one_possible_value(ira->codegen, field->type_entry)) { | |
| 17124 | Error err; | |
| 17125 | ZigType *field_type = resolve_struct_field_type(ira->codegen, field); | |
| 17126 | if (field_type == nullptr) | |
| 17127 | return ira->codegen->invalid_instruction; | |
| 17128 | switch (type_has_one_possible_value(ira->codegen, field_type)) { | |
| 17042 | 17129 | case OnePossibleValueInvalid: |
| 17043 | 17130 | return ira->codegen->invalid_instruction; |
| 17044 | 17131 | case OnePossibleValueYes: { |
| 17045 | IrInstruction *elem = ir_const(ira, source_instr, field->type_entry); | |
| 17132 | IrInstruction *elem = ir_const(ira, source_instr, field_type); | |
| 17046 | 17133 | return ir_get_ref(ira, source_instr, elem, false, false); |
| 17047 | 17134 | } |
| 17048 | 17135 | case OnePossibleValueNo: |
| 17049 | 17136 | break; |
| 17050 | 17137 | } |
| 17138 | if ((err = type_resolve(ira->codegen, struct_type, ResolveStatusAlignmentKnown))) | |
| 17139 | return ira->codegen->invalid_instruction; | |
| 17051 | 17140 | assert(struct_ptr->value.type->id == ZigTypeIdPointer); |
| 17052 | bool is_packed = (struct_type->data.structure.layout == ContainerLayoutPacked); | |
| 17053 | uint32_t align_bytes = is_packed ? 1 : get_abi_alignment(ira->codegen, field->type_entry); | |
| 17054 | 17141 | uint32_t ptr_bit_offset = struct_ptr->value.type->data.pointer.bit_offset_in_host; |
| 17055 | 17142 | uint32_t ptr_host_int_bytes = struct_ptr->value.type->data.pointer.host_int_bytes; |
| 17056 | 17143 | uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ? |
| 17057 | 17144 | get_host_int_bytes(ira->codegen, struct_type, field) : ptr_host_int_bytes; |
| 17058 | 17145 | bool is_const = struct_ptr->value.type->data.pointer.is_const; |
| 17059 | 17146 | bool is_volatile = struct_ptr->value.type->data.pointer.is_volatile; |
| 17060 | ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field->type_entry, | |
| 17061 | is_const, is_volatile, PtrLenSingle, align_bytes, | |
| 17147 | ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, | |
| 17148 | is_const, is_volatile, PtrLenSingle, field->align, | |
| 17062 | 17149 | (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), |
| 17063 | 17150 | (uint32_t)host_int_bytes_for_result_type, false); |
| 17064 | 17151 | if (instr_is_comptime(struct_ptr)) { |
| ... | ... | @@ -17113,7 +17200,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ |
| 17113 | 17200 | Error err; |
| 17114 | 17201 | |
| 17115 | 17202 | ZigType *bare_type = container_ref_type(container_type); |
| 17116 | if ((err = ensure_complete_type(ira->codegen, bare_type))) | |
| 17203 | if ((err = type_resolve(ira->codegen, bare_type, ResolveStatusSizeKnown))) | |
| 17117 | 17204 | return ira->codegen->invalid_instruction; |
| 17118 | 17205 | |
| 17119 | 17206 | assert(container_ptr->value.type->id == ZigTypeIdPointer); |
| ... | ... | @@ -17243,23 +17330,22 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, |
| 17243 | 17330 | } |
| 17244 | 17331 | |
| 17245 | 17332 | static IrInstruction *ir_error_dependency_loop(IrAnalyze *ira, IrInstruction *source_instr) { |
| 17246 | ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("dependency loop detected")); | |
| 17247 | emit_error_notes_for_ref_stack(ira->codegen, msg); | |
| 17333 | ir_add_error(ira, source_instr, buf_sprintf("dependency loop detected")); | |
| 17248 | 17334 | return ira->codegen->invalid_instruction; |
| 17249 | 17335 | } |
| 17250 | 17336 | |
| 17251 | 17337 | static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) { |
| 17252 | resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node); | |
| 17253 | if (tld->resolution == TldResolutionInvalid) | |
| 17338 | resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node, true); | |
| 17339 | if (tld->resolution == TldResolutionInvalid) { | |
| 17254 | 17340 | return ira->codegen->invalid_instruction; |
| 17341 | } | |
| 17255 | 17342 | |
| 17256 | 17343 | switch (tld->id) { |
| 17257 | 17344 | case TldIdContainer: |
| 17258 | 17345 | case TldIdCompTime: |
| 17259 | 17346 | case TldIdUsingNamespace: |
| 17260 | 17347 | zig_unreachable(); |
| 17261 | case TldIdVar: | |
| 17262 | { | |
| 17348 | case TldIdVar: { | |
| 17263 | 17349 | TldVar *tld_var = (TldVar *)tld; |
| 17264 | 17350 | ZigVar *var = tld_var->var; |
| 17265 | 17351 | if (var == nullptr) { |
| ... | ... | @@ -17271,8 +17357,7 @@ static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_ |
| 17271 | 17357 | |
| 17272 | 17358 | return ir_get_var_ptr(ira, source_instruction, var); |
| 17273 | 17359 | } |
| 17274 | case TldIdFn: | |
| 17275 | { | |
| 17360 | case TldIdFn: { | |
| 17276 | 17361 | TldFn *tld_fn = (TldFn *)tld; |
| 17277 | 17362 | ZigFn *fn_entry = tld_fn->fn_entry; |
| 17278 | 17363 | assert(fn_entry->type_entry); |
| ... | ... | @@ -17396,7 +17481,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc |
| 17396 | 17481 | return ira->codegen->invalid_instruction; |
| 17397 | 17482 | } else if (is_container(child_type)) { |
| 17398 | 17483 | if (child_type->id == ZigTypeIdEnum) { |
| 17399 | if ((err = ensure_complete_type(ira->codegen, child_type))) | |
| 17484 | if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown))) | |
| 17400 | 17485 | return ira->codegen->invalid_instruction; |
| 17401 | 17486 | |
| 17402 | 17487 | TypeEnumField *field = find_enum_type_field(child_type, field_name); |
| ... | ... | @@ -17425,7 +17510,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc |
| 17425 | 17510 | (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr || |
| 17426 | 17511 | child_type->data.unionation.decl_node->data.container_decl.auto_enum)) |
| 17427 | 17512 | { |
| 17428 | if ((err = ensure_complete_type(ira->codegen, child_type))) | |
| 17513 | if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown))) | |
| 17429 | 17514 | return ira->codegen->invalid_instruction; |
| 17430 | 17515 | TypeUnionField *field = find_union_type_field(child_type, field_name); |
| 17431 | 17516 | if (field) { |
| ... | ... | @@ -17844,65 +17929,29 @@ static IrInstruction *ir_analyze_instruction_any_frame_type(IrAnalyze *ira, |
| 17844 | 17929 | static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 17845 | 17930 | IrInstructionSliceType *slice_type_instruction) |
| 17846 | 17931 | { |
| 17847 | Error err; | |
| 17848 | uint32_t align_bytes = 0; | |
| 17932 | IrInstruction *result = ir_const(ira, &slice_type_instruction->base, ira->codegen->builtin_types.entry_type); | |
| 17933 | result->value.special = ConstValSpecialLazy; | |
| 17934 | ||
| 17935 | LazyValueSliceType *lazy_slice_type = allocate<LazyValueSliceType>(1); | |
| 17936 | lazy_slice_type->ira = ira; | |
| 17937 | result->value.data.x_lazy = &lazy_slice_type->base; | |
| 17938 | lazy_slice_type->base.id = LazyValueIdSliceType; | |
| 17939 | ||
| 17849 | 17940 | if (slice_type_instruction->align_value != nullptr) { |
| 17850 | if (!ir_resolve_align(ira, slice_type_instruction->align_value->child, &align_bytes)) | |
| 17941 | lazy_slice_type->align_inst = slice_type_instruction->align_value->child; | |
| 17942 | if (ir_resolve_const(ira, lazy_slice_type->align_inst, LazyOk) == nullptr) | |
| 17851 | 17943 | return ira->codegen->invalid_instruction; |
| 17852 | 17944 | } |
| 17853 | 17945 | |
| 17854 | ZigType *child_type = ir_resolve_type(ira, slice_type_instruction->child_type->child); | |
| 17855 | if (type_is_invalid(child_type)) | |
| 17946 | lazy_slice_type->elem_type = slice_type_instruction->child_type->child; | |
| 17947 | if (ir_resolve_type_lazy(ira, lazy_slice_type->elem_type) == nullptr) | |
| 17856 | 17948 | return ira->codegen->invalid_instruction; |
| 17857 | 17949 | |
| 17858 | bool is_const = slice_type_instruction->is_const; | |
| 17859 | bool is_volatile = slice_type_instruction->is_volatile; | |
| 17860 | bool is_allow_zero = slice_type_instruction->is_allow_zero; | |
| 17950 | lazy_slice_type->is_const = slice_type_instruction->is_const; | |
| 17951 | lazy_slice_type->is_volatile = slice_type_instruction->is_volatile; | |
| 17952 | lazy_slice_type->is_allowzero = slice_type_instruction->is_allow_zero; | |
| 17861 | 17953 | |
| 17862 | switch (child_type->id) { | |
| 17863 | case ZigTypeIdInvalid: // handled above | |
| 17864 | zig_unreachable(); | |
| 17865 | case ZigTypeIdUnreachable: | |
| 17866 | case ZigTypeIdUndefined: | |
| 17867 | case ZigTypeIdNull: | |
| 17868 | case ZigTypeIdArgTuple: | |
| 17869 | case ZigTypeIdOpaque: | |
| 17870 | ir_add_error_node(ira, slice_type_instruction->base.source_node, | |
| 17871 | buf_sprintf("slice of type '%s' not allowed", buf_ptr(&child_type->name))); | |
| 17872 | return ira->codegen->invalid_instruction; | |
| 17873 | case ZigTypeIdMetaType: | |
| 17874 | case ZigTypeIdVoid: | |
| 17875 | case ZigTypeIdBool: | |
| 17876 | case ZigTypeIdInt: | |
| 17877 | case ZigTypeIdFloat: | |
| 17878 | case ZigTypeIdPointer: | |
| 17879 | case ZigTypeIdArray: | |
| 17880 | case ZigTypeIdStruct: | |
| 17881 | case ZigTypeIdComptimeFloat: | |
| 17882 | case ZigTypeIdComptimeInt: | |
| 17883 | case ZigTypeIdEnumLiteral: | |
| 17884 | case ZigTypeIdOptional: | |
| 17885 | case ZigTypeIdErrorUnion: | |
| 17886 | case ZigTypeIdErrorSet: | |
| 17887 | case ZigTypeIdEnum: | |
| 17888 | case ZigTypeIdUnion: | |
| 17889 | case ZigTypeIdFn: | |
| 17890 | case ZigTypeIdBoundFn: | |
| 17891 | case ZigTypeIdVector: | |
| 17892 | case ZigTypeIdFnFrame: | |
| 17893 | case ZigTypeIdAnyFrame: | |
| 17894 | { | |
| 17895 | ResolveStatus needed_status = (align_bytes == 0) ? | |
| 17896 | ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown; | |
| 17897 | if ((err = type_resolve(ira->codegen, child_type, needed_status))) | |
| 17898 | return ira->codegen->invalid_instruction; | |
| 17899 | ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, child_type, | |
| 17900 | is_const, is_volatile, PtrLenUnknown, align_bytes, 0, 0, is_allow_zero); | |
| 17901 | ZigType *result_type = get_slice_type(ira->codegen, slice_ptr_type); | |
| 17902 | return ir_const_type(ira, &slice_type_instruction->base, result_type); | |
| 17903 | } | |
| 17904 | } | |
| 17905 | zig_unreachable(); | |
| 17954 | return result; | |
| 17906 | 17955 | } |
| 17907 | 17956 | |
| 17908 | 17957 | static IrInstruction *ir_analyze_instruction_global_asm(IrAnalyze *ira, IrInstructionGlobalAsm *instruction) { |
| ... | ... | @@ -18008,7 +18057,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, |
| 18008 | 18057 | case ZigTypeIdFnFrame: |
| 18009 | 18058 | case ZigTypeIdAnyFrame: |
| 18010 | 18059 | { |
| 18011 | if ((err = ensure_complete_type(ira->codegen, child_type))) | |
| 18060 | if ((err = type_resolve(ira->codegen, child_type, ResolveStatusSizeKnown))) | |
| 18012 | 18061 | return ira->codegen->invalid_instruction; |
| 18013 | 18062 | ZigType *result_type = get_array_type(ira->codegen, child_type, size); |
| 18014 | 18063 | return ir_const_type(ira, &array_type_instruction->base, result_type); |
| ... | ... | @@ -18024,7 +18073,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 18024 | 18073 | IrInstruction *type_value = size_of_instruction->type_value->child; |
| 18025 | 18074 | ZigType *type_entry = ir_resolve_type(ira, type_value); |
| 18026 | 18075 | |
| 18027 | if ((err = ensure_complete_type(ira->codegen, type_entry))) | |
| 18076 | if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusSizeKnown))) | |
| 18028 | 18077 | return ira->codegen->invalid_instruction; |
| 18029 | 18078 | |
| 18030 | 18079 | switch (type_entry->id) { |
| ... | ... | @@ -18529,7 +18578,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 18529 | 18578 | if (pointee_val->special == ConstValSpecialRuntime) |
| 18530 | 18579 | pointee_val = nullptr; |
| 18531 | 18580 | } |
| 18532 | if ((err = ensure_complete_type(ira->codegen, target_type))) | |
| 18581 | if ((err = type_resolve(ira->codegen, target_type, ResolveStatusSizeKnown))) | |
| 18533 | 18582 | return ira->codegen->invalid_instruction; |
| 18534 | 18583 | |
| 18535 | 18584 | switch (target_type->id) { |
| ... | ... | @@ -19070,7 +19119,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc |
| 19070 | 19119 | Scope *analyze_scope = &get_container_scope(container_type)->base; |
| 19071 | 19120 | // memoize it |
| 19072 | 19121 | field->init_val = analyze_const_value(ira->codegen, analyze_scope, init_node, |
| 19073 | field->type_entry, nullptr); | |
| 19122 | field->type_entry, nullptr, UndefOk); | |
| 19074 | 19123 | } |
| 19075 | 19124 | if (type_is_invalid(field->init_val->type)) |
| 19076 | 19125 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -19276,8 +19325,7 @@ static IrInstruction *ir_analyze_instruction_compile_err(IrAnalyze *ira, |
| 19276 | 19325 | if (!msg_buf) |
| 19277 | 19326 | return ira->codegen->invalid_instruction; |
| 19278 | 19327 | |
| 19279 | ErrorMsg *msg = ir_add_error(ira, &instruction->base, msg_buf); | |
| 19280 | emit_error_notes_for_ref_stack(ira->codegen, msg); | |
| 19328 | ir_add_error(ira, &instruction->base, msg_buf); | |
| 19281 | 19329 | |
| 19282 | 19330 | return ira->codegen->invalid_instruction; |
| 19283 | 19331 | } |
| ... | ... | @@ -19319,7 +19367,10 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct |
| 19319 | 19367 | ZigType *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, |
| 19320 | 19368 | true, false, PtrLenUnknown, 0, 0, 0, false); |
| 19321 | 19369 | ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type); |
| 19322 | if (casted_value->value.special == ConstValSpecialStatic) { | |
| 19370 | if (instr_is_comptime(casted_value)) { | |
| 19371 | ConstExprValue *val = ir_resolve_const(ira, casted_value, UndefBad); | |
| 19372 | if (val == nullptr) | |
| 19373 | return ira->codegen->invalid_instruction; | |
| 19323 | 19374 | ErrorTableEntry *err = casted_value->value.data.x_err_set; |
| 19324 | 19375 | if (!err->cached_error_name_val) { |
| 19325 | 19376 | ConstExprValue *array_val = create_const_str_lit(ira->codegen, &err->name); |
| ... | ... | @@ -19391,7 +19442,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, |
| 19391 | 19442 | return ira->codegen->invalid_instruction; |
| 19392 | 19443 | } |
| 19393 | 19444 | |
| 19394 | if ((err = ensure_complete_type(ira->codegen, container_type))) | |
| 19445 | if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) | |
| 19395 | 19446 | return ira->codegen->invalid_instruction; |
| 19396 | 19447 | |
| 19397 | 19448 | TypeStructField *field = find_struct_type_field(container_type, field_name); |
| ... | ... | @@ -19470,7 +19521,7 @@ static TypeStructField *validate_byte_offset(IrAnalyze *ira, |
| 19470 | 19521 | return nullptr; |
| 19471 | 19522 | |
| 19472 | 19523 | Error err; |
| 19473 | if ((err = ensure_complete_type(ira->codegen, container_type))) | |
| 19524 | if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) | |
| 19474 | 19525 | return nullptr; |
| 19475 | 19526 | |
| 19476 | 19527 | Buf *field_name = ir_resolve_str(ira, field_name_value); |
| ... | ... | @@ -19574,11 +19625,9 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig |
| 19574 | 19625 | |
| 19575 | 19626 | ZigVar *var = tld->var; |
| 19576 | 19627 | |
| 19577 | if ((err = ensure_complete_type(ira->codegen, var->const_value->type))) | |
| 19578 | return ira->codegen->builtin_types.entry_invalid; | |
| 19579 | ||
| 19580 | 19628 | assert(var->const_value->type->id == ZigTypeIdMetaType); |
| 19581 | return var->const_value->data.x_type; | |
| 19629 | ||
| 19630 | return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, nullptr, var->const_value); | |
| 19582 | 19631 | } |
| 19583 | 19632 | |
| 19584 | 19633 | static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr, ConstExprValue *out_val, |
| ... | ... | @@ -19594,15 +19643,15 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr |
| 19594 | 19643 | ensure_field_index(type_info_declaration_type, "data", 2); |
| 19595 | 19644 | |
| 19596 | 19645 | ZigType *type_info_declaration_data_type = ir_type_info_get_type(ira, "Data", type_info_declaration_type); |
| 19597 | if ((err = ensure_complete_type(ira->codegen, type_info_declaration_data_type))) | |
| 19646 | if ((err = type_resolve(ira->codegen, type_info_declaration_data_type, ResolveStatusSizeKnown))) | |
| 19598 | 19647 | return err; |
| 19599 | 19648 | |
| 19600 | 19649 | ZigType *type_info_fn_decl_type = ir_type_info_get_type(ira, "FnDecl", type_info_declaration_data_type); |
| 19601 | if ((err = ensure_complete_type(ira->codegen, type_info_fn_decl_type))) | |
| 19650 | if ((err = type_resolve(ira->codegen, type_info_fn_decl_type, ResolveStatusSizeKnown))) | |
| 19602 | 19651 | return err; |
| 19603 | 19652 | |
| 19604 | 19653 | ZigType *type_info_fn_decl_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_decl_type); |
| 19605 | if ((err = ensure_complete_type(ira->codegen, type_info_fn_decl_inline_type))) | |
| 19654 | if ((err = type_resolve(ira->codegen, type_info_fn_decl_inline_type, ResolveStatusSizeKnown))) | |
| 19606 | 19655 | return err; |
| 19607 | 19656 | |
| 19608 | 19657 | // Loop through our declarations once to figure out how many declarations we will generate info for. |
| ... | ... | @@ -19613,7 +19662,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr |
| 19613 | 19662 | while ((curr_entry = decl_it.next()) != nullptr) { |
| 19614 | 19663 | // If the declaration is unresolved, force it to be resolved again. |
| 19615 | 19664 | if (curr_entry->value->resolution == TldResolutionUnresolved) { |
| 19616 | resolve_top_level_decl(ira->codegen, curr_entry->value, curr_entry->value->source_node); | |
| 19665 | resolve_top_level_decl(ira->codegen, curr_entry->value, curr_entry->value->source_node, false); | |
| 19617 | 19666 | if (curr_entry->value->resolution != TldResolutionOk) { |
| 19618 | 19667 | return ErrorSemanticAnalyzeFail; |
| 19619 | 19668 | } |
| ... | ... | @@ -19673,7 +19722,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr |
| 19673 | 19722 | case TldIdVar: |
| 19674 | 19723 | { |
| 19675 | 19724 | ZigVar *var = ((TldVar *)curr_entry->value)->var; |
| 19676 | if ((err = ensure_complete_type(ira->codegen, var->const_value->type))) | |
| 19725 | if ((err = type_resolve(ira->codegen, var->const_value->type, ResolveStatusSizeKnown))) | |
| 19677 | 19726 | return ErrorSemanticAnalyzeFail; |
| 19678 | 19727 | |
| 19679 | 19728 | if (var->const_value->type->id == ZigTypeIdMetaType) { |
| ... | ... | @@ -19799,7 +19848,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr |
| 19799 | 19848 | case TldIdContainer: |
| 19800 | 19849 | { |
| 19801 | 19850 | ZigType *type_entry = ((TldContainer *)curr_entry->value)->type_entry; |
| 19802 | if ((err = ensure_complete_type(ira->codegen, type_entry))) | |
| 19851 | if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusSizeKnown))) | |
| 19803 | 19852 | return ErrorSemanticAnalyzeFail; |
| 19804 | 19853 | |
| 19805 | 19854 | // This is a type. |
| ... | ... | @@ -19855,7 +19904,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty |
| 19855 | 19904 | return nullptr; |
| 19856 | 19905 | |
| 19857 | 19906 | ZigType *type_info_pointer_type = ir_type_info_get_type(ira, "Pointer", nullptr); |
| 19858 | assertNoError(ensure_complete_type(ira->codegen, type_info_pointer_type)); | |
| 19907 | assertNoError(type_resolve(ira->codegen, type_info_pointer_type, ResolveStatusSizeKnown)); | |
| 19859 | 19908 | |
| 19860 | 19909 | ConstExprValue *result = create_const_vals(1); |
| 19861 | 19910 | result->special = ConstValSpecialStatic; |
| ... | ... | @@ -19867,7 +19916,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty |
| 19867 | 19916 | // size: Size |
| 19868 | 19917 | ensure_field_index(result->type, "size", 0); |
| 19869 | 19918 | ZigType *type_info_pointer_size_type = ir_type_info_get_type(ira, "Size", type_info_pointer_type); |
| 19870 | assertNoError(ensure_complete_type(ira->codegen, type_info_pointer_size_type)); | |
| 19919 | assertNoError(type_resolve(ira->codegen, type_info_pointer_size_type, ResolveStatusSizeKnown)); | |
| 19871 | 19920 | fields[0].special = ConstValSpecialStatic; |
| 19872 | 19921 | fields[0].type = type_info_pointer_size_type; |
| 19873 | 19922 | bigint_init_unsigned(&fields[0].data.x_enum_tag, size_enum_index); |
| ... | ... | @@ -20345,6 +20394,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr |
| 20345 | 20394 | inner_fields[1].special = ConstValSpecialStatic; |
| 20346 | 20395 | inner_fields[1].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_num_lit_int); |
| 20347 | 20396 | |
| 20397 | ZigType *field_type = resolve_struct_field_type(ira->codegen, struct_field); | |
| 20398 | if (field_type == nullptr) | |
| 20399 | return ErrorSemanticAnalyzeFail; | |
| 20400 | if ((err = type_resolve(ira->codegen, field_type, ResolveStatusZeroBitsKnown))) | |
| 20401 | return err; | |
| 20348 | 20402 | if (!type_has_bits(struct_field->type_entry)) { |
| 20349 | 20403 | inner_fields[1].data.x_optional = nullptr; |
| 20350 | 20404 | } else { |
| ... | ... | @@ -20581,7 +20635,7 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct |
| 20581 | 20635 | ZigType *void_type = ira->codegen->builtin_types.entry_void; |
| 20582 | 20636 | ConstExprValue *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type, |
| 20583 | 20637 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, |
| 20584 | &cimport_scope->buf, block_node, nullptr, nullptr, nullptr); | |
| 20638 | &cimport_scope->buf, block_node, nullptr, nullptr, nullptr, UndefBad); | |
| 20585 | 20639 | if (type_is_invalid(cimport_result->type)) |
| 20586 | 20640 | return ira->codegen->invalid_instruction; |
| 20587 | 20641 | |
| ... | ... | @@ -21181,7 +21235,7 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru |
| 21181 | 21235 | |
| 21182 | 21236 | ConstExprValue *len_val = &val->data.x_struct.fields[slice_len_index]; |
| 21183 | 21237 | if (value_is_comptime(len_val)) { |
| 21184 | known_len = bigint_as_unsigned(&len_val->data.x_bigint); | |
| 21238 | known_len = bigint_as_u64(&len_val->data.x_bigint); | |
| 21185 | 21239 | have_known_len = true; |
| 21186 | 21240 | } |
| 21187 | 21241 | } |
| ... | ... | @@ -21482,64 +21536,75 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio |
| 21482 | 21536 | return ira->codegen->invalid_instruction; |
| 21483 | 21537 | |
| 21484 | 21538 | // TODO test this at comptime with u8 and non-u8 types |
| 21485 | if (casted_dest_ptr->value.special == ConstValSpecialStatic && | |
| 21486 | casted_byte->value.special == ConstValSpecialStatic && | |
| 21487 | casted_count->value.special == ConstValSpecialStatic && | |
| 21488 | casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr && | |
| 21489 | casted_dest_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) | |
| 21539 | if (instr_is_comptime(casted_dest_ptr) && | |
| 21540 | instr_is_comptime(casted_byte) && | |
| 21541 | instr_is_comptime(casted_count)) | |
| 21490 | 21542 | { |
| 21491 | ConstExprValue *dest_ptr_val = &casted_dest_ptr->value; | |
| 21543 | ConstExprValue *dest_ptr_val = ir_resolve_const(ira, casted_dest_ptr, UndefBad); | |
| 21544 | if (dest_ptr_val == nullptr) | |
| 21545 | return ira->codegen->invalid_instruction; | |
| 21492 | 21546 | |
| 21493 | ConstExprValue *dest_elements; | |
| 21494 | size_t start; | |
| 21495 | size_t bound_end; | |
| 21496 | switch (dest_ptr_val->data.x_ptr.special) { | |
| 21497 | case ConstPtrSpecialInvalid: | |
| 21498 | case ConstPtrSpecialDiscard: | |
| 21499 | zig_unreachable(); | |
| 21500 | case ConstPtrSpecialRef: | |
| 21501 | dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; | |
| 21502 | start = 0; | |
| 21503 | bound_end = 1; | |
| 21504 | break; | |
| 21505 | case ConstPtrSpecialBaseArray: | |
| 21506 | { | |
| 21507 | ConstExprValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; | |
| 21508 | expand_undef_array(ira->codegen, array_val); | |
| 21509 | dest_elements = array_val->data.x_array.data.s_none.elements; | |
| 21510 | start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; | |
| 21511 | bound_end = array_val->type->data.array.len; | |
| 21512 | break; | |
| 21513 | } | |
| 21514 | case ConstPtrSpecialBaseStruct: | |
| 21515 | zig_panic("TODO memset on const inner struct"); | |
| 21516 | case ConstPtrSpecialBaseErrorUnionCode: | |
| 21517 | zig_panic("TODO memset on const inner error union code"); | |
| 21518 | case ConstPtrSpecialBaseErrorUnionPayload: | |
| 21519 | zig_panic("TODO memset on const inner error union payload"); | |
| 21520 | case ConstPtrSpecialBaseOptionalPayload: | |
| 21521 | zig_panic("TODO memset on const inner optional payload"); | |
| 21522 | case ConstPtrSpecialHardCodedAddr: | |
| 21523 | zig_unreachable(); | |
| 21524 | case ConstPtrSpecialFunction: | |
| 21525 | zig_panic("TODO memset on ptr cast from function"); | |
| 21526 | case ConstPtrSpecialNull: | |
| 21527 | zig_panic("TODO memset on null ptr"); | |
| 21528 | } | |
| 21547 | ConstExprValue *byte_val = ir_resolve_const(ira, casted_byte, UndefOk); | |
| 21548 | if (byte_val == nullptr) | |
| 21549 | return ira->codegen->invalid_instruction; | |
| 21529 | 21550 | |
| 21530 | size_t count = bigint_as_unsigned(&casted_count->value.data.x_bigint); | |
| 21531 | size_t end = start + count; | |
| 21532 | if (end > bound_end) { | |
| 21533 | ir_add_error(ira, count_value, buf_sprintf("out of bounds pointer access")); | |
| 21551 | ConstExprValue *count_val = ir_resolve_const(ira, casted_count, UndefBad); | |
| 21552 | if (count_val == nullptr) | |
| 21534 | 21553 | return ira->codegen->invalid_instruction; |
| 21535 | } | |
| 21536 | 21554 | |
| 21537 | ConstExprValue *byte_val = &casted_byte->value; | |
| 21538 | for (size_t i = start; i < end; i += 1) { | |
| 21539 | copy_const_val(&dest_elements[i], byte_val, true); | |
| 21540 | } | |
| 21555 | if (casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr && | |
| 21556 | casted_dest_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) | |
| 21557 | { | |
| 21558 | ConstExprValue *dest_elements; | |
| 21559 | size_t start; | |
| 21560 | size_t bound_end; | |
| 21561 | switch (dest_ptr_val->data.x_ptr.special) { | |
| 21562 | case ConstPtrSpecialInvalid: | |
| 21563 | case ConstPtrSpecialDiscard: | |
| 21564 | zig_unreachable(); | |
| 21565 | case ConstPtrSpecialRef: | |
| 21566 | dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; | |
| 21567 | start = 0; | |
| 21568 | bound_end = 1; | |
| 21569 | break; | |
| 21570 | case ConstPtrSpecialBaseArray: | |
| 21571 | { | |
| 21572 | ConstExprValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; | |
| 21573 | expand_undef_array(ira->codegen, array_val); | |
| 21574 | dest_elements = array_val->data.x_array.data.s_none.elements; | |
| 21575 | start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; | |
| 21576 | bound_end = array_val->type->data.array.len; | |
| 21577 | break; | |
| 21578 | } | |
| 21579 | case ConstPtrSpecialBaseStruct: | |
| 21580 | zig_panic("TODO memset on const inner struct"); | |
| 21581 | case ConstPtrSpecialBaseErrorUnionCode: | |
| 21582 | zig_panic("TODO memset on const inner error union code"); | |
| 21583 | case ConstPtrSpecialBaseErrorUnionPayload: | |
| 21584 | zig_panic("TODO memset on const inner error union payload"); | |
| 21585 | case ConstPtrSpecialBaseOptionalPayload: | |
| 21586 | zig_panic("TODO memset on const inner optional payload"); | |
| 21587 | case ConstPtrSpecialHardCodedAddr: | |
| 21588 | zig_unreachable(); | |
| 21589 | case ConstPtrSpecialFunction: | |
| 21590 | zig_panic("TODO memset on ptr cast from function"); | |
| 21591 | case ConstPtrSpecialNull: | |
| 21592 | zig_panic("TODO memset on null ptr"); | |
| 21593 | } | |
| 21541 | 21594 | |
| 21542 | return ir_const_void(ira, &instruction->base); | |
| 21595 | size_t count = bigint_as_usize(&count_val->data.x_bigint); | |
| 21596 | size_t end = start + count; | |
| 21597 | if (end > bound_end) { | |
| 21598 | ir_add_error(ira, count_value, buf_sprintf("out of bounds pointer access")); | |
| 21599 | return ira->codegen->invalid_instruction; | |
| 21600 | } | |
| 21601 | ||
| 21602 | for (size_t i = start; i < end; i += 1) { | |
| 21603 | copy_const_val(&dest_elements[i], byte_val, true); | |
| 21604 | } | |
| 21605 | ||
| 21606 | return ir_const_void(ira, &instruction->base); | |
| 21607 | } | |
| 21543 | 21608 | } |
| 21544 | 21609 | |
| 21545 | 21610 | IrInstruction *result = ir_build_memset(&ira->new_irb, instruction->base.scope, instruction->base.source_node, |
| ... | ... | @@ -21607,107 +21672,118 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio |
| 21607 | 21672 | |
| 21608 | 21673 | // TODO test this at comptime with u8 and non-u8 types |
| 21609 | 21674 | // TODO test with dest ptr being a global runtime variable |
| 21610 | if (casted_dest_ptr->value.special == ConstValSpecialStatic && | |
| 21611 | casted_src_ptr->value.special == ConstValSpecialStatic && | |
| 21612 | casted_count->value.special == ConstValSpecialStatic && | |
| 21613 | casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) | |
| 21675 | if (instr_is_comptime(casted_dest_ptr) && | |
| 21676 | instr_is_comptime(casted_src_ptr) && | |
| 21677 | instr_is_comptime(casted_count)) | |
| 21614 | 21678 | { |
| 21615 | size_t count = bigint_as_unsigned(&casted_count->value.data.x_bigint); | |
| 21679 | ConstExprValue *dest_ptr_val = ir_resolve_const(ira, casted_dest_ptr, UndefBad); | |
| 21680 | if (dest_ptr_val == nullptr) | |
| 21681 | return ira->codegen->invalid_instruction; | |
| 21616 | 21682 | |
| 21617 | ConstExprValue *dest_ptr_val = &casted_dest_ptr->value; | |
| 21618 | ConstExprValue *dest_elements; | |
| 21619 | size_t dest_start; | |
| 21620 | size_t dest_end; | |
| 21621 | switch (dest_ptr_val->data.x_ptr.special) { | |
| 21622 | case ConstPtrSpecialInvalid: | |
| 21623 | case ConstPtrSpecialDiscard: | |
| 21624 | zig_unreachable(); | |
| 21625 | case ConstPtrSpecialRef: | |
| 21626 | dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; | |
| 21627 | dest_start = 0; | |
| 21628 | dest_end = 1; | |
| 21629 | break; | |
| 21630 | case ConstPtrSpecialBaseArray: | |
| 21631 | { | |
| 21632 | ConstExprValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; | |
| 21633 | expand_undef_array(ira->codegen, array_val); | |
| 21634 | dest_elements = array_val->data.x_array.data.s_none.elements; | |
| 21635 | dest_start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; | |
| 21636 | dest_end = array_val->type->data.array.len; | |
| 21637 | break; | |
| 21638 | } | |
| 21639 | case ConstPtrSpecialBaseStruct: | |
| 21640 | zig_panic("TODO memcpy on const inner struct"); | |
| 21641 | case ConstPtrSpecialBaseErrorUnionCode: | |
| 21642 | zig_panic("TODO memcpy on const inner error union code"); | |
| 21643 | case ConstPtrSpecialBaseErrorUnionPayload: | |
| 21644 | zig_panic("TODO memcpy on const inner error union payload"); | |
| 21645 | case ConstPtrSpecialBaseOptionalPayload: | |
| 21646 | zig_panic("TODO memcpy on const inner optional payload"); | |
| 21647 | case ConstPtrSpecialHardCodedAddr: | |
| 21648 | zig_unreachable(); | |
| 21649 | case ConstPtrSpecialFunction: | |
| 21650 | zig_panic("TODO memcpy on ptr cast from function"); | |
| 21651 | case ConstPtrSpecialNull: | |
| 21652 | zig_panic("TODO memcpy on null ptr"); | |
| 21653 | } | |
| 21683 | ConstExprValue *src_ptr_val = ir_resolve_const(ira, casted_src_ptr, UndefBad); | |
| 21684 | if (src_ptr_val == nullptr) | |
| 21685 | return ira->codegen->invalid_instruction; | |
| 21654 | 21686 | |
| 21655 | if (dest_start + count > dest_end) { | |
| 21656 | ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); | |
| 21687 | ConstExprValue *count_val = ir_resolve_const(ira, casted_count, UndefBad); | |
| 21688 | if (count_val == nullptr) | |
| 21657 | 21689 | return ira->codegen->invalid_instruction; |
| 21658 | } | |
| 21659 | 21690 | |
| 21660 | ConstExprValue *src_ptr_val = &casted_src_ptr->value; | |
| 21661 | ConstExprValue *src_elements; | |
| 21662 | size_t src_start; | |
| 21663 | size_t src_end; | |
| 21691 | if (dest_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { | |
| 21692 | size_t count = bigint_as_usize(&count_val->data.x_bigint); | |
| 21664 | 21693 | |
| 21665 | switch (src_ptr_val->data.x_ptr.special) { | |
| 21666 | case ConstPtrSpecialInvalid: | |
| 21667 | case ConstPtrSpecialDiscard: | |
| 21668 | zig_unreachable(); | |
| 21669 | case ConstPtrSpecialRef: | |
| 21670 | src_elements = src_ptr_val->data.x_ptr.data.ref.pointee; | |
| 21671 | src_start = 0; | |
| 21672 | src_end = 1; | |
| 21673 | break; | |
| 21674 | case ConstPtrSpecialBaseArray: | |
| 21675 | { | |
| 21676 | ConstExprValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val; | |
| 21677 | expand_undef_array(ira->codegen, array_val); | |
| 21678 | src_elements = array_val->data.x_array.data.s_none.elements; | |
| 21679 | src_start = src_ptr_val->data.x_ptr.data.base_array.elem_index; | |
| 21680 | src_end = array_val->type->data.array.len; | |
| 21694 | ConstExprValue *dest_elements; | |
| 21695 | size_t dest_start; | |
| 21696 | size_t dest_end; | |
| 21697 | switch (dest_ptr_val->data.x_ptr.special) { | |
| 21698 | case ConstPtrSpecialInvalid: | |
| 21699 | case ConstPtrSpecialDiscard: | |
| 21700 | zig_unreachable(); | |
| 21701 | case ConstPtrSpecialRef: | |
| 21702 | dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; | |
| 21703 | dest_start = 0; | |
| 21704 | dest_end = 1; | |
| 21681 | 21705 | break; |
| 21682 | } | |
| 21683 | case ConstPtrSpecialBaseStruct: | |
| 21684 | zig_panic("TODO memcpy on const inner struct"); | |
| 21685 | case ConstPtrSpecialBaseErrorUnionCode: | |
| 21686 | zig_panic("TODO memcpy on const inner error union code"); | |
| 21687 | case ConstPtrSpecialBaseErrorUnionPayload: | |
| 21688 | zig_panic("TODO memcpy on const inner error union payload"); | |
| 21689 | case ConstPtrSpecialBaseOptionalPayload: | |
| 21690 | zig_panic("TODO memcpy on const inner optional payload"); | |
| 21691 | case ConstPtrSpecialHardCodedAddr: | |
| 21692 | zig_unreachable(); | |
| 21693 | case ConstPtrSpecialFunction: | |
| 21694 | zig_panic("TODO memcpy on ptr cast from function"); | |
| 21695 | case ConstPtrSpecialNull: | |
| 21696 | zig_panic("TODO memcpy on null ptr"); | |
| 21697 | } | |
| 21706 | case ConstPtrSpecialBaseArray: | |
| 21707 | { | |
| 21708 | ConstExprValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; | |
| 21709 | expand_undef_array(ira->codegen, array_val); | |
| 21710 | dest_elements = array_val->data.x_array.data.s_none.elements; | |
| 21711 | dest_start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; | |
| 21712 | dest_end = array_val->type->data.array.len; | |
| 21713 | break; | |
| 21714 | } | |
| 21715 | case ConstPtrSpecialBaseStruct: | |
| 21716 | zig_panic("TODO memcpy on const inner struct"); | |
| 21717 | case ConstPtrSpecialBaseErrorUnionCode: | |
| 21718 | zig_panic("TODO memcpy on const inner error union code"); | |
| 21719 | case ConstPtrSpecialBaseErrorUnionPayload: | |
| 21720 | zig_panic("TODO memcpy on const inner error union payload"); | |
| 21721 | case ConstPtrSpecialBaseOptionalPayload: | |
| 21722 | zig_panic("TODO memcpy on const inner optional payload"); | |
| 21723 | case ConstPtrSpecialHardCodedAddr: | |
| 21724 | zig_unreachable(); | |
| 21725 | case ConstPtrSpecialFunction: | |
| 21726 | zig_panic("TODO memcpy on ptr cast from function"); | |
| 21727 | case ConstPtrSpecialNull: | |
| 21728 | zig_panic("TODO memcpy on null ptr"); | |
| 21729 | } | |
| 21698 | 21730 | |
| 21699 | if (src_start + count > src_end) { | |
| 21700 | ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); | |
| 21701 | return ira->codegen->invalid_instruction; | |
| 21702 | } | |
| 21731 | if (dest_start + count > dest_end) { | |
| 21732 | ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); | |
| 21733 | return ira->codegen->invalid_instruction; | |
| 21734 | } | |
| 21703 | 21735 | |
| 21704 | // TODO check for noalias violations - this should be generalized to work for any function | |
| 21736 | ConstExprValue *src_elements; | |
| 21737 | size_t src_start; | |
| 21738 | size_t src_end; | |
| 21705 | 21739 | |
| 21706 | for (size_t i = 0; i < count; i += 1) { | |
| 21707 | copy_const_val(&dest_elements[dest_start + i], &src_elements[src_start + i], true); | |
| 21708 | } | |
| 21740 | switch (src_ptr_val->data.x_ptr.special) { | |
| 21741 | case ConstPtrSpecialInvalid: | |
| 21742 | case ConstPtrSpecialDiscard: | |
| 21743 | zig_unreachable(); | |
| 21744 | case ConstPtrSpecialRef: | |
| 21745 | src_elements = src_ptr_val->data.x_ptr.data.ref.pointee; | |
| 21746 | src_start = 0; | |
| 21747 | src_end = 1; | |
| 21748 | break; | |
| 21749 | case ConstPtrSpecialBaseArray: | |
| 21750 | { | |
| 21751 | ConstExprValue *array_val = src_ptr_val->data.x_ptr.data.base_array.array_val; | |
| 21752 | expand_undef_array(ira->codegen, array_val); | |
| 21753 | src_elements = array_val->data.x_array.data.s_none.elements; | |
| 21754 | src_start = src_ptr_val->data.x_ptr.data.base_array.elem_index; | |
| 21755 | src_end = array_val->type->data.array.len; | |
| 21756 | break; | |
| 21757 | } | |
| 21758 | case ConstPtrSpecialBaseStruct: | |
| 21759 | zig_panic("TODO memcpy on const inner struct"); | |
| 21760 | case ConstPtrSpecialBaseErrorUnionCode: | |
| 21761 | zig_panic("TODO memcpy on const inner error union code"); | |
| 21762 | case ConstPtrSpecialBaseErrorUnionPayload: | |
| 21763 | zig_panic("TODO memcpy on const inner error union payload"); | |
| 21764 | case ConstPtrSpecialBaseOptionalPayload: | |
| 21765 | zig_panic("TODO memcpy on const inner optional payload"); | |
| 21766 | case ConstPtrSpecialHardCodedAddr: | |
| 21767 | zig_unreachable(); | |
| 21768 | case ConstPtrSpecialFunction: | |
| 21769 | zig_panic("TODO memcpy on ptr cast from function"); | |
| 21770 | case ConstPtrSpecialNull: | |
| 21771 | zig_panic("TODO memcpy on null ptr"); | |
| 21772 | } | |
| 21709 | 21773 | |
| 21710 | return ir_const_void(ira, &instruction->base); | |
| 21774 | if (src_start + count > src_end) { | |
| 21775 | ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); | |
| 21776 | return ira->codegen->invalid_instruction; | |
| 21777 | } | |
| 21778 | ||
| 21779 | // TODO check for noalias violations - this should be generalized to work for any function | |
| 21780 | ||
| 21781 | for (size_t i = 0; i < count; i += 1) { | |
| 21782 | copy_const_val(&dest_elements[dest_start + i], &src_elements[src_start + i], true); | |
| 21783 | } | |
| 21784 | ||
| 21785 | return ir_const_void(ira, &instruction->base); | |
| 21786 | } | |
| 21711 | 21787 | } |
| 21712 | 21788 | |
| 21713 | 21789 | IrInstruction *result = ir_build_memcpy(&ira->new_irb, instruction->base.scope, instruction->base.source_node, |
| ... | ... | @@ -21877,6 +21953,11 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 21877 | 21953 | if (slice_ptr == nullptr) |
| 21878 | 21954 | return ira->codegen->invalid_instruction; |
| 21879 | 21955 | |
| 21956 | if (slice_ptr->special == ConstValSpecialUndef) { | |
| 21957 | ir_add_error(ira, &instruction->base, buf_sprintf("slice of undefined")); | |
| 21958 | return ira->codegen->invalid_instruction; | |
| 21959 | } | |
| 21960 | ||
| 21880 | 21961 | parent_ptr = &slice_ptr->data.x_struct.fields[slice_ptr_index]; |
| 21881 | 21962 | if (parent_ptr->special == ConstValSpecialUndef) { |
| 21882 | 21963 | ir_add_error(ira, &instruction->base, buf_sprintf("slice of undefined")); |
| ... | ... | @@ -21897,7 +21978,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 21897 | 21978 | case ConstPtrSpecialBaseArray: |
| 21898 | 21979 | array_val = parent_ptr->data.x_ptr.data.base_array.array_val; |
| 21899 | 21980 | abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; |
| 21900 | rel_end = bigint_as_unsigned(&len_val->data.x_bigint); | |
| 21981 | rel_end = bigint_as_usize(&len_val->data.x_bigint); | |
| 21901 | 21982 | break; |
| 21902 | 21983 | case ConstPtrSpecialBaseStruct: |
| 21903 | 21984 | zig_panic("TODO slice const inner struct"); |
| ... | ... | @@ -21910,7 +21991,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 21910 | 21991 | case ConstPtrSpecialHardCodedAddr: |
| 21911 | 21992 | array_val = nullptr; |
| 21912 | 21993 | abs_offset = 0; |
| 21913 | rel_end = bigint_as_unsigned(&len_val->data.x_bigint); | |
| 21994 | rel_end = bigint_as_usize(&len_val->data.x_bigint); | |
| 21914 | 21995 | break; |
| 21915 | 21996 | case ConstPtrSpecialFunction: |
| 21916 | 21997 | zig_panic("TODO slice of slice cast from function"); |
| ... | ... | @@ -21921,7 +22002,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 21921 | 22002 | zig_unreachable(); |
| 21922 | 22003 | } |
| 21923 | 22004 | |
| 21924 | uint64_t start_scalar = bigint_as_unsigned(&casted_start->value.data.x_bigint); | |
| 22005 | uint64_t start_scalar = bigint_as_u64(&casted_start->value.data.x_bigint); | |
| 21925 | 22006 | if (!ptr_is_undef && start_scalar > rel_end) { |
| 21926 | 22007 | ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice")); |
| 21927 | 22008 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -21929,7 +22010,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 21929 | 22010 | |
| 21930 | 22011 | uint64_t end_scalar; |
| 21931 | 22012 | if (end) { |
| 21932 | end_scalar = bigint_as_unsigned(&end->value.data.x_bigint); | |
| 22013 | end_scalar = bigint_as_u64(&end->value.data.x_bigint); | |
| 21933 | 22014 | } else { |
| 21934 | 22015 | end_scalar = rel_end; |
| 21935 | 22016 | } |
| ... | ... | @@ -22021,7 +22102,7 @@ static IrInstruction *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInst |
| 22021 | 22102 | return ira->codegen->invalid_instruction; |
| 22022 | 22103 | ZigType *container_type = ir_resolve_type(ira, container); |
| 22023 | 22104 | |
| 22024 | if ((err = ensure_complete_type(ira->codegen, container_type))) | |
| 22105 | if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) | |
| 22025 | 22106 | return ira->codegen->invalid_instruction; |
| 22026 | 22107 | |
| 22027 | 22108 | uint64_t result; |
| ... | ... | @@ -22057,7 +22138,7 @@ static IrInstruction *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstr |
| 22057 | 22138 | if (type_is_invalid(container_type)) |
| 22058 | 22139 | return ira->codegen->invalid_instruction; |
| 22059 | 22140 | |
| 22060 | if ((err = ensure_complete_type(ira->codegen, container_type))) | |
| 22141 | if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) | |
| 22061 | 22142 | return ira->codegen->invalid_instruction; |
| 22062 | 22143 | |
| 22063 | 22144 | |
| ... | ... | @@ -22100,7 +22181,7 @@ static IrInstruction *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstr |
| 22100 | 22181 | if (type_is_invalid(container_type)) |
| 22101 | 22182 | return ira->codegen->invalid_instruction; |
| 22102 | 22183 | |
| 22103 | if ((err = ensure_complete_type(ira->codegen, container_type))) | |
| 22184 | if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) | |
| 22104 | 22185 | return ira->codegen->invalid_instruction; |
| 22105 | 22186 | |
| 22106 | 22187 | uint64_t member_index; |
| ... | ... | @@ -22249,53 +22330,24 @@ static IrInstruction *ir_analyze_instruction_frame_size(IrAnalyze *ira, IrInstru |
| 22249 | 22330 | } |
| 22250 | 22331 | |
| 22251 | 22332 | static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAlignOf *instruction) { |
| 22252 | Error err; | |
| 22253 | IrInstruction *type_value = instruction->type_value->child; | |
| 22254 | if (type_is_invalid(type_value->value.type)) | |
| 22255 | return ira->codegen->invalid_instruction; | |
| 22256 | ZigType *type_entry = ir_resolve_type(ira, type_value); | |
| 22333 | // Here we create a lazy value in order to avoid resolving the alignment of the type | |
| 22334 | // immediately. This avoids false positive dependency loops such as: | |
| 22335 | // const Node = struct { | |
| 22336 | // field: []align(@alignOf(Node)) Node, | |
| 22337 | // }; | |
| 22338 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_num_lit_int); | |
| 22339 | result->value.special = ConstValSpecialLazy; | |
| 22340 | ||
| 22341 | LazyValueAlignOf *lazy_align_of = allocate<LazyValueAlignOf>(1); | |
| 22342 | lazy_align_of->ira = ira; | |
| 22343 | result->value.data.x_lazy = &lazy_align_of->base; | |
| 22344 | lazy_align_of->base.id = LazyValueIdAlignOf; | |
| 22257 | 22345 | |
| 22258 | if ((err = type_resolve(ira->codegen, type_entry, ResolveStatusAlignmentKnown))) | |
| 22346 | lazy_align_of->target_type = instruction->type_value->child; | |
| 22347 | if (ir_resolve_type_lazy(ira, lazy_align_of->target_type) == nullptr) | |
| 22259 | 22348 | return ira->codegen->invalid_instruction; |
| 22260 | 22349 | |
| 22261 | switch (type_entry->id) { | |
| 22262 | case ZigTypeIdInvalid: | |
| 22263 | zig_unreachable(); | |
| 22264 | case ZigTypeIdMetaType: | |
| 22265 | case ZigTypeIdUnreachable: | |
| 22266 | case ZigTypeIdComptimeFloat: | |
| 22267 | case ZigTypeIdComptimeInt: | |
| 22268 | case ZigTypeIdEnumLiteral: | |
| 22269 | case ZigTypeIdUndefined: | |
| 22270 | case ZigTypeIdNull: | |
| 22271 | case ZigTypeIdBoundFn: | |
| 22272 | case ZigTypeIdArgTuple: | |
| 22273 | case ZigTypeIdVoid: | |
| 22274 | case ZigTypeIdOpaque: | |
| 22275 | ir_add_error(ira, instruction->type_value, | |
| 22276 | buf_sprintf("no align available for type '%s'", buf_ptr(&type_entry->name))); | |
| 22277 | return ira->codegen->invalid_instruction; | |
| 22278 | case ZigTypeIdBool: | |
| 22279 | case ZigTypeIdInt: | |
| 22280 | case ZigTypeIdFloat: | |
| 22281 | case ZigTypeIdPointer: | |
| 22282 | case ZigTypeIdArray: | |
| 22283 | case ZigTypeIdStruct: | |
| 22284 | case ZigTypeIdOptional: | |
| 22285 | case ZigTypeIdErrorUnion: | |
| 22286 | case ZigTypeIdErrorSet: | |
| 22287 | case ZigTypeIdEnum: | |
| 22288 | case ZigTypeIdUnion: | |
| 22289 | case ZigTypeIdFn: | |
| 22290 | case ZigTypeIdVector: | |
| 22291 | case ZigTypeIdFnFrame: | |
| 22292 | case ZigTypeIdAnyFrame: | |
| 22293 | { | |
| 22294 | uint64_t align_in_bytes = get_abi_alignment(ira->codegen, type_entry); | |
| 22295 | return ir_const_unsigned(ira, &instruction->base, align_in_bytes); | |
| 22296 | } | |
| 22297 | } | |
| 22298 | zig_unreachable(); | |
| 22350 | return result; | |
| 22299 | 22351 | } |
| 22300 | 22352 | |
| 22301 | 22353 | static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstructionOverflowOp *instruction) { |
| ... | ... | @@ -22359,13 +22411,26 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr |
| 22359 | 22411 | if (type_is_invalid(casted_result_ptr->value.type)) |
| 22360 | 22412 | return ira->codegen->invalid_instruction; |
| 22361 | 22413 | |
| 22362 | if (casted_op1->value.special == ConstValSpecialStatic && | |
| 22363 | casted_op2->value.special == ConstValSpecialStatic && | |
| 22364 | casted_result_ptr->value.special == ConstValSpecialStatic) | |
| 22414 | if (instr_is_comptime(casted_op1) && | |
| 22415 | instr_is_comptime(casted_op2) && | |
| 22416 | instr_is_comptime(casted_result_ptr)) | |
| 22365 | 22417 | { |
| 22366 | BigInt *op1_bigint = &casted_op1->value.data.x_bigint; | |
| 22367 | BigInt *op2_bigint = &casted_op2->value.data.x_bigint; | |
| 22368 | ConstExprValue *pointee_val = const_ptr_pointee(ira, ira->codegen, &casted_result_ptr->value, casted_result_ptr->source_node); | |
| 22418 | ConstExprValue *op1_val = ir_resolve_const(ira, casted_op1, UndefBad); | |
| 22419 | if (op1_val == nullptr) | |
| 22420 | return ira->codegen->invalid_instruction; | |
| 22421 | ||
| 22422 | ConstExprValue *op2_val = ir_resolve_const(ira, casted_op2, UndefBad); | |
| 22423 | if (op2_val == nullptr) | |
| 22424 | return ira->codegen->invalid_instruction; | |
| 22425 | ||
| 22426 | ConstExprValue *result_val = ir_resolve_const(ira, casted_result_ptr, UndefBad); | |
| 22427 | if (result_val == nullptr) | |
| 22428 | return ira->codegen->invalid_instruction; | |
| 22429 | ||
| 22430 | BigInt *op1_bigint = &op1_val->data.x_bigint; | |
| 22431 | BigInt *op2_bigint = &op2_val->data.x_bigint; | |
| 22432 | ConstExprValue *pointee_val = const_ptr_pointee(ira, ira->codegen, result_val, | |
| 22433 | casted_result_ptr->source_node); | |
| 22369 | 22434 | if (pointee_val == nullptr) |
| 22370 | 22435 | return ira->codegen->invalid_instruction; |
| 22371 | 22436 | BigInt *dest_bigint = &pointee_val->data.x_bigint; |
| ... | ... | @@ -22754,84 +22819,64 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct |
| 22754 | 22819 | AstNode *proto_node = instruction->base.source_node; |
| 22755 | 22820 | assert(proto_node->type == NodeTypeFnProto); |
| 22756 | 22821 | |
| 22822 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); | |
| 22823 | result->value.special = ConstValSpecialLazy; | |
| 22824 | ||
| 22825 | LazyValueFnType *lazy_fn_type = allocate<LazyValueFnType>(1); | |
| 22826 | lazy_fn_type->ira = ira; | |
| 22827 | result->value.data.x_lazy = &lazy_fn_type->base; | |
| 22828 | lazy_fn_type->base.id = LazyValueIdFnType; | |
| 22829 | ||
| 22757 | 22830 | if (proto_node->data.fn_proto.auto_err_set) { |
| 22758 | 22831 | ir_add_error(ira, &instruction->base, |
| 22759 | 22832 | buf_sprintf("inferring error set of return type valid only for function definitions")); |
| 22760 | 22833 | return ira->codegen->invalid_instruction; |
| 22761 | 22834 | } |
| 22762 | 22835 | |
| 22763 | FnTypeId fn_type_id = {0}; | |
| 22764 | init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length); | |
| 22836 | size_t param_count = proto_node->data.fn_proto.params.length; | |
| 22837 | lazy_fn_type->proto_node = proto_node; | |
| 22838 | lazy_fn_type->param_types = allocate<IrInstruction *>(param_count); | |
| 22765 | 22839 | |
| 22766 | for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) { | |
| 22767 | AstNode *param_node = proto_node->data.fn_proto.params.at(fn_type_id.next_param_index); | |
| 22840 | for (size_t param_index = 0; param_index < param_count; param_index += 1) { | |
| 22841 | AstNode *param_node = proto_node->data.fn_proto.params.at(param_index); | |
| 22768 | 22842 | assert(param_node->type == NodeTypeParamDecl); |
| 22769 | 22843 | |
| 22770 | 22844 | bool param_is_var_args = param_node->data.param_decl.is_var_args; |
| 22771 | 22845 | if (param_is_var_args) { |
| 22772 | if (fn_type_id.cc == CallingConventionC) { | |
| 22773 | fn_type_id.param_count = fn_type_id.next_param_index; | |
| 22774 | continue; | |
| 22775 | } else if (fn_type_id.cc == CallingConventionUnspecified) { | |
| 22776 | return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id)); | |
| 22846 | if (proto_node->data.fn_proto.cc == CallingConventionC) { | |
| 22847 | break; | |
| 22848 | } else if (proto_node->data.fn_proto.cc == CallingConventionUnspecified) { | |
| 22849 | lazy_fn_type->is_generic = true; | |
| 22850 | return result; | |
| 22777 | 22851 | } else { |
| 22778 | 22852 | zig_unreachable(); |
| 22779 | 22853 | } |
| 22780 | 22854 | } |
| 22781 | FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index]; | |
| 22782 | param_info->is_noalias = param_node->data.param_decl.is_noalias; | |
| 22783 | 22855 | |
| 22784 | if (instruction->param_types[fn_type_id.next_param_index] == nullptr) { | |
| 22785 | param_info->type = nullptr; | |
| 22786 | return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id)); | |
| 22787 | } else { | |
| 22788 | IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->child; | |
| 22789 | if (type_is_invalid(param_type_value->value.type)) | |
| 22790 | return ira->codegen->invalid_instruction; | |
| 22791 | ZigType *param_type = ir_resolve_type(ira, param_type_value); | |
| 22792 | switch (type_requires_comptime(ira->codegen, param_type)) { | |
| 22793 | case ReqCompTimeYes: | |
| 22794 | if (!calling_convention_allows_zig_types(fn_type_id.cc)) { | |
| 22795 | ir_add_error(ira, param_type_value, | |
| 22796 | buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'", | |
| 22797 | buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc))); | |
| 22798 | return ira->codegen->invalid_instruction; | |
| 22799 | } | |
| 22800 | param_info->type = param_type; | |
| 22801 | fn_type_id.next_param_index += 1; | |
| 22802 | return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id)); | |
| 22803 | case ReqCompTimeInvalid: | |
| 22804 | return ira->codegen->invalid_instruction; | |
| 22805 | case ReqCompTimeNo: | |
| 22806 | break; | |
| 22807 | } | |
| 22808 | if (!type_has_bits(param_type) && !calling_convention_allows_zig_types(fn_type_id.cc)) { | |
| 22809 | ir_add_error(ira, param_type_value, | |
| 22810 | buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'", | |
| 22811 | buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc))); | |
| 22812 | return ira->codegen->invalid_instruction; | |
| 22813 | } | |
| 22814 | param_info->type = param_type; | |
| 22856 | if (instruction->param_types[param_index] == nullptr) { | |
| 22857 | lazy_fn_type->is_generic = true; | |
| 22858 | return result; | |
| 22815 | 22859 | } |
| 22816 | 22860 | |
| 22861 | IrInstruction *param_type_value = instruction->param_types[param_index]->child; | |
| 22862 | if (type_is_invalid(param_type_value->value.type)) | |
| 22863 | return ira->codegen->invalid_instruction; | |
| 22864 | if (ir_resolve_const(ira, param_type_value, LazyOk) == nullptr) | |
| 22865 | return ira->codegen->invalid_instruction; | |
| 22866 | lazy_fn_type->param_types[param_index] = param_type_value; | |
| 22817 | 22867 | } |
| 22818 | 22868 | |
| 22819 | 22869 | if (instruction->align_value != nullptr) { |
| 22820 | if (!ir_resolve_align(ira, instruction->align_value->child, &fn_type_id.alignment)) | |
| 22870 | lazy_fn_type->align_inst = instruction->align_value->child; | |
| 22871 | if (ir_resolve_const(ira, lazy_fn_type->align_inst, LazyOk) == nullptr) | |
| 22821 | 22872 | return ira->codegen->invalid_instruction; |
| 22822 | 22873 | } |
| 22823 | 22874 | |
| 22824 | IrInstruction *return_type_value = instruction->return_type->child; | |
| 22825 | fn_type_id.return_type = ir_resolve_type(ira, return_type_value); | |
| 22826 | if (type_is_invalid(fn_type_id.return_type)) | |
| 22827 | return ira->codegen->invalid_instruction; | |
| 22828 | if (fn_type_id.return_type->id == ZigTypeIdOpaque) { | |
| 22829 | ir_add_error(ira, instruction->return_type, | |
| 22830 | buf_sprintf("return type cannot be opaque")); | |
| 22831 | return ira->codegen->invalid_instruction; | |
| 22832 | } | |
| 22875 | lazy_fn_type->return_type = instruction->return_type->child; | |
| 22876 | if (ir_resolve_const(ira, lazy_fn_type->return_type, LazyOk) == nullptr) | |
| 22877 | return ira->codegen->invalid_instruction; | |
| 22833 | 22878 | |
| 22834 | return ir_const_type(ira, &instruction->base, get_fn_type(ira->codegen, &fn_type_id)); | |
| 22879 | return result; | |
| 22835 | 22880 | } |
| 22836 | 22881 | |
| 22837 | 22882 | static IrInstruction *ir_analyze_instruction_test_comptime(IrAnalyze *ira, IrInstructionTestComptime *instruction) { |
| ... | ... | @@ -23218,7 +23263,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ |
| 23218 | 23263 | if (!val) |
| 23219 | 23264 | return ira->codegen->invalid_instruction; |
| 23220 | 23265 | |
| 23221 | if (val->special == ConstValSpecialStatic) { | |
| 23266 | if (value_is_comptime(val) && val->special != ConstValSpecialUndef) { | |
| 23222 | 23267 | bool is_addr_zero = val->data.x_ptr.special == ConstPtrSpecialNull || |
| 23223 | 23268 | (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && |
| 23224 | 23269 | val->data.x_ptr.data.hard_coded_addr.addr == 0); |
| ... | ... | @@ -23258,6 +23303,12 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ |
| 23258 | 23303 | |
| 23259 | 23304 | IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr, safety_check_on); |
| 23260 | 23305 | |
| 23306 | if ((err = type_resolve(ira->codegen, dest_type, ResolveStatusZeroBitsKnown))) | |
| 23307 | return ira->codegen->invalid_instruction; | |
| 23308 | ||
| 23309 | if ((err = type_resolve(ira->codegen, src_type, ResolveStatusZeroBitsKnown))) | |
| 23310 | return ira->codegen->invalid_instruction; | |
| 23311 | ||
| 23261 | 23312 | if (type_has_bits(dest_type) && !type_has_bits(src_type)) { |
| 23262 | 23313 | ErrorMsg *msg = ir_add_error(ira, source_instr, |
| 23263 | 23314 | buf_sprintf("'%s' and '%s' do not have the same in-memory representation", |
| ... | ... | @@ -23309,8 +23360,10 @@ static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ConstExp |
| 23309 | 23360 | } |
| 23310 | 23361 | |
| 23311 | 23362 | static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) { |
| 23312 | if (val->special == ConstValSpecialUndef) | |
| 23363 | if (val->special == ConstValSpecialUndef) { | |
| 23364 | expand_undef_struct(codegen, val); | |
| 23313 | 23365 | val->special = ConstValSpecialStatic; |
| 23366 | } | |
| 23314 | 23367 | assert(val->special == ConstValSpecialStatic); |
| 23315 | 23368 | switch (val->type->id) { |
| 23316 | 23369 | case ZigTypeIdInvalid: |
| ... | ... | @@ -23500,7 +23553,7 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou |
| 23500 | 23553 | BigInt bn; |
| 23501 | 23554 | bigint_read_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, |
| 23502 | 23555 | codegen->is_big_endian, false); |
| 23503 | val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_unsigned(&bn); | |
| 23556 | val->data.x_ptr.data.hard_coded_addr.addr = bigint_as_usize(&bn); | |
| 23504 | 23557 | return ErrorNone; |
| 23505 | 23558 | } |
| 23506 | 23559 | case ZigTypeIdArray: |
| ... | ... | @@ -23693,7 +23746,7 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc |
| 23693 | 23746 | if (!val) |
| 23694 | 23747 | return ira->codegen->invalid_instruction; |
| 23695 | 23748 | |
| 23696 | uint64_t addr = bigint_as_unsigned(&val->data.x_bigint); | |
| 23749 | uint64_t addr = bigint_as_u64(&val->data.x_bigint); | |
| 23697 | 23750 | if (!ptr_allows_addr_zero(ptr_type) && addr == 0) { |
| 23698 | 23751 | ir_add_error(ira, source_instr, |
| 23699 | 23752 | buf_sprintf("pointer type '%s' does not allow address zero", buf_ptr(&ptr_type->name))); |
| ... | ... | @@ -23746,8 +23799,9 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, |
| 23746 | 23799 | IrInstructionDeclRef *instruction) |
| 23747 | 23800 | { |
| 23748 | 23801 | IrInstruction *ref_instruction = ir_analyze_decl_ref(ira, &instruction->base, instruction->tld); |
| 23749 | if (type_is_invalid(ref_instruction->value.type)) | |
| 23802 | if (type_is_invalid(ref_instruction->value.type)) { | |
| 23750 | 23803 | return ira->codegen->invalid_instruction; |
| 23804 | } | |
| 23751 | 23805 | |
| 23752 | 23806 | if (instruction->lval == LValPtr) { |
| 23753 | 23807 | return ref_instruction; |
| ... | ... | @@ -23795,53 +23849,32 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru |
| 23795 | 23849 | } |
| 23796 | 23850 | |
| 23797 | 23851 | static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstructionPtrType *instruction) { |
| 23798 | Error err; | |
| 23799 | ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child); | |
| 23800 | if (type_is_invalid(child_type)) | |
| 23801 | return ira->codegen->invalid_instruction; | |
| 23852 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); | |
| 23853 | result->value.special = ConstValSpecialLazy; | |
| 23802 | 23854 | |
| 23803 | if (child_type->id == ZigTypeIdUnreachable) { | |
| 23804 | ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed")); | |
| 23805 | return ira->codegen->invalid_instruction; | |
| 23806 | } else if (child_type->id == ZigTypeIdOpaque && instruction->ptr_len == PtrLenUnknown) { | |
| 23807 | ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque")); | |
| 23855 | LazyValuePtrType *lazy_ptr_type = allocate<LazyValuePtrType>(1); | |
| 23856 | lazy_ptr_type->ira = ira; | |
| 23857 | result->value.data.x_lazy = &lazy_ptr_type->base; | |
| 23858 | lazy_ptr_type->base.id = LazyValueIdPtrType; | |
| 23859 | ||
| 23860 | lazy_ptr_type->elem_type = instruction->child_type->child; | |
| 23861 | if (ir_resolve_type_lazy(ira, lazy_ptr_type->elem_type) == nullptr) | |
| 23808 | 23862 | return ira->codegen->invalid_instruction; |
| 23809 | } else if (instruction->ptr_len == PtrLenC) { | |
| 23810 | if (!type_allowed_in_extern(ira->codegen, child_type)) { | |
| 23811 | ir_add_error(ira, &instruction->base, | |
| 23812 | buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", buf_ptr(&child_type->name))); | |
| 23813 | return ira->codegen->invalid_instruction; | |
| 23814 | } else if (child_type->id == ZigTypeIdOpaque) { | |
| 23815 | ir_add_error(ira, &instruction->base, buf_sprintf("C pointers cannot point opaque types")); | |
| 23816 | return ira->codegen->invalid_instruction; | |
| 23817 | } else if (instruction->is_allow_zero) { | |
| 23818 | ir_add_error(ira, &instruction->base, buf_sprintf("C pointers always allow address zero")); | |
| 23819 | return ira->codegen->invalid_instruction; | |
| 23820 | } | |
| 23821 | } | |
| 23822 | 23863 | |
| 23823 | uint32_t align_bytes; | |
| 23824 | 23864 | if (instruction->align_value != nullptr) { |
| 23825 | if (!ir_resolve_align(ira, instruction->align_value->child, &align_bytes)) | |
| 23865 | lazy_ptr_type->align_inst = instruction->align_value->child; | |
| 23866 | if (ir_resolve_const(ira, lazy_ptr_type->align_inst, LazyOk) == nullptr) | |
| 23826 | 23867 | return ira->codegen->invalid_instruction; |
| 23827 | if ((err = type_resolve(ira->codegen, child_type, ResolveStatusAlignmentKnown))) | |
| 23828 | return ira->codegen->invalid_instruction; | |
| 23829 | if (!type_has_bits(child_type)) { | |
| 23830 | align_bytes = 0; | |
| 23831 | } | |
| 23832 | } else { | |
| 23833 | if ((err = type_resolve(ira->codegen, child_type, ResolveStatusZeroBitsKnown))) | |
| 23834 | return ira->codegen->invalid_instruction; | |
| 23835 | align_bytes = 0; | |
| 23836 | 23868 | } |
| 23837 | 23869 | |
| 23838 | bool allow_zero = instruction->is_allow_zero || instruction->ptr_len == PtrLenC; | |
| 23870 | lazy_ptr_type->ptr_len = instruction->ptr_len; | |
| 23871 | lazy_ptr_type->is_const = instruction->is_const; | |
| 23872 | lazy_ptr_type->is_volatile = instruction->is_volatile; | |
| 23873 | lazy_ptr_type->is_allowzero = instruction->is_allow_zero; | |
| 23874 | lazy_ptr_type->bit_offset_in_host = instruction->bit_offset_start; | |
| 23875 | lazy_ptr_type->host_int_bytes = instruction->host_int_bytes; | |
| 23839 | 23876 | |
| 23840 | ZigType *result_type = get_pointer_to_type_extra(ira->codegen, child_type, | |
| 23841 | instruction->is_const, instruction->is_volatile, | |
| 23842 | instruction->ptr_len, align_bytes, | |
| 23843 | instruction->bit_offset_start, instruction->host_int_bytes, allow_zero); | |
| 23844 | return ir_const_type(ira, &instruction->base, result_type); | |
| 23877 | return result; | |
| 23845 | 23878 | } |
| 23846 | 23879 | |
| 23847 | 23880 | static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) { |
| ... | ... | @@ -23954,7 +23987,7 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct |
| 23954 | 23987 | return ira->codegen->invalid_instruction; |
| 23955 | 23988 | |
| 23956 | 23989 | if (enum_type->id == ZigTypeIdEnum) { |
| 23957 | if ((err = ensure_complete_type(ira->codegen, enum_type))) | |
| 23990 | if ((err = type_resolve(ira->codegen, enum_type, ResolveStatusSizeKnown))) | |
| 23958 | 23991 | return ira->codegen->invalid_instruction; |
| 23959 | 23992 | |
| 23960 | 23993 | return ir_const_type(ira, &instruction->base, enum_type->data.enumeration.tag_int_type); |
| ... | ... | @@ -25100,7 +25133,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 25100 | 25133 | ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_exec, |
| 25101 | 25134 | ZigType *expected_type, AstNode *expected_type_source_node) |
| 25102 | 25135 | { |
| 25103 | assert(!old_exec->invalid); | |
| 25136 | assert(old_exec->first_err_trace_msg == nullptr); | |
| 25104 | 25137 | assert(expected_type == nullptr || !type_is_invalid(expected_type)); |
| 25105 | 25138 | |
| 25106 | 25139 | IrAnalyze *ira = allocate<IrAnalyze>(1); |
| ... | ... | @@ -25147,6 +25180,18 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ |
| 25147 | 25180 | old_instruction->child = new_instruction; |
| 25148 | 25181 | |
| 25149 | 25182 | if (type_is_invalid(new_instruction->value.type)) { |
| 25183 | if (new_exec->first_err_trace_msg != nullptr) { | |
| 25184 | ira->codegen->trace_err = new_exec->first_err_trace_msg; | |
| 25185 | } else { | |
| 25186 | new_exec->first_err_trace_msg = ira->codegen->trace_err; | |
| 25187 | } | |
| 25188 | if (new_exec->first_err_trace_msg != nullptr && | |
| 25189 | !old_instruction->source_node->already_traced_this_node) | |
| 25190 | { | |
| 25191 | old_instruction->source_node->already_traced_this_node = true; | |
| 25192 | new_exec->first_err_trace_msg = add_error_note(ira->codegen, new_exec->first_err_trace_msg, | |
| 25193 | old_instruction->source_node, buf_create_from_str("referenced here")); | |
| 25194 | } | |
| 25150 | 25195 | return ira->codegen->builtin_types.entry_invalid; |
| 25151 | 25196 | } |
| 25152 | 25197 | |
| ... | ... | @@ -25158,7 +25203,15 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ |
| 25158 | 25203 | ira->instruction_index += 1; |
| 25159 | 25204 | } |
| 25160 | 25205 | |
| 25161 | if (new_exec->invalid) { | |
| 25206 | if (new_exec->first_err_trace_msg != nullptr) { | |
| 25207 | codegen->trace_err = new_exec->first_err_trace_msg; | |
| 25208 | if (codegen->trace_err != nullptr && new_exec->source_node != nullptr && | |
| 25209 | !new_exec->source_node->already_traced_this_node) | |
| 25210 | { | |
| 25211 | new_exec->source_node->already_traced_this_node = true; | |
| 25212 | codegen->trace_err = add_error_note(codegen, codegen->trace_err, | |
| 25213 | new_exec->source_node, buf_create_from_str("referenced here")); | |
| 25214 | } | |
| 25162 | 25215 | return ira->codegen->builtin_types.entry_invalid; |
| 25163 | 25216 | } else if (ira->src_implicit_return_type_list.length == 0) { |
| 25164 | 25217 | return codegen->builtin_types.entry_unreachable; |
| ... | ... | @@ -25354,3 +25407,336 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 25354 | 25407 | } |
| 25355 | 25408 | zig_unreachable(); |
| 25356 | 25409 | } |
| 25410 | ||
| 25411 | static ZigType *ir_resolve_lazy_fn_type(IrAnalyze *ira, AstNode *source_node, LazyValueFnType *lazy_fn_type) { | |
| 25412 | Error err; | |
| 25413 | AstNode *proto_node = lazy_fn_type->proto_node; | |
| 25414 | ||
| 25415 | FnTypeId fn_type_id = {0}; | |
| 25416 | init_fn_type_id(&fn_type_id, proto_node, proto_node->data.fn_proto.params.length); | |
| 25417 | ||
| 25418 | for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) { | |
| 25419 | AstNode *param_node = proto_node->data.fn_proto.params.at(fn_type_id.next_param_index); | |
| 25420 | assert(param_node->type == NodeTypeParamDecl); | |
| 25421 | ||
| 25422 | bool param_is_var_args = param_node->data.param_decl.is_var_args; | |
| 25423 | if (param_is_var_args) { | |
| 25424 | if (fn_type_id.cc == CallingConventionC) { | |
| 25425 | fn_type_id.param_count = fn_type_id.next_param_index; | |
| 25426 | continue; | |
| 25427 | } else if (fn_type_id.cc == CallingConventionUnspecified) { | |
| 25428 | return get_generic_fn_type(ira->codegen, &fn_type_id); | |
| 25429 | } else { | |
| 25430 | zig_unreachable(); | |
| 25431 | } | |
| 25432 | } | |
| 25433 | FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index]; | |
| 25434 | param_info->is_noalias = param_node->data.param_decl.is_noalias; | |
| 25435 | ||
| 25436 | if (lazy_fn_type->param_types[fn_type_id.next_param_index] == nullptr) { | |
| 25437 | param_info->type = nullptr; | |
| 25438 | return get_generic_fn_type(ira->codegen, &fn_type_id); | |
| 25439 | } else { | |
| 25440 | IrInstruction *param_type_inst = lazy_fn_type->param_types[fn_type_id.next_param_index]; | |
| 25441 | ZigType *param_type = ir_resolve_type(ira, param_type_inst); | |
| 25442 | if (type_is_invalid(param_type)) | |
| 25443 | return nullptr; | |
| 25444 | switch (type_requires_comptime(ira->codegen, param_type)) { | |
| 25445 | case ReqCompTimeYes: | |
| 25446 | if (!calling_convention_allows_zig_types(fn_type_id.cc)) { | |
| 25447 | ir_add_error(ira, param_type_inst, | |
| 25448 | buf_sprintf("parameter of type '%s' not allowed in function with calling convention '%s'", | |
| 25449 | buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc))); | |
| 25450 | return nullptr; | |
| 25451 | } | |
| 25452 | param_info->type = param_type; | |
| 25453 | fn_type_id.next_param_index += 1; | |
| 25454 | return get_generic_fn_type(ira->codegen, &fn_type_id); | |
| 25455 | case ReqCompTimeInvalid: | |
| 25456 | return nullptr; | |
| 25457 | case ReqCompTimeNo: | |
| 25458 | break; | |
| 25459 | } | |
| 25460 | if (!calling_convention_allows_zig_types(fn_type_id.cc)) { | |
| 25461 | if ((err = type_resolve(ira->codegen, param_type, ResolveStatusZeroBitsKnown))) | |
| 25462 | return nullptr; | |
| 25463 | if (!type_has_bits(param_type)) { | |
| 25464 | ir_add_error(ira, param_type_inst, | |
| 25465 | buf_sprintf("parameter of type '%s' has 0 bits; not allowed in function with calling convention '%s'", | |
| 25466 | buf_ptr(&param_type->name), calling_convention_name(fn_type_id.cc))); | |
| 25467 | return nullptr; | |
| 25468 | } | |
| 25469 | } | |
| 25470 | param_info->type = param_type; | |
| 25471 | } | |
| 25472 | } | |
| 25473 | ||
| 25474 | if (lazy_fn_type->align_inst != nullptr) { | |
| 25475 | if (!ir_resolve_align(ira, lazy_fn_type->align_inst, &fn_type_id.alignment)) | |
| 25476 | return nullptr; | |
| 25477 | } | |
| 25478 | ||
| 25479 | fn_type_id.return_type = ir_resolve_type(ira, lazy_fn_type->return_type); | |
| 25480 | if (type_is_invalid(fn_type_id.return_type)) | |
| 25481 | return nullptr; | |
| 25482 | if (fn_type_id.return_type->id == ZigTypeIdOpaque) { | |
| 25483 | ir_add_error(ira, lazy_fn_type->return_type, buf_create_from_str("return type cannot be opaque")); | |
| 25484 | return nullptr; | |
| 25485 | } | |
| 25486 | ||
| 25487 | return get_fn_type(ira->codegen, &fn_type_id); | |
| 25488 | } | |
| 25489 | ||
| 25490 | static Error ir_resolve_lazy_raw(AstNode *source_node, ConstExprValue *val) { | |
| 25491 | Error err; | |
| 25492 | if (val->special != ConstValSpecialLazy) | |
| 25493 | return ErrorNone; | |
| 25494 | switch (val->data.x_lazy->id) { | |
| 25495 | case LazyValueIdInvalid: | |
| 25496 | zig_unreachable(); | |
| 25497 | case LazyValueIdAlignOf: { | |
| 25498 | LazyValueAlignOf *lazy_align_of = reinterpret_cast<LazyValueAlignOf *>(val->data.x_lazy); | |
| 25499 | IrAnalyze *ira = lazy_align_of->ira; | |
| 25500 | ||
| 25501 | if (lazy_align_of->target_type->value.special == ConstValSpecialStatic) { | |
| 25502 | switch (lazy_align_of->target_type->value.data.x_type->id) { | |
| 25503 | case ZigTypeIdInvalid: | |
| 25504 | zig_unreachable(); | |
| 25505 | case ZigTypeIdMetaType: | |
| 25506 | case ZigTypeIdUnreachable: | |
| 25507 | case ZigTypeIdComptimeFloat: | |
| 25508 | case ZigTypeIdComptimeInt: | |
| 25509 | case ZigTypeIdEnumLiteral: | |
| 25510 | case ZigTypeIdUndefined: | |
| 25511 | case ZigTypeIdNull: | |
| 25512 | case ZigTypeIdBoundFn: | |
| 25513 | case ZigTypeIdArgTuple: | |
| 25514 | case ZigTypeIdVoid: | |
| 25515 | case ZigTypeIdOpaque: | |
| 25516 | ir_add_error(ira, lazy_align_of->target_type, | |
| 25517 | buf_sprintf("no align available for type '%s'", | |
| 25518 | buf_ptr(&lazy_align_of->target_type->value.data.x_type->name))); | |
| 25519 | return ErrorSemanticAnalyzeFail; | |
| 25520 | case ZigTypeIdBool: | |
| 25521 | case ZigTypeIdInt: | |
| 25522 | case ZigTypeIdFloat: | |
| 25523 | case ZigTypeIdPointer: | |
| 25524 | case ZigTypeIdArray: | |
| 25525 | case ZigTypeIdStruct: | |
| 25526 | case ZigTypeIdOptional: | |
| 25527 | case ZigTypeIdErrorUnion: | |
| 25528 | case ZigTypeIdErrorSet: | |
| 25529 | case ZigTypeIdEnum: | |
| 25530 | case ZigTypeIdUnion: | |
| 25531 | case ZigTypeIdFn: | |
| 25532 | case ZigTypeIdVector: | |
| 25533 | case ZigTypeIdFnFrame: | |
| 25534 | case ZigTypeIdAnyFrame: | |
| 25535 | break; | |
| 25536 | } | |
| 25537 | } | |
| 25538 | ||
| 25539 | uint32_t align_in_bytes; | |
| 25540 | if ((err = type_val_resolve_abi_align(ira->codegen, &lazy_align_of->target_type->value, | |
| 25541 | &align_in_bytes))) | |
| 25542 | { | |
| 25543 | return err; | |
| 25544 | } | |
| 25545 | ||
| 25546 | val->special = ConstValSpecialStatic; | |
| 25547 | assert(val->type->id == ZigTypeIdComptimeInt); | |
| 25548 | bigint_init_unsigned(&val->data.x_bigint, align_in_bytes); | |
| 25549 | return ErrorNone; | |
| 25550 | } | |
| 25551 | case LazyValueIdSliceType: { | |
| 25552 | LazyValueSliceType *lazy_slice_type = reinterpret_cast<LazyValueSliceType *>(val->data.x_lazy); | |
| 25553 | IrAnalyze *ira = lazy_slice_type->ira; | |
| 25554 | ||
| 25555 | uint32_t align_bytes = 0; | |
| 25556 | if (lazy_slice_type->align_inst != nullptr) { | |
| 25557 | if (!ir_resolve_align(ira, lazy_slice_type->align_inst, &align_bytes)) | |
| 25558 | return ErrorSemanticAnalyzeFail; | |
| 25559 | } | |
| 25560 | ZigType *elem_type = ir_resolve_type(ira, lazy_slice_type->elem_type); | |
| 25561 | if (type_is_invalid(elem_type)) | |
| 25562 | return ErrorSemanticAnalyzeFail; | |
| 25563 | ||
| 25564 | switch (elem_type->id) { | |
| 25565 | case ZigTypeIdInvalid: // handled above | |
| 25566 | zig_unreachable(); | |
| 25567 | case ZigTypeIdUnreachable: | |
| 25568 | case ZigTypeIdUndefined: | |
| 25569 | case ZigTypeIdNull: | |
| 25570 | case ZigTypeIdArgTuple: | |
| 25571 | case ZigTypeIdOpaque: | |
| 25572 | ir_add_error(ira, lazy_slice_type->elem_type, | |
| 25573 | buf_sprintf("slice of type '%s' not allowed", buf_ptr(&elem_type->name))); | |
| 25574 | return ErrorSemanticAnalyzeFail; | |
| 25575 | case ZigTypeIdMetaType: | |
| 25576 | case ZigTypeIdVoid: | |
| 25577 | case ZigTypeIdBool: | |
| 25578 | case ZigTypeIdInt: | |
| 25579 | case ZigTypeIdFloat: | |
| 25580 | case ZigTypeIdPointer: | |
| 25581 | case ZigTypeIdArray: | |
| 25582 | case ZigTypeIdStruct: | |
| 25583 | case ZigTypeIdComptimeFloat: | |
| 25584 | case ZigTypeIdComptimeInt: | |
| 25585 | case ZigTypeIdEnumLiteral: | |
| 25586 | case ZigTypeIdOptional: | |
| 25587 | case ZigTypeIdErrorUnion: | |
| 25588 | case ZigTypeIdErrorSet: | |
| 25589 | case ZigTypeIdEnum: | |
| 25590 | case ZigTypeIdUnion: | |
| 25591 | case ZigTypeIdFn: | |
| 25592 | case ZigTypeIdBoundFn: | |
| 25593 | case ZigTypeIdVector: | |
| 25594 | case ZigTypeIdFnFrame: | |
| 25595 | case ZigTypeIdAnyFrame: | |
| 25596 | break; | |
| 25597 | } | |
| 25598 | ||
| 25599 | ResolveStatus needed_status = (align_bytes == 0) ? | |
| 25600 | ResolveStatusZeroBitsKnown : ResolveStatusAlignmentKnown; | |
| 25601 | if ((err = type_resolve(ira->codegen, elem_type, needed_status))) | |
| 25602 | return err; | |
| 25603 | ZigType *slice_ptr_type = get_pointer_to_type_extra(ira->codegen, elem_type, | |
| 25604 | lazy_slice_type->is_const, lazy_slice_type->is_volatile, PtrLenUnknown, align_bytes, | |
| 25605 | 0, 0, lazy_slice_type->is_allowzero); | |
| 25606 | val->special = ConstValSpecialStatic; | |
| 25607 | assert(val->type->id == ZigTypeIdMetaType); | |
| 25608 | val->data.x_type = get_slice_type(ira->codegen, slice_ptr_type); | |
| 25609 | return ErrorNone; | |
| 25610 | } | |
| 25611 | case LazyValueIdPtrType: { | |
| 25612 | LazyValuePtrType *lazy_ptr_type = reinterpret_cast<LazyValuePtrType *>(val->data.x_lazy); | |
| 25613 | IrAnalyze *ira = lazy_ptr_type->ira; | |
| 25614 | ||
| 25615 | uint32_t align_bytes = 0; | |
| 25616 | if (lazy_ptr_type->align_inst != nullptr) { | |
| 25617 | if (!ir_resolve_align(ira, lazy_ptr_type->align_inst, &align_bytes)) | |
| 25618 | return ErrorSemanticAnalyzeFail; | |
| 25619 | } | |
| 25620 | ZigType *elem_type = ir_resolve_type(ira, lazy_ptr_type->elem_type); | |
| 25621 | if (type_is_invalid(elem_type)) | |
| 25622 | return ErrorSemanticAnalyzeFail; | |
| 25623 | ||
| 25624 | if (elem_type->id == ZigTypeIdUnreachable) { | |
| 25625 | ir_add_error(ira, lazy_ptr_type->elem_type, | |
| 25626 | buf_create_from_str("pointer to noreturn not allowed")); | |
| 25627 | return ErrorSemanticAnalyzeFail; | |
| 25628 | } else if (elem_type->id == ZigTypeIdOpaque && lazy_ptr_type->ptr_len == PtrLenUnknown) { | |
| 25629 | ir_add_error(ira, lazy_ptr_type->elem_type, | |
| 25630 | buf_create_from_str("unknown-length pointer to opaque")); | |
| 25631 | return ErrorSemanticAnalyzeFail; | |
| 25632 | } else if (lazy_ptr_type->ptr_len == PtrLenC) { | |
| 25633 | if (!type_allowed_in_extern(ira->codegen, elem_type)) { | |
| 25634 | ir_add_error(ira, lazy_ptr_type->elem_type, | |
| 25635 | buf_sprintf("C pointers cannot point to non-C-ABI-compatible type '%s'", | |
| 25636 | buf_ptr(&elem_type->name))); | |
| 25637 | return ErrorSemanticAnalyzeFail; | |
| 25638 | } else if (elem_type->id == ZigTypeIdOpaque) { | |
| 25639 | ir_add_error(ira, lazy_ptr_type->elem_type, | |
| 25640 | buf_sprintf("C pointers cannot point opaque types")); | |
| 25641 | return ErrorSemanticAnalyzeFail; | |
| 25642 | } else if (lazy_ptr_type->is_allowzero) { | |
| 25643 | ir_add_error(ira, lazy_ptr_type->elem_type, | |
| 25644 | buf_sprintf("C pointers always allow address zero")); | |
| 25645 | return ErrorSemanticAnalyzeFail; | |
| 25646 | } | |
| 25647 | } | |
| 25648 | ||
| 25649 | if (align_bytes != 0) { | |
| 25650 | if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusAlignmentKnown))) | |
| 25651 | return err; | |
| 25652 | if (!type_has_bits(elem_type)) | |
| 25653 | align_bytes = 0; | |
| 25654 | } | |
| 25655 | bool allow_zero = lazy_ptr_type->is_allowzero || lazy_ptr_type->ptr_len == PtrLenC; | |
| 25656 | assert(val->type->id == ZigTypeIdMetaType); | |
| 25657 | val->data.x_type = get_pointer_to_type_extra(ira->codegen, elem_type, | |
| 25658 | lazy_ptr_type->is_const, lazy_ptr_type->is_volatile, lazy_ptr_type->ptr_len, align_bytes, | |
| 25659 | lazy_ptr_type->bit_offset_in_host, lazy_ptr_type->host_int_bytes, | |
| 25660 | allow_zero); | |
| 25661 | val->special = ConstValSpecialStatic; | |
| 25662 | return ErrorNone; | |
| 25663 | } | |
| 25664 | case LazyValueIdOptType: { | |
| 25665 | LazyValueOptType *lazy_opt_type = reinterpret_cast<LazyValueOptType *>(val->data.x_lazy); | |
| 25666 | IrAnalyze *ira = lazy_opt_type->ira; | |
| 25667 | ||
| 25668 | ZigType *payload_type = ir_resolve_type(ira, lazy_opt_type->payload_type); | |
| 25669 | if (type_is_invalid(payload_type)) | |
| 25670 | return ErrorSemanticAnalyzeFail; | |
| 25671 | ||
| 25672 | if (payload_type->id == ZigTypeIdOpaque || payload_type->id == ZigTypeIdUnreachable) { | |
| 25673 | ir_add_error(ira, lazy_opt_type->payload_type, | |
| 25674 | buf_sprintf("type '%s' cannot be optional", buf_ptr(&payload_type->name))); | |
| 25675 | return ErrorSemanticAnalyzeFail; | |
| 25676 | } | |
| 25677 | ||
| 25678 | if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) | |
| 25679 | return err; | |
| 25680 | ||
| 25681 | assert(val->type->id == ZigTypeIdMetaType); | |
| 25682 | val->data.x_type = get_optional_type(ira->codegen, payload_type); | |
| 25683 | val->special = ConstValSpecialStatic; | |
| 25684 | return ErrorNone; | |
| 25685 | } | |
| 25686 | case LazyValueIdFnType: { | |
| 25687 | LazyValueFnType *lazy_fn_type = reinterpret_cast<LazyValueFnType *>(val->data.x_lazy); | |
| 25688 | ZigType *fn_type = ir_resolve_lazy_fn_type(lazy_fn_type->ira, source_node, lazy_fn_type); | |
| 25689 | if (fn_type == nullptr) | |
| 25690 | return ErrorSemanticAnalyzeFail; | |
| 25691 | val->special = ConstValSpecialStatic; | |
| 25692 | assert(val->type->id == ZigTypeIdMetaType); | |
| 25693 | val->data.x_type = fn_type; | |
| 25694 | return ErrorNone; | |
| 25695 | } | |
| 25696 | case LazyValueIdErrUnionType: { | |
| 25697 | LazyValueErrUnionType *lazy_err_union_type = | |
| 25698 | reinterpret_cast<LazyValueErrUnionType *>(val->data.x_lazy); | |
| 25699 | IrAnalyze *ira = lazy_err_union_type->ira; | |
| 25700 | ||
| 25701 | ZigType *err_set_type = ir_resolve_type(ira, lazy_err_union_type->err_set_type); | |
| 25702 | if (type_is_invalid(err_set_type)) | |
| 25703 | return ErrorSemanticAnalyzeFail; | |
| 25704 | ||
| 25705 | ZigType *payload_type = ir_resolve_type(ira, lazy_err_union_type->payload_type); | |
| 25706 | if (type_is_invalid(payload_type)) | |
| 25707 | return ErrorSemanticAnalyzeFail; | |
| 25708 | ||
| 25709 | if (err_set_type->id != ZigTypeIdErrorSet) { | |
| 25710 | ir_add_error(ira, lazy_err_union_type->err_set_type, | |
| 25711 | buf_sprintf("expected error set type, found type '%s'", | |
| 25712 | buf_ptr(&err_set_type->name))); | |
| 25713 | return ErrorSemanticAnalyzeFail; | |
| 25714 | } | |
| 25715 | ||
| 25716 | if ((err = type_resolve(ira->codegen, payload_type, ResolveStatusSizeKnown))) | |
| 25717 | return ErrorSemanticAnalyzeFail; | |
| 25718 | ||
| 25719 | assert(val->type->id == ZigTypeIdMetaType); | |
| 25720 | val->data.x_type = get_error_union_type(ira->codegen, err_set_type, payload_type); | |
| 25721 | val->special = ConstValSpecialStatic; | |
| 25722 | return ErrorNone; | |
| 25723 | } | |
| 25724 | } | |
| 25725 | zig_unreachable(); | |
| 25726 | } | |
| 25727 | ||
| 25728 | Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val) { | |
| 25729 | Error err; | |
| 25730 | if ((err = ir_resolve_lazy_raw(source_node, val))) { | |
| 25731 | if (codegen->trace_err != nullptr && !source_node->already_traced_this_node) { | |
| 25732 | source_node->already_traced_this_node = true; | |
| 25733 | codegen->trace_err = add_error_note(codegen, codegen->trace_err, source_node, | |
| 25734 | buf_create_from_str("referenced here")); | |
| 25735 | } | |
| 25736 | return err; | |
| 25737 | } | |
| 25738 | if (type_is_invalid(val->type)) { | |
| 25739 | return ErrorSemanticAnalyzeFail; | |
| 25740 | } | |
| 25741 | return ErrorNone; | |
| 25742 | } |
src/ir.hpp+3-3| ... | ... | @@ -16,7 +16,9 @@ bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry); |
| 16 | 16 | ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, |
| 17 | 17 | ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota, |
| 18 | 18 | ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, |
| 19 | IrExecutable *parent_exec, AstNode *expected_type_source_node); | |
| 19 | IrExecutable *parent_exec, AstNode *expected_type_source_node, UndefAllowed undef); | |
| 20 | ||
| 21 | Error ir_resolve_lazy(CodeGen *codegen, AstNode *source_node, ConstExprValue *val); | |
| 20 | 22 | |
| 21 | 23 | ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable, |
| 22 | 24 | ZigType *expected_type, AstNode *expected_type_source_node); |
| ... | ... | @@ -28,6 +30,4 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal |
| 28 | 30 | AstNode *source_node); |
| 29 | 31 | const char *float_op_to_name(BuiltinFnId op, bool llvm_name); |
| 30 | 32 | |
| 31 | void ir_add_analysis_trace(IrAnalyze *ira, ErrorMsg *err_msg, Buf *text); | |
| 32 | ||
| 33 | 33 | #endif |
src/os.cpp+15-15| ... | ... | @@ -1125,29 +1125,27 @@ Error os_get_cwd(Buf *out_cwd) { |
| 1125 | 1125 | #endif |
| 1126 | 1126 | } |
| 1127 | 1127 | |
| 1128 | #if defined(ZIG_OS_WINDOWS) | |
| 1129 | 1128 | #define is_wprefix(s, prefix) \ |
| 1130 | 1129 | (wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0) |
| 1131 | static bool is_stderr_cyg_pty(void) { | |
| 1132 | HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE); | |
| 1133 | if (stderr_handle == INVALID_HANDLE_VALUE) | |
| 1130 | bool ATTRIBUTE_MUST_USE os_is_cygwin_pty(int fd) { | |
| 1131 | #if defined(ZIG_OS_WINDOWS) | |
| 1132 | HANDLE handle = (HANDLE)_get_osfhandle(fd); | |
| 1133 | ||
| 1134 | // Cygwin/msys's pty is a pipe. | |
| 1135 | if (handle == INVALID_HANDLE_VALUE || GetFileType(handle) != FILE_TYPE_PIPE) { | |
| 1134 | 1136 | return false; |
| 1137 | } | |
| 1135 | 1138 | |
| 1136 | 1139 | int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * MAX_PATH; |
| 1137 | FILE_NAME_INFO *nameinfo; | |
| 1138 | 1140 | WCHAR *p = NULL; |
| 1139 | 1141 | |
| 1140 | // Cygwin/msys's pty is a pipe. | |
| 1141 | if (GetFileType(stderr_handle) != FILE_TYPE_PIPE) { | |
| 1142 | return 0; | |
| 1143 | } | |
| 1144 | nameinfo = (FILE_NAME_INFO *)allocate<char>(size); | |
| 1142 | FILE_NAME_INFO *nameinfo = (FILE_NAME_INFO *)allocate<char>(size); | |
| 1145 | 1143 | if (nameinfo == NULL) { |
| 1146 | return 0; | |
| 1144 | return false; | |
| 1147 | 1145 | } |
| 1148 | 1146 | // Check the name of the pipe: |
| 1149 | 1147 | // '\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master' |
| 1150 | if (GetFileInformationByHandleEx(stderr_handle, FileNameInfo, nameinfo, size)) { | |
| 1148 | if (GetFileInformationByHandleEx(handle, FileNameInfo, nameinfo, size)) { | |
| 1151 | 1149 | nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0'; |
| 1152 | 1150 | p = nameinfo->FileName; |
| 1153 | 1151 | if (is_wprefix(p, L"\\cygwin-")) { /* Cygwin */ |
| ... | ... | @@ -1180,12 +1178,14 @@ static bool is_stderr_cyg_pty(void) { |
| 1180 | 1178 | } |
| 1181 | 1179 | free(nameinfo); |
| 1182 | 1180 | return (p != NULL); |
| 1183 | } | |
| 1181 | #else | |
| 1182 | return false; | |
| 1184 | 1183 | #endif |
| 1184 | } | |
| 1185 | 1185 | |
| 1186 | 1186 | bool os_stderr_tty(void) { |
| 1187 | 1187 | #if defined(ZIG_OS_WINDOWS) |
| 1188 | return _isatty(_fileno(stderr)) != 0 || is_stderr_cyg_pty(); | |
| 1188 | return _isatty(fileno(stderr)) != 0 || os_is_cygwin_pty(fileno(stderr)); | |
| 1189 | 1189 | #elif defined(ZIG_OS_POSIX) |
| 1190 | 1190 | return isatty(STDERR_FILENO) != 0; |
| 1191 | 1191 | #else |
| ... | ... | @@ -1486,7 +1486,7 @@ WORD original_console_attributes = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BL |
| 1486 | 1486 | |
| 1487 | 1487 | void os_stderr_set_color(TermColor color) { |
| 1488 | 1488 | #if defined(ZIG_OS_WINDOWS) |
| 1489 | if (is_stderr_cyg_pty()) { | |
| 1489 | if (os_stderr_tty()) { | |
| 1490 | 1490 | set_color_posix(color); |
| 1491 | 1491 | return; |
| 1492 | 1492 | } |
src/os.hpp+8| ... | ... | @@ -11,6 +11,7 @@ |
| 11 | 11 | #include "list.hpp" |
| 12 | 12 | #include "buffer.hpp" |
| 13 | 13 | #include "error.hpp" |
| 14 | #include "target.hpp" | |
| 14 | 15 | #include "zig_llvm.h" |
| 15 | 16 | #include "windows_sdk.h" |
| 16 | 17 | |
| ... | ... | @@ -88,6 +89,11 @@ struct Termination { |
| 88 | 89 | #define OsFile int |
| 89 | 90 | #endif |
| 90 | 91 | |
| 92 | #if defined(ZIG_OS_WINDOWS) | |
| 93 | #undef fileno | |
| 94 | #define fileno _fileno | |
| 95 | #endif | |
| 96 | ||
| 91 | 97 | struct OsTimeStamp { |
| 92 | 98 | uint64_t sec; |
| 93 | 99 | uint64_t nsec; |
| ... | ... | @@ -152,6 +158,8 @@ Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf |
| 152 | 158 | Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); |
| 153 | 159 | Error ATTRIBUTE_MUST_USE os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); |
| 154 | 160 | |
| 161 | bool ATTRIBUTE_MUST_USE os_is_cygwin_pty(int fd); | |
| 162 | ||
| 155 | 163 | Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths); |
| 156 | 164 | |
| 157 | 165 | #endif |
src/parser.cpp+5-3| ... | ... | @@ -782,24 +782,26 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) { |
| 782 | 782 | return res; |
| 783 | 783 | } |
| 784 | 784 | |
| 785 | // ContainerField <- IDENTIFIER (COLON TypeExpr)? (EQUAL Expr)? | |
| 785 | // ContainerField <- IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)? | |
| 786 | 786 | static AstNode *ast_parse_container_field(ParseContext *pc) { |
| 787 | 787 | Token *identifier = eat_token_if(pc, TokenIdSymbol); |
| 788 | 788 | if (identifier == nullptr) |
| 789 | 789 | return nullptr; |
| 790 | 790 | |
| 791 | 791 | AstNode *type_expr = nullptr; |
| 792 | if (eat_token_if(pc, TokenIdColon) != nullptr) | |
| 792 | if (eat_token_if(pc, TokenIdColon) != nullptr) { | |
| 793 | 793 | type_expr = ast_expect(pc, ast_parse_type_expr); |
| 794 | } | |
| 795 | AstNode *align_expr = ast_parse_byte_align(pc); | |
| 794 | 796 | AstNode *expr = nullptr; |
| 795 | 797 | if (eat_token_if(pc, TokenIdEq) != nullptr) |
| 796 | 798 | expr = ast_expect(pc, ast_parse_expr); |
| 797 | 799 | |
| 798 | ||
| 799 | 800 | AstNode *res = ast_create_node(pc, NodeTypeStructField, identifier); |
| 800 | 801 | res->data.struct_field.name = token_buf(identifier); |
| 801 | 802 | res->data.struct_field.type = type_expr; |
| 802 | 803 | res->data.struct_field.value = expr; |
| 804 | res->data.struct_field.align_expr = align_expr; | |
| 803 | 805 | return res; |
| 804 | 806 | } |
| 805 | 807 |
src/target.cpp+14-1| ... | ... | @@ -504,6 +504,16 @@ Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) { |
| 504 | 504 | return ErrorNone; |
| 505 | 505 | } |
| 506 | 506 | |
| 507 | static ZigLLVM_EnvironmentType target_get_win32_abi() { | |
| 508 | FILE* files[] = { stdin, stdout, stderr, nullptr }; | |
| 509 | for (int i = 0; files[i] != nullptr; i++) { | |
| 510 | if (os_is_cygwin_pty(fileno(files[i]))) { | |
| 511 | return ZigLLVM_GNU; | |
| 512 | } | |
| 513 | } | |
| 514 | return ZigLLVM_MSVC; | |
| 515 | } | |
| 516 | ||
| 507 | 517 | void get_native_target(ZigTarget *target) { |
| 508 | 518 | // first zero initialize |
| 509 | 519 | *target = {}; |
| ... | ... | @@ -518,6 +528,9 @@ void get_native_target(ZigTarget *target) { |
| 518 | 528 | &target->abi, |
| 519 | 529 | &oformat); |
| 520 | 530 | target->os = get_zig_os_type(os_type); |
| 531 | if (target->os == OsWindows) { | |
| 532 | target->abi = target_get_win32_abi(); | |
| 533 | } | |
| 521 | 534 | target->is_native = true; |
| 522 | 535 | if (target->abi == ZigLLVM_UnknownEnvironment) { |
| 523 | 536 | target->abi = target_default_abi(target->arch, target->os); |
| ... | ... | @@ -1651,7 +1664,7 @@ ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) { |
| 1651 | 1664 | return ZigLLVM_GNU; |
| 1652 | 1665 | case OsUefi: |
| 1653 | 1666 | case OsWindows: |
| 1654 | return ZigLLVM_MSVC; | |
| 1667 | return ZigLLVM_MSVC; | |
| 1655 | 1668 | case OsLinux: |
| 1656 | 1669 | case OsWASI: |
| 1657 | 1670 | case OsEmscripten: |
src/tokenizer.cpp+1-1| ... | ... | @@ -841,7 +841,7 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 841 | 841 | case TokenizeStateSawAmpersand: |
| 842 | 842 | switch (c) { |
| 843 | 843 | case '&': |
| 844 | tokenize_error(&t, "`&&` is invalid. Note that `and` is boolean AND."); | |
| 844 | tokenize_error(&t, "`&&` is invalid. Note that `and` is boolean AND"); | |
| 845 | 845 | break; |
| 846 | 846 | case '=': |
| 847 | 847 | set_token_id(&t, t.cur_tok, TokenIdBitAndEq); |
src/zig_llvm.cpp+3-3| ... | ... | @@ -15,9 +15,9 @@ |
| 15 | 15 | |
| 16 | 16 | #include "zig_llvm.h" |
| 17 | 17 | |
| 18 | #if __GNUC__ >= 8 | |
| 18 | #if __GNUC__ >= 9 | |
| 19 | 19 | #pragma GCC diagnostic push |
| 20 | #pragma GCC diagnostic ignored "-Wclass-memaccess" | |
| 20 | #pragma GCC diagnostic ignored "-Winit-list-lifetime" | |
| 21 | 21 | #endif |
| 22 | 22 | |
| 23 | 23 | #include <llvm/Analysis/TargetLibraryInfo.h> |
| ... | ... | @@ -50,7 +50,7 @@ |
| 50 | 50 | |
| 51 | 51 | #include <lld/Common/Driver.h> |
| 52 | 52 | |
| 53 | #if __GNUC__ >= 8 | |
| 53 | #if __GNUC__ >= 9 | |
| 54 | 54 | #pragma GCC diagnostic pop |
| 55 | 55 | #endif |
| 56 | 56 |
std/array_list.zig+12-9| ... | ... | @@ -6,20 +6,23 @@ const mem = std.mem; |
| 6 | 6 | const Allocator = mem.Allocator; |
| 7 | 7 | |
| 8 | 8 | pub fn ArrayList(comptime T: type) type { |
| 9 | return AlignedArrayList(T, @alignOf(T)); | |
| 9 | return AlignedArrayList(T, null); | |
| 10 | 10 | } |
| 11 | 11 | |
| 12 | pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { | |
| 12 | pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type { | |
| 13 | 13 | return struct { |
| 14 | 14 | const Self = @This(); |
| 15 | 15 | |
| 16 | 16 | /// Use toSlice instead of slicing this directly, because if you don't |
| 17 | 17 | /// specify the end position of the slice, this will potentially give |
| 18 | 18 | /// you uninitialized memory. |
| 19 | items: []align(A) T, | |
| 19 | items: Slice, | |
| 20 | 20 | len: usize, |
| 21 | 21 | allocator: *Allocator, |
| 22 | 22 | |
| 23 | pub const Slice = if (alignment) |a| ([]align(a) T) else []T; | |
| 24 | pub const SliceConst = if (alignment) |a| ([]align(a) const T) else []const T; | |
| 25 | ||
| 23 | 26 | /// Deinitialize with `deinit` or use `toOwnedSlice`. |
| 24 | 27 | pub fn init(allocator: *Allocator) Self { |
| 25 | 28 | return Self{ |
| ... | ... | @@ -33,11 +36,11 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { |
| 33 | 36 | self.allocator.free(self.items); |
| 34 | 37 | } |
| 35 | 38 | |
| 36 | pub fn toSlice(self: Self) []align(A) T { | |
| 39 | pub fn toSlice(self: Self) Slice { | |
| 37 | 40 | return self.items[0..self.len]; |
| 38 | 41 | } |
| 39 | 42 | |
| 40 | pub fn toSliceConst(self: Self) []align(A) const T { | |
| 43 | pub fn toSliceConst(self: Self) SliceConst { | |
| 41 | 44 | return self.items[0..self.len]; |
| 42 | 45 | } |
| 43 | 46 | |
| ... | ... | @@ -69,7 +72,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { |
| 69 | 72 | /// ArrayList takes ownership of the passed in slice. The slice must have been |
| 70 | 73 | /// allocated with `allocator`. |
| 71 | 74 | /// Deinitialize with `deinit` or use `toOwnedSlice`. |
| 72 | pub fn fromOwnedSlice(allocator: *Allocator, slice: []align(A) T) Self { | |
| 75 | pub fn fromOwnedSlice(allocator: *Allocator, slice: Slice) Self { | |
| 73 | 76 | return Self{ |
| 74 | 77 | .items = slice, |
| 75 | 78 | .len = slice.len, |
| ... | ... | @@ -78,7 +81,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { |
| 78 | 81 | } |
| 79 | 82 | |
| 80 | 83 | /// The caller owns the returned memory. ArrayList becomes empty. |
| 81 | pub fn toOwnedSlice(self: *Self) []align(A) T { | |
| 84 | pub fn toOwnedSlice(self: *Self) Slice { | |
| 82 | 85 | const allocator = self.allocator; |
| 83 | 86 | const result = allocator.shrink(self.items, self.len); |
| 84 | 87 | self.* = init(allocator); |
| ... | ... | @@ -93,7 +96,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { |
| 93 | 96 | self.items[n] = item; |
| 94 | 97 | } |
| 95 | 98 | |
| 96 | pub fn insertSlice(self: *Self, n: usize, items: []align(A) const T) !void { | |
| 99 | pub fn insertSlice(self: *Self, n: usize, items: SliceConst) !void { | |
| 97 | 100 | try self.ensureCapacity(self.len + items.len); |
| 98 | 101 | self.len += items.len; |
| 99 | 102 | |
| ... | ... | @@ -141,7 +144,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { |
| 141 | 144 | return self.swapRemove(i); |
| 142 | 145 | } |
| 143 | 146 | |
| 144 | pub fn appendSlice(self: *Self, items: []align(A) const T) !void { | |
| 147 | pub fn appendSlice(self: *Self, items: SliceConst) !void { | |
| 145 | 148 | try self.ensureCapacity(self.len + items.len); |
| 146 | 149 | mem.copy(T, self.items[self.len..], items); |
| 147 | 150 | self.len += items.len; |
std/crypto/benchmark.zig created+198| ... | ... | @@ -0,0 +1,198 @@ |
| 1 | // zig run benchmark.zig --release-fast --override-std-dir .. | |
| 2 | ||
| 3 | const builtin = @import("builtin"); | |
| 4 | const std = @import("../std.zig"); | |
| 5 | const time = std.time; | |
| 6 | const Timer = time.Timer; | |
| 7 | const crypto = std.crypto; | |
| 8 | ||
| 9 | const KiB = 1024; | |
| 10 | const MiB = 1024 * KiB; | |
| 11 | ||
| 12 | var prng = std.rand.DefaultPrng.init(0); | |
| 13 | ||
| 14 | const Crypto = struct { | |
| 15 | ty: type, | |
| 16 | name: []const u8, | |
| 17 | }; | |
| 18 | ||
| 19 | const hashes = [_]Crypto{ | |
| 20 | Crypto{ .ty = crypto.Md5, .name = "md5" }, | |
| 21 | Crypto{ .ty = crypto.Sha1, .name = "sha1" }, | |
| 22 | Crypto{ .ty = crypto.Sha256, .name = "sha256" }, | |
| 23 | Crypto{ .ty = crypto.Sha512, .name = "sha512" }, | |
| 24 | Crypto{ .ty = crypto.Sha3_256, .name = "sha3-256" }, | |
| 25 | Crypto{ .ty = crypto.Sha3_512, .name = "sha3-512" }, | |
| 26 | Crypto{ .ty = crypto.Blake2s256, .name = "blake2s" }, | |
| 27 | Crypto{ .ty = crypto.Blake2b512, .name = "blake2b" }, | |
| 28 | }; | |
| 29 | ||
| 30 | pub fn benchmarkHash(comptime Hash: var, comptime bytes: comptime_int) !u64 { | |
| 31 | var h = Hash.init(); | |
| 32 | ||
| 33 | var block: [Hash.digest_length]u8 = undefined; | |
| 34 | prng.random.bytes(block[0..]); | |
| 35 | ||
| 36 | var offset: usize = 0; | |
| 37 | var timer = try Timer.start(); | |
| 38 | const start = timer.lap(); | |
| 39 | while (offset < bytes) : (offset += block.len) { | |
| 40 | h.update(block[0..]); | |
| 41 | } | |
| 42 | const end = timer.read(); | |
| 43 | ||
| 44 | const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s; | |
| 45 | const throughput = @floatToInt(u64, bytes / elapsed_s); | |
| 46 | ||
| 47 | return throughput; | |
| 48 | } | |
| 49 | ||
| 50 | const macs = [_]Crypto{ | |
| 51 | Crypto{ .ty = crypto.Poly1305, .name = "poly1305" }, | |
| 52 | Crypto{ .ty = crypto.HmacMd5, .name = "hmac-md5" }, | |
| 53 | Crypto{ .ty = crypto.HmacSha1, .name = "hmac-sha1" }, | |
| 54 | Crypto{ .ty = crypto.HmacSha256, .name = "hmac-sha256" }, | |
| 55 | }; | |
| 56 | ||
| 57 | pub fn benchmarkMac(comptime Mac: var, comptime bytes: comptime_int) !u64 { | |
| 58 | std.debug.assert(32 >= Mac.mac_length and 32 >= Mac.minimum_key_length); | |
| 59 | ||
| 60 | var in: [1 * MiB]u8 = undefined; | |
| 61 | prng.random.bytes(in[0..]); | |
| 62 | ||
| 63 | var key: [32]u8 = undefined; | |
| 64 | prng.random.bytes(key[0..]); | |
| 65 | ||
| 66 | var offset: usize = 0; | |
| 67 | var timer = try Timer.start(); | |
| 68 | const start = timer.lap(); | |
| 69 | while (offset < bytes) : (offset += in.len) { | |
| 70 | Mac.create(key[0..], in[0..], key); | |
| 71 | } | |
| 72 | const end = timer.read(); | |
| 73 | ||
| 74 | const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s; | |
| 75 | const throughput = @floatToInt(u64, bytes / elapsed_s); | |
| 76 | ||
| 77 | return throughput; | |
| 78 | } | |
| 79 | ||
| 80 | const exchanges = [_]Crypto{Crypto{ .ty = crypto.X25519, .name = "x25519" }}; | |
| 81 | ||
| 82 | pub fn benchmarkKeyExchange(comptime DhKeyExchange: var, comptime exchange_count: comptime_int) !u64 { | |
| 83 | std.debug.assert(DhKeyExchange.minimum_key_length >= DhKeyExchange.secret_length); | |
| 84 | ||
| 85 | var in: [DhKeyExchange.minimum_key_length]u8 = undefined; | |
| 86 | prng.random.bytes(in[0..]); | |
| 87 | ||
| 88 | var out: [DhKeyExchange.minimum_key_length]u8 = undefined; | |
| 89 | prng.random.bytes(out[0..]); | |
| 90 | ||
| 91 | var offset: usize = 0; | |
| 92 | var timer = try Timer.start(); | |
| 93 | const start = timer.lap(); | |
| 94 | { | |
| 95 | var i: usize = 0; | |
| 96 | while (i < exchange_count) : (i += 1) { | |
| 97 | _ = DhKeyExchange.create(out[0..], out, in); | |
| 98 | } | |
| 99 | } | |
| 100 | const end = timer.read(); | |
| 101 | ||
| 102 | const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s; | |
| 103 | const throughput = @floatToInt(u64, exchange_count / elapsed_s); | |
| 104 | ||
| 105 | return throughput; | |
| 106 | } | |
| 107 | ||
| 108 | fn usage() void { | |
| 109 | std.debug.warn( | |
| 110 | \\throughput_test [options] | |
| 111 | \\ | |
| 112 | \\Options: | |
| 113 | \\ --filter [test-name] | |
| 114 | \\ --seed [int] | |
| 115 | \\ --help | |
| 116 | \\ | |
| 117 | ); | |
| 118 | } | |
| 119 | ||
| 120 | fn mode(comptime x: comptime_int) comptime_int { | |
| 121 | return if (builtin.mode == builtin.Mode.Debug) x / 64 else x; | |
| 122 | } | |
| 123 | ||
| 124 | // TODO(#1358): Replace with builtin formatted padding when available. | |
| 125 | fn printPad(stdout: var, s: []const u8) !void { | |
| 126 | var i: usize = 0; | |
| 127 | while (i < 12 - s.len) : (i += 1) { | |
| 128 | try stdout.print(" "); | |
| 129 | } | |
| 130 | try stdout.print("{}", s); | |
| 131 | } | |
| 132 | ||
| 133 | pub fn main() !void { | |
| 134 | var stdout_file = try std.io.getStdOut(); | |
| 135 | var stdout_out_stream = stdout_file.outStream(); | |
| 136 | const stdout = &stdout_out_stream.stream; | |
| 137 | ||
| 138 | var buffer: [1024]u8 = undefined; | |
| 139 | var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]); | |
| 140 | const args = try std.process.argsAlloc(&fixed.allocator); | |
| 141 | ||
| 142 | var filter: ?[]u8 = ""; | |
| 143 | ||
| 144 | var i: usize = 1; | |
| 145 | while (i < args.len) : (i += 1) { | |
| 146 | if (std.mem.eql(u8, args[i], "--mode")) { | |
| 147 | try stdout.print("{}\n", builtin.mode); | |
| 148 | return; | |
| 149 | } else if (std.mem.eql(u8, args[i], "--seed")) { | |
| 150 | i += 1; | |
| 151 | if (i == args.len) { | |
| 152 | usage(); | |
| 153 | std.os.exit(1); | |
| 154 | } | |
| 155 | ||
| 156 | const seed = try std.fmt.parseUnsigned(u32, args[i], 10); | |
| 157 | prng.seed(seed); | |
| 158 | } else if (std.mem.eql(u8, args[i], "--filter")) { | |
| 159 | i += 1; | |
| 160 | if (i == args.len) { | |
| 161 | usage(); | |
| 162 | std.os.exit(1); | |
| 163 | } | |
| 164 | ||
| 165 | filter = args[i]; | |
| 166 | } else if (std.mem.eql(u8, args[i], "--help")) { | |
| 167 | usage(); | |
| 168 | return; | |
| 169 | } else { | |
| 170 | usage(); | |
| 171 | std.os.exit(1); | |
| 172 | } | |
| 173 | } | |
| 174 | ||
| 175 | inline for (hashes) |H| { | |
| 176 | if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) { | |
| 177 | const throughput = try benchmarkHash(H.ty, mode(32 * MiB)); | |
| 178 | try printPad(stdout, H.name); | |
| 179 | try stdout.print(": {} MiB/s\n", throughput / (1 * MiB)); | |
| 180 | } | |
| 181 | } | |
| 182 | ||
| 183 | inline for (macs) |M| { | |
| 184 | if (filter == null or std.mem.indexOf(u8, M.name, filter.?) != null) { | |
| 185 | const throughput = try benchmarkMac(M.ty, mode(128 * MiB)); | |
| 186 | try printPad(stdout, M.name); | |
| 187 | try stdout.print(": {} MiB/s\n", throughput / (1 * MiB)); | |
| 188 | } | |
| 189 | } | |
| 190 | ||
| 191 | inline for (exchanges) |E| { | |
| 192 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { | |
| 193 | const throughput = try benchmarkKeyExchange(E.ty, mode(1000)); | |
| 194 | try printPad(stdout, E.name); | |
| 195 | try stdout.print(": {} exchanges/s\n", throughput); | |
| 196 | } | |
| 197 | } | |
| 198 | } |
std/crypto/blake2.zig+2-2| ... | ... | @@ -269,8 +269,8 @@ pub const Blake2b512 = Blake2b(512); |
| 269 | 269 | fn Blake2b(comptime out_len: usize) type { |
| 270 | 270 | return struct { |
| 271 | 271 | const Self = @This(); |
| 272 | const block_length = 128; | |
| 273 | const digest_length = out_len / 8; | |
| 272 | pub const block_length = 128; | |
| 273 | pub const digest_length = out_len / 8; | |
| 274 | 274 | |
| 275 | 275 | const iv = [8]u64{ |
| 276 | 276 | 0x6a09e667f3bcc908, |
std/crypto/sha2.zig+2-2| ... | ... | @@ -420,8 +420,8 @@ pub const Sha512 = Sha2_64(Sha512Params); |
| 420 | 420 | fn Sha2_64(comptime params: Sha2Params64) type { |
| 421 | 421 | return struct { |
| 422 | 422 | const Self = @This(); |
| 423 | const block_length = 128; | |
| 424 | const digest_length = params.out_len / 8; | |
| 423 | pub const block_length = 128; | |
| 424 | pub const digest_length = params.out_len / 8; | |
| 425 | 425 | |
| 426 | 426 | s: [8]u64, |
| 427 | 427 | // Streaming Cache |
std/crypto/throughput_test.zig deleted-193| ... | ... | @@ -1,193 +0,0 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const std = @import("std"); | |
| 3 | const time = std.time; | |
| 4 | const Timer = time.Timer; | |
| 5 | const crypto = @import("../crypto.zig"); | |
| 6 | ||
| 7 | const KiB = 1024; | |
| 8 | const MiB = 1024 * KiB; | |
| 9 | ||
| 10 | var prng = std.rand.DefaultPrng.init(0); | |
| 11 | ||
| 12 | const Crypto = struct { | |
| 13 | ty: type, | |
| 14 | name: []const u8, | |
| 15 | }; | |
| 16 | ||
| 17 | const hashes = []Crypto{ | |
| 18 | Crypto{ .ty = crypto.Md5, .name = "md5" }, | |
| 19 | Crypto{ .ty = crypto.Sha1, .name = "sha1" }, | |
| 20 | Crypto{ .ty = crypto.Sha256, .name = "sha256" }, | |
| 21 | Crypto{ .ty = crypto.Sha512, .name = "sha512" }, | |
| 22 | Crypto{ .ty = crypto.Sha3_256, .name = "sha3-256" }, | |
| 23 | Crypto{ .ty = crypto.Sha3_512, .name = "sha3-512" }, | |
| 24 | Crypto{ .ty = crypto.Blake2s256, .name = "blake2s" }, | |
| 25 | Crypto{ .ty = crypto.Blake2b512, .name = "blake2b" }, | |
| 26 | }; | |
| 27 | ||
| 28 | pub fn benchmarkHash(comptime Hash: var, comptime bytes: comptime_int) !u64 { | |
| 29 | var h = Hash.init(); | |
| 30 | ||
| 31 | var block: [Hash.digest_length]u8 = undefined; | |
| 32 | prng.random.bytes(block[0..]); | |
| 33 | ||
| 34 | var offset: usize = 0; | |
| 35 | var timer = try Timer.start(); | |
| 36 | const start = timer.lap(); | |
| 37 | while (offset < bytes) : (offset += block.len) { | |
| 38 | h.update(block[0..]); | |
| 39 | } | |
| 40 | const end = timer.read(); | |
| 41 | ||
| 42 | const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s; | |
| 43 | const throughput = @floatToInt(u64, bytes / elapsed_s); | |
| 44 | ||
| 45 | return throughput; | |
| 46 | } | |
| 47 | ||
| 48 | const macs = []Crypto{ | |
| 49 | Crypto{ .ty = crypto.Poly1305, .name = "poly1305" }, | |
| 50 | Crypto{ .ty = crypto.HmacMd5, .name = "hmac-md5" }, | |
| 51 | Crypto{ .ty = crypto.HmacSha1, .name = "hmac-sha1" }, | |
| 52 | Crypto{ .ty = crypto.HmacSha256, .name = "hmac-sha256" }, | |
| 53 | }; | |
| 54 | ||
| 55 | pub fn benchmarkMac(comptime Mac: var, comptime bytes: comptime_int) !u64 { | |
| 56 | std.debug.assert(32 >= Mac.mac_length and 32 >= Mac.minimum_key_length); | |
| 57 | ||
| 58 | var in: [1 * MiB]u8 = undefined; | |
| 59 | prng.random.bytes(in[0..]); | |
| 60 | ||
| 61 | var key: [32]u8 = undefined; | |
| 62 | prng.random.bytes(key[0..]); | |
| 63 | ||
| 64 | var offset: usize = 0; | |
| 65 | var timer = try Timer.start(); | |
| 66 | const start = timer.lap(); | |
| 67 | while (offset < bytes) : (offset += in.len) { | |
| 68 | Mac.create(key[0..], in[0..], key); | |
| 69 | } | |
| 70 | const end = timer.read(); | |
| 71 | ||
| 72 | const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s; | |
| 73 | const throughput = @floatToInt(u64, bytes / elapsed_s); | |
| 74 | ||
| 75 | return throughput; | |
| 76 | } | |
| 77 | ||
| 78 | const exchanges = []Crypto{Crypto{ .ty = crypto.X25519, .name = "x25519" }}; | |
| 79 | ||
| 80 | pub fn benchmarkKeyExchange(comptime DhKeyExchange: var, comptime exchange_count: comptime_int) !u64 { | |
| 81 | std.debug.assert(DhKeyExchange.minimum_key_length >= DhKeyExchange.secret_length); | |
| 82 | ||
| 83 | var in: [DhKeyExchange.minimum_key_length]u8 = undefined; | |
| 84 | prng.random.bytes(in[0..]); | |
| 85 | ||
| 86 | var out: [DhKeyExchange.minimum_key_length]u8 = undefined; | |
| 87 | prng.random.bytes(out[0..]); | |
| 88 | ||
| 89 | var offset: usize = 0; | |
| 90 | var timer = try Timer.start(); | |
| 91 | const start = timer.lap(); | |
| 92 | { | |
| 93 | var i: usize = 0; | |
| 94 | while (i < exchange_count) : (i += 1) { | |
| 95 | _ = DhKeyExchange.create(out[0..], out, in); | |
| 96 | } | |
| 97 | } | |
| 98 | const end = timer.read(); | |
| 99 | ||
| 100 | const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s; | |
| 101 | const throughput = @floatToInt(u64, exchange_count / elapsed_s); | |
| 102 | ||
| 103 | return throughput; | |
| 104 | } | |
| 105 | ||
| 106 | fn usage() void { | |
| 107 | std.debug.warn( | |
| 108 | \\throughput_test [options] | |
| 109 | \\ | |
| 110 | \\Options: | |
| 111 | \\ --filter [test-name] | |
| 112 | \\ --seed [int] | |
| 113 | \\ --help | |
| 114 | \\ | |
| 115 | ); | |
| 116 | } | |
| 117 | ||
| 118 | fn mode(comptime x: comptime_int) comptime_int { | |
| 119 | return if (builtin.mode == builtin.Mode.Debug) x / 64 else x; | |
| 120 | } | |
| 121 | ||
| 122 | // TODO(#1358): Replace with builtin formatted padding when available. | |
| 123 | fn printPad(stdout: var, s: []const u8) !void { | |
| 124 | var i: usize = 0; | |
| 125 | while (i < 12 - s.len) : (i += 1) { | |
| 126 | try stdout.print(" "); | |
| 127 | } | |
| 128 | try stdout.print("{}", s); | |
| 129 | } | |
| 130 | ||
| 131 | pub fn main() !void { | |
| 132 | var stdout_file = try std.io.getStdOut(); | |
| 133 | var stdout_out_stream = stdout_file.outStream(); | |
| 134 | const stdout = &stdout_out_stream.stream; | |
| 135 | ||
| 136 | var buffer: [1024]u8 = undefined; | |
| 137 | var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]); | |
| 138 | const args = try std.os.argsAlloc(&fixed.allocator); | |
| 139 | ||
| 140 | var filter: ?[]u8 = ""; | |
| 141 | ||
| 142 | var i: usize = 1; | |
| 143 | while (i < args.len) : (i += 1) { | |
| 144 | if (std.mem.eql(u8, args[i], "--seed")) { | |
| 145 | i += 1; | |
| 146 | if (i == args.len) { | |
| 147 | usage(); | |
| 148 | std.os.exit(1); | |
| 149 | } | |
| 150 | ||
| 151 | const seed = try std.fmt.parseUnsigned(u32, args[i], 10); | |
| 152 | prng.seed(seed); | |
| 153 | } else if (std.mem.eql(u8, args[i], "--filter")) { | |
| 154 | i += 1; | |
| 155 | if (i == args.len) { | |
| 156 | usage(); | |
| 157 | std.os.exit(1); | |
| 158 | } | |
| 159 | ||
| 160 | filter = args[i]; | |
| 161 | } else if (std.mem.eql(u8, args[i], "--help")) { | |
| 162 | usage(); | |
| 163 | return; | |
| 164 | } else { | |
| 165 | usage(); | |
| 166 | std.os.exit(1); | |
| 167 | } | |
| 168 | } | |
| 169 | ||
| 170 | inline for (hashes) |H| { | |
| 171 | if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) { | |
| 172 | const throughput = try benchmarkHash(H.ty, mode(32 * MiB)); | |
| 173 | try printPad(stdout, H.name); | |
| 174 | try stdout.print(": {} MiB/s\n", throughput / (1 * MiB)); | |
| 175 | } | |
| 176 | } | |
| 177 | ||
| 178 | inline for (macs) |M| { | |
| 179 | if (filter == null or std.mem.indexOf(u8, M.name, filter.?) != null) { | |
| 180 | const throughput = try benchmarkMac(M.ty, mode(128 * MiB)); | |
| 181 | try printPad(stdout, M.name); | |
| 182 | try stdout.print(": {} MiB/s\n", throughput / (1 * MiB)); | |
| 183 | } | |
| 184 | } | |
| 185 | ||
| 186 | inline for (exchanges) |E| { | |
| 187 | if (filter == null or std.mem.indexOf(u8, E.name, filter.?) != null) { | |
| 188 | const throughput = try benchmarkKeyExchange(E.ty, mode(1000)); | |
| 189 | try printPad(stdout, E.name); | |
| 190 | try stdout.print(": {} exchanges/s\n", throughput); | |
| 191 | } | |
| 192 | } | |
| 193 | } |
std/event/fs.zig+15-5| ... | ... | @@ -719,6 +719,16 @@ pub const WatchEventId = enum { |
| 719 | 719 | Delete, |
| 720 | 720 | }; |
| 721 | 721 | |
| 722 | fn eqlString(a: []const u16, b: []const u16) bool { | |
| 723 | if (a.len != b.len) return false; | |
| 724 | if (a.ptr == b.ptr) return true; | |
| 725 | return mem.compare(u16, a, b) == .Equal; | |
| 726 | } | |
| 727 | ||
| 728 | fn hashString(s: []const u16) u32 { | |
| 729 | return @truncate(u32, std.hash.Wyhash.hash(0, @sliceToBytes(s))); | |
| 730 | } | |
| 731 | ||
| 722 | 732 | //pub const WatchEventError = error{ |
| 723 | 733 | // UserResourceLimitReached, |
| 724 | 734 | // SystemResources, |
| ... | ... | @@ -736,7 +746,7 @@ pub const WatchEventId = enum { |
| 736 | 746 | // file_table: FileTable, |
| 737 | 747 | // table_lock: event.Lock, |
| 738 | 748 | // |
| 739 | // const FileTable = std.AutoHashMap([]const u8, *Put); | |
| 749 | // const FileTable = std.StringHashmap(*Put); | |
| 740 | 750 | // const Put = struct { |
| 741 | 751 | // putter: anyframe, |
| 742 | 752 | // value_ptr: *V, |
| ... | ... | @@ -755,8 +765,8 @@ pub const WatchEventId = enum { |
| 755 | 765 | // all_putters: std.atomic.Queue(anyframe), |
| 756 | 766 | // ref_count: std.atomic.Int(usize), |
| 757 | 767 | // |
| 758 | // const DirTable = std.AutoHashMap([]const u8, *Dir); | |
| 759 | // const FileTable = std.AutoHashMap([]const u16, V); | |
| 768 | // const DirTable = std.StringHashMap(*Dir); | |
| 769 | // const FileTable = std.HashMap([]const u16, V, hashString, eqlString); | |
| 760 | 770 | // |
| 761 | 771 | // const Dir = struct { |
| 762 | 772 | // putter: anyframe, |
| ... | ... | @@ -772,7 +782,7 @@ pub const WatchEventId = enum { |
| 772 | 782 | // table_lock: event.Lock, |
| 773 | 783 | // |
| 774 | 784 | // const WdTable = std.AutoHashMap(i32, Dir); |
| 775 | // const FileTable = std.AutoHashMap([]const u8, V); | |
| 785 | // const FileTable = std.StringHashMap(V); | |
| 776 | 786 | // |
| 777 | 787 | // const Dir = struct { |
| 778 | 788 | // dirname: []const u8, |
| ... | ... | @@ -780,7 +790,7 @@ pub const WatchEventId = enum { |
| 780 | 790 | // }; |
| 781 | 791 | // }; |
| 782 | 792 | // |
| 783 | // const FileToHandle = std.AutoHashMap([]const u8, anyframe); | |
| 793 | // const FileToHandle = std.StringHashMap(anyframe); | |
| 784 | 794 | // |
| 785 | 795 | // const Self = @This(); |
| 786 | 796 | // |
std/hash/auto_hash.zig+229-62| ... | ... | @@ -1,11 +1,79 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | const assert = std.debug.assert; | |
| 3 | 4 | const mem = std.mem; |
| 4 | 5 | const meta = std.meta; |
| 5 | 6 | |
| 7 | /// Describes how pointer types should be hashed. | |
| 8 | pub const HashStrategy = enum { | |
| 9 | /// Do not follow pointers, only hash their value. | |
| 10 | Shallow, | |
| 11 | ||
| 12 | /// Follow pointers, hash the pointee content. | |
| 13 | /// Only dereferences one level, ie. it is changed into .Shallow when a | |
| 14 | /// pointer type is encountered. | |
| 15 | Deep, | |
| 16 | ||
| 17 | /// Follow pointers, hash the pointee content. | |
| 18 | /// Dereferences all pointers encountered. | |
| 19 | /// Assumes no cycle. | |
| 20 | DeepRecursive, | |
| 21 | }; | |
| 22 | ||
| 23 | /// Helper function to hash a pointer and mutate the strategy if needed. | |
| 24 | pub fn hashPointer(hasher: var, key: var, comptime strat: HashStrategy) void { | |
| 25 | const info = @typeInfo(@typeOf(key)); | |
| 26 | ||
| 27 | switch (info.Pointer.size) { | |
| 28 | builtin.TypeInfo.Pointer.Size.One => switch (strat) { | |
| 29 | .Shallow => hash(hasher, @ptrToInt(key), .Shallow), | |
| 30 | .Deep => hash(hasher, key.*, .Shallow), | |
| 31 | .DeepRecursive => hash(hasher, key.*, .DeepRecursive), | |
| 32 | }, | |
| 33 | ||
| 34 | builtin.TypeInfo.Pointer.Size.Slice => switch (strat) { | |
| 35 | .Shallow => { | |
| 36 | hashPointer(hasher, key.ptr, .Shallow); | |
| 37 | hash(hasher, key.len, .Shallow); | |
| 38 | }, | |
| 39 | .Deep => hashArray(hasher, key, .Shallow), | |
| 40 | .DeepRecursive => hashArray(hasher, key, .DeepRecursive), | |
| 41 | }, | |
| 42 | ||
| 43 | builtin.TypeInfo.Pointer.Size.Many, | |
| 44 | builtin.TypeInfo.Pointer.Size.C, | |
| 45 | => switch (strat) { | |
| 46 | .Shallow => hash(hasher, @ptrToInt(key), .Shallow), | |
| 47 | else => @compileError( | |
| 48 | \\ unknown-length pointers and C pointers cannot be hashed deeply. | |
| 49 | \\ Consider providing your own hash function. | |
| 50 | ), | |
| 51 | }, | |
| 52 | } | |
| 53 | } | |
| 54 | ||
| 55 | /// Helper function to hash a set of contiguous objects, from an array or slice. | |
| 56 | pub fn hashArray(hasher: var, key: var, comptime strat: HashStrategy) void { | |
| 57 | switch (strat) { | |
| 58 | .Shallow => { | |
| 59 | // TODO detect via a trait when Key has no padding bits to | |
| 60 | // hash it as an array of bytes. | |
| 61 | // Otherwise, hash every element. | |
| 62 | for (key) |element| { | |
| 63 | hash(hasher, element, .Shallow); | |
| 64 | } | |
| 65 | }, | |
| 66 | else => { | |
| 67 | for (key) |element| { | |
| 68 | hash(hasher, element, strat); | |
| 69 | } | |
| 70 | }, | |
| 71 | } | |
| 72 | } | |
| 73 | ||
| 6 | 74 | /// Provides generic hashing for any eligible type. |
| 7 | /// Only hashes `key` itself, pointers are not followed. | |
| 8 | pub fn autoHash(hasher: var, key: var) void { | |
| 75 | /// Strategy is provided to determine if pointers should be followed or not. | |
| 76 | pub fn hash(hasher: var, key: var, comptime strat: HashStrategy) void { | |
| 9 | 77 | const Key = @typeOf(key); |
| 10 | 78 | switch (@typeInfo(Key)) { |
| 11 | 79 | .NoReturn, |
| ... | ... | @@ -26,35 +94,18 @@ pub fn autoHash(hasher: var, key: var) void { |
| 26 | 94 | // TODO Check if the situation is better after #561 is resolved. |
| 27 | 95 | .Int => @inlineCall(hasher.update, std.mem.asBytes(&key)), |
| 28 | 96 | |
| 29 | .Float => |info| autoHash(hasher, @bitCast(@IntType(false, info.bits), key)), | |
| 97 | .Float => |info| hash(hasher, @bitCast(@IntType(false, info.bits), key), strat), | |
| 30 | 98 | |
| 31 | .Bool => autoHash(hasher, @boolToInt(key)), | |
| 32 | .Enum => autoHash(hasher, @enumToInt(key)), | |
| 33 | .ErrorSet => autoHash(hasher, @errorToInt(key)), | |
| 34 | .AnyFrame, .Fn => autoHash(hasher, @ptrToInt(key)), | |
| 99 | .Bool => hash(hasher, @boolToInt(key), strat), | |
| 100 | .Enum => hash(hasher, @enumToInt(key), strat), | |
| 101 | .ErrorSet => hash(hasher, @errorToInt(key), strat), | |
| 102 | .AnyFrame, .Fn => hash(hasher, @ptrToInt(key), strat), | |
| 35 | 103 | |
| 36 | .Pointer => |info| switch (info.size) { | |
| 37 | builtin.TypeInfo.Pointer.Size.One, | |
| 38 | builtin.TypeInfo.Pointer.Size.Many, | |
| 39 | builtin.TypeInfo.Pointer.Size.C, | |
| 40 | => autoHash(hasher, @ptrToInt(key)), | |
| 104 | .Pointer => @inlineCall(hashPointer, hasher, key, strat), | |
| 41 | 105 | |
| 42 | builtin.TypeInfo.Pointer.Size.Slice => { | |
| 43 | autoHash(hasher, key.ptr); | |
| 44 | autoHash(hasher, key.len); | |
| 45 | }, | |
| 46 | }, | |
| 47 | ||
| 48 | .Optional => if (key) |k| autoHash(hasher, k), | |
| 106 | .Optional => if (key) |k| hash(hasher, k, strat), | |
| 49 | 107 | |
| 50 | .Array => { | |
| 51 | // TODO detect via a trait when Key has no padding bits to | |
| 52 | // hash it as an array of bytes. | |
| 53 | // Otherwise, hash every element. | |
| 54 | for (key) |element| { | |
| 55 | autoHash(hasher, element); | |
| 56 | } | |
| 57 | }, | |
| 108 | .Array => hashArray(hasher, key, strat), | |
| 58 | 109 | |
| 59 | 110 | .Vector => |info| { |
| 60 | 111 | if (info.child.bit_count % 8 == 0) { |
| ... | ... | @@ -67,7 +118,7 @@ pub fn autoHash(hasher: var, key: var) void { |
| 67 | 118 | const array: [info.len]info.child = key; |
| 68 | 119 | comptime var i: u32 = 0; |
| 69 | 120 | inline while (i < info.len) : (i += 1) { |
| 70 | autoHash(hasher, array[i]); | |
| 121 | hash(hasher, array[i], strat); | |
| 71 | 122 | } |
| 72 | 123 | } |
| 73 | 124 | }, |
| ... | ... | @@ -79,19 +130,19 @@ pub fn autoHash(hasher: var, key: var) void { |
| 79 | 130 | inline for (info.fields) |field| { |
| 80 | 131 | // We reuse the hash of the previous field as the seed for the |
| 81 | 132 | // next one so that they're dependant. |
| 82 | autoHash(hasher, @field(key, field.name)); | |
| 133 | hash(hasher, @field(key, field.name), strat); | |
| 83 | 134 | } |
| 84 | 135 | }, |
| 85 | 136 | |
| 86 | 137 | .Union => |info| blk: { |
| 87 | 138 | if (info.tag_type) |tag_type| { |
| 88 | 139 | const tag = meta.activeTag(key); |
| 89 | const s = autoHash(hasher, tag); | |
| 140 | const s = hash(hasher, tag, strat); | |
| 90 | 141 | inline for (info.fields) |field| { |
| 91 | 142 | const enum_field = field.enum_field.?; |
| 92 | 143 | if (enum_field.value == @enumToInt(tag)) { |
| 93 | autoHash(hasher, @field(key, enum_field.name)); | |
| 94 | // TODO use a labelled break when it does not crash the compiler. | |
| 144 | hash(hasher, @field(key, enum_field.name), strat); | |
| 145 | // TODO use a labelled break when it does not crash the compiler. cf #2908 | |
| 95 | 146 | // break :blk; |
| 96 | 147 | return; |
| 97 | 148 | } |
| ... | ... | @@ -102,25 +153,102 @@ pub fn autoHash(hasher: var, key: var) void { |
| 102 | 153 | |
| 103 | 154 | .ErrorUnion => blk: { |
| 104 | 155 | const payload = key catch |err| { |
| 105 | autoHash(hasher, err); | |
| 156 | hash(hasher, err, strat); | |
| 106 | 157 | break :blk; |
| 107 | 158 | }; |
| 108 | autoHash(hasher, payload); | |
| 159 | hash(hasher, payload, strat); | |
| 109 | 160 | }, |
| 110 | 161 | } |
| 111 | 162 | } |
| 112 | 163 | |
| 164 | /// Provides generic hashing for any eligible type. | |
| 165 | /// Only hashes `key` itself, pointers are not followed. | |
| 166 | /// Slices are rejected to avoid ambiguity on the user's intention. | |
| 167 | pub fn autoHash(hasher: var, key: var) void { | |
| 168 | const Key = @typeOf(key); | |
| 169 | if (comptime meta.trait.isSlice(Key)) { | |
| 170 | comptime assert(@hasDecl(std, "StringHashMap")); // detect when the following message needs updated | |
| 171 | const extra_help = if (Key == []const u8) | |
| 172 | " Consider std.StringHashMap for hashing the contents of []const u8." | |
| 173 | else | |
| 174 | ""; | |
| 175 | ||
| 176 | @compileError("std.auto_hash.autoHash does not allow slices (here " ++ @typeName(Key) ++ | |
| 177 | ") because the intent is unclear. Consider using std.auto_hash.hash or providing your own hash function instead." ++ | |
| 178 | extra_help); | |
| 179 | } | |
| 180 | ||
| 181 | hash(hasher, key, .Shallow); | |
| 182 | } | |
| 183 | ||
| 113 | 184 | const testing = std.testing; |
| 114 | 185 | const Wyhash = std.hash.Wyhash; |
| 115 | 186 | |
| 116 | fn testAutoHash(key: var) u64 { | |
| 187 | fn testHash(key: var) u64 { | |
| 188 | // Any hash could be used here, for testing autoHash. | |
| 189 | var hasher = Wyhash.init(0); | |
| 190 | hash(&hasher, key, .Shallow); | |
| 191 | return hasher.final(); | |
| 192 | } | |
| 193 | ||
| 194 | fn testHashShallow(key: var) u64 { | |
| 195 | // Any hash could be used here, for testing autoHash. | |
| 196 | var hasher = Wyhash.init(0); | |
| 197 | hash(&hasher, key, .Shallow); | |
| 198 | return hasher.final(); | |
| 199 | } | |
| 200 | ||
| 201 | fn testHashDeep(key: var) u64 { | |
| 117 | 202 | // Any hash could be used here, for testing autoHash. |
| 118 | 203 | var hasher = Wyhash.init(0); |
| 119 | autoHash(&hasher, key); | |
| 204 | hash(&hasher, key, .Deep); | |
| 120 | 205 | return hasher.final(); |
| 121 | 206 | } |
| 122 | 207 | |
| 123 | test "autoHash slice" { | |
| 208 | fn testHashDeepRecursive(key: var) u64 { | |
| 209 | // Any hash could be used here, for testing autoHash. | |
| 210 | var hasher = Wyhash.init(0); | |
| 211 | hash(&hasher, key, .DeepRecursive); | |
| 212 | return hasher.final(); | |
| 213 | } | |
| 214 | ||
| 215 | test "hash pointer" { | |
| 216 | const array = [_]u32{ 123, 123, 123 }; | |
| 217 | const a = &array[0]; | |
| 218 | const b = &array[1]; | |
| 219 | const c = &array[2]; | |
| 220 | const d = a; | |
| 221 | ||
| 222 | testing.expect(testHashShallow(a) == testHashShallow(d)); | |
| 223 | testing.expect(testHashShallow(a) != testHashShallow(c)); | |
| 224 | testing.expect(testHashShallow(a) != testHashShallow(b)); | |
| 225 | ||
| 226 | testing.expect(testHashDeep(a) == testHashDeep(a)); | |
| 227 | testing.expect(testHashDeep(a) == testHashDeep(c)); | |
| 228 | testing.expect(testHashDeep(a) == testHashDeep(b)); | |
| 229 | ||
| 230 | testing.expect(testHashDeepRecursive(a) == testHashDeepRecursive(a)); | |
| 231 | testing.expect(testHashDeepRecursive(a) == testHashDeepRecursive(c)); | |
| 232 | testing.expect(testHashDeepRecursive(a) == testHashDeepRecursive(b)); | |
| 233 | } | |
| 234 | ||
| 235 | test "hash slice shallow" { | |
| 236 | // Allocate one array dynamically so that we're assured it is not merged | |
| 237 | // with the other by the optimization passes. | |
| 238 | const array1 = try std.heap.direct_allocator.create([6]u32); | |
| 239 | defer std.heap.direct_allocator.destroy(array1); | |
| 240 | array1.* = [_]u32{ 1, 2, 3, 4, 5, 6 }; | |
| 241 | const array2 = [_]u32{ 1, 2, 3, 4, 5, 6 }; | |
| 242 | const a = array1[0..]; | |
| 243 | const b = array2[0..]; | |
| 244 | const c = array1[0..3]; | |
| 245 | testing.expect(testHashShallow(a) == testHashShallow(a)); | |
| 246 | testing.expect(testHashShallow(a) != testHashShallow(array1)); | |
| 247 | testing.expect(testHashShallow(a) != testHashShallow(b)); | |
| 248 | testing.expect(testHashShallow(a) != testHashShallow(c)); | |
| 249 | } | |
| 250 | ||
| 251 | test "hash slice deep" { | |
| 124 | 252 | // Allocate one array dynamically so that we're assured it is not merged |
| 125 | 253 | // with the other by the optimization passes. |
| 126 | 254 | const array1 = try std.heap.direct_allocator.create([6]u32); |
| ... | ... | @@ -130,23 +258,62 @@ test "autoHash slice" { |
| 130 | 258 | const a = array1[0..]; |
| 131 | 259 | const b = array2[0..]; |
| 132 | 260 | const c = array1[0..3]; |
| 133 | testing.expect(testAutoHash(a) == testAutoHash(a)); | |
| 134 | testing.expect(testAutoHash(a) != testAutoHash(array1)); | |
| 135 | testing.expect(testAutoHash(a) != testAutoHash(b)); | |
| 136 | testing.expect(testAutoHash(a) != testAutoHash(c)); | |
| 261 | testing.expect(testHashDeep(a) == testHashDeep(a)); | |
| 262 | testing.expect(testHashDeep(a) == testHashDeep(array1)); | |
| 263 | testing.expect(testHashDeep(a) == testHashDeep(b)); | |
| 264 | testing.expect(testHashDeep(a) != testHashDeep(c)); | |
| 265 | } | |
| 266 | ||
| 267 | test "hash struct deep" { | |
| 268 | const Foo = struct { | |
| 269 | a: u32, | |
| 270 | b: f64, | |
| 271 | c: *bool, | |
| 272 | ||
| 273 | const Self = @This(); | |
| 274 | ||
| 275 | pub fn init(allocator: *mem.Allocator, a_: u32, b_: f64, c_: bool) !Self { | |
| 276 | const ptr = try allocator.create(bool); | |
| 277 | ptr.* = c_; | |
| 278 | return Self{ .a = a_, .b = b_, .c = ptr }; | |
| 279 | } | |
| 280 | }; | |
| 281 | ||
| 282 | const allocator = std.heap.direct_allocator; | |
| 283 | const foo = try Foo.init(allocator, 123, 1.0, true); | |
| 284 | const bar = try Foo.init(allocator, 123, 1.0, true); | |
| 285 | const baz = try Foo.init(allocator, 123, 1.0, false); | |
| 286 | defer allocator.destroy(foo.c); | |
| 287 | defer allocator.destroy(bar.c); | |
| 288 | defer allocator.destroy(baz.c); | |
| 289 | ||
| 290 | testing.expect(testHashDeep(foo) == testHashDeep(bar)); | |
| 291 | testing.expect(testHashDeep(foo) != testHashDeep(baz)); | |
| 292 | testing.expect(testHashDeep(bar) != testHashDeep(baz)); | |
| 293 | ||
| 294 | var hasher = Wyhash.init(0); | |
| 295 | const h = testHashDeep(foo); | |
| 296 | autoHash(&hasher, foo.a); | |
| 297 | autoHash(&hasher, foo.b); | |
| 298 | autoHash(&hasher, foo.c.*); | |
| 299 | testing.expectEqual(h, hasher.final()); | |
| 300 | ||
| 301 | const h2 = testHashDeepRecursive(&foo); | |
| 302 | testing.expect(h2 != testHashDeep(&foo)); | |
| 303 | testing.expect(h2 == testHashDeep(foo)); | |
| 137 | 304 | } |
| 138 | 305 | |
| 139 | test "testAutoHash optional" { | |
| 306 | test "testHash optional" { | |
| 140 | 307 | const a: ?u32 = 123; |
| 141 | 308 | const b: ?u32 = null; |
| 142 | testing.expectEqual(testAutoHash(a), testAutoHash(u32(123))); | |
| 143 | testing.expect(testAutoHash(a) != testAutoHash(b)); | |
| 144 | testing.expectEqual(testAutoHash(b), 0); | |
| 309 | testing.expectEqual(testHash(a), testHash(u32(123))); | |
| 310 | testing.expect(testHash(a) != testHash(b)); | |
| 311 | testing.expectEqual(testHash(b), 0); | |
| 145 | 312 | } |
| 146 | 313 | |
| 147 | test "testAutoHash array" { | |
| 314 | test "testHash array" { | |
| 148 | 315 | const a = [_]u32{ 1, 2, 3 }; |
| 149 | const h = testAutoHash(a); | |
| 316 | const h = testHash(a); | |
| 150 | 317 | var hasher = Wyhash.init(0); |
| 151 | 318 | autoHash(&hasher, u32(1)); |
| 152 | 319 | autoHash(&hasher, u32(2)); |
| ... | ... | @@ -154,14 +321,14 @@ test "testAutoHash array" { |
| 154 | 321 | testing.expectEqual(h, hasher.final()); |
| 155 | 322 | } |
| 156 | 323 | |
| 157 | test "testAutoHash struct" { | |
| 324 | test "testHash struct" { | |
| 158 | 325 | const Foo = struct { |
| 159 | 326 | a: u32 = 1, |
| 160 | 327 | b: u32 = 2, |
| 161 | 328 | c: u32 = 3, |
| 162 | 329 | }; |
| 163 | 330 | const f = Foo{}; |
| 164 | const h = testAutoHash(f); | |
| 331 | const h = testHash(f); | |
| 165 | 332 | var hasher = Wyhash.init(0); |
| 166 | 333 | autoHash(&hasher, u32(1)); |
| 167 | 334 | autoHash(&hasher, u32(2)); |
| ... | ... | @@ -169,7 +336,7 @@ test "testAutoHash struct" { |
| 169 | 336 | testing.expectEqual(h, hasher.final()); |
| 170 | 337 | } |
| 171 | 338 | |
| 172 | test "testAutoHash union" { | |
| 339 | test "testHash union" { | |
| 173 | 340 | const Foo = union(enum) { |
| 174 | 341 | A: u32, |
| 175 | 342 | B: f32, |
| ... | ... | @@ -179,24 +346,24 @@ test "testAutoHash union" { |
| 179 | 346 | const a = Foo{ .A = 18 }; |
| 180 | 347 | var b = Foo{ .B = 12.34 }; |
| 181 | 348 | const c = Foo{ .C = 18 }; |
| 182 | testing.expect(testAutoHash(a) == testAutoHash(a)); | |
| 183 | testing.expect(testAutoHash(a) != testAutoHash(b)); | |
| 184 | testing.expect(testAutoHash(a) != testAutoHash(c)); | |
| 349 | testing.expect(testHash(a) == testHash(a)); | |
| 350 | testing.expect(testHash(a) != testHash(b)); | |
| 351 | testing.expect(testHash(a) != testHash(c)); | |
| 185 | 352 | |
| 186 | 353 | b = Foo{ .A = 18 }; |
| 187 | testing.expect(testAutoHash(a) == testAutoHash(b)); | |
| 354 | testing.expect(testHash(a) == testHash(b)); | |
| 188 | 355 | } |
| 189 | 356 | |
| 190 | test "testAutoHash vector" { | |
| 357 | test "testHash vector" { | |
| 191 | 358 | const a: @Vector(4, u32) = [_]u32{ 1, 2, 3, 4 }; |
| 192 | 359 | const b: @Vector(4, u32) = [_]u32{ 1, 2, 3, 5 }; |
| 193 | 360 | const c: @Vector(4, u31) = [_]u31{ 1, 2, 3, 4 }; |
| 194 | testing.expect(testAutoHash(a) == testAutoHash(a)); | |
| 195 | testing.expect(testAutoHash(a) != testAutoHash(b)); | |
| 196 | testing.expect(testAutoHash(a) != testAutoHash(c)); | |
| 361 | testing.expect(testHash(a) == testHash(a)); | |
| 362 | testing.expect(testHash(a) != testHash(b)); | |
| 363 | testing.expect(testHash(a) != testHash(c)); | |
| 197 | 364 | } |
| 198 | 365 | |
| 199 | test "testAutoHash error union" { | |
| 366 | test "testHash error union" { | |
| 200 | 367 | const Errors = error{Test}; |
| 201 | 368 | const Foo = struct { |
| 202 | 369 | a: u32 = 1, |
| ... | ... | @@ -205,7 +372,7 @@ test "testAutoHash error union" { |
| 205 | 372 | }; |
| 206 | 373 | const f = Foo{}; |
| 207 | 374 | const g: Errors!Foo = Errors.Test; |
| 208 | testing.expect(testAutoHash(f) != testAutoHash(g)); | |
| 209 | testing.expect(testAutoHash(f) == testAutoHash(Foo{})); | |
| 210 | testing.expect(testAutoHash(g) == testAutoHash(Errors.Test)); | |
| 375 | testing.expect(testHash(f) != testHash(g)); | |
| 376 | testing.expect(testHash(f) == testHash(Foo{})); | |
| 377 | testing.expect(testHash(g) == testHash(Errors.Test)); | |
| 211 | 378 | } |
std/hash/benchmark.zig created+273| ... | ... | @@ -0,0 +1,273 @@ |
| 1 | // zig run benchmark.zig --release-fast --override-std-dir .. | |
| 2 | ||
| 3 | const builtin = @import("builtin"); | |
| 4 | const std = @import("std"); | |
| 5 | const time = std.time; | |
| 6 | const Timer = time.Timer; | |
| 7 | const hash = std.hash; | |
| 8 | ||
| 9 | const KiB = 1024; | |
| 10 | const MiB = 1024 * KiB; | |
| 11 | const GiB = 1024 * MiB; | |
| 12 | ||
| 13 | var prng = std.rand.DefaultPrng.init(0); | |
| 14 | ||
| 15 | const Hash = struct { | |
| 16 | ty: type, | |
| 17 | name: []const u8, | |
| 18 | has_iterative_api: bool = true, | |
| 19 | init_u8s: ?[]const u8 = null, | |
| 20 | init_u64: ?u64 = null, | |
| 21 | }; | |
| 22 | ||
| 23 | const siphash_key = "0123456789abcdef"; | |
| 24 | ||
| 25 | const hashes = [_]Hash{ | |
| 26 | Hash{ | |
| 27 | .ty = hash.Wyhash, | |
| 28 | .name = "wyhash", | |
| 29 | .init_u64 = 0, | |
| 30 | }, | |
| 31 | Hash{ | |
| 32 | .ty = hash.SipHash64(1, 3), | |
| 33 | .name = "siphash(1,3)", | |
| 34 | .init_u8s = siphash_key, | |
| 35 | }, | |
| 36 | Hash{ | |
| 37 | .ty = hash.SipHash64(2, 4), | |
| 38 | .name = "siphash(2,4)", | |
| 39 | .init_u8s = siphash_key, | |
| 40 | }, | |
| 41 | Hash{ | |
| 42 | .ty = hash.Fnv1a_64, | |
| 43 | .name = "fnv1a", | |
| 44 | }, | |
| 45 | Hash{ | |
| 46 | .ty = hash.Adler32, | |
| 47 | .name = "adler32", | |
| 48 | }, | |
| 49 | Hash{ | |
| 50 | .ty = hash.crc.Crc32WithPoly(hash.crc.Polynomial.IEEE), | |
| 51 | .name = "crc32-slicing-by-8", | |
| 52 | }, | |
| 53 | Hash{ | |
| 54 | .ty = hash.crc.Crc32SmallWithPoly(hash.crc.Polynomial.IEEE), | |
| 55 | .name = "crc32-half-byte-lookup", | |
| 56 | }, | |
| 57 | Hash{ | |
| 58 | .ty = hash.CityHash32, | |
| 59 | .name = "cityhash-32", | |
| 60 | .has_iterative_api = false, | |
| 61 | }, | |
| 62 | Hash{ | |
| 63 | .ty = hash.CityHash64, | |
| 64 | .name = "cityhash-64", | |
| 65 | .has_iterative_api = false, | |
| 66 | }, | |
| 67 | Hash{ | |
| 68 | .ty = hash.Murmur2_32, | |
| 69 | .name = "murmur2-32", | |
| 70 | .has_iterative_api = false, | |
| 71 | }, | |
| 72 | Hash{ | |
| 73 | .ty = hash.Murmur2_64, | |
| 74 | .name = "murmur2-64", | |
| 75 | .has_iterative_api = false, | |
| 76 | }, | |
| 77 | Hash{ | |
| 78 | .ty = hash.Murmur3_32, | |
| 79 | .name = "murmur3-32", | |
| 80 | .has_iterative_api = false, | |
| 81 | }, | |
| 82 | }; | |
| 83 | ||
| 84 | const Result = struct { | |
| 85 | hash: u64, | |
| 86 | throughput: u64, | |
| 87 | }; | |
| 88 | ||
| 89 | const block_size: usize = 8 * 8192; | |
| 90 | ||
| 91 | pub fn benchmarkHash(comptime H: var, bytes: usize) !Result { | |
| 92 | var h = blk: { | |
| 93 | if (H.init_u8s) |init| { | |
| 94 | break :blk H.ty.init(init); | |
| 95 | } | |
| 96 | if (H.init_u64) |init| { | |
| 97 | break :blk H.ty.init(init); | |
| 98 | } | |
| 99 | break :blk H.ty.init(); | |
| 100 | }; | |
| 101 | ||
| 102 | var block: [block_size]u8 = undefined; | |
| 103 | prng.random.bytes(block[0..]); | |
| 104 | ||
| 105 | var offset: usize = 0; | |
| 106 | var timer = try Timer.start(); | |
| 107 | const start = timer.lap(); | |
| 108 | while (offset < bytes) : (offset += block.len) { | |
| 109 | h.update(block[0..]); | |
| 110 | } | |
| 111 | const end = timer.read(); | |
| 112 | ||
| 113 | const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s; | |
| 114 | const throughput = @floatToInt(u64, @intToFloat(f64, bytes) / elapsed_s); | |
| 115 | ||
| 116 | return Result{ | |
| 117 | .hash = h.final(), | |
| 118 | .throughput = throughput, | |
| 119 | }; | |
| 120 | } | |
| 121 | ||
| 122 | pub fn benchmarkHashSmallKeys(comptime H: var, key_size: usize, bytes: usize) !Result { | |
| 123 | const key_count = bytes / key_size; | |
| 124 | var block: [block_size]u8 = undefined; | |
| 125 | prng.random.bytes(block[0..]); | |
| 126 | ||
| 127 | var i: usize = 0; | |
| 128 | var timer = try Timer.start(); | |
| 129 | const start = timer.lap(); | |
| 130 | ||
| 131 | var sum: u64 = 0; | |
| 132 | while (i < key_count) : (i += 1) { | |
| 133 | const small_key = block[0..key_size]; | |
| 134 | sum +%= blk: { | |
| 135 | if (H.init_u8s) |init| { | |
| 136 | break :blk H.ty.hash(init, small_key); | |
| 137 | } | |
| 138 | if (H.init_u64) |init| { | |
| 139 | break :blk H.ty.hash(init, small_key); | |
| 140 | } | |
| 141 | break :blk H.ty.hash(small_key); | |
| 142 | }; | |
| 143 | } | |
| 144 | const end = timer.read(); | |
| 145 | ||
| 146 | const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s; | |
| 147 | const throughput = @floatToInt(u64, @intToFloat(f64, bytes) / elapsed_s); | |
| 148 | ||
| 149 | return Result{ | |
| 150 | .hash = sum, | |
| 151 | .throughput = throughput, | |
| 152 | }; | |
| 153 | } | |
| 154 | ||
| 155 | fn usage() void { | |
| 156 | std.debug.warn( | |
| 157 | \\throughput_test [options] | |
| 158 | \\ | |
| 159 | \\Options: | |
| 160 | \\ --filter [test-name] | |
| 161 | \\ --seed [int] | |
| 162 | \\ --count [int] | |
| 163 | \\ --key-size [int] | |
| 164 | \\ --iterative-only | |
| 165 | \\ --help | |
| 166 | \\ | |
| 167 | ); | |
| 168 | } | |
| 169 | ||
| 170 | fn mode(comptime x: comptime_int) comptime_int { | |
| 171 | return if (builtin.mode == builtin.Mode.Debug) x / 64 else x; | |
| 172 | } | |
| 173 | ||
| 174 | // TODO(#1358): Replace with builtin formatted padding when available. | |
| 175 | fn printPad(stdout: var, s: []const u8) !void { | |
| 176 | var i: usize = 0; | |
| 177 | while (i < 12 - s.len) : (i += 1) { | |
| 178 | try stdout.print(" "); | |
| 179 | } | |
| 180 | try stdout.print("{}", s); | |
| 181 | } | |
| 182 | ||
| 183 | pub fn main() !void { | |
| 184 | var stdout_file = try std.io.getStdOut(); | |
| 185 | var stdout_out_stream = stdout_file.outStream(); | |
| 186 | const stdout = &stdout_out_stream.stream; | |
| 187 | ||
| 188 | var buffer: [1024]u8 = undefined; | |
| 189 | var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]); | |
| 190 | const args = try std.process.argsAlloc(&fixed.allocator); | |
| 191 | ||
| 192 | var filter: ?[]u8 = ""; | |
| 193 | var count: usize = mode(128 * MiB); | |
| 194 | var key_size: usize = 32; | |
| 195 | var seed: u32 = 0; | |
| 196 | var test_iterative_only = false; | |
| 197 | ||
| 198 | var i: usize = 1; | |
| 199 | while (i < args.len) : (i += 1) { | |
| 200 | if (std.mem.eql(u8, args[i], "--mode")) { | |
| 201 | try stdout.print("{}\n", builtin.mode); | |
| 202 | return; | |
| 203 | } else if (std.mem.eql(u8, args[i], "--seed")) { | |
| 204 | i += 1; | |
| 205 | if (i == args.len) { | |
| 206 | usage(); | |
| 207 | std.os.exit(1); | |
| 208 | } | |
| 209 | ||
| 210 | seed = try std.fmt.parseUnsigned(u32, args[i], 10); | |
| 211 | // we seed later | |
| 212 | } else if (std.mem.eql(u8, args[i], "--filter")) { | |
| 213 | i += 1; | |
| 214 | if (i == args.len) { | |
| 215 | usage(); | |
| 216 | std.os.exit(1); | |
| 217 | } | |
| 218 | ||
| 219 | filter = args[i]; | |
| 220 | } else if (std.mem.eql(u8, args[i], "--count")) { | |
| 221 | i += 1; | |
| 222 | if (i == args.len) { | |
| 223 | usage(); | |
| 224 | std.os.exit(1); | |
| 225 | } | |
| 226 | ||
| 227 | const c = try std.fmt.parseUnsigned(usize, args[i], 10); | |
| 228 | count = c * MiB; | |
| 229 | } else if (std.mem.eql(u8, args[i], "--key-size")) { | |
| 230 | i += 1; | |
| 231 | if (i == args.len) { | |
| 232 | usage(); | |
| 233 | std.os.exit(1); | |
| 234 | } | |
| 235 | ||
| 236 | key_size = try std.fmt.parseUnsigned(usize, args[i], 10); | |
| 237 | if (key_size > block_size) { | |
| 238 | try stdout.print("key_size cannot exceed block size of {}\n", block_size); | |
| 239 | std.os.exit(1); | |
| 240 | } | |
| 241 | } else if (std.mem.eql(u8, args[i], "--iterative-only")) { | |
| 242 | test_iterative_only = true; | |
| 243 | } else if (std.mem.eql(u8, args[i], "--help")) { | |
| 244 | usage(); | |
| 245 | return; | |
| 246 | } else { | |
| 247 | usage(); | |
| 248 | std.os.exit(1); | |
| 249 | } | |
| 250 | } | |
| 251 | ||
| 252 | inline for (hashes) |H| { | |
| 253 | if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) { | |
| 254 | if (!test_iterative_only or H.has_iterative_api) { | |
| 255 | try stdout.print("{}\n", H.name); | |
| 256 | ||
| 257 | // Always reseed prior to every call so we are hashing the same buffer contents. | |
| 258 | // This allows easier comparison between different implementations. | |
| 259 | if (H.has_iterative_api) { | |
| 260 | prng.seed(seed); | |
| 261 | const result = try benchmarkHash(H, count); | |
| 262 | try stdout.print(" iterative: {:4} MiB/s [{x:0<16}]\n", result.throughput / (1 * MiB), result.hash); | |
| 263 | } | |
| 264 | ||
| 265 | if (!test_iterative_only) { | |
| 266 | prng.seed(seed); | |
| 267 | const result_small = try benchmarkHashSmallKeys(H, key_size, count); | |
| 268 | try stdout.print(" small keys: {:4} MiB/s [{x:0<16}]\n", result_small.throughput / (1 * MiB), result_small.hash); | |
| 269 | } | |
| 270 | } | |
| 271 | } | |
| 272 | } | |
| 273 | } |
std/hash/crc.zig+3-3| ... | ... | @@ -10,9 +10,9 @@ const debug = std.debug; |
| 10 | 10 | const testing = std.testing; |
| 11 | 11 | |
| 12 | 12 | pub const Polynomial = struct { |
| 13 | const IEEE = 0xedb88320; | |
| 14 | const Castagnoli = 0x82f63b78; | |
| 15 | const Koopman = 0xeb31d82e; | |
| 13 | pub const IEEE = 0xedb88320; | |
| 14 | pub const Castagnoli = 0x82f63b78; | |
| 15 | pub const Koopman = 0xeb31d82e; | |
| 16 | 16 | }; |
| 17 | 17 | |
| 18 | 18 | // IEEE is by far the most common CRC and so is aliased by default. |
std/hash/siphash.zig+107-45| ... | ... | @@ -21,7 +21,7 @@ pub fn SipHash128(comptime c_rounds: usize, comptime d_rounds: usize) type { |
| 21 | 21 | return SipHash(u128, c_rounds, d_rounds); |
| 22 | 22 | } |
| 23 | 23 | |
| 24 | fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) type { | |
| 24 | fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) type { | |
| 25 | 25 | assert(T == u64 or T == u128); |
| 26 | 26 | assert(c_rounds > 0 and d_rounds > 0); |
| 27 | 27 | |
| ... | ... | @@ -34,10 +34,6 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) |
| 34 | 34 | v1: u64, |
| 35 | 35 | v2: u64, |
| 36 | 36 | v3: u64, |
| 37 | ||
| 38 | // streaming cache | |
| 39 | buf: [8]u8, | |
| 40 | buf_len: usize, | |
| 41 | 37 | msg_len: u8, |
| 42 | 38 | |
| 43 | 39 | pub fn init(key: []const u8) Self { |
| ... | ... | @@ -51,9 +47,6 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) |
| 51 | 47 | .v1 = k1 ^ 0x646f72616e646f6d, |
| 52 | 48 | .v2 = k0 ^ 0x6c7967656e657261, |
| 53 | 49 | .v3 = k1 ^ 0x7465646279746573, |
| 54 | ||
| 55 | .buf = undefined, | |
| 56 | .buf_len = 0, | |
| 57 | 50 | .msg_len = 0, |
| 58 | 51 | }; |
| 59 | 52 | |
| ... | ... | @@ -64,73 +57,66 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) |
| 64 | 57 | return d; |
| 65 | 58 | } |
| 66 | 59 | |
| 67 | pub fn update(d: *Self, b: []const u8) void { | |
| 68 | var off: usize = 0; | |
| 69 | ||
| 70 | // Partial from previous. | |
| 71 | if (d.buf_len != 0 and d.buf_len + b.len > 8) { | |
| 72 | off += 8 - d.buf_len; | |
| 73 | mem.copy(u8, d.buf[d.buf_len..], b[0..off]); | |
| 74 | d.round(d.buf[0..]); | |
| 75 | d.buf_len = 0; | |
| 76 | } | |
| 60 | pub fn update(self: *Self, b: []const u8) void { | |
| 61 | std.debug.assert(b.len % 8 == 0); | |
| 77 | 62 | |
| 78 | // Full middle blocks. | |
| 79 | while (off + 8 <= b.len) : (off += 8) { | |
| 80 | d.round(b[off .. off + 8]); | |
| 63 | var off: usize = 0; | |
| 64 | while (off < b.len) : (off += 8) { | |
| 65 | @inlineCall(self.round, b[off .. off + 8]); | |
| 81 | 66 | } |
| 82 | 67 | |
| 83 | // Remainder for next pass. | |
| 84 | mem.copy(u8, d.buf[d.buf_len..], b[off..]); | |
| 85 | d.buf_len += @intCast(u8, b[off..].len); | |
| 86 | d.msg_len +%= @truncate(u8, b.len); | |
| 68 | self.msg_len +%= @truncate(u8, b.len); | |
| 87 | 69 | } |
| 88 | 70 | |
| 89 | pub fn final(d: *Self) T { | |
| 90 | // Padding | |
| 91 | mem.set(u8, d.buf[d.buf_len..], 0); | |
| 92 | d.buf[7] = d.msg_len; | |
| 93 | d.round(d.buf[0..]); | |
| 71 | pub fn final(self: *Self, b: []const u8) T { | |
| 72 | std.debug.assert(b.len < 8); | |
| 73 | ||
| 74 | self.msg_len +%= @truncate(u8, b.len); | |
| 75 | ||
| 76 | var buf = [_]u8{0} ** 8; | |
| 77 | mem.copy(u8, buf[0..], b[0..]); | |
| 78 | buf[7] = self.msg_len; | |
| 79 | self.round(buf[0..]); | |
| 94 | 80 | |
| 95 | 81 | if (T == u128) { |
| 96 | d.v2 ^= 0xee; | |
| 82 | self.v2 ^= 0xee; | |
| 97 | 83 | } else { |
| 98 | d.v2 ^= 0xff; | |
| 84 | self.v2 ^= 0xff; | |
| 99 | 85 | } |
| 100 | 86 | |
| 101 | 87 | comptime var i: usize = 0; |
| 102 | 88 | inline while (i < d_rounds) : (i += 1) { |
| 103 | @inlineCall(sipRound, d); | |
| 89 | @inlineCall(sipRound, self); | |
| 104 | 90 | } |
| 105 | 91 | |
| 106 | const b1 = d.v0 ^ d.v1 ^ d.v2 ^ d.v3; | |
| 92 | const b1 = self.v0 ^ self.v1 ^ self.v2 ^ self.v3; | |
| 107 | 93 | if (T == u64) { |
| 108 | 94 | return b1; |
| 109 | 95 | } |
| 110 | 96 | |
| 111 | d.v1 ^= 0xdd; | |
| 97 | self.v1 ^= 0xdd; | |
| 112 | 98 | |
| 113 | 99 | comptime var j: usize = 0; |
| 114 | 100 | inline while (j < d_rounds) : (j += 1) { |
| 115 | @inlineCall(sipRound, d); | |
| 101 | @inlineCall(sipRound, self); | |
| 116 | 102 | } |
| 117 | 103 | |
| 118 | const b2 = d.v0 ^ d.v1 ^ d.v2 ^ d.v3; | |
| 104 | const b2 = self.v0 ^ self.v1 ^ self.v2 ^ self.v3; | |
| 119 | 105 | return (u128(b2) << 64) | b1; |
| 120 | 106 | } |
| 121 | 107 | |
| 122 | fn round(d: *Self, b: []const u8) void { | |
| 108 | fn round(self: *Self, b: []const u8) void { | |
| 123 | 109 | assert(b.len == 8); |
| 124 | 110 | |
| 125 | 111 | const m = mem.readIntSliceLittle(u64, b[0..]); |
| 126 | d.v3 ^= m; | |
| 112 | self.v3 ^= m; | |
| 127 | 113 | |
| 128 | 114 | comptime var i: usize = 0; |
| 129 | 115 | inline while (i < c_rounds) : (i += 1) { |
| 130 | @inlineCall(sipRound, d); | |
| 116 | @inlineCall(sipRound, self); | |
| 131 | 117 | } |
| 132 | 118 | |
| 133 | d.v0 ^= m; | |
| 119 | self.v0 ^= m; | |
| 134 | 120 | } |
| 135 | 121 | |
| 136 | 122 | fn sipRound(d: *Self) void { |
| ... | ... | @@ -151,9 +137,61 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) |
| 151 | 137 | } |
| 152 | 138 | |
| 153 | 139 | pub fn hash(key: []const u8, input: []const u8) T { |
| 140 | const aligned_len = input.len - (input.len % 8); | |
| 141 | ||
| 154 | 142 | var c = Self.init(key); |
| 155 | c.update(input); | |
| 156 | return c.final(); | |
| 143 | @inlineCall(c.update, input[0..aligned_len]); | |
| 144 | return @inlineCall(c.final, input[aligned_len..]); | |
| 145 | } | |
| 146 | }; | |
| 147 | } | |
| 148 | ||
| 149 | pub fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) type { | |
| 150 | assert(T == u64 or T == u128); | |
| 151 | assert(c_rounds > 0 and d_rounds > 0); | |
| 152 | ||
| 153 | return struct { | |
| 154 | const State = SipHashStateless(T, c_rounds, d_rounds); | |
| 155 | const Self = @This(); | |
| 156 | const digest_size = 64; | |
| 157 | const block_size = 64; | |
| 158 | ||
| 159 | state: State, | |
| 160 | buf: [8]u8, | |
| 161 | buf_len: usize, | |
| 162 | ||
| 163 | pub fn init(key: []const u8) Self { | |
| 164 | return Self{ | |
| 165 | .state = State.init(key), | |
| 166 | .buf = undefined, | |
| 167 | .buf_len = 0, | |
| 168 | }; | |
| 169 | } | |
| 170 | ||
| 171 | pub fn update(self: *Self, b: []const u8) void { | |
| 172 | var off: usize = 0; | |
| 173 | ||
| 174 | if (self.buf_len != 0 and self.buf_len + b.len >= 8) { | |
| 175 | off += 8 - self.buf_len; | |
| 176 | mem.copy(u8, self.buf[self.buf_len..], b[0..off]); | |
| 177 | self.state.update(self.buf[0..]); | |
| 178 | self.buf_len = 0; | |
| 179 | } | |
| 180 | ||
| 181 | const remain_len = b.len - off; | |
| 182 | const aligned_len = remain_len - (remain_len % 8); | |
| 183 | self.state.update(b[off .. off + aligned_len]); | |
| 184 | ||
| 185 | mem.copy(u8, self.buf[self.buf_len..], b[off + aligned_len ..]); | |
| 186 | self.buf_len += @intCast(u8, b[off + aligned_len ..].len); | |
| 187 | } | |
| 188 | ||
| 189 | pub fn final(self: *Self) T { | |
| 190 | return self.state.final(self.buf[0..self.buf_len]); | |
| 191 | } | |
| 192 | ||
| 193 | pub fn hash(key: []const u8, input: []const u8) T { | |
| 194 | return State.hash(key, input); | |
| 157 | 195 | } |
| 158 | 196 | }; |
| 159 | 197 | } |
| ... | ... | @@ -237,7 +275,7 @@ test "siphash64-2-4 sanity" { |
| 237 | 275 | buffer[i] = @intCast(u8, i); |
| 238 | 276 | |
| 239 | 277 | const expected = mem.readIntLittle(u64, &vector); |
| 240 | testing.expect(siphash.hash(test_key, buffer[0..i]) == expected); | |
| 278 | testing.expectEqual(siphash.hash(test_key, buffer[0..i]), expected); | |
| 241 | 279 | } |
| 242 | 280 | } |
| 243 | 281 | |
| ... | ... | @@ -316,6 +354,30 @@ test "siphash128-2-4 sanity" { |
| 316 | 354 | buffer[i] = @intCast(u8, i); |
| 317 | 355 | |
| 318 | 356 | const expected = mem.readIntLittle(u128, &vector); |
| 319 | testing.expect(siphash.hash(test_key, buffer[0..i]) == expected); | |
| 357 | testing.expectEqual(siphash.hash(test_key, buffer[0..i]), expected); | |
| 358 | } | |
| 359 | } | |
| 360 | ||
| 361 | test "iterative non-divisible update" { | |
| 362 | var buf: [1024]u8 = undefined; | |
| 363 | for (buf) |*e, i| { | |
| 364 | e.* = @truncate(u8, i); | |
| 365 | } | |
| 366 | ||
| 367 | const key = "0x128dad08f12307"; | |
| 368 | const Siphash = SipHash64(2, 4); | |
| 369 | ||
| 370 | var end: usize = 9; | |
| 371 | while (end < buf.len) : (end += 9) { | |
| 372 | const non_iterative_hash = Siphash.hash(key, buf[0..end]); | |
| 373 | ||
| 374 | var wy = Siphash.init(key); | |
| 375 | var i: usize = 0; | |
| 376 | while (i < end) : (i += 7) { | |
| 377 | wy.update(buf[i..std.math.min(i + 7, end)]); | |
| 378 | } | |
| 379 | const iterative_hash = wy.final(); | |
| 380 | ||
| 381 | std.testing.expectEqual(iterative_hash, non_iterative_hash); | |
| 320 | 382 | } |
| 321 | 383 | } |
std/hash/throughput_test.zig deleted-148| ... | ... | @@ -1,148 +0,0 @@ |
| 1 | const builtin = @import("builtin"); | |
| 2 | const std = @import("std"); | |
| 3 | const time = std.time; | |
| 4 | const Timer = time.Timer; | |
| 5 | const hash = std.hash; | |
| 6 | ||
| 7 | const KiB = 1024; | |
| 8 | const MiB = 1024 * KiB; | |
| 9 | const GiB = 1024 * MiB; | |
| 10 | ||
| 11 | var prng = std.rand.DefaultPrng.init(0); | |
| 12 | ||
| 13 | const Hash = struct { | |
| 14 | ty: type, | |
| 15 | name: []const u8, | |
| 16 | init_u8s: ?[]const u8 = null, | |
| 17 | init_u64: ?u64 = null, | |
| 18 | }; | |
| 19 | ||
| 20 | const siphash_key = "0123456789abcdef"; | |
| 21 | ||
| 22 | const hashes = [_]Hash{ | |
| 23 | Hash{ .ty = hash.Wyhash, .name = "wyhash", .init_u64 = 0 }, | |
| 24 | Hash{ .ty = hash.SipHash64(1, 3), .name = "siphash(1,3)", .init_u8s = siphash_key }, | |
| 25 | Hash{ .ty = hash.SipHash64(2, 4), .name = "siphash(2,4)", .init_u8s = siphash_key }, | |
| 26 | Hash{ .ty = hash.Fnv1a_64, .name = "fnv1a" }, | |
| 27 | Hash{ .ty = hash.Crc32, .name = "crc32" }, | |
| 28 | }; | |
| 29 | ||
| 30 | const Result = struct { | |
| 31 | hash: u64, | |
| 32 | throughput: u64, | |
| 33 | }; | |
| 34 | ||
| 35 | pub fn benchmarkHash(comptime H: var, bytes: usize) !Result { | |
| 36 | var h = blk: { | |
| 37 | if (H.init_u8s) |init| { | |
| 38 | break :blk H.ty.init(init); | |
| 39 | } | |
| 40 | if (H.init_u64) |init| { | |
| 41 | break :blk H.ty.init(init); | |
| 42 | } | |
| 43 | break :blk H.ty.init(); | |
| 44 | }; | |
| 45 | ||
| 46 | var block: [8192]u8 = undefined; | |
| 47 | prng.random.bytes(block[0..]); | |
| 48 | ||
| 49 | var offset: usize = 0; | |
| 50 | var timer = try Timer.start(); | |
| 51 | const start = timer.lap(); | |
| 52 | while (offset < bytes) : (offset += block.len) { | |
| 53 | h.update(block[0..]); | |
| 54 | } | |
| 55 | const end = timer.read(); | |
| 56 | ||
| 57 | const elapsed_s = @intToFloat(f64, end - start) / time.ns_per_s; | |
| 58 | const throughput = @floatToInt(u64, @intToFloat(f64, bytes) / elapsed_s); | |
| 59 | ||
| 60 | return Result{ | |
| 61 | .hash = h.final(), | |
| 62 | .throughput = throughput, | |
| 63 | }; | |
| 64 | } | |
| 65 | ||
| 66 | fn usage() void { | |
| 67 | std.debug.warn( | |
| 68 | \\throughput_test [options] | |
| 69 | \\ | |
| 70 | \\Options: | |
| 71 | \\ --filter [test-name] | |
| 72 | \\ --seed [int] | |
| 73 | \\ --count [int] | |
| 74 | \\ --help | |
| 75 | \\ | |
| 76 | ); | |
| 77 | } | |
| 78 | ||
| 79 | fn mode(comptime x: comptime_int) comptime_int { | |
| 80 | return if (builtin.mode == builtin.Mode.Debug) x / 64 else x; | |
| 81 | } | |
| 82 | ||
| 83 | // TODO(#1358): Replace with builtin formatted padding when available. | |
| 84 | fn printPad(stdout: var, s: []const u8) !void { | |
| 85 | var i: usize = 0; | |
| 86 | while (i < 12 - s.len) : (i += 1) { | |
| 87 | try stdout.print(" "); | |
| 88 | } | |
| 89 | try stdout.print("{}", s); | |
| 90 | } | |
| 91 | ||
| 92 | pub fn main() !void { | |
| 93 | var stdout_file = try std.io.getStdOut(); | |
| 94 | var stdout_out_stream = stdout_file.outStream(); | |
| 95 | const stdout = &stdout_out_stream.stream; | |
| 96 | ||
| 97 | var buffer: [1024]u8 = undefined; | |
| 98 | var fixed = std.heap.FixedBufferAllocator.init(buffer[0..]); | |
| 99 | const args = try std.process.argsAlloc(&fixed.allocator); | |
| 100 | ||
| 101 | var filter: ?[]u8 = ""; | |
| 102 | var count: usize = mode(128 * MiB); | |
| 103 | ||
| 104 | var i: usize = 1; | |
| 105 | while (i < args.len) : (i += 1) { | |
| 106 | if (std.mem.eql(u8, args[i], "--seed")) { | |
| 107 | i += 1; | |
| 108 | if (i == args.len) { | |
| 109 | usage(); | |
| 110 | std.os.exit(1); | |
| 111 | } | |
| 112 | ||
| 113 | const seed = try std.fmt.parseUnsigned(u32, args[i], 10); | |
| 114 | prng.seed(seed); | |
| 115 | } else if (std.mem.eql(u8, args[i], "--filter")) { | |
| 116 | i += 1; | |
| 117 | if (i == args.len) { | |
| 118 | usage(); | |
| 119 | std.os.exit(1); | |
| 120 | } | |
| 121 | ||
| 122 | filter = args[i]; | |
| 123 | } else if (std.mem.eql(u8, args[i], "--count")) { | |
| 124 | i += 1; | |
| 125 | if (i == args.len) { | |
| 126 | usage(); | |
| 127 | std.os.exit(1); | |
| 128 | } | |
| 129 | ||
| 130 | const c = try std.fmt.parseUnsigned(u32, args[i], 10); | |
| 131 | count = c * MiB; | |
| 132 | } else if (std.mem.eql(u8, args[i], "--help")) { | |
| 133 | usage(); | |
| 134 | return; | |
| 135 | } else { | |
| 136 | usage(); | |
| 137 | std.os.exit(1); | |
| 138 | } | |
| 139 | } | |
| 140 | ||
| 141 | inline for (hashes) |H| { | |
| 142 | if (filter == null or std.mem.indexOf(u8, H.name, filter.?) != null) { | |
| 143 | const result = try benchmarkHash(H, count); | |
| 144 | try printPad(stdout, H.name); | |
| 145 | try stdout.print(": {:4} MiB/s [{:16}]\n", result.throughput / (1 * MiB), result.hash); | |
| 146 | } | |
| 147 | } | |
| 148 | } |
std/hash/wyhash.zig+117-21| ... | ... | @@ -10,7 +10,8 @@ const primes = [_]u64{ |
| 10 | 10 | }; |
| 11 | 11 | |
| 12 | 12 | fn read_bytes(comptime bytes: u8, data: []const u8) u64 { |
| 13 | return mem.readVarInt(u64, data[0..bytes], .Little); | |
| 13 | const T = @IntType(false, 8 * bytes); | |
| 14 | return mem.readIntSliceLittle(T, data[0..bytes]); | |
| 14 | 15 | } |
| 15 | 16 | |
| 16 | 17 | fn read_8bytes_swapped(data: []const u8) u64 { |
| ... | ... | @@ -31,18 +32,21 @@ fn mix1(a: u64, b: u64, seed: u64) u64 { |
| 31 | 32 | return mum(a ^ seed ^ primes[2], b ^ seed ^ primes[3]); |
| 32 | 33 | } |
| 33 | 34 | |
| 34 | pub const Wyhash = struct { | |
| 35 | // Wyhash version which does not store internal state for handling partial buffers. | |
| 36 | // This is needed so that we can maximize the speed for the short key case, which will | |
| 37 | // use the non-iterative api which the public Wyhash exposes. | |
| 38 | const WyhashStateless = struct { | |
| 35 | 39 | seed: u64, |
| 36 | 40 | msg_len: usize, |
| 37 | 41 | |
| 38 | pub fn init(seed: u64) Wyhash { | |
| 39 | return Wyhash{ | |
| 42 | pub fn init(seed: u64) WyhashStateless { | |
| 43 | return WyhashStateless{ | |
| 40 | 44 | .seed = seed, |
| 41 | 45 | .msg_len = 0, |
| 42 | 46 | }; |
| 43 | 47 | } |
| 44 | 48 | |
| 45 | fn round(self: *Wyhash, b: []const u8) void { | |
| 49 | fn round(self: *WyhashStateless, b: []const u8) void { | |
| 46 | 50 | std.debug.assert(b.len == 32); |
| 47 | 51 | |
| 48 | 52 | self.seed = mix0( |
| ... | ... | @@ -56,12 +60,25 @@ pub const Wyhash = struct { |
| 56 | 60 | ); |
| 57 | 61 | } |
| 58 | 62 | |
| 59 | fn partial(self: *Wyhash, b: []const u8) void { | |
| 60 | const rem_key = b; | |
| 61 | const rem_len = b.len; | |
| 63 | pub fn update(self: *WyhashStateless, b: []const u8) void { | |
| 64 | std.debug.assert(b.len % 32 == 0); | |
| 65 | ||
| 66 | var off: usize = 0; | |
| 67 | while (off < b.len) : (off += 32) { | |
| 68 | @inlineCall(self.round, b[off .. off + 32]); | |
| 69 | } | |
| 62 | 70 | |
| 63 | var seed = self.seed; | |
| 64 | seed = switch (@intCast(u5, rem_len)) { | |
| 71 | self.msg_len += b.len; | |
| 72 | } | |
| 73 | ||
| 74 | pub fn final(self: *WyhashStateless, b: []const u8) u64 { | |
| 75 | std.debug.assert(b.len < 32); | |
| 76 | ||
| 77 | const seed = self.seed; | |
| 78 | const rem_len = @intCast(u5, b.len); | |
| 79 | const rem_key = b[0..rem_len]; | |
| 80 | ||
| 81 | self.seed = switch (rem_len) { | |
| 65 | 82 | 0 => seed, |
| 66 | 83 | 1 => mix0(read_bytes(1, rem_key), primes[4], seed), |
| 67 | 84 | 2 => mix0(read_bytes(2, rem_key), primes[4], seed), |
| ... | ... | @@ -95,34 +112,70 @@ pub const Wyhash = struct { |
| 95 | 112 | 30 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_8bytes_swapped(rem_key[16..]), (read_bytes(4, rem_key[24..]) << 16) | read_bytes(2, rem_key[28..]), seed), |
| 96 | 113 | 31 => mix0(read_8bytes_swapped(rem_key), read_8bytes_swapped(rem_key[8..]), seed) ^ mix1(read_8bytes_swapped(rem_key[16..]), (read_bytes(4, rem_key[24..]) << 24) | (read_bytes(2, rem_key[28..]) << 8) | read_bytes(1, rem_key[30..]), seed), |
| 97 | 114 | }; |
| 98 | self.seed = seed; | |
| 115 | ||
| 116 | self.msg_len += b.len; | |
| 117 | return mum(self.seed ^ self.msg_len, primes[4]); | |
| 118 | } | |
| 119 | ||
| 120 | pub fn hash(seed: u64, input: []const u8) u64 { | |
| 121 | const aligned_len = input.len - (input.len % 32); | |
| 122 | ||
| 123 | var c = WyhashStateless.init(seed); | |
| 124 | @inlineCall(c.update, input[0..aligned_len]); | |
| 125 | return @inlineCall(c.final, input[aligned_len..]); | |
| 126 | } | |
| 127 | }; | |
| 128 | ||
| 129 | /// Fast non-cryptographic 64bit hash function. | |
| 130 | /// See https://github.com/wangyi-fudan/wyhash | |
| 131 | pub const Wyhash = struct { | |
| 132 | state: WyhashStateless, | |
| 133 | ||
| 134 | buf: [32]u8, | |
| 135 | buf_len: usize, | |
| 136 | ||
| 137 | pub fn init(seed: u64) Wyhash { | |
| 138 | return Wyhash{ | |
| 139 | .state = WyhashStateless.init(seed), | |
| 140 | .buf = undefined, | |
| 141 | .buf_len = 0, | |
| 142 | }; | |
| 99 | 143 | } |
| 100 | 144 | |
| 101 | 145 | pub fn update(self: *Wyhash, b: []const u8) void { |
| 102 | 146 | var off: usize = 0; |
| 103 | 147 | |
| 104 | // Full middle blocks. | |
| 105 | while (off + 32 <= b.len) : (off += 32) { | |
| 106 | @inlineCall(self.round, b[off .. off + 32]); | |
| 148 | if (self.buf_len != 0 and self.buf_len + b.len >= 32) { | |
| 149 | off += 32 - self.buf_len; | |
| 150 | mem.copy(u8, self.buf[self.buf_len..], b[0..off]); | |
| 151 | self.state.update(self.buf[0..]); | |
| 152 | self.buf_len = 0; | |
| 107 | 153 | } |
| 108 | 154 | |
| 109 | self.partial(b[off..]); | |
| 110 | self.msg_len += b.len; | |
| 155 | const remain_len = b.len - off; | |
| 156 | const aligned_len = remain_len - (remain_len % 32); | |
| 157 | self.state.update(b[off .. off + aligned_len]); | |
| 158 | ||
| 159 | mem.copy(u8, self.buf[self.buf_len..], b[off + aligned_len ..]); | |
| 160 | self.buf_len += @intCast(u8, b[off + aligned_len ..].len); | |
| 111 | 161 | } |
| 112 | 162 | |
| 113 | 163 | pub fn final(self: *Wyhash) u64 { |
| 114 | return mum(self.seed ^ self.msg_len, primes[4]); | |
| 164 | const seed = self.state.seed; | |
| 165 | const rem_len = @intCast(u5, self.buf_len); | |
| 166 | const rem_key = self.buf[0..self.buf_len]; | |
| 167 | ||
| 168 | return self.state.final(rem_key); | |
| 115 | 169 | } |
| 116 | 170 | |
| 117 | 171 | pub fn hash(seed: u64, input: []const u8) u64 { |
| 118 | var c = Wyhash.init(seed); | |
| 119 | c.update(input); | |
| 120 | return c.final(); | |
| 172 | return WyhashStateless.hash(seed, input); | |
| 121 | 173 | } |
| 122 | 174 | }; |
| 123 | 175 | |
| 176 | const expectEqual = std.testing.expectEqual; | |
| 177 | ||
| 124 | 178 | test "test vectors" { |
| 125 | const expectEqual = std.testing.expectEqual; | |
| 126 | 179 | const hash = Wyhash.hash; |
| 127 | 180 | |
| 128 | 181 | expectEqual(hash(0, ""), 0x0); |
| ... | ... | @@ -133,3 +186,46 @@ test "test vectors" { |
| 133 | 186 | expectEqual(hash(5, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), 0x602a1894d3bbfe7f); |
| 134 | 187 | expectEqual(hash(6, "12345678901234567890123456789012345678901234567890123456789012345678901234567890"), 0x829e9c148b75970e); |
| 135 | 188 | } |
| 189 | ||
| 190 | test "test vectors streaming" { | |
| 191 | var wh = Wyhash.init(5); | |
| 192 | for ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789") |e| { | |
| 193 | wh.update(mem.asBytes(&e)); | |
| 194 | } | |
| 195 | expectEqual(wh.final(), 0x602a1894d3bbfe7f); | |
| 196 | ||
| 197 | const pattern = "1234567890"; | |
| 198 | const count = 8; | |
| 199 | const result = 0x829e9c148b75970e; | |
| 200 | expectEqual(Wyhash.hash(6, pattern ** 8), result); | |
| 201 | ||
| 202 | wh = Wyhash.init(6); | |
| 203 | var i: u32 = 0; | |
| 204 | while (i < count) : (i += 1) { | |
| 205 | wh.update(pattern); | |
| 206 | } | |
| 207 | expectEqual(wh.final(), result); | |
| 208 | } | |
| 209 | ||
| 210 | test "iterative non-divisible update" { | |
| 211 | var buf: [8192]u8 = undefined; | |
| 212 | for (buf) |*e, i| { | |
| 213 | e.* = @truncate(u8, i); | |
| 214 | } | |
| 215 | ||
| 216 | const seed = 0x128dad08f; | |
| 217 | ||
| 218 | var end: usize = 32; | |
| 219 | while (end < buf.len) : (end += 32) { | |
| 220 | const non_iterative_hash = Wyhash.hash(seed, buf[0..end]); | |
| 221 | ||
| 222 | var wy = Wyhash.init(seed); | |
| 223 | var i: usize = 0; | |
| 224 | while (i < end) : (i += 33) { | |
| 225 | wy.update(buf[i..std.math.min(i + 33, end)]); | |
| 226 | } | |
| 227 | const iterative_hash = wy.final(); | |
| 228 | ||
| 229 | std.testing.expectEqual(iterative_hash, non_iterative_hash); | |
| 230 | } | |
| 231 | } |
std/hash_map.zig+15| ... | ... | @@ -17,6 +17,21 @@ pub fn AutoHashMap(comptime K: type, comptime V: type) type { |
| 17 | 17 | return HashMap(K, V, getAutoHashFn(K), getAutoEqlFn(K)); |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | /// Builtin hashmap for strings as keys. | |
| 21 | pub fn StringHashMap(comptime V: type) type { | |
| 22 | return HashMap([]const u8, V, hashString, eqlString); | |
| 23 | } | |
| 24 | ||
| 25 | pub fn eqlString(a: []const u8, b: []const u8) bool { | |
| 26 | if (a.len != b.len) return false; | |
| 27 | if (a.ptr == b.ptr) return true; | |
| 28 | return mem.compare(u8, a, b) == .Equal; | |
| 29 | } | |
| 30 | ||
| 31 | pub fn hashString(s: []const u8) u32 { | |
| 32 | return @truncate(u32, std.hash.Wyhash.hash(0, s)); | |
| 33 | } | |
| 34 | ||
| 20 | 35 | pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u32, comptime eql: fn (a: K, b: K) bool) type { |
| 21 | 36 | return struct { |
| 22 | 37 | entries: []Entry, |
std/http/headers.zig+1-11| ... | ... | @@ -102,19 +102,9 @@ test "HeaderEntry" { |
| 102 | 102 | testing.expectEqualSlices(u8, "x", e.value); |
| 103 | 103 | } |
| 104 | 104 | |
| 105 | fn stringEql(a: []const u8, b: []const u8) bool { | |
| 106 | if (a.len != b.len) return false; | |
| 107 | if (a.ptr == b.ptr) return true; | |
| 108 | return mem.compare(u8, a, b) == .Equal; | |
| 109 | } | |
| 110 | ||
| 111 | fn stringHash(s: []const u8) u32 { | |
| 112 | return @truncate(u32, std.hash.Wyhash.hash(0, s)); | |
| 113 | } | |
| 114 | ||
| 115 | 105 | const HeaderList = std.ArrayList(HeaderEntry); |
| 116 | 106 | const HeaderIndexList = std.ArrayList(usize); |
| 117 | const HeaderIndex = std.HashMap([]const u8, HeaderIndexList, stringHash, stringEql); | |
| 107 | const HeaderIndex = std.StringHashMap(HeaderIndexList); | |
| 118 | 108 | |
| 119 | 109 | pub const Headers = struct { |
| 120 | 110 | // the owned header field name is stored in the index as part of the key |
std/os/windows.zig+3-4| ... | ... | @@ -65,7 +65,7 @@ pub const CreateFileError = error{ |
| 65 | 65 | InvalidUtf8, |
| 66 | 66 | |
| 67 | 67 | /// On Windows, file paths cannot contain these characters: |
| 68 | /// '/', '*', '?', '"', '<', '>', '|' | |
| 68 | /// '*', '?', '"', '<', '>', '|', and '/' (when the ABI is not GNU) | |
| 69 | 69 | BadPathName, |
| 70 | 70 | |
| 71 | 71 | Unexpected, |
| ... | ... | @@ -836,11 +836,10 @@ pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) |
| 836 | 836 | // > converting the name to an NT-style name, except when using the "\\?\" |
| 837 | 837 | // > prefix as detailed in the following sections. |
| 838 | 838 | // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation |
| 839 | // Because we want the larger maximum path length for absolute paths, we | |
| 840 | // disallow forward slashes in zig std lib file functions on Windows. | |
| 841 | 839 | for (s) |byte| { |
| 842 | 840 | switch (byte) { |
| 843 | '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName, | |
| 841 | '*', '?', '"', '<', '>', '|' => return error.BadPathName, | |
| 842 | '/' => if (builtin.abi == .msvc) return error.BadPathName, | |
| 844 | 843 | else => {}, |
| 845 | 844 | } |
| 846 | 845 | } |
std/std.zig+1| ... | ... | @@ -17,6 +17,7 @@ pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList; |
| 17 | 17 | pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; |
| 18 | 18 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; |
| 19 | 19 | pub const SpinLock = @import("spinlock.zig").SpinLock; |
| 20 | pub const StringHashMap = @import("hash_map.zig").StringHashMap; | |
| 20 | 21 | pub const ChildProcess = @import("child_process.zig").ChildProcess; |
| 21 | 22 | pub const TailQueue = @import("linked_list.zig").TailQueue; |
| 22 | 23 | pub const Thread = @import("thread.zig").Thread; |
std/zig/ast.zig+1| ... | ... | @@ -761,6 +761,7 @@ pub const Node = struct { |
| 761 | 761 | name_token: TokenIndex, |
| 762 | 762 | type_expr: ?*Node, |
| 763 | 763 | value_expr: ?*Node, |
| 764 | align_expr: ?*Node, | |
| 764 | 765 | |
| 765 | 766 | pub fn iterate(self: *ContainerField, index: usize) ?*Node { |
| 766 | 767 | var i = index; |
std/zig/parse.zig+9-6| ... | ... | @@ -380,16 +380,18 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 380 | 380 | return &node.base; |
| 381 | 381 | } |
| 382 | 382 | |
| 383 | /// ContainerField <- IDENTIFIER (COLON TypeExpr)? (EQUAL Expr)? | |
| 383 | /// ContainerField <- IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)? | |
| 384 | 384 | fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 385 | 385 | const name_token = eatToken(it, .Identifier) orelse return null; |
| 386 | 386 | |
| 387 | const type_expr = if (eatToken(it, .Colon)) |_| | |
| 388 | try expectNode(arena, it, tree, parseTypeExpr, AstError{ | |
| 387 | var align_expr: ?*Node = null; | |
| 388 | var type_expr: ?*Node = null; | |
| 389 | if (eatToken(it, .Colon)) |_| { | |
| 390 | type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | |
| 389 | 391 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, |
| 390 | }) | |
| 391 | else | |
| 392 | null; | |
| 392 | }); | |
| 393 | align_expr = try parseByteAlign(arena, it, tree); | |
| 394 | } | |
| 393 | 395 | |
| 394 | 396 | const value_expr = if (eatToken(it, .Equal)) |_| |
| 395 | 397 | try expectNode(arena, it, tree, parseExpr, AstError{ |
| ... | ... | @@ -406,6 +408,7 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 406 | 408 | .name_token = name_token, |
| 407 | 409 | .type_expr = type_expr, |
| 408 | 410 | .value_expr = value_expr, |
| 411 | .align_expr = align_expr, | |
| 409 | 412 | }; |
| 410 | 413 | return &node.base; |
| 411 | 414 | } |
std/zig/parser_test.zig+120-1| ... | ... | @@ -166,6 +166,15 @@ test "zig fmt: doc comments on param decl" { |
| 166 | 166 | ); |
| 167 | 167 | } |
| 168 | 168 | |
| 169 | test "zig fmt: aligned struct field" { | |
| 170 | try testCanonical( | |
| 171 | \\pub const S = struct { | |
| 172 | \\ f: i32 align(32), | |
| 173 | \\}; | |
| 174 | \\ | |
| 175 | ); | |
| 176 | } | |
| 177 | ||
| 169 | 178 | test "zig fmt: preserve space between async fn definitions" { |
| 170 | 179 | try testCanonical( |
| 171 | 180 | \\async fn a() void {} |
| ... | ... | @@ -201,6 +210,103 @@ test "zig fmt: comment to disable/enable zig fmt" { |
| 201 | 210 | ); |
| 202 | 211 | } |
| 203 | 212 | |
| 213 | test "zig fmt: line comment following 'zig fmt: off'" { | |
| 214 | try testCanonical( | |
| 215 | \\// zig fmt: off | |
| 216 | \\// Test | |
| 217 | \\const e = f; | |
| 218 | ); | |
| 219 | } | |
| 220 | ||
| 221 | test "zig fmt: doc comment following 'zig fmt: off'" { | |
| 222 | try testCanonical( | |
| 223 | \\// zig fmt: off | |
| 224 | \\/// test | |
| 225 | \\const e = f; | |
| 226 | ); | |
| 227 | } | |
| 228 | ||
| 229 | test "zig fmt: line and doc comment following 'zig fmt: off'" { | |
| 230 | try testCanonical( | |
| 231 | \\// zig fmt: off | |
| 232 | \\// test 1 | |
| 233 | \\/// test 2 | |
| 234 | \\const e = f; | |
| 235 | ); | |
| 236 | } | |
| 237 | ||
| 238 | test "zig fmt: doc and line comment following 'zig fmt: off'" { | |
| 239 | try testCanonical( | |
| 240 | \\// zig fmt: off | |
| 241 | \\/// test 1 | |
| 242 | \\// test 2 | |
| 243 | \\const e = f; | |
| 244 | ); | |
| 245 | } | |
| 246 | ||
| 247 | test "zig fmt: alternating 'zig fmt: off' and 'zig fmt: on'" { | |
| 248 | try testCanonical( | |
| 249 | \\// zig fmt: off | |
| 250 | \\// zig fmt: on | |
| 251 | \\// zig fmt: off | |
| 252 | \\const e = f; | |
| 253 | \\// zig fmt: off | |
| 254 | \\// zig fmt: on | |
| 255 | \\// zig fmt: off | |
| 256 | \\const a = b; | |
| 257 | \\// zig fmt: on | |
| 258 | \\const c = d; | |
| 259 | \\// zig fmt: on | |
| 260 | \\ | |
| 261 | ); | |
| 262 | } | |
| 263 | ||
| 264 | test "zig fmt: line comment following 'zig fmt: on'" { | |
| 265 | try testCanonical( | |
| 266 | \\// zig fmt: off | |
| 267 | \\const e = f; | |
| 268 | \\// zig fmt: on | |
| 269 | \\// test | |
| 270 | \\const e = f; | |
| 271 | \\ | |
| 272 | ); | |
| 273 | } | |
| 274 | ||
| 275 | test "zig fmt: doc comment following 'zig fmt: on'" { | |
| 276 | try testCanonical( | |
| 277 | \\// zig fmt: off | |
| 278 | \\const e = f; | |
| 279 | \\// zig fmt: on | |
| 280 | \\/// test | |
| 281 | \\const e = f; | |
| 282 | \\ | |
| 283 | ); | |
| 284 | } | |
| 285 | ||
| 286 | test "zig fmt: line and doc comment following 'zig fmt: on'" { | |
| 287 | try testCanonical( | |
| 288 | \\// zig fmt: off | |
| 289 | \\const e = f; | |
| 290 | \\// zig fmt: on | |
| 291 | \\// test1 | |
| 292 | \\/// test2 | |
| 293 | \\const e = f; | |
| 294 | \\ | |
| 295 | ); | |
| 296 | } | |
| 297 | ||
| 298 | test "zig fmt: doc and line comment following 'zig fmt: on'" { | |
| 299 | try testCanonical( | |
| 300 | \\// zig fmt: off | |
| 301 | \\const e = f; | |
| 302 | \\// zig fmt: on | |
| 303 | \\/// test1 | |
| 304 | \\// test2 | |
| 305 | \\const e = f; | |
| 306 | \\ | |
| 307 | ); | |
| 308 | } | |
| 309 | ||
| 204 | 310 | test "zig fmt: pointer of unknown length" { |
| 205 | 311 | try testCanonical( |
| 206 | 312 | \\fn foo(ptr: [*]u8) void {} |
| ... | ... | @@ -2269,7 +2375,6 @@ test "zig fmt: if type expr" { |
| 2269 | 2375 | \\ |
| 2270 | 2376 | ); |
| 2271 | 2377 | } |
| 2272 | ||
| 2273 | 2378 | test "zig fmt: file ends with struct field" { |
| 2274 | 2379 | try testTransform( |
| 2275 | 2380 | \\a: bool |
| ... | ... | @@ -2279,6 +2384,20 @@ test "zig fmt: file ends with struct field" { |
| 2279 | 2384 | ); |
| 2280 | 2385 | } |
| 2281 | 2386 | |
| 2387 | test "zig fmt: comment after empty comment" { | |
| 2388 | try testTransform( | |
| 2389 | \\const x = true; // | |
| 2390 | \\// | |
| 2391 | \\// | |
| 2392 | \\//a | |
| 2393 | \\ | |
| 2394 | , | |
| 2395 | \\const x = true; | |
| 2396 | \\//a | |
| 2397 | \\ | |
| 2398 | ); | |
| 2399 | } | |
| 2400 | ||
| 2282 | 2401 | test "zig fmt: comments at several places in struct init" { |
| 2283 | 2402 | try testTransform( |
| 2284 | 2403 | \\var bar = Bar{ |
std/zig/render.zig+115-36| ... | ... | @@ -89,41 +89,98 @@ fn renderRoot( |
| 89 | 89 | var it = tree.root_node.decls.iterator(0); |
| 90 | 90 | while (true) { |
| 91 | 91 | var decl = (it.next() orelse return).*; |
| 92 | // look for zig fmt: off comment | |
| 93 | var start_token_index = decl.firstToken(); | |
| 94 | zig_fmt_loop: while (start_token_index != 0) { | |
| 95 | start_token_index -= 1; | |
| 96 | const start_token = tree.tokens.at(start_token_index); | |
| 97 | switch (start_token.id) { | |
| 92 | ||
| 93 | // This loop does the following: | |
| 94 | // | |
| 95 | // - Iterates through line/doc comment tokens that precedes the current | |
| 96 | // decl. | |
| 97 | // - Figures out the first token index (`copy_start_token_index`) which | |
| 98 | // hasn't been copied to the output stream yet. | |
| 99 | // - Detects `zig fmt: (off|on)` in the line comment tokens, and | |
| 100 | // determines whether the current decl should be reformatted or not. | |
| 101 | // | |
| 102 | var token_index = decl.firstToken(); | |
| 103 | var fmt_active = true; | |
| 104 | var found_fmt_directive = false; | |
| 105 | ||
| 106 | var copy_start_token_index = token_index; | |
| 107 | ||
| 108 | while (token_index != 0) { | |
| 109 | token_index -= 1; | |
| 110 | const token = tree.tokens.at(token_index); | |
| 111 | switch (token.id) { | |
| 98 | 112 | Token.Id.LineComment => {}, |
| 99 | Token.Id.DocComment => continue, | |
| 113 | Token.Id.DocComment => { | |
| 114 | copy_start_token_index = token_index; | |
| 115 | continue; | |
| 116 | }, | |
| 100 | 117 | else => break, |
| 101 | 118 | } |
| 102 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(start_token)[2..], " "), "zig fmt: off")) { | |
| 103 | var end_token_index = start_token_index; | |
| 104 | while (true) { | |
| 105 | end_token_index += 1; | |
| 106 | const end_token = tree.tokens.at(end_token_index); | |
| 107 | switch (end_token.id) { | |
| 119 | ||
| 120 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) { | |
| 121 | if (!found_fmt_directive) { | |
| 122 | fmt_active = false; | |
| 123 | found_fmt_directive = true; | |
| 124 | } | |
| 125 | } else if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: on")) { | |
| 126 | if (!found_fmt_directive) { | |
| 127 | fmt_active = true; | |
| 128 | found_fmt_directive = true; | |
| 129 | } | |
| 130 | } | |
| 131 | } | |
| 132 | ||
| 133 | if (!fmt_active) { | |
| 134 | // Reformatting is disabled for the current decl and possibly some | |
| 135 | // more decls that follow. | |
| 136 | // Find the next `decl` for which reformatting is re-enabled. | |
| 137 | token_index = decl.firstToken(); | |
| 138 | ||
| 139 | while (!fmt_active) { | |
| 140 | decl = (it.next() orelse { | |
| 141 | // If there's no next reformatted `decl`, just copy the | |
| 142 | // remaining input tokens and bail out. | |
| 143 | const start = tree.tokens.at(copy_start_token_index).start; | |
| 144 | try copyFixingWhitespace(stream, tree.source[start..]); | |
| 145 | return; | |
| 146 | }).*; | |
| 147 | var decl_first_token_index = decl.firstToken(); | |
| 148 | ||
| 149 | while (token_index < decl_first_token_index) : (token_index += 1) { | |
| 150 | const token = tree.tokens.at(token_index); | |
| 151 | switch (token.id) { | |
| 108 | 152 | Token.Id.LineComment => {}, |
| 109 | Token.Id.Eof => { | |
| 110 | const start = tree.tokens.at(start_token_index + 1).start; | |
| 111 | try copyFixingWhitespace(stream, tree.source[start..]); | |
| 112 | return; | |
| 113 | }, | |
| 153 | Token.Id.Eof => unreachable, | |
| 114 | 154 | else => continue, |
| 115 | 155 | } |
| 116 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(end_token)[2..], " "), "zig fmt: on")) { | |
| 117 | const start = tree.tokens.at(start_token_index + 1).start; | |
| 118 | try copyFixingWhitespace(stream, tree.source[start..end_token.end]); | |
| 119 | try stream.writeByte('\n'); | |
| 120 | while (tree.tokens.at(decl.firstToken()).start < end_token.end) { | |
| 121 | decl = (it.next() orelse return).*; | |
| 122 | } | |
| 123 | break :zig_fmt_loop; | |
| 156 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: on")) { | |
| 157 | fmt_active = true; | |
| 158 | } else if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) { | |
| 159 | fmt_active = false; | |
| 124 | 160 | } |
| 125 | 161 | } |
| 126 | 162 | } |
| 163 | ||
| 164 | // Found the next `decl` for which reformatting is enabled. Copy | |
| 165 | // the input tokens before the `decl` that haven't been copied yet. | |
| 166 | var copy_end_token_index = decl.firstToken(); | |
| 167 | token_index = copy_end_token_index; | |
| 168 | while (token_index != 0) { | |
| 169 | token_index -= 1; | |
| 170 | const token = tree.tokens.at(token_index); | |
| 171 | switch (token.id) { | |
| 172 | Token.Id.LineComment => {}, | |
| 173 | Token.Id.DocComment => { | |
| 174 | copy_end_token_index = token_index; | |
| 175 | continue; | |
| 176 | }, | |
| 177 | else => break, | |
| 178 | } | |
| 179 | } | |
| 180 | ||
| 181 | const start = tree.tokens.at(copy_start_token_index).start; | |
| 182 | const end = tree.tokens.at(copy_end_token_index).start; | |
| 183 | try copyFixingWhitespace(stream, tree.source[start..end]); | |
| 127 | 184 | } |
| 128 | 185 | |
| 129 | 186 | try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl); |
| ... | ... | @@ -206,7 +263,20 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i |
| 206 | 263 | } else if (field.type_expr != null and field.value_expr == null) { |
| 207 | 264 | try renderToken(tree, stream, field.name_token, indent, start_col, Space.None); // name |
| 208 | 265 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // : |
| 209 | return renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Comma); // type, | |
| 266 | ||
| 267 | if (field.align_expr) |align_value_expr| { | |
| 268 | try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Space); // type | |
| 269 | const lparen_token = tree.prevToken(align_value_expr.firstToken()); | |
| 270 | const align_kw = tree.prevToken(lparen_token); | |
| 271 | const rparen_token = tree.nextToken(align_value_expr.lastToken()); | |
| 272 | try renderToken(tree, stream, align_kw, indent, start_col, Space.None); // align | |
| 273 | try renderToken(tree, stream, lparen_token, indent, start_col, Space.None); // ( | |
| 274 | try renderExpression(allocator, stream, tree, indent, start_col, align_value_expr, Space.None); // alignment | |
| 275 | try renderToken(tree, stream, rparen_token, indent, start_col, Space.Comma); // ) | |
| 276 | } else { | |
| 277 | try renderExpression(allocator, stream, tree, indent, start_col, field.type_expr.?, Space.Comma); // type, | |
| 278 | } | |
| 279 | ||
| 210 | 280 | } else if (field.type_expr == null and field.value_expr != null) { |
| 211 | 281 | try renderToken(tree, stream, field.name_token, indent, start_col, Space.Space); // name |
| 212 | 282 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // = |
| ... | ... | @@ -1924,15 +1994,24 @@ fn renderTokenOffset( |
| 1924 | 1994 | } |
| 1925 | 1995 | } |
| 1926 | 1996 | |
| 1927 | const comment_is_empty = mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ").len == 2; | |
| 1928 | if (comment_is_empty) { | |
| 1929 | switch (space) { | |
| 1930 | Space.Newline => { | |
| 1931 | try stream.writeByte('\n'); | |
| 1932 | start_col.* = 0; | |
| 1933 | return; | |
| 1934 | }, | |
| 1935 | else => {}, | |
| 1997 | while (true) { | |
| 1998 | const comment_is_empty = mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ").len == 2; | |
| 1999 | if (comment_is_empty) { | |
| 2000 | switch (space) { | |
| 2001 | Space.Newline => { | |
| 2002 | offset += 1; | |
| 2003 | token = next_token; | |
| 2004 | next_token = tree.tokens.at(token_index + offset); | |
| 2005 | if (next_token.id != .LineComment) { | |
| 2006 | try stream.writeByte('\n'); | |
| 2007 | start_col.* = 0; | |
| 2008 | return; | |
| 2009 | } | |
| 2010 | }, | |
| 2011 | else => break, | |
| 2012 | } | |
| 2013 | } else { | |
| 2014 | break; | |
| 1936 | 2015 | } |
| 1937 | 2016 | } |
| 1938 | 2017 |
test/compile_errors.zig+89-44| ... | ... | @@ -2,6 +2,51 @@ const tests = @import("tests.zig"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5 | cases.add( | |
| 6 | "struct depends on itself via optional field", | |
| 7 | \\const LhsExpr = struct { | |
| 8 | \\ rhsExpr: ?AstObject, | |
| 9 | \\}; | |
| 10 | \\const AstObject = union { | |
| 11 | \\ lhsExpr: LhsExpr, | |
| 12 | \\}; | |
| 13 | \\export fn entry() void { | |
| 14 | \\ const lhsExpr = LhsExpr{ .rhsExpr = null }; | |
| 15 | \\ const obj = AstObject{ .lhsExpr = lhsExpr }; | |
| 16 | \\} | |
| 17 | , | |
| 18 | "tmp.zig:1:17: error: struct 'LhsExpr' depends on itself", | |
| 19 | "tmp.zig:5:5: note: while checking this field", | |
| 20 | "tmp.zig:2:5: note: while checking this field", | |
| 21 | ); | |
| 22 | ||
| 23 | cases.add( | |
| 24 | "alignment of enum field specified", | |
| 25 | \\const Number = enum { | |
| 26 | \\ a, | |
| 27 | \\ b align(i32), | |
| 28 | \\}; | |
| 29 | \\export fn entry1() void { | |
| 30 | \\ var x: Number = undefined; | |
| 31 | \\} | |
| 32 | , | |
| 33 | "tmp.zig:3:13: error: structs and unions, not enums, support field alignment", | |
| 34 | "tmp.zig:1:16: note: consider 'union(enum)' here", | |
| 35 | ); | |
| 36 | ||
| 37 | cases.add( | |
| 38 | "bad alignment type", | |
| 39 | \\export fn entry1() void { | |
| 40 | \\ var x: []align(true) i32 = undefined; | |
| 41 | \\} | |
| 42 | \\export fn entry2() void { | |
| 43 | \\ var x: *align(f64(12.34)) i32 = undefined; | |
| 44 | \\} | |
| 45 | , | |
| 46 | "tmp.zig:2:20: error: expected type 'u29', found 'bool'", | |
| 47 | "tmp.zig:5:22: error: fractional component prevents float value 12.340000 from being casted to type 'u29'", | |
| 48 | ); | |
| 49 | ||
| 5 | 50 | cases.addCase(x: { |
| 6 | 51 | var tc = cases.create("variable in inline assembly template cannot be found", |
| 7 | 52 | \\export fn entry() void { |
| ... | ... | @@ -10,7 +55,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 10 | 55 | \\ : [bar] "=r" (-> usize) |
| 11 | 56 | \\ ); |
| 12 | 57 | \\} |
| 13 | , "tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs."); | |
| 58 | , "tmp.zig:2:14: error: could not find 'foo' in the inputs or outputs"); | |
| 14 | 59 | tc.target = tests.Target{ |
| 15 | 60 | .Cross = tests.CrossTarget{ |
| 16 | 61 | .arch = .x86_64, |
| ... | ... | @@ -53,8 +98,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 53 | 98 | \\} |
| 54 | 99 | , |
| 55 | 100 | "tmp.zig:8:1: error: '@Frame(rangeSum)' depends on itself", |
| 56 | "tmp.zig:15:33: note: when analyzing type '@Frame(rangeSumIndirect)' here", | |
| 57 | "tmp.zig:26:25: note: when analyzing type '@Frame(rangeSum)' here", | |
| 101 | "tmp.zig:15:33: note: when analyzing type '@Frame(rangeSum)' here", | |
| 102 | "tmp.zig:26:25: note: when analyzing type '@Frame(rangeSumIndirect)' here", | |
| 58 | 103 | ); |
| 59 | 104 | |
| 60 | 105 | cases.add( |
| ... | ... | @@ -245,7 +290,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 245 | 290 | , |
| 246 | 291 | "tmp.zig:4:1: error: unable to determine async function frame of 'amain'", |
| 247 | 292 | "tmp.zig:5:10: note: analysis of function 'other' depends on the frame", |
| 248 | "tmp.zig:8:13: note: depends on the frame here", | |
| 293 | "tmp.zig:8:13: note: referenced here", | |
| 249 | 294 | ); |
| 250 | 295 | |
| 251 | 296 | cases.add( |
| ... | ... | @@ -258,7 +303,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 258 | 303 | \\} |
| 259 | 304 | , |
| 260 | 305 | "tmp.zig:4:1: error: cannot resolve '@Frame(amain)': function not fully analyzed yet", |
| 261 | "tmp.zig:5:13: note: depends on its own frame here", | |
| 306 | "tmp.zig:5:13: note: referenced here", | |
| 262 | 307 | ); |
| 263 | 308 | |
| 264 | 309 | cases.add( |
| ... | ... | @@ -404,7 +449,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 404 | 449 | \\ const foo: Foo = undefined; |
| 405 | 450 | \\} |
| 406 | 451 | , |
| 407 | "tmp.zig:2:8: error: expected type 'type', found '(undefined)'", | |
| 452 | "tmp.zig:2:8: error: use of undefined value here causes undefined behavior", | |
| 408 | 453 | ); |
| 409 | 454 | |
| 410 | 455 | cases.add( |
| ... | ... | @@ -470,7 +515,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 470 | 515 | ); |
| 471 | 516 | |
| 472 | 517 | cases.add( |
| 473 | "Generic function where return type is self-referenced", | |
| 518 | "generic function where return type is self-referenced", | |
| 474 | 519 | \\fn Foo(comptime T: type) Foo(T) { |
| 475 | 520 | \\ return struct{ x: T }; |
| 476 | 521 | \\} |
| ... | ... | @@ -481,7 +526,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 481 | 526 | \\} |
| 482 | 527 | , |
| 483 | 528 | "tmp.zig:1:29: error: evaluation exceeded 1000 backwards branches", |
| 484 | "tmp.zig:1:29: note: called from here", | |
| 529 | "tmp.zig:5:18: note: referenced here", | |
| 485 | 530 | ); |
| 486 | 531 | |
| 487 | 532 | cases.add( |
| ... | ... | @@ -645,7 +690,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 645 | 690 | \\const A = struct { a : A, }; |
| 646 | 691 | \\export fn entry() usize { return @sizeOf(A); } |
| 647 | 692 | , |
| 648 | "tmp.zig:1:11: error: struct 'A' contains itself", | |
| 693 | "tmp.zig:1:11: error: struct 'A' depends on itself", | |
| 649 | 694 | ); |
| 650 | 695 | |
| 651 | 696 | cases.add( |
| ... | ... | @@ -655,7 +700,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 655 | 700 | \\const C = struct { a : A, }; |
| 656 | 701 | \\export fn entry() usize { return @sizeOf(A); } |
| 657 | 702 | , |
| 658 | "tmp.zig:1:11: error: struct 'A' contains itself", | |
| 703 | "tmp.zig:1:11: error: struct 'A' depends on itself", | |
| 659 | 704 | ); |
| 660 | 705 | |
| 661 | 706 | cases.add( |
| ... | ... | @@ -670,7 +715,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 670 | 715 | \\ return @sizeOf(@typeOf(foo.x)); |
| 671 | 716 | \\} |
| 672 | 717 | , |
| 673 | "tmp.zig:1:13: error: struct 'Foo' contains itself", | |
| 718 | "tmp.zig:1:13: error: struct 'Foo' depends on itself", | |
| 674 | 719 | "tmp.zig:8:28: note: referenced here", |
| 675 | 720 | ); |
| 676 | 721 | |
| ... | ... | @@ -689,7 +734,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 689 | 734 | \\} |
| 690 | 735 | , |
| 691 | 736 | "tmp.zig:7:9: error: dependency loop detected", |
| 692 | "tmp.zig:2:19: note: called from here", | |
| 737 | "tmp.zig:2:19: note: referenced here", | |
| 693 | 738 | "tmp.zig:10:21: note: referenced here", |
| 694 | 739 | ); |
| 695 | 740 | |
| ... | ... | @@ -703,7 +748,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 703 | 748 | \\ var s: Foo = Foo.E; |
| 704 | 749 | \\} |
| 705 | 750 | , |
| 706 | "tmp.zig:1:17: error: 'Foo' depends on itself", | |
| 751 | "tmp.zig:1:17: error: enum 'Foo' depends on itself", | |
| 707 | 752 | ); |
| 708 | 753 | |
| 709 | 754 | cases.add( |
| ... | ... | @@ -866,7 +911,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 866 | 911 | break :x tc; |
| 867 | 912 | }); |
| 868 | 913 | |
| 869 | cases.addTest( | |
| 914 | cases.add( | |
| 870 | 915 | "export generic function", |
| 871 | 916 | \\export fn foo(num: var) i32 { |
| 872 | 917 | \\ return 0; |
| ... | ... | @@ -875,17 +920,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 875 | 920 | "tmp.zig:1:15: error: parameter of type 'var' not allowed in function with calling convention 'ccc'", |
| 876 | 921 | ); |
| 877 | 922 | |
| 878 | cases.addTest( | |
| 923 | cases.add( | |
| 879 | 924 | "C pointer to c_void", |
| 880 | 925 | \\export fn a() void { |
| 881 | 926 | \\ var x: *c_void = undefined; |
| 882 | 927 | \\ var y: [*c]c_void = x; |
| 883 | 928 | \\} |
| 884 | 929 | , |
| 885 | "tmp.zig:3:12: error: C pointers cannot point opaque types", | |
| 930 | "tmp.zig:3:16: error: C pointers cannot point opaque types", | |
| 886 | 931 | ); |
| 887 | 932 | |
| 888 | cases.addTest( | |
| 933 | cases.add( | |
| 889 | 934 | "directly embedding opaque type in struct and union", |
| 890 | 935 | \\const O = @OpaqueType(); |
| 891 | 936 | \\const Foo = struct { |
| ... | ... | @@ -906,7 +951,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 906 | 951 | "tmp.zig:7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions", |
| 907 | 952 | ); |
| 908 | 953 | |
| 909 | cases.addTest( | |
| 954 | cases.add( | |
| 910 | 955 | "implicit cast between C pointer and Zig pointer - bad const/align/child", |
| 911 | 956 | \\export fn a() void { |
| 912 | 957 | \\ var x: [*c]u8 = undefined; |
| ... | ... | @@ -942,7 +987,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 942 | 987 | "tmp.zig:23:22: error: expected type '[*c]u32', found '*u8'", |
| 943 | 988 | ); |
| 944 | 989 | |
| 945 | cases.addTest( | |
| 990 | cases.add( | |
| 946 | 991 | "implicit casting null c pointer to zig pointer", |
| 947 | 992 | \\comptime { |
| 948 | 993 | \\ var c_ptr: [*c]u8 = 0; |
| ... | ... | @@ -952,7 +997,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 952 | 997 | "tmp.zig:3:24: error: null pointer casted to type '*u8'", |
| 953 | 998 | ); |
| 954 | 999 | |
| 955 | cases.addTest( | |
| 1000 | cases.add( | |
| 956 | 1001 | "implicit casting undefined c pointer to zig pointer", |
| 957 | 1002 | \\comptime { |
| 958 | 1003 | \\ var c_ptr: [*c]u8 = undefined; |
| ... | ... | @@ -962,7 +1007,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 962 | 1007 | "tmp.zig:3:24: error: use of undefined value here causes undefined behavior", |
| 963 | 1008 | ); |
| 964 | 1009 | |
| 965 | cases.addTest( | |
| 1010 | cases.add( | |
| 966 | 1011 | "implicit casting C pointers which would mess up null semantics", |
| 967 | 1012 | \\export fn entry() void { |
| 968 | 1013 | \\ var slice: []const u8 = "aoeu"; |
| ... | ... | @@ -987,7 +1032,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 987 | 1032 | "tmp.zig:13:35: note: mutable '[*c]const u8' allows illegal null values stored to type '[*]u8'", |
| 988 | 1033 | ); |
| 989 | 1034 | |
| 990 | cases.addTest( | |
| 1035 | cases.add( | |
| 991 | 1036 | "implicit casting too big integers to C pointers", |
| 992 | 1037 | \\export fn a() void { |
| 993 | 1038 | \\ var ptr: [*c]u8 = (1 << 64) + 1; |
| ... | ... | @@ -1001,14 +1046,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1001 | 1046 | "tmp.zig:6:23: error: integer type 'u65' too big for implicit @intToPtr to type '[*c]u8'", |
| 1002 | 1047 | ); |
| 1003 | 1048 | |
| 1004 | cases.addTest( | |
| 1049 | cases.add( | |
| 1005 | 1050 | "C pointer pointing to non C ABI compatible type or has align attr", |
| 1006 | 1051 | \\const Foo = struct {}; |
| 1007 | 1052 | \\export fn a() void { |
| 1008 | 1053 | \\ const T = [*c]Foo; |
| 1009 | 1054 | \\} |
| 1010 | 1055 | , |
| 1011 | "tmp.zig:3:15: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", | |
| 1056 | "tmp.zig:3:19: error: C pointers cannot point to non-C-ABI-compatible type 'Foo'", | |
| 1012 | 1057 | ); |
| 1013 | 1058 | |
| 1014 | 1059 | cases.addCase(x: { |
| ... | ... | @@ -1029,7 +1074,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1029 | 1074 | break :x tc; |
| 1030 | 1075 | }); |
| 1031 | 1076 | |
| 1032 | cases.addTest( | |
| 1077 | cases.add( | |
| 1033 | 1078 | "assign to invalid dereference", |
| 1034 | 1079 | \\export fn entry() void { |
| 1035 | 1080 | \\ 'a'.* = 1; |
| ... | ... | @@ -1038,7 +1083,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1038 | 1083 | "tmp.zig:2:8: error: attempt to dereference non-pointer type 'comptime_int'", |
| 1039 | 1084 | ); |
| 1040 | 1085 | |
| 1041 | cases.addTest( | |
| 1086 | cases.add( | |
| 1042 | 1087 | "take slice of invalid dereference", |
| 1043 | 1088 | \\export fn entry() void { |
| 1044 | 1089 | \\ const x = 'a'.*[0..]; |
| ... | ... | @@ -1047,7 +1092,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1047 | 1092 | "tmp.zig:2:18: error: attempt to dereference non-pointer type 'comptime_int'", |
| 1048 | 1093 | ); |
| 1049 | 1094 | |
| 1050 | cases.addTest( | |
| 1095 | cases.add( | |
| 1051 | 1096 | "@truncate undefined value", |
| 1052 | 1097 | \\export fn entry() void { |
| 1053 | 1098 | \\ var z = @truncate(u8, u16(undefined)); |
| ... | ... | @@ -1091,7 +1136,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1091 | 1136 | \\ return 5678; |
| 1092 | 1137 | \\} |
| 1093 | 1138 | , |
| 1094 | "tmp.zig:2:12: error: `&&` is invalid. Note that `and` is boolean AND.", | |
| 1139 | "tmp.zig:2:12: error: `&&` is invalid. Note that `and` is boolean AND", | |
| 1095 | 1140 | ); |
| 1096 | 1141 | |
| 1097 | 1142 | cases.add( |
| ... | ... | @@ -1935,7 +1980,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1935 | 1980 | "unknown length pointer to opaque", |
| 1936 | 1981 | \\export const T = [*]@OpaqueType(); |
| 1937 | 1982 | , |
| 1938 | "tmp.zig:1:18: error: unknown-length pointer to opaque", | |
| 1983 | "tmp.zig:1:21: error: unknown-length pointer to opaque", | |
| 1939 | 1984 | ); |
| 1940 | 1985 | |
| 1941 | 1986 | cases.add( |
| ... | ... | @@ -2924,7 +2969,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 2924 | 2969 | \\fn a() *noreturn {} |
| 2925 | 2970 | \\export fn entry() void { _ = a(); } |
| 2926 | 2971 | , |
| 2927 | "tmp.zig:1:8: error: pointer to noreturn not allowed", | |
| 2972 | "tmp.zig:1:9: error: pointer to noreturn not allowed", | |
| 2928 | 2973 | ); |
| 2929 | 2974 | |
| 2930 | 2975 | cases.add( |
| ... | ... | @@ -3596,7 +3641,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3596 | 3641 | ); |
| 3597 | 3642 | |
| 3598 | 3643 | cases.add( |
| 3599 | "non constant expression in array size outside function", | |
| 3644 | "non constant expression in array size", | |
| 3600 | 3645 | \\const Foo = struct { |
| 3601 | 3646 | \\ y: [get()]u8, |
| 3602 | 3647 | \\}; |
| ... | ... | @@ -3606,8 +3651,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3606 | 3651 | \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); } |
| 3607 | 3652 | , |
| 3608 | 3653 | "tmp.zig:5:25: error: unable to evaluate constant expression", |
| 3609 | "tmp.zig:2:12: note: called from here", | |
| 3610 | "tmp.zig:2:8: note: called from here", | |
| 3654 | "tmp.zig:2:12: note: referenced here", | |
| 3611 | 3655 | ); |
| 3612 | 3656 | |
| 3613 | 3657 | cases.add( |
| ... | ... | @@ -3701,7 +3745,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3701 | 3745 | \\export fn entry() usize { return @sizeOf(@typeOf(y)); } |
| 3702 | 3746 | , |
| 3703 | 3747 | "tmp.zig:3:14: error: division by zero", |
| 3704 | "tmp.zig:1:14: note: called from here", | |
| 3748 | "tmp.zig:1:14: note: referenced here", | |
| 3705 | 3749 | ); |
| 3706 | 3750 | |
| 3707 | 3751 | cases.add( |
| ... | ... | @@ -4133,7 +4177,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4133 | 4177 | \\export fn entry() usize { return @sizeOf(@typeOf(seventh_fib_number)); } |
| 4134 | 4178 | , |
| 4135 | 4179 | "tmp.zig:3:21: error: evaluation exceeded 1000 backwards branches", |
| 4136 | "tmp.zig:3:21: note: called from here", | |
| 4180 | "tmp.zig:1:37: note: referenced here", | |
| 4181 | "tmp.zig:6:50: note: referenced here", | |
| 4137 | 4182 | ); |
| 4138 | 4183 | |
| 4139 | 4184 | cases.add( |
| ... | ... | @@ -4174,7 +4219,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4174 | 4219 | \\export fn entry() usize { return @sizeOf(@typeOf(a)); } |
| 4175 | 4220 | , |
| 4176 | 4221 | "tmp.zig:6:26: error: unable to evaluate constant expression", |
| 4177 | "tmp.zig:4:17: note: called from here", | |
| 4222 | "tmp.zig:4:17: note: referenced here", | |
| 4178 | 4223 | ); |
| 4179 | 4224 | |
| 4180 | 4225 | cases.add( |
| ... | ... | @@ -4257,7 +4302,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4257 | 4302 | \\export fn entry() usize { return @sizeOf(@typeOf(y)); } |
| 4258 | 4303 | , |
| 4259 | 4304 | "tmp.zig:3:12: error: negation caused overflow", |
| 4260 | "tmp.zig:1:14: note: called from here", | |
| 4305 | "tmp.zig:1:14: note: referenced here", | |
| 4261 | 4306 | ); |
| 4262 | 4307 | |
| 4263 | 4308 | cases.add( |
| ... | ... | @@ -4270,7 +4315,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4270 | 4315 | \\export fn entry() usize { return @sizeOf(@typeOf(y)); } |
| 4271 | 4316 | , |
| 4272 | 4317 | "tmp.zig:3:14: error: operation caused overflow", |
| 4273 | "tmp.zig:1:14: note: called from here", | |
| 4318 | "tmp.zig:1:14: note: referenced here", | |
| 4274 | 4319 | ); |
| 4275 | 4320 | |
| 4276 | 4321 | cases.add( |
| ... | ... | @@ -4283,7 +4328,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4283 | 4328 | \\export fn entry() usize { return @sizeOf(@typeOf(y)); } |
| 4284 | 4329 | , |
| 4285 | 4330 | "tmp.zig:3:14: error: operation caused overflow", |
| 4286 | "tmp.zig:1:14: note: called from here", | |
| 4331 | "tmp.zig:1:14: note: referenced here", | |
| 4287 | 4332 | ); |
| 4288 | 4333 | |
| 4289 | 4334 | cases.add( |
| ... | ... | @@ -4296,7 +4341,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4296 | 4341 | \\export fn entry() usize { return @sizeOf(@typeOf(y)); } |
| 4297 | 4342 | , |
| 4298 | 4343 | "tmp.zig:3:14: error: operation caused overflow", |
| 4299 | "tmp.zig:1:14: note: called from here", | |
| 4344 | "tmp.zig:1:14: note: referenced here", | |
| 4300 | 4345 | ); |
| 4301 | 4346 | |
| 4302 | 4347 | cases.add( |
| ... | ... | @@ -4388,7 +4433,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4388 | 4433 | \\} |
| 4389 | 4434 | , |
| 4390 | 4435 | "tmp.zig:3:7: error: unable to evaluate constant expression", |
| 4391 | "tmp.zig:16:19: note: called from here", | |
| 4436 | "tmp.zig:16:19: note: referenced here", | |
| 4392 | 4437 | ); |
| 4393 | 4438 | |
| 4394 | 4439 | cases.add( |
| ... | ... | @@ -4717,7 +4762,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4717 | 4762 | \\} |
| 4718 | 4763 | , |
| 4719 | 4764 | "tmp.zig:10:14: error: unable to evaluate constant expression", |
| 4720 | "tmp.zig:6:20: note: called from here", | |
| 4765 | "tmp.zig:6:20: note: referenced here", | |
| 4721 | 4766 | ); |
| 4722 | 4767 | |
| 4723 | 4768 | cases.add( |
| ... | ... | @@ -5864,7 +5909,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5864 | 5909 | \\} |
| 5865 | 5910 | , |
| 5866 | 5911 | "tmp.zig:4:25: error: aoeu", |
| 5867 | "tmp.zig:1:36: note: called from here", | |
| 5912 | "tmp.zig:1:36: note: referenced here", | |
| 5868 | 5913 | "tmp.zig:12:20: note: referenced here", |
| 5869 | 5914 | ); |
| 5870 | 5915 | |
| ... | ... | @@ -5939,7 +5984,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5939 | 5984 | \\ var x: MultipleChoice = undefined; |
| 5940 | 5985 | \\} |
| 5941 | 5986 | , |
| 5942 | "tmp.zig:2:14: error: non-enum union field assignment", | |
| 5987 | "tmp.zig:2:14: error: untagged union field assignment", | |
| 5943 | 5988 | "tmp.zig:1:24: note: consider 'union(enum)' here", |
| 5944 | 5989 | ); |
| 5945 | 5990 |
test/stage1/behavior.zig+4| ... | ... | @@ -15,6 +15,7 @@ comptime { |
| 15 | 15 | _ = @import("behavior/bugs/1111.zig"); |
| 16 | 16 | _ = @import("behavior/bugs/1120.zig"); |
| 17 | 17 | _ = @import("behavior/bugs/1277.zig"); |
| 18 | _ = @import("behavior/bugs/1310.zig"); | |
| 18 | 19 | _ = @import("behavior/bugs/1322.zig"); |
| 19 | 20 | _ = @import("behavior/bugs/1381.zig"); |
| 20 | 21 | _ = @import("behavior/bugs/1421.zig"); |
| ... | ... | @@ -22,15 +23,18 @@ comptime { |
| 22 | 23 | _ = @import("behavior/bugs/1486.zig"); |
| 23 | 24 | _ = @import("behavior/bugs/1500.zig"); |
| 24 | 25 | _ = @import("behavior/bugs/1607.zig"); |
| 26 | _ = @import("behavior/bugs/1735.zig"); | |
| 25 | 27 | _ = @import("behavior/bugs/1851.zig"); |
| 26 | 28 | _ = @import("behavior/bugs/1914.zig"); |
| 27 | 29 | _ = @import("behavior/bugs/2006.zig"); |
| 28 | 30 | _ = @import("behavior/bugs/2114.zig"); |
| 29 | 31 | _ = @import("behavior/bugs/2346.zig"); |
| 30 | 32 | _ = @import("behavior/bugs/2578.zig"); |
| 33 | _ = @import("behavior/bugs/3112.zig"); | |
| 31 | 34 | _ = @import("behavior/bugs/394.zig"); |
| 32 | 35 | _ = @import("behavior/bugs/421.zig"); |
| 33 | 36 | _ = @import("behavior/bugs/529.zig"); |
| 37 | _ = @import("behavior/bugs/624.zig"); | |
| 34 | 38 | _ = @import("behavior/bugs/655.zig"); |
| 35 | 39 | _ = @import("behavior/bugs/656.zig"); |
| 36 | 40 | _ = @import("behavior/bugs/679.zig"); |
test/stage1/behavior/align.zig+15| ... | ... | @@ -290,3 +290,18 @@ test "read 128-bit field from default aligned struct in global memory" { |
| 290 | 290 | expect((@ptrToInt(&default_aligned_global.badguy) % 16) == 0); |
| 291 | 291 | expect(12 == default_aligned_global.badguy); |
| 292 | 292 | } |
| 293 | ||
| 294 | test "struct field explicit alignment" { | |
| 295 | const S = struct { | |
| 296 | const Node = struct { | |
| 297 | next: *Node, | |
| 298 | massive_byte: u8 align(64), | |
| 299 | }; | |
| 300 | }; | |
| 301 | ||
| 302 | var node: S.Node = undefined; | |
| 303 | node.massive_byte = 100; | |
| 304 | expect(node.massive_byte == 100); | |
| 305 | comptime expect(@typeOf(&node.massive_byte) == *align(64) u8); | |
| 306 | expect(@ptrToInt(&node.massive_byte) % 64 == 0); | |
| 307 | } |
test/stage1/behavior/array.zig+6| ... | ... | @@ -292,3 +292,9 @@ test "read/write through global variable array of struct fields initialized via |
| 292 | 292 | }; |
| 293 | 293 | S.doTheTest(); |
| 294 | 294 | } |
| 295 | ||
| 296 | test "implicit cast zero sized array ptr to slice" { | |
| 297 | var b = ""; | |
| 298 | const c: []const u8 = &b; | |
| 299 | expect(c.len == 0); | |
| 300 | } |
test/stage1/behavior/bugs/1310.zig created+24| ... | ... | @@ -0,0 +1,24 @@ |
| 1 | const std = @import("std"); | |
| 2 | const expect = std.testing.expect; | |
| 3 | ||
| 4 | pub const VM = ?[*]const struct_InvocationTable_; | |
| 5 | pub const struct_InvocationTable_ = extern struct { | |
| 6 | GetVM: ?extern fn (?[*]VM) c_int, | |
| 7 | }; | |
| 8 | ||
| 9 | pub const struct_VM_ = extern struct { | |
| 10 | functions: ?[*]const struct_InvocationTable_, | |
| 11 | }; | |
| 12 | ||
| 13 | //excised output from stdlib.h etc | |
| 14 | ||
| 15 | pub const InvocationTable_ = struct_InvocationTable_; | |
| 16 | pub const VM_ = struct_VM_; | |
| 17 | ||
| 18 | extern fn agent_callback(_vm: [*]VM, options: [*]u8) i32 { | |
| 19 | return 11; | |
| 20 | } | |
| 21 | ||
| 22 | test "fixed" { | |
| 23 | expect(agent_callback(undefined, undefined) == 11); | |
| 24 | } |
test/stage1/behavior/bugs/1735.zig created+46| ... | ... | @@ -0,0 +1,46 @@ |
| 1 | const std = @import("std"); | |
| 2 | ||
| 3 | const mystruct = struct { | |
| 4 | pending: ?listofstructs, | |
| 5 | }; | |
| 6 | pub fn TailQueue(comptime T: type) type { | |
| 7 | return struct { | |
| 8 | const Self = @This(); | |
| 9 | ||
| 10 | pub const Node = struct { | |
| 11 | prev: ?*Node, | |
| 12 | next: ?*Node, | |
| 13 | data: T, | |
| 14 | }; | |
| 15 | ||
| 16 | first: ?*Node, | |
| 17 | last: ?*Node, | |
| 18 | len: usize, | |
| 19 | ||
| 20 | pub fn init() Self { | |
| 21 | return Self{ | |
| 22 | .first = null, | |
| 23 | .last = null, | |
| 24 | .len = 0, | |
| 25 | }; | |
| 26 | } | |
| 27 | }; | |
| 28 | } | |
| 29 | const listofstructs = TailQueue(mystruct); | |
| 30 | ||
| 31 | const a = struct { | |
| 32 | const Self = @This(); | |
| 33 | ||
| 34 | foo: listofstructs, | |
| 35 | ||
| 36 | pub fn init() Self { | |
| 37 | return Self{ | |
| 38 | .foo = listofstructs.init(), | |
| 39 | }; | |
| 40 | } | |
| 41 | }; | |
| 42 | ||
| 43 | test "intialization" { | |
| 44 | var t = a.init(); | |
| 45 | std.testing.expect(t.foo.len == 0); | |
| 46 | } |
test/stage1/behavior/bugs/3112.zig created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | const std = @import("std"); | |
| 2 | const expect = std.testing.expect; | |
| 3 | ||
| 4 | const State = struct { | |
| 5 | const Self = @This(); | |
| 6 | enter: fn (previous: ?Self) void, | |
| 7 | }; | |
| 8 | ||
| 9 | fn prev(p: ?State) void { | |
| 10 | expect(p == null); | |
| 11 | } | |
| 12 | ||
| 13 | test "zig test crash" { | |
| 14 | var global: State = undefined; | |
| 15 | global.enter = prev; | |
| 16 | global.enter(null); | |
| 17 | } |
test/stage1/behavior/bugs/624.zig created+23| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | const std = @import("std"); | |
| 2 | const expect = std.testing.expect; | |
| 3 | ||
| 4 | const TestContext = struct { | |
| 5 | server_context: *ListenerContext, | |
| 6 | }; | |
| 7 | ||
| 8 | const ListenerContext = struct { | |
| 9 | context_alloc: *ContextAllocator, | |
| 10 | }; | |
| 11 | ||
| 12 | const ContextAllocator = MemoryPool(TestContext); | |
| 13 | ||
| 14 | fn MemoryPool(comptime T: type) type { | |
| 15 | return struct { | |
| 16 | n: usize, | |
| 17 | }; | |
| 18 | } | |
| 19 | ||
| 20 | test "foo" { | |
| 21 | var allocator = ContextAllocator{ .n = 10 }; | |
| 22 | expect(allocator.n == 10); | |
| 23 | } |
test/stage1/behavior/error.zig+20| ... | ... | @@ -375,3 +375,23 @@ test "implicit cast to optional to error union to return result loc" { |
| 375 | 375 | S.entry(); |
| 376 | 376 | //comptime S.entry(); TODO |
| 377 | 377 | } |
| 378 | ||
| 379 | test "function pointer with return type that is error union with payload which is pointer of parent struct" { | |
| 380 | const S = struct { | |
| 381 | const Foo = struct { | |
| 382 | fun: fn (a: i32) (anyerror!*Foo), | |
| 383 | }; | |
| 384 | ||
| 385 | const Err = error{UnspecifiedErr}; | |
| 386 | ||
| 387 | fn bar(a: i32) anyerror!*Foo { | |
| 388 | return Err.UnspecifiedErr; | |
| 389 | } | |
| 390 | ||
| 391 | fn doTheTest() void { | |
| 392 | var x = Foo{ .fun = bar }; | |
| 393 | expectError(error.UnspecifiedErr, x.fun(1)); | |
| 394 | } | |
| 395 | }; | |
| 396 | S.doTheTest(); | |
| 397 | } |
test/stage1/behavior/misc.zig+15| ... | ... | @@ -706,3 +706,18 @@ test "result location zero sized array inside struct field implicit cast to slic |
| 706 | 706 | var foo = E{ .entries = [_]u32{} }; |
| 707 | 707 | expect(foo.entries.len == 0); |
| 708 | 708 | } |
| 709 | ||
| 710 | var global_foo: *i32 = undefined; | |
| 711 | ||
| 712 | test "global variable assignment with optional unwrapping with var initialized to undefined" { | |
| 713 | const S = struct { | |
| 714 | var data: i32 = 1234; | |
| 715 | fn foo() ?*i32 { | |
| 716 | return &data; | |
| 717 | } | |
| 718 | }; | |
| 719 | global_foo = S.foo() orelse { | |
| 720 | @panic("bad"); | |
| 721 | }; | |
| 722 | expect(global_foo.* == 1234); | |
| 723 | } |
test/stage1/behavior/optional.zig+19| ... | ... | @@ -100,3 +100,22 @@ test "nested orelse" { |
| 100 | 100 | S.entry(); |
| 101 | 101 | comptime S.entry(); |
| 102 | 102 | } |
| 103 | ||
| 104 | test "self-referential struct through a slice of optional" { | |
| 105 | const S = struct { | |
| 106 | const Node = struct { | |
| 107 | children: []?Node, | |
| 108 | data: ?u8, | |
| 109 | ||
| 110 | fn new() Node { | |
| 111 | return Node{ | |
| 112 | .children = undefined, | |
| 113 | .data = null, | |
| 114 | }; | |
| 115 | } | |
| 116 | }; | |
| 117 | }; | |
| 118 | ||
| 119 | var n = S.Node.new(); | |
| 120 | expect(n.data == null); | |
| 121 | } |
tools/process_headers.zig+2-5| ... | ... | @@ -504,12 +504,9 @@ const Contents = struct { |
| 504 | 504 | } |
| 505 | 505 | }; |
| 506 | 506 | |
| 507 | comptime { | |
| 508 | @compileError("the behavior of std.AutoHashMap changed and []const u8 will be treated as a pointer. will need to update the hash maps to actually do some kind of hashing on the slices."); | |
| 509 | } | |
| 510 | const HashToContents = std.AutoHashMap([]const u8, Contents); | |
| 507 | const HashToContents = std.StringHashMap(Contents); | |
| 511 | 508 | const TargetToHash = std.HashMap(DestTarget, []const u8, DestTarget.hash, DestTarget.eql); |
| 512 | const PathTable = std.AutoHashMap([]const u8, *TargetToHash); | |
| 509 | const PathTable = std.StringHashMap(*TargetToHash); | |
| 513 | 510 | |
| 514 | 511 | const LibCVendor = enum { |
| 515 | 512 | musl, |
tools/update_glibc.zig+3-3| ... | ... | @@ -118,7 +118,7 @@ const FunctionSet = struct { |
| 118 | 118 | list: std.ArrayList(VersionedFn), |
| 119 | 119 | fn_vers_list: FnVersionList, |
| 120 | 120 | }; |
| 121 | const FnVersionList = std.AutoHashMap([]const u8, std.ArrayList(usize)); | |
| 121 | const FnVersionList = std.StringHashMap(std.ArrayList(usize)); | |
| 122 | 122 | |
| 123 | 123 | const VersionedFn = struct { |
| 124 | 124 | ver: []const u8, // example: "GLIBC_2.15" |
| ... | ... | @@ -140,8 +140,8 @@ pub fn main() !void { |
| 140 | 140 | const prefix = try fs.path.join(allocator, [_][]const u8{ in_glibc_dir, "sysdeps", "unix", "sysv", "linux" }); |
| 141 | 141 | const glibc_out_dir = try fs.path.join(allocator, [_][]const u8{ zig_src_dir, "libc", "glibc" }); |
| 142 | 142 | |
| 143 | var global_fn_set = std.AutoHashMap([]const u8, Function).init(allocator); | |
| 144 | var global_ver_set = std.AutoHashMap([]const u8, usize).init(allocator); | |
| 143 | var global_fn_set = std.StringHashMap(Function).init(allocator); | |
| 144 | var global_ver_set = std.StringHashMap(usize).init(allocator); | |
| 145 | 145 | var target_functions = std.AutoHashMap(usize, FunctionSet).init(allocator); |
| 146 | 146 | |
| 147 | 147 | for (abi_lists) |*abi_list| { |