| author | |
| committer | |
| log | 928ce5e326ccd1b7456002c28f34975b5bc4b13f |
| tree | 5706376fe74103223511f5a4954ce2dff0b08d0e |
| parent | 2f3ad48c9b35ccac377e710a4eee6b35f60b119f |
| parent | e8a9caa3dd0aef7b745b8197afecec90598b2cdd |
| signature |
47 files changed, 3555 insertions(+), 1739 deletions(-)
src/all_types.hpp+118-31| ... | @@ -47,6 +47,19 @@ struct ResultLocPeer; | ... | @@ -47,6 +47,19 @@ struct ResultLocPeer; |
| 47 | struct ResultLocPeerParent; | 47 | struct ResultLocPeerParent; |
| 48 | struct ResultLocBitCast; | 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 | enum X64CABIClass { | 63 | enum X64CABIClass { |
| 51 | X64CABIClass_Unknown, | 64 | X64CABIClass_Unknown, |
| 52 | X64CABIClass_MEMORY, | 65 | X64CABIClass_MEMORY, |
| ... | @@ -69,9 +82,9 @@ struct IrExecutable { | ... | @@ -69,9 +82,9 @@ struct IrExecutable { |
| 69 | IrExecutable *source_exec; | 82 | IrExecutable *source_exec; |
| 70 | IrAnalyze *analysis; | 83 | IrAnalyze *analysis; |
| 71 | Scope *begin_scope; | 84 | Scope *begin_scope; |
| 85 | ErrorMsg *first_err_trace_msg; | ||
| 72 | ZigList<Tld *> tld_list; | 86 | ZigList<Tld *> tld_list; |
| 73 | 87 | ||
| 74 | bool invalid; | ||
| 75 | bool is_inline; | 88 | bool is_inline; |
| 76 | bool is_generic_instantiation; | 89 | bool is_generic_instantiation; |
| 77 | bool need_err_code_spill; | 90 | bool need_err_code_spill; |
| ... | @@ -255,6 +268,7 @@ enum ConstValSpecial { | ... | @@ -255,6 +268,7 @@ enum ConstValSpecial { |
| 255 | ConstValSpecialRuntime, | 268 | ConstValSpecialRuntime, |
| 256 | ConstValSpecialStatic, | 269 | ConstValSpecialStatic, |
| 257 | ConstValSpecialUndef, | 270 | ConstValSpecialUndef, |
| 271 | ConstValSpecialLazy, | ||
| 258 | }; | 272 | }; |
| 259 | 273 | ||
| 260 | enum RuntimeHintErrorUnion { | 274 | enum RuntimeHintErrorUnion { |
| ... | @@ -291,6 +305,82 @@ struct ConstGlobalRefs { | ... | @@ -291,6 +305,82 @@ struct ConstGlobalRefs { |
| 291 | uint32_t align; | 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 | struct ConstExprValue { | 384 | struct ConstExprValue { |
| 295 | ZigType *type; | 385 | ZigType *type; |
| 296 | ConstValSpecial special; | 386 | ConstValSpecial special; |
| ... | @@ -318,6 +408,7 @@ struct ConstExprValue { | ... | @@ -318,6 +408,7 @@ struct ConstExprValue { |
| 318 | ConstPtrValue x_ptr; | 408 | ConstPtrValue x_ptr; |
| 319 | ConstArgTuple x_arg_tuple; | 409 | ConstArgTuple x_arg_tuple; |
| 320 | Buf *x_enum_literal; | 410 | Buf *x_enum_literal; |
| 411 | LazyValue *x_lazy; | ||
| 321 | 412 | ||
| 322 | // populated if special == ConstValSpecialRuntime | 413 | // populated if special == ConstValSpecialRuntime |
| 323 | RuntimeHintErrorUnion rh_error_union; | 414 | RuntimeHintErrorUnion rh_error_union; |
| ... | @@ -364,6 +455,7 @@ enum TldResolution { | ... | @@ -364,6 +455,7 @@ enum TldResolution { |
| 364 | TldResolutionUnresolved, | 455 | TldResolutionUnresolved, |
| 365 | TldResolutionResolving, | 456 | TldResolutionResolving, |
| 366 | TldResolutionInvalid, | 457 | TldResolutionInvalid, |
| 458 | TldResolutionOkLazy, | ||
| 367 | TldResolutionOk, | 459 | TldResolutionOk, |
| 368 | }; | 460 | }; |
| 369 | 461 | ||
| ... | @@ -420,10 +512,12 @@ struct TypeEnumField { | ... | @@ -420,10 +512,12 @@ struct TypeEnumField { |
| 420 | 512 | ||
| 421 | struct TypeUnionField { | 513 | struct TypeUnionField { |
| 422 | Buf *name; | 514 | Buf *name; |
| 515 | ZigType *type_entry; // available after ResolveStatusSizeKnown | ||
| 516 | ConstExprValue *type_val; // available after ResolveStatusZeroBitsKnown | ||
| 423 | TypeEnumField *enum_field; | 517 | TypeEnumField *enum_field; |
| 424 | ZigType *type_entry; | ||
| 425 | AstNode *decl_node; | 518 | AstNode *decl_node; |
| 426 | uint32_t gen_index; | 519 | uint32_t gen_index; |
| 520 | uint32_t align; | ||
| 427 | }; | 521 | }; |
| 428 | 522 | ||
| 429 | enum NodeType { | 523 | enum NodeType { |
| ... | @@ -849,6 +943,8 @@ struct AstNodeStructField { | ... | @@ -849,6 +943,8 @@ struct AstNodeStructField { |
| 849 | Buf *name; | 943 | Buf *name; |
| 850 | AstNode *type; | 944 | AstNode *type; |
| 851 | AstNode *value; | 945 | AstNode *value; |
| 946 | // populated if the "align(A)" is present | ||
| 947 | AstNode *align_expr; | ||
| 852 | }; | 948 | }; |
| 853 | 949 | ||
| 854 | struct AstNodeStringLiteral { | 950 | struct AstNodeStringLiteral { |
| ... | @@ -944,6 +1040,7 @@ struct AstNodeEnumLiteral { | ... | @@ -944,6 +1040,7 @@ struct AstNodeEnumLiteral { |
| 944 | 1040 | ||
| 945 | struct AstNode { | 1041 | struct AstNode { |
| 946 | enum NodeType type; | 1042 | enum NodeType type; |
| 1043 | bool already_traced_this_node; | ||
| 947 | size_t line; | 1044 | size_t line; |
| 948 | size_t column; | 1045 | size_t column; |
| 949 | ZigType *owner; | 1046 | ZigType *owner; |
| ... | @@ -1039,12 +1136,6 @@ struct FnTypeId { | ... | @@ -1039,12 +1136,6 @@ struct FnTypeId { |
| 1039 | uint32_t fn_type_id_hash(FnTypeId*); | 1136 | uint32_t fn_type_id_hash(FnTypeId*); |
| 1040 | bool fn_type_id_eql(FnTypeId *a, FnTypeId *b); | 1137 | bool fn_type_id_eql(FnTypeId *a, FnTypeId *b); |
| 1041 | 1138 | ||
| 1042 | enum PtrLen { | ||
| 1043 | PtrLenUnknown, | ||
| 1044 | PtrLenSingle, | ||
| 1045 | PtrLenC, | ||
| 1046 | }; | ||
| 1047 | |||
| 1048 | struct ZigTypePointer { | 1139 | struct ZigTypePointer { |
| 1049 | ZigType *child_type; | 1140 | ZigType *child_type; |
| 1050 | ZigType *slice_parent; | 1141 | ZigType *slice_parent; |
| ... | @@ -1055,6 +1146,7 @@ struct ZigTypePointer { | ... | @@ -1055,6 +1146,7 @@ struct ZigTypePointer { |
| 1055 | bool is_const; | 1146 | bool is_const; |
| 1056 | bool is_volatile; | 1147 | bool is_volatile; |
| 1057 | bool allow_zero; | 1148 | bool allow_zero; |
| 1149 | bool resolve_loop_flag_zero_bits; | ||
| 1058 | }; | 1150 | }; |
| 1059 | 1151 | ||
| 1060 | struct ZigTypeInt { | 1152 | struct ZigTypeInt { |
| ... | @@ -1073,7 +1165,8 @@ struct ZigTypeArray { | ... | @@ -1073,7 +1165,8 @@ struct ZigTypeArray { |
| 1073 | 1165 | ||
| 1074 | struct TypeStructField { | 1166 | struct TypeStructField { |
| 1075 | Buf *name; | 1167 | Buf *name; |
| 1076 | ZigType *type_entry; | 1168 | ZigType *type_entry; // available after ResolveStatusSizeKnown |
| 1169 | ConstExprValue *type_val; // available after ResolveStatusZeroBitsKnown | ||
| 1077 | size_t src_index; | 1170 | size_t src_index; |
| 1078 | size_t gen_index; | 1171 | size_t gen_index; |
| 1079 | size_t offset; // byte offset from beginning of struct | 1172 | size_t offset; // byte offset from beginning of struct |
| ... | @@ -1129,15 +1222,16 @@ struct ZigTypeStruct { | ... | @@ -1129,15 +1222,16 @@ struct ZigTypeStruct { |
| 1129 | ResolveStatus resolve_status; | 1222 | ResolveStatus resolve_status; |
| 1130 | 1223 | ||
| 1131 | bool is_slice; | 1224 | bool is_slice; |
| 1132 | bool resolve_loop_flag; // set this flag temporarily to detect infinite loops | ||
| 1133 | bool reported_infinite_err; | ||
| 1134 | // whether any of the fields require comptime | 1225 | // whether any of the fields require comptime |
| 1135 | // known after ResolveStatusZeroBitsKnown | 1226 | // known after ResolveStatusZeroBitsKnown |
| 1136 | bool requires_comptime; | 1227 | bool requires_comptime; |
| 1228 | bool resolve_loop_flag_zero_bits; | ||
| 1229 | bool resolve_loop_flag_other; | ||
| 1137 | }; | 1230 | }; |
| 1138 | 1231 | ||
| 1139 | struct ZigTypeOptional { | 1232 | struct ZigTypeOptional { |
| 1140 | ZigType *child_type; | 1233 | ZigType *child_type; |
| 1234 | ResolveStatus resolve_status; | ||
| 1141 | }; | 1235 | }; |
| 1142 | 1236 | ||
| 1143 | struct ZigTypeErrorUnion { | 1237 | struct ZigTypeErrorUnion { |
| ... | @@ -1155,26 +1249,20 @@ struct ZigTypeErrorSet { | ... | @@ -1155,26 +1249,20 @@ struct ZigTypeErrorSet { |
| 1155 | 1249 | ||
| 1156 | struct ZigTypeEnum { | 1250 | struct ZigTypeEnum { |
| 1157 | AstNode *decl_node; | 1251 | AstNode *decl_node; |
| 1158 | ContainerLayout layout; | ||
| 1159 | uint32_t src_field_count; | ||
| 1160 | TypeEnumField *fields; | 1252 | TypeEnumField *fields; |
| 1161 | bool is_invalid; // true if any fields are invalid | ||
| 1162 | ZigType *tag_int_type; | 1253 | ZigType *tag_int_type; |
| 1163 | 1254 | ||
| 1164 | ScopeDecls *decls_scope; | 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 | LLVMValueRef name_function; | 1257 | LLVMValueRef name_function; |
| 1176 | 1258 | ||
| 1177 | HashMap<Buf *, TypeEnumField *, buf_hash, buf_eql_buf> fields_by_name; | 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 | uint32_t type_ptr_hash(const ZigType *ptr); | 1268 | uint32_t type_ptr_hash(const ZigType *ptr); |
| ... | @@ -1187,7 +1275,7 @@ struct ZigTypeUnion { | ... | @@ -1187,7 +1275,7 @@ struct ZigTypeUnion { |
| 1187 | HashMap<Buf *, TypeUnionField *, buf_hash, buf_eql_buf> fields_by_name; | 1275 | HashMap<Buf *, TypeUnionField *, buf_hash, buf_eql_buf> fields_by_name; |
| 1188 | ZigType *tag_type; // always an enum or null | 1276 | ZigType *tag_type; // always an enum or null |
| 1189 | LLVMTypeRef union_llvm_type; | 1277 | LLVMTypeRef union_llvm_type; |
| 1190 | ZigType *most_aligned_union_member; | 1278 | TypeUnionField *most_aligned_union_member; |
| 1191 | size_t gen_union_index; | 1279 | size_t gen_union_index; |
| 1192 | size_t gen_tag_index; | 1280 | size_t gen_tag_index; |
| 1193 | size_t union_abi_size; | 1281 | size_t union_abi_size; |
| ... | @@ -1199,11 +1287,11 @@ struct ZigTypeUnion { | ... | @@ -1199,11 +1287,11 @@ struct ZigTypeUnion { |
| 1199 | ResolveStatus resolve_status; | 1287 | ResolveStatus resolve_status; |
| 1200 | 1288 | ||
| 1201 | bool have_explicit_tag_type; | 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 | // whether any of the fields require comptime | 1290 | // whether any of the fields require comptime |
| 1205 | // the value is not valid until zero_bits_known == true | 1291 | // the value is not valid until zero_bits_known == true |
| 1206 | bool requires_comptime; | 1292 | bool requires_comptime; |
| 1293 | bool resolve_loop_flag_zero_bits; | ||
| 1294 | bool resolve_loop_flag_other; | ||
| 1207 | }; | 1295 | }; |
| 1208 | 1296 | ||
| 1209 | struct FnGenParamInfo { | 1297 | struct FnGenParamInfo { |
| ... | @@ -1715,6 +1803,7 @@ struct CodeGen { | ... | @@ -1715,6 +1803,7 @@ struct CodeGen { |
| 1715 | //////////////////////////// Runtime State | 1803 | //////////////////////////// Runtime State |
| 1716 | LLVMModuleRef module; | 1804 | LLVMModuleRef module; |
| 1717 | ZigList<ErrorMsg*> errors; | 1805 | ZigList<ErrorMsg*> errors; |
| 1806 | ErrorMsg *trace_err; | ||
| 1718 | LLVMBuilderRef builder; | 1807 | LLVMBuilderRef builder; |
| 1719 | ZigLLVMDIBuilder *dbuilder; | 1808 | ZigLLVMDIBuilder *dbuilder; |
| 1720 | ZigLLVMDICompileUnit *compile_unit; | 1809 | ZigLLVMDICompileUnit *compile_unit; |
| ... | @@ -1767,7 +1856,6 @@ struct CodeGen { | ... | @@ -1767,7 +1856,6 @@ struct CodeGen { |
| 1767 | ZigList<Tld *> resolve_queue; | 1856 | ZigList<Tld *> resolve_queue; |
| 1768 | size_t resolve_queue_index; | 1857 | size_t resolve_queue_index; |
| 1769 | ZigList<TimeEvent> timing_events; | 1858 | ZigList<TimeEvent> timing_events; |
| 1770 | ZigList<AstNode *> tld_ref_source_node_stack; | ||
| 1771 | ZigList<ZigFn *> inline_fns; | 1859 | ZigList<ZigFn *> inline_fns; |
| 1772 | ZigList<ZigFn *> test_fns; | 1860 | ZigList<ZigFn *> test_fns; |
| 1773 | ZigList<ErrorTableEntry *> errors_by_index; | 1861 | ZigList<ErrorTableEntry *> errors_by_index; |
| ... | @@ -1852,7 +1940,6 @@ struct CodeGen { | ... | @@ -1852,7 +1940,6 @@ struct CodeGen { |
| 1852 | ZigFn *main_fn; | 1940 | ZigFn *main_fn; |
| 1853 | ZigFn *panic_fn; | 1941 | ZigFn *panic_fn; |
| 1854 | TldFn *panic_tld_fn; | 1942 | TldFn *panic_tld_fn; |
| 1855 | AstNode *root_export_decl; | ||
| 1856 | 1943 | ||
| 1857 | WantPIC want_pic; | 1944 | WantPIC want_pic; |
| 1858 | WantStackCheck want_stack_check; | 1945 | WantStackCheck want_stack_check; |
| ... | @@ -1940,7 +2027,7 @@ struct CodeGen { | ... | @@ -1940,7 +2027,7 @@ struct CodeGen { |
| 1940 | Buf *zig_lib_dir; | 2027 | Buf *zig_lib_dir; |
| 1941 | Buf *zig_std_dir; | 2028 | Buf *zig_std_dir; |
| 1942 | Buf *dynamic_linker_path; | 2029 | Buf *dynamic_linker_path; |
| 1943 | Buf *version_script_path; | 2030 | Buf *version_script_path; |
| 1944 | 2031 | ||
| 1945 | const char **llvm_argv; | 2032 | const char **llvm_argv; |
| 1946 | size_t llvm_argv_len; | 2033 | size_t llvm_argv_len; |
| ... | @@ -3657,13 +3744,13 @@ enum ResultLocId { | ... | @@ -3657,13 +3744,13 @@ enum ResultLocId { |
| 3657 | ResultLocIdBitCast, | 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 | // ir_reset_result | 3748 | // ir_reset_result |
| 3662 | struct ResultLoc { | 3749 | struct ResultLoc { |
| 3663 | ResultLocId id; | 3750 | ResultLocId id; |
| 3664 | bool written; | 3751 | bool written; |
| 3665 | bool allow_write_through_const; | 3752 | bool allow_write_through_const; |
| 3666 | IrInstruction *resolved_loc; // result ptr | 3753 | IrInstruction *resolved_loc; // result ptr |
| 3667 | IrInstruction *source_instruction; | 3754 | IrInstruction *source_instruction; |
| 3668 | IrInstruction *gen_instruction; // value to store to the result loc | 3755 | IrInstruction *gen_instruction; // value to store to the result loc |
| 3669 | ZigType *implicit_elem_type; | 3756 | ZigType *implicit_elem_type; |
src/analyze.cpp+853-479| ... | @@ -20,7 +20,7 @@ | ... | @@ -20,7 +20,7 @@ |
| 20 | 20 | ||
| 21 | static const size_t default_backward_branch_quota = 1000; | 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 | static Error ATTRIBUTE_MUST_USE resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type); | 25 | static Error ATTRIBUTE_MUST_USE resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type); |
| 26 | static Error ATTRIBUTE_MUST_USE resolve_struct_alignment(CodeGen *g, ZigType *struct_type); | 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,13 +59,15 @@ ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg) { |
| 59 | root_struct->source_code, root_struct->line_offsets, msg); | 59 | root_struct->source_code, root_struct->line_offsets, msg); |
| 60 | 60 | ||
| 61 | g->errors.append(err); | 61 | g->errors.append(err); |
| 62 | g->trace_err = err; | ||
| 62 | return err; | 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 | Token fake_token; | 67 | Token fake_token; |
| 67 | fake_token.start_line = node->line; | 68 | fake_token.start_line = node->line; |
| 68 | fake_token.start_column = node->column; | 69 | fake_token.start_column = node->column; |
| 70 | node->already_traced_this_node = true; | ||
| 69 | return add_token_error(g, node->owner, &fake_token, msg); | 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,6 +273,8 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { |
| 271 | return type_entry->data.structure.resolve_status >= status; | 273 | return type_entry->data.structure.resolve_status >= status; |
| 272 | case ZigTypeIdUnion: | 274 | case ZigTypeIdUnion: |
| 273 | return type_entry->data.unionation.resolve_status >= status; | 275 | return type_entry->data.unionation.resolve_status >= status; |
| 276 | case ZigTypeIdEnum: | ||
| 277 | return type_entry->data.enumeration.resolve_status >= status; | ||
| 274 | case ZigTypeIdFnFrame: | 278 | case ZigTypeIdFnFrame: |
| 275 | switch (status) { | 279 | switch (status) { |
| 276 | case ResolveStatusInvalid: | 280 | case ResolveStatusInvalid: |
| ... | @@ -285,32 +289,28 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { | ... | @@ -285,32 +289,28 @@ bool type_is_resolved(ZigType *type_entry, ResolveStatus status) { |
| 285 | case ResolveStatusLLVMFull: | 289 | case ResolveStatusLLVMFull: |
| 286 | return type_entry->llvm_type != nullptr; | 290 | return type_entry->llvm_type != nullptr; |
| 287 | } | 291 | } |
| 288 | case ZigTypeIdEnum: | 292 | case ZigTypeIdOpaque: |
| 293 | return status < ResolveStatusSizeKnown; | ||
| 294 | case ZigTypeIdPointer: | ||
| 289 | switch (status) { | 295 | switch (status) { |
| 290 | case ResolveStatusUnstarted: | ||
| 291 | return true; | ||
| 292 | case ResolveStatusInvalid: | 296 | case ResolveStatusInvalid: |
| 293 | zig_unreachable(); | 297 | zig_unreachable(); |
| 298 | case ResolveStatusUnstarted: | ||
| 299 | return true; | ||
| 294 | case ResolveStatusZeroBitsKnown: | 300 | case ResolveStatusZeroBitsKnown: |
| 295 | return type_entry->data.enumeration.zero_bits_known; | ||
| 296 | case ResolveStatusAlignmentKnown: | 301 | case ResolveStatusAlignmentKnown: |
| 297 | return type_entry->data.enumeration.zero_bits_known; | ||
| 298 | case ResolveStatusSizeKnown: | 302 | case ResolveStatusSizeKnown: |
| 299 | return type_entry->data.enumeration.complete; | 303 | return type_entry->abi_size != SIZE_MAX; |
| 300 | case ResolveStatusLLVMFwdDecl: | 304 | case ResolveStatusLLVMFwdDecl: |
| 301 | case ResolveStatusLLVMFull: | 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 | case ZigTypeIdMetaType: | 308 | case ZigTypeIdMetaType: |
| 308 | case ZigTypeIdVoid: | 309 | case ZigTypeIdVoid: |
| 309 | case ZigTypeIdBool: | 310 | case ZigTypeIdBool: |
| 310 | case ZigTypeIdUnreachable: | 311 | case ZigTypeIdUnreachable: |
| 311 | case ZigTypeIdInt: | 312 | case ZigTypeIdInt: |
| 312 | case ZigTypeIdFloat: | 313 | case ZigTypeIdFloat: |
| 313 | case ZigTypeIdPointer: | ||
| 314 | case ZigTypeIdArray: | 314 | case ZigTypeIdArray: |
| 315 | case ZigTypeIdComptimeFloat: | 315 | case ZigTypeIdComptimeFloat: |
| 316 | case ZigTypeIdComptimeInt: | 316 | case ZigTypeIdComptimeInt: |
| ... | @@ -460,8 +460,6 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons | ... | @@ -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 | ZigType *entry = new_type_table_entry(ZigTypeIdPointer); | 463 | ZigType *entry = new_type_table_entry(ZigTypeIdPointer); |
| 466 | 464 | ||
| 467 | const char *star_str = ptr_len_to_star_str(ptr_len); | 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,17 +489,21 @@ ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_cons |
| 491 | buf_ptr(&child_type->name)); | 489 | buf_ptr(&child_type->name)); |
| 492 | } | 490 | } |
| 493 | 491 | ||
| 494 | assert(child_type->id != ZigTypeIdInvalid); | 492 | if (type_is_resolved(child_type, ResolveStatusZeroBitsKnown)) { |
| 495 | 493 | if (type_has_bits(child_type)) { | |
| 496 | if (type_has_bits(child_type)) { | 494 | entry->abi_size = g->builtin_types.entry_usize->abi_size; |
| 497 | entry->abi_size = g->builtin_types.entry_usize->abi_size; | 495 | entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; |
| 498 | entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; | 496 | entry->abi_align = g->builtin_types.entry_usize->abi_align; |
| 499 | 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 | } else { | 503 | } else { |
| 501 | assert(byte_alignment == 0); | 504 | entry->abi_size = SIZE_MAX; |
| 502 | entry->abi_size = 0; | 505 | entry->size_in_bits = SIZE_MAX; |
| 503 | entry->size_in_bits = 0; | 506 | entry->abi_align = UINT32_MAX; |
| 504 | entry->abi_align = 0; | ||
| 505 | } | 507 | } |
| 506 | 508 | ||
| 507 | entry->data.pointer.ptr_len = ptr_len; | 509 | entry->data.pointer.ptr_len = ptr_len; |
| ... | @@ -564,6 +566,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { | ... | @@ -564,6 +566,7 @@ ZigType *get_optional_type(CodeGen *g, ZigType *child_type) { |
| 564 | } | 566 | } |
| 565 | 567 | ||
| 566 | entry->data.maybe.child_type = child_type; | 568 | entry->data.maybe.child_type = child_type; |
| 569 | entry->data.maybe.resolve_status = ResolveStatusSizeKnown; | ||
| 567 | 570 | ||
| 568 | child_type->optional_parent = entry; | 571 | child_type->optional_parent = entry; |
| 569 | return entry; | 572 | return entry; |
| ... | @@ -865,7 +868,7 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { | ... | @@ -865,7 +868,7 @@ ZigType *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) { |
| 865 | return table_entry->value; | 868 | return table_entry->value; |
| 866 | } | 869 | } |
| 867 | if (fn_type_id->return_type != nullptr) { | 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 | return g->builtin_types.entry_invalid; | 872 | return g->builtin_types.entry_invalid; |
| 870 | assert(fn_type_id->return_type->id != ZigTypeIdOpaque); | 873 | assert(fn_type_id->return_type->id != ZigTypeIdOpaque); |
| 871 | } else { | 874 | } else { |
| ... | @@ -960,31 +963,276 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind | ... | @@ -960,31 +963,276 @@ ZigType *get_partial_container_type(CodeGen *g, Scope *scope, ContainerKind kind |
| 960 | return entry; | 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 | size_t backward_branch_count = 0; | 969 | size_t backward_branch_count = 0; |
| 965 | size_t backward_branch_quota = default_backward_branch_quota; | 970 | size_t backward_branch_quota = default_backward_branch_quota; |
| 966 | return ir_eval_const_value(g, scope, node, type_entry, | 971 | return ir_eval_const_value(g, scope, node, type_entry, |
| 967 | &backward_branch_count, &backward_branch_quota, | 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) { | 976 | static Error type_val_resolve_zero_bits(CodeGen *g, ConstExprValue *type_val, ZigType *parent_type, |
| 972 | ConstExprValue *result = analyze_const_value(g, scope, node, g->builtin_types.entry_type, nullptr); | 977 | ConstExprValue *parent_type_val, bool *is_zero_bits) |
| 973 | if (type_is_invalid(result->type)) | 978 | { |
| 974 | return g->builtin_types.entry_invalid; | 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); | 1004 | if (parent_type_val == &lazy_ptr_type->elem_type->value) { |
| 977 | // Reject undefined as valid `type` type even though the specification | 1005 | // Does a struct which contains a pointer field to itself have bits? Yes. |
| 978 | // allows it to be casted to anything. | 1006 | *is_zero_bits = false; |
| 979 | // See also ir_resolve_type() | 1007 | return ErrorNone; |
| 980 | if (result->special == ConstValSpecialUndef) { | 1008 | } else { |
| 981 | add_node_error(g, node, | 1009 | if (parent_type_val == nullptr) { |
| 982 | buf_sprintf("expected type 'type', found '%s'", | 1010 | parent_type_val = type_val; |
| 983 | buf_ptr(&g->builtin_types.entry_undef->name))); | 1011 | } |
| 984 | return g->builtin_types.entry_invalid; | 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 | return result->data.x_type; | 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,11 +1280,12 @@ void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_cou |
| 1032 | } | 1280 | } |
| 1033 | 1281 | ||
| 1034 | static bool analyze_const_align(CodeGen *g, Scope *scope, AstNode *node, uint32_t *result) { | 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 | if (type_is_invalid(align_result->type)) | 1285 | if (type_is_invalid(align_result->type)) |
| 1037 | return false; | 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 | if (align_bytes == 0) { | 1289 | if (align_bytes == 0) { |
| 1041 | add_node_error(g, node, buf_sprintf("alignment must be >= 1")); | 1290 | add_node_error(g, node, buf_sprintf("alignment must be >= 1")); |
| 1042 | return false; | 1291 | return false; |
| ... | @@ -1054,7 +1303,7 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf ** | ... | @@ -1054,7 +1303,7 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf ** |
| 1054 | ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, | 1303 | ZigType *ptr_type = get_pointer_to_type_extra(g, g->builtin_types.entry_u8, true, false, |
| 1055 | PtrLenUnknown, 0, 0, 0, false); | 1304 | PtrLenUnknown, 0, 0, 0, false); |
| 1056 | ZigType *str_type = get_slice_type(g, ptr_type); | 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 | if (type_is_invalid(result_val->type)) | 1307 | if (type_is_invalid(result_val->type)) |
| 1059 | return false; | 1308 | return false; |
| 1060 | 1309 | ||
| ... | @@ -1068,7 +1317,7 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf ** | ... | @@ -1068,7 +1317,7 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf ** |
| 1068 | return true; | 1317 | return true; |
| 1069 | } | 1318 | } |
| 1070 | expand_undef_array(g, array_val); | 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 | Buf *result = buf_alloc(); | 1321 | Buf *result = buf_alloc(); |
| 1073 | buf_resize(result, len); | 1322 | buf_resize(result, len); |
| 1074 | for (size_t i = 0; i < len; i += 1) { | 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,7 +1327,7 @@ static bool analyze_const_string(CodeGen *g, Scope *scope, AstNode *node, Buf ** |
| 1078 | add_node_error(g, node, buf_sprintf("use of undefined value")); | 1327 | add_node_error(g, node, buf_sprintf("use of undefined value")); |
| 1079 | return false; | 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 | assert(big_c <= UINT8_MAX); | 1331 | assert(big_c <= UINT8_MAX); |
| 1083 | uint8_t c = (uint8_t)big_c; | 1332 | uint8_t c = (uint8_t)big_c; |
| 1084 | buf_ptr(result)[i] = c; | 1333 | buf_ptr(result)[i] = c; |
| ... | @@ -1404,7 +1653,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc | ... | @@ -1404,7 +1653,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc |
| 1404 | add_node_error(g, proto_node, | 1653 | add_node_error(g, proto_node, |
| 1405 | buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447")); | 1654 | buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447")); |
| 1406 | return g->builtin_types.entry_invalid; | 1655 | return g->builtin_types.entry_invalid; |
| 1407 | //return get_generic_fn_type(g, &fn_type_id); | ||
| 1408 | } | 1656 | } |
| 1409 | 1657 | ||
| 1410 | ZigType *specified_return_type = analyze_type_expr(g, child_scope, fn_proto->return_type); | 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,14 +1671,17 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc |
| 1423 | } | 1671 | } |
| 1424 | 1672 | ||
| 1425 | if (!calling_convention_allows_zig_types(fn_type_id.cc) && | 1673 | if (!calling_convention_allows_zig_types(fn_type_id.cc) && |
| 1426 | fn_type_id.return_type->id != ZigTypeIdVoid && | 1674 | fn_type_id.return_type->id != ZigTypeIdVoid) |
| 1427 | !type_allowed_in_extern(g, fn_type_id.return_type)) | ||
| 1428 | { | 1675 | { |
| 1429 | add_node_error(g, fn_proto->return_type, | 1676 | if ((err = type_resolve(g, fn_type_id.return_type, ResolveStatusSizeKnown))) |
| 1430 | buf_sprintf("return type '%s' not allowed in function with calling convention '%s'", | 1677 | return g->builtin_types.entry_invalid; |
| 1431 | buf_ptr(&fn_type_id.return_type->name), | 1678 | if (!type_allowed_in_extern(g, fn_type_id.return_type)) { |
| 1432 | calling_convention_name(fn_type_id.cc))); | 1679 | add_node_error(g, fn_proto->return_type, |
| 1433 | return g->builtin_types.entry_invalid; | 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 | switch (fn_type_id.return_type->id) { | 1687 | switch (fn_type_id.return_type->id) { |
| ... | @@ -1490,7 +1741,7 @@ bool type_is_invalid(ZigType *type_entry) { | ... | @@ -1490,7 +1741,7 @@ bool type_is_invalid(ZigType *type_entry) { |
| 1490 | case ZigTypeIdUnion: | 1741 | case ZigTypeIdUnion: |
| 1491 | return type_entry->data.unionation.resolve_status == ResolveStatusInvalid; | 1742 | return type_entry->data.unionation.resolve_status == ResolveStatusInvalid; |
| 1492 | case ZigTypeIdEnum: | 1743 | case ZigTypeIdEnum: |
| 1493 | return type_entry->data.enumeration.is_invalid; | 1744 | return type_entry->data.enumeration.resolve_status == ResolveStatusInvalid; |
| 1494 | default: | 1745 | default: |
| 1495 | return false; | 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,6 +1835,17 @@ static size_t get_abi_size_bytes(size_t size_in_bits, size_t pointer_size_bytes) |
| 1584 | return align_forward(store_size_bytes, abi_align); | 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 | static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { | 1849 | static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { |
| 1588 | assert(struct_type->id == ZigTypeIdStruct); | 1850 | assert(struct_type->id == ZigTypeIdStruct); |
| 1589 | 1851 | ||
| ... | @@ -1599,12 +1861,11 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { | ... | @@ -1599,12 +1861,11 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { |
| 1599 | 1861 | ||
| 1600 | AstNode *decl_node = struct_type->data.structure.decl_node; | 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 | if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { | 1865 | if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { |
| 1604 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | 1866 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 1605 | ErrorMsg *msg = add_node_error(g, decl_node, | 1867 | add_node_error(g, decl_node, |
| 1606 | buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name))); | 1868 | buf_sprintf("struct '%s' depends on itself", buf_ptr(&struct_type->name))); |
| 1607 | emit_error_notes_for_ref_stack(g, msg); | ||
| 1608 | } | 1869 | } |
| 1609 | return ErrorSemanticAnalyzeFail; | 1870 | return ErrorSemanticAnalyzeFail; |
| 1610 | } | 1871 | } |
| ... | @@ -1615,20 +1876,10 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { | ... | @@ -1615,20 +1876,10 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { |
| 1615 | size_t field_count = struct_type->data.structure.src_field_count; | 1876 | size_t field_count = struct_type->data.structure.src_field_count; |
| 1616 | 1877 | ||
| 1617 | bool packed = (struct_type->data.structure.layout == ContainerLayoutPacked); | 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 | uint32_t *host_int_bytes = packed ? allocate<uint32_t>(struct_type->data.structure.gen_field_count) : nullptr; | 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 | size_t packed_bits_offset = 0; | 1883 | size_t packed_bits_offset = 0; |
| 1633 | size_t next_offset = 0; | 1884 | size_t next_offset = 0; |
| 1634 | size_t first_packed_bits_offset_misalign = SIZE_MAX; | 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,13 +1892,25 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { |
| 1641 | TypeStructField *field = &struct_type->data.structure.fields[i]; | 1892 | TypeStructField *field = &struct_type->data.structure.fields[i]; |
| 1642 | if (field->gen_index == SIZE_MAX) | 1893 | if (field->gen_index == SIZE_MAX) |
| 1643 | continue; | 1894 | continue; |
| 1644 | ZigType *field_type = field->type_entry; | ||
| 1645 | assert(field_type != nullptr); | ||
| 1646 | 1895 | ||
| 1647 | field->gen_index = gen_field_index; | 1896 | field->gen_index = gen_field_index; |
| 1648 | field->offset = next_offset; | 1897 | field->offset = next_offset; |
| 1649 | 1898 | ||
| 1650 | if (packed) { | 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 | size_t field_size_in_bits = type_size_bits(g, field_type); | 1914 | size_t field_size_in_bits = type_size_bits(g, field_type); |
| 1652 | size_t next_packed_bits_offset = packed_bits_offset + field_size_in_bits; | 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,6 +1946,15 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { |
| 1683 | } | 1946 | } |
| 1684 | packed_bits_offset = next_packed_bits_offset; | 1947 | packed_bits_offset = next_packed_bits_offset; |
| 1685 | } else { | 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 | gen_field_index += 1; | 1958 | gen_field_index += 1; |
| 1687 | size_t next_src_field_index = i + 1; | 1959 | size_t next_src_field_index = i + 1; |
| 1688 | for (; next_src_field_index < field_count; next_src_field_index += 1) { | 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,9 +1962,9 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { |
| 1690 | break; | 1962 | break; |
| 1691 | } | 1963 | } |
| 1692 | } | 1964 | } |
| 1693 | size_t next_abi_align = (next_src_field_index == field_count) ? | 1965 | size_t next_align = (next_src_field_index == field_count) ? |
| 1694 | abi_align : struct_type->data.structure.fields[next_src_field_index].type_entry->abi_align; | 1966 | abi_align : struct_type->data.structure.fields[next_src_field_index].align; |
| 1695 | next_offset = next_field_offset(next_offset, abi_align, field_type->abi_size, next_abi_align); | 1967 | next_offset = next_field_offset(next_offset, abi_align, field_abi_size, next_align); |
| 1696 | size_in_bits = next_offset * 8; | 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,9 +1980,39 @@ static Error resolve_struct_type(CodeGen *g, ZigType *struct_type) { |
| 1708 | struct_type->size_in_bits = size_in_bits; | 1980 | struct_type->size_in_bits = size_in_bits; |
| 1709 | struct_type->data.structure.resolve_status = ResolveStatusSizeKnown; | 1981 | struct_type->data.structure.resolve_status = ResolveStatusSizeKnown; |
| 1710 | struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index; | 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 | struct_type->data.structure.host_int_bytes = host_int_bytes; | 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 | return ErrorNone; | 2016 | return ErrorNone; |
| 1715 | } | 2017 | } |
| 1716 | 2018 | ||
| ... | @@ -1728,22 +2030,21 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { | ... | @@ -1728,22 +2030,21 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { |
| 1728 | if (union_type->data.unionation.resolve_status >= ResolveStatusAlignmentKnown) | 2030 | if (union_type->data.unionation.resolve_status >= ResolveStatusAlignmentKnown) |
| 1729 | return ErrorNone; | 2031 | return ErrorNone; |
| 1730 | 2032 | ||
| 1731 | if (union_type->data.unionation.resolve_loop_flag) { | 2033 | AstNode *decl_node = union_type->data.structure.decl_node; |
| 1732 | if (!union_type->data.unionation.reported_infinite_err) { | 2034 | |
| 1733 | AstNode *decl_node = union_type->data.unionation.decl_node; | 2035 | if (union_type->data.unionation.resolve_loop_flag_other) { |
| 1734 | union_type->data.unionation.reported_infinite_err = true; | 2036 | if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { |
| 1735 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 2037 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 1736 | ErrorMsg *msg = add_node_error(g, decl_node, | 2038 | add_node_error(g, decl_node, |
| 1737 | buf_sprintf("union '%s' contains itself", buf_ptr(&union_type->name))); | 2039 | buf_sprintf("union '%s' depends on itself", buf_ptr(&union_type->name))); |
| 1738 | emit_error_notes_for_ref_stack(g, msg); | ||
| 1739 | } | 2040 | } |
| 1740 | return ErrorSemanticAnalyzeFail; | 2041 | return ErrorSemanticAnalyzeFail; |
| 1741 | } | 2042 | } |
| 1742 | 2043 | ||
| 1743 | // set temporary flag | 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 | uint32_t field_count = union_type->data.unionation.src_field_count; | 2048 | uint32_t field_count = union_type->data.unionation.src_field_count; |
| 1748 | bool packed = union_type->data.unionation.layout == ContainerLayoutPacked; | 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,34 +2053,44 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { |
| 1752 | if (field->gen_index == UINT32_MAX) | 2053 | if (field->gen_index == UINT32_MAX) |
| 1753 | continue; | 2054 | continue; |
| 1754 | 2055 | ||
| 1755 | size_t this_field_align; | 2056 | AstNode *align_expr = field->decl_node->data.struct_field.align_expr; |
| 1756 | if (packed) { | 2057 | if (align_expr != nullptr) { |
| 1757 | // TODO: https://github.com/ziglang/zig/issues/1512 | 2058 | if (!analyze_const_align(g, &union_type->data.unionation.decls_scope->base, align_expr, |
| 1758 | this_field_align = 1; | 2059 | &field->align)) |
| 1759 | // This is the same hack as resolve_struct_alignment. See the comment there. | 2060 | { |
| 1760 | } else if (field->type_entry == nullptr) { | 2061 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 1761 | this_field_align = g->builtin_types.entry_usize->abi_align; | 2062 | return err; |
| 1762 | } else { | 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 | if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { | 2069 | if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) { |
| 1764 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 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 | if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) | 2083 | if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) |
| 1769 | return ErrorSemanticAnalyzeFail; | 2084 | return ErrorSemanticAnalyzeFail; |
| 1770 | |||
| 1771 | this_field_align = field->type_entry->abi_align; | ||
| 1772 | } | 2085 | } |
| 1773 | 2086 | ||
| 1774 | if (most_aligned_union_member == nullptr || | 2087 | if (most_aligned_union_member == nullptr || field->align > most_aligned_union_member->align) { |
| 1775 | this_field_align > most_aligned_union_member->abi_align) | 2088 | most_aligned_union_member = field; |
| 1776 | { | ||
| 1777 | most_aligned_union_member = field->type_entry; | ||
| 1778 | } | 2089 | } |
| 1779 | } | 2090 | } |
| 1780 | 2091 | ||
| 1781 | // unset temporary flag | 2092 | // unset temporary flag |
| 1782 | union_type->data.unionation.resolve_loop_flag = false; | 2093 | union_type->data.unionation.resolve_loop_flag_other = false; |
| 1783 | union_type->data.unionation.resolve_status = ResolveStatusAlignmentKnown; | 2094 | union_type->data.unionation.resolve_status = ResolveStatusAlignmentKnown; |
| 1784 | union_type->data.unionation.most_aligned_union_member = most_aligned_union_member; | 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,18 +2104,18 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { |
| 1793 | union_type->abi_align = tag_type->abi_align; | 2104 | union_type->abi_align = tag_type->abi_align; |
| 1794 | union_type->data.unionation.gen_tag_index = SIZE_MAX; | 2105 | union_type->data.unionation.gen_tag_index = SIZE_MAX; |
| 1795 | union_type->data.unionation.gen_union_index = SIZE_MAX; | 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 | union_type->abi_align = tag_type->abi_align; | 2108 | union_type->abi_align = tag_type->abi_align; |
| 1798 | union_type->data.unionation.gen_tag_index = 0; | 2109 | union_type->data.unionation.gen_tag_index = 0; |
| 1799 | union_type->data.unionation.gen_union_index = 1; | 2110 | union_type->data.unionation.gen_union_index = 1; |
| 1800 | } else { | 2111 | } else { |
| 1801 | union_type->abi_align = most_aligned_union_member->abi_align; | 2112 | union_type->abi_align = most_aligned_union_member->align; |
| 1802 | union_type->data.unionation.gen_union_index = 0; | 2113 | union_type->data.unionation.gen_union_index = 0; |
| 1803 | union_type->data.unionation.gen_tag_index = 1; | 2114 | union_type->data.unionation.gen_tag_index = 1; |
| 1804 | } | 2115 | } |
| 1805 | } else { | 2116 | } else { |
| 1806 | assert(most_aligned_union_member != nullptr); | 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 | union_type->data.unionation.gen_union_index = SIZE_MAX; | 2119 | union_type->data.unionation.gen_union_index = SIZE_MAX; |
| 1809 | union_type->data.unionation.gen_tag_index = SIZE_MAX; | 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,6 +2123,17 @@ static Error resolve_union_alignment(CodeGen *g, ZigType *union_type) { |
| 1812 | return ErrorNone; | 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 | static Error resolve_union_type(CodeGen *g, ZigType *union_type) { | 2137 | static Error resolve_union_type(CodeGen *g, ZigType *union_type) { |
| 1816 | assert(union_type->id == ZigTypeIdUnion); | 2138 | assert(union_type->id == ZigTypeIdUnion); |
| 1817 | 2139 | ||
| ... | @@ -1831,30 +2153,32 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { | ... | @@ -1831,30 +2153,32 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { |
| 1831 | assert(decl_node->type == NodeTypeContainerDecl); | 2153 | assert(decl_node->type == NodeTypeContainerDecl); |
| 1832 | 2154 | ||
| 1833 | uint32_t field_count = union_type->data.unionation.src_field_count; | 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 | assert(union_type->data.unionation.fields); | 2158 | assert(union_type->data.unionation.fields); |
| 1837 | 2159 | ||
| 1838 | size_t union_abi_size = 0; | 2160 | size_t union_abi_size = 0; |
| 1839 | size_t union_size_in_bits = 0; | 2161 | size_t union_size_in_bits = 0; |
| 1840 | 2162 | ||
| 1841 | if (union_type->data.unionation.resolve_loop_flag) { | 2163 | if (union_type->data.unionation.resolve_loop_flag_other) { |
| 1842 | if (!union_type->data.unionation.reported_infinite_err) { | 2164 | if (union_type->data.unionation.resolve_status != ResolveStatusInvalid) { |
| 1843 | union_type->data.unionation.reported_infinite_err = true; | ||
| 1844 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 2165 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 1845 | ErrorMsg *msg = add_node_error(g, decl_node, | 2166 | add_node_error(g, decl_node, |
| 1846 | buf_sprintf("union '%s' depends on its own size", buf_ptr(&union_type->name))); | 2167 | buf_sprintf("union '%s' depends on itself", buf_ptr(&union_type->name))); |
| 1847 | emit_error_notes_for_ref_stack(g, msg); | ||
| 1848 | } | 2168 | } |
| 1849 | return ErrorSemanticAnalyzeFail; | 2169 | return ErrorSemanticAnalyzeFail; |
| 1850 | } | 2170 | } |
| 1851 | 2171 | ||
| 1852 | // set temporary flag | 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 | for (uint32_t i = 0; i < field_count; i += 1) { | 2175 | for (uint32_t i = 0; i < field_count; i += 1) { |
| 1856 | TypeUnionField *union_field = &union_type->data.unionation.fields[i]; | 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 | if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) { | 2183 | if ((err = type_resolve(g, field_type, ResolveStatusSizeKnown))) { |
| 1860 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 2184 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| ... | @@ -1874,11 +2198,11 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { | ... | @@ -1874,11 +2198,11 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { |
| 1874 | // The union itself for now has to be treated as being independently aligned. | 2198 | // The union itself for now has to be treated as being independently aligned. |
| 1875 | // See https://github.com/ziglang/zig/issues/2166. | 2199 | // See https://github.com/ziglang/zig/issues/2166. |
| 1876 | if (most_aligned_union_member != nullptr) { | 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 | // unset temporary flag | 2204 | // unset temporary flag |
| 1881 | union_type->data.unionation.resolve_loop_flag = false; | 2205 | union_type->data.unionation.resolve_loop_flag_other = false; |
| 1882 | union_type->data.unionation.resolve_status = ResolveStatusSizeKnown; | 2206 | union_type->data.unionation.resolve_status = ResolveStatusSizeKnown; |
| 1883 | union_type->data.unionation.union_abi_size = union_abi_size; | 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,7 +2221,7 @@ static Error resolve_union_type(CodeGen *g, ZigType *union_type) { |
| 1897 | field_sizes[union_type->data.unionation.gen_tag_index] = tag_type->abi_size; | 2221 | field_sizes[union_type->data.unionation.gen_tag_index] = tag_type->abi_size; |
| 1898 | field_aligns[union_type->data.unionation.gen_tag_index] = tag_type->abi_align; | 2222 | field_aligns[union_type->data.unionation.gen_tag_index] = tag_type->abi_align; |
| 1899 | field_sizes[union_type->data.unionation.gen_union_index] = union_abi_size; | 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 | size_t field2_offset = next_field_offset(0, union_type->abi_align, field_sizes[0], field_aligns[1]); | 2225 | size_t field2_offset = next_field_offset(0, union_type->abi_align, field_sizes[0], field_aligns[1]); |
| 1902 | union_type->abi_size = next_field_offset(field2_offset, union_type->abi_align, field_sizes[1], union_type->abi_align); | 2226 | union_type->abi_size = next_field_offset(field2_offset, union_type->abi_align, field_sizes[1], union_type->abi_align); |
| 1903 | union_type->size_in_bits = union_type->abi_size * 8; | 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,24 +2249,25 @@ static bool type_is_valid_extern_enum_tag(CodeGen *g, ZigType *ty) { |
| 1925 | static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { | 2249 | static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 1926 | assert(enum_type->id == ZigTypeIdEnum); | 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 | return ErrorSemanticAnalyzeFail; | 2253 | return ErrorSemanticAnalyzeFail; |
| 1930 | 2254 | if (enum_type->data.enumeration.resolve_status >= ResolveStatusZeroBitsKnown) | |
| 1931 | if (enum_type->data.enumeration.zero_bits_known) | ||
| 1932 | return ErrorNone; | 2255 | return ErrorNone; |
| 1933 | 2256 | ||
| 1934 | if (enum_type->data.enumeration.zero_bits_loop_flag) { | 2257 | AstNode *decl_node = enum_type->data.enumeration.decl_node; |
| 1935 | ErrorMsg *msg = add_node_error(g, enum_type->data.enumeration.decl_node, | 2258 | assert(decl_node->type == NodeTypeContainerDecl); |
| 1936 | buf_sprintf("'%s' depends on itself", buf_ptr(&enum_type->name))); | 2259 | |
| 1937 | emit_error_notes_for_ref_stack(g, msg); | 2260 | if (enum_type->data.enumeration.resolve_loop_flag) { |
| 1938 | enum_type->data.enumeration.is_invalid = true; | 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 | return ErrorSemanticAnalyzeFail; | 2267 | return ErrorSemanticAnalyzeFail; |
| 1940 | } | 2268 | } |
| 1941 | 2269 | ||
| 1942 | enum_type->data.enumeration.zero_bits_loop_flag = true; | 2270 | enum_type->data.enumeration.resolve_loop_flag = true; |
| 1943 | |||
| 1944 | AstNode *decl_node = enum_type->data.enumeration.decl_node; | ||
| 1945 | assert(decl_node->type == NodeTypeContainerDecl); | ||
| 1946 | 2271 | ||
| 1947 | assert(!enum_type->data.enumeration.fields); | 2272 | assert(!enum_type->data.enumeration.fields); |
| 1948 | uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; | 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,9 +2276,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 1951 | 2276 | ||
| 1952 | enum_type->data.enumeration.src_field_count = field_count; | 2277 | enum_type->data.enumeration.src_field_count = field_count; |
| 1953 | enum_type->data.enumeration.fields = nullptr; | 2278 | enum_type->data.enumeration.fields = nullptr; |
| 1954 | enum_type->data.enumeration.is_invalid = true; | 2279 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; |
| 1955 | enum_type->data.enumeration.zero_bits_loop_flag = false; | ||
| 1956 | enum_type->data.enumeration.zero_bits_known = true; | ||
| 1957 | return ErrorSemanticAnalyzeFail; | 2280 | return ErrorSemanticAnalyzeFail; |
| 1958 | } | 2281 | } |
| 1959 | 2282 | ||
| ... | @@ -1982,14 +2305,14 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { | ... | @@ -1982,14 +2305,14 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 1982 | if (decl_node->data.container_decl.init_arg_expr != nullptr) { | 2305 | if (decl_node->data.container_decl.init_arg_expr != nullptr) { |
| 1983 | ZigType *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr); | 2306 | ZigType *wanted_tag_int_type = analyze_type_expr(g, scope, decl_node->data.container_decl.init_arg_expr); |
| 1984 | if (type_is_invalid(wanted_tag_int_type)) { | 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 | } else if (wanted_tag_int_type->id != ZigTypeIdInt) { | 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 | add_node_error(g, decl_node->data.container_decl.init_arg_expr, | 2311 | add_node_error(g, decl_node->data.container_decl.init_arg_expr, |
| 1989 | buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name))); | 2312 | buf_sprintf("expected integer, found '%s'", buf_ptr(&wanted_tag_int_type->name))); |
| 1990 | } else if (enum_type->data.enumeration.layout == ContainerLayoutExtern && | 2313 | } else if (enum_type->data.enumeration.layout == ContainerLayoutExtern && |
| 1991 | !type_is_valid_extern_enum_tag(g, wanted_tag_int_type)) { | 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 | ErrorMsg *msg = add_node_error(g, decl_node->data.container_decl.init_arg_expr, | 2316 | ErrorMsg *msg = add_node_error(g, decl_node->data.container_decl.init_arg_expr, |
| 1994 | buf_sprintf("'%s' is not a valid tag type for an extern enum", | 2317 | buf_sprintf("'%s' is not a valid tag type for an extern enum", |
| 1995 | buf_ptr(&wanted_tag_int_type->name))); | 2318 | buf_ptr(&wanted_tag_int_type->name))); |
| ... | @@ -2022,6 +2345,11 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { | ... | @@ -2022,6 +2345,11 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2022 | buf_sprintf("structs and unions, not enums, support field types")); | 2345 | buf_sprintf("structs and unions, not enums, support field types")); |
| 2023 | add_error_note(g, msg, decl_node, | 2346 | add_error_note(g, msg, decl_node, |
| 2024 | buf_sprintf("consider 'union(enum)' here")); | 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 | auto field_entry = enum_type->data.enumeration.fields_by_name.put_unique(type_enum_field->name, type_enum_field); | 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,7 +2357,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2029 | ErrorMsg *msg = add_node_error(g, field_node, | 2357 | ErrorMsg *msg = add_node_error(g, field_node, |
| 2030 | buf_sprintf("duplicate enum field: '%s'", buf_ptr(type_enum_field->name))); | 2358 | buf_sprintf("duplicate enum field: '%s'", buf_ptr(type_enum_field->name))); |
| 2031 | add_error_note(g, msg, field_entry->value->decl_node, buf_sprintf("other field here")); | 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 | continue; | 2361 | continue; |
| 2034 | } | 2362 | } |
| 2035 | 2363 | ||
| ... | @@ -2037,9 +2365,10 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { | ... | @@ -2037,9 +2365,10 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2037 | 2365 | ||
| 2038 | if (tag_value != nullptr) { | 2366 | if (tag_value != nullptr) { |
| 2039 | // A user-specified value is available | 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 | if (type_is_invalid(result->type)) { | 2370 | if (type_is_invalid(result->type)) { |
| 2042 | enum_type->data.enumeration.is_invalid = true; | 2371 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; |
| 2043 | continue; | 2372 | continue; |
| 2044 | } | 2373 | } |
| 2045 | 2374 | ||
| ... | @@ -2060,7 +2389,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { | ... | @@ -2060,7 +2389,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2060 | if (!bigint_fits_in_bits(&type_enum_field->value, | 2389 | if (!bigint_fits_in_bits(&type_enum_field->value, |
| 2061 | tag_int_type->size_in_bits, | 2390 | tag_int_type->size_in_bits, |
| 2062 | tag_int_type->data.integral.is_signed)) { | 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 | Buf *val_buf = buf_alloc(); | 2394 | Buf *val_buf = buf_alloc(); |
| 2066 | bigint_append_buf(val_buf, &type_enum_field->value, 10); | 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,7 +2404,7 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2075 | // Make sure the value is unique | 2404 | // Make sure the value is unique |
| 2076 | auto entry = occupied_tag_values.put_unique(type_enum_field->value, field_node); | 2405 | auto entry = occupied_tag_values.put_unique(type_enum_field->value, field_node); |
| 2077 | if (entry != nullptr) { | 2406 | if (entry != nullptr) { |
| 2078 | enum_type->data.enumeration.is_invalid = true; | 2407 | enum_type->data.enumeration.resolve_status = ResolveStatusInvalid; |
| 2079 | 2408 | ||
| 2080 | Buf *val_buf = buf_alloc(); | 2409 | Buf *val_buf = buf_alloc(); |
| 2081 | bigint_append_buf(val_buf, &type_enum_field->value, 10); | 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,13 +2418,12 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) { |
| 2089 | last_enum_field = type_enum_field; | 2418 | last_enum_field = type_enum_field; |
| 2090 | } | 2419 | } |
| 2091 | 2420 | ||
| 2092 | enum_type->data.enumeration.zero_bits_loop_flag = false; | 2421 | if (enum_type->data.enumeration.resolve_status == ResolveStatusInvalid) |
| 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) | ||
| 2097 | return ErrorSemanticAnalyzeFail; | 2422 | return ErrorSemanticAnalyzeFail; |
| 2098 | 2423 | ||
| 2424 | enum_type->data.enumeration.resolve_loop_flag = false; | ||
| 2425 | enum_type->data.enumeration.resolve_status = ResolveStatusSizeKnown; | ||
| 2426 | |||
| 2099 | return ErrorNone; | 2427 | return ErrorNone; |
| 2100 | } | 2428 | } |
| 2101 | 2429 | ||
| ... | @@ -2112,16 +2440,17 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { | ... | @@ -2112,16 +2440,17 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { |
| 2112 | AstNode *decl_node = struct_type->data.structure.decl_node; | 2440 | AstNode *decl_node = struct_type->data.structure.decl_node; |
| 2113 | assert(decl_node->type == NodeTypeContainerDecl); | 2441 | assert(decl_node->type == NodeTypeContainerDecl); |
| 2114 | 2442 | ||
| 2115 | if (struct_type->data.structure.resolve_loop_flag) { | 2443 | if (struct_type->data.structure.resolve_loop_flag_zero_bits) { |
| 2116 | // TODO This is a problem. I believe it can be solved with lazy values. | 2444 | if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { |
| 2117 | struct_type->size_in_bits = SIZE_MAX; | 2445 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 2118 | struct_type->abi_size = SIZE_MAX; | 2446 | add_node_error(g, decl_node, |
| 2119 | struct_type->data.structure.resolve_status = ResolveStatusZeroBitsKnown; | 2447 | buf_sprintf("struct '%s' depends on itself", |
| 2120 | struct_type->data.structure.resolve_loop_flag = false; | 2448 | buf_ptr(&struct_type->name))); |
| 2121 | return ErrorNone; | 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 | assert(!struct_type->data.structure.fields); | 2455 | assert(!struct_type->data.structure.fields); |
| 2127 | size_t field_count = decl_node->data.container_decl.fields.length; | 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,58 +2482,60 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { |
| 2153 | return ErrorSemanticAnalyzeFail; | 2482 | return ErrorSemanticAnalyzeFail; |
| 2154 | } | 2483 | } |
| 2155 | 2484 | ||
| 2156 | ZigType *field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); | 2485 | ConstExprValue *field_type_val = analyze_const_value(g, scope, |
| 2157 | type_struct_field->type_entry = field_type; | 2486 | field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); |
| 2158 | if (type_is_invalid(field_type)) { | 2487 | if (type_is_invalid(field_type_val->type)) { |
| 2159 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | 2488 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 2160 | return ErrorSemanticAnalyzeFail; | 2489 | return ErrorSemanticAnalyzeFail; |
| 2161 | } | 2490 | } |
| 2491 | assert(field_type_val->special != ConstValSpecialRuntime); | ||
| 2492 | type_struct_field->type_val = field_type_val; | ||
| 2162 | if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) | 2493 | if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) |
| 2163 | return ErrorSemanticAnalyzeFail; | 2494 | return ErrorSemanticAnalyzeFail; |
| 2164 | 2495 | ||
| 2165 | if (struct_type->data.structure.layout == ContainerLayoutExtern && | 2496 | bool field_is_opaque_type; |
| 2166 | !type_allowed_in_extern(g, field_type)) | 2497 | if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_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))); | ||
| 2171 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | 2498 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 2172 | return ErrorSemanticAnalyzeFail; | 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 | 2501 | if (field_is_opaque_type) { | |
| 2180 | type_struct_field->src_index = i; | ||
| 2181 | type_struct_field->gen_index = SIZE_MAX; | ||
| 2182 | |||
| 2183 | if (field_type->id == ZigTypeIdOpaque) { | ||
| 2184 | add_node_error(g, field_node->data.struct_field.type, | 2502 | add_node_error(g, field_node->data.struct_field.type, |
| 2185 | buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs")); | 2503 | buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in structs")); |
| 2186 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | 2504 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 2187 | return ErrorSemanticAnalyzeFail; | 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 | case ReqCompTimeYes: | 2512 | case ReqCompTimeYes: |
| 2191 | struct_type->data.structure.requires_comptime = true; | 2513 | struct_type->data.structure.requires_comptime = true; |
| 2192 | break; | 2514 | break; |
| 2193 | case ReqCompTimeInvalid: | 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 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | 2520 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 2195 | return ErrorSemanticAnalyzeFail; | 2521 | return ErrorSemanticAnalyzeFail; |
| 2196 | case ReqCompTimeNo: | 2522 | case ReqCompTimeNo: |
| 2197 | break; | 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 | continue; | 2532 | continue; |
| 2202 | 2533 | ||
| 2203 | type_struct_field->gen_index = gen_field_index; | 2534 | type_struct_field->gen_index = gen_field_index; |
| 2204 | gen_field_index += 1; | 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 | struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index; | 2539 | struct_type->data.structure.gen_field_count = (uint32_t)gen_field_index; |
| 2209 | if (gen_field_index != 0) { | 2540 | if (gen_field_index != 0) { |
| 2210 | struct_type->abi_size = SIZE_MAX; | 2541 | struct_type->abi_size = SIZE_MAX; |
| ... | @@ -2234,17 +2565,16 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { | ... | @@ -2234,17 +2565,16 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { |
| 2234 | 2565 | ||
| 2235 | AstNode *decl_node = struct_type->data.structure.decl_node; | 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 | if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { | 2569 | if (struct_type->data.structure.resolve_status != ResolveStatusInvalid) { |
| 2239 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | 2570 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 2240 | ErrorMsg *msg = add_node_error(g, decl_node, | 2571 | add_node_error(g, decl_node, |
| 2241 | buf_sprintf("struct '%s' contains itself", buf_ptr(&struct_type->name))); | 2572 | buf_sprintf("struct '%s' depends on itself", buf_ptr(&struct_type->name))); |
| 2242 | emit_error_notes_for_ref_stack(g, msg); | ||
| 2243 | } | 2573 | } |
| 2244 | return ErrorSemanticAnalyzeFail; | 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 | assert(decl_node->type == NodeTypeContainerDecl); | 2578 | assert(decl_node->type == NodeTypeContainerDecl); |
| 2249 | 2579 | ||
| 2250 | size_t field_count = struct_type->data.structure.src_field_count; | 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,35 +2585,35 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) { |
| 2255 | if (field->gen_index == SIZE_MAX) | 2585 | if (field->gen_index == SIZE_MAX) |
| 2256 | continue; | 2586 | continue; |
| 2257 | 2587 | ||
| 2258 | size_t this_field_align; | 2588 | AstNode *align_expr = field->decl_node->data.struct_field.align_expr; |
| 2259 | if (packed) { | 2589 | if (align_expr != nullptr) { |
| 2260 | // TODO: https://github.com/ziglang/zig/issues/1512 | 2590 | if (!analyze_const_align(g, &struct_type->data.structure.decls_scope->base, align_expr, |
| 2261 | this_field_align = 1; | 2591 | &field->align)) |
| 2262 | // TODO If we have no type_entry for the field, we've already failed to | 2592 | { |
| 2263 | // compile the program correctly. This stage1 compiler needs a deeper | 2593 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; |
| 2264 | // reworking to make this correct, or we can ignore the problem | 2594 | return err; |
| 2265 | // and make sure it is fixed in stage2. This workaround is for when | 2595 | } |
| 2266 | // there is a false positive of a dependency loop, of alignment depending | 2596 | } else if (packed) { |
| 2267 | // on itself. When this false positive happens we assume a pointer-aligned | 2597 | field->align = 1; |
| 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; | ||
| 2272 | } else { | 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 | struct_type->data.structure.resolve_status = ResolveStatusInvalid; | 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 | 2611 | if (field->align > struct_type->abi_align) { |
| 2281 | if (this_field_align > struct_type->abi_align) { | 2612 | struct_type->abi_align = field->align; |
| 2282 | struct_type->abi_align = this_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 | if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) { | 2618 | if (struct_type->data.structure.resolve_status == ResolveStatusInvalid) { |
| 2289 | return ErrorSemanticAnalyzeFail; | 2619 | return ErrorSemanticAnalyzeFail; |
| ... | @@ -2304,23 +2634,21 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { | ... | @@ -2304,23 +2634,21 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 2304 | if (union_type->data.unionation.resolve_status >= ResolveStatusZeroBitsKnown) | 2634 | if (union_type->data.unionation.resolve_status >= ResolveStatusZeroBitsKnown) |
| 2305 | return ErrorNone; | 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 | AstNode *decl_node = union_type->data.unionation.decl_node; | 2637 | AstNode *decl_node = union_type->data.unionation.decl_node; |
| 2322 | assert(decl_node->type == NodeTypeContainerDecl); | 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 | assert(union_type->data.unionation.fields == nullptr); | 2652 | assert(union_type->data.unionation.fields == nullptr); |
| 2325 | uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; | 2653 | uint32_t field_count = (uint32_t)decl_node->data.container_decl.fields.length; |
| 2326 | if (field_count == 0) { | 2654 | if (field_count == 0) { |
| ... | @@ -2380,14 +2708,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { | ... | @@ -2380,14 +2708,13 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 2380 | tag_type->size_in_bits = tag_int_type->size_in_bits; | 2708 | tag_type->size_in_bits = tag_int_type->size_in_bits; |
| 2381 | 2709 | ||
| 2382 | tag_type->data.enumeration.tag_int_type = tag_int_type; | 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 | tag_type->data.enumeration.decl_node = decl_node; | 2712 | tag_type->data.enumeration.decl_node = decl_node; |
| 2385 | tag_type->data.enumeration.layout = ContainerLayoutAuto; | 2713 | tag_type->data.enumeration.layout = ContainerLayoutAuto; |
| 2386 | tag_type->data.enumeration.src_field_count = field_count; | 2714 | tag_type->data.enumeration.src_field_count = field_count; |
| 2387 | tag_type->data.enumeration.fields = allocate<TypeEnumField>(field_count); | 2715 | tag_type->data.enumeration.fields = allocate<TypeEnumField>(field_count); |
| 2388 | tag_type->data.enumeration.fields_by_name.init(field_count); | 2716 | tag_type->data.enumeration.fields_by_name.init(field_count); |
| 2389 | tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope; | 2717 | tag_type->data.enumeration.decls_scope = union_type->data.unionation.decls_scope; |
| 2390 | tag_type->data.enumeration.complete = true; | ||
| 2391 | } else if (enum_type_node != nullptr) { | 2718 | } else if (enum_type_node != nullptr) { |
| 2392 | ZigType *enum_type = analyze_type_expr(g, scope, enum_type_node); | 2719 | ZigType *enum_type = analyze_type_expr(g, scope, enum_type_node); |
| 2393 | if (type_is_invalid(enum_type)) { | 2720 | if (type_is_invalid(enum_type)) { |
| ... | @@ -2429,49 +2756,68 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { | ... | @@ -2429,49 +2756,68 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 2429 | return ErrorSemanticAnalyzeFail; | 2756 | return ErrorSemanticAnalyzeFail; |
| 2430 | } | 2757 | } |
| 2431 | 2758 | ||
| 2432 | ZigType *field_type; | 2759 | bool field_is_zero_bits; |
| 2433 | if (field_node->data.struct_field.type == nullptr) { | 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) { | 2761 | if (decl_node->data.container_decl.auto_enum || |
| 2435 | field_type = g->builtin_types.entry_void; | 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 | } else { | 2766 | } else { |
| 2437 | add_node_error(g, field_node, buf_sprintf("union field missing type")); | 2767 | add_node_error(g, field_node, buf_sprintf("union field missing type")); |
| 2438 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 2768 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 2439 | return ErrorSemanticAnalyzeFail; | 2769 | return ErrorSemanticAnalyzeFail; |
| 2440 | } | 2770 | } |
| 2441 | } else { | 2771 | } else { |
| 2442 | field_type = analyze_type_expr(g, scope, field_node->data.struct_field.type); | 2772 | ConstExprValue *field_type_val = analyze_const_value(g, scope, |
| 2443 | if ((err = type_resolve(g, field_type, ResolveStatusAlignmentKnown))) { | 2773 | field_node->data.struct_field.type, g->builtin_types.entry_type, nullptr, LazyOkNoUndef); |
| 2774 | if (type_is_invalid(field_type_val->type)) { | ||
| 2444 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 2775 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 2445 | return ErrorSemanticAnalyzeFail; | 2776 | return ErrorSemanticAnalyzeFail; |
| 2446 | } | 2777 | } |
| 2778 | assert(field_type_val->special != ConstValSpecialRuntime); | ||
| 2779 | union_field->type_val = field_type_val; | ||
| 2447 | if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) | 2780 | if (union_type->data.unionation.resolve_status == ResolveStatusInvalid) |
| 2448 | return ErrorSemanticAnalyzeFail; | 2781 | return ErrorSemanticAnalyzeFail; |
| 2449 | } | ||
| 2450 | union_field->type_entry = field_type; | ||
| 2451 | 2782 | ||
| 2452 | if (field_type->id == ZigTypeIdOpaque) { | 2783 | bool field_is_opaque_type; |
| 2453 | add_node_error(g, field_node->data.struct_field.type, | 2784 | if ((err = type_val_resolve_is_opaque_type(g, field_type_val, &field_is_opaque_type))) { |
| 2454 | buf_sprintf("opaque types have unknown size and therefore cannot be directly embedded in unions")); | 2785 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 2455 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 2786 | return ErrorSemanticAnalyzeFail; |
| 2456 | return ErrorSemanticAnalyzeFail; | 2787 | } |
| 2457 | } | 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)) { | 2796 | switch (type_val_resolve_requires_comptime(g, field_type_val)) { |
| 2460 | case ReqCompTimeInvalid: | 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 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 2812 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 2462 | return ErrorSemanticAnalyzeFail; | 2813 | return ErrorSemanticAnalyzeFail; |
| 2463 | case ReqCompTimeYes: | 2814 | } |
| 2464 | union_type->data.unionation.requires_comptime = true; | ||
| 2465 | break; | ||
| 2466 | case ReqCompTimeNo: | ||
| 2467 | break; | ||
| 2468 | } | 2815 | } |
| 2469 | 2816 | ||
| 2470 | if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) { | 2817 | if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) { |
| 2471 | ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value, | 2818 | ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value, |
| 2472 | buf_sprintf("non-enum union field assignment")); | 2819 | buf_create_from_str("untagged union field assignment")); |
| 2473 | add_error_note(g, msg, decl_node, | 2820 | add_error_note(g, msg, decl_node, buf_create_from_str("consider 'union(enum)' here")); |
| 2474 | buf_sprintf("consider 'union(enum)' here")); | ||
| 2475 | } | 2821 | } |
| 2476 | 2822 | ||
| 2477 | if (create_enum_type) { | 2823 | if (create_enum_type) { |
| ... | @@ -2489,7 +2835,8 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { | ... | @@ -2489,7 +2835,8 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 2489 | // In a second pass we will fill in the unspecified ones. | 2835 | // In a second pass we will fill in the unspecified ones. |
| 2490 | if (tag_value != nullptr) { | 2836 | if (tag_value != nullptr) { |
| 2491 | ZigType *tag_int_type = tag_type->data.enumeration.tag_int_type; | 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 | if (type_is_invalid(result->type)) { | 2840 | if (type_is_invalid(result->type)) { |
| 2494 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; | 2841 | union_type->data.unionation.resolve_status = ResolveStatusInvalid; |
| 2495 | return ErrorSemanticAnalyzeFail; | 2842 | return ErrorSemanticAnalyzeFail; |
| ... | @@ -2530,7 +2877,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { | ... | @@ -2530,7 +2877,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 2530 | } | 2877 | } |
| 2531 | assert(union_field->enum_field != nullptr); | 2878 | assert(union_field->enum_field != nullptr); |
| 2532 | 2879 | ||
| 2533 | if (!type_has_bits(field_type)) | 2880 | if (field_is_zero_bits) |
| 2534 | continue; | 2881 | continue; |
| 2535 | 2882 | ||
| 2536 | union_field->gen_index = gen_field_index; | 2883 | union_field->gen_index = gen_field_index; |
| ... | @@ -2607,7 +2954,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { | ... | @@ -2607,7 +2954,7 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) { |
| 2607 | return ErrorSemanticAnalyzeFail; | 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 | union_type->data.unionation.gen_field_count = gen_field_index; | 2959 | union_type->data.unionation.gen_field_count = gen_field_index; |
| 2613 | bool zero_bits = gen_field_index == 0 && (field_count < 2 || !src_have_tag); | 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,6 +3011,8 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node) { |
| 2664 | fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr : | 3011 | fn_entry->body_node = (proto_node->data.fn_proto.fn_def_node == nullptr) ? nullptr : |
| 2665 | proto_node->data.fn_proto.fn_def_node->data.fn_def.body; | 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 | return fn_entry; | 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,7 +3039,7 @@ void typecheck_panic_fn(CodeGen *g, TldFn *tld_fn, ZigFn *panic_fn) { |
| 2690 | fake_decl->data.symbol_expr.symbol = tld_fn->base.name; | 3039 | fake_decl->data.symbol_expr.symbol = tld_fn->base.name; |
| 2691 | 3040 | ||
| 2692 | // call this for the side effects of casting to panic_fn_type | 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 | ZigType *get_test_fn_type(CodeGen *g) { | 3045 | ZigType *get_test_fn_type(CodeGen *g) { |
| ... | @@ -2836,7 +3185,8 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { | ... | @@ -2836,7 +3185,8 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 2836 | static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) { | 3185 | static void resolve_decl_comptime(CodeGen *g, TldCompTime *tld_comptime) { |
| 2837 | assert(tld_comptime->base.source_node->type == NodeTypeCompTime); | 3186 | assert(tld_comptime->base.source_node->type == NodeTypeCompTime); |
| 2838 | AstNode *expr_node = tld_comptime->base.source_node->data.comptime_expr.expr; | 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 | static void add_top_level_decl(CodeGen *g, ScopeDecls *decls_scope, Tld *tld) { | 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,7 +3281,7 @@ void init_tld(Tld *tld, TldId id, Buf *name, VisibMod visib_mod, AstNode *source |
| 2931 | 3281 | ||
| 2932 | void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) { | 3282 | void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value) { |
| 2933 | Tld *tld = get_container_scope(g->compile_var_import)->decl_table.get(name); | 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 | assert(tld->id == TldIdVar); | 3285 | assert(tld->id == TldIdVar); |
| 2936 | TldVar *tld_var = (TldVar *)tld; | 3286 | TldVar *tld_var = (TldVar *)tld; |
| 2937 | tld_var->var->const_value = value; | 3287 | tld_var->var->const_value = value; |
| ... | @@ -3173,7 +3523,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf | ... | @@ -3173,7 +3523,7 @@ ZigVar *add_variable(CodeGen *g, AstNode *source_node, Scope *parent_scope, Buf |
| 3173 | return variable_entry; | 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 | AstNode *source_node = tld_var->base.source_node; | 3527 | AstNode *source_node = tld_var->base.source_node; |
| 3178 | AstNodeVariableDeclaration *var_decl = &source_node->data.variable_declaration; | 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,9 +3535,8 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { |
| 3185 | ZigType *explicit_type = nullptr; | 3535 | ZigType *explicit_type = nullptr; |
| 3186 | if (var_decl->type) { | 3536 | if (var_decl->type) { |
| 3187 | if (tld_var->analyzing_type) { | 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 | buf_sprintf("type of '%s' depends on itself", buf_ptr(tld_var->base.name))); | 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 | explicit_type = g->builtin_types.entry_invalid; | 3540 | explicit_type = g->builtin_types.entry_invalid; |
| 3192 | } else { | 3541 | } else { |
| 3193 | tld_var->analyzing_type = true; | 3542 | tld_var->analyzing_type = true; |
| ... | @@ -3205,7 +3554,8 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { | ... | @@ -3205,7 +3554,8 @@ static void resolve_decl_var(CodeGen *g, TldVar *tld_var) { |
| 3205 | if (explicit_type && explicit_type->id == ZigTypeIdInvalid) { | 3554 | if (explicit_type && explicit_type->id == ZigTypeIdInvalid) { |
| 3206 | implicit_type = explicit_type; | 3555 | implicit_type = explicit_type; |
| 3207 | } else if (var_decl->expr) { | 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 | assert(init_value); | 3559 | assert(init_value); |
| 3210 | implicit_type = init_value->type; | 3560 | implicit_type = init_value->type; |
| 3211 | 3561 | ||
| ... | @@ -3360,7 +3710,8 @@ static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, Sco | ... | @@ -3360,7 +3710,8 @@ static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, Sco |
| 3360 | using_namespace->base.resolution = TldResolutionResolving; | 3710 | using_namespace->base.resolution = TldResolutionResolving; |
| 3361 | assert(using_namespace->base.source_node->type == NodeTypeUsingNamespace); | 3711 | assert(using_namespace->base.source_node->type == NodeTypeUsingNamespace); |
| 3362 | ConstExprValue *result = analyze_const_value(g, &dest_decls_scope->base, | 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 | using_namespace->using_namespace_value = result; | 3715 | using_namespace->using_namespace_value = result; |
| 3365 | 3716 | ||
| 3366 | if (type_is_invalid(result->type)) { | 3717 | if (type_is_invalid(result->type)) { |
| ... | @@ -3380,51 +3731,61 @@ static void preview_use_decl(CodeGen *g, TldUsingNamespace *using_namespace, Sco | ... | @@ -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) { | 3734 | void resolve_top_level_decl(CodeGen *g, Tld *tld, AstNode *source_node, bool allow_lazy) { |
| 3384 | if (tld->resolution != TldResolutionUnresolved) | 3735 | bool want_resolve_lazy = tld->resolution == TldResolutionOkLazy && !allow_lazy; |
| 3736 | if (tld->resolution != TldResolutionUnresolved && !want_resolve_lazy) | ||
| 3385 | return; | 3737 | return; |
| 3386 | 3738 | ||
| 3387 | assert(tld->resolution != TldResolutionResolving); | ||
| 3388 | tld->resolution = TldResolutionResolving; | 3739 | tld->resolution = TldResolutionResolving; |
| 3389 | g->tld_ref_source_node_stack.append(source_node); | ||
| 3390 | 3740 | ||
| 3391 | switch (tld->id) { | 3741 | switch (tld->id) { |
| 3392 | case TldIdVar: | 3742 | case TldIdVar: { |
| 3393 | { | 3743 | TldVar *tld_var = (TldVar *)tld; |
| 3394 | TldVar *tld_var = (TldVar *)tld; | 3744 | if (want_resolve_lazy) { |
| 3395 | resolve_decl_var(g, tld_var); | 3745 | ir_resolve_lazy(g, source_node, tld_var->var->const_value); |
| 3396 | break; | 3746 | } else { |
| 3397 | } | 3747 | resolve_decl_var(g, tld_var, allow_lazy); |
| 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; | ||
| 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 | case TldIdUsingNamespace: { | 3773 | case TldIdUsingNamespace: { |
| 3417 | TldUsingNamespace *tld_using_namespace = (TldUsingNamespace *)tld; | 3774 | TldUsingNamespace *tld_using_namespace = (TldUsingNamespace *)tld; |
| 3418 | assert(tld_using_namespace->base.parent_scope->id == ScopeIdDecls); | 3775 | assert(tld_using_namespace->base.parent_scope->id == ScopeIdDecls); |
| 3419 | ScopeDecls *dest_decls_scope = (ScopeDecls *)tld_using_namespace->base.parent_scope; | 3776 | ScopeDecls *dest_decls_scope = (ScopeDecls *)tld_using_namespace->base.parent_scope; |
| 3420 | preview_use_decl(g, tld_using_namespace, dest_decls_scope); | 3777 | preview_use_decl(g, tld_using_namespace, dest_decls_scope); |
| 3421 | resolve_use_decl(g, tld_using_namespace, dest_decls_scope); | 3778 | resolve_use_decl(g, tld_using_namespace, dest_decls_scope); |
| 3779 | |||
| 3780 | tld->resolution = TldResolutionOk; | ||
| 3422 | break; | 3781 | break; |
| 3423 | } | 3782 | } |
| 3424 | } | 3783 | } |
| 3425 | 3784 | ||
| 3426 | tld->resolution = TldResolutionOk; | 3785 | if (g->trace_err != nullptr && source_node != nullptr && !source_node->already_traced_this_node) { |
| 3427 | g->tld_ref_source_node_stack.pop(); | 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 | Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name) { | 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,7 +3911,7 @@ TypeUnionField *find_union_field_by_tag(ZigType *type_entry, const BigInt *tag) |
| 3550 | } | 3911 | } |
| 3551 | 3912 | ||
| 3552 | TypeEnumField *find_enum_field_by_tag(ZigType *enum_type, const BigInt *tag) { | 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 | for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) { | 3915 | for (uint32_t i = 0; i < enum_type->data.enumeration.src_field_count; i += 1) { |
| 3555 | TypeEnumField *field = &enum_type->data.enumeration.fields[i]; | 3916 | TypeEnumField *field = &enum_type->data.enumeration.fields[i]; |
| 3556 | if (bigint_cmp(&field->value, tag) == CmpEQ) { | 3917 | if (bigint_cmp(&field->value, tag) == CmpEQ) { |
| ... | @@ -3619,43 +3980,6 @@ ZigType *container_ref_type(ZigType *type_entry) { | ... | @@ -3619,43 +3980,6 @@ ZigType *container_ref_type(ZigType *type_entry) { |
| 3619 | type_entry->data.pointer.child_type : type_entry; | 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 | ZigType *get_src_ptr_type(ZigType *type) { | 3983 | ZigType *get_src_ptr_type(ZigType *type) { |
| 3660 | if (type->id == ZigTypeIdPointer) return type; | 3984 | if (type->id == ZigTypeIdPointer) return type; |
| 3661 | if (type->id == ZigTypeIdFn) return type; | 3985 | if (type->id == ZigTypeIdFn) return type; |
| ... | @@ -3791,6 +4115,13 @@ static void resolve_async_fn_frame(CodeGen *g, ZigFn *fn) { | ... | @@ -3791,6 +4115,13 @@ static void resolve_async_fn_frame(CodeGen *g, ZigFn *fn) { |
| 3791 | ZigType *frame_type = get_fn_frame_type(g, fn); | 4115 | ZigType *frame_type = get_fn_frame_type(g, fn); |
| 3792 | Error err; | 4116 | Error err; |
| 3793 | if ((err = type_resolve(g, frame_type, ResolveStatusSizeKnown))) { | 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 | fn->anal_state = FnAnalStateInvalid; | 4125 | fn->anal_state = FnAnalStateInvalid; |
| 3795 | return; | 4126 | return; |
| 3796 | } | 4127 | } |
| ... | @@ -3906,7 +4237,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) { | ... | @@ -3906,7 +4237,7 @@ static void analyze_fn_ir(CodeGen *g, ZigFn *fn, AstNode *return_type_node) { |
| 3906 | &fn->analyzed_executable, fn_type_id->return_type, return_type_node); | 4237 | &fn->analyzed_executable, fn_type_id->return_type, return_type_node); |
| 3907 | fn->src_implicit_return_type = block_return_type; | 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 | assert(g->errors.length > 0); | 4241 | assert(g->errors.length > 0); |
| 3911 | fn->anal_state = FnAnalStateInvalid; | 4242 | fn->anal_state = FnAnalStateInvalid; |
| 3912 | return; | 4243 | return; |
| ... | @@ -3990,7 +4321,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { | ... | @@ -3990,7 +4321,7 @@ static void analyze_fn_body(CodeGen *g, ZigFn *fn_table_entry) { |
| 3990 | assert(!fn_type->data.fn.is_generic); | 4321 | assert(!fn_type->data.fn.is_generic); |
| 3991 | 4322 | ||
| 3992 | ir_gen_fn(g, fn_table_entry); | 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 | fn_table_entry->anal_state = FnAnalStateInvalid; | 4325 | fn_table_entry->anal_state = FnAnalStateInvalid; |
| 3995 | return; | 4326 | return; |
| 3996 | } | 4327 | } |
| ... | @@ -4128,12 +4459,14 @@ void semantic_analyze(CodeGen *g) { | ... | @@ -4128,12 +4459,14 @@ void semantic_analyze(CodeGen *g) { |
| 4128 | { | 4459 | { |
| 4129 | for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) { | 4460 | for (; g->resolve_queue_index < g->resolve_queue.length; g->resolve_queue_index += 1) { |
| 4130 | Tld *tld = g->resolve_queue.at(g->resolve_queue_index); | 4461 | Tld *tld = g->resolve_queue.at(g->resolve_queue_index); |
| 4462 | g->trace_err = nullptr; | ||
| 4131 | AstNode *source_node = nullptr; | 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 | for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { | 4467 | for (; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { |
| 4136 | ZigFn *fn_entry = g->fn_defs.at(g->fn_defs_index); | 4468 | ZigFn *fn_entry = g->fn_defs.at(g->fn_defs_index); |
| 4469 | g->trace_err = nullptr; | ||
| 4137 | analyze_fn_body(g, fn_entry); | 4470 | analyze_fn_body(g, fn_entry); |
| 4138 | } | 4471 | } |
| 4139 | } | 4472 | } |
| ... | @@ -4145,6 +4478,7 @@ void semantic_analyze(CodeGen *g) { | ... | @@ -4145,6 +4478,7 @@ void semantic_analyze(CodeGen *g) { |
| 4145 | // second pass over functions for detecting async | 4478 | // second pass over functions for detecting async |
| 4146 | for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { | 4479 | for (g->fn_defs_index = 0; g->fn_defs_index < g->fn_defs.length; g->fn_defs_index += 1) { |
| 4147 | ZigFn *fn = g->fn_defs.at(g->fn_defs_index); | 4480 | ZigFn *fn = g->fn_defs.at(g->fn_defs_index); |
| 4481 | g->trace_err = nullptr; | ||
| 4148 | analyze_fn_async(g, fn, true); | 4482 | analyze_fn_async(g, fn, true); |
| 4149 | if (fn_is_async(fn) && fn->non_async_node != nullptr) { | 4483 | if (fn_is_async(fn) && fn->non_async_node != nullptr) { |
| 4150 | ErrorMsg *msg = add_node_error(g, fn->proto_node, | 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,7 +5124,10 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { |
| 4790 | case ZigTypeIdStruct: | 5124 | case ZigTypeIdStruct: |
| 4791 | for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { | 5125 | for (size_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) { |
| 4792 | TypeStructField *field = &type_entry->data.structure.fields[i]; | 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 | case OnePossibleValueInvalid: | 5131 | case OnePossibleValueInvalid: |
| 4795 | return OnePossibleValueInvalid; | 5132 | return OnePossibleValueInvalid; |
| 4796 | case OnePossibleValueNo: | 5133 | case OnePossibleValueNo: |
| ... | @@ -4816,18 +5153,19 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { | ... | @@ -4816,18 +5153,19 @@ OnePossibleValue type_has_one_possible_value(CodeGen *g, ZigType *type_entry) { |
| 4816 | case ZigTypeIdUnion: | 5153 | case ZigTypeIdUnion: |
| 4817 | if (type_entry->data.unionation.src_field_count > 1) | 5154 | if (type_entry->data.unionation.src_field_count > 1) |
| 4818 | return OnePossibleValueNo; | 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 | zig_unreachable(); | 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 | Error err; | 5166 | Error err; |
| 4826 | if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown))) | 5167 | switch (ty->id) { |
| 4827 | return ReqCompTimeInvalid; | ||
| 4828 | switch (type_entry->id) { | ||
| 4829 | case ZigTypeIdInvalid: | 5168 | case ZigTypeIdInvalid: |
| 4830 | case ZigTypeIdOpaque: | ||
| 4831 | zig_unreachable(); | 5169 | zig_unreachable(); |
| 4832 | case ZigTypeIdComptimeFloat: | 5170 | case ZigTypeIdComptimeFloat: |
| 4833 | case ZigTypeIdComptimeInt: | 5171 | case ZigTypeIdComptimeInt: |
| ... | @@ -4839,23 +5177,36 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { | ... | @@ -4839,23 +5177,36 @@ ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) { |
| 4839 | case ZigTypeIdArgTuple: | 5177 | case ZigTypeIdArgTuple: |
| 4840 | return ReqCompTimeYes; | 5178 | return ReqCompTimeYes; |
| 4841 | case ZigTypeIdArray: | 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 | case ZigTypeIdStruct: | 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 | case ZigTypeIdUnion: | 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 | case ZigTypeIdOptional: | 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 | case ZigTypeIdErrorUnion: | 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 | case ZigTypeIdPointer: | 5201 | case ZigTypeIdPointer: |
| 4852 | if (type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) { | 5202 | if (ty->data.pointer.child_type->id == ZigTypeIdOpaque) { |
| 4853 | return ReqCompTimeNo; | 5203 | return ReqCompTimeNo; |
| 4854 | } else { | 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 | case ZigTypeIdFn: | 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 | case ZigTypeIdEnum: | 5210 | case ZigTypeIdEnum: |
| 4860 | case ZigTypeIdErrorSet: | 5211 | case ZigTypeIdErrorSet: |
| 4861 | case ZigTypeIdBool: | 5212 | case ZigTypeIdBool: |
| ... | @@ -5143,34 +5494,6 @@ ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_ | ... | @@ -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 | ConstExprValue *create_const_vals(size_t count) { | 5497 | ConstExprValue *create_const_vals(size_t count) { |
| 5175 | ConstGlobalRefs *global_refs = allocate<ConstGlobalRefs>(count); | 5498 | ConstGlobalRefs *global_refs = allocate<ConstGlobalRefs>(count); |
| 5176 | ConstExprValue *vals = allocate<ConstExprValue>(count); | 5499 | ConstExprValue *vals = allocate<ConstExprValue>(count); |
| ... | @@ -5180,10 +5503,6 @@ ConstExprValue *create_const_vals(size_t count) { | ... | @@ -5180,10 +5503,6 @@ ConstExprValue *create_const_vals(size_t count) { |
| 5180 | return vals; | 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 | static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) { | 5506 | static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) { |
| 5188 | if (orig_fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) | 5507 | if (orig_fn_type->data.fn.fn_type_id.cc == CallingConventionAsync) |
| 5189 | return orig_fn_type; | 5508 | return orig_fn_type; |
| ... | @@ -5197,27 +5516,6 @@ static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) { | ... | @@ -5197,27 +5516,6 @@ static ZigType *get_async_fn_type(CodeGen *g, ZigType *orig_fn_type) { |
| 5197 | return fn_type; | 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 | static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { | 5519 | static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5222 | Error err; | 5520 | Error err; |
| 5223 | 5521 | ||
| ... | @@ -5229,14 +5527,8 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { | ... | @@ -5229,14 +5527,8 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5229 | 5527 | ||
| 5230 | if (frame_type->data.frame.resolve_loop_type != nullptr) { | 5528 | if (frame_type->data.frame.resolve_loop_type != nullptr) { |
| 5231 | if (!frame_type->data.frame.reported_loop_err) { | 5529 | if (!frame_type->data.frame.reported_loop_err) { |
| 5232 | frame_type->data.frame.reported_loop_err = true; | 5530 | add_node_error(g, fn->proto_node, |
| 5233 | ErrorMsg *msg = add_node_error(g, fn->proto_node, | ||
| 5234 | buf_sprintf("'%s' depends on itself", buf_ptr(&frame_type->name))); | 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 | return ErrorSemanticAnalyzeFail; | 5533 | return ErrorSemanticAnalyzeFail; |
| 5242 | } | 5534 | } |
| ... | @@ -5252,11 +5544,9 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { | ... | @@ -5252,11 +5544,9 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5252 | return ErrorSemanticAnalyzeFail; | 5544 | return ErrorSemanticAnalyzeFail; |
| 5253 | break; | 5545 | break; |
| 5254 | case FnAnalStateProbing: { | 5546 | case FnAnalStateProbing: { |
| 5255 | ErrorMsg *msg = add_node_error(g, fn->proto_node, | 5547 | add_node_error(g, fn->proto_node, |
| 5256 | buf_sprintf("cannot resolve '%s': function not fully analyzed yet", | 5548 | buf_sprintf("cannot resolve '%s': function not fully analyzed yet", |
| 5257 | buf_ptr(&frame_type->name))); | 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 | return ErrorSemanticAnalyzeFail; | 5550 | return ErrorSemanticAnalyzeFail; |
| 5261 | } | 5551 | } |
| 5262 | } | 5552 | } |
| ... | @@ -5327,10 +5617,8 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { | ... | @@ -5327,10 +5617,8 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5327 | if (callee->anal_state == FnAnalStateProbing) { | 5617 | if (callee->anal_state == FnAnalStateProbing) { |
| 5328 | ErrorMsg *msg = add_node_error(g, fn->proto_node, | 5618 | ErrorMsg *msg = add_node_error(g, fn->proto_node, |
| 5329 | buf_sprintf("unable to determine async function frame of '%s'", buf_ptr(&fn->symbol_name))); | 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 | buf_sprintf("analysis of function '%s' depends on the frame", buf_ptr(&callee->symbol_name))); | 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 | return ErrorSemanticAnalyzeFail; | 5622 | return ErrorSemanticAnalyzeFail; |
| 5335 | } | 5623 | } |
| 5336 | 5624 | ||
| ... | @@ -5442,6 +5730,37 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { | ... | @@ -5442,6 +5730,37 @@ static Error resolve_async_frame(CodeGen *g, ZigType *frame_type) { |
| 5442 | return ErrorNone; | 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 | Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { | 5764 | Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { |
| 5446 | if (type_is_invalid(ty)) | 5765 | if (type_is_invalid(ty)) |
| 5447 | return ErrorSemanticAnalyzeFail; | 5766 | return ErrorSemanticAnalyzeFail; |
| ... | @@ -5451,36 +5770,48 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { | ... | @@ -5451,36 +5770,48 @@ Error type_resolve(CodeGen *g, ZigType *ty, ResolveStatus status) { |
| 5451 | case ResolveStatusInvalid: | 5770 | case ResolveStatusInvalid: |
| 5452 | zig_unreachable(); | 5771 | zig_unreachable(); |
| 5453 | case ResolveStatusZeroBitsKnown: | 5772 | case ResolveStatusZeroBitsKnown: |
| 5454 | if (ty->id == ZigTypeIdStruct) { | 5773 | switch (ty->id) { |
| 5455 | return resolve_struct_zero_bits(g, ty); | 5774 | case ZigTypeIdStruct: |
| 5456 | } else if (ty->id == ZigTypeIdEnum) { | 5775 | return resolve_struct_zero_bits(g, ty); |
| 5457 | return resolve_enum_zero_bits(g, ty); | 5776 | case ZigTypeIdEnum: |
| 5458 | } else if (ty->id == ZigTypeIdUnion) { | 5777 | return resolve_enum_zero_bits(g, ty); |
| 5459 | return resolve_union_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 | case ResolveStatusAlignmentKnown: | 5785 | case ResolveStatusAlignmentKnown: |
| 5463 | if (ty->id == ZigTypeIdStruct) { | 5786 | switch (ty->id) { |
| 5464 | return resolve_struct_alignment(g, ty); | 5787 | case ZigTypeIdStruct: |
| 5465 | } else if (ty->id == ZigTypeIdEnum) { | 5788 | return resolve_struct_alignment(g, ty); |
| 5466 | return resolve_enum_zero_bits(g, ty); | 5789 | case ZigTypeIdEnum: |
| 5467 | } else if (ty->id == ZigTypeIdUnion) { | 5790 | return resolve_enum_zero_bits(g, ty); |
| 5468 | return resolve_union_alignment(g, ty); | 5791 | case ZigTypeIdUnion: |
| 5469 | } else if (ty->id == ZigTypeIdFnFrame) { | 5792 | return resolve_union_alignment(g, ty); |
| 5470 | return resolve_async_frame(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 | case ResolveStatusSizeKnown: | 5800 | case ResolveStatusSizeKnown: |
| 5474 | if (ty->id == ZigTypeIdStruct) { | 5801 | switch (ty->id) { |
| 5475 | return resolve_struct_type(g, ty); | 5802 | case ZigTypeIdStruct: |
| 5476 | } else if (ty->id == ZigTypeIdEnum) { | 5803 | return resolve_struct_type(g, ty); |
| 5477 | return resolve_enum_zero_bits(g, ty); | 5804 | case ZigTypeIdEnum: |
| 5478 | } else if (ty->id == ZigTypeIdUnion) { | 5805 | return resolve_enum_zero_bits(g, ty); |
| 5479 | return resolve_union_type(g, ty); | 5806 | case ZigTypeIdUnion: |
| 5480 | } else if (ty->id == ZigTypeIdFnFrame) { | 5807 | return resolve_union_type(g, ty); |
| 5481 | return resolve_async_frame(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 | case ResolveStatusLLVMFwdDecl: | 5815 | case ResolveStatusLLVMFwdDecl: |
| 5485 | case ResolveStatusLLVMFull: | 5816 | case ResolveStatusLLVMFull: |
| 5486 | resolve_llvm_types(g, ty, status); | 5817 | resolve_llvm_types(g, ty, status); |
| ... | @@ -5855,6 +6186,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { | ... | @@ -5855,6 +6186,9 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 5855 | case ConstValSpecialRuntime: | 6186 | case ConstValSpecialRuntime: |
| 5856 | buf_appendf(buf, "(runtime value)"); | 6187 | buf_appendf(buf, "(runtime value)"); |
| 5857 | return; | 6188 | return; |
| 6189 | case ConstValSpecialLazy: | ||
| 6190 | buf_appendf(buf, "(lazy value)"); | ||
| 6191 | return; | ||
| 5858 | case ConstValSpecialUndef: | 6192 | case ConstValSpecialUndef: |
| 5859 | buf_appendf(buf, "undefined"); | 6193 | buf_appendf(buf, "undefined"); |
| 5860 | return; | 6194 | return; |
| ... | @@ -5976,7 +6310,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { | ... | @@ -5976,7 +6310,7 @@ void render_const_value(CodeGen *g, Buf *buf, ConstExprValue *const_val) { |
| 5976 | { | 6310 | { |
| 5977 | if (is_slice(type_entry)) { | 6311 | if (is_slice(type_entry)) { |
| 5978 | ConstExprValue *len_val = &const_val->data.x_struct.fields[slice_len_index]; | 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 | ConstExprValue *ptr_val = &const_val->data.x_struct.fields[slice_ptr_index]; | 6315 | ConstExprValue *ptr_val = &const_val->data.x_struct.fields[slice_ptr_index]; |
| 5982 | if (ptr_val->special == ConstValSpecialUndef) { | 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,12 +6385,12 @@ ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits) { |
| 6051 | entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type); | 6385 | entry->abi_size = LLVMABISizeOfType(g->target_data_ref, entry->llvm_type); |
| 6052 | entry->abi_align = LLVMABIAlignmentOfType(g->target_data_ref, entry->llvm_type); | 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 | // Override the incorrect alignment reported by LLVM. Clang does this as well. | 6389 | // Override the incorrect alignment reported by LLVM. Clang does this as well. |
| 6056 | // On x86_64 there are some instructions like CMPXCHG16B which require this. | 6390 | // On x86_64 there are some instructions like CMPXCHG16B which require this. |
| 6057 | // On all targets, integers 128 bits and above have ABI alignment of 16. | 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 | // See: https://github.com/ziglang/zig/issues/2987 | 6393 | // See: https://github.com/ziglang/zig/issues/2987 |
| 6059 | assert(entry->abi_align == 8); // if this trips we can remove the workaround | ||
| 6060 | entry->abi_align = 16; | 6394 | entry->abi_align = 16; |
| 6061 | } | 6395 | } |
| 6062 | } | 6396 | } |
| ... | @@ -6229,6 +6563,40 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { | ... | @@ -6229,6 +6563,40 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) { |
| 6229 | zig_unreachable(); | 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 | // Canonicalize the array value as ConstArraySpecialNone | 6600 | // Canonicalize the array value as ConstArraySpecialNone |
| 6233 | void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { | 6601 | void expand_undef_array(CodeGen *g, ConstExprValue *const_val) { |
| 6234 | size_t elem_count; | 6602 | size_t elem_count; |
| ... | @@ -6492,7 +6860,7 @@ bool type_ptr_eql(const ZigType *a, const ZigType *b) { | ... | @@ -6492,7 +6860,7 @@ bool type_ptr_eql(const ZigType *a, const ZigType *b) { |
| 6492 | 6860 | ||
| 6493 | ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { | 6861 | ConstExprValue *get_builtin_value(CodeGen *codegen, const char *name) { |
| 6494 | Tld *tld = get_container_scope(codegen->compile_var_import)->decl_table.get(buf_create_from_str(name)); | 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 | assert(tld->id == TldIdVar); | 6864 | assert(tld->id == TldIdVar); |
| 6497 | TldVar *tld_var = (TldVar *)tld; | 6865 | TldVar *tld_var = (TldVar *)tld; |
| 6498 | ConstExprValue *var_value = tld_var->var->const_value; | 6866 | ConstExprValue *var_value = tld_var->var->const_value; |
| ... | @@ -6707,19 +7075,6 @@ bool ptr_allows_addr_zero(ZigType *ptr_type) { | ... | @@ -6707,19 +7075,6 @@ bool ptr_allows_addr_zero(ZigType *ptr_type) { |
| 6707 | return false; | 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 | Buf *type_bare_name(ZigType *type_entry) { | 7078 | Buf *type_bare_name(ZigType *type_entry) { |
| 6724 | if (is_slice(type_entry)) { | 7079 | if (is_slice(type_entry)) { |
| 6725 | return &type_entry->name; | 7080 | return &type_entry->name; |
| ... | @@ -7122,10 +7477,9 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS | ... | @@ -7122,10 +7477,9 @@ static void resolve_llvm_types_struct(CodeGen *g, ZigType *struct_type, ResolveS |
| 7122 | struct_type->data.structure.resolve_status = ResolveStatusLLVMFull; | 7477 | struct_type->data.structure.resolve_status = ResolveStatusLLVMFull; |
| 7123 | } | 7478 | } |
| 7124 | 7479 | ||
| 7125 | static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type) { | 7480 | static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type, ResolveStatus wanted_resolve_status) { |
| 7126 | assert(!enum_type->data.enumeration.is_invalid); | 7481 | assert(enum_type->data.enumeration.resolve_status >= ResolveStatusSizeKnown); |
| 7127 | assert(enum_type->data.enumeration.complete); | 7482 | if (enum_type->data.enumeration.resolve_status >= wanted_resolve_status) return; |
| 7128 | if (enum_type->llvm_di_type != nullptr) return; | ||
| 7129 | 7483 | ||
| 7130 | Scope *scope = &enum_type->data.enumeration.decls_scope->base; | 7484 | Scope *scope = &enum_type->data.enumeration.decls_scope->base; |
| 7131 | ZigType *import = get_scope_import(scope); | 7485 | ZigType *import = get_scope_import(scope); |
| ... | @@ -7146,6 +7500,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type) { | ... | @@ -7146,6 +7500,7 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type) { |
| 7146 | debug_align_in_bits, | 7500 | debug_align_in_bits, |
| 7147 | ZigLLVM_DIFlags_Zero, | 7501 | ZigLLVM_DIFlags_Zero, |
| 7148 | nullptr, di_element_types, (int)debug_field_count, 0, nullptr, ""); | 7502 | nullptr, di_element_types, (int)debug_field_count, 0, nullptr, ""); |
| 7503 | enum_type->data.enumeration.resolve_status = ResolveStatusLLVMFull; | ||
| 7149 | return; | 7504 | return; |
| 7150 | } | 7505 | } |
| 7151 | 7506 | ||
| ... | @@ -7178,14 +7533,16 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type) { | ... | @@ -7178,14 +7533,16 @@ static void resolve_llvm_types_enum(CodeGen *g, ZigType *enum_type) { |
| 7178 | get_llvm_di_type(g, tag_int_type), ""); | 7533 | get_llvm_di_type(g, tag_int_type), ""); |
| 7179 | 7534 | ||
| 7180 | enum_type->llvm_di_type = tag_di_type; | 7535 | enum_type->llvm_di_type = tag_di_type; |
| 7536 | enum_type->data.enumeration.resolve_status = ResolveStatusLLVMFull; | ||
| 7181 | } | 7537 | } |
| 7182 | 7538 | ||
| 7183 | static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveStatus wanted_resolve_status) { | 7539 | static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveStatus wanted_resolve_status) { |
| 7184 | if (union_type->data.unionation.resolve_status >= wanted_resolve_status) return; | 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 | ZigType *tag_type = union_type->data.unionation.tag_type; | 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 | union_type->llvm_type = get_llvm_type(g, tag_type); | 7546 | union_type->llvm_type = get_llvm_type(g, tag_type); |
| 7190 | union_type->llvm_di_type = get_llvm_di_type(g, tag_type); | 7547 | union_type->llvm_di_type = get_llvm_di_type(g, tag_type); |
| 7191 | union_type->data.unionation.resolve_status = ResolveStatusLLVMFull; | 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,7 +7566,6 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 7209 | if (ResolveStatusLLVMFwdDecl >= wanted_resolve_status) return; | 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 | ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(gen_field_count); | 7569 | ZigLLVMDIType **union_inner_di_types = allocate<ZigLLVMDIType*>(gen_field_count); |
| 7214 | uint32_t field_count = union_type->data.unionation.src_field_count; | 7570 | uint32_t field_count = union_type->data.unionation.src_field_count; |
| 7215 | for (uint32_t i = 0; i < field_count; i += 1) { | 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,17 +7592,17 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 7236 | if (tag_type == nullptr || !type_has_bits(tag_type)) { | 7592 | if (tag_type == nullptr || !type_has_bits(tag_type)) { |
| 7237 | assert(most_aligned_union_member != nullptr); | 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 | if (padding_bytes > 0) { | 7596 | if (padding_bytes > 0) { |
| 7241 | ZigType *u8_type = get_int_type(g, false, 8); | 7597 | ZigType *u8_type = get_int_type(g, false, 8); |
| 7242 | ZigType *padding_array = get_array_type(g, u8_type, padding_bytes); | 7598 | ZigType *padding_array = get_array_type(g, u8_type, padding_bytes); |
| 7243 | LLVMTypeRef union_element_types[] = { | 7599 | LLVMTypeRef union_element_types[] = { |
| 7244 | most_aligned_union_member->llvm_type, | 7600 | most_aligned_union_member->type_entry->llvm_type, |
| 7245 | get_llvm_type(g, padding_array), | 7601 | get_llvm_type(g, padding_array), |
| 7246 | }; | 7602 | }; |
| 7247 | LLVMStructSetBody(union_type->llvm_type, union_element_types, 2, false); | 7603 | LLVMStructSetBody(union_type->llvm_type, union_element_types, 2, false); |
| 7248 | } else { | 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 | union_type->data.unionation.union_llvm_type = union_type->llvm_type; | 7607 | union_type->data.unionation.union_llvm_type = union_type->llvm_type; |
| 7252 | union_type->data.unionation.gen_tag_index = SIZE_MAX; | 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,7 +7613,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 7257 | ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&union_type->name), | 7613 | ZigLLVMFileToScope(import->data.structure.root_struct->di_file), buf_ptr(&union_type->name), |
| 7258 | import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), | 7614 | import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), |
| 7259 | union_type->data.unionation.union_abi_size * 8, | 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 | ZigLLVM_DIFlags_Zero, union_inner_di_types, | 7617 | ZigLLVM_DIFlags_Zero, union_inner_di_types, |
| 7262 | gen_field_count, 0, ""); | 7618 | gen_field_count, 0, ""); |
| 7263 | 7619 | ||
| ... | @@ -7268,14 +7624,14 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta | ... | @@ -7268,14 +7624,14 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 7268 | } | 7624 | } |
| 7269 | 7625 | ||
| 7270 | LLVMTypeRef union_type_ref; | 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 | if (padding_bytes == 0) { | 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 | } else { | 7630 | } else { |
| 7275 | ZigType *u8_type = get_int_type(g, false, 8); | 7631 | ZigType *u8_type = get_int_type(g, false, 8); |
| 7276 | ZigType *padding_array = get_array_type(g, u8_type, padding_bytes); | 7632 | ZigType *padding_array = get_array_type(g, u8_type, padding_bytes); |
| 7277 | LLVMTypeRef union_element_types[] = { | 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 | get_llvm_type(g, padding_array), | 7635 | get_llvm_type(g, padding_array), |
| 7280 | }; | 7636 | }; |
| 7281 | union_type_ref = LLVMStructType(union_element_types, 2, false); | 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,7 +7647,7 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 7291 | ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, | 7647 | ZigLLVMDIType *union_di_type = ZigLLVMCreateDebugUnionType(g->dbuilder, |
| 7292 | ZigLLVMTypeToScope(union_type->llvm_di_type), "AnonUnion", | 7648 | ZigLLVMTypeToScope(union_type->llvm_di_type), "AnonUnion", |
| 7293 | import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), | 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 | ZigLLVM_DIFlags_Zero, union_inner_di_types, gen_field_count, 0, ""); | 7651 | ZigLLVM_DIFlags_Zero, union_inner_di_types, gen_field_count, 0, ""); |
| 7296 | 7652 | ||
| 7297 | uint64_t union_offset_in_bits = 8*LLVMOffsetOfElement(g->target_data_ref, union_type->llvm_type, | 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,8 +7658,8 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 7302 | ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, | 7658 | ZigLLVMDIType *union_member_di_type = ZigLLVMCreateDebugMemberType(g->dbuilder, |
| 7303 | ZigLLVMTypeToScope(union_type->llvm_di_type), "payload", | 7659 | ZigLLVMTypeToScope(union_type->llvm_di_type), "payload", |
| 7304 | import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), | 7660 | import->data.structure.root_struct->di_file, (unsigned)(decl_node->line + 1), |
| 7305 | most_aligned_union_member->size_in_bits, | 7661 | most_aligned_union_member->type_entry->size_in_bits, |
| 7306 | 8*most_aligned_union_member->abi_align, | 7662 | 8*most_aligned_union_member->align, |
| 7307 | union_offset_in_bits, | 7663 | union_offset_in_bits, |
| 7308 | ZigLLVM_DIFlags_Zero, union_di_type); | 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,6 +7696,9 @@ static void resolve_llvm_types_union(CodeGen *g, ZigType *union_type, ResolveSta |
| 7340 | static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { | 7696 | static void resolve_llvm_types_pointer(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { |
| 7341 | if (type->llvm_di_type != nullptr) return; | 7697 | if (type->llvm_di_type != nullptr) return; |
| 7342 | 7698 | ||
| 7699 | if (resolve_pointer_zero_bits(g, type) != ErrorNone) | ||
| 7700 | zig_unreachable(); | ||
| 7701 | |||
| 7343 | if (!type_has_bits(type)) { | 7702 | if (!type_has_bits(type)) { |
| 7344 | type->llvm_type = g->builtin_types.entry_void->llvm_type; | 7703 | type->llvm_type = g->builtin_types.entry_void->llvm_type; |
| 7345 | type->llvm_di_type = g->builtin_types.entry_void->llvm_di_type; | 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,8 +7765,11 @@ static void resolve_llvm_types_integer(CodeGen *g, ZigType *type) { |
| 7406 | type->llvm_type = LLVMIntType(type->size_in_bits); | 7765 | type->llvm_type = LLVMIntType(type->size_in_bits); |
| 7407 | } | 7766 | } |
| 7408 | 7767 | ||
| 7409 | static void resolve_llvm_types_optional(CodeGen *g, ZigType *type) { | 7768 | static void resolve_llvm_types_optional(CodeGen *g, ZigType *type, ResolveStatus wanted_resolve_status) { |
| 7410 | if (type->llvm_di_type != nullptr) return; | 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 | LLVMTypeRef bool_llvm_type = get_llvm_type(g, g->builtin_types.entry_bool); | 7774 | LLVMTypeRef bool_llvm_type = get_llvm_type(g, g->builtin_types.entry_bool); |
| 7413 | ZigLLVMDIType *bool_llvm_di_type = get_llvm_di_type(g, g->builtin_types.entry_bool); | 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,30 +7778,41 @@ static void resolve_llvm_types_optional(CodeGen *g, ZigType *type) { |
| 7416 | if (!type_has_bits(child_type)) { | 7778 | if (!type_has_bits(child_type)) { |
| 7417 | type->llvm_type = bool_llvm_type; | 7779 | type->llvm_type = bool_llvm_type; |
| 7418 | type->llvm_di_type = bool_llvm_di_type; | 7780 | type->llvm_di_type = bool_llvm_di_type; |
| 7781 | type->data.maybe.resolve_status = ResolveStatusLLVMFull; | ||
| 7419 | return; | 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 | if (type_is_nonnull_ptr(child_type) || child_type->id == ZigTypeIdErrorSet) { | 7785 | if (type_is_nonnull_ptr(child_type) || child_type->id == ZigTypeIdErrorSet) { |
| 7426 | type->llvm_type = child_llvm_type; | 7786 | type->llvm_type = get_llvm_type(g, child_type); |
| 7427 | type->llvm_di_type = child_llvm_di_type; | 7787 | type->llvm_di_type = get_llvm_di_type(g, child_type); |
| 7788 | type->data.maybe.resolve_status = ResolveStatusLLVMFull; | ||
| 7428 | return; | 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 | LLVMTypeRef elem_types[] = { | 7811 | LLVMTypeRef elem_types[] = { |
| 7432 | get_llvm_type(g, child_type), | 7812 | get_llvm_type(g, child_type), |
| 7433 | LLVMInt1Type(), | 7813 | LLVMInt1Type(), |
| 7434 | }; | 7814 | }; |
| 7435 | type->llvm_type = LLVMStructType(elem_types, 2, false); | 7815 | LLVMStructSetBody(type->llvm_type, 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); | ||
| 7443 | 7816 | ||
| 7444 | uint64_t val_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, child_llvm_type); | 7817 | uint64_t val_debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, child_llvm_type); |
| 7445 | uint64_t val_debug_align_in_bits = 8*LLVMABISizeOfType(g->target_data_ref, child_llvm_type); | 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,6 +7847,7 @@ static void resolve_llvm_types_optional(CodeGen *g, ZigType *type) { |
| 7474 | 7847 | ||
| 7475 | ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type); | 7848 | ZigLLVMReplaceTemporary(g->dbuilder, type->llvm_di_type, replacement_di_type); |
| 7476 | type->llvm_di_type = replacement_di_type; | 7849 | type->llvm_di_type = replacement_di_type; |
| 7850 | type->data.maybe.resolve_status = ResolveStatusLLVMFull; | ||
| 7477 | } | 7851 | } |
| 7478 | 7852 | ||
| 7479 | static void resolve_llvm_types_error_union(CodeGen *g, ZigType *type) { | 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,7 +8283,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r |
| 7909 | else | 8283 | else |
| 7910 | return resolve_llvm_types_struct(g, type, wanted_resolve_status, nullptr); | 8284 | return resolve_llvm_types_struct(g, type, wanted_resolve_status, nullptr); |
| 7911 | case ZigTypeIdEnum: | 8285 | case ZigTypeIdEnum: |
| 7912 | return resolve_llvm_types_enum(g, type); | 8286 | return resolve_llvm_types_enum(g, type, wanted_resolve_status); |
| 7913 | case ZigTypeIdUnion: | 8287 | case ZigTypeIdUnion: |
| 7914 | return resolve_llvm_types_union(g, type, wanted_resolve_status); | 8288 | return resolve_llvm_types_union(g, type, wanted_resolve_status); |
| 7915 | case ZigTypeIdPointer: | 8289 | case ZigTypeIdPointer: |
| ... | @@ -7917,7 +8291,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r | ... | @@ -7917,7 +8291,7 @@ static void resolve_llvm_types(CodeGen *g, ZigType *type, ResolveStatus wanted_r |
| 7917 | case ZigTypeIdInt: | 8291 | case ZigTypeIdInt: |
| 7918 | return resolve_llvm_types_integer(g, type); | 8292 | return resolve_llvm_types_integer(g, type); |
| 7919 | case ZigTypeIdOptional: | 8293 | case ZigTypeIdOptional: |
| 7920 | return resolve_llvm_types_optional(g, type); | 8294 | return resolve_llvm_types_optional(g, type, wanted_resolve_status); |
| 7921 | case ZigTypeIdErrorUnion: | 8295 | case ZigTypeIdErrorUnion: |
| 7922 | return resolve_llvm_types_error_union(g, type); | 8296 | return resolve_llvm_types_error_union(g, type); |
| 7923 | case ZigTypeIdArray: | 8297 | case ZigTypeIdArray: |
src/analyze.hpp+9-8| ... | @@ -11,10 +11,9 @@ | ... | @@ -11,10 +11,9 @@ |
| 11 | #include "all_types.hpp" | 11 | #include "all_types.hpp" |
| 12 | 12 | ||
| 13 | void semantic_analyze(CodeGen *g); | 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 | ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg); | 15 | ErrorMsg *add_token_error(CodeGen *g, ZigType *owner, Token *token, Buf *msg); |
| 16 | ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, const AstNode *node, Buf *msg); | 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 | ZigType *new_type_table_entry(ZigTypeId id); | 17 | ZigType *new_type_table_entry(ZigTypeId id); |
| 19 | ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn); | 18 | ZigType *get_fn_frame_type(CodeGen *g, ZigFn *fn); |
| 20 | ZigType *get_pointer_to_type(CodeGen *g, ZigType *child_type, bool is_const); | 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,7 +58,7 @@ ZigType *add_source_file(CodeGen *g, ZigPackage *package, Buf *abs_full_path, Bu |
| 59 | ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name, ScopeFnDef **crossed_fndef_scope); | 58 | ZigVar *find_variable(CodeGen *g, Scope *orig_context, Buf *name, ScopeFnDef **crossed_fndef_scope); |
| 60 | Tld *find_decl(CodeGen *g, Scope *scope, Buf *name); | 59 | Tld *find_decl(CodeGen *g, Scope *scope, Buf *name); |
| 61 | Tld *find_container_decl(CodeGen *g, ScopeDecls *decls_scope, Buf *name); | 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 | ZigType *get_src_ptr_type(ZigType *type); | 63 | ZigType *get_src_ptr_type(ZigType *type); |
| 65 | ZigType *get_codegen_ptr_type(ZigType *type); | 64 | ZigType *get_codegen_ptr_type(ZigType *type); |
| ... | @@ -71,7 +70,6 @@ bool type_is_complete(ZigType *type_entry); | ... | @@ -71,7 +70,6 @@ bool type_is_complete(ZigType *type_entry); |
| 71 | bool type_is_resolved(ZigType *type_entry, ResolveStatus status); | 70 | bool type_is_resolved(ZigType *type_entry, ResolveStatus status); |
| 72 | bool type_is_invalid(ZigType *type_entry); | 71 | bool type_is_invalid(ZigType *type_entry); |
| 73 | bool type_is_global_error_set(ZigType *err_set_type); | 72 | bool type_is_global_error_set(ZigType *err_set_type); |
| 74 | Error resolve_container_type(CodeGen *g, ZigType *type_entry); | ||
| 75 | ScopeDecls *get_container_scope(ZigType *type_entry); | 73 | ScopeDecls *get_container_scope(ZigType *type_entry); |
| 76 | TypeStructField *find_struct_type_field(ZigType *type_entry, Buf *name); | 74 | TypeStructField *find_struct_type_field(ZigType *type_entry, Buf *name); |
| 77 | TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name); | 75 | TypeEnumField *find_enum_type_field(ZigType *enum_type, Buf *name); |
| ... | @@ -95,7 +93,6 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node); | ... | @@ -95,7 +93,6 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node); |
| 95 | ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value); | 93 | ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value); |
| 96 | void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_count_alloc); | 94 | void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_count_alloc); |
| 97 | AstNode *get_param_decl_node(ZigFn *fn_entry, size_t index); | 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 | Error ATTRIBUTE_MUST_USE type_resolve(CodeGen *g, ZigType *type_entry, ResolveStatus status); | 96 | Error ATTRIBUTE_MUST_USE type_resolve(CodeGen *g, ZigType *type_entry, ResolveStatus status); |
| 100 | void complete_enum(CodeGen *g, ZigType *enum_type); | 97 | void complete_enum(CodeGen *g, ZigType *enum_type); |
| 101 | bool ir_get_var_is_comptime(ZigVar *var); | 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,12 +166,11 @@ ConstExprValue *create_const_slice(CodeGen *g, ConstExprValue *array_val, size_t |
| 169 | void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_index_start, size_t arg_index_end); | 166 | void init_const_arg_tuple(CodeGen *g, ConstExprValue *const_val, size_t arg_index_start, size_t arg_index_end); |
| 170 | ConstExprValue *create_const_arg_tuple(CodeGen *g, size_t arg_index_start, size_t arg_index_end); | 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 | ConstExprValue *create_const_vals(size_t count); | 169 | ConstExprValue *create_const_vals(size_t count); |
| 175 | 170 | ||
| 176 | ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); | 171 | ZigType *make_int_type(CodeGen *g, bool is_signed, uint32_t size_in_bits); |
| 177 | void expand_undef_array(CodeGen *g, ConstExprValue *const_val); | 172 | void expand_undef_array(CodeGen *g, ConstExprValue *const_val); |
| 173 | void expand_undef_struct(CodeGen *g, ConstExprValue *const_val); | ||
| 178 | void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value); | 174 | void update_compile_var(CodeGen *g, Buf *name, ConstExprValue *value); |
| 179 | 175 | ||
| 180 | const char *type_id_name(ZigTypeId id); | 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,9 +240,14 @@ void add_cc_args(CodeGen *g, ZigList<const char *> &args, const char *out_dep_pa |
| 244 | 240 | ||
| 245 | void src_assert(bool ok, AstNode *source_node); | 241 | void src_assert(bool ok, AstNode *source_node); |
| 246 | bool is_container(ZigType *type_entry); | 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 | void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn); | 246 | void resolve_llvm_types_fn(CodeGen *g, ZigFn *fn); |
| 250 | bool fn_is_async(ZigFn *fn); | 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 | #endif | 253 | #endif |
src/bigint.cpp+22-1| ... | @@ -15,6 +15,8 @@ | ... | @@ -15,6 +15,8 @@ |
| 15 | #include <limits> | 15 | #include <limits> |
| 16 | #include <algorithm> | 16 | #include <algorithm> |
| 17 | 17 | ||
| 18 | static uint64_t bigint_as_unsigned(const BigInt *bigint); | ||
| 19 | |||
| 18 | static void bigint_normalize(BigInt *dest) { | 20 | static void bigint_normalize(BigInt *dest) { |
| 19 | const uint64_t *digits = bigint_ptr(dest); | 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,7 +1662,7 @@ size_t bigint_clz(const BigInt *bi, size_t bit_count) { |
| 1660 | return count; | 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 | assert(!bigint->is_negative); | 1666 | assert(!bigint->is_negative); |
| 1665 | if (bigint->digit_count == 0) { | 1667 | if (bigint->digit_count == 0) { |
| 1666 | return 0; | 1668 | return 0; |
| ... | @@ -1671,6 +1673,25 @@ uint64_t bigint_as_unsigned(const BigInt *bigint) { | ... | @@ -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 | int64_t bigint_as_signed(const BigInt *bigint) { | 1695 | int64_t bigint_as_signed(const BigInt *bigint) { |
| 1675 | if (bigint->digit_count == 0) { | 1696 | if (bigint->digit_count == 0) { |
| 1676 | return 0; | 1697 | return 0; |
src/bigint.hpp+4-1| ... | @@ -36,7 +36,10 @@ void bigint_init_bigfloat(BigInt *dest, const BigFloat *op); | ... | @@ -36,7 +36,10 @@ void bigint_init_bigfloat(BigInt *dest, const BigFloat *op); |
| 36 | void bigint_init_data(BigInt *dest, const uint64_t *digits, size_t digit_count, bool is_negative); | 36 | void bigint_init_data(BigInt *dest, const uint64_t *digits, size_t digit_count, bool is_negative); |
| 37 | 37 | ||
| 38 | // panics if number won't fit | 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 | int64_t bigint_as_signed(const BigInt *bigint); | 43 | int64_t bigint_as_signed(const BigInt *bigint); |
| 41 | 44 | ||
| 42 | static inline const uint64_t *bigint_ptr(const BigInt *bigint) { | 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,7 +2872,7 @@ static void add_error_range_check(CodeGen *g, ZigType *err_set_type, ZigType *in |
| 2872 | eval_min_max_value_int(g, int_type, &biggest_possible_err_val, true); | 2872 | eval_min_max_value_int(g, int_type, &biggest_possible_err_val, true); |
| 2873 | 2873 | ||
| 2874 | if (bigint_fits_in_bits(&biggest_possible_err_val, 64, false) && | 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 | ok_bit = neq_zero_bit; | 2877 | ok_bit = neq_zero_bit; |
| 2878 | } else { | 2878 | } else { |
| ... | @@ -3052,8 +3052,10 @@ static LLVMValueRef ir_render_ptr_of_array_to_slice(CodeGen *g, IrExecutable *ex | ... | @@ -3052,8 +3052,10 @@ static LLVMValueRef ir_render_ptr_of_array_to_slice(CodeGen *g, IrExecutable *ex |
| 3052 | IrInstructionPtrOfArrayToSlice *instruction) | 3052 | IrInstructionPtrOfArrayToSlice *instruction) |
| 3053 | { | 3053 | { |
| 3054 | ZigType *actual_type = instruction->operand->value.type; | 3054 | ZigType *actual_type = instruction->operand->value.type; |
| 3055 | LLVMValueRef expr_val = ir_llvm_value(g, instruction->operand); | 3055 | ZigType *slice_type = instruction->base.value.type; |
| 3056 | assert(expr_val); | 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 | LLVMValueRef result_loc = ir_llvm_value(g, instruction->result_loc); | 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,15 +3063,21 @@ static LLVMValueRef ir_render_ptr_of_array_to_slice(CodeGen *g, IrExecutable *ex |
| 3061 | ZigType *array_type = actual_type->data.pointer.child_type; | 3063 | ZigType *array_type = actual_type->data.pointer.child_type; |
| 3062 | assert(array_type->id == ZigTypeIdArray); | 3064 | assert(array_type->id == ZigTypeIdArray); |
| 3063 | 3065 | ||
| 3064 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, slice_ptr_index, ""); | 3066 | if (type_has_bits(actual_type)) { |
| 3065 | LLVMValueRef indices[] = { | 3067 | LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, result_loc, ptr_index, ""); |
| 3066 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), | 3068 | LLVMValueRef indices[] = { |
| 3067 | LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 0, false), | 3069 | LLVMConstNull(g->builtin_types.entry_usize->llvm_type), |
| 3068 | }; | 3070 | LLVMConstInt(g->builtin_types.entry_usize->llvm_type, 0, false), |
| 3069 | LLVMValueRef slice_start_ptr = LLVMBuildInBoundsGEP(g->builder, expr_val, indices, 2, ""); | 3071 | }; |
| 3070 | gen_store_untyped(g, slice_start_ptr, ptr_field_ptr, 0, false); | 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 | LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, | 3081 | LLVMValueRef len_value = LLVMConstInt(g->builtin_types.entry_usize->llvm_type, |
| 3074 | array_type->data.array.len, false); | 3082 | array_type->data.array.len, false); |
| 3075 | gen_store_untyped(g, len_value, len_field_ptr, 0, false); | 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,6 +3394,8 @@ static bool value_is_all_undef_array(ConstExprValue *const_val, size_t len) { |
| 3386 | 3394 | ||
| 3387 | static bool value_is_all_undef(ConstExprValue *const_val) { | 3395 | static bool value_is_all_undef(ConstExprValue *const_val) { |
| 3388 | switch (const_val->special) { | 3396 | switch (const_val->special) { |
| 3397 | case ConstValSpecialLazy: | ||
| 3398 | zig_unreachable(); | ||
| 3389 | case ConstValSpecialRuntime: | 3399 | case ConstValSpecialRuntime: |
| 3390 | return false; | 3400 | return false; |
| 3391 | case ConstValSpecialUndef: | 3401 | case ConstValSpecialUndef: |
| ... | @@ -3525,6 +3535,8 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir | ... | @@ -3525,6 +3535,8 @@ static LLVMValueRef ir_render_store_ptr(CodeGen *g, IrExecutable *executable, Ir |
| 3525 | } | 3535 | } |
| 3526 | 3536 | ||
| 3527 | static LLVMValueRef ir_render_var_ptr(CodeGen *g, IrExecutable *executable, IrInstructionVarPtr *instruction) { | 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 | ZigVar *var = instruction->var; | 3540 | ZigVar *var = instruction->var; |
| 3529 | if (type_has_bits(var->var_type)) { | 3541 | if (type_has_bits(var->var_type)) { |
| 3530 | assert(var->value_ref); | 3542 | assert(var->value_ref); |
| ... | @@ -6041,6 +6053,7 @@ static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *un | ... | @@ -6041,6 +6053,7 @@ static LLVMValueRef gen_const_ptr_union_recursive(CodeGen *g, ConstExprValue *un |
| 6041 | 6053 | ||
| 6042 | static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) { | 6054 | static LLVMValueRef pack_const_int(CodeGen *g, LLVMTypeRef big_int_type_ref, ConstExprValue *const_val) { |
| 6043 | switch (const_val->special) { | 6055 | switch (const_val->special) { |
| 6056 | case ConstValSpecialLazy: | ||
| 6044 | case ConstValSpecialRuntime: | 6057 | case ConstValSpecialRuntime: |
| 6045 | zig_unreachable(); | 6058 | zig_unreachable(); |
| 6046 | case ConstValSpecialUndef: | 6059 | case ConstValSpecialUndef: |
| ... | @@ -6300,6 +6313,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c | ... | @@ -6300,6 +6313,8 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 6300 | assert(type_has_bits(type_entry)); | 6313 | assert(type_has_bits(type_entry)); |
| 6301 | 6314 | ||
| 6302 | switch (const_val->special) { | 6315 | switch (const_val->special) { |
| 6316 | case ConstValSpecialLazy: | ||
| 6317 | zig_unreachable(); | ||
| 6303 | case ConstValSpecialRuntime: | 6318 | case ConstValSpecialRuntime: |
| 6304 | zig_unreachable(); | 6319 | zig_unreachable(); |
| 6305 | case ConstValSpecialUndef: | 6320 | case ConstValSpecialUndef: |
| ... | @@ -6563,7 +6578,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c | ... | @@ -6563,7 +6578,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, ConstExprValue *const_val, const c |
| 6563 | uint64_t pad_bytes = type_entry->data.unionation.union_abi_size - field_type_bytes; | 6578 | uint64_t pad_bytes = type_entry->data.unionation.union_abi_size - field_type_bytes; |
| 6564 | LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value, ""); | 6579 | LLVMValueRef correctly_typed_value = gen_const_val(g, payload_value, ""); |
| 6565 | make_unnamed_struct = is_llvm_value_unnamed_type(g, payload_value->type, correctly_typed_value) || | 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 | if (pad_bytes == 0) { | 6584 | if (pad_bytes == 0) { |
| ... | @@ -8905,7 +8920,7 @@ static void gen_root_source(CodeGen *g) { | ... | @@ -8905,7 +8920,7 @@ static void gen_root_source(CodeGen *g) { |
| 8905 | } | 8920 | } |
| 8906 | Tld *panic_tld = find_decl(g, &get_container_scope(import_with_panic)->base, buf_create_from_str("panic")); | 8921 | Tld *panic_tld = find_decl(g, &get_container_scope(import_with_panic)->base, buf_create_from_str("panic")); |
| 8907 | assert(panic_tld != nullptr); | 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,11 +152,6 @@ struct ConstCastBadAllowsZero { |
| 152 | }; | 152 | }; |
| 153 | 153 | ||
| 154 | 154 | ||
| 155 | enum UndefAllowed { | ||
| 156 | UndefOk, | ||
| 157 | UndefBad, | ||
| 158 | }; | ||
| 159 | |||
| 160 | static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); | 155 | static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope); |
| 161 | static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, | 156 | static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *scope, LVal lval, |
| 162 | ResultLoc *result_loc); | 157 | ResultLoc *result_loc); |
| ... | @@ -234,6 +229,7 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c | ... | @@ -234,6 +229,7 @@ static ConstExprValue *const_ptr_pointee_unchecked(CodeGen *g, ConstExprValue *c |
| 234 | } | 229 | } |
| 235 | case ConstPtrSpecialBaseStruct: { | 230 | case ConstPtrSpecialBaseStruct: { |
| 236 | ConstExprValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val; | 231 | ConstExprValue *struct_val = const_val->data.x_ptr.data.base_struct.struct_val; |
| 232 | expand_undef_struct(g, struct_val); | ||
| 237 | result = &struct_val->data.x_struct.fields[const_val->data.x_ptr.data.base_struct.field_index]; | 233 | result = &struct_val->data.x_struct.fields[const_val->data.x_ptr.data.base_struct.field_index]; |
| 238 | break; | 234 | break; |
| 239 | } | 235 | } |
| ... | @@ -402,7 +398,7 @@ static void ir_ref_var(ZigVar *var) { | ... | @@ -402,7 +398,7 @@ static void ir_ref_var(ZigVar *var) { |
| 402 | ZigType *ir_analyze_type_expr(IrAnalyze *ira, Scope *scope, AstNode *node) { | 398 | ZigType *ir_analyze_type_expr(IrAnalyze *ira, Scope *scope, AstNode *node) { |
| 403 | ConstExprValue *result = ir_eval_const_value(ira->codegen, scope, node, ira->codegen->builtin_types.entry_type, | 399 | ConstExprValue *result = ir_eval_const_value(ira->codegen, scope, node, ira->codegen->builtin_types.entry_type, |
| 404 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, nullptr, | 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 | if (type_is_invalid(result->type)) | 403 | if (type_is_invalid(result->type)) |
| 408 | return ira->codegen->builtin_types.entry_invalid; | 404 | return ira->codegen->builtin_types.entry_invalid; |
| ... | @@ -5766,7 +5762,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -5766,7 +5762,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode |
| 5766 | buf_sprintf("value %s too large for u32 bit offset", buf_ptr(val_buf))); | 5762 | buf_sprintf("value %s too large for u32 bit offset", buf_ptr(val_buf))); |
| 5767 | return irb->codegen->invalid_instruction; | 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 | uint32_t host_int_bytes = 0; | 5768 | uint32_t host_int_bytes = 0; |
| ... | @@ -5778,7 +5774,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode | ... | @@ -5778,7 +5774,7 @@ static IrInstruction *ir_gen_pointer_type(IrBuilder *irb, Scope *scope, AstNode |
| 5778 | buf_sprintf("value %s too large for u32 byte count", buf_ptr(val_buf))); | 5774 | buf_sprintf("value %s too large for u32 byte count", buf_ptr(val_buf))); |
| 5779 | return irb->codegen->invalid_instruction; | 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 | if (host_int_bytes != 0 && bit_offset_start >= host_int_bytes * 8) { | 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,7 +6854,7 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod |
| 6858 | uint32_t len = asm_token.end - asm_token.start - 2; | 6854 | uint32_t len = asm_token.end - asm_token.start - 2; |
| 6859 | 6855 | ||
| 6860 | add_node_error(irb->codegen, node, | 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 | len, ptr)); | 6858 | len, ptr)); |
| 6863 | return irb->codegen->invalid_instruction; | 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,7 +8107,12 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, Scope *sc |
| 8111 | ir_build_reset_result(irb, scope, node, result_loc); | 8107 | ir_build_reset_result(irb, scope, node, result_loc); |
| 8112 | } | 8108 | } |
| 8113 | IrInstruction *result = ir_gen_node_raw(irb, node, scope, lval, result_loc); | 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 | return result; | 8116 | return result; |
| 8116 | } | 8117 | } |
| 8117 | 8118 | ||
| ... | @@ -8119,21 +8120,20 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) { | ... | @@ -8119,21 +8120,20 @@ static IrInstruction *ir_gen_node(IrBuilder *irb, AstNode *node, Scope *scope) { |
| 8119 | return ir_gen_node_extra(irb, node, scope, LValNone, nullptr); | 8120 | return ir_gen_node_extra(irb, node, scope, LValNone, nullptr); |
| 8120 | } | 8121 | } |
| 8121 | 8122 | ||
| 8122 | static void invalidate_exec(IrExecutable *exec) { | 8123 | static void invalidate_exec(IrExecutable *exec, ErrorMsg *msg) { |
| 8123 | if (exec->invalid) | 8124 | if (exec->first_err_trace_msg != nullptr) |
| 8124 | return; | 8125 | return; |
| 8125 | 8126 | ||
| 8126 | exec->invalid = true; | 8127 | exec->first_err_trace_msg = msg; |
| 8127 | 8128 | ||
| 8128 | for (size_t i = 0; i < exec->tld_list.length; i += 1) { | 8129 | for (size_t i = 0; i < exec->tld_list.length; i += 1) { |
| 8129 | exec->tld_list.items[i]->resolution = TldResolutionInvalid; | 8130 | exec->tld_list.items[i]->resolution = TldResolutionInvalid; |
| 8130 | } | 8131 | } |
| 8131 | 8132 | ||
| 8132 | if (exec->source_exec != nullptr) | 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 | bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_executable) { | 8137 | bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_executable) { |
| 8138 | assert(node->owner); | 8138 | assert(node->owner); |
| 8139 | 8139 | ||
| ... | @@ -8151,8 +8151,10 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec | ... | @@ -8151,8 +8151,10 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec |
| 8151 | 8151 | ||
| 8152 | IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone, nullptr); | 8152 | IrInstruction *result = ir_gen_node_extra(irb, node, scope, LValNone, nullptr); |
| 8153 | assert(result); | 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 | return false; | 8156 | return false; |
| 8157 | } | ||
| 8156 | 8158 | ||
| 8157 | if (!instr_is_unreachable(result)) { | 8159 | if (!instr_is_unreachable(result)) { |
| 8158 | ir_mark_gen(ir_build_add_implicit_return_type(irb, scope, result->source_node, result)); | 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,15 +8183,9 @@ static void ir_add_call_stack_errors(CodeGen *codegen, IrExecutable *exec, Error |
| 8181 | ir_add_call_stack_errors(codegen, exec->parent_exec, err_msg, limit - 1); | 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 | static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) { | 8186 | static ErrorMsg *exec_add_error_node(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, Buf *msg) { |
| 8191 | invalidate_exec(exec); | ||
| 8192 | ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); | 8187 | ErrorMsg *err_msg = add_node_error(codegen, source_node, msg); |
| 8188 | invalidate_exec(exec, err_msg); | ||
| 8193 | if (exec->parent_exec) { | 8189 | if (exec->parent_exec) { |
| 8194 | ir_add_call_stack_errors(codegen, exec, err_msg, 10); | 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,6 +8219,7 @@ static Error eval_comptime_ptr_reinterpret(IrAnalyze *ira, CodeGen *codegen, Ast |
| 8223 | { | 8219 | { |
| 8224 | Error err; | 8220 | Error err; |
| 8225 | assert(ptr_val->type->id == ZigTypeIdPointer); | 8221 | assert(ptr_val->type->id == ZigTypeIdPointer); |
| 8222 | assert(ptr_val->special == ConstValSpecialStatic); | ||
| 8226 | ConstExprValue tmp = {}; | 8223 | ConstExprValue tmp = {}; |
| 8227 | tmp.special = ConstValSpecialStatic; | 8224 | tmp.special = ConstValSpecialStatic; |
| 8228 | tmp.type = ptr_val->type->data.pointer.child_type; | 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,7 +9013,8 @@ static bool ir_num_lit_fits_in_other_type(IrAnalyze *ira, IrInstruction *instruc |
| 9016 | } | 9013 | } |
| 9017 | 9014 | ||
| 9018 | ConstExprValue *const_val = ir_resolve_const(ira, instruction, UndefBad); | 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 | bool const_val_is_int = (const_val->type->id == ZigTypeIdInt || const_val->type->id == ZigTypeIdComptimeInt); | 9019 | bool const_val_is_int = (const_val->type->id == ZigTypeIdInt || const_val->type->id == ZigTypeIdComptimeInt); |
| 9022 | bool const_val_is_float = (const_val->type->id == ZigTypeIdFloat || const_val->type->id == ZigTypeIdComptimeFloat); | 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,6 +9374,14 @@ static ConstCastOnly types_match_const_cast_only(IrAnalyze *ira, ZigType *wanted |
| 9376 | result.id = ConstCastResultIdInvalid; | 9374 | result.id = ConstCastResultIdInvalid; |
| 9377 | return result; | 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 | bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len; | 9385 | bool ptr_lens_equal = actual_ptr_type->data.pointer.ptr_len == wanted_ptr_type->data.pointer.ptr_len; |
| 9380 | if ((ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr) && | 9386 | if ((ptr_lens_equal || wanted_is_c_ptr || actual_is_c_ptr) && |
| 9381 | type_has_bits(wanted_type) == type_has_bits(actual_type) && | 9387 | type_has_bits(wanted_type) == type_has_bits(actual_type) && |
| ... | @@ -10634,7 +10640,7 @@ static void ir_finish_bb(IrAnalyze *ira) { | ... | @@ -10634,7 +10640,7 @@ static void ir_finish_bb(IrAnalyze *ira) { |
| 10634 | 10640 | ||
| 10635 | static IrInstruction *ir_unreach_error(IrAnalyze *ira) { | 10641 | static IrInstruction *ir_unreach_error(IrAnalyze *ira) { |
| 10636 | ira->old_bb_index = SIZE_MAX; | 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 | return ira->codegen->unreach_instruction; | 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,32 +10728,57 @@ static IrInstruction *ir_get_const_ptr(IrAnalyze *ira, IrInstruction *instructio |
| 10722 | return const_instr; | 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 | static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed) { | 10765 | static ConstExprValue *ir_resolve_const(IrAnalyze *ira, IrInstruction *value, UndefAllowed undef_allowed) { |
| 10726 | switch (value->value.special) { | 10766 | Error err; |
| 10727 | case ConstValSpecialStatic: | 10767 | if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, value->source_node, |
| 10728 | return &value->value; | 10768 | &value->value, undef_allowed))) |
| 10729 | case ConstValSpecialRuntime: | 10769 | { |
| 10730 | if (!type_has_bits(value->value.type)) { | 10770 | return nullptr; |
| 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 | } | ||
| 10742 | } | 10771 | } |
| 10743 | zig_unreachable(); | 10772 | return &value->value; |
| 10744 | } | 10773 | } |
| 10745 | 10774 | ||
| 10746 | ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, | 10775 | ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, |
| 10747 | ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota, | 10776 | ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota, |
| 10748 | ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, | 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 | if (expected_type != nullptr && type_is_invalid(expected_type)) | 10782 | if (expected_type != nullptr && type_is_invalid(expected_type)) |
| 10752 | return &codegen->invalid_instruction->value; | 10783 | return &codegen->invalid_instruction->value; |
| 10753 | 10784 | ||
| ... | @@ -10761,8 +10792,10 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod | ... | @@ -10761,8 +10792,10 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod |
| 10761 | ir_executable->begin_scope = scope; | 10792 | ir_executable->begin_scope = scope; |
| 10762 | ir_gen(codegen, node, scope, ir_executable); | 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 | return &codegen->invalid_instruction->value; | 10797 | return &codegen->invalid_instruction->value; |
| 10798 | } | ||
| 10766 | 10799 | ||
| 10767 | if (codegen->verbose_ir) { | 10800 | if (codegen->verbose_ir) { |
| 10768 | fprintf(stderr, "\nSource: "); | 10801 | fprintf(stderr, "\nSource: "); |
| ... | @@ -10783,8 +10816,9 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod | ... | @@ -10783,8 +10816,9 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod |
| 10783 | analyzed_executable->backward_branch_quota = backward_branch_quota; | 10816 | analyzed_executable->backward_branch_quota = backward_branch_quota; |
| 10784 | analyzed_executable->begin_scope = scope; | 10817 | analyzed_executable->begin_scope = scope; |
| 10785 | ZigType *result_type = ir_analyze(codegen, ir_executable, analyzed_executable, expected_type, expected_type_source_node); | 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 | return &codegen->invalid_instruction->value; | 10820 | return &codegen->invalid_instruction->value; |
| 10821 | } | ||
| 10788 | 10822 | ||
| 10789 | if (codegen->verbose_ir) { | 10823 | if (codegen->verbose_ir) { |
| 10790 | fprintf(stderr, "{ // (analyzed)\n"); | 10824 | fprintf(stderr, "{ // (analyzed)\n"); |
| ... | @@ -10792,7 +10826,14 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod | ... | @@ -10792,7 +10826,14 @@ ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *nod |
| 10792 | fprintf(stderr, "}\n"); | 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 | static ErrorTableEntry *ir_resolve_error(IrAnalyze *ira, IrInstruction *err_value) { | 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,22 +10854,43 @@ static ErrorTableEntry *ir_resolve_error(IrAnalyze *ira, IrInstruction *err_valu |
| 10813 | return const_val->data.x_err_set; | 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 | if (type_is_invalid(type_value->value.type)) | 10869 | if (type_is_invalid(type_value->value.type)) |
| 10818 | return ira->codegen->builtin_types.entry_invalid; | 10870 | return nullptr; |
| 10819 | 10871 | ||
| 10820 | if (type_value->value.type->id != ZigTypeIdMetaType) { | 10872 | if (type_value->value.type->id != ZigTypeIdMetaType) { |
| 10821 | ir_add_error(ira, type_value, | 10873 | ir_add_error(ira, type_value, |
| 10822 | buf_sprintf("expected type 'type', found '%s'", buf_ptr(&type_value->value.type->name))); | 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); | 10878 | Error err; |
| 10827 | if (!const_val) | 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 | return ira->codegen->builtin_types.entry_invalid; | 10891 | return ira->codegen->builtin_types.entry_invalid; |
| 10829 | 10892 | ||
| 10830 | assert(const_val->data.x_type != nullptr); | 10893 | return ir_resolve_const_type(ira->codegen, ira->new_irb.exec, type_value->source_node, val); |
| 10831 | return const_val->data.x_type; | ||
| 10832 | } | 10894 | } |
| 10833 | 10895 | ||
| 10834 | static ZigType *ir_resolve_int_type(IrAnalyze *ira, IrInstruction *type_value) { | 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,14 +11088,21 @@ static IrInstruction *ir_analyze_err_set_cast(IrAnalyze *ira, IrInstruction *sou |
| 11026 | } | 11088 | } |
| 11027 | 11089 | ||
| 11028 | static IrInstruction *ir_analyze_frame_ptr_to_anyframe(IrAnalyze *ira, IrInstruction *source_instr, | 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)) { | 11093 | if (instr_is_comptime(frame_ptr)) { |
| 11032 | zig_panic("TODO comptime frame pointer"); | 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 | IrInstruction *result = ir_build_cast(&ira->new_irb, source_instr->scope, source_instr->source_node, | 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 | result->value.type = wanted_type; | 11106 | result->value.type = wanted_type; |
| 11038 | return result; | 11107 | return result; |
| 11039 | } | 11108 | } |
| ... | @@ -11152,6 +11221,9 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi | ... | @@ -11152,6 +11221,9 @@ static IrInstruction *ir_get_ref(IrAnalyze *ira, IrInstruction *source_instructi |
| 11152 | ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type, | 11221 | ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, value->value.type, |
| 11153 | is_const, is_volatile, PtrLenSingle, 0, 0, 0, false); | 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 | IrInstruction *result_loc; | 11227 | IrInstruction *result_loc; |
| 11156 | if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) { | 11228 | if (type_has_bits(ptr_type) && !handle_is_ptr(value->value.type)) { |
| 11157 | result_loc = ir_resolve_result(ira, source_instruction, no_result_loc(), value->value.type, nullptr, true, | 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,7 +11394,7 @@ static IrInstruction *ir_analyze_undefined_to_anything(IrAnalyze *ira, IrInstruc |
| 11322 | IrInstruction *target, ZigType *wanted_type) | 11394 | IrInstruction *target, ZigType *wanted_type) |
| 11323 | { | 11395 | { |
| 11324 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); | 11396 | IrInstruction *result = ir_const(ira, source_instr, wanted_type); |
| 11325 | init_const_undefined(ira->codegen, &result->value); | 11397 | result->value.special = ConstValSpecialUndef; |
| 11326 | return result; | 11398 | return result; |
| 11327 | } | 11399 | } |
| 11328 | 11400 | ||
| ... | @@ -11345,10 +11417,13 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so | ... | @@ -11345,10 +11417,13 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so |
| 11345 | return ira->codegen->invalid_instruction; | 11417 | return ira->codegen->invalid_instruction; |
| 11346 | TypeUnionField *union_field = find_union_field_by_tag(wanted_type, &val->data.x_enum_tag); | 11418 | TypeUnionField *union_field = find_union_field_by_tag(wanted_type, &val->data.x_enum_tag); |
| 11347 | assert(union_field != nullptr); | 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 | return ira->codegen->invalid_instruction; | 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 | case OnePossibleValueInvalid: | 11427 | case OnePossibleValueInvalid: |
| 11353 | return ira->codegen->invalid_instruction; | 11428 | return ira->codegen->invalid_instruction; |
| 11354 | case OnePossibleValueNo: { | 11429 | case OnePossibleValueNo: { |
| ... | @@ -11357,7 +11432,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so | ... | @@ -11357,7 +11432,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so |
| 11357 | ErrorMsg *msg = ir_add_error(ira, source_instr, | 11432 | ErrorMsg *msg = ir_add_error(ira, source_instr, |
| 11358 | buf_sprintf("cast to union '%s' must initialize '%s' field '%s'", | 11433 | buf_sprintf("cast to union '%s' must initialize '%s' field '%s'", |
| 11359 | buf_ptr(&wanted_type->name), | 11434 | buf_ptr(&wanted_type->name), |
| 11360 | buf_ptr(&union_field->type_entry->name), | 11435 | buf_ptr(&field_type->name), |
| 11361 | buf_ptr(union_field->name))); | 11436 | buf_ptr(union_field->name))); |
| 11362 | add_error_note(ira->codegen, msg, field_node, | 11437 | add_error_note(ira->codegen, msg, field_node, |
| 11363 | buf_sprintf("field '%s' declared here", buf_ptr(union_field->name))); | 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,7 +11448,7 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so |
| 11373 | bigint_init_bigint(&result->value.data.x_union.tag, &val->data.x_enum_tag); | 11448 | bigint_init_bigint(&result->value.data.x_union.tag, &val->data.x_enum_tag); |
| 11374 | result->value.data.x_union.payload = create_const_vals(1); | 11449 | result->value.data.x_union.payload = create_const_vals(1); |
| 11375 | result->value.data.x_union.payload->special = ConstValSpecialStatic; | 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 | return result; | 11452 | return result; |
| 11378 | } | 11453 | } |
| 11379 | 11454 | ||
| ... | @@ -11390,12 +11465,17 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so | ... | @@ -11390,12 +11465,17 @@ static IrInstruction *ir_analyze_enum_to_union(IrAnalyze *ira, IrInstruction *so |
| 11390 | buf_ptr(&wanted_type->name))); | 11465 | buf_ptr(&wanted_type->name))); |
| 11391 | for (uint32_t i = 0; i < wanted_type->data.unionation.src_field_count; i += 1) { | 11466 | for (uint32_t i = 0; i < wanted_type->data.unionation.src_field_count; i += 1) { |
| 11392 | TypeUnionField *union_field = &wanted_type->data.unionation.fields[i]; | 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 | AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at(i); | 11474 | AstNode *field_node = wanted_type->data.unionation.decl_node->data.container_decl.fields.at(i); |
| 11395 | add_error_note(ira->codegen, msg, field_node, | 11475 | add_error_note(ira->codegen, msg, field_node, |
| 11396 | buf_sprintf("field '%s' has type '%s'", | 11476 | buf_sprintf("field '%s' has type '%s'", |
| 11397 | buf_ptr(union_field->name), | 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 | return ira->codegen->invalid_instruction; | 11481 | return ira->codegen->invalid_instruction; |
| ... | @@ -11461,7 +11541,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour | ... | @@ -11461,7 +11541,7 @@ static IrInstruction *ir_analyze_int_to_enum(IrAnalyze *ira, IrInstruction *sour |
| 11461 | 11541 | ||
| 11462 | ZigType *actual_type = target->value.type; | 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 | return ira->codegen->invalid_instruction; | 11545 | return ira->codegen->invalid_instruction; |
| 11466 | 11546 | ||
| 11467 | if (actual_type != wanted_type->data.enumeration.tag_int_type) { | 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,7 +11630,7 @@ static IrInstruction *ir_analyze_int_to_err(IrAnalyze *ira, IrInstruction *sourc |
| 11550 | return ira->codegen->invalid_instruction; | 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 | result->value.data.x_err_set = ira->codegen->errors_by_index.at(index); | 11634 | result->value.data.x_err_set = ira->codegen->errors_by_index.at(index); |
| 11555 | return result; | 11635 | return result; |
| 11556 | } else { | 11636 | } else { |
| ... | @@ -12508,26 +12588,22 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc | ... | @@ -12508,26 +12588,22 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc |
| 12508 | return ir_build_load_ptr_gen(ira, source_instruction, ptr, child_type, result_loc_inst); | 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) { | 12591 | static bool ir_resolve_const_align(CodeGen *codegen, IrExecutable *exec, AstNode *source_node, |
| 12512 | if (type_is_invalid(value->value.type)) | 12592 | ConstExprValue *const_val, uint32_t *out) |
| 12513 | return false; | 12593 | { |
| 12514 | 12594 | Error err; | |
| 12515 | IrInstruction *casted_value = ir_implicit_cast(ira, value, get_align_amt_type(ira->codegen)); | 12595 | if ((err = ir_resolve_const_val(codegen, exec, source_node, const_val, UndefBad))) |
| 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) | ||
| 12521 | return false; | 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 | if (align_bytes == 0) { | 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 | return false; | 12601 | return false; |
| 12527 | } | 12602 | } |
| 12528 | 12603 | ||
| 12529 | if (!is_power_of_2(align_bytes)) { | 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 | return false; | 12607 | return false; |
| 12532 | } | 12608 | } |
| 12533 | 12609 | ||
| ... | @@ -12535,6 +12611,18 @@ static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out | ... | @@ -12535,6 +12611,18 @@ static bool ir_resolve_align(IrAnalyze *ira, IrInstruction *value, uint32_t *out |
| 12535 | return true; | 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 | static bool ir_resolve_unsigned(IrAnalyze *ira, IrInstruction *value, ZigType *int_type, uint64_t *out) { | 12626 | static bool ir_resolve_unsigned(IrAnalyze *ira, IrInstruction *value, ZigType *int_type, uint64_t *out) { |
| 12539 | if (type_is_invalid(value->value.type)) | 12627 | if (type_is_invalid(value->value.type)) |
| 12540 | return false; | 12628 | return false; |
| ... | @@ -12547,7 +12635,7 @@ static bool ir_resolve_unsigned(IrAnalyze *ira, IrInstruction *value, ZigType *i | ... | @@ -12547,7 +12635,7 @@ static bool ir_resolve_unsigned(IrAnalyze *ira, IrInstruction *value, ZigType *i |
| 12547 | if (!const_val) | 12635 | if (!const_val) |
| 12548 | return false; | 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 | return true; | 12639 | return true; |
| 12552 | } | 12640 | } |
| 12553 | 12641 | ||
| ... | @@ -12595,7 +12683,7 @@ static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, Atomic | ... | @@ -12595,7 +12683,7 @@ static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, Atomic |
| 12595 | if (!const_val) | 12683 | if (!const_val) |
| 12596 | return false; | 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 | return true; | 12687 | return true; |
| 12600 | } | 12688 | } |
| 12601 | 12689 | ||
| ... | @@ -12615,7 +12703,7 @@ static bool ir_resolve_atomic_rmw_op(IrAnalyze *ira, IrInstruction *value, Atomi | ... | @@ -12615,7 +12703,7 @@ static bool ir_resolve_atomic_rmw_op(IrAnalyze *ira, IrInstruction *value, Atomi |
| 12615 | if (!const_val) | 12703 | if (!const_val) |
| 12616 | return false; | 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 | return true; | 12707 | return true; |
| 12620 | } | 12708 | } |
| 12621 | 12709 | ||
| ... | @@ -12635,7 +12723,7 @@ static bool ir_resolve_global_linkage(IrAnalyze *ira, IrInstruction *value, Glob | ... | @@ -12635,7 +12723,7 @@ static bool ir_resolve_global_linkage(IrAnalyze *ira, IrInstruction *value, Glob |
| 12635 | if (!const_val) | 12723 | if (!const_val) |
| 12636 | return false; | 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 | return true; | 12727 | return true; |
| 12640 | } | 12728 | } |
| 12641 | 12729 | ||
| ... | @@ -12655,7 +12743,7 @@ static bool ir_resolve_float_mode(IrAnalyze *ira, IrInstruction *value, FloatMod | ... | @@ -12655,7 +12743,7 @@ static bool ir_resolve_float_mode(IrAnalyze *ira, IrInstruction *value, FloatMod |
| 12655 | if (!const_val) | 12743 | if (!const_val) |
| 12656 | return false; | 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 | return true; | 12747 | return true; |
| 12660 | } | 12748 | } |
| 12661 | 12749 | ||
| ... | @@ -12684,7 +12772,7 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { | ... | @@ -12684,7 +12772,7 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { |
| 12684 | return array_val->data.x_array.data.s_buf; | 12772 | return array_val->data.x_array.data.s_buf; |
| 12685 | } | 12773 | } |
| 12686 | expand_undef_array(ira->codegen, array_val); | 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 | Buf *result = buf_alloc(); | 12776 | Buf *result = buf_alloc(); |
| 12689 | buf_resize(result, len); | 12777 | buf_resize(result, len); |
| 12690 | for (size_t i = 0; i < len; i += 1) { | 12778 | for (size_t i = 0; i < len; i += 1) { |
| ... | @@ -12694,7 +12782,7 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { | ... | @@ -12694,7 +12782,7 @@ static Buf *ir_resolve_str(IrAnalyze *ira, IrInstruction *value) { |
| 12694 | ir_add_error(ira, casted_value, buf_sprintf("use of undefined value")); | 12782 | ir_add_error(ira, casted_value, buf_sprintf("use of undefined value")); |
| 12695 | return nullptr; | 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 | assert(big_c <= UINT8_MAX); | 12786 | assert(big_c <= UINT8_MAX); |
| 12699 | uint8_t c = (uint8_t)big_c; | 12787 | uint8_t c = (uint8_t)big_c; |
| 12700 | buf_ptr(result)[i] = c; | 12788 | buf_ptr(result)[i] = c; |
| ... | @@ -12719,7 +12807,9 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio | ... | @@ -12719,7 +12807,9 @@ static IrInstruction *ir_analyze_instruction_return(IrAnalyze *ira, IrInstructio |
| 12719 | if (type_is_invalid(operand->value.type)) | 12807 | if (type_is_invalid(operand->value.type)) |
| 12720 | return ir_unreach_error(ira); | 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 | // result location mechanism took care of it. | 12813 | // result location mechanism took care of it. |
| 12724 | IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope, | 12814 | IrInstruction *result = ir_build_return(&ira->new_irb, instruction->base.scope, |
| 12725 | instruction->base.source_node, nullptr); | 12815 | instruction->base.source_node, nullptr); |
| ... | @@ -13576,21 +13666,34 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp | ... | @@ -13576,21 +13666,34 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 13576 | if (type_is_invalid(casted_op2->value.type)) | 13666 | if (type_is_invalid(casted_op2->value.type)) |
| 13577 | return ira->codegen->invalid_instruction; | 13667 | return ira->codegen->invalid_instruction; |
| 13578 | 13668 | ||
| 13579 | if (op1->value.special == ConstValSpecialUndef || casted_op2->value.special == ConstValSpecialUndef) { | 13669 | // If either operand is undef, result is undef. |
| 13580 | IrInstruction *result = ir_const(ira, &instruction->base, op1->value.type); | 13670 | ConstExprValue *op1_val = nullptr; |
| 13581 | result->value.special = ConstValSpecialUndef; | 13671 | ConstExprValue *op2_val = nullptr; |
| 13582 | return result; | 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 | (op1->value.data.x_ptr.special == ConstPtrSpecialHardCodedAddr || | 13688 | (op1->value.data.x_ptr.special == ConstPtrSpecialHardCodedAddr || |
| 13586 | op1->value.data.x_ptr.special == ConstPtrSpecialNull)) | 13689 | op1->value.data.x_ptr.special == ConstPtrSpecialNull)) |
| 13587 | { | 13690 | { |
| 13588 | uint64_t start_addr = (op1->value.data.x_ptr.special == ConstPtrSpecialNull) ? | 13691 | uint64_t start_addr = (op1_val->data.x_ptr.special == ConstPtrSpecialNull) ? |
| 13589 | 0 : op1->value.data.x_ptr.data.hard_coded_addr.addr; | 13692 | 0 : op1_val->data.x_ptr.data.hard_coded_addr.addr; |
| 13590 | uint64_t elem_offset; | 13693 | uint64_t elem_offset; |
| 13591 | if (!ir_resolve_usize(ira, casted_op2, &elem_offset)) | 13694 | if (!ir_resolve_usize(ira, casted_op2, &elem_offset)) |
| 13592 | return ira->codegen->invalid_instruction; | 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 | if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) | 13697 | if ((err = type_resolve(ira->codegen, elem_type, ResolveStatusSizeKnown))) |
| 13595 | return ira->codegen->invalid_instruction; | 13698 | return ira->codegen->invalid_instruction; |
| 13596 | uint64_t byte_offset = type_size(ira->codegen, elem_type) * elem_offset; | 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,7 +13705,7 @@ static IrInstruction *ir_analyze_bin_op_math(IrAnalyze *ira, IrInstructionBinOp |
| 13602 | } else { | 13705 | } else { |
| 13603 | zig_unreachable(); | 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 | result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; | 13709 | result->value.data.x_ptr.special = ConstPtrSpecialHardCodedAddr; |
| 13607 | result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar; | 13710 | result->value.data.x_ptr.mut = ConstPtrMutRuntimeVar; |
| 13608 | result->value.data.x_ptr.data.hard_coded_addr.addr = new_addr; | 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,7 +13932,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i |
| 13829 | op1_array_val = ptr_val->data.x_ptr.data.base_array.array_val; | 13932 | op1_array_val = ptr_val->data.x_ptr.data.base_array.array_val; |
| 13830 | op1_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; | 13933 | op1_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; |
| 13831 | ConstExprValue *len_val = &op1_val->data.x_struct.fields[slice_len_index]; | 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 | } else { | 13936 | } else { |
| 13834 | ir_add_error(ira, op1, | 13937 | ir_add_error(ira, op1, |
| 13835 | buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op1->value.type->name))); | 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,7 +13965,7 @@ static IrInstruction *ir_analyze_array_cat(IrAnalyze *ira, IrInstructionBinOp *i |
| 13862 | op2_array_val = ptr_val->data.x_ptr.data.base_array.array_val; | 13965 | op2_array_val = ptr_val->data.x_ptr.data.base_array.array_val; |
| 13863 | op2_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; | 13966 | op2_array_index = ptr_val->data.x_ptr.data.base_array.elem_index; |
| 13864 | ConstExprValue *len_val = &op2_val->data.x_struct.fields[slice_len_index]; | 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 | } else { | 13969 | } else { |
| 13867 | ir_add_error(ira, op2, | 13970 | ir_add_error(ira, op2, |
| 13868 | buf_sprintf("expected array or C string literal, found '%s'", buf_ptr(&op2->value.type->name))); | 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,9 +14274,13 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, |
| 14171 | } | 14274 | } |
| 14172 | break; | 14275 | break; |
| 14173 | case ReqCompTimeNo: | 14276 | case ReqCompTimeNo: |
| 14174 | if (init_val != nullptr) { | 14277 | if (init_val != nullptr && value_is_comptime(init_val)) { |
| 14175 | if (init_val->special == ConstValSpecialStatic && | 14278 | if ((err = ir_resolve_const_val(ira->codegen, ira->new_irb.exec, |
| 14176 | init_val->type->id == ZigTypeIdFn && | 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 | init_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr && | 14284 | init_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr && |
| 14178 | init_val->data.x_ptr.data.fn.fn_entry->fn_inline == FnInlineAlways) | 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,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 | // Resolve ConstPtrMutInfer | 14342 | // Resolve ConstPtrMutInfer |
| 14236 | if (var->gen_is_const) { | 14343 | if (var->gen_is_const) { |
| 14237 | var_ptr->value.data.x_ptr.mut = ConstPtrMutComptimeConst; | 14344 | var_ptr->value.data.x_ptr.mut = ConstPtrMutComptimeConst; |
| ... | @@ -14242,6 +14349,10 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, | ... | @@ -14242,6 +14349,10 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, |
| 14242 | // since it's a comptime val there are no instructions for it. | 14349 | // since it's a comptime val there are no instructions for it. |
| 14243 | // we memcpy the init value here | 14350 | // we memcpy the init value here |
| 14244 | IrInstruction *deref = ir_get_deref(ira, var_ptr, var_ptr, nullptr); | 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 | // If this assertion trips, something is wrong with the IR instructions, because | 14356 | // If this assertion trips, something is wrong with the IR instructions, because |
| 14246 | // we expected the above deref to return a constant value, but it created a runtime | 14357 | // we expected the above deref to return a constant value, but it created a runtime |
| 14247 | // instruction. | 14358 | // instruction. |
| ... | @@ -14250,7 +14361,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, | ... | @@ -14250,7 +14361,7 @@ static IrInstruction *ir_analyze_instruction_decl_var(IrAnalyze *ira, |
| 14250 | ir_analyze_store_ptr(ira, var_ptr, var_ptr, deref, false); | 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 | assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length); | 14365 | assert(var->mem_slot_index < ira->exec_context.mem_slot_list.length); |
| 14255 | ConstExprValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index); | 14366 | ConstExprValue *mem_slot = ira->exec_context.mem_slot_list.at(var->mem_slot_index); |
| 14256 | copy_const_val(mem_slot, init_val, !is_comptime_var || var->gen_is_const); | 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,28 +14626,23 @@ static IrInstruction *ir_analyze_instruction_error_return_trace(IrAnalyze *ira, |
| 14515 | static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira, | 14626 | static IrInstruction *ir_analyze_instruction_error_union(IrAnalyze *ira, |
| 14516 | IrInstructionErrorUnion *instruction) | 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); | 14632 | LazyValueErrUnionType *lazy_err_union_type = allocate<LazyValueErrUnionType>(1); |
| 14521 | if (type_is_invalid(err_set_type)) | 14633 | lazy_err_union_type->ira = ira; |
| 14522 | return ira->codegen->invalid_instruction; | 14634 | result->value.data.x_lazy = &lazy_err_union_type->base; |
| 14523 | 14635 | lazy_err_union_type->base.id = LazyValueIdErrUnionType; | |
| 14524 | ZigType *payload_type = ir_resolve_type(ira, instruction->payload->child); | ||
| 14525 | if (type_is_invalid(payload_type)) | ||
| 14526 | return ira->codegen->invalid_instruction; | ||
| 14527 | 14636 | ||
| 14528 | if (err_set_type->id != ZigTypeIdErrorSet) { | 14637 | lazy_err_union_type->err_set_type = instruction->err_set->child; |
| 14529 | ir_add_error(ira, instruction->err_set->child, | 14638 | if (ir_resolve_type_lazy(ira, lazy_err_union_type->err_set_type) == nullptr) |
| 14530 | buf_sprintf("expected error set type, found type '%s'", | ||
| 14531 | buf_ptr(&err_set_type->name))); | ||
| 14532 | return ira->codegen->invalid_instruction; | 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 | return ira->codegen->invalid_instruction; | 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 | static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_inst, ZigType *var_type, | 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,6 +14661,10 @@ static IrInstruction *ir_analyze_alloca(IrAnalyze *ira, IrInstruction *source_in |
| 14555 | 14661 | ||
| 14556 | if ((err = type_resolve(ira->codegen, var_type, ResolveStatusZeroBitsKnown))) | 14662 | if ((err = type_resolve(ira->codegen, var_type, ResolveStatusZeroBitsKnown))) |
| 14557 | return ira->codegen->invalid_instruction; | 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 | assert(result->base.value.data.x_ptr.special != ConstPtrSpecialInvalid); | 14668 | assert(result->base.value.data.x_ptr.special != ConstPtrSpecialInvalid); |
| 14559 | 14669 | ||
| 14560 | pointee->type = var_type; | 14670 | pointee->type = var_type; |
| ... | @@ -15174,23 +15284,25 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, | ... | @@ -15174,23 +15284,25 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 15174 | 15284 | ||
| 15175 | bool comptime_var_mem = ir_get_var_is_comptime(var); | 15285 | bool comptime_var_mem = ir_get_var_is_comptime(var); |
| 15176 | bool linkage_makes_it_runtime = var->decl_node->data.variable_declaration.is_extern; | 15286 | bool linkage_makes_it_runtime = var->decl_node->data.variable_declaration.is_extern; |
| 15177 | bool is_const = var->src_is_const; | ||
| 15178 | bool is_volatile = false; | 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 | if (linkage_makes_it_runtime) | 15294 | if (linkage_makes_it_runtime) |
| 15181 | goto no_mem_slot; | 15295 | goto no_mem_slot; |
| 15182 | 15296 | ||
| 15183 | if (var->const_value->special == ConstValSpecialStatic) { | 15297 | if (value_is_comptime(var->const_value)) { |
| 15184 | mem_slot = var->const_value; | 15298 | mem_slot = var->const_value; |
| 15185 | } else { | 15299 | } else if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) { |
| 15186 | if (var->mem_slot_index != SIZE_MAX && (comptime_var_mem || var->gen_is_const)) { | 15300 | // find the relevant exec_context |
| 15187 | // find the relevant exec_context | 15301 | assert(var->owner_exec != nullptr); |
| 15188 | assert(var->owner_exec != nullptr); | 15302 | assert(var->owner_exec->analysis != nullptr); |
| 15189 | assert(var->owner_exec->analysis != nullptr); | 15303 | IrExecContext *exec_context = &var->owner_exec->analysis->exec_context; |
| 15190 | IrExecContext *exec_context = &var->owner_exec->analysis->exec_context; | 15304 | assert(var->mem_slot_index < exec_context->mem_slot_list.length); |
| 15191 | assert(var->mem_slot_index < exec_context->mem_slot_list.length); | 15305 | mem_slot = exec_context->mem_slot_list.at(var->mem_slot_index); |
| 15192 | mem_slot = exec_context->mem_slot_list.at(var->mem_slot_index); | ||
| 15193 | } | ||
| 15194 | } | 15306 | } |
| 15195 | 15307 | ||
| 15196 | if (mem_slot != nullptr) { | 15308 | if (mem_slot != nullptr) { |
| ... | @@ -15198,6 +15310,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, | ... | @@ -15198,6 +15310,7 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 15198 | case ConstValSpecialRuntime: | 15310 | case ConstValSpecialRuntime: |
| 15199 | goto no_mem_slot; | 15311 | goto no_mem_slot; |
| 15200 | case ConstValSpecialStatic: // fallthrough | 15312 | case ConstValSpecialStatic: // fallthrough |
| 15313 | case ConstValSpecialLazy: // fallthrough | ||
| 15201 | case ConstValSpecialUndef: { | 15314 | case ConstValSpecialUndef: { |
| 15202 | ConstPtrMut ptr_mut; | 15315 | ConstPtrMut ptr_mut; |
| 15203 | if (comptime_var_mem) { | 15316 | if (comptime_var_mem) { |
| ... | @@ -15208,8 +15321,11 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, | ... | @@ -15208,8 +15321,11 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 15208 | assert(!comptime_var_mem); | 15321 | assert(!comptime_var_mem); |
| 15209 | ptr_mut = ConstPtrMutRuntimeVar; | 15322 | ptr_mut = ConstPtrMutRuntimeVar; |
| 15210 | } | 15323 | } |
| 15211 | return ir_get_const_ptr(ira, instruction, mem_slot, var->var_type, | 15324 | result->value.special = ConstValSpecialStatic; |
| 15212 | ptr_mut, is_const, is_volatile, var->align_bytes); | 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 | zig_unreachable(); | 15331 | zig_unreachable(); |
| ... | @@ -15217,15 +15333,10 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, | ... | @@ -15217,15 +15333,10 @@ static IrInstruction *ir_get_var_ptr(IrAnalyze *ira, IrInstruction *instruction, |
| 15217 | 15333 | ||
| 15218 | no_mem_slot: | 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 | bool in_fn_scope = (scope_fn_entry(var->parent_scope) != nullptr); | 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 | // This function is called when a comptime value becomes accessible at runtime. | 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,7 +15600,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15489 | AstNode *body_node = fn_entry->body_node; | 15600 | AstNode *body_node = fn_entry->body_node; |
| 15490 | result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type, | 15601 | result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type, |
| 15491 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, | 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 | if (inferred_err_set_type != nullptr) { | 15606 | if (inferred_err_set_type != nullptr) { |
| 15495 | inferred_err_set_type->data.error_set.infer_fn = nullptr; | 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,8 +15625,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15513 | ira->codegen->memoized_fn_eval_table.put(exec_scope, result); | 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 | return ira->codegen->invalid_instruction; | 15629 | return ira->codegen->invalid_instruction; |
| 15630 | } | ||
| 15518 | } | 15631 | } |
| 15519 | 15632 | ||
| 15520 | IrInstruction *new_instruction = ir_const(ira, &call_instruction->base, result->type); | 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,7 +15798,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 15685 | ConstExprValue *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope, | 15798 | ConstExprValue *align_result = ir_eval_const_value(ira->codegen, impl_fn->child_scope, |
| 15686 | fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen), | 15799 | fn_proto_node->data.fn_proto.align_expr, get_align_amt_type(ira->codegen), |
| 15687 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, | 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 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, | 15803 | IrInstructionConst *const_instruction = ir_create_instruction<IrInstructionConst>(&ira->new_irb, |
| 15690 | impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr); | 15804 | impl_fn->child_scope, fn_proto_node->data.fn_proto.align_expr); |
| 15691 | copy_const_val(&const_instruction->base.value, align_result, true); | 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,51 +16180,20 @@ static Error ir_read_const_ptr(IrAnalyze *ira, CodeGen *codegen, AstNode *source |
| 16066 | zig_unreachable(); | 16180 | zig_unreachable(); |
| 16067 | } | 16181 | } |
| 16068 | 16182 | ||
| 16069 | static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp *un_op_instruction) { | 16183 | static IrInstruction *ir_analyze_optional_type(IrAnalyze *ira, IrInstructionUnOp *instruction) { |
| 16070 | Error err; | 16184 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); |
| 16071 | IrInstruction *value = un_op_instruction->value->child; | 16185 | result->value.special = ConstValSpecialLazy; |
| 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; | ||
| 16077 | 16186 | ||
| 16078 | switch (type_entry->id) { | 16187 | LazyValueOptType *lazy_opt_type = allocate<LazyValueOptType>(1); |
| 16079 | case ZigTypeIdInvalid: | 16188 | lazy_opt_type->ira = ira; |
| 16080 | zig_unreachable(); | 16189 | result->value.data.x_lazy = &lazy_opt_type->base; |
| 16081 | case ZigTypeIdMetaType: | 16190 | lazy_opt_type->base.id = LazyValueIdOptType; |
| 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)); | ||
| 16106 | 16191 | ||
| 16107 | case ZigTypeIdUnreachable: | 16192 | lazy_opt_type->payload_type = instruction->value->child; |
| 16108 | case ZigTypeIdOpaque: | 16193 | if (ir_resolve_type_lazy(ira, lazy_opt_type->payload_type) == nullptr) |
| 16109 | ir_add_error_node(ira, un_op_instruction->base.source_node, | 16194 | return ira->codegen->invalid_instruction; |
| 16110 | buf_sprintf("type '%s' not optional", buf_ptr(&type_entry->name))); | 16195 | |
| 16111 | return ira->codegen->invalid_instruction; | 16196 | return result; |
| 16112 | } | ||
| 16113 | zig_unreachable(); | ||
| 16114 | } | 16197 | } |
| 16115 | 16198 | ||
| 16116 | static ErrorMsg *ir_eval_negation_scalar(IrAnalyze *ira, IrInstruction *source_instr, ZigType *scalar_type, | 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,14 +16810,14 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 16727 | return ira->codegen->invalid_instruction; | 16810 | return ira->codegen->invalid_instruction; |
| 16728 | 16811 | ||
| 16729 | bool safety_check_on = elem_ptr_instruction->safety_check_on; | 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 | return ira->codegen->invalid_instruction; | 16814 | return ira->codegen->invalid_instruction; |
| 16732 | 16815 | ||
| 16733 | uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type); | 16816 | uint64_t elem_size = type_size(ira->codegen, return_type->data.pointer.child_type); |
| 16734 | uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type); | 16817 | uint64_t abi_align = get_abi_alignment(ira->codegen, return_type->data.pointer.child_type); |
| 16735 | uint64_t ptr_align = get_ptr_align(ira->codegen, return_type); | 16818 | uint64_t ptr_align = get_ptr_align(ira->codegen, return_type); |
| 16736 | if (instr_is_comptime(casted_elem_index)) { | 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 | if (array_type->id == ZigTypeIdArray) { | 16821 | if (array_type->id == ZigTypeIdArray) { |
| 16739 | uint64_t array_len = array_type->data.array.len; | 16822 | uint64_t array_len = array_type->data.array.len; |
| 16740 | if (index >= array_len) { | 16823 | if (index >= array_len) { |
| ... | @@ -16896,7 +16979,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct | ... | @@ -16896,7 +16979,7 @@ static IrInstruction *ir_analyze_instruction_elem_ptr(IrAnalyze *ira, IrInstruct |
| 16896 | ConstExprValue *len_field = &array_ptr_val->data.x_struct.fields[slice_len_index]; | 16979 | ConstExprValue *len_field = &array_ptr_val->data.x_struct.fields[slice_len_index]; |
| 16897 | IrInstruction *result = ir_const(ira, &elem_ptr_instruction->base, return_type); | 16980 | IrInstruction *result = ir_const(ira, &elem_ptr_instruction->base, return_type); |
| 16898 | ConstExprValue *out_val = &result->value; | 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 | if (index >= slice_len) { | 16983 | if (index >= slice_len) { |
| 16901 | ir_add_error_node(ira, elem_ptr_instruction->base.source_node, | 16984 | ir_add_error_node(ira, elem_ptr_instruction->base.source_node, |
| 16902 | buf_sprintf("index %" ZIG_PRI_u64 " outside slice of size %" ZIG_PRI_u64, | 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,7 +17088,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, |
| 17005 | auto entry = container_scope->decl_table.maybe_get(field_name); | 17088 | auto entry = container_scope->decl_table.maybe_get(field_name); |
| 17006 | Tld *tld = entry ? entry->value : nullptr; | 17089 | Tld *tld = entry ? entry->value : nullptr; |
| 17007 | if (tld && tld->id == TldIdFn) { | 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 | if (tld->resolution == TldResolutionInvalid) | 17092 | if (tld->resolution == TldResolutionInvalid) |
| 17010 | return ira->codegen->invalid_instruction; | 17093 | return ira->codegen->invalid_instruction; |
| 17011 | TldFn *tld_fn = (TldFn *)tld; | 17094 | TldFn *tld_fn = (TldFn *)tld; |
| ... | @@ -17038,27 +17121,31 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, | ... | @@ -17038,27 +17121,31 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira, |
| 17038 | static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction *source_instr, | 17121 | static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction *source_instr, |
| 17039 | TypeStructField *field, IrInstruction *struct_ptr, ZigType *struct_type, bool initializing) | 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 | case OnePossibleValueInvalid: | 17129 | case OnePossibleValueInvalid: |
| 17043 | return ira->codegen->invalid_instruction; | 17130 | return ira->codegen->invalid_instruction; |
| 17044 | case OnePossibleValueYes: { | 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 | return ir_get_ref(ira, source_instr, elem, false, false); | 17133 | return ir_get_ref(ira, source_instr, elem, false, false); |
| 17047 | } | 17134 | } |
| 17048 | case OnePossibleValueNo: | 17135 | case OnePossibleValueNo: |
| 17049 | break; | 17136 | break; |
| 17050 | } | 17137 | } |
| 17138 | if ((err = type_resolve(ira->codegen, struct_type, ResolveStatusAlignmentKnown))) | ||
| 17139 | return ira->codegen->invalid_instruction; | ||
| 17051 | assert(struct_ptr->value.type->id == ZigTypeIdPointer); | 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 | uint32_t ptr_bit_offset = struct_ptr->value.type->data.pointer.bit_offset_in_host; | 17141 | uint32_t ptr_bit_offset = struct_ptr->value.type->data.pointer.bit_offset_in_host; |
| 17055 | uint32_t ptr_host_int_bytes = struct_ptr->value.type->data.pointer.host_int_bytes; | 17142 | uint32_t ptr_host_int_bytes = struct_ptr->value.type->data.pointer.host_int_bytes; |
| 17056 | uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ? | 17143 | uint32_t host_int_bytes_for_result_type = (ptr_host_int_bytes == 0) ? |
| 17057 | get_host_int_bytes(ira->codegen, struct_type, field) : ptr_host_int_bytes; | 17144 | get_host_int_bytes(ira->codegen, struct_type, field) : ptr_host_int_bytes; |
| 17058 | bool is_const = struct_ptr->value.type->data.pointer.is_const; | 17145 | bool is_const = struct_ptr->value.type->data.pointer.is_const; |
| 17059 | bool is_volatile = struct_ptr->value.type->data.pointer.is_volatile; | 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, | 17147 | ZigType *ptr_type = get_pointer_to_type_extra(ira->codegen, field_type, |
| 17061 | is_const, is_volatile, PtrLenSingle, align_bytes, | 17148 | is_const, is_volatile, PtrLenSingle, field->align, |
| 17062 | (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), | 17149 | (uint32_t)(ptr_bit_offset + field->bit_offset_in_host), |
| 17063 | (uint32_t)host_int_bytes_for_result_type, false); | 17150 | (uint32_t)host_int_bytes_for_result_type, false); |
| 17064 | if (instr_is_comptime(struct_ptr)) { | 17151 | if (instr_is_comptime(struct_ptr)) { |
| ... | @@ -17113,7 +17200,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ | ... | @@ -17113,7 +17200,7 @@ static IrInstruction *ir_analyze_container_field_ptr(IrAnalyze *ira, Buf *field_ |
| 17113 | Error err; | 17200 | Error err; |
| 17114 | 17201 | ||
| 17115 | ZigType *bare_type = container_ref_type(container_type); | 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 | return ira->codegen->invalid_instruction; | 17204 | return ira->codegen->invalid_instruction; |
| 17118 | 17205 | ||
| 17119 | assert(container_ptr->value.type->id == ZigTypeIdPointer); | 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,23 +17330,22 @@ static void add_link_lib_symbol(IrAnalyze *ira, Buf *lib_name, Buf *symbol_name, |
| 17243 | } | 17330 | } |
| 17244 | 17331 | ||
| 17245 | static IrInstruction *ir_error_dependency_loop(IrAnalyze *ira, IrInstruction *source_instr) { | 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")); | 17333 | ir_add_error(ira, source_instr, buf_sprintf("dependency loop detected")); |
| 17247 | emit_error_notes_for_ref_stack(ira->codegen, msg); | ||
| 17248 | return ira->codegen->invalid_instruction; | 17334 | return ira->codegen->invalid_instruction; |
| 17249 | } | 17335 | } |
| 17250 | 17336 | ||
| 17251 | static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_instruction, Tld *tld) { | 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); | 17338 | resolve_top_level_decl(ira->codegen, tld, source_instruction->source_node, true); |
| 17253 | if (tld->resolution == TldResolutionInvalid) | 17339 | if (tld->resolution == TldResolutionInvalid) { |
| 17254 | return ira->codegen->invalid_instruction; | 17340 | return ira->codegen->invalid_instruction; |
| 17341 | } | ||
| 17255 | 17342 | ||
| 17256 | switch (tld->id) { | 17343 | switch (tld->id) { |
| 17257 | case TldIdContainer: | 17344 | case TldIdContainer: |
| 17258 | case TldIdCompTime: | 17345 | case TldIdCompTime: |
| 17259 | case TldIdUsingNamespace: | 17346 | case TldIdUsingNamespace: |
| 17260 | zig_unreachable(); | 17347 | zig_unreachable(); |
| 17261 | case TldIdVar: | 17348 | case TldIdVar: { |
| 17262 | { | ||
| 17263 | TldVar *tld_var = (TldVar *)tld; | 17349 | TldVar *tld_var = (TldVar *)tld; |
| 17264 | ZigVar *var = tld_var->var; | 17350 | ZigVar *var = tld_var->var; |
| 17265 | if (var == nullptr) { | 17351 | if (var == nullptr) { |
| ... | @@ -17271,8 +17357,7 @@ static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_ | ... | @@ -17271,8 +17357,7 @@ static IrInstruction *ir_analyze_decl_ref(IrAnalyze *ira, IrInstruction *source_ |
| 17271 | 17357 | ||
| 17272 | return ir_get_var_ptr(ira, source_instruction, var); | 17358 | return ir_get_var_ptr(ira, source_instruction, var); |
| 17273 | } | 17359 | } |
| 17274 | case TldIdFn: | 17360 | case TldIdFn: { |
| 17275 | { | ||
| 17276 | TldFn *tld_fn = (TldFn *)tld; | 17361 | TldFn *tld_fn = (TldFn *)tld; |
| 17277 | ZigFn *fn_entry = tld_fn->fn_entry; | 17362 | ZigFn *fn_entry = tld_fn->fn_entry; |
| 17278 | assert(fn_entry->type_entry); | 17363 | assert(fn_entry->type_entry); |
| ... | @@ -17396,7 +17481,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc | ... | @@ -17396,7 +17481,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc |
| 17396 | return ira->codegen->invalid_instruction; | 17481 | return ira->codegen->invalid_instruction; |
| 17397 | } else if (is_container(child_type)) { | 17482 | } else if (is_container(child_type)) { |
| 17398 | if (child_type->id == ZigTypeIdEnum) { | 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 | return ira->codegen->invalid_instruction; | 17485 | return ira->codegen->invalid_instruction; |
| 17401 | 17486 | ||
| 17402 | TypeEnumField *field = find_enum_type_field(child_type, field_name); | 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,7 +17510,7 @@ static IrInstruction *ir_analyze_instruction_field_ptr(IrAnalyze *ira, IrInstruc |
| 17425 | (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr || | 17510 | (child_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr || |
| 17426 | child_type->data.unionation.decl_node->data.container_decl.auto_enum)) | 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 | return ira->codegen->invalid_instruction; | 17514 | return ira->codegen->invalid_instruction; |
| 17430 | TypeUnionField *field = find_union_type_field(child_type, field_name); | 17515 | TypeUnionField *field = find_union_type_field(child_type, field_name); |
| 17431 | if (field) { | 17516 | if (field) { |
| ... | @@ -17844,65 +17929,29 @@ static IrInstruction *ir_analyze_instruction_any_frame_type(IrAnalyze *ira, | ... | @@ -17844,65 +17929,29 @@ static IrInstruction *ir_analyze_instruction_any_frame_type(IrAnalyze *ira, |
| 17844 | static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, | 17929 | static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira, |
| 17845 | IrInstructionSliceType *slice_type_instruction) | 17930 | IrInstructionSliceType *slice_type_instruction) |
| 17846 | { | 17931 | { |
| 17847 | Error err; | 17932 | IrInstruction *result = ir_const(ira, &slice_type_instruction->base, ira->codegen->builtin_types.entry_type); |
| 17848 | uint32_t align_bytes = 0; | 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 | if (slice_type_instruction->align_value != nullptr) { | 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 | return ira->codegen->invalid_instruction; | 17943 | return ira->codegen->invalid_instruction; |
| 17852 | } | 17944 | } |
| 17853 | 17945 | ||
| 17854 | ZigType *child_type = ir_resolve_type(ira, slice_type_instruction->child_type->child); | 17946 | lazy_slice_type->elem_type = slice_type_instruction->child_type->child; |
| 17855 | if (type_is_invalid(child_type)) | 17947 | if (ir_resolve_type_lazy(ira, lazy_slice_type->elem_type) == nullptr) |
| 17856 | return ira->codegen->invalid_instruction; | 17948 | return ira->codegen->invalid_instruction; |
| 17857 | 17949 | ||
| 17858 | bool is_const = slice_type_instruction->is_const; | 17950 | lazy_slice_type->is_const = slice_type_instruction->is_const; |
| 17859 | bool is_volatile = slice_type_instruction->is_volatile; | 17951 | lazy_slice_type->is_volatile = slice_type_instruction->is_volatile; |
| 17860 | bool is_allow_zero = slice_type_instruction->is_allow_zero; | 17952 | lazy_slice_type->is_allowzero = slice_type_instruction->is_allow_zero; |
| 17861 | 17953 | ||
| 17862 | switch (child_type->id) { | 17954 | return result; |
| 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(); | ||
| 17906 | } | 17955 | } |
| 17907 | 17956 | ||
| 17908 | static IrInstruction *ir_analyze_instruction_global_asm(IrAnalyze *ira, IrInstructionGlobalAsm *instruction) { | 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,7 +18057,7 @@ static IrInstruction *ir_analyze_instruction_array_type(IrAnalyze *ira, |
| 18008 | case ZigTypeIdFnFrame: | 18057 | case ZigTypeIdFnFrame: |
| 18009 | case ZigTypeIdAnyFrame: | 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 | return ira->codegen->invalid_instruction; | 18061 | return ira->codegen->invalid_instruction; |
| 18013 | ZigType *result_type = get_array_type(ira->codegen, child_type, size); | 18062 | ZigType *result_type = get_array_type(ira->codegen, child_type, size); |
| 18014 | return ir_const_type(ira, &array_type_instruction->base, result_type); | 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,7 +18073,7 @@ static IrInstruction *ir_analyze_instruction_size_of(IrAnalyze *ira, |
| 18024 | IrInstruction *type_value = size_of_instruction->type_value->child; | 18073 | IrInstruction *type_value = size_of_instruction->type_value->child; |
| 18025 | ZigType *type_entry = ir_resolve_type(ira, type_value); | 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 | return ira->codegen->invalid_instruction; | 18077 | return ira->codegen->invalid_instruction; |
| 18029 | 18078 | ||
| 18030 | switch (type_entry->id) { | 18079 | switch (type_entry->id) { |
| ... | @@ -18529,7 +18578,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, | ... | @@ -18529,7 +18578,7 @@ static IrInstruction *ir_analyze_instruction_switch_target(IrAnalyze *ira, |
| 18529 | if (pointee_val->special == ConstValSpecialRuntime) | 18578 | if (pointee_val->special == ConstValSpecialRuntime) |
| 18530 | pointee_val = nullptr; | 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 | return ira->codegen->invalid_instruction; | 18582 | return ira->codegen->invalid_instruction; |
| 18534 | 18583 | ||
| 18535 | switch (target_type->id) { | 18584 | switch (target_type->id) { |
| ... | @@ -19070,7 +19119,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc | ... | @@ -19070,7 +19119,7 @@ static IrInstruction *ir_analyze_container_init_fields(IrAnalyze *ira, IrInstruc |
| 19070 | Scope *analyze_scope = &get_container_scope(container_type)->base; | 19119 | Scope *analyze_scope = &get_container_scope(container_type)->base; |
| 19071 | // memoize it | 19120 | // memoize it |
| 19072 | field->init_val = analyze_const_value(ira->codegen, analyze_scope, init_node, | 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 | if (type_is_invalid(field->init_val->type)) | 19124 | if (type_is_invalid(field->init_val->type)) |
| 19076 | return ira->codegen->invalid_instruction; | 19125 | return ira->codegen->invalid_instruction; |
| ... | @@ -19276,8 +19325,7 @@ static IrInstruction *ir_analyze_instruction_compile_err(IrAnalyze *ira, | ... | @@ -19276,8 +19325,7 @@ static IrInstruction *ir_analyze_instruction_compile_err(IrAnalyze *ira, |
| 19276 | if (!msg_buf) | 19325 | if (!msg_buf) |
| 19277 | return ira->codegen->invalid_instruction; | 19326 | return ira->codegen->invalid_instruction; |
| 19278 | 19327 | ||
| 19279 | ErrorMsg *msg = ir_add_error(ira, &instruction->base, msg_buf); | 19328 | ir_add_error(ira, &instruction->base, msg_buf); |
| 19280 | emit_error_notes_for_ref_stack(ira->codegen, msg); | ||
| 19281 | 19329 | ||
| 19282 | return ira->codegen->invalid_instruction; | 19330 | return ira->codegen->invalid_instruction; |
| 19283 | } | 19331 | } |
| ... | @@ -19319,7 +19367,10 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct | ... | @@ -19319,7 +19367,10 @@ static IrInstruction *ir_analyze_instruction_err_name(IrAnalyze *ira, IrInstruct |
| 19319 | ZigType *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, | 19367 | ZigType *u8_ptr_type = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, |
| 19320 | true, false, PtrLenUnknown, 0, 0, 0, false); | 19368 | true, false, PtrLenUnknown, 0, 0, 0, false); |
| 19321 | ZigType *str_type = get_slice_type(ira->codegen, u8_ptr_type); | 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 | ErrorTableEntry *err = casted_value->value.data.x_err_set; | 19374 | ErrorTableEntry *err = casted_value->value.data.x_err_set; |
| 19324 | if (!err->cached_error_name_val) { | 19375 | if (!err->cached_error_name_val) { |
| 19325 | ConstExprValue *array_val = create_const_str_lit(ira->codegen, &err->name); | 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,7 +19442,7 @@ static IrInstruction *ir_analyze_instruction_field_parent_ptr(IrAnalyze *ira, |
| 19391 | return ira->codegen->invalid_instruction; | 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 | return ira->codegen->invalid_instruction; | 19446 | return ira->codegen->invalid_instruction; |
| 19396 | 19447 | ||
| 19397 | TypeStructField *field = find_struct_type_field(container_type, field_name); | 19448 | TypeStructField *field = find_struct_type_field(container_type, field_name); |
| ... | @@ -19470,7 +19521,7 @@ static TypeStructField *validate_byte_offset(IrAnalyze *ira, | ... | @@ -19470,7 +19521,7 @@ static TypeStructField *validate_byte_offset(IrAnalyze *ira, |
| 19470 | return nullptr; | 19521 | return nullptr; |
| 19471 | 19522 | ||
| 19472 | Error err; | 19523 | Error err; |
| 19473 | if ((err = ensure_complete_type(ira->codegen, container_type))) | 19524 | if ((err = type_resolve(ira->codegen, container_type, ResolveStatusSizeKnown))) |
| 19474 | return nullptr; | 19525 | return nullptr; |
| 19475 | 19526 | ||
| 19476 | Buf *field_name = ir_resolve_str(ira, field_name_value); | 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,11 +19625,9 @@ static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, Zig |
| 19574 | 19625 | ||
| 19575 | ZigVar *var = tld->var; | 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 | assert(var->const_value->type->id == ZigTypeIdMetaType); | 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 | static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr, ConstExprValue *out_val, | 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,15 +19643,15 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr |
| 19594 | ensure_field_index(type_info_declaration_type, "data", 2); | 19643 | ensure_field_index(type_info_declaration_type, "data", 2); |
| 19595 | 19644 | ||
| 19596 | ZigType *type_info_declaration_data_type = ir_type_info_get_type(ira, "Data", type_info_declaration_type); | 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 | return err; | 19647 | return err; |
| 19599 | 19648 | ||
| 19600 | ZigType *type_info_fn_decl_type = ir_type_info_get_type(ira, "FnDecl", type_info_declaration_data_type); | 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 | return err; | 19651 | return err; |
| 19603 | 19652 | ||
| 19604 | ZigType *type_info_fn_decl_inline_type = ir_type_info_get_type(ira, "Inline", type_info_fn_decl_type); | 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 | return err; | 19655 | return err; |
| 19607 | 19656 | ||
| 19608 | // Loop through our declarations once to figure out how many declarations we will generate info for. | 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,7 +19662,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr |
| 19613 | while ((curr_entry = decl_it.next()) != nullptr) { | 19662 | while ((curr_entry = decl_it.next()) != nullptr) { |
| 19614 | // If the declaration is unresolved, force it to be resolved again. | 19663 | // If the declaration is unresolved, force it to be resolved again. |
| 19615 | if (curr_entry->value->resolution == TldResolutionUnresolved) { | 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 | if (curr_entry->value->resolution != TldResolutionOk) { | 19666 | if (curr_entry->value->resolution != TldResolutionOk) { |
| 19618 | return ErrorSemanticAnalyzeFail; | 19667 | return ErrorSemanticAnalyzeFail; |
| 19619 | } | 19668 | } |
| ... | @@ -19673,7 +19722,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr | ... | @@ -19673,7 +19722,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr |
| 19673 | case TldIdVar: | 19722 | case TldIdVar: |
| 19674 | { | 19723 | { |
| 19675 | ZigVar *var = ((TldVar *)curr_entry->value)->var; | 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 | return ErrorSemanticAnalyzeFail; | 19726 | return ErrorSemanticAnalyzeFail; |
| 19678 | 19727 | ||
| 19679 | if (var->const_value->type->id == ZigTypeIdMetaType) { | 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,7 +19848,7 @@ static Error ir_make_type_info_decls(IrAnalyze *ira, IrInstruction *source_instr |
| 19799 | case TldIdContainer: | 19848 | case TldIdContainer: |
| 19800 | { | 19849 | { |
| 19801 | ZigType *type_entry = ((TldContainer *)curr_entry->value)->type_entry; | 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 | return ErrorSemanticAnalyzeFail; | 19852 | return ErrorSemanticAnalyzeFail; |
| 19804 | 19853 | ||
| 19805 | // This is a type. | 19854 | // This is a type. |
| ... | @@ -19855,7 +19904,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty | ... | @@ -19855,7 +19904,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty |
| 19855 | return nullptr; | 19904 | return nullptr; |
| 19856 | 19905 | ||
| 19857 | ZigType *type_info_pointer_type = ir_type_info_get_type(ira, "Pointer", nullptr); | 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 | ConstExprValue *result = create_const_vals(1); | 19909 | ConstExprValue *result = create_const_vals(1); |
| 19861 | result->special = ConstValSpecialStatic; | 19910 | result->special = ConstValSpecialStatic; |
| ... | @@ -19867,7 +19916,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty | ... | @@ -19867,7 +19916,7 @@ static ConstExprValue *create_ptr_like_type_info(IrAnalyze *ira, ZigType *ptr_ty |
| 19867 | // size: Size | 19916 | // size: Size |
| 19868 | ensure_field_index(result->type, "size", 0); | 19917 | ensure_field_index(result->type, "size", 0); |
| 19869 | ZigType *type_info_pointer_size_type = ir_type_info_get_type(ira, "Size", type_info_pointer_type); | 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 | fields[0].special = ConstValSpecialStatic; | 19920 | fields[0].special = ConstValSpecialStatic; |
| 19872 | fields[0].type = type_info_pointer_size_type; | 19921 | fields[0].type = type_info_pointer_size_type; |
| 19873 | bigint_init_unsigned(&fields[0].data.x_enum_tag, size_enum_index); | 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,6 +20394,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInstruction *source_instr |
| 20345 | inner_fields[1].special = ConstValSpecialStatic; | 20394 | inner_fields[1].special = ConstValSpecialStatic; |
| 20346 | inner_fields[1].type = get_optional_type(ira->codegen, ira->codegen->builtin_types.entry_num_lit_int); | 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 | if (!type_has_bits(struct_field->type_entry)) { | 20402 | if (!type_has_bits(struct_field->type_entry)) { |
| 20349 | inner_fields[1].data.x_optional = nullptr; | 20403 | inner_fields[1].data.x_optional = nullptr; |
| 20350 | } else { | 20404 | } else { |
| ... | @@ -20581,7 +20635,7 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct | ... | @@ -20581,7 +20635,7 @@ static IrInstruction *ir_analyze_instruction_c_import(IrAnalyze *ira, IrInstruct |
| 20581 | ZigType *void_type = ira->codegen->builtin_types.entry_void; | 20635 | ZigType *void_type = ira->codegen->builtin_types.entry_void; |
| 20582 | ConstExprValue *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type, | 20636 | ConstExprValue *cimport_result = ir_eval_const_value(ira->codegen, &cimport_scope->base, block_node, void_type, |
| 20583 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, nullptr, | 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 | if (type_is_invalid(cimport_result->type)) | 20639 | if (type_is_invalid(cimport_result->type)) |
| 20586 | return ira->codegen->invalid_instruction; | 20640 | return ira->codegen->invalid_instruction; |
| 20587 | 20641 | ||
| ... | @@ -21181,7 +21235,7 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru | ... | @@ -21181,7 +21235,7 @@ static IrInstruction *ir_analyze_instruction_from_bytes(IrAnalyze *ira, IrInstru |
| 21181 | 21235 | ||
| 21182 | ConstExprValue *len_val = &val->data.x_struct.fields[slice_len_index]; | 21236 | ConstExprValue *len_val = &val->data.x_struct.fields[slice_len_index]; |
| 21183 | if (value_is_comptime(len_val)) { | 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 | have_known_len = true; | 21239 | have_known_len = true; |
| 21186 | } | 21240 | } |
| 21187 | } | 21241 | } |
| ... | @@ -21482,64 +21536,75 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio | ... | @@ -21482,64 +21536,75 @@ static IrInstruction *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructio |
| 21482 | return ira->codegen->invalid_instruction; | 21536 | return ira->codegen->invalid_instruction; |
| 21483 | 21537 | ||
| 21484 | // TODO test this at comptime with u8 and non-u8 types | 21538 | // TODO test this at comptime with u8 and non-u8 types |
| 21485 | if (casted_dest_ptr->value.special == ConstValSpecialStatic && | 21539 | if (instr_is_comptime(casted_dest_ptr) && |
| 21486 | casted_byte->value.special == ConstValSpecialStatic && | 21540 | instr_is_comptime(casted_byte) && |
| 21487 | casted_count->value.special == ConstValSpecialStatic && | 21541 | instr_is_comptime(casted_count)) |
| 21488 | casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr && | ||
| 21489 | casted_dest_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) | ||
| 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; | 21547 | ConstExprValue *byte_val = ir_resolve_const(ira, casted_byte, UndefOk); |
| 21494 | size_t start; | 21548 | if (byte_val == nullptr) |
| 21495 | size_t bound_end; | 21549 | return ira->codegen->invalid_instruction; |
| 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 | } | ||
| 21529 | 21550 | ||
| 21530 | size_t count = bigint_as_unsigned(&casted_count->value.data.x_bigint); | 21551 | ConstExprValue *count_val = ir_resolve_const(ira, casted_count, UndefBad); |
| 21531 | size_t end = start + count; | 21552 | if (count_val == nullptr) |
| 21532 | if (end > bound_end) { | ||
| 21533 | ir_add_error(ira, count_value, buf_sprintf("out of bounds pointer access")); | ||
| 21534 | return ira->codegen->invalid_instruction; | 21553 | return ira->codegen->invalid_instruction; |
| 21535 | } | ||
| 21536 | 21554 | ||
| 21537 | ConstExprValue *byte_val = &casted_byte->value; | 21555 | if (casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr && |
| 21538 | for (size_t i = start; i < end; i += 1) { | 21556 | casted_dest_ptr->value.data.x_ptr.mut != ConstPtrMutRuntimeVar) |
| 21539 | copy_const_val(&dest_elements[i], byte_val, true); | 21557 | { |
| 21540 | } | 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 | IrInstruction *result = ir_build_memset(&ira->new_irb, instruction->base.scope, instruction->base.source_node, | 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,107 +21672,118 @@ static IrInstruction *ir_analyze_instruction_memcpy(IrAnalyze *ira, IrInstructio |
| 21607 | 21672 | ||
| 21608 | // TODO test this at comptime with u8 and non-u8 types | 21673 | // TODO test this at comptime with u8 and non-u8 types |
| 21609 | // TODO test with dest ptr being a global runtime variable | 21674 | // TODO test with dest ptr being a global runtime variable |
| 21610 | if (casted_dest_ptr->value.special == ConstValSpecialStatic && | 21675 | if (instr_is_comptime(casted_dest_ptr) && |
| 21611 | casted_src_ptr->value.special == ConstValSpecialStatic && | 21676 | instr_is_comptime(casted_src_ptr) && |
| 21612 | casted_count->value.special == ConstValSpecialStatic && | 21677 | instr_is_comptime(casted_count)) |
| 21613 | casted_dest_ptr->value.data.x_ptr.special != ConstPtrSpecialHardCodedAddr) | ||
| 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; | 21683 | ConstExprValue *src_ptr_val = ir_resolve_const(ira, casted_src_ptr, UndefBad); |
| 21618 | ConstExprValue *dest_elements; | 21684 | if (src_ptr_val == nullptr) |
| 21619 | size_t dest_start; | 21685 | return ira->codegen->invalid_instruction; |
| 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 | } | ||
| 21654 | 21686 | ||
| 21655 | if (dest_start + count > dest_end) { | 21687 | ConstExprValue *count_val = ir_resolve_const(ira, casted_count, UndefBad); |
| 21656 | ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); | 21688 | if (count_val == nullptr) |
| 21657 | return ira->codegen->invalid_instruction; | 21689 | return ira->codegen->invalid_instruction; |
| 21658 | } | ||
| 21659 | 21690 | ||
| 21660 | ConstExprValue *src_ptr_val = &casted_src_ptr->value; | 21691 | if (dest_ptr_val->data.x_ptr.special != ConstPtrSpecialHardCodedAddr) { |
| 21661 | ConstExprValue *src_elements; | 21692 | size_t count = bigint_as_usize(&count_val->data.x_bigint); |
| 21662 | size_t src_start; | ||
| 21663 | size_t src_end; | ||
| 21664 | 21693 | ||
| 21665 | switch (src_ptr_val->data.x_ptr.special) { | 21694 | ConstExprValue *dest_elements; |
| 21666 | case ConstPtrSpecialInvalid: | 21695 | size_t dest_start; |
| 21667 | case ConstPtrSpecialDiscard: | 21696 | size_t dest_end; |
| 21668 | zig_unreachable(); | 21697 | switch (dest_ptr_val->data.x_ptr.special) { |
| 21669 | case ConstPtrSpecialRef: | 21698 | case ConstPtrSpecialInvalid: |
| 21670 | src_elements = src_ptr_val->data.x_ptr.data.ref.pointee; | 21699 | case ConstPtrSpecialDiscard: |
| 21671 | src_start = 0; | 21700 | zig_unreachable(); |
| 21672 | src_end = 1; | 21701 | case ConstPtrSpecialRef: |
| 21673 | break; | 21702 | dest_elements = dest_ptr_val->data.x_ptr.data.ref.pointee; |
| 21674 | case ConstPtrSpecialBaseArray: | 21703 | dest_start = 0; |
| 21675 | { | 21704 | dest_end = 1; |
| 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; | ||
| 21681 | break; | 21705 | break; |
| 21682 | } | 21706 | case ConstPtrSpecialBaseArray: |
| 21683 | case ConstPtrSpecialBaseStruct: | 21707 | { |
| 21684 | zig_panic("TODO memcpy on const inner struct"); | 21708 | ConstExprValue *array_val = dest_ptr_val->data.x_ptr.data.base_array.array_val; |
| 21685 | case ConstPtrSpecialBaseErrorUnionCode: | 21709 | expand_undef_array(ira->codegen, array_val); |
| 21686 | zig_panic("TODO memcpy on const inner error union code"); | 21710 | dest_elements = array_val->data.x_array.data.s_none.elements; |
| 21687 | case ConstPtrSpecialBaseErrorUnionPayload: | 21711 | dest_start = dest_ptr_val->data.x_ptr.data.base_array.elem_index; |
| 21688 | zig_panic("TODO memcpy on const inner error union payload"); | 21712 | dest_end = array_val->type->data.array.len; |
| 21689 | case ConstPtrSpecialBaseOptionalPayload: | 21713 | break; |
| 21690 | zig_panic("TODO memcpy on const inner optional payload"); | 21714 | } |
| 21691 | case ConstPtrSpecialHardCodedAddr: | 21715 | case ConstPtrSpecialBaseStruct: |
| 21692 | zig_unreachable(); | 21716 | zig_panic("TODO memcpy on const inner struct"); |
| 21693 | case ConstPtrSpecialFunction: | 21717 | case ConstPtrSpecialBaseErrorUnionCode: |
| 21694 | zig_panic("TODO memcpy on ptr cast from function"); | 21718 | zig_panic("TODO memcpy on const inner error union code"); |
| 21695 | case ConstPtrSpecialNull: | 21719 | case ConstPtrSpecialBaseErrorUnionPayload: |
| 21696 | zig_panic("TODO memcpy on null ptr"); | 21720 | zig_panic("TODO memcpy on const inner error union payload"); |
| 21697 | } | 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) { | 21731 | if (dest_start + count > dest_end) { |
| 21700 | ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); | 21732 | ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds pointer access")); |
| 21701 | return ira->codegen->invalid_instruction; | 21733 | return ira->codegen->invalid_instruction; |
| 21702 | } | 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) { | 21740 | switch (src_ptr_val->data.x_ptr.special) { |
| 21707 | copy_const_val(&dest_elements[dest_start + i], &src_elements[src_start + i], true); | 21741 | case ConstPtrSpecialInvalid: |
| 21708 | } | 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 | IrInstruction *result = ir_build_memcpy(&ira->new_irb, instruction->base.scope, instruction->base.source_node, | 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,6 +21953,11 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 21877 | if (slice_ptr == nullptr) | 21953 | if (slice_ptr == nullptr) |
| 21878 | return ira->codegen->invalid_instruction; | 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 | parent_ptr = &slice_ptr->data.x_struct.fields[slice_ptr_index]; | 21961 | parent_ptr = &slice_ptr->data.x_struct.fields[slice_ptr_index]; |
| 21881 | if (parent_ptr->special == ConstValSpecialUndef) { | 21962 | if (parent_ptr->special == ConstValSpecialUndef) { |
| 21882 | ir_add_error(ira, &instruction->base, buf_sprintf("slice of undefined")); | 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,7 +21978,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 21897 | case ConstPtrSpecialBaseArray: | 21978 | case ConstPtrSpecialBaseArray: |
| 21898 | array_val = parent_ptr->data.x_ptr.data.base_array.array_val; | 21979 | array_val = parent_ptr->data.x_ptr.data.base_array.array_val; |
| 21899 | abs_offset = parent_ptr->data.x_ptr.data.base_array.elem_index; | 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 | break; | 21982 | break; |
| 21902 | case ConstPtrSpecialBaseStruct: | 21983 | case ConstPtrSpecialBaseStruct: |
| 21903 | zig_panic("TODO slice const inner struct"); | 21984 | zig_panic("TODO slice const inner struct"); |
| ... | @@ -21910,7 +21991,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction | ... | @@ -21910,7 +21991,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 21910 | case ConstPtrSpecialHardCodedAddr: | 21991 | case ConstPtrSpecialHardCodedAddr: |
| 21911 | array_val = nullptr; | 21992 | array_val = nullptr; |
| 21912 | abs_offset = 0; | 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 | break; | 21995 | break; |
| 21915 | case ConstPtrSpecialFunction: | 21996 | case ConstPtrSpecialFunction: |
| 21916 | zig_panic("TODO slice of slice cast from function"); | 21997 | zig_panic("TODO slice of slice cast from function"); |
| ... | @@ -21921,7 +22002,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction | ... | @@ -21921,7 +22002,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 21921 | zig_unreachable(); | 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 | if (!ptr_is_undef && start_scalar > rel_end) { | 22006 | if (!ptr_is_undef && start_scalar > rel_end) { |
| 21926 | ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice")); | 22007 | ir_add_error(ira, &instruction->base, buf_sprintf("out of bounds slice")); |
| 21927 | return ira->codegen->invalid_instruction; | 22008 | return ira->codegen->invalid_instruction; |
| ... | @@ -21929,7 +22010,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction | ... | @@ -21929,7 +22010,7 @@ static IrInstruction *ir_analyze_instruction_slice(IrAnalyze *ira, IrInstruction |
| 21929 | 22010 | ||
| 21930 | uint64_t end_scalar; | 22011 | uint64_t end_scalar; |
| 21931 | if (end) { | 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 | } else { | 22014 | } else { |
| 21934 | end_scalar = rel_end; | 22015 | end_scalar = rel_end; |
| 21935 | } | 22016 | } |
| ... | @@ -22021,7 +22102,7 @@ static IrInstruction *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInst | ... | @@ -22021,7 +22102,7 @@ static IrInstruction *ir_analyze_instruction_member_count(IrAnalyze *ira, IrInst |
| 22021 | return ira->codegen->invalid_instruction; | 22102 | return ira->codegen->invalid_instruction; |
| 22022 | ZigType *container_type = ir_resolve_type(ira, container); | 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 | return ira->codegen->invalid_instruction; | 22106 | return ira->codegen->invalid_instruction; |
| 22026 | 22107 | ||
| 22027 | uint64_t result; | 22108 | uint64_t result; |
| ... | @@ -22057,7 +22138,7 @@ static IrInstruction *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstr | ... | @@ -22057,7 +22138,7 @@ static IrInstruction *ir_analyze_instruction_member_type(IrAnalyze *ira, IrInstr |
| 22057 | if (type_is_invalid(container_type)) | 22138 | if (type_is_invalid(container_type)) |
| 22058 | return ira->codegen->invalid_instruction; | 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 | return ira->codegen->invalid_instruction; | 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,7 +22181,7 @@ static IrInstruction *ir_analyze_instruction_member_name(IrAnalyze *ira, IrInstr |
| 22100 | if (type_is_invalid(container_type)) | 22181 | if (type_is_invalid(container_type)) |
| 22101 | return ira->codegen->invalid_instruction; | 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 | return ira->codegen->invalid_instruction; | 22185 | return ira->codegen->invalid_instruction; |
| 22105 | 22186 | ||
| 22106 | uint64_t member_index; | 22187 | uint64_t member_index; |
| ... | @@ -22249,53 +22330,24 @@ static IrInstruction *ir_analyze_instruction_frame_size(IrAnalyze *ira, IrInstru | ... | @@ -22249,53 +22330,24 @@ static IrInstruction *ir_analyze_instruction_frame_size(IrAnalyze *ira, IrInstru |
| 22249 | } | 22330 | } |
| 22250 | 22331 | ||
| 22251 | static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAlignOf *instruction) { | 22332 | static IrInstruction *ir_analyze_instruction_align_of(IrAnalyze *ira, IrInstructionAlignOf *instruction) { |
| 22252 | Error err; | 22333 | // Here we create a lazy value in order to avoid resolving the alignment of the type |
| 22253 | IrInstruction *type_value = instruction->type_value->child; | 22334 | // immediately. This avoids false positive dependency loops such as: |
| 22254 | if (type_is_invalid(type_value->value.type)) | 22335 | // const Node = struct { |
| 22255 | return ira->codegen->invalid_instruction; | 22336 | // field: []align(@alignOf(Node)) Node, |
| 22256 | ZigType *type_entry = ir_resolve_type(ira, type_value); | 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 | return ira->codegen->invalid_instruction; | 22348 | return ira->codegen->invalid_instruction; |
| 22260 | 22349 | ||
| 22261 | switch (type_entry->id) { | 22350 | return result; |
| 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(); | ||
| 22299 | } | 22351 | } |
| 22300 | 22352 | ||
| 22301 | static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstructionOverflowOp *instruction) { | 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,13 +22411,26 @@ static IrInstruction *ir_analyze_instruction_overflow_op(IrAnalyze *ira, IrInstr |
| 22359 | if (type_is_invalid(casted_result_ptr->value.type)) | 22411 | if (type_is_invalid(casted_result_ptr->value.type)) |
| 22360 | return ira->codegen->invalid_instruction; | 22412 | return ira->codegen->invalid_instruction; |
| 22361 | 22413 | ||
| 22362 | if (casted_op1->value.special == ConstValSpecialStatic && | 22414 | if (instr_is_comptime(casted_op1) && |
| 22363 | casted_op2->value.special == ConstValSpecialStatic && | 22415 | instr_is_comptime(casted_op2) && |
| 22364 | casted_result_ptr->value.special == ConstValSpecialStatic) | 22416 | instr_is_comptime(casted_result_ptr)) |
| 22365 | { | 22417 | { |
| 22366 | BigInt *op1_bigint = &casted_op1->value.data.x_bigint; | 22418 | ConstExprValue *op1_val = ir_resolve_const(ira, casted_op1, UndefBad); |
| 22367 | BigInt *op2_bigint = &casted_op2->value.data.x_bigint; | 22419 | if (op1_val == nullptr) |
| 22368 | ConstExprValue *pointee_val = const_ptr_pointee(ira, ira->codegen, &casted_result_ptr->value, casted_result_ptr->source_node); | 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 | if (pointee_val == nullptr) | 22434 | if (pointee_val == nullptr) |
| 22370 | return ira->codegen->invalid_instruction; | 22435 | return ira->codegen->invalid_instruction; |
| 22371 | BigInt *dest_bigint = &pointee_val->data.x_bigint; | 22436 | BigInt *dest_bigint = &pointee_val->data.x_bigint; |
| ... | @@ -22754,84 +22819,64 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct | ... | @@ -22754,84 +22819,64 @@ static IrInstruction *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruct |
| 22754 | AstNode *proto_node = instruction->base.source_node; | 22819 | AstNode *proto_node = instruction->base.source_node; |
| 22755 | assert(proto_node->type == NodeTypeFnProto); | 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 | if (proto_node->data.fn_proto.auto_err_set) { | 22830 | if (proto_node->data.fn_proto.auto_err_set) { |
| 22758 | ir_add_error(ira, &instruction->base, | 22831 | ir_add_error(ira, &instruction->base, |
| 22759 | buf_sprintf("inferring error set of return type valid only for function definitions")); | 22832 | buf_sprintf("inferring error set of return type valid only for function definitions")); |
| 22760 | return ira->codegen->invalid_instruction; | 22833 | return ira->codegen->invalid_instruction; |
| 22761 | } | 22834 | } |
| 22762 | 22835 | ||
| 22763 | FnTypeId fn_type_id = {0}; | 22836 | size_t param_count = proto_node->data.fn_proto.params.length; |
| 22764 | init_fn_type_id(&fn_type_id, proto_node, 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) { | 22840 | for (size_t param_index = 0; param_index < param_count; param_index += 1) { |
| 22767 | AstNode *param_node = proto_node->data.fn_proto.params.at(fn_type_id.next_param_index); | 22841 | AstNode *param_node = proto_node->data.fn_proto.params.at(param_index); |
| 22768 | assert(param_node->type == NodeTypeParamDecl); | 22842 | assert(param_node->type == NodeTypeParamDecl); |
| 22769 | 22843 | ||
| 22770 | bool param_is_var_args = param_node->data.param_decl.is_var_args; | 22844 | bool param_is_var_args = param_node->data.param_decl.is_var_args; |
| 22771 | if (param_is_var_args) { | 22845 | if (param_is_var_args) { |
| 22772 | if (fn_type_id.cc == CallingConventionC) { | 22846 | if (proto_node->data.fn_proto.cc == CallingConventionC) { |
| 22773 | fn_type_id.param_count = fn_type_id.next_param_index; | 22847 | break; |
| 22774 | continue; | 22848 | } else if (proto_node->data.fn_proto.cc == CallingConventionUnspecified) { |
| 22775 | } else if (fn_type_id.cc == CallingConventionUnspecified) { | 22849 | lazy_fn_type->is_generic = true; |
| 22776 | return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id)); | 22850 | return result; |
| 22777 | } else { | 22851 | } else { |
| 22778 | zig_unreachable(); | 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) { | 22856 | if (instruction->param_types[param_index] == nullptr) { |
| 22785 | param_info->type = nullptr; | 22857 | lazy_fn_type->is_generic = true; |
| 22786 | return ir_const_type(ira, &instruction->base, get_generic_fn_type(ira->codegen, &fn_type_id)); | 22858 | return result; |
| 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; | ||
| 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 | if (instruction->align_value != nullptr) { | 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 | return ira->codegen->invalid_instruction; | 22872 | return ira->codegen->invalid_instruction; |
| 22822 | } | 22873 | } |
| 22823 | 22874 | ||
| 22824 | IrInstruction *return_type_value = instruction->return_type->child; | 22875 | lazy_fn_type->return_type = instruction->return_type->child; |
| 22825 | fn_type_id.return_type = ir_resolve_type(ira, return_type_value); | 22876 | if (ir_resolve_const(ira, lazy_fn_type->return_type, LazyOk) == nullptr) |
| 22826 | if (type_is_invalid(fn_type_id.return_type)) | 22877 | return ira->codegen->invalid_instruction; |
| 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 | } | ||
| 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 | static IrInstruction *ir_analyze_instruction_test_comptime(IrAnalyze *ira, IrInstructionTestComptime *instruction) { | 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,7 +23263,7 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ |
| 23218 | if (!val) | 23263 | if (!val) |
| 23219 | return ira->codegen->invalid_instruction; | 23264 | return ira->codegen->invalid_instruction; |
| 23220 | 23265 | ||
| 23221 | if (val->special == ConstValSpecialStatic) { | 23266 | if (value_is_comptime(val) && val->special != ConstValSpecialUndef) { |
| 23222 | bool is_addr_zero = val->data.x_ptr.special == ConstPtrSpecialNull || | 23267 | bool is_addr_zero = val->data.x_ptr.special == ConstPtrSpecialNull || |
| 23223 | (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && | 23268 | (val->data.x_ptr.special == ConstPtrSpecialHardCodedAddr && |
| 23224 | val->data.x_ptr.data.hard_coded_addr.addr == 0); | 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,6 +23303,12 @@ static IrInstruction *ir_analyze_ptr_cast(IrAnalyze *ira, IrInstruction *source_ |
| 23258 | 23303 | ||
| 23259 | IrInstruction *casted_ptr = ir_build_ptr_cast_gen(ira, source_instr, dest_type, ptr, safety_check_on); | 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 | if (type_has_bits(dest_type) && !type_has_bits(src_type)) { | 23312 | if (type_has_bits(dest_type) && !type_has_bits(src_type)) { |
| 23262 | ErrorMsg *msg = ir_add_error(ira, source_instr, | 23313 | ErrorMsg *msg = ir_add_error(ira, source_instr, |
| 23263 | buf_sprintf("'%s' and '%s' do not have the same in-memory representation", | 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,8 +23360,10 @@ static void buf_write_value_bytes_array(CodeGen *codegen, uint8_t *buf, ConstExp |
| 23309 | } | 23360 | } |
| 23310 | 23361 | ||
| 23311 | static void buf_write_value_bytes(CodeGen *codegen, uint8_t *buf, ConstExprValue *val) { | 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 | val->special = ConstValSpecialStatic; | 23365 | val->special = ConstValSpecialStatic; |
| 23366 | } | ||
| 23314 | assert(val->special == ConstValSpecialStatic); | 23367 | assert(val->special == ConstValSpecialStatic); |
| 23315 | switch (val->type->id) { | 23368 | switch (val->type->id) { |
| 23316 | case ZigTypeIdInvalid: | 23369 | case ZigTypeIdInvalid: |
| ... | @@ -23500,7 +23553,7 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou | ... | @@ -23500,7 +23553,7 @@ static Error buf_read_value_bytes(IrAnalyze *ira, CodeGen *codegen, AstNode *sou |
| 23500 | BigInt bn; | 23553 | BigInt bn; |
| 23501 | bigint_read_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, | 23554 | bigint_read_twos_complement(&bn, buf, codegen->builtin_types.entry_usize->data.integral.bit_count, |
| 23502 | codegen->is_big_endian, false); | 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 | return ErrorNone; | 23557 | return ErrorNone; |
| 23505 | } | 23558 | } |
| 23506 | case ZigTypeIdArray: | 23559 | case ZigTypeIdArray: |
| ... | @@ -23693,7 +23746,7 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc | ... | @@ -23693,7 +23746,7 @@ static IrInstruction *ir_analyze_int_to_ptr(IrAnalyze *ira, IrInstruction *sourc |
| 23693 | if (!val) | 23746 | if (!val) |
| 23694 | return ira->codegen->invalid_instruction; | 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 | if (!ptr_allows_addr_zero(ptr_type) && addr == 0) { | 23750 | if (!ptr_allows_addr_zero(ptr_type) && addr == 0) { |
| 23698 | ir_add_error(ira, source_instr, | 23751 | ir_add_error(ira, source_instr, |
| 23699 | buf_sprintf("pointer type '%s' does not allow address zero", buf_ptr(&ptr_type->name))); | 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,8 +23799,9 @@ static IrInstruction *ir_analyze_instruction_decl_ref(IrAnalyze *ira, |
| 23746 | IrInstructionDeclRef *instruction) | 23799 | IrInstructionDeclRef *instruction) |
| 23747 | { | 23800 | { |
| 23748 | IrInstruction *ref_instruction = ir_analyze_decl_ref(ira, &instruction->base, instruction->tld); | 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 | return ira->codegen->invalid_instruction; | 23803 | return ira->codegen->invalid_instruction; |
| 23804 | } | ||
| 23751 | 23805 | ||
| 23752 | if (instruction->lval == LValPtr) { | 23806 | if (instruction->lval == LValPtr) { |
| 23753 | return ref_instruction; | 23807 | return ref_instruction; |
| ... | @@ -23795,53 +23849,32 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru | ... | @@ -23795,53 +23849,32 @@ static IrInstruction *ir_analyze_instruction_ptr_to_int(IrAnalyze *ira, IrInstru |
| 23795 | } | 23849 | } |
| 23796 | 23850 | ||
| 23797 | static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstructionPtrType *instruction) { | 23851 | static IrInstruction *ir_analyze_instruction_ptr_type(IrAnalyze *ira, IrInstructionPtrType *instruction) { |
| 23798 | Error err; | 23852 | IrInstruction *result = ir_const(ira, &instruction->base, ira->codegen->builtin_types.entry_type); |
| 23799 | ZigType *child_type = ir_resolve_type(ira, instruction->child_type->child); | 23853 | result->value.special = ConstValSpecialLazy; |
| 23800 | if (type_is_invalid(child_type)) | ||
| 23801 | return ira->codegen->invalid_instruction; | ||
| 23802 | 23854 | ||
| 23803 | if (child_type->id == ZigTypeIdUnreachable) { | 23855 | LazyValuePtrType *lazy_ptr_type = allocate<LazyValuePtrType>(1); |
| 23804 | ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed")); | 23856 | lazy_ptr_type->ira = ira; |
| 23805 | return ira->codegen->invalid_instruction; | 23857 | result->value.data.x_lazy = &lazy_ptr_type->base; |
| 23806 | } else if (child_type->id == ZigTypeIdOpaque && instruction->ptr_len == PtrLenUnknown) { | 23858 | lazy_ptr_type->base.id = LazyValueIdPtrType; |
| 23807 | ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque")); | 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 | return ira->codegen->invalid_instruction; | 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 | if (instruction->align_value != nullptr) { | 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 | return ira->codegen->invalid_instruction; | 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, | 23877 | return result; |
| 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); | ||
| 23845 | } | 23878 | } |
| 23846 | 23879 | ||
| 23847 | static IrInstruction *ir_analyze_instruction_align_cast(IrAnalyze *ira, IrInstructionAlignCast *instruction) { | 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,7 +23987,7 @@ static IrInstruction *ir_analyze_instruction_tag_type(IrAnalyze *ira, IrInstruct |
| 23954 | return ira->codegen->invalid_instruction; | 23987 | return ira->codegen->invalid_instruction; |
| 23955 | 23988 | ||
| 23956 | if (enum_type->id == ZigTypeIdEnum) { | 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 | return ira->codegen->invalid_instruction; | 23991 | return ira->codegen->invalid_instruction; |
| 23959 | 23992 | ||
| 23960 | return ir_const_type(ira, &instruction->base, enum_type->data.enumeration.tag_int_type); | 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,7 +25133,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 25100 | ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_exec, | 25133 | ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_exec, |
| 25101 | ZigType *expected_type, AstNode *expected_type_source_node) | 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 | assert(expected_type == nullptr || !type_is_invalid(expected_type)); | 25137 | assert(expected_type == nullptr || !type_is_invalid(expected_type)); |
| 25105 | 25138 | ||
| 25106 | IrAnalyze *ira = allocate<IrAnalyze>(1); | 25139 | IrAnalyze *ira = allocate<IrAnalyze>(1); |
| ... | @@ -25147,6 +25180,18 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ | ... | @@ -25147,6 +25180,18 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ |
| 25147 | old_instruction->child = new_instruction; | 25180 | old_instruction->child = new_instruction; |
| 25148 | 25181 | ||
| 25149 | if (type_is_invalid(new_instruction->value.type)) { | 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 | return ira->codegen->builtin_types.entry_invalid; | 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,7 +25203,15 @@ ZigType *ir_analyze(CodeGen *codegen, IrExecutable *old_exec, IrExecutable *new_ |
| 25158 | ira->instruction_index += 1; | 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 | return ira->codegen->builtin_types.entry_invalid; | 25215 | return ira->codegen->builtin_types.entry_invalid; |
| 25163 | } else if (ira->src_implicit_return_type_list.length == 0) { | 25216 | } else if (ira->src_implicit_return_type_list.length == 0) { |
| 25164 | return codegen->builtin_types.entry_unreachable; | 25217 | return codegen->builtin_types.entry_unreachable; |
| ... | @@ -25354,3 +25407,336 @@ bool ir_has_side_effects(IrInstruction *instruction) { | ... | @@ -25354,3 +25407,336 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 25354 | } | 25407 | } |
| 25355 | zig_unreachable(); | 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,7 +16,9 @@ bool ir_gen_fn(CodeGen *g, ZigFn *fn_entry); |
| 16 | ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, | 16 | ConstExprValue *ir_eval_const_value(CodeGen *codegen, Scope *scope, AstNode *node, |
| 17 | ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota, | 17 | ZigType *expected_type, size_t *backward_branch_count, size_t *backward_branch_quota, |
| 18 | ZigFn *fn_entry, Buf *c_import_buf, AstNode *source_node, Buf *exec_name, | 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 | ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable, | 23 | ZigType *ir_analyze(CodeGen *g, IrExecutable *old_executable, IrExecutable *new_executable, |
| 22 | ZigType *expected_type, AstNode *expected_type_source_node); | 24 | ZigType *expected_type, AstNode *expected_type_source_node); |
| ... | @@ -28,6 +30,4 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal | ... | @@ -28,6 +30,4 @@ ConstExprValue *const_ptr_pointee(IrAnalyze *ira, CodeGen *codegen, ConstExprVal |
| 28 | AstNode *source_node); | 30 | AstNode *source_node); |
| 29 | const char *float_op_to_name(BuiltinFnId op, bool llvm_name); | 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 | #endif | 33 | #endif |
src/os.cpp+15-15| ... | @@ -1125,29 +1125,27 @@ Error os_get_cwd(Buf *out_cwd) { | ... | @@ -1125,29 +1125,27 @@ Error os_get_cwd(Buf *out_cwd) { |
| 1125 | #endif | 1125 | #endif |
| 1126 | } | 1126 | } |
| 1127 | 1127 | ||
| 1128 | #if defined(ZIG_OS_WINDOWS) | ||
| 1129 | #define is_wprefix(s, prefix) \ | 1128 | #define is_wprefix(s, prefix) \ |
| 1130 | (wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0) | 1129 | (wcsncmp((s), (prefix), sizeof(prefix) / sizeof(WCHAR) - 1) == 0) |
| 1131 | static bool is_stderr_cyg_pty(void) { | 1130 | bool ATTRIBUTE_MUST_USE os_is_cygwin_pty(int fd) { |
| 1132 | HANDLE stderr_handle = GetStdHandle(STD_ERROR_HANDLE); | 1131 | #if defined(ZIG_OS_WINDOWS) |
| 1133 | if (stderr_handle == INVALID_HANDLE_VALUE) | 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 | return false; | 1136 | return false; |
| 1137 | } | ||
| 1135 | 1138 | ||
| 1136 | int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * MAX_PATH; | 1139 | int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * MAX_PATH; |
| 1137 | FILE_NAME_INFO *nameinfo; | ||
| 1138 | WCHAR *p = NULL; | 1140 | WCHAR *p = NULL; |
| 1139 | 1141 | ||
| 1140 | // Cygwin/msys's pty is a pipe. | 1142 | FILE_NAME_INFO *nameinfo = (FILE_NAME_INFO *)allocate<char>(size); |
| 1141 | if (GetFileType(stderr_handle) != FILE_TYPE_PIPE) { | ||
| 1142 | return 0; | ||
| 1143 | } | ||
| 1144 | nameinfo = (FILE_NAME_INFO *)allocate<char>(size); | ||
| 1145 | if (nameinfo == NULL) { | 1143 | if (nameinfo == NULL) { |
| 1146 | return 0; | 1144 | return false; |
| 1147 | } | 1145 | } |
| 1148 | // Check the name of the pipe: | 1146 | // Check the name of the pipe: |
| 1149 | // '\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master' | 1147 | // '\{cygwin,msys}-XXXXXXXXXXXXXXXX-ptyN-{from,to}-master' |
| 1150 | if (GetFileInformationByHandleEx(stderr_handle, FileNameInfo, nameinfo, size)) { | 1148 | if (GetFileInformationByHandleEx(handle, FileNameInfo, nameinfo, size)) { |
| 1151 | nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0'; | 1149 | nameinfo->FileName[nameinfo->FileNameLength / sizeof(WCHAR)] = L'\0'; |
| 1152 | p = nameinfo->FileName; | 1150 | p = nameinfo->FileName; |
| 1153 | if (is_wprefix(p, L"\\cygwin-")) { /* Cygwin */ | 1151 | if (is_wprefix(p, L"\\cygwin-")) { /* Cygwin */ |
| ... | @@ -1180,12 +1178,14 @@ static bool is_stderr_cyg_pty(void) { | ... | @@ -1180,12 +1178,14 @@ static bool is_stderr_cyg_pty(void) { |
| 1180 | } | 1178 | } |
| 1181 | free(nameinfo); | 1179 | free(nameinfo); |
| 1182 | return (p != NULL); | 1180 | return (p != NULL); |
| 1183 | } | 1181 | #else |
| 1182 | return false; | ||
| 1184 | #endif | 1183 | #endif |
| 1184 | } | ||
| 1185 | 1185 | ||
| 1186 | bool os_stderr_tty(void) { | 1186 | bool os_stderr_tty(void) { |
| 1187 | #if defined(ZIG_OS_WINDOWS) | 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 | #elif defined(ZIG_OS_POSIX) | 1189 | #elif defined(ZIG_OS_POSIX) |
| 1190 | return isatty(STDERR_FILENO) != 0; | 1190 | return isatty(STDERR_FILENO) != 0; |
| 1191 | #else | 1191 | #else |
| ... | @@ -1486,7 +1486,7 @@ WORD original_console_attributes = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BL | ... | @@ -1486,7 +1486,7 @@ WORD original_console_attributes = FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_BL |
| 1486 | 1486 | ||
| 1487 | void os_stderr_set_color(TermColor color) { | 1487 | void os_stderr_set_color(TermColor color) { |
| 1488 | #if defined(ZIG_OS_WINDOWS) | 1488 | #if defined(ZIG_OS_WINDOWS) |
| 1489 | if (is_stderr_cyg_pty()) { | 1489 | if (os_stderr_tty()) { |
| 1490 | set_color_posix(color); | 1490 | set_color_posix(color); |
| 1491 | return; | 1491 | return; |
| 1492 | } | 1492 | } |
src/os.hpp+8| ... | @@ -11,6 +11,7 @@ | ... | @@ -11,6 +11,7 @@ |
| 11 | #include "list.hpp" | 11 | #include "list.hpp" |
| 12 | #include "buffer.hpp" | 12 | #include "buffer.hpp" |
| 13 | #include "error.hpp" | 13 | #include "error.hpp" |
| 14 | #include "target.hpp" | ||
| 14 | #include "zig_llvm.h" | 15 | #include "zig_llvm.h" |
| 15 | #include "windows_sdk.h" | 16 | #include "windows_sdk.h" |
| 16 | 17 | ||
| ... | @@ -88,6 +89,11 @@ struct Termination { | ... | @@ -88,6 +89,11 @@ struct Termination { |
| 88 | #define OsFile int | 89 | #define OsFile int |
| 89 | #endif | 90 | #endif |
| 90 | 91 | ||
| 92 | #if defined(ZIG_OS_WINDOWS) | ||
| 93 | #undef fileno | ||
| 94 | #define fileno _fileno | ||
| 95 | #endif | ||
| 96 | |||
| 91 | struct OsTimeStamp { | 97 | struct OsTimeStamp { |
| 92 | uint64_t sec; | 98 | uint64_t sec; |
| 93 | uint64_t nsec; | 99 | uint64_t nsec; |
| ... | @@ -152,6 +158,8 @@ Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf | ... | @@ -152,6 +158,8 @@ Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf |
| 152 | Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); | 158 | Error ATTRIBUTE_MUST_USE os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); |
| 153 | Error ATTRIBUTE_MUST_USE os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type); | 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 | Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths); | 163 | Error ATTRIBUTE_MUST_USE os_self_exe_shared_libs(ZigList<Buf *> &paths); |
| 156 | 164 | ||
| 157 | #endif | 165 | #endif |
src/parser.cpp+5-3| ... | @@ -782,24 +782,26 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) { | ... | @@ -782,24 +782,26 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) { |
| 782 | return res; | 782 | return res; |
| 783 | } | 783 | } |
| 784 | 784 | ||
| 785 | // ContainerField <- IDENTIFIER (COLON TypeExpr)? (EQUAL Expr)? | 785 | // ContainerField <- IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)? |
| 786 | static AstNode *ast_parse_container_field(ParseContext *pc) { | 786 | static AstNode *ast_parse_container_field(ParseContext *pc) { |
| 787 | Token *identifier = eat_token_if(pc, TokenIdSymbol); | 787 | Token *identifier = eat_token_if(pc, TokenIdSymbol); |
| 788 | if (identifier == nullptr) | 788 | if (identifier == nullptr) |
| 789 | return nullptr; | 789 | return nullptr; |
| 790 | 790 | ||
| 791 | AstNode *type_expr = nullptr; | 791 | AstNode *type_expr = nullptr; |
| 792 | if (eat_token_if(pc, TokenIdColon) != nullptr) | 792 | if (eat_token_if(pc, TokenIdColon) != nullptr) { |
| 793 | type_expr = ast_expect(pc, ast_parse_type_expr); | 793 | type_expr = ast_expect(pc, ast_parse_type_expr); |
| 794 | } | ||
| 795 | AstNode *align_expr = ast_parse_byte_align(pc); | ||
| 794 | AstNode *expr = nullptr; | 796 | AstNode *expr = nullptr; |
| 795 | if (eat_token_if(pc, TokenIdEq) != nullptr) | 797 | if (eat_token_if(pc, TokenIdEq) != nullptr) |
| 796 | expr = ast_expect(pc, ast_parse_expr); | 798 | expr = ast_expect(pc, ast_parse_expr); |
| 797 | 799 | ||
| 798 | |||
| 799 | AstNode *res = ast_create_node(pc, NodeTypeStructField, identifier); | 800 | AstNode *res = ast_create_node(pc, NodeTypeStructField, identifier); |
| 800 | res->data.struct_field.name = token_buf(identifier); | 801 | res->data.struct_field.name = token_buf(identifier); |
| 801 | res->data.struct_field.type = type_expr; | 802 | res->data.struct_field.type = type_expr; |
| 802 | res->data.struct_field.value = expr; | 803 | res->data.struct_field.value = expr; |
| 804 | res->data.struct_field.align_expr = align_expr; | ||
| 803 | return res; | 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,6 +504,16 @@ Error target_parse_glibc_version(ZigGLibCVersion *glibc_ver, const char *text) { |
| 504 | return ErrorNone; | 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 | void get_native_target(ZigTarget *target) { | 517 | void get_native_target(ZigTarget *target) { |
| 508 | // first zero initialize | 518 | // first zero initialize |
| 509 | *target = {}; | 519 | *target = {}; |
| ... | @@ -518,6 +528,9 @@ void get_native_target(ZigTarget *target) { | ... | @@ -518,6 +528,9 @@ void get_native_target(ZigTarget *target) { |
| 518 | &target->abi, | 528 | &target->abi, |
| 519 | &oformat); | 529 | &oformat); |
| 520 | target->os = get_zig_os_type(os_type); | 530 | target->os = get_zig_os_type(os_type); |
| 531 | if (target->os == OsWindows) { | ||
| 532 | target->abi = target_get_win32_abi(); | ||
| 533 | } | ||
| 521 | target->is_native = true; | 534 | target->is_native = true; |
| 522 | if (target->abi == ZigLLVM_UnknownEnvironment) { | 535 | if (target->abi == ZigLLVM_UnknownEnvironment) { |
| 523 | target->abi = target_default_abi(target->arch, target->os); | 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,7 +1664,7 @@ ZigLLVM_EnvironmentType target_default_abi(ZigLLVM_ArchType arch, Os os) { |
| 1651 | return ZigLLVM_GNU; | 1664 | return ZigLLVM_GNU; |
| 1652 | case OsUefi: | 1665 | case OsUefi: |
| 1653 | case OsWindows: | 1666 | case OsWindows: |
| 1654 | return ZigLLVM_MSVC; | 1667 | return ZigLLVM_MSVC; |
| 1655 | case OsLinux: | 1668 | case OsLinux: |
| 1656 | case OsWASI: | 1669 | case OsWASI: |
| 1657 | case OsEmscripten: | 1670 | case OsEmscripten: |
src/tokenizer.cpp+1-1| ... | @@ -841,7 +841,7 @@ void tokenize(Buf *buf, Tokenization *out) { | ... | @@ -841,7 +841,7 @@ void tokenize(Buf *buf, Tokenization *out) { |
| 841 | case TokenizeStateSawAmpersand: | 841 | case TokenizeStateSawAmpersand: |
| 842 | switch (c) { | 842 | switch (c) { |
| 843 | case '&': | 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 | break; | 845 | break; |
| 846 | case '=': | 846 | case '=': |
| 847 | set_token_id(&t, t.cur_tok, TokenIdBitAndEq); | 847 | set_token_id(&t, t.cur_tok, TokenIdBitAndEq); |
src/zig_llvm.cpp+3-3| ... | @@ -15,9 +15,9 @@ | ... | @@ -15,9 +15,9 @@ |
| 15 | 15 | ||
| 16 | #include "zig_llvm.h" | 16 | #include "zig_llvm.h" |
| 17 | 17 | ||
| 18 | #if __GNUC__ >= 8 | 18 | #if __GNUC__ >= 9 |
| 19 | #pragma GCC diagnostic push | 19 | #pragma GCC diagnostic push |
| 20 | #pragma GCC diagnostic ignored "-Wclass-memaccess" | 20 | #pragma GCC diagnostic ignored "-Winit-list-lifetime" |
| 21 | #endif | 21 | #endif |
| 22 | 22 | ||
| 23 | #include <llvm/Analysis/TargetLibraryInfo.h> | 23 | #include <llvm/Analysis/TargetLibraryInfo.h> |
| ... | @@ -50,7 +50,7 @@ | ... | @@ -50,7 +50,7 @@ |
| 50 | 50 | ||
| 51 | #include <lld/Common/Driver.h> | 51 | #include <lld/Common/Driver.h> |
| 52 | 52 | ||
| 53 | #if __GNUC__ >= 8 | 53 | #if __GNUC__ >= 9 |
| 54 | #pragma GCC diagnostic pop | 54 | #pragma GCC diagnostic pop |
| 55 | #endif | 55 | #endif |
| 56 | 56 |
std/array_list.zig+12-9| ... | @@ -6,20 +6,23 @@ const mem = std.mem; | ... | @@ -6,20 +6,23 @@ const mem = std.mem; |
| 6 | const Allocator = mem.Allocator; | 6 | const Allocator = mem.Allocator; |
| 7 | 7 | ||
| 8 | pub fn ArrayList(comptime T: type) type { | 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 | return struct { | 13 | return struct { |
| 14 | const Self = @This(); | 14 | const Self = @This(); |
| 15 | 15 | ||
| 16 | /// Use toSlice instead of slicing this directly, because if you don't | 16 | /// Use toSlice instead of slicing this directly, because if you don't |
| 17 | /// specify the end position of the slice, this will potentially give | 17 | /// specify the end position of the slice, this will potentially give |
| 18 | /// you uninitialized memory. | 18 | /// you uninitialized memory. |
| 19 | items: []align(A) T, | 19 | items: Slice, |
| 20 | len: usize, | 20 | len: usize, |
| 21 | allocator: *Allocator, | 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 | /// Deinitialize with `deinit` or use `toOwnedSlice`. | 26 | /// Deinitialize with `deinit` or use `toOwnedSlice`. |
| 24 | pub fn init(allocator: *Allocator) Self { | 27 | pub fn init(allocator: *Allocator) Self { |
| 25 | return Self{ | 28 | return Self{ |
| ... | @@ -33,11 +36,11 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { | ... | @@ -33,11 +36,11 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { |
| 33 | self.allocator.free(self.items); | 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 | return self.items[0..self.len]; | 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 | return self.items[0..self.len]; | 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,7 +72,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { |
| 69 | /// ArrayList takes ownership of the passed in slice. The slice must have been | 72 | /// ArrayList takes ownership of the passed in slice. The slice must have been |
| 70 | /// allocated with `allocator`. | 73 | /// allocated with `allocator`. |
| 71 | /// Deinitialize with `deinit` or use `toOwnedSlice`. | 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 | return Self{ | 76 | return Self{ |
| 74 | .items = slice, | 77 | .items = slice, |
| 75 | .len = slice.len, | 78 | .len = slice.len, |
| ... | @@ -78,7 +81,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { | ... | @@ -78,7 +81,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { |
| 78 | } | 81 | } |
| 79 | 82 | ||
| 80 | /// The caller owns the returned memory. ArrayList becomes empty. | 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 | const allocator = self.allocator; | 85 | const allocator = self.allocator; |
| 83 | const result = allocator.shrink(self.items, self.len); | 86 | const result = allocator.shrink(self.items, self.len); |
| 84 | self.* = init(allocator); | 87 | self.* = init(allocator); |
| ... | @@ -93,7 +96,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { | ... | @@ -93,7 +96,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { |
| 93 | self.items[n] = item; | 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 | try self.ensureCapacity(self.len + items.len); | 100 | try self.ensureCapacity(self.len + items.len); |
| 98 | self.len += items.len; | 101 | self.len += items.len; |
| 99 | 102 | ||
| ... | @@ -141,7 +144,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { | ... | @@ -141,7 +144,7 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type { |
| 141 | return self.swapRemove(i); | 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 | try self.ensureCapacity(self.len + items.len); | 148 | try self.ensureCapacity(self.len + items.len); |
| 146 | mem.copy(T, self.items[self.len..], items); | 149 | mem.copy(T, self.items[self.len..], items); |
| 147 | self.len += items.len; | 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,8 +269,8 @@ pub const Blake2b512 = Blake2b(512); |
| 269 | fn Blake2b(comptime out_len: usize) type { | 269 | fn Blake2b(comptime out_len: usize) type { |
| 270 | return struct { | 270 | return struct { |
| 271 | const Self = @This(); | 271 | const Self = @This(); |
| 272 | const block_length = 128; | 272 | pub const block_length = 128; |
| 273 | const digest_length = out_len / 8; | 273 | pub const digest_length = out_len / 8; |
| 274 | 274 | ||
| 275 | const iv = [8]u64{ | 275 | const iv = [8]u64{ |
| 276 | 0x6a09e667f3bcc908, | 276 | 0x6a09e667f3bcc908, |
std/crypto/sha2.zig+2-2| ... | @@ -420,8 +420,8 @@ pub const Sha512 = Sha2_64(Sha512Params); | ... | @@ -420,8 +420,8 @@ pub const Sha512 = Sha2_64(Sha512Params); |
| 420 | fn Sha2_64(comptime params: Sha2Params64) type { | 420 | fn Sha2_64(comptime params: Sha2Params64) type { |
| 421 | return struct { | 421 | return struct { |
| 422 | const Self = @This(); | 422 | const Self = @This(); |
| 423 | const block_length = 128; | 423 | pub const block_length = 128; |
| 424 | const digest_length = params.out_len / 8; | 424 | pub const digest_length = params.out_len / 8; |
| 425 | 425 | ||
| 426 | s: [8]u64, | 426 | s: [8]u64, |
| 427 | // Streaming Cache | 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,6 +719,16 @@ pub const WatchEventId = enum { |
| 719 | Delete, | 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 | //pub const WatchEventError = error{ | 732 | //pub const WatchEventError = error{ |
| 723 | // UserResourceLimitReached, | 733 | // UserResourceLimitReached, |
| 724 | // SystemResources, | 734 | // SystemResources, |
| ... | @@ -736,7 +746,7 @@ pub const WatchEventId = enum { | ... | @@ -736,7 +746,7 @@ pub const WatchEventId = enum { |
| 736 | // file_table: FileTable, | 746 | // file_table: FileTable, |
| 737 | // table_lock: event.Lock, | 747 | // table_lock: event.Lock, |
| 738 | // | 748 | // |
| 739 | // const FileTable = std.AutoHashMap([]const u8, *Put); | 749 | // const FileTable = std.StringHashmap(*Put); |
| 740 | // const Put = struct { | 750 | // const Put = struct { |
| 741 | // putter: anyframe, | 751 | // putter: anyframe, |
| 742 | // value_ptr: *V, | 752 | // value_ptr: *V, |
| ... | @@ -755,8 +765,8 @@ pub const WatchEventId = enum { | ... | @@ -755,8 +765,8 @@ pub const WatchEventId = enum { |
| 755 | // all_putters: std.atomic.Queue(anyframe), | 765 | // all_putters: std.atomic.Queue(anyframe), |
| 756 | // ref_count: std.atomic.Int(usize), | 766 | // ref_count: std.atomic.Int(usize), |
| 757 | // | 767 | // |
| 758 | // const DirTable = std.AutoHashMap([]const u8, *Dir); | 768 | // const DirTable = std.StringHashMap(*Dir); |
| 759 | // const FileTable = std.AutoHashMap([]const u16, V); | 769 | // const FileTable = std.HashMap([]const u16, V, hashString, eqlString); |
| 760 | // | 770 | // |
| 761 | // const Dir = struct { | 771 | // const Dir = struct { |
| 762 | // putter: anyframe, | 772 | // putter: anyframe, |
| ... | @@ -772,7 +782,7 @@ pub const WatchEventId = enum { | ... | @@ -772,7 +782,7 @@ pub const WatchEventId = enum { |
| 772 | // table_lock: event.Lock, | 782 | // table_lock: event.Lock, |
| 773 | // | 783 | // |
| 774 | // const WdTable = std.AutoHashMap(i32, Dir); | 784 | // const WdTable = std.AutoHashMap(i32, Dir); |
| 775 | // const FileTable = std.AutoHashMap([]const u8, V); | 785 | // const FileTable = std.StringHashMap(V); |
| 776 | // | 786 | // |
| 777 | // const Dir = struct { | 787 | // const Dir = struct { |
| 778 | // dirname: []const u8, | 788 | // dirname: []const u8, |
| ... | @@ -780,7 +790,7 @@ pub const WatchEventId = enum { | ... | @@ -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 | // const Self = @This(); | 795 | // const Self = @This(); |
| 786 | // | 796 | // |
std/hash/auto_hash.zig+229-62| ... | @@ -1,11 +1,79 @@ | ... | @@ -1,11 +1,79 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | const assert = std.debug.assert; | ||
| 3 | const mem = std.mem; | 4 | const mem = std.mem; |
| 4 | const meta = std.meta; | 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 | /// Provides generic hashing for any eligible type. | 74 | /// Provides generic hashing for any eligible type. |
| 7 | /// Only hashes `key` itself, pointers are not followed. | 75 | /// Strategy is provided to determine if pointers should be followed or not. |
| 8 | pub fn autoHash(hasher: var, key: var) void { | 76 | pub fn hash(hasher: var, key: var, comptime strat: HashStrategy) void { |
| 9 | const Key = @typeOf(key); | 77 | const Key = @typeOf(key); |
| 10 | switch (@typeInfo(Key)) { | 78 | switch (@typeInfo(Key)) { |
| 11 | .NoReturn, | 79 | .NoReturn, |
| ... | @@ -26,35 +94,18 @@ pub fn autoHash(hasher: var, key: var) void { | ... | @@ -26,35 +94,18 @@ pub fn autoHash(hasher: var, key: var) void { |
| 26 | // TODO Check if the situation is better after #561 is resolved. | 94 | // TODO Check if the situation is better after #561 is resolved. |
| 27 | .Int => @inlineCall(hasher.update, std.mem.asBytes(&key)), | 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)), | 99 | .Bool => hash(hasher, @boolToInt(key), strat), |
| 32 | .Enum => autoHash(hasher, @enumToInt(key)), | 100 | .Enum => hash(hasher, @enumToInt(key), strat), |
| 33 | .ErrorSet => autoHash(hasher, @errorToInt(key)), | 101 | .ErrorSet => hash(hasher, @errorToInt(key), strat), |
| 34 | .AnyFrame, .Fn => autoHash(hasher, @ptrToInt(key)), | 102 | .AnyFrame, .Fn => hash(hasher, @ptrToInt(key), strat), |
| 35 | 103 | ||
| 36 | .Pointer => |info| switch (info.size) { | 104 | .Pointer => @inlineCall(hashPointer, hasher, key, strat), |
| 37 | builtin.TypeInfo.Pointer.Size.One, | ||
| 38 | builtin.TypeInfo.Pointer.Size.Many, | ||
| 39 | builtin.TypeInfo.Pointer.Size.C, | ||
| 40 | => autoHash(hasher, @ptrToInt(key)), | ||
| 41 | 105 | ||
| 42 | builtin.TypeInfo.Pointer.Size.Slice => { | 106 | .Optional => if (key) |k| hash(hasher, k, strat), |
| 43 | autoHash(hasher, key.ptr); | ||
| 44 | autoHash(hasher, key.len); | ||
| 45 | }, | ||
| 46 | }, | ||
| 47 | |||
| 48 | .Optional => if (key) |k| autoHash(hasher, k), | ||
| 49 | 107 | ||
| 50 | .Array => { | 108 | .Array => hashArray(hasher, key, strat), |
| 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 | }, | ||
| 58 | 109 | ||
| 59 | .Vector => |info| { | 110 | .Vector => |info| { |
| 60 | if (info.child.bit_count % 8 == 0) { | 111 | if (info.child.bit_count % 8 == 0) { |
| ... | @@ -67,7 +118,7 @@ pub fn autoHash(hasher: var, key: var) void { | ... | @@ -67,7 +118,7 @@ pub fn autoHash(hasher: var, key: var) void { |
| 67 | const array: [info.len]info.child = key; | 118 | const array: [info.len]info.child = key; |
| 68 | comptime var i: u32 = 0; | 119 | comptime var i: u32 = 0; |
| 69 | inline while (i < info.len) : (i += 1) { | 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,19 +130,19 @@ pub fn autoHash(hasher: var, key: var) void { |
| 79 | inline for (info.fields) |field| { | 130 | inline for (info.fields) |field| { |
| 80 | // We reuse the hash of the previous field as the seed for the | 131 | // We reuse the hash of the previous field as the seed for the |
| 81 | // next one so that they're dependant. | 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 | .Union => |info| blk: { | 137 | .Union => |info| blk: { |
| 87 | if (info.tag_type) |tag_type| { | 138 | if (info.tag_type) |tag_type| { |
| 88 | const tag = meta.activeTag(key); | 139 | const tag = meta.activeTag(key); |
| 89 | const s = autoHash(hasher, tag); | 140 | const s = hash(hasher, tag, strat); |
| 90 | inline for (info.fields) |field| { | 141 | inline for (info.fields) |field| { |
| 91 | const enum_field = field.enum_field.?; | 142 | const enum_field = field.enum_field.?; |
| 92 | if (enum_field.value == @enumToInt(tag)) { | 143 | if (enum_field.value == @enumToInt(tag)) { |
| 93 | autoHash(hasher, @field(key, enum_field.name)); | 144 | hash(hasher, @field(key, enum_field.name), strat); |
| 94 | // TODO use a labelled break when it does not crash the compiler. | 145 | // TODO use a labelled break when it does not crash the compiler. cf #2908 |
| 95 | // break :blk; | 146 | // break :blk; |
| 96 | return; | 147 | return; |
| 97 | } | 148 | } |
| ... | @@ -102,25 +153,102 @@ pub fn autoHash(hasher: var, key: var) void { | ... | @@ -102,25 +153,102 @@ pub fn autoHash(hasher: var, key: var) void { |
| 102 | 153 | ||
| 103 | .ErrorUnion => blk: { | 154 | .ErrorUnion => blk: { |
| 104 | const payload = key catch |err| { | 155 | const payload = key catch |err| { |
| 105 | autoHash(hasher, err); | 156 | hash(hasher, err, strat); |
| 106 | break :blk; | 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 | const testing = std.testing; | 184 | const testing = std.testing; |
| 114 | const Wyhash = std.hash.Wyhash; | 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 | // Any hash could be used here, for testing autoHash. | 202 | // Any hash could be used here, for testing autoHash. |
| 118 | var hasher = Wyhash.init(0); | 203 | var hasher = Wyhash.init(0); |
| 119 | autoHash(&hasher, key); | 204 | hash(&hasher, key, .Deep); |
| 120 | return hasher.final(); | 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 | // Allocate one array dynamically so that we're assured it is not merged | 252 | // Allocate one array dynamically so that we're assured it is not merged |
| 125 | // with the other by the optimization passes. | 253 | // with the other by the optimization passes. |
| 126 | const array1 = try std.heap.direct_allocator.create([6]u32); | 254 | const array1 = try std.heap.direct_allocator.create([6]u32); |
| ... | @@ -130,23 +258,62 @@ test "autoHash slice" { | ... | @@ -130,23 +258,62 @@ test "autoHash slice" { |
| 130 | const a = array1[0..]; | 258 | const a = array1[0..]; |
| 131 | const b = array2[0..]; | 259 | const b = array2[0..]; |
| 132 | const c = array1[0..3]; | 260 | const c = array1[0..3]; |
| 133 | testing.expect(testAutoHash(a) == testAutoHash(a)); | 261 | testing.expect(testHashDeep(a) == testHashDeep(a)); |
| 134 | testing.expect(testAutoHash(a) != testAutoHash(array1)); | 262 | testing.expect(testHashDeep(a) == testHashDeep(array1)); |
| 135 | testing.expect(testAutoHash(a) != testAutoHash(b)); | 263 | testing.expect(testHashDeep(a) == testHashDeep(b)); |
| 136 | testing.expect(testAutoHash(a) != testAutoHash(c)); | 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 | const a: ?u32 = 123; | 307 | const a: ?u32 = 123; |
| 141 | const b: ?u32 = null; | 308 | const b: ?u32 = null; |
| 142 | testing.expectEqual(testAutoHash(a), testAutoHash(u32(123))); | 309 | testing.expectEqual(testHash(a), testHash(u32(123))); |
| 143 | testing.expect(testAutoHash(a) != testAutoHash(b)); | 310 | testing.expect(testHash(a) != testHash(b)); |
| 144 | testing.expectEqual(testAutoHash(b), 0); | 311 | testing.expectEqual(testHash(b), 0); |
| 145 | } | 312 | } |
| 146 | 313 | ||
| 147 | test "testAutoHash array" { | 314 | test "testHash array" { |
| 148 | const a = [_]u32{ 1, 2, 3 }; | 315 | const a = [_]u32{ 1, 2, 3 }; |
| 149 | const h = testAutoHash(a); | 316 | const h = testHash(a); |
| 150 | var hasher = Wyhash.init(0); | 317 | var hasher = Wyhash.init(0); |
| 151 | autoHash(&hasher, u32(1)); | 318 | autoHash(&hasher, u32(1)); |
| 152 | autoHash(&hasher, u32(2)); | 319 | autoHash(&hasher, u32(2)); |
| ... | @@ -154,14 +321,14 @@ test "testAutoHash array" { | ... | @@ -154,14 +321,14 @@ test "testAutoHash array" { |
| 154 | testing.expectEqual(h, hasher.final()); | 321 | testing.expectEqual(h, hasher.final()); |
| 155 | } | 322 | } |
| 156 | 323 | ||
| 157 | test "testAutoHash struct" { | 324 | test "testHash struct" { |
| 158 | const Foo = struct { | 325 | const Foo = struct { |
| 159 | a: u32 = 1, | 326 | a: u32 = 1, |
| 160 | b: u32 = 2, | 327 | b: u32 = 2, |
| 161 | c: u32 = 3, | 328 | c: u32 = 3, |
| 162 | }; | 329 | }; |
| 163 | const f = Foo{}; | 330 | const f = Foo{}; |
| 164 | const h = testAutoHash(f); | 331 | const h = testHash(f); |
| 165 | var hasher = Wyhash.init(0); | 332 | var hasher = Wyhash.init(0); |
| 166 | autoHash(&hasher, u32(1)); | 333 | autoHash(&hasher, u32(1)); |
| 167 | autoHash(&hasher, u32(2)); | 334 | autoHash(&hasher, u32(2)); |
| ... | @@ -169,7 +336,7 @@ test "testAutoHash struct" { | ... | @@ -169,7 +336,7 @@ test "testAutoHash struct" { |
| 169 | testing.expectEqual(h, hasher.final()); | 336 | testing.expectEqual(h, hasher.final()); |
| 170 | } | 337 | } |
| 171 | 338 | ||
| 172 | test "testAutoHash union" { | 339 | test "testHash union" { |
| 173 | const Foo = union(enum) { | 340 | const Foo = union(enum) { |
| 174 | A: u32, | 341 | A: u32, |
| 175 | B: f32, | 342 | B: f32, |
| ... | @@ -179,24 +346,24 @@ test "testAutoHash union" { | ... | @@ -179,24 +346,24 @@ test "testAutoHash union" { |
| 179 | const a = Foo{ .A = 18 }; | 346 | const a = Foo{ .A = 18 }; |
| 180 | var b = Foo{ .B = 12.34 }; | 347 | var b = Foo{ .B = 12.34 }; |
| 181 | const c = Foo{ .C = 18 }; | 348 | const c = Foo{ .C = 18 }; |
| 182 | testing.expect(testAutoHash(a) == testAutoHash(a)); | 349 | testing.expect(testHash(a) == testHash(a)); |
| 183 | testing.expect(testAutoHash(a) != testAutoHash(b)); | 350 | testing.expect(testHash(a) != testHash(b)); |
| 184 | testing.expect(testAutoHash(a) != testAutoHash(c)); | 351 | testing.expect(testHash(a) != testHash(c)); |
| 185 | 352 | ||
| 186 | b = Foo{ .A = 18 }; | 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 | const a: @Vector(4, u32) = [_]u32{ 1, 2, 3, 4 }; | 358 | const a: @Vector(4, u32) = [_]u32{ 1, 2, 3, 4 }; |
| 192 | const b: @Vector(4, u32) = [_]u32{ 1, 2, 3, 5 }; | 359 | const b: @Vector(4, u32) = [_]u32{ 1, 2, 3, 5 }; |
| 193 | const c: @Vector(4, u31) = [_]u31{ 1, 2, 3, 4 }; | 360 | const c: @Vector(4, u31) = [_]u31{ 1, 2, 3, 4 }; |
| 194 | testing.expect(testAutoHash(a) == testAutoHash(a)); | 361 | testing.expect(testHash(a) == testHash(a)); |
| 195 | testing.expect(testAutoHash(a) != testAutoHash(b)); | 362 | testing.expect(testHash(a) != testHash(b)); |
| 196 | testing.expect(testAutoHash(a) != testAutoHash(c)); | 363 | testing.expect(testHash(a) != testHash(c)); |
| 197 | } | 364 | } |
| 198 | 365 | ||
| 199 | test "testAutoHash error union" { | 366 | test "testHash error union" { |
| 200 | const Errors = error{Test}; | 367 | const Errors = error{Test}; |
| 201 | const Foo = struct { | 368 | const Foo = struct { |
| 202 | a: u32 = 1, | 369 | a: u32 = 1, |
| ... | @@ -205,7 +372,7 @@ test "testAutoHash error union" { | ... | @@ -205,7 +372,7 @@ test "testAutoHash error union" { |
| 205 | }; | 372 | }; |
| 206 | const f = Foo{}; | 373 | const f = Foo{}; |
| 207 | const g: Errors!Foo = Errors.Test; | 374 | const g: Errors!Foo = Errors.Test; |
| 208 | testing.expect(testAutoHash(f) != testAutoHash(g)); | 375 | testing.expect(testHash(f) != testHash(g)); |
| 209 | testing.expect(testAutoHash(f) == testAutoHash(Foo{})); | 376 | testing.expect(testHash(f) == testHash(Foo{})); |
| 210 | testing.expect(testAutoHash(g) == testAutoHash(Errors.Test)); | 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,9 +10,9 @@ const debug = std.debug; |
| 10 | const testing = std.testing; | 10 | const testing = std.testing; |
| 11 | 11 | ||
| 12 | pub const Polynomial = struct { | 12 | pub const Polynomial = struct { |
| 13 | const IEEE = 0xedb88320; | 13 | pub const IEEE = 0xedb88320; |
| 14 | const Castagnoli = 0x82f63b78; | 14 | pub const Castagnoli = 0x82f63b78; |
| 15 | const Koopman = 0xeb31d82e; | 15 | pub const Koopman = 0xeb31d82e; |
| 16 | }; | 16 | }; |
| 17 | 17 | ||
| 18 | // IEEE is by far the most common CRC and so is aliased by default. | 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,7 +21,7 @@ pub fn SipHash128(comptime c_rounds: usize, comptime d_rounds: usize) type { |
| 21 | return SipHash(u128, c_rounds, d_rounds); | 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 | assert(T == u64 or T == u128); | 25 | assert(T == u64 or T == u128); |
| 26 | assert(c_rounds > 0 and d_rounds > 0); | 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,10 +34,6 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) |
| 34 | v1: u64, | 34 | v1: u64, |
| 35 | v2: u64, | 35 | v2: u64, |
| 36 | v3: u64, | 36 | v3: u64, |
| 37 | |||
| 38 | // streaming cache | ||
| 39 | buf: [8]u8, | ||
| 40 | buf_len: usize, | ||
| 41 | msg_len: u8, | 37 | msg_len: u8, |
| 42 | 38 | ||
| 43 | pub fn init(key: []const u8) Self { | 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,9 +47,6 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) |
| 51 | .v1 = k1 ^ 0x646f72616e646f6d, | 47 | .v1 = k1 ^ 0x646f72616e646f6d, |
| 52 | .v2 = k0 ^ 0x6c7967656e657261, | 48 | .v2 = k0 ^ 0x6c7967656e657261, |
| 53 | .v3 = k1 ^ 0x7465646279746573, | 49 | .v3 = k1 ^ 0x7465646279746573, |
| 54 | |||
| 55 | .buf = undefined, | ||
| 56 | .buf_len = 0, | ||
| 57 | .msg_len = 0, | 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,73 +57,66 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) |
| 64 | return d; | 57 | return d; |
| 65 | } | 58 | } |
| 66 | 59 | ||
| 67 | pub fn update(d: *Self, b: []const u8) void { | 60 | pub fn update(self: *Self, b: []const u8) void { |
| 68 | var off: usize = 0; | 61 | std.debug.assert(b.len % 8 == 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 | } | ||
| 77 | 62 | ||
| 78 | // Full middle blocks. | 63 | var off: usize = 0; |
| 79 | while (off + 8 <= b.len) : (off += 8) { | 64 | while (off < b.len) : (off += 8) { |
| 80 | d.round(b[off .. off + 8]); | 65 | @inlineCall(self.round, b[off .. off + 8]); |
| 81 | } | 66 | } |
| 82 | 67 | ||
| 83 | // Remainder for next pass. | 68 | self.msg_len +%= @truncate(u8, b.len); |
| 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); | ||
| 87 | } | 69 | } |
| 88 | 70 | ||
| 89 | pub fn final(d: *Self) T { | 71 | pub fn final(self: *Self, b: []const u8) T { |
| 90 | // Padding | 72 | std.debug.assert(b.len < 8); |
| 91 | mem.set(u8, d.buf[d.buf_len..], 0); | 73 | |
| 92 | d.buf[7] = d.msg_len; | 74 | self.msg_len +%= @truncate(u8, b.len); |
| 93 | d.round(d.buf[0..]); | 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 | if (T == u128) { | 81 | if (T == u128) { |
| 96 | d.v2 ^= 0xee; | 82 | self.v2 ^= 0xee; |
| 97 | } else { | 83 | } else { |
| 98 | d.v2 ^= 0xff; | 84 | self.v2 ^= 0xff; |
| 99 | } | 85 | } |
| 100 | 86 | ||
| 101 | comptime var i: usize = 0; | 87 | comptime var i: usize = 0; |
| 102 | inline while (i < d_rounds) : (i += 1) { | 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 | if (T == u64) { | 93 | if (T == u64) { |
| 108 | return b1; | 94 | return b1; |
| 109 | } | 95 | } |
| 110 | 96 | ||
| 111 | d.v1 ^= 0xdd; | 97 | self.v1 ^= 0xdd; |
| 112 | 98 | ||
| 113 | comptime var j: usize = 0; | 99 | comptime var j: usize = 0; |
| 114 | inline while (j < d_rounds) : (j += 1) { | 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 | return (u128(b2) << 64) | b1; | 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 | assert(b.len == 8); | 109 | assert(b.len == 8); |
| 124 | 110 | ||
| 125 | const m = mem.readIntSliceLittle(u64, b[0..]); | 111 | const m = mem.readIntSliceLittle(u64, b[0..]); |
| 126 | d.v3 ^= m; | 112 | self.v3 ^= m; |
| 127 | 113 | ||
| 128 | comptime var i: usize = 0; | 114 | comptime var i: usize = 0; |
| 129 | inline while (i < c_rounds) : (i += 1) { | 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 | fn sipRound(d: *Self) void { | 122 | fn sipRound(d: *Self) void { |
| ... | @@ -151,9 +137,61 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) | ... | @@ -151,9 +137,61 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) |
| 151 | } | 137 | } |
| 152 | 138 | ||
| 153 | pub fn hash(key: []const u8, input: []const u8) T { | 139 | pub fn hash(key: []const u8, input: []const u8) T { |
| 140 | const aligned_len = input.len - (input.len % 8); | ||
| 141 | |||
| 154 | var c = Self.init(key); | 142 | var c = Self.init(key); |
| 155 | c.update(input); | 143 | @inlineCall(c.update, input[0..aligned_len]); |
| 156 | return c.final(); | 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,7 +275,7 @@ test "siphash64-2-4 sanity" { |
| 237 | buffer[i] = @intCast(u8, i); | 275 | buffer[i] = @intCast(u8, i); |
| 238 | 276 | ||
| 239 | const expected = mem.readIntLittle(u64, &vector); | 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,6 +354,30 @@ test "siphash128-2-4 sanity" { |
| 316 | buffer[i] = @intCast(u8, i); | 354 | buffer[i] = @intCast(u8, i); |
| 317 | 355 | ||
| 318 | const expected = mem.readIntLittle(u128, &vector); | 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,7 +10,8 @@ const primes = [_]u64{ |
| 10 | }; | 10 | }; |
| 11 | 11 | ||
| 12 | fn read_bytes(comptime bytes: u8, data: []const u8) u64 { | 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 | fn read_8bytes_swapped(data: []const u8) u64 { | 17 | fn read_8bytes_swapped(data: []const u8) u64 { |
| ... | @@ -31,18 +32,21 @@ fn mix1(a: u64, b: u64, seed: u64) u64 { | ... | @@ -31,18 +32,21 @@ fn mix1(a: u64, b: u64, seed: u64) u64 { |
| 31 | return mum(a ^ seed ^ primes[2], b ^ seed ^ primes[3]); | 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 | seed: u64, | 39 | seed: u64, |
| 36 | msg_len: usize, | 40 | msg_len: usize, |
| 37 | 41 | ||
| 38 | pub fn init(seed: u64) Wyhash { | 42 | pub fn init(seed: u64) WyhashStateless { |
| 39 | return Wyhash{ | 43 | return WyhashStateless{ |
| 40 | .seed = seed, | 44 | .seed = seed, |
| 41 | .msg_len = 0, | 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 | std.debug.assert(b.len == 32); | 50 | std.debug.assert(b.len == 32); |
| 47 | 51 | ||
| 48 | self.seed = mix0( | 52 | self.seed = mix0( |
| ... | @@ -56,12 +60,25 @@ pub const Wyhash = struct { | ... | @@ -56,12 +60,25 @@ pub const Wyhash = struct { |
| 56 | ); | 60 | ); |
| 57 | } | 61 | } |
| 58 | 62 | ||
| 59 | fn partial(self: *Wyhash, b: []const u8) void { | 63 | pub fn update(self: *WyhashStateless, b: []const u8) void { |
| 60 | const rem_key = b; | 64 | std.debug.assert(b.len % 32 == 0); |
| 61 | const rem_len = b.len; | 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; | 71 | self.msg_len += b.len; |
| 64 | seed = switch (@intCast(u5, rem_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 | 0 => seed, | 82 | 0 => seed, |
| 66 | 1 => mix0(read_bytes(1, rem_key), primes[4], seed), | 83 | 1 => mix0(read_bytes(1, rem_key), primes[4], seed), |
| 67 | 2 => mix0(read_bytes(2, rem_key), primes[4], seed), | 84 | 2 => mix0(read_bytes(2, rem_key), primes[4], seed), |
| ... | @@ -95,34 +112,70 @@ pub const Wyhash = struct { | ... | @@ -95,34 +112,70 @@ pub const Wyhash = struct { |
| 95 | 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), | 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 | 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), | 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 | pub fn update(self: *Wyhash, b: []const u8) void { | 145 | pub fn update(self: *Wyhash, b: []const u8) void { |
| 102 | var off: usize = 0; | 146 | var off: usize = 0; |
| 103 | 147 | ||
| 104 | // Full middle blocks. | 148 | if (self.buf_len != 0 and self.buf_len + b.len >= 32) { |
| 105 | while (off + 32 <= b.len) : (off += 32) { | 149 | off += 32 - self.buf_len; |
| 106 | @inlineCall(self.round, b[off .. off + 32]); | 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..]); | 155 | const remain_len = b.len - off; |
| 110 | self.msg_len += b.len; | 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 | pub fn final(self: *Wyhash) u64 { | 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 | pub fn hash(seed: u64, input: []const u8) u64 { | 171 | pub fn hash(seed: u64, input: []const u8) u64 { |
| 118 | var c = Wyhash.init(seed); | 172 | return WyhashStateless.hash(seed, input); |
| 119 | c.update(input); | ||
| 120 | return c.final(); | ||
| 121 | } | 173 | } |
| 122 | }; | 174 | }; |
| 123 | 175 | ||
| 176 | const expectEqual = std.testing.expectEqual; | ||
| 177 | |||
| 124 | test "test vectors" { | 178 | test "test vectors" { |
| 125 | const expectEqual = std.testing.expectEqual; | ||
| 126 | const hash = Wyhash.hash; | 179 | const hash = Wyhash.hash; |
| 127 | 180 | ||
| 128 | expectEqual(hash(0, ""), 0x0); | 181 | expectEqual(hash(0, ""), 0x0); |
| ... | @@ -133,3 +186,46 @@ test "test vectors" { | ... | @@ -133,3 +186,46 @@ test "test vectors" { |
| 133 | expectEqual(hash(5, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), 0x602a1894d3bbfe7f); | 186 | expectEqual(hash(5, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"), 0x602a1894d3bbfe7f); |
| 134 | expectEqual(hash(6, "12345678901234567890123456789012345678901234567890123456789012345678901234567890"), 0x829e9c148b75970e); | 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,6 +17,21 @@ pub fn AutoHashMap(comptime K: type, comptime V: type) type { |
| 17 | return HashMap(K, V, getAutoHashFn(K), getAutoEqlFn(K)); | 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 | pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u32, comptime eql: fn (a: K, b: K) bool) type { | 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 | return struct { | 36 | return struct { |
| 22 | entries: []Entry, | 37 | entries: []Entry, |
std/http/headers.zig+1-11| ... | @@ -102,19 +102,9 @@ test "HeaderEntry" { | ... | @@ -102,19 +102,9 @@ test "HeaderEntry" { |
| 102 | testing.expectEqualSlices(u8, "x", e.value); | 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 | const HeaderList = std.ArrayList(HeaderEntry); | 105 | const HeaderList = std.ArrayList(HeaderEntry); |
| 116 | const HeaderIndexList = std.ArrayList(usize); | 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 | pub const Headers = struct { | 109 | pub const Headers = struct { |
| 120 | // the owned header field name is stored in the index as part of the key | 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,7 +65,7 @@ pub const CreateFileError = error{ |
| 65 | InvalidUtf8, | 65 | InvalidUtf8, |
| 66 | 66 | ||
| 67 | /// On Windows, file paths cannot contain these characters: | 67 | /// On Windows, file paths cannot contain these characters: |
| 68 | /// '/', '*', '?', '"', '<', '>', '|' | 68 | /// '*', '?', '"', '<', '>', '|', and '/' (when the ABI is not GNU) |
| 69 | BadPathName, | 69 | BadPathName, |
| 70 | 70 | ||
| 71 | Unexpected, | 71 | Unexpected, |
| ... | @@ -836,11 +836,10 @@ pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) | ... | @@ -836,11 +836,10 @@ pub fn sliceToPrefixedSuffixedFileW(s: []const u8, comptime suffix: []const u16) |
| 836 | // > converting the name to an NT-style name, except when using the "\\?\" | 836 | // > converting the name to an NT-style name, except when using the "\\?\" |
| 837 | // > prefix as detailed in the following sections. | 837 | // > prefix as detailed in the following sections. |
| 838 | // from https://docs.microsoft.com/en-us/windows/desktop/FileIO/naming-a-file#maximum-path-length-limitation | 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 | for (s) |byte| { | 839 | for (s) |byte| { |
| 842 | switch (byte) { | 840 | switch (byte) { |
| 843 | '/', '*', '?', '"', '<', '>', '|' => return error.BadPathName, | 841 | '*', '?', '"', '<', '>', '|' => return error.BadPathName, |
| 842 | '/' => if (builtin.abi == .msvc) return error.BadPathName, | ||
| 844 | else => {}, | 843 | else => {}, |
| 845 | } | 844 | } |
| 846 | } | 845 | } |
std/std.zig+1| ... | @@ -17,6 +17,7 @@ pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList; | ... | @@ -17,6 +17,7 @@ pub const SinglyLinkedList = @import("linked_list.zig").SinglyLinkedList; |
| 17 | pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; | 17 | pub const StaticallyInitializedMutex = @import("statically_initialized_mutex.zig").StaticallyInitializedMutex; |
| 18 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; | 18 | pub const SegmentedList = @import("segmented_list.zig").SegmentedList; |
| 19 | pub const SpinLock = @import("spinlock.zig").SpinLock; | 19 | pub const SpinLock = @import("spinlock.zig").SpinLock; |
| 20 | pub const StringHashMap = @import("hash_map.zig").StringHashMap; | ||
| 20 | pub const ChildProcess = @import("child_process.zig").ChildProcess; | 21 | pub const ChildProcess = @import("child_process.zig").ChildProcess; |
| 21 | pub const TailQueue = @import("linked_list.zig").TailQueue; | 22 | pub const TailQueue = @import("linked_list.zig").TailQueue; |
| 22 | pub const Thread = @import("thread.zig").Thread; | 23 | pub const Thread = @import("thread.zig").Thread; |
std/zig/ast.zig+1| ... | @@ -761,6 +761,7 @@ pub const Node = struct { | ... | @@ -761,6 +761,7 @@ pub const Node = struct { |
| 761 | name_token: TokenIndex, | 761 | name_token: TokenIndex, |
| 762 | type_expr: ?*Node, | 762 | type_expr: ?*Node, |
| 763 | value_expr: ?*Node, | 763 | value_expr: ?*Node, |
| 764 | align_expr: ?*Node, | ||
| 764 | 765 | ||
| 765 | pub fn iterate(self: *ContainerField, index: usize) ?*Node { | 766 | pub fn iterate(self: *ContainerField, index: usize) ?*Node { |
| 766 | var i = index; | 767 | var i = index; |
std/zig/parse.zig+9-6| ... | @@ -380,16 +380,18 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | ... | @@ -380,16 +380,18 @@ fn parseVarDecl(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 380 | return &node.base; | 380 | return &node.base; |
| 381 | } | 381 | } |
| 382 | 382 | ||
| 383 | /// ContainerField <- IDENTIFIER (COLON TypeExpr)? (EQUAL Expr)? | 383 | /// ContainerField <- IDENTIFIER (COLON TypeExpr ByteAlign?)? (EQUAL Expr)? |
| 384 | fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { | 384 | fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node { |
| 385 | const name_token = eatToken(it, .Identifier) orelse return null; | 385 | const name_token = eatToken(it, .Identifier) orelse return null; |
| 386 | 386 | ||
| 387 | const type_expr = if (eatToken(it, .Colon)) |_| | 387 | var align_expr: ?*Node = null; |
| 388 | try expectNode(arena, it, tree, parseTypeExpr, AstError{ | 388 | var type_expr: ?*Node = null; |
| 389 | if (eatToken(it, .Colon)) |_| { | ||
| 390 | type_expr = try expectNode(arena, it, tree, parseTypeExpr, AstError{ | ||
| 389 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, | 391 | .ExpectedTypeExpr = AstError.ExpectedTypeExpr{ .token = it.index }, |
| 390 | }) | 392 | }); |
| 391 | else | 393 | align_expr = try parseByteAlign(arena, it, tree); |
| 392 | null; | 394 | } |
| 393 | 395 | ||
| 394 | const value_expr = if (eatToken(it, .Equal)) |_| | 396 | const value_expr = if (eatToken(it, .Equal)) |_| |
| 395 | try expectNode(arena, it, tree, parseExpr, AstError{ | 397 | try expectNode(arena, it, tree, parseExpr, AstError{ |
| ... | @@ -406,6 +408,7 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No | ... | @@ -406,6 +408,7 @@ fn parseContainerField(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*No |
| 406 | .name_token = name_token, | 408 | .name_token = name_token, |
| 407 | .type_expr = type_expr, | 409 | .type_expr = type_expr, |
| 408 | .value_expr = value_expr, | 410 | .value_expr = value_expr, |
| 411 | .align_expr = align_expr, | ||
| 409 | }; | 412 | }; |
| 410 | return &node.base; | 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,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 | test "zig fmt: preserve space between async fn definitions" { | 178 | test "zig fmt: preserve space between async fn definitions" { |
| 170 | try testCanonical( | 179 | try testCanonical( |
| 171 | \\async fn a() void {} | 180 | \\async fn a() void {} |
| ... | @@ -201,6 +210,103 @@ test "zig fmt: comment to disable/enable zig fmt" { | ... | @@ -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 | test "zig fmt: pointer of unknown length" { | 310 | test "zig fmt: pointer of unknown length" { |
| 205 | try testCanonical( | 311 | try testCanonical( |
| 206 | \\fn foo(ptr: [*]u8) void {} | 312 | \\fn foo(ptr: [*]u8) void {} |
| ... | @@ -2269,7 +2375,6 @@ test "zig fmt: if type expr" { | ... | @@ -2269,7 +2375,6 @@ test "zig fmt: if type expr" { |
| 2269 | \\ | 2375 | \\ |
| 2270 | ); | 2376 | ); |
| 2271 | } | 2377 | } |
| 2272 | |||
| 2273 | test "zig fmt: file ends with struct field" { | 2378 | test "zig fmt: file ends with struct field" { |
| 2274 | try testTransform( | 2379 | try testTransform( |
| 2275 | \\a: bool | 2380 | \\a: bool |
| ... | @@ -2279,6 +2384,20 @@ test "zig fmt: file ends with struct field" { | ... | @@ -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 | test "zig fmt: comments at several places in struct init" { | 2401 | test "zig fmt: comments at several places in struct init" { |
| 2283 | try testTransform( | 2402 | try testTransform( |
| 2284 | \\var bar = Bar{ | 2403 | \\var bar = Bar{ |
std/zig/render.zig+115-36| ... | @@ -89,41 +89,98 @@ fn renderRoot( | ... | @@ -89,41 +89,98 @@ fn renderRoot( |
| 89 | var it = tree.root_node.decls.iterator(0); | 89 | var it = tree.root_node.decls.iterator(0); |
| 90 | while (true) { | 90 | while (true) { |
| 91 | var decl = (it.next() orelse return).*; | 91 | var decl = (it.next() orelse return).*; |
| 92 | // look for zig fmt: off comment | 92 | |
| 93 | var start_token_index = decl.firstToken(); | 93 | // This loop does the following: |
| 94 | zig_fmt_loop: while (start_token_index != 0) { | 94 | // |
| 95 | start_token_index -= 1; | 95 | // - Iterates through line/doc comment tokens that precedes the current |
| 96 | const start_token = tree.tokens.at(start_token_index); | 96 | // decl. |
| 97 | switch (start_token.id) { | 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 | Token.Id.LineComment => {}, | 112 | Token.Id.LineComment => {}, |
| 99 | Token.Id.DocComment => continue, | 113 | Token.Id.DocComment => { |
| 114 | copy_start_token_index = token_index; | ||
| 115 | continue; | ||
| 116 | }, | ||
| 100 | else => break, | 117 | else => break, |
| 101 | } | 118 | } |
| 102 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(start_token)[2..], " "), "zig fmt: off")) { | 119 | |
| 103 | var end_token_index = start_token_index; | 120 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) { |
| 104 | while (true) { | 121 | if (!found_fmt_directive) { |
| 105 | end_token_index += 1; | 122 | fmt_active = false; |
| 106 | const end_token = tree.tokens.at(end_token_index); | 123 | found_fmt_directive = true; |
| 107 | switch (end_token.id) { | 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 | Token.Id.LineComment => {}, | 152 | Token.Id.LineComment => {}, |
| 109 | Token.Id.Eof => { | 153 | Token.Id.Eof => unreachable, |
| 110 | const start = tree.tokens.at(start_token_index + 1).start; | ||
| 111 | try copyFixingWhitespace(stream, tree.source[start..]); | ||
| 112 | return; | ||
| 113 | }, | ||
| 114 | else => continue, | 154 | else => continue, |
| 115 | } | 155 | } |
| 116 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(end_token)[2..], " "), "zig fmt: on")) { | 156 | if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: on")) { |
| 117 | const start = tree.tokens.at(start_token_index + 1).start; | 157 | fmt_active = true; |
| 118 | try copyFixingWhitespace(stream, tree.source[start..end_token.end]); | 158 | } else if (mem.eql(u8, mem.trim(u8, tree.tokenSlicePtr(token)[2..], " "), "zig fmt: off")) { |
| 119 | try stream.writeByte('\n'); | 159 | fmt_active = false; |
| 120 | while (tree.tokens.at(decl.firstToken()).start < end_token.end) { | ||
| 121 | decl = (it.next() orelse return).*; | ||
| 122 | } | ||
| 123 | break :zig_fmt_loop; | ||
| 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 | try renderTopLevelDecl(allocator, stream, tree, 0, &start_col, decl); | 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,7 +263,20 @@ fn renderTopLevelDecl(allocator: *mem.Allocator, stream: var, tree: *ast.Tree, i |
| 206 | } else if (field.type_expr != null and field.value_expr == null) { | 263 | } else if (field.type_expr != null and field.value_expr == null) { |
| 207 | try renderToken(tree, stream, field.name_token, indent, start_col, Space.None); // name | 264 | try renderToken(tree, stream, field.name_token, indent, start_col, Space.None); // name |
| 208 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // : | 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 | } else if (field.type_expr == null and field.value_expr != null) { | 280 | } else if (field.type_expr == null and field.value_expr != null) { |
| 211 | try renderToken(tree, stream, field.name_token, indent, start_col, Space.Space); // name | 281 | try renderToken(tree, stream, field.name_token, indent, start_col, Space.Space); // name |
| 212 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // = | 282 | try renderToken(tree, stream, tree.nextToken(field.name_token), indent, start_col, Space.Space); // = |
| ... | @@ -1924,15 +1994,24 @@ fn renderTokenOffset( | ... | @@ -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; | 1997 | while (true) { |
| 1928 | if (comment_is_empty) { | 1998 | const comment_is_empty = mem.trimRight(u8, tree.tokenSlicePtr(next_token), " ").len == 2; |
| 1929 | switch (space) { | 1999 | if (comment_is_empty) { |
| 1930 | Space.Newline => { | 2000 | switch (space) { |
| 1931 | try stream.writeByte('\n'); | 2001 | Space.Newline => { |
| 1932 | start_col.* = 0; | 2002 | offset += 1; |
| 1933 | return; | 2003 | token = next_token; |
| 1934 | }, | 2004 | next_token = tree.tokens.at(token_index + offset); |
| 1935 | else => {}, | 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,6 +2,51 @@ const tests = @import("tests.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | 3 | ||
| 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 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 | cases.addCase(x: { | 50 | cases.addCase(x: { |
| 6 | var tc = cases.create("variable in inline assembly template cannot be found", | 51 | var tc = cases.create("variable in inline assembly template cannot be found", |
| 7 | \\export fn entry() void { | 52 | \\export fn entry() void { |
| ... | @@ -10,7 +55,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -10,7 +55,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 10 | \\ : [bar] "=r" (-> usize) | 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 | tc.target = tests.Target{ | 59 | tc.target = tests.Target{ |
| 15 | .Cross = tests.CrossTarget{ | 60 | .Cross = tests.CrossTarget{ |
| 16 | .arch = .x86_64, | 61 | .arch = .x86_64, |
| ... | @@ -53,8 +98,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -53,8 +98,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 53 | \\} | 98 | \\} |
| 54 | , | 99 | , |
| 55 | "tmp.zig:8:1: error: '@Frame(rangeSum)' depends on itself", | 100 | "tmp.zig:8:1: error: '@Frame(rangeSum)' depends on itself", |
| 56 | "tmp.zig:15:33: note: when analyzing type '@Frame(rangeSumIndirect)' here", | 101 | "tmp.zig:15:33: note: when analyzing type '@Frame(rangeSum)' here", |
| 57 | "tmp.zig:26:25: note: when analyzing type '@Frame(rangeSum)' here", | 102 | "tmp.zig:26:25: note: when analyzing type '@Frame(rangeSumIndirect)' here", |
| 58 | ); | 103 | ); |
| 59 | 104 | ||
| 60 | cases.add( | 105 | cases.add( |
| ... | @@ -245,7 +290,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -245,7 +290,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 245 | , | 290 | , |
| 246 | "tmp.zig:4:1: error: unable to determine async function frame of 'amain'", | 291 | "tmp.zig:4:1: error: unable to determine async function frame of 'amain'", |
| 247 | "tmp.zig:5:10: note: analysis of function 'other' depends on the frame", | 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 | cases.add( | 296 | cases.add( |
| ... | @@ -258,7 +303,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -258,7 +303,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 258 | \\} | 303 | \\} |
| 259 | , | 304 | , |
| 260 | "tmp.zig:4:1: error: cannot resolve '@Frame(amain)': function not fully analyzed yet", | 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 | cases.add( | 309 | cases.add( |
| ... | @@ -404,7 +449,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -404,7 +449,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 404 | \\ const foo: Foo = undefined; | 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 | cases.add( | 455 | cases.add( |
| ... | @@ -470,7 +515,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -470,7 +515,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 470 | ); | 515 | ); |
| 471 | 516 | ||
| 472 | cases.add( | 517 | cases.add( |
| 473 | "Generic function where return type is self-referenced", | 518 | "generic function where return type is self-referenced", |
| 474 | \\fn Foo(comptime T: type) Foo(T) { | 519 | \\fn Foo(comptime T: type) Foo(T) { |
| 475 | \\ return struct{ x: T }; | 520 | \\ return struct{ x: T }; |
| 476 | \\} | 521 | \\} |
| ... | @@ -481,7 +526,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -481,7 +526,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 481 | \\} | 526 | \\} |
| 482 | , | 527 | , |
| 483 | "tmp.zig:1:29: error: evaluation exceeded 1000 backwards branches", | 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 | cases.add( | 532 | cases.add( |
| ... | @@ -645,7 +690,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -645,7 +690,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 645 | \\const A = struct { a : A, }; | 690 | \\const A = struct { a : A, }; |
| 646 | \\export fn entry() usize { return @sizeOf(A); } | 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 | cases.add( | 696 | cases.add( |
| ... | @@ -655,7 +700,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -655,7 +700,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 655 | \\const C = struct { a : A, }; | 700 | \\const C = struct { a : A, }; |
| 656 | \\export fn entry() usize { return @sizeOf(A); } | 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 | cases.add( | 706 | cases.add( |
| ... | @@ -670,7 +715,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -670,7 +715,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 670 | \\ return @sizeOf(@typeOf(foo.x)); | 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 | "tmp.zig:8:28: note: referenced here", | 719 | "tmp.zig:8:28: note: referenced here", |
| 675 | ); | 720 | ); |
| 676 | 721 | ||
| ... | @@ -689,7 +734,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -689,7 +734,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 689 | \\} | 734 | \\} |
| 690 | , | 735 | , |
| 691 | "tmp.zig:7:9: error: dependency loop detected", | 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 | "tmp.zig:10:21: note: referenced here", | 738 | "tmp.zig:10:21: note: referenced here", |
| 694 | ); | 739 | ); |
| 695 | 740 | ||
| ... | @@ -703,7 +748,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -703,7 +748,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 703 | \\ var s: Foo = Foo.E; | 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 | cases.add( | 754 | cases.add( |
| ... | @@ -866,7 +911,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -866,7 +911,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 866 | break :x tc; | 911 | break :x tc; |
| 867 | }); | 912 | }); |
| 868 | 913 | ||
| 869 | cases.addTest( | 914 | cases.add( |
| 870 | "export generic function", | 915 | "export generic function", |
| 871 | \\export fn foo(num: var) i32 { | 916 | \\export fn foo(num: var) i32 { |
| 872 | \\ return 0; | 917 | \\ return 0; |
| ... | @@ -875,17 +920,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -875,17 +920,17 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 875 | "tmp.zig:1:15: error: parameter of type 'var' not allowed in function with calling convention 'ccc'", | 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 | "C pointer to c_void", | 924 | "C pointer to c_void", |
| 880 | \\export fn a() void { | 925 | \\export fn a() void { |
| 881 | \\ var x: *c_void = undefined; | 926 | \\ var x: *c_void = undefined; |
| 882 | \\ var y: [*c]c_void = x; | 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 | "directly embedding opaque type in struct and union", | 934 | "directly embedding opaque type in struct and union", |
| 890 | \\const O = @OpaqueType(); | 935 | \\const O = @OpaqueType(); |
| 891 | \\const Foo = struct { | 936 | \\const Foo = struct { |
| ... | @@ -906,7 +951,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -906,7 +951,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 906 | "tmp.zig:7:10: error: opaque types have unknown size and therefore cannot be directly embedded in unions", | 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 | "implicit cast between C pointer and Zig pointer - bad const/align/child", | 955 | "implicit cast between C pointer and Zig pointer - bad const/align/child", |
| 911 | \\export fn a() void { | 956 | \\export fn a() void { |
| 912 | \\ var x: [*c]u8 = undefined; | 957 | \\ var x: [*c]u8 = undefined; |
| ... | @@ -942,7 +987,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -942,7 +987,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 942 | "tmp.zig:23:22: error: expected type '[*c]u32', found '*u8'", | 987 | "tmp.zig:23:22: error: expected type '[*c]u32', found '*u8'", |
| 943 | ); | 988 | ); |
| 944 | 989 | ||
| 945 | cases.addTest( | 990 | cases.add( |
| 946 | "implicit casting null c pointer to zig pointer", | 991 | "implicit casting null c pointer to zig pointer", |
| 947 | \\comptime { | 992 | \\comptime { |
| 948 | \\ var c_ptr: [*c]u8 = 0; | 993 | \\ var c_ptr: [*c]u8 = 0; |
| ... | @@ -952,7 +997,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -952,7 +997,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 952 | "tmp.zig:3:24: error: null pointer casted to type '*u8'", | 997 | "tmp.zig:3:24: error: null pointer casted to type '*u8'", |
| 953 | ); | 998 | ); |
| 954 | 999 | ||
| 955 | cases.addTest( | 1000 | cases.add( |
| 956 | "implicit casting undefined c pointer to zig pointer", | 1001 | "implicit casting undefined c pointer to zig pointer", |
| 957 | \\comptime { | 1002 | \\comptime { |
| 958 | \\ var c_ptr: [*c]u8 = undefined; | 1003 | \\ var c_ptr: [*c]u8 = undefined; |
| ... | @@ -962,7 +1007,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -962,7 +1007,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 962 | "tmp.zig:3:24: error: use of undefined value here causes undefined behavior", | 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 | "implicit casting C pointers which would mess up null semantics", | 1011 | "implicit casting C pointers which would mess up null semantics", |
| 967 | \\export fn entry() void { | 1012 | \\export fn entry() void { |
| 968 | \\ var slice: []const u8 = "aoeu"; | 1013 | \\ var slice: []const u8 = "aoeu"; |
| ... | @@ -987,7 +1032,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -987,7 +1032,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 987 | "tmp.zig:13:35: note: mutable '[*c]const u8' allows illegal null values stored to type '[*]u8'", | 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 | "implicit casting too big integers to C pointers", | 1036 | "implicit casting too big integers to C pointers", |
| 992 | \\export fn a() void { | 1037 | \\export fn a() void { |
| 993 | \\ var ptr: [*c]u8 = (1 << 64) + 1; | 1038 | \\ var ptr: [*c]u8 = (1 << 64) + 1; |
| ... | @@ -1001,14 +1046,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -1001,14 +1046,14 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1001 | "tmp.zig:6:23: error: integer type 'u65' too big for implicit @intToPtr to type '[*c]u8'", | 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 | "C pointer pointing to non C ABI compatible type or has align attr", | 1050 | "C pointer pointing to non C ABI compatible type or has align attr", |
| 1006 | \\const Foo = struct {}; | 1051 | \\const Foo = struct {}; |
| 1007 | \\export fn a() void { | 1052 | \\export fn a() void { |
| 1008 | \\ const T = [*c]Foo; | 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 | cases.addCase(x: { | 1059 | cases.addCase(x: { |
| ... | @@ -1029,7 +1074,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -1029,7 +1074,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1029 | break :x tc; | 1074 | break :x tc; |
| 1030 | }); | 1075 | }); |
| 1031 | 1076 | ||
| 1032 | cases.addTest( | 1077 | cases.add( |
| 1033 | "assign to invalid dereference", | 1078 | "assign to invalid dereference", |
| 1034 | \\export fn entry() void { | 1079 | \\export fn entry() void { |
| 1035 | \\ 'a'.* = 1; | 1080 | \\ 'a'.* = 1; |
| ... | @@ -1038,7 +1083,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -1038,7 +1083,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1038 | "tmp.zig:2:8: error: attempt to dereference non-pointer type 'comptime_int'", | 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 | "take slice of invalid dereference", | 1087 | "take slice of invalid dereference", |
| 1043 | \\export fn entry() void { | 1088 | \\export fn entry() void { |
| 1044 | \\ const x = 'a'.*[0..]; | 1089 | \\ const x = 'a'.*[0..]; |
| ... | @@ -1047,7 +1092,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -1047,7 +1092,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1047 | "tmp.zig:2:18: error: attempt to dereference non-pointer type 'comptime_int'", | 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 | "@truncate undefined value", | 1096 | "@truncate undefined value", |
| 1052 | \\export fn entry() void { | 1097 | \\export fn entry() void { |
| 1053 | \\ var z = @truncate(u8, u16(undefined)); | 1098 | \\ var z = @truncate(u8, u16(undefined)); |
| ... | @@ -1091,7 +1136,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -1091,7 +1136,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1091 | \\ return 5678; | 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 | cases.add( | 1142 | cases.add( |
| ... | @@ -1935,7 +1980,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -1935,7 +1980,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1935 | "unknown length pointer to opaque", | 1980 | "unknown length pointer to opaque", |
| 1936 | \\export const T = [*]@OpaqueType(); | 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 | cases.add( | 1986 | cases.add( |
| ... | @@ -2924,7 +2969,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -2924,7 +2969,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 2924 | \\fn a() *noreturn {} | 2969 | \\fn a() *noreturn {} |
| 2925 | \\export fn entry() void { _ = a(); } | 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 | cases.add( | 2975 | cases.add( |
| ... | @@ -3596,7 +3641,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -3596,7 +3641,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3596 | ); | 3641 | ); |
| 3597 | 3642 | ||
| 3598 | cases.add( | 3643 | cases.add( |
| 3599 | "non constant expression in array size outside function", | 3644 | "non constant expression in array size", |
| 3600 | \\const Foo = struct { | 3645 | \\const Foo = struct { |
| 3601 | \\ y: [get()]u8, | 3646 | \\ y: [get()]u8, |
| 3602 | \\}; | 3647 | \\}; |
| ... | @@ -3606,8 +3651,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -3606,8 +3651,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3606 | \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); } | 3651 | \\export fn entry() usize { return @sizeOf(@typeOf(Foo)); } |
| 3607 | , | 3652 | , |
| 3608 | "tmp.zig:5:25: error: unable to evaluate constant expression", | 3653 | "tmp.zig:5:25: error: unable to evaluate constant expression", |
| 3609 | "tmp.zig:2:12: note: called from here", | 3654 | "tmp.zig:2:12: note: referenced here", |
| 3610 | "tmp.zig:2:8: note: called from here", | ||
| 3611 | ); | 3655 | ); |
| 3612 | 3656 | ||
| 3613 | cases.add( | 3657 | cases.add( |
| ... | @@ -3701,7 +3745,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -3701,7 +3745,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 3701 | \\export fn entry() usize { return @sizeOf(@typeOf(y)); } | 3745 | \\export fn entry() usize { return @sizeOf(@typeOf(y)); } |
| 3702 | , | 3746 | , |
| 3703 | "tmp.zig:3:14: error: division by zero", | 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 | cases.add( | 3751 | cases.add( |
| ... | @@ -4133,7 +4177,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -4133,7 +4177,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4133 | \\export fn entry() usize { return @sizeOf(@typeOf(seventh_fib_number)); } | 4177 | \\export fn entry() usize { return @sizeOf(@typeOf(seventh_fib_number)); } |
| 4134 | , | 4178 | , |
| 4135 | "tmp.zig:3:21: error: evaluation exceeded 1000 backwards branches", | 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 | cases.add( | 4184 | cases.add( |
| ... | @@ -4174,7 +4219,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -4174,7 +4219,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4174 | \\export fn entry() usize { return @sizeOf(@typeOf(a)); } | 4219 | \\export fn entry() usize { return @sizeOf(@typeOf(a)); } |
| 4175 | , | 4220 | , |
| 4176 | "tmp.zig:6:26: error: unable to evaluate constant expression", | 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 | cases.add( | 4225 | cases.add( |
| ... | @@ -4257,7 +4302,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -4257,7 +4302,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4257 | \\export fn entry() usize { return @sizeOf(@typeOf(y)); } | 4302 | \\export fn entry() usize { return @sizeOf(@typeOf(y)); } |
| 4258 | , | 4303 | , |
| 4259 | "tmp.zig:3:12: error: negation caused overflow", | 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 | cases.add( | 4308 | cases.add( |
| ... | @@ -4270,7 +4315,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -4270,7 +4315,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4270 | \\export fn entry() usize { return @sizeOf(@typeOf(y)); } | 4315 | \\export fn entry() usize { return @sizeOf(@typeOf(y)); } |
| 4271 | , | 4316 | , |
| 4272 | "tmp.zig:3:14: error: operation caused overflow", | 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 | cases.add( | 4321 | cases.add( |
| ... | @@ -4283,7 +4328,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -4283,7 +4328,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4283 | \\export fn entry() usize { return @sizeOf(@typeOf(y)); } | 4328 | \\export fn entry() usize { return @sizeOf(@typeOf(y)); } |
| 4284 | , | 4329 | , |
| 4285 | "tmp.zig:3:14: error: operation caused overflow", | 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 | cases.add( | 4334 | cases.add( |
| ... | @@ -4296,7 +4341,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -4296,7 +4341,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4296 | \\export fn entry() usize { return @sizeOf(@typeOf(y)); } | 4341 | \\export fn entry() usize { return @sizeOf(@typeOf(y)); } |
| 4297 | , | 4342 | , |
| 4298 | "tmp.zig:3:14: error: operation caused overflow", | 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 | cases.add( | 4347 | cases.add( |
| ... | @@ -4388,7 +4433,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -4388,7 +4433,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4388 | \\} | 4433 | \\} |
| 4389 | , | 4434 | , |
| 4390 | "tmp.zig:3:7: error: unable to evaluate constant expression", | 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 | cases.add( | 4439 | cases.add( |
| ... | @@ -4717,7 +4762,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -4717,7 +4762,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4717 | \\} | 4762 | \\} |
| 4718 | , | 4763 | , |
| 4719 | "tmp.zig:10:14: error: unable to evaluate constant expression", | 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 | cases.add( | 4768 | cases.add( |
| ... | @@ -5864,7 +5909,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -5864,7 +5909,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5864 | \\} | 5909 | \\} |
| 5865 | , | 5910 | , |
| 5866 | "tmp.zig:4:25: error: aoeu", | 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 | "tmp.zig:12:20: note: referenced here", | 5913 | "tmp.zig:12:20: note: referenced here", |
| 5869 | ); | 5914 | ); |
| 5870 | 5915 | ||
| ... | @@ -5939,7 +5984,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -5939,7 +5984,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5939 | \\ var x: MultipleChoice = undefined; | 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 | "tmp.zig:1:24: note: consider 'union(enum)' here", | 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,6 +15,7 @@ comptime { |
| 15 | _ = @import("behavior/bugs/1111.zig"); | 15 | _ = @import("behavior/bugs/1111.zig"); |
| 16 | _ = @import("behavior/bugs/1120.zig"); | 16 | _ = @import("behavior/bugs/1120.zig"); |
| 17 | _ = @import("behavior/bugs/1277.zig"); | 17 | _ = @import("behavior/bugs/1277.zig"); |
| 18 | _ = @import("behavior/bugs/1310.zig"); | ||
| 18 | _ = @import("behavior/bugs/1322.zig"); | 19 | _ = @import("behavior/bugs/1322.zig"); |
| 19 | _ = @import("behavior/bugs/1381.zig"); | 20 | _ = @import("behavior/bugs/1381.zig"); |
| 20 | _ = @import("behavior/bugs/1421.zig"); | 21 | _ = @import("behavior/bugs/1421.zig"); |
| ... | @@ -22,15 +23,18 @@ comptime { | ... | @@ -22,15 +23,18 @@ comptime { |
| 22 | _ = @import("behavior/bugs/1486.zig"); | 23 | _ = @import("behavior/bugs/1486.zig"); |
| 23 | _ = @import("behavior/bugs/1500.zig"); | 24 | _ = @import("behavior/bugs/1500.zig"); |
| 24 | _ = @import("behavior/bugs/1607.zig"); | 25 | _ = @import("behavior/bugs/1607.zig"); |
| 26 | _ = @import("behavior/bugs/1735.zig"); | ||
| 25 | _ = @import("behavior/bugs/1851.zig"); | 27 | _ = @import("behavior/bugs/1851.zig"); |
| 26 | _ = @import("behavior/bugs/1914.zig"); | 28 | _ = @import("behavior/bugs/1914.zig"); |
| 27 | _ = @import("behavior/bugs/2006.zig"); | 29 | _ = @import("behavior/bugs/2006.zig"); |
| 28 | _ = @import("behavior/bugs/2114.zig"); | 30 | _ = @import("behavior/bugs/2114.zig"); |
| 29 | _ = @import("behavior/bugs/2346.zig"); | 31 | _ = @import("behavior/bugs/2346.zig"); |
| 30 | _ = @import("behavior/bugs/2578.zig"); | 32 | _ = @import("behavior/bugs/2578.zig"); |
| 33 | _ = @import("behavior/bugs/3112.zig"); | ||
| 31 | _ = @import("behavior/bugs/394.zig"); | 34 | _ = @import("behavior/bugs/394.zig"); |
| 32 | _ = @import("behavior/bugs/421.zig"); | 35 | _ = @import("behavior/bugs/421.zig"); |
| 33 | _ = @import("behavior/bugs/529.zig"); | 36 | _ = @import("behavior/bugs/529.zig"); |
| 37 | _ = @import("behavior/bugs/624.zig"); | ||
| 34 | _ = @import("behavior/bugs/655.zig"); | 38 | _ = @import("behavior/bugs/655.zig"); |
| 35 | _ = @import("behavior/bugs/656.zig"); | 39 | _ = @import("behavior/bugs/656.zig"); |
| 36 | _ = @import("behavior/bugs/679.zig"); | 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,3 +290,18 @@ test "read 128-bit field from default aligned struct in global memory" { |
| 290 | expect((@ptrToInt(&default_aligned_global.badguy) % 16) == 0); | 290 | expect((@ptrToInt(&default_aligned_global.badguy) % 16) == 0); |
| 291 | expect(12 == default_aligned_global.badguy); | 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,3 +292,9 @@ test "read/write through global variable array of struct fields initialized via |
| 292 | }; | 292 | }; |
| 293 | S.doTheTest(); | 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,3 +375,23 @@ test "implicit cast to optional to error union to return result loc" { |
| 375 | S.entry(); | 375 | S.entry(); |
| 376 | //comptime S.entry(); TODO | 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,3 +706,18 @@ test "result location zero sized array inside struct field implicit cast to slic |
| 706 | var foo = E{ .entries = [_]u32{} }; | 706 | var foo = E{ .entries = [_]u32{} }; |
| 707 | expect(foo.entries.len == 0); | 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,3 +100,22 @@ test "nested orelse" { |
| 100 | S.entry(); | 100 | S.entry(); |
| 101 | comptime S.entry(); | 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,12 +504,9 @@ const Contents = struct { |
| 504 | } | 504 | } |
| 505 | }; | 505 | }; |
| 506 | 506 | ||
| 507 | comptime { | 507 | const HashToContents = std.StringHashMap(Contents); |
| 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); | ||
| 511 | const TargetToHash = std.HashMap(DestTarget, []const u8, DestTarget.hash, DestTarget.eql); | 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 | const LibCVendor = enum { | 511 | const LibCVendor = enum { |
| 515 | musl, | 512 | musl, |
tools/update_glibc.zig+3-3| ... | @@ -118,7 +118,7 @@ const FunctionSet = struct { | ... | @@ -118,7 +118,7 @@ const FunctionSet = struct { |
| 118 | list: std.ArrayList(VersionedFn), | 118 | list: std.ArrayList(VersionedFn), |
| 119 | fn_vers_list: FnVersionList, | 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 | const VersionedFn = struct { | 123 | const VersionedFn = struct { |
| 124 | ver: []const u8, // example: "GLIBC_2.15" | 124 | ver: []const u8, // example: "GLIBC_2.15" |
| ... | @@ -140,8 +140,8 @@ pub fn main() !void { | ... | @@ -140,8 +140,8 @@ pub fn main() !void { |
| 140 | const prefix = try fs.path.join(allocator, [_][]const u8{ in_glibc_dir, "sysdeps", "unix", "sysv", "linux" }); | 140 | const prefix = try fs.path.join(allocator, [_][]const u8{ in_glibc_dir, "sysdeps", "unix", "sysv", "linux" }); |
| 141 | const glibc_out_dir = try fs.path.join(allocator, [_][]const u8{ zig_src_dir, "libc", "glibc" }); | 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); | 143 | var global_fn_set = std.StringHashMap(Function).init(allocator); |
| 144 | var global_ver_set = std.AutoHashMap([]const u8, usize).init(allocator); | 144 | var global_ver_set = std.StringHashMap(usize).init(allocator); |
| 145 | var target_functions = std.AutoHashMap(usize, FunctionSet).init(allocator); | 145 | var target_functions = std.AutoHashMap(usize, FunctionSet).init(allocator); |
| 146 | 146 | ||
| 147 | for (abi_lists) |*abi_list| { | 147 | for (abi_lists) |*abi_list| { |