authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-30 23:16:32-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-30 23:19:10-07:00
logcf4aad4858ac61b4814d8f021c8eae22ee7f63e6
tree24b38ed2af8bc40ffa056b5deb3d932916d8c770
parent08565b23f94655e3b2610187f71ba774ce89eeb8

AstGen: fix referencing unreferencable instructions

Sema avoids adding map entries for certain instructions such as `set_eval_branch_quota` and `atomic_store`. This means that result location semantics in AstGen must not emit any instructions that attempt to use the result of any of these instructions. This commit makes AstGen replace such instructions with `Zir.Inst.Ref.void_value` if their result value ends up being referenced. This fixes a compiler crash when running std lib atomic tests.

3 files changed, 311 insertions(+), 1 deletions(-)

src/AstGen.zig+10-1
......@@ -8924,9 +8924,18 @@ fn nodeImpliesComptimeOnly(tree: *const Ast, start_node: Ast.Node.Index) bool {
89248924fn rvalue(
89258925 gz: *GenZir,
89268926 rl: ResultLoc,
8927 result: Zir.Inst.Ref,
8927 raw_result: Zir.Inst.Ref,
89288928 src_node: Ast.Node.Index,
89298929) InnerError!Zir.Inst.Ref {
8930 const result = r: {
8931 if (refToIndex(raw_result)) |result_index| {
8932 const zir_tags = gz.astgen.instructions.items(.tag);
8933 if (zir_tags[result_index].isAlwaysVoid()) {
8934 break :r Zir.Inst.Ref.void_value;
8935 }
8936 }
8937 break :r raw_result;
8938 };
89308939 if (gz.endsWithNoReturn()) return result;
89318940 switch (rl) {
89328941 .none, .coerced_ty => return result,
src/Zir.zig+267
......@@ -1262,6 +1262,273 @@ pub const Inst = struct {
12621262 };
12631263 }
12641264
1265 /// AstGen uses this to find out if `Ref.void_value` should be used in place
1266 /// of the result of a given instruction. This allows Sema to forego adding
1267 /// the instruction to the map after analysis.
1268 pub fn isAlwaysVoid(tag: Tag) bool {
1269 return switch (tag) {
1270 .breakpoint,
1271 .fence,
1272 .@"break",
1273 .break_inline,
1274 .condbr,
1275 .condbr_inline,
1276 .compile_error,
1277 .ret_node,
1278 .ret_load,
1279 .ret_tok,
1280 .ret_err_value,
1281 .@"unreachable",
1282 .repeat,
1283 .repeat_inline,
1284 .panic,
1285 .dbg_stmt,
1286 .dbg_var_ptr,
1287 .dbg_var_val,
1288 .ensure_result_used,
1289 .ensure_result_non_error,
1290 .ensure_err_payload_void,
1291 .set_eval_branch_quota,
1292 .atomic_store,
1293 .store,
1294 .store_node,
1295 .store_to_block_ptr,
1296 .store_to_inferred_ptr,
1297 .resolve_inferred_alloc,
1298 .validate_array_init_ty,
1299 .validate_struct_init_ty,
1300 .validate_struct_init,
1301 .validate_struct_init_comptime,
1302 .validate_array_init,
1303 .validate_array_init_comptime,
1304 .@"export",
1305 .export_value,
1306 .set_align_stack,
1307 .set_cold,
1308 .set_float_mode,
1309 .set_runtime_safety,
1310 .memcpy,
1311 .memset,
1312 => true,
1313
1314 .param,
1315 .param_comptime,
1316 .param_anytype,
1317 .param_anytype_comptime,
1318 .add,
1319 .addwrap,
1320 .add_sat,
1321 .alloc,
1322 .alloc_mut,
1323 .alloc_comptime_mut,
1324 .alloc_inferred,
1325 .alloc_inferred_mut,
1326 .alloc_inferred_comptime,
1327 .alloc_inferred_comptime_mut,
1328 .make_ptr_const,
1329 .array_cat,
1330 .array_mul,
1331 .array_type,
1332 .array_type_sentinel,
1333 .vector_type,
1334 .elem_type,
1335 .indexable_ptr_len,
1336 .anyframe_type,
1337 .as,
1338 .as_node,
1339 .bit_and,
1340 .bitcast,
1341 .bit_or,
1342 .block,
1343 .block_inline,
1344 .suspend_block,
1345 .loop,
1346 .bool_br_and,
1347 .bool_br_or,
1348 .bool_not,
1349 .call,
1350 .cmp_lt,
1351 .cmp_lte,
1352 .cmp_eq,
1353 .cmp_gte,
1354 .cmp_gt,
1355 .cmp_neq,
1356 .coerce_result_ptr,
1357 .error_set_decl,
1358 .error_set_decl_anon,
1359 .error_set_decl_func,
1360 .decl_ref,
1361 .decl_val,
1362 .load,
1363 .div,
1364 .elem_ptr,
1365 .elem_val,
1366 .elem_ptr_node,
1367 .elem_ptr_imm,
1368 .elem_val_node,
1369 .field_ptr,
1370 .field_val,
1371 .field_call_bind,
1372 .field_ptr_named,
1373 .field_val_named,
1374 .field_call_bind_named,
1375 .func,
1376 .func_inferred,
1377 .has_decl,
1378 .int,
1379 .int_big,
1380 .float,
1381 .float128,
1382 .int_type,
1383 .is_non_null,
1384 .is_non_null_ptr,
1385 .is_non_err,
1386 .is_non_err_ptr,
1387 .mod_rem,
1388 .mul,
1389 .mulwrap,
1390 .mul_sat,
1391 .param_type,
1392 .ref,
1393 .shl,
1394 .shl_sat,
1395 .shr,
1396 .str,
1397 .sub,
1398 .subwrap,
1399 .sub_sat,
1400 .negate,
1401 .negate_wrap,
1402 .typeof,
1403 .typeof_builtin,
1404 .xor,
1405 .optional_type,
1406 .optional_payload_safe,
1407 .optional_payload_unsafe,
1408 .optional_payload_safe_ptr,
1409 .optional_payload_unsafe_ptr,
1410 .err_union_payload_safe,
1411 .err_union_payload_unsafe,
1412 .err_union_payload_safe_ptr,
1413 .err_union_payload_unsafe_ptr,
1414 .err_union_code,
1415 .err_union_code_ptr,
1416 .error_to_int,
1417 .int_to_error,
1418 .ptr_type,
1419 .ptr_type_simple,
1420 .enum_literal,
1421 .merge_error_sets,
1422 .error_union_type,
1423 .bit_not,
1424 .error_value,
1425 .slice_start,
1426 .slice_end,
1427 .slice_sentinel,
1428 .import,
1429 .typeof_log2_int_type,
1430 .log2_int_type,
1431 .switch_capture,
1432 .switch_capture_ref,
1433 .switch_capture_multi,
1434 .switch_capture_multi_ref,
1435 .switch_block,
1436 .switch_cond,
1437 .switch_cond_ref,
1438 .array_base_ptr,
1439 .field_base_ptr,
1440 .struct_init_empty,
1441 .struct_init,
1442 .struct_init_ref,
1443 .struct_init_anon,
1444 .struct_init_anon_ref,
1445 .array_init,
1446 .array_init_sent,
1447 .array_init_anon,
1448 .array_init_ref,
1449 .array_init_sent_ref,
1450 .array_init_anon_ref,
1451 .union_init,
1452 .field_type,
1453 .field_type_ref,
1454 .int_to_enum,
1455 .enum_to_int,
1456 .type_info,
1457 .size_of,
1458 .bit_size_of,
1459 .ptr_to_int,
1460 .align_of,
1461 .bool_to_int,
1462 .embed_file,
1463 .error_name,
1464 .sqrt,
1465 .sin,
1466 .cos,
1467 .exp,
1468 .exp2,
1469 .log,
1470 .log2,
1471 .log10,
1472 .fabs,
1473 .floor,
1474 .ceil,
1475 .trunc,
1476 .round,
1477 .tag_name,
1478 .reify,
1479 .type_name,
1480 .frame_type,
1481 .frame_size,
1482 .float_to_int,
1483 .int_to_float,
1484 .int_to_ptr,
1485 .float_cast,
1486 .int_cast,
1487 .err_set_cast,
1488 .ptr_cast,
1489 .truncate,
1490 .align_cast,
1491 .has_field,
1492 .clz,
1493 .ctz,
1494 .pop_count,
1495 .byte_swap,
1496 .bit_reverse,
1497 .div_exact,
1498 .div_floor,
1499 .div_trunc,
1500 .mod,
1501 .rem,
1502 .shl_exact,
1503 .shr_exact,
1504 .bit_offset_of,
1505 .offset_of,
1506 .cmpxchg_strong,
1507 .cmpxchg_weak,
1508 .splat,
1509 .reduce,
1510 .shuffle,
1511 .select,
1512 .atomic_load,
1513 .atomic_rmw,
1514 .mul_add,
1515 .builtin_call,
1516 .field_parent_ptr,
1517 .maximum,
1518 .minimum,
1519 .builtin_async_call,
1520 .c_import,
1521 .@"resume",
1522 .@"await",
1523 .await_nosuspend,
1524 .ret_err_value_code,
1525 .extended,
1526 .closure_get,
1527 .closure_capture,
1528 => false,
1529 };
1530 }
1531
12651532 /// Used by debug safety-checking code.
12661533 pub const data_tags = list: {
12671534 @setEvalBranchQuota(2000);
test/behavior/atomics.zig+34
......@@ -305,3 +305,37 @@ fn testAtomicsWithType(comptime T: type, a: T, b: T) !void {
305305 if (@sizeOf(T) != 0)
306306 try expect(@cmpxchgStrong(T, &x, b, a, .SeqCst, .SeqCst).? == a);
307307}
308
309test "return @atomicStore, using it as a void value" {
310 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
311 if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; // TODO
312 if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO
313 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO
314 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
315
316 const S = struct {
317 const A = struct {
318 value: usize,
319
320 pub fn store(self: *A, value: usize) void {
321 return @atomicStore(usize, &self.value, value, .Unordered);
322 }
323
324 pub fn store2(self: *A, value: usize) void {
325 return switch (value) {
326 else => @atomicStore(usize, &self.value, value, .Unordered),
327 };
328 }
329 };
330
331 fn doTheTest() !void {
332 var x: A = .{ .value = 5 };
333 x.store(10);
334 try expect(x.value == 10);
335 x.store(100);
336 try expect(x.value == 100);
337 }
338 };
339 try S.doTheTest();
340 comptime try S.doTheTest();
341}