| author | bors <bors@rust-lang.org> 2026-04-29 21:53:58 UTC |
| committer | bors <bors@rust-lang.org> 2026-04-29 21:53:58 UTC |
| log | a021a7796f66600f46013d6c8d1dfc9e8d7f4a92 |
| tree | 4caaa57eb3529794ae3f4b3bf6403657930e47c2 |
| parent | c935696dd07ca51e6fba2f6579919eea2a50863b |
| parent | d550bd5c1b87226d56dc3691e5e1d425d399b2bf |
Rollup of 21 pull requests
Successful merges:
- rust-lang/rust#155966 (miri subtree update)
- rust-lang/rust#154149 (resolve: Extend `ambiguous_import_visibilities` deprecation lint to glob-vs-glob ambiguities)
- rust-lang/rust#155189 (simd_reduce_min/max: remove float support)
- rust-lang/rust#155562 (Add a missing `GenericTypeVisitable`, and avoid having interner traits for `FnSigKind` and `Abi`)
- rust-lang/rust#155608 (rustc_middle: Implement the `partial_cmp` operation for `DefId`s)
- rust-lang/rust#155721 (When archive format is wrong produce an error instead of ICE)
- rust-lang/rust#155794 (privacy: share effective visibility initialization)
- rust-lang/rust#155832 (c-variadic: more precise compatibility check in const-eval)
- rust-lang/rust#155856 (std_detect: support detecting more features on aarch64 Windows)
- rust-lang/rust#155861 (Suggest `[const] Trait` bounds in more places)
- rust-lang/rust#155899 (`dlltool`: Set the working directory to workaround `--temp-prefix` bug)
- rust-lang/rust#155916 (Update with new LLVM 22 target for `wasm32-wali-linux-musl` target)
- rust-lang/rust#155935 (remap OUT_DIR paths to fix build script path leakage in crate metadata. )
- rust-lang/rust#155950 (use the new `//@ needs-asm-mnemonic: ret` more)
- rust-lang/rust#155958 (ci(free-disk-space): remove more tools and fix warnings)
- rust-lang/rust#155711 (bump curl-sys and openssl-sys to support OpenSSL 4.0.x)
- rust-lang/rust#155831 (Add `AcceptContext::expect_key_value`)
- rust-lang/rust#155877 (Avoid misleading return-type note for foreign `Fn` callees)
- rust-lang/rust#155949 (Update `opt_ast_lowering_delayed_lints` query to allow "stealing" lints, allowing to use `FnOnce` instead of `Fn`)
- rust-lang/rust#155951 (Make `FlatMapInPlaceVec` an unsafe trait.)
- rust-lang/rust#155967 (Fix `doc_cfg` feature for extern items)230 files changed, 3564 insertions(+), 1303 deletions(-)
Cargo.lock+4-4| ... | ... | @@ -994,9 +994,9 @@ dependencies = [ |
| 994 | 994 | |
| 995 | 995 | [[package]] |
| 996 | 996 | name = "curl-sys" |
| 997 | version = "0.4.84+curl-8.17.0" | |
| 997 | version = "0.4.87+curl-8.19.0" | |
| 998 | 998 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 999 | checksum = "abc4294dc41b882eaff37973c2ec3ae203d0091341ee68fbadd1d06e0c18a73b" | |
| 999 | checksum = "61a460380f0ef783703dcbe909107f39c162adeac050d73c850055118b5b6327" | |
| 1000 | 1000 | dependencies = [ |
| 1001 | 1001 | "cc", |
| 1002 | 1002 | "libc", |
| ... | ... | @@ -2728,9 +2728,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" |
| 2728 | 2728 | |
| 2729 | 2729 | [[package]] |
| 2730 | 2730 | name = "openssl-sys" |
| 2731 | version = "0.9.111" | |
| 2731 | version = "0.9.114" | |
| 2732 | 2732 | source = "registry+https://github.com/rust-lang/crates.io-index" |
| 2733 | checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" | |
| 2733 | checksum = "13ce1245cd07fcc4cfdb438f7507b0c7e4f3849a69fd84d52374c66d83741bb6" | |
| 2734 | 2734 | dependencies = [ |
| 2735 | 2735 | "cc", |
| 2736 | 2736 | "libc", |
compiler/rustc_ast_lowering/src/lib.rs+1-1| ... | ... | @@ -765,7 +765,7 @@ impl<'hir> LoweringContext<'_, 'hir> { |
| 765 | 765 | let mut bodies = std::mem::take(&mut self.bodies); |
| 766 | 766 | let define_opaque = std::mem::take(&mut self.define_opaque); |
| 767 | 767 | let trait_map = std::mem::take(&mut self.trait_map); |
| 768 | let delayed_lints = std::mem::take(&mut self.delayed_lints).into_boxed_slice(); | |
| 768 | let delayed_lints = Steal::new(std::mem::take(&mut self.delayed_lints).into_boxed_slice()); | |
| 769 | 769 | |
| 770 | 770 | #[cfg(debug_assertions)] |
| 771 | 771 | for (id, attrs) in attrs.iter() { |
compiler/rustc_attr_parsing/src/attributes/cfg.rs+6-13| ... | ... | @@ -113,7 +113,7 @@ pub fn parse_cfg_entry( |
| 113 | 113 | else { |
| 114 | 114 | return Err(cx.adcx().expected_identifier(meta.path().span())); |
| 115 | 115 | }; |
| 116 | parse_name_value(name, meta.path().span(), a.name_value(), meta.span(), cx)? | |
| 116 | parse_name_value(name, meta.path().span(), a.as_name_value(), meta.span(), cx)? | |
| 117 | 117 | } |
| 118 | 118 | }, |
| 119 | 119 | MetaItemOrLitParser::Lit(lit) => match lit.kind { |
| ... | ... | @@ -175,23 +175,16 @@ fn parse_cfg_entry_target( |
| 175 | 175 | let mut result = ThinVec::new(); |
| 176 | 176 | for sub_item in list.mixed() { |
| 177 | 177 | // First, validate that this is a NameValue item |
| 178 | let Some(sub_item) = sub_item.meta_item() else { | |
| 179 | cx.adcx().expected_name_value(sub_item.span(), None); | |
| 180 | continue; | |
| 181 | }; | |
| 182 | let Some(nv) = sub_item.args().name_value() else { | |
| 183 | cx.adcx().expected_name_value(sub_item.span(), None); | |
| 178 | let Some((name, value)) = cx.expect_name_value(sub_item, sub_item.span(), None) else { | |
| 184 | 179 | continue; |
| 185 | 180 | }; |
| 186 | 181 | |
| 187 | 182 | // Then, parse it as a name-value item |
| 188 | let Some(name) = sub_item.path().word_sym().filter(|s| !s.is_path_segment_keyword()) else { | |
| 189 | return Err(cx.adcx().expected_identifier(sub_item.path().span())); | |
| 190 | }; | |
| 183 | if name.is_path_segment_keyword() { | |
| 184 | return Err(cx.adcx().expected_identifier(name.span)); | |
| 185 | } | |
| 191 | 186 | let name = Symbol::intern(&format!("target_{name}")); |
| 192 | if let Ok(cfg) = | |
| 193 | parse_name_value(name, sub_item.path().span(), Some(nv), sub_item.span(), cx) | |
| 194 | { | |
| 187 | if let Ok(cfg) = parse_name_value(name, sub_item.span(), Some(value), sub_item.span(), cx) { | |
| 195 | 188 | result.push(cfg); |
| 196 | 189 | } |
| 197 | 190 | } |
compiler/rustc_attr_parsing/src/attributes/cfi_encoding.rs+1-5| ... | ... | @@ -11,11 +11,7 @@ impl SingleAttributeParser for CfiEncodingParser { |
| 11 | 11 | const TEMPLATE: AttributeTemplate = template!(NameValueStr: "encoding"); |
| 12 | 12 | |
| 13 | 13 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 14 | let Some(name_value) = args.name_value() else { | |
| 15 | let attr_span = cx.attr_span; | |
| 16 | cx.adcx().expected_name_value(attr_span, Some(sym::cfi_encoding)); | |
| 17 | return None; | |
| 18 | }; | |
| 14 | let name_value = cx.expect_name_value(args, cx.attr_span, Some(sym::cfi_encoding))?; | |
| 19 | 15 | |
| 20 | 16 | let Some(value_str) = name_value.value_as_str() else { |
| 21 | 17 | cx.adcx().expected_string_literal(name_value.value_span, None); |
compiler/rustc_attr_parsing/src/attributes/codegen_attrs.rs+31-67| ... | ... | @@ -118,11 +118,7 @@ impl SingleAttributeParser for ExportNameParser { |
| 118 | 118 | const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); |
| 119 | 119 | |
| 120 | 120 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 121 | let Some(nv) = args.name_value() else { | |
| 122 | let attr_span = cx.attr_span; | |
| 123 | cx.adcx().expected_name_value(attr_span, None); | |
| 124 | return None; | |
| 125 | }; | |
| 121 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 126 | 122 | let Some(name) = nv.value_as_str() else { |
| 127 | 123 | cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); |
| 128 | 124 | return None; |
| ... | ... | @@ -146,11 +142,7 @@ impl SingleAttributeParser for RustcObjcClassParser { |
| 146 | 142 | const TEMPLATE: AttributeTemplate = template!(NameValueStr: "ClassName"); |
| 147 | 143 | |
| 148 | 144 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 149 | let Some(nv) = args.name_value() else { | |
| 150 | let attr_span = cx.attr_span; | |
| 151 | cx.adcx().expected_name_value(attr_span, None); | |
| 152 | return None; | |
| 153 | }; | |
| 145 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 154 | 146 | let Some(classname) = nv.value_as_str() else { |
| 155 | 147 | // `#[rustc_objc_class = ...]` is expected to be used as an implementation detail |
| 156 | 148 | // inside a standard library macro, but `cx.expected_string_literal` exposes too much. |
| ... | ... | @@ -177,11 +169,7 @@ impl SingleAttributeParser for RustcObjcSelectorParser { |
| 177 | 169 | const TEMPLATE: AttributeTemplate = template!(NameValueStr: "methodName"); |
| 178 | 170 | |
| 179 | 171 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 180 | let Some(nv) = args.name_value() else { | |
| 181 | let attr_span = cx.attr_span; | |
| 182 | cx.adcx().expected_name_value(attr_span, None); | |
| 183 | return None; | |
| 184 | }; | |
| 172 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 185 | 173 | let Some(methname) = nv.value_as_str() else { |
| 186 | 174 | // `#[rustc_objc_selector = ...]` is expected to be used as an implementation detail |
| 187 | 175 | // inside a standard library macro, but `cx.expected_string_literal` exposes too much. |
| ... | ... | @@ -471,29 +459,20 @@ fn parse_tf_attribute( |
| 471 | 459 | return features; |
| 472 | 460 | } |
| 473 | 461 | for item in list.mixed() { |
| 474 | let Some(name_value) = item.meta_item() else { | |
| 475 | cx.adcx().expected_name_value(item.span(), Some(sym::enable)); | |
| 462 | let Some((ident, value)) = cx.expect_name_value(item, item.span(), Some(sym::enable)) | |
| 463 | else { | |
| 476 | 464 | return features; |
| 477 | 465 | }; |
| 478 | 466 | |
| 479 | 467 | // Validate name |
| 480 | let Some(name) = name_value.path().word_sym() else { | |
| 481 | cx.adcx().expected_name_value(name_value.path().span(), Some(sym::enable)); | |
| 482 | return features; | |
| 483 | }; | |
| 484 | if name != sym::enable { | |
| 485 | cx.adcx().expected_name_value(name_value.path().span(), Some(sym::enable)); | |
| 468 | if ident.name != sym::enable { | |
| 469 | cx.adcx().expected_specific_argument(ident.span, &[sym::enable]); | |
| 486 | 470 | return features; |
| 487 | 471 | } |
| 488 | 472 | |
| 489 | 473 | // Use value |
| 490 | let Some(name_value) = name_value.args().name_value() else { | |
| 491 | cx.adcx().expected_name_value(item.span(), Some(sym::enable)); | |
| 492 | return features; | |
| 493 | }; | |
| 494 | let Some(value_str) = name_value.value_as_str() else { | |
| 495 | cx.adcx() | |
| 496 | .expected_string_literal(name_value.value_span, Some(name_value.value_as_lit())); | |
| 474 | let Some(value_str) = value.value_as_str() else { | |
| 475 | cx.adcx().expected_string_literal(value.value_span, Some(value.value_as_lit())); | |
| 497 | 476 | return features; |
| 498 | 477 | }; |
| 499 | 478 | for feature in value_str.as_str().split(",") { |
| ... | ... | @@ -592,14 +571,7 @@ impl SingleAttributeParser for SanitizeParser { |
| 592 | 571 | let mut rtsan = None; |
| 593 | 572 | |
| 594 | 573 | for item in list.mixed() { |
| 595 | let Some(item) = item.meta_item() else { | |
| 596 | cx.adcx().expected_name_value(item.span(), None); | |
| 597 | continue; | |
| 598 | }; | |
| 599 | ||
| 600 | let path = item.path().word_sym(); | |
| 601 | let Some(value) = item.args().name_value() else { | |
| 602 | cx.adcx().expected_name_value(item.span(), path); | |
| 574 | let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else { | |
| 603 | 575 | continue; |
| 604 | 576 | }; |
| 605 | 577 | |
| ... | ... | @@ -628,20 +600,20 @@ impl SingleAttributeParser for SanitizeParser { |
| 628 | 600 | } |
| 629 | 601 | }; |
| 630 | 602 | |
| 631 | match path { | |
| 632 | Some(sym::address) | Some(sym::kernel_address) => { | |
| 603 | match ident.name { | |
| 604 | sym::address | sym::kernel_address => { | |
| 633 | 605 | apply(SanitizerSet::ADDRESS | SanitizerSet::KERNELADDRESS) |
| 634 | 606 | } |
| 635 | Some(sym::cfi) => apply(SanitizerSet::CFI), | |
| 636 | Some(sym::kcfi) => apply(SanitizerSet::KCFI), | |
| 637 | Some(sym::memory) => apply(SanitizerSet::MEMORY), | |
| 638 | Some(sym::memtag) => apply(SanitizerSet::MEMTAG), | |
| 639 | Some(sym::shadow_call_stack) => apply(SanitizerSet::SHADOWCALLSTACK), | |
| 640 | Some(sym::thread) => apply(SanitizerSet::THREAD), | |
| 641 | Some(sym::hwaddress) | Some(sym::kernel_hwaddress) => { | |
| 607 | sym::cfi => apply(SanitizerSet::CFI), | |
| 608 | sym::kcfi => apply(SanitizerSet::KCFI), | |
| 609 | sym::memory => apply(SanitizerSet::MEMORY), | |
| 610 | sym::memtag => apply(SanitizerSet::MEMTAG), | |
| 611 | sym::shadow_call_stack => apply(SanitizerSet::SHADOWCALLSTACK), | |
| 612 | sym::thread => apply(SanitizerSet::THREAD), | |
| 613 | sym::hwaddress | sym::kernel_hwaddress => { | |
| 642 | 614 | apply(SanitizerSet::HWADDRESS | SanitizerSet::KERNELHWADDRESS) |
| 643 | 615 | } |
| 644 | Some(sym::realtime) => match value.value_as_str() { | |
| 616 | sym::realtime => match value.value_as_str() { | |
| 645 | 617 | Some(sym::nonblocking) => rtsan = Some(RtsanSetting::Nonblocking), |
| 646 | 618 | Some(sym::blocking) => rtsan = Some(RtsanSetting::Blocking), |
| 647 | 619 | Some(sym::caller) => rtsan = Some(RtsanSetting::Caller), |
| ... | ... | @@ -654,7 +626,7 @@ impl SingleAttributeParser for SanitizeParser { |
| 654 | 626 | }, |
| 655 | 627 | _ => { |
| 656 | 628 | cx.adcx().expected_specific_argument_strings( |
| 657 | item.path().span(), | |
| 629 | ident.span, | |
| 658 | 630 | &[ |
| 659 | 631 | sym::address, |
| 660 | 632 | sym::kernel_address, |
| ... | ... | @@ -725,33 +697,25 @@ impl SingleAttributeParser for PatchableFunctionEntryParser { |
| 725 | 697 | let mut errored = false; |
| 726 | 698 | |
| 727 | 699 | for item in meta_item_list.mixed() { |
| 728 | let Some(meta_item) = item.meta_item() else { | |
| 729 | errored = true; | |
| 730 | cx.adcx().expected_name_value(item.span(), None); | |
| 731 | continue; | |
| 732 | }; | |
| 733 | ||
| 734 | let Some(name_value_lit) = meta_item.args().name_value() else { | |
| 735 | errored = true; | |
| 736 | cx.adcx().expected_name_value(item.span(), None); | |
| 700 | let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else { | |
| 737 | 701 | continue; |
| 738 | 702 | }; |
| 739 | 703 | |
| 740 | let attrib_to_write = match meta_item.ident().map(|ident| ident.name) { | |
| 741 | Some(sym::prefix_nops) => { | |
| 704 | let attrib_to_write = match ident.name { | |
| 705 | sym::prefix_nops => { | |
| 742 | 706 | // Duplicate prefixes are not allowed |
| 743 | 707 | if prefix.is_some() { |
| 744 | 708 | errored = true; |
| 745 | cx.adcx().duplicate_key(meta_item.path().span(), sym::prefix_nops); | |
| 709 | cx.adcx().duplicate_key(ident.span, sym::prefix_nops); | |
| 746 | 710 | continue; |
| 747 | 711 | } |
| 748 | 712 | &mut prefix |
| 749 | 713 | } |
| 750 | Some(sym::entry_nops) => { | |
| 714 | sym::entry_nops => { | |
| 751 | 715 | // Duplicate entries are not allowed |
| 752 | 716 | if entry.is_some() { |
| 753 | 717 | errored = true; |
| 754 | cx.adcx().duplicate_key(meta_item.path().span(), sym::entry_nops); | |
| 718 | cx.adcx().duplicate_key(ident.span, sym::entry_nops); | |
| 755 | 719 | continue; |
| 756 | 720 | } |
| 757 | 721 | &mut entry |
| ... | ... | @@ -759,23 +723,23 @@ impl SingleAttributeParser for PatchableFunctionEntryParser { |
| 759 | 723 | _ => { |
| 760 | 724 | errored = true; |
| 761 | 725 | cx.adcx().expected_specific_argument( |
| 762 | meta_item.path().span(), | |
| 726 | ident.span, | |
| 763 | 727 | &[sym::prefix_nops, sym::entry_nops], |
| 764 | 728 | ); |
| 765 | 729 | continue; |
| 766 | 730 | } |
| 767 | 731 | }; |
| 768 | 732 | |
| 769 | let rustc_ast::LitKind::Int(val, _) = name_value_lit.value_as_lit().kind else { | |
| 733 | let rustc_ast::LitKind::Int(val, _) = value.value_as_lit().kind else { | |
| 770 | 734 | errored = true; |
| 771 | cx.adcx().expected_integer_literal(name_value_lit.value_span); | |
| 735 | cx.adcx().expected_integer_literal(value.value_span); | |
| 772 | 736 | continue; |
| 773 | 737 | }; |
| 774 | 738 | |
| 775 | 739 | let Ok(val) = val.get().try_into() else { |
| 776 | 740 | errored = true; |
| 777 | 741 | cx.adcx().expected_integer_literal_in_range( |
| 778 | name_value_lit.value_span, | |
| 742 | value.value_span, | |
| 779 | 743 | u8::MIN as isize, |
| 780 | 744 | u8::MAX as isize, |
| 781 | 745 | ); |
compiler/rustc_attr_parsing/src/attributes/crate_level.rs+7-38| ... | ... | @@ -16,11 +16,7 @@ impl SingleAttributeParser for CrateNameParser { |
| 16 | 16 | const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); |
| 17 | 17 | |
| 18 | 18 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 19 | let ArgParser::NameValue(n) = args else { | |
| 20 | let attr_span = cx.attr_span; | |
| 21 | cx.adcx().expected_name_value(attr_span, None); | |
| 22 | return None; | |
| 23 | }; | |
| 19 | let n = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 24 | 20 | |
| 25 | 21 | let Some(name) = n.value_as_str() else { |
| 26 | 22 | cx.adcx().expected_string_literal(n.value_span, Some(n.value_as_lit())); |
| ... | ... | @@ -47,11 +43,7 @@ impl CombineAttributeParser for CrateTypeParser { |
| 47 | 43 | cx: &mut AcceptContext<'_, '_>, |
| 48 | 44 | args: &ArgParser, |
| 49 | 45 | ) -> impl IntoIterator<Item = Self::Item> { |
| 50 | let ArgParser::NameValue(n) = args else { | |
| 51 | let attr_span = cx.attr_span; | |
| 52 | cx.adcx().expected_name_value(attr_span, None); | |
| 53 | return None; | |
| 54 | }; | |
| 46 | let n = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 55 | 47 | |
| 56 | 48 | let Some(crate_type) = n.value_as_str() else { |
| 57 | 49 | cx.adcx().expected_string_literal(n.value_span, Some(n.value_as_lit())); |
| ... | ... | @@ -95,11 +87,7 @@ impl SingleAttributeParser for RecursionLimitParser { |
| 95 | 87 | const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); |
| 96 | 88 | |
| 97 | 89 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 98 | let ArgParser::NameValue(nv) = args else { | |
| 99 | let attr_span = cx.attr_span; | |
| 100 | cx.adcx().expected_name_value(attr_span, None); | |
| 101 | return None; | |
| 102 | }; | |
| 90 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 103 | 91 | |
| 104 | 92 | Some(AttributeKind::RecursionLimit { |
| 105 | 93 | limit: cx.parse_limit_int(nv)?, |
| ... | ... | @@ -117,11 +105,7 @@ impl SingleAttributeParser for MoveSizeLimitParser { |
| 117 | 105 | const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); |
| 118 | 106 | |
| 119 | 107 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 120 | let ArgParser::NameValue(nv) = args else { | |
| 121 | let attr_span = cx.attr_span; | |
| 122 | cx.adcx().expected_name_value(attr_span, None); | |
| 123 | return None; | |
| 124 | }; | |
| 108 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 125 | 109 | |
| 126 | 110 | Some(AttributeKind::MoveSizeLimit { |
| 127 | 111 | limit: cx.parse_limit_int(nv)?, |
| ... | ... | @@ -140,11 +124,7 @@ impl SingleAttributeParser for TypeLengthLimitParser { |
| 140 | 124 | const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); |
| 141 | 125 | |
| 142 | 126 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 143 | let ArgParser::NameValue(nv) = args else { | |
| 144 | let attr_span = cx.attr_span; | |
| 145 | cx.adcx().expected_name_value(attr_span, None); | |
| 146 | return None; | |
| 147 | }; | |
| 127 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 148 | 128 | |
| 149 | 129 | Some(AttributeKind::TypeLengthLimit { |
| 150 | 130 | limit: cx.parse_limit_int(nv)?, |
| ... | ... | @@ -162,11 +142,7 @@ impl SingleAttributeParser for PatternComplexityLimitParser { |
| 162 | 142 | const ALLOWED_TARGETS: AllowedTargets = AllowedTargets::AllowList(&[Allow(Target::Crate)]); |
| 163 | 143 | |
| 164 | 144 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 165 | let ArgParser::NameValue(nv) = args else { | |
| 166 | let attr_span = cx.attr_span; | |
| 167 | cx.adcx().expected_name_value(attr_span, None); | |
| 168 | return None; | |
| 169 | }; | |
| 145 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 170 | 146 | |
| 171 | 147 | Some(AttributeKind::PatternComplexityLimit { |
| 172 | 148 | limit: cx.parse_limit_int(nv)?, |
| ... | ... | @@ -219,14 +195,7 @@ impl SingleAttributeParser for WindowsSubsystemParser { |
| 219 | 195 | const TEMPLATE: AttributeTemplate = template!(NameValueStr: ["windows", "console"], "https://doc.rust-lang.org/reference/runtime.html#the-windows_subsystem-attribute"); |
| 220 | 196 | |
| 221 | 197 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 222 | let Some(nv) = args.name_value() else { | |
| 223 | let inner_span = cx.inner_span; | |
| 224 | cx.adcx().expected_name_value( | |
| 225 | args.span().unwrap_or(inner_span), | |
| 226 | Some(sym::windows_subsystem), | |
| 227 | ); | |
| 228 | return None; | |
| 229 | }; | |
| 198 | let nv = cx.expect_name_value(args, cx.inner_span, Some(sym::windows_subsystem))?; | |
| 230 | 199 | |
| 231 | 200 | let kind = match nv.value_as_str() { |
| 232 | 201 | Some(sym::console) => WindowsSubsystemKind::Console, |
compiler/rustc_attr_parsing/src/attributes/debugger.rs+8-17| ... | ... | @@ -21,33 +21,24 @@ impl CombineAttributeParser for DebuggerViualizerParser { |
| 21 | 21 | args: &ArgParser, |
| 22 | 22 | ) -> impl IntoIterator<Item = Self::Item> { |
| 23 | 23 | let single = cx.expect_single_element_list(args, cx.attr_span)?; |
| 24 | let Some(mi) = single.meta_item() else { | |
| 25 | cx.adcx().expected_name_value(single.span(), None); | |
| 26 | return None; | |
| 27 | }; | |
| 28 | let path = mi.path().word_sym(); | |
| 29 | let visualizer_type = match path { | |
| 30 | Some(sym::natvis_file) => DebuggerVisualizerType::Natvis, | |
| 31 | Some(sym::gdb_script_file) => DebuggerVisualizerType::GdbPrettyPrinter, | |
| 24 | let (ident, args) = cx.expect_name_value(single, single.span(), None)?; | |
| 25 | let visualizer_type = match ident.name { | |
| 26 | sym::natvis_file => DebuggerVisualizerType::Natvis, | |
| 27 | sym::gdb_script_file => DebuggerVisualizerType::GdbPrettyPrinter, | |
| 32 | 28 | _ => { |
| 33 | 29 | cx.adcx().expected_specific_argument( |
| 34 | mi.path().span(), | |
| 30 | ident.span, | |
| 35 | 31 | &[sym::natvis_file, sym::gdb_script_file], |
| 36 | 32 | ); |
| 37 | 33 | return None; |
| 38 | 34 | } |
| 39 | 35 | }; |
| 40 | 36 | |
| 41 | let Some(path) = mi.args().name_value() else { | |
| 42 | cx.adcx().expected_name_value(single.span(), path); | |
| 43 | return None; | |
| 44 | }; | |
| 45 | ||
| 46 | let Some(path) = path.value_as_str() else { | |
| 47 | cx.adcx().expected_string_literal(path.value_span, Some(path.value_as_lit())); | |
| 37 | let Some(path) = args.value_as_str() else { | |
| 38 | cx.adcx().expected_string_literal(args.value_span, Some(args.value_as_lit())); | |
| 48 | 39 | return None; |
| 49 | 40 | }; |
| 50 | 41 | |
| 51 | Some(DebugVisualizer { span: mi.span(), visualizer_type, path }) | |
| 42 | Some(DebugVisualizer { span: ident.span.to(args.value_span), visualizer_type, path }) | |
| 52 | 43 | } |
| 53 | 44 | } |
compiler/rustc_attr_parsing/src/attributes/deprecation.rs+4-8| ... | ... | @@ -18,15 +18,11 @@ fn get( |
| 18 | 18 | cx.adcx().duplicate_key(param_span, name); |
| 19 | 19 | return None; |
| 20 | 20 | } |
| 21 | if let Some(v) = arg.name_value() { | |
| 22 | if let Some(value_str) = v.value_as_ident() { | |
| 23 | Some(value_str) | |
| 24 | } else { | |
| 25 | cx.adcx().expected_string_literal(v.value_span, Some(&v.value_as_lit())); | |
| 26 | None | |
| 27 | } | |
| 21 | let v = cx.expect_name_value(arg, param_span, Some(name))?; | |
| 22 | if let Some(value_str) = v.value_as_ident() { | |
| 23 | Some(value_str) | |
| 28 | 24 | } else { |
| 29 | cx.adcx().expected_name_value(param_span, Some(name)); | |
| 25 | cx.adcx().expected_string_literal(v.value_span, Some(&v.value_as_lit())); | |
| 30 | 26 | None |
| 31 | 27 | } |
| 32 | 28 | } |
compiler/rustc_attr_parsing/src/attributes/diagnostic/mod.rs+1-1| ... | ... | @@ -270,7 +270,7 @@ fn parse_directive_items<'p>( |
| 270 | 270 | // But we don't assert its presence yet because we don't want to mention it |
| 271 | 271 | // if someone does something like `#[diagnostic::on_unimplemented(doesnt_exist)]`. |
| 272 | 272 | // That happens in the big `match` below. |
| 273 | let value: Option<Ident> = match item.args().name_value() { | |
| 273 | let value: Option<Ident> = match item.args().as_name_value() { | |
| 274 | 274 | Some(nv) => Some(or_malformed!(nv.value_as_ident()?)), |
| 275 | 275 | None => None, |
| 276 | 276 | }; |
compiler/rustc_attr_parsing/src/attributes/doc.rs+5-5| ... | ... | @@ -113,7 +113,7 @@ fn parse_keyword_and_attribute( |
| 113 | 113 | attr_value: &mut Option<(Symbol, Span)>, |
| 114 | 114 | attr_name: Symbol, |
| 115 | 115 | ) { |
| 116 | let Some(nv) = args.name_value() else { | |
| 116 | let Some(nv) = args.as_name_value() else { | |
| 117 | 117 | expected_name_value(cx, args.span().unwrap_or(path.span()), path.word_sym()); |
| 118 | 118 | return; |
| 119 | 119 | }; |
| ... | ... | @@ -397,7 +397,7 @@ impl DocParser { |
| 397 | 397 | super::cfg::parse_name_value( |
| 398 | 398 | name, |
| 399 | 399 | sub_item.path().span(), |
| 400 | a.name_value(), | |
| 400 | a.as_name_value(), | |
| 401 | 401 | sub_item.span(), |
| 402 | 402 | cx, |
| 403 | 403 | ) |
| ... | ... | @@ -408,7 +408,7 @@ impl DocParser { |
| 408 | 408 | // If `value` is `Some`, `a.name_value()` will always return |
| 409 | 409 | // `Some` as well. |
| 410 | 410 | value: value |
| 411 | .map(|v| (v, a.name_value().unwrap().value_span)), | |
| 411 | .map(|v| (v, a.as_name_value().unwrap().value_span)), | |
| 412 | 412 | }) |
| 413 | 413 | } |
| 414 | 414 | } |
| ... | ... | @@ -498,7 +498,7 @@ impl DocParser { |
| 498 | 498 | } |
| 499 | 499 | macro_rules! string_arg_and_crate_level { |
| 500 | 500 | ($ident: ident) => {{ |
| 501 | let Some(nv) = args.name_value() else { | |
| 501 | let Some(nv) = args.as_name_value() else { | |
| 502 | 502 | expected_name_value(cx, args.span().unwrap_or(path.span()), path.word_sym()); |
| 503 | 503 | return; |
| 504 | 504 | }; |
| ... | ... | @@ -605,7 +605,7 @@ impl DocParser { |
| 605 | 605 | span, |
| 606 | 606 | ); |
| 607 | 607 | } |
| 608 | Some(sym::include) if let Some(nv) = args.name_value() => { | |
| 608 | Some(sym::include) if let Some(nv) = args.as_name_value() => { | |
| 609 | 609 | let inner = match cx.attr_style { |
| 610 | 610 | AttrStyle::Outer => "", |
| 611 | 611 | AttrStyle::Inner => "!", |
compiler/rustc_attr_parsing/src/attributes/link_attrs.rs+16-30| ... | ... | @@ -36,11 +36,7 @@ impl SingleAttributeParser for LinkNameParser { |
| 36 | 36 | ); |
| 37 | 37 | |
| 38 | 38 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 39 | let Some(nv) = args.name_value() else { | |
| 40 | let attr_span = cx.attr_span; | |
| 41 | cx.adcx().expected_name_value(attr_span, None); | |
| 42 | return None; | |
| 43 | }; | |
| 39 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 44 | 40 | let Some(name) = nv.value_as_str() else { |
| 45 | 41 | cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); |
| 46 | 42 | return None; |
| ... | ... | @@ -261,12 +257,11 @@ impl LinkParser { |
| 261 | 257 | cx.adcx().duplicate_key(item.span(), sym::name); |
| 262 | 258 | return true; |
| 263 | 259 | } |
| 264 | let Some(nv) = item.args().name_value() else { | |
| 265 | cx.adcx().expected_name_value(item.span(), Some(sym::name)); | |
| 260 | let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::name)) else { | |
| 266 | 261 | return false; |
| 267 | 262 | }; |
| 268 | 263 | let Some(link_name) = nv.value_as_str() else { |
| 269 | cx.adcx().expected_name_value(item.span(), Some(sym::name)); | |
| 264 | cx.adcx().expected_string_literal(nv.args_span(), Some(nv.value_as_lit())); | |
| 270 | 265 | return false; |
| 271 | 266 | }; |
| 272 | 267 | |
| ... | ... | @@ -288,12 +283,11 @@ impl LinkParser { |
| 288 | 283 | cx.adcx().duplicate_key(item.span(), sym::kind); |
| 289 | 284 | return true; |
| 290 | 285 | } |
| 291 | let Some(nv) = item.args().name_value() else { | |
| 292 | cx.adcx().expected_name_value(item.span(), Some(sym::kind)); | |
| 286 | let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::kind)) else { | |
| 293 | 287 | return true; |
| 294 | 288 | }; |
| 295 | 289 | let Some(link_kind) = nv.value_as_str() else { |
| 296 | cx.adcx().expected_name_value(item.span(), Some(sym::kind)); | |
| 290 | cx.adcx().expected_string_literal(item.span(), Some(nv.value_as_lit())); | |
| 297 | 291 | return true; |
| 298 | 292 | }; |
| 299 | 293 | |
| ... | ... | @@ -368,12 +362,11 @@ impl LinkParser { |
| 368 | 362 | cx.adcx().duplicate_key(item.span(), sym::modifiers); |
| 369 | 363 | return true; |
| 370 | 364 | } |
| 371 | let Some(nv) = item.args().name_value() else { | |
| 372 | cx.adcx().expected_name_value(item.span(), Some(sym::modifiers)); | |
| 365 | let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::modifiers)) else { | |
| 373 | 366 | return true; |
| 374 | 367 | }; |
| 375 | 368 | let Some(link_modifiers) = nv.value_as_str() else { |
| 376 | cx.adcx().expected_name_value(item.span(), Some(sym::modifiers)); | |
| 369 | cx.adcx().expected_string_literal(item.span(), Some(nv.value_as_lit())); | |
| 377 | 370 | return true; |
| 378 | 371 | }; |
| 379 | 372 | *modifiers = Some((link_modifiers, nv.value_span)); |
| ... | ... | @@ -410,12 +403,13 @@ impl LinkParser { |
| 410 | 403 | cx.adcx().duplicate_key(item.span(), sym::wasm_import_module); |
| 411 | 404 | return true; |
| 412 | 405 | } |
| 413 | let Some(nv) = item.args().name_value() else { | |
| 414 | cx.adcx().expected_name_value(item.span(), Some(sym::wasm_import_module)); | |
| 406 | let Some(nv) = | |
| 407 | cx.expect_name_value(item.args(), item.span(), Some(sym::wasm_import_module)) | |
| 408 | else { | |
| 415 | 409 | return true; |
| 416 | 410 | }; |
| 417 | 411 | let Some(link_wasm_import_module) = nv.value_as_str() else { |
| 418 | cx.adcx().expected_name_value(item.span(), Some(sym::wasm_import_module)); | |
| 412 | cx.adcx().expected_string_literal(item.span(), Some(nv.value_as_lit())); | |
| 419 | 413 | return true; |
| 420 | 414 | }; |
| 421 | 415 | *wasm_import_module = Some((link_wasm_import_module, item.span())); |
| ... | ... | @@ -431,12 +425,12 @@ impl LinkParser { |
| 431 | 425 | cx.adcx().duplicate_key(item.span(), sym::import_name_type); |
| 432 | 426 | return true; |
| 433 | 427 | } |
| 434 | let Some(nv) = item.args().name_value() else { | |
| 435 | cx.adcx().expected_name_value(item.span(), Some(sym::import_name_type)); | |
| 428 | let Some(nv) = cx.expect_name_value(item.args(), item.span(), Some(sym::import_name_type)) | |
| 429 | else { | |
| 436 | 430 | return true; |
| 437 | 431 | }; |
| 438 | 432 | let Some(link_import_name_type) = nv.value_as_str() else { |
| 439 | cx.adcx().expected_name_value(item.span(), Some(sym::import_name_type)); | |
| 433 | cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); | |
| 440 | 434 | return true; |
| 441 | 435 | }; |
| 442 | 436 | if cx.sess().target.arch != Arch::X86 { |
| ... | ... | @@ -503,11 +497,7 @@ impl SingleAttributeParser for LinkSectionParser { |
| 503 | 497 | ); |
| 504 | 498 | |
| 505 | 499 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 506 | let Some(nv) = args.name_value() else { | |
| 507 | let attr_span = cx.attr_span; | |
| 508 | cx.adcx().expected_name_value(attr_span, None); | |
| 509 | return None; | |
| 510 | }; | |
| 500 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 511 | 501 | let Some(name) = nv.value_as_str() else { |
| 512 | 502 | cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); |
| 513 | 503 | return None; |
| ... | ... | @@ -638,11 +628,7 @@ impl SingleAttributeParser for LinkageParser { |
| 638 | 628 | ]); |
| 639 | 629 | |
| 640 | 630 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 641 | let Some(name_value) = args.name_value() else { | |
| 642 | let attr_span = cx.attr_span; | |
| 643 | cx.adcx().expected_name_value(attr_span, Some(sym::linkage)); | |
| 644 | return None; | |
| 645 | }; | |
| 631 | let name_value = cx.expect_name_value(args, cx.attr_span, Some(sym::linkage))?; | |
| 646 | 632 | |
| 647 | 633 | let Some(value) = name_value.value_as_str() else { |
| 648 | 634 | cx.adcx() |
compiler/rustc_attr_parsing/src/attributes/path.rs+1-5| ... | ... | @@ -13,11 +13,7 @@ impl SingleAttributeParser for PathParser { |
| 13 | 13 | ); |
| 14 | 14 | |
| 15 | 15 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 16 | let Some(nv) = args.name_value() else { | |
| 17 | let attr_span = cx.attr_span; | |
| 18 | cx.adcx().expected_name_value(attr_span, None); | |
| 19 | return None; | |
| 20 | }; | |
| 16 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 21 | 17 | let Some(path) = nv.value_as_str() else { |
| 22 | 18 | cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); |
| 23 | 19 | return None; |
compiler/rustc_attr_parsing/src/attributes/prototype.rs+15-21| ... | ... | @@ -7,7 +7,7 @@ use rustc_span::{Span, Symbol, sym}; |
| 7 | 7 | |
| 8 | 8 | use crate::attributes::SingleAttributeParser; |
| 9 | 9 | use crate::context::AcceptContext; |
| 10 | use crate::parser::ArgParser; | |
| 10 | use crate::parser::{ArgParser, NameValueParser}; | |
| 11 | 11 | use crate::session_diagnostics; |
| 12 | 12 | use crate::target_checking::AllowedTargets; |
| 13 | 13 | use crate::target_checking::Policy::Allow; |
| ... | ... | @@ -29,23 +29,23 @@ impl SingleAttributeParser for CustomMirParser { |
| 29 | 29 | let mut failed = false; |
| 30 | 30 | |
| 31 | 31 | for item in list.mixed() { |
| 32 | let Some(meta_item) = item.meta_item() else { | |
| 33 | cx.adcx().expected_name_value(item.span(), None); | |
| 32 | let Some((path, arg)) = cx.expect_name_value(item, item.span(), None) else { | |
| 34 | 33 | failed = true; |
| 35 | 34 | break; |
| 36 | 35 | }; |
| 37 | 36 | |
| 38 | if let Some(arg) = meta_item.word_is(sym::dialect) { | |
| 39 | extract_value(cx, sym::dialect, arg, meta_item.span(), &mut dialect, &mut failed); | |
| 40 | } else if let Some(arg) = meta_item.word_is(sym::phase) { | |
| 41 | extract_value(cx, sym::phase, arg, meta_item.span(), &mut phase, &mut failed); | |
| 42 | } else if let Some(..) = meta_item.path().word() { | |
| 43 | cx.adcx().expected_specific_argument(meta_item.span(), &[sym::dialect, sym::phase]); | |
| 44 | failed = true; | |
| 45 | } else { | |
| 46 | cx.adcx().expected_name_value(meta_item.span(), None); | |
| 47 | failed = true; | |
| 48 | }; | |
| 37 | match path.name { | |
| 38 | sym::dialect => { | |
| 39 | extract_value(cx, sym::dialect, arg, item.span(), &mut dialect, &mut failed) | |
| 40 | } | |
| 41 | sym::phase => { | |
| 42 | extract_value(cx, sym::phase, arg, item.span(), &mut phase, &mut failed) | |
| 43 | } | |
| 44 | _ => { | |
| 45 | cx.adcx().expected_specific_argument(item.span(), &[sym::dialect, sym::phase]); | |
| 46 | failed = true; | |
| 47 | } | |
| 48 | } | |
| 49 | 49 | } |
| 50 | 50 | |
| 51 | 51 | let dialect = parse_dialect(cx, dialect, &mut failed); |
| ... | ... | @@ -63,7 +63,7 @@ impl SingleAttributeParser for CustomMirParser { |
| 63 | 63 | fn extract_value( |
| 64 | 64 | cx: &mut AcceptContext<'_, '_>, |
| 65 | 65 | key: Symbol, |
| 66 | arg: &ArgParser, | |
| 66 | val: &NameValueParser, | |
| 67 | 67 | span: Span, |
| 68 | 68 | out_val: &mut Option<(Symbol, Span)>, |
| 69 | 69 | failed: &mut bool, |
| ... | ... | @@ -74,12 +74,6 @@ fn extract_value( |
| 74 | 74 | return; |
| 75 | 75 | } |
| 76 | 76 | |
| 77 | let Some(val) = arg.name_value() else { | |
| 78 | cx.adcx().expected_name_value(span, Some(key)); | |
| 79 | *failed = true; | |
| 80 | return; | |
| 81 | }; | |
| 82 | ||
| 83 | 77 | let Some(value_sym) = val.value_as_str() else { |
| 84 | 78 | cx.adcx().expected_string_literal(val.value_span, Some(val.value_as_lit())); |
| 85 | 79 | *failed = true; |
compiler/rustc_attr_parsing/src/attributes/rustc_allocator.rs+3-3| ... | ... | @@ -26,9 +26,9 @@ impl SingleAttributeParser for RustcAllocatorZeroedVariantParser { |
| 26 | 26 | AllowedTargets::AllowList(&[Allow(Target::Fn), Allow(Target::ForeignFn)]); |
| 27 | 27 | const TEMPLATE: AttributeTemplate = template!(NameValueStr: "function"); |
| 28 | 28 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 29 | let Some(name) = args.name_value().and_then(NameValueParser::value_as_str) else { | |
| 30 | let attr_span = cx.attr_span; | |
| 31 | cx.adcx().expected_name_value(attr_span, None); | |
| 29 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 30 | let Some(name) = nv.value_as_str() else { | |
| 31 | cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); | |
| 32 | 32 | return None; |
| 33 | 33 | }; |
| 34 | 34 |
compiler/rustc_attr_parsing/src/attributes/rustc_internal.rs+42-90| ... | ... | @@ -209,18 +209,17 @@ fn parse_cgu_fields( |
| 209 | 209 | let mut kind = None::<(Symbol, Span)>; |
| 210 | 210 | |
| 211 | 211 | for arg in args.mixed() { |
| 212 | let Some(arg) = arg.meta_item() else { | |
| 213 | cx.adcx().expected_name_value(args.span, None); | |
| 212 | let Some((ident, arg)) = cx.expect_name_value(arg, arg.span(), None) else { | |
| 214 | 213 | continue; |
| 215 | 214 | }; |
| 216 | 215 | |
| 217 | let res = match arg.ident().map(|i| i.name) { | |
| 218 | Some(sym::cfg) => &mut cfg, | |
| 219 | Some(sym::module) => &mut module, | |
| 220 | Some(sym::kind) if accepts_kind => &mut kind, | |
| 216 | let res = match ident.name { | |
| 217 | sym::cfg => &mut cfg, | |
| 218 | sym::module => &mut module, | |
| 219 | sym::kind if accepts_kind => &mut kind, | |
| 221 | 220 | _ => { |
| 222 | 221 | cx.adcx().expected_specific_argument( |
| 223 | arg.path().span(), | |
| 222 | ident.span, | |
| 224 | 223 | if accepts_kind { |
| 225 | 224 | &[sym::cfg, sym::module, sym::kind] |
| 226 | 225 | } else { |
| ... | ... | @@ -231,22 +230,17 @@ fn parse_cgu_fields( |
| 231 | 230 | } |
| 232 | 231 | }; |
| 233 | 232 | |
| 234 | let Some(i) = arg.args().name_value() else { | |
| 235 | cx.adcx().expected_name_value(arg.span(), None); | |
| 236 | continue; | |
| 237 | }; | |
| 238 | ||
| 239 | let Some(str) = i.value_as_str() else { | |
| 240 | cx.adcx().expected_string_literal(i.value_span, Some(i.value_as_lit())); | |
| 233 | let Some(str) = arg.value_as_str() else { | |
| 234 | cx.adcx().expected_string_literal(arg.value_span, Some(arg.value_as_lit())); | |
| 241 | 235 | continue; |
| 242 | 236 | }; |
| 243 | 237 | |
| 244 | 238 | if res.is_some() { |
| 245 | cx.adcx().duplicate_key(arg.span(), arg.ident().unwrap().name); | |
| 239 | cx.adcx().duplicate_key(ident.span.to(arg.args_span()), ident.name); | |
| 246 | 240 | continue; |
| 247 | 241 | } |
| 248 | 242 | |
| 249 | *res = Some((str, i.value_span)); | |
| 243 | *res = Some((str, arg.value_span)); | |
| 250 | 244 | } |
| 251 | 245 | |
| 252 | 246 | let Some((cfg, _)) = cfg else { |
| ... | ... | @@ -349,23 +343,15 @@ impl SingleAttributeParser for RustcDeprecatedSafe2024Parser { |
| 349 | 343 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 350 | 344 | let single = cx.expect_single_element_list(args, cx.attr_span)?; |
| 351 | 345 | |
| 352 | let Some(arg) = single.meta_item() else { | |
| 353 | cx.adcx().expected_name_value(single.span(), None); | |
| 354 | return None; | |
| 355 | }; | |
| 356 | ||
| 357 | let Some(args) = arg.word_is(sym::audit_that) else { | |
| 358 | cx.adcx().expected_specific_argument(arg.span(), &[sym::audit_that]); | |
| 359 | return None; | |
| 360 | }; | |
| 346 | let (path, arg) = cx.expect_name_value(single, cx.attr_span, None)?; | |
| 361 | 347 | |
| 362 | let Some(nv) = args.name_value() else { | |
| 363 | cx.adcx().expected_name_value(arg.span(), Some(sym::audit_that)); | |
| 348 | if path.name != sym::audit_that { | |
| 349 | cx.adcx().expected_specific_argument(path.span, &[sym::audit_that]); | |
| 364 | 350 | return None; |
| 365 | 351 | }; |
| 366 | 352 | |
| 367 | let Some(suggestion) = nv.value_as_str() else { | |
| 368 | cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); | |
| 353 | let Some(suggestion) = arg.value_as_str() else { | |
| 354 | cx.adcx().expected_string_literal(arg.value_span, Some(arg.value_as_lit())); | |
| 369 | 355 | return None; |
| 370 | 356 | }; |
| 371 | 357 | |
| ... | ... | @@ -412,39 +398,33 @@ impl SingleAttributeParser for RustcNeverTypeOptionsParser { |
| 412 | 398 | let mut diverging_block_default = None::<Ident>; |
| 413 | 399 | |
| 414 | 400 | for arg in list.mixed() { |
| 415 | let Some(meta) = arg.meta_item() else { | |
| 416 | cx.adcx().expected_name_value(arg.span(), None); | |
| 401 | let Some((ident, arg)) = cx.expect_name_value(arg, arg.span(), None) else { | |
| 417 | 402 | continue; |
| 418 | 403 | }; |
| 419 | 404 | |
| 420 | let res = match meta.ident().map(|i| i.name) { | |
| 421 | Some(sym::fallback) => &mut fallback, | |
| 422 | Some(sym::diverging_block_default) => &mut diverging_block_default, | |
| 405 | let res = match ident.name { | |
| 406 | sym::fallback => &mut fallback, | |
| 407 | sym::diverging_block_default => &mut diverging_block_default, | |
| 423 | 408 | _ => { |
| 424 | 409 | cx.adcx().expected_specific_argument( |
| 425 | meta.path().span(), | |
| 410 | ident.span, | |
| 426 | 411 | &[sym::fallback, sym::diverging_block_default], |
| 427 | 412 | ); |
| 428 | 413 | continue; |
| 429 | 414 | } |
| 430 | 415 | }; |
| 431 | 416 | |
| 432 | let Some(nv) = meta.args().name_value() else { | |
| 433 | cx.adcx().expected_name_value(meta.span(), None); | |
| 434 | continue; | |
| 435 | }; | |
| 436 | ||
| 437 | let Some(field) = nv.value_as_str() else { | |
| 438 | cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); | |
| 417 | let Some(field) = arg.value_as_str() else { | |
| 418 | cx.adcx().expected_string_literal(arg.value_span, Some(arg.value_as_lit())); | |
| 439 | 419 | continue; |
| 440 | 420 | }; |
| 441 | 421 | |
| 442 | 422 | if res.is_some() { |
| 443 | cx.adcx().duplicate_key(meta.span(), meta.ident().unwrap().name); | |
| 423 | cx.adcx().duplicate_key(ident.span, ident.name); | |
| 444 | 424 | continue; |
| 445 | 425 | } |
| 446 | 426 | |
| 447 | *res = Some(Ident { name: field, span: nv.value_span }); | |
| 427 | *res = Some(Ident { name: field, span: arg.value_span }); | |
| 448 | 428 | } |
| 449 | 429 | |
| 450 | 430 | let fallback = match fallback { |
| ... | ... | @@ -562,11 +542,7 @@ impl SingleAttributeParser for RustcSimdMonomorphizeLaneLimitParser { |
| 562 | 542 | const TEMPLATE: AttributeTemplate = template!(NameValueStr: "N"); |
| 563 | 543 | |
| 564 | 544 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 565 | let ArgParser::NameValue(nv) = args else { | |
| 566 | let attr_span = cx.attr_span; | |
| 567 | cx.adcx().expected_name_value(attr_span, None); | |
| 568 | return None; | |
| 569 | }; | |
| 545 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 570 | 546 | Some(AttributeKind::RustcSimdMonomorphizeLaneLimit(cx.parse_limit_int(nv)?)) |
| 571 | 547 | } |
| 572 | 548 | } |
| ... | ... | @@ -603,11 +579,7 @@ impl SingleAttributeParser for LangParser { |
| 603 | 579 | const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); |
| 604 | 580 | |
| 605 | 581 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 606 | let Some(nv) = args.name_value() else { | |
| 607 | let attr_span = cx.attr_span; | |
| 608 | cx.adcx().expected_name_value(attr_span, None); | |
| 609 | return None; | |
| 610 | }; | |
| 582 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 611 | 583 | let Some(name) = nv.value_as_str() else { |
| 612 | 584 | cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); |
| 613 | 585 | return None; |
| ... | ... | @@ -701,13 +673,11 @@ impl CombineAttributeParser for RustcMirParser { |
| 701 | 673 | sym::rustc_peek_liveness => Some(RustcMirKind::PeekLiveness), |
| 702 | 674 | sym::stop_after_dataflow => Some(RustcMirKind::StopAfterDataflow), |
| 703 | 675 | sym::borrowck_graphviz_postflow => { |
| 704 | let Some(nv) = mi.args().name_value() else { | |
| 705 | cx.adcx().expected_name_value( | |
| 706 | mi.span(), | |
| 707 | Some(sym::borrowck_graphviz_postflow), | |
| 708 | ); | |
| 709 | return None; | |
| 710 | }; | |
| 676 | let nv = cx.expect_name_value( | |
| 677 | mi.args(), | |
| 678 | mi.span(), | |
| 679 | Some(sym::borrowck_graphviz_postflow), | |
| 680 | )?; | |
| 711 | 681 | let Some(path) = nv.value_as_str() else { |
| 712 | 682 | cx.adcx().expected_string_literal(nv.value_span, None); |
| 713 | 683 | return None; |
| ... | ... | @@ -721,13 +691,11 @@ impl CombineAttributeParser for RustcMirParser { |
| 721 | 691 | } |
| 722 | 692 | } |
| 723 | 693 | sym::borrowck_graphviz_format => { |
| 724 | let Some(nv) = mi.args().name_value() else { | |
| 725 | cx.adcx().expected_name_value( | |
| 726 | mi.span(), | |
| 727 | Some(sym::borrowck_graphviz_format), | |
| 728 | ); | |
| 729 | return None; | |
| 730 | }; | |
| 694 | let nv = cx.expect_name_value( | |
| 695 | mi.args(), | |
| 696 | mi.span(), | |
| 697 | Some(sym::borrowck_graphviz_format), | |
| 698 | )?; | |
| 731 | 699 | let Some(format) = nv.value_as_ident() else { |
| 732 | 700 | cx.adcx().expected_identifier(nv.value_span); |
| 733 | 701 | return None; |
| ... | ... | @@ -814,10 +782,7 @@ impl CombineAttributeParser for RustcCleanParser { |
| 814 | 782 | let mut cfg = None; |
| 815 | 783 | |
| 816 | 784 | for item in list.mixed() { |
| 817 | let Some((value, name)) = | |
| 818 | item.meta_item().and_then(|m| Option::zip(m.args().name_value(), m.ident())) | |
| 819 | else { | |
| 820 | cx.adcx().expected_name_value(item.span(), None); | |
| 785 | let Some((ident, value)) = cx.expect_name_value(item, item.span(), None) else { | |
| 821 | 786 | continue; |
| 822 | 787 | }; |
| 823 | 788 | let value_span = value.value_span; |
| ... | ... | @@ -825,11 +790,10 @@ impl CombineAttributeParser for RustcCleanParser { |
| 825 | 790 | cx.adcx().expected_string_literal(value_span, None); |
| 826 | 791 | continue; |
| 827 | 792 | }; |
| 828 | match name.name { | |
| 793 | match ident.name { | |
| 829 | 794 | sym::cfg if cfg.is_some() => { |
| 830 | 795 | cx.adcx().duplicate_key(item.span(), sym::cfg); |
| 831 | 796 | } |
| 832 | ||
| 833 | 797 | sym::cfg => { |
| 834 | 798 | cfg = Some(value); |
| 835 | 799 | } |
| ... | ... | @@ -851,7 +815,7 @@ impl CombineAttributeParser for RustcCleanParser { |
| 851 | 815 | } |
| 852 | 816 | _ => { |
| 853 | 817 | cx.adcx().expected_specific_argument( |
| 854 | name.span, | |
| 818 | ident.span, | |
| 855 | 819 | &[sym::cfg, sym::except, sym::loaded_from_disk], |
| 856 | 820 | ); |
| 857 | 821 | } |
| ... | ... | @@ -1047,11 +1011,7 @@ impl SingleAttributeParser for RustcDiagnosticItemParser { |
| 1047 | 1011 | const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); |
| 1048 | 1012 | |
| 1049 | 1013 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 1050 | let Some(nv) = args.name_value() else { | |
| 1051 | let attr_span = cx.attr_span; | |
| 1052 | cx.adcx().expected_name_value(attr_span, None); | |
| 1053 | return None; | |
| 1054 | }; | |
| 1014 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 1055 | 1015 | let Some(value) = nv.value_as_str() else { |
| 1056 | 1016 | cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); |
| 1057 | 1017 | return None; |
| ... | ... | @@ -1106,11 +1066,7 @@ impl SingleAttributeParser for RustcReservationImplParser { |
| 1106 | 1066 | const TEMPLATE: AttributeTemplate = template!(NameValueStr: "reservation message"); |
| 1107 | 1067 | |
| 1108 | 1068 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 1109 | let Some(nv) = args.name_value() else { | |
| 1110 | let attr_span = cx.attr_span; | |
| 1111 | cx.adcx().expected_name_value(args.span().unwrap_or(attr_span), None); | |
| 1112 | return None; | |
| 1113 | }; | |
| 1069 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 1114 | 1070 | |
| 1115 | 1071 | let Some(value_str) = nv.value_as_str() else { |
| 1116 | 1072 | cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); |
| ... | ... | @@ -1137,11 +1093,7 @@ impl SingleAttributeParser for RustcDocPrimitiveParser { |
| 1137 | 1093 | const TEMPLATE: AttributeTemplate = template!(NameValueStr: "primitive name"); |
| 1138 | 1094 | |
| 1139 | 1095 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 1140 | let Some(nv) = args.name_value() else { | |
| 1141 | let span = cx.attr_span; | |
| 1142 | cx.adcx().expected_name_value(args.span().unwrap_or(span), None); | |
| 1143 | return None; | |
| 1144 | }; | |
| 1096 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 1145 | 1097 | |
| 1146 | 1098 | let Some(value_str) = nv.value_as_str() else { |
| 1147 | 1099 | cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); |
compiler/rustc_attr_parsing/src/attributes/stability.rs+14-13| ... | ... | @@ -102,9 +102,7 @@ impl AttributeParser for StabilityParser { |
| 102 | 102 | template!(NameValueStr: "deprecation message"), |
| 103 | 103 | |this, cx, args| { |
| 104 | 104 | reject_outside_std!(cx); |
| 105 | let Some(nv) = args.name_value() else { | |
| 106 | let attr_span = cx.attr_span; | |
| 107 | cx.adcx().expected_name_value(attr_span, None); | |
| 105 | let Some(nv) = cx.expect_name_value(args, cx.attr_span, None) else { | |
| 108 | 106 | return; |
| 109 | 107 | }; |
| 110 | 108 | let Some(value_str) = nv.value_as_str() else { |
| ... | ... | @@ -290,16 +288,19 @@ fn insert_value_into_option_or_error( |
| 290 | 288 | ) -> Option<()> { |
| 291 | 289 | if item.is_some() { |
| 292 | 290 | cx.adcx().duplicate_key(name.span, name.name); |
| 293 | None | |
| 294 | } else if let Some(v) = param.args().name_value() | |
| 295 | && let Some(s) = v.value_as_str() | |
| 296 | { | |
| 297 | *item = Some(s); | |
| 298 | Some(()) | |
| 299 | } else { | |
| 300 | cx.adcx().expected_name_value(param.span(), Some(name.name)); | |
| 301 | None | |
| 291 | return None; | |
| 302 | 292 | } |
| 293 | ||
| 294 | let (_ident, arg) = cx.expect_name_value(param, param.span(), Some(name.name))?; | |
| 295 | ||
| 296 | let Some(s) = arg.value_as_str() else { | |
| 297 | cx.adcx().expected_string_literal(arg.value_span, Some(arg.value_as_lit())); | |
| 298 | return None; | |
| 299 | }; | |
| 300 | ||
| 301 | *item = Some(s); | |
| 302 | ||
| 303 | Some(()) | |
| 303 | 304 | } |
| 304 | 305 | |
| 305 | 306 | /// Read the content of a `stable`/`rustc_const_stable` attribute, and return the feature name and |
| ... | ... | @@ -409,7 +410,7 @@ pub(crate) fn parse_unstability( |
| 409 | 410 | session_diagnostics::InvalidIssueString { |
| 410 | 411 | span: param.span(), |
| 411 | 412 | cause: session_diagnostics::InvalidIssueStringCause::from_int_error_kind( |
| 412 | param.args().name_value().unwrap().value_span, | |
| 413 | param.args().as_name_value().unwrap().value_span, | |
| 413 | 414 | err.kind(), |
| 414 | 415 | ), |
| 415 | 416 | }, |
compiler/rustc_attr_parsing/src/attributes/test_attrs.rs+11-24| ... | ... | @@ -73,20 +73,14 @@ impl SingleAttributeParser for ShouldPanicParser { |
| 73 | 73 | } |
| 74 | 74 | ArgParser::List(list) => { |
| 75 | 75 | let single = cx.expect_single(list)?; |
| 76 | let Some(single) = single.meta_item() else { | |
| 77 | cx.adcx().expected_name_value(single.span(), Some(sym::expected)); | |
| 78 | return None; | |
| 79 | }; | |
| 80 | if !single.path().word_is(sym::expected) { | |
| 76 | let (ident, arg) = | |
| 77 | cx.expect_name_value(single, single.span(), Some(sym::expected))?; | |
| 78 | if ident.name != sym::expected { | |
| 81 | 79 | cx.adcx().expected_specific_argument_strings(list.span, &[sym::expected]); |
| 82 | 80 | return None; |
| 83 | 81 | } |
| 84 | let Some(nv) = single.args().name_value() else { | |
| 85 | cx.adcx().expected_name_value(single.span(), Some(sym::expected)); | |
| 86 | return None; | |
| 87 | }; | |
| 88 | let Some(expected) = nv.value_as_str() else { | |
| 89 | cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); | |
| 82 | let Some(expected) = arg.value_as_str() else { | |
| 83 | cx.adcx().expected_string_literal(arg.value_span, Some(arg.value_as_lit())); | |
| 90 | 84 | return None; |
| 91 | 85 | }; |
| 92 | 86 | Some(expected) |
| ... | ... | @@ -104,14 +98,11 @@ impl SingleAttributeParser for ReexportTestHarnessMainParser { |
| 104 | 98 | const TEMPLATE: AttributeTemplate = template!(NameValueStr: "name"); |
| 105 | 99 | |
| 106 | 100 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 107 | let Some(nv) = args.name_value() else { | |
| 108 | let inner_span = cx.inner_span; | |
| 109 | cx.adcx().expected_name_value( | |
| 110 | args.span().unwrap_or(inner_span), | |
| 111 | Some(sym::reexport_test_harness_main), | |
| 112 | ); | |
| 113 | return None; | |
| 114 | }; | |
| 101 | let nv = cx.expect_name_value( | |
| 102 | args, | |
| 103 | args.span().unwrap_or(cx.inner_span), | |
| 104 | Some(sym::reexport_test_harness_main), | |
| 105 | )?; | |
| 115 | 106 | |
| 116 | 107 | let Some(name) = nv.value_as_str() else { |
| 117 | 108 | cx.adcx().expected_string_literal(nv.value_span, Some(nv.value_as_lit())); |
| ... | ... | @@ -220,11 +211,7 @@ impl SingleAttributeParser for RustcTestMarkerParser { |
| 220 | 211 | const TEMPLATE: AttributeTemplate = template!(NameValueStr: "test_path"); |
| 221 | 212 | |
| 222 | 213 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 223 | let Some(name_value) = args.name_value() else { | |
| 224 | let attr_span = cx.attr_span; | |
| 225 | cx.adcx().expected_name_value(attr_span, Some(sym::rustc_test_marker)); | |
| 226 | return None; | |
| 227 | }; | |
| 214 | let name_value = cx.expect_name_value(args, cx.attr_span, Some(sym::rustc_test_marker))?; | |
| 228 | 215 | |
| 229 | 216 | let Some(value_str) = name_value.value_as_str() else { |
| 230 | 217 | cx.adcx().expected_string_literal(name_value.value_span, None); |
compiler/rustc_attr_parsing/src/attributes/transparency.rs+1-5| ... | ... | @@ -14,11 +14,7 @@ impl SingleAttributeParser for RustcMacroTransparencyParser { |
| 14 | 14 | template!(NameValueStr: ["transparent", "semiopaque", "opaque"]); |
| 15 | 15 | |
| 16 | 16 | fn convert(cx: &mut AcceptContext<'_, '_>, args: &ArgParser) -> Option<AttributeKind> { |
| 17 | let Some(nv) = args.name_value() else { | |
| 18 | let attr_span = cx.attr_span; | |
| 19 | cx.adcx().expected_name_value(attr_span, None); | |
| 20 | return None; | |
| 21 | }; | |
| 17 | let nv = cx.expect_name_value(args, cx.attr_span, None)?; | |
| 22 | 18 | match nv.value_as_str() { |
| 23 | 19 | Some(sym::transparent) => Some(Transparency::Transparent), |
| 24 | 20 | Some(sym::semiopaque) => Some(Transparency::SemiOpaque), |
compiler/rustc_attr_parsing/src/context.rs+126-10| ... | ... | @@ -14,7 +14,7 @@ use rustc_hir::attrs::AttributeKind; |
| 14 | 14 | use rustc_parse::parser::Recovery; |
| 15 | 15 | use rustc_session::Session; |
| 16 | 16 | use rustc_session::lint::{Lint, LintId}; |
| 17 | use rustc_span::{ErrorGuaranteed, Span, Symbol}; | |
| 17 | use rustc_span::{ErrorGuaranteed, Ident, Span, Symbol}; | |
| 18 | 18 | |
| 19 | 19 | // Glob imports to avoid big, bitrotty import lists |
| 20 | 20 | use crate::attributes::allow_unstable::*; |
| ... | ... | @@ -59,7 +59,10 @@ use crate::attributes::test_attrs::*; |
| 59 | 59 | use crate::attributes::traits::*; |
| 60 | 60 | use crate::attributes::transparency::*; |
| 61 | 61 | use crate::attributes::{AttributeParser as _, AttributeSafety, Combine, Single, WithoutArgs}; |
| 62 | use crate::parser::{ArgParser, MetaItemListParser, MetaItemOrLitParser, RefPathParser}; | |
| 62 | use crate::parser::{ | |
| 63 | ArgParser, MetaItemListParser, MetaItemOrLitParser, MetaItemParser, NameValueParser, | |
| 64 | RefPathParser, | |
| 65 | }; | |
| 63 | 66 | use crate::session_diagnostics::{ |
| 64 | 67 | AttributeParseError, AttributeParseErrorReason, AttributeParseErrorSuggestions, |
| 65 | 68 | ParsedDescription, |
| ... | ... | @@ -490,7 +493,7 @@ impl<'f, 'sess: 'f> AcceptContext<'f, 'sess> { |
| 490 | 493 | /// - `#[allow(clippy::complexity)]`: `(clippy::complexity)` is a list |
| 491 | 494 | /// - `#[rustfmt::skip::macros(target_macro_name)]`: `(target_macro_name)` is a list |
| 492 | 495 | /// |
| 493 | /// This is a higher-level (and harder to misuse) wrapper over [`ArgParser::as_list`]. That | |
| 496 | /// This is a higher-level (and harder to misuse) wrapper over [`ArgParser::as_list`] that | |
| 494 | 497 | /// allows using `?` when the attribute parsing function allows it. You may still want to use |
| 495 | 498 | /// [`ArgParser::as_list`] for the following reasons: |
| 496 | 499 | /// |
| ... | ... | @@ -511,8 +514,8 @@ impl<'f, 'sess: 'f> AcceptContext<'f, 'sess> { |
| 511 | 514 | /// Asserts that a [`MetaItemListParser`] contains a single element and returns it, or emits an |
| 512 | 515 | /// error and returns `None`. |
| 513 | 516 | /// |
| 514 | /// This is a higher-level (and harder to misuse) wrapper over [`MetaItemListParser::as_single`]. | |
| 515 | /// That allows using `?` to early return. You may still want to use | |
| 517 | /// This is a higher-level (and harder to misuse) wrapper over [`MetaItemListParser::as_single`], | |
| 518 | /// that allows using `?` to early return. You may still want to use | |
| 516 | 519 | /// [`MetaItemListParser::as_single`] for the following reasons: |
| 517 | 520 | /// |
| 518 | 521 | /// - You want to emit your own diagnostics (for instance, with [`SharedContext::emit_err`]). |
| ... | ... | @@ -527,6 +530,123 @@ impl<'f, 'sess: 'f> AcceptContext<'f, 'sess> { |
| 527 | 530 | } |
| 528 | 531 | single |
| 529 | 532 | } |
| 533 | ||
| 534 | /// Asserts that a node is a name-value pair. | |
| 535 | /// | |
| 536 | /// Some examples: | |
| 537 | /// | |
| 538 | /// - `#[clippy::cyclomatic_complexity = "100"]`: `clippy::cyclomatic_complexity = "100"` is a | |
| 539 | /// name-value pair, where the name is a path (`clippy::cyclomatic_complexity`). You already | |
| 540 | /// checked the path to get an `ArgParser`, so this method will effectively only assert that | |
| 541 | /// the `= "100"` is there and returns it. | |
| 542 | /// - `#[doc = "hello"]`: `doc = "hello` is also a name value pair. `= "hello"` is returned. | |
| 543 | /// - `#[serde(rename_all = "lowercase")]`: `rename_all = "lowercase"` is a name value pair, | |
| 544 | /// where the name is an identifier (`rename_all`) and the value is a literal (`"lowercase"`). | |
| 545 | /// This returns both the path and the value. | |
| 546 | /// | |
| 547 | /// `arg` must be a reference to any node that may contain a name-value pair, that is: | |
| 548 | /// | |
| 549 | /// - [`MetaItemOrLitParser`], | |
| 550 | /// - [`MetaItemParser`], | |
| 551 | /// - [`ArgParser`]. | |
| 552 | /// | |
| 553 | /// `name` can be set to `Some` for a nicer error message talking about the specific name that | |
| 554 | /// was found lacking a value. | |
| 555 | /// | |
| 556 | /// This is a higher-level (and harder to misuse) wrapper over multiple `as_` methods in the | |
| 557 | /// [`parser`][crate::parser] module. You may still want to use the lower-level methods for the | |
| 558 | /// following reasons: | |
| 559 | /// | |
| 560 | /// - You want to emit your own diagnostics (for instance, with [`SharedContext::emit_err`]). | |
| 561 | /// - The attribute can be parsed in multiple ways and it does not make sense to emit an error. | |
| 562 | pub(crate) fn expect_name_value<'arg, Arg>( | |
| 563 | &mut self, | |
| 564 | arg: &'arg Arg, | |
| 565 | span: Span, | |
| 566 | name: Option<Symbol>, | |
| 567 | ) -> Option<Arg::Output<'arg>> | |
| 568 | where | |
| 569 | Arg: ExpectNameValue, | |
| 570 | { | |
| 571 | arg.expect_name_value(self, span, name) | |
| 572 | } | |
| 573 | } | |
| 574 | ||
| 575 | pub(crate) trait ExpectNameValue { | |
| 576 | type Output<'a> | |
| 577 | where | |
| 578 | Self: 'a; | |
| 579 | ||
| 580 | fn expect_name_value<'a, 'f, 'sess>( | |
| 581 | &'a self, | |
| 582 | cx: &mut AcceptContext<'f, 'sess>, | |
| 583 | span: Span, | |
| 584 | name: Option<Symbol>, | |
| 585 | ) -> Option<Self::Output<'a>>; | |
| 586 | } | |
| 587 | ||
| 588 | impl ExpectNameValue for MetaItemOrLitParser { | |
| 589 | type Output<'a> = (Ident, &'a NameValueParser); | |
| 590 | ||
| 591 | fn expect_name_value<'a, 'f, 'sess>( | |
| 592 | &'a self, | |
| 593 | cx: &mut AcceptContext<'f, 'sess>, | |
| 594 | span: Span, | |
| 595 | name: Option<Symbol>, | |
| 596 | ) -> Option<Self::Output<'a>> { | |
| 597 | let Some(meta_item) = self.meta_item() else { | |
| 598 | cx.adcx().expected_name_value(self.span(), name); | |
| 599 | return None; | |
| 600 | }; | |
| 601 | ||
| 602 | meta_item.expect_name_value(cx, span, name) | |
| 603 | } | |
| 604 | } | |
| 605 | ||
| 606 | impl ExpectNameValue for MetaItemParser { | |
| 607 | type Output<'a> = (Ident, &'a NameValueParser); | |
| 608 | ||
| 609 | fn expect_name_value<'a, 'f, 'sess>( | |
| 610 | &'a self, | |
| 611 | cx: &mut AcceptContext<'f, 'sess>, | |
| 612 | _span: Span, // Not needed: `MetaItemOrLitParser` carry its own span. | |
| 613 | name: Option<Symbol>, | |
| 614 | ) -> Option<Self::Output<'a>> { | |
| 615 | let word = self.path().word(); | |
| 616 | let arg = self.args().as_name_value(); | |
| 617 | ||
| 618 | if word.is_none() { | |
| 619 | cx.adcx().expected_identifier(self.path().span()); | |
| 620 | } | |
| 621 | ||
| 622 | if arg.is_none() { | |
| 623 | cx.adcx().expected_name_value(self.span(), name); | |
| 624 | } | |
| 625 | ||
| 626 | let Some((word, arg)) = word.zip(arg) else { | |
| 627 | return None; | |
| 628 | }; | |
| 629 | ||
| 630 | Some((word, arg)) | |
| 631 | } | |
| 632 | } | |
| 633 | ||
| 634 | impl ExpectNameValue for ArgParser { | |
| 635 | type Output<'a> = &'a NameValueParser; | |
| 636 | ||
| 637 | fn expect_name_value<'a, 'f, 'sess>( | |
| 638 | &'a self, | |
| 639 | cx: &mut AcceptContext<'f, 'sess>, | |
| 640 | span: Span, | |
| 641 | name: Option<Symbol>, | |
| 642 | ) -> Option<Self::Output<'a>> { | |
| 643 | let Some(nv) = self.as_name_value() else { | |
| 644 | cx.adcx().expected_name_value(span, name); | |
| 645 | return None; | |
| 646 | }; | |
| 647 | ||
| 648 | Some(nv) | |
| 649 | } | |
| 530 | 650 | } |
| 531 | 651 | |
| 532 | 652 | impl<'f, 'sess> Deref for AcceptContext<'f, 'sess> { |
| ... | ... | @@ -751,11 +871,7 @@ impl<'a, 'f, 'sess: 'f> AttributeDiagnosticContext<'a, 'f, 'sess> { |
| 751 | 871 | |
| 752 | 872 | /// Emit an error that a `name = value` pair was expected at this span. The symbol can be given for |
| 753 | 873 | /// a nicer error message talking about the specific name that was found lacking a value. |
| 754 | pub(crate) fn expected_name_value( | |
| 755 | &mut self, | |
| 756 | span: Span, | |
| 757 | name: Option<Symbol>, | |
| 758 | ) -> ErrorGuaranteed { | |
| 874 | fn expected_name_value(&mut self, span: Span, name: Option<Symbol>) -> ErrorGuaranteed { | |
| 759 | 875 | self.emit_parse_error(span, AttributeParseErrorReason::ExpectedNameValue(name)) |
| 760 | 876 | } |
| 761 | 877 |
compiler/rustc_attr_parsing/src/parser.rs+4-3| ... | ... | @@ -192,7 +192,7 @@ impl ArgParser { |
| 192 | 192 | /// to get an `ArgParser`, so this method will effectively only assert that the `= "100"` is |
| 193 | 193 | /// there |
| 194 | 194 | /// - `#[doc = "hello"]`: `doc = "hello` is also a name value pair |
| 195 | pub fn name_value(&self) -> Option<&NameValueParser> { | |
| 195 | pub fn as_name_value(&self) -> Option<&NameValueParser> { | |
| 196 | 196 | match self { |
| 197 | 197 | Self::NameValue(n) => Some(n), |
| 198 | 198 | Self::List(_) | Self::NoArgs => None, |
| ... | ... | @@ -264,8 +264,9 @@ impl MetaItemOrLitParser { |
| 264 | 264 | /// MetaItems consist of some path, and some args. The args could be empty. In other words: |
| 265 | 265 | /// |
| 266 | 266 | /// - `name` -> args are empty |
| 267 | /// - `name(...)` -> args are a [`list`](ArgParser::as_list), which is the bit between the parentheses | |
| 268 | /// - `name = value`-> arg is [`name_value`](ArgParser::name_value), where the argument is the | |
| 267 | /// - `name(...)` -> args are a [`list`](ArgParser::as_list), which is the bit between the | |
| 268 | /// parentheses | |
| 269 | /// - `name = value`-> arg is [`name_value`](ArgParser::as_name_value), where the argument is the | |
| 269 | 270 | /// `= value` part |
| 270 | 271 | /// |
| 271 | 272 | /// The syntax of MetaItems can be found at <https://doc.rust-lang.org/reference/attributes.html> |
compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs+65-38| ... | ... | @@ -4,6 +4,7 @@ use either::Either; |
| 4 | 4 | use hir::{ExprKind, Param}; |
| 5 | 5 | use rustc_abi::FieldIdx; |
| 6 | 6 | use rustc_errors::{Applicability, Diag}; |
| 7 | use rustc_hir::def_id::DefId; | |
| 7 | 8 | use rustc_hir::intravisit::Visitor; |
| 8 | 9 | use rustc_hir::{self as hir, BindingMode, ByRef, Node}; |
| 9 | 10 | use rustc_middle::bug; |
| ... | ... | @@ -1092,42 +1093,65 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 1092 | 1093 | let mut look_at_return = true; |
| 1093 | 1094 | |
| 1094 | 1095 | err.span_label(closure_span, "in this closure"); |
| 1095 | // If the HIR node is a function or method call, get the DefId | |
| 1096 | // of the callee function or method, the span, and args of the call expr | |
| 1097 | let get_call_details = || { | |
| 1098 | let hir::Node::Expr(hir::Expr { hir_id, kind, .. }) = node else { | |
| 1099 | return None; | |
| 1096 | let closure_arg_has_fn_trait_bound = | |
| 1097 | |callee_def_id, input_index, generic_args: ty::GenericArgsRef<'tcx>| { | |
| 1098 | let sig = tcx.fn_sig(callee_def_id).instantiate(tcx, generic_args).skip_binder(); | |
| 1099 | let Some(input_ty): Option<Ty<'tcx>> = sig.inputs().get(input_index).copied() | |
| 1100 | else { | |
| 1101 | return false; | |
| 1102 | }; | |
| 1103 | ||
| 1104 | tcx.predicates_of(callee_def_id) | |
| 1105 | .instantiate(tcx, generic_args) | |
| 1106 | .predicates | |
| 1107 | .iter() | |
| 1108 | .any(|predicate| { | |
| 1109 | predicate.as_trait_clause().is_some_and(|trait_pred| { | |
| 1110 | trait_pred.polarity() == ty::PredicatePolarity::Positive | |
| 1111 | && tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) | |
| 1112 | == Some(ty::ClosureKind::Fn) | |
| 1113 | && trait_pred.self_ty().skip_binder().peel_refs() | |
| 1114 | == input_ty.peel_refs() | |
| 1115 | }) | |
| 1116 | }) | |
| 1100 | 1117 | }; |
| 1101 | 1118 | |
| 1102 | let typeck_results = tcx.typeck(def_id); | |
| 1119 | // If the HIR node is a function or method call, get the DefId | |
| 1120 | // of the callee function or method, the span, and argument info for the call expr. | |
| 1121 | let get_call_details = | |
| 1122 | || -> Option<(DefId, Span, usize, usize, ty::GenericArgsRef<'tcx>)> { | |
| 1123 | let hir::Node::Expr(hir::Expr { hir_id, kind, .. }) = node else { | |
| 1124 | return None; | |
| 1125 | }; | |
| 1103 | 1126 | |
| 1104 | match kind { | |
| 1105 | hir::ExprKind::Call(expr, args) => { | |
| 1106 | if let Some(ty::FnDef(def_id, _)) = | |
| 1107 | typeck_results.node_type_opt(expr.hir_id).as_ref().map(|ty| ty.kind()) | |
| 1108 | { | |
| 1109 | Some((*def_id, expr.span, *args)) | |
| 1110 | } else { | |
| 1111 | None | |
| 1127 | let typeck_results = tcx.typeck(def_id); | |
| 1128 | ||
| 1129 | match kind { | |
| 1130 | hir::ExprKind::Call(expr, args) => { | |
| 1131 | if let Some(ty::FnDef(def_id, generic_args)) = | |
| 1132 | typeck_results.node_type_opt(expr.hir_id).as_ref().map(|ty| ty.kind()) | |
| 1133 | { | |
| 1134 | let arg_pos = args.iter().position(|arg| arg.hir_id == closure_id)?; | |
| 1135 | Some((*def_id, expr.span, arg_pos, arg_pos, generic_args)) | |
| 1136 | } else { | |
| 1137 | None | |
| 1138 | } | |
| 1112 | 1139 | } |
| 1140 | hir::ExprKind::MethodCall(_, _, args, span) => { | |
| 1141 | let arg_pos = args.iter().position(|arg| arg.hir_id == closure_id)?; | |
| 1142 | let def_id = typeck_results.type_dependent_def_id(*hir_id)?; | |
| 1143 | let generic_args = typeck_results.node_args_opt(*hir_id)?; | |
| 1144 | Some((def_id, *span, arg_pos, arg_pos + 1, generic_args)) | |
| 1145 | } | |
| 1146 | _ => None, | |
| 1113 | 1147 | } |
| 1114 | hir::ExprKind::MethodCall(_, _, args, span) => typeck_results | |
| 1115 | .type_dependent_def_id(*hir_id) | |
| 1116 | .map(|def_id| (def_id, *span, *args)), | |
| 1117 | _ => None, | |
| 1118 | } | |
| 1119 | }; | |
| 1148 | }; | |
| 1120 | 1149 | |
| 1121 | 1150 | // If we can detect the expression to be a function or method call where the closure was |
| 1122 | 1151 | // an argument, we point at the function or method definition argument... |
| 1123 | if let Some((callee_def_id, call_span, call_args)) = get_call_details() { | |
| 1124 | let arg_pos = call_args | |
| 1125 | .iter() | |
| 1126 | .enumerate() | |
| 1127 | .filter(|(_, arg)| arg.hir_id == closure_id) | |
| 1128 | .map(|(pos, _)| pos) | |
| 1129 | .next(); | |
| 1130 | ||
| 1152 | if let Some((callee_def_id, call_span, arg_pos, input_index, generic_args)) = | |
| 1153 | get_call_details() | |
| 1154 | { | |
| 1131 | 1155 | let arg = match tcx.hir_get_if_local(callee_def_id) { |
| 1132 | 1156 | Some( |
| 1133 | 1157 | hir::Node::Item(hir::Item { |
| ... | ... | @@ -1144,16 +1168,12 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 1144 | 1168 | .. |
| 1145 | 1169 | }), |
| 1146 | 1170 | ) => Some( |
| 1147 | arg_pos | |
| 1148 | .and_then(|pos| { | |
| 1149 | sig.decl.inputs.get( | |
| 1150 | pos + if sig.decl.implicit_self().has_implicit_self() { | |
| 1151 | 1 | |
| 1152 | } else { | |
| 1153 | 0 | |
| 1154 | }, | |
| 1155 | ) | |
| 1156 | }) | |
| 1171 | sig.decl | |
| 1172 | .inputs | |
| 1173 | .get( | |
| 1174 | arg_pos | |
| 1175 | + if sig.decl.implicit_self().has_implicit_self() { 1 } else { 0 }, | |
| 1176 | ) | |
| 1157 | 1177 | .map(|arg| arg.span) |
| 1158 | 1178 | .unwrap_or(ident.span), |
| 1159 | 1179 | ), |
| ... | ... | @@ -1163,6 +1183,13 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 1163 | 1183 | err.span_label(span, "change this to accept `FnMut` instead of `Fn`"); |
| 1164 | 1184 | err.span_label(call_span, "expects `Fn` instead of `FnMut`"); |
| 1165 | 1185 | look_at_return = false; |
| 1186 | } else if closure_arg_has_fn_trait_bound(callee_def_id, input_index, generic_args) { | |
| 1187 | // The callee is not local, so we cannot point at its argument declaration, but we | |
| 1188 | // can still explain that this call site expects an `Fn` closure. Avoid falling | |
| 1189 | // through to the enclosing function's return type, which is misleading in cases | |
| 1190 | // like `flat_map(|_| external::map(|_| ...))`. | |
| 1191 | err.span_label(call_span, "expects `Fn` instead of `FnMut`"); | |
| 1192 | look_at_return = false; | |
| 1166 | 1193 | } |
| 1167 | 1194 | } |
| 1168 | 1195 |
compiler/rustc_borrowck/src/diagnostics/region_errors.rs+3-2| ... | ... | @@ -1085,8 +1085,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { |
| 1085 | 1085 | } |
| 1086 | 1086 | |
| 1087 | 1087 | // Build a new closure where the return type is an owned value, instead of a ref. |
| 1088 | let fn_sig_kind = | |
| 1089 | FnSigKind::default().set_safe(true).set_c_variadic(liberated_sig.c_variadic()); | |
| 1088 | let fn_sig_kind = FnSigKind::default() | |
| 1089 | .set_safety(hir::Safety::Safe) | |
| 1090 | .set_c_variadic(liberated_sig.c_variadic()); | |
| 1090 | 1091 | let closure_sig_as_fn_ptr_ty = Ty::new_fn_ptr( |
| 1091 | 1092 | tcx, |
| 1092 | 1093 | ty::Binder::dummy(tcx.mk_fn_sig( |
compiler/rustc_codegen_gcc/src/builder.rs-57| ... | ... | @@ -2313,67 +2313,10 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> { |
| 2313 | 2313 | self.vector_extremum(a, b, ExtremumOperation::Min) |
| 2314 | 2314 | } |
| 2315 | 2315 | |
| 2316 | #[cfg(feature = "master")] | |
| 2317 | pub fn vector_reduce_fmin(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { | |
| 2318 | let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); | |
| 2319 | let element_count = vector_type.get_num_units(); | |
| 2320 | let mut acc = self | |
| 2321 | .context | |
| 2322 | .new_vector_access(self.location, src, self.context.new_rvalue_zero(self.int_type)) | |
| 2323 | .to_rvalue(); | |
| 2324 | for i in 1..element_count { | |
| 2325 | let elem = self | |
| 2326 | .context | |
| 2327 | .new_vector_access( | |
| 2328 | self.location, | |
| 2329 | src, | |
| 2330 | self.context.new_rvalue_from_int(self.int_type, i as _), | |
| 2331 | ) | |
| 2332 | .to_rvalue(); | |
| 2333 | let cmp = self.context.new_comparison(self.location, ComparisonOp::LessThan, acc, elem); | |
| 2334 | acc = self.select(cmp, acc, elem); | |
| 2335 | } | |
| 2336 | acc | |
| 2337 | } | |
| 2338 | ||
| 2339 | #[cfg(not(feature = "master"))] | |
| 2340 | pub fn vector_reduce_fmin(&mut self, _src: RValue<'gcc>) -> RValue<'gcc> { | |
| 2341 | unimplemented!(); | |
| 2342 | } | |
| 2343 | ||
| 2344 | 2316 | pub fn vector_maximum_number_nsz(&mut self, a: RValue<'gcc>, b: RValue<'gcc>) -> RValue<'gcc> { |
| 2345 | 2317 | self.vector_extremum(a, b, ExtremumOperation::Max) |
| 2346 | 2318 | } |
| 2347 | 2319 | |
| 2348 | #[cfg(feature = "master")] | |
| 2349 | pub fn vector_reduce_fmax(&mut self, src: RValue<'gcc>) -> RValue<'gcc> { | |
| 2350 | let vector_type = src.get_type().unqualified().dyncast_vector().expect("vector type"); | |
| 2351 | let element_count = vector_type.get_num_units(); | |
| 2352 | let mut acc = self | |
| 2353 | .context | |
| 2354 | .new_vector_access(self.location, src, self.context.new_rvalue_zero(self.int_type)) | |
| 2355 | .to_rvalue(); | |
| 2356 | for i in 1..element_count { | |
| 2357 | let elem = self | |
| 2358 | .context | |
| 2359 | .new_vector_access( | |
| 2360 | self.location, | |
| 2361 | src, | |
| 2362 | self.context.new_rvalue_from_int(self.int_type, i as _), | |
| 2363 | ) | |
| 2364 | .to_rvalue(); | |
| 2365 | let cmp = | |
| 2366 | self.context.new_comparison(self.location, ComparisonOp::GreaterThan, acc, elem); | |
| 2367 | acc = self.select(cmp, acc, elem); | |
| 2368 | } | |
| 2369 | acc | |
| 2370 | } | |
| 2371 | ||
| 2372 | #[cfg(not(feature = "master"))] | |
| 2373 | pub fn vector_reduce_fmax(&mut self, _src: RValue<'gcc>) -> RValue<'gcc> { | |
| 2374 | unimplemented!(); | |
| 2375 | } | |
| 2376 | ||
| 2377 | 2320 | pub fn vector_select( |
| 2378 | 2321 | &mut self, |
| 2379 | 2322 | cond: RValue<'gcc>, |
compiler/rustc_codegen_gcc/src/intrinsic/simd.rs+3-4| ... | ... | @@ -1422,7 +1422,7 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( |
| 1422 | 1422 | ); |
| 1423 | 1423 | |
| 1424 | 1424 | macro_rules! minmax_red { |
| 1425 | ($name:ident: $int_red:ident, $float_red:ident) => { | |
| 1425 | ($name:ident: $int_red:ident) => { | |
| 1426 | 1426 | if name == sym::$name { |
| 1427 | 1427 | require!( |
| 1428 | 1428 | ret_ty == in_elem, |
| ... | ... | @@ -1430,7 +1430,6 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( |
| 1430 | 1430 | ); |
| 1431 | 1431 | return match *in_elem.kind() { |
| 1432 | 1432 | ty::Int(_) | ty::Uint(_) => Ok(bx.$int_red(args[0].immediate())), |
| 1433 | ty::Float(_) => Ok(bx.$float_red(args[0].immediate())), | |
| 1434 | 1433 | _ => return_error!(InvalidMonomorphization::UnsupportedSymbol { |
| 1435 | 1434 | span, |
| 1436 | 1435 | name, |
| ... | ... | @@ -1444,8 +1443,8 @@ pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>( |
| 1444 | 1443 | }; |
| 1445 | 1444 | } |
| 1446 | 1445 | |
| 1447 | minmax_red!(simd_reduce_min: vector_reduce_min, vector_reduce_fmin); | |
| 1448 | minmax_red!(simd_reduce_max: vector_reduce_max, vector_reduce_fmax); | |
| 1446 | minmax_red!(simd_reduce_min: vector_reduce_min); | |
| 1447 | minmax_red!(simd_reduce_max: vector_reduce_max); | |
| 1449 | 1448 | |
| 1450 | 1449 | macro_rules! bitwise_red { |
| 1451 | 1450 | ($name:ident : $op:expr, $boolean:expr) => { |
compiler/rustc_codegen_llvm/src/builder.rs-6| ... | ... | @@ -1668,12 +1668,6 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> { |
| 1668 | 1668 | pub(crate) fn vector_reduce_xor(&mut self, src: &'ll Value) -> &'ll Value { |
| 1669 | 1669 | self.call_intrinsic("llvm.vector.reduce.xor", &[self.val_ty(src)], &[src]) |
| 1670 | 1670 | } |
| 1671 | pub(crate) fn vector_reduce_fmin(&mut self, src: &'ll Value) -> &'ll Value { | |
| 1672 | self.call_intrinsic("llvm.vector.reduce.fmin", &[self.val_ty(src)], &[src]) | |
| 1673 | } | |
| 1674 | pub(crate) fn vector_reduce_fmax(&mut self, src: &'ll Value) -> &'ll Value { | |
| 1675 | self.call_intrinsic("llvm.vector.reduce.fmax", &[self.val_ty(src)], &[src]) | |
| 1676 | } | |
| 1677 | 1671 | pub(crate) fn vector_reduce_min(&mut self, src: &'ll Value, is_signed: bool) -> &'ll Value { |
| 1678 | 1672 | self.call_intrinsic( |
| 1679 | 1673 | if is_signed { "llvm.vector.reduce.smin" } else { "llvm.vector.reduce.umin" }, |
compiler/rustc_codegen_llvm/src/intrinsic.rs+4-4| ... | ... | @@ -2922,7 +2922,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>( |
| 2922 | 2922 | ); |
| 2923 | 2923 | |
| 2924 | 2924 | macro_rules! minmax_red { |
| 2925 | ($name:ident: $int_red:ident, $float_red:ident) => { | |
| 2925 | ($name:ident: $int_red:ident) => { | |
| 2926 | 2926 | if name == sym::$name { |
| 2927 | 2927 | require!( |
| 2928 | 2928 | ret_ty == in_elem, |
| ... | ... | @@ -2931,7 +2931,6 @@ fn generic_simd_intrinsic<'ll, 'tcx>( |
| 2931 | 2931 | return match in_elem.kind() { |
| 2932 | 2932 | ty::Int(_i) => Ok(bx.$int_red(args[0].immediate(), true)), |
| 2933 | 2933 | ty::Uint(_u) => Ok(bx.$int_red(args[0].immediate(), false)), |
| 2934 | ty::Float(_f) => Ok(bx.$float_red(args[0].immediate())), | |
| 2935 | 2934 | _ => return_error!(InvalidMonomorphization::UnsupportedSymbol { |
| 2936 | 2935 | span, |
| 2937 | 2936 | name, |
| ... | ... | @@ -2945,8 +2944,9 @@ fn generic_simd_intrinsic<'ll, 'tcx>( |
| 2945 | 2944 | }; |
| 2946 | 2945 | } |
| 2947 | 2946 | |
| 2948 | minmax_red!(simd_reduce_min: vector_reduce_min, vector_reduce_fmin); | |
| 2949 | minmax_red!(simd_reduce_max: vector_reduce_max, vector_reduce_fmax); | |
| 2947 | // Currently no support for float due to <https://github.com/llvm/llvm-project/issues/185827>. | |
| 2948 | minmax_red!(simd_reduce_min: vector_reduce_min); | |
| 2949 | minmax_red!(simd_reduce_max: vector_reduce_max); | |
| 2950 | 2950 | |
| 2951 | 2951 | macro_rules! bitwise_red { |
| 2952 | 2952 | ($name:ident : $red:ident, $boolean:expr) => { |
compiler/rustc_codegen_ssa/src/back/archive.rs+82-11| ... | ... | @@ -9,7 +9,7 @@ use ar_archive_writer::{ |
| 9 | 9 | ArchiveKind, COFFShortExport, MachineTypes, NewArchiveMember, write_archive_to_stream, |
| 10 | 10 | }; |
| 11 | 11 | pub use ar_archive_writer::{DEFAULT_OBJECT_READER, ObjectReader}; |
| 12 | use object::read::archive::ArchiveFile; | |
| 12 | use object::read::archive::{ArchiveFile, ArchiveKind as ObjectArchiveKind}; | |
| 13 | 13 | use object::read::macho::FatArch; |
| 14 | 14 | use rustc_data_structures::fx::FxIndexSet; |
| 15 | 15 | use rustc_data_structures::memmap::Mmap; |
| ... | ... | @@ -217,12 +217,10 @@ fn create_mingw_dll_import_lib( |
| 217 | 217 | // able to control the *exact* spelling of each of the symbols that are being imported: |
| 218 | 218 | // hence we don't want `dlltool` adding leading underscores automatically. |
| 219 | 219 | let dlltool = find_binutils_dlltool(sess); |
| 220 | let temp_prefix = { | |
| 221 | let mut path = PathBuf::from(&output_path); | |
| 222 | path.pop(); | |
| 223 | path.push(lib_name); | |
| 224 | path | |
| 225 | }; | |
| 220 | // temp_prefix doesn't handle paths with spaces so | |
| 221 | // use a relative path and set the current working directory | |
| 222 | let cwd = output_path.parent().unwrap_or(output_path); | |
| 223 | let temp_prefix = lib_name; | |
| 226 | 224 | // dlltool target architecture args from: |
| 227 | 225 | // https://github.com/llvm/llvm-project-release-prs/blob/llvmorg-15.0.6/llvm/lib/ToolDrivers/llvm-dlltool/DlltoolDriver.cpp#L69 |
| 228 | 226 | let (dlltool_target_arch, dlltool_target_bitness) = match &sess.target.arch { |
| ... | ... | @@ -246,7 +244,8 @@ fn create_mingw_dll_import_lib( |
| 246 | 244 | .arg(dlltool_target_bitness) |
| 247 | 245 | .arg("--no-leading-underscore") |
| 248 | 246 | .arg("--temp-prefix") |
| 249 | .arg(temp_prefix); | |
| 247 | .arg(temp_prefix) | |
| 248 | .current_dir(cwd); | |
| 250 | 249 | |
| 251 | 250 | match dlltool_cmd.output() { |
| 252 | 251 | Err(e) => { |
| ... | ... | @@ -320,6 +319,50 @@ pub trait ArchiveBuilder { |
| 320 | 319 | fn build(self: Box<Self>, output: &Path) -> bool; |
| 321 | 320 | } |
| 322 | 321 | |
| 322 | fn target_archive_format_to_object_kind(format: &str) -> Option<ObjectArchiveKind> { | |
| 323 | match format { | |
| 324 | "gnu" => Some(ObjectArchiveKind::Gnu), | |
| 325 | "bsd" => Some(ObjectArchiveKind::Bsd), | |
| 326 | "darwin" => Some(ObjectArchiveKind::Bsd64), | |
| 327 | "coff" => Some(ObjectArchiveKind::Coff), | |
| 328 | "aix_big" => Some(ObjectArchiveKind::AixBig), | |
| 329 | _ => None, | |
| 330 | } | |
| 331 | } | |
| 332 | ||
| 333 | fn archive_kinds_compatible(actual: ObjectArchiveKind, expected: ObjectArchiveKind) -> bool { | |
| 334 | if actual == expected { | |
| 335 | return true; | |
| 336 | } | |
| 337 | matches!( | |
| 338 | (actual, expected), | |
| 339 | // An archive without long filenames or symbol table is detected as Unknown; | |
| 340 | // this is compatible with any target format. | |
| 341 | (ObjectArchiveKind::Unknown, _) | |
| 342 | // 64-bit symbol table variants are compatible with their 32-bit counterparts | |
| 343 | | (ObjectArchiveKind::Gnu64, ObjectArchiveKind::Gnu) | |
| 344 | | (ObjectArchiveKind::Gnu, ObjectArchiveKind::Gnu64) | |
| 345 | | (ObjectArchiveKind::Bsd64, ObjectArchiveKind::Bsd) | |
| 346 | | (ObjectArchiveKind::Bsd, ObjectArchiveKind::Bsd64) | |
| 347 | // GNU and COFF archives share the same magic and member header format; | |
| 348 | // only the symbol table layout differs. | |
| 349 | | (ObjectArchiveKind::Gnu, ObjectArchiveKind::Coff) | |
| 350 | | (ObjectArchiveKind::Coff, ObjectArchiveKind::Gnu) | |
| 351 | | (ObjectArchiveKind::Gnu64, ObjectArchiveKind::Coff) | |
| 352 | ) | |
| 353 | } | |
| 354 | ||
| 355 | fn archive_kind_display_name(kind: ObjectArchiveKind) -> String { | |
| 356 | match kind { | |
| 357 | ObjectArchiveKind::Gnu | ObjectArchiveKind::Gnu64 => "GNU".to_string(), | |
| 358 | ObjectArchiveKind::Bsd => "BSD".to_string(), | |
| 359 | ObjectArchiveKind::Bsd64 => "Darwin".to_string(), | |
| 360 | ObjectArchiveKind::Coff => "COFF".to_string(), | |
| 361 | ObjectArchiveKind::AixBig => "AIX big".to_string(), | |
| 362 | _ => format!("{kind:?}"), | |
| 363 | } | |
| 364 | } | |
| 365 | ||
| 323 | 366 | pub struct ArArchiveBuilderBuilder; |
| 324 | 367 | |
| 325 | 368 | impl ArchiveBuilderBuilder for ArArchiveBuilderBuilder { |
| ... | ... | @@ -420,6 +463,19 @@ impl<'a> ArchiveBuilder for ArArchiveBuilder<'a> { |
| 420 | 463 | .map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; |
| 421 | 464 | let archive_index = self.src_archives.len(); |
| 422 | 465 | |
| 466 | if let Some(expected_kind) = | |
| 467 | target_archive_format_to_object_kind(&self.sess.target.archive_format) | |
| 468 | { | |
| 469 | let actual_kind = archive.kind(); | |
| 470 | if !archive_kinds_compatible(actual_kind, expected_kind) { | |
| 471 | self.sess.dcx().emit_warn(crate::errors::IncompatibleArchiveFormat { | |
| 472 | path: archive_path.clone(), | |
| 473 | actual: archive_kind_display_name(actual_kind), | |
| 474 | expected: archive_kind_display_name(expected_kind), | |
| 475 | }); | |
| 476 | } | |
| 477 | } | |
| 478 | ||
| 423 | 479 | for entry in archive.members() { |
| 424 | 480 | let entry = entry.map_err(|err| io::Error::new(io::ErrorKind::InvalidData, err))?; |
| 425 | 481 | let file_name = String::from_utf8(entry.name().to_vec()) |
| ... | ... | @@ -482,9 +538,24 @@ impl<'a> ArArchiveBuilder<'a> { |
| 482 | 538 | match entry { |
| 483 | 539 | ArchiveEntry::FromArchive { archive_index, file_range } => { |
| 484 | 540 | let src_archive = &self.src_archives[archive_index]; |
| 485 | ||
| 486 | let data = &src_archive.1 | |
| 487 | [file_range.0 as usize..file_range.0 as usize + file_range.1 as usize]; | |
| 541 | let archive_data = &src_archive.1; | |
| 542 | let start = file_range.0 as usize; | |
| 543 | let end = start + file_range.1 as usize; | |
| 544 | let Some(data) = archive_data.get(start..end) else { | |
| 545 | return Err(io_error_context( | |
| 546 | "invalid archive member", | |
| 547 | io::Error::new( | |
| 548 | io::ErrorKind::InvalidData, | |
| 549 | format!( | |
| 550 | "archive member at offset {start} with size {} \ | |
| 551 | exceeds archive size {} in `{}`", | |
| 552 | file_range.1, | |
| 553 | archive_data.len(), | |
| 554 | src_archive.0.display(), | |
| 555 | ), | |
| 556 | ), | |
| 557 | )); | |
| 558 | }; | |
| 488 | 559 | |
| 489 | 560 | Box::new(data) as Box<dyn AsRef<[u8]>> |
| 490 | 561 | } |
compiler/rustc_codegen_ssa/src/errors.rs+12| ... | ... | @@ -677,6 +677,18 @@ pub(crate) struct UnknownArchiveKind<'a> { |
| 677 | 677 | pub kind: &'a str, |
| 678 | 678 | } |
| 679 | 679 | |
| 680 | #[derive(Diagnostic)] | |
| 681 | #[diag("archive `{$path}` was built as {$actual} format, but the target expects {$expected}")] | |
| 682 | #[help( | |
| 683 | "this often occurs when using BSD-format archive tools on a Linux target; \ | |
| 684 | rebuild the archive with the correct format for the target platform" | |
| 685 | )] | |
| 686 | pub(crate) struct IncompatibleArchiveFormat { | |
| 687 | pub path: PathBuf, | |
| 688 | pub actual: String, | |
| 689 | pub expected: String, | |
| 690 | } | |
| 691 | ||
| 680 | 692 | #[derive(Diagnostic)] |
| 681 | 693 | #[diag("linking static libraries is not supported for BPF")] |
| 682 | 694 | pub(crate) struct BpfStaticlibNotSupported; |
compiler/rustc_const_eval/src/interpret/intrinsics.rs+150-14| ... | ... | @@ -8,6 +8,7 @@ use std::assert_matches; |
| 8 | 8 | |
| 9 | 9 | use rustc_abi::{FieldIdx, HasDataLayout, Size, VariantIdx}; |
| 10 | 10 | use rustc_apfloat::ieee::{Double, Half, Quad, Single}; |
| 11 | use rustc_ast::{IntTy, UintTy}; | |
| 11 | 12 | use rustc_middle::mir::interpret::{CTFE_ALLOC_SALT, read_target_uint, write_target_uint}; |
| 12 | 13 | use rustc_middle::mir::{self, BinOp, ConstValue, NonDivergingIntrinsic}; |
| 13 | 14 | use rustc_middle::ty::layout::TyAndLayout; |
| ... | ... | @@ -21,9 +22,9 @@ use super::util::ensure_monomorphic_enough; |
| 21 | 22 | use super::{ |
| 22 | 23 | AllocId, CheckInAllocMsg, ImmTy, InterpCx, InterpResult, Machine, OpTy, PlaceTy, Pointer, |
| 23 | 24 | PointerArithmetic, Projectable, Provenance, Scalar, err_ub_format, err_unsup_format, interp_ok, |
| 24 | throw_inval, throw_ub, throw_ub_format, throw_unsup_format, | |
| 25 | throw_inval, throw_ub, throw_ub_format, | |
| 25 | 26 | }; |
| 26 | use crate::interpret::Writeable; | |
| 27 | use crate::interpret::{MPlaceTy, Writeable}; | |
| 27 | 28 | |
| 28 | 29 | #[derive(Copy, Clone, Debug, PartialEq, Eq)] |
| 29 | 30 | enum MulAddType { |
| ... | ... | @@ -56,6 +57,22 @@ pub(crate) enum MinMax { |
| 56 | 57 | MaximumNumberNsz, |
| 57 | 58 | } |
| 58 | 59 | |
| 60 | /// Whether two types `T` and `U` are compatible when a value of type `T` is passed as a c-variadic | |
| 61 | /// argument and read as a value of type `U`. | |
| 62 | enum VarArgCompatible { | |
| 63 | /// `T` and `U` are compatible, e.g. | |
| 64 | /// | |
| 65 | /// - They're the same type. | |
| 66 | /// - One is `usize`/`isize`, the other an integer type of the same width | |
| 67 | /// and sign on the current target. | |
| 68 | /// - They are compatible pointer types (see the exact rules below). | |
| 69 | Compatible, | |
| 70 | /// `T` and `U` are definitely not compatible. | |
| 71 | Incompatible, | |
| 72 | /// `T` and `U` are corresponding signed and unsigned integer types. | |
| 73 | CastIntTo { source_is_signed: bool }, | |
| 74 | } | |
| 75 | ||
| 59 | 76 | /// Directly returns an `Allocation` containing an absolute path representation of the given type. |
| 60 | 77 | pub(crate) fn alloc_type_name<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (AllocId, u64) { |
| 61 | 78 | let path = crate::util::type_name(tcx, ty); |
| ... | ... | @@ -739,18 +756,13 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { |
| 739 | 756 | throw_ub!(VaArgOutOfBounds); |
| 740 | 757 | }; |
| 741 | 758 | |
| 742 | // NOTE: In C some type conversions are allowed (e.g. casting between signed and | |
| 743 | // unsigned integers). For now we require c-variadic arguments to be read with the | |
| 744 | // exact type they were passed as. | |
| 745 | if arg_mplace.layout.ty != dest.layout.ty { | |
| 746 | throw_unsup_format!( | |
| 747 | "va_arg type mismatch: requested `{}`, but next argument is `{}`", | |
| 748 | dest.layout.ty, | |
| 749 | arg_mplace.layout.ty | |
| 750 | ); | |
| 751 | } | |
| 752 | // Copy the argument. | |
| 753 | self.copy_op(&arg_mplace, dest)?; | |
| 759 | // Error when the caller's argument is not c-variadic compatible with the type | |
| 760 | // requested by the callee. | |
| 761 | self.validate_c_variadic_argument(&arg_mplace, dest.layout)?; | |
| 762 | ||
| 763 | // Copy the argument, allowing a transmute and relying on the compatibility check | |
| 764 | // rejecting conversions between types of different size. | |
| 765 | self.copy_op_allow_transmute(&arg_mplace, dest)?; | |
| 754 | 766 | |
| 755 | 767 | // Update the VaList pointer. |
| 756 | 768 | let new_key = self.va_list_ptr(varargs); |
| ... | ... | @@ -766,6 +778,130 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { |
| 766 | 778 | interp_ok(true) |
| 767 | 779 | } |
| 768 | 780 | |
| 781 | /// Validate whether the value and type passed by the caller are compatible with the type | |
| 782 | /// requested by the callee. Based on section 7.16.1.1 of the C23 specification. | |
| 783 | /// | |
| 784 | /// The callee requesting a value of a type is valid when that type is compatible with the type | |
| 785 | /// provided by the caller (see `validate_c_variadic_compatible_ty`) and, if both types are | |
| 786 | /// integers of the same size but different signedness, the passed value must be representable | |
| 787 | /// in both types. | |
| 788 | fn validate_c_variadic_argument( | |
| 789 | &mut self, | |
| 790 | arg_mplace: &MPlaceTy<'tcx, M::Provenance>, | |
| 791 | callee_type: TyAndLayout<'tcx>, | |
| 792 | ) -> InterpResult<'tcx> { | |
| 793 | let callee_ty = callee_type.ty; | |
| 794 | let caller_ty = arg_mplace.layout.ty; | |
| 795 | ||
| 796 | // Identical types are clearly compatible. | |
| 797 | if caller_ty == callee_ty { | |
| 798 | return interp_ok(()); | |
| 799 | } | |
| 800 | ||
| 801 | // Types of different sizes can never be compatible. | |
| 802 | if arg_mplace.layout.size != callee_type.size { | |
| 803 | throw_ub_format!( | |
| 804 | "va_arg type mismatch: requested `{}` is incompatible with next argument of type `{}`", | |
| 805 | callee_ty, | |
| 806 | caller_ty, | |
| 807 | ) | |
| 808 | } | |
| 809 | ||
| 810 | match self.validate_c_variadic_compatible_ty(arg_mplace.layout.ty, callee_type.ty)? { | |
| 811 | VarArgCompatible::Compatible => interp_ok(()), | |
| 812 | VarArgCompatible::Incompatible => throw_ub_format!( | |
| 813 | "va_arg type mismatch: requested `{}` is incompatible with next argument of type `{}`", | |
| 814 | callee_ty, | |
| 815 | caller_ty, | |
| 816 | ), | |
| 817 | VarArgCompatible::CastIntTo { source_is_signed } => { | |
| 818 | // Check that the value can be represented in the target type. | |
| 819 | let size = arg_mplace.layout.size; | |
| 820 | let scalar = self.read_scalar(arg_mplace)?; | |
| 821 | if scalar.to_int(size)? < 0 { | |
| 822 | throw_ub_format!( | |
| 823 | "va_arg value mismatch: value `{value}_{caller_ty}` cannot be represented by type `{callee_ty}`", | |
| 824 | value = if source_is_signed { | |
| 825 | scalar.to_int(size)?.to_string() | |
| 826 | } else { | |
| 827 | scalar.to_uint(size)?.to_string() | |
| 828 | } | |
| 829 | ) | |
| 830 | } | |
| 831 | ||
| 832 | interp_ok(()) | |
| 833 | } | |
| 834 | } | |
| 835 | } | |
| 836 | ||
| 837 | /// Check whether the caller and callee type are compatible for c-variadic calls. Further | |
| 838 | /// validation of the argument value may be needed to detect all UB. | |
| 839 | /// | |
| 840 | /// Types `T` and `U` are compatible when: | |
| 841 | /// | |
| 842 | /// - `T` and `U` are the same type. | |
| 843 | /// - `T` and `U` are integer types of the same size. | |
| 844 | /// - `T` and `U` are both pointers, and their target types are compatible. | |
| 845 | /// - `T` is a pointer to [`std::ffi::c_void`] and `U` is a pointer to [`i8`] or [`u8`], | |
| 846 | /// or vice versa. | |
| 847 | fn validate_c_variadic_compatible_ty( | |
| 848 | &mut self, | |
| 849 | caller_type: Ty<'tcx>, | |
| 850 | callee_type: Ty<'tcx>, | |
| 851 | ) -> InterpResult<'tcx, VarArgCompatible> { | |
| 852 | if caller_type == callee_type { | |
| 853 | return interp_ok(VarArgCompatible::Compatible); | |
| 854 | } | |
| 855 | ||
| 856 | if self.layout_of(caller_type)?.size != self.layout_of(callee_type)?.size { | |
| 857 | return interp_ok(VarArgCompatible::Incompatible); | |
| 858 | } | |
| 859 | ||
| 860 | // Any character type (`char`, `unsigned char` and `signed char`) is compatible with | |
| 861 | // `void*`, so the signedness of `c_char` is irrelevant here. | |
| 862 | let is_c_char = |ty: Ty<'_>| matches!(ty.kind(), ty::Uint(UintTy::U8) | ty::Int(IntTy::I8)); | |
| 863 | ||
| 864 | match (caller_type.kind(), callee_type.kind()) { | |
| 865 | (ty::RawPtr(caller_target_ty, _), ty::RawPtr(callee_target_ty, _)) => { | |
| 866 | // In C, types can be qualified by a combination of `const`, `volatile` and | |
| 867 | // `restrict`. These properties are irrelevant for the ABI, and don't have an | |
| 868 | // equivalent in rust. | |
| 869 | ||
| 870 | // Accept the cast if one type is pointer to void, and the other is a pointer to | |
| 871 | // a character type (`char`, `unsigned char` and `signed char`). | |
| 872 | if caller_target_ty.is_c_void(self.tcx.tcx) && is_c_char(*callee_target_ty) { | |
| 873 | return interp_ok(VarArgCompatible::Compatible); | |
| 874 | } | |
| 875 | if callee_target_ty.is_c_void(self.tcx.tcx) && is_c_char(*caller_target_ty) { | |
| 876 | return interp_ok(VarArgCompatible::Compatible); | |
| 877 | } | |
| 878 | ||
| 879 | // Accept the cast if both types are pointers to compatible types. | |
| 880 | match self | |
| 881 | .validate_c_variadic_compatible_ty(*caller_target_ty, *callee_target_ty)? | |
| 882 | { | |
| 883 | VarArgCompatible::Incompatible => interp_ok(VarArgCompatible::Incompatible), | |
| 884 | VarArgCompatible::Compatible => interp_ok(VarArgCompatible::Compatible), | |
| 885 | VarArgCompatible::CastIntTo { source_is_signed: _ } => { | |
| 886 | // The integer cast check is not needed when the value is behind a pointer. | |
| 887 | interp_ok(VarArgCompatible::Compatible) | |
| 888 | } | |
| 889 | } | |
| 890 | } | |
| 891 | (ty::Int(_), ty::Uint(_)) => { | |
| 892 | interp_ok(VarArgCompatible::CastIntTo { source_is_signed: true }) | |
| 893 | } | |
| 894 | (ty::Uint(_), ty::Int(_)) => { | |
| 895 | interp_ok(VarArgCompatible::CastIntTo { source_is_signed: false }) | |
| 896 | } | |
| 897 | (ty::Int(_), ty::Int(_)) | (ty::Uint(_), ty::Uint(_)) => { | |
| 898 | // E.g. cast between `usize` and `u64` on a 64-bit platform. | |
| 899 | interp_ok(VarArgCompatible::Compatible) | |
| 900 | } | |
| 901 | _ => interp_ok(VarArgCompatible::Incompatible), | |
| 902 | } | |
| 903 | } | |
| 904 | ||
| 769 | 905 | pub(super) fn eval_nondiverging_intrinsic( |
| 770 | 906 | &mut self, |
| 771 | 907 | intrinsic: &NonDivergingIntrinsic<'tcx>, |
compiler/rustc_data_structures/src/flat_map_in_place.rs+10-5| ... | ... | @@ -67,8 +67,13 @@ impl<V: FlatMapInPlaceVec> FlatMapInPlace<V::Elem> for V { |
| 67 | 67 | } |
| 68 | 68 | } |
| 69 | 69 | |
| 70 | // A vec-like type must implement these operations to support `flat_map_in_place`. | |
| 71 | pub trait FlatMapInPlaceVec { | |
| 70 | /// A vec-like type must implement these operations to support `flat_map_in_place`. | |
| 71 | /// | |
| 72 | /// # Safety | |
| 73 | /// | |
| 74 | /// The memory safety of the unsafe block in `flat_map_in_place` relies on impls of this trait | |
| 75 | /// implementing all the operations correctly. | |
| 76 | pub unsafe trait FlatMapInPlaceVec { | |
| 72 | 77 | type Elem; |
| 73 | 78 | |
| 74 | 79 | fn len(&self) -> usize; |
| ... | ... | @@ -78,7 +83,7 @@ pub trait FlatMapInPlaceVec { |
| 78 | 83 | fn insert(&mut self, idx: usize, elem: Self::Elem); |
| 79 | 84 | } |
| 80 | 85 | |
| 81 | impl<T> FlatMapInPlaceVec for Vec<T> { | |
| 86 | unsafe impl<T> FlatMapInPlaceVec for Vec<T> { | |
| 82 | 87 | type Elem = T; |
| 83 | 88 | |
| 84 | 89 | fn len(&self) -> usize { |
| ... | ... | @@ -104,7 +109,7 @@ impl<T> FlatMapInPlaceVec for Vec<T> { |
| 104 | 109 | } |
| 105 | 110 | } |
| 106 | 111 | |
| 107 | impl<T> FlatMapInPlaceVec for ThinVec<T> { | |
| 112 | unsafe impl<T> FlatMapInPlaceVec for ThinVec<T> { | |
| 108 | 113 | type Elem = T; |
| 109 | 114 | |
| 110 | 115 | fn len(&self) -> usize { |
| ... | ... | @@ -130,7 +135,7 @@ impl<T> FlatMapInPlaceVec for ThinVec<T> { |
| 130 | 135 | } |
| 131 | 136 | } |
| 132 | 137 | |
| 133 | impl<T, const N: usize> FlatMapInPlaceVec for SmallVec<[T; N]> { | |
| 138 | unsafe impl<T, const N: usize> FlatMapInPlaceVec for SmallVec<[T; N]> { | |
| 134 | 139 | type Elem = T; |
| 135 | 140 | |
| 136 | 141 | fn len(&self) -> usize { |
compiler/rustc_hir/src/hir.rs+2-1| ... | ... | @@ -18,6 +18,7 @@ pub use rustc_ast::{ |
| 18 | 18 | }; |
| 19 | 19 | use rustc_data_structures::fingerprint::Fingerprint; |
| 20 | 20 | use rustc_data_structures::sorted_map::SortedMap; |
| 21 | use rustc_data_structures::steal::Steal; | |
| 21 | 22 | use rustc_data_structures::tagged_ptr::TaggedRef; |
| 22 | 23 | use rustc_error_messages::{DiagArgValue, IntoDiagArg}; |
| 23 | 24 | use rustc_index::IndexVec; |
| ... | ... | @@ -1636,7 +1637,7 @@ pub struct OwnerInfo<'hir> { |
| 1636 | 1637 | /// WARNING: The delayed lints are not hashed as a part of the `OwnerInfo`, and therefore |
| 1637 | 1638 | /// should only be accessed in `eval_always` queries. |
| 1638 | 1639 | #[stable_hasher(ignore)] |
| 1639 | pub delayed_lints: DelayedLints, | |
| 1640 | pub delayed_lints: Steal<DelayedLints>, | |
| 1640 | 1641 | } |
| 1641 | 1642 | |
| 1642 | 1643 | impl<'tcx> OwnerInfo<'tcx> { |
compiler/rustc_hir_analysis/src/check/always_applicable.rs+14-4| ... | ... | @@ -217,16 +217,26 @@ fn ensure_all_fields_are_const_destruct<'tcx>( |
| 217 | 217 | unreachable!() |
| 218 | 218 | }; |
| 219 | 219 | let field_ty = eff.trait_ref.self_ty(); |
| 220 | let diag = struct_span_code_err!( | |
| 220 | let mut diag = struct_span_code_err!( | |
| 221 | 221 | tcx.dcx(), |
| 222 | 222 | error.root_obligation.cause.span, |
| 223 | 223 | E0367, |
| 224 | 224 | "`{field_ty}` does not implement `[const] Destruct`", |
| 225 | 225 | ) |
| 226 | 226 | .with_span_note(impl_span, "required for this `Drop` impl"); |
| 227 | if field_ty.has_param() { | |
| 228 | // FIXME: suggest adding `[const] Destruct` by teaching | |
| 229 | // `suggest_restricting_param_bound` about const traits. | |
| 227 | if field_ty.has_param() | |
| 228 | && let Some(generics) = tcx.hir_node_by_def_id(impl_def_id).generics() | |
| 229 | { | |
| 230 | let destruct_def_id = tcx.lang_items().destruct_trait(); | |
| 231 | ty::suggest_constraining_type_param( | |
| 232 | tcx, | |
| 233 | generics, | |
| 234 | &mut diag, | |
| 235 | &field_ty.to_string(), | |
| 236 | "[const] Destruct", | |
| 237 | destruct_def_id, | |
| 238 | None, | |
| 239 | ); | |
| 230 | 240 | } |
| 231 | 241 | Err(diag.emit()) |
| 232 | 242 | }) |
compiler/rustc_hir_analysis/src/hir_ty_lowering/mod.rs+1-1| ... | ... | @@ -3590,7 +3590,7 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ { |
| 3590 | 3590 | |
| 3591 | 3591 | let fn_sig_kind = FnSigKind::default() |
| 3592 | 3592 | .set_abi(abi) |
| 3593 | .set_safe(safety.is_safe()) | |
| 3593 | .set_safety(safety) | |
| 3594 | 3594 | .set_c_variadic(decl.fn_decl_kind.c_variadic()); |
| 3595 | 3595 | let fn_ty = tcx.mk_fn_sig(input_tys, output_ty, fn_sig_kind); |
| 3596 | 3596 | let fn_ptr_ty = ty::Binder::bind_with_vars(fn_ty, bound_vars); |
compiler/rustc_hir_typeck/src/closure.rs+4-4| ... | ... | @@ -723,7 +723,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 723 | 723 | let bound_sig = expected_sig.sig.map_bound(|sig| { |
| 724 | 724 | let fn_sig_kind = FnSigKind::default() |
| 725 | 725 | .set_abi(ExternAbi::RustCall) |
| 726 | .set_safe(true) | |
| 726 | .set_safety(hir::Safety::Safe) | |
| 727 | 727 | .set_c_variadic(sig.c_variadic()); |
| 728 | 728 | self.tcx.mk_fn_sig(sig.inputs().iter().cloned(), sig.output(), fn_sig_kind) |
| 729 | 729 | }); |
| ... | ... | @@ -860,7 +860,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 860 | 860 | |
| 861 | 861 | let fn_sig_kind = FnSigKind::default() |
| 862 | 862 | .set_abi(ExternAbi::RustCall) |
| 863 | .set_safe(true) | |
| 863 | .set_safety(hir::Safety::Safe) | |
| 864 | 864 | .set_c_variadic(expected_sigs.liberated_sig.c_variadic()); |
| 865 | 865 | expected_sigs.liberated_sig = |
| 866 | 866 | self.tcx.mk_fn_sig(inputs, supplied_output_ty, fn_sig_kind); |
| ... | ... | @@ -935,7 +935,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 935 | 935 | |
| 936 | 936 | let fn_sig_kind = FnSigKind::default() |
| 937 | 937 | .set_abi(ExternAbi::RustCall) |
| 938 | .set_safe(true) | |
| 938 | .set_safety(hir::Safety::Safe) | |
| 939 | 939 | .set_c_variadic(decl.c_variadic()); |
| 940 | 940 | let result = ty::Binder::bind_with_vars( |
| 941 | 941 | self.tcx.mk_fn_sig(supplied_arguments, supplied_return, fn_sig_kind), |
| ... | ... | @@ -1098,7 +1098,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |
| 1098 | 1098 | |
| 1099 | 1099 | let fn_sig_kind = FnSigKind::default() |
| 1100 | 1100 | .set_abi(ExternAbi::RustCall) |
| 1101 | .set_safe(true) | |
| 1101 | .set_safety(hir::Safety::Safe) | |
| 1102 | 1102 | .set_c_variadic(decl.c_variadic()); |
| 1103 | 1103 | let result = ty::Binder::dummy(self.tcx.mk_fn_sig(supplied_arguments, err_ty, fn_sig_kind)); |
| 1104 | 1104 |
compiler/rustc_interface/src/passes.rs+2-2| ... | ... | @@ -1041,7 +1041,7 @@ impl<'a, 'b, 'tcx> Diagnostic<'a, ()> for DiagCallback<'b, 'tcx> { |
| 1041 | 1041 | pub fn emit_delayed_lints(tcx: TyCtxt<'_>) { |
| 1042 | 1042 | for owner_id in tcx.hir_crate_items(()).delayed_lint_items() { |
| 1043 | 1043 | if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) { |
| 1044 | for lint in delayed_lints { | |
| 1044 | for lint in delayed_lints.steal() { | |
| 1045 | 1045 | tcx.emit_node_span_lint( |
| 1046 | 1046 | lint.lint_id.lint, |
| 1047 | 1047 | lint.id, |
| ... | ... | @@ -1117,7 +1117,7 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { |
| 1117 | 1117 | let hir_items = tcx.hir_crate_items(()); |
| 1118 | 1118 | for owner_id in hir_items.owners() { |
| 1119 | 1119 | if let Some(delayed_lints) = tcx.opt_ast_lowering_delayed_lints(owner_id) |
| 1120 | && !delayed_lints.is_empty() | |
| 1120 | && !delayed_lints.borrow().is_empty() | |
| 1121 | 1121 | { |
| 1122 | 1122 | // Assert that delayed_lint_items also picked up this item to have lints. |
| 1123 | 1123 | assert!(hir_items.delayed_lint_items().any(|i| i == owner_id)); |
compiler/rustc_middle/src/middle/privacy.rs+17-15| ... | ... | @@ -8,6 +8,7 @@ use std::hash::Hash; |
| 8 | 8 | use rustc_data_structures::fx::{FxIndexMap, IndexEntry}; |
| 9 | 9 | use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; |
| 10 | 10 | use rustc_hir::def::DefKind; |
| 11 | use rustc_hir::{ItemKind, Node, UseKind}; | |
| 11 | 12 | use rustc_macros::HashStable; |
| 12 | 13 | use rustc_span::def_id::{CRATE_DEF_ID, LocalDefId}; |
| 13 | 14 | |
| ... | ... | @@ -185,13 +186,20 @@ impl EffectiveVisibilities { |
| 185 | 186 | if !is_impl && tcx.trait_impl_of_assoc(def_id.to_def_id()).is_none() { |
| 186 | 187 | let nominal_vis = tcx.visibility(def_id); |
| 187 | 188 | if ev.reachable.greater_than(nominal_vis, tcx) { |
| 188 | span_bug!( | |
| 189 | span, | |
| 190 | "{:?}: reachable {:?} > nominal {:?}", | |
| 191 | def_id, | |
| 192 | ev.reachable, | |
| 193 | nominal_vis, | |
| 194 | ); | |
| 189 | if let Node::Item(item) = tcx.hir_node_by_def_id(def_id) | |
| 190 | && let ItemKind::Use(_, UseKind::Glob) = item.kind | |
| 191 | { | |
| 192 | // Glob import visibilities can be increased by other | |
| 193 | // more public glob imports in cases of ambiguity. | |
| 194 | } else { | |
| 195 | span_bug!( | |
| 196 | span, | |
| 197 | "{:?}: reachable {:?} > nominal {:?}", | |
| 198 | def_id, | |
| 199 | ev.reachable, | |
| 200 | nominal_vis, | |
| 201 | ); | |
| 202 | } | |
| 195 | 203 | } |
| 196 | 204 | } |
| 197 | 205 | } |
| ... | ... | @@ -207,12 +215,11 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> { |
| 207 | 215 | self.map.get(&id) |
| 208 | 216 | } |
| 209 | 217 | |
| 210 | // FIXME: Share code with `fn update`. | |
| 211 | 218 | pub fn effective_vis_or_private( |
| 212 | 219 | &mut self, |
| 213 | 220 | id: Id, |
| 214 | 221 | lazy_private_vis: impl FnOnce() -> Visibility, |
| 215 | ) -> &EffectiveVisibility { | |
| 222 | ) -> &mut EffectiveVisibility { | |
| 216 | 223 | self.map.entry(id).or_insert_with(|| EffectiveVisibility::from_vis(lazy_private_vis())) |
| 217 | 224 | } |
| 218 | 225 | |
| ... | ... | @@ -226,11 +233,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> { |
| 226 | 233 | tcx: TyCtxt<'_>, |
| 227 | 234 | ) -> bool { |
| 228 | 235 | let mut changed = false; |
| 229 | let mut current_effective_vis = self | |
| 230 | .map | |
| 231 | .get(&id) | |
| 232 | .copied() | |
| 233 | .unwrap_or_else(|| EffectiveVisibility::from_vis(lazy_private_vis())); | |
| 236 | let current_effective_vis = self.effective_vis_or_private(id, lazy_private_vis); | |
| 234 | 237 | |
| 235 | 238 | let mut inherited_effective_vis_at_prev_level = *inherited_effective_vis.at_level(level); |
| 236 | 239 | let mut calculated_effective_vis = inherited_effective_vis_at_prev_level; |
| ... | ... | @@ -268,7 +271,6 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> { |
| 268 | 271 | } |
| 269 | 272 | } |
| 270 | 273 | |
| 271 | self.map.insert(id, current_effective_vis); | |
| 272 | 274 | changed |
| 273 | 275 | } |
| 274 | 276 | } |
compiler/rustc_middle/src/queries.rs+1-1| ... | ... | @@ -274,7 +274,7 @@ rustc_queries! { |
| 274 | 274 | /// |
| 275 | 275 | /// This can be conveniently accessed by `tcx.hir_*` methods. |
| 276 | 276 | /// Avoid calling this query directly. |
| 277 | query opt_ast_lowering_delayed_lints(key: hir::OwnerId) -> Option<&'tcx hir::lints::DelayedLints> { | |
| 277 | query opt_ast_lowering_delayed_lints(key: hir::OwnerId) -> Option<&'tcx Steal<hir::lints::DelayedLints>> { | |
| 278 | 278 | desc { "getting AST lowering delayed lints in `{}`", tcx.def_path_str(key) } |
| 279 | 279 | // This query has to be `no_hash` and `eval_always`, |
| 280 | 280 | // because it accesses `delayed_lints` which is not hashed as part of the HIR |
compiler/rustc_middle/src/ty/context.rs+24-57| ... | ... | @@ -46,7 +46,7 @@ use rustc_span::def_id::{CRATE_DEF_ID, DefPathHash, StableCrateId}; |
| 46 | 46 | use rustc_span::{DUMMY_SP, Ident, Span, Symbol, kw, sym}; |
| 47 | 47 | use rustc_type_ir::TyKind::*; |
| 48 | 48 | pub use rustc_type_ir::lift::Lift; |
| 49 | use rustc_type_ir::{CollectAndApply, FnSigKind, WithCachedTypeInfo, elaborate, search_graph}; | |
| 49 | use rustc_type_ir::{CollectAndApply, WithCachedTypeInfo, elaborate, search_graph}; | |
| 50 | 50 | use tracing::{debug, instrument}; |
| 51 | 51 | |
| 52 | 52 | use crate::arena::Arena; |
| ... | ... | @@ -66,11 +66,11 @@ use crate::traits; |
| 66 | 66 | use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData, PredefinedOpaques}; |
| 67 | 67 | use crate::ty::predicate::ExistentialPredicateStableCmpExt as _; |
| 68 | 68 | use crate::ty::{ |
| 69 | self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, GenericArg, GenericArgs, | |
| 70 | GenericArgsRef, GenericParamDefKind, List, ListWithCachedTypeInfo, ParamConst, Pattern, | |
| 71 | PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, PredicatePolarity, | |
| 72 | Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, ValTree, ValTreeKind, | |
| 73 | Visibility, | |
| 69 | self, AdtDef, AdtDefData, AdtKind, Binder, Clause, Clauses, Const, FnSigKind, GenericArg, | |
| 70 | GenericArgs, GenericArgsRef, GenericParamDefKind, List, ListWithCachedTypeInfo, ParamConst, | |
| 71 | Pattern, PatternKind, PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, | |
| 72 | PredicatePolarity, Region, RegionKind, ReprOptions, TraitObjectVisitor, Ty, TyKind, TyVid, | |
| 73 | ValTree, ValTreeKind, Visibility, | |
| 74 | 74 | }; |
| 75 | 75 | |
| 76 | 76 | impl<'tcx> rustc_type_ir::inherent::DefId<TyCtxt<'tcx>> for DefId { |
| ... | ... | @@ -83,50 +83,6 @@ impl<'tcx> rustc_type_ir::inherent::DefId<TyCtxt<'tcx>> for DefId { |
| 83 | 83 | } |
| 84 | 84 | } |
| 85 | 85 | |
| 86 | impl<'tcx> rustc_type_ir::inherent::FSigKind<TyCtxt<'tcx>> for FnSigKind { | |
| 87 | fn fn_sig_kind(self) -> Self { | |
| 88 | self | |
| 89 | } | |
| 90 | ||
| 91 | fn new(abi: ExternAbi, safety: hir::Safety, c_variadic: bool) -> Self { | |
| 92 | FnSigKind::default().set_abi(abi).set_safe(safety.is_safe()).set_c_variadic(c_variadic) | |
| 93 | } | |
| 94 | ||
| 95 | fn abi(self) -> ExternAbi { | |
| 96 | self.abi() | |
| 97 | } | |
| 98 | ||
| 99 | fn safety(self) -> hir::Safety { | |
| 100 | if self.is_safe() { hir::Safety::Safe } else { hir::Safety::Unsafe } | |
| 101 | } | |
| 102 | ||
| 103 | fn c_variadic(self) -> bool { | |
| 104 | self.c_variadic() | |
| 105 | } | |
| 106 | } | |
| 107 | ||
| 108 | impl<'tcx> rustc_type_ir::inherent::Abi<TyCtxt<'tcx>> for ExternAbi { | |
| 109 | fn abi(self) -> Self { | |
| 110 | self | |
| 111 | } | |
| 112 | ||
| 113 | fn rust() -> Self { | |
| 114 | ExternAbi::Rust | |
| 115 | } | |
| 116 | ||
| 117 | fn is_rust(self) -> bool { | |
| 118 | matches!(self, ExternAbi::Rust) | |
| 119 | } | |
| 120 | ||
| 121 | fn pack_abi(self) -> u8 { | |
| 122 | self.as_packed() | |
| 123 | } | |
| 124 | ||
| 125 | fn unpack_abi(abi_index: u8) -> Self { | |
| 126 | Self::from_packed(abi_index) | |
| 127 | } | |
| 128 | } | |
| 129 | ||
| 130 | 86 | impl<'tcx> rustc_type_ir::inherent::Safety<TyCtxt<'tcx>> for hir::Safety { |
| 131 | 87 | fn safe() -> Self { |
| 132 | 88 | hir::Safety::Safe |
| ... | ... | @@ -1335,7 +1291,7 @@ impl<'tcx> TyCtxt<'tcx> { |
| 1335 | 1291 | let caller_features = &self.body_codegen_attrs(caller).target_features; |
| 1336 | 1292 | if self.is_target_feature_call_safe(&fun_features, &caller_features) { |
| 1337 | 1293 | return Some(fun_sig.map_bound(|sig| ty::FnSig { |
| 1338 | fn_sig_kind: fun_sig.fn_sig_kind().set_safe(true), | |
| 1294 | fn_sig_kind: fun_sig.fn_sig_kind().set_safety(hir::Safety::Safe), | |
| 1339 | 1295 | ..sig |
| 1340 | 1296 | })); |
| 1341 | 1297 | } |
| ... | ... | @@ -2104,7 +2060,10 @@ impl<'tcx> TyCtxt<'tcx> { |
| 2104 | 2060 | assert!(sig.safety().is_safe()); |
| 2105 | 2061 | Ty::new_fn_ptr( |
| 2106 | 2062 | self, |
| 2107 | sig.map_bound(|sig| ty::FnSig { fn_sig_kind: sig.fn_sig_kind.set_safe(false), ..sig }), | |
| 2063 | sig.map_bound(|sig| ty::FnSig { | |
| 2064 | fn_sig_kind: sig.fn_sig_kind.set_safety(hir::Safety::Unsafe), | |
| 2065 | ..sig | |
| 2066 | }), | |
| 2108 | 2067 | ) |
| 2109 | 2068 | } |
| 2110 | 2069 | |
| ... | ... | @@ -2113,7 +2072,10 @@ impl<'tcx> TyCtxt<'tcx> { |
| 2113 | 2072 | /// unsafe. |
| 2114 | 2073 | pub fn safe_to_unsafe_sig(self, sig: PolyFnSig<'tcx>) -> PolyFnSig<'tcx> { |
| 2115 | 2074 | assert!(sig.safety().is_safe()); |
| 2116 | sig.map_bound(|sig| ty::FnSig { fn_sig_kind: sig.fn_sig_kind.set_safe(false), ..sig }) | |
| 2075 | sig.map_bound(|sig| ty::FnSig { | |
| 2076 | fn_sig_kind: sig.fn_sig_kind.set_safety(hir::Safety::Unsafe), | |
| 2077 | ..sig | |
| 2078 | }) | |
| 2117 | 2079 | } |
| 2118 | 2080 | |
| 2119 | 2081 | /// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name` |
| ... | ... | @@ -2158,7 +2120,7 @@ impl<'tcx> TyCtxt<'tcx> { |
| 2158 | 2120 | self.mk_fn_sig( |
| 2159 | 2121 | params, |
| 2160 | 2122 | s.output(), |
| 2161 | s.fn_sig_kind.set_safe(safety.is_safe()).set_abi(ExternAbi::Rust), | |
| 2123 | s.fn_sig_kind.set_safety(safety).set_abi(ExternAbi::Rust), | |
| 2162 | 2124 | ) |
| 2163 | 2125 | }) |
| 2164 | 2126 | } |
| ... | ... | @@ -2417,7 +2379,12 @@ impl<'tcx> TyCtxt<'tcx> { |
| 2417 | 2379 | // IntoIterator` instead of `I: Iterator`, and it doesn't have a slice |
| 2418 | 2380 | // variant, because of the need to combine `inputs` and `output`. This |
| 2419 | 2381 | // explains the lack of `_from_iter` suffix. |
| 2420 | pub fn mk_fn_sig<I, T>(self, inputs: I, output: I::Item, fn_sig_kind: FnSigKind) -> T::Output | |
| 2382 | pub fn mk_fn_sig<I, T>( | |
| 2383 | self, | |
| 2384 | inputs: I, | |
| 2385 | output: I::Item, | |
| 2386 | fn_sig_kind: FnSigKind<'tcx>, | |
| 2387 | ) -> T::Output | |
| 2421 | 2388 | where |
| 2422 | 2389 | I: IntoIterator<Item = T>, |
| 2423 | 2390 | T: CollectAndApply<Ty<'tcx>, ty::FnSig<'tcx>>, |
| ... | ... | @@ -2439,7 +2406,7 @@ impl<'tcx> TyCtxt<'tcx> { |
| 2439 | 2406 | I: IntoIterator<Item = T>, |
| 2440 | 2407 | T: CollectAndApply<Ty<'tcx>, ty::FnSig<'tcx>>, |
| 2441 | 2408 | { |
| 2442 | self.mk_fn_sig(inputs, output, FnSigKind::default().set_safe(safety.is_safe())) | |
| 2409 | self.mk_fn_sig(inputs, output, FnSigKind::default().set_safety(safety)) | |
| 2443 | 2410 | } |
| 2444 | 2411 | |
| 2445 | 2412 | /// `mk_fn_sig`, but with a safe Rust ABI, and no C-variadic argument. |
| ... | ... | @@ -2448,7 +2415,7 @@ impl<'tcx> TyCtxt<'tcx> { |
| 2448 | 2415 | I: IntoIterator<Item = T>, |
| 2449 | 2416 | T: CollectAndApply<Ty<'tcx>, ty::FnSig<'tcx>>, |
| 2450 | 2417 | { |
| 2451 | self.mk_fn_sig(inputs, output, FnSigKind::default().set_safe(true)) | |
| 2418 | self.mk_fn_sig(inputs, output, FnSigKind::default().set_safety(hir::Safety::Safe)) | |
| 2452 | 2419 | } |
| 2453 | 2420 | |
| 2454 | 2421 | pub fn mk_poly_existential_predicates_from_iter<I, T>(self, iter: I) -> T::Output |
compiler/rustc_middle/src/ty/context/impl_interner.rs+1-6| ... | ... | @@ -2,7 +2,6 @@ |
| 2 | 2 | |
| 3 | 3 | use std::{debug_assert_matches, fmt}; |
| 4 | 4 | |
| 5 | use rustc_abi::ExternAbi; | |
| 6 | 5 | use rustc_errors::ErrorGuaranteed; |
| 7 | 6 | use rustc_hir as hir; |
| 8 | 7 | use rustc_hir::def::{CtorKind, CtorOf, DefKind}; |
| ... | ... | @@ -10,9 +9,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; |
| 10 | 9 | use rustc_hir::lang_items::LangItem; |
| 11 | 10 | use rustc_span::{DUMMY_SP, Span, Symbol}; |
| 12 | 11 | use rustc_type_ir::lang_items::{SolverAdtLangItem, SolverLangItem, SolverTraitLangItem}; |
| 13 | use rustc_type_ir::{ | |
| 14 | CollectAndApply, FnSigKind, Interner, TypeFoldable, Unnormalized, search_graph, | |
| 15 | }; | |
| 12 | use rustc_type_ir::{CollectAndApply, Interner, TypeFoldable, Unnormalized, search_graph}; | |
| 16 | 13 | |
| 17 | 14 | use crate::dep_graph::{DepKind, DepNodeIndex}; |
| 18 | 15 | use crate::infer::canonical::CanonicalVarKinds; |
| ... | ... | @@ -92,9 +89,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { |
| 92 | 89 | type AllocId = crate::mir::interpret::AllocId; |
| 93 | 90 | type Pat = Pattern<'tcx>; |
| 94 | 91 | type PatList = &'tcx List<Pattern<'tcx>>; |
| 95 | type FSigKind = FnSigKind; | |
| 96 | 92 | type Safety = hir::Safety; |
| 97 | type Abi = ExternAbi; | |
| 98 | 93 | type Const = ty::Const<'tcx>; |
| 99 | 94 | type Consts = &'tcx List<Self::Const>; |
| 100 | 95 |
compiler/rustc_middle/src/ty/mod.rs+30-17| ... | ... | @@ -338,18 +338,39 @@ impl TyCtxt<'_> { |
| 338 | 338 | self.parent(id.into().to_def_id()).expect_local() |
| 339 | 339 | } |
| 340 | 340 | |
| 341 | pub fn is_descendant_of(self, mut descendant: DefId, ancestor: DefId) -> bool { | |
| 342 | if descendant.krate != ancestor.krate { | |
| 343 | return false; | |
| 341 | /// Compare def-ids based on their position in def-id tree, ancestor def-ids are considered | |
| 342 | /// larger than descendant def-ids, and two different def-ids are considered unordered if | |
| 343 | /// neither of them is an ancestor of the other. | |
| 344 | fn def_id_partial_cmp(self, lhs: DefId, rhs: DefId) -> Option<Ordering> { | |
| 345 | // Def-ids from different crates are always unordered. | |
| 346 | if lhs.krate != rhs.krate { | |
| 347 | return None; | |
| 344 | 348 | } |
| 345 | 349 | |
| 346 | while descendant != ancestor { | |
| 347 | match self.opt_parent(descendant) { | |
| 348 | Some(parent) => descendant = parent, | |
| 349 | None => return false, | |
| 350 | // Def-ids of parent nodes are always created before def-ids of child nodes | |
| 351 | // and have a smaller index, so we only need to search in one direction, | |
| 352 | // either from lhs to rhs, or vice versa. | |
| 353 | let search = |mut start: DefId, finish: DefId, ord| { | |
| 354 | while start.index != finish.index { | |
| 355 | match self.opt_parent(start) { | |
| 356 | Some(parent) => start.index = parent.index, | |
| 357 | None => return None, | |
| 358 | } | |
| 350 | 359 | } |
| 360 | Some(ord) | |
| 361 | }; | |
| 362 | match lhs.index.cmp(&rhs.index) { | |
| 363 | Ordering::Equal => Some(Ordering::Equal), | |
| 364 | Ordering::Less => search(rhs, lhs, Ordering::Greater), | |
| 365 | Ordering::Greater => search(lhs, rhs, Ordering::Less), | |
| 351 | 366 | } |
| 352 | true | |
| 367 | } | |
| 368 | ||
| 369 | pub fn is_descendant_of(self, descendant: DefId, ancestor: DefId) -> bool { | |
| 370 | matches!( | |
| 371 | self.def_id_partial_cmp(descendant, ancestor), | |
| 372 | Some(Ordering::Less | Ordering::Equal) | |
| 373 | ) | |
| 353 | 374 | } |
| 354 | 375 | } |
| 355 | 376 | |
| ... | ... | @@ -391,15 +412,7 @@ impl<Id: Into<DefId>> Visibility<Id> { |
| 391 | 412 | (Visibility::Restricted(_), Visibility::Public) => Some(Ordering::Less), |
| 392 | 413 | (Visibility::Restricted(lhs_id), Visibility::Restricted(rhs_id)) => { |
| 393 | 414 | let (lhs_id, rhs_id) = (lhs_id.into(), rhs_id.into()); |
| 394 | if lhs_id == rhs_id { | |
| 395 | Some(Ordering::Equal) | |
| 396 | } else if tcx.is_descendant_of(rhs_id, lhs_id) { | |
| 397 | Some(Ordering::Greater) | |
| 398 | } else if tcx.is_descendant_of(lhs_id, rhs_id) { | |
| 399 | Some(Ordering::Less) | |
| 400 | } else { | |
| 401 | None | |
| 402 | } | |
| 415 | tcx.def_id_partial_cmp(lhs_id, rhs_id) | |
| 403 | 416 | } |
| 404 | 417 | } |
| 405 | 418 | } |
compiler/rustc_middle/src/ty/print/pretty.rs+1-1| ... | ... | @@ -751,7 +751,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { |
| 751 | 751 | if self.tcx().codegen_fn_attrs(def_id).safe_target_features { |
| 752 | 752 | write!(self, "#[target_features] ")?; |
| 753 | 753 | sig = sig.map_bound(|mut sig| { |
| 754 | sig.fn_sig_kind = sig.fn_sig_kind.set_safe(true); | |
| 754 | sig.fn_sig_kind = sig.fn_sig_kind.set_safety(hir::Safety::Safe); | |
| 755 | 755 | sig |
| 756 | 756 | }); |
| 757 | 757 | } |
compiler/rustc_middle/src/ty/structural_impls.rs-1| ... | ... | @@ -198,7 +198,6 @@ TrivialLiftImpls! { |
| 198 | 198 | rustc_hir::Safety, |
| 199 | 199 | rustc_middle::mir::ConstValue, |
| 200 | 200 | rustc_type_ir::BoundConstness, |
| 201 | rustc_type_ir::FnSigKind, | |
| 202 | 201 | rustc_type_ir::PredicatePolarity, |
| 203 | 202 | // tidy-alphabetical-end |
| 204 | 203 | } |
compiler/rustc_middle/src/ty/sty.rs+1-1| ... | ... | @@ -37,7 +37,7 @@ pub type TypeAndMut<'tcx> = ir::TypeAndMut<TyCtxt<'tcx>>; |
| 37 | 37 | pub type AliasTy<'tcx> = ir::AliasTy<TyCtxt<'tcx>>; |
| 38 | 38 | pub type AliasTyKind<'tcx> = ir::AliasTyKind<TyCtxt<'tcx>>; |
| 39 | 39 | pub type FnSig<'tcx> = ir::FnSig<TyCtxt<'tcx>>; |
| 40 | pub type FnSigKind = ir::FnSigKind; | |
| 40 | pub type FnSigKind<'tcx> = ir::FnSigKind<TyCtxt<'tcx>>; | |
| 41 | 41 | pub type Binder<'tcx, T> = ir::Binder<TyCtxt<'tcx>, T>; |
| 42 | 42 | pub type EarlyBinder<'tcx, T> = ir::EarlyBinder<TyCtxt<'tcx>, T>; |
| 43 | 43 | pub type Unnormalized<'tcx, T> = ir::Unnormalized<TyCtxt<'tcx>, T>; |
compiler/rustc_public/src/unstable/convert/internal.rs+1-1| ... | ... | @@ -314,7 +314,7 @@ impl RustcInternal for FnSig { |
| 314 | 314 | ) -> Self::T<'tcx> { |
| 315 | 315 | let fn_sig_kind = rustc_ty::FnSigKind::default() |
| 316 | 316 | .set_abi(self.abi.internal(tables, tcx)) |
| 317 | .set_safe(self.safety == Safety::Safe) | |
| 317 | .set_safety(self.safety.internal(tables, tcx)) | |
| 318 | 318 | .set_c_variadic(self.c_variadic); |
| 319 | 319 | tcx.lift(rustc_ty::FnSig { |
| 320 | 320 | inputs_and_output: tcx.mk_type_list(&self.inputs_and_output.internal(tables, tcx)), |
compiler/rustc_public/src/unstable/convert/stable/ty.rs+1-1| ... | ... | @@ -257,7 +257,7 @@ where |
| 257 | 257 | |
| 258 | 258 | // This internal type isn't publicly exposed, because it is an implementation detail. |
| 259 | 259 | // But it's a public field of FnSig (which has a public mirror type), so allow conversions. |
| 260 | impl<'tcx> Stable<'tcx> for ty::FnSigKind { | |
| 260 | impl<'tcx> Stable<'tcx> for ty::FnSigKind<'tcx> { | |
| 261 | 261 | type T = (bool /*c_variadic*/, crate::mir::Safety, crate::ty::Abi); |
| 262 | 262 | fn stable<'cx>( |
| 263 | 263 | &self, |
compiler/rustc_resolve/src/build_reduced_graph.rs+3-1| ... | ... | @@ -93,7 +93,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |
| 93 | 93 | ambiguity: CmCell::new(ambiguity), |
| 94 | 94 | // External ambiguities always report the `AMBIGUOUS_GLOB_IMPORTS` lint at the moment. |
| 95 | 95 | warn_ambiguity: CmCell::new(true), |
| 96 | vis: CmCell::new(vis), | |
| 96 | initial_vis: vis, | |
| 97 | ambiguity_vis_max: CmCell::new(None), | |
| 98 | ambiguity_vis_min: CmCell::new(None), | |
| 97 | 99 | span, |
| 98 | 100 | expansion, |
| 99 | 101 | parent_module: Some(parent.to_module()), |
compiler/rustc_resolve/src/effective_visibilities.rs+4| ... | ... | @@ -182,6 +182,10 @@ impl<'a, 'ra, 'tcx> EffectiveVisibilitiesVisitor<'a, 'ra, 'tcx> { |
| 182 | 182 | parent_id.level(), |
| 183 | 183 | tcx, |
| 184 | 184 | ); |
| 185 | if let Some(max_vis_decl) = decl.ambiguity_vis_max.get() { | |
| 186 | // Avoid the most visible import in an ambiguous glob set being reported as unused. | |
| 187 | self.update_import(max_vis_decl, parent_id); | |
| 188 | } | |
| 185 | 189 | } |
| 186 | 190 | |
| 187 | 191 | fn update_def( |
compiler/rustc_resolve/src/ident.rs+30| ... | ... | @@ -490,6 +490,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |
| 490 | 490 | } |
| 491 | 491 | Some(Finalize { import, .. }) => import, |
| 492 | 492 | }; |
| 493 | this.get_mut().maybe_push_glob_vs_glob_vis_ambiguity( | |
| 494 | ident, | |
| 495 | orig_ident_span, | |
| 496 | decl, | |
| 497 | import, | |
| 498 | ); | |
| 493 | 499 | |
| 494 | 500 | if let Some(&(innermost_decl, _)) = innermost_results.first() { |
| 495 | 501 | // Found another solution, if the first one was "weak", report an error. |
| ... | ... | @@ -779,6 +785,30 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |
| 779 | 785 | ret.map_err(ControlFlow::Continue) |
| 780 | 786 | } |
| 781 | 787 | |
| 788 | fn maybe_push_glob_vs_glob_vis_ambiguity( | |
| 789 | &mut self, | |
| 790 | ident: IdentKey, | |
| 791 | orig_ident_span: Span, | |
| 792 | decl: Decl<'ra>, | |
| 793 | import: Option<ImportSummary>, | |
| 794 | ) { | |
| 795 | let Some(import) = import else { return }; | |
| 796 | let vis1 = self.import_decl_vis(decl, import); | |
| 797 | let vis2 = self.import_decl_vis_ext(decl, import, true); | |
| 798 | if vis1 != vis2 { | |
| 799 | self.ambiguity_errors.push(AmbiguityError { | |
| 800 | kind: AmbiguityKind::GlobVsGlob, | |
| 801 | ambig_vis: Some((vis1, vis2)), | |
| 802 | ident: ident.orig(orig_ident_span), | |
| 803 | b1: decl.ambiguity_vis_max.get().unwrap_or(decl), | |
| 804 | b2: decl.ambiguity_vis_min.get().unwrap_or(decl), | |
| 805 | scope1: Scope::ModuleGlobs(decl.parent_module.unwrap(), None), | |
| 806 | scope2: Scope::ModuleGlobs(decl.parent_module.unwrap(), None), | |
| 807 | warning: Some(AmbiguityWarning::GlobImport), | |
| 808 | }); | |
| 809 | } | |
| 810 | } | |
| 811 | ||
| 782 | 812 | fn maybe_push_ambiguity( |
| 783 | 813 | &mut self, |
| 784 | 814 | ident: IdentKey, |
compiler/rustc_resolve/src/imports.rs+32-12| ... | ... | @@ -370,8 +370,17 @@ fn remove_same_import<'ra>(d1: Decl<'ra>, d2: Decl<'ra>) -> (Decl<'ra>, Decl<'ra |
| 370 | 370 | |
| 371 | 371 | impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |
| 372 | 372 | pub(crate) fn import_decl_vis(&self, decl: Decl<'ra>, import: ImportSummary) -> Visibility { |
| 373 | self.import_decl_vis_ext(decl, import, false) | |
| 374 | } | |
| 375 | ||
| 376 | pub(crate) fn import_decl_vis_ext( | |
| 377 | &self, | |
| 378 | decl: Decl<'ra>, | |
| 379 | import: ImportSummary, | |
| 380 | min: bool, | |
| 381 | ) -> Visibility { | |
| 373 | 382 | assert!(import.vis.is_accessible_from(import.nearest_parent_mod, self.tcx)); |
| 374 | let decl_vis = decl.vis(); | |
| 383 | let decl_vis = if min { decl.min_vis() } else { decl.vis() }; | |
| 375 | 384 | if decl_vis.partial_cmp(import.vis, self.tcx) == Some(Ordering::Less) |
| 376 | 385 | && decl_vis.is_accessible_from(import.nearest_parent_mod, self.tcx) |
| 377 | 386 | && pub_use_of_private_extern_crate_hack(import, decl).is_none() |
| ... | ... | @@ -409,7 +418,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |
| 409 | 418 | ambiguity: CmCell::new(None), |
| 410 | 419 | warn_ambiguity: CmCell::new(false), |
| 411 | 420 | span: import.span, |
| 412 | vis: CmCell::new(vis.to_def_id()), | |
| 421 | initial_vis: vis.to_def_id(), | |
| 422 | ambiguity_vis_max: CmCell::new(None), | |
| 423 | ambiguity_vis_min: CmCell::new(None), | |
| 413 | 424 | expansion: import.parent_scope.expansion, |
| 414 | 425 | parent_module: Some(import.parent_scope.module), |
| 415 | 426 | }) |
| ... | ... | @@ -434,8 +445,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |
| 434 | 445 | // - A glob decl is overwritten by its clone after setting ambiguity in it. |
| 435 | 446 | // FIXME: avoid this by removing `warn_ambiguity`, or by triggering glob re-fetch |
| 436 | 447 | // with the same decl in some way. |
| 437 | // - A glob decl is overwritten by a glob decl with larger visibility. | |
| 438 | // FIXME: avoid this by updating this visibility in place. | |
| 439 | 448 | // - A glob decl is overwritten by a glob decl re-fetching an |
| 440 | 449 | // overwritten decl from other module (the recursive case). |
| 441 | 450 | // Here we are detecting all such re-fetches and overwrite old decls |
| ... | ... | @@ -449,8 +458,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |
| 449 | 458 | // FIXME: reenable the asserts when `warn_ambiguity` is removed (#149195). |
| 450 | 459 | // assert_ne!(old_deep_decl, deep_decl); |
| 451 | 460 | // assert!(old_deep_decl.is_glob_import()); |
| 452 | // FIXME: reenable the assert when visibility is updated in place. | |
| 453 | // assert!(!deep_decl.is_glob_import()); | |
| 461 | assert!(!deep_decl.is_glob_import()); | |
| 454 | 462 | if old_glob_decl.ambiguity.get().is_some() && glob_decl.ambiguity.get().is_none() { |
| 455 | 463 | // Do not lose glob ambiguities when re-fetching the glob. |
| 456 | 464 | glob_decl.ambiguity.set_unchecked(old_glob_decl.ambiguity.get()); |
| ... | ... | @@ -470,12 +478,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |
| 470 | 478 | // FIXME: remove this when `warn_ambiguity` is removed (#149195). |
| 471 | 479 | self.arenas.alloc_decl((*old_glob_decl).clone()) |
| 472 | 480 | } |
| 473 | } else if glob_decl.vis().greater_than(old_glob_decl.vis(), self.tcx) { | |
| 474 | // We are glob-importing the same item but with greater visibility. | |
| 481 | } else if let old_vis = old_glob_decl.vis() | |
| 482 | && let vis = glob_decl.vis() | |
| 483 | && old_vis != vis | |
| 484 | { | |
| 485 | // We are glob-importing the same item but with a different visibility. | |
| 475 | 486 | // All visibilities here are ordered because all of them are ancestors of `module`. |
| 476 | // FIXME: Update visibility in place, but without regressions | |
| 477 | // (#152004, #151124, #152347). | |
| 478 | glob_decl | |
| 487 | if vis.greater_than(old_vis, self.tcx) { | |
| 488 | old_glob_decl.ambiguity_vis_max.set_unchecked(Some(glob_decl)); | |
| 489 | } else if let old_min_vis = old_glob_decl.min_vis() | |
| 490 | && old_min_vis != vis | |
| 491 | && old_min_vis.greater_than(vis, self.tcx) | |
| 492 | { | |
| 493 | old_glob_decl.ambiguity_vis_min.set_unchecked(Some(glob_decl)); | |
| 494 | } | |
| 495 | old_glob_decl | |
| 479 | 496 | } else if glob_decl.is_ambiguity_recursive() && !old_glob_decl.is_ambiguity_recursive() { |
| 480 | 497 | // Overwriting a non-ambiguous glob import with an ambiguous glob import. |
| 481 | 498 | old_glob_decl.ambiguity.set_unchecked(Some(glob_decl)); |
| ... | ... | @@ -498,6 +515,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |
| 498 | 515 | ) -> Result<(), Decl<'ra>> { |
| 499 | 516 | assert!(!decl.warn_ambiguity.get()); |
| 500 | 517 | assert!(decl.ambiguity.get().is_none()); |
| 518 | assert!(decl.ambiguity_vis_max.get().is_none()); | |
| 519 | assert!(decl.ambiguity_vis_min.get().is_none()); | |
| 501 | 520 | let module = decl.parent_module.unwrap().expect_local(); |
| 502 | 521 | assert!(self.is_accessible_from(decl.vis(), module.to_module())); |
| 503 | 522 | let res = decl.res(); |
| ... | ... | @@ -556,11 +575,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |
| 556 | 575 | .resolution_or_default(module.to_module(), key, orig_ident_span) |
| 557 | 576 | .borrow_mut_unchecked(); |
| 558 | 577 | let old_decl = resolution.determined_decl(); |
| 578 | let old_vis = old_decl.map(|d| d.vis()); | |
| 559 | 579 | |
| 560 | 580 | let t = f(self, resolution); |
| 561 | 581 | |
| 562 | 582 | if let Some(binding) = resolution.determined_decl() |
| 563 | && old_decl != Some(binding) | |
| 583 | && (old_decl != Some(binding) || old_vis != Some(binding.vis())) | |
| 564 | 584 | { |
| 565 | 585 | (binding, t, warn_ambiguity || old_decl.is_some()) |
| 566 | 586 | } else { |
compiler/rustc_resolve/src/lib.rs+17-3| ... | ... | @@ -929,7 +929,13 @@ struct DeclData<'ra> { |
| 929 | 929 | warn_ambiguity: CmCell<bool>, |
| 930 | 930 | expansion: LocalExpnId, |
| 931 | 931 | span: Span, |
| 932 | vis: CmCell<Visibility<DefId>>, | |
| 932 | initial_vis: Visibility<DefId>, | |
| 933 | /// If the declaration refers to an ambiguous glob set, then this is the most visible | |
| 934 | /// declaration from the set, if its visibility is different from `initial_vis`. | |
| 935 | ambiguity_vis_max: CmCell<Option<Decl<'ra>>>, | |
| 936 | /// If the declaration refers to an ambiguous glob set, then this is the least visible | |
| 937 | /// declaration from the set, if its visibility is different from `initial_vis`. | |
| 938 | ambiguity_vis_min: CmCell<Option<Decl<'ra>>>, | |
| 933 | 939 | parent_module: Option<Module<'ra>>, |
| 934 | 940 | } |
| 935 | 941 | |
| ... | ... | @@ -1049,7 +1055,13 @@ struct AmbiguityError<'ra> { |
| 1049 | 1055 | |
| 1050 | 1056 | impl<'ra> DeclData<'ra> { |
| 1051 | 1057 | fn vis(&self) -> Visibility<DefId> { |
| 1052 | self.vis.get() | |
| 1058 | // Select the maximum visibility if there are multiple ambiguous glob imports. | |
| 1059 | self.ambiguity_vis_max.get().map(|d| d.vis()).unwrap_or_else(|| self.initial_vis) | |
| 1060 | } | |
| 1061 | ||
| 1062 | fn min_vis(&self) -> Visibility<DefId> { | |
| 1063 | // Select the minimum visibility if there are multiple ambiguous glob imports. | |
| 1064 | self.ambiguity_vis_min.get().map(|d| d.vis()).unwrap_or_else(|| self.initial_vis) | |
| 1053 | 1065 | } |
| 1054 | 1066 | |
| 1055 | 1067 | fn res(&self) -> Res { |
| ... | ... | @@ -1505,7 +1517,9 @@ impl<'ra> ResolverArenas<'ra> { |
| 1505 | 1517 | kind: DeclKind::Def(res), |
| 1506 | 1518 | ambiguity: CmCell::new(None), |
| 1507 | 1519 | warn_ambiguity: CmCell::new(false), |
| 1508 | vis: CmCell::new(vis), | |
| 1520 | initial_vis: vis, | |
| 1521 | ambiguity_vis_max: CmCell::new(None), | |
| 1522 | ambiguity_vis_min: CmCell::new(None), | |
| 1509 | 1523 | span, |
| 1510 | 1524 | expansion, |
| 1511 | 1525 | parent_module, |
compiler/rustc_target/src/spec/targets/wasm32_wali_linux_musl.rs+2-2| ... | ... | @@ -13,7 +13,7 @@ pub(crate) fn target() -> Target { |
| 13 | 13 | options.add_pre_link_args( |
| 14 | 14 | LinkerFlavor::WasmLld(Cc::Yes), |
| 15 | 15 | &[ |
| 16 | "--target=wasm32-wasi-threads", | |
| 16 | "--target=wasm32-linux-muslwali", | |
| 17 | 17 | "-Wl,--export-memory,", |
| 18 | 18 | "-Wl,--shared-memory", |
| 19 | 19 | "-Wl,--max-memory=1073741824", |
| ... | ... | @@ -21,7 +21,7 @@ pub(crate) fn target() -> Target { |
| 21 | 21 | ); |
| 22 | 22 | |
| 23 | 23 | Target { |
| 24 | llvm_target: "wasm32-wasi".into(), | |
| 24 | llvm_target: "wasm32-linux-muslwali".into(), | |
| 25 | 25 | metadata: TargetMetadata { |
| 26 | 26 | description: Some("WebAssembly Linux Interface with musl-libc".into()), |
| 27 | 27 | tier: Some(3), |
compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs+20-3| ... | ... | @@ -25,8 +25,8 @@ use rustc_middle::traits::select::OverflowError; |
| 25 | 25 | use rustc_middle::ty::abstract_const::NotConstEvaluatable; |
| 26 | 26 | use rustc_middle::ty::error::{ExpectedFound, TypeError}; |
| 27 | 27 | use rustc_middle::ty::print::{ |
| 28 | PrintPolyTraitPredicateExt, PrintTraitPredicateExt as _, PrintTraitRefExt as _, | |
| 29 | with_forced_trimmed_paths, | |
| 28 | PrintPolyTraitPredicateExt, PrintPolyTraitRefExt as _, PrintTraitPredicateExt as _, | |
| 29 | PrintTraitRefExt as _, with_forced_trimmed_paths, | |
| 30 | 30 | }; |
| 31 | 31 | use rustc_middle::ty::{ |
| 32 | 32 | self, GenericArgKind, TraitRef, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, |
| ... | ... | @@ -886,6 +886,23 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { |
| 886 | 886 | ); |
| 887 | 887 | } |
| 888 | 888 | } |
| 889 | } else if let ty::Param(param) = trait_ref.self_ty().skip_binder().kind() | |
| 890 | && let Some(generics) = | |
| 891 | self.tcx.hir_node_by_def_id(main_obligation.cause.body_id).generics() | |
| 892 | { | |
| 893 | let constraint = ty::print::with_no_trimmed_paths!(format!( | |
| 894 | "[const] {}", | |
| 895 | trait_ref.map_bound(|tr| tr.trait_ref).print_trait_sugared(), | |
| 896 | )); | |
| 897 | ty::suggest_constraining_type_param( | |
| 898 | self.tcx, | |
| 899 | generics, | |
| 900 | &mut diag, | |
| 901 | param.name.as_str(), | |
| 902 | &constraint, | |
| 903 | Some(trait_ref.def_id()), | |
| 904 | None, | |
| 905 | ); | |
| 889 | 906 | } |
| 890 | 907 | diag |
| 891 | 908 | } |
| ... | ... | @@ -2708,7 +2725,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> { |
| 2708 | 2725 | fn predicate_can_apply( |
| 2709 | 2726 | &self, |
| 2710 | 2727 | param_env: ty::ParamEnv<'tcx>, |
| 2711 | pred: ty::PolyTraitPredicate<'tcx>, | |
| 2728 | pred: impl Upcast<TyCtxt<'tcx>, ty::Predicate<'tcx>> + TypeFoldable<TyCtxt<'tcx>>, | |
| 2712 | 2729 | ) -> bool { |
| 2713 | 2730 | struct ParamToVarFolder<'a, 'tcx> { |
| 2714 | 2731 | infcx: &'a InferCtxt<'tcx>, |
compiler/rustc_type_ir/src/error.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | use derive_where::derive_where; |
| 2 | use rustc_abi::ExternAbi; | |
| 2 | 3 | use rustc_type_ir_macros::{GenericTypeVisitable, TypeFoldable_Generic, TypeVisitable_Generic}; |
| 3 | 4 | |
| 4 | 5 | use crate::solve::NoSolution; |
| ... | ... | @@ -25,7 +26,7 @@ pub enum TypeError<I: Interner> { |
| 25 | 26 | Mismatch, |
| 26 | 27 | PolarityMismatch(#[type_visitable(ignore)] ExpectedFound<ty::PredicatePolarity>), |
| 27 | 28 | SafetyMismatch(#[type_visitable(ignore)] ExpectedFound<I::Safety>), |
| 28 | AbiMismatch(#[type_visitable(ignore)] ExpectedFound<I::Abi>), | |
| 29 | AbiMismatch(#[type_visitable(ignore)] ExpectedFound<ExternAbi>), | |
| 29 | 30 | Mutability, |
| 30 | 31 | ArgumentMutability(usize), |
| 31 | 32 | TupleSize(ExpectedFound<usize>), |
compiler/rustc_type_ir/src/generic_visit.rs+7| ... | ... | @@ -15,6 +15,8 @@ use rustc_index::{Idx, IndexVec}; |
| 15 | 15 | use smallvec::SmallVec; |
| 16 | 16 | use thin_vec::ThinVec; |
| 17 | 17 | |
| 18 | use crate::Interner; | |
| 19 | ||
| 18 | 20 | /// This trait is implemented for every type that can be visited, |
| 19 | 21 | /// providing the skeleton of the traversal. |
| 20 | 22 | /// |
| ... | ... | @@ -210,4 +212,9 @@ trivial_impls!( |
| 210 | 212 | rustc_hash::FxBuildHasher, |
| 211 | 213 | crate::TypeFlags, |
| 212 | 214 | crate::solve::GoalSource, |
| 215 | rustc_abi::ExternAbi, | |
| 213 | 216 | ); |
| 217 | ||
| 218 | impl<I: Interner, V> GenericTypeVisitable<V> for crate::FnSigKind<I> { | |
| 219 | fn generic_visit_with(&self, _visitor: &mut V) {} | |
| 220 | } |
compiler/rustc_type_ir/src/inherent.rs-36| ... | ... | @@ -205,42 +205,6 @@ pub trait Tys<I: Interner<Tys = Self>>: |
| 205 | 205 | fn output(self) -> I::Ty; |
| 206 | 206 | } |
| 207 | 207 | |
| 208 | #[rust_analyzer::prefer_underscore_import] | |
| 209 | pub trait FSigKind<I: Interner<FSigKind = Self>>: Copy + Debug + Hash + Eq { | |
| 210 | /// The identity function. | |
| 211 | fn fn_sig_kind(self) -> Self; | |
| 212 | ||
| 213 | /// Create a new FnSigKind with the given ABI, safety, and C-style variadic flag. | |
| 214 | fn new(abi: I::Abi, safety: I::Safety, c_variadic: bool) -> Self; | |
| 215 | ||
| 216 | /// Returns the ABI. | |
| 217 | fn abi(self) -> I::Abi; | |
| 218 | ||
| 219 | /// Returns the safety mode. | |
| 220 | fn safety(self) -> I::Safety; | |
| 221 | ||
| 222 | /// Do the function arguments end with a C-style variadic argument? | |
| 223 | fn c_variadic(self) -> bool; | |
| 224 | } | |
| 225 | ||
| 226 | #[rust_analyzer::prefer_underscore_import] | |
| 227 | pub trait Abi<I: Interner<Abi = Self>>: Copy + Debug + Hash + Eq { | |
| 228 | /// The identity function. | |
| 229 | fn abi(self) -> Self; | |
| 230 | ||
| 231 | /// The ABI `extern "Rust"`. | |
| 232 | fn rust() -> I::Abi; | |
| 233 | ||
| 234 | /// Whether this ABI is `extern "Rust"`. | |
| 235 | fn is_rust(self) -> bool; | |
| 236 | ||
| 237 | /// Pack the ABI into a small dense integer, so it can be stored as packed `FnSigKind` flags. | |
| 238 | fn pack_abi(self) -> u8; | |
| 239 | ||
| 240 | /// Unpack the ABI from packed `FnSigKind` flags. | |
| 241 | fn unpack_abi(abi_index: u8) -> Self; | |
| 242 | } | |
| 243 | ||
| 244 | 208 | #[rust_analyzer::prefer_underscore_import] |
| 245 | 209 | pub trait Safety<I: Interner<Safety = Self>>: Copy + Debug + Hash + Eq { |
| 246 | 210 | /// The `safe` safety mode. |
compiler/rustc_type_ir/src/interner.rs-2| ... | ... | @@ -145,9 +145,7 @@ pub trait Interner: |
| 145 | 145 | + Eq |
| 146 | 146 | + TypeVisitable<Self> |
| 147 | 147 | + SliceLike<Item = Self::Pat>; |
| 148 | type FSigKind: FSigKind<Self>; | |
| 149 | 148 | type Safety: Safety<Self>; |
| 150 | type Abi: Abi<Self>; | |
| 151 | 149 | |
| 152 | 150 | // Kinds of consts |
| 153 | 151 | type Const: Const<Self>; |
compiler/rustc_type_ir/src/ty_kind.rs+52-32| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | 1 | use std::fmt; |
| 2 | use std::marker::PhantomData; | |
| 2 | 3 | use std::ops::Deref; |
| 3 | 4 | |
| 4 | 5 | use derive_where::derive_where; |
| ... | ... | @@ -762,18 +763,31 @@ impl<I: Interner> Eq for TypeAndMut<I> {} |
| 762 | 763 | |
| 763 | 764 | /// Contains the packed non-type fields of a function signature. |
| 764 | 765 | // FIXME(splat): add the splatted argument index as a u16 |
| 765 | #[derive(Copy, Clone, PartialEq, Eq, Hash)] | |
| 766 | #[derive_where(Copy, Clone, PartialEq, Eq, Hash; I: Interner)] | |
| 767 | #[derive(TypeVisitable_Generic, TypeFoldable_Generic)] | |
| 766 | 768 | #[cfg_attr( |
| 767 | 769 | feature = "nightly", |
| 768 | 770 | derive(Encodable_NoContext, Decodable_NoContext, HashStable_NoContext) |
| 769 | 771 | )] |
| 770 | pub struct FnSigKind { | |
| 772 | pub struct FnSigKind<I: Interner> { | |
| 771 | 773 | /// Holds the c_variadic and safety bitflags, and 6 bits for the `ExternAbi` variant and unwind |
| 772 | 774 | /// flag. |
| 775 | #[type_visitable(ignore)] | |
| 776 | #[type_foldable(identity)] | |
| 773 | 777 | flags: u8, |
| 778 | #[type_visitable(ignore)] | |
| 779 | #[type_foldable(identity)] | |
| 780 | _marker: PhantomData<fn() -> I>, | |
| 774 | 781 | } |
| 775 | 782 | |
| 776 | impl fmt::Debug for FnSigKind { | |
| 783 | impl<I: Interner, J: Interner> crate::lift::Lift<J> for FnSigKind<I> { | |
| 784 | type Lifted = FnSigKind<J>; | |
| 785 | fn lift_to_interner(self, _cx: J) -> Option<Self::Lifted> { | |
| 786 | Some(FnSigKind { flags: self.flags, _marker: PhantomData }) | |
| 787 | } | |
| 788 | } | |
| 789 | ||
| 790 | impl<I: Interner> fmt::Debug for FnSigKind<I> { | |
| 777 | 791 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 778 | 792 | let mut f = f.debug_tuple("FnSigKind"); |
| 779 | 793 | |
| ... | ... | @@ -793,7 +807,7 @@ impl fmt::Debug for FnSigKind { |
| 793 | 807 | } |
| 794 | 808 | } |
| 795 | 809 | |
| 796 | impl FnSigKind { | |
| 810 | impl<I: Interner> FnSigKind<I> { | |
| 797 | 811 | /// Mask for the `ExternAbi` variant, including the unwind flag. |
| 798 | 812 | const EXTERN_ABI_MASK: u8 = 0b111111; |
| 799 | 813 | |
| ... | ... | @@ -806,13 +820,21 @@ impl FnSigKind { |
| 806 | 820 | /// Create a new FnSigKind with the "Rust" ABI, "Unsafe" safety, and no C-style variadic argument. |
| 807 | 821 | /// To modify these flags, use the `set_*` methods, for readability. |
| 808 | 822 | // FIXME: use Default instead when that trait is const stable. |
| 809 | pub const fn default() -> Self { | |
| 810 | Self { flags: 0 }.set_abi(ExternAbi::Rust).set_safe(false).set_c_variadic(false) | |
| 823 | pub fn default() -> Self { | |
| 824 | Self { flags: 0, _marker: PhantomData } | |
| 825 | .set_abi(ExternAbi::Rust) | |
| 826 | .set_safety(I::Safety::unsafe_mode()) | |
| 827 | .set_c_variadic(false) | |
| 828 | } | |
| 829 | ||
| 830 | /// Create a new FnSigKind with the given ABI, safety, and C-style variadic flag. | |
| 831 | pub fn new(abi: ExternAbi, safety: I::Safety, c_variadic: bool) -> Self { | |
| 832 | Self::default().set_abi(abi).set_safety(safety).set_c_variadic(c_variadic) | |
| 811 | 833 | } |
| 812 | 834 | |
| 813 | 835 | /// Set the ABI, including the unwind flag. |
| 814 | 836 | #[must_use = "this method does not modify the receiver"] |
| 815 | pub const fn set_abi(mut self, abi: ExternAbi) -> Self { | |
| 837 | pub fn set_abi(mut self, abi: ExternAbi) -> Self { | |
| 816 | 838 | let abi_index = abi.as_packed(); |
| 817 | 839 | assert!(abi_index <= Self::EXTERN_ABI_MASK); |
| 818 | 840 | |
| ... | ... | @@ -824,8 +846,8 @@ impl FnSigKind { |
| 824 | 846 | |
| 825 | 847 | /// Set the safety flag, `true` is `Safe`. |
| 826 | 848 | #[must_use = "this method does not modify the receiver"] |
| 827 | pub const fn set_safe(mut self, is_safe: bool) -> Self { | |
| 828 | if is_safe { | |
| 849 | pub fn set_safety(mut self, safety: I::Safety) -> Self { | |
| 850 | if safety.is_safe() { | |
| 829 | 851 | self.flags |= Self::SAFE_FLAG; |
| 830 | 852 | } else { |
| 831 | 853 | self.flags &= !Self::SAFE_FLAG; |
| ... | ... | @@ -836,7 +858,7 @@ impl FnSigKind { |
| 836 | 858 | |
| 837 | 859 | /// Set the C-style variadic argument flag. |
| 838 | 860 | #[must_use = "this method does not modify the receiver"] |
| 839 | pub const fn set_c_variadic(mut self, c_variadic: bool) -> Self { | |
| 861 | pub fn set_c_variadic(mut self, c_variadic: bool) -> Self { | |
| 840 | 862 | if c_variadic { |
| 841 | 863 | self.flags |= Self::C_VARIADIC_FLAG; |
| 842 | 864 | } else { |
| ... | ... | @@ -847,18 +869,23 @@ impl FnSigKind { |
| 847 | 869 | } |
| 848 | 870 | |
| 849 | 871 | /// Get the ABI, including the unwind flag. |
| 850 | pub const fn abi(self) -> ExternAbi { | |
| 872 | pub fn abi(self) -> ExternAbi { | |
| 851 | 873 | let abi_index = self.flags & Self::EXTERN_ABI_MASK; |
| 852 | 874 | ExternAbi::from_packed(abi_index) |
| 853 | 875 | } |
| 854 | 876 | |
| 855 | 877 | /// Get the safety flag. |
| 856 | pub const fn is_safe(self) -> bool { | |
| 878 | pub fn is_safe(self) -> bool { | |
| 857 | 879 | self.flags & Self::SAFE_FLAG != 0 |
| 858 | 880 | } |
| 859 | 881 | |
| 882 | /// Returns the safety mode. | |
| 883 | pub fn safety(self) -> I::Safety { | |
| 884 | if self.is_safe() { I::Safety::safe() } else { I::Safety::unsafe_mode() } | |
| 885 | } | |
| 886 | ||
| 860 | 887 | /// Do the function arguments end with a C-style variadic argument? |
| 861 | pub const fn c_variadic(self) -> bool { | |
| 888 | pub fn c_variadic(self) -> bool { | |
| 862 | 889 | self.flags & Self::C_VARIADIC_FLAG != 0 |
| 863 | 890 | } |
| 864 | 891 | } |
| ... | ... | @@ -873,7 +900,7 @@ pub struct FnSig<I: Interner> { |
| 873 | 900 | pub inputs_and_output: I::Tys, |
| 874 | 901 | #[type_visitable(ignore)] |
| 875 | 902 | #[type_foldable(identity)] |
| 876 | pub fn_sig_kind: I::FSigKind, | |
| 903 | pub fn_sig_kind: FnSigKind<I>, | |
| 877 | 904 | } |
| 878 | 905 | |
| 879 | 906 | impl<I: Interner> Eq for FnSig<I> {} |
| ... | ... | @@ -888,25 +915,18 @@ impl<I: Interner> FnSig<I> { |
| 888 | 915 | } |
| 889 | 916 | |
| 890 | 917 | pub fn is_fn_trait_compatible(self) -> bool { |
| 891 | !self.c_variadic() && self.safety().is_safe() && self.abi().is_rust() | |
| 918 | !self.c_variadic() && self.safety().is_safe() && self.abi() == ExternAbi::Rust | |
| 892 | 919 | } |
| 893 | 920 | |
| 894 | pub fn set_safe(self, is_safe: bool) -> Self { | |
| 895 | Self { | |
| 896 | fn_sig_kind: I::FSigKind::new( | |
| 897 | self.abi(), | |
| 898 | if is_safe { I::Safety::safe() } else { I::Safety::unsafe_mode() }, | |
| 899 | self.c_variadic(), | |
| 900 | ), | |
| 901 | ..self | |
| 902 | } | |
| 921 | pub fn set_safety(self, safety: I::Safety) -> Self { | |
| 922 | Self { fn_sig_kind: FnSigKind::new(self.abi(), safety, self.c_variadic()), ..self } | |
| 903 | 923 | } |
| 904 | 924 | |
| 905 | 925 | pub fn safety(self) -> I::Safety { |
| 906 | 926 | self.fn_sig_kind.safety() |
| 907 | 927 | } |
| 908 | 928 | |
| 909 | pub fn abi(self) -> I::Abi { | |
| 929 | pub fn abi(self) -> ExternAbi { | |
| 910 | 930 | self.fn_sig_kind.abi() |
| 911 | 931 | } |
| 912 | 932 | |
| ... | ... | @@ -917,7 +937,7 @@ impl<I: Interner> FnSig<I> { |
| 917 | 937 | pub fn dummy() -> Self { |
| 918 | 938 | Self { |
| 919 | 939 | inputs_and_output: Default::default(), |
| 920 | fn_sig_kind: I::FSigKind::new(I::Abi::rust(), I::Safety::safe(), false), | |
| 940 | fn_sig_kind: FnSigKind::new(ExternAbi::Rust, I::Safety::safe(), false), | |
| 921 | 941 | } |
| 922 | 942 | } |
| 923 | 943 | } |
| ... | ... | @@ -943,7 +963,7 @@ impl<I: Interner> ty::Binder<I, FnSig<I>> { |
| 943 | 963 | self.map_bound(|fn_sig| fn_sig.output()) |
| 944 | 964 | } |
| 945 | 965 | |
| 946 | pub fn fn_sig_kind(self) -> I::FSigKind { | |
| 966 | pub fn fn_sig_kind(self) -> FnSigKind<I> { | |
| 947 | 967 | self.skip_binder().fn_sig_kind |
| 948 | 968 | } |
| 949 | 969 | |
| ... | ... | @@ -955,7 +975,7 @@ impl<I: Interner> ty::Binder<I, FnSig<I>> { |
| 955 | 975 | self.skip_binder().safety() |
| 956 | 976 | } |
| 957 | 977 | |
| 958 | pub fn abi(self) -> I::Abi { | |
| 978 | pub fn abi(self) -> ExternAbi { | |
| 959 | 979 | self.skip_binder().abi() |
| 960 | 980 | } |
| 961 | 981 | |
| ... | ... | @@ -976,7 +996,7 @@ impl<I: Interner> fmt::Debug for FnSig<I> { |
| 976 | 996 | let FnSig { inputs_and_output: _, fn_sig_kind } = sig; |
| 977 | 997 | |
| 978 | 998 | write!(f, "{}", fn_sig_kind.safety().prefix_str())?; |
| 979 | if !fn_sig_kind.abi().is_rust() { | |
| 999 | if fn_sig_kind.abi() != ExternAbi::Rust { | |
| 980 | 1000 | write!(f, "extern \"{:?}\" ", fn_sig_kind.abi())?; |
| 981 | 1001 | } |
| 982 | 1002 | |
| ... | ... | @@ -1131,7 +1151,7 @@ impl<I: Interner> ty::Binder<I, FnSigTys<I>> { |
| 1131 | 1151 | pub struct FnHeader<I: Interner> { |
| 1132 | 1152 | #[type_visitable(ignore)] |
| 1133 | 1153 | #[type_foldable(identity)] |
| 1134 | pub fn_sig_kind: I::FSigKind, | |
| 1154 | pub fn_sig_kind: FnSigKind<I>, | |
| 1135 | 1155 | } |
| 1136 | 1156 | |
| 1137 | 1157 | impl<I: Interner> FnHeader<I> { |
| ... | ... | @@ -1143,12 +1163,12 @@ impl<I: Interner> FnHeader<I> { |
| 1143 | 1163 | self.fn_sig_kind.safety() |
| 1144 | 1164 | } |
| 1145 | 1165 | |
| 1146 | pub fn abi(self) -> I::Abi { | |
| 1166 | pub fn abi(self) -> ExternAbi { | |
| 1147 | 1167 | self.fn_sig_kind.abi() |
| 1148 | 1168 | } |
| 1149 | 1169 | |
| 1150 | 1170 | pub fn dummy() -> Self { |
| 1151 | Self { fn_sig_kind: I::FSigKind::new(I::Abi::rust(), I::Safety::safe(), false) } | |
| 1171 | Self { fn_sig_kind: FnSigKind::new(ExternAbi::Rust, I::Safety::safe(), false) } | |
| 1152 | 1172 | } |
| 1153 | 1173 | } |
| 1154 | 1174 |
compiler/rustc_type_ir/src/ty_kind/closure.rs+2-2| ... | ... | @@ -9,7 +9,7 @@ use crate::data_structures::DelayedMap; |
| 9 | 9 | use crate::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable, shift_region}; |
| 10 | 10 | use crate::inherent::*; |
| 11 | 11 | use crate::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; |
| 12 | use crate::{self as ty, Interner}; | |
| 12 | use crate::{self as ty, FnSigKind, Interner}; | |
| 13 | 13 | |
| 14 | 14 | /// A closure can be modeled as a struct that looks like: |
| 15 | 15 | /// ```ignore (illustrative) |
| ... | ... | @@ -367,7 +367,7 @@ pub struct CoroutineClosureSignature<I: Interner> { |
| 367 | 367 | /// Always safe, RustCall, non-c-variadic |
| 368 | 368 | #[type_visitable(ignore)] |
| 369 | 369 | #[type_foldable(identity)] |
| 370 | pub fn_sig_kind: I::FSigKind, | |
| 370 | pub fn_sig_kind: FnSigKind<I>, | |
| 371 | 371 | } |
| 372 | 372 | |
| 373 | 373 | impl<I: Interner> Eq for CoroutineClosureSignature<I> {} |
library/core/src/ffi/va_list.rs+14-4| ... | ... | @@ -390,11 +390,21 @@ impl<'f> VaList<'f> { |
| 390 | 390 | /// |
| 391 | 391 | /// # Safety |
| 392 | 392 | /// |
| 393 | /// This function is only sound to call when there is another argument to read, and that | |
| 394 | /// argument is a properly initialized value of the type `T`. | |
| 393 | /// This function is safe to call only if all of the following conditions are satisfied: | |
| 395 | 394 | /// |
| 396 | /// Calling this function with an incompatible type, an invalid value, or when there | |
| 397 | /// are no more variable arguments, is unsound. | |
| 395 | /// - There is another c-variadic argument to read. | |
| 396 | /// - The actual type of the argument `U` is compatible with `T` (as defined below). | |
| 397 | /// - If `U` and `T` are both integer types, then the value passed by the caller must be | |
| 398 | /// representable in both types. | |
| 399 | /// | |
| 400 | /// Types `T` and `U` are compatible when: | |
| 401 | /// | |
| 402 | /// - `T` and `U` are the same type. | |
| 403 | /// - `T` and `U` are integer types of the same size. | |
| 404 | /// - `T` and `U` are both pointers, and their target types are compatible. | |
| 405 | /// - `T` is a pointer to [`c_void`] and `U` is a pointer to [`i8`] or [`u8`], or vice versa. | |
| 406 | /// | |
| 407 | /// [`c_void`]: core::ffi::c_void | |
| 398 | 408 | #[inline] // Avoid codegen when not used to help backends that don't support VaList. |
| 399 | 409 | #[rustc_const_unstable(feature = "const_c_variadic", issue = "151787")] |
| 400 | 410 | pub const unsafe fn next_arg<T: VaArgSafe>(&mut self) -> T { |
library/core/src/intrinsics/simd/mod.rs+7-11| ... | ... | @@ -520,7 +520,7 @@ pub unsafe fn simd_reduce_mul_unordered<T, U>(x: T) -> U; |
| 520 | 520 | |
| 521 | 521 | /// Checks if all mask values are true. |
| 522 | 522 | /// |
| 523 | /// `T` must be a vector of integer primitive types. | |
| 523 | /// `T` must be a vector of integers. | |
| 524 | 524 | /// |
| 525 | 525 | /// # Safety |
| 526 | 526 | /// `x` must contain only `0` or `!0`. |
| ... | ... | @@ -530,7 +530,7 @@ pub const unsafe fn simd_reduce_all<T>(x: T) -> bool; |
| 530 | 530 | |
| 531 | 531 | /// Checks if any mask value is true. |
| 532 | 532 | /// |
| 533 | /// `T` must be a vector of integer primitive types. | |
| 533 | /// `T` must be a vector of integers. | |
| 534 | 534 | /// |
| 535 | 535 | /// # Safety |
| 536 | 536 | /// `x` must contain only `0` or `!0`. |
| ... | ... | @@ -540,29 +540,25 @@ pub const unsafe fn simd_reduce_any<T>(x: T) -> bool; |
| 540 | 540 | |
| 541 | 541 | /// Returns the maximum element of a vector. |
| 542 | 542 | /// |
| 543 | /// `T` must be a vector of integers or floats. | |
| 543 | /// `T` must be a vector of integers. | |
| 544 | 544 | /// |
| 545 | 545 | /// `U` must be the element type of `T`. |
| 546 | /// | |
| 547 | /// For floating-point values, uses IEEE-754 `maxNum`. | |
| 548 | 546 | #[rustc_intrinsic] |
| 549 | 547 | #[rustc_nounwind] |
| 550 | 548 | pub const unsafe fn simd_reduce_max<T, U>(x: T) -> U; |
| 551 | 549 | |
| 552 | 550 | /// Returns the minimum element of a vector. |
| 553 | 551 | /// |
| 554 | /// `T` must be a vector of integers or floats. | |
| 552 | /// `T` must be a vector of integers. | |
| 555 | 553 | /// |
| 556 | 554 | /// `U` must be the element type of `T`. |
| 557 | /// | |
| 558 | /// For floating-point values, uses IEEE-754 `minNum`. | |
| 559 | 555 | #[rustc_intrinsic] |
| 560 | 556 | #[rustc_nounwind] |
| 561 | 557 | pub const unsafe fn simd_reduce_min<T, U>(x: T) -> U; |
| 562 | 558 | |
| 563 | 559 | /// Logical "and"s all elements together. |
| 564 | 560 | /// |
| 565 | /// `T` must be a vector of integers or floats. | |
| 561 | /// `T` must be a vector of integers. | |
| 566 | 562 | /// |
| 567 | 563 | /// `U` must be the element type of `T`. |
| 568 | 564 | #[rustc_intrinsic] |
| ... | ... | @@ -571,7 +567,7 @@ pub const unsafe fn simd_reduce_and<T, U>(x: T) -> U; |
| 571 | 567 | |
| 572 | 568 | /// Logical "ors" all elements together. |
| 573 | 569 | /// |
| 574 | /// `T` must be a vector of integers or floats. | |
| 570 | /// `T` must be a vector of integers. | |
| 575 | 571 | /// |
| 576 | 572 | /// `U` must be the element type of `T`. |
| 577 | 573 | #[rustc_intrinsic] |
| ... | ... | @@ -580,7 +576,7 @@ pub const unsafe fn simd_reduce_or<T, U>(x: T) -> U; |
| 580 | 576 | |
| 581 | 577 | /// Logical "exclusive ors" all elements together. |
| 582 | 578 | /// |
| 583 | /// `T` must be a vector of integers or floats. | |
| 579 | /// `T` must be a vector of integers. | |
| 584 | 580 | /// |
| 585 | 581 | /// `U` must be the element type of `T`. |
| 586 | 582 | #[rustc_intrinsic] |
library/std_detect/src/detect/os/windows/aarch64.rs+53-5| ... | ... | @@ -31,8 +31,14 @@ pub(crate) fn detect_features() -> cache::Initializer { |
| 31 | 31 | const PF_ARM_SVE_SHA3_INSTRUCTIONS_AVAILABLE: u32 = 55; |
| 32 | 32 | const PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE: u32 = 56; |
| 33 | 33 | // const PF_ARM_SVE_I8MM_INSTRUCTIONS_AVAILABLE: u32 = 57; |
| 34 | // const PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE: u32 = 58; | |
| 35 | // const PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE: u32 = 59; | |
| 34 | const PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE: u32 = 58; | |
| 35 | const PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE: u32 = 59; | |
| 36 | const PF_ARM_LSE2_AVAILABLE: u32 = 62; | |
| 37 | const PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE: u32 = 64; | |
| 38 | const PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE: u32 = 65; | |
| 39 | const PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE: u32 = 66; | |
| 40 | const PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE: u32 = 67; | |
| 41 | const PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE: u32 = 68; | |
| 36 | 42 | |
| 37 | 43 | unsafe extern "system" { |
| 38 | 44 | fn IsProcessorFeaturePresent(ProcessorFeature: DWORD) -> BOOL; |
| ... | ... | @@ -46,9 +52,11 @@ pub(crate) fn detect_features() -> cache::Initializer { |
| 46 | 52 | } |
| 47 | 53 | }; |
| 48 | 54 | |
| 49 | // Some features may be supported on current CPU, | |
| 50 | // but no way to detect it by OS API. | |
| 51 | // Also, we require unsafe block for the extern "system" calls. | |
| 55 | // Some features may be supported on the current CPU but have no | |
| 56 | // detection path through the Win32 API; those report `false`. | |
| 57 | // SAFETY: `IsProcessorFeaturePresent` is a Win32 entry point taking a | |
| 58 | // `DWORD` by value and returning a `BOOL`. No pointer parameters, | |
| 59 | // no out-parameters, no thread-safety constraints. | |
| 52 | 60 | unsafe { |
| 53 | 61 | enable_feature( |
| 54 | 62 | Feature::fp, |
| ... | ... | @@ -112,6 +120,46 @@ pub(crate) fn detect_features() -> cache::Initializer { |
| 112 | 120 | Feature::sve2_sm4, |
| 113 | 121 | IsProcessorFeaturePresent(PF_ARM_SVE_SM4_INSTRUCTIONS_AVAILABLE) != FALSE, |
| 114 | 122 | ); |
| 123 | enable_feature( | |
| 124 | Feature::f32mm, | |
| 125 | IsProcessorFeaturePresent(PF_ARM_SVE_F32MM_INSTRUCTIONS_AVAILABLE) != FALSE, | |
| 126 | ); | |
| 127 | enable_feature( | |
| 128 | Feature::f64mm, | |
| 129 | IsProcessorFeaturePresent(PF_ARM_SVE_F64MM_INSTRUCTIONS_AVAILABLE) != FALSE, | |
| 130 | ); | |
| 131 | enable_feature( | |
| 132 | Feature::lse2, | |
| 133 | IsProcessorFeaturePresent(PF_ARM_LSE2_AVAILABLE) != FALSE, | |
| 134 | ); | |
| 135 | enable_feature( | |
| 136 | Feature::fp16, | |
| 137 | IsProcessorFeaturePresent(PF_ARM_V82_FP16_INSTRUCTIONS_AVAILABLE) != FALSE, | |
| 138 | ); | |
| 139 | enable_feature( | |
| 140 | Feature::i8mm, | |
| 141 | IsProcessorFeaturePresent(PF_ARM_V82_I8MM_INSTRUCTIONS_AVAILABLE) != FALSE, | |
| 142 | ); | |
| 143 | enable_feature( | |
| 144 | Feature::bf16, | |
| 145 | IsProcessorFeaturePresent(PF_ARM_V86_BF16_INSTRUCTIONS_AVAILABLE) != FALSE, | |
| 146 | ); | |
| 147 | // stdarch `sha3` is FEAT_SHA3 + FEAT_SHA512 together; Windows | |
| 148 | // exposes them as two separate flags. | |
| 149 | enable_feature( | |
| 150 | Feature::sha3, | |
| 151 | IsProcessorFeaturePresent(PF_ARM_SHA3_INSTRUCTIONS_AVAILABLE) != FALSE | |
| 152 | && IsProcessorFeaturePresent(PF_ARM_SHA512_INSTRUCTIONS_AVAILABLE) != FALSE, | |
| 153 | ); | |
| 154 | // No PF_ARM_RDM_* constant exists. Derive FEAT_RDM from FEAT_DotProd: | |
| 155 | // DotProd is an optional v8.2-A feature only present on cores that | |
| 156 | // implement at least v8.1-A; v8.1-A with AdvSIMD mandates FEAT_RDM | |
| 157 | // (Arm ARM K.a §D17.2.91), and AdvSIMD is universal on Windows-on-ARM. | |
| 158 | // Same inference shipped in .NET 10 (dotnet/runtime PR 109493). | |
| 159 | enable_feature( | |
| 160 | Feature::rdm, | |
| 161 | IsProcessorFeaturePresent(PF_ARM_V82_DP_INSTRUCTIONS_AVAILABLE) != FALSE, | |
| 162 | ); | |
| 115 | 163 | // PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE means aes, sha1, sha2 and |
| 116 | 164 | // pmull support |
| 117 | 165 | let crypto = |
library/std_detect/tests/cpu-detection.rs+8| ... | ... | @@ -150,14 +150,22 @@ fn aarch64_linux() { |
| 150 | 150 | fn aarch64_windows() { |
| 151 | 151 | println!("asimd: {:?}", is_aarch64_feature_detected!("asimd")); |
| 152 | 152 | println!("fp: {:?}", is_aarch64_feature_detected!("fp")); |
| 153 | println!("fp16: {:?}", is_aarch64_feature_detected!("fp16")); | |
| 153 | 154 | println!("crc: {:?}", is_aarch64_feature_detected!("crc")); |
| 154 | 155 | println!("lse: {:?}", is_aarch64_feature_detected!("lse")); |
| 156 | println!("lse2: {:?}", is_aarch64_feature_detected!("lse2")); | |
| 157 | println!("rdm: {:?}", is_aarch64_feature_detected!("rdm")); | |
| 155 | 158 | println!("dotprod: {:?}", is_aarch64_feature_detected!("dotprod")); |
| 159 | println!("i8mm: {:?}", is_aarch64_feature_detected!("i8mm")); | |
| 160 | println!("bf16: {:?}", is_aarch64_feature_detected!("bf16")); | |
| 156 | 161 | println!("jsconv: {:?}", is_aarch64_feature_detected!("jsconv")); |
| 157 | 162 | println!("rcpc: {:?}", is_aarch64_feature_detected!("rcpc")); |
| 158 | 163 | println!("aes: {:?}", is_aarch64_feature_detected!("aes")); |
| 159 | 164 | println!("pmull: {:?}", is_aarch64_feature_detected!("pmull")); |
| 160 | 165 | println!("sha2: {:?}", is_aarch64_feature_detected!("sha2")); |
| 166 | println!("sha3: {:?}", is_aarch64_feature_detected!("sha3")); | |
| 167 | println!("f32mm: {:?}", is_aarch64_feature_detected!("f32mm")); | |
| 168 | println!("f64mm: {:?}", is_aarch64_feature_detected!("f64mm")); | |
| 161 | 169 | } |
| 162 | 170 | |
| 163 | 171 | #[test] |
src/bootstrap/src/core/builder/cargo.rs+4| ... | ... | @@ -1073,6 +1073,8 @@ impl Builder<'_> { |
| 1073 | 1073 | // rustc creates absolute paths (in part bc of the `rust-src` unremap |
| 1074 | 1074 | // and for working directory) so let's remap the build directory as well. |
| 1075 | 1075 | format!("{}={map_to}", self.build.src.display()), |
| 1076 | // remap OUT_DIR so they don't leak into artifacts. | |
| 1077 | format!("{}={map_to}/out", self.build.out.display()), | |
| 1076 | 1078 | ] |
| 1077 | 1079 | .join("\t"); |
| 1078 | 1080 | cargo.env("RUSTC_DEBUGINFO_MAP", map); |
| ... | ... | @@ -1093,6 +1095,8 @@ impl Builder<'_> { |
| 1093 | 1095 | // rustc creates absolute paths (in part bc of the `rust-src` unremap |
| 1094 | 1096 | // and for working directory) so let's remap the build directory as well. |
| 1095 | 1097 | format!("{}={map_to}", self.build.src.display()), |
| 1098 | // remap OUT_DIR so they don't leak into artifacts. | |
| 1099 | format!("{}={map_to}/out", self.build.out.display()), | |
| 1096 | 1100 | ] |
| 1097 | 1101 | .join("\t"); |
| 1098 | 1102 | cargo.env("RUSTC_DEBUGINFO_MAP", map); |
src/ci/scripts/free-disk-space-linux.sh+85-24| ... | ... | @@ -96,15 +96,11 @@ removeUnusedFilesAndDirs() { |
| 96 | 96 | ) |
| 97 | 97 | |
| 98 | 98 | if isGitHubRunner; then |
| 99 | # Paths common to all runners (both x86 and ARM) | |
| 99 | 100 | to_remove+=( |
| 100 | 101 | "/usr/local/aws-sam-cli" |
| 101 | 102 | "/usr/local/doc/cmake" |
| 102 | "/usr/local/julia"* | |
| 103 | "/usr/local/lib/android" | |
| 104 | "/usr/local/share/chromedriver-"* | |
| 105 | "/usr/local/share/chromium" | |
| 106 | 103 | "/usr/local/share/cmake-"* |
| 107 | "/usr/local/share/edge_driver" | |
| 108 | 104 | "/usr/local/share/emacs" |
| 109 | 105 | "/usr/local/share/gecko_driver" |
| 110 | 106 | "/usr/local/share/icons" |
| ... | ... | @@ -112,16 +108,13 @@ removeUnusedFilesAndDirs() { |
| 112 | 108 | "/usr/local/share/vcpkg" |
| 113 | 109 | "/usr/local/share/vim" |
| 114 | 110 | "/usr/share/apache-maven-"* |
| 115 | "/usr/share/gradle-"* | |
| 116 | 111 | "/usr/share/kotlinc" |
| 117 | "/usr/share/miniconda" | |
| 118 | 112 | "/usr/share/php" |
| 119 | 113 | "/usr/share/ri" |
| 120 | 114 | "/usr/share/swift" |
| 121 | 115 | |
| 122 | 116 | # binaries |
| 123 | 117 | "/usr/local/bin/azcopy" |
| 124 | "/usr/local/bin/bicep" | |
| 125 | 118 | "/usr/local/bin/ccmake" |
| 126 | 119 | "/usr/local/bin/cmake-"* |
| 127 | 120 | "/usr/local/bin/cmake" |
| ... | ... | @@ -135,16 +128,53 @@ removeUnusedFilesAndDirs() { |
| 135 | 128 | "/usr/local/bin/phpunit" |
| 136 | 129 | "/usr/local/bin/pulumi-"* |
| 137 | 130 | "/usr/local/bin/pulumi" |
| 138 | "/usr/local/bin/stack" | |
| 139 | ||
| 140 | # Haskell runtime | |
| 141 | "/usr/local/.ghcup" | |
| 142 | 131 | |
| 143 | 132 | # Azure |
| 144 | 133 | "/opt/az" |
| 145 | 134 | "/usr/share/az_"* |
| 135 | ||
| 136 | # Microsoft Edge and powershell | |
| 137 | "/opt/microsoft" | |
| 138 | ||
| 139 | "/opt/pipx" | |
| 140 | "/opt/pipx_bin" | |
| 141 | ) | |
| 142 | ||
| 143 | # Paths only present in x86 runners | |
| 144 | local github_runner_x86_paths=( | |
| 145 | "/usr/local/julia"* | |
| 146 | "/usr/local/lib/android" | |
| 147 | "/usr/local/share/chromedriver-"* | |
| 148 | "/usr/local/share/chromium" | |
| 149 | "/usr/local/share/edge_driver" | |
| 150 | "/usr/share/gradle-"* | |
| 151 | "/usr/share/miniconda" | |
| 152 | ||
| 153 | # binaries | |
| 154 | "/usr/local/bin/bicep" | |
| 155 | "/usr/local/bin/stack" | |
| 156 | ||
| 157 | # Haskell runtime | |
| 158 | "/usr/local/.ghcup" | |
| 146 | 159 | ) |
| 147 | 160 | |
| 161 | if isX86; then | |
| 162 | to_remove+=("${github_runner_x86_paths[@]}") | |
| 163 | else | |
| 164 | # warn if x86-only paths are present in other runners | |
| 165 | local existing_github_runner_x86_paths=() | |
| 166 | local x86_path | |
| 167 | for x86_path in "${github_runner_x86_paths[@]}"; do | |
| 168 | if [ -e "$x86_path" ]; then | |
| 169 | existing_github_runner_x86_paths+=("$x86_path") | |
| 170 | fi | |
| 171 | done | |
| 172 | ||
| 173 | if [ "${#existing_github_runner_x86_paths[@]}" -ne 0 ]; then | |
| 174 | echo "::warning::You can remove the following paths to save space: ${existing_github_runner_x86_paths[*]}" | |
| 175 | fi | |
| 176 | fi | |
| 177 | ||
| 148 | 178 | if [ -n "${AGENT_TOOLSDIRECTORY:-}" ]; then |
| 149 | 179 | # Environment variable set by GitHub Actions |
| 150 | 180 | to_remove+=( |
| ... | ... | @@ -201,10 +231,22 @@ cleanPackages() { |
| 201 | 231 | '^dotnet-.*' |
| 202 | 232 | '^llvm-.*' |
| 203 | 233 | '^mongodb-.*' |
| 234 | '^temurin-.*-jdk' | |
| 235 | 'buildah' | |
| 204 | 236 | 'firefox' |
| 237 | 'google-cloud-cli' | |
| 238 | 'google-cloud-sdk' | |
| 239 | 'kubectl' | |
| 205 | 240 | 'libgl1-mesa-dri' |
| 206 | 241 | 'mono-devel' |
| 207 | 242 | 'php.*' |
| 243 | 'podman' | |
| 244 | 'skopeo' | |
| 245 | ) | |
| 246 | local x86_only_packages=( | |
| 247 | 'google-chrome-stable' | |
| 248 | 'microsoft-edge-stable' | |
| 249 | 'powershell' | |
| 208 | 250 | ) |
| 209 | 251 | |
| 210 | 252 | if isGitHubRunner; then |
| ... | ... | @@ -213,12 +255,20 @@ cleanPackages() { |
| 213 | 255 | ) |
| 214 | 256 | |
| 215 | 257 | if isX86; then |
| 216 | packages+=( | |
| 217 | 'google-chrome-stable' | |
| 218 | 'google-cloud-cli' | |
| 219 | 'google-cloud-sdk' | |
| 220 | 'powershell' | |
| 221 | ) | |
| 258 | packages+=("${x86_only_packages[@]}") | |
| 259 | else | |
| 260 | # warn if x86-only packages are installed on other runners | |
| 261 | local installed_x86_only_packages=() | |
| 262 | local package | |
| 263 | for package in "${x86_only_packages[@]}"; do | |
| 264 | if dpkg-query -W -f='${binary:Package}\n' "$package" >/dev/null 2>&1; then | |
| 265 | installed_x86_only_packages+=("$package") | |
| 266 | fi | |
| 267 | done | |
| 268 | ||
| 269 | if [ "${#installed_x86_only_packages[@]}" -ne 0 ]; then | |
| 270 | echo "::warning::You can remove the following packages to save space: ${installed_x86_only_packages[*]}" | |
| 271 | fi | |
| 222 | 272 | fi |
| 223 | 273 | else |
| 224 | 274 | packages+=( |
| ... | ... | @@ -235,11 +285,19 @@ cleanPackages() { |
| 235 | 285 | || echo "::warning::The command [sudo apt-get clean] failed" |
| 236 | 286 | } |
| 237 | 287 | |
| 238 | # Remove Docker images. | |
| 239 | # Ubuntu 22 runners have docker images already installed. | |
| 240 | # They aren't present in ubuntu 24 runners. | |
| 288 | # Remove preinstalled Docker images. | |
| 241 | 289 | cleanDocker() { |
| 290 | local images | |
| 291 | images=$(sudo docker image ls -q) | |
| 292 | ||
| 293 | if [ -z "$images" ]; then | |
| 294 | echo "=> No docker images to remove." | |
| 295 | return | |
| 296 | fi | |
| 297 | ||
| 242 | 298 | echo "=> Removing the following docker images:" |
| 299 | # Use "docker image ls" without "-q" to get the full table output which contains | |
| 300 | # also the image names and sizes. | |
| 243 | 301 | sudo docker image ls |
| 244 | 302 | echo "=> Removing docker images..." |
| 245 | 303 | sudo docker image prune --all --force || true |
| ... | ... | @@ -253,7 +311,8 @@ cleanSwap() { |
| 253 | 311 | } |
| 254 | 312 | |
| 255 | 313 | sufficientSpaceEarlyExit() { |
| 256 | local available_space_kb=$(df -k . --output=avail | tail -n 1) | |
| 314 | local available_space_kb | |
| 315 | available_space_kb=$(df -k . --output=avail | tail -n 1) | |
| 257 | 316 | |
| 258 | 317 | if [ "$available_space_kb" -ge "$space_target_kb" ]; then |
| 259 | 318 | echo "Sufficient disk space available (${available_space_kb}KB >= ${space_target_kb}KB). Skipping cleanup." |
| ... | ... | @@ -267,7 +326,8 @@ sufficientSpaceEarlyExit() { |
| 267 | 326 | checkAlternative() { |
| 268 | 327 | local gha_alt_disk="/mnt" |
| 269 | 328 | |
| 270 | local available_space_kb=$(df -k "$gha_alt_disk" --output=avail | tail -n 1) | |
| 329 | local available_space_kb | |
| 330 | available_space_kb=$(df -k "$gha_alt_disk" --output=avail | tail -n 1) | |
| 271 | 331 | |
| 272 | 332 | # mount options that trade durability for performance |
| 273 | 333 | # ignore-tidy-linelength |
| ... | ... | @@ -276,7 +336,8 @@ checkAlternative() { |
| 276 | 336 | # GHA has a 2nd disk mounted at /mnt that is almost empty. |
| 277 | 337 | # Check if it's a valid mountpoint and it has enough available space. |
| 278 | 338 | if mountpoint "$gha_alt_disk" && [ "$available_space_kb" -ge "$space_target_kb" ]; then |
| 279 | local blkdev=$(df -k "$gha_alt_disk" --output=source | tail -n 1) | |
| 339 | local blkdev | |
| 340 | blkdev=$(df -k "$gha_alt_disk" --output=source | tail -n 1) | |
| 280 | 341 | echo "Sufficient space available on $blkdev mounted at $gha_alt_disk" |
| 281 | 342 | # see cleanSwap(), swapfile may be mounted under /mnt |
| 282 | 343 | sudo swapoff -a || true |
src/librustdoc/clean/mod.rs+10-2| ... | ... | @@ -3260,14 +3260,22 @@ fn clean_maybe_renamed_foreign_item<'tcx>( |
| 3260 | 3260 | hir::ForeignItemKind::Type => ForeignTypeItem, |
| 3261 | 3261 | }; |
| 3262 | 3262 | |
| 3263 | generate_item_with_correct_attrs( | |
| 3263 | let mut clean_item = generate_item_with_correct_attrs( | |
| 3264 | 3264 | cx, |
| 3265 | 3265 | kind, |
| 3266 | 3266 | item.owner_id.def_id.to_def_id(), |
| 3267 | 3267 | item.ident.name, |
| 3268 | 3268 | import_id.as_slice(), |
| 3269 | 3269 | renamed, |
| 3270 | ) | |
| 3270 | ); | |
| 3271 | // We also need to take into account the `extern` block (doc_)cfg attributes. | |
| 3272 | let mut attrs = Attributes::from_hir(inline::load_attrs( | |
| 3273 | cx.tcx, | |
| 3274 | cx.tcx.hir_owner_parent(item.owner_id).owner.to_def_id(), | |
| 3275 | )); | |
| 3276 | attrs.merge_with(std::mem::take(&mut clean_item.inner.attrs)); | |
| 3277 | clean_item.inner.attrs = attrs; | |
| 3278 | clean_item | |
| 3271 | 3279 | }) |
| 3272 | 3280 | } |
| 3273 | 3281 |
src/librustdoc/clean/types.rs+6| ... | ... | @@ -1093,6 +1093,12 @@ impl Attributes { |
| 1093 | 1093 | } |
| 1094 | 1094 | aliases.into_iter().collect::<Vec<_>>().into() |
| 1095 | 1095 | } |
| 1096 | ||
| 1097 | pub(crate) fn merge_with(&mut self, other: Self) { | |
| 1098 | let Self { doc_strings, other_attrs } = other; | |
| 1099 | self.doc_strings.extend(doc_strings); | |
| 1100 | self.other_attrs.extend(other_attrs); | |
| 1101 | } | |
| 1096 | 1102 | } |
| 1097 | 1103 | |
| 1098 | 1104 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
src/tools/miri/README.md+2| ... | ... | @@ -511,6 +511,8 @@ to Miri failing to detect cases of undefined behavior in a program. |
| 511 | 511 | of Rust will be stricter than Tree Borrows. In other words, if you use Tree Borrows, |
| 512 | 512 | even if your code is accepted today, it might be declared UB in the future. |
| 513 | 513 | This is much less likely with Stacked Borrows. |
| 514 | * `-Zmiri-tree-borrows-implicit-writes` enables implicit writes for all `&mut` function arguments. | |
| 515 | This makes Tree Borrows less permissive. | |
| 514 | 516 | * `-Zmiri-tree-borrows-no-precise-interior-mut` makes Tree Borrows |
| 515 | 517 | track interior mutable data on the level of references instead of on the |
| 516 | 518 | byte-level as is done by default. Therefore, with this flag, Tree |
src/tools/miri/src/bin/miri.rs+11| ... | ... | @@ -515,6 +515,7 @@ fn main() -> ExitCode { |
| 515 | 515 | miri_config.borrow_tracker = |
| 516 | 516 | Some(BorrowTrackerMethod::TreeBorrows(TreeBorrowsParams { |
| 517 | 517 | precise_interior_mut: true, |
| 518 | implicit_writes: false, | |
| 518 | 519 | })); |
| 519 | 520 | } else if arg == "-Zmiri-tree-borrows-no-precise-interior-mut" { |
| 520 | 521 | match &mut miri_config.borrow_tracker { |
| ... | ... | @@ -526,6 +527,16 @@ fn main() -> ExitCode { |
| 526 | 527 | "`-Zmiri-tree-borrows` is required before `-Zmiri-tree-borrows-no-precise-interior-mut`" |
| 527 | 528 | ), |
| 528 | 529 | }; |
| 530 | } else if arg == "-Zmiri-tree-borrows-implicit-writes" { | |
| 531 | match &mut miri_config.borrow_tracker { | |
| 532 | Some(BorrowTrackerMethod::TreeBorrows(params)) => { | |
| 533 | params.implicit_writes = true; | |
| 534 | } | |
| 535 | _ => | |
| 536 | fatal_error!( | |
| 537 | "`-Zmiri-tree-borrows` is required before `-Zmiri-tree-borrows-implicit-writes`" | |
| 538 | ), | |
| 539 | }; | |
| 529 | 540 | } else if arg == "-Zmiri-disable-data-race-detector" { |
| 530 | 541 | miri_config.data_race_detector = false; |
| 531 | 542 | miri_config.weak_memory_emulation = false; |
src/tools/miri/src/borrow_tracker/mod.rs+2| ... | ... | @@ -224,6 +224,8 @@ pub enum BorrowTrackerMethod { |
| 224 | 224 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] |
| 225 | 225 | pub struct TreeBorrowsParams { |
| 226 | 226 | pub precise_interior_mut: bool, |
| 227 | /// Controls whether `&mut` function arguments are immediately activated with an implicit write. | |
| 228 | pub implicit_writes: bool, | |
| 227 | 229 | } |
| 228 | 230 | |
| 229 | 231 | impl BorrowTrackerMethod { |
src/tools/miri/src/borrow_tracker/tree_borrows/diagnostics.rs+3-3| ... | ... | @@ -15,7 +15,7 @@ use crate::*; |
| 15 | 15 | #[derive(Clone, Copy, Debug)] |
| 16 | 16 | pub enum AccessCause { |
| 17 | 17 | Explicit(AccessKind), |
| 18 | Reborrow, | |
| 18 | Reborrow(AccessKind), | |
| 19 | 19 | Dealloc, |
| 20 | 20 | FnExit(AccessKind), |
| 21 | 21 | } |
| ... | ... | @@ -24,7 +24,7 @@ impl fmt::Display for AccessCause { |
| 24 | 24 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
| 25 | 25 | match self { |
| 26 | 26 | Self::Explicit(kind) => write!(f, "{kind}"), |
| 27 | Self::Reborrow => write!(f, "reborrow"), | |
| 27 | Self::Reborrow(_) => write!(f, "reborrow"), | |
| 28 | 28 | Self::Dealloc => write!(f, "deallocation"), |
| 29 | 29 | // This is dead code, since the protector release access itself can never |
| 30 | 30 | // cause UB (while the protector is active, if some other access invalidates |
| ... | ... | @@ -40,7 +40,7 @@ impl AccessCause { |
| 40 | 40 | let rel = if is_foreign { "foreign" } else { "child" }; |
| 41 | 41 | match self { |
| 42 | 42 | Self::Explicit(kind) => format!("{rel} {kind}"), |
| 43 | Self::Reborrow => format!("reborrow (acting as a {rel} read access)"), | |
| 43 | Self::Reborrow(kind) => format!("reborrow (acting as a {rel} {kind})"), | |
| 44 | 44 | Self::Dealloc => format!("deallocation (acting as a {rel} write access)"), |
| 45 | 45 | Self::FnExit(kind) => format!("protector release (acting as a {rel} {kind})"), |
| 46 | 46 | } |
src/tools/miri/src/borrow_tracker/tree_borrows/mod.rs+102-51| ... | ... | @@ -6,7 +6,7 @@ use rustc_middle::ty::{self, Ty}; |
| 6 | 6 | use self::foreign_access_skipping::IdempotentForeignAccess; |
| 7 | 7 | use self::tree::LocationState; |
| 8 | 8 | use crate::borrow_tracker::{AccessKind, GlobalState, GlobalStateInner, ProtectorKind}; |
| 9 | use crate::concurrency::data_race::NaReadType; | |
| 9 | use crate::concurrency::data_race::{NaReadType, NaWriteType}; | |
| 10 | 10 | use crate::*; |
| 11 | 11 | |
| 12 | 12 | pub mod diagnostics; |
| ... | ... | @@ -109,13 +109,8 @@ impl<'tcx> Tree { |
| 109 | 109 | pub struct NewPermission { |
| 110 | 110 | /// Permission for the frozen part of the range. |
| 111 | 111 | freeze_perm: Permission, |
| 112 | /// Whether a read access should be performed on the frozen part on a retag. | |
| 113 | freeze_access: bool, | |
| 114 | 112 | /// Permission for the non-frozen part of the range. |
| 115 | 113 | nonfreeze_perm: Permission, |
| 116 | /// Whether a read access should be performed on the non-frozen | |
| 117 | /// part on a retag. | |
| 118 | nonfreeze_access: bool, | |
| 119 | 114 | /// Permission for memory outside the range. |
| 120 | 115 | outside_perm: Permission, |
| 121 | 116 | /// Whether this pointer is part of the arguments of a function call. |
| ... | ... | @@ -138,36 +133,78 @@ impl<'tcx> NewPermission { |
| 138 | 133 | let ty_is_freeze = pointee.is_freeze(*cx.tcx, cx.typing_env()); |
| 139 | 134 | let is_protected = retag_kind == RetagKind::FnEntry; |
| 140 | 135 | |
| 136 | // Check if the implicit writes check has been enabled for this function using the `-Zmiri-tree-borrows-implicit-writes` flag | |
| 137 | let implicit_writes = cx | |
| 138 | .machine | |
| 139 | .borrow_tracker | |
| 140 | .as_ref() | |
| 141 | .unwrap() | |
| 142 | .borrow() | |
| 143 | .borrow_tracker_method | |
| 144 | .get_tree_borrows_params() | |
| 145 | .implicit_writes; | |
| 146 | ||
| 141 | 147 | if matches!(ref_mutability, Some(Mutability::Mut) | None if !ty_is_unpin) { |
| 142 | 148 | // Mutable reference / Box to pinning type: retagging is a NOP. |
| 143 | 149 | // FIXME: with `UnsafePinned`, this should do proper per-byte tracking. |
| 144 | 150 | return None; |
| 145 | 151 | } |
| 146 | 152 | |
| 147 | let freeze_perm = match ref_mutability { | |
| 148 | // Shared references are frozen. | |
| 149 | Some(Mutability::Not) => Permission::new_frozen(), | |
| 150 | // Mutable references and Boxes are reserved. | |
| 151 | _ => Permission::new_reserved_frz(), | |
| 152 | }; | |
| 153 | let nonfreeze_perm = match ref_mutability { | |
| 154 | // Shared references are "transparent". | |
| 155 | Some(Mutability::Not) => Permission::new_cell(), | |
| 156 | // *Protected* mutable references and boxes are reserved without regarding for interior mutability. | |
| 157 | _ if is_protected => Permission::new_reserved_frz(), | |
| 158 | // Unprotected mutable references and boxes start in `ReservedIm`. | |
| 159 | _ => Permission::new_reserved_im(), | |
| 153 | enum Part { | |
| 154 | InsideFrozen, | |
| 155 | InsideUnsafeCell, | |
| 156 | Outside, | |
| 157 | } | |
| 158 | use Part::*; | |
| 159 | ||
| 160 | let perm = |part: Part| { | |
| 161 | // Whether we should consider this byte to be frozen. | |
| 162 | // Outside bytes are frozen only if the entire type is frozen. | |
| 163 | let frozen = match part { | |
| 164 | InsideFrozen => true, | |
| 165 | InsideUnsafeCell => false, | |
| 166 | Outside => ty_is_freeze, | |
| 167 | }; | |
| 168 | match ref_mutability { | |
| 169 | // Shared references | |
| 170 | Some(Mutability::Not) => | |
| 171 | if frozen { | |
| 172 | Permission::new_frozen() | |
| 173 | } else { | |
| 174 | Permission::new_cell() | |
| 175 | }, | |
| 176 | // Mutable references | |
| 177 | Some(Mutability::Mut) => { | |
| 178 | if is_protected && implicit_writes && !matches!(part, Outside) { | |
| 179 | // We cannot use `Unique` for the outside part. | |
| 180 | Permission::new_unique() | |
| 181 | } else if is_protected || frozen { | |
| 182 | // We also use this for protected `&mut UnsafeCell` as otherwise adding | |
| 183 | // `noalias` would not be sound. | |
| 184 | Permission::new_reserved_frz() | |
| 185 | } else { | |
| 186 | Permission::new_reserved_im() | |
| 187 | } | |
| 188 | } | |
| 189 | // Boxes | |
| 190 | None => | |
| 191 | if is_protected && implicit_writes && !matches!(part, Outside) { | |
| 192 | // Boxes are treated the same as mutable references. | |
| 193 | Permission::new_unique() | |
| 194 | } else if is_protected || frozen { | |
| 195 | // We also use this for protected `Box<UnsafeCell>` as otherwise adding | |
| 196 | // `noalias` would not be sound. | |
| 197 | Permission::new_reserved_frz() | |
| 198 | } else { | |
| 199 | Permission::new_reserved_im() | |
| 200 | }, | |
| 201 | } | |
| 160 | 202 | }; |
| 161 | 203 | |
| 162 | // Everything except for `Cell` gets an initial access. | |
| 163 | let initial_access = |perm: &Permission| !perm.is_cell(); | |
| 164 | ||
| 165 | 204 | Some(NewPermission { |
| 166 | freeze_perm, | |
| 167 | freeze_access: initial_access(&freeze_perm), | |
| 168 | nonfreeze_perm, | |
| 169 | nonfreeze_access: initial_access(&nonfreeze_perm), | |
| 170 | outside_perm: if ty_is_freeze { freeze_perm } else { nonfreeze_perm }, | |
| 205 | freeze_perm: perm(InsideFrozen), | |
| 206 | nonfreeze_perm: perm(InsideUnsafeCell), | |
| 207 | outside_perm: perm(Outside), | |
| 171 | 208 | protector: is_protected.then_some(if ref_mutability.is_some() { |
| 172 | 209 | // Strong protector for references |
| 173 | 210 | ProtectorKind::StrongProtector |
| ... | ... | @@ -288,13 +325,10 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 288 | 325 | |
| 289 | 326 | // Compute initial "inside" permissions. |
| 290 | 327 | let loc_state = |frozen: bool| -> LocationState { |
| 291 | let (perm, access) = if frozen { | |
| 292 | (new_perm.freeze_perm, new_perm.freeze_access) | |
| 293 | } else { | |
| 294 | (new_perm.nonfreeze_perm, new_perm.nonfreeze_access) | |
| 295 | }; | |
| 328 | let perm = if frozen { new_perm.freeze_perm } else { new_perm.nonfreeze_perm }; | |
| 296 | 329 | let sifa = perm.strongest_idempotent_foreign_access(protected); |
| 297 | if access { | |
| 330 | ||
| 331 | if perm.associated_access().is_some() { | |
| 298 | 332 | LocationState::new_accessed(perm, sifa) |
| 299 | 333 | } else { |
| 300 | 334 | LocationState::new_non_accessed(perm, sifa) |
| ... | ... | @@ -303,11 +337,10 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 303 | 337 | let inside_perms = if !precise_interior_mut { |
| 304 | 338 | // For `!Freeze` types, just pretend the entire thing is an `UnsafeCell`. |
| 305 | 339 | let ty_is_freeze = place.layout.ty.is_freeze(*this.tcx, this.typing_env()); |
| 306 | let state = loc_state(ty_is_freeze); | |
| 307 | DedupRangeMap::new(ptr_size, state) | |
| 340 | DedupRangeMap::new(ptr_size, loc_state(ty_is_freeze)) | |
| 308 | 341 | } else { |
| 309 | 342 | // The initial state will be overwritten by the visitor below. |
| 310 | let mut perms_map: DedupRangeMap<LocationState> = DedupRangeMap::new( | |
| 343 | let mut perms_map = DedupRangeMap::new( | |
| 311 | 344 | ptr_size, |
| 312 | 345 | LocationState::new_accessed( |
| 313 | 346 | Permission::new_disabled(), |
| ... | ... | @@ -327,9 +360,18 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 327 | 360 | let alloc_extra = this.get_alloc_extra(alloc_id)?; |
| 328 | 361 | let mut tree_borrows = alloc_extra.borrow_tracker_tb().borrow_mut(); |
| 329 | 362 | |
| 330 | for (perm_range, perm) in inside_perms.iter_all() { | |
| 331 | if perm.accessed() { | |
| 332 | // Some reborrows incur a read access to the parent. | |
| 363 | for (perm_range, loc_state) in inside_perms.iter_all() { | |
| 364 | if let Some(access) = loc_state.permission().associated_access() { | |
| 365 | // Some reborrows incur a read/write access to the parent. | |
| 366 | // As a write also implies a read, a single write is performed instead of a read and a write. | |
| 367 | ||
| 368 | // writing to an immutable allocation (static variables) is UB, check this here | |
| 369 | if access == AccessKind::Write | |
| 370 | && this.get_alloc_mutability(alloc_id).unwrap().is_not() | |
| 371 | { | |
| 372 | throw_ub!(WriteToReadOnly(alloc_id)) | |
| 373 | } | |
| 374 | ||
| 333 | 375 | // Adjust range to be relative to allocation start (rather than to `place`). |
| 334 | 376 | let range_in_alloc = AllocRange { |
| 335 | 377 | start: Size::from_bytes(perm_range.start) + base_offset, |
| ... | ... | @@ -339,8 +381,8 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 339 | 381 | tree_borrows.perform_access( |
| 340 | 382 | parent_prov, |
| 341 | 383 | range_in_alloc, |
| 342 | AccessKind::Read, | |
| 343 | diagnostics::AccessCause::Reborrow, | |
| 384 | access, | |
| 385 | diagnostics::AccessCause::Reborrow(access), | |
| 344 | 386 | this.machine.borrow_tracker.as_ref().unwrap(), |
| 345 | 387 | alloc_id, |
| 346 | 388 | this.machine.current_user_relevant_span(), |
| ... | ... | @@ -349,17 +391,29 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 349 | 391 | // Also inform the data race model (but only if any bytes are actually affected). |
| 350 | 392 | if range_in_alloc.size.bytes() > 0 { |
| 351 | 393 | if let Some(data_race) = alloc_extra.data_race.as_vclocks_ref() { |
| 352 | data_race.read_non_atomic( | |
| 353 | alloc_id, | |
| 354 | range_in_alloc, | |
| 355 | NaReadType::Retag, | |
| 356 | Some(place.layout.ty), | |
| 357 | &this.machine, | |
| 358 | )? | |
| 394 | match access { | |
| 395 | AccessKind::Read => | |
| 396 | data_race.read_non_atomic( | |
| 397 | alloc_id, | |
| 398 | range_in_alloc, | |
| 399 | NaReadType::Retag, | |
| 400 | Some(place.layout.ty), | |
| 401 | &this.machine, | |
| 402 | )?, | |
| 403 | AccessKind::Write => | |
| 404 | data_race.write_non_atomic( | |
| 405 | alloc_id, | |
| 406 | range_in_alloc, | |
| 407 | NaWriteType::Retag, | |
| 408 | Some(place.layout.ty), | |
| 409 | &this.machine, | |
| 410 | )?, | |
| 411 | }; | |
| 359 | 412 | } |
| 360 | 413 | } |
| 361 | 414 | } |
| 362 | 415 | } |
| 416 | ||
| 363 | 417 | // Record the parent-child pair in the tree. |
| 364 | 418 | tree_borrows.new_child( |
| 365 | 419 | base_offset, |
| ... | ... | @@ -370,7 +424,6 @@ trait EvalContextPrivExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 370 | 424 | protected, |
| 371 | 425 | this.machine.current_user_relevant_span(), |
| 372 | 426 | )?; |
| 373 | drop(tree_borrows); | |
| 374 | 427 | |
| 375 | 428 | interp_ok(Some(new_prov)) |
| 376 | 429 | } |
| ... | ... | @@ -550,9 +603,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 550 | 603 | // argument doesn't matter |
| 551 | 604 | // (`ty_is_freeze || true` in `new_reserved` will always be `true`). |
| 552 | 605 | freeze_perm: Permission::new_reserved_frz(), |
| 553 | freeze_access: true, | |
| 554 | 606 | nonfreeze_perm: Permission::new_reserved_frz(), |
| 555 | nonfreeze_access: true, | |
| 556 | 607 | outside_perm: Permission::new_reserved_frz(), |
| 557 | 608 | protector: Some(ProtectorKind::StrongProtector), |
| 558 | 609 | }; |
src/tools/miri/src/borrow_tracker/tree_borrows/perms.rs+10-7| ... | ... | @@ -91,7 +91,7 @@ impl PartialOrd for PermissionPriv { |
| 91 | 91 | impl PermissionPriv { |
| 92 | 92 | /// Check if `self` can be the initial state of a pointer. |
| 93 | 93 | fn is_initial(&self) -> bool { |
| 94 | matches!(self, ReservedFrz { conflicted: false } | Frozen | ReservedIM | Cell) | |
| 94 | matches!(self, ReservedFrz { conflicted: false } | Frozen | ReservedIM | Cell | Unique) | |
| 95 | 95 | } |
| 96 | 96 | |
| 97 | 97 | /// Reject `ReservedIM` that cannot exist in the presence of a protector. |
| ... | ... | @@ -265,14 +265,17 @@ impl Permission { |
| 265 | 265 | self.inner == Cell |
| 266 | 266 | } |
| 267 | 267 | |
| 268 | /// Default initial permission of the root of a new tree at inbounds positions. | |
| 269 | /// Must *only* be used for the root, this is not in general an "initial" permission! | |
| 268 | /// Check if `self` is a Permission of type `Unique` | |
| 269 | pub fn is_unique(&self) -> bool { | |
| 270 | self.inner == Unique | |
| 271 | } | |
| 272 | ||
| 273 | /// Create a new Permission of type `Unique` | |
| 270 | 274 | pub fn new_unique() -> Self { |
| 271 | 275 | Self { inner: Unique } |
| 272 | 276 | } |
| 273 | 277 | |
| 274 | /// Default initial permission of a reborrowed mutable reference that is either | |
| 275 | /// protected or not interior mutable. | |
| 278 | /// Create a new Permission of type `ReservedFrz` with conflictedReserved set to false | |
| 276 | 279 | pub fn new_reserved_frz() -> Self { |
| 277 | 280 | Self { inner: ReservedFrz { conflicted: false } } |
| 278 | 281 | } |
| ... | ... | @@ -304,8 +307,8 @@ impl Permission { |
| 304 | 307 | self.inner.compatible_with_protector() |
| 305 | 308 | } |
| 306 | 309 | |
| 307 | /// What kind of access to perform before releasing the protector. | |
| 308 | pub fn protector_end_access(&self) -> Option<AccessKind> { | |
| 310 | /// What kind of access to perform before releasing the protector or on a reborrow. | |
| 311 | pub fn associated_access(&self) -> Option<AccessKind> { | |
| 309 | 312 | match self.inner { |
| 310 | 313 | // Do not do perform access if it is a `Cell`, as this |
| 311 | 314 | // can cause data races when using thread-safe data types. |
src/tools/miri/src/borrow_tracker/tree_borrows/tree.rs+10-1| ... | ... | @@ -63,6 +63,7 @@ impl LocationState { |
| 63 | 63 | /// `sifa` is the (strongest) idempotent foreign access, see `foreign_access_skipping.rs` |
| 64 | 64 | pub fn new_non_accessed(permission: Permission, sifa: IdempotentForeignAccess) -> Self { |
| 65 | 65 | assert!(permission.is_initial() || permission.is_disabled()); |
| 66 | assert!(!permission.is_unique()); | |
| 66 | 67 | Self { permission, accessed: false, idempotent_foreign_access: sifa } |
| 67 | 68 | } |
| 68 | 69 | |
| ... | ... | @@ -73,6 +74,12 @@ impl LocationState { |
| 73 | 74 | Self { permission, accessed: true, idempotent_foreign_access: sifa } |
| 74 | 75 | } |
| 75 | 76 | |
| 77 | /// Checks whether the current location state is ever reachable in a real execution. | |
| 78 | pub fn possible(&self) -> bool { | |
| 79 | // `Unique` can only be reached on actually accessed locations. | |
| 80 | self.accessed || !self.permission.is_unique() | |
| 81 | } | |
| 82 | ||
| 76 | 83 | /// Check if the location has been accessed, i.e. if it has |
| 77 | 84 | /// ever been accessed through a child pointer. |
| 78 | 85 | pub fn accessed(&self) -> bool { |
| ... | ... | @@ -150,6 +157,7 @@ impl LocationState { |
| 150 | 157 | if protected && self.accessed && transition.produces_disabled() { |
| 151 | 158 | return Err(TransitionError::ProtectedDisabled(old_perm)); |
| 152 | 159 | } |
| 160 | debug_assert!(self.possible()); | |
| 153 | 161 | Ok(transition) |
| 154 | 162 | } |
| 155 | 163 | |
| ... | ... | @@ -397,6 +405,7 @@ impl<'tcx> Tree { |
| 397 | 405 | ProvenanceExtra::Wildcard => None, |
| 398 | 406 | }; |
| 399 | 407 | assert!(outside_perm.is_initial()); |
| 408 | assert!(!outside_perm.is_unique()); | |
| 400 | 409 | |
| 401 | 410 | let default_strongest_idempotent = |
| 402 | 411 | outside_perm.strongest_idempotent_foreign_access(protected); |
| ... | ... | @@ -690,7 +699,7 @@ impl<'tcx> Tree { |
| 690 | 699 | for (loc_range, loc) in self.locations.iter_mut_all() { |
| 691 | 700 | // Only visit accessed permissions |
| 692 | 701 | if let Some(p) = loc.perms.get(source_idx) |
| 693 | && let Some(access_kind) = p.permission.protector_end_access() | |
| 702 | && let Some(access_kind) = p.permission.associated_access() | |
| 694 | 703 | && p.accessed |
| 695 | 704 | { |
| 696 | 705 | let diagnostics = DiagnosticInfo { |
src/tools/miri/src/borrow_tracker/tree_borrows/tree/tests.rs+22-16| ... | ... | @@ -9,13 +9,17 @@ use crate::borrow_tracker::tree_borrows::exhaustive::{Exhaustive, precondition}; |
| 9 | 9 | impl Exhaustive for LocationState { |
| 10 | 10 | fn exhaustive() -> Box<dyn Iterator<Item = Self>> { |
| 11 | 11 | // We keep `latest_foreign_access` at `None` as that's just a cache. |
| 12 | Box::new(<(Permission, bool)>::exhaustive().map(|(permission, accessed)| { | |
| 13 | Self { | |
| 14 | permission, | |
| 15 | accessed, | |
| 16 | idempotent_foreign_access: IdempotentForeignAccess::default(), | |
| 17 | } | |
| 18 | })) | |
| 12 | Box::new( | |
| 13 | <(Permission, bool)>::exhaustive() | |
| 14 | .map(|(permission, accessed)| { | |
| 15 | Self { | |
| 16 | permission, | |
| 17 | accessed, | |
| 18 | idempotent_foreign_access: IdempotentForeignAccess::default(), | |
| 19 | } | |
| 20 | }) | |
| 21 | .filter(|x| x.possible()), | |
| 22 | ) | |
| 19 | 23 | } |
| 20 | 24 | } |
| 21 | 25 | |
| ... | ... | @@ -438,17 +442,19 @@ mod spurious_read { |
| 438 | 442 | /// Perform a read on the given pointer if its state is `accessed`. |
| 439 | 443 | /// Must be called just after reborrowing a pointer, and just after |
| 440 | 444 | /// removing a protector. |
| 441 | fn read_if_accessed(self, ptr: PtrSelector) -> Result<Self, ()> { | |
| 445 | fn retag_dependent_access(self, ptr: PtrSelector) -> Result<Self, ()> { | |
| 442 | 446 | let accessed = match ptr { |
| 443 | PtrSelector::X => self.x.state.accessed, | |
| 444 | PtrSelector::Y => self.y.state.accessed, | |
| 447 | PtrSelector::X => | |
| 448 | self.x.state.permission.associated_access().filter(|_| self.x.state.accessed), | |
| 449 | PtrSelector::Y => | |
| 450 | self.y.state.permission.associated_access().filter(|_| self.y.state.accessed), | |
| 445 | 451 | PtrSelector::Other => |
| 446 | 452 | panic!( |
| 447 | 453 | "the `accessed` status of `PtrSelector::Other` is unknown, do not pass it to `read_if_accessed`" |
| 448 | 454 | ), |
| 449 | 455 | }; |
| 450 | if accessed { | |
| 451 | self.perform_test_access(&TestAccess { ptr, kind: AccessKind::Read }) | |
| 456 | if let Some(kind) = accessed { | |
| 457 | self.perform_test_access(&TestAccess { ptr, kind }) | |
| 452 | 458 | } else { |
| 453 | 459 | Ok(self) |
| 454 | 460 | } |
| ... | ... | @@ -457,13 +463,13 @@ mod spurious_read { |
| 457 | 463 | /// Remove the protector of `x`, including the implicit read on function exit. |
| 458 | 464 | fn end_protector_x(self) -> Result<Self, ()> { |
| 459 | 465 | let x = self.x.end_protector(); |
| 460 | Self { x, ..self }.read_if_accessed(PtrSelector::X) | |
| 466 | Self { x, ..self }.retag_dependent_access(PtrSelector::X) | |
| 461 | 467 | } |
| 462 | 468 | |
| 463 | 469 | /// Remove the protector of `y`, including the implicit read on function exit. |
| 464 | 470 | fn end_protector_y(self) -> Result<Self, ()> { |
| 465 | 471 | let y = self.y.end_protector(); |
| 466 | Self { y, ..self }.read_if_accessed(PtrSelector::Y) | |
| 472 | Self { y, ..self }.retag_dependent_access(PtrSelector::Y) | |
| 467 | 473 | } |
| 468 | 474 | |
| 469 | 475 | fn retag_y(self, new_y: LocStateProt) -> Result<Self, ()> { |
| ... | ... | @@ -473,7 +479,7 @@ mod spurious_read { |
| 473 | 479 | } |
| 474 | 480 | // `xy_rel` changes to "mutually foreign" now: `y` can no longer be a parent of `x`. |
| 475 | 481 | Self { y: new_y, xy_rel: RelPosXY::MutuallyForeign, ..self } |
| 476 | .read_if_accessed(PtrSelector::Y) | |
| 482 | .retag_dependent_access(PtrSelector::Y) | |
| 477 | 483 | } |
| 478 | 484 | |
| 479 | 485 | fn perform_test_event<RetX, RetY>(self, evt: &TestEvent<RetX, RetY>) -> Result<Self, ()> { |
| ... | ... | @@ -696,7 +702,7 @@ mod spurious_read { |
| 696 | 702 | fn initial_state(&self) -> Result<LocStateProtPair, ()> { |
| 697 | 703 | let (x, y) = self.retag_permissions(); |
| 698 | 704 | let state = LocStateProtPair { xy_rel: self.xy_rel, x, y }; |
| 699 | state.read_if_accessed(PtrSelector::X) | |
| 705 | state.retag_dependent_access(PtrSelector::X) | |
| 700 | 706 | } |
| 701 | 707 | } |
| 702 | 708 |
src/tools/miri/src/concurrency/data_race.rs+4-4| ... | ... | @@ -1243,21 +1243,21 @@ impl VClockAlloc { |
| 1243 | 1243 | /// operation. The `ty` parameter is used for diagnostics, letting |
| 1244 | 1244 | /// the user know which type was written. |
| 1245 | 1245 | pub fn write_non_atomic<'tcx>( |
| 1246 | &mut self, | |
| 1246 | &self, | |
| 1247 | 1247 | alloc_id: AllocId, |
| 1248 | 1248 | access_range: AllocRange, |
| 1249 | 1249 | write_type: NaWriteType, |
| 1250 | 1250 | ty: Option<Ty<'_>>, |
| 1251 | machine: &mut MiriMachine<'_>, | |
| 1251 | machine: &MiriMachine<'_>, | |
| 1252 | 1252 | ) -> InterpResult<'tcx> { |
| 1253 | 1253 | let current_span = machine.current_user_relevant_span(); |
| 1254 | let global = machine.data_race.as_vclocks_mut().unwrap(); | |
| 1254 | let global = machine.data_race.as_vclocks_ref().unwrap(); | |
| 1255 | 1255 | if !global.race_detecting() { |
| 1256 | 1256 | return interp_ok(()); |
| 1257 | 1257 | } |
| 1258 | 1258 | let (index, mut thread_clocks) = global.active_thread_state_mut(&machine.threads); |
| 1259 | 1259 | for (mem_clocks_range, mem_clocks) in |
| 1260 | self.alloc_ranges.get_mut().iter_mut(access_range.start, access_range.size) | |
| 1260 | self.alloc_ranges.borrow_mut().iter_mut(access_range.start, access_range.size) | |
| 1261 | 1261 | { |
| 1262 | 1262 | if let Err(DataRace) = |
| 1263 | 1263 | mem_clocks.write_race_detect(&mut thread_clocks, index, write_type, current_span) |
src/tools/miri/src/helpers.rs+1-1| ... | ... | @@ -407,7 +407,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 407 | 407 | let sig = this.tcx.mk_fn_sig( |
| 408 | 408 | args.iter().map(|a| a.layout.ty), |
| 409 | 409 | dest.layout.ty, |
| 410 | FnSigKind::default().set_abi(caller_abi).set_safe(true), | |
| 410 | FnSigKind::default().set_abi(caller_abi).set_safety(rustc_hir::Safety::Safe), | |
| 411 | 411 | ); |
| 412 | 412 | let caller_fn_abi = this.fn_abi_of_fn_ptr(ty::Binder::dummy(sig), ty::List::empty())?; |
| 413 | 413 |
src/tools/miri/src/shims/sig.rs+3-1| ... | ... | @@ -275,7 +275,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 275 | 275 | let fn_sig_binder = Binder::dummy(FnSig { |
| 276 | 276 | inputs_and_output: this.machine.tcx.mk_type_list(&inputs_and_output), |
| 277 | 277 | // Safety does not matter for the ABI. |
| 278 | fn_sig_kind: FnSigKind::default().set_abi(shim_sig.abi).set_safe(true), | |
| 278 | fn_sig_kind: FnSigKind::default() | |
| 279 | .set_abi(shim_sig.abi) | |
| 280 | .set_safety(rustc_hir::Safety::Safe), | |
| 279 | 281 | }); |
| 280 | 282 | let callee_fn_abi = this.fn_abi_of_fn_ptr(fn_sig_binder, Default::default())?; |
| 281 | 283 |
src/tools/miri/src/shims/unix/foreign_items.rs+10| ... | ... | @@ -350,6 +350,16 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 350 | 350 | let result = this.fstat(fd, buf)?; |
| 351 | 351 | this.write_scalar(result, dest)?; |
| 352 | 352 | } |
| 353 | "lstat" => { | |
| 354 | let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; | |
| 355 | let result = this.lstat(path, buf)?; | |
| 356 | this.write_scalar(result, dest)?; | |
| 357 | } | |
| 358 | "stat" => { | |
| 359 | let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; | |
| 360 | let result = this.stat(path, buf)?; | |
| 361 | this.write_scalar(result, dest)?; | |
| 362 | } | |
| 353 | 363 | "rename" => { |
| 354 | 364 | // FIXME: This does not have a direct test (#3179). |
| 355 | 365 | let [oldpath, newpath] = this.check_shim_sig( |
src/tools/miri/src/shims/unix/freebsd/foreign_items.rs+2-6| ... | ... | @@ -136,16 +136,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 136 | 136 | } |
| 137 | 137 | |
| 138 | 138 | // File related shims |
| 139 | // For those, we both intercept `func` and `call@FBSD_1.0` symbols cases | |
| 140 | // since freebsd 12 the former form can be expected. | |
| 141 | "stat" | "stat@FBSD_1.0" => { | |
| 142 | // FIXME: This does not have a direct test (#3179). | |
| 139 | "stat@FBSD_1.0" => { | |
| 143 | 140 | let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; |
| 144 | 141 | let result = this.stat(path, buf)?; |
| 145 | 142 | this.write_scalar(result, dest)?; |
| 146 | 143 | } |
| 147 | "lstat" | "lstat@FBSD_1.0" => { | |
| 148 | // FIXME: This does not have a direct test (#3179). | |
| 144 | "lstat@FBSD_1.0" => { | |
| 149 | 145 | let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; |
| 150 | 146 | let result = this.lstat(path, buf)?; |
| 151 | 147 | this.write_scalar(result, dest)?; |
src/tools/miri/src/shims/unix/fs.rs+92-39| ... | ... | @@ -243,12 +243,12 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 243 | 243 | |
| 244 | 244 | this.write_int_fields_named( |
| 245 | 245 | &[ |
| 246 | ("st_dev", metadata.dev.into()), | |
| 246 | ("st_dev", metadata.dev.unwrap_or(0).into()), | |
| 247 | 247 | ("st_mode", mode.into()), |
| 248 | ("st_nlink", 0), | |
| 249 | ("st_ino", 0), | |
| 250 | ("st_uid", metadata.uid.into()), | |
| 251 | ("st_gid", metadata.gid.into()), | |
| 248 | ("st_nlink", metadata.nlink.unwrap_or(0).into()), | |
| 249 | ("st_ino", metadata.ino.unwrap_or(0).into()), | |
| 250 | ("st_uid", metadata.uid.unwrap_or(0).into()), | |
| 251 | ("st_gid", metadata.gid.unwrap_or(0).into()), | |
| 252 | 252 | ("st_rdev", 0), |
| 253 | 253 | ("st_atime", access_sec.into()), |
| 254 | 254 | ("st_atime_nsec", access_nsec.into()), |
| ... | ... | @@ -257,8 +257,8 @@ trait EvalContextExtPrivate<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 257 | 257 | ("st_ctime", 0), |
| 258 | 258 | ("st_ctime_nsec", 0), |
| 259 | 259 | ("st_size", metadata.size.into()), |
| 260 | ("st_blocks", 0), | |
| 261 | ("st_blksize", 0), | |
| 260 | ("st_blocks", metadata.blocks.unwrap_or(0).into()), | |
| 261 | ("st_blksize", metadata.blksize.unwrap_or(0).into()), | |
| 262 | 262 | ], |
| 263 | 263 | &buf, |
| 264 | 264 | )?; |
| ... | ... | @@ -586,9 +586,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 586 | 586 | |
| 587 | 587 | if !matches!( |
| 588 | 588 | &this.tcx.sess.target.os, |
| 589 | Os::MacOs | Os::FreeBsd | Os::Solaris | Os::Illumos | Os::Android | |
| 589 | Os::MacOs | Os::FreeBsd | Os::Solaris | Os::Illumos | Os::Android | Os::Linux | |
| 590 | 590 | ) { |
| 591 | panic!("`macos_fbsd_solaris_stat` should not be called on {}", this.tcx.sess.target.os); | |
| 591 | panic!("`stat` should not be called on {}", this.tcx.sess.target.os); | |
| 592 | 592 | } |
| 593 | 593 | |
| 594 | 594 | let path_scalar = this.read_pointer(path_op)?; |
| ... | ... | @@ -615,12 +615,9 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 615 | 615 | |
| 616 | 616 | if !matches!( |
| 617 | 617 | &this.tcx.sess.target.os, |
| 618 | Os::MacOs | Os::FreeBsd | Os::Solaris | Os::Illumos | Os::Android | |
| 618 | Os::MacOs | Os::FreeBsd | Os::Solaris | Os::Illumos | Os::Android | Os::Linux | |
| 619 | 619 | ) { |
| 620 | panic!( | |
| 621 | "`macos_fbsd_solaris_lstat` should not be called on {}", | |
| 622 | this.tcx.sess.target.os | |
| 623 | ); | |
| 620 | panic!("`lstat` should not be called on {}", this.tcx.sess.target.os); | |
| 624 | 621 | } |
| 625 | 622 | |
| 626 | 623 | let path_scalar = this.read_pointer(path_op)?; |
| ... | ... | @@ -730,12 +727,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 730 | 727 | return this.set_last_error_and_return_i32(ecode); |
| 731 | 728 | } |
| 732 | 729 | |
| 733 | // the `_mask_op` parameter specifies the file information that the caller requested. | |
| 734 | // However `statx` is allowed to return information that was not requested or to not | |
| 735 | // return information that was requested. This `mask` represents the information we can | |
| 736 | // actually provide for any target. | |
| 737 | let mut mask = this.eval_libc_u32("STATX_TYPE") | this.eval_libc_u32("STATX_SIZE"); | |
| 738 | ||
| 739 | 730 | // If the `AT_SYMLINK_NOFOLLOW` flag is set, we query the file's metadata without following |
| 740 | 731 | // symbolic links. |
| 741 | 732 | let follow_symlink = flags & this.eval_libc_i32("AT_SYMLINK_NOFOLLOW") == 0; |
| ... | ... | @@ -752,6 +743,29 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 752 | 743 | Err(err) => return this.set_last_error_and_return_i32(err), |
| 753 | 744 | }; |
| 754 | 745 | |
| 746 | // The `_mask_op` parameter specifies the file information that the caller requested. | |
| 747 | // However, `statx` is allowed to return information that was not requested or to not | |
| 748 | // return information that was requested. This `mask` represents the information we can | |
| 749 | // actually provide for any target. | |
| 750 | let mut mask = this.eval_libc_u32("STATX_TYPE") | this.eval_libc_u32("STATX_SIZE"); | |
| 751 | ||
| 752 | // Check which pieces of metadata we acquired, and set the appropriate flags in the mask. | |
| 753 | if metadata.ino.is_some() { | |
| 754 | mask |= this.eval_libc_u32("STATX_INO"); | |
| 755 | } | |
| 756 | if metadata.nlink.is_some() { | |
| 757 | mask |= this.eval_libc_u32("STATX_NLINK"); | |
| 758 | } | |
| 759 | if metadata.uid.is_some() { | |
| 760 | mask |= this.eval_libc_u32("STATX_UID"); | |
| 761 | } | |
| 762 | if metadata.gid.is_some() { | |
| 763 | mask |= this.eval_libc_u32("STATX_GID"); | |
| 764 | } | |
| 765 | if metadata.blocks.is_some() { | |
| 766 | mask |= this.eval_libc_u32("STATX_BLOCKS"); | |
| 767 | } | |
| 768 | ||
| 755 | 769 | // `statx.stx_mode` is `__u16`. `libc::S_IF*` are of type `mode_t`, which varies in |
| 756 | 770 | // width across targets (`u16` on macOS, `u32` on Linux). Read using `mode_t`'s size. |
| 757 | 771 | let mode_t_size = this.libc_ty_layout("mode_t").size; |
| ... | ... | @@ -791,15 +805,15 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 791 | 805 | this.write_int_fields_named( |
| 792 | 806 | &[ |
| 793 | 807 | ("stx_mask", mask.into()), |
| 794 | ("stx_blksize", 0), | |
| 808 | ("stx_blksize", metadata.blksize.unwrap_or(0).into()), | |
| 795 | 809 | ("stx_attributes", 0), |
| 796 | ("stx_nlink", 0), | |
| 797 | ("stx_uid", 0), | |
| 798 | ("stx_gid", 0), | |
| 810 | ("stx_nlink", metadata.nlink.unwrap_or(0).into()), | |
| 811 | ("stx_uid", metadata.uid.unwrap_or(0).into()), | |
| 812 | ("stx_gid", metadata.gid.unwrap_or(0).into()), | |
| 799 | 813 | ("stx_mode", mode.into()), |
| 800 | ("stx_ino", 0), | |
| 814 | ("stx_ino", metadata.ino.unwrap_or(0).into()), | |
| 801 | 815 | ("stx_size", metadata.size.into()), |
| 802 | ("stx_blocks", 0), | |
| 816 | ("stx_blocks", metadata.blocks.unwrap_or(0).into()), | |
| 803 | 817 | ("stx_attributes_mask", 0), |
| 804 | 818 | ("stx_rdev_major", 0), |
| 805 | 819 | ("stx_rdev_minor", 0), |
| ... | ... | @@ -1664,15 +1678,24 @@ fn file_type_to_mode_name(file_type: std::fs::FileType) -> &'static str { |
| 1664 | 1678 | |
| 1665 | 1679 | /// Stores a file's metadata in order to avoid code duplication in the different metadata related |
| 1666 | 1680 | /// shims. |
| 1681 | /// | |
| 1682 | /// Some fields are host/platform-specific. `None` means that Miri does not have a real value for | |
| 1683 | /// this field, for example because the metadata is synthetic or because the host platform does not | |
| 1684 | /// expose it. `statx` must only advertise the corresponding `STATX_*` bit when the field is `Some`; | |
| 1685 | /// legacy `stat` writes zero for `None` to preserve the old fallback behavior. | |
| 1667 | 1686 | struct FileMetadata { |
| 1668 | 1687 | mode: Scalar, |
| 1669 | 1688 | size: u64, |
| 1670 | 1689 | created: Option<(u64, u32)>, |
| 1671 | 1690 | accessed: Option<(u64, u32)>, |
| 1672 | 1691 | modified: Option<(u64, u32)>, |
| 1673 | dev: u64, | |
| 1674 | uid: u32, | |
| 1675 | gid: u32, | |
| 1692 | dev: Option<u64>, | |
| 1693 | ino: Option<u64>, | |
| 1694 | nlink: Option<u64>, | |
| 1695 | uid: Option<u32>, | |
| 1696 | gid: Option<u32>, | |
| 1697 | blksize: Option<u64>, | |
| 1698 | blocks: Option<u64>, | |
| 1676 | 1699 | } |
| 1677 | 1700 | |
| 1678 | 1701 | impl FileMetadata { |
| ... | ... | @@ -1711,9 +1734,13 @@ impl FileMetadata { |
| 1711 | 1734 | created: None, |
| 1712 | 1735 | accessed: None, |
| 1713 | 1736 | modified: None, |
| 1714 | dev: 0, | |
| 1715 | uid: 0, | |
| 1716 | gid: 0, | |
| 1737 | dev: None, | |
| 1738 | uid: None, | |
| 1739 | gid: None, | |
| 1740 | blksize: None, | |
| 1741 | blocks: None, | |
| 1742 | ino: None, | |
| 1743 | nlink: None, | |
| 1717 | 1744 | })) |
| 1718 | 1745 | } |
| 1719 | 1746 | |
| ... | ... | @@ -1743,16 +1770,42 @@ impl FileMetadata { |
| 1743 | 1770 | unix => { |
| 1744 | 1771 | use std::os::unix::fs::MetadataExt; |
| 1745 | 1772 | let dev = metadata.dev(); |
| 1773 | let ino = metadata.ino(); | |
| 1774 | let nlink = metadata.nlink(); | |
| 1746 | 1775 | let uid = metadata.uid(); |
| 1747 | 1776 | let gid = metadata.gid(); |
| 1777 | let blksize = metadata.blksize(); | |
| 1778 | let blocks = metadata.blocks(); | |
| 1779 | ||
| 1780 | interp_ok(Ok(FileMetadata { | |
| 1781 | mode, | |
| 1782 | size, | |
| 1783 | created, | |
| 1784 | accessed, | |
| 1785 | modified, | |
| 1786 | dev: Some(dev), | |
| 1787 | ino: Some(ino), | |
| 1788 | nlink: Some(nlink), | |
| 1789 | uid: Some(uid), | |
| 1790 | gid: Some(gid), | |
| 1791 | blksize: Some(blksize), | |
| 1792 | blocks: Some(blocks), | |
| 1793 | })) | |
| 1748 | 1794 | } |
| 1749 | _ => { | |
| 1750 | let dev = 0; | |
| 1751 | let uid = 0; | |
| 1752 | let gid = 0; | |
| 1753 | } | |
| 1795 | _ => interp_ok(Ok(FileMetadata { | |
| 1796 | mode, | |
| 1797 | size, | |
| 1798 | created, | |
| 1799 | accessed, | |
| 1800 | modified, | |
| 1801 | dev: None, | |
| 1802 | ino: None, | |
| 1803 | nlink: None, | |
| 1804 | uid: None, | |
| 1805 | gid: None, | |
| 1806 | blksize: None, | |
| 1807 | blocks: None, | |
| 1808 | })), | |
| 1754 | 1809 | } |
| 1755 | ||
| 1756 | interp_ok(Ok(FileMetadata { mode, size, created, accessed, modified, dev, uid, gid })) | |
| 1757 | 1810 | } |
| 1758 | 1811 | } |
src/tools/miri/src/shims/unix/linux/foreign_items.rs-1| ... | ... | @@ -124,7 +124,6 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 124 | 124 | this.write_scalar(result, dest)?; |
| 125 | 125 | } |
| 126 | 126 | "statx" => { |
| 127 | // FIXME: This does not have a direct test (#3179). | |
| 128 | 127 | let [dirfd, pathname, flags, mask, statxbuf] = |
| 129 | 128 | this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; |
| 130 | 129 | let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?; |
src/tools/miri/src/shims/unix/macos/foreign_items.rs+2-4| ... | ... | @@ -46,14 +46,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 46 | 46 | let result = this.close(result)?; |
| 47 | 47 | this.write_scalar(result, dest)?; |
| 48 | 48 | } |
| 49 | "stat" | "stat$INODE64" => { | |
| 50 | // FIXME: This does not have a direct test (#3179). | |
| 49 | "stat$INODE64" => { | |
| 51 | 50 | let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; |
| 52 | 51 | let result = this.stat(path, buf)?; |
| 53 | 52 | this.write_scalar(result, dest)?; |
| 54 | 53 | } |
| 55 | "lstat" | "lstat$INODE64" => { | |
| 56 | // FIXME: This does not have a direct test (#3179). | |
| 54 | "lstat$INODE64" => { | |
| 57 | 55 | let [path, buf] = this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; |
| 58 | 56 | let result = this.lstat(path, buf)?; |
| 59 | 57 | this.write_scalar(result, dest)?; |
src/tools/miri/src/shims/unix/socket.rs+2-2| ... | ... | @@ -316,10 +316,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 316 | 316 | flags |
| 317 | 317 | ); |
| 318 | 318 | } |
| 319 | if protocol != 0 { | |
| 319 | if protocol != 0 && protocol != this.eval_libc_i32("IPPROTO_TCP") { | |
| 320 | 320 | throw_unsup_format!( |
| 321 | 321 | "socket: socket protocol {protocol} is unsupported, \ |
| 322 | only 0 is allowed" | |
| 322 | only IPPROTO_TCP and 0 are allowed" | |
| 323 | 323 | ); |
| 324 | 324 | } |
| 325 | 325 |
src/tools/miri/src/shims/x86/avx512.rs+10-1| ... | ... | @@ -3,7 +3,9 @@ use rustc_middle::ty::Ty; |
| 3 | 3 | use rustc_span::Symbol; |
| 4 | 4 | use rustc_target::callconv::FnAbi; |
| 5 | 5 | |
| 6 | use super::{packssdw, packsswb, packusdw, packuswb, permute, pmaddbw, pmaddwd, psadbw, pshufb}; | |
| 6 | use super::{ | |
| 7 | packssdw, packsswb, packusdw, packuswb, permute, permute2, pmaddbw, pmaddwd, psadbw, pshufb, | |
| 8 | }; | |
| 7 | 9 | use crate::*; |
| 8 | 10 | |
| 9 | 11 | impl<'tcx> EvalContextExt<'tcx> for crate::MiriInterpCx<'tcx> {} |
| ... | ... | @@ -111,6 +113,13 @@ pub(super) trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> { |
| 111 | 113 | |
| 112 | 114 | permute(this, left, right, dest)?; |
| 113 | 115 | } |
| 116 | // Used to implement the _mm512_permutex2var_epi64 intrinsic. | |
| 117 | "vpermi2var.q.512" => { | |
| 118 | let [left, indices, right] = | |
| 119 | this.check_shim_sig_lenient(abi, CanonAbi::C, link_name, args)?; | |
| 120 | ||
| 121 | permute2(this, left, indices, right, dest)?; | |
| 122 | } | |
| 114 | 123 | // Used to implement the _mm512_shuffle_epi8 intrinsic. |
| 115 | 124 | "pshuf.b.512" => { |
| 116 | 125 | let [left, right] = |
src/tools/miri/src/shims/x86/mod.rs+48| ... | ... | @@ -1107,6 +1107,54 @@ fn permute<'tcx>( |
| 1107 | 1107 | interp_ok(()) |
| 1108 | 1108 | } |
| 1109 | 1109 | |
| 1110 | /// Shuffle elements from *two* source registers (`left` and `right`) using | |
| 1111 | /// the corresponding index in `indices`, and store the results in `dest`. | |
| 1112 | /// | |
| 1113 | /// For a vector with `N` lanes, the low `log2(N)` bits of each index select a | |
| 1114 | /// lane within a source vector. Bit `log2(N)` selects the source vector (`0` => | |
| 1115 | /// `left`, `1` => `right`), and all higher bits are ignored. | |
| 1116 | /// Equivalently, lane `i` of the result is copied from | |
| 1117 | /// `src[indices[i] & (N - 1)]` where | |
| 1118 | /// `src = if indices[i] & N == 0 { left } else { right }`. | |
| 1119 | /// | |
| 1120 | /// <https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm512_permutex2var_epi64> | |
| 1121 | fn permute2<'tcx>( | |
| 1122 | ecx: &mut crate::MiriInterpCx<'tcx>, | |
| 1123 | left: &OpTy<'tcx>, | |
| 1124 | indices: &OpTy<'tcx>, | |
| 1125 | right: &OpTy<'tcx>, | |
| 1126 | dest: &MPlaceTy<'tcx>, | |
| 1127 | ) -> InterpResult<'tcx, ()> { | |
| 1128 | let (left, left_len) = ecx.project_to_simd(left)?; | |
| 1129 | let (indices, indices_len) = ecx.project_to_simd(indices)?; | |
| 1130 | let (right, right_len) = ecx.project_to_simd(right)?; | |
| 1131 | let (dest, dest_len) = ecx.project_to_simd(dest)?; | |
| 1132 | ||
| 1133 | assert_eq!(dest_len, left_len); | |
| 1134 | assert_eq!(dest_len, indices_len); | |
| 1135 | assert_eq!(dest_len, right_len); | |
| 1136 | ||
| 1137 | // Use the low bits to select a lane within either input vector, and the next bit to | |
| 1138 | // choose between the two vectors. | |
| 1139 | assert!(dest_len.is_power_of_two()); | |
| 1140 | let lane_mask = u128::from(dest_len).strict_sub(1); | |
| 1141 | let vector_select_bit = u128::from(dest_len); | |
| 1142 | ||
| 1143 | for i in 0..dest_len { | |
| 1144 | let dest = ecx.project_index(&dest, i)?; | |
| 1145 | let index_place = ecx.project_index(&indices, i)?; | |
| 1146 | let index = ecx.read_scalar(&index_place)?.to_uint(index_place.layout.size)?; | |
| 1147 | // `lane_mask` is at most `dest_len - 1` which fits in a `u64`, so this cannot fail. | |
| 1148 | let lane = u64::try_from(index & lane_mask).unwrap(); | |
| 1149 | let src = if index & vector_select_bit == 0 { &left } else { &right }; | |
| 1150 | let element = ecx.project_index(src, lane)?; | |
| 1151 | ||
| 1152 | ecx.copy_op(&element, &dest)?; | |
| 1153 | } | |
| 1154 | ||
| 1155 | interp_ok(()) | |
| 1156 | } | |
| 1157 | ||
| 1110 | 1158 | /// Multiplies packed 16-bit signed integer values, truncates the 32-bit |
| 1111 | 1159 | /// product to the 18 most significant bits by right-shifting, and then |
| 1112 | 1160 | /// divides the 18-bit value by 2 (rounding to nearest) by first adding |
src/tools/miri/tests/fail/both_borrows/aliasing_mut1.rs+3-1| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_iwrites | |
| 2 | 2 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | //@[tree_iwrites]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 3 | 4 | use std::mem; |
| 4 | 5 | |
| 5 | 6 | fn safe(x: &mut i32, y: &mut i32) { |
| 6 | 7 | //~[stack]^ ERROR: protect |
| 8 | //~[tree_iwrites]^^ ERROR: /Undefined Behavior: reborrow through .* at .* is forbidden/ | |
| 7 | 9 | *x = 1; //~[tree] ERROR: /write access through .* is forbidden/ |
| 8 | 10 | *y = 2; |
| 9 | 11 | } |
src/tools/miri/tests/fail/both_borrows/aliasing_mut1.tree_iwrites.stderr created+31| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | error: Undefined Behavior: reborrow through <TAG> at ALLOC[0x0] is forbidden | |
| 2 | --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC | |
| 3 | | | |
| 4 | LL | fn safe(x: &mut i32, y: &mut i32) { | |
| 5 | | ^ Undefined Behavior occurred here | |
| 6 | | | |
| 7 | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental | |
| 8 | = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information | |
| 9 | = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child) | |
| 10 | = help: this reborrow (acting as a foreign write access) would cause the protected tag <TAG> (currently Unique) to become Disabled | |
| 11 | = help: protected tags must never be Disabled | |
| 12 | help: the accessed tag <TAG> was created here | |
| 13 | --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC | |
| 14 | | | |
| 15 | LL | let xraw: *mut i32 = unsafe { mem::transmute(&mut x) }; | |
| 16 | | ^^^^^^ | |
| 17 | help: the protected tag <TAG> was created here, in the initial state Reserved | |
| 18 | --> tests/fail/both_borrows/aliasing_mut1.rs:LL:CC | |
| 19 | | | |
| 20 | LL | fn safe(x: &mut i32, y: &mut i32) { | |
| 21 | | ^ | |
| 22 | = note: stack backtrace: | |
| 23 | 0: safe | |
| 24 | at tests/fail/both_borrows/aliasing_mut1.rs:LL:CC | |
| 25 | 1: main | |
| 26 | at tests/fail/both_borrows/aliasing_mut1.rs:LL:CC | |
| 27 | ||
| 28 | note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | |
| 29 | ||
| 30 | error: aborting due to 1 previous error | |
| 31 |
src/tools/miri/tests/fail/both_borrows/aliasing_mut2.rs+3-1| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_iwrites | |
| 2 | 2 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | //@[tree_iwrites]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 3 | 4 | use std::mem; |
| 4 | 5 | |
| 5 | 6 | fn safe(x: &i32, y: &mut i32) { |
| 6 | 7 | //~[stack]^ ERROR: protect |
| 8 | //~[tree_iwrites]^^ ERROR: /Undefined Behavior: reborrow through .* at .* is forbidden/ | |
| 7 | 9 | let _v = *x; |
| 8 | 10 | *y = 2; //~[tree] ERROR: /write access through .* is forbidden/ |
| 9 | 11 | } |
src/tools/miri/tests/fail/both_borrows/aliasing_mut2.tree_iwrites.stderr created+31| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | error: Undefined Behavior: reborrow through <TAG> at ALLOC[0x0] is forbidden | |
| 2 | --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC | |
| 3 | | | |
| 4 | LL | fn safe(x: &i32, y: &mut i32) { | |
| 5 | | ^ Undefined Behavior occurred here | |
| 6 | | | |
| 7 | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental | |
| 8 | = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information | |
| 9 | = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child) | |
| 10 | = help: this reborrow (acting as a foreign write access) would cause the protected tag <TAG> (currently Frozen) to become Disabled | |
| 11 | = help: protected tags must never be Disabled | |
| 12 | help: the accessed tag <TAG> was created here | |
| 13 | --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC | |
| 14 | | | |
| 15 | LL | let xref = &mut x; | |
| 16 | | ^^^^^^ | |
| 17 | help: the protected tag <TAG> was created here, in the initial state Frozen | |
| 18 | --> tests/fail/both_borrows/aliasing_mut2.rs:LL:CC | |
| 19 | | | |
| 20 | LL | fn safe(x: &i32, y: &mut i32) { | |
| 21 | | ^ | |
| 22 | = note: stack backtrace: | |
| 23 | 0: safe | |
| 24 | at tests/fail/both_borrows/aliasing_mut2.rs:LL:CC | |
| 25 | 1: main | |
| 26 | at tests/fail/both_borrows/aliasing_mut2.rs:LL:CC | |
| 27 | ||
| 28 | note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | |
| 29 | ||
| 30 | error: aborting due to 1 previous error | |
| 31 |
src/tools/miri/tests/fail/both_borrows/aliasing_mut3.rs+3-1| ... | ... | @@ -1,9 +1,11 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_iwrites | |
| 2 | 2 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | //@[tree_iwrites]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 3 | 4 | use std::mem; |
| 4 | 5 | |
| 5 | 6 | fn safe(x: &mut i32, y: &i32) { |
| 6 | 7 | //~[stack]^ ERROR: borrow stack |
| 8 | //~[tree_iwrites]^^ ERROR: /Undefined Behavior: reborrow through .* at .* is forbidden/ | |
| 7 | 9 | *x = 1; //~[tree] ERROR: /write access through .* is forbidden/ |
| 8 | 10 | let _v = *y; |
| 9 | 11 | } |
src/tools/miri/tests/fail/both_borrows/aliasing_mut3.tree_iwrites.stderr created+30| ... | ... | @@ -0,0 +1,30 @@ |
| 1 | error: Undefined Behavior: reborrow through <TAG> at ALLOC[0x0] is forbidden | |
| 2 | --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC | |
| 3 | | | |
| 4 | LL | fn safe(x: &mut i32, y: &i32) { | |
| 5 | | ^ Undefined Behavior occurred here | |
| 6 | | | |
| 7 | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental | |
| 8 | = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information | |
| 9 | = help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access) | |
| 10 | help: the accessed tag <TAG> was created here, in the initial state Frozen | |
| 11 | --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC | |
| 12 | | | |
| 13 | LL | let xshr = &*xref; | |
| 14 | | ^^^^^^ | |
| 15 | help: the accessed tag <TAG> later transitioned to Disabled due to a reborrow (acting as a foreign write access) at offsets [0x0..0x4] | |
| 16 | --> tests/fail/both_borrows/aliasing_mut3.rs:LL:CC | |
| 17 | | | |
| 18 | LL | fn safe(x: &mut i32, y: &i32) { | |
| 19 | | ^ | |
| 20 | = help: this transition corresponds to a loss of read permissions | |
| 21 | = note: stack backtrace: | |
| 22 | 0: safe | |
| 23 | at tests/fail/both_borrows/aliasing_mut3.rs:LL:CC | |
| 24 | 1: main | |
| 25 | at tests/fail/both_borrows/aliasing_mut3.rs:LL:CC | |
| 26 | ||
| 27 | note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | |
| 28 | ||
| 29 | error: aborting due to 1 previous error | |
| 30 |
src/tools/miri/tests/fail/both_borrows/aliasing_mut4.rs+3-1| ... | ... | @@ -1,12 +1,14 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_iwrites | |
| 2 | 2 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 3 | //@[tree]error-in-other-file: /write access through .* is forbidden/ |
| 4 | //@[tree_iwrites]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 4 | 5 | use std::cell::Cell; |
| 5 | 6 | use std::mem; |
| 6 | 7 | |
| 7 | 8 | // Make sure &mut UnsafeCell also is exclusive |
| 8 | 9 | fn safe(x: &i32, y: &mut Cell<i32>) { |
| 9 | 10 | //~[stack]^ ERROR: protect |
| 11 | //~[tree_iwrites]^^ ERROR: /Undefined Behavior: reborrow through .* at .* is forbidden/ | |
| 10 | 12 | y.set(1); |
| 11 | 13 | let _load = *x; |
| 12 | 14 | } |
src/tools/miri/tests/fail/both_borrows/aliasing_mut4.tree_iwrites.stderr created+31| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | error: Undefined Behavior: reborrow through <TAG> at ALLOC[0x0] is forbidden | |
| 2 | --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | |
| 3 | | | |
| 4 | LL | fn safe(x: &i32, y: &mut Cell<i32>) { | |
| 5 | | ^ Undefined Behavior occurred here | |
| 6 | | | |
| 7 | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental | |
| 8 | = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information | |
| 9 | = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child) | |
| 10 | = help: this reborrow (acting as a foreign write access) would cause the protected tag <TAG> (currently Frozen) to become Disabled | |
| 11 | = help: protected tags must never be Disabled | |
| 12 | help: the accessed tag <TAG> was created here | |
| 13 | --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | |
| 14 | | | |
| 15 | LL | let xref = &mut x; | |
| 16 | | ^^^^^^ | |
| 17 | help: the protected tag <TAG> was created here, in the initial state Frozen | |
| 18 | --> tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | |
| 19 | | | |
| 20 | LL | fn safe(x: &i32, y: &mut Cell<i32>) { | |
| 21 | | ^ | |
| 22 | = note: stack backtrace: | |
| 23 | 0: safe | |
| 24 | at tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | |
| 25 | 1: main | |
| 26 | at tests/fail/both_borrows/aliasing_mut4.rs:LL:CC | |
| 27 | ||
| 28 | note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | |
| 29 | ||
| 30 | error: aborting due to 1 previous error | |
| 31 |
src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.rs+2| ... | ... | @@ -1,4 +1,6 @@ |
| 1 | 1 | //! A version of `cell_inside_struct` that dumps the tree so that we can see what is happening. |
| 2 | //@revisions: tree tree_implicit_writes | |
| 3 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows-implicit-writes | |
| 2 | 4 | //@compile-flags: -Zmiri-tree-borrows |
| 3 | 5 | #[path = "../../utils/mod.rs"] |
| 4 | 6 | #[macro_use] |
src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.stderr deleted-25| ... | ... | @@ -1,25 +0,0 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 4.. 8 | |
| 4 | | Act | Act | └─┬──<TAG=root of the allocation> | |
| 5 | | Frz |?Cel | └────<TAG=a> | |
| 6 | ────────────────────────────────────────────────── | |
| 7 | error: Undefined Behavior: write access through <TAG> (a) at ALLOC[0x0] is forbidden | |
| 8 | --> tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC | |
| 9 | | | |
| 10 | LL | (*a).field1 = 88; | |
| 11 | | ^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | |
| 12 | | | |
| 13 | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental | |
| 14 | = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information | |
| 15 | = help: the accessed tag <TAG> (a) has state Frozen which forbids this child write access | |
| 16 | help: the accessed tag <TAG> was created here, in the initial state Cell | |
| 17 | --> tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC | |
| 18 | | | |
| 19 | LL | let a = &root; | |
| 20 | | ^^^^^ | |
| 21 | ||
| 22 | note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | |
| 23 | ||
| 24 | error: aborting due to 1 previous error | |
| 25 |
src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.tree.stderr created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 4.. 8 | |
| 4 | | Act | Act | └─┬──<TAG=root of the allocation> | |
| 5 | | Frz |?Cel | └────<TAG=a> | |
| 6 | ────────────────────────────────────────────────── | |
| 7 | error: Undefined Behavior: write access through <TAG> (a) at ALLOC[0x0] is forbidden | |
| 8 | --> tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC | |
| 9 | | | |
| 10 | LL | (*a).field1 = 88; | |
| 11 | | ^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | |
| 12 | | | |
| 13 | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental | |
| 14 | = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information | |
| 15 | = help: the accessed tag <TAG> (a) has state Frozen which forbids this child write access | |
| 16 | help: the accessed tag <TAG> was created here, in the initial state Cell | |
| 17 | --> tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC | |
| 18 | | | |
| 19 | LL | let a = &root; | |
| 20 | | ^^^^^ | |
| 21 | ||
| 22 | note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | |
| 23 | ||
| 24 | error: aborting due to 1 previous error | |
| 25 |
src/tools/miri/tests/fail/tree_borrows/cell-inside-struct.tree_implicit_writes.stderr created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 4.. 8 | |
| 4 | | Act | Act | └─┬──<TAG=root of the allocation> | |
| 5 | | Frz |?Cel | └────<TAG=a> | |
| 6 | ────────────────────────────────────────────────── | |
| 7 | error: Undefined Behavior: write access through <TAG> (a) at ALLOC[0x0] is forbidden | |
| 8 | --> tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC | |
| 9 | | | |
| 10 | LL | (*a).field1 = 88; | |
| 11 | | ^^^^^^^^^^^^^^^^ Undefined Behavior occurred here | |
| 12 | | | |
| 13 | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental | |
| 14 | = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information | |
| 15 | = help: the accessed tag <TAG> (a) has state Frozen which forbids this child write access | |
| 16 | help: the accessed tag <TAG> was created here, in the initial state Cell | |
| 17 | --> tests/fail/tree_borrows/cell-inside-struct.rs:LL:CC | |
| 18 | | | |
| 19 | LL | let a = &root; | |
| 20 | | ^^^^^ | |
| 21 | ||
| 22 | note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | |
| 23 | ||
| 24 | error: aborting due to 1 previous error | |
| 25 |
src/tools/miri/tests/fail/tree_borrows/implicit_writes/as_mut_ptr.rs created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | // This code no longer works using implicit writes in tree borrows. | |
| 2 | // This code tests that. The passing version is in `pass/tree_borrows/implicit_writes/as_mut_ptr.rs`. | |
| 3 | //@compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 4 | ||
| 5 | fn main() { | |
| 6 | let mut x: [u8; 3] = [1, 2, 3]; | |
| 7 | ||
| 8 | let ptr = std::ptr::from_mut(&mut x); | |
| 9 | let a = unsafe { &mut *ptr }; | |
| 10 | let b = unsafe { &mut *ptr }; | |
| 11 | ||
| 12 | let _c = as_mut_ptr(a); | |
| 13 | println!("{:?}", *b); //~ ERROR: /Undefined Behavior: reborrow through .* at .* is forbidden/ | |
| 14 | } | |
| 15 | ||
| 16 | pub const fn as_mut_ptr(x: &mut [u8; 3]) -> *mut u8 { | |
| 17 | x as *mut [u8] as *mut u8 | |
| 18 | } |
src/tools/miri/tests/fail/tree_borrows/implicit_writes/as_mut_ptr.stderr created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | error: Undefined Behavior: reborrow through <TAG> at ALLOC[0x0] is forbidden | |
| 2 | --> tests/fail/tree_borrows/implicit_writes/as_mut_ptr.rs:LL:CC | |
| 3 | | | |
| 4 | LL | println!("{:?}", *b); | |
| 5 | | ^^ Undefined Behavior occurred here | |
| 6 | | | |
| 7 | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental | |
| 8 | = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information | |
| 9 | = help: the accessed tag <TAG> has state Disabled which forbids this reborrow (acting as a child read access) | |
| 10 | help: the accessed tag <TAG> was created here, in the initial state Reserved | |
| 11 | --> tests/fail/tree_borrows/implicit_writes/as_mut_ptr.rs:LL:CC | |
| 12 | | | |
| 13 | LL | let b = unsafe { &mut *ptr }; | |
| 14 | | ^^^^^^^^^ | |
| 15 | help: the accessed tag <TAG> later transitioned to Disabled due to a reborrow (acting as a foreign write access) at offsets [0x0..0x3] | |
| 16 | --> tests/fail/tree_borrows/implicit_writes/as_mut_ptr.rs:LL:CC | |
| 17 | | | |
| 18 | LL | pub const fn as_mut_ptr(x: &mut [u8; 3]) -> *mut u8 { | |
| 19 | | ^ | |
| 20 | = help: this transition corresponds to a loss of read and write permissions | |
| 21 | ||
| 22 | note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | |
| 23 | ||
| 24 | error: aborting due to 1 previous error | |
| 25 |
src/tools/miri/tests/fail/tree_borrows/implicit_writes/fnentry_invalidation.rs created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | //@compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | // This test is identical to `fail/stacked_borrows/fnentry_invalidation.rs`. | |
| 3 | // This test shows that when `-Zmiri-tree-borrows-implicit-writes` is enabled, Tree Borrows behaves more like Stacked Borrows, and the additional write in `fail/tree_borrows/fnentry_invalidation.rs` is not needed to detect / cause UB. | |
| 4 | ||
| 5 | fn main() { | |
| 6 | let mut x = 0i32; | |
| 7 | let z = &mut x as *mut i32; | |
| 8 | x.do_bad(); | |
| 9 | unsafe { | |
| 10 | let _oof = *z; //~ ERROR: /read access through .* at .* is forbidden/ | |
| 11 | } | |
| 12 | } | |
| 13 | ||
| 14 | trait Bad { | |
| 15 | fn do_bad(&mut self) { | |
| 16 | // who knows | |
| 17 | } | |
| 18 | } | |
| 19 | ||
| 20 | impl Bad for i32 {} |
src/tools/miri/tests/fail/tree_borrows/implicit_writes/fnentry_invalidation.stderr created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | error: Undefined Behavior: read access through <TAG> at ALLOC[0x0] is forbidden | |
| 2 | --> tests/fail/tree_borrows/implicit_writes/fnentry_invalidation.rs:LL:CC | |
| 3 | | | |
| 4 | LL | let _oof = *z; | |
| 5 | | ^^ Undefined Behavior occurred here | |
| 6 | | | |
| 7 | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental | |
| 8 | = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information | |
| 9 | = help: the accessed tag <TAG> has state Disabled which forbids this child read access | |
| 10 | help: the accessed tag <TAG> was created here, in the initial state Reserved | |
| 11 | --> tests/fail/tree_borrows/implicit_writes/fnentry_invalidation.rs:LL:CC | |
| 12 | | | |
| 13 | LL | let z = &mut x as *mut i32; | |
| 14 | | ^^^^^^ | |
| 15 | help: the accessed tag <TAG> later transitioned to Disabled due to a reborrow (acting as a foreign write access) at offsets [0x0..0x4] | |
| 16 | --> tests/fail/tree_borrows/implicit_writes/fnentry_invalidation.rs:LL:CC | |
| 17 | | | |
| 18 | LL | fn do_bad(&mut self) { | |
| 19 | | ^^^^^^^^^ | |
| 20 | = help: this transition corresponds to a loss of read and write permissions | |
| 21 | ||
| 22 | note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | |
| 23 | ||
| 24 | error: aborting due to 1 previous error | |
| 25 |
src/tools/miri/tests/fail/tree_borrows/implicit_writes/ptr_write.rs created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | // Tests that UB is detected for reading from a mutable reference by another pointer (as there could be a write on that mutable reference now) | |
| 2 | //@compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 3 | ||
| 4 | fn main() { | |
| 5 | let mut x = 0u8; | |
| 6 | let ptr = &raw mut x; | |
| 7 | let res = dereference(&mut x, ptr); | |
| 8 | assert_eq!(*res, 0); | |
| 9 | } | |
| 10 | ||
| 11 | fn dereference<T>(x: T, y: *mut u8) -> T { | |
| 12 | // miri inserts an implicit write here | |
| 13 | let _ = unsafe { *y }; //~ ERROR: read access | |
| 14 | // x = 42; // we'd like to add this write, so there must already be UB without it because there sure is with it. | |
| 15 | x | |
| 16 | } |
src/tools/miri/tests/fail/tree_borrows/implicit_writes/ptr_write.stderr created+31| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | error: Undefined Behavior: read access through <TAG> (root of the allocation) at ALLOC[0x0] is forbidden | |
| 2 | --> tests/fail/tree_borrows/implicit_writes/ptr_write.rs:LL:CC | |
| 3 | | | |
| 4 | LL | let _ = unsafe { *y }; | |
| 5 | | ^^ Undefined Behavior occurred here | |
| 6 | | | |
| 7 | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental | |
| 8 | = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information | |
| 9 | = help: the accessed tag <TAG> (root of the allocation) is foreign to the protected tag <TAG> (i.e., it is not a child) | |
| 10 | = help: this foreign read access would cause the protected tag <TAG> (currently Unique) to become Disabled | |
| 11 | = help: protected tags must never be Disabled | |
| 12 | help: the accessed tag <TAG> was created here | |
| 13 | --> tests/fail/tree_borrows/implicit_writes/ptr_write.rs:LL:CC | |
| 14 | | | |
| 15 | LL | let ptr = &raw mut x; | |
| 16 | | ^^^^^^^^^^ | |
| 17 | help: the protected tag <TAG> was created here, in the initial state Reserved | |
| 18 | --> tests/fail/tree_borrows/implicit_writes/ptr_write.rs:LL:CC | |
| 19 | | | |
| 20 | LL | fn dereference<T>(x: T, y: *mut u8) -> T { | |
| 21 | | ^ | |
| 22 | = note: stack backtrace: | |
| 23 | 0: dereference | |
| 24 | at tests/fail/tree_borrows/implicit_writes/ptr_write.rs:LL:CC | |
| 25 | 1: main | |
| 26 | at tests/fail/tree_borrows/implicit_writes/ptr_write.rs:LL:CC | |
| 27 | ||
| 28 | note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | |
| 29 | ||
| 30 | error: aborting due to 1 previous error | |
| 31 |
src/tools/miri/tests/fail/tree_borrows/implicit_writes/ptr_write_box.rs created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | // same test as `ptr_write.rs` but with `Box` | |
| 2 | //@compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 3 | ||
| 4 | fn main() { | |
| 5 | let mut x: Box<u8> = Box::new(0u8); | |
| 6 | let ptr = &raw mut *x; | |
| 7 | let res = dereference(x, ptr); | |
| 8 | assert_eq!(*res, 0); | |
| 9 | } | |
| 10 | ||
| 11 | fn dereference<T>(x: T, y: *mut u8) -> T { | |
| 12 | // miri inserts an implicit write here | |
| 13 | let _ = unsafe { *y }; //~ ERROR: read access | |
| 14 | // x = 42; // we'd like to add this write, so there must already be UB without it because there sure is with it. | |
| 15 | x | |
| 16 | } |
src/tools/miri/tests/fail/tree_borrows/implicit_writes/ptr_write_box.stderr created+31| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | error: Undefined Behavior: read access through <TAG> at ALLOC[0x0] is forbidden | |
| 2 | --> tests/fail/tree_borrows/implicit_writes/ptr_write_box.rs:LL:CC | |
| 3 | | | |
| 4 | LL | let _ = unsafe { *y }; | |
| 5 | | ^^ Undefined Behavior occurred here | |
| 6 | | | |
| 7 | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental | |
| 8 | = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information | |
| 9 | = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child) | |
| 10 | = help: this foreign read access would cause the protected tag <TAG> (currently Unique) to become Disabled | |
| 11 | = help: protected tags must never be Disabled | |
| 12 | help: the accessed tag <TAG> was created here | |
| 13 | --> tests/fail/tree_borrows/implicit_writes/ptr_write_box.rs:LL:CC | |
| 14 | | | |
| 15 | LL | let mut x: Box<u8> = Box::new(0u8); | |
| 16 | | ^^^^^^^^^^^^^ | |
| 17 | help: the protected tag <TAG> was created here, in the initial state Reserved | |
| 18 | --> tests/fail/tree_borrows/implicit_writes/ptr_write_box.rs:LL:CC | |
| 19 | | | |
| 20 | LL | fn dereference<T>(x: T, y: *mut u8) -> T { | |
| 21 | | ^ | |
| 22 | = note: stack backtrace: | |
| 23 | 0: dereference | |
| 24 | at tests/fail/tree_borrows/implicit_writes/ptr_write_box.rs:LL:CC | |
| 25 | 1: main | |
| 26 | at tests/fail/tree_borrows/implicit_writes/ptr_write_box.rs:LL:CC | |
| 27 | ||
| 28 | note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | |
| 29 | ||
| 30 | error: aborting due to 1 previous error | |
| 31 |
src/tools/miri/tests/fail/tree_borrows/implicit_writes/ptr_write_unsafe_cell.rs created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | // same test as `ptr_write.rs` but with `UnsafeCell` | |
| 2 | //@compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 3 | ||
| 4 | use std::cell::UnsafeCell; | |
| 5 | ||
| 6 | fn main() { | |
| 7 | let mut x: UnsafeCell<u8> = 0u8.into(); | |
| 8 | let ptr = x.get(); | |
| 9 | let res = dereference(&mut x, ptr); | |
| 10 | assert_eq!(*res.get_mut(), 0); | |
| 11 | } | |
| 12 | ||
| 13 | fn dereference<T>(x: T, y: *mut u8) -> T { | |
| 14 | // miri inserts an implicit write here | |
| 15 | let _ = unsafe { *y }; //~ ERROR: read access | |
| 16 | // x = 42; // we'd like to add this write, so there must already be UB without it because there sure is with it. | |
| 17 | x | |
| 18 | } |
src/tools/miri/tests/fail/tree_borrows/implicit_writes/ptr_write_unsafe_cell.stderr created+31| ... | ... | @@ -0,0 +1,31 @@ |
| 1 | error: Undefined Behavior: read access through <TAG> at ALLOC[0x0] is forbidden | |
| 2 | --> tests/fail/tree_borrows/implicit_writes/ptr_write_unsafe_cell.rs:LL:CC | |
| 3 | | | |
| 4 | LL | let _ = unsafe { *y }; | |
| 5 | | ^^ Undefined Behavior occurred here | |
| 6 | | | |
| 7 | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Tree Borrows rules it violated are still experimental | |
| 8 | = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/tree-borrows.md for further information | |
| 9 | = help: the accessed tag <TAG> is foreign to the protected tag <TAG> (i.e., it is not a child) | |
| 10 | = help: this foreign read access would cause the protected tag <TAG> (currently Unique) to become Disabled | |
| 11 | = help: protected tags must never be Disabled | |
| 12 | help: the accessed tag <TAG> was created here | |
| 13 | --> tests/fail/tree_borrows/implicit_writes/ptr_write_unsafe_cell.rs:LL:CC | |
| 14 | | | |
| 15 | LL | let ptr = x.get(); | |
| 16 | | ^^^^^^^ | |
| 17 | help: the protected tag <TAG> was created here, in the initial state Reserved | |
| 18 | --> tests/fail/tree_borrows/implicit_writes/ptr_write_unsafe_cell.rs:LL:CC | |
| 19 | | | |
| 20 | LL | fn dereference<T>(x: T, y: *mut u8) -> T { | |
| 21 | | ^ | |
| 22 | = note: stack backtrace: | |
| 23 | 0: dereference | |
| 24 | at tests/fail/tree_borrows/implicit_writes/ptr_write_unsafe_cell.rs:LL:CC | |
| 25 | 1: main | |
| 26 | at tests/fail/tree_borrows/implicit_writes/ptr_write_unsafe_cell.rs:LL:CC | |
| 27 | ||
| 28 | note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | |
| 29 | ||
| 30 | error: aborting due to 1 previous error | |
| 31 |
src/tools/miri/tests/fail/tree_borrows/implicit_writes/retag_is_race.rs created+47| ... | ... | @@ -0,0 +1,47 @@ |
| 1 | // This is mostly the same test as `tests/pass/tree_borrows/retag_no_race.rs`, but it now fails under implicit writes, meaning that there is now Undefined Behaviour. It has been changed slightly have the same interleaving on all targets. | |
| 2 | //@compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 3 | // This test relies on a specific interleaving that cannot be enforced with just barriers. We must remove preemption so that the execution and the error messages are deterministic. | |
| 4 | //@compile-flags: -Zmiri-deterministic-concurrency | |
| 5 | use std::ptr::addr_of_mut; | |
| 6 | use std::sync::{Arc, Barrier}; | |
| 7 | use std::thread; | |
| 8 | ||
| 9 | #[derive(Copy, Clone)] | |
| 10 | struct SendPtr(*mut u8); | |
| 11 | ||
| 12 | unsafe impl Send for SendPtr {} | |
| 13 | ||
| 14 | fn thread_1(x: SendPtr, barrier: Arc<Barrier>) { | |
| 15 | let x = unsafe { &mut *x.0 }; | |
| 16 | barrier.wait(); // init | |
| 17 | ||
| 18 | let _v = *x; | |
| 19 | ||
| 20 | barrier.wait(); // write | |
| 21 | } | |
| 22 | ||
| 23 | fn thread_2(y: SendPtr, barrier: Arc<Barrier>) { | |
| 24 | let y = unsafe { &mut *y.0 }; | |
| 25 | barrier.wait(); // init | |
| 26 | thread::yield_now(); // force other thread to read first | |
| 27 | ||
| 28 | fn write(y: &mut u8, v: u8, barrier: &Arc<Barrier>) { | |
| 29 | //~^ ERROR: /Undefined Behavior: Data race detected between .* non-atomic read on thread .* and .* retag write of type .* on thread .* at .*/ | |
| 30 | barrier.wait(); // write | |
| 31 | *y = v; | |
| 32 | } | |
| 33 | write(&mut *y, 42, &barrier); | |
| 34 | } | |
| 35 | ||
| 36 | fn main() { | |
| 37 | let mut data = 0u8; | |
| 38 | let p = SendPtr(addr_of_mut!(data)); | |
| 39 | let barrier = Arc::new(Barrier::new(2)); | |
| 40 | let b1 = Arc::clone(&barrier); | |
| 41 | let b2 = Arc::clone(&barrier); | |
| 42 | ||
| 43 | let h1 = thread::spawn(move || thread_1(p, b1)); | |
| 44 | let h2 = thread::spawn(move || thread_2(p, b2)); | |
| 45 | h1.join().unwrap(); | |
| 46 | h2.join().unwrap(); | |
| 47 | } |
src/tools/miri/tests/fail/tree_borrows/implicit_writes/retag_is_race.stderr created+34| ... | ... | @@ -0,0 +1,34 @@ |
| 1 | error: Undefined Behavior: Data race detected between (1) non-atomic read on thread `unnamed-ID` and (2) retag write of type `u8` on thread `unnamed-ID` at ALLOC | |
| 2 | --> tests/fail/tree_borrows/implicit_writes/retag_is_race.rs:LL:CC | |
| 3 | | | |
| 4 | LL | fn write(y: &mut u8, v: u8, barrier: &Arc<Barrier>) { | |
| 5 | | ^ (2) just happened here | |
| 6 | | | |
| 7 | help: and (1) occurred earlier here | |
| 8 | --> tests/fail/tree_borrows/implicit_writes/retag_is_race.rs:LL:CC | |
| 9 | | | |
| 10 | LL | let _v = *x; | |
| 11 | | ^^ | |
| 12 | = help: retags occur on all (re)borrows and as well as when references are copied or moved | |
| 13 | = help: retags permit optimizations that insert speculative reads or writes | |
| 14 | = help: therefore from the perspective of data races, a retag has the same implications as a read or write | |
| 15 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior | |
| 16 | = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information | |
| 17 | = note: this is on thread `unnamed-ID` | |
| 18 | = note: stack backtrace: | |
| 19 | 0: thread_2::write | |
| 20 | at tests/fail/tree_borrows/implicit_writes/retag_is_race.rs:LL:CC | |
| 21 | 1: thread_2 | |
| 22 | at tests/fail/tree_borrows/implicit_writes/retag_is_race.rs:LL:CC | |
| 23 | 2: main::{closure#1} | |
| 24 | at tests/fail/tree_borrows/implicit_writes/retag_is_race.rs:LL:CC | |
| 25 | note: the last function in that backtrace got called indirectly due to this code | |
| 26 | --> tests/fail/tree_borrows/implicit_writes/retag_is_race.rs:LL:CC | |
| 27 | | | |
| 28 | LL | let h2 = thread::spawn(move || thread_2(p, b2)); | |
| 29 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 30 | ||
| 31 | note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | |
| 32 | ||
| 33 | error: aborting due to 1 previous error | |
| 34 |
src/tools/miri/tests/fail/tree_borrows/implicit_writes/static_memory_modification.rs created+11| ... | ... | @@ -0,0 +1,11 @@ |
| 1 | // Tests that inserting an implicit write to a read-only allocation generates the correct error message. | |
| 2 | //@compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 3 | static X: usize = 5; | |
| 4 | ||
| 5 | #[allow(mutable_transmutes)] | |
| 6 | fn main() { | |
| 7 | let x = unsafe { std::mem::transmute::<&usize, &mut usize>(&X) }; | |
| 8 | foo(x); | |
| 9 | } | |
| 10 | ||
| 11 | fn foo(_x: &mut usize) {} //~ ERROR: writing to alloc1 which is read-only |
src/tools/miri/tests/fail/tree_borrows/implicit_writes/static_memory_modification.stderr created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | error: Undefined Behavior: writing to ALLOC which is read-only | |
| 2 | --> tests/fail/tree_borrows/implicit_writes/static_memory_modification.rs:LL:CC | |
| 3 | | | |
| 4 | LL | fn foo(_x: &mut usize) {} | |
| 5 | | ^^ Undefined Behavior occurred here | |
| 6 | | | |
| 7 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior | |
| 8 | = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information | |
| 9 | = note: stack backtrace: | |
| 10 | 0: foo | |
| 11 | at tests/fail/tree_borrows/implicit_writes/static_memory_modification.rs:LL:CC | |
| 12 | 1: main | |
| 13 | at tests/fail/tree_borrows/implicit_writes/static_memory_modification.rs:LL:CC | |
| 14 | ||
| 15 | note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace | |
| 16 | ||
| 17 | error: aborting due to 1 previous error | |
| 18 |
src/tools/miri/tests/pass-dep/libc/libc-fs.rs+206-14| ... | ... | @@ -43,6 +43,8 @@ fn main() { |
| 43 | 43 | #[cfg(target_os = "linux")] |
| 44 | 44 | test_sync_file_range(); |
| 45 | 45 | test_fstat(); |
| 46 | test_stat(); | |
| 47 | test_lstat(); | |
| 46 | 48 | test_isatty(); |
| 47 | 49 | test_read_and_uninit(); |
| 48 | 50 | test_nofollow_not_symlink(); |
| ... | ... | @@ -50,6 +52,147 @@ fn main() { |
| 50 | 52 | test_ioctl(); |
| 51 | 53 | test_opendir_closedir(); |
| 52 | 54 | test_readdir(); |
| 55 | #[cfg(target_os = "linux")] | |
| 56 | test_statx_on_file_path(); | |
| 57 | #[cfg(target_os = "linux")] | |
| 58 | test_statx_on_file_descriptor(); | |
| 59 | #[cfg(target_os = "linux")] | |
| 60 | test_statx_empty_path_on_pipe(); | |
| 61 | } | |
| 62 | ||
| 63 | #[cfg(target_os = "linux")] | |
| 64 | #[track_caller] | |
| 65 | fn assert_statx_matches_metadata(stx: &libc::statx, meta: &std::fs::Metadata, expected_size: u64) { | |
| 66 | use std::os::unix::fs::MetadataExt; | |
| 67 | let mask = stx.stx_mask; | |
| 68 | ||
| 69 | // Guaranteed by the shim on any Linux target. | |
| 70 | assert!(mask & libc::STATX_TYPE != 0); | |
| 71 | assert!(mask & libc::STATX_SIZE != 0); | |
| 72 | assert_eq!(stx.stx_size, expected_size); | |
| 73 | assert_eq!((stx.stx_mode as u32) & libc::S_IFMT, libc::S_IFREG); | |
| 74 | ||
| 75 | // Host-dependent enrichment: only assert when the mask says the field is real. | |
| 76 | if mask & libc::STATX_INO != 0 { | |
| 77 | assert_eq!(stx.stx_ino, meta.ino()); | |
| 78 | } | |
| 79 | if mask & libc::STATX_NLINK != 0 { | |
| 80 | assert_eq!(stx.stx_nlink as u64, meta.nlink()); | |
| 81 | } | |
| 82 | if mask & libc::STATX_UID != 0 { | |
| 83 | assert_eq!(stx.stx_uid, meta.uid()); | |
| 84 | } | |
| 85 | if mask & libc::STATX_GID != 0 { | |
| 86 | assert_eq!(stx.stx_gid, meta.gid()); | |
| 87 | } | |
| 88 | if mask & libc::STATX_BLOCKS != 0 { | |
| 89 | assert_eq!(stx.stx_blocks, meta.blocks()); | |
| 90 | } | |
| 91 | ||
| 92 | // We don't support non-S_IFMT bits in stx_mode. | |
| 93 | assert_eq!(mask & libc::STATX_MODE, 0); | |
| 94 | ||
| 95 | // Do not assert stx_blksize and stx_dev_* : there are no mask bits for them. | |
| 96 | } | |
| 97 | ||
| 98 | #[cfg(target_os = "linux")] | |
| 99 | fn test_statx_on_file_descriptor() { | |
| 100 | use std::mem::MaybeUninit; | |
| 101 | ||
| 102 | let bytes = b"hello"; | |
| 103 | let path = utils::prepare_with_content("miri_test_libc_statx_fd.txt", bytes); | |
| 104 | let file = File::open(&path).unwrap(); | |
| 105 | ||
| 106 | unsafe { | |
| 107 | let mut stx = MaybeUninit::<libc::statx>::zeroed(); | |
| 108 | let ret = libc::statx( | |
| 109 | file.as_raw_fd(), | |
| 110 | c"".as_ptr(), | |
| 111 | libc::AT_EMPTY_PATH, | |
| 112 | libc::STATX_BASIC_STATS | libc::STATX_BTIME, | |
| 113 | stx.as_mut_ptr(), | |
| 114 | ); | |
| 115 | assert_eq!(ret, 0, "statx failed: {}", std::io::Error::last_os_error()); | |
| 116 | ||
| 117 | let stx = stx.assume_init(); | |
| 118 | let meta = file.metadata().unwrap(); | |
| 119 | assert_statx_matches_metadata(&stx, &meta, bytes.len() as u64); | |
| 120 | } | |
| 121 | ||
| 122 | drop(file); | |
| 123 | remove_file(&path).unwrap(); | |
| 124 | } | |
| 125 | ||
| 126 | #[cfg(target_os = "linux")] | |
| 127 | fn test_statx_on_file_path() { | |
| 128 | use std::mem::MaybeUninit; | |
| 129 | ||
| 130 | let bytes = b"hello"; | |
| 131 | let path = utils::prepare_with_content("miri_test_libc_statx.txt", bytes); | |
| 132 | let c_path = CString::new(path.as_os_str().as_bytes()).expect("CString::new failed"); | |
| 133 | ||
| 134 | unsafe { | |
| 135 | let mut stx = MaybeUninit::<libc::statx>::zeroed(); | |
| 136 | let ret = libc::statx( | |
| 137 | libc::AT_FDCWD, | |
| 138 | c_path.as_ptr(), | |
| 139 | 0, | |
| 140 | libc::STATX_BASIC_STATS | libc::STATX_BTIME, | |
| 141 | stx.as_mut_ptr(), | |
| 142 | ); | |
| 143 | assert_eq!(ret, 0, "statx failed: {}", std::io::Error::last_os_error()); | |
| 144 | ||
| 145 | let stx = stx.assume_init(); | |
| 146 | let meta = std::fs::metadata(&path).unwrap(); | |
| 147 | assert_statx_matches_metadata(&stx, &meta, bytes.len() as u64); | |
| 148 | } | |
| 149 | ||
| 150 | remove_file(&path).unwrap(); | |
| 151 | } | |
| 152 | ||
| 153 | #[cfg(target_os = "linux")] | |
| 154 | fn test_statx_empty_path_on_pipe() { | |
| 155 | use libc_utils::errno_check; | |
| 156 | ||
| 157 | unsafe { | |
| 158 | let mut fds = [0; 2]; | |
| 159 | errno_check(libc::pipe(fds.as_mut_ptr())); | |
| 160 | ||
| 161 | let mut statx_buf = std::mem::MaybeUninit::<libc::statx>::zeroed(); | |
| 162 | ||
| 163 | let ret = libc::statx( | |
| 164 | fds[0], | |
| 165 | c"".as_ptr(), | |
| 166 | libc::AT_EMPTY_PATH, | |
| 167 | libc::STATX_BASIC_STATS, | |
| 168 | statx_buf.as_mut_ptr(), | |
| 169 | ); | |
| 170 | ||
| 171 | assert_eq!( | |
| 172 | ret, | |
| 173 | 0, | |
| 174 | "statx on pipe with AT_EMPTY_PATH failed: {}", | |
| 175 | std::io::Error::last_os_error() | |
| 176 | ); | |
| 177 | ||
| 178 | let statx_buf = statx_buf.assume_init(); | |
| 179 | ||
| 180 | assert_ne!(statx_buf.stx_mask & libc::STATX_TYPE, 0); | |
| 181 | assert_ne!(statx_buf.stx_mask & libc::STATX_SIZE, 0); | |
| 182 | assert_eq!(statx_buf.stx_mask & libc::STATX_MODE, 0); | |
| 183 | assert_eq!((statx_buf.stx_mode as libc::mode_t) & libc::S_IFMT, libc::S_IFIFO); | |
| 184 | assert_eq!(statx_buf.stx_size, 0); | |
| 185 | ||
| 186 | // Synthetic metadata must not advertise host-only fields. | |
| 187 | assert_eq!(statx_buf.stx_mask & libc::STATX_INO, 0); | |
| 188 | assert_eq!(statx_buf.stx_mask & libc::STATX_NLINK, 0); | |
| 189 | assert_eq!(statx_buf.stx_mask & libc::STATX_UID, 0); | |
| 190 | assert_eq!(statx_buf.stx_mask & libc::STATX_GID, 0); | |
| 191 | assert_eq!(statx_buf.stx_mask & libc::STATX_BLOCKS, 0); | |
| 192 | ||
| 193 | errno_check(libc::close(fds[0])); | |
| 194 | errno_check(libc::close(fds[1])); | |
| 195 | } | |
| 53 | 196 | } |
| 54 | 197 | |
| 55 | 198 | fn test_file_open_unix_allow_two_args() { |
| ... | ... | @@ -464,24 +607,55 @@ fn test_fstat() { |
| 464 | 607 | assert_eq!(stat.st_mode & libc::S_IFMT, libc::S_IFREG); |
| 465 | 608 | |
| 466 | 609 | // Check that all fields are initialized. |
| 467 | let _st_nlink = stat.st_nlink; | |
| 468 | let _st_blksize = stat.st_blksize; | |
| 469 | let _st_blocks = stat.st_blocks; | |
| 470 | let _st_ino = stat.st_ino; | |
| 471 | let _st_dev = stat.st_dev; | |
| 472 | let _st_uid = stat.st_uid; | |
| 473 | let _st_gid = stat.st_gid; | |
| 474 | let _st_rdev = stat.st_rdev; | |
| 475 | let _st_atime = stat.st_atime; | |
| 476 | let _st_mtime = stat.st_mtime; | |
| 477 | let _st_ctime = stat.st_ctime; | |
| 478 | let _st_atime_nsec = stat.st_atime_nsec; | |
| 479 | let _st_mtime_nsec = stat.st_mtime_nsec; | |
| 480 | let _st_ctime_nsec = stat.st_ctime_nsec; | |
| 610 | check_stat_fields(stat); | |
| 611 | ||
| 612 | remove_file(&path).unwrap(); | |
| 613 | } | |
| 614 | ||
| 615 | fn test_stat() { | |
| 616 | use std::mem::MaybeUninit; | |
| 617 | ||
| 618 | let path = utils::prepare_with_content("miri_test_libc_stat.txt", b"hello"); | |
| 619 | let cpath = CString::new(path.as_os_str().as_bytes()).unwrap(); | |
| 620 | ||
| 621 | let mut stat = MaybeUninit::<libc::stat>::uninit(); | |
| 622 | let res = unsafe { libc::stat(cpath.as_ptr(), stat.as_mut_ptr()) }; | |
| 623 | assert_eq!(res, 0); | |
| 624 | let stat = unsafe { stat.assume_init_ref() }; | |
| 625 | ||
| 626 | assert_eq!(stat.st_size, 5); | |
| 627 | assert_eq!(stat.st_mode & libc::S_IFMT, libc::S_IFREG); | |
| 628 | ||
| 629 | // Check that all fields are initialized. | |
| 630 | check_stat_fields(stat); | |
| 481 | 631 | |
| 482 | 632 | remove_file(&path).unwrap(); |
| 483 | 633 | } |
| 484 | 634 | |
| 635 | fn test_lstat() { | |
| 636 | use std::mem::MaybeUninit; | |
| 637 | ||
| 638 | let path = utils::prepare_with_content("miri_test_libc_lstat.txt", b"hello"); | |
| 639 | let symlink_path = utils::prepare("miri_test_libc_lstat_symlink.txt"); | |
| 640 | ||
| 641 | std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); | |
| 642 | ||
| 643 | let cpath = CString::new(symlink_path.as_os_str().as_bytes()).unwrap(); | |
| 644 | ||
| 645 | let mut stat = MaybeUninit::<libc::stat>::uninit(); | |
| 646 | let res = unsafe { libc::lstat(cpath.as_ptr(), stat.as_mut_ptr()) }; | |
| 647 | assert_eq!(res, 0); | |
| 648 | let stat = unsafe { stat.assume_init_ref() }; | |
| 649 | ||
| 650 | assert_eq!(stat.st_mode & libc::S_IFMT, libc::S_IFLNK); | |
| 651 | ||
| 652 | // Check that all fields are initialized. | |
| 653 | check_stat_fields(stat); | |
| 654 | ||
| 655 | remove_file(&symlink_path).unwrap(); | |
| 656 | remove_file(&path).unwrap(); | |
| 657 | } | |
| 658 | ||
| 485 | 659 | fn test_isatty() { |
| 486 | 660 | // Testing whether our isatty shim returns the right value would require controlling whether |
| 487 | 661 | // these streams are actually TTYs, which is hard. |
| ... | ... | @@ -651,3 +825,21 @@ fn test_readdir() { |
| 651 | 825 | remove_file(&file2).unwrap(); |
| 652 | 826 | remove_dir(&dir_path).unwrap(); |
| 653 | 827 | } |
| 828 | ||
| 829 | /// Check that all common fields of a `stat` struct are initialized. | |
| 830 | pub fn check_stat_fields(stat: &libc::stat) { | |
| 831 | let _st_nlink = stat.st_nlink; | |
| 832 | let _st_blksize = stat.st_blksize; | |
| 833 | let _st_blocks = stat.st_blocks; | |
| 834 | let _st_ino = stat.st_ino; | |
| 835 | let _st_dev = stat.st_dev; | |
| 836 | let _st_uid = stat.st_uid; | |
| 837 | let _st_gid = stat.st_gid; | |
| 838 | let _st_rdev = stat.st_rdev; | |
| 839 | let _st_atime = stat.st_atime; | |
| 840 | let _st_mtime = stat.st_mtime; | |
| 841 | let _st_ctime = stat.st_ctime; | |
| 842 | let _st_atime_nsec = stat.st_atime_nsec; | |
| 843 | let _st_mtime_nsec = stat.st_mtime_nsec; | |
| 844 | let _st_ctime_nsec = stat.st_ctime_nsec; | |
| 845 | } |
src/tools/miri/tests/pass-dep/libc/libc-socket.rs+16| ... | ... | @@ -16,6 +16,7 @@ const TEST_BYTES: &[u8] = b"these are some test bytes!"; |
| 16 | 16 | |
| 17 | 17 | fn main() { |
| 18 | 18 | test_create_close(); |
| 19 | test_create_close_tcp(); | |
| 19 | 20 | test_bind_ipv4(); |
| 20 | 21 | test_bind_ipv4_reuseaddr(); |
| 21 | 22 | test_set_reuseaddr_invalid_len(); |
| ... | ... | @@ -59,6 +60,21 @@ fn test_create_close() { |
| 59 | 60 | unsafe { errno_check(libc::close(sockfd)) }; |
| 60 | 61 | } |
| 61 | 62 | |
| 63 | /// Test creating a socket and then closing it afterwards but we explicitly | |
| 64 | /// specify that the TCP protocol should be used. | |
| 65 | fn test_create_close_tcp() { | |
| 66 | let sockfd = unsafe { | |
| 67 | errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, libc::IPPROTO_TCP)).unwrap() | |
| 68 | }; | |
| 69 | ||
| 70 | let flags = unsafe { errno_result(libc::fcntl(sockfd, libc::F_GETFL, 0)).unwrap() }; | |
| 71 | ||
| 72 | // Ensure that socket is initially blocking. | |
| 73 | assert_eq!(flags & libc::O_NONBLOCK, 0); | |
| 74 | ||
| 75 | unsafe { errno_check(libc::close(sockfd)) }; | |
| 76 | } | |
| 77 | ||
| 62 | 78 | fn test_bind_ipv4() { |
| 63 | 79 | let sockfd = |
| 64 | 80 | unsafe { errno_result(libc::socket(libc::AF_INET, libc::SOCK_STREAM, 0)).unwrap() }; |
src/tools/miri/tests/pass/associated-const.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | trait Foo { |
| 4 | 5 | const ID: i32; |
src/tools/miri/tests/pass/assume_bug.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | fn main() { |
| 4 | 5 | vec![()].into_iter(); |
src/tools/miri/tests/pass/async-drop.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@compile-flags: -Zmiri-strict-provenance |
| 3 | 4 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 4 | 5 |
src/tools/miri/tests/pass/async-drop.tree_implicit_writes.stdout created+23| ... | ... | @@ -0,0 +1,23 @@ |
| 1 | AsyncInt::async_drop: 0 | |
| 2 | AsyncInt::async_drop: 1 | |
| 3 | AsyncInt::async_drop: 2 | |
| 4 | AsyncInt::async_drop: 3 | |
| 5 | AsyncInt::async_drop: 4 | |
| 6 | AsyncStruct::async_drop: 6 | |
| 7 | AsyncInt::async_drop: 7 | |
| 8 | AsyncInt::async_drop: 8 | |
| 9 | AsyncReference::async_drop: 10 | |
| 10 | AsyncInt::async_drop: 11 | |
| 11 | AsyncEnum(A)::async_drop: 12 | |
| 12 | SyncInt::drop: 12 | |
| 13 | AsyncEnum(B)::async_drop: 13 | |
| 14 | AsyncInt::async_drop: 13 | |
| 15 | SyncInt::drop: 14 | |
| 16 | SyncThenAsync::drop: 15 | |
| 17 | AsyncInt::async_drop: 16 | |
| 18 | SyncInt::drop: 17 | |
| 19 | AsyncInt::async_drop: 18 | |
| 20 | AsyncInt::async_drop: 19 | |
| 21 | AsyncInt::async_drop: 20 | |
| 22 | AsyncUnion::async_drop: 21, 21 | |
| 23 | AsyncInt::async_drop: 10 |
src/tools/miri/tests/pass/async-niche-aliasing.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | |
| 4 | 5 | use std::future::Future; |
src/tools/miri/tests/pass/atomic.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | //@compile-flags: -Zmiri-strict-provenance |
| 4 | 5 |
src/tools/miri/tests/pass/both_borrows/2phase.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | |
| 4 | 5 | trait S: Sized { |
src/tools/miri/tests/pass/both_borrows/basic_aliasing_model.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | #![feature(allocator_api)] |
| 4 | 5 | use std::alloc::{Layout, alloc, dealloc}; |
src/tools/miri/tests/pass/both_borrows/int-to-ptr.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@compile-flags: -Zmiri-permissive-provenance |
| 3 | 4 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 4 | 5 | use std::ptr; |
src/tools/miri/tests/pass/both_borrows/interior_mutability.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | #![allow(dangerous_implicit_autorefs)] |
| 4 | 5 |
src/tools/miri/tests/pass/both_borrows/issue-miri-2389.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@compile-flags: -Zmiri-permissive-provenance |
| 3 | 4 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 4 | 5 | use std::cell::Cell; |
src/tools/miri/tests/pass/both_borrows/maybe_dangling.rs+2-1| ... | ... | @@ -1,7 +1,8 @@ |
| 1 | 1 | // Check that `MaybeDangling` actually prevents UB when it wraps dangling |
| 2 | 2 | // boxes and references |
| 3 | 3 | // |
| 4 | //@revisions: stack tree | |
| 4 | //@revisions: stack tree tree_implicit_writes | |
| 5 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 5 | 6 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 6 | 7 | #![feature(maybe_dangling)] |
| 7 | 8 |
src/tools/miri/tests/pass/both_borrows/unsafe_pinned.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | #![feature(unsafe_pinned)] |
| 4 | 5 |
src/tools/miri/tests/pass/box-custom-alloc-aliasing.rs+2-1| ... | ... | @@ -2,7 +2,8 @@ |
| 2 | 2 | //! If `Box` has a local allocator, then it can't be `noalias` as the allocator |
| 3 | 3 | //! may want to access allocator state based on the data pointer. |
| 4 | 4 | |
| 5 | //@revisions: stack tree | |
| 5 | //@revisions: stack tree tree_implicit_writes | |
| 6 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 6 | 7 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 7 | 8 | #![feature(allocator_api)] |
| 8 | 9 |
src/tools/miri/tests/pass/btreemap.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | //@compile-flags: -Zmiri-strict-provenance |
| 4 | 5 | use std::collections::{BTreeMap, BTreeSet}; |
src/tools/miri/tests/pass/cast-rfc0401-vtable-kinds.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | // Check that you can cast between different pointers to trait objects |
| 4 | 5 | // whose vtable have the same kind (both lengths, or both trait pointers). |
src/tools/miri/tests/pass/concurrency/channels.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | //@compile-flags: -Zmiri-strict-provenance |
| 4 | 5 |
src/tools/miri/tests/pass/concurrency/sync.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | // We use `yield` to test specific interleavings, so disable automatic preemption. |
| 4 | 5 | //@compile-flags: -Zmiri-disable-isolation -Zmiri-deterministic-concurrency |
src/tools/miri/tests/pass/concurrency/sync.tree_implicit_writes.stdout created+20| ... | ... | @@ -0,0 +1,20 @@ |
| 1 | before wait | |
| 2 | before wait | |
| 3 | before wait | |
| 4 | before wait | |
| 5 | before wait | |
| 6 | before wait | |
| 7 | before wait | |
| 8 | before wait | |
| 9 | before wait | |
| 10 | before wait | |
| 11 | after wait | |
| 12 | after wait | |
| 13 | after wait | |
| 14 | after wait | |
| 15 | after wait | |
| 16 | after wait | |
| 17 | after wait | |
| 18 | after wait | |
| 19 | after wait | |
| 20 | after wait |
src/tools/miri/tests/pass/coroutine.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | #![feature(coroutines, coroutine_trait, never_type, stmt_expr_attributes)] |
| 4 | 5 |
src/tools/miri/tests/pass/disable-alignment-check.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | //@compile-flags: -Zmiri-disable-alignment-check -Cdebug-assertions=no |
| 4 | 5 |
src/tools/miri/tests/pass/disjoint-array-accesses.rs+2-1| ... | ... | @@ -2,7 +2,8 @@ |
| 2 | 2 | // unexpectedly caused borrowck errors for disjoint borrows of array elements, for which we had no |
| 3 | 3 | // tests. This is a collection of a few code samples from that issue. |
| 4 | 4 | |
| 5 | //@revisions: stack tree | |
| 5 | //@revisions: stack tree tree_implicit_writes | |
| 6 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 6 | 7 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 7 | 8 | |
| 8 | 9 | struct Test { |
src/tools/miri/tests/pass/dyn-arbitrary-self.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | #![feature(arbitrary_self_types_pointers, unsize, coerce_unsized, dispatch_from_dyn)] |
| 4 | 5 | #![feature(rustc_attrs)] |
src/tools/miri/tests/pass/extern_types.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | #![feature(extern_types)] |
| 4 | 5 |
src/tools/miri/tests/pass/future-self-referential.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | |
| 4 | 5 | use std::future::*; |
src/tools/miri/tests/pass/issues/issue-miri-3473.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | use std::cell::UnsafeCell; |
| 4 | 5 |
src/tools/miri/tests/pass/linked-list.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | #![feature(linked_list_cursors)] |
| 4 | 5 | use std::collections::LinkedList; |
src/tools/miri/tests/pass/many_shr_bor.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | // Make sure validation can handle many overlapping shared borrows for different parts of a data structure |
| 4 | 5 | use std::cell::RefCell; |
src/tools/miri/tests/pass/memleak_ignored.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | //@compile-flags: -Zmiri-ignore-leaks |
| 4 | 5 |
src/tools/miri/tests/pass/option_box_transmute_ptr.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | // This tests that the size of Option<Box<i32>> is the same as *const i32. |
| 4 | 5 | fn option_box_deref() -> i32 { |
src/tools/miri/tests/pass/provenance.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | use std::{mem, ptr}; |
| 4 | 5 |
src/tools/miri/tests/pass/ptr_int_casts.rs+2-1| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | //@compile-flags: -Zmiri-permissive-provenance |
| 2 | //@revisions: stack tree | |
| 2 | //@revisions: stack tree tree_implicit_writes | |
| 3 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 3 | 4 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 4 | 5 | use std::{mem, ptr}; |
| 5 | 6 |
src/tools/miri/tests/pass/ptr_int_from_exposed.rs+2-1| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | //@compile-flags: -Zmiri-permissive-provenance |
| 2 | //@revisions: stack tree | |
| 2 | //@revisions: stack tree tree_implicit_writes | |
| 3 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 3 | 4 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 4 | 5 | |
| 5 | 6 | use std::ptr; |
src/tools/miri/tests/pass/ptr_int_transmute.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | // Test what happens when we read parts of a pointer. |
| 4 | 5 | // Related to <https://github.com/rust-lang/rust/issues/69488>. |
src/tools/miri/tests/pass/rc.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | //@compile-flags: -Zmiri-strict-provenance |
| 4 | 5 | #![feature(get_mut_unchecked)] |
src/tools/miri/tests/pass/send-is-not-static-par-for.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | use std::sync::Mutex; |
| 4 | 5 |
src/tools/miri/tests/pass/shims/available-parallelism.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | fn main() { |
| 4 | 5 | assert_eq!(std::thread::available_parallelism().unwrap().get(), 1); |
src/tools/miri/tests/pass/shims/x86/intrinsics-x86-avx512.rs+27| ... | ... | @@ -243,6 +243,33 @@ unsafe fn test_avx512() { |
| 243 | 243 | } |
| 244 | 244 | test_mm512_permutexvar_epi64(); |
| 245 | 245 | |
| 246 | #[target_feature(enable = "avx512f")] | |
| 247 | unsafe fn test_mm512_permutex2var_epi64() { | |
| 248 | // a[i] = (i+1) * 10, b[i] = (i+1) * 100. | |
| 249 | let a = _mm512_set_epi64(80, 70, 60, 50, 40, 30, 20, 10); | |
| 250 | let b = _mm512_set_epi64(800, 700, 600, 500, 400, 300, 200, 100); | |
| 251 | ||
| 252 | // All from `a`: identity (bit 3 clear). | |
| 253 | let idx = _mm512_set_epi64(7, 6, 5, 4, 3, 2, 1, 0); | |
| 254 | assert_eq_m512i(_mm512_permutex2var_epi64(a, idx, b), a); | |
| 255 | ||
| 256 | // All from `b` (bit 3 set). | |
| 257 | let idx = _mm512_set_epi64(15, 14, 13, 12, 11, 10, 9, 8); | |
| 258 | assert_eq_m512i(_mm512_permutex2var_epi64(a, idx, b), b); | |
| 259 | ||
| 260 | // Interleave: even elements from `a`, odd from `b`. | |
| 261 | let idx = _mm512_set_epi64(15, 6, 13, 4, 11, 2, 9, 0); | |
| 262 | let e = _mm512_set_epi64(800, 70, 600, 50, 400, 30, 200, 10); | |
| 263 | assert_eq_m512i(_mm512_permutex2var_epi64(a, idx, b), e); | |
| 264 | ||
| 265 | // Only the low 4 bits of each index are used: bits [2:0] pick the lane, | |
| 266 | // bit 3 selects between `a` and `b`. | |
| 267 | let idx = _mm512_set_epi64(0, -1, -128, i64::MIN, 15, 8, 128, i64::MAX); | |
| 268 | let e = _mm512_set_epi64(10, 800, 10, 10, 800, 100, 10, 800); | |
| 269 | assert_eq_m512i(_mm512_permutex2var_epi64(a, idx, b), e); | |
| 270 | } | |
| 271 | test_mm512_permutex2var_epi64(); | |
| 272 | ||
| 246 | 273 | #[target_feature(enable = "avx512bw")] |
| 247 | 274 | unsafe fn test_mm512_shuffle_epi8() { |
| 248 | 275 | #[rustfmt::skip] |
src/tools/miri/tests/pass/strange_references.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | |
| 4 | 5 | // Create zero-sized references to vtables and function data. |
src/tools/miri/tests/pass/threadleak_ignored.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | //@compile-flags: -Zmiri-ignore-leaks |
| 4 | 5 |
src/tools/miri/tests/pass/threadleak_ignored.tree_implicit_writes.stderr created+1| ... | ... | @@ -0,0 +1 @@ |
| 1 | Dropping 0 |
src/tools/miri/tests/pass/tls/tls_macro_drop.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | |
| 4 | 5 | use std::cell::RefCell; |
src/tools/miri/tests/pass/tls/tls_macro_drop.tree_implicit_writes.stdout created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | Dropping: 8 (should be before 'Continue main 1'). | |
| 2 | Dropping: 8 (should be before 'Continue main 1'). | |
| 3 | Continue main 1. | |
| 4 | Joining: 7 (should be before 'Continue main 2'). | |
| 5 | Continue main 2. | |
| 6 | Foo dtor (should be before `Bar dtor`). | |
| 7 | Bar dtor (should be before `Continue main 3`). | |
| 8 | Continue main 3. |
src/tools/miri/tests/pass/tls/tls_static.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | //@compile-flags: -Zmiri-strict-provenance |
| 4 | 5 |
src/tools/miri/tests/pass/transmute_ptr.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | use std::mem; |
| 4 | 5 |
src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.rs+2| ... | ... | @@ -1,4 +1,6 @@ |
| 1 | 1 | // We disable the GC for this test because it would change what is printed. |
| 2 | //@revisions: tree tree_implicit_writes | |
| 3 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows-implicit-writes | |
| 2 | 4 | //@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 |
| 3 | 5 | #[path = "../../utils/mod.rs"] |
| 4 | 6 | #[macro_use] |
src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.stderr deleted-16| ... | ... | @@ -1,16 +0,0 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 1 | |
| 4 | | Act | └─┬──<TAG=root of the allocation> | |
| 5 | | ReIM| └─┬──<TAG=data> | |
| 6 | |?Cel | ├────<TAG=x> | |
| 7 | |?Cel | └────<TAG=y> | |
| 8 | ────────────────────────────────────────────────── | |
| 9 | ────────────────────────────────────────────────── | |
| 10 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 11 | 0.. 1 | |
| 12 | | Act | └─┬──<TAG=root of the allocation> | |
| 13 | | Act | └─┬──<TAG=data> | |
| 14 | | Cel | ├────<TAG=x> | |
| 15 | | Cel | └────<TAG=y> | |
| 16 | ────────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.tree.stderr created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 1 | |
| 4 | | Act | └─┬──<TAG=root of the allocation> | |
| 5 | | ReIM| └─┬──<TAG=data> | |
| 6 | |?Cel | ├────<TAG=x> | |
| 7 | |?Cel | └────<TAG=y> | |
| 8 | ────────────────────────────────────────────────── | |
| 9 | ────────────────────────────────────────────────── | |
| 10 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 11 | 0.. 1 | |
| 12 | | Act | └─┬──<TAG=root of the allocation> | |
| 13 | | Act | └─┬──<TAG=data> | |
| 14 | | Cel | ├────<TAG=x> | |
| 15 | | Cel | └────<TAG=y> | |
| 16 | ────────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/cell-alternate-writes.tree_implicit_writes.stderr created+16| ... | ... | @@ -0,0 +1,16 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 1 | |
| 4 | | Act | └─┬──<TAG=root of the allocation> | |
| 5 | | ReIM| └─┬──<TAG=data> | |
| 6 | |?Cel | ├────<TAG=x> | |
| 7 | |?Cel | └────<TAG=y> | |
| 8 | ────────────────────────────────────────────────── | |
| 9 | ────────────────────────────────────────────────── | |
| 10 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 11 | 0.. 1 | |
| 12 | | Act | └─┬──<TAG=root of the allocation> | |
| 13 | | Act | └─┬──<TAG=data> | |
| 14 | | Cel | ├────<TAG=x> | |
| 15 | | Cel | └────<TAG=y> | |
| 16 | ────────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/cell-inside-box.rs+2| ... | ... | @@ -1,3 +1,5 @@ |
| 1 | //@revisions: tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows-implicit-writes | |
| 1 | 3 | //@compile-flags: -Zmiri-tree-borrows |
| 2 | 4 | #![feature(box_as_ptr)] |
| 3 | 5 | #[path = "../../utils/mod.rs"] |
src/tools/miri/tests/pass/tree_borrows/cell-inside-box.stderr deleted-7| ... | ... | @@ -1,7 +0,0 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 4 | |
| 4 | | Act | └─┬──<TAG=root of the allocation> | |
| 5 | | Act | └─┬──<TAG=ptr1> | |
| 6 | | ReIM| └────<TAG=ptr2> | |
| 7 | ────────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/cell-inside-box.tree.stderr created+7| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 4 | |
| 4 | | Act | └─┬──<TAG=root of the allocation> | |
| 5 | | Act | └─┬──<TAG=ptr1> | |
| 6 | | ReIM| └────<TAG=ptr2> | |
| 7 | ────────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/cell-inside-box.tree_implicit_writes.stderr created+7| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 4 | |
| 4 | | Act | └─┬──<TAG=root of the allocation> | |
| 5 | | Act | └─┬──<TAG=ptr1> | |
| 6 | | ReIM| └────<TAG=ptr2> | |
| 7 | ────────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/cell-inside-struct.rs+2| ... | ... | @@ -1,5 +1,7 @@ |
| 1 | 1 | //! The same as `tests/fail/tree-borrows/cell-inside-struct` but with |
| 2 | 2 | //! precise tracking of interior mutability disabled. |
| 3 | //@revisions: tree tree_implicit_writes | |
| 4 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows-implicit-writes | |
| 3 | 5 | //@compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-no-precise-interior-mut |
| 4 | 6 | #[path = "../../utils/mod.rs"] |
| 5 | 7 | #[macro_use] |
src/tools/miri/tests/pass/tree_borrows/cell-inside-struct.stderr deleted-6| ... | ... | @@ -1,6 +0,0 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 8 | |
| 4 | | Act | └─┬──<TAG=root of the allocation> | |
| 5 | |?Cel | └────<TAG=a> | |
| 6 | ────────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/cell-inside-struct.tree.stderr created+6| ... | ... | @@ -0,0 +1,6 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 8 | |
| 4 | | Act | └─┬──<TAG=root of the allocation> | |
| 5 | |?Cel | └────<TAG=a> | |
| 6 | ────────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/cell-inside-struct.tree_implicit_writes.stderr created+6| ... | ... | @@ -0,0 +1,6 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 8 | |
| 4 | | Act | └─┬──<TAG=root of the allocation> | |
| 5 | |?Cel | └────<TAG=a> | |
| 6 | ────────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/cell-lazy-write-to-surrounding.rs+2| ... | ... | @@ -1,3 +1,5 @@ |
| 1 | //@revisions: tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows-implicit-writes | |
| 1 | 3 | //@compile-flags: -Zmiri-tree-borrows |
| 2 | 4 | |
| 3 | 5 | use std::cell::Cell; |
src/tools/miri/tests/pass/tree_borrows/end-of-protector.rs+2| ... | ... | @@ -1,4 +1,6 @@ |
| 1 | 1 | // We disable the GC for this test because it would change what is printed. |
| 2 | //@revisions: tree tree_implicit_writes | |
| 3 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows-implicit-writes | |
| 2 | 4 | //@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 |
| 3 | 5 | |
| 4 | 6 | // Check that a protector goes back to normal behavior when the function |
src/tools/miri/tests/pass/tree_borrows/end-of-protector.stderr deleted-36| ... | ... | @@ -1,36 +0,0 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 1 | |
| 4 | | Act | └─┬──<TAG=root of the allocation> | |
| 5 | | Res | └─┬──<TAG=data> | |
| 6 | | Res | └────<TAG=x> | |
| 7 | ────────────────────────────────────────────────── | |
| 8 | ────────────────────────────────────────────────── | |
| 9 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 10 | 0.. 1 | |
| 11 | | Act | └─┬──<TAG=root of the allocation> | |
| 12 | | Res | └─┬──<TAG=data> | |
| 13 | | Res | └─┬──<TAG=x> | |
| 14 | | Res | └─┬──<TAG=caller:x> | |
| 15 | | Res | └────<TAG=callee:x> Strongly protected | |
| 16 | ────────────────────────────────────────────────── | |
| 17 | ────────────────────────────────────────────────── | |
| 18 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 19 | 0.. 1 | |
| 20 | | Act | └─┬──<TAG=root of the allocation> | |
| 21 | | Res | └─┬──<TAG=data> | |
| 22 | | Res | ├─┬──<TAG=x> | |
| 23 | | Res | │ └─┬──<TAG=caller:x> | |
| 24 | | Res | │ └────<TAG=callee:x> | |
| 25 | | Res | └────<TAG=y> | |
| 26 | ────────────────────────────────────────────────── | |
| 27 | ────────────────────────────────────────────────── | |
| 28 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 29 | 0.. 1 | |
| 30 | | Act | └─┬──<TAG=root of the allocation> | |
| 31 | | Act | └─┬──<TAG=data> | |
| 32 | | Dis | ├─┬──<TAG=x> | |
| 33 | | Dis | │ └─┬──<TAG=caller:x> | |
| 34 | | Dis | │ └────<TAG=callee:x> | |
| 35 | | Act | └────<TAG=y> | |
| 36 | ────────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/end-of-protector.tree.stderr created+36| ... | ... | @@ -0,0 +1,36 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 1 | |
| 4 | | Act | └─┬──<TAG=root of the allocation> | |
| 5 | | Res | └─┬──<TAG=data> | |
| 6 | | Res | └────<TAG=x> | |
| 7 | ────────────────────────────────────────────────── | |
| 8 | ────────────────────────────────────────────────── | |
| 9 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 10 | 0.. 1 | |
| 11 | | Act | └─┬──<TAG=root of the allocation> | |
| 12 | | Res | └─┬──<TAG=data> | |
| 13 | | Res | └─┬──<TAG=x> | |
| 14 | | Res | └─┬──<TAG=caller:x> | |
| 15 | | Res | └────<TAG=callee:x> Strongly protected | |
| 16 | ────────────────────────────────────────────────── | |
| 17 | ────────────────────────────────────────────────── | |
| 18 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 19 | 0.. 1 | |
| 20 | | Act | └─┬──<TAG=root of the allocation> | |
| 21 | | Res | └─┬──<TAG=data> | |
| 22 | | Res | ├─┬──<TAG=x> | |
| 23 | | Res | │ └─┬──<TAG=caller:x> | |
| 24 | | Res | │ └────<TAG=callee:x> | |
| 25 | | Res | └────<TAG=y> | |
| 26 | ────────────────────────────────────────────────── | |
| 27 | ────────────────────────────────────────────────── | |
| 28 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 29 | 0.. 1 | |
| 30 | | Act | └─┬──<TAG=root of the allocation> | |
| 31 | | Act | └─┬──<TAG=data> | |
| 32 | | Dis | ├─┬──<TAG=x> | |
| 33 | | Dis | │ └─┬──<TAG=caller:x> | |
| 34 | | Dis | │ └────<TAG=callee:x> | |
| 35 | | Act | └────<TAG=y> | |
| 36 | ────────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/end-of-protector.tree_implicit_writes.stderr created+36| ... | ... | @@ -0,0 +1,36 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 1 | |
| 4 | | Act | └─┬──<TAG=root of the allocation> | |
| 5 | | Res | └─┬──<TAG=data> | |
| 6 | | Res | └────<TAG=x> | |
| 7 | ────────────────────────────────────────────────── | |
| 8 | ────────────────────────────────────────────────── | |
| 9 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 10 | 0.. 1 | |
| 11 | | Act | └─┬──<TAG=root of the allocation> | |
| 12 | | Act | └─┬──<TAG=data> | |
| 13 | | Act | └─┬──<TAG=x> | |
| 14 | | Act | └─┬──<TAG=caller:x> | |
| 15 | | Act | └────<TAG=callee:x> Strongly protected | |
| 16 | ────────────────────────────────────────────────── | |
| 17 | ────────────────────────────────────────────────── | |
| 18 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 19 | 0.. 1 | |
| 20 | | Act | └─┬──<TAG=root of the allocation> | |
| 21 | | Act | └─┬──<TAG=data> | |
| 22 | | Frz | ├─┬──<TAG=x> | |
| 23 | | Frz | │ └─┬──<TAG=caller:x> | |
| 24 | | Frz | │ └────<TAG=callee:x> | |
| 25 | | Res | └────<TAG=y> | |
| 26 | ────────────────────────────────────────────────── | |
| 27 | ────────────────────────────────────────────────── | |
| 28 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 29 | 0.. 1 | |
| 30 | | Act | └─┬──<TAG=root of the allocation> | |
| 31 | | Act | └─┬──<TAG=data> | |
| 32 | | Dis | ├─┬──<TAG=x> | |
| 33 | | Dis | │ └─┬──<TAG=caller:x> | |
| 34 | | Dis | │ └────<TAG=callee:x> | |
| 35 | | Act | └────<TAG=y> | |
| 36 | ────────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/implicit-writes-permissions.rs created+17| ... | ... | @@ -0,0 +1,17 @@ |
| 1 | // Tests that the permissions are as expected after reborrowing. | |
| 2 | // To be precise, this tests that at the start of a function, a mutable reference is Unique. | |
| 3 | //@compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 4 | ||
| 5 | unsafe extern "Rust" { | |
| 6 | safe fn miri_get_alloc_id(ptr: *const u8) -> u64; | |
| 7 | safe fn miri_print_borrow_state(alloc_id: u64, show_unnamed: bool); | |
| 8 | } | |
| 9 | ||
| 10 | fn bar(x: &mut u8) { | |
| 11 | miri_print_borrow_state(miri_get_alloc_id(x), true); | |
| 12 | } | |
| 13 | ||
| 14 | fn main() { | |
| 15 | let mut x = 0u8; | |
| 16 | bar(&mut x); | |
| 17 | } |
src/tools/miri/tests/pass/tree_borrows/implicit-writes-permissions.stderr created+7| ... | ... | @@ -0,0 +1,7 @@ |
| 1 | ────────────────────────────────────────────── | |
| 2 | 0.. 1 | |
| 3 | | Act | └─┬──<TAG=root of the allocation> | |
| 4 | | Act | └─┬──<TAG> | |
| 5 | | Act | └─┬──<TAG> | |
| 6 | | Act | └────<TAG> Strongly protected | |
| 7 | ────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/no_implicit_writes.rs created+55| ... | ... | @@ -0,0 +1,55 @@ |
| 1 | // Shows that without implicit writes, `tests/fail/tree_borrows/implicit_writes/ptr_write.rs`, `tests/fail/tree_borrows/implicit_writes/ptr_write_unsafe_cell.rs`, `tests/fail/tree_borrows/implicit_writes/ptr_write_box.rs`, `tests/fail/tree_borrows/implicit_writes/as_mut_ptr.rs` would pass. | |
| 2 | //@compile-flags: -Zmiri-tree-borrows | |
| 3 | ||
| 4 | use std::cell::UnsafeCell; | |
| 5 | ||
| 6 | fn main() { | |
| 7 | normal(); | |
| 8 | unsafe_cell(); | |
| 9 | box_test(); | |
| 10 | as_mut_ptr_test() | |
| 11 | } | |
| 12 | ||
| 13 | fn normal() { | |
| 14 | let mut x = 0u8; | |
| 15 | let ptr = &raw mut x; | |
| 16 | let res = dereference(&mut x, ptr); | |
| 17 | assert_eq!(*res, 0); | |
| 18 | } | |
| 19 | ||
| 20 | fn unsafe_cell() { | |
| 21 | let mut x: UnsafeCell<u8> = 0u8.into(); | |
| 22 | let ptr = x.get(); | |
| 23 | let res = dereference(&mut x, ptr); | |
| 24 | assert_eq!(*res.get_mut(), 0); | |
| 25 | } | |
| 26 | ||
| 27 | fn box_test() { | |
| 28 | let mut x: Box<u8> = Box::new(0u8); | |
| 29 | let ptr = &raw mut *x; | |
| 30 | let res = dereference(x, ptr); | |
| 31 | assert_eq!(*res, 0); | |
| 32 | } | |
| 33 | ||
| 34 | fn dereference<T>(x: T, y: *mut u8) -> T { | |
| 35 | // miri inserts an implicit write here | |
| 36 | let _ = unsafe { *y }; | |
| 37 | // x = 42; // we'd like to add this write, so there must already be UB without it because there sure is with it. | |
| 38 | x | |
| 39 | } | |
| 40 | ||
| 41 | fn as_mut_ptr_test() { | |
| 42 | let mut x: [u8; 3] = [1, 2, 3]; | |
| 43 | ||
| 44 | let ptr = std::ptr::from_mut(&mut x); | |
| 45 | let a = unsafe { &mut *ptr }; | |
| 46 | let b = unsafe { &mut *ptr }; | |
| 47 | ||
| 48 | let _c = as_mut_ptr(a); | |
| 49 | assert_eq!(*b, [1, 2, 3]); | |
| 50 | } | |
| 51 | ||
| 52 | // this should be the same as the implementation for slice, as this is known to cause errors and we want to test that behavior here | |
| 53 | const fn as_mut_ptr(x: &mut [u8; 3]) -> *mut u8 { | |
| 54 | x as *mut [u8] as *mut u8 | |
| 55 | } |
src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.rs deleted-114| ... | ... | @@ -1,114 +0,0 @@ |
| 1 | //@compile-flags: -Zmiri-tree-borrows | |
| 2 | // This test relies on a specific interleaving that cannot be enforced | |
| 3 | // with just barriers. We must remove preemption so that the execution and the | |
| 4 | // error messages are deterministic. | |
| 5 | //@compile-flags: -Zmiri-deterministic-concurrency | |
| 6 | use std::ptr::addr_of_mut; | |
| 7 | use std::sync::{Arc, Barrier}; | |
| 8 | use std::thread; | |
| 9 | ||
| 10 | #[derive(Copy, Clone)] | |
| 11 | struct SendPtr(*mut u8); | |
| 12 | ||
| 13 | unsafe impl Send for SendPtr {} | |
| 14 | ||
| 15 | // This test features the problematic pattern | |
| 16 | // | |
| 17 | // read x || retag y (&mut, protect) | |
| 18 | // -- sync -- | |
| 19 | // || write y | |
| 20 | // | |
| 21 | // In which | |
| 22 | // - one interleaving (`1:read; 2:retag; 2:write`) does not have UB if retags | |
| 23 | // count only as reads for the data race model, | |
| 24 | // - the other interleaving (`2:retag; 1:read; 2:write`) has UB (`noalias` violation). | |
| 25 | // | |
| 26 | // The interleaving executed here is the one that does not have UB, | |
| 27 | // i.e. | |
| 28 | // 1:read x | |
| 29 | // 2:retag y | |
| 30 | // 2:write y | |
| 31 | // | |
| 32 | // Tree Borrows considers that the read of `x` cannot be in conflict | |
| 33 | // with `y` because `y` did not even exist yet when `x` was accessed. | |
| 34 | // | |
| 35 | // As long as we are not emitting any writes for the data race model | |
| 36 | // upon retags of mutable references, it should not have any issue with | |
| 37 | // this code either. | |
| 38 | // We do not want to emit a write for the data race model, because | |
| 39 | // although there is race-like behavior going on in this pattern | |
| 40 | // (where some but not all interleavings contain UB), making this an actual | |
| 41 | // data race has the confusing consequence of one single access being treated | |
| 42 | // as being of different `AccessKind`s by different parts of Miri | |
| 43 | // (a retag would be always a read for the aliasing model, and sometimes a write | |
| 44 | // for the data race model). | |
| 45 | ||
| 46 | // The other interleaving is a subsequence of `tests/fail/tree_borrows/spurious_read.rs` | |
| 47 | // which asserts that | |
| 48 | // 2:retag y | |
| 49 | // 1:read x | |
| 50 | // 2:write y | |
| 51 | // is UB. | |
| 52 | ||
| 53 | type IdxBarrier = (usize, Arc<Barrier>); | |
| 54 | // We're going to enforce a specific interleaving of two | |
| 55 | // threads, we use this macro in an effort to make it feasible | |
| 56 | // to check in the output that the execution is properly synchronized. | |
| 57 | // | |
| 58 | // Provide `synchronized!(thread, msg)` where thread is | |
| 59 | // a `(thread_id: usize, barrier: Arc<Barrier>)`, and `msg` the message | |
| 60 | // to be displayed when the thread reaches this point in the execution. | |
| 61 | macro_rules! synchronized { | |
| 62 | ($thread:expr, $msg:expr) => {{ | |
| 63 | let (thread_id, barrier) = &$thread; | |
| 64 | eprintln!("Thread {} executing: {}", thread_id, $msg); | |
| 65 | barrier.wait(); | |
| 66 | }}; | |
| 67 | } | |
| 68 | ||
| 69 | fn thread_1(x: SendPtr, barrier: IdxBarrier) { | |
| 70 | let x = unsafe { &mut *x.0 }; | |
| 71 | synchronized!(barrier, "spawn"); | |
| 72 | ||
| 73 | synchronized!(barrier, "read x || retag y"); | |
| 74 | // This is the interleaving without UB: by the time | |
| 75 | // the other thread starts retagging, this thread | |
| 76 | // has already finished all its work using `y`. | |
| 77 | let _v = *x; | |
| 78 | synchronized!(barrier, "write y"); | |
| 79 | synchronized!(barrier, "exit"); | |
| 80 | } | |
| 81 | ||
| 82 | fn thread_2(y: SendPtr, barrier: IdxBarrier) { | |
| 83 | let y = unsafe { &mut *y.0 }; | |
| 84 | synchronized!(barrier, "spawn"); | |
| 85 | ||
| 86 | fn write(y: &mut u8, v: u8, barrier: &IdxBarrier) { | |
| 87 | synchronized!(barrier, "write y"); | |
| 88 | *y = v; | |
| 89 | } | |
| 90 | synchronized!(barrier, "read x || retag y"); | |
| 91 | // We don't use a barrier here so that *if* the retag counted as a write | |
| 92 | // for the data race model, then it would be UB. | |
| 93 | // We still want to make sure that the other thread goes first as per the | |
| 94 | // interleaving that we are testing, so we use `yield_now + preemption-rate=0` | |
| 95 | // which has the effect of forcing a specific interleaving while still | |
| 96 | // not counting as "synchronization" from the point of view of the data | |
| 97 | // race model. | |
| 98 | thread::yield_now(); | |
| 99 | write(&mut *y, 42, &barrier); | |
| 100 | synchronized!(barrier, "exit"); | |
| 101 | } | |
| 102 | ||
| 103 | fn main() { | |
| 104 | let mut data = 0u8; | |
| 105 | let p = SendPtr(addr_of_mut!(data)); | |
| 106 | let barrier = Arc::new(Barrier::new(2)); | |
| 107 | let b1 = (1, Arc::clone(&barrier)); | |
| 108 | let b2 = (2, Arc::clone(&barrier)); | |
| 109 | ||
| 110 | let h1 = thread::spawn(move || thread_1(p, b1)); | |
| 111 | let h2 = thread::spawn(move || thread_2(p, b2)); | |
| 112 | h1.join().unwrap(); | |
| 113 | h2.join().unwrap(); | |
| 114 | } |
src/tools/miri/tests/pass/tree_borrows/read_retag_no_race.stderr deleted-8| ... | ... | @@ -1,8 +0,0 @@ |
| 1 | Thread 1 executing: spawn | |
| 2 | Thread 2 executing: spawn | |
| 3 | Thread 2 executing: read x || retag y | |
| 4 | Thread 1 executing: read x || retag y | |
| 5 | Thread 1 executing: write y | |
| 6 | Thread 2 executing: write y | |
| 7 | Thread 2 executing: exit | |
| 8 | Thread 1 executing: exit |
src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.rs+2| ... | ... | @@ -1,4 +1,6 @@ |
| 1 | 1 | // We disable the GC for this test because it would change what is printed. |
| 2 | //@revisions: tree tree_implicit_writes | |
| 3 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows-implicit-writes | |
| 2 | 4 | //@compile-flags: -Zmiri-tree-borrows -Zmiri-provenance-gc=0 |
| 3 | 5 | |
| 4 | 6 | #[path = "../../utils/mod.rs"] |
src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.stderr deleted-15| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 1 | |
| 4 | | Act | └─┬──<TAG=root of the allocation> | |
| 5 | | Act | └─┬──<TAG=parent> | |
| 6 | | Act | └────<TAG=x> | |
| 7 | ────────────────────────────────────────────────── | |
| 8 | ────────────────────────────────────────────────── | |
| 9 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 10 | 0.. 1 | |
| 11 | | Act | └─┬──<TAG=root of the allocation> | |
| 12 | | Act | └─┬──<TAG=parent> | |
| 13 | | Frz | ├────<TAG=x> | |
| 14 | | Res | └────<TAG=y> | |
| 15 | ────────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.tree.stderr created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 1 | |
| 4 | | Act | └─┬──<TAG=root of the allocation> | |
| 5 | | Act | └─┬──<TAG=parent> | |
| 6 | | Act | └────<TAG=x> | |
| 7 | ────────────────────────────────────────────────── | |
| 8 | ────────────────────────────────────────────────── | |
| 9 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 10 | 0.. 1 | |
| 11 | | Act | └─┬──<TAG=root of the allocation> | |
| 12 | | Act | └─┬──<TAG=parent> | |
| 13 | | Frz | ├────<TAG=x> | |
| 14 | | Res | └────<TAG=y> | |
| 15 | ────────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/reborrow-is-read.tree_implicit_writes.stderr created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | ────────────────────────────────────────────────── | |
| 2 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 3 | 0.. 1 | |
| 4 | | Act | └─┬──<TAG=root of the allocation> | |
| 5 | | Act | └─┬──<TAG=parent> | |
| 6 | | Act | └────<TAG=x> | |
| 7 | ────────────────────────────────────────────────── | |
| 8 | ────────────────────────────────────────────────── | |
| 9 | Warning: this tree is indicative only. Some tags may have been hidden. | |
| 10 | 0.. 1 | |
| 11 | | Act | └─┬──<TAG=root of the allocation> | |
| 12 | | Act | └─┬──<TAG=parent> | |
| 13 | | Frz | ├────<TAG=x> | |
| 14 | | Res | └────<TAG=y> | |
| 15 | ────────────────────────────────────────────────── |
src/tools/miri/tests/pass/tree_borrows/retag_no_race.rs created+114| ... | ... | @@ -0,0 +1,114 @@ |
| 1 | //@compile-flags: -Zmiri-tree-borrows | |
| 2 | // This test relies on a specific interleaving that cannot be enforced | |
| 3 | // with just barriers. We must remove preemption so that the execution and the | |
| 4 | // error messages are deterministic. | |
| 5 | //@compile-flags: -Zmiri-deterministic-concurrency | |
| 6 | use std::ptr::addr_of_mut; | |
| 7 | use std::sync::{Arc, Barrier}; | |
| 8 | use std::thread; | |
| 9 | ||
| 10 | #[derive(Copy, Clone)] | |
| 11 | struct SendPtr(*mut u8); | |
| 12 | ||
| 13 | unsafe impl Send for SendPtr {} | |
| 14 | ||
| 15 | // This test features the problematic pattern | |
| 16 | // | |
| 17 | // read x || retag y (&mut, protect) | |
| 18 | // -- sync -- | |
| 19 | // || write y | |
| 20 | // | |
| 21 | // In which | |
| 22 | // - one interleaving (`1:read; 2:retag; 2:write`) does not have UB if retags | |
| 23 | // count only as reads for the data race model, | |
| 24 | // - the other interleaving (`2:retag; 1:read; 2:write`) has UB (`noalias` violation). | |
| 25 | // | |
| 26 | // The interleaving executed here is the one that does not have UB, | |
| 27 | // i.e. | |
| 28 | // 1:read x | |
| 29 | // 2:retag y | |
| 30 | // 2:write y | |
| 31 | // | |
| 32 | // Tree Borrows considers that the read of `x` cannot be in conflict | |
| 33 | // with `y` because `y` did not even exist yet when `x` was accessed. | |
| 34 | // | |
| 35 | // As long as we are not emitting any writes for the data race model | |
| 36 | // upon retags of mutable references, it should not have any issue with | |
| 37 | // this code either. | |
| 38 | // We do not want to emit a write for the data race model, because | |
| 39 | // although there is race-like behavior going on in this pattern | |
| 40 | // (where some but not all interleavings contain UB), making this an actual | |
| 41 | // data race has the confusing consequence of one single access being treated | |
| 42 | // as being of different `AccessKind`s by different parts of Miri | |
| 43 | // (a retag would be always a read for the aliasing model, and sometimes a write | |
| 44 | // for the data race model). | |
| 45 | ||
| 46 | // The other interleaving is a subsequence of `tests/fail/tree_borrows/spurious_read.rs` | |
| 47 | // which asserts that | |
| 48 | // 2:retag y | |
| 49 | // 1:read x | |
| 50 | // 2:write y | |
| 51 | // is UB. | |
| 52 | ||
| 53 | type IdxBarrier = (usize, Arc<Barrier>); | |
| 54 | // We're going to enforce a specific interleaving of two | |
| 55 | // threads, we use this macro in an effort to make it feasible | |
| 56 | // to check in the output that the execution is properly synchronized. | |
| 57 | // | |
| 58 | // Provide `synchronized!(thread, msg)` where thread is | |
| 59 | // a `(thread_id: usize, barrier: Arc<Barrier>)`, and `msg` the message | |
| 60 | // to be displayed when the thread reaches this point in the execution. | |
| 61 | macro_rules! synchronized { | |
| 62 | ($thread:expr, $msg:expr) => {{ | |
| 63 | let (thread_id, barrier) = &$thread; | |
| 64 | eprintln!("Thread {} executing: {}", thread_id, $msg); | |
| 65 | barrier.wait(); | |
| 66 | }}; | |
| 67 | } | |
| 68 | ||
| 69 | fn thread_1(x: SendPtr, barrier: IdxBarrier) { | |
| 70 | let x = unsafe { &mut *x.0 }; | |
| 71 | synchronized!(barrier, "spawn"); | |
| 72 | ||
| 73 | synchronized!(barrier, "read x || retag y"); | |
| 74 | // This is the interleaving without UB: by the time | |
| 75 | // the other thread starts retagging, this thread | |
| 76 | // has already finished all its work using `y`. | |
| 77 | let _v = *x; | |
| 78 | synchronized!(barrier, "write y"); | |
| 79 | synchronized!(barrier, "exit"); | |
| 80 | } | |
| 81 | ||
| 82 | fn thread_2(y: SendPtr, barrier: IdxBarrier) { | |
| 83 | let y = unsafe { &mut *y.0 }; | |
| 84 | synchronized!(barrier, "spawn"); | |
| 85 | ||
| 86 | fn write(y: &mut u8, v: u8, barrier: &IdxBarrier) { | |
| 87 | synchronized!(barrier, "write y"); | |
| 88 | *y = v; | |
| 89 | } | |
| 90 | synchronized!(barrier, "read x || retag y"); | |
| 91 | // We don't use a barrier here so that *if* the retag counted as a write | |
| 92 | // for the data race model, then it would be UB. | |
| 93 | // We still want to make sure that the other thread goes first as per the | |
| 94 | // interleaving that we are testing, so we use `yield_now + preemption-rate=0` | |
| 95 | // which has the effect of forcing a specific interleaving while still | |
| 96 | // not counting as "synchronization" from the point of view of the data | |
| 97 | // race model. | |
| 98 | thread::yield_now(); | |
| 99 | write(&mut *y, 42, &barrier); | |
| 100 | synchronized!(barrier, "exit"); | |
| 101 | } | |
| 102 | ||
| 103 | fn main() { | |
| 104 | let mut data = 0u8; | |
| 105 | let p = SendPtr(addr_of_mut!(data)); | |
| 106 | let barrier = Arc::new(Barrier::new(2)); | |
| 107 | let b1 = (1, Arc::clone(&barrier)); | |
| 108 | let b2 = (2, Arc::clone(&barrier)); | |
| 109 | ||
| 110 | let h1 = thread::spawn(move || thread_1(p, b1)); | |
| 111 | let h2 = thread::spawn(move || thread_2(p, b2)); | |
| 112 | h1.join().unwrap(); | |
| 113 | h2.join().unwrap(); | |
| 114 | } |
src/tools/miri/tests/pass/tree_borrows/retag_no_race.stderr created+8| ... | ... | @@ -0,0 +1,8 @@ |
| 1 | Thread 1 executing: spawn | |
| 2 | Thread 2 executing: spawn | |
| 3 | Thread 2 executing: read x || retag y | |
| 4 | Thread 1 executing: read x || retag y | |
| 5 | Thread 1 executing: write y | |
| 6 | Thread 2 executing: write y | |
| 7 | Thread 2 executing: exit | |
| 8 | Thread 1 executing: exit |
src/tools/miri/tests/pass/tree_borrows/transmute-unsafecell.rs+2| ... | ... | @@ -1,3 +1,5 @@ |
| 1 | //@revisions: tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows-implicit-writes | |
| 1 | 3 | //@compile-flags: -Zmiri-tree-borrows |
| 2 | 4 | |
| 3 | 5 | //! Testing `mem::transmute` between types with and without interior mutability. |
src/tools/miri/tests/pass/tree_borrows/tree-borrows.rs+33| ... | ... | @@ -1,3 +1,5 @@ |
| 1 | //@revisions: tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows-implicit-writes | |
| 1 | 3 | //@compile-flags: -Zmiri-tree-borrows |
| 2 | 4 | #![feature(allocator_api)] |
| 3 | 5 | |
| ... | ... | @@ -12,6 +14,7 @@ fn main() { |
| 12 | 14 | direct_mut_to_const_raw(); |
| 13 | 15 | local_addr_of_mut(); |
| 14 | 16 | returned_mut_is_usable(); |
| 17 | array_pointer_access(); | |
| 15 | 18 | } |
| 16 | 19 | |
| 17 | 20 | #[allow(unused_assignments)] |
| ... | ... | @@ -102,3 +105,33 @@ fn direct_mut_to_const_raw() { |
| 102 | 105 | } |
| 103 | 106 | assert_eq!(*x, 1); |
| 104 | 107 | } |
| 108 | ||
| 109 | // Tests that accessing the same array using disjoint pointers does not cause UB under Tree Borrows. | |
| 110 | // The pointer will access the memory range using the outside permission, thus testing if it has been set correctly. | |
| 111 | // In particular, in implicit_writes mode we used to set the "outside" permissions to | |
| 112 | // `Unique`, which caused an ICE. | |
| 113 | // Put differently, this checks the absence of subobject provenance for arrays. | |
| 114 | fn array_pointer_access() { | |
| 115 | let mut x = [1u8; 11]; | |
| 116 | let y = (&raw mut x).cast(); | |
| 117 | let res = foo(&mut x[0], y); | |
| 118 | assert_eq!(res, 20); | |
| 119 | } | |
| 120 | ||
| 121 | fn foo(x: &mut u8, y: *mut u8) -> u8 { | |
| 122 | unsafe { | |
| 123 | let x: *mut u8 = x; | |
| 124 | let res1 = access_nexts(x.add(1), y.add(1)); | |
| 125 | let res2 = access_nexts(y.add(1), x.add(1)); | |
| 126 | res1 + res2 | |
| 127 | } | |
| 128 | } | |
| 129 | ||
| 130 | fn access_nexts(x: *mut u8, y: *mut u8) -> u8 { | |
| 131 | let mut sum = 0; | |
| 132 | for i in 0..5 { | |
| 133 | sum += unsafe { *x.add(2 * i) }; | |
| 134 | sum += unsafe { *y.add(2 * i + 1) }; | |
| 135 | } | |
| 136 | sum | |
| 137 | } |
src/tools/miri/tests/pass/tree_borrows/wildcard/reborrow.rs+2| ... | ... | @@ -1,3 +1,5 @@ |
| 1 | //@revisions: tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows-implicit-writes | |
| 1 | 3 | //@compile-flags: -Zmiri-tree-borrows -Zmiri-permissive-provenance |
| 2 | 4 | |
| 3 | 5 | pub fn main() { |
src/tools/miri/tests/pass/unsized.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 3 | 4 | #![feature(unsized_fn_params)] |
| 4 | 5 | #![feature(custom_mir, core_intrinsics)] |
src/tools/miri/tests/pass/vecdeque.rs+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | //@revisions: stack tree | |
| 1 | //@revisions: stack tree tree_implicit_writes | |
| 2 | //@[tree_implicit_writes]compile-flags: -Zmiri-tree-borrows -Zmiri-tree-borrows-implicit-writes | |
| 2 | 3 | //@compile-flags: -Zmiri-strict-provenance |
| 3 | 4 | //@[tree]compile-flags: -Zmiri-tree-borrows |
| 4 | 5 | use std::collections::VecDeque; |
tests/codegen-llvm/cffi/c-variadic-naked.rs+1-1| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | //@ needs-asm-support |
| 2 | //@ only-x86_64 | |
| 2 | //@ needs-asm-mnemonic: ret | |
| 3 | 3 | |
| 4 | 4 | // tests that `va_start` is not injected into naked functions |
| 5 | 5 |
tests/codegen-llvm/naked-fn/aligned.rs+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | //@ compile-flags: -C no-prepopulate-passes -Copt-level=0 |
| 2 | 2 | //@ needs-asm-support |
| 3 | //@ ignore-arm no "ret" mnemonic | |
| 3 | //@ needs-asm-mnemonic: ret | |
| 4 | 4 | //@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) |
| 5 | 5 | |
| 6 | 6 | #![crate_type = "lib"] |
tests/codegen-llvm/naked-fn/min-function-alignment.rs+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | //@ compile-flags: -C no-prepopulate-passes -Copt-level=0 -Zmin-function-alignment=16 |
| 2 | 2 | //@ needs-asm-support |
| 3 | //@ ignore-arm no "ret" mnemonic | |
| 3 | //@ needs-asm-mnemonic: ret | |
| 4 | 4 | //@ ignore-wasm32 aligning functions is not currently supported on wasm (#143368) |
| 5 | 5 | |
| 6 | 6 | // FIXME(#82232, #143834): temporarily renamed to mitigate `#[align]` nameres ambiguity |
tests/run-make/archive-corrupt-error/corrupt.a created+3| ... | ... | @@ -0,0 +1,3 @@ |
| 1 | !<arch> | |
| 2 | corrupt.o/ 0 0 0 100644 10000 ` | |
| 3 | small_data |
tests/run-make/archive-corrupt-error/lib.rs created+3| ... | ... | @@ -0,0 +1,3 @@ |
| 1 | extern "C" { | |
| 2 | fn foo() -> i32; | |
| 3 | } |
tests/run-make/archive-corrupt-error/rmake.rs created+21| ... | ... | @@ -0,0 +1,21 @@ |
| 1 | // Regression test for https://github.com/rust-lang/rust/issues/148217 | |
| 2 | // A corrupt archive with member offset exceeding file boundary should produce | |
| 3 | // an error, not an ICE. | |
| 4 | ||
| 5 | //@ ignore-cross-compile | |
| 6 | ||
| 7 | use run_make_support::{path, rfs, rustc, static_lib_name}; | |
| 8 | ||
| 9 | fn main() { | |
| 10 | rfs::create_dir("archive"); | |
| 11 | rfs::copy("corrupt.a", path("archive").join(static_lib_name("corrupt"))); | |
| 12 | rustc() | |
| 13 | .input("lib.rs") | |
| 14 | .crate_type("rlib") | |
| 15 | .library_search_path("archive") | |
| 16 | .arg("-lstatic=corrupt") | |
| 17 | .run_fail() | |
| 18 | .assert_stderr_not_contains("panicked") | |
| 19 | .assert_stderr_not_contains("unexpectedly panicked") | |
| 20 | .assert_stderr_contains("invalid archive member"); | |
| 21 | } |
tests/run-make/archive-format-error/lib.rs created+3| ... | ... | @@ -0,0 +1,3 @@ |
| 1 | extern "C" { | |
| 2 | fn foo() -> i32; | |
| 3 | } |
tests/run-make/archive-format-error/native.c created+1| ... | ... | @@ -0,0 +1 @@ |
| 1 | int foo() { return 42; } |
tests/run-make/archive-format-error/rmake.rs created+22| ... | ... | @@ -0,0 +1,22 @@ |
| 1 | // Regression test for https://github.com/rust-lang/rust/issues/148217 | |
| 2 | // BSD format archive on a Linux target should emit a format mismatch warning. | |
| 3 | ||
| 4 | //@ ignore-cross-compile | |
| 5 | //@ only-linux | |
| 6 | ||
| 7 | use run_make_support::{cc, llvm_ar, path, rfs, rustc, static_lib_name}; | |
| 8 | ||
| 9 | fn main() { | |
| 10 | rfs::create_dir("archive"); | |
| 11 | ||
| 12 | cc().arg("-c").input("native.c").output("archive/native.o").run(); | |
| 13 | let bsd_archive = path("archive").join(static_lib_name("native_bsd")); | |
| 14 | llvm_ar().arg("rcus").arg("--format=bsd").output_input(&bsd_archive, "archive/native.o").run(); | |
| 15 | rustc() | |
| 16 | .input("lib.rs") | |
| 17 | .crate_type("rlib") | |
| 18 | .library_search_path("archive") | |
| 19 | .arg("-lstatic=native_bsd") | |
| 20 | .run() | |
| 21 | .assert_stderr_contains("was built as BSD format, but the target expects GNU"); | |
| 22 | } |
tests/run-make/raw-dylib-custom-dlltool/script.cmd+1-1| ... | ... | @@ -1,2 +1,2 @@ |
| 1 | echo Called dlltool via script.cmd> actual.txt | |
| 1 | echo Called dlltool via script.cmd> %~dp0\actual.txt | |
| 2 | 2 | dlltool.exe %* |
tests/run-make/raw-dylib-whitespace/main.rs created+18| ... | ... | @@ -0,0 +1,18 @@ |
| 1 | type BOOL = i32; | |
| 2 | ||
| 3 | #[cfg_attr( | |
| 4 | target_arch = "x86", | |
| 5 | link(name = "bcryptprimitives", kind = "raw-dylib", import_name_type = "undecorated") | |
| 6 | )] | |
| 7 | #[cfg_attr(not(target_arch = "x86"), link(name = "bcryptprimitives", kind = "raw-dylib"))] | |
| 8 | extern "system" { | |
| 9 | fn ProcessPrng(pbdata: *mut u8, cbdata: usize) -> BOOL; | |
| 10 | } | |
| 11 | ||
| 12 | fn main() { | |
| 13 | let mut num: u8 = 0; | |
| 14 | unsafe { | |
| 15 | ProcessPrng(&mut num, 1); | |
| 16 | } | |
| 17 | println!("{num}"); | |
| 18 | } |
tests/run-make/raw-dylib-whitespace/rmake.rs created+15| ... | ... | @@ -0,0 +1,15 @@ |
| 1 | // Ensure that raw-dylib still works if the output directory contains spaces. | |
| 2 | ||
| 3 | //@ only-windows-gnu | |
| 4 | //@ ignore-cross-compile | |
| 5 | //@ needs-dlltool | |
| 6 | // Reason: this test specifically checks the dlltool feature, | |
| 7 | // which is only used on windows-gnu. | |
| 8 | ||
| 9 | use run_make_support::{rfs, rustc}; | |
| 10 | ||
| 11 | fn main() { | |
| 12 | let out_dir = std::path::absolute("path with spaces").unwrap(); | |
| 13 | rfs::create_dir_all(&out_dir); | |
| 14 | rustc().crate_type("bin").input("main.rs").out_dir(&out_dir).env("TMP", &out_dir).run(); | |
| 15 | } |
tests/rustdoc-html/doc-cfg/extern-items.rs created+26| ... | ... | @@ -0,0 +1,26 @@ |
| 1 | // Ensure that the `cfg` on the extern blocks are correctly taken into account by | |
| 2 | // their children. | |
| 3 | // Regression test for <https://github.com/rust-lang/rust/issues/150268>. | |
| 4 | ||
| 5 | #![feature(doc_cfg)] | |
| 6 | #![crate_name = "foo"] | |
| 7 | ||
| 8 | //@has 'foo/index.html' | |
| 9 | //@count - '//*[@class="stab portability"]' 2 | |
| 10 | //@has - '//*[@class="stab portability"]' 'Non-banana' | |
| 11 | ||
| 12 | //@has 'foo/fn.doc_cfg_doesnt_work.html' | |
| 13 | //@has - '//*[@class="stab portability"]' 'Available on non-crate feature banana only.' | |
| 14 | ||
| 15 | //@has 'foo/fn.doc_cfg_works.html' | |
| 16 | //@has - '//*[@class="stab portability"]' 'Available on non-crate feature banana only.' | |
| 17 | ||
| 18 | unsafe extern "C" { | |
| 19 | #[cfg(not(feature = "banana"))] | |
| 20 | pub fn doc_cfg_works(); | |
| 21 | } | |
| 22 | ||
| 23 | #[cfg(not(feature = "banana"))] | |
| 24 | unsafe extern "C" { | |
| 25 | pub fn doc_cfg_doesnt_work(); | |
| 26 | } |
tests/ui/cfg/cfg-target-compact-errors.rs+13| ... | ... | @@ -4,22 +4,35 @@ |
| 4 | 4 | |
| 5 | 5 | #[cfg(target(o::o))] |
| 6 | 6 | //~^ ERROR malformed `cfg` attribute input |
| 7 | //~| NOTE expected a valid identifier here | |
| 8 | //~| NOTE for more information, visit | |
| 9 | //~| ERROR malformed `cfg` attribute input | |
| 10 | //~| NOTE expected this to be of the form `... = "..."` | |
| 11 | //~| NOTE for more information, visit | |
| 7 | 12 | fn one() {} |
| 8 | 13 | |
| 9 | 14 | #[cfg(target(os = 8))] |
| 10 | 15 | //~^ ERROR malformed `cfg` attribute input |
| 16 | //~| NOTE expected a string literal here | |
| 17 | //~| NOTE for more information, visit | |
| 11 | 18 | fn two() {} |
| 12 | 19 | |
| 13 | 20 | #[cfg(target(os = "linux", pointer(width = "64")))] |
| 14 | 21 | //~^ ERROR malformed `cfg` attribute input |
| 22 | //~| NOTE expected this to be of the form `... = "..."` | |
| 23 | //~| NOTE for more information, visit | |
| 15 | 24 | fn three() {} |
| 16 | 25 | |
| 17 | 26 | #[cfg(target(true))] |
| 18 | 27 | //~^ ERROR malformed `cfg` attribute input |
| 28 | //~| NOTE expected this to be of the form `... = "..."` | |
| 29 | //~| NOTE for more information, visit | |
| 19 | 30 | fn four() {} |
| 20 | 31 | |
| 21 | 32 | #[cfg(target(clippy::os = "linux"))] |
| 22 | 33 | //~^ ERROR malformed `cfg` attribute input |
| 34 | //~| NOTE for more information, visit | |
| 35 | //~| NOTE expected a valid identifier here | |
| 23 | 36 | fn five() {} |
| 24 | 37 | |
| 25 | 38 | fn main() {} |
tests/ui/cfg/cfg-target-compact-errors.stderr+20-5| ... | ... | @@ -1,3 +1,18 @@ |
| 1 | error[E0539]: malformed `cfg` attribute input | |
| 2 | --> $DIR/cfg-target-compact-errors.rs:5:1 | |
| 3 | | | |
| 4 | LL | #[cfg(target(o::o))] | |
| 5 | | ^^^^^^^^^^^^^----^^^ | |
| 6 | | | | |
| 7 | | expected a valid identifier here | |
| 8 | | | |
| 9 | = note: for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg-attribute> | |
| 10 | help: must be of the form | |
| 11 | | | |
| 12 | LL - #[cfg(target(o::o))] | |
| 13 | LL + #[cfg(predicate)] | |
| 14 | | | |
| 15 | ||
| 1 | 16 | error[E0539]: malformed `cfg` attribute input |
| 2 | 17 | --> $DIR/cfg-target-compact-errors.rs:5:1 |
| 3 | 18 | | |
| ... | ... | @@ -14,7 +29,7 @@ LL + #[cfg(predicate)] |
| 14 | 29 | | |
| 15 | 30 | |
| 16 | 31 | error[E0539]: malformed `cfg` attribute input |
| 17 | --> $DIR/cfg-target-compact-errors.rs:9:1 | |
| 32 | --> $DIR/cfg-target-compact-errors.rs:14:1 | |
| 18 | 33 | | |
| 19 | 34 | LL | #[cfg(target(os = 8))] |
| 20 | 35 | | ^^^^^^^^^^^^^^^^^^-^^^ |
| ... | ... | @@ -29,7 +44,7 @@ LL + #[cfg(predicate)] |
| 29 | 44 | | |
| 30 | 45 | |
| 31 | 46 | error[E0539]: malformed `cfg` attribute input |
| 32 | --> $DIR/cfg-target-compact-errors.rs:13:1 | |
| 47 | --> $DIR/cfg-target-compact-errors.rs:20:1 | |
| 33 | 48 | | |
| 34 | 49 | LL | #[cfg(target(os = "linux", pointer(width = "64")))] |
| 35 | 50 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^---------------------^^^ |
| ... | ... | @@ -44,7 +59,7 @@ LL + #[cfg(predicate)] |
| 44 | 59 | | |
| 45 | 60 | |
| 46 | 61 | error[E0539]: malformed `cfg` attribute input |
| 47 | --> $DIR/cfg-target-compact-errors.rs:17:1 | |
| 62 | --> $DIR/cfg-target-compact-errors.rs:26:1 | |
| 48 | 63 | | |
| 49 | 64 | LL | #[cfg(target(true))] |
| 50 | 65 | | ^^^^^^^^^^^^^----^^^ |
| ... | ... | @@ -59,7 +74,7 @@ LL + #[cfg(predicate)] |
| 59 | 74 | | |
| 60 | 75 | |
| 61 | 76 | error[E0539]: malformed `cfg` attribute input |
| 62 | --> $DIR/cfg-target-compact-errors.rs:21:1 | |
| 77 | --> $DIR/cfg-target-compact-errors.rs:32:1 | |
| 63 | 78 | | |
| 64 | 79 | LL | #[cfg(target(clippy::os = "linux"))] |
| 65 | 80 | | ^^^^^^^^^^^^^----------^^^^^^^^^^^^^ |
| ... | ... | @@ -73,6 +88,6 @@ LL - #[cfg(target(clippy::os = "linux"))] |
| 73 | 88 | LL + #[cfg(predicate)] |
| 74 | 89 | | |
| 75 | 90 | |
| 76 | error: aborting due to 5 previous errors | |
| 91 | error: aborting due to 6 previous errors | |
| 77 | 92 | |
| 78 | 93 | For more information about this error, try `rustc --explain E0539`. |
tests/ui/closures/auxiliary/wrong-closure-arg-suggestion-aux.rs created+34| ... | ... | @@ -0,0 +1,34 @@ |
| 1 | pub struct P; | |
| 2 | pub struct Map<F>(pub F); | |
| 3 | ||
| 4 | pub trait PIter: Sized { | |
| 5 | fn map<F>(self, f: F) -> Map<F> | |
| 6 | where | |
| 7 | F: Fn(i32); | |
| 8 | ||
| 9 | fn flat_map<F, U>(self, f: F) | |
| 10 | where | |
| 11 | F: Fn(i32) -> U; | |
| 12 | } | |
| 13 | ||
| 14 | impl PIter for P { | |
| 15 | fn map<F>(self, f: F) -> Map<F> | |
| 16 | where | |
| 17 | F: Fn(i32), | |
| 18 | { | |
| 19 | Map(f) | |
| 20 | } | |
| 21 | ||
| 22 | fn flat_map<F, U>(self, _: F) | |
| 23 | where | |
| 24 | F: Fn(i32) -> U, | |
| 25 | { | |
| 26 | } | |
| 27 | } | |
| 28 | ||
| 29 | pub fn to_fn<F>(f: F) -> Map<F> | |
| 30 | where | |
| 31 | F: Fn(i32), | |
| 32 | { | |
| 33 | Map(f) | |
| 34 | } |
tests/ui/closures/wrong-closure-arg-suggestion-125325.rs+39| ... | ... | @@ -1,3 +1,5 @@ |
| 1 | //@ aux-build:wrong-closure-arg-suggestion-aux.rs | |
| 2 | ||
| 1 | 3 | // Regression test for #125325 |
| 2 | 4 | |
| 3 | 5 | // Tests that we suggest changing an `impl Fn` param |
| ... | ... | @@ -6,6 +8,10 @@ |
| 6 | 8 | // Ensures that it works that way for both |
| 7 | 9 | // functions and methods |
| 8 | 10 | |
| 11 | extern crate wrong_closure_arg_suggestion_aux as aux; | |
| 12 | ||
| 13 | use aux::{P, PIter, to_fn}; | |
| 14 | ||
| 9 | 15 | struct S; |
| 10 | 16 | |
| 11 | 17 | impl S { |
| ... | ... | @@ -26,4 +32,37 @@ fn test_func(s: &S) -> usize { |
| 26 | 32 | //~^ ERROR cannot assign to `x`, as it is a captured variable in a `Fn` closure |
| 27 | 33 | } |
| 28 | 34 | |
| 35 | // Regression test for <https://github.com/rust-lang/rust/issues/155727>. | |
| 36 | // | |
| 37 | // When the relevant `Fn` bound comes from a non-local callee, we should still | |
| 38 | // explain the call-site expectation instead of falling back to the enclosing | |
| 39 | // function's return type. | |
| 40 | struct Counter { | |
| 41 | counter: i32, | |
| 42 | } | |
| 43 | ||
| 44 | impl Counter { | |
| 45 | fn external_fn(mut self) -> i32 { | |
| 46 | take(|_| to_fn(|_| self.counter += 1)); | |
| 47 | //~^ ERROR cannot assign to `self.counter`, as `Fn` closures cannot mutate their captured variables [E0594] | |
| 48 | //~| ERROR lifetime may not live long enough | |
| 49 | //~| ERROR cannot borrow `self` as mutable, as it is a captured variable in a `Fn` closure [E0596] | |
| 50 | self.counter | |
| 51 | } | |
| 52 | ||
| 53 | fn external_method(mut self) -> i32 { | |
| 54 | P.flat_map(|_| P.map(|_| self.counter += 1)); | |
| 55 | //~^ ERROR cannot assign to `self.counter`, as `Fn` closures cannot mutate their captured variables [E0594] | |
| 56 | //~| ERROR lifetime may not live long enough | |
| 57 | //~| ERROR cannot borrow `self` as mutable, as it is a captured variable in a `Fn` closure [E0596] | |
| 58 | self.counter | |
| 59 | } | |
| 60 | } | |
| 61 | ||
| 62 | fn take<F, U>(_: F) | |
| 63 | where | |
| 64 | F: Fn(i32) -> U, | |
| 65 | { | |
| 66 | } | |
| 67 | ||
| 29 | 68 | fn main() {} |
tests/ui/closures/wrong-closure-arg-suggestion-125325.stderr+74-4| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | 1 | error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure |
| 2 | --> $DIR/wrong-closure-arg-suggestion-125325.rs:23:21 | |
| 2 | --> $DIR/wrong-closure-arg-suggestion-125325.rs:29:21 | |
| 3 | 3 | | |
| 4 | 4 | LL | fn assoc_func(&self, _f: impl Fn()) -> usize { |
| 5 | 5 | | --------- change this to accept `FnMut` instead of `Fn` |
| ... | ... | @@ -14,7 +14,7 @@ LL | s.assoc_func(|| x = ()); |
| 14 | 14 | | expects `Fn` instead of `FnMut` |
| 15 | 15 | |
| 16 | 16 | error[E0594]: cannot assign to `x`, as it is a captured variable in a `Fn` closure |
| 17 | --> $DIR/wrong-closure-arg-suggestion-125325.rs:25:13 | |
| 17 | --> $DIR/wrong-closure-arg-suggestion-125325.rs:31:13 | |
| 18 | 18 | | |
| 19 | 19 | LL | fn func(_f: impl Fn()) -> usize { |
| 20 | 20 | | --------- change this to accept `FnMut` instead of `Fn` |
| ... | ... | @@ -28,6 +28,76 @@ LL | func(|| x = ()) |
| 28 | 28 | | | in this closure |
| 29 | 29 | | expects `Fn` instead of `FnMut` |
| 30 | 30 | |
| 31 | error: aborting due to 2 previous errors | |
| 31 | error[E0594]: cannot assign to `self.counter`, as `Fn` closures cannot mutate their captured variables | |
| 32 | --> $DIR/wrong-closure-arg-suggestion-125325.rs:46:28 | |
| 33 | | | |
| 34 | LL | take(|_| to_fn(|_| self.counter += 1)); | |
| 35 | | ----- --- ^^^^^^^^^^^^^^^^^ cannot assign | |
| 36 | | | | | |
| 37 | | | in this closure | |
| 38 | | expects `Fn` instead of `FnMut` | |
| 39 | ||
| 40 | error: lifetime may not live long enough | |
| 41 | --> $DIR/wrong-closure-arg-suggestion-125325.rs:46:18 | |
| 42 | | | |
| 43 | LL | take(|_| to_fn(|_| self.counter += 1)); | |
| 44 | | --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2` | |
| 45 | | | | | |
| 46 | | | return type of closure `aux::Map<{closure@$DIR/wrong-closure-arg-suggestion-125325.rs:46:24: 46:27}>` contains a lifetime `'2` | |
| 47 | | lifetime `'1` represents this closure's body | |
| 48 | | | |
| 49 | = note: closure implements `Fn`, so references to captured variables can't escape the closure | |
| 50 | ||
| 51 | error[E0596]: cannot borrow `self` as mutable, as it is a captured variable in a `Fn` closure | |
| 52 | --> $DIR/wrong-closure-arg-suggestion-125325.rs:46:24 | |
| 53 | | | |
| 54 | LL | take(|_| to_fn(|_| self.counter += 1)); | |
| 55 | | ---- --- ^^^ ------------ mutable borrow occurs due to use of `self` in closure | |
| 56 | | | | | | |
| 57 | | | | cannot borrow as mutable | |
| 58 | | | in this closure | |
| 59 | | expects `Fn` instead of `FnMut` | |
| 60 | ... | |
| 61 | LL | fn take<F, U>(_: F) | |
| 62 | | - change this to accept `FnMut` instead of `Fn` | |
| 63 | ||
| 64 | error[E0594]: cannot assign to `self.counter`, as `Fn` closures cannot mutate their captured variables | |
| 65 | --> $DIR/wrong-closure-arg-suggestion-125325.rs:54:34 | |
| 66 | | | |
| 67 | LL | P.flat_map(|_| P.map(|_| self.counter += 1)); | |
| 68 | | --------^^^^^^^^^^^^^^^^^- | |
| 69 | | | | | | |
| 70 | | | | cannot assign | |
| 71 | | | in this closure | |
| 72 | | expects `Fn` instead of `FnMut` | |
| 73 | ||
| 74 | error: lifetime may not live long enough | |
| 75 | --> $DIR/wrong-closure-arg-suggestion-125325.rs:54:24 | |
| 76 | | | |
| 77 | LL | P.flat_map(|_| P.map(|_| self.counter += 1)); | |
| 78 | | --- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2` | |
| 79 | | | | | |
| 80 | | | return type of closure `aux::Map<{closure@$DIR/wrong-closure-arg-suggestion-125325.rs:54:30: 54:33}>` contains a lifetime `'2` | |
| 81 | | lifetime `'1` represents this closure's body | |
| 82 | | | |
| 83 | = note: closure implements `Fn`, so references to captured variables can't escape the closure | |
| 84 | help: consider adding 'move' keyword before the nested closure | |
| 85 | | | |
| 86 | LL | P.flat_map(|_| P.map(move |_| self.counter += 1)); | |
| 87 | | ++++ | |
| 88 | ||
| 89 | error[E0596]: cannot borrow `self` as mutable, as it is a captured variable in a `Fn` closure | |
| 90 | --> $DIR/wrong-closure-arg-suggestion-125325.rs:54:30 | |
| 91 | | | |
| 92 | LL | P.flat_map(|_| P.map(|_| self.counter += 1)); | |
| 93 | | -------------------^^^-------------------- | |
| 94 | | | | | | | |
| 95 | | | | | mutable borrow occurs due to use of `self` in closure | |
| 96 | | | | cannot borrow as mutable | |
| 97 | | | in this closure | |
| 98 | | expects `Fn` instead of `FnMut` | |
| 99 | ||
| 100 | error: aborting due to 8 previous errors | |
| 32 | 101 | |
| 33 | For more information about this error, try `rustc --explain E0594`. | |
| 102 | Some errors have detailed explanations: E0594, E0596. | |
| 103 | For more information about an error, try `rustc --explain E0594`. |
tests/ui/consts/const-eval/c-variadic-fail.rs+67-10| ... | ... | @@ -6,7 +6,7 @@ |
| 6 | 6 | #![feature(const_destruct)] |
| 7 | 7 | #![feature(const_clone)] |
| 8 | 8 | |
| 9 | use std::ffi::VaList; | |
| 9 | use std::ffi::{VaList, c_char, c_void}; | |
| 10 | 10 | use std::mem::MaybeUninit; |
| 11 | 11 | |
| 12 | 12 | const unsafe extern "C" fn read_n<const N: usize>(mut ap: ...) { |
| ... | ... | @@ -37,7 +37,7 @@ const unsafe extern "C" fn read_as<T: core::ffi::VaArgSafe>(mut ap: ...) -> T { |
| 37 | 37 | ap.next_arg::<T>() |
| 38 | 38 | } |
| 39 | 39 | |
| 40 | unsafe fn read_cast() { | |
| 40 | unsafe fn read_cast_numeric() { | |
| 41 | 41 | const { read_as::<i32>(1i32) }; |
| 42 | 42 | const { read_as::<u32>(1u32) }; |
| 43 | 43 | |
| ... | ... | @@ -47,20 +47,76 @@ unsafe fn read_cast() { |
| 47 | 47 | const { read_as::<i64>(1i64) }; |
| 48 | 48 | const { read_as::<u64>(1u64) }; |
| 49 | 49 | |
| 50 | // A cast between signed and unsigned is OK so long as both types can represent the value. | |
| 50 | 51 | const { read_as::<u32>(1i32) }; |
| 51 | //~^ ERROR va_arg type mismatch: requested `u32`, but next argument is `i32` | |
| 52 | ||
| 53 | 52 | const { read_as::<i32>(1u32) }; |
| 54 | //~^ ERROR va_arg type mismatch: requested `i32`, but next argument is `u32` | |
| 53 | ||
| 54 | type ConcreteUsize = cfg_select! { | |
| 55 | target_pointer_width = "16" => u16, | |
| 56 | target_pointer_width = "32" => u32, | |
| 57 | target_pointer_width = "64" => u64, | |
| 58 | }; | |
| 59 | ||
| 60 | type ConcreteIsize = cfg_select! { | |
| 61 | target_pointer_width = "16" => i16, | |
| 62 | target_pointer_width = "32" => i32, | |
| 63 | target_pointer_width = "64" => i64, | |
| 64 | }; | |
| 65 | ||
| 66 | const { read_as::<ConcreteUsize>(1usize) }; | |
| 67 | const { read_as::<usize>(1 as ConcreteUsize) }; | |
| 68 | ||
| 69 | const { read_as::<ConcreteIsize>(-1isize) }; | |
| 70 | const { read_as::<isize>(-1 as ConcreteIsize) }; | |
| 71 | ||
| 72 | const { read_as::<u32>(-1i32) }; | |
| 73 | //~^ ERROR va_arg value mismatch: value `-1_i32` cannot be represented by type `u32` | |
| 74 | const { read_as::<u32>(i32::MIN) }; | |
| 75 | //~^ ERROR va_arg value mismatch: value `-2147483648_i32` cannot be represented by type `u32` | |
| 76 | const { read_as::<i32>(u32::MAX) }; | |
| 77 | //~^ ERROR va_arg value mismatch: value `4294967295_u32` cannot be represented by type `i32` | |
| 78 | const { read_as::<i32>(i32::MAX as u32 + 1) }; | |
| 79 | //~^ ERROR va_arg value mismatch: value `2147483648_u32` cannot be represented by type `i32` | |
| 80 | const { read_as::<i64>(u64::MAX) }; | |
| 81 | //~^ ERROR va_arg value mismatch: value `18446744073709551615_u64` cannot be represented by type `i64` | |
| 82 | const { read_as::<i64>(i64::MAX as u64 + 1) }; | |
| 83 | //~^ ERROR va_arg value mismatch: value `9223372036854775808_u64` cannot be represented by type `i64` | |
| 55 | 84 | |
| 56 | 85 | const { read_as::<i32>(1u64) }; |
| 57 | //~^ ERROR va_arg type mismatch: requested `i32`, but next argument is `u64` | |
| 86 | //~^ ERROR va_arg type mismatch: requested `i32` is incompatible with next argument of type `u64` | |
| 58 | 87 | |
| 59 | 88 | const { read_as::<f64>(1i32) }; |
| 60 | //~^ ERROR va_arg type mismatch: requested `f64`, but next argument is `i32` | |
| 89 | //~^ ERROR va_arg type mismatch: requested `f64` is incompatible with next argument of type `i32` | |
| 90 | } | |
| 61 | 91 | |
| 62 | const { read_as::<*const u8>(1i32) }; | |
| 63 | //~^ ERROR va_arg type mismatch: requested `*const u8`, but next argument is `i32` | |
| 92 | unsafe fn read_cast_pointer() { | |
| 93 | // A pointer mutability cast is OK. | |
| 94 | const { read_as::<*const i32>(std::ptr::dangling_mut::<i32>()) }; | |
| 95 | const { read_as::<*mut i32>(std::ptr::dangling::<i32>()) }; | |
| 96 | ||
| 97 | // A pointer cast is OK between compatible types. | |
| 98 | const { read_as::<*const i32>(std::ptr::dangling::<u32>()) }; | |
| 99 | const { read_as::<*const i32>(std::ptr::dangling_mut::<u32>()) }; | |
| 100 | const { read_as::<*mut i32>(std::ptr::dangling::<u32>()) }; | |
| 101 | const { read_as::<*mut i32>(std::ptr::dangling_mut::<u32>()) }; | |
| 102 | ||
| 103 | // Casting between pointers to i8/u8 and c_void is OK. | |
| 104 | const { read_as::<*const c_char>(std::ptr::dangling::<c_void>()) }; | |
| 105 | const { read_as::<*const c_void>(std::ptr::dangling::<c_char>()) }; | |
| 106 | const { read_as::<*const i8>(std::ptr::dangling::<c_void>()) }; | |
| 107 | const { read_as::<*const c_void>(std::ptr::dangling::<i8>()) }; | |
| 108 | const { read_as::<*const u8>(std::ptr::dangling::<c_void>()) }; | |
| 109 | const { read_as::<*const c_void>(std::ptr::dangling::<u8>()) }; | |
| 110 | ||
| 111 | const { read_as::<*const u16>(std::ptr::dangling::<c_void>()) }; | |
| 112 | //~^ ERROR va_arg type mismatch: requested `*const u16` is incompatible with next argument of type `*const c_void` | |
| 113 | const { read_as::<*const c_void>(std::ptr::dangling::<u16>()) }; | |
| 114 | //~^ ERROR va_arg type mismatch: requested `*const c_void` is incompatible with next argument of type `*const u16` | |
| 115 | const { read_as::<*const u16>(std::ptr::dangling::<i32>()) }; | |
| 116 | //~^ ERROR va_arg type mismatch: requested `*const u16` is incompatible with next argument of type `*const i32` | |
| 117 | ||
| 118 | const { read_as::<*const u8>(1usize) }; | |
| 119 | //~^ ERROR requested `*const u8` is incompatible with next argument of type `usize` | |
| 64 | 120 | } |
| 65 | 121 | |
| 66 | 122 | fn use_after_free() { |
| ... | ... | @@ -138,7 +194,8 @@ fn drop_of_invalid() { |
| 138 | 194 | fn main() { |
| 139 | 195 | unsafe { |
| 140 | 196 | read_too_many(); |
| 141 | read_cast(); | |
| 197 | read_cast_numeric(); | |
| 198 | read_cast_pointer(); | |
| 142 | 199 | manual_copy_read(); |
| 143 | 200 | manual_copy_drop(); |
| 144 | 201 | manual_copy_forget(); |
tests/ui/consts/const-eval/c-variadic-fail.stderr+255-59| ... | ... | @@ -54,11 +54,11 @@ LL | const { read_n::<2>(1) } |
| 54 | 54 | | |
| 55 | 55 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 56 | 56 | |
| 57 | error[E0080]: va_arg type mismatch: requested `u32`, but next argument is `i32` | |
| 58 | --> $DIR/c-variadic-fail.rs:50:13 | |
| 57 | error[E0080]: va_arg value mismatch: value `-1_i32` cannot be represented by type `u32` | |
| 58 | --> $DIR/c-variadic-fail.rs:72:13 | |
| 59 | 59 | | |
| 60 | LL | const { read_as::<u32>(1i32) }; | |
| 61 | | ^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast::{constant#6}` failed inside this call | |
| 60 | LL | const { read_as::<u32>(-1i32) }; | |
| 61 | | ^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_numeric::{constant#12}` failed inside this call | |
| 62 | 62 | | |
| 63 | 63 | note: inside `read_as::<u32>` |
| 64 | 64 | --> $DIR/c-variadic-fail.rs:37:5 |
| ... | ... | @@ -69,24 +69,52 @@ note: inside `VaList::<'_>::next_arg::<u32>` |
| 69 | 69 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL |
| 70 | 70 | |
| 71 | 71 | note: erroneous constant encountered |
| 72 | --> $DIR/c-variadic-fail.rs:50:5 | |
| 72 | --> $DIR/c-variadic-fail.rs:72:5 | |
| 73 | 73 | | |
| 74 | LL | const { read_as::<u32>(1i32) }; | |
| 75 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 74 | LL | const { read_as::<u32>(-1i32) }; | |
| 75 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 76 | 76 | |
| 77 | 77 | note: erroneous constant encountered |
| 78 | --> $DIR/c-variadic-fail.rs:50:5 | |
| 78 | --> $DIR/c-variadic-fail.rs:72:5 | |
| 79 | 79 | | |
| 80 | LL | const { read_as::<u32>(1i32) }; | |
| 81 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 80 | LL | const { read_as::<u32>(-1i32) }; | |
| 81 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 82 | | | |
| 83 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` | |
| 84 | ||
| 85 | error[E0080]: va_arg value mismatch: value `-2147483648_i32` cannot be represented by type `u32` | |
| 86 | --> $DIR/c-variadic-fail.rs:74:13 | |
| 87 | | | |
| 88 | LL | const { read_as::<u32>(i32::MIN) }; | |
| 89 | | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_numeric::{constant#13}` failed inside this call | |
| 90 | | | |
| 91 | note: inside `read_as::<u32>` | |
| 92 | --> $DIR/c-variadic-fail.rs:37:5 | |
| 93 | | | |
| 94 | LL | ap.next_arg::<T>() | |
| 95 | | ^^^^^^^^^^^^^^^^^^ | |
| 96 | note: inside `VaList::<'_>::next_arg::<u32>` | |
| 97 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL | |
| 98 | ||
| 99 | note: erroneous constant encountered | |
| 100 | --> $DIR/c-variadic-fail.rs:74:5 | |
| 101 | | | |
| 102 | LL | const { read_as::<u32>(i32::MIN) }; | |
| 103 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 104 | ||
| 105 | note: erroneous constant encountered | |
| 106 | --> $DIR/c-variadic-fail.rs:74:5 | |
| 107 | | | |
| 108 | LL | const { read_as::<u32>(i32::MIN) }; | |
| 109 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 82 | 110 | | |
| 83 | 111 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 84 | 112 | |
| 85 | error[E0080]: va_arg type mismatch: requested `i32`, but next argument is `u32` | |
| 86 | --> $DIR/c-variadic-fail.rs:53:13 | |
| 113 | error[E0080]: va_arg value mismatch: value `4294967295_u32` cannot be represented by type `i32` | |
| 114 | --> $DIR/c-variadic-fail.rs:76:13 | |
| 87 | 115 | | |
| 88 | LL | const { read_as::<i32>(1u32) }; | |
| 89 | | ^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast::{constant#7}` failed inside this call | |
| 116 | LL | const { read_as::<i32>(u32::MAX) }; | |
| 117 | | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_numeric::{constant#14}` failed inside this call | |
| 90 | 118 | | |
| 91 | 119 | note: inside `read_as::<i32>` |
| 92 | 120 | --> $DIR/c-variadic-fail.rs:37:5 |
| ... | ... | @@ -97,24 +125,108 @@ note: inside `VaList::<'_>::next_arg::<i32>` |
| 97 | 125 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL |
| 98 | 126 | |
| 99 | 127 | note: erroneous constant encountered |
| 100 | --> $DIR/c-variadic-fail.rs:53:5 | |
| 128 | --> $DIR/c-variadic-fail.rs:76:5 | |
| 101 | 129 | | |
| 102 | LL | const { read_as::<i32>(1u32) }; | |
| 103 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 130 | LL | const { read_as::<i32>(u32::MAX) }; | |
| 131 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 104 | 132 | |
| 105 | 133 | note: erroneous constant encountered |
| 106 | --> $DIR/c-variadic-fail.rs:53:5 | |
| 134 | --> $DIR/c-variadic-fail.rs:76:5 | |
| 107 | 135 | | |
| 108 | LL | const { read_as::<i32>(1u32) }; | |
| 109 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 136 | LL | const { read_as::<i32>(u32::MAX) }; | |
| 137 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 138 | | | |
| 139 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` | |
| 140 | ||
| 141 | error[E0080]: va_arg value mismatch: value `2147483648_u32` cannot be represented by type `i32` | |
| 142 | --> $DIR/c-variadic-fail.rs:78:13 | |
| 143 | | | |
| 144 | LL | const { read_as::<i32>(i32::MAX as u32 + 1) }; | |
| 145 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_numeric::{constant#15}` failed inside this call | |
| 146 | | | |
| 147 | note: inside `read_as::<i32>` | |
| 148 | --> $DIR/c-variadic-fail.rs:37:5 | |
| 149 | | | |
| 150 | LL | ap.next_arg::<T>() | |
| 151 | | ^^^^^^^^^^^^^^^^^^ | |
| 152 | note: inside `VaList::<'_>::next_arg::<i32>` | |
| 153 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL | |
| 154 | ||
| 155 | note: erroneous constant encountered | |
| 156 | --> $DIR/c-variadic-fail.rs:78:5 | |
| 157 | | | |
| 158 | LL | const { read_as::<i32>(i32::MAX as u32 + 1) }; | |
| 159 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 160 | ||
| 161 | note: erroneous constant encountered | |
| 162 | --> $DIR/c-variadic-fail.rs:78:5 | |
| 163 | | | |
| 164 | LL | const { read_as::<i32>(i32::MAX as u32 + 1) }; | |
| 165 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 166 | | | |
| 167 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` | |
| 168 | ||
| 169 | error[E0080]: va_arg value mismatch: value `18446744073709551615_u64` cannot be represented by type `i64` | |
| 170 | --> $DIR/c-variadic-fail.rs:80:13 | |
| 171 | | | |
| 172 | LL | const { read_as::<i64>(u64::MAX) }; | |
| 173 | | ^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_numeric::{constant#16}` failed inside this call | |
| 174 | | | |
| 175 | note: inside `read_as::<i64>` | |
| 176 | --> $DIR/c-variadic-fail.rs:37:5 | |
| 177 | | | |
| 178 | LL | ap.next_arg::<T>() | |
| 179 | | ^^^^^^^^^^^^^^^^^^ | |
| 180 | note: inside `VaList::<'_>::next_arg::<i64>` | |
| 181 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL | |
| 182 | ||
| 183 | note: erroneous constant encountered | |
| 184 | --> $DIR/c-variadic-fail.rs:80:5 | |
| 185 | | | |
| 186 | LL | const { read_as::<i64>(u64::MAX) }; | |
| 187 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 188 | ||
| 189 | note: erroneous constant encountered | |
| 190 | --> $DIR/c-variadic-fail.rs:80:5 | |
| 191 | | | |
| 192 | LL | const { read_as::<i64>(u64::MAX) }; | |
| 193 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 194 | | | |
| 195 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` | |
| 196 | ||
| 197 | error[E0080]: va_arg value mismatch: value `9223372036854775808_u64` cannot be represented by type `i64` | |
| 198 | --> $DIR/c-variadic-fail.rs:82:13 | |
| 199 | | | |
| 200 | LL | const { read_as::<i64>(i64::MAX as u64 + 1) }; | |
| 201 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_numeric::{constant#17}` failed inside this call | |
| 202 | | | |
| 203 | note: inside `read_as::<i64>` | |
| 204 | --> $DIR/c-variadic-fail.rs:37:5 | |
| 205 | | | |
| 206 | LL | ap.next_arg::<T>() | |
| 207 | | ^^^^^^^^^^^^^^^^^^ | |
| 208 | note: inside `VaList::<'_>::next_arg::<i64>` | |
| 209 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL | |
| 210 | ||
| 211 | note: erroneous constant encountered | |
| 212 | --> $DIR/c-variadic-fail.rs:82:5 | |
| 213 | | | |
| 214 | LL | const { read_as::<i64>(i64::MAX as u64 + 1) }; | |
| 215 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 216 | ||
| 217 | note: erroneous constant encountered | |
| 218 | --> $DIR/c-variadic-fail.rs:82:5 | |
| 219 | | | |
| 220 | LL | const { read_as::<i64>(i64::MAX as u64 + 1) }; | |
| 221 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 110 | 222 | | |
| 111 | 223 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 112 | 224 | |
| 113 | error[E0080]: va_arg type mismatch: requested `i32`, but next argument is `u64` | |
| 114 | --> $DIR/c-variadic-fail.rs:56:13 | |
| 225 | error[E0080]: va_arg type mismatch: requested `i32` is incompatible with next argument of type `u64` | |
| 226 | --> $DIR/c-variadic-fail.rs:85:13 | |
| 115 | 227 | | |
| 116 | 228 | LL | const { read_as::<i32>(1u64) }; |
| 117 | | ^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast::{constant#8}` failed inside this call | |
| 229 | | ^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_numeric::{constant#18}` failed inside this call | |
| 118 | 230 | | |
| 119 | 231 | note: inside `read_as::<i32>` |
| 120 | 232 | --> $DIR/c-variadic-fail.rs:37:5 |
| ... | ... | @@ -125,24 +237,24 @@ note: inside `VaList::<'_>::next_arg::<i32>` |
| 125 | 237 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL |
| 126 | 238 | |
| 127 | 239 | note: erroneous constant encountered |
| 128 | --> $DIR/c-variadic-fail.rs:56:5 | |
| 240 | --> $DIR/c-variadic-fail.rs:85:5 | |
| 129 | 241 | | |
| 130 | 242 | LL | const { read_as::<i32>(1u64) }; |
| 131 | 243 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 132 | 244 | |
| 133 | 245 | note: erroneous constant encountered |
| 134 | --> $DIR/c-variadic-fail.rs:56:5 | |
| 246 | --> $DIR/c-variadic-fail.rs:85:5 | |
| 135 | 247 | | |
| 136 | 248 | LL | const { read_as::<i32>(1u64) }; |
| 137 | 249 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 138 | 250 | | |
| 139 | 251 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 140 | 252 | |
| 141 | error[E0080]: va_arg type mismatch: requested `f64`, but next argument is `i32` | |
| 142 | --> $DIR/c-variadic-fail.rs:59:13 | |
| 253 | error[E0080]: va_arg type mismatch: requested `f64` is incompatible with next argument of type `i32` | |
| 254 | --> $DIR/c-variadic-fail.rs:88:13 | |
| 143 | 255 | | |
| 144 | 256 | LL | const { read_as::<f64>(1i32) }; |
| 145 | | ^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast::{constant#9}` failed inside this call | |
| 257 | | ^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_numeric::{constant#19}` failed inside this call | |
| 146 | 258 | | |
| 147 | 259 | note: inside `read_as::<f64>` |
| 148 | 260 | --> $DIR/c-variadic-fail.rs:37:5 |
| ... | ... | @@ -153,24 +265,108 @@ note: inside `VaList::<'_>::next_arg::<f64>` |
| 153 | 265 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL |
| 154 | 266 | |
| 155 | 267 | note: erroneous constant encountered |
| 156 | --> $DIR/c-variadic-fail.rs:59:5 | |
| 268 | --> $DIR/c-variadic-fail.rs:88:5 | |
| 157 | 269 | | |
| 158 | 270 | LL | const { read_as::<f64>(1i32) }; |
| 159 | 271 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 160 | 272 | |
| 161 | 273 | note: erroneous constant encountered |
| 162 | --> $DIR/c-variadic-fail.rs:59:5 | |
| 274 | --> $DIR/c-variadic-fail.rs:88:5 | |
| 163 | 275 | | |
| 164 | 276 | LL | const { read_as::<f64>(1i32) }; |
| 165 | 277 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 166 | 278 | | |
| 167 | 279 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 168 | 280 | |
| 169 | error[E0080]: va_arg type mismatch: requested `*const u8`, but next argument is `i32` | |
| 170 | --> $DIR/c-variadic-fail.rs:62:13 | |
| 281 | error[E0080]: va_arg type mismatch: requested `*const u16` is incompatible with next argument of type `*const c_void` | |
| 282 | --> $DIR/c-variadic-fail.rs:111:13 | |
| 283 | | | |
| 284 | LL | const { read_as::<*const u16>(std::ptr::dangling::<c_void>()) }; | |
| 285 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_pointer::{constant#12}` failed inside this call | |
| 286 | | | |
| 287 | note: inside `read_as::<*const u16>` | |
| 288 | --> $DIR/c-variadic-fail.rs:37:5 | |
| 289 | | | |
| 290 | LL | ap.next_arg::<T>() | |
| 291 | | ^^^^^^^^^^^^^^^^^^ | |
| 292 | note: inside `VaList::<'_>::next_arg::<*const u16>` | |
| 293 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL | |
| 294 | ||
| 295 | note: erroneous constant encountered | |
| 296 | --> $DIR/c-variadic-fail.rs:111:5 | |
| 297 | | | |
| 298 | LL | const { read_as::<*const u16>(std::ptr::dangling::<c_void>()) }; | |
| 299 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 300 | ||
| 301 | note: erroneous constant encountered | |
| 302 | --> $DIR/c-variadic-fail.rs:111:5 | |
| 303 | | | |
| 304 | LL | const { read_as::<*const u16>(std::ptr::dangling::<c_void>()) }; | |
| 305 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 306 | | | |
| 307 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` | |
| 308 | ||
| 309 | error[E0080]: va_arg type mismatch: requested `*const c_void` is incompatible with next argument of type `*const u16` | |
| 310 | --> $DIR/c-variadic-fail.rs:113:13 | |
| 311 | | | |
| 312 | LL | const { read_as::<*const c_void>(std::ptr::dangling::<u16>()) }; | |
| 313 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_pointer::{constant#13}` failed inside this call | |
| 171 | 314 | | |
| 172 | LL | const { read_as::<*const u8>(1i32) }; | |
| 173 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast::{constant#10}` failed inside this call | |
| 315 | note: inside `read_as::<*const c_void>` | |
| 316 | --> $DIR/c-variadic-fail.rs:37:5 | |
| 317 | | | |
| 318 | LL | ap.next_arg::<T>() | |
| 319 | | ^^^^^^^^^^^^^^^^^^ | |
| 320 | note: inside `VaList::<'_>::next_arg::<*const c_void>` | |
| 321 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL | |
| 322 | ||
| 323 | note: erroneous constant encountered | |
| 324 | --> $DIR/c-variadic-fail.rs:113:5 | |
| 325 | | | |
| 326 | LL | const { read_as::<*const c_void>(std::ptr::dangling::<u16>()) }; | |
| 327 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 328 | ||
| 329 | note: erroneous constant encountered | |
| 330 | --> $DIR/c-variadic-fail.rs:113:5 | |
| 331 | | | |
| 332 | LL | const { read_as::<*const c_void>(std::ptr::dangling::<u16>()) }; | |
| 333 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 334 | | | |
| 335 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` | |
| 336 | ||
| 337 | error[E0080]: va_arg type mismatch: requested `*const u16` is incompatible with next argument of type `*const i32` | |
| 338 | --> $DIR/c-variadic-fail.rs:115:13 | |
| 339 | | | |
| 340 | LL | const { read_as::<*const u16>(std::ptr::dangling::<i32>()) }; | |
| 341 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_pointer::{constant#14}` failed inside this call | |
| 342 | | | |
| 343 | note: inside `read_as::<*const u16>` | |
| 344 | --> $DIR/c-variadic-fail.rs:37:5 | |
| 345 | | | |
| 346 | LL | ap.next_arg::<T>() | |
| 347 | | ^^^^^^^^^^^^^^^^^^ | |
| 348 | note: inside `VaList::<'_>::next_arg::<*const u16>` | |
| 349 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL | |
| 350 | ||
| 351 | note: erroneous constant encountered | |
| 352 | --> $DIR/c-variadic-fail.rs:115:5 | |
| 353 | | | |
| 354 | LL | const { read_as::<*const u16>(std::ptr::dangling::<i32>()) }; | |
| 355 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 356 | ||
| 357 | note: erroneous constant encountered | |
| 358 | --> $DIR/c-variadic-fail.rs:115:5 | |
| 359 | | | |
| 360 | LL | const { read_as::<*const u16>(std::ptr::dangling::<i32>()) }; | |
| 361 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 362 | | | |
| 363 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` | |
| 364 | ||
| 365 | error[E0080]: va_arg type mismatch: requested `*const u8` is incompatible with next argument of type `usize` | |
| 366 | --> $DIR/c-variadic-fail.rs:118:13 | |
| 367 | | | |
| 368 | LL | const { read_as::<*const u8>(1usize) }; | |
| 369 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ evaluation of `read_cast_pointer::{constant#15}` failed inside this call | |
| 174 | 370 | | |
| 175 | 371 | note: inside `read_as::<*const u8>` |
| 176 | 372 | --> $DIR/c-variadic-fail.rs:37:5 |
| ... | ... | @@ -181,21 +377,21 @@ note: inside `VaList::<'_>::next_arg::<*const u8>` |
| 181 | 377 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL |
| 182 | 378 | |
| 183 | 379 | note: erroneous constant encountered |
| 184 | --> $DIR/c-variadic-fail.rs:62:5 | |
| 380 | --> $DIR/c-variadic-fail.rs:118:5 | |
| 185 | 381 | | |
| 186 | LL | const { read_as::<*const u8>(1i32) }; | |
| 187 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 382 | LL | const { read_as::<*const u8>(1usize) }; | |
| 383 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 188 | 384 | |
| 189 | 385 | note: erroneous constant encountered |
| 190 | --> $DIR/c-variadic-fail.rs:62:5 | |
| 386 | --> $DIR/c-variadic-fail.rs:118:5 | |
| 191 | 387 | | |
| 192 | LL | const { read_as::<*const u8>(1i32) }; | |
| 193 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 388 | LL | const { read_as::<*const u8>(1usize) }; | |
| 389 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 194 | 390 | | |
| 195 | 391 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 196 | 392 | |
| 197 | 393 | error[E0080]: memory access failed: ALLOC0 has been freed, so this pointer is dangling |
| 198 | --> $DIR/c-variadic-fail.rs:75:13 | |
| 394 | --> $DIR/c-variadic-fail.rs:131:13 | |
| 199 | 395 | | |
| 200 | 396 | LL | ap.next_arg::<i32>(); |
| 201 | 397 | | ^^^^^^^^^^^^^^^^^^^^ evaluation of `use_after_free::{constant#0}` failed inside this call |
| ... | ... | @@ -204,7 +400,7 @@ note: inside `VaList::<'_>::next_arg::<i32>` |
| 204 | 400 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL |
| 205 | 401 | |
| 206 | 402 | note: erroneous constant encountered |
| 207 | --> $DIR/c-variadic-fail.rs:71:5 | |
| 403 | --> $DIR/c-variadic-fail.rs:127:5 | |
| 208 | 404 | | |
| 209 | 405 | LL | / const { |
| 210 | 406 | LL | | unsafe { |
| ... | ... | @@ -215,7 +411,7 @@ LL | | }; |
| 215 | 411 | | |_____^ |
| 216 | 412 | |
| 217 | 413 | note: erroneous constant encountered |
| 218 | --> $DIR/c-variadic-fail.rs:71:5 | |
| 414 | --> $DIR/c-variadic-fail.rs:127:5 | |
| 219 | 415 | | |
| 220 | 416 | LL | / const { |
| 221 | 417 | LL | | unsafe { |
| ... | ... | @@ -228,13 +424,13 @@ LL | | }; |
| 228 | 424 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 229 | 425 | |
| 230 | 426 | error[E0080]: using ALLOC1 as variable argument list pointer but it does not point to a variable argument list |
| 231 | --> $DIR/c-variadic-fail.rs:97:22 | |
| 427 | --> $DIR/c-variadic-fail.rs:153:22 | |
| 232 | 428 | | |
| 233 | 429 | LL | const { unsafe { helper(1, 2, 3) } }; |
| 234 | 430 | | ^^^^^^^^^^^^^^^ evaluation of `manual_copy_drop::{constant#0}` failed inside this call |
| 235 | 431 | | |
| 236 | 432 | note: inside `manual_copy_drop::helper` |
| 237 | --> $DIR/c-variadic-fail.rs:94:9 | |
| 433 | --> $DIR/c-variadic-fail.rs:150:9 | |
| 238 | 434 | | |
| 239 | 435 | LL | drop(ap); |
| 240 | 436 | | ^^^^^^^^ |
| ... | ... | @@ -246,13 +442,13 @@ note: inside `<VaList<'_> as Drop>::drop` |
| 246 | 442 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL |
| 247 | 443 | |
| 248 | 444 | note: erroneous constant encountered |
| 249 | --> $DIR/c-variadic-fail.rs:97:5 | |
| 445 | --> $DIR/c-variadic-fail.rs:153:5 | |
| 250 | 446 | | |
| 251 | 447 | LL | const { unsafe { helper(1, 2, 3) } }; |
| 252 | 448 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 253 | 449 | |
| 254 | 450 | note: erroneous constant encountered |
| 255 | --> $DIR/c-variadic-fail.rs:97:5 | |
| 451 | --> $DIR/c-variadic-fail.rs:153:5 | |
| 256 | 452 | | |
| 257 | 453 | LL | const { unsafe { helper(1, 2, 3) } }; |
| 258 | 454 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -260,13 +456,13 @@ LL | const { unsafe { helper(1, 2, 3) } }; |
| 260 | 456 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 261 | 457 | |
| 262 | 458 | error[E0080]: using ALLOC2 as variable argument list pointer but it does not point to a variable argument list |
| 263 | --> $DIR/c-variadic-fail.rs:113:22 | |
| 459 | --> $DIR/c-variadic-fail.rs:169:22 | |
| 264 | 460 | | |
| 265 | 461 | LL | const { unsafe { helper(1, 2, 3) } }; |
| 266 | 462 | | ^^^^^^^^^^^^^^^ evaluation of `manual_copy_forget::{constant#0}` failed inside this call |
| 267 | 463 | | |
| 268 | 464 | note: inside `manual_copy_forget::helper` |
| 269 | --> $DIR/c-variadic-fail.rs:110:9 | |
| 465 | --> $DIR/c-variadic-fail.rs:166:9 | |
| 270 | 466 | | |
| 271 | 467 | LL | drop(ap); |
| 272 | 468 | | ^^^^^^^^ |
| ... | ... | @@ -278,13 +474,13 @@ note: inside `<VaList<'_> as Drop>::drop` |
| 278 | 474 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL |
| 279 | 475 | |
| 280 | 476 | note: erroneous constant encountered |
| 281 | --> $DIR/c-variadic-fail.rs:113:5 | |
| 477 | --> $DIR/c-variadic-fail.rs:169:5 | |
| 282 | 478 | | |
| 283 | 479 | LL | const { unsafe { helper(1, 2, 3) } }; |
| 284 | 480 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 285 | 481 | |
| 286 | 482 | note: erroneous constant encountered |
| 287 | --> $DIR/c-variadic-fail.rs:113:5 | |
| 483 | --> $DIR/c-variadic-fail.rs:169:5 | |
| 288 | 484 | | |
| 289 | 485 | LL | const { unsafe { helper(1, 2, 3) } }; |
| 290 | 486 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -292,13 +488,13 @@ LL | const { unsafe { helper(1, 2, 3) } }; |
| 292 | 488 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 293 | 489 | |
| 294 | 490 | error[E0080]: using ALLOC3 as variable argument list pointer but it does not point to a variable argument list |
| 295 | --> $DIR/c-variadic-fail.rs:126:22 | |
| 491 | --> $DIR/c-variadic-fail.rs:182:22 | |
| 296 | 492 | | |
| 297 | 493 | LL | const { unsafe { helper(1, 2, 3) } }; |
| 298 | 494 | | ^^^^^^^^^^^^^^^ evaluation of `manual_copy_read::{constant#0}` failed inside this call |
| 299 | 495 | | |
| 300 | 496 | note: inside `manual_copy_read::helper` |
| 301 | --> $DIR/c-variadic-fail.rs:123:17 | |
| 497 | --> $DIR/c-variadic-fail.rs:179:17 | |
| 302 | 498 | | |
| 303 | 499 | LL | let _ = ap.next_arg::<i32>(); |
| 304 | 500 | | ^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -306,13 +502,13 @@ note: inside `VaList::<'_>::next_arg::<i32>` |
| 306 | 502 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL |
| 307 | 503 | |
| 308 | 504 | note: erroneous constant encountered |
| 309 | --> $DIR/c-variadic-fail.rs:126:5 | |
| 505 | --> $DIR/c-variadic-fail.rs:182:5 | |
| 310 | 506 | | |
| 311 | 507 | LL | const { unsafe { helper(1, 2, 3) } }; |
| 312 | 508 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 313 | 509 | |
| 314 | 510 | note: erroneous constant encountered |
| 315 | --> $DIR/c-variadic-fail.rs:126:5 | |
| 511 | --> $DIR/c-variadic-fail.rs:182:5 | |
| 316 | 512 | | |
| 317 | 513 | LL | const { unsafe { helper(1, 2, 3) } }; |
| 318 | 514 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| ... | ... | @@ -320,7 +516,7 @@ LL | const { unsafe { helper(1, 2, 3) } }; |
| 320 | 516 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 321 | 517 | |
| 322 | 518 | error[E0080]: pointer not dereferenceable: pointer must point to some allocation, but got null pointer |
| 323 | --> $DIR/c-variadic-fail.rs:134:5 | |
| 519 | --> $DIR/c-variadic-fail.rs:190:5 | |
| 324 | 520 | | |
| 325 | 521 | LL | } |
| 326 | 522 | | ^ evaluation of `drop_of_invalid::{constant#0}` failed inside this call |
| ... | ... | @@ -331,7 +527,7 @@ note: inside `<VaList<'_> as Drop>::drop` |
| 331 | 527 | --> $SRC_DIR/core/src/ffi/va_list.rs:LL:COL |
| 332 | 528 | |
| 333 | 529 | note: erroneous constant encountered |
| 334 | --> $DIR/c-variadic-fail.rs:131:5 | |
| 530 | --> $DIR/c-variadic-fail.rs:187:5 | |
| 335 | 531 | | |
| 336 | 532 | LL | / const { |
| 337 | 533 | LL | | let mut invalid: MaybeUninit<VaList> = MaybeUninit::zeroed(); |
| ... | ... | @@ -340,7 +536,7 @@ LL | | } |
| 340 | 536 | | |_____^ |
| 341 | 537 | |
| 342 | 538 | note: erroneous constant encountered |
| 343 | --> $DIR/c-variadic-fail.rs:131:5 | |
| 539 | --> $DIR/c-variadic-fail.rs:187:5 | |
| 344 | 540 | | |
| 345 | 541 | LL | / const { |
| 346 | 542 | LL | | let mut invalid: MaybeUninit<VaList> = MaybeUninit::zeroed(); |
| ... | ... | @@ -350,6 +546,6 @@ LL | | } |
| 350 | 546 | | |
| 351 | 547 | = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` |
| 352 | 548 | |
| 353 | error: aborting due to 12 previous errors | |
| 549 | error: aborting due to 19 previous errors | |
| 354 | 550 | |
| 355 | 551 | For more information about this error, try `rustc --explain E0080`. |
tests/ui/consts/drop-impl-nonconst-drop-field.stderr+4| ... | ... | @@ -21,6 +21,10 @@ note: required for this `Drop` impl |
| 21 | 21 | | |
| 22 | 22 | LL | impl<T> const Drop for ConstDrop2<T> { |
| 23 | 23 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 24 | help: consider restricting type parameter `T` with unstable trait `Destruct` | |
| 25 | | | |
| 26 | LL | impl<T: [const] Destruct> const Drop for ConstDrop2<T> { | |
| 27 | | ++++++++++++++++++ | |
| 24 | 28 | |
| 25 | 29 | error: aborting due to 2 previous errors |
| 26 | 30 |
tests/ui/consts/trait_alias.fail.stderr+5| ... | ... | @@ -3,6 +3,11 @@ error[E0277]: the trait bound `T: [const] Baz` is not satisfied |
| 3 | 3 | | |
| 4 | 4 | LL | x.baz(); |
| 5 | 5 | | ^^^ |
| 6 | | | |
| 7 | help: consider further restricting type parameter `T` with trait `Baz` | |
| 8 | | | |
| 9 | LL | const fn foo<T: [const] Foo + [const] Baz>(x: &T) { | |
| 10 | | +++++++++++++ | |
| 6 | 11 | |
| 7 | 12 | error: aborting due to 1 previous error |
| 8 | 13 |
tests/ui/consts/trait_alias.next_fail.stderr+5| ... | ... | @@ -3,6 +3,11 @@ error[E0277]: the trait bound `T: [const] Baz` is not satisfied |
| 3 | 3 | | |
| 4 | 4 | LL | x.baz(); |
| 5 | 5 | | ^^^ |
| 6 | | | |
| 7 | help: consider further restricting type parameter `T` with trait `Baz` | |
| 8 | | | |
| 9 | LL | const fn foo<T: [const] Foo + [const] Baz>(x: &T) { | |
| 10 | | +++++++++++++ | |
| 6 | 11 | |
| 7 | 12 | error: aborting due to 1 previous error |
| 8 | 13 |
tests/ui/imports/ambiguous-import-visibility-globglob-priv.stderr+6-6| ... | ... | @@ -5,10 +5,10 @@ LL | use crate::both::private::S; |
| 5 | 5 | | ^ private struct import |
| 6 | 6 | | |
| 7 | 7 | note: the struct import `S` is defined here... |
| 8 | --> $DIR/ambiguous-import-visibility-globglob-priv.rs:8:24 | |
| 8 | --> $DIR/ambiguous-import-visibility-globglob-priv.rs:7:13 | |
| 9 | 9 | | |
| 10 | LL | pub(super) use crate::m::*; | |
| 11 | | ^^^^^^^^^^^ | |
| 10 | LL | use crate::m::*; | |
| 11 | | ^^^^^^^^^^^ | |
| 12 | 12 | note: ...and refers to the struct `S` which is defined here |
| 13 | 13 | --> $DIR/ambiguous-import-visibility-globglob-priv.rs:2:5 |
| 14 | 14 | | |
| ... | ... | @@ -27,10 +27,10 @@ LL | use crate::both::private::S; |
| 27 | 27 | | ^ private struct import |
| 28 | 28 | | |
| 29 | 29 | note: the struct import `S` is defined here... |
| 30 | --> $DIR/ambiguous-import-visibility-globglob-priv.rs:8:24 | |
| 30 | --> $DIR/ambiguous-import-visibility-globglob-priv.rs:7:13 | |
| 31 | 31 | | |
| 32 | LL | pub(super) use crate::m::*; | |
| 33 | | ^^^^^^^^^^^ | |
| 32 | LL | use crate::m::*; | |
| 33 | | ^^^^^^^^^^^ | |
| 34 | 34 | note: ...and refers to the struct `S` which is defined here |
| 35 | 35 | --> $DIR/ambiguous-import-visibility-globglob-priv.rs:2:5 |
| 36 | 36 | | |
tests/ui/imports/ambiguous-import-visibility-globglob.rs+12-2| ... | ... | @@ -1,7 +1,5 @@ |
| 1 | 1 | //@ check-pass |
| 2 | 2 | |
| 3 | // FIXME: should report "ambiguous import visibility" in all the cases below. | |
| 4 | ||
| 5 | 3 | mod m { |
| 6 | 4 | pub struct S {} |
| 7 | 5 | } |
| ... | ... | @@ -12,7 +10,11 @@ mod min_vis_first { |
| 12 | 10 | pub use crate::m::*; |
| 13 | 11 | |
| 14 | 12 | pub use self::S as S1; |
| 13 | //~^ WARN ambiguous import visibility | |
| 14 | //~| WARN this was previously accepted | |
| 15 | 15 | pub(crate) use self::S as S2; |
| 16 | //~^ WARN ambiguous import visibility | |
| 17 | //~| WARN this was previously accepted | |
| 16 | 18 | use self::S as S3; // OK |
| 17 | 19 | } |
| 18 | 20 | |
| ... | ... | @@ -22,7 +24,11 @@ mod mid_vis_first { |
| 22 | 24 | pub use crate::m::*; |
| 23 | 25 | |
| 24 | 26 | pub use self::S as S1; |
| 27 | //~^ WARN ambiguous import visibility | |
| 28 | //~| WARN this was previously accepted | |
| 25 | 29 | pub(crate) use self::S as S2; |
| 30 | //~^ WARN ambiguous import visibility | |
| 31 | //~| WARN this was previously accepted | |
| 26 | 32 | use self::S as S3; // OK |
| 27 | 33 | } |
| 28 | 34 | |
| ... | ... | @@ -32,7 +38,11 @@ mod max_vis_first { |
| 32 | 38 | pub(crate) use crate::m::*; |
| 33 | 39 | |
| 34 | 40 | pub use self::S as S1; |
| 41 | //~^ WARN ambiguous import visibility | |
| 42 | //~| WARN this was previously accepted | |
| 35 | 43 | pub(crate) use self::S as S2; |
| 44 | //~^ WARN ambiguous import visibility | |
| 45 | //~| WARN this was previously accepted | |
| 36 | 46 | use self::S as S3; // OK |
| 37 | 47 | } |
| 38 | 48 |
tests/ui/imports/ambiguous-import-visibility-globglob.stderr created+135| ... | ... | @@ -0,0 +1,135 @@ |
| 1 | warning: ambiguous import visibility: pub or pub(in crate::min_vis_first) | |
| 2 | --> $DIR/ambiguous-import-visibility-globglob.rs:12:19 | |
| 3 | | | |
| 4 | LL | pub use self::S as S1; | |
| 5 | | ^ | |
| 6 | | | |
| 7 | = note: ambiguous because of multiple glob imports of a name in the same module | |
| 8 | note: `S` could refer to the struct imported here | |
| 9 | --> $DIR/ambiguous-import-visibility-globglob.rs:10:13 | |
| 10 | | | |
| 11 | LL | pub use crate::m::*; | |
| 12 | | ^^^^^^^^^^^ | |
| 13 | = help: consider adding an explicit import of `S` to disambiguate | |
| 14 | note: `S` could also refer to the struct imported here | |
| 15 | --> $DIR/ambiguous-import-visibility-globglob.rs:8:9 | |
| 16 | | | |
| 17 | LL | use crate::m::*; | |
| 18 | | ^^^^^^^^^^^ | |
| 19 | = help: consider adding an explicit import of `S` to disambiguate | |
| 20 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! | |
| 21 | = note: for more information, see issue #149145 <https://github.com/rust-lang/rust/issues/149145> | |
| 22 | = note: `#[warn(ambiguous_import_visibilities)]` (part of `#[warn(future_incompatible)]`) on by default | |
| 23 | ||
| 24 | warning: ambiguous import visibility: pub(crate) or pub(in crate::min_vis_first) | |
| 25 | --> $DIR/ambiguous-import-visibility-globglob.rs:15:26 | |
| 26 | | | |
| 27 | LL | pub(crate) use self::S as S2; | |
| 28 | | ^ | |
| 29 | | | |
| 30 | = note: ambiguous because of multiple glob imports of a name in the same module | |
| 31 | note: `S` could refer to the struct imported here | |
| 32 | --> $DIR/ambiguous-import-visibility-globglob.rs:10:13 | |
| 33 | | | |
| 34 | LL | pub use crate::m::*; | |
| 35 | | ^^^^^^^^^^^ | |
| 36 | = help: consider adding an explicit import of `S` to disambiguate | |
| 37 | note: `S` could also refer to the struct imported here | |
| 38 | --> $DIR/ambiguous-import-visibility-globglob.rs:8:9 | |
| 39 | | | |
| 40 | LL | use crate::m::*; | |
| 41 | | ^^^^^^^^^^^ | |
| 42 | = help: consider adding an explicit import of `S` to disambiguate | |
| 43 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! | |
| 44 | = note: for more information, see issue #149145 <https://github.com/rust-lang/rust/issues/149145> | |
| 45 | ||
| 46 | warning: ambiguous import visibility: pub or pub(in crate::mid_vis_first) | |
| 47 | --> $DIR/ambiguous-import-visibility-globglob.rs:26:19 | |
| 48 | | | |
| 49 | LL | pub use self::S as S1; | |
| 50 | | ^ | |
| 51 | | | |
| 52 | = note: ambiguous because of multiple glob imports of a name in the same module | |
| 53 | note: `S` could refer to the struct imported here | |
| 54 | --> $DIR/ambiguous-import-visibility-globglob.rs:24:13 | |
| 55 | | | |
| 56 | LL | pub use crate::m::*; | |
| 57 | | ^^^^^^^^^^^ | |
| 58 | = help: consider adding an explicit import of `S` to disambiguate | |
| 59 | note: `S` could also refer to the struct imported here | |
| 60 | --> $DIR/ambiguous-import-visibility-globglob.rs:23:9 | |
| 61 | | | |
| 62 | LL | use crate::m::*; | |
| 63 | | ^^^^^^^^^^^ | |
| 64 | = help: consider adding an explicit import of `S` to disambiguate | |
| 65 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! | |
| 66 | = note: for more information, see issue #149145 <https://github.com/rust-lang/rust/issues/149145> | |
| 67 | ||
| 68 | warning: ambiguous import visibility: pub(crate) or pub(in crate::mid_vis_first) | |
| 69 | --> $DIR/ambiguous-import-visibility-globglob.rs:29:26 | |
| 70 | | | |
| 71 | LL | pub(crate) use self::S as S2; | |
| 72 | | ^ | |
| 73 | | | |
| 74 | = note: ambiguous because of multiple glob imports of a name in the same module | |
| 75 | note: `S` could refer to the struct imported here | |
| 76 | --> $DIR/ambiguous-import-visibility-globglob.rs:24:13 | |
| 77 | | | |
| 78 | LL | pub use crate::m::*; | |
| 79 | | ^^^^^^^^^^^ | |
| 80 | = help: consider adding an explicit import of `S` to disambiguate | |
| 81 | note: `S` could also refer to the struct imported here | |
| 82 | --> $DIR/ambiguous-import-visibility-globglob.rs:23:9 | |
| 83 | | | |
| 84 | LL | use crate::m::*; | |
| 85 | | ^^^^^^^^^^^ | |
| 86 | = help: consider adding an explicit import of `S` to disambiguate | |
| 87 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! | |
| 88 | = note: for more information, see issue #149145 <https://github.com/rust-lang/rust/issues/149145> | |
| 89 | ||
| 90 | warning: ambiguous import visibility: pub or pub(in crate::max_vis_first) | |
| 91 | --> $DIR/ambiguous-import-visibility-globglob.rs:40:19 | |
| 92 | | | |
| 93 | LL | pub use self::S as S1; | |
| 94 | | ^ | |
| 95 | | | |
| 96 | = note: ambiguous because of multiple glob imports of a name in the same module | |
| 97 | note: `S` could refer to the struct imported here | |
| 98 | --> $DIR/ambiguous-import-visibility-globglob.rs:36:13 | |
| 99 | | | |
| 100 | LL | pub use crate::m::*; | |
| 101 | | ^^^^^^^^^^^ | |
| 102 | = help: consider adding an explicit import of `S` to disambiguate | |
| 103 | note: `S` could also refer to the struct imported here | |
| 104 | --> $DIR/ambiguous-import-visibility-globglob.rs:37:9 | |
| 105 | | | |
| 106 | LL | use crate::m::*; | |
| 107 | | ^^^^^^^^^^^ | |
| 108 | = help: consider adding an explicit import of `S` to disambiguate | |
| 109 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! | |
| 110 | = note: for more information, see issue #149145 <https://github.com/rust-lang/rust/issues/149145> | |
| 111 | ||
| 112 | warning: ambiguous import visibility: pub(crate) or pub(in crate::max_vis_first) | |
| 113 | --> $DIR/ambiguous-import-visibility-globglob.rs:43:26 | |
| 114 | | | |
| 115 | LL | pub(crate) use self::S as S2; | |
| 116 | | ^ | |
| 117 | | | |
| 118 | = note: ambiguous because of multiple glob imports of a name in the same module | |
| 119 | note: `S` could refer to the struct imported here | |
| 120 | --> $DIR/ambiguous-import-visibility-globglob.rs:36:13 | |
| 121 | | | |
| 122 | LL | pub use crate::m::*; | |
| 123 | | ^^^^^^^^^^^ | |
| 124 | = help: consider adding an explicit import of `S` to disambiguate | |
| 125 | note: `S` could also refer to the struct imported here | |
| 126 | --> $DIR/ambiguous-import-visibility-globglob.rs:37:9 | |
| 127 | | | |
| 128 | LL | use crate::m::*; | |
| 129 | | ^^^^^^^^^^^ | |
| 130 | = help: consider adding an explicit import of `S` to disambiguate | |
| 131 | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! | |
| 132 | = note: for more information, see issue #149145 <https://github.com/rust-lang/rust/issues/149145> | |
| 133 | ||
| 134 | warning: 6 warnings emitted | |
| 135 |
tests/ui/imports/overwrite-vis-unused.rs+2-2| ... | ... | @@ -1,12 +1,12 @@ |
| 1 | 1 | // Regression test for issues #152004 and #151124. |
| 2 | ||
| 2 | //@ check-pass | |
| 3 | 3 | #![deny(unused)] |
| 4 | 4 | |
| 5 | 5 | mod m { |
| 6 | 6 | pub struct S {} |
| 7 | 7 | } |
| 8 | 8 | |
| 9 | use m::*; //~ ERROR unused import: `m::*` | |
| 9 | use m::*; | |
| 10 | 10 | pub use m::*; |
| 11 | 11 | |
| 12 | 12 | fn main() {} |
tests/ui/imports/overwrite-vis-unused.stderr deleted-15| ... | ... | @@ -1,15 +0,0 @@ |
| 1 | error: unused import: `m::*` | |
| 2 | --> $DIR/overwrite-vis-unused.rs:9:5 | |
| 3 | | | |
| 4 | LL | use m::*; | |
| 5 | | ^^^^ | |
| 6 | | | |
| 7 | note: the lint level is defined here | |
| 8 | --> $DIR/overwrite-vis-unused.rs:3:9 | |
| 9 | | | |
| 10 | LL | #![deny(unused)] | |
| 11 | | ^^^^^^ | |
| 12 | = note: `#[deny(unused_imports)]` implied by `#[deny(unused)]` | |
| 13 | ||
| 14 | error: aborting due to 1 previous error | |
| 15 |
tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.rs-1| ... | ... | @@ -7,7 +7,6 @@ |
| 7 | 7 | //@ normalize-stderr: "[^ ]*/foo.dll_imports.lib" -> "$$LIB_FILE" |
| 8 | 8 | //@ normalize-stderr: "-m [^ ]*" -> "$$TARGET_MACHINE" |
| 9 | 9 | //@ normalize-stderr: "-f [^ ]*" -> "$$ASM_FLAGS" |
| 10 | //@ normalize-stderr: "--temp-prefix [^ ]*/foo.dll" -> "$$TEMP_PREFIX" | |
| 11 | 10 | #[link(name = "foo", kind = "raw-dylib")] |
| 12 | 11 | extern "C" { |
| 13 | 12 | // `@1` is an invalid name to export, as it usually indicates that something |
tests/ui/linkage-attr/raw-dylib/windows/dlltool-failed.stderr+1-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | error: dlltool could not create import library with $DLLTOOL -d $DEF_FILE -D foo.dll -l $LIB_FILE $TARGET_MACHINE $ASM_FLAGS --no-leading-underscore $TEMP_PREFIX: | |
| 1 | error: dlltool could not create import library with $DLLTOOL -d $DEF_FILE -D foo.dll -l $LIB_FILE $TARGET_MACHINE $ASM_FLAGS --no-leading-underscore --temp-prefix foo.dll: | |
| 2 | 2 | |
| 3 | 3 | $DLLTOOL: Syntax error in def file $DEF_FILE:1␍ |
| 4 | 4 |
tests/ui/linkage-attr/raw-dylib/windows/import-name-type-invalid-format.stderr+3-3| ... | ... | @@ -2,9 +2,9 @@ error[E0539]: malformed `link` attribute input |
| 2 | 2 | --> $DIR/import-name-type-invalid-format.rs:9:1 |
| 3 | 3 | | |
| 4 | 4 | LL | #[link(name = "foo", kind = "raw-dylib", import_name_type = 6)] |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^--------------------^^ | |
| 6 | | | | |
| 7 | | expected this to be of the form `import_name_type = "..."` | |
| 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-^^ | |
| 6 | | | | |
| 7 | | expected a string literal here | |
| 8 | 8 | | |
| 9 | 9 | = note: for more information, visit <https://doc.rust-lang.org/reference/items/external-blocks.html#the-link-attribute> |
| 10 | 10 |
tests/ui/simd/intrinsic/generic-reduction-pass.rs+5-4| ... | ... | @@ -109,10 +109,11 @@ const fn ordered() { |
| 109 | 109 | let r: f32 = simd_reduce_mul_ordered(x, 2.); |
| 110 | 110 | assert_eq!(r, -48_f32); |
| 111 | 111 | |
| 112 | let r: f32 = simd_reduce_min(x); | |
| 113 | assert_eq!(r, -2_f32); | |
| 114 | let r: f32 = simd_reduce_max(x); | |
| 115 | assert_eq!(r, 4_f32); | |
| 112 | // FIXME: re-enable when the intrinsic works on floats again. | |
| 113 | // let r: f32 = simd_reduce_min(x); | |
| 114 | // assert_eq!(r, -2_f32); | |
| 115 | // let r: f32 = simd_reduce_max(x); | |
| 116 | // assert_eq!(r, 4_f32); | |
| 116 | 117 | } |
| 117 | 118 | |
| 118 | 119 | unsafe { |
tests/ui/target-feature/invalid-attribute.rs+1-1| ... | ... | @@ -31,7 +31,7 @@ extern "Rust" {} |
| 31 | 31 | //~| NOTE expected this to be of the form `enable = "..."` |
| 32 | 32 | #[target_feature(disable = "baz")] |
| 33 | 33 | //~^ ERROR malformed `target_feature` attribute |
| 34 | //~| NOTE expected this to be of the form `enable = "..."` | |
| 34 | //~| NOTE the only valid argument here is `enable` | |
| 35 | 35 | unsafe fn foo() {} |
| 36 | 36 | |
| 37 | 37 | #[target_feature(enable = "sse2")] |
tests/ui/target-feature/invalid-attribute.stderr+1-1| ... | ... | @@ -56,7 +56,7 @@ error[E0539]: malformed `target_feature` attribute input |
| 56 | 56 | LL | #[target_feature(disable = "baz")] |
| 57 | 57 | | ^^^^^^^^^^^^^^^^^-------^^^^^^^^^^ |
| 58 | 58 | | | |
| 59 | | expected this to be of the form `enable = "..."` | |
| 59 | | the only valid argument here is `enable` | |
| 60 | 60 | | |
| 61 | 61 | help: must be of the form |
| 62 | 62 | | |
tests/ui/test-attrs/test-should-panic-attr.rs+1-1| ... | ... | @@ -19,7 +19,7 @@ fn test2() { |
| 19 | 19 | #[test] |
| 20 | 20 | #[should_panic(expect)] |
| 21 | 21 | //~^ ERROR malformed `should_panic` attribute input |
| 22 | //~| NOTE the only valid argument here is "expected" | |
| 22 | //~| NOTE expected this to be of the form `expected = "..."` | |
| 23 | 23 | //~| NOTE for more information, visit |
| 24 | 24 | fn test3() { |
| 25 | 25 | panic!(); |
tests/ui/test-attrs/test-should-panic-attr.stderr+3-3| ... | ... | @@ -22,9 +22,9 @@ error[E0539]: malformed `should_panic` attribute input |
| 22 | 22 | --> $DIR/test-should-panic-attr.rs:20:1 |
| 23 | 23 | | |
| 24 | 24 | LL | #[should_panic(expect)] |
| 25 | | ^^^^^^^^^^^^^^--------^ | |
| 26 | | | | |
| 27 | | the only valid argument here is "expected" | |
| 25 | | ^^^^^^^^^^^^^^^------^^ | |
| 26 | | | | |
| 27 | | expected this to be of the form `expected = "..."` | |
| 28 | 28 | | |
| 29 | 29 | = note: for more information, visit <https://doc.rust-lang.org/reference/attributes/testing.html#the-should_panic-attribute> |
| 30 | 30 | help: try changing it to one of the following valid forms of the attribute |
tests/ui/traits/const-traits/super-traits-fail-2.yn.stderr+5| ... | ... | @@ -15,6 +15,11 @@ error[E0277]: the trait bound `T: [const] Foo` is not satisfied |
| 15 | 15 | | |
| 16 | 16 | LL | x.a(); |
| 17 | 17 | | ^ |
| 18 | | | |
| 19 | help: consider further restricting type parameter `T` with trait `Foo` | |
| 20 | | | |
| 21 | LL | const fn foo<T: Bar + [const] Foo>(x: &T) { | |
| 22 | | +++++++++++++ | |
| 18 | 23 | |
| 19 | 24 | error: aborting due to 2 previous errors |
| 20 | 25 |
tests/ui/traits/const-traits/super-traits-fail-2.yy.stderr+5| ... | ... | @@ -3,6 +3,11 @@ error[E0277]: the trait bound `T: [const] Foo` is not satisfied |
| 3 | 3 | | |
| 4 | 4 | LL | x.a(); |
| 5 | 5 | | ^ |
| 6 | | | |
| 7 | help: consider further restricting type parameter `T` with trait `Foo` | |
| 8 | | | |
| 9 | LL | const fn foo<T: Bar + [const] Foo>(x: &T) { | |
| 10 | | +++++++++++++ | |
| 6 | 11 | |
| 7 | 12 | error: aborting due to 1 previous error |
| 8 | 13 |
tests/ui/traits/const-traits/super-traits-fail-3.yyn.stderr+5| ... | ... | @@ -38,6 +38,11 @@ error[E0277]: the trait bound `T: [const] Foo` is not satisfied |
| 38 | 38 | | |
| 39 | 39 | LL | x.a(); |
| 40 | 40 | | ^ |
| 41 | | | |
| 42 | help: consider further restricting type parameter `T` with trait `Foo` | |
| 43 | | | |
| 44 | LL | const fn foo<T: [const] Bar + [const] Foo>(x: &T) { | |
| 45 | | +++++++++++++ | |
| 41 | 46 | |
| 42 | 47 | error: aborting due to 4 previous errors |
| 43 | 48 |